← back to pin list

Approach defaults -- scoped lead-in record per feature class + the three-way GROUP save both modals share, BUILT (Jordan 2026-09-20)

kerfmaster pin list · UI / workflow decisions

recordmixedStates 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-20, one brick. THE RECORD: approach defaults (approach = lead-in + pierce, his glossary) per feature class (outer / inner / circle -- the start-defaults classes, one modal grammar), fields lead_length / shape (straight|radiused) / angle (deg off perpendicular) / lead_out; SPARSE PER FIELD -- saving one field to a scope never touches that scope's other fields, every field carries its own provenance ({v, source:{who, date, group?}}). RESOLUTION mirrors start defaults per FIELD: job > material > machine > shop > the Rev2 lead_in table seed; a typed per-feature override always outranks the lot. THE GROUP SAVE (his 'one better'): scope 'materials' + a picked list -- a BULK WRITE of the same sparse update to each picked material's own record, deliberately NOT a new scope tier, so resolution stays predictable and a later single-material save simply overwrites its row; provenance names the group it rode in with; picks validate against the Rev2 sheet so a typo can never invent a material. ONE MACHINERY: server._defaults_save carries start_defaults AND approach_defaults (run_startdefaults refactored onto it -- the start-point modal gains the same 'a group of materials...' option), client matPicker (family filter + thickness min/max + tick/untick shown; a TICKED row never hides under a filter) serves both modals. ENGINE: write_gcode_macrob(lead_defaults={cls: length}) -- consumed exactly like an operator per-feature lead_length (which outranks it), pierce-standoff still judged at the TABLE value (a default never relaxes a gate, aid-the-operator), lead source reads default:approach (full length) / rule:shortened-to-fit (honest shortening), None = byte-identical legacy; wired at every plan/post site (review, dragcheck, quote, single post, both nest posts, plassign batch, _pl_build part-list plans, plpost post_kw). Server doors GET/POST /api/jobs//approachdefaults (state ships the machine's Rev2 rows for the picker); client: Tooling drawer 'approach defaults' row -> admodal (3 classes x 4 fields, resolved value + winning scope as placeholder, x clears a field at the chosen scope), five Apply-to choices incl. the group. HONEST LIMITS (intent): shape / angle / lead_out are RECORDED and shown ('recorded, not cut yet' chips + modal note) -- the engine cuts straight perpendicular leads and no lead-outs today; their emitters are the next slice, and the wizard shop-level question is queued behind it. PROVEN: test_approach.py 17 controls (dark seam byte-identical; per-class lengths + sources; operator outranks; table class honest; too-long default shortens honestly; per-field cross-scope resolution; engine dict excludes the table seed; junk refusals; group provenance) + app/verify_approach.js 18/18 on the scratch instance (drawer -> modal -> sparse job save -> REAL RE-PLAN runs inner 0.2 default:approach while outer+circle keep table:lead_len -> group save 'mild steel .5-.75 in two clicks' lands on all three rows with group provenance -> refusals -> cleanup proven) + live on dev 44558b-10 (fixture restored to its committed state after, stated) + start_anchor/drag/tooling_doc/pl_sync/pierce_sub + verify_warnnav 10/10, verify_draghandle 13/13 green. Zero dev O-numbers. Cross: start-default-modal (the machinery reused), metacam-add-toolpath-walkthrough (the reference screenshots), aid-the-operator-philosophy.