Skip to content

Split the extdeps scope-placement gate's two bases; make its refusal loud - #7660

Merged
briansrls merged 17 commits into
mainfrom
session/nimble-seal-512
Aug 2, 2026
Merged

briansrls merged 17 commits into
mainfrom
session/nimble-seal-512

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The two follow-ups from the #7644 diagnosis of the ten-run extdeps_scope_placement_gate_passes red on main.

1. The gate read one base for two different questions

scope_placement_added_paths diffed legacy_manifest_freeze_sha..HEAD and fed both arms. The membership arm asks "does this change introduce an unrostered dag/extdeps file"; the freeze arm asks "does any manifest row name a file created after the anchor". Only the second is inherently a whole-population question.

Consequence: one unrostered file on main refused every open branch, and the party blocked was never the party at fault. #7573 added dag/extdeps/session_dashboard.dag eleven seconds after the gate landed in #7571, its own CI ran against a gate-less base, and main then refused ten consecutive runs while unrelated lanes spent sessions proving the red was not theirs. extdeps_scope_frontier_law meanwhile claimed "only paths the change itself introduces are judged" — true of the intent, false of the mechanism.

Now: membership reads origin/main...HEAD, freeze keeps freeze..HEAD. One shared fold (diff_added_paths_observation) builds both, so the base is a call-site parameter rather than a duplicated parse. The verdict splits into two pure functions with the live manifest_remove_only_verdict kept outside them, so both are hermetically testable.

This is a trade, not a pure win, and it is declared rather than absorbed. The freeze-base read incidentally re-verified roster membership across the whole post-freeze population every run; merge-base grain does not. scope_placement_base_split_note records the narrowing with bounded population, residual detection, and a restoration trigger (the v2.lens.mandatory_tag region promotion), per DESIGN §4b meta-obligation 3.

2. The refusal was mute in CI

The gate built a located diagnostic naming the offending path; tools.ci_gates exit_ok discarded it one frame above, so CI reported returned Bool(false) and nothing else.

The *_failure_receipt companion mechanism already existed (v2.std.native_agreement, whose authority note describes this exact class). It was unreachable here for two independent reasons, and fixing either alone ships dead code:

  • failure_receipt_companion derived the name from _holds only; every cheap-floor gate witness ends _passes.
  • claim_executor — the binary CI actually runs — never invoked the companion at all, though cli_run has since the Lane B work. A genuine dual-surface divergence: the same witness was loud locally and mute in CI.

Both now route through the one derivation and the one runner. The Rust delta is ~20 lines and adds no new mechanism.

Verified by execution

Kernel controls, six new plus the four pre-existing ones that could have broken — all PASS via claim_batch.

The base wiring is not covered by those, and the note in the witness file says so explicitly. The verdict fns are pure in the observation handed to them, so nothing asserted there can distinguish which base produced it — a regression feeding the membership arm the freeze base would leave every witness green. An earlier draft of that note claimed the opposite; it was wrong and is corrected in-file.

The wiring is covered by executing the wet gate under a perturbation that reproduces the incident. With the session_dashboard roster row removed, the freeze population carries an unrostered file while this change adds none:

state result
inherited unrostered file, none added by this change ExitSuccess — old wiring refused here; this is the fleet-block, gone
unrostered file added by this change (temporary probe, reverted) ExitFailure naming dag/extdeps/tmpprobe/probe.dag
receipt on that refusal returns exactly the reason string CI will append after returned Bool(false) |
receipt on success empty

Gate-equivalent compile-clean: 0 blocking errors.

Closing the wiring hole in-corpus needs a structural reader over the call graph asserting which observation function feeds which arm. That is the honest next step and is not built here.

🤖 Generated with Claude Code

gunbc-ci-auto-heal added 11 commits August 2, 2026 00:10
# Conflicts:
#	dag/gunbc/extdeps_scope_frontier.dag
# Conflicts:
#	dag/extdeps/session_dashboard.dag
#	dag/gunbc/extdeps_scope_frontier.dag
…loud

The placement arm now reads origin/main...HEAD (what THIS change adds) while the
freeze arm keeps legacy_manifest_freeze_sha..HEAD (the whole post-freeze
population it inherently needs). Feeding both arms the freeze base meant one
unrostered file on main refused every open branch, so the blocked party was
never the party at fault.

Loudness: claim_executor now projects the failure-receipt companion that
cli_run has projected since the Lane B agreement work, and the companion name
derives from _passes as well as _holds. Without both, the gate witnesses were
unreachable from that channel and ten consecutive main reds reported nothing
but 'returned Bool(false)'.
…he base

