Skip to content

Complexity foundation: loop typing + measure-derived termination + claim-bin cwd fix - #6373

Merged
briansrls merged 17 commits into
mainfrom
claude/complexity-work-status-97zmt9
Jul 10, 2026
Merged

briansrls merged 17 commits into
mainfrom
claude/complexity-work-status-97zmt9

Conversation

@briansrls

@briansrls briansrls commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

What this is

Reworked down to the fork-free foundation. An earlier version of this branch added a derived-complexity-floor feature (~10k lines), but auditing it against DESIGN.md surfaced a §3/§4 fork: the "cost-shape lowering" (dag_surface_lower_*) was a second, hand-rolled body producer running beside the compiler's own — it re-lowered the surface parse tree by hand (one if-arm per production), skipping resolve/normalize/body_producer, and produced a shape that matched neither the real inferred tree nor its own synthetic test subjects. It caught zero real quadratics on the corpus and generated a cascade of point-fixes (per-form lowering lanes, a lexeme-recovery module, a GeneratedArtifact name collision, missing Branch-descent). All of that has been backed out.

What's left is only the genuinely fork-free, behavior-real changes.

Behavioral changes kept

  1. 04_infer Loop arm — an iteration-fold body is typed as a per-iteration transform (τ → τ under the measure); divergent and refinement-shaped bodies refuse with the located infer_loop_iteration_type_mismatch.
  2. Measure-derived loop termination — loop_multiplicity over the cited measure_descent_fact_registry (lattice meet + lexicographic strict-dimension proof), grounded on the dag/std/termination.dag single authority (a §3 de-fork).
  3. claim_batch / claim_executor cwd fix (Rust) — relative path args resolve against the process cwd and refuse (exit 2, located) on missing paths, closing the baked-root mixed-tree fail-open.

9 files, ~+1k. Verified by execution against merged base: 8 loop-multiplicity + 5 loop-infer witnesses PASS; roster-shape, generated-artifact drift, and enforcement-consistency + repo-wide-complexity meta-gates PASS. The two new loop tests are CI-enrolled so the kept behavior gates.

Deferred to real compiler work (not landed as a fork)

The derived-complexity-floor feature's real home is a general body-producer stage — §4's "one grammar read in both directions": a row-driven ingest fold (the inverse of the already-row-driven emitter in 06_translate), which also subsumes the pre-existing MVP1 03_body_producer. That, plus affordable whole-tree corpus resolution, is what would let a complexity lens catch real quadratics. It's ordinary-but-substantial compiler work, tracked separately. Also noted for separate cleanup: the two same-named GeneratedArtifact types (a §3 fork).

🤖 Generated with Claude Code

https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc

4. Binding-side StampLexeme completion (a0f8385 — closes the rust_tests red)

The foundation above lexeme-stamped identifier references (primary_expr_core → ^x) but binding introductions (typed params via dag_grammar_binding_name_terminal) still stamped ^dag_token_ident — so resolve's now-real name lookup rejected the valid bisect module (witness_bisect_wave1_parse_module_add_correctness_holds, the two red nextest jobs).

Root cause, proven by execution: the normalized wave1 tree has no Arrow nodes (normalize is shape-preserving; Arrows exist only after the post-resolve MVP body producer), so add_arrow_domain_named_params never fires and nothing binds fn params on this path. The pre-PR green was vacuous: class-stamped refs collapse to ^dag_token_ident, which is grammar-carried and hence canonical — resolve on main accepts a module referencing an undefined variable (proven with and without params in scope). This PR's reference-side flip exposed that fail-open; the fix completes the migration rather than reverting it (reverting reds fold_lowering_test 3/6 — proven both directions).

Fix (interim, dissolution trigger on the carrier — dag_fn_decl_param_scope_note): binding names stamp lexemes at the single shared authority; dag_fn_decl_param_binding_atoms harvests exactly the binding-name atoms from the ^dag_surface_param_list capture (preserved qualified_name/type subtrees and lex token-class atoms skipped); resolve pushes a ScopeFrame at fn_decl production wrappers. Dissolves into add_arrow_domain_named_params when body-lowering lands fn_decl → Arrow in normalize.

Red controls (new, CI-gated via interpreted_parse_bisect_unbound_reference_rejected): witness_bisect_wave1_unbound_reference_rejected + _no_binding_rejected — an unbound body reference must resolve-reject; they go false if the vacuity ever returns.

Receipts (isolated worktree, frozen PR-state binary; probe1 = fixed, probe2 = PR-head baseline): bisect 6/6 (incl. both red controls) · fold_lowering 6/6 · r1_fold_analysis 4/4 · budget_roster 2/2 · loop witnesses 20/20 · parse_binding_fidelity + add_arrow_eval keystone 6/6 — all green both sides, zero divergence. The two previously-failing rust tests + the new red-control test pass locally against the committed fix.

Known pre-existing red (declared, not introduced): cwc_resolution_probe_test::cwc_cwc_module_resolve_accepts (+ its conjunction cwc_nary_coproduct_normalize_boundary_holds) fails identically on the PR head baseline — constructor/type references need decl-name/namespace scoping, which is the operator-signed namespace-only-resolution lane (containment tree as naming authority), not this fix. Local-discovery path only; not CI-enrolled.

5. Merge of main + rename repoint (13203b2, 936017f)

