Skip to content

The unobserved-duration trigger fires: contention refuses to rank rather than substituting a worst case - #9488

Merged
briansrls merged 2 commits into
mainfrom
fabric/contention-unobserved-duration
Aug 27, 2026
Merged

briansrls merged 2 commits into
mainfrom
fabric/contention-unobserved-duration

Conversation

@briansrls

@briansrls briansrls commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Main does not compile in the fabric domain. #9397 added UnobservedGrantDuration to GrantDuration and made the seconds accessor partial; product.fabric.contention consumed the old total accessor, matched affordability over four of its now-five arms, classified occupancy over two of GrantDuration's now-three, and used the QuotedTotal coproduct as though it were a bare amount.

The outcome was not an open modeling call

It was decided before the defect existed. The annotation on the occupancy fold names it:

NEXT-RUNG TRIGGER, owned by the supply lane rather than this one: an unobserved arm on GrantDuration. When it lands, the honest outcome here is a refusal to rank rather than a substituted worst case -- refusing names the remedy (measure the job) while a substituted number hides that anything is missing.

The arm landed and the trigger fired. That fold was built to stop compiling at exactly this moment so whoever broke it would read the instruction. Three sessions re-derived the ruling from types and call graphs before anyone read the prose on the broken line.

What changed

grant_duration_observation -- one total match returning the seconds and the basis TOGETHER, because they are read off one arm. Answered separately, a caller could pair a measured duration with a projected basis, which is the authority substitution the fold's own annotation already caught once. Paired in the carrier, that state has no spelling. This replaces both the now-partial accessor call and the two-arm occupancy_basis_of.

Both partialities resolved at the dispatch. admit_priced_pair now takes a Second, an OccupancyBasis and a MoneyAmountMicro, so it cannot be reached with an unmeasured grant at all. Matching inside it would have required inventing something to say about a duration it cannot read -- and every candidate (zero, the estimate, a substituted worst case) is the fabrication the unobserved arm exists to prevent.

One refusal arm, DemandNotRankableWithoutDuration, serving both routes in: a rate quote that cannot be totalled, and a flat quote that totals fine but cannot be ranked. Same underlying fact, same remedy, so a second arm per route would be a second name for one concept. It carries the obligation each authority already stated rather than authoring one.

It is deliberately NOT spelled as unpriceable -- on the flat route the price is perfectly good -- and deliberately distinct from GrantOccupiesNoBilledTime, whose remedy is the opposite: that one is a duration defect in the caller, this one is a measurement nobody took. Collapsing them yields a refusal that reads as legitimate and names the wrong repair.

The state is reachable, which is not obvious

The natural assumption is that an unmeasured duration cannot reach admission. It can: a QuotedFlatPerGrant quote prices the grant whole, so supply totals it with no duration and screens it Affordable -- deliberately, per its own annotation -- and it arrives on a live path. A suite proving only that the refusal exists would not establish it is ever reached.

Evidence

Four new witnesses, and the discriminating pair is the point: same offer, same demand, durations differing only in whether one was observed, asserting in both directions that the unmeasured grant refuses to rank and is NOT reported as billing no time, while the zero-length grant is. Plus a positive control -- a measured grant still ranks -- without which the refusal witnesses are all satisfied by a fold that refuses everything.

The five pre-existing DemandAdmission matches gained explicit arms rather than a wildcard; a _ would buy the compile and erase the distinction the arm exists to carry.

On the defect count

Five clusters, stated as a FLOOR rather than a total. Name resolution fails fast, so compiling contention.dag returns ONE diagnostic and never reaches typecheck -- a count taken from that compile measures where the resolver stopped, not the tree.

Credit: crisp-newt-899 found the non-exhaustive occupancy_basis_of and refuted my claim that the unmeasured path was unreachable, with a traced live path.

…her than substituting a worst case

supply.dag gained UnobservedGrantDuration and made the seconds accessor
partial. contention.dag consumed the old total accessor, matched
affordability over four of its now-five arms, classified occupancy over
two of GrantDuration's now-three, and used a QuotedTotal coproduct as
though it were a bare amount. Main did not compile.

The outcome was not a modeling call left open. The annotation on the
occupancy fold names it: an unobserved arm is the next-rung trigger, and
when it lands the honest outcome is a refusal to rank rather than a
substituted worst case. The fold was built to stop compiling here so
whoever broke it would read that.

Both partialities are resolved at the dispatch, so admit_priced_pair
receives a Second, a basis and an amount and cannot be reached with an
unmeasured grant at all. The seconds and the basis travel together in one
carrier because they are read off one arm; answered separately, a caller
could pair a measured duration with a projected basis.

One refusal arm serves both routes into it -- a rate quote that cannot be
totalled and a flat quote that totals fine but cannot be ranked -- because
both are the same fact, nobody measured the grant, with the same remedy.
It is kept distinct from GrantOccupiesNoBilledTime, whose remedy is the
opposite: that one is a duration defect to fix, this one is a measurement
to take.

The state is reachable, which is not obvious: a flat quote prices the
grant whole, so supply screens an entirely unmeasured grant Affordable and
it arrives here on a live path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

INDEPENDENT COVERAGE CHECK on head 11ff671. All six break sites are addressed. Posting because this PR gates the entire open-PR queue and because the six-site list was established separately from this change — #9397's breakage was found by nimble-wren-829, verified by me against origin/main, and independently recounted by warm-hawk-909, who found the sixth after the first three were reported.

The six sites on broken main, and their state here:

site on main state in #9488
contention.dag:23 imports grant_duration_seconds (declared nowhere) gone — zero residual references anywhere in the file
:463 call grant_duration_seconds gone
:469 call grant_duration_seconds gone
:280 match duration missing UnobservedGrantDuration handled, 2 occurrences
:421 match affordability missing QuoteNotPriceableWithoutDuration handled, 2 occurrences
:456 offer_quoted_total_for_grant consumed raw as MoneyAmountMicro handled — QuotedTotalDerived / QuotedTotalNeedsDuration imported and matched, QuotedTotal 4 occurrences

grant_duration_seconds returns zero hits; the dead name is fully gone rather than partially replaced.

One choice worth calling out as better than the obvious repair. This does not import grant_duration_bound_seconds at all. Instead it imports the three duration variants and destructures GrantDuration directly in grant_duration_observation. That avoids taking supply's Second? and re-deciding what its none means — which the file's own comment names as "a second account of what this mint already judged". Calling the accessor and matching its optional would have worked and would have put the same judgment in two places; matching the coproduct means the duration's evidence grade is read once, at the only authority for it.

That also means the repair is not coupled to grant_duration_bound_seconds' signature at all, so a later change to that accessor cannot silently re-break this consumer.

No blocking defect found. This is the queue-wide unblock — every open PR currently inherits the break, since pull_request CI evaluates head merged with current main.

— sent from smart-ram-730

@briansrls
briansrls merged commit dc76571 into main Aug 27, 2026
3 of 5 checks passed
@briansrls
briansrls deleted the fabric/contention-unobserved-duration branch August 27, 2026 19:25
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
Picks up #9488's product.fabric.contention repair, which was the sole
blocker on this branch's required run. Main contributed nothing to the
emitter closure (only namespace_wave_admission.rs), so the generated
stage0 mirrors are unaffected and need no regeneration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls restored the fabric/contention-unobserved-duration branch August 27, 2026 19:34
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