Skip to content

Model target producer bindings and instrument standings - #9323

Closed
gunbai-bot[bot] wants to merge 0 commit into
mainfrom
session/bright-moth-189
Closed

gunbai-bot[bot] wants to merge 0 commit into
mainfrom
session/bright-moth-189

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add TargetBinding as a peer relation to BuildTarget, with a unique label-keyed index and typed bound/missing/unknown lookup outcomes
  • admit only structurally round-tripping labels before their rendering becomes an index key, preventing forged label records from aliasing another target or bypassing the unknown-target refusal
  • extend TestStanding with producer-specific behavioral-receipt and heads-reading differential observations without adding argv or execution details to the target model
  • refuse instrument standings at the //:required and Blaze-export boundaries instead of collapsing their observations into generic pass/fail statuses
  • distinguish completed negative observations, subject-unreached outcomes, and typed producer refusals

Test plan

  • targeted claim_batch execution over target_binding_witness_test.dag — 7/7 PASS, including the canonical-known-target vs forged-binding-target rendered-key collision
  • pre-fix measurement probe rendered_key_collision_currently_misbinds — PASS, confirming the silent alias before the repair
  • git diff --check — PASS
  • push hook cargo fmt --all --check — PASS

Dashboard node: adhoc-df227240-974

@gunbai-bot gunbai-bot Bot changed the title Target producer binding + producer-specific TestStanding arms (no argv in BuildTarget) Model target producer bindings and instrument standings Aug 26, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 26, 2026 08:03
gunbai-bot Bot pushed a commit that referenced this pull request Aug 26, 2026
… written

PanickedBeforeVerdict and NotAttemptedAfterAbort landed on the floor's disposition
vocabulary after #9323 wrote gunbc.build_target's two wildcard-free policy folds, so
the merge of main into this branch is where they meet and refuse to compile. That is
the fold behaving exactly as its own comment says it must: a new arm fails to compile
rather than being inherited from whichever arm a wildcard named.

Both are UNSATISFIED for the aggregate. NotAttemptedAfterAbort is the one that would
have been damaging to absorb -- a required set treating 'never attempted' as satisfied
reports itself green over a run that stopped early, the empty-observation narrow
arriving as a green.

The Blaze export gives NotAttemptedAfterAbort its exact upstream member,
HALTED_BEFORE_TESTING, rather than the tempting INCOMPLETE that would have collapsed
it into a pile upstream already distinguishes. PanickedBeforeVerdict has no member and
joins FAILED beside RuntimeErroredBeforeVerdict.
gunbai-bot Bot pushed a commit that referenced this pull request Aug 26, 2026
…er INCOMPLETE

#9343 landed on main fixing the same two ClaimDisposition arms this branch fixed
independently, so the two met in build_target.dag. Both halves resolved deliberately
rather than by taking a side whole.

THE IMPORT: main's build_target.dag has no gunbc.target_binding import because #9323
has not merged, so main's TestStanding carries three arms and this branch's carries
seven. Taking main's side would have deleted the four producer arms and every consumer
of them. HEAD's side survives.

THE EXPORT, AND THIS IS A DELIBERATE DIVERGENCE FROM #9343 RATHER THAN A MERGE
ARTEFACT. The aggregate policy is byte-identical between us -- both arms unsatisfied,
same causes. The Blaze export differs on one line: #9343 renders NotAttemptedAfterAbort
as INCOMPLETE, this keeps HALTED_BEFORE_TESTING.

The reason is upstream. NotAttemptedAfterAbort is constructed from NotAttempted
{ halted_by }, and Bazel's HALTED_BEFORE_TESTING means exactly 'the test did not run
because the build was halted'. It is an exact member for the fact, so the export loses
nothing; INCOMPLETE collapses it into the pile that module's own comment already
describes as lossy, beside HostToolUnresolvedBeforeVerdict and RouteGapBeforeVerdict.
Nothing reads the export back into a decision, so this is a fidelity choice and not a
correctness one -- a one-line revert if the reviewer prefers main's reading.
briansrls pushed a commit that referenced this pull request Aug 27, 2026
* Model target producer bindings

* Type instrument refusal causes

* Reject noncanonical target index labels

* Refuse noncanonical target lookup labels

* Home label canonicality in label authority

* Name canonicality for label authority

* Keep label annotation at module grain

* Seal target binding index construction

* wip: target dispatch seam

* fix: single-arm coproducts need a record body

* Delete the claim_executor route atomically, and name the unpinned-tree limit

The old --heads-reading-differential mode is removed in the same change that makes
the instrument addressable, so there is never an interval where two routes to one
producer both work. Its parse-wall figures survive as an explicitly unmodeled host
line: a replacement that silently drops a capability is not a replacement.

The producer executes against an unpinned live working tree and the carriers now
say so. InvocationOutcome stays an OUTCOME rather than a receipt, and both the
model and the host record that no digest field can close the gap -- the tree can go
A -> B -> A while the producer reads a mixed population and both hashes agree.

* Classify the two ClaimDisposition arms main added after this fold was written

