Repository navigation
Sweep dead prose data-String rows (comments smuggled in strings): 215 rows across ~130 files - #6424
Conversation
…erence v1 modules / deliberately-broken fixtures outside the per-PR frontier's root set, so any diff touch makes frontier population fail Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… carrier (cursor review on #6424) The deleted prose rows at these sites were the only on-carrier marks for live scaffolds. Per the review, re-homed as typed rows instead of prose: money-measure grounding scaffolds in card_intake / tcgplayer pricing / tcgplayer store (Scaffold dissolves_to SingleAuthority, bound to the bare-Float decls), deploy_access_preflight hand-shell (Scaffold dissolves_to RealizationDispatch), vocab narrowing_reason_same_variant hand-rolled tag-equality (Scaffold dissolves_to SingleAuthority), and the reconcile_grounded caller obligation as Disposition Terminal (named irreducible residue). All six files entry-probe clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Re: cursor/composer-2.5 REQUEST_CHANGES (review 36540) — all five findings addressed in d4ce97e (+2945177556), taking the review's own suggested shape: the still-live scaffolds keep their marks, re-homed onto the typed
The prose deletions at those sites stay deleted, per the review's "re-home the gates that still apply, then re-delete the duplicate prose rows". All six files entry-probe clean ( — sent from smart-boar-596 |
…or round 2 on #6424) deploy_target_host_preflight_block and merge_admission stamp/gate scripts get Scaffold rows binding the shared live_deploy_emit_shell_dissolution_trigger authority (the fleet_show_effective_read idiom the review points at). Full audit of all 67 deleted dissolve-marks against the medium-structure roster: host_identity adopt/converge/observation, fleet_show, and seam_transport were ALREADY covered by surviving typed *_scaffold rows (the deleted prose was duplicate representation); the only uncovered rostered emitter was live_deploy/emit itself (emit_sudo_wrapped_script_body — now typed), plus ci_workflow step-timeout value-Measure grounding (same mechanical family as the tcgplayer money rows — now typed). All four files entry-probe clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Re: cursor round 2 (review 36543) — both findings valid, fixed in a2be14c (+c973b67a20):
Also pre-empted round 3 with a full audit of all 67 deleted dissolve-marks against — sent from smart-boar-596 |
…dispatch_tmux trigger Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#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>
…ow-on to #6424) (#6428) * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * Revert note deletions under src/v2/test/manual - manual witnesses reference v1 modules / deliberately-broken fixtures outside the per-PR frontier's root set, so any diff touch makes frontier population fail Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * Re-home the five still-live scaffold marks onto the typed Disposition carrier (cursor review on #6424) The deleted prose rows at these sites were the only on-carrier marks for live scaffolds. Per the review, re-homed as typed rows instead of prose: money-measure grounding scaffolds in card_intake / tcgplayer pricing / tcgplayer store (Scaffold dissolves_to SingleAuthority, bound to the bare-Float decls), deploy_access_preflight hand-shell (Scaffold dissolves_to RealizationDispatch), vocab narrowing_reason_same_variant hand-rolled tag-equality (Scaffold dissolves_to SingleAuthority), and the reconcile_grounded caller obligation as Disposition Terminal (named irreducible residue). All six files entry-probe clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: get rid of all of these in code strings * Re-home remaining live-scaffold marks as typed Disposition rows (cursor round 2 on #6424) deploy_target_host_preflight_block and merge_admission stamp/gate scripts get Scaffold rows binding the shared live_deploy_emit_shell_dissolution_trigger authority (the fleet_show_effective_read idiom the review points at). Full audit of all 67 deleted dissolve-marks against the medium-structure roster: host_identity adopt/converge/observation, fleet_show, and seam_transport were ALREADY covered by surviving typed *_scaffold rows (the deleted prose was duplicate representation); the only uncovered rostered emitter was live_deploy/emit itself (emit_sudo_wrapped_script_body — now typed), plus ci_workflow step-timeout value-Measure grounding (same mechanical family as the tcgplayer money rows — now typed). All four files entry-probe clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…aim-bin cwd fix (#6373) * complexity foundation only: loop typing + measure-derived termination + 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 * M1+fold-lowering: the un-forked forward fold->Loop desugaring, first 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 * grammar: general expression ident head stamps its lexeme, not the token 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 * M2 verification: fold callee name survives parse on real source 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 * M2: fold->Loop desugaring reads the real surface fold-call shape 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 * M3: distill a real fold body into R1's fold-step subject; catch a real 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 * Challenge R1 against real corpus shapes: coverage boundary + per-cause 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 * Kill the R1 bridge: linear fold over Node, no intermediate subject 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 * Complete the StampLexeme binding-side migration: fn params scope for 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> * WIP: complexity * WIP: complexity * Accumulator-copy lens: invert verdict polarity to prove-safe-or-refuse — 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> * Stage-0 design: general body producer — forward reading of the grammar rows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Register general-body-producer milestone in DESIGN.md open threads (body-lowering Stages 1-3 landed) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Resolve merge: old r1 lens file stays deleted (renamed in-branch); port #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> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Brian Searls <briansearls1@gmail.com>
…versions, duplicate removals
- 25 seed-realized prose rows deleted BILATERALLY: the .dag data row AND its generated stage0 pub fn (all had zero callers on both sides; cargo check + nextest green). Files: src/v1/{04_env,04_infer,04_resolve,05_emit_rust,dag_collect,dag_collect_support}.dag + dag/std/{algebra,computation,measure,realization_schedule}.dag and their std_*/v1_compiler_* seed realizations.
- 6 more rows converted to typed Disposition Scaffold: ci_witness_optin_inversion, export_signature_facts_host_scaffold_dissolution_trigger (+ firewall-test grader), interface_summary_v0_dissolution_trigger, host_kernel_relu_mul_add_op_codes_scaffold_note, and the hand_lens_host_bridge scaffold-index pair (watchdog field String -> Disposition, predicates typed).
- 2 duplicates deleted: tailscale_acl_phase2_design_status (typed live-write disposition already existed; witness greps dropped).
- 5 dead notes deleted in frontier-resolvable src/v2/test/manual files.
- BLOCKED (1): rust_literal_emit_string_refusal_note stays prose - importing std.disposition into its closure trips the variant-name collision wall (Terminal in both GrammarExpr and Disposition), the exact cross-tree duplicate-name hazard the forensics_6280 report flagged. Unblocks when that name fork is resolved.
Verified: all diff files entry-probe clean (src/v1 files excluded - outside frontier roots, proven by #6424); watchdog/tailscale/firewall witnesses green by execution; seed cargo check + nextest green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sposition conversions (#6431) * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * Revert note deletions under src/v2/test/manual - manual witnesses reference v1 modules / deliberately-broken fixtures outside the per-PR frontier's root set, so any diff touch makes frontier population fail Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * Re-home the five still-live scaffold marks onto the typed Disposition carrier (cursor review on #6424) The deleted prose rows at these sites were the only on-carrier marks for live scaffolds. Per the review, re-homed as typed rows instead of prose: money-measure grounding scaffolds in card_intake / tcgplayer pricing / tcgplayer store (Scaffold dissolves_to SingleAuthority, bound to the bare-Float decls), deploy_access_preflight hand-shell (Scaffold dissolves_to RealizationDispatch), vocab narrowing_reason_same_variant hand-rolled tag-equality (Scaffold dissolves_to SingleAuthority), and the reconcile_grounded caller obligation as Disposition Terminal (named irreducible residue). All six files entry-probe clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: get rid of all of these in code strings * Re-home remaining live-scaffold marks as typed Disposition rows (cursor round 2 on #6424) deploy_target_host_preflight_block and merge_admission stamp/gate scripts get Scaffold rows binding the shared live_deploy_emit_shell_dissolution_trigger authority (the fleet_show_effective_read idiom the review points at). Full audit of all 67 deleted dissolve-marks against the medium-structure roster: host_identity adopt/converge/observation, fleet_show, and seam_transport were ALREADY covered by surviving typed *_scaffold rows (the deleted prose was duplicate representation); the only uncovered rostered emitter was live_deploy/emit itself (emit_sudo_wrapped_script_body — now typed), plus ci_workflow step-timeout value-Measure grounding (same mechanical family as the tcgplayer money rows — now typed). All four files entry-probe clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * WIP: get rid of all of these in code strings * Clean remaining prose-comment rows: bilateral seed deletes, typed conversions, duplicate removals - 25 seed-realized prose rows deleted BILATERALLY: the .dag data row AND its generated stage0 pub fn (all had zero callers on both sides; cargo check + nextest green). Files: src/v1/{04_env,04_infer,04_resolve,05_emit_rust,dag_collect,dag_collect_support}.dag + dag/std/{algebra,computation,measure,realization_schedule}.dag and their std_*/v1_compiler_* seed realizations. - 6 more rows converted to typed Disposition Scaffold: ci_witness_optin_inversion, export_signature_facts_host_scaffold_dissolution_trigger (+ firewall-test grader), interface_summary_v0_dissolution_trigger, host_kernel_relu_mul_add_op_codes_scaffold_note, and the hand_lens_host_bridge scaffold-index pair (watchdog field String -> Disposition, predicates typed). - 2 duplicates deleted: tailscale_acl_phase2_design_status (typed live-write disposition already existed; witness greps dropped). - 5 dead notes deleted in frontier-resolvable src/v2/test/manual files. - BLOCKED (1): rust_literal_emit_string_refusal_note stays prose - importing std.disposition into its closure trips the variant-name collision wall (Terminal in both GrammarExpr and Disposition), the exact cross-tree duplicate-name hazard the forensics_6280 report flagged. Unblocks when that name fork is resolved. Verified: all diff files entry-probe clean (src/v1 files excluded - outside frontier roots, proven by #6424); watchdog/tailscale/firewall witnesses green by execution; seed cargo check + nextest green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…w-value prose Banning // made comment syntax unwritable but not commentary unwritable. It removed the only structural signal separating commentary from program data, so the corpus smuggled prose into data String rows where intent is mechanically undecidable. Verified as three merged PRs: #5579 f9cc238 remove DAG comment trivia rules #6262 9e7c3c1 hoist .dag // comments to typed data rows #6424 c14e001 sweep 215 dead prose data-String rows Reframes the destination as a modeled source annotation -- a sidecar on ParseArtifact, never restored trivia, never a namespace binding -- with the semantic/authored-source projection pair as the load-bearing law. Corrects the sample's standing: #6424 swept 215 dead rows before it was drawn, so it measures survivors and cannot refute the dead population or settle representation. Value and representation are independent axes: a note can be irreducible and still wrong as data Foo: String. Replaces D1-D4 (delete rate, ceilings) with D-A..D-D (carrier, attachment, erasure, migration). Carries the proposed DESIGN paragraph for review without landing it. Nothing deleted, migrated, or reconciled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…urce data (audit complete, D-A..D-D ruled) (#7797) * WIP: prose cleanup * Add the reconciliation worklist section to the prose policy audit Where a split pass would start: 50% of the time-bound marker mass sits in 63 of 617 files, and 124 mega-notes carry a marker between them. Names the two head files that are load-bearing per DESIGN so they do not lead the pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Recut the prose audit: the defect is lost source-level intent, not low-value prose Banning // made comment syntax unwritable but not commentary unwritable. It removed the only structural signal separating commentary from program data, so the corpus smuggled prose into data String rows where intent is mechanically undecidable. Verified as three merged PRs: #5579 f9cc238 remove DAG comment trivia rules #6262 9e7c3c1 hoist .dag // comments to typed data rows #6424 c14e001 sweep 215 dead prose data-String rows Reframes the destination as a modeled source annotation -- a sidecar on ParseArtifact, never restored trivia, never a namespace binding -- with the semantic/authored-source projection pair as the load-bearing law. Corrects the sample's standing: #6424 swept 215 dead rows before it was drawn, so it measures survivors and cannot refute the dead population or settle representation. Value and representation are independent axes: a note can be irreducible and still wrong as data Foo: String. Replaces D1-D4 (delete rate, ceilings) with D-A..D-D (carrier, attachment, erasure, migration). Carries the proposed DESIGN paragraph for review without landing it. Nothing deleted, migrated, or reconciled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * chore: regenerate drifted generated artifacts (ci auto-heal) * Land the source-annotation policy in DESIGN.md 4c; rule D-A..D-D Canonical guidance lands through gunbc.design_document section_4c_blocks with DESIGN.md regenerated, never hand-edited. The rule: prose is not forbidden; unclassified prose is. // becomes the explicit quarantine boundary. Four structural corrections to the destination: 2a a THIRD lexical channel (AnnotationRule), not an ordinary TokenRule -- a token still joins the semantic stream and buys parser filtering, token-order effects, allocator risk 2b AuthoredParseArtifact WRAPS the semantic artifact rather than widening it, so ordinary compilation receives a type that cannot hold annotations; erasure becomes structural. The equality law is over the semantic graph projection, excluding textual provenance, because inserting a comment necessarily moves byte ranges 2c an annotation must NOT consume a semantic OccurrenceId -- the allocator is graph-scoped, so a comment could shift declaration identities in the same source and in later modules. First carrier has no annotation identity; ordered graph carries multiplicity 2e attachment narrows to module-item grain only, with an explicit AnnotationPlacement observation so trailing stays distinguishable after whitespace removal D-D approved debt-only: SourceAnnotationRationale is not declared in Slice 1, since a variant with no authoring path or consumer is speculative vocabulary. Doc-graph row rebinds from the generic StandingIntent to the seams this work actually changes: LexRule, ParseArtifact, dag_line_comment_fidelity, dag_comment_wall_line_comment_refused. Nothing deleted, migrated, or reconciled; no slice started. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Align the doc-graph dissolution trigger with the ruled D-A/D-C design review 48112 (cursor/composer-2.5) caught the trigger naming TokenRule as the target carrier -- the design D-A explicitly rejects. The trigger was authored before the operator's correction and not updated with the audit doc and DESIGN 4c, so a typed scaffold marker was steering Slice 2 at the wrong carrier. Fixes a second stale claim in the same string the review did not reach: "semantic-erasure proven by identical emitted bytes". Byte equality is exactly what D-C says is insufficient -- the emitter may ignore occurrence ids and stay byte-identical while the identity graph moves. The trigger now names the seven D-C proofs instead. Trigger now states: AnnotationRule on a third lexical channel (never TriviaRule, never TokenRule), authored wrapper over an unchanged semantic artifact, no semantic occurrence identity consumed, module-item attachment with trailing/body/unattached/block refusing, erasure by the seven D-C proofs, and the representation partition complete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
…rasure (#7807) * WIP: prose cleanup * Add the reconciliation worklist section to the prose policy audit Where a split pass would start: 50% of the time-bound marker mass sits in 63 of 617 files, and 124 mega-notes carry a marker between them. Names the two head files that are load-bearing per DESIGN so they do not lead the pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Recut the prose audit: the defect is lost source-level intent, not low-value prose Banning // made comment syntax unwritable but not commentary unwritable. It removed the only structural signal separating commentary from program data, so the corpus smuggled prose into data String rows where intent is mechanically undecidable. Verified as three merged PRs: #5579 f9cc238 remove DAG comment trivia rules #6262 9e7c3c1 hoist .dag // comments to typed data rows #6424 c14e001 sweep 215 dead prose data-String rows Reframes the destination as a modeled source annotation -- a sidecar on ParseArtifact, never restored trivia, never a namespace binding -- with the semantic/authored-source projection pair as the load-bearing law. Corrects the sample's standing: #6424 swept 215 dead rows before it was drawn, so it measures survivors and cannot refute the dead population or settle representation. Value and representation are independent axes: a note can be irreducible and still wrong as data Foo: String. Replaces D1-D4 (delete rate, ceilings) with D-A..D-D (carrier, attachment, erasure, migration). Carries the proposed DESIGN paragraph for review without landing it. Nothing deleted, migrated, or reconciled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * chore: regenerate drifted generated artifacts (ci auto-heal) * Land the source-annotation policy in DESIGN.md 4c; rule D-A..D-D Canonical guidance lands through gunbc.design_document section_4c_blocks with DESIGN.md regenerated, never hand-edited. The rule: prose is not forbidden; unclassified prose is. // becomes the explicit quarantine boundary. Four structural corrections to the destination: 2a a THIRD lexical channel (AnnotationRule), not an ordinary TokenRule -- a token still joins the semantic stream and buys parser filtering, token-order effects, allocator risk 2b AuthoredParseArtifact WRAPS the semantic artifact rather than widening it, so ordinary compilation receives a type that cannot hold annotations; erasure becomes structural. The equality law is over the semantic graph projection, excluding textual provenance, because inserting a comment necessarily moves byte ranges 2c an annotation must NOT consume a semantic OccurrenceId -- the allocator is graph-scoped, so a comment could shift declaration identities in the same source and in later modules. First carrier has no annotation identity; ordered graph carries multiplicity 2e attachment narrows to module-item grain only, with an explicit AnnotationPlacement observation so trailing stays distinguishable after whitespace removal D-D approved debt-only: SourceAnnotationRationale is not declared in Slice 1, since a variant with no authoring path or consumer is speculative vocabulary. Doc-graph row rebinds from the generic StandingIntent to the seams this work actually changes: LexRule, ParseArtifact, dag_line_comment_fidelity, dag_comment_wall_line_comment_refused. Nothing deleted, migrated, or reconciled; no slice started. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Align the doc-graph dissolution trigger with the ruled D-A/D-C design review 48112 (cursor/composer-2.5) caught the trigger naming TokenRule as the target carrier -- the design D-A explicitly rejects. The trigger was authored before the operator's correction and not updated with the audit doc and DESIGN 4c, so a typed scaffold marker was steering Slice 2 at the wrong carrier. Fixes a second stale claim in the same string the review did not reach: "semantic-erasure proven by identical emitted bytes". Byte equality is exactly what D-C says is insufficient -- the emitter may ignore occurrence ids and stay byte-identical while the identity graph moves. The trigger now names the seven D-C proofs instead. Trigger now states: AnnotationRule on a third lexical channel (never TriviaRule, never TokenRule), authored wrapper over an unchanged semantic artifact, no semantic occurrence identity consumed, module-item attachment with trailing/body/unattached/block refusing, erasure by the seven D-C proofs, and the representation partition complete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * M1 slice 1: AnnotationRule third lexical channel, captured with placement DESIGN 4c requires a comment to reach neither destination the lexer already has. TriviaRule consumes and emits nothing, so a comment routed there is invisible to every parser, lens, census and SCM operation. TokenRule emits into the semantic stream, so a comment routed there becomes something every parser must filter and sits in the path of occurrence allocation. This adds the third: LexRule = TokenRule | TriviaRule | AnnotationRule plus UnboundSourceAnnotation (no identity of its own -- binding is the parser's job, and minting one here would draw from the semantic occurrence allocator, which 4c forbids), AnnotationPlacement, and LexArtifact { tokens, annotations }. lex_walk_artifact is the authored result; lex_walk is its semantic projection and is what every existing caller keeps using. One traversal read two ways, derived in that direction only, so a semantic consumer cannot reach annotation text. Placement is observed at capture because it cannot be reconstructed: whitespace is trivia, so once it is gone a trailing comment and a leading comment on the next declaration are indistinguishable. The walk tracks line_has_semantic_token -- set by a token, reset by trivia carrying a line feed. Adding the variant redded six matches across three files; each got a real arm rather than a wildcard, which is the closed-coproduct discipline working as intended. Green by execution: lex_match_thunk_claims_holds, and all seven dag_comment_wall_test probes still pass -- line comments in real .dag source still REFUSE, because the v1 production tokenizer is untouched until the realization slice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * M1 slice 2: one std authority for source annotations, not a v1/v2 fork Correcting slice 1: AnnotationPlacement was declared inside v2.std.compilers.lexing, and the v1 seed tokenizer cannot import v2 modules -- so realizing the v1 half would have forced a second spelling of one concept. That is precisely the nicknaming defect this lane exists to remove, and it would have been minted BY the lane removing it. dag/std/source_annotation.dag is now the language-agnostic authority. It names no .dag syntax and no lexical rule; both seeds import it. v1 files already import std.* (std.types, std.occurrence_identity), so the seam exists. Carries AnnotationPlacement, SourceAnnotationDebt, SourceAnnotationGraph (ordered -- order and multiplicity are the whole of an annotation's identity when rows carry no key), the typed attachment refusals, and annotation_placement_is_attachable as the single predicate saying the first cut admits leading only. SourceAnnotationDebt deliberately has NO identity field. An OccurrenceId would draw from the graph-scoped semantic allocator, so inserting a comment could shift declaration identities later in the same source and in later-parsed modules. `subject` refers; it never mints. Debt is the type's standing law rather than a variant, so no rationale category ships without an authoring path or consumer. v2.std.compilers.lexing keeps only what is lexical and imports the rest. Green: lex_match_thunk_claims_holds and the comment wall probes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * chore: regenerate drifted generated artifacts (ci auto-heal) * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * chore: regenerate drifted generated artifacts (ci auto-heal) * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * Thread authored artifact through both v1 frontend paths; five D-C erasure controls Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: regenerate drifted generated artifacts (ci auto-heal) * Physical-line placement, admission wall, single frontend seam Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * Regen stage0: emit annotation channel into the seed; fix import + portability defects regen exposed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * Restore roster rows dropped by generated-file merge; place std.source_annotation in the stage0 crate partition Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * Rename LATER-cased witness: emitted Rust must be snake_case under -D warnings Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: regenerate drifted generated artifacts (ci auto-heal) * WIP: prose cleanup * WIP: prose cleanup * P0-1 blank lines split authored blocks; P0-2 lower the claim to its honest rung Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * chore: regenerate drifted generated artifacts (ci auto-heal) * D-C property 4: establish semantic erasure at the emitted-bytes boundary The two byte-equality arms could not be enrolled as .dag witnesses, so they were established by host execution and the measurement recorded in-carrier rather than dropped. Measured: annotated and bare twins emit byte-identical Rust across all six emitted files (exit 0, zero diagnostics), while a real semantic change to the same bare twin emits different bytes -- so the equality is not a statement about an emitter that ignores its input. The enrolled arm proves the annotated fixture really carried prose (2 rows) where its twin carried none. Why not enrolled: no .dag-reachable surface returns emitted bytes. compile_to_resolved from interpreted .dag raises `map_keys expects a map, got Record` in the RESOLVE half -- reproduced on the smallest possible input, so it is a pre-existing model-versus-realization fork outside this lane, not a property of the fixture. The working host arms return a Bool and a diagnostic census; asserting "both twins compile" through the Bool would wear this property's name while passing for any pair of compiling programs, and adding a bytes-returning arm would grow hand-maintained cli_run.rs against its hollowing plan to satisfy a witness. Next trigger named in the carrier. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * WIP: prose cleanup * WIP: prose cleanup * WIP: prose cleanup * Regenerate ci.yml for the new stage0 witness module Derived-only: the heal exclude list gains v1_tests_claim_v1_annotation_target_emission_test.rs, projected from the same stage0 emit roster that regen writes. Committed as author because workflow paths cannot auto-heal (the App lacks workflows:write). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Regenerate v1_std_core.rs after merging main's function-value call wall The merge resolved this GENERATED file by taking this branch's copy, which carries SourceAnnotationRefused but not main's CallNamedArgOnFunctionValue (#7834) — so the enum lost a variant that main's hand-maintained cli_run.rs and the generated infer projection both construct, and the workspace stopped compiling. Regenerated rather than hand-merged: a generated file's authority is its .dag source, and hand-picking hunks across a merge is how rows go missing silently. Both variants are present and the emission is stable across generations. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
…sanctions Both review findings verified against the code and both are correct. QUADRATIC FOLD. measurement_run_causes folded over samples while measurement_sample_causes filtered the whole sample list twice per sample - once for duplicate detection, once for parent presence - and measurement_expected_span_causes filtered it once per expected span. Occurrence count, duplicate, parent presence and expected presence are four questions with one answer: how many times did this span report? That count is now built in one pass and the rest are lookups, which is linear. DESIGN section 6 fixes a cost-shape defect regardless of the realized n, because 'n is small here' is not a time-stable fact - and a measurement carrier is exactly the thing that will later be pointed at a run with thousands of spans. Only lookups are performed against the map, never an iteration, so cause ordering still follows the sample fold and nothing here becomes an order-exposing operation. PROSE ROWS. measurement_subject_rung_note and witness_note were data ...: String rows, which is the shape 4c names as misplaced or dead data - mechanically indistinguishable from program data, and the exact convention #6262 introduced and #6424 had to sweep 215 rows of. I argued the previous instance of this finding on the grounds that the typed home did not exist, which was true of the dissolution half and beside the point for the rest: 4c's sanctioned form for irreducible rationale is a standalone leading // block attached to a module-scope declaration, and this file already used that form for its other commentary. Both rows are now such blocks - the rung note above admit_measurement_run, the witness note above the first helper. Nothing was deleted; the prose moved to the grain that classifies it as prose.
…TACHMENT POINT (review 56593) review 56593 is correct: two `data ..._note: String` rows carrying nothing but commentary are exactly what DESIGN §4c names as misplaced or dead semantic data, and §4c's own history says why -- the corpus already tried hoisting comments into String rows (#6262) and the first cleanup that forced swept 215 dead prose rows across ~130 files (#6424). The interesting part is how they got there, because the symptom pointed at the wrong fix. The first cut wrote these as `//` blocks, and the parser refused them: they sat INSIDE the `service git.Core { ... }` body, and §4c admits only standalone leading `//` attached to MODULE-SCOPE declarations. I concluded `//` was unavailable and changed the carrier. The actual defect was the attachment point -- git.dag already carries 48 module-scope `//` blocks, so the annotation channel was available the whole time and I had measured only that one position was not. Both rationales now attach to the module-scope ExternalAuthority anchors for the git commands they describe, which are the declarations whose subject they actually are. Verified by execution, and the counter moves in the direction that proves the point rather than merely not breaking: 4123 files parse-clean, and the declaration count drops 79438 -> 79436, exactly the two String rows removed. The prose left the semantic program instead of being reworded inside it -- §4c's annotation capture is disjoint from semantic occurrence allocation, so an annotation must not appear in that count at all. Diff confined to the three intended regions; an incidental whole-file newline collapse that had removed a blank line under the module header was reverted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ree and not list one, resolve a ref and not enumerate refs (#9431) * Model git's two enumeration reads: the substrate could create a worktree and not list one, resolve a ref and not enumerate refs extdeps.git declares 66 operations and neither `for-each-ref` nor `worktree list`. The asymmetry is the finding: worktree ADD is modeled in both its branch and detached forms, so a linked worktree can be CREATED and never ENUMERATED; ObserveRef resolves one ref the caller already names, and RemoteBranches returns remote-tracking names only, offline, with no object id. Neither gap is a defect in those operations -- they answer "where is this ref" and "which remote branches does this clone know about". The missing question is "what is the COMPLETE set, and where does each member point", and a check built without it is a check over an authored list, which by construction cannot see an addition. ForEachRefIn formats NUL-separated fields on newline-separated records. That is safety rather than convenience: git-check-ref-format(1) forbids space, newline and ASCII control characters inside a ref name, so a record cannot be split by its own content, and the symref field is empty for an ordinary ref -- a trailing empty field must stay observable rather than collapse into the separator. It is deliberately a LOGICAL ref read, not a storage read. Whether a ref lives loose under .git/refs or inside packed-refs is git storage policy that changes under ordinary maintenance with no ref having moved. Both directions were measured on srv1: a digest over storage reports a difference where nothing changed, and misses one where a loose ref shadows a stale packed entry. WorktreeListIn uses --porcelain -z, the form git-worktree(1) directs callers to rather than interpreting paths under GIT_DIR themselves. Each entry carries absolute path, HEAD, branch-or-detached, and the locked and prunable standings -- the tuple a preservation comparison needs, none of it recoverable from the filesystem without re-deciding git's own layout. Both are readonly and report exit_code + stderr rather than a success Bool, per this module's integration_write_operations_note: the seed derives exit_success as exactly exit_code == 0, so carrying both would represent one fact twice. Verified: 4123 files parse-clean; declaration count moves 79434 -> 79438, exactly the four top-level declarations added. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pin for-each-ref's order in the operation: an unpinned enumeration hashes the same ref set two ways The projection was already fixed to refname/objectname/symref rather than taken as a caller format string. The ORDER was not, and for the consumer this operation exists to serve that is the same defect one step later: a consumer comparing two enumerations digests them, so an unpinned order makes the digest a function of git's default ordering rather than of the ref set, and the same set can hash two ways. --sort=refname is pinned in the operation for that reason, and refname specifically because it is the one field guaranteed unique across the set -- which makes the order total rather than merely deterministic. Also records why there is no -z here. git-for-each-ref(1) documents no -z option; the NUL separator comes from %00 inside its own format language. Spelling a -z that upstream does not have would be a fabricated interface: it would fail at the transport rather than in review, and the extdeps duty is to model what the tool actually accepts. WorktreeListIn does carry -z because git-worktree(1) documents it. Verified: 4123 files parse-clean; declaration count unchanged at 79438, as expected for a string extension plus one argv element. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The prose was in the wrong CARRIER because I fixed it at the wrong ATTACHMENT POINT (review 56593) review 56593 is correct: two `data ..._note: String` rows carrying nothing but commentary are exactly what DESIGN §4c names as misplaced or dead semantic data, and §4c's own history says why -- the corpus already tried hoisting comments into String rows (#6262) and the first cleanup that forced swept 215 dead prose rows across ~130 files (#6424). The interesting part is how they got there, because the symptom pointed at the wrong fix. The first cut wrote these as `//` blocks, and the parser refused them: they sat INSIDE the `service git.Core { ... }` body, and §4c admits only standalone leading `//` attached to MODULE-SCOPE declarations. I concluded `//` was unavailable and changed the carrier. The actual defect was the attachment point -- git.dag already carries 48 module-scope `//` blocks, so the annotation channel was available the whole time and I had measured only that one position was not. Both rationales now attach to the module-scope ExternalAuthority anchors for the git commands they describe, which are the declarations whose subject they actually are. Verified by execution, and the counter moves in the direction that proves the point rather than merely not breaking: 4123 files parse-clean, and the declaration count drops 79438 -> 79436, exactly the two String rows removed. The prose left the semantic program instead of being reworded inside it -- §4c's annotation capture is disjoint from semantic occurrence allocation, so an annotation must not appear in that count at all. Diff confined to the three intended regions; an incidental whole-file newline collapse that had removed a blank line under the module header was reverted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: gunbc-ci-auto-heal <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…obligations (§4c) Addresses review 57011 (REQUEST_CHANGES, narrowly on §4c). Both findings verified against the code and both fixed rather than argued. FINDING 1 -- the two `data ...: String` notes were hoisted prose. Correct, and the precedent I had followed does not excuse it: I modeled this carrier on `gunbc.whole_corpus_compile_admission`, which uses the same pattern on main. §4c records that hoisting comments into `data ...: String` rows was itself the failure (#6262), and that the first cleanup it forced swept 215 dead prose rows across ~130 files (#6424). An existing instance is not a licence. Both notes are now `//` annotation blocks, which is the sanctioned quarantine channel, and the module carries zero commentary String rows. The machine-consumed counts the review asked to be lifted are now a typed row, `ConformanceDivergence`, with the site count and state count as separate members because two states refuse at two sites each -- a site total read as a state total overstates the divergence. `conformance_divergence_is_observed` derives the verdict rather than storing it, so the finding EXPIRES LOUDLY: if a conformance relation later lands and the carrier names every state the host refuses, the witness goes red instead of the census standing as a claim about a state that has ended. FINDING 2 -- the String payloads on the coproduct arms. The review called these less severe; they were the load-bearing half, and fixing them made a case testable that had been unrepresentable. `Retired` carried free-form `*_empty_receipt: String` fields, which can ASSERT discharge without exhibiting it. It now carries `discharged: List<RetirementObligation>` over a closed two-member vocabulary, and `retirement_fully_discharged` requires both. So a retirement that names itself while discharging only one obligation now admits NEITHER deletion -- which is this carrier's own thesis enforced one level in: naming a disposition is not proving it. That case could not be written before, so it could not be tested; `witness_partial_retirement_admits_neither_deletion` covers it now. `RouteRefuted` / `RouteUnexamined` are payload-free. Each route is a named `data` declaration with its reasoning in a `//` block above it, so the rationale sits in the channel §4c sanctions and where a reader actually encounters it, rather than in a string nothing consumes. WHAT DID NOT CHANGE: the lifecycle coproduct, the asymmetric admittance pair, and the witnesses the review found well-modeled. The asymmetry is still asserted as a DISAGREEMENT under Transferred and an agreement under a fully discharged Retired, because separate assertions are satisfied by a pair that answers false to everything -- the fused row again in typed clothing. Verified by execution: 0 blocking errors, contributing zero advisory diagnostics of its own (7 sources, 12 files emitted, 95 advisories all from the shared std closure). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ransfer and retirement are fused (#9521) * File a contradiction between two authorities: DESIGN records a climb trigger for the pair the hollowing plan schedules for deletion DESIGN records the regen host's hand-written ordering at *mitigatable* with "the host being derived from the carrier" as its next-rung trigger. `gunbc.plans.cli_run_hollowing_plan` carries a row whose subject is exactly that pair -- authority `v2.workflow.required_regen` / `v1_compiler.required_regen_host` -- and dispositions it `delete-with-v1`, trigger "Wave 4 real-fixpoint cutover", adding "bulk GENERATED cutover, not piecemeal". One authority asserts a climb, the other schedules a deletion, neither cites the other, and nothing refuses over the pair. This carrier records that and nothing else. It is not a repair, not a plan, and not a proposal for the Wave 4 work: resolving the contradiction means editing DESIGN against a plan, which is an operator decision. It gates nothing and says so, since a carrier named for a wall while occupying none is inflation (DESIGN 4b). Three findings, all measured: 1. THE AUTHORITY RELATIONSHIP IS A COMMENT. `required_regen_run` and `required_regen_sync_admission` occur exactly once across all of src/v1/stage0/src/*.rs, and the occurrence is prose naming the carrier as authority for an ordering. No production Rust calls into it; its only executor is its own witness. That is specification-without-execution on the production path, and it explains the divergence better than the host's Vec<String> refusal channel does -- 23 production refusal sites covering ~21 distinct states against six named by the carrier is what a comment-held correspondence produces given time, because nothing ever forced the two together. 2. THE TRIGGER HAS FAILED THREE PRECONDITIONS, each found only by attempting the step the previous one unblocked: the carrier sits in a tree the regen closure does not root; a relocated carrier still needs a seed-side consumer that does not exist; and the only honest candidate consumer is hand-Rust already scheduled for deletion at the same gate. A trigger nobody can satisfy is worse than a declared stall -- 4b(2) exists to separate "cannot climb" from "can climb but unbuilt", and this row reads as the second while being the first, so it never ranks and never retires. 3. CLOSURE MEMBERSHIP IS BY IMPORT, NOT BY RESIDENCE. The control table carries both arms -- two modules with seed importers, emitted; three with none, not emitted -- so precondition two is checkable by the next reader rather than re-derivable only by trying it. The witness makes the record self-invalidating: it asserts the trigger is unsatisfiable, so repairing a precondition turns it RED and forces the census to be revisited instead of decaying silently. It declares SubstrateInputsOnly explicitly, because the fail-closed default would make it ReadsLiveTree and DECLINED -- discovered, counted, never executed -- which is exactly the inert decoration this census warns about. Both control arms are asserted in each direction plus an anti-vacuity check, since either arm alone passes over an empty table. Verified by execution: 0 blocking errors for both modules, contributing zero advisory diagnostics of their own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Wave 4 lacks a total disposition for the required-regen obligation: transfer and retirement are fused Recut of this PR's original claim, which overreached in two ways. Both were mine and both are removed rather than softened. WHAT THIS NOW CLAIMS. `gunbc.plans.cli_run_hollowing_plan` carries one row -- authority `v2.workflow.required_regen` / `v1_compiler.required_regen_host` -- dispositioned `delete-with-v1` at the Wave 4 cutover. That row answers for two different futures with different obligations: TRANSFER, where the operation survives under a successor and owes an equivalence receipt, and RETIRE, where the operation ceases and owes proof its subject is empty. Both end in deleting the same two files, which is why one row can cover them and why nothing notices that it does. `delete-with-v1` states the ACTION and leaves the JUSTIFICATION unstated. The plan may still choose retirement. What it may not do is let `delete-with-v1` stand in for PROVING the subject retired. THE ASYMMETRY IS THE CONTENT. The host is one realization, so a transfer moves its work to the successor and a retirement ends it -- both admit deletion. The carrier is the operation's DEFINITION, so deleting it under a transfer destroys the referent of the very equivalence receipt that transfer owes. Only retirement admits it. A symmetric pair of predicates would be the fused row again in typed clothing, so the witness asserts the two must DISAGREE under Transferred and AGREE under Retired. WHAT WAS WRONG BEFORE. 1. THREE FAILED ROUTES ARE NOT AN IMPOSSIBILITY PROOF. The original concluded the trigger was unsatisfiable and the class could not climb. The evidence licenses only CurrentSeedImportDerivationUnavailable. "Host derived from carrier" does not require the host to import a Rust type generated into the v1 stage0 closure; that is one construction, and it is the one refuted. Four others -- build-time generation, interpreting the carrier and passing a typed receipt, moving the operation to the promoted v2 product, and the operation retiring with its subject -- are reachable and UNEXAMINED, and are now enumerated as such. This was the same equivalence-across-a-gap this lane had already caught itself making about the closure stubs. 2. COMMENT-HELD CONFORMANCE IS NOT ABSENT ENFORCEMENT. The grep establishes that no production Rust CONSUMES the carrier. It does not establish that required-regen behaviour is absent: the hand-written host is an INDEPENDENT REALIZATION and it does enforce the operation. The honest pair is OperationEnforcedByIndependentRealization with CarrierRealizationConformanceUnobserved. What is missing is a mechanically enforced RELATION between two realizations, not the enforcement, and that changes both severity and repair. 3. DESIGN AND THE PLAN ARE NOT NECESSARILY CONTRADICTORY. A next-rung trigger is an obligation while its subject remains LIVE, and a terminal migration may remove the subject entirely -- deleting an operation whose subject is gone is retiring it, not declining to climb. They are compatible under exactly that condition, and nobody had checked whether it holds. The unchecked condition is the defect; the arbitration request between the two authorities is withdrawn. WHAT SURVIVES, with its measurements: the seed-import route is genuinely unavailable (closed two-variant regen roots, zero emitted files declaring a v2.* source module, and the both-arms closure-membership control table showing membership is by import rather than residence); carrier/host conformance is comment-held, at a cost of 23 production refusal sites covering ~21 distinct states against six the carrier names; and the plan's row is not total. The witness guards the specific overclaim that caused this recut: if anyone later marks every derivation route refuted, the impossibility claim returns silently, so `witness_exactly_one_route_is_refuted` and `witness_no_impossibility_claim_is_reachable` go red instead. One gap stated rather than papered over: nothing detects the plan GAINING a disposition later, so that half remains review diligence. Verified by execution: 0 blocking errors, contributing zero advisory diagnostics of its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Convert the carrier's prose to annotations and its receipts to typed obligations (§4c) Addresses review 57011 (REQUEST_CHANGES, narrowly on §4c). Both findings verified against the code and both fixed rather than argued. FINDING 1 -- the two `data ...: String` notes were hoisted prose. Correct, and the precedent I had followed does not excuse it: I modeled this carrier on `gunbc.whole_corpus_compile_admission`, which uses the same pattern on main. §4c records that hoisting comments into `data ...: String` rows was itself the failure (#6262), and that the first cleanup it forced swept 215 dead prose rows across ~130 files (#6424). An existing instance is not a licence. Both notes are now `//` annotation blocks, which is the sanctioned quarantine channel, and the module carries zero commentary String rows. The machine-consumed counts the review asked to be lifted are now a typed row, `ConformanceDivergence`, with the site count and state count as separate members because two states refuse at two sites each -- a site total read as a state total overstates the divergence. `conformance_divergence_is_observed` derives the verdict rather than storing it, so the finding EXPIRES LOUDLY: if a conformance relation later lands and the carrier names every state the host refuses, the witness goes red instead of the census standing as a claim about a state that has ended. FINDING 2 -- the String payloads on the coproduct arms. The review called these less severe; they were the load-bearing half, and fixing them made a case testable that had been unrepresentable. `Retired` carried free-form `*_empty_receipt: String` fields, which can ASSERT discharge without exhibiting it. It now carries `discharged: List<RetirementObligation>` over a closed two-member vocabulary, and `retirement_fully_discharged` requires both. So a retirement that names itself while discharging only one obligation now admits NEITHER deletion -- which is this carrier's own thesis enforced one level in: naming a disposition is not proving it. That case could not be written before, so it could not be tested; `witness_partial_retirement_admits_neither_deletion` covers it now. `RouteRefuted` / `RouteUnexamined` are payload-free. Each route is a named `data` declaration with its reasoning in a `//` block above it, so the rationale sits in the channel §4c sanctions and where a reader actually encounters it, rather than in a string nothing consumes. WHAT DID NOT CHANGE: the lifecycle coproduct, the asymmetric admittance pair, and the witnesses the review found well-modeled. The asymmetry is still asserted as a DISAGREEMENT under Transferred and an agreement under a fully discharged Retired, because separate assertions are satisfied by a pair that answers false to everything -- the fused row again in typed clothing. Verified by execution: 0 blocking errors, contributing zero advisory diagnostics of its own (7 sources, 12 files emitted, 95 advisories all from the shared std closure). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Dissolve the transcribed conformance counts and the retirement predicate, and split transfer by what the successor replaces Review 57020 raised two findings and both are correct. The five conformance counts were transcribed off a live-tree scan with no instrument naming them -- the 2026-08-24 ruling's exact prohibition. The repair is not to re-source them. The standing this carrier needs is qualitative: has a conformance relation been observed at all. The predicate that consumed the counts answered false regardless of whether they were current, so the numbers could rot without changing any decision, which is the evidence they were not carrying one. They are replaced by a typed RealizationConformance whose live value asserts an ABSENCE of observation and therefore owes no instrument. Conformance is modeled as its own axis rather than an arm of the lifecycle, because the operation's fate and the state of the relation between its realizations are independent questions. The retirement predicate was a hand-rolled Bool over a closed coproduct. Rather than respell it, the state that made it necessary is gone: a partially discharged retirement is now its own arm, Retired carries nothing, and the predicate dissolved rather than being reformulated. This also removes a state with no meaning -- Retired with an empty discharge list was neither retired nor prepared. Separately, a defect of my own found before review reached it: the transfer arm carried a successor AUTHORITY while denying carrier deletion, so the carrier encoded a terminal state in which two definitions answer for one operation. Split into RealizationTransferred (carrier stays canonical) and AuthorityTransferred (both delete), with a witness asserting the two DISAGREE, so re-fusing them in either direction goes red. Verified by execution, not by compiling: all seven affected witnesses return true, against an oracle first shown to discriminate by a planted false control. Compiles 0 blocking / 95 advisory, unchanged baseline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Delete the control table's transcribed magnitude, keeping the distinction its consumers actually read Review 57043 approved but noted that the closure-membership control table reintroduced transcribed integers in a file that elsewhere retracts them. Measured against the consumers rather than argued: every reader tested seed_importers == 0 or > 0, so the MAGNITUDE was read by nothing and a row could drift from one importer to seven with no witness changing. That is the same test this file applies to the conformance counts a few declarations up -- a member that can rot without changing any decision was never carrying one -- so the magnitude is deleted rather than defended as a fixture. The field becomes seed_reachable: Bool, which is the zero/non-zero distinction the rule actually turns on and a structural fact about the import graph rather than a measurement of a population. emitted stays a stored Bool because it IS read directly: it is the observed consequence the control exists to pair against reachability. Expressing reachability as a coproduct was considered and rejected -- filtering on it would have required a match returning true for one arm and false for the other, which is the predicate-dissolution shape review 57020 objected to. All three affected witnesses verified by execution, not by compiling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Force a fresh merge ref: this PR's checks were pinned to a base that predates #9560 The three failing checks on 4d22d6d started 01:10-02:10Z, so refs/pull/9521/merge was computed against main as it stood before ba27746 (#9560) landed. That base no longer exists. A rerun replays the pinned ref and would reproduce the red exactly; only a push forces recomputation. The trigger for pushing was a settled, non-cancelled witnesses run on a head containing #9560: run 33140335064 on ba27746, with required-witnesses-build, required-witnesses-floor and witnesses all green. No content change. The tree is byte-identical to 4d22d6d. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Absorption was fused into AuthorityTransferred, and its incompleteness was one symbol over two owners The carrier exists to name a fused disposition, and it fused one two levels in. ABSORPTION IS A THIRD CONTINUATION. An obligation can survive while ceasing to be an INDEPENDENTLY NAMED operation, performed as one inseparable part of a broader transaction. That is not an authority transfer: a transfer hands the operation to a successor that still answers for it by name, while absorption dissolves the name and owes a COVERAGE receipt over every old input population, ordering guarantee, refusal and consumer obligation. WHY THE COMPLETED ARM ALONE WOULD HAVE BEEN A DECORATION. A completed absorption has the same deletion truth table as an authority transfer -- the absorber is canonical, so both files go -- so an Absorbed arm on its own changes no predicate outcome and no witness over it can go red for the right reason. The INCOMPLETE state is what makes it a wall: coverage that has not been demonstrated admits NEITHER deletion, which authority transfer never does. AND INCOMPLETENESS ITSELF SPLITS, IN TWO, WHICH IS THE ARM COUNT AND ITS REASON. An unproduced coverage receipt is an ABSENT OBSERVATION -- the absorber may cover everything, the remedy is to produce the receipt, owned by whoever lands the absorption. A receipt that SHOWS a gap is an observation with a negative result -- the remedy is to widen the absorber or refuse the absorption, owned by whoever owns the broader operation, and the design is wrong. Opposite owners, opposite repairs: DESIGN's not-applicable-rendered-as-malformed conflation. The two AGREE on both deletion predicates, which is exactly why collapsing them is tempting and exactly why a truth-table test cannot see the split. THE PRECEDENT IS IN THIS FILE, AND IT IS NOT THE ONE FIRST PROPOSED. A peer suggested retirement's three arms as precedent for distinguishing kinds of incompleteness. Checked: they are MirrorPopulationStillOccupied / RequiredConsumersRemain / BothObligationsOutstanding -- subsets over two named obligations, not kinds of incompleteness. The analogy fails and did not carry the split. What carried it is that this module ALREADY separates absent-observation from negative-result twice: RouteStatus (RouteRefuted vs RouteUnexamined) and RealizationConformance (unobserved vs observed). Collapsing absorption's would leave one module speaking two vocabularies about one concept. NO THIRD ARM. "Absorber not yet identified" is not a coverage state -- an obligation with no named absorber is Active, not absorbed. THE SPLIT IS READ, NOT MERELY DECLARED. Without a consumer, AbsorptionCoverage would be the richer name over an unchanged wall this module objects to elsewhere, so absorption_coverage_is_refuted answers the question whose two states have different owners. EVIDENCE, EXECUTED. Six witnesses green. Mutation: fusing prepared absorption with authority transfer on the carrier axis (one arm, false -> true) turns the disagreement witness and the closed-vocabulary gap sweep RED, while the agree-on-deletion-differ-on-refutation witness correctly stays green because it tests the other axis -- evidence the witnesses are not restatements of one assertion. Carrier restored byte-identical to its pre-mutation bytes and both reds return to green. ONE ANNOTATION RECORDS A WORKAROUND FOR A FILED PARSER DEFECT. The parser refuses a newline between the parameter list and the return arrow, at ANY name length -- executed on a controlled pair, a one-character name with the break refuses and the same name with the arrow on one line compiles clean. A test fn name here is therefore short in order to keep the ARROW on one line, not because short names are preferred; the defect is filed and owned elsewhere. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sweep of the comment-smuggled-in-a-string habit (operator directive, 2026-07-09): top-level
data <name>: String = "<prose>"rows that exist only to hold a comment — rulings, receipts, dissolve-on narratives — because.daghas no comment syntax (#5579 comment wall).What this PR does
Deletes 215 dead prose data rows across ~130 files (~430 lines, zero additions).
Selection was mechanical and fail-closed, not name-based:
data X: Stringrow whose value is prose-shaped (>10 chars, ≥4 words);Xanywhere in*.dagor*.rs(including the stage0 seed, so seed-realized rows are excluded);ci_regen_ratchet_removed_note, cited only from two other dead notes).A row with any consumer — emitted into an artifact, asserted by a witness, realized in the seed — was left untouched.
What was deliberately NOT deleted (reverted after CI receipts)
src/v2/test/manual/**note deletions were reverted (receipts: runs 29053815785, 29054469047). The per-PR affected-set frontier strict-resolves every diff-touched file, and manual witnesses are outside its resolvable set by design —forensics_6280_synth_producer.dagdeliberately constructs a bareRejectedwith no import (it IS the constructor-owner wall-gap reproducer), andownership_movable_test.dagimportsv1.compiler.ownershipoutside the frontier roots. Touching those files at all reds the floor, independent of what the edit is. Cleaning them means deleting/relocating the fixture families wholesale — follow-up, not this sweep.Residue (follow-up surface, censused in-session)
*_dissolution_triggermarks with real consumers, incl. seed-realized ones (witness_span_note→std_realization_schedule.rs) needing hand-reconcile with the seed.rationale:,dissolve_on:onConstructionJustificationetc.) — shape changes on load-bearing carriers, checkpoint-gated.forensics_6280_quarantine_note) — outside this pass's single-line class.inert_carriercovers type carriers only), and the habit is live — two newcatalog_*_noterows were authored on an unlanded branch the same day. A dead-prose-data-row lens (construction: a data row with no consumer is dead code) is the piece that makes this sweep stick. Proposed as follow-up work item.