← back to pin list

Part-list programs post as MAIN + SUB-PROGRAM CALLOUTS (G52 + M98P, one sub per distinct part x orientation) -- and MACRO RUNS where the layout earns them (P9997 arrays, style auto/partbypart)

kerfmaster pin list · The interface — recorded intent (build later)

recordStates what the code does today. Auditable against the code — this is the only type that can go stale.

Content last changed 2026-09-20 — computed from the item itself, not typed.

Built 2026-09-17 (Jordan 'GO' on his O33342 catch -- 'I expected to see a main program with nest macros (P9997) and sub-program callouts; it looks like you just nested it as one big part'). Not P9997 (a part-list is part-by-part by construction -- several unique shapes, nothing to array), but his 2026-09-06 ruling's form: each sheet posts a MAIN (merged header, one G52X..Y.. + M98P<sub> per placement in the emission order, G52X0Y0 clear before M30) with ONE SUB per DISTINCT part x orientation riding in the same file -- the program stays short and one edit in a sub reaches every copy.

Zero drift on every cut: each sub's body posts through emit.write_gcode_macrob itself on the part's rotated geometry (the cl_post per-band precedent -- leads, scrap-side comp, Rev2 registers, slug tabs, micro-merge, chording, traverse routing = the machinery every program runs), so a sub IS the lone-part plan the pack reserved envelopes from (per orientation -- the plans_rot decisions): what the sheet reserved is what posts BY CONSTRUCTION. The merged header unions the per-part used-only records (emit stats.header_use, record only) through emit's own _cond_lines/_dreg_lines -- the one-register-one-value law holds ACROSS parts (two parts forcing one D register to two values refuses whole, in emit's own words).

Sub numbers join the shop sequence (next_subnums, keys = part x orientation, shared across sheets -- same body, same number on the control) and KEEP across re-posts AND re-packs (job.pl_sub_onums). The audit is unchanged in authority: nc_audit.expand_g52 expands the calls and judges the part-by-part form the machine executes against the PLACED geometry, callouts mapping back to (sub, local FEATURE). The clicked nest order and per-part Manual Sort ride as before -- the main's call order / each sub's own order. Per-sub tooling documents in plpost*_tooling.json; the slug report merges every placement's slugs at sheet coordinates. UI: the Post tab names the form and lists each sub (O-number, part, rotation, features x copies, warnings).

Proven: test_pl_subcall.py 18 NEW controls (main structure, used-only union both directions, register-conflict refusal, expand_g52 audit clean with a 180 sub, numbers kept across re-post and re-pack; control 9 caught the fixture's own overlapping placement -- the audit red proving itself) + 18 neighbour suites green. Delivered pre-2026-09-17 programs stand and still audit (the legacy expanded form). Honest limits: no typed sub-number override door on this surface yet (the postnest door's part-list twin is its own build); live Playwright verify of the Post-tab sub rows rides the next session.