PanickedBeforeVerdict and NotAttemptedAfterAbort landed on the floor's disposition
vocabulary after #9323 wrote gunbc.build_target's two wildcard-free policy folds, so
the merge of main into this branch is where they meet and refuse to compile. That is
the fold behaving exactly as its own comment says it must: a new arm fails to compile
rather than being inherited from whichever arm a wildcard named.

Both are UNSATISFIED for the aggregate. NotAttemptedAfterAbort is the one that would
have been damaging to absorb -- a required set treating 'never attempted' as satisfied
reports itself green over a run that stopped early, the empty-observation narrow
arriving as a green.

The Blaze export gives NotAttemptedAfterAbort its exact upstream member,
HALTED_BEFORE_TESTING, rather than the tempting INCOMPLETE that would have collapsed
it into a pile upstream already distinguishes. PanickedBeforeVerdict has no member and
joins FAILED beside RuntimeErroredBeforeVerdict.

* Register the host seam as seed-retained and install the regenerated CLI mirror

Two regen obligations the CLI model change created.

target_invocation_host.rs is a committed src/v1/stage0/src/*.rs the emitter does not
produce, so regen refused it as a mirror that stopped being emitted. It is declared
as a SeedRetainedIntrinsicRegistration with has_pub_mod: false, matching
required_regen_host and declaration_index -- it is wired by #[path] mod inside
cli_run.rs and contributes no pub mod line to the emitted lib.rs. The registration
moves three generated artifacts alongside it, as every prior registration has.

gunbc_cli_dispatch_surface.rs is the emitted mirror of the module that gained the
operand axis, installed from the regen candidate rather than hand-written: the two
new one-arm enums, CliOperandRow, the operands field on every subcommand, the
CliInvokesBoundTargetProducer arm and the test verb row.

* cargo fmt

* Write the HALTED_BEFORE_TESTING argument onto the arm, with its receipt

The export arm for NotAttemptedAfterAbort has now been decided twice, the other way:
gunbc#9343 chose INCOMPLETE on main while this branch chose HALTED_BEFORE_TESTING, and
the two met in a merge. Without the argument written down, the next reader diffing
against that history finds an unexplained divergence and 'fixes' it back.

The receipt is checked rather than recalled: extdeps.bazel.test_status carries
TestStatusHaltedBeforeTesting as wire number 8, BLAZE_HALTED_BEFORE_TESTING, and the
disposition is built from NotAttempted { halted_by }. Same fact, exact member.

Module-scope comment, above the declaration -- the annotation grain rule refuses one
inside the match body.

* The main merge landed #9343's arms BESIDE mine, not onto them

Both ClaimDisposition folds in gunbc.build_target carried two PanickedBeforeVerdict
arms and two NotAttemptedAfterAbort arms after the merge, and the export's second
NotAttemptedAfterAbort carried #9343's INCOMPLETE. Whichever way the compiler resolves
a duplicate, one of the two readings was wrong: first-match-wins reds the witness,
last-wins makes my change dead code and silently keeps the other value.

HOW I MISSED IT, because the check I ran looked sufficient and was not. After the merge
I grepped the diff against main and saw my HALTED_BEFORE_TESTING arm present, and
concluded the resolution was right. Presence is not exclusivity. A conflict git reports
gets resolved carefully; a hunk that applies CLEANLY beside an existing one does not
announce itself, and that is the direction this class always arrives from. Found by
cool-swift-307 reading my head, not by me and not by CI -- no checks had run.

Both folds are now one arm per member: 13 arms against ClaimDisposition's 13 members,
verified by counting rather than by eye, and every other match in the touched modules
swept for the same shape.

bazel_target_model_witness_test moved with the code rather than being left asserting
the value the code no longer produces. Its run/never-ran argument is UNCHANGED and
survives intact -- INCOMPLETE is in the never-ran family, so the split it tests was
never wrong, only vaguer than upstream allows. What the arm records now is which
never-ran member is exact, with the wire number and both PRs named.

* Retain label canonicality refusal causes

* Carry the typed canonicality cause through the invocation route

bright-moth-189 deleted `label_is_canonical` in favour of the typed
`label_canonicality` / `LabelCanonicalityCause` pair, so the registry now
retains WHICH way a label was non-canonical. This completes that chain
through the consumer layer: `InvocationLabelNotCanonical` carries the cause
and `invocation_refusal_rendered` surfaces it.

Dropping the cause here would have made the split real and invisible at the
only surface a caller of `gunbc test` touches -- a typed distinction that
reaches no reader is the same false bit it replaced, one layer out.

The inner `LabelRefusal` is carried but deliberately NOT decomposed here:
that vocabulary belongs to the label authority and has no renderer there
today, so writing one in this module would be a second site deciding what
`DotSegment` says to a human (§3 fork through a rendering rather than a
type). This names the CLASS of repair, which is what distinguishes the arms.

Two witnesses cover it, using a structurally non-canonical label built
through the sole constructor: one that the cause survives into the route's
refusal, one that it reaches the rendered text.

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>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot closed this Aug 27, 2026
@gunbai-bot
gunbai-bot Bot force-pushed the session/bright-moth-189 branch from f037b60 to 39688a5 Compare August 27, 2026 00:57
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.

0 participants