The renamed control asserts what it actually tests (an empty change set admits).
The base wiring is one frame above these pure fns and is covered by executing
the wet gate under a roster perturbation, recorded in the PR.
…n (review 47022)

Names the lane (v1 exit), the concrete ROADMAP row (Get hand-written Rust in
this repository down to zero, authority dag/gunbc/v1_deletion_plan.dag), and
the dissolution trigger (deleted WITH claim_executor, not migrated ahead of it).

States the measurable facts rather than asserting a census movement: zero new
tracked-Rust paths, so the path-grain population is unchanged, and HandAuthoredLOC
is an explicitly deferred axis of stage0_rust_honest_frontier_projection, so there
is no line census to shrink.
@gunbai-bot

gunbai-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in 0636534716a. The hand-Rust receipt is now carried in the diff itself, on claim_result_for_outcome. Taking the three offered discharge forms in turn, because two of them have no mechanism to satisfy and I would rather say so than fabricate one.

"Deleted scaffold path" — not applicable. This PR deletes no scaffold. Claiming one would be false.

"Census shrink" — no census moves, and I verified this rather than asserting it.

  • The PR adds zero tracked-Rust paths. git diff --name-status origin/main...HEAD | grep -E "^A" | grep '\.rs$' is empty; both .rs files are M, already tracked, and neither carries a rust_source_lifecycle_residue_rows row. So the path-grain population gunbc.stage0_rust_honest_frontier_projection measures — exact_unclassified_tracked_rust_paths over tracked_paths minus generated minus admitted-disposition — is unchanged by this diff.
  • The axis that would price added lines is HandAuthoredLOC, and stage0_rust_honest_frontier_projection_note declares it one of three axes "explicitly deferred to the v1-honest-frontier follow-on; this first slice does not claim them." There is therefore no line-grain census in the corpus to shrink. Reporting a shrink against a deferred axis would be exactly the fabricated receipt DESIGN §5 forbids.

"Explicit deferral naming a lane and concrete ROADMAP row" — this one is fair, and it is now discharged.

  • Lane: v1 exit (ROADMAP §11 lists its fourth finish line as zero hand-maintained Rust).
  • Row: "Get hand-written Rust in this repository down to zero", authority dag/gunbc/v1_deletion_plan.dag.
  • Dissolution trigger: the projection is floor-runner plumbing with no independent lifetime — it is deleted with claim_executor when witness execution leaves the hand-maintained seed runner, not migrated ahead of it.

One constraint worth stating, since it bounds the alternative: writing this in .dag first is not available. The failure-receipt channel is the seed's own witness-reporting surface, and .dag has no print primitive — grep -rn "^fn print\|^func print\|fn println" dag/std/ src/v2/std/ returns nothing. The reason string is pure data until a seed frame renders it. That is why the .dag half of this PR builds the located diagnostic and the seed half is the only thing that can surface it.

The alternative to the ~20 seed lines was leaving the reason discarded — which is the §5 trap this PR exists to close. A refusal nobody can locate is not a refusal anyone can act on, and that is precisely what cost two sessions on the main red this follow-up came out of.

— sent from nimble-seal-512

gunbc-ci-auto-heal added 4 commits August 2, 2026 02:23
Main is red on extdeps.transports.rest importing ContentHash from std.types
after #7480 moved it to std.content_hash. A dedicated repair PR (#7656) plus
#7650 and #7648 already carry the fix, and the full repair also needs the
coproduct construction in rest_exchange_replay_test.dag. Keeping #7660 scoped
to the gate rather than racing three lanes on the same file.
@gunbai-bot

gunbai-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Note for whoever merges, since review 47108 picked up on the rest-exchange test change: dag/test/claim/rest_exchange_replay_test.dag appears in both this PR and #7663, deliberately.

#7663 is the owner — it repairs main's second #7480 breakage (the bare string no longer inhabits the ContentHash coproduct). It landed in this branch first only because I hit that compile error while trying to get this PR's CI to run, then split it out so it can merge independently of the gate work.

The two copies are byte-identical, so the merge is clean in either order, and the file drops out of this PR's diff once #7663 lands and this branch merges main. No action needed; flagging it so it is not read as scope creep or as a conflicting edit.

Worth knowing while assessing this PR's CI: it is red on main's breakage, not on this diff. ci is skipped behind regen/heal, so the gate changes here have not executed in CI yet. #7663 removes the resolve failure but does not fully green main — six rest_exchange_replay witnesses are separately regressed by #7480, proven against a pre-#7480 baseline, and that layer is unowned.

— sent from nimble-seal-512

@briansrls
briansrls merged commit 8435bba into main Aug 2, 2026
5 checks passed
@briansrls
briansrls deleted the session/nimble-seal-512 branch August 2, 2026 13:45
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.

1 participant