Skip to content

feat(disney_ear_hanger): two-piece dovetail Multiconnect mount + slim 6mm plate (pst-j3ej) - #71

Merged
SeanOC merged 3 commits into
mainfrom
gc-pilot/pst-j3ej
Aug 22, 2026
Merged

feat(disney_ear_hanger): two-piece dovetail Multiconnect mount + slim 6mm plate (pst-j3ej)#71
SeanOC merged 3 commits into
mainfrom
gc-pilot/pst-j3ej

Conversation

@SeanOC

@SeanOC SeanOC commented Aug 21, 2026

Copy link
Copy Markdown
Owner

What & why (pst-j3ej, operator-picked A1+B1)

Redesigns the Multiconnect ear-hanger mount, which the operator flagged as (1) far
too thick for a trivially light headband and (2) unprintable without heavy supports
(the one-piece welded the slot plate perpendicular to the saddle).

A1 — slim plate

The Multiconnect slot slab drops from 6.5mm slab + 4mm plate cap (~10mm) to a
slim 6.0mm slab (4.15mm engaging recess + 1.85mm back wall) via patch-0002's
backThickness param, which keeps the engaging profile identical.

B1 — two-piece dovetail

mount_type splits multiconnect into two fanned, separately-printed STLs:

variant is
multiconnect_plate slim slot plate + male dovetail rail
multiconnect_saddle saddle + solid wall-end backing + female socket

earHanger() is untouched, so tab stays byte-identical and opengrid is unchanged.
Joint: the rail slides across the wall so gravity + the cantilever lever-out
bear on the dovetail shoulders, not the slide axis (operator's load rule).
Friction fit (dovetail_clearance ~0.25mm, @PARAM) + an optional glue dot.

Plate orientation — bug fixed, then stood up (the last three commits)

The first cut of the plate had the slot slab's rotation inverted, so the exported
part met a Multiconnect board with a solid face — the slot openings pointed at the
rail instead of the board, and the plate could not engage at all. Codex-review caught
it; no machine invariant did.

  • e4cd6eb (codex-gate fix) flipped the slab so the slots face the board — but in a
    flat print that lands the retention undercuts as ~107 mm² of severe
    (<25°-from-horizontal) downward overhang: functional but needs support, which
    breaks the bead's "zero-support both" rule.
  • 7d7207d (this branch head) resolves it per the operator's decision this session:
    print the plate STANDING — a wall in the X-Z plane on its z=0 edge, slot openings
    horizontal — the standard zero-support Multiconnect orientation the sibling
    backers (apple_tv) already use. The rail protrudes horizontally off the solid back and
    adds no overhang; its trapezoid is unchanged (24 × 4 × 8→12) so it still mates the
    socket. (A flat print can't both face the slots at the board and stay support-free —
    openings and rail are opposite faces of the same axis.)

New machine guard so this can't regress: mc_plate-slot-direction — AIR just inside
the -Y board face at the central slot, SOLID behind it (verified: fires on a Y-mirrored
mesh). _check_mc_plate was rewritten for the standing frame.

Verification

  • All 4 variants watertight / 1 solid / seat min-Z=0 (CGAL export pipeline).
  • tab default STL geometry unchanged; opengrid + multiconnect_saddle untouched.
  • Standing plate: slots open on the -Y board face across the range; rail flares
    8→12 over 4mm depth × 24mm long, mates the socket; CGAL watertight/1-solid/seats
    z=0 at width/height 1..6, on_ramp, retention, clearance extremes
    .
  • wasm param-sweep 31/31; 218/218 unit tests; invariants ok.
  • Plate renders regenerated (standing). Stale hand-made assembled render dropped
    (render-all doesn't maintain it) — the per-part isos + the header assembly note cover
    the two-piece.

🤖 Generated with Claude Code

… 6mm plate (pst-j3ej)

Operator-picked redesign (A1+B1) of the Multiconnect ear-hanger mount, which
was far too thick for a trivial load and could not print without heavy
supports (plate perpendicular to saddle).

A1 slim plate: the Multiconnect slot slab drops from 6.5mm (+4mm plate cap,
~10mm) to a slim 6.0mm — 4.15mm engaging recess + 1.85mm back wall — via
patch-0002's backThickness param, which keeps the engaging profile identical.

B1 two-piece dovetail: mount_type splits multiconnect into two fanned,
separately-printed STLs joined by a dovetail:
  * multiconnect_plate  — the slim slot plate + a male dovetail rail.
  * multiconnect_saddle — the saddle with a solid wall-end backing and a
    matching female socket (earHanger() untouched, so tab/opengrid stay
    byte-identical; the arch is hollow through the wall cap, so a backing
    refills the channel to host the socket).
The rail slides across the wall (horizontal slide) so gravity + the
cantilever lever-out both bear on the dovetail shoulders, not the slide
(operator's load rule). Friction fit (dovetail_clearance ~0.25mm @PARAM) +
optional glue dot. Joint dims are fixed so a tab/opengrid back could adopt
the same rail later (bead: don't preclude it).

Print (judgment call — flagged): a saddle-facing rail cannot coexist with
slot-openings-UP in a flat print (the rail would point below the bed), so the
plate prints FLAT slot-DOWN / rail-UP (the existing supportless sibling-backer
orientation), not the bead's literal "slot-up". Both parts print flat and
support-free.

Verified: all 4 variants watertight/1-solid/seated via the CGAL export
pipeline; tab default STL geometry unchanged; rail<->socket dims mate with
clearance; socket stays embedded in solid backing across hangerLength 15..60
and width/height 1..6; invariants sidecar rewritten (opengrid + mc_plate +
mc_saddle checks); wasm param-sweep 31/31; 218/218 unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MhF6eqWoyMf6xSg25ZH2v2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stuff Ready Ready Preview Aug 21, 2026 9:52pm

Request Review

@SeanOC

SeanOC commented Aug 21, 2026

Copy link
Copy Markdown
Owner Author

Codex gate review — changes requested

One blocking defect; everything else verified solid.

BLOCKING — the Multiconnect plate is printed slot-side up; it cannot engage a board.
models/disney_ear_hanger.scad:490 applies rotate([-90,0,0]) to multiconnectBack(). In the vendored lib frame the slot tools are recessed from the y=-t face (openings there; blind back wall at y=0) — see scripts/patches/QuackWorks/0002 and the sibling convention models/apple_tv_4th_gen_holder.scad:352-370 (rotate(180,[0,1,1]), openings on the panel face). rotate([-90,0,0]) maps y=-t -> build z=+6, so the openings land on the TOP (rail side) and the blind face on the bed. Measured on exports/disney_ear_hanger-multiconnect_plate.stl: the z=0 cross-section is the full solid footprint (no slot voids), the channels occupy z[1.85,5.35] opening upward, and only a 1.85mm wall sits between the slots and the board face. Mounted flat on a Multiconnect board the plate presents a solid face to the rails — the part fails its sole function. The header comments (scad:69-77, 471-477) assert the opposite orientation.

Smallest honest fix (verified on a patched copy): at models/disney_ear_hanger.scad:490 replace rotate([-90, 0, 0]) with translate([0, H, mc_thickness]) rotate([90, 0, 0]) — watertight, 1 solid, seats z=0, footprint/height unchanged, slot void z[0,4.15] opening at the board side, 1.85mm blind wall now under the rail (flanks still self-supporting). Correct the inverted comments, add a sidecar probe pinning slot direction (AIR at [W/2, H/2, 1.0], SOLID at [W/2, H/2, 5.0]), regenerate renders/exports.

Why CI missed it: _check_mc_plate (models/disney_ear_hanger.invariants.py:263) probes footprint/height/rail and a corner column outside the slot ladder — it passes for either orientation.

Non-blocking notes:

  • renders/disney_ear_hanger/assembled_multiconnect.png is not produced by scripts/render-all.py (views are top/front/side/iso) and will silently go stale; teach render-all an assembled view or drop it.
  • No cross-part mating assertion; I verified fit manually (boolean intersection 0 mm³, rail fully engaged with 0.3mm face-seat gap) — a sidecar probe would pin it.

Verified good: dovetail joint mates with zero interference; tab/opengrid byte-identical/unchanged; all exports watertight + seated; invariants and CI green; pins and license split untouched.

…rd (pst-cu7n)

The multiconnect_plate printed slot-side UP: rotate([-90,0,0]) mapped the
vendored slot openings (recessed from the y=-t face) to build z=+t (the rail
side), leaving a solid 1.85mm blind wall on the board-side face. Mounted flat
on a Multiconnect board the plate presented a solid face to the rails and
could not engage — the part failed its sole function. The header already
described the intended slot-DOWN orientation; only the transform (and its
inline comment) were inverted.

Fix: translate([0,H,mc_thickness]) rotate([90,0,0]) lands the openings at
build z=0 (board side, on the bed) with the blind wall tucked under the rail.
Verified: watertight, 1 solid, seats z=0, footprint/height unchanged; slot
void z[0,4.15] opening at the board side; CGAL clean at width/height extremes.

- Correct the inverted transform comment.
- Add a slot-direction invariant probe (AIR at [W/2,H/2,1.0], SOLID at
  [W/2,H/2,5.0]) — fails the old orientation, passes the new. The prior
  _check_mc_plate probes missed it (footprint/height/rail only).
- Regenerate the multiconnect_plate renders; drop the orphan
  assembled_multiconnect.png (render-all does not produce it).

Gates: npm test 218/218, disney sweep 31/31 (wasm), invariants ok, CGAL
export watertight.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFxBnoNNfgTpDG8yrgnvi2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…at flip (pst-j3ej)

Supersedes the codex-gate flat fix in e4cd6eb (pst-cu7n): that flip made the
plate functional but printed the slot RETENTION UNDERCUTS as ~107mm2 of
severe (<25deg-from-horizontal) downward overhang — it needs support, which
violates the bead's "zero-support both" hard rule. The operator (Sean, this
session) chose the standing print instead: a flat orientation cannot both
present the slots to the board AND stay support-free, because the slot
openings and the dovetail rail are opposite faces of the same axis.

The plate now prints in multiconnectBack's native frame — a wall in the X-Z
plane standing on its z=0 edge, slot openings horizontal — the standard
zero-support Multiconnect orientation the sibling backers (apple_tv) already
use. The rail protrudes +Y off the solid back and adds no overhang. Its
trapezoid is unchanged (24 x 4 x 8->12) so it still mates the saddle socket.

Keeps e4cd6eb's correctness intent (slots face the board) and its
slot-direction invariant, re-expressed for the standing frame:
- mc_slab_standing / plate_rail_standing (native frame, rail out +Y).
- Header + module comments rewritten for the standing print.
- _check_mc_plate rewritten for the standing frame (footprint W x H in X-Z);
  mc_plate-slot-direction probe: AIR just inside the -Y board face at the
  central slot, SOLID behind it (verified: fires on a Y-mirrored mesh).

Gates: invariants ok; unit 218/218; wasm sweep 31/31; CGAL watertight /
1 solid / seats z=0 across width/height 1..6, on_ramp, retention, clearance.
tab byte-identical; opengrid/saddle untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CAY86pxqsdqK2Lc6trRVH

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@SeanOC

SeanOC commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Codex gate review — pass

codex-review status set to success on e4cd6eb.

What I verified independently (fresh worktree, pinned engine 2025.06.12.ai25773, vendored libs re-cloned at their pins):

  • All 4 filename-grid STLs (tab, opengrid, multiconnect_plate, multiconnect_saddle) export watertight, 1 solid, min-Z=0; scripts/check-invariants.py disney_ear_hanger → ok with the rewritten sidecar.
  • Tab byte-identical: re-exported from main and from this head with the same engine — identical vertices/bounds/volume (9551.24 mm³).
  • Slim-plate claim holds against the vendored source: multiconnectSlotDesign.scad:42 depends on backThickness only through the tool translate, so 6.0mm keeps the ~4.15mm engaging profile identical and adds/removes only the meat behind the blind face.
  • Joint mates: rail measured 8.4→11.8mm flare over 4mm depth (design 8→12), socket 8.2→11.9mm (design 8.25→12.25), flank slopes match; an assembly simulation mapping ~99k rail interior points into the mated saddle frame found zero interference. Socket open both ends, backed solid at the blind end.
  • pst-cu7n flip verified on the mesh: board-side (z=1.0) air, rail-side (z=5.0) solid — slot mouths face the board.
  • No stale references to the old one-piece multiconnect variant anywhere in app/lib/scripts/docs; presets updated. License header + CC BY-NC-SA split intact.

Non-blocking nits (not gate-worthy, suggesting a small follow-up if anyone wants):

  1. models/disney_ear_hanger.invariants.py:57_DT_CLEAR is defined but never used.
  2. models/disney_ear_hanger.invariants.py:117_air_span_z reports max−min over all air points between the probe bounds; at deep socket depths a second air interval outside the part inflates the number (14.8 reported vs ~11.9 true span). Measuring the air interval containing dovetail_z would be more precise; harmless for the current monotonic-flare check.
  3. dovetail_backing() comment says it refills "the arch channel" — it actually refills the arch's full outer silhouette across the wall slab (including the upstream clip regions, verified on the mesh). Intentional and correct for the flat seat; comment just understates it.

Slot-down/rail-up print orientation judgment call is sound (a saddle-facing rail can't coexist with slot-up in a flat print) — flagging for operator awareness only.

@SeanOC

SeanOC commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Codex gate review — pass

codex-review status set to success on 7d7207d (re-review of the standing-plate commit).

Verified independently (scratch worktree, pinned engine, libs re-vendored at their pins):

  • All 4 STLs export watertight / 1 solid / min-Z=0; check-invariants green; CI all green.
  • Standing plate: bounds 28×(6+4)×56, slots open on the −Y board face, solid back behind; rail flare 8.6→11.8mm, length 23.6mm; joint re-mated into the saddle with zero interference (~99k rail points).
  • Tab byte-identical to main; opengrid/saddle geometry unchanged from the prior revision (vertex-set equal; only CGAL triangle-order noise).
  • Zero-support claim tested with the repo's own scan convention (apple_tv header documents it: flag faces >50° from vertical, exclude bed): standing plate = 228 mm², vs 1319 mm² for the shipped apple_tv standing backer under the identical scan — ~6× cleaner. The flat revision it supersedes measured ~1032 mm² of steep retention-dome ceilings + slot-mouth bridges, which this orientation eliminates. Residual is the inherent slot lead-in/on-ramp walls of any standing Multiconnect print.

Non-blocking findings:

  1. models/disney_ear_hanger.scad:474-481 — the old flat-orientation PART A comment block was left in place with the new standing block appended (482-489); the two contradict each other and 474-481 describes a rotation this revision no longer uses. Smallest fix: delete lines 474-481.
  2. Carryovers from the prior review, still present: unused _DT_CLEAR (invariants.py:57), _air_span_z max−min over all air intervals (invariants.py:117), and the dovetail_backing() comment understating its refill scope.

56mm-tall standing wall with a 72mm² bed footprint — brim if tippy is your call, and the header says so honestly.

@SeanOC
SeanOC merged commit 1daf5bc into main Aug 22, 2026
9 checks passed
@SeanOC
SeanOC deleted the gc-pilot/pst-j3ej branch August 22, 2026 01:07
@SeanOC

SeanOC commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Codex gate review — changes requested

codex-review set to failure on 7d7207d. One blocking finding on the dovetail joint; everything else in this revision verifies clean. Note: this replaces my earlier pass on e4cd6eb — my containment-probe measurements under-sampled the joint's exact flank widths; plane-slice cross-sections (below) expose the defect, which has been present since the feature commit and is therefore in-scope for this PR.

BLOCKING — the dovetail joint is an interference fit, not a clearance fit

What: Exact cross-sections of both exported STLs (plane-slice, no probe ambiguity), plate centre x=14, mated at the wall face:

depth from wall face rail z-width socket air gap clearance
0.02 8.551 8.314 −0.237
1.0 9.422 9.205 −0.218
2.0 10.311 10.114 −0.197
3.0 11.200 11.023 −0.177
3.9 12.000 11.841 −0.159

The rail is 0.16–0.24mm WIDER than the socket at every depth — the parts collide on the flanks and cannot slide together (the joint's entire purpose). At print tolerances of 0.1–0.15mm this is a hard bind, not a snug friction fit.

Why: plate_rail_standing() (models/disney_ear_hanger.scad:528-535) hulls the neck cube from y=−0.3 (the bury embed) to the tip band. The hull spreads every cross-section toward the wider tip: at the plate face (y=0) the rail reads ~8.53mm, not dt_neck (8) — the flank slope becomes 0.89mm/mm instead of the socket's 0.80mm/mm ((dt_tip+c−dt_neck−c)/(dt_depth+0.4)). So even though the socket mouth is dt_neck + c = 8.25 > 8, the actual rail base is already past it before the joint starts. The flat revision's plate_rail() had the identical hull-spread (verified: its base-layer z-width is also 8.551), so this has been present since 5c46507 — but it ships nothing a user can assemble, so it blocks.

Smallest honest fix (pick one):

  1. models/disney_ear_hanger.scad:175 — set dovetail_clearance = 0.8;. Then mouth = 8.8 vs rail base 8.533 (+0.27 entry clearance) and clearance ≥0.27 at every depth. One line; the @PARAM already documents "bump it if the parts bind". If you want to keep the 0.25 nominal, compensate for the hull spread instead (see 2).
  2. models/disney_ear_hanger.scad:531-532 — anchor the neck cube's top face at the plate face so the hull cannot spread the base: e.g. translate([0, -bury, 0]) cube([dt_len, bury, dt_neck], anchor=BOTTOM) (or an equivalent non-hull prism for the buried root + a pure trapezoid hull above y=0). Rail base then reads 8.0 and the existing 0.25 clearance works as designed.

Either way, please verify post-fix with a plane-slice measurement (rail z-width at x=W/2 vs socket air gap at y=0 across depths 0..3.9) — a containment-probe check will not catch 0.2mm flank errors, which is how this slipped through the sidecar and two gate reviews. Consider adding that slice-based flank-clearance assertion to _check_mc_plate/_check_mc_saddle (the sidecar currently only asserts the flare is monotonic).

Non-blocking

  1. models/disney_ear_hanger.scad:474-481 — stale flat-orientation PART A comment block left in place, directly contradicted by the standing block at 482-489; delete 474-481.
  2. models/disney_ear_hanger.scad:520-527 — rail comment claims "Same trapezoidal shape ... the saddle socket receives" — false as built (hull spread); update with whichever fix you take.
  3. Carryovers: unused _DT_CLEAR (invariants.py:57); _air_span_z max−min over all air intervals (invariants.py:117); dovetail_backing() comment understates its refill scope.

Verified clean in this revision

  • Standing plate geometry: watertight/1-solid/min-Z=0 across all 4 variants; footprint 28×56, depth 6+4; slots open on the −Y board face; rail 24mm long, 8→12 flare; bed seat 72mm² wall footprint.
  • Zero-support claim holds under the repo's own scan convention: 228mm² flagged vs 1319mm² for the shipped apple_tv standing backer; flat revision's 1032mm² of steep ceilings eliminated.
  • Tab byte-identical to main; opengrid/saddle geometry unchanged from e4cd6eb; CI all green; license split intact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant