Repository navigation
body-lowering: DESIGN + staged plan — faithful runtime-iteration inference - #6190
Conversation
…thfully represent runtime iteration
Design-first milestone deliverable (no load-bearing edits). Fixes the gap
from receipts: a Loop node carries its cycle as an acyclic encoding (measure
^loop_bound_edge + iteration-fold body, §4), but the inferred tree drops both
loop facts:
1. behavior_multiplicity(Loop) decides termination TAG-ONLY — the Node, and
thus the measure, is not in scope — so every raw loop is Violates
regardless of its descent evidence (cardinality.dag:219-228).
2. LoopBound{measure,termination}, the carrier that would bind measure→proof,
is a DEAD SCAFFOLD (loop_bound_witness_for_node has zero callers) and even
it computes termination without reading the measure.
3. 04_infer has NO Loop arm — the body is typed as an opaque conjunction with
no per-iteration τ→τ relation (Branch/Match get real arm-typing; Loop
doesn't).
Thesis: derive termination FROM the measure (fail-closed to DescentUnknown) +
type the body as a repeated transform — both as Loop sugar readers, so
For/While/Retry/recursion type at once. Blocked-on: a DescentEvidence §3 fork
(cardinality.dag:108 bare vs dag/std/termination.dag lattice) consolidates
first. Staged plan (5 separately-signed PRs) + 3 open flags for operator sign.
Registers the milestone as a DESIGN.md open thread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…igned) FLAG A: DescentEvidence authority ruled dag/std/termination.dag (§7); Stage 1 designed against it now, consolidation LANDING held for operator standing v2<->dag-fork confirm. FLAG B signed — Loop-multiplicity node-awareness is principled (termination depends on the measure, a node-level fact the tag can't carry); rationale to live in-code. FLAG C signed with §5 requirement — refinement-typed loops fail-closed (refused, not silently fabricated as tau->tau); Stage-3 witness must include a refinement loop that goes red. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
loop_bound_witness_for_node is NOT zero-callers — it is consumed by the cost/complexity lenses (src/v2/lens/cost.dag:168 base_cost_for_loop and subject_complexity_budget_roster.dag:45), which read only its `measure` field for sizing. Correct gap 2 to its real, sound point: (a) no INFERENCE consumer of the carrier, and (b) its `termination` field is computed measure-blind (tag-only, cardinality.dag:284) — a hollow second representation of a proof the measure already determines. Retarget Stage 2 to "first measure-aware termination consumer" (not "first caller"), so wiring instructions don't misroute implementers. Drops the incorrect "dead scaffold" framing in the doc and the DESIGN.md bullet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed in 23fcdb0 — the caller receipt was wrong and I've corrected it. Verified against the live tree: `loop_bound_witness_for_node` is indeed called from `src/v2/lens/cost.dag:168` (`base_cost_for_loop`) and `src/v2/test/claim/complexity_gate/subject_complexity_budget_roster.dag:45` — not zero-callers. My exploration only grepped `std`/`compiler` and missed `lens/` and `test/`; thanks for catching it against DESIGN.md's verify-receipts bar. I've rewritten gap 2 (and the DESIGN.md bullet + Stage 2) to its real, sound point, which you flagged as intact: those existing consumers read only the carrier's `measure` field (for cost sizing, `linear_in_node(measure)`), never its `termination` field — and that `termination` is itself computed measure-blind via the tag-only `termination_proof_witness_for_node` (`cardinality.dag:284`). So the two-fold gap is (a) no inference consumer of the carrier and (b) its `termination` field is a hollow second representation of a proof the measure already determines. Stage 2 now targets the "first measure-aware termination consumer," not "first caller," so wiring instructions don't misroute implementers. Dropped the "dead scaffold" framing entirely. — sent from fierce-bee-749 |
…ority #6190 hand-edited DESIGN.md only; WIP main_wet regen dropped the bullet. Add the row to open_threads_blocks so generated_artifact drift stays green. Co-authored-by: Cursor <cursoragent@cursor.com>
…table (#6176) * 2-emit-partition: grammar JSON for healthz body; structured shell in v1_dag_parse transport Migrate roadmap_site_healthz_body() from hand-concat JSON to extdeps.languages.json.emit grammar rows; replace RawLine string-shell in v1_dag_parse_transport with structured command(var_ref). Witness updated for canonical serializer spacing. Co-authored-by: Cursor <cursoragent@cursor.com> * 2-emit-partition: witness quoted var_ref in v1_dag_parse transport VarRef already serializes as "$NAME" via serialize_bash (same bytes as the retired RawLine). Add floor witness proving the v1_dag_parse program emits a double-quoted command-position variable and REDs on unquoted word-split form. Co-authored-by: Cursor <cursoragent@cursor.com> * #6174: wall JsonNumberLexeme construction behind json_number_lexeme_valid Add json_number_lexeme(s) -> JsonNumberLexeme? as the only public mint path for arbitrary spellings; unchecked cast is internal to grammar.dag. Export json_number_from_lexeme_string for emit callers. Floor witnesses: GREEN on valid lexemes, RED refusing invalid at construction (not-a-number, 12abc, empty, 01). Co-authored-by: Cursor <cursoragent@cursor.com> * #6174: drop fabricated "0" fallback in json_int_lexeme Int→to_string is witness-proven valid JSON number syntax; use the grounded Int constructor path directly instead of Absent=>"0" fabrication. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(ci): repair rust_tests after main merge — NFR roster drift + witness-a line Main landed new closed-coproduct wildcard sites (srv3 install diagnostic, nbd_proxy_serve, decl_index) without roster enrollment; refresh NON_FOLD_RESIDUE_ROSTER so partition witnesses pass. Rebase witness (a) body-touch fixture line 78→83 after floor_disc_helper_fn shifted the fixture in #6061. Co-authored-by: Cursor <cursoragent@cursor.com> * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * ci: raise job timeout 50→90min — batch-1 still running at 48min on 50min cap Run 28645912887 canceled batch-1 compile-clean at 47m51s into the gate (50m19s job total incl. release build). 50min sat inside the measured ~50min+ floor wall; bump to 90min interim headroom until compile-clean serial wall is killed (ROADMAP §3 2-compile-clean-serial). Co-authored-by: Cursor <cursoragent@cursor.com> * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * fix(ci): rustfmt frontier test assert; unblock rust_tests on 7948ff cargo fmt --check failed on multi-line assert in import_preamble_plus_fn_body_populates_touched_entry_not_fail_closed. Co-authored-by: Cursor <cursoragent@cursor.com> * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * fix(ci): frontier diff attributes deletions + import-preamble test Track `-` hunk rows in parse_unified_diff_changed_new_lines so deletion-only edits populate edited_test_fns/touched_entry_files (§5 fail-closed). Fall back to new-side hunk ranges only when no +/- rows were attributed. Import-preamble regression uses a git-diff fixture with space-prefixed context lines. Co-authored-by: Cursor <cursoragent@cursor.com> * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * fix(ci): skip non-.dag paths in frontier diff — avoid full-corpus OOM Mixed PR diffs (emit.dag + cli_run.rs + testdata fixtures) previously fail-closed on the first non-.dag path and forced a full witness corpus (OOM on batch-2). Skip non-.dag paths for frontier attribution; remain fail-closed only when the diff is exclusively non-.dag. Co-authored-by: Cursor <cursoragent@cursor.com> * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * fix(design): restore body-lowering open thread removed by WIP commit Revert accidental DESIGN.md deletion from bfe40ad — unrelated to JsonNumberLexeme construct-safety; the open thread remains tracked at docs/plans/body-lowering-design.md. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(design): enroll body-lowering open thread in design_document authority #6190 hand-edited DESIGN.md only; WIP main_wet regen dropped the bullet. Add the row to open_threads_blocks so generated_artifact drift stays green. Co-authored-by: Cursor <cursoragent@cursor.com> * WIP: shell/json/yaml emit-partition migration (ROADMAP §2 'emit partition cle * fix(ci): unblock batch-2 floor witnesses (extdeps/srv3/tailscale) - tailscale: authority witness via literal URI wire (json.emit anchor shadowing) - srv3: iso=match grounds on intent hash; ServeReady+websocket→AttachedToExpectedServe - extdeps anchors for yaml/tools/os modules (already on branch) Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Cursor <cursoragent@cursor.com>
Deliverable for the BODY-LOWERING MILESTONE (design-first, model-before-implement)
This PR is the design + staged plan — no load-bearing pipeline/substrate edits. Each implementation stage is a separate, separately-signed PR (see §5 of the doc).
The gap (from receipts)
DESIGN.md §4: "recursion is sugar over
Loop; cyclic relations via acyclic encodings." ALoopnode carries its cycle as an acyclic encoding — one^loop_bound_edgemeasure + iteration-fold body (node.dag:210,279-284). The substrate models this faithfully; the inferred tree does not interpret it:behavior_multiplicity(Loop)(cardinality.dag:219-228) takes only theBehaviortag — the measure is structurally out of scope — so every raw loop isViolatesregardless of its descent evidence.LoopBound{measure, termination}/loop_bound_witness_for_node(cardinality.dag:278) has zero callers, and even it computesterminationwithout reading the measure it just extracted.04_infer. Branch/Match get per-arm body-typing + unification; Loop falls to the generic path and is typed as an opaque conjunction — no per-iterationτ→τrelation.Thesis
Derive the loop's type from its measure and its body, not its tag: (T1) termination = a lattice-meet over the measure's
DescentEvidence, fail-closed toDescentUnknown → Violates; (T2) type the body as a repeated transform with a fixpoint relation. Both areLoopsugar readers, soFor/While/Retry/recursion type at once (no N×M).Adjacent finding (blocks Stage 1)
DescentEvidenceis forked (§3): barecardinality.dag:108-111vs the richerdag/std/termination.daglattice (meet/join/promote_to_strict). The fix needs the lattice (multi-measure loops terminate by meet), so consolidation onto one authority must land first.Staged plan
DescentEvidence(FLAG A). 2. Node-aware Loop multiplicity + wire the dead carrier (T1). 3. Loop arm in04_infer(T2). 4. (optional) body-producer fixture realism.Every stage carries a discriminating red control (perturb the measure/body → verdict flips) per DESIGN.md §5.
Open flags for operator sign
DescentEvidenceauthority (v2src/v2/stdvsdag/std)?node_multiplicity) while other behaviors stay tag-only — accept the asymmetry?τ→τ); refinement-typed loops are a named follow-on.Full design:
docs/plans/body-lowering-design.md. Registered as a DESIGN.md open thread.