Repository navigation
Floor: observe-only execution-grain reach selection (claims whose verdict a body change can move; #12361 near-miss) - #12384
Conversation
…dict a body change can move) gunbc#12361 enqueued over a green floor while ten claims were true at base and false at head. The floor executes a static gate roster plus edited test fns; its only dependents walk (interface_changed_consumers) is compile-grain and correctly stops at interfaces, so body-only edits reach no claim. - namespace_baseline body_reach_from_changed_declarations: reverse reach over every read channel of the parse-phase DeclarationIndex, same read_binding rule, propagating through bodies. Seeds: the declaration grain of the floor's own line attribution (FloorDiffEdits touched_declarations) plus every interface change. - The floor prints [floor-plan] BodyReachWitness / body-reach-selection and plans nothing from it: making v2.test.* differentially merge-blocking waits on operator sign-off (neat-boar-16 ruling 2026-09-26). - Model: v2.workflow.floor_subject_seed ReachConsumer / reach_propagates, with its claim; RFM row green_floor_executes_no_claim_whose_verdict_a_body_change_can_move; seed-growth admission record enumerates the new hand items. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nly the reads they rebind The unrelated-diff control (#12353) reached 13147 witnesses, the same order as #12361's replay. Two defects, both measured on srv1: - the flat bare channel admitted dotted field accesses (cfg.root, whose empty candidate set says nothing about top-level root) and ambiguous bare names; the global-bare lookup resolves only a BARE name to a UNIQUE declarer, so the execution walk now admits exactly that (fan-out ran through test-local helpers named root/subject/observed/standing). - an import-region edit seeded every declaration in its file (684 seeds from an 11-file diff); import_rebound_declarations now seeds only the reads whose import binding changed between the two indexes. Receipt gains the binding kind and one BodyReachSeed line per seed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replay evidence (srv1, via neat-boar-16; planning receipts only, each run stopped after planning)Round 1 FAILED its control:
An unrelated diff selected as much as the replay, so the selection discriminated nothing. Two defects were located from the fan-out (
Round 2, after the fixes (commit c4bbb44):
Pending, condition (b): the cost of EXECUTING the selection at base and at head (one Pre-existing, not this PR: Separate finding (compile walk, not changed here): |
…replay; enabling step is its own change Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s landed row green_floor_is_bounded_by_its_gate_population duplicated the class #12384 landed as green_floor_executes_no_claim_whose_verdict_a_body_change_can_move, and its module-grain closure figure is superseded by declaration reach. The distinct class is the Arrow domain's meaning not being carried on the Node (E1/E2 encodings, operation payloads, the shape-based spine recognizer), with Program P (single Arrow encoding) as its trigger. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Work item adhoc-be476b8f-943. Design ruled by neat-boar-16 (2026-09-26). Scope: selector + model + RFM row, observe-only. Operator ruling 2026-09-27: the per-PR v2 claim comparison is merge-blocking over this reach selection ∩ the v2 claim set (never the whole set). That enabling step is a separate follow-up PR stacked on this one; the execution-cost receipt (condition b) and the main-sha baseline belong to it.
What "affected" meant (read from #12361's floor run 36256059426 @ e659b86)
required_gate_prefixesandrequired_gate_authored_modules, whose one v2 member isv2.test.claim.body_lowering.statement_let_bind) plus changed witnesses (test fns whose own lines the diff edits). That run had planned=537 and changed_witnesses=7.interface_changed_consumers, 8 changes, 1 consumer added).v2.test.claim.*/v2.test.execution.*, outside the executed population. One of them sits in a touched file, so this is not a file-grain gap.Earliest unjustified boundary
The only dependents walk is compile-grain, and it correctly stops at interfaces: a body-only edit can't make a caller's caller fail to typecheck. Nothing relates a body change to a claim verdict. #12361 changed only bodies (
arrow_signature_edges_conform,eval_bind_arrow_params,infer_application_formals/_argument_inhabitance).This PR
namespace_baselinebody_reach_from_changed_declarationsdoes reverse reach over every read channel of the parse-phaseDeclarationIndex. It uses the sameread_bindingrule as the interface walk and propagates through bodies. Readers are inverted once into a leaf map, so cost is linear in the reads touched.FloorDiffEdits.touched_declarations(the declaration grain of the floor's own line attribution; an import-region edit seeds every declaration in its file) plus every interface change (the only seed a removed declaration has).[floor-plan] BodyReachWitness identity=… through=…and a[floor-phase] phase=body-reach-selectionsummary, and plans nothing from it.v2.workflow.floor_subject_seedReachConsumer/reach_propagates, where a body read propagates forClaimExecutionand not forStrictPreparation. It is one rule keyed on its consumer, not a second relation.green_floor_executes_no_claim_whose_verdict_a_body_change_can_move.floor_arm_set_consumer_seed_growth) enumerates the new hand items.Import-closure selection was rejected: v2's resolver ignores imports, and the namespace cut deletes them.
Evidence
a_body_only_change_reaches_the_witness_two_calls_away. The interface walk plans nothing; the reach walk selects the witness two calls away, and neither the idle importer nor the unrelated witness. Control:no_changed_declaration_reaches_nothing. Both pass (remotecargo test)..dagclaima_body_read_propagates_for_claim_execution_and_not_for_strict_preparationpasses underclaim_batch, and so does its neighbouronly_an_interface_read_propagates_a_change.process_cwd_mutation_reachability_gate(2 tests) fails identically on clean main 980761c; pre-existing.Condition (a): the base-verdict cache, for the enabling step
The base verdict is a materialization (
std.materialization_ladder). Its key must be complete over everything the verdict depends on:The reach digest is the load-bearing part. A key over the claim's own file alone is exactly this row's failure again, one layer down. Because reach is computed at the grain of the reference index, the key inherits that bound: a dependency only through an inferred type, which no declaration on the path spells, escapes it. That bound belongs on the cache's refusal list, not silently in its key.
🤖 Generated with Claude Code