Main's #6415 removed the wave# vocabulary while this branch was in flight; the merge was textually conflict-free but semantically broken (branch-side additions called dag_language_model_wave1/dag_wave1_lex_token_symbol whose definitions main renamed) — that was the compile-clean red on the merge run. The merge commit repoints every branch-side usage to main's names (dag_language_model, dag_lex_token_symbol, witness names de-waved; tree-wide wave1 residue = 0, matching main's sweep). 936017ff67 additionally dissolves dimension_row_is_strict's parallel DescentEvidence match into evidence_rank (both sides read the std.termination authority — review finding, cursor). Re-verified post-merge by execution: bisect 3/3 (incl. both red controls), fold_lowering 6/6, loop_multiplicity 8/8 (both lexicographic strict-dimension paths), loop_infer 5/5, plus the renamed rust tests green.

6. Accumulator-copy lens: prove-safe-or-refuse (4b6b719 — operator ruling: no false cleans)

The lens's original polarity ("is this argument the carrier? no → clean") had four silent false-clean arms (let-aliased carrier, missing port argument, unregistered combiner reached by the carrier, fold with unreadable accumulator) plus a port-reader bug that read a call's head symbol as a bare name (list_append(left: reverse(acc)) classified clean). Inverted: a site in iteration context is now Suspect, provably-fresh (pure literal — the only clean syntax can prove), or a counted refusal with a named cause; out-of-iteration sites are out of the rule's declared domain, and the domain is stated by accumulator_copy_report's folds_seen/carriers_bound counters, never implied clean. Every old false-clean class is pinned RED by a new discriminating witness. Also renamed off the planning codename per the standing no-codename rule: complexity_r1_accumulator_copy* → complexity_accumulator_copy*. Named residue on the carrier: shadowed carrier names can false-alarm (safe direction); non-fold iteration constructs are outside the declared domain — both dissolve on the resolved dataflow graph. 20/20 witnesses by execution; enrollment rows updated.

7. Stage-0 design: general body producer (4b7bc41, 56efe35 — operator direction: this PR delivers the full feature)

docs/plans/general-body-producer-design.md + the DESIGN.md open-thread registration (source-edited in dag/gunbc/design_document.dag, regenerated through the gated path, drift gate PASS). The doc is the model-before-implement deliverable for the remaining body-lowering keystone: lowering real ingested fn bodies into substrate behaviors as one row-selected fold in normalize — the forward reading of the same GrammarRelationRow rows the emitter reads backward (DESIGN §4), subsuming the fixture-bound MVP 03_body_producer and dissolving this PR's lens refusal buckets stage by stage (within-body → cross-decl → per-op derivation → MVP subsumption), each stage priced by the refusal causes it zeroes with RED controls kept live. The reverted cost-shape fork from this PR's own history is written in as the negative authority (per-production if-arm dispatch, pre-resolve, third body shape — never again). Flags for operator sign in doc §9: D (param-binding protocol), E (one sugar-rule table), F (3-edge Loop shape). Per the discipline, implementation stages land as separate signed PRs; this PR carries the lens (§6), the loop-typing foundation (Stages 1–3), and the design that connects them.

@briansrls briansrls changed the title Body-lowering design Stage 2: Loop multiplicity from measure Complexity lane: R1 enrolled + body-lowering Stages 2–3 + cost judgment un-opaqued + derived-floor ruling Jul 8, 2026
@briansrls briansrls changed the title Complexity lane: R1 enrolled + body-lowering Stages 2–3 + cost judgment un-opaqued + derived-floor ruling Complexity lane: derived floor live end-to-end — planted quadratic source → FloorError in CI Jul 8, 2026
@briansrls
briansrls force-pushed the claude/complexity-work-status-97zmt9 branch from 1d9a230 to 5cfd288 Compare July 9, 2026 03:27
@briansrls briansrls changed the title Complexity lane: derived floor live end-to-end — planted quadratic source → FloorError in CI Complexity foundation: loop typing + measure-derived termination + claim-bin cwd fix Jul 9, 2026
… + claim-bin cwd fix

Reworked to drop the forked complexity machinery. The cost-shape lowering
(dag_surface_lower_*) was a second, hand-rolled body producer running beside
the compiler's own — a §3/§4 fork: it re-lowered the surface parse tree by
hand (one if-arm per production), skipping resolve + normalize + body_producer,
and produced a shape that matched neither the real inferred tree nor its own
synthetic test subjects. It caught zero real quadratics and generated a
cascade of point-fixes (per-form lowering lanes, a lexeme-recovery module, a
GeneratedArtifact name collision, missing Branch-descent). All of it is backed
out. The general body producer that would replace it — §4's "one grammar read
in both directions" (row-driven ingest, the inverse of the row-driven emitter),
which also subsumes the pre-existing MVP1 03_body_producer — is left as
compiler work, not landed as a fork.

Kept: the genuinely fork-free, DESIGN-clean behavioral changes.

- 04_infer gains the Loop arm: an iteration-fold body is typed as a
  per-iteration transform (τ → τ under the measure); divergent and
  refinement-shaped bodies refuse with the located infer_loop_iteration_type_mismatch.
- Measure-derived loop termination (loop_multiplicity over the cited
  measure_descent_fact_registry, lattice meet + lexicographic strict-dimension
  proof), grounded on the dag/std/termination.dag single authority.
- claim_batch / claim_executor resolve relative path args against the process
  cwd and refuse (exit 2, located) on missing paths — closes the baked-root
  mixed-tree fail-open.

Verified by execution against the merged base: 8 loop-multiplicity + 5
loop-infer witnesses PASS; roster-shape, generated-artifact drift, and
enforcement-consistency + repo-wide-complexity meta-gates PASS. The two new
loop tests are CI-enrolled so the kept behavior gates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc
@briansrls
briansrls force-pushed the claude/complexity-work-status-97zmt9 branch from 5cfd288 to cb6e64e Compare July 9, 2026 04:13
claude added 7 commits July 9, 2026 04:27
…slice

The first real piece of the general body producer that replaces the removed
cost-shape fork (and, eventually, the hand-rolled MVP1 loop shapes). A surface
fold has no dedicated grammar production — it parses as an ordinary call — so
its lowering is a SEMANTIC desugaring keyed on the RESOLVED callee identity
(DESIGN §4: fold/recursion is sugar over Loop), never a lexeme scan. Given a
resolved fold call (positional children [callee, collection, init,
iteration_body]), fold_call_to_loop lifts the iteration body into the canonical
seam Loop bounded by the registered fold-iteration measure, and the kept
loop_multiplicity derives PROVEN termination from it — the same real derivation
the foundation's loop witnesses use, now reached from a fold-call shape.

This pins the seam (M1) and lands the desugaring unit (core of M2), verified by
execution: fold_call_lowers_to_terminating_loop (proven termination) +
short_fold_call_refuses_no_loop_fabricated (fail-closed red control). It is
deliberately resolve-agnostic — it consumes an already-resolved fold-call node —
so it is the same desugaring the whole-tree body producer will run on real
resolved fold calls once corpus resolution is affordable.

Remaining toward catching real quadratics: wire this to real resolved corpus
source (M2 full), corpus-scale resolution affordability (M4), re-key the
accumulator-copy rule to the seam Loop shape (M3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc
…en class

Foundational name-resolution fix. dag_grammar_primary_expr_core stamped the
general expression ident head with StampClass, so a general call's callee came
out as ^dag_token_ident — the NAME dropped at parse. That made every operation
(fold, contains, list_append, ...) unidentifiable in real code and left
resolution nothing to bind: a self-inconsistency in the grammar, since
qualified names (dag_grammar_qualified_name_expr) already StampLexeme.

Switch that one terminal to dag_grammar_terminal_lexeme, identical to how
qualified names already carry their name. Now a general call carries its callee
name, resolution can bind it (resolve_atom looks up the identity in scope), and
consumers read the canonical identity the homogeneous way the R1 lens already
does (r1_symbol_of = atom.identity, matched against a symbol-keyed registry).
This is the existing identification path, not a new mechanism — and NOT the
removed fork's post-hoc lexeme-recovery hack (StampLexeme preserves the name AT
parse; the hack recovered it from the token stream after the fact).

This unblocks operation-identification in real code — the prerequisite for the
complexity feature (and general name resolution broadly). v2 is not in
production, so this is the right window for the change.

Verified: all 4 v2 language parse tests pass; the whole-tree compile-clean gate,
emit-host, source-root-ingest, and self-host gates pass (the content-hash ripple
is contained); parse floor witness green (parse perf witness runs the v1 parser,
unaffected — a transient timing FAIL re-ran green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc
First check on real source that the StampLexeme grammar fix does its job: a real
fold snippet ingested through the census path (tokenize -> parse_module ->
normalize, v2.lens.enforcement.cost_coverage) yields a tree in which ^fold (the
callee) and ^xs (the collection) appear as atom identities — the names survive,
so operation recognition is now possible the homogeneous way the R1 lens reads
atom.identity. fold_callee_name_survives_parse is the RED control the pre-fix
StampClass regression breaks. CI-enrolled.

Grounding note recorded for the next slice: the fold call is NOT shaped as a
head-positional callee (that probe failed); it carries the surface call
production structure, so the desugaring will navigate it homogeneously via
parse_subtree_find_production_captured (the same helper cost_coverage already
uses to locate fn bodies) to extract the fn-literal iteration body, then desugar
via v2.compiler.fold_lowering.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc
Correct fold_call_to_loop to consume the actual surface fold-call subtree
(the primary_expr captured child) rather than a guessed
ComputationNode-with-positional-children shape whose index-3 body slot was
wrong for real folds (fold's iteration body is a NAMED fn-literal arg, not
positional[3]).

The desugaring now identifies the call homogeneously:
- fold_call_head_symbol reads the sequence-left head projection (the callee
  ^fold), the same way the qualified-name parser reads sequence heads;
- fold_call_iteration_body locates the sole ^dag_surface_fn_literal argument
  and lifts its ^dag_surface_fn_body, the same way cost_coverage locates fn
  bodies (parse_subtree_find_production_captured).

Keyed on the callee identity (DESIGN §4: fold/recursion is sugar over Loop),
never a lexeme scan. Fail-closed twice: a call whose head is not ^fold
refuses (^fold_lowering_not_a_fold_call); a fold call carrying no fn-literal
iteration body refuses (^fold_lowering_shape_invalid) — never fabricates a
loop.

Verified end-to-end on real source through the census ingest
(tokenize -> parse_module -> normalize): fold(xs, init: 0, f: fn(acc, x) { acc })
lowers to the canonical seam Loop and loop_multiplicity derives PROVEN
termination from the fold-iteration measure. Both fail-closed arms proven
discriminating by perturbation (each red control flips to FAIL when its arm
is defeated).

Consolidate the two probe test files into one end-to-end witness
(fold_lowering_test), folding in the StampLexeme survival checks (^fold/^xs
survive parse) as the grammar red control; drop the now-redundant
fold_real_source_test and update the CI witness roster.

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

Deliver the accumulator-copy lens's first real-source consumer: a surface
projection that reads a parsed fold call and builds R1's fold-step subject
(Instantiation[acc_binder, combiner, call[port0, port1]]), so R1 catches a
real quadratic end-to-end instead of only judging synthetic fixtures.

This is the peer projection of M2's fold_call_to_loop (DESIGN §2 Realization:
one surface fold call, N consumers — the loop projection is for termination,
this one for cost/copy-detection). Both read the SAME located fold call
through the SAME fn-literal locator, now factored out as
v2.compiler.fold_lowering.fold_call_step_fn (§3 single authority for "where
the step function is").

Foundational grammar fix: fn-literal parameters were stamped as the token
class (^dag_token_ident), dropping their names — the same StampLexeme drop
already fixed for call heads. Verified by execution: an unused param vanished
before the fix, survives after. R1 needs the accumulator's name (param 0) to
check whether it lands in the combiner's copied port, so the name must
survive parse.

The distiller (v2.lens.complexity_r1_accumulator_copy.surface_subject) reads
four symbols at the surface/lexeme level: acc_binder = step-fn param 0;
combiner = the head of the call in the step-fn body; port0/port1 = that
call's first two argument values in declared order. Fail-closed at every
step: no step fn / no first param / body not a two-argument call / an
argument not a bare name all REFUSE with a located diagnostic — never
fabricate a subject a fold R1 cannot read as clean.

Proven end-to-end on real source (v2.test.claim.complexity.r1_surface_subject),
through the census ingest: fold(..., fn(acc, x) { list_append(left: acc,
right: x) }) projects Poly(2); the SAME combiner with the accumulator flipped
to the non-copied port (list_append(left: x, right: acc)) is clean —
isolating the copied-port check as the sole difference; an identity-body fold
refuses. Discrimination proven by perturbation: a bogus acc_binder flips the
quadratic to clean (acc_binder is read independently, not circularly).

Surface-level because corpus resolution/body-production is not yet
affordable; a resolved-body read supersedes this once it is, with the seam
(fold_call_step_fn) unchanged. Whole-corpus enrollment (sweep every fold, not
these snippets) remains future work. Full CI floor green (4 batches, 30
witnesses).

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

Following the methodology "run the model on the real system and let where it
comes back lacking be the signal it's not done" — challenged the M3 distiller
against the actual corpus suspect shape (src/v2/workflow/glob_discovery_law.dag),
not the textbook snippet the M3 tests were written around.

Finding (verified by execution): the distiller MISSES the real quadratic. The
real suspect is fold_list with the copying list_append(left: acc, right: Cons{..})
buried inside an if-branch and a struct-literal grow-by-one arg. The distiller
reads only "the first call in the step body" — which is the if-CONDITION, a
one-argument call — so it reads the branch condition as the combiner and refuses
(cause: port1_opaque) rather than looking inside the branch. Corpus scale for
context: ~676 fold + ~413 fold_list + ~37 fold_node calls; the textbook direct-
combiner-body shape the distiller handles is the minority.

Captured as a committed coverage-boundary witness
(real_branch_body_quadratic_is_currently_missed): a RED that flips to FAIL the
moment the distiller learns to traverse branches — the flip is the dissolution
trigger to widen it into a positive catch. This is the honest "green on the
textbook shape, not done on real code" marker.

Made the distiller's refusals per-cause (FoldSurfaceRead classification →
no_step_fn / no_accumulator_param / body_not_located / body_head_opaque /
port0_opaque / port1_opaque), so the gap is a typed, located, legible fact
rather than one opaque shape-invalid (DESIGN §5: a refusal must be a typed,
located diagnostic). fold_call_to_r1_subject's public Outcome contract is
unchanged; the M3 tests pass unchanged.

Note: a whole-corpus quantified sweep of the distiller hits the same
affordability wall as M4 (per-file ingest + O(folds×subtree) walks), so
quantifying at scale waits on that infra; the qualitative finding here is
decisive on its own. Full CI floor green (4 batches, 31 witnesses).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc
Replace the 230-line surface-navigation distiller (surface_subject.dag) and the
bespoke r1_fold_step_subject intermediate with a single linear fold, so the lens
is stage1→stage2→… with each stage consuming the previous stage's natural type
(a Node), no adapter.

Two halves, cleanly split:
- COST MODEL (complexity_r1_accumulator_copy.dag) — navigation-free. Owns the
  copied-port registry lookup and classify_call(at, combiner, port_syms,
  carriers) → Optional<Finding>. Finding = Poly2Suspect | AnalysisOpaque.
- TRAVERSAL (complexity_r1_accumulator_copy/analyze.dag) — the fold.
  analyze(node, carriers) recurses over the whole tree threading the carrier
  environment down: at a fold-family call it binds the step-fn's accumulator; at
  every combiner call it asks classify_call.

Because the fold VISITS every node instead of doing targeted "first call in the
body" lookup, a copy inside an if/match/let is found by construction. The real
glob_discovery_law shape (fold_list, copying list_append(left: acc, ...) inside
an if-branch, grow-by-one struct arg) that the bridge MISSED is now CAUGHT — the
old coverage-boundary witness flipped from "currently missed" to
real_branch_body_quadratic_is_caught. classify_call reads only the copied port,
so the old over-strict "both ports must be bare names" gap is gone too. Ports are
read as DIRECT args (no descent into an arg's value) so a nested call doesn't
shift the copied-port index (map_merge's copied port is index 1).

Fail-closed preserved: a known combiner whose copied port is not a bare name is a
counted, located AnalysisOpaque finding — "could not tell" stays distinct from
"clean" (DESIGN §5).

Deletes surface_subject.dag, the r1_fold_step_subject/r1_judge_fold_step judge,
and the 5 synthetic red/green fixtures; the registry coverage they gave is
consolidated into a direct classify_call unit test
(complexity_r1_accumulator_copy_test) covering list_append/list_snoc/map_merge
suspects, non-copied-port and unregistered-combiner cleans, and the opaque case.
r1_surface_subject_test → r1_fold_analysis_test (drives the fold end-to-end).

Remaining (the follow-on "guessing" discussion): three surface reads inside the
fold are still syntactic — carrier = positional first param, combiner = lexeme
name, carrier-in-copied-port = symbol equality not dataflow — which want to be
edge lookups in a resolved/bound tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJjv8DKX4PpywPNTy6wpc
This was referenced Jul 9, 2026
…real, resolve loses its vacuity

The foundation PR lexeme-stamped identifier REFERENCES (primary_expr_core -> ^x)
but binding INTRODUCTIONS (typed params via dag_grammar_binding_name_terminal)
still stamped ^dag_token_ident, so resolve's real name lookup rejected the valid
bisect module (the rust_tests red: witness_bisect_wave1_parse_module_add_correctness_holds).

Root cause, proven by execution: the normalized wave1 tree has NO Arrow nodes
(normalize is shape-preserving; Arrows are built only by the post-resolve MVP
body producer), so add_arrow_domain_named_params never fires and nothing binds
param names. The pre-PR green was VACUOUS: class-stamped refs collapse to
^dag_token_ident, which is grammar-carried and therefore canonical, so resolve
on main accepts a module referencing an undefined variable (proven with and
without params in scope).

Fix (interim, dissolution trigger on the carrier):
- dag_grammar_binding_name_terminal ident arm -> StampLexeme (names are identities,
  consistent with the namespace-only-resolution direction)
- dag_fn_decl_param_binding_atoms + dag_param_binding_atom_harvest: harvest exactly
  the binding-name atoms from the ^dag_surface_param_list capture (preserved
  qualified_name/module_header subtrees and lex token-class atoms skipped)
- resolve: scope_with_fn_decl_params pushes a ScopeFrame at fn_decl production
  wrappers so param declarations AND body references resolve under it
- dissolves into add_arrow_domain_named_params when body-lowering lands
  fn_decl -> Arrow lowering in normalize (note data row beside the readers)

Red controls (new, CI-gated via interpreted_parse_termination_test):
witness_bisect_wave1_unbound_reference_rejected + _no_binding_rejected pin the
non-vacuous behavior - an unbound body reference must resolve-reject. They go
false if the vacuity ever returns.

Verified by execution in an isolated worktree: bisect witness green, both new
red controls green, fold_lowering 6/6, r1_fold_analysis, budget_roster gate,
loop witnesses, truncated-source rejection all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 9, 2026
Brian Searls and others added 5 commits July 9, 2026 21:05
…e — no false cleans

Operator ruling 2026-07-09: a false clean is forbidden; refusal is the only sound
answer syntax cannot prove. The old classify_call asked "is this argument the
carrier?" and answered CLEAN on "no" — unprovable on a parse tree (a let can alias
any name to the carrier). Four false-clean arms existed:
- bare non-carrier name in the copied port (let-alias hole)
- missing port argument (list_at Absent -> silent)
- unregistered combiner receiving the carrier (registry gap -> silent)
- fold with unreadable accumulator (empty carriers -> everything below compared clean)
Plus a port-reader bug: an argument CALL's head symbol read as a bare name, so
list_append(left: reverse(acc)) classified clean.

New lattice per registered-combiner site in iteration context:
- bare name == live carrier              -> Poly2Suspect (unchanged)
- pure literal (zero value identifiers)  -> the only provable clean
- everything else                        -> Unclassifiable { cause }, counted:
  ^copied_port_name_may_alias | ^copied_port_computed_argument |
  ^copied_port_argument_missing | ^combiner_unregistered_carrier_reaches |
  ^fold_accumulator_unread | ^call_head_unreadable
Out-of-iteration sites are out of the rule's domain (a single append is linear);
the domain itself is stated by accumulator_copy_report's folds_seen/carriers_bound,
never implied clean. Port reading now counts value identifiers in the argument
subtree (0 -> literal, 1 -> bare name, else computed) so call heads cannot
masquerade as names. Known residue named on the carrier: shadowed carrier names
can false-ALARM (safe direction); non-fold iteration is outside the declared
domain. Both dissolve on the resolved dataflow graph.

Also renames the family off its planning codename (standing no-codename rule):
complexity_r1_accumulator_copy* -> complexity_accumulator_copy*, r1_* helpers
dissolved or renamed, hollow r1_symbols_equal alias inlined.

Verified by execution: 10/10 unit lattice witnesses + 10/10 end-to-end ingest
witnesses, including red controls that pin each old false-clean class
(let_alias_refuses_not_clean, nested_call_head_cannot_masquerade_as_bare_name,
noncarrier_name_in_copied_port_refuses_not_clean, named_step_fold_refuses_
accumulator_unread). CI enrollment rows updated to the new entries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r rows

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot force-pushed the claude/complexity-work-status-97zmt9 branch from 38a71ee to 4b6b719 Compare July 9, 2026 23:47
…ody-lowering Stages 1-3 landed)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brian Searls and others added 2 commits July 10, 2026 00:41
#6424 prose sweep to the renamed lens files

The modify/delete conflict left main's copy of complexity_r1_accumulator_copy.dag in the tree beside its renamed successor — a dual representation. Deleted. The sweep's rule applies to the renamed files' own prose rows (6 data-String notes: census recall, 3 registry citations, the fail-closed lattice note, and both test-file notes) — swept here; the typed construction_justification row and the 20 witnesses remain the carriers of those facts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@briansrls
briansrls merged commit fdcb2f1 into main Jul 10, 2026
3 checks passed
@briansrls
briansrls deleted the claude/complexity-work-status-97zmt9 branch July 10, 2026 01:24
briansrls added a commit that referenced this pull request Jul 10, 2026
…ering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 10, 2026
* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* Analysis spine: spine_receipt composes dependency_view + materialize (increment 1)

The Rc-safe half of run ≜ realize ∘ materialize ∘ dependency_view: compose
the two catamorphisms that need no interpreter thread-safety.

- src/v2/std/spine.dag: level-profile fold over the DependencyView DAG →
  critical_path_depth (longest dependency chain / the reduce spine) +
  independence_width (max nodes at one level / what parallelizes to hw width).
  spine_receipt emits the §9 numbers by COMPUTATION, not assertion, joining
  materialize's content-hash Share/dedup counts.
- Discriminating RED (§9): single chain A→B→C → depth 3 / width 1 (serial);
  root over N independent leaves → depth 2 / width N.
- Witnesses 9/9 (spine) green by execution; materialize 6/6 unchanged.

The RUNNER (wall-clock parallel execution, §8 steps 3-4) stays increment 2+,
gated on interpreter Rc→Arc (v1 interp is !Send). This increment measures the
achievable width/critical-path floor the runner targets; it does not fabricate
wall-clock N×.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Unbundle recompute-trace interpreter extension from the analysis-spine PR

CI root cause: the recompute-trace extension edited v1_interpreter.rs, which
hosts the atom_identity_hash/hash_combine fnv1a64 intrinsics that
dag_collect_fingerprint_witness executes. That correctly invalidated the
re-verify 'assumed-green node-frontier' SKIP of that witness (cone-touch,
fail-closed) — but the witness is a pre-existing 806s (13min) fnv1a64
whole-corpus walk, so un-skipping it blew the 30-min floor budget. Main stays
green only because its interpreter cone is untouched (witness stays skipped).

The interpreter extension is a separable, env-gated (GUNBC_RECOMPUTE_TRACE=1),
READ-mode diagnostic — not a dependency of the spine/materialize analysis
substrate (pure .dag, content_hash-based). Reverting v1_interpreter.rs to main
restores byte-identical interpreter content → the fingerprint witness returns to
assumed-green SKIP → floor budget restored. The recompute-trace extension lands
as its own follow-up PR where the fingerprint-witness re-run is expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Materialization ladder: the state x decision law, as executable witnesses

The operator's 4-rule business logic generalized on one axis: the decision is
a function of WHEN the redundancy is knowable and WHETHER what was knowable
was prepared for. Errors fire only on knowable-but-unprepared; genuine
emergence and declared triviality are typed acceptances, never silence.

std.materialization_ladder (dag/std):
- Frame/FrameKind: SharedStateFrame | IsolatedChildrenFrame |
  ReplayedFrame{attempts} | UnboundedSiblingsFrame — the nested-scope axis;
  a 'run' at any layer is a frame, never a different kind of thing.
- DemandNature: Pure | IdempotentEffect | WorldRead{envelope_declared} |
  FreshEffect — the D3 effect gate; TTL = unmodeled dependency XOR declared
  staleness, never an eviction knob.
- CacheProvider: keying (ContentKeyed|ExistenceKeyed) + EvictionPolicy
  (ScopeExit|SpacePacked) REQUIRED by construction — rule 3 unwritable-bad.
- LadderVerdict (total): AuthoredDuplication | Discharged | RefusedNoProvider
  | RefusedScopeTooNarrow | RefusedExistenceKeyed (the build-if-absent #6352
  wall) | RefusedUnmodeledWorldRead | ExemptFreshEffect |
  AcceptedBelowCostFloor | AcceptedSingleRecompute.
- Declared-emergent frames obligate UP FRONT: retry frames derive
  checkpointing, unbounded-sibling frames (server loops, CI-runs-over-time)
  derive persistent caches — prepare-before-demand.

12/12 witnesses green by execution; each test is one cell of the table,
fixtures mirror the live worked example (workflow/jobs/steps, retry, fleet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Docs crystallization: derived materialization placement into roadmap ④ + the state x decision table

- roadmap_authority ④ (ROADMAP.md regenerated via main_wet, drift-consistent):
  the nested-frame law, plurality cells, declared-emergent prepare-up-front,
  keying/staleness walls, the caching-completion un-shelve, the ①-vs-§2
  cross-run-caching contradiction subsumed into per-node derived verdicts,
  and the v1.compiler.ownership §3-convergence row.
- duplicate-work design doc: the state x decision table as the qualifier's
  final verdict logic + the ownership consolidation subsection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Consolidation plan: realization + materialization + ownership are one law

Operator synthesis (2026-07-09): Materialization = the verdict vocabulary;
ownership = the verdict computation at the eval frame; realization = provider
selection discharging the verdict at each frame's carrier. Share's handler is
layer-aware — the cheapest cache is a REFERENCE (same program + ref-capable
carrier + readonly => point-at-it, no copy, no destroyed memory), demoting
through HAMT structural share / process memo / artifact / CAS, and demotion
must be priced, never silent (#6249 clone-fallback is the receipt).

Census of every hand-rolled instance found in-tree (16 rows): each named with
its frame, ladder cell, action, and dissolution trigger — ownership
(consolidated), Rc/HAMT (reference tier), clone-fallback (demotion wall),
ParseTable + cached_stage (C5 grounding), M1 memo / intern / assumed-green /
sccache / cargo-cache (C2 provider rows), PROCESS_RESOLVE_STORE (C3 = the 9GB
scope fix), build-if-absent (landed as the keying wall), resolve-cache #5789
(rule-4 requirements), recompute-trace (state-4 finding source). Peers kept
distinct: affected-set, Independence/Placement, mutable state.

Sequence C1-C5 with C1 = this PR (ladder + live CI gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Ownership refactored onto materialization: the value tier, tested as providers

First consolidation increment (operator-directed): v1.compiler.ownership's
decision IS provider selection at the value grain, now expressed in the ladder
and proven by mirror witnesses.

- ProviderTier: Reference | Copy | Memo{keying} | Artifact{keying} | Cas{keying}
  — keying folded INTO store tiers, so an existence-keyed reference is
  unwritable BY SHAPE (§5 construction); frame obligations at isolation LCAs
  are dischargeable only by store tiers (a reference cannot cross an isolation
  boundary — witnessed).
- Value tier: AccessMode (Read|Consume|Carry|Project), ValueUsage,
  value_materialization -> ValueDead | ValueMoved | ValueSharedByReference |
  ValueDemotedToCopy (PRICED, requires a declared CopyTier provider — the
  #6249 silent clone-fallback made refusable) | ValueRefusedAffine |
  ValueRefusedNoCarrierProvider.
- Faithful to v1's THREE distinct plurality readings, kept separate:
  take_count = semantic_consumer_count (Consumed only, affine axis);
  value_access_plurality = binding_fan_out (Carry excluded, reference axis);
  borrow_count = whole_value_borrow_count (Read+Carry not Project, movability).
- Fold-accumulator case mirrored at conservative pre-FoldAccUnwrap semantics:
  carries excluded from plurality but blocking the move -> demoted-to-copy.

23/23 witnesses green (14 frame cells + 9 value cells). Corpus-level
equivalence against live v1 ownership folds = the C4 receipt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* WIP: Duplicate Computation/Materialization

* G: exhaustive cache/share census (52 mechanisms, 6 groups) + C0 catalog-grounding of provider rows + forward-wiring walls

The sweep found the tree already models caches: extdeps/cache cache_catalog
(CacheInterfaceCatalogFacts, 9 rows) + extdeps/realization carrier facts +
the warm==cold purity oracle. C0 grounds CacheProvider on that catalog
(provider_from_catalog projection; CacheProvider.id -> CacheInterfaceId)
so the ladder and the catalog never restate each other's half. Three
forward walls (demands-from-DependencyView, hand-cache shape lens,
live-provider-or-red) make new caches born as provider rows only.

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

* WIP: Duplicate Computation/Materialization

* C0: provider rows derive from the cited cache catalog (extdeps/cache/materialization.dag projection)

Operator ruling 2026-07-09: extdeps stays the ground-truth/interface layer;
every USE of a cache goes through materialization so memo never gets
re-invented. provider_from_catalog is the only door from a catalog row into
the ladder: keying/tier/eviction derived from cited facts (mechanism->class:
InProcess=>ScopeExit; Ttl/Lru/SizeBounded=>SpacePacked; Never/Manual outside
a process => typed ProjectionRefused, counted by the new enrolled witness;
HandAuthored/prefix-fallback keys => ExistenceKeyed until key-completeness
upgrades them). CI sccache row now derived, hand-typed tier facts deleted,
6/6 + 23/23 witnesses green. 10b re-scoped: v1-internal caches = inventory
only (retire with seed); ParseTable/cached_stage promoted to next.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Fail-closed hardening: RefusedNatureConflict arm, weakest-claim nature default, UsesStep silence counted, ladder cells enrolled in CI

The complexity-lens false-clean lesson applied to this gate before anyone
relies on it: (1) heterogeneous natures on one identity were first-wins —
now a typed RefusedNatureConflict (24th ladder cell, RED witness); (2) an
unrostered run-step claimed PureComputation — now IdempotentEffect, the
weakest claim (verdict-identical, no purity overclaim; a misdeclared
WorldRead can no longer be legally memoized by default); (3) UsesStep
foreign actions produced silence — now a pinned denominator (==9; a new
foreign action must consciously bump it); (4) the ladder's 24 cells enroll
on the CI surface so the law's own witnesses gate every run. 24/24 + 7/7.

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

* WIP: Duplicate Computation/Materialization

* M1 ratchet bump: declared resolve count 1 -> 3 (gate's first live catch — enrollment pays counted resolves)

Run 29058798771: enrolling the ladder witness file moved resolves_total
1 -> 3 (each enrolled entry file pays one closure resolve against the
shared index) and the receipt gate redded that exact run — the designed
semantics, receipted in the note. Bump acknowledges the two witness-entry
resolves as declared debt; M2 (one closure resolve per roots set)
ratchets back toward 1.

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

* Retire the M1/M2 labels from carriers (no-codename rule; collided with DESIGN's floor-memoization M1/M2)

Step renamed to 'Floor resolve receipt gate (declared cold-resolve count)';
notes and the gate echo now say what the things are: the counted
cold-resolve receipt, and the shared-resolve rewire (one closure resolve
per source-roots set). Naming-retirement note left on the carrier.

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

* WIP: Duplicate Computation/Materialization

* Run-step natures pinned as counted claims, not affordances

Operator ruling 2026-07-10: hardcoded shell scripts get no affordances
— run-steps are supposed to be modeled as typed intents and emitted
(shell-emission-model slice 4 covers ci_workflow RunSteps). Until that
slice lands, every nature in job_run_demands is a claim (rostered
FreshEffect / weakest-default IdempotentEffect), never derived from a
modeled effect row. Count the whole claimed-nature surface (16 by
execution) and pin it in the enrolled witness: a new raw-script step
must consciously bump the pin, and slice-4 migration becomes a
countable ratchet ending at zero, where the pin becomes a wall.
Rejected alternative recorded in the carrier note: a per-step
declared-natures roster (a second parallel ledger over scripts the
shell-emission plan already governs).

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

* Regen DESIGN.md after main merge (duplicate-work row + #6373 body-lowering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

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

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 10, 2026
…rier (#6435)

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* Analysis spine: spine_receipt composes dependency_view + materialize (increment 1)

The Rc-safe half of run ≜ realize ∘ materialize ∘ dependency_view: compose
the two catamorphisms that need no interpreter thread-safety.

- src/v2/std/spine.dag: level-profile fold over the DependencyView DAG →
  critical_path_depth (longest dependency chain / the reduce spine) +
  independence_width (max nodes at one level / what parallelizes to hw width).
  spine_receipt emits the §9 numbers by COMPUTATION, not assertion, joining
  materialize's content-hash Share/dedup counts.
- Discriminating RED (§9): single chain A→B→C → depth 3 / width 1 (serial);
  root over N independent leaves → depth 2 / width N.
- Witnesses 9/9 (spine) green by execution; materialize 6/6 unchanged.

The RUNNER (wall-clock parallel execution, §8 steps 3-4) stays increment 2+,
gated on interpreter Rc→Arc (v1 interp is !Send). This increment measures the
achievable width/critical-path floor the runner targets; it does not fabricate
wall-clock N×.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Unbundle recompute-trace interpreter extension from the analysis-spine PR

CI root cause: the recompute-trace extension edited v1_interpreter.rs, which
hosts the atom_identity_hash/hash_combine fnv1a64 intrinsics that
dag_collect_fingerprint_witness executes. That correctly invalidated the
re-verify 'assumed-green node-frontier' SKIP of that witness (cone-touch,
fail-closed) — but the witness is a pre-existing 806s (13min) fnv1a64
whole-corpus walk, so un-skipping it blew the 30-min floor budget. Main stays
green only because its interpreter cone is untouched (witness stays skipped).

The interpreter extension is a separable, env-gated (GUNBC_RECOMPUTE_TRACE=1),
READ-mode diagnostic — not a dependency of the spine/materialize analysis
substrate (pure .dag, content_hash-based). Reverting v1_interpreter.rs to main
restores byte-identical interpreter content → the fingerprint witness returns to
assumed-green SKIP → floor budget restored. The recompute-trace extension lands
as its own follow-up PR where the fingerprint-witness re-run is expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Materialization ladder: the state x decision law, as executable witnesses

The operator's 4-rule business logic generalized on one axis: the decision is
a function of WHEN the redundancy is knowable and WHETHER what was knowable
was prepared for. Errors fire only on knowable-but-unprepared; genuine
emergence and declared triviality are typed acceptances, never silence.

std.materialization_ladder (dag/std):
- Frame/FrameKind: SharedStateFrame | IsolatedChildrenFrame |
  ReplayedFrame{attempts} | UnboundedSiblingsFrame — the nested-scope axis;
  a 'run' at any layer is a frame, never a different kind of thing.
- DemandNature: Pure | IdempotentEffect | WorldRead{envelope_declared} |
  FreshEffect — the D3 effect gate; TTL = unmodeled dependency XOR declared
  staleness, never an eviction knob.
- CacheProvider: keying (ContentKeyed|ExistenceKeyed) + EvictionPolicy
  (ScopeExit|SpacePacked) REQUIRED by construction — rule 3 unwritable-bad.
- LadderVerdict (total): AuthoredDuplication | Discharged | RefusedNoProvider
  | RefusedScopeTooNarrow | RefusedExistenceKeyed (the build-if-absent #6352
  wall) | RefusedUnmodeledWorldRead | ExemptFreshEffect |
  AcceptedBelowCostFloor | AcceptedSingleRecompute.
- Declared-emergent frames obligate UP FRONT: retry frames derive
  checkpointing, unbounded-sibling frames (server loops, CI-runs-over-time)
  derive persistent caches — prepare-before-demand.

12/12 witnesses green by execution; each test is one cell of the table,
fixtures mirror the live worked example (workflow/jobs/steps, retry, fleet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Docs crystallization: derived materialization placement into roadmap ④ + the state x decision table

- roadmap_authority ④ (ROADMAP.md regenerated via main_wet, drift-consistent):
  the nested-frame law, plurality cells, declared-emergent prepare-up-front,
  keying/staleness walls, the caching-completion un-shelve, the ①-vs-§2
  cross-run-caching contradiction subsumed into per-node derived verdicts,
  and the v1.compiler.ownership §3-convergence row.
- duplicate-work design doc: the state x decision table as the qualifier's
  final verdict logic + the ownership consolidation subsection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Consolidation plan: realization + materialization + ownership are one law

Operator synthesis (2026-07-09): Materialization = the verdict vocabulary;
ownership = the verdict computation at the eval frame; realization = provider
selection discharging the verdict at each frame's carrier. Share's handler is
layer-aware — the cheapest cache is a REFERENCE (same program + ref-capable
carrier + readonly => point-at-it, no copy, no destroyed memory), demoting
through HAMT structural share / process memo / artifact / CAS, and demotion
must be priced, never silent (#6249 clone-fallback is the receipt).

Census of every hand-rolled instance found in-tree (16 rows): each named with
its frame, ladder cell, action, and dissolution trigger — ownership
(consolidated), Rc/HAMT (reference tier), clone-fallback (demotion wall),
ParseTable + cached_stage (C5 grounding), M1 memo / intern / assumed-green /
sccache / cargo-cache (C2 provider rows), PROCESS_RESOLVE_STORE (C3 = the 9GB
scope fix), build-if-absent (landed as the keying wall), resolve-cache #5789
(rule-4 requirements), recompute-trace (state-4 finding source). Peers kept
distinct: affected-set, Independence/Placement, mutable state.

Sequence C1-C5 with C1 = this PR (ladder + live CI gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Ownership refactored onto materialization: the value tier, tested as providers

First consolidation increment (operator-directed): v1.compiler.ownership's
decision IS provider selection at the value grain, now expressed in the ladder
and proven by mirror witnesses.

- ProviderTier: Reference | Copy | Memo{keying} | Artifact{keying} | Cas{keying}
  — keying folded INTO store tiers, so an existence-keyed reference is
  unwritable BY SHAPE (§5 construction); frame obligations at isolation LCAs
  are dischargeable only by store tiers (a reference cannot cross an isolation
  boundary — witnessed).
- Value tier: AccessMode (Read|Consume|Carry|Project), ValueUsage,
  value_materialization -> ValueDead | ValueMoved | ValueSharedByReference |
  ValueDemotedToCopy (PRICED, requires a declared CopyTier provider — the
  #6249 silent clone-fallback made refusable) | ValueRefusedAffine |
  ValueRefusedNoCarrierProvider.
- Faithful to v1's THREE distinct plurality readings, kept separate:
  take_count = semantic_consumer_count (Consumed only, affine axis);
  value_access_plurality = binding_fan_out (Carry excluded, reference axis);
  borrow_count = whole_value_borrow_count (Read+Carry not Project, movability).
- Fold-accumulator case mirrored at conservative pre-FoldAccUnwrap semantics:
  carries excluded from plurality but blocking the move -> demoted-to-copy.

23/23 witnesses green (14 frame cells + 9 value cells). Corpus-level
equivalence against live v1 ownership folds = the C4 receipt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* WIP: Duplicate Computation/Materialization

* G: exhaustive cache/share census (52 mechanisms, 6 groups) + C0 catalog-grounding of provider rows + forward-wiring walls

The sweep found the tree already models caches: extdeps/cache cache_catalog
(CacheInterfaceCatalogFacts, 9 rows) + extdeps/realization carrier facts +
the warm==cold purity oracle. C0 grounds CacheProvider on that catalog
(provider_from_catalog projection; CacheProvider.id -> CacheInterfaceId)
so the ladder and the catalog never restate each other's half. Three
forward walls (demands-from-DependencyView, hand-cache shape lens,
live-provider-or-red) make new caches born as provider rows only.

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

* WIP: Duplicate Computation/Materialization

* C0: provider rows derive from the cited cache catalog (extdeps/cache/materialization.dag projection)

Operator ruling 2026-07-09: extdeps stays the ground-truth/interface layer;
every USE of a cache goes through materialization so memo never gets
re-invented. provider_from_catalog is the only door from a catalog row into
the ladder: keying/tier/eviction derived from cited facts (mechanism->class:
InProcess=>ScopeExit; Ttl/Lru/SizeBounded=>SpacePacked; Never/Manual outside
a process => typed ProjectionRefused, counted by the new enrolled witness;
HandAuthored/prefix-fallback keys => ExistenceKeyed until key-completeness
upgrades them). CI sccache row now derived, hand-typed tier facts deleted,
6/6 + 23/23 witnesses green. 10b re-scoped: v1-internal caches = inventory
only (retire with seed); ParseTable/cached_stage promoted to next.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Fail-closed hardening: RefusedNatureConflict arm, weakest-claim nature default, UsesStep silence counted, ladder cells enrolled in CI

The complexity-lens false-clean lesson applied to this gate before anyone
relies on it: (1) heterogeneous natures on one identity were first-wins —
now a typed RefusedNatureConflict (24th ladder cell, RED witness); (2) an
unrostered run-step claimed PureComputation — now IdempotentEffect, the
weakest claim (verdict-identical, no purity overclaim; a misdeclared
WorldRead can no longer be legally memoized by default); (3) UsesStep
foreign actions produced silence — now a pinned denominator (==9; a new
foreign action must consciously bump it); (4) the ladder's 24 cells enroll
on the CI surface so the law's own witnesses gate every run. 24/24 + 7/7.

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

* WIP: Duplicate Computation/Materialization

* M1 ratchet bump: declared resolve count 1 -> 3 (gate's first live catch — enrollment pays counted resolves)

Run 29058798771: enrolling the ladder witness file moved resolves_total
1 -> 3 (each enrolled entry file pays one closure resolve against the
shared index) and the receipt gate redded that exact run — the designed
semantics, receipted in the note. Bump acknowledges the two witness-entry
resolves as declared debt; M2 (one closure resolve per roots set)
ratchets back toward 1.

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

* Retire the M1/M2 labels from carriers (no-codename rule; collided with DESIGN's floor-memoization M1/M2)

Step renamed to 'Floor resolve receipt gate (declared cold-resolve count)';
notes and the gate echo now say what the things are: the counted
cold-resolve receipt, and the shared-resolve rewire (one closure resolve
per source-roots set). Naming-retirement note left on the carrier.

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

* WIP: Duplicate Computation/Materialization

* Run-step natures pinned as counted claims, not affordances

Operator ruling 2026-07-10: hardcoded shell scripts get no affordances
— run-steps are supposed to be modeled as typed intents and emitted
(shell-emission-model slice 4 covers ci_workflow RunSteps). Until that
slice lands, every nature in job_run_demands is a claim (rostered
FreshEffect / weakest-default IdempotentEffect), never derived from a
modeled effect row. Count the whole claimed-nature surface (16 by
execution) and pin it in the enrolled witness: a new raw-script step
must consciously bump the pin, and slice-4 migration becomes a
countable ratchet ending at zero, where the pin becomes a wall.
Rejected alternative recorded in the carrier note: a per-step
declared-natures roster (a second parallel ledger over scripts the
shell-emission plan already governs).

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

* Regen DESIGN.md after main merge (duplicate-work row + #6373 body-lowering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

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

* WIP: Duplicate Computation/Materialization

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 10, 2026
…ate (#6441)

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* Analysis spine: spine_receipt composes dependency_view + materialize (increment 1)

The Rc-safe half of run ≜ realize ∘ materialize ∘ dependency_view: compose
the two catamorphisms that need no interpreter thread-safety.

- src/v2/std/spine.dag: level-profile fold over the DependencyView DAG →
  critical_path_depth (longest dependency chain / the reduce spine) +
  independence_width (max nodes at one level / what parallelizes to hw width).
  spine_receipt emits the §9 numbers by COMPUTATION, not assertion, joining
  materialize's content-hash Share/dedup counts.
- Discriminating RED (§9): single chain A→B→C → depth 3 / width 1 (serial);
  root over N independent leaves → depth 2 / width N.
- Witnesses 9/9 (spine) green by execution; materialize 6/6 unchanged.

The RUNNER (wall-clock parallel execution, §8 steps 3-4) stays increment 2+,
gated on interpreter Rc→Arc (v1 interp is !Send). This increment measures the
achievable width/critical-path floor the runner targets; it does not fabricate
wall-clock N×.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Unbundle recompute-trace interpreter extension from the analysis-spine PR

CI root cause: the recompute-trace extension edited v1_interpreter.rs, which
hosts the atom_identity_hash/hash_combine fnv1a64 intrinsics that
dag_collect_fingerprint_witness executes. That correctly invalidated the
re-verify 'assumed-green node-frontier' SKIP of that witness (cone-touch,
fail-closed) — but the witness is a pre-existing 806s (13min) fnv1a64
whole-corpus walk, so un-skipping it blew the 30-min floor budget. Main stays
green only because its interpreter cone is untouched (witness stays skipped).

The interpreter extension is a separable, env-gated (GUNBC_RECOMPUTE_TRACE=1),
READ-mode diagnostic — not a dependency of the spine/materialize analysis
substrate (pure .dag, content_hash-based). Reverting v1_interpreter.rs to main
restores byte-identical interpreter content → the fingerprint witness returns to
assumed-green SKIP → floor budget restored. The recompute-trace extension lands
as its own follow-up PR where the fingerprint-witness re-run is expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Materialization ladder: the state x decision law, as executable witnesses

The operator's 4-rule business logic generalized on one axis: the decision is
a function of WHEN the redundancy is knowable and WHETHER what was knowable
was prepared for. Errors fire only on knowable-but-unprepared; genuine
emergence and declared triviality are typed acceptances, never silence.

std.materialization_ladder (dag/std):
- Frame/FrameKind: SharedStateFrame | IsolatedChildrenFrame |
  ReplayedFrame{attempts} | UnboundedSiblingsFrame — the nested-scope axis;
  a 'run' at any layer is a frame, never a different kind of thing.
- DemandNature: Pure | IdempotentEffect | WorldRead{envelope_declared} |
  FreshEffect — the D3 effect gate; TTL = unmodeled dependency XOR declared
  staleness, never an eviction knob.
- CacheProvider: keying (ContentKeyed|ExistenceKeyed) + EvictionPolicy
  (ScopeExit|SpacePacked) REQUIRED by construction — rule 3 unwritable-bad.
- LadderVerdict (total): AuthoredDuplication | Discharged | RefusedNoProvider
  | RefusedScopeTooNarrow | RefusedExistenceKeyed (the build-if-absent #6352
  wall) | RefusedUnmodeledWorldRead | ExemptFreshEffect |
  AcceptedBelowCostFloor | AcceptedSingleRecompute.
- Declared-emergent frames obligate UP FRONT: retry frames derive
  checkpointing, unbounded-sibling frames (server loops, CI-runs-over-time)
  derive persistent caches — prepare-before-demand.

12/12 witnesses green by execution; each test is one cell of the table,
fixtures mirror the live worked example (workflow/jobs/steps, retry, fleet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Docs crystallization: derived materialization placement into roadmap ④ + the state x decision table

- roadmap_authority ④ (ROADMAP.md regenerated via main_wet, drift-consistent):
  the nested-frame law, plurality cells, declared-emergent prepare-up-front,
  keying/staleness walls, the caching-completion un-shelve, the ①-vs-§2
  cross-run-caching contradiction subsumed into per-node derived verdicts,
  and the v1.compiler.ownership §3-convergence row.
- duplicate-work design doc: the state x decision table as the qualifier's
  final verdict logic + the ownership consolidation subsection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Consolidation plan: realization + materialization + ownership are one law

Operator synthesis (2026-07-09): Materialization = the verdict vocabulary;
ownership = the verdict computation at the eval frame; realization = provider
selection discharging the verdict at each frame's carrier. Share's handler is
layer-aware — the cheapest cache is a REFERENCE (same program + ref-capable
carrier + readonly => point-at-it, no copy, no destroyed memory), demoting
through HAMT structural share / process memo / artifact / CAS, and demotion
must be priced, never silent (#6249 clone-fallback is the receipt).

Census of every hand-rolled instance found in-tree (16 rows): each named with
its frame, ladder cell, action, and dissolution trigger — ownership
(consolidated), Rc/HAMT (reference tier), clone-fallback (demotion wall),
ParseTable + cached_stage (C5 grounding), M1 memo / intern / assumed-green /
sccache / cargo-cache (C2 provider rows), PROCESS_RESOLVE_STORE (C3 = the 9GB
scope fix), build-if-absent (landed as the keying wall), resolve-cache #5789
(rule-4 requirements), recompute-trace (state-4 finding source). Peers kept
distinct: affected-set, Independence/Placement, mutable state.

Sequence C1-C5 with C1 = this PR (ladder + live CI gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Ownership refactored onto materialization: the value tier, tested as providers

First consolidation increment (operator-directed): v1.compiler.ownership's
decision IS provider selection at the value grain, now expressed in the ladder
and proven by mirror witnesses.

- ProviderTier: Reference | Copy | Memo{keying} | Artifact{keying} | Cas{keying}
  — keying folded INTO store tiers, so an existence-keyed reference is
  unwritable BY SHAPE (§5 construction); frame obligations at isolation LCAs
  are dischargeable only by store tiers (a reference cannot cross an isolation
  boundary — witnessed).
- Value tier: AccessMode (Read|Consume|Carry|Project), ValueUsage,
  value_materialization -> ValueDead | ValueMoved | ValueSharedByReference |
  ValueDemotedToCopy (PRICED, requires a declared CopyTier provider — the
  #6249 silent clone-fallback made refusable) | ValueRefusedAffine |
  ValueRefusedNoCarrierProvider.
- Faithful to v1's THREE distinct plurality readings, kept separate:
  take_count = semantic_consumer_count (Consumed only, affine axis);
  value_access_plurality = binding_fan_out (Carry excluded, reference axis);
  borrow_count = whole_value_borrow_count (Read+Carry not Project, movability).
- Fold-accumulator case mirrored at conservative pre-FoldAccUnwrap semantics:
  carries excluded from plurality but blocking the move -> demoted-to-copy.

23/23 witnesses green (14 frame cells + 9 value cells). Corpus-level
equivalence against live v1 ownership folds = the C4 receipt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* WIP: Duplicate Computation/Materialization

* G: exhaustive cache/share census (52 mechanisms, 6 groups) + C0 catalog-grounding of provider rows + forward-wiring walls

The sweep found the tree already models caches: extdeps/cache cache_catalog
(CacheInterfaceCatalogFacts, 9 rows) + extdeps/realization carrier facts +
the warm==cold purity oracle. C0 grounds CacheProvider on that catalog
(provider_from_catalog projection; CacheProvider.id -> CacheInterfaceId)
so the ladder and the catalog never restate each other's half. Three
forward walls (demands-from-DependencyView, hand-cache shape lens,
live-provider-or-red) make new caches born as provider rows only.

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

* WIP: Duplicate Computation/Materialization

* C0: provider rows derive from the cited cache catalog (extdeps/cache/materialization.dag projection)

Operator ruling 2026-07-09: extdeps stays the ground-truth/interface layer;
every USE of a cache goes through materialization so memo never gets
re-invented. provider_from_catalog is the only door from a catalog row into
the ladder: keying/tier/eviction derived from cited facts (mechanism->class:
InProcess=>ScopeExit; Ttl/Lru/SizeBounded=>SpacePacked; Never/Manual outside
a process => typed ProjectionRefused, counted by the new enrolled witness;
HandAuthored/prefix-fallback keys => ExistenceKeyed until key-completeness
upgrades them). CI sccache row now derived, hand-typed tier facts deleted,
6/6 + 23/23 witnesses green. 10b re-scoped: v1-internal caches = inventory
only (retire with seed); ParseTable/cached_stage promoted to next.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Fail-closed hardening: RefusedNatureConflict arm, weakest-claim nature default, UsesStep silence counted, ladder cells enrolled in CI

The complexity-lens false-clean lesson applied to this gate before anyone
relies on it: (1) heterogeneous natures on one identity were first-wins —
now a typed RefusedNatureConflict (24th ladder cell, RED witness); (2) an
unrostered run-step claimed PureComputation — now IdempotentEffect, the
weakest claim (verdict-identical, no purity overclaim; a misdeclared
WorldRead can no longer be legally memoized by default); (3) UsesStep
foreign actions produced silence — now a pinned denominator (==9; a new
foreign action must consciously bump it); (4) the ladder's 24 cells enroll
on the CI surface so the law's own witnesses gate every run. 24/24 + 7/7.

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

* WIP: Duplicate Computation/Materialization

* M1 ratchet bump: declared resolve count 1 -> 3 (gate's first live catch — enrollment pays counted resolves)

Run 29058798771: enrolling the ladder witness file moved resolves_total
1 -> 3 (each enrolled entry file pays one closure resolve against the
shared index) and the receipt gate redded that exact run — the designed
semantics, receipted in the note. Bump acknowledges the two witness-entry
resolves as declared debt; M2 (one closure resolve per roots set)
ratchets back toward 1.

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

* Retire the M1/M2 labels from carriers (no-codename rule; collided with DESIGN's floor-memoization M1/M2)

Step renamed to 'Floor resolve receipt gate (declared cold-resolve count)';
notes and the gate echo now say what the things are: the counted
cold-resolve receipt, and the shared-resolve rewire (one closure resolve
per source-roots set). Naming-retirement note left on the carrier.

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

* WIP: Duplicate Computation/Materialization

* Run-step natures pinned as counted claims, not affordances

Operator ruling 2026-07-10: hardcoded shell scripts get no affordances
— run-steps are supposed to be modeled as typed intents and emitted
(shell-emission-model slice 4 covers ci_workflow RunSteps). Until that
slice lands, every nature in job_run_demands is a claim (rostered
FreshEffect / weakest-default IdempotentEffect), never derived from a
modeled effect row. Count the whole claimed-nature surface (16 by
execution) and pin it in the enrolled witness: a new raw-script step
must consciously bump the pin, and slice-4 migration becomes a
countable ratchet ending at zero, where the pin becomes a wall.
Rejected alternative recorded in the carrier note: a per-step
declared-natures roster (a second parallel ledger over scripts the
shell-emission plan already governs).

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

* Regen DESIGN.md after main merge (duplicate-work row + #6373 body-lowering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Inferred materialization increment 1: floor demand ledger + receipt-or-red gate

Running IS enrolling: the interpreter ledgers every keyed pure call and every
InterpContext absorbs its totals into a process accumulator on Drop — by
construction, no eval path escapes the receipt. claim_executor writes
target/floor-materialization-receipt.txt at walk end; trace defaults ON in
the executor, and an explicit =0 zeroes keyed_calls which the gate refuses.

Gate arms this push (all verified under dash from the emitted ci.yml):
receipt missing/malformed/keyed_calls=0 fail closed. Exact pins for
unkeyed_calls and duplicated_keys land from the FIRST CI receipt (the
resolve gate's measure-then-pin path) — unkeyed is known nonzero on the
floor (count_matching takes a predicate closure; closures are the one
disclosed identity-less class, dissolve-on captured-env content identity).

Unit witness green: resolve -> eval -> ctx Drop -> absorb -> drain-once.
Step addition bumped the claimed-natures pin 16 -> 17 consciously.

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

* Review fix: drop the racy drain-once assertion from the receipt unit test

opus-4-7 finding on #6441: under plain cargo test (still the documented
runner) tests share a process, the env latch is OnceLock-sticky, and
sibling ctx drops could absorb between the two takes — making the
drain-empty assertion racy. Absorb-on-Drop stays asserted (monotone under
concurrent absorbs: siblings only ADD); drain-once is Option::take by
construction, not asserted through the shared global. Comment states the
sharing semantics explicitly.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 10, 2026
… gated) (#6455)

* Inferred materialization increment 1: floor demand ledger + receipt gate (#6441)

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* Analysis spine: spine_receipt composes dependency_view + materialize (increment 1)

The Rc-safe half of run ≜ realize ∘ materialize ∘ dependency_view: compose
the two catamorphisms that need no interpreter thread-safety.

- src/v2/std/spine.dag: level-profile fold over the DependencyView DAG →
  critical_path_depth (longest dependency chain / the reduce spine) +
  independence_width (max nodes at one level / what parallelizes to hw width).
  spine_receipt emits the §9 numbers by COMPUTATION, not assertion, joining
  materialize's content-hash Share/dedup counts.
- Discriminating RED (§9): single chain A→B→C → depth 3 / width 1 (serial);
  root over N independent leaves → depth 2 / width N.
- Witnesses 9/9 (spine) green by execution; materialize 6/6 unchanged.

The RUNNER (wall-clock parallel execution, §8 steps 3-4) stays increment 2+,
gated on interpreter Rc→Arc (v1 interp is !Send). This increment measures the
achievable width/critical-path floor the runner targets; it does not fabricate
wall-clock N×.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Unbundle recompute-trace interpreter extension from the analysis-spine PR

CI root cause: the recompute-trace extension edited v1_interpreter.rs, which
hosts the atom_identity_hash/hash_combine fnv1a64 intrinsics that
dag_collect_fingerprint_witness executes. That correctly invalidated the
re-verify 'assumed-green node-frontier' SKIP of that witness (cone-touch,
fail-closed) — but the witness is a pre-existing 806s (13min) fnv1a64
whole-corpus walk, so un-skipping it blew the 30-min floor budget. Main stays
green only because its interpreter cone is untouched (witness stays skipped).

The interpreter extension is a separable, env-gated (GUNBC_RECOMPUTE_TRACE=1),
READ-mode diagnostic — not a dependency of the spine/materialize analysis
substrate (pure .dag, content_hash-based). Reverting v1_interpreter.rs to main
restores byte-identical interpreter content → the fingerprint witness returns to
assumed-green SKIP → floor budget restored. The recompute-trace extension lands
as its own follow-up PR where the fingerprint-witness re-run is expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Materialization ladder: the state x decision law, as executable witnesses

The operator's 4-rule business logic generalized on one axis: the decision is
a function of WHEN the redundancy is knowable and WHETHER what was knowable
was prepared for. Errors fire only on knowable-but-unprepared; genuine
emergence and declared triviality are typed acceptances, never silence.

std.materialization_ladder (dag/std):
- Frame/FrameKind: SharedStateFrame | IsolatedChildrenFrame |
  ReplayedFrame{attempts} | UnboundedSiblingsFrame — the nested-scope axis;
  a 'run' at any layer is a frame, never a different kind of thing.
- DemandNature: Pure | IdempotentEffect | WorldRead{envelope_declared} |
  FreshEffect — the D3 effect gate; TTL = unmodeled dependency XOR declared
  staleness, never an eviction knob.
- CacheProvider: keying (ContentKeyed|ExistenceKeyed) + EvictionPolicy
  (ScopeExit|SpacePacked) REQUIRED by construction — rule 3 unwritable-bad.
- LadderVerdict (total): AuthoredDuplication | Discharged | RefusedNoProvider
  | RefusedScopeTooNarrow | RefusedExistenceKeyed (the build-if-absent #6352
  wall) | RefusedUnmodeledWorldRead | ExemptFreshEffect |
  AcceptedBelowCostFloor | AcceptedSingleRecompute.
- Declared-emergent frames obligate UP FRONT: retry frames derive
  checkpointing, unbounded-sibling frames (server loops, CI-runs-over-time)
  derive persistent caches — prepare-before-demand.

12/12 witnesses green by execution; each test is one cell of the table,
fixtures mirror the live worked example (workflow/jobs/steps, retry, fleet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Docs crystallization: derived materialization placement into roadmap ④ + the state x decision table

- roadmap_authority ④ (ROADMAP.md regenerated via main_wet, drift-consistent):
  the nested-frame law, plurality cells, declared-emergent prepare-up-front,
  keying/staleness walls, the caching-completion un-shelve, the ①-vs-§2
  cross-run-caching contradiction subsumed into per-node derived verdicts,
  and the v1.compiler.ownership §3-convergence row.
- duplicate-work design doc: the state x decision table as the qualifier's
  final verdict logic + the ownership consolidation subsection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Consolidation plan: realization + materialization + ownership are one law

Operator synthesis (2026-07-09): Materialization = the verdict vocabulary;
ownership = the verdict computation at the eval frame; realization = provider
selection discharging the verdict at each frame's carrier. Share's handler is
layer-aware — the cheapest cache is a REFERENCE (same program + ref-capable
carrier + readonly => point-at-it, no copy, no destroyed memory), demoting
through HAMT structural share / process memo / artifact / CAS, and demotion
must be priced, never silent (#6249 clone-fallback is the receipt).

Census of every hand-rolled instance found in-tree (16 rows): each named with
its frame, ladder cell, action, and dissolution trigger — ownership
(consolidated), Rc/HAMT (reference tier), clone-fallback (demotion wall),
ParseTable + cached_stage (C5 grounding), M1 memo / intern / assumed-green /
sccache / cargo-cache (C2 provider rows), PROCESS_RESOLVE_STORE (C3 = the 9GB
scope fix), build-if-absent (landed as the keying wall), resolve-cache #5789
(rule-4 requirements), recompute-trace (state-4 finding source). Peers kept
distinct: affected-set, Independence/Placement, mutable state.

Sequence C1-C5 with C1 = this PR (ladder + live CI gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Ownership refactored onto materialization: the value tier, tested as providers

First consolidation increment (operator-directed): v1.compiler.ownership's
decision IS provider selection at the value grain, now expressed in the ladder
and proven by mirror witnesses.

- ProviderTier: Reference | Copy | Memo{keying} | Artifact{keying} | Cas{keying}
  — keying folded INTO store tiers, so an existence-keyed reference is
  unwritable BY SHAPE (§5 construction); frame obligations at isolation LCAs
  are dischargeable only by store tiers (a reference cannot cross an isolation
  boundary — witnessed).
- Value tier: AccessMode (Read|Consume|Carry|Project), ValueUsage,
  value_materialization -> ValueDead | ValueMoved | ValueSharedByReference |
  ValueDemotedToCopy (PRICED, requires a declared CopyTier provider — the
  #6249 silent clone-fallback made refusable) | ValueRefusedAffine |
  ValueRefusedNoCarrierProvider.
- Faithful to v1's THREE distinct plurality readings, kept separate:
  take_count = semantic_consumer_count (Consumed only, affine axis);
  value_access_plurality = binding_fan_out (Carry excluded, reference axis);
  borrow_count = whole_value_borrow_count (Read+Carry not Project, movability).
- Fold-accumulator case mirrored at conservative pre-FoldAccUnwrap semantics:
  carries excluded from plurality but blocking the move -> demoted-to-copy.

23/23 witnesses green (14 frame cells + 9 value cells). Corpus-level
equivalence against live v1 ownership folds = the C4 receipt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* WIP: Duplicate Computation/Materialization

* G: exhaustive cache/share census (52 mechanisms, 6 groups) + C0 catalog-grounding of provider rows + forward-wiring walls

The sweep found the tree already models caches: extdeps/cache cache_catalog
(CacheInterfaceCatalogFacts, 9 rows) + extdeps/realization carrier facts +
the warm==cold purity oracle. C0 grounds CacheProvider on that catalog
(provider_from_catalog projection; CacheProvider.id -> CacheInterfaceId)
so the ladder and the catalog never restate each other's half. Three
forward walls (demands-from-DependencyView, hand-cache shape lens,
live-provider-or-red) make new caches born as provider rows only.

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

* WIP: Duplicate Computation/Materialization

* C0: provider rows derive from the cited cache catalog (extdeps/cache/materialization.dag projection)

Operator ruling 2026-07-09: extdeps stays the ground-truth/interface layer;
every USE of a cache goes through materialization so memo never gets
re-invented. provider_from_catalog is the only door from a catalog row into
the ladder: keying/tier/eviction derived from cited facts (mechanism->class:
InProcess=>ScopeExit; Ttl/Lru/SizeBounded=>SpacePacked; Never/Manual outside
a process => typed ProjectionRefused, counted by the new enrolled witness;
HandAuthored/prefix-fallback keys => ExistenceKeyed until key-completeness
upgrades them). CI sccache row now derived, hand-typed tier facts deleted,
6/6 + 23/23 witnesses green. 10b re-scoped: v1-internal caches = inventory
only (retire with seed); ParseTable/cached_stage promoted to next.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Fail-closed hardening: RefusedNatureConflict arm, weakest-claim nature default, UsesStep silence counted, ladder cells enrolled in CI

The complexity-lens false-clean lesson applied to this gate before anyone
relies on it: (1) heterogeneous natures on one identity were first-wins —
now a typed RefusedNatureConflict (24th ladder cell, RED witness); (2) an
unrostered run-step claimed PureComputation — now IdempotentEffect, the
weakest claim (verdict-identical, no purity overclaim; a misdeclared
WorldRead can no longer be legally memoized by default); (3) UsesStep
foreign actions produced silence — now a pinned denominator (==9; a new
foreign action must consciously bump it); (4) the ladder's 24 cells enroll
on the CI surface so the law's own witnesses gate every run. 24/24 + 7/7.

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

* WIP: Duplicate Computation/Materialization

* M1 ratchet bump: declared resolve count 1 -> 3 (gate's first live catch — enrollment pays counted resolves)

Run 29058798771: enrolling the ladder witness file moved resolves_total
1 -> 3 (each enrolled entry file pays one closure resolve against the
shared index) and the receipt gate redded that exact run — the designed
semantics, receipted in the note. Bump acknowledges the two witness-entry
resolves as declared debt; M2 (one closure resolve per roots set)
ratchets back toward 1.

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

* Retire the M1/M2 labels from carriers (no-codename rule; collided with DESIGN's floor-memoization M1/M2)

Step renamed to 'Floor resolve receipt gate (declared cold-resolve count)';
notes and the gate echo now say what the things are: the counted
cold-resolve receipt, and the shared-resolve rewire (one closure resolve
per source-roots set). Naming-retirement note left on the carrier.

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

* WIP: Duplicate Computation/Materialization

* Run-step natures pinned as counted claims, not affordances

Operator ruling 2026-07-10: hardcoded shell scripts get no affordances
— run-steps are supposed to be modeled as typed intents and emitted
(shell-emission-model slice 4 covers ci_workflow RunSteps). Until that
slice lands, every nature in job_run_demands is a claim (rostered
FreshEffect / weakest-default IdempotentEffect), never derived from a
modeled effect row. Count the whole claimed-nature surface (16 by
execution) and pin it in the enrolled witness: a new raw-script step
must consciously bump the pin, and slice-4 migration becomes a
countable ratchet ending at zero, where the pin becomes a wall.
Rejected alternative recorded in the carrier note: a per-step
declared-natures roster (a second parallel ledger over scripts the
shell-emission plan already governs).

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

* Regen DESIGN.md after main merge (duplicate-work row + #6373 body-lowering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Inferred materialization increment 1: floor demand ledger + receipt-or-red gate

Running IS enrolling: the interpreter ledgers every keyed pure call and every
InterpContext absorbs its totals into a process accumulator on Drop — by
construction, no eval path escapes the receipt. claim_executor writes
target/floor-materialization-receipt.txt at walk end; trace defaults ON in
the executor, and an explicit =0 zeroes keyed_calls which the gate refuses.

Gate arms this push (all verified under dash from the emitted ci.yml):
receipt missing/malformed/keyed_calls=0 fail closed. Exact pins for
unkeyed_calls and duplicated_keys land from the FIRST CI receipt (the
resolve gate's measure-then-pin path) — unkeyed is known nonzero on the
floor (count_matching takes a predicate closure; closures are the one
disclosed identity-less class, dissolve-on captured-env content identity).

Unit witness green: resolve -> eval -> ctx Drop -> absorb -> drain-once.
Step addition bumped the claimed-natures pin 16 -> 17 consciously.

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

* Review fix: drop the racy drain-once assertion from the receipt unit test

opus-4-7 finding on #6441: under plain cargo test (still the documented
runner) tests share a process, the env latch is OnceLock-sticky, and
sibling ctx drops could absorb between the two takes — making the
drain-empty assertion racy. Absorb-on-Drop stays asserted (monotone under
concurrent absorbs: siblings only ADD); drain-once is Option::take by
construction, not asserted through the shared global. Comment states the
sharing semantics explicitly.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Turn on affected-set CI: re-land witness enrollment flip (discovery shrunk by affected set) + falsifier host-OOM receipt (#6438)

* WIP: Re-land affected-set CI enrollment flip once shard resolve footprint is

* WIP: Re-land affected-set CI enrollment flip once shard resolve footprint is

* Fix CI OOM: pin discovery corpus spawn_width_cap to 1.

Run 28999086030 OOM-killed at width=2 on the 24GiB live slot during the
discovery-flip corpus batch. Gate workloads still fit at width=2; only the
tree-wide discovery batch serializes via spawn_width_cap=1, with a receipt
witness and dissolve-on note.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix type error in corpus discovery spawn width cap helper.

Both if-branches must return Nat (hardware_thread_count_value), not a
bare Int literal.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Merge affected-set enrollment flip (takeover of PR #6403 from session/gentle-stag-677-flip)

Conflict resolutions onto post-#6422/#6431/#6432/#6435 main:
- ci_witness_optin_inversion: main's typed Scaffold Disposition -> Terminal (dissolve fired at the flip; roster stays as explicit-entry home, exclusivity dissolved)
- floor step timeout: 45 (main) vs 60 (flip) -> 60 with provenance note
- ci_spec notes: kept flip notes, stale fixed-8 phrasing dated
- falsifier width note: + RESIDUE paragraph (5x exit-137 on srv2-class slots = converge lane, not plan width)

Verified before commit: discovery batches charge corpus_resolve_nanos (own key), resolve_nanos=0 -> resolves_total declared 3 is NOT moved by the flip.

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

* WIP: affected set processing

* WIP: affected set processing

* WIP: affected set processing

* WIP: affected set processing

* Correct the false flip receipt + kill-surviving calibration receipts (space-lens loop)

CORRECTED RECEIPT: run 29000557166's floor never completed - the executor was
host-OOM-killed mid-discovery-corpus at ~8min; the log's ExitSuccess belongs to
the merge-admission stamp tool stamping CI_FLOOR_EXIT=137. No flipped corpus
has completed in CI (0/1 ci + 0/5 falsifier). Both carrier notes corrected.

Calibration (coordinated with merry-owl-649's space-lens lane):
- roster_import_closure_nodes_pre_resolve: shared closure-count authority
  (pure import walk, closure grain not entry grain), emitted BEFORE the heavy
  resolve so killed runs still yield the (nodes, peak) lower-bound pair
- width-1 definition-drift oracle: pre-resolve walk must equal post-resolve
  resolved union on completed runs; refuses on divergence. Proven by execution:
  pre == post == 190/213 nodes across Off/Applied modes
- kill-surviving cgroup memory.peak pre/post steps (post is always()) in the
  ci job and falsifier.yml; scope semantics labeled on the emission lines
  (reset=ok floor-scoped; span compares post>pre; never silently conflated)
- job backstop timeouts extended by the two aux steps in both jobs

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

* WIP: affected set processing

* Calibration pairs carry censored-vs-exact labels (methodology: killed runs are censored observations)

Floor steps get id=floor; the always() post-peak step emits floor_outcome so
each (closure_nodes, peak) pair is explicitly labeled: success = exact point,
anything else = censored lower bound (true demand strictly greater than read).
Prevents the fit from treating cap-kill reads as point estimates, which would
drag the slope down and make the predictor underestimate - the dangerous
direction (merry-owl methodology catch, 2026-07-10).

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

* WIP: affected set processing

* Review fixes: explicit witness import + complete step-budget ledger

- ci_floor_plan_witness_test.dag: import witness_ci_corpus_discovery_serializes_at_width_one
  explicitly (cursor catch on #6438). The call resolved pre-fix via the seed resolver's flat
  namespace, so the witness ran green by execution; the explicit import restores the file's
  per-symbol import convention.
- ci_workflow.dag: the resolve-receipt gate step had NO step cap — a hang there could only die
  by job-cancel (the #6323 starvation-kill class). It now carries the aux cap (script is a
  sub-second receipt read) and the ci job backstop counts four aux terms (peak pre/post,
  resolve-receipt gate, merge-admission gate): every step budgeted, backstop = step-sum + prelude
  (claude review catch on #6438, sharpened).
- falsifier_workflow_witness_test.dag: falsifier_backstop_is_step_sum_plus_prelude asserted the
  pre-calibration formula — latent red proven by execution (FAIL receipt), fixed to the live
  two-aux sum, re-run PASS.
- ci.yml regenerated byte-stable from the carrier (backstops 125->130, gate step timeout 5m).

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

* Rebind calibration provenance comments to real artifacts (cursor review catch)

The two cli_run.rs comments cited docs/plans/space-lens-minimal-project.md, which does
not exist on main — the predictor design is in flight on PR #6442 (merry-owl-649's lane)
and was never landed under that path. Rebound: the shared closure-definition authority is
stated as this function itself, with the in-flight design cited by PR number and the
landed parent-lane authorities cited by real paths (compute-envelope-model.md fleet
envelope; input-envelope-roadmap.md admission). No behavior change; cargo check clean.

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

* WIP: affected set processing

* Remove stray empty file (shell-redirect artifact the auto-committer flushed)

An internal-messaging command's backtick content was command-substituted by bash; a
'-> fail-closed' fragment became a stdout redirect and created an empty file at the
repo root, which the auto-committer then committed as 38f0a46. No tree content
beyond the empty file; removing it restores the branch to e99c757's content.

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

* WIP: affected set processing

* Scaffold-mark the cgroup peak calibration shell (cursor review catch)

The three concat-built calibration runners (ci_cgroup_peak_locate_shell,
ci_floor_peak_pre_script, ci_floor_peak_post_script) landed without the on-carrier
scaffold markers repo convention requires for hand-shell. Each now carries a
Disposition = Scaffold { dissolves_to: RealizationDispatch } row binding the decl
(the ci_materialization pattern), and both scripts embed the shared dissolve-on
note as a shell comment (the ci_spec pattern): dissolution = bash-emit (#5828 /
gap-B emit(intent, Bash)) realizing the observation as an emitted ShellProgram
intent or a typed host Observe effect. ci.yml + falsifier.yml regenerated;
falsifier_workflow_witness_holds and the flip witnesses re-run PASS.

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

* Merge origin/main into session/loyal-wren-398 (resolve #6441 step-list conflict)

Conflict resolution, all consciously declared:
- ci_job steps: union — the calibration peak pre/post steps wrap the floor step (this
  branch) and #6441's materialization receipt gate slots between the resolve-receipt
  gate and the merge-admission gate (main).
- The incoming materialization receipt gate step landed with timeout none — the same
  uncapped-step starvation-kill class this branch's review fix eliminated — so it now
  carries the aux cap, and the ci backstop counts FIVE aux terms (peak pre, peak post,
  resolve-receipt gate, materialization receipt gate, merge-admission gate); the budget
  disposition note records the merge provenance.
- ci_run_step_natures_are_claims_counted_not_silent: RunStep count pin bumped 17 -> 19,
  acknowledging the two peak calibration steps #6441's count predates (conscious-count
  discipline; proven red at 17 then green at 19 by execution).
- ci.yml regenerated from the merged carriers (backstops 130 -> 135).

Verified on the merged tree: release bins rebuilt on merged Rust; falsifier workflow
witness, flip witnesses, floor-plan/optin/width witnesses, and all 8 ci_materialization
witnesses PASS; generated-artifact regen ExitSuccess.

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

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* ShellProgram -> DAG: transport intent collapse + live importer ratchet (phase 0 of the sidecar dissolution) (#6449)

* WIP: ShellProgram -> DAG

* WIP: ShellProgram -> DAG

* WIP: ShellProgram -> DAG

* WIP: ShellProgram -> DAG

* WIP: ShellProgram -> DAG

* bash fold: native Concat/CmdSubst/WithRedir coverage + measured cost wall on the whole-tree emit path

Fold-family productions extended so the fold no longer refuses word
Concat/CmdSubst or stmt WithRedir (all four Redir variants): new
concat_parts/word-compound/with_redir production families, lex tokens,
kind-tag emit transforms, and recursive bundle arms. Byte-identity vs
serialize_bash proven by execution: five depth-2 oracle tests plus the
depth-4 assign_root_stmt manual probe (ROOT=$('git' 'rev-parse'
'--show-toplevel' 2>/dev/null || 'pwd') byte-exact). The delegated
fail-closed RED control repoints from WithRedir (now native) to Heredoc
(still delegated) so the boundary guard stays discriminating.

Measured cost wall, declared on-carrier (bash_program_emit_cost_wall_note):
whole-tree backward row-selection is ~alternatives^depth (1s flat stmt,
64s for the single depth-4 stmt, DNF >8min for the full witness_bin
program) because formal_production_unique_lhs_exact_match deep-validates
every candidate per level and the descent re-validates each level again.
Real-program oracles therefore stay MANUAL probes, not test fns (a
discovery-run test would hang the local floor); the probe note on the
test carrier names the dissolution triggers.

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

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* B1: NameResolutionPolicy row + position-tracked resolve (NamespaceOnlyY gated).

Add v2.std.resolution_policy (ImportScoped default | NamespaceOnlyY). Thread
ResolveContext { position, expected, policy } through resolve walk; namespace-only
skips import module bindings and uses symbol_index at position. Policy pilot
witness: green under NamespaceOnlyY at type position, RED under ImportScoped at
module position. Import-scoped global default unchanged — zero corpus churn.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Wave 1A - namespace-only name resolution: make the syntactic containment tree the single naming authority (qualified name = nesting position, reference = lexical lookup up ancestors, . = projection one level down). Path: confirm loyal-heron SymbolIndex scaling receipt FIRST, then SymbolIndex = conta (#6451)

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* v2.std.symbol_index: materialize containment tree as single naming authority

Add SymbolIndex fill from nesting (qualified path → Node), qualified-name
path algebra bridges, and discriminating witnesses. Retarget #6436 variant-
visibility scaffold to dissolve into symbol_index_lexical_lookup; harvest_unique
stays interim until module-scoped index scan lands.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* Fix rust fmt on qualified-name bridge host functions (CI rust_tests gate).

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* Remove symbol_index_has_path; tests match symbol_index_lookup directly

Dissolve Optional→Bool predicate in new std/ surface per review. Lexical
lookup root termination already uses qualified_name_is_empty (not dotted
string projection).

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* Address review: is_empty authority, host scaffold binds, layer split

- Remove qualified_name_is_empty; lexical lookup uses is_empty(xs: position)
- Host dispositions bind to from/to_dotted_string bridges; add P5 receipt tests
- Move extdeps-coupled fill to v2.compiler.symbol_index_fill (layer DAG fix)

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* Wire resolver through SymbolIndex; dissolve harvest_unique_disj interim.

Build SymbolIndex at admission and thread it through Namespace. resolve_atom
falls back to symbol_index_lexical_lookup for unbound atoms after import-scoped
lookup_chain. Fill-time unique-variant aliases (suffix-scan equivalent) replace
#6436 harvest_unique_disj. Equivalence witnesses prove SymbolIndex-alone covers
variant visibility (green + without-alias RED control); end-to-end wire green.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: Wave 1A - namespace-only name resolution: make the syntactic containment

* Drop unused ResolveContext.expected until expected-type lane lands.

Removes the dead field and uncalled resolve_ctx_with_expected helper
flagged in #6454 review 36717 — B1 uses position-only disambiguation;
expected-type filtering returns when that slice is scoped.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: gunbai-bot[bot] <289086189+gunbai-bot[bot]@users.noreply.github.com>
Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Brian Searls <11205878+briansrls@users.noreply.github.com>
briansrls added a commit that referenced this pull request Jul 11, 2026
…eipt-write refusal + counter invariant (#6456)

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* Analysis spine: spine_receipt composes dependency_view + materialize (increment 1)

The Rc-safe half of run ≜ realize ∘ materialize ∘ dependency_view: compose
the two catamorphisms that need no interpreter thread-safety.

- src/v2/std/spine.dag: level-profile fold over the DependencyView DAG →
  critical_path_depth (longest dependency chain / the reduce spine) +
  independence_width (max nodes at one level / what parallelizes to hw width).
  spine_receipt emits the §9 numbers by COMPUTATION, not assertion, joining
  materialize's content-hash Share/dedup counts.
- Discriminating RED (§9): single chain A→B→C → depth 3 / width 1 (serial);
  root over N independent leaves → depth 2 / width N.
- Witnesses 9/9 (spine) green by execution; materialize 6/6 unchanged.

The RUNNER (wall-clock parallel execution, §8 steps 3-4) stays increment 2+,
gated on interpreter Rc→Arc (v1 interp is !Send). This increment measures the
achievable width/critical-path floor the runner targets; it does not fabricate
wall-clock N×.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Unbundle recompute-trace interpreter extension from the analysis-spine PR

CI root cause: the recompute-trace extension edited v1_interpreter.rs, which
hosts the atom_identity_hash/hash_combine fnv1a64 intrinsics that
dag_collect_fingerprint_witness executes. That correctly invalidated the
re-verify 'assumed-green node-frontier' SKIP of that witness (cone-touch,
fail-closed) — but the witness is a pre-existing 806s (13min) fnv1a64
whole-corpus walk, so un-skipping it blew the 30-min floor budget. Main stays
green only because its interpreter cone is untouched (witness stays skipped).

The interpreter extension is a separable, env-gated (GUNBC_RECOMPUTE_TRACE=1),
READ-mode diagnostic — not a dependency of the spine/materialize analysis
substrate (pure .dag, content_hash-based). Reverting v1_interpreter.rs to main
restores byte-identical interpreter content → the fingerprint witness returns to
assumed-green SKIP → floor budget restored. The recompute-trace extension lands
as its own follow-up PR where the fingerprint-witness re-run is expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Materialization ladder: the state x decision law, as executable witnesses

The operator's 4-rule business logic generalized on one axis: the decision is
a function of WHEN the redundancy is knowable and WHETHER what was knowable
was prepared for. Errors fire only on knowable-but-unprepared; genuine
emergence and declared triviality are typed acceptances, never silence.

std.materialization_ladder (dag/std):
- Frame/FrameKind: SharedStateFrame | IsolatedChildrenFrame |
  ReplayedFrame{attempts} | UnboundedSiblingsFrame — the nested-scope axis;
  a 'run' at any layer is a frame, never a different kind of thing.
- DemandNature: Pure | IdempotentEffect | WorldRead{envelope_declared} |
  FreshEffect — the D3 effect gate; TTL = unmodeled dependency XOR declared
  staleness, never an eviction knob.
- CacheProvider: keying (ContentKeyed|ExistenceKeyed) + EvictionPolicy
  (ScopeExit|SpacePacked) REQUIRED by construction — rule 3 unwritable-bad.
- LadderVerdict (total): AuthoredDuplication | Discharged | RefusedNoProvider
  | RefusedScopeTooNarrow | RefusedExistenceKeyed (the build-if-absent #6352
  wall) | RefusedUnmodeledWorldRead | ExemptFreshEffect |
  AcceptedBelowCostFloor | AcceptedSingleRecompute.
- Declared-emergent frames obligate UP FRONT: retry frames derive
  checkpointing, unbounded-sibling frames (server loops, CI-runs-over-time)
  derive persistent caches — prepare-before-demand.

12/12 witnesses green by execution; each test is one cell of the table,
fixtures mirror the live worked example (workflow/jobs/steps, retry, fleet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Docs crystallization: derived materialization placement into roadmap ④ + the state x decision table

- roadmap_authority ④ (ROADMAP.md regenerated via main_wet, drift-consistent):
  the nested-frame law, plurality cells, declared-emergent prepare-up-front,
  keying/staleness walls, the caching-completion un-shelve, the ①-vs-§2
  cross-run-caching contradiction subsumed into per-node derived verdicts,
  and the v1.compiler.ownership §3-convergence row.
- duplicate-work design doc: the state x decision table as the qualifier's
  final verdict logic + the ownership consolidation subsection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Consolidation plan: realization + materialization + ownership are one law

Operator synthesis (2026-07-09): Materialization = the verdict vocabulary;
ownership = the verdict computation at the eval frame; realization = provider
selection discharging the verdict at each frame's carrier. Share's handler is
layer-aware — the cheapest cache is a REFERENCE (same program + ref-capable
carrier + readonly => point-at-it, no copy, no destroyed memory), demoting
through HAMT structural share / process memo / artifact / CAS, and demotion
must be priced, never silent (#6249 clone-fallback is the receipt).

Census of every hand-rolled instance found in-tree (16 rows): each named with
its frame, ladder cell, action, and dissolution trigger — ownership
(consolidated), Rc/HAMT (reference tier), clone-fallback (demotion wall),
ParseTable + cached_stage (C5 grounding), M1 memo / intern / assumed-green /
sccache / cargo-cache (C2 provider rows), PROCESS_RESOLVE_STORE (C3 = the 9GB
scope fix), build-if-absent (landed as the keying wall), resolve-cache #5789
(rule-4 requirements), recompute-trace (state-4 finding source). Peers kept
distinct: affected-set, Independence/Placement, mutable state.

Sequence C1-C5 with C1 = this PR (ladder + live CI gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Ownership refactored onto materialization: the value tier, tested as providers

First consolidation increment (operator-directed): v1.compiler.ownership's
decision IS provider selection at the value grain, now expressed in the ladder
and proven by mirror witnesses.

- ProviderTier: Reference | Copy | Memo{keying} | Artifact{keying} | Cas{keying}
  — keying folded INTO store tiers, so an existence-keyed reference is
  unwritable BY SHAPE (§5 construction); frame obligations at isolation LCAs
  are dischargeable only by store tiers (a reference cannot cross an isolation
  boundary — witnessed).
- Value tier: AccessMode (Read|Consume|Carry|Project), ValueUsage,
  value_materialization -> ValueDead | ValueMoved | ValueSharedByReference |
  ValueDemotedToCopy (PRICED, requires a declared CopyTier provider — the
  #6249 silent clone-fallback made refusable) | ValueRefusedAffine |
  ValueRefusedNoCarrierProvider.
- Faithful to v1's THREE distinct plurality readings, kept separate:
  take_count = semantic_consumer_count (Consumed only, affine axis);
  value_access_plurality = binding_fan_out (Carry excluded, reference axis);
  borrow_count = whole_value_borrow_count (Read+Carry not Project, movability).
- Fold-accumulator case mirrored at conservative pre-FoldAccUnwrap semantics:
  carries excluded from plurality but blocking the move -> demoted-to-copy.

23/23 witnesses green (14 frame cells + 9 value cells). Corpus-level
equivalence against live v1 ownership folds = the C4 receipt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* WIP: Duplicate Computation/Materialization

* G: exhaustive cache/share census (52 mechanisms, 6 groups) + C0 catalog-grounding of provider rows + forward-wiring walls

The sweep found the tree already models caches: extdeps/cache cache_catalog
(CacheInterfaceCatalogFacts, 9 rows) + extdeps/realization carrier facts +
the warm==cold purity oracle. C0 grounds CacheProvider on that catalog
(provider_from_catalog projection; CacheProvider.id -> CacheInterfaceId)
so the ladder and the catalog never restate each other's half. Three
forward walls (demands-from-DependencyView, hand-cache shape lens,
live-provider-or-red) make new caches born as provider rows only.

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

* WIP: Duplicate Computation/Materialization

* C0: provider rows derive from the cited cache catalog (extdeps/cache/materialization.dag projection)

Operator ruling 2026-07-09: extdeps stays the ground-truth/interface layer;
every USE of a cache goes through materialization so memo never gets
re-invented. provider_from_catalog is the only door from a catalog row into
the ladder: keying/tier/eviction derived from cited facts (mechanism->class:
InProcess=>ScopeExit; Ttl/Lru/SizeBounded=>SpacePacked; Never/Manual outside
a process => typed ProjectionRefused, counted by the new enrolled witness;
HandAuthored/prefix-fallback keys => ExistenceKeyed until key-completeness
upgrades them). CI sccache row now derived, hand-typed tier facts deleted,
6/6 + 23/23 witnesses green. 10b re-scoped: v1-internal caches = inventory
only (retire with seed); ParseTable/cached_stage promoted to next.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Fail-closed hardening: RefusedNatureConflict arm, weakest-claim nature default, UsesStep silence counted, ladder cells enrolled in CI

The complexity-lens false-clean lesson applied to this gate before anyone
relies on it: (1) heterogeneous natures on one identity were first-wins —
now a typed RefusedNatureConflict (24th ladder cell, RED witness); (2) an
unrostered run-step claimed PureComputation — now IdempotentEffect, the
weakest claim (verdict-identical, no purity overclaim; a misdeclared
WorldRead can no longer be legally memoized by default); (3) UsesStep
foreign actions produced silence — now a pinned denominator (==9; a new
foreign action must consciously bump it); (4) the ladder's 24 cells enroll
on the CI surface so the law's own witnesses gate every run. 24/24 + 7/7.

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

* WIP: Duplicate Computation/Materialization

* M1 ratchet bump: declared resolve count 1 -> 3 (gate's first live catch — enrollment pays counted resolves)

Run 29058798771: enrolling the ladder witness file moved resolves_total
1 -> 3 (each enrolled entry file pays one closure resolve against the
shared index) and the receipt gate redded that exact run — the designed
semantics, receipted in the note. Bump acknowledges the two witness-entry
resolves as declared debt; M2 (one closure resolve per roots set)
ratchets back toward 1.

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

* Retire the M1/M2 labels from carriers (no-codename rule; collided with DESIGN's floor-memoization M1/M2)

Step renamed to 'Floor resolve receipt gate (declared cold-resolve count)';
notes and the gate echo now say what the things are: the counted
cold-resolve receipt, and the shared-resolve rewire (one closure resolve
per source-roots set). Naming-retirement note left on the carrier.

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

* WIP: Duplicate Computation/Materialization

* Run-step natures pinned as counted claims, not affordances

Operator ruling 2026-07-10: hardcoded shell scripts get no affordances
— run-steps are supposed to be modeled as typed intents and emitted
(shell-emission-model slice 4 covers ci_workflow RunSteps). Until that
slice lands, every nature in job_run_demands is a claim (rostered
FreshEffect / weakest-default IdempotentEffect), never derived from a
modeled effect row. Count the whole claimed-nature surface (16 by
execution) and pin it in the enrolled witness: a new raw-script step
must consciously bump the pin, and slice-4 migration becomes a
countable ratchet ending at zero, where the pin becomes a wall.
Rejected alternative recorded in the carrier note: a per-step
declared-natures roster (a second parallel ledger over scripts the
shell-emission plan already governs).

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

* Regen DESIGN.md after main merge (duplicate-work row + #6373 body-lowering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Inferred materialization increment 1: floor demand ledger + receipt-or-red gate

Running IS enrolling: the interpreter ledgers every keyed pure call and every
InterpContext absorbs its totals into a process accumulator on Drop — by
construction, no eval path escapes the receipt. claim_executor writes
target/floor-materialization-receipt.txt at walk end; trace defaults ON in
the executor, and an explicit =0 zeroes keyed_calls which the gate refuses.

Gate arms this push (all verified under dash from the emitted ci.yml):
receipt missing/malformed/keyed_calls=0 fail closed. Exact pins for
unkeyed_calls and duplicated_keys land from the FIRST CI receipt (the
resolve gate's measure-then-pin path) — unkeyed is known nonzero on the
floor (count_matching takes a predicate closure; closures are the one
disclosed identity-less class, dissolve-on captured-env content identity).

Unit witness green: resolve -> eval -> ctx Drop -> absorb -> drain-once.
Step addition bumped the claimed-natures pin 16 -> 17 consciously.

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

* Review fix: drop the racy drain-once assertion from the receipt unit test

opus-4-7 finding on #6441: under plain cargo test (still the documented
runner) tests share a process, the env latch is OnceLock-sticky, and
sibling ctx drops could absorb between the two takes — making the
drain-empty assertion racy. Absorb-on-Drop stays asserted (monotone under
concurrent absorbs: siblings only ADD); drain-once is Option::take by
construction, not asserted through the shared global. Comment states the
sharing semantics explicitly.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 11, 2026
…ncident, argued serially with receipts) (#6469)

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* WIP: Duplicate Computation

* Analysis spine: spine_receipt composes dependency_view + materialize (increment 1)

The Rc-safe half of run ≜ realize ∘ materialize ∘ dependency_view: compose
the two catamorphisms that need no interpreter thread-safety.

- src/v2/std/spine.dag: level-profile fold over the DependencyView DAG →
  critical_path_depth (longest dependency chain / the reduce spine) +
  independence_width (max nodes at one level / what parallelizes to hw width).
  spine_receipt emits the §9 numbers by COMPUTATION, not assertion, joining
  materialize's content-hash Share/dedup counts.
- Discriminating RED (§9): single chain A→B→C → depth 3 / width 1 (serial);
  root over N independent leaves → depth 2 / width N.
- Witnesses 9/9 (spine) green by execution; materialize 6/6 unchanged.

The RUNNER (wall-clock parallel execution, §8 steps 3-4) stays increment 2+,
gated on interpreter Rc→Arc (v1 interp is !Send). This increment measures the
achievable width/critical-path floor the runner targets; it does not fabricate
wall-clock N×.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Unbundle recompute-trace interpreter extension from the analysis-spine PR

CI root cause: the recompute-trace extension edited v1_interpreter.rs, which
hosts the atom_identity_hash/hash_combine fnv1a64 intrinsics that
dag_collect_fingerprint_witness executes. That correctly invalidated the
re-verify 'assumed-green node-frontier' SKIP of that witness (cone-touch,
fail-closed) — but the witness is a pre-existing 806s (13min) fnv1a64
whole-corpus walk, so un-skipping it blew the 30-min floor budget. Main stays
green only because its interpreter cone is untouched (witness stays skipped).

The interpreter extension is a separable, env-gated (GUNBC_RECOMPUTE_TRACE=1),
READ-mode diagnostic — not a dependency of the spine/materialize analysis
substrate (pure .dag, content_hash-based). Reverting v1_interpreter.rs to main
restores byte-identical interpreter content → the fingerprint witness returns to
assumed-green SKIP → floor budget restored. The recompute-trace extension lands
as its own follow-up PR where the fingerprint-witness re-run is expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Materialization ladder: the state x decision law, as executable witnesses

The operator's 4-rule business logic generalized on one axis: the decision is
a function of WHEN the redundancy is knowable and WHETHER what was knowable
was prepared for. Errors fire only on knowable-but-unprepared; genuine
emergence and declared triviality are typed acceptances, never silence.

std.materialization_ladder (dag/std):
- Frame/FrameKind: SharedStateFrame | IsolatedChildrenFrame |
  ReplayedFrame{attempts} | UnboundedSiblingsFrame — the nested-scope axis;
  a 'run' at any layer is a frame, never a different kind of thing.
- DemandNature: Pure | IdempotentEffect | WorldRead{envelope_declared} |
  FreshEffect — the D3 effect gate; TTL = unmodeled dependency XOR declared
  staleness, never an eviction knob.
- CacheProvider: keying (ContentKeyed|ExistenceKeyed) + EvictionPolicy
  (ScopeExit|SpacePacked) REQUIRED by construction — rule 3 unwritable-bad.
- LadderVerdict (total): AuthoredDuplication | Discharged | RefusedNoProvider
  | RefusedScopeTooNarrow | RefusedExistenceKeyed (the build-if-absent #6352
  wall) | RefusedUnmodeledWorldRead | ExemptFreshEffect |
  AcceptedBelowCostFloor | AcceptedSingleRecompute.
- Declared-emergent frames obligate UP FRONT: retry frames derive
  checkpointing, unbounded-sibling frames (server loops, CI-runs-over-time)
  derive persistent caches — prepare-before-demand.

12/12 witnesses green by execution; each test is one cell of the table,
fixtures mirror the live worked example (workflow/jobs/steps, retry, fleet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Docs crystallization: derived materialization placement into roadmap ④ + the state x decision table

- roadmap_authority ④ (ROADMAP.md regenerated via main_wet, drift-consistent):
  the nested-frame law, plurality cells, declared-emergent prepare-up-front,
  keying/staleness walls, the caching-completion un-shelve, the ①-vs-§2
  cross-run-caching contradiction subsumed into per-node derived verdicts,
  and the v1.compiler.ownership §3-convergence row.
- duplicate-work design doc: the state x decision table as the qualifier's
  final verdict logic + the ownership consolidation subsection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Consolidation plan: realization + materialization + ownership are one law

Operator synthesis (2026-07-09): Materialization = the verdict vocabulary;
ownership = the verdict computation at the eval frame; realization = provider
selection discharging the verdict at each frame's carrier. Share's handler is
layer-aware — the cheapest cache is a REFERENCE (same program + ref-capable
carrier + readonly => point-at-it, no copy, no destroyed memory), demoting
through HAMT structural share / process memo / artifact / CAS, and demotion
must be priced, never silent (#6249 clone-fallback is the receipt).

Census of every hand-rolled instance found in-tree (16 rows): each named with
its frame, ladder cell, action, and dissolution trigger — ownership
(consolidated), Rc/HAMT (reference tier), clone-fallback (demotion wall),
ParseTable + cached_stage (C5 grounding), M1 memo / intern / assumed-green /
sccache / cargo-cache (C2 provider rows), PROCESS_RESOLVE_STORE (C3 = the 9GB
scope fix), build-if-absent (landed as the keying wall), resolve-cache #5789
(rule-4 requirements), recompute-trace (state-4 finding source). Peers kept
distinct: affected-set, Independence/Placement, mutable state.

Sequence C1-C5 with C1 = this PR (ladder + live CI gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* Ownership refactored onto materialization: the value tier, tested as providers

First consolidation increment (operator-directed): v1.compiler.ownership's
decision IS provider selection at the value grain, now expressed in the ladder
and proven by mirror witnesses.

- ProviderTier: Reference | Copy | Memo{keying} | Artifact{keying} | Cas{keying}
  — keying folded INTO store tiers, so an existence-keyed reference is
  unwritable BY SHAPE (§5 construction); frame obligations at isolation LCAs
  are dischargeable only by store tiers (a reference cannot cross an isolation
  boundary — witnessed).
- Value tier: AccessMode (Read|Consume|Carry|Project), ValueUsage,
  value_materialization -> ValueDead | ValueMoved | ValueSharedByReference |
  ValueDemotedToCopy (PRICED, requires a declared CopyTier provider — the
  #6249 silent clone-fallback made refusable) | ValueRefusedAffine |
  ValueRefusedNoCarrierProvider.
- Faithful to v1's THREE distinct plurality readings, kept separate:
  take_count = semantic_consumer_count (Consumed only, affine axis);
  value_access_plurality = binding_fan_out (Carry excluded, reference axis);
  borrow_count = whole_value_borrow_count (Read+Carry not Project, movability).
- Fold-accumulator case mirrored at conservative pre-FoldAccUnwrap semantics:
  carries excluded from plurality but blocking the move -> demoted-to-copy.

23/23 witnesses green (14 frame cells + 9 value cells). Corpus-level
equivalence against live v1 ownership folds = the C4 receipt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Duplicate Computation

* WIP: Duplicate Computation/Materialization

* G: exhaustive cache/share census (52 mechanisms, 6 groups) + C0 catalog-grounding of provider rows + forward-wiring walls

The sweep found the tree already models caches: extdeps/cache cache_catalog
(CacheInterfaceCatalogFacts, 9 rows) + extdeps/realization carrier facts +
the warm==cold purity oracle. C0 grounds CacheProvider on that catalog
(provider_from_catalog projection; CacheProvider.id -> CacheInterfaceId)
so the ladder and the catalog never restate each other's half. Three
forward walls (demands-from-DependencyView, hand-cache shape lens,
live-provider-or-red) make new caches born as provider rows only.

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

* WIP: Duplicate Computation/Materialization

* C0: provider rows derive from the cited cache catalog (extdeps/cache/materialization.dag projection)

Operator ruling 2026-07-09: extdeps stays the ground-truth/interface layer;
every USE of a cache goes through materialization so memo never gets
re-invented. provider_from_catalog is the only door from a catalog row into
the ladder: keying/tier/eviction derived from cited facts (mechanism->class:
InProcess=>ScopeExit; Ttl/Lru/SizeBounded=>SpacePacked; Never/Manual outside
a process => typed ProjectionRefused, counted by the new enrolled witness;
HandAuthored/prefix-fallback keys => ExistenceKeyed until key-completeness
upgrades them). CI sccache row now derived, hand-typed tier facts deleted,
6/6 + 23/23 witnesses green. 10b re-scoped: v1-internal caches = inventory
only (retire with seed); ParseTable/cached_stage promoted to next.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Fail-closed hardening: RefusedNatureConflict arm, weakest-claim nature default, UsesStep silence counted, ladder cells enrolled in CI

The complexity-lens false-clean lesson applied to this gate before anyone
relies on it: (1) heterogeneous natures on one identity were first-wins —
now a typed RefusedNatureConflict (24th ladder cell, RED witness); (2) an
unrostered run-step claimed PureComputation — now IdempotentEffect, the
weakest claim (verdict-identical, no purity overclaim; a misdeclared
WorldRead can no longer be legally memoized by default); (3) UsesStep
foreign actions produced silence — now a pinned denominator (==9; a new
foreign action must consciously bump it); (4) the ladder's 24 cells enroll
on the CI surface so the law's own witnesses gate every run. 24/24 + 7/7.

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

* WIP: Duplicate Computation/Materialization

* M1 ratchet bump: declared resolve count 1 -> 3 (gate's first live catch — enrollment pays counted resolves)

Run 29058798771: enrolling the ladder witness file moved resolves_total
1 -> 3 (each enrolled entry file pays one closure resolve against the
shared index) and the receipt gate redded that exact run — the designed
semantics, receipted in the note. Bump acknowledges the two witness-entry
resolves as declared debt; M2 (one closure resolve per roots set)
ratchets back toward 1.

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

* Retire the M1/M2 labels from carriers (no-codename rule; collided with DESIGN's floor-memoization M1/M2)

Step renamed to 'Floor resolve receipt gate (declared cold-resolve count)';
notes and the gate echo now say what the things are: the counted
cold-resolve receipt, and the shared-resolve rewire (one closure resolve
per source-roots set). Naming-retirement note left on the carrier.

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

* WIP: Duplicate Computation/Materialization

* Run-step natures pinned as counted claims, not affordances

Operator ruling 2026-07-10: hardcoded shell scripts get no affordances
— run-steps are supposed to be modeled as typed intents and emitted
(shell-emission-model slice 4 covers ci_workflow RunSteps). Until that
slice lands, every nature in job_run_demands is a claim (rostered
FreshEffect / weakest-default IdempotentEffect), never derived from a
modeled effect row. Count the whole claimed-nature surface (16 by
execution) and pin it in the enrolled witness: a new raw-script step
must consciously bump the pin, and slice-4 migration becomes a
countable ratchet ending at zero, where the pin becomes a wall.
Rejected alternative recorded in the carrier note: a per-step
declared-natures roster (a second parallel ledger over scripts the
shell-emission plan already governs).

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

* Regen DESIGN.md after main merge (duplicate-work row + #6373 body-lowering row coexist)

Conflict was both sides editing the open-threads list in design_document.dag:
ours added the duplicate-work thread, main's #6373 rewrote body-lowering to
Stages 1-3 LANDED. Resolution keeps both rows in the .dag authority; DESIGN.md
regenerated from it, never hand-edited.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* Inferred materialization increment 1: floor demand ledger + receipt-or-red gate

Running IS enrolling: the interpreter ledgers every keyed pure call and every
InterpContext absorbs its totals into a process accumulator on Drop — by
construction, no eval path escapes the receipt. claim_executor writes
target/floor-materialization-receipt.txt at walk end; trace defaults ON in
the executor, and an explicit =0 zeroes keyed_calls which the gate refuses.

Gate arms this push (all verified under dash from the emitted ci.yml):
receipt missing/malformed/keyed_calls=0 fail closed. Exact pins for
unkeyed_calls and duplicated_keys land from the FIRST CI receipt (the
resolve gate's measure-then-pin path) — unkeyed is known nonzero on the
floor (count_matching takes a predicate closure; closures are the one
disclosed identity-less class, dissolve-on captured-env content identity).

Unit witness green: resolve -> eval -> ctx Drop -> absorb -> drain-once.
Step addition bumped the claimed-natures pin 16 -> 17 consciously.

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

* Review fix: drop the racy drain-once assertion from the receipt unit test

opus-4-7 finding on #6441: under plain cargo test (still the documented
runner) tests share a process, the env latch is OnceLock-sticky, and
sibling ctx drops could absorb between the two takes — making the
drain-empty assertion racy. Absorb-on-Drop stays asserted (monotone under
concurrent absorbs: siblings only ADD); drain-once is Option::take by
construction, not asserted through the shared global. Comment states the
sharing semantics explicitly.

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

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

* WIP: Duplicate Computation/Materialization

---------

Co-authored-by: Brian Searls <briansrls@gunb.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Brian Searls <11205878+briansrls@users.noreply.github.com>
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.

2 participants