Walls complete (12 log courses, top at z≈3.15). Now the gabled shingle roof with ridge cap, eaves, and the front porch:

import bpy, math

scene = bpy.context.scene
CX = 6.8
MAT_LOG   = bpy.data.materials["LogMat"]
MAT_PLANK = bpy.data.materials["PlankMat"]
MAT_DARK  = bpy.data.materials["DarkWood"]
MAT_ROOF  = bpy.data.materials["RoofMat"]
MAT_TRIM  = bpy.data.materials["TrimWood"]
MAT_STONE = bpy.data.materials["StoneMat"]

def link_to(obj, cname):
    col = bpy.data.collections.get(cname)
    if col is None:
        col = bpy.data.collections.new(cname); scene.collection.children.link(col)
    for c in list(obj.users_collection): c.objects.unlink(obj)
    col.objects.link(obj)

def box(name, sx,sy,sz, loc, rot=(0,0,0), mat=None):
    bpy.ops.mesh.primitive_cube_add(size=1, location=loc, rotation=rot)
    ob=bpy.context.active_object; ob.name=name
    ob.scale=(sx/2, sy/2, sz/2)
    bpy.ops.object.transform_apply(scale=True)
    if mat: ob.data.materials.append(mat)
    return ob

CAB="Cabin"
W=8.4; D=6.2; TOP_Z=3.1527
peak_h=2.35; PEAK_Z=TOP_Z+peak_h
OVR_X = 0.55   # gable overhang along X
OVR_Y = 0.42   # eave overhang along Y

slope = (peak_h)/(W/2 + OVR_X)
ang = math.atan(slope)
half_span = W/2+OVR_X
slant_len = math.hypot(peak_h, half_span) + 0.10

# under-roof deck
deck_l = box("RoofDeckL", slant_len, D+2*OVR_Y, 0.06, (0,0,0), mat=MAT_DARK)
mid_x_l = CX - half_span/2; mid_z = TOP_Z + peak_h/2
deck_l.location=(mid_x_l-0.03, 0, mid_z)
deck_l.rotation_euler=(0,-ang,0); link_to(deck_l,CAB)
deck_r = box("RoofDeckR", slant_len, D+2*OVR_Y, 0.06, (0,0,0), mat=MAT_DARK)
deck_r.location=(CX+half_span/2+0.03, 0, mid_z)
deck_r.rotation_euler=(0, ang,0); link_to(deck_r,CAB)

# shingle courses
n_courses = 13
for i in range(n_courses):
    t0 = i/n_courses; t1=(i+1)/n_courses
    # param along slant from eave to ridge
    s_mid = slant_len*(t0+t1)/2
    # position: start at eave edge point
    ex = -half_span  # left eave x rel CX
    ez = TOP_Z - 0.02
    # direction up-slope (unit): (+cos? ) slope dir normalized
    ux = math.cos(ang); uz = math.sin(ang)
    px = ex + ux*s_mid; pz = ez + uz*s_mid
    wdt = slant_len*(t1-t0)+0.035
    sh_l = box(f"ShingleL{i}", wdt, D+2*OVR_Y, 0.055, (CX+px-0.02, 0, pz), rot=(0,-ang,0), mat=MAT_ROOF)
    link_to(sh_l,CAB)
    sh_r = box(f"ShingleR{i}", wdt, D+2*OVR_Y, 0.055, (CX-px+0.02, 0, pz), rot=(0, ang,0), mat=MAT_ROOF)
    link_to(sh_r,CAB)

# ridge cap
ridge_len = D+2*OVR_Y+0.1
ridge = box("RidgeCap", 0.34, ridge_len, 0.11, (CX, 0, PEAK_Z+0.075), mat=MAT_ROOF)
ridge.rotation_euler=(0,0,math.pi/4)
# scale so diagonal covers: keep as diamond prism look via two angled boxes instead
bpy.ops.object.delete()
r1 = box("RidgeA", 0.20, ridge_len, 0.09, (CX-0.085,0,PEAK_Z+0.10), rot=(0,-ang*0.15,0), mat=MAT_ROOF)
link_to(r1,CAB)
r2 = box("RidgeB", 0.20, ridge_len, 0.09, (CX+0.085,0,PEAK_Z+0.10), rot=(0, ang*0.15,0), mat=MAT_ROOF)
link_to(r2,CAB)