MACRO RUNS BUILT 2026-09-19 (Jordan 'Go' -- born from his 'I used to be able to select the gcode nesting style... where did it go?' on his 12-pc BRONX kit, 6 parts x qty 2; the answer: the selector lives on true-nest jobs, a part-list posts part-by-part by construction -- and his kit was the arrayable case the 2026-09-18 offer named). ENGINE pl_post.detect_macro_runs(placements): runs are MEASURED off the placed layout itself, never the pack strategy -- per key (part x orientation) placements sharing an X split into maximal uniform-Y-pitch columns, congruent columns at uniform X advance merge into KxQ arrays; a hand-nudged copy honestly falls out of its run into its own K1Q1; alternate-180 layouts read as two arrays by construction (the two-P9997 ruling). write_sheet_subcall(macro=arrays) posts the TRUE-NEST MACRO FORM: one G172X..Y.. + G65P9997I..J..K..Q..H1B1A<sub> per array (the exact O33286/emit syntax nc_audit.expand_p9997 already executes), no G52 anywhere -- and NEVER A MIXED MAIN (the two-shapes ruling): in macro form every placement rides an array, a lone one as K1Q1 (the main-program-style pin's own words). The subs are BYTE-IDENTICAL across the two forms -- the form changes, never a cut; placements, audit frame, slug numbering and the recorded part order all reorder to the control's own serpentine traversal, so what is recorded is what runs.

THE DOOR: POST /api/jobs/<id>/plpost takes style auto|partbypart, persisted on the job (pl_style) like the O-numbers; auto posts macro ONLY where a real run (2+ instances) exists -- otherwise the sub-call form stands with the honest reason recorded (style_reason); a clicked part sequence keeps the sub-call form (macro arrays run the control's serpentine, so a custom sequence posts part-by-part -- the two-shapes rule); an unknown style refuses. The program record carries style/style_pick/style_reason and the arrays run by run (part, rot, sub, origin, pitches, KxQ). CLIENT: the Post tab gets the main-program-style select (Auto -- macro runs where the layout earns them / Part-by-Part -- sub calls only; sticky pick, the 2026-09-06 nestStylePick lesson), the drawer names the form and every array in plain words, and the section note states both forms and the never-mixed rule.

Proven: NEW test_pl_macro.py 19 controls (detection incl. the 12-pc kit shape, nudged-copy fallout, K2Q2 serpentine merge, alternate-180, singles; writer form + expand_p9997 execution + audit on placed geometry, byte-identical subs, coverage refusal; e2e style flip/persist/sequence-fallback/refusal). test_pl_subcall 18 + test_pl_seq 27 updated to take the explicit Part-by-Part pick (their subject IS the sub-call form; auto now honestly posts their uniform kits as macros). Neighbours green: pl_post 26, pl_sync 23, pl_deliver 28, pl_select 21, pl_tool 18, pierce_sub; live verify_pltabs 19/19 (style select + new note wording), verify_plpost 14/14 (fixture takes the pick), plrefresh 16/16, refusal 16/16, plsel 17/17, plseq 15/15.

SPARE PITCH WORDS 2026-09-20: pl_post.fill_spare_pitch(arrays, envs, bridges) fills every count-1 axis after detection -- the value is the part's toolpath-envelope span (geometry + pierce/lead extents, the pack's own reservation) PLUS the part's resolved bridge (operator override or table seed -- Jordan's refinement: a nonstandard clearance shows in the macro words), the same arithmetic a real uniform run packs at; where the same part x orientation already runs as a REAL array on the sheet, that array's measured pitch is lent first so the made-up part lands on the existing pattern. Inert at count 1 by the control's own semantics (a pitch is read only past the first instance) -- no cut moves, words only; measured run pitches are never touched; a key with no envelope/bridge record (old packs) keeps its zeros honestly. The true-nest surface has filled its lone axes with size + gap since seq-display-is-the-program (_seq_arrays ph+gap/pw+gap); this is the part-list twin. run_plpost builds the envelopes from the pack's own plans/plans_rot rotated to the sub frame and bridges from the placements (_pl_fill_bridges heals old hand layouts); arrays and drawer rows carry spare=[axes] and the Post tab names the spare pitch 'posted for make-up parts (inert until K/Q is raised)'. Proven: test_pl_macro 19 -> 25 (lone fills both axes, real run keeps measured pitch, same-key lending, honest zeros, e2e door fill + no I0/J0 words on posted G65 calls) + subcall 18, pl_post 26, pl_seq 27, pl_sync 23, pl_deliver 28; live on dev: CAMP kit re-post O33385 kept, 38/38 G65 calls carry real pitches, K1 siblings lend from their K3 runs, audit red 0; verify_plpost 14/14 (its live fixtures consumed dev O33395-33396 + subs 75426-75428, stated; the CAMP re-post itself kept O33385, no new number).