# fascia boards at eaves
fasc_y = D/2+OVR_Y
for sy in (-1,1):
    f1 = box(f"FasciaL{sy}", slant_len, 0.10, 0.16, (mid_x_l-0.03, sy*fasc_y, mid_z), rot=(0,-ang,0), mat=MAT_TRIM)
    link_to(f1,CAB)
    f2 = box(f"FasciaR{sy}", slant_len, 0.10, 0.16, (CX+half_span/2+0.03, sy*fasc_y, mid_z), rot=(0,ang,0), mat=MAT_TRIM)
    link_to(f2,CAB)

# ---------------- front porch (-Y side) ----------------
PZ = 0.30          # porch deck top height
POR_W = W+0.9
POR_D = 1.75
porch = box("PorchDeck", POR_W, POR_D, 0.14, (CX, -D/2-POR_D/2+0.12, PZ-0.07), mat=MAT_PLANK)
link_to(porch,CAB)

# porch foundation piers
import random
random.seed(5)
nx = 4
for ix in range(nx):
    px_ = CX - POR_W/2 + 0.45 + ix*(POR_W-0.9)/(nx-1)
    pier = box(f"PorchPier{ix}", 0.26,0.26,PZ-0.14, (px_, -D/2-POR_D/2+0.28, (PZ-0.14)/2), mat=MAT_STONE)
    link_to(pier,CAB)

# porch posts
POST_H = 2.25
post_xs = [CX-POR_W/2+0.18, CX+POR_W/2-0.18]
for ix,px_ in enumerate(post_xs):
    post = box(f"PorchPost{ix}", 0.19,0.19,POST_H,(px_, -D/2-POR_D+0.22, PZ+POST_H/2), mat=MAT_LOG)
    link_to(post,CAB)

# porch roof beams
beam_f = box("PorchBeamF", POR_W, 0.17, 0.24, (CX, -D/2-POR_D+0.22, PZ+POST_H+0.12), mat=MAT_PLANK)
link_to(beam_f,CAB)
beam_b = box("PorchBeamB", POR_W, 0.15, 0.20, (CX, -D/2+0.05, PZ+POST_H+0.12), mat=MAT_PLANK)
link_to(beam_b,CAB)

# porch rafters sloping down away from cabin
pr_ang = math.radians(14)
pr_span = POR_D-0.05
pr_len = pr_span/math.cos(pr_ang)+0.25
n_r = 7
for i in range(n_r):
    rx = CX-POR_W/2+0.3+i*(POR_W-0.6)/(n_r-1)
    rafter = box(f"PorchRafter{i}", 0.10, pr_len, 0.14,
                 (rx, -D/2-POR_D/2+0.05, PZ+POST_H+0.16+math.tan(pr_ang)*(POR_D/2-0.05)-0.06),
                 rot=(pr_ang,0,0), mat=MAT_PLANK)
    link_to(rafter,CAB)
# porch roof planks
proof = box("PorchRoof", POR_W+0.25, pr_len+0.1, 0.05,
            (CX, -D/2-POR_D/2+0.05, PZ+POST_H+0.30+math.tan(pr_ang)*(POR_D/2-0.05)),
            rot=(pr_ang,0,0), mat=MAT_ROOF)
link_to(proof,CAB)

# porch steps toward path
st = box("StepTop", 1.5, 0.38, 0.14, (doorx:=CX-2.35, -D/2-POR_D+0.55, PZ-0.21+0.0), mat=MAT_PLANK)
link_to(st,"Cabin")
st2 = box("StepBot", 1.6, 0.38, 0.14, (CX-2.35, -D/2-POR_D+0.95, PZ-0.35), mat=MAT_PLANK)
link_to(st2,"Cabin")

result={"ok":True,"objects":len(bpy.data.objects)}