Skip to content

Three scan-producer defects that #11564 merged without - #11656

Merged
briansrls merged 12 commits into
mainfrom
fix/scan-producer-digest-and-outcome
Sep 20, 2026
Merged

briansrls merged 12 commits into
mainfrom
fix/scan-producer-digest-and-outcome

Conversation

@briansrls

@briansrls briansrls commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Three defects from review 67692 that never reached main, cherry-picked onto current main.

Provenance — corrected

This was my error, not a merge-queue defect. An earlier version of this body claimed #11564 merged at a superseded head and framed it as a queue hazard. That is false and the correction matters more than the claim did.

PR #11564's branch is census/scan-and-observation, head 5e5f060b. I pushed the fixes to census/scan-observation-record — a different, similarly-named branch, which is the dead branch from the mis-cut PR #11541. The queue merged exactly the head attached to the PR, correctly. I inferred a queue defect from "fixes absent from main" plus a later push timestamp, without checking that the branch I pushed to was the PR's branch.

What was live on main

1. The body digest hashed the query. scan_observation stored content_hash_atom(value: query) into a field documented as "what makes the stored bytes checkable without re-reading them". Every record in a scan carried the same digest, so a reader checking bytes against it got a green establishing nothing — §5 fabricated plausible output.

Repaired one field over from where the module already says this honestly: ObservationDigestStanding = DigestUnobservable | DigestObserved, beside the ObservationBudgetStanding that carries BudgetUnobservable for the same transport for the same reason. This transport hands back a decoded shape and exposes no raw body, so there are no bytes to hash.

2. The module's product was unreachable. scan_partition dropped walked.hits, so scan_hits_if_declared_population(receipt, hits) asked for a list no caller could obtain — §3c dangling, and it was the stated product.

The old annotation's reasoning was right — a reader handed a bare list cannot see the standing — and the answer is a coproduct rather than a gate. After a further round, the binding is structural rather than merely colocated: ScanOutcome is sole_constructor and is minted only inside scan_partition, where the receipt and the hits both originate from one walked state. The exported (receipt, hits) mint is gone, so an outside caller can no longer pair a green receipt for population A with hits from population B.

3. The pairing obligation was asserted in prose. The witness header claimed it was "met by scan_partition"; no claim invokes scan_partition, and an annotation is never evidence that a machine claim holds. The header now states the gap, why a lane with no network or credential cannot close it, and exactly what does.

Evidence

The freely-testable judgement is scan_is_a_declared_population over a supplied receipt, and the file's pre-existing pair is its wall and control. A later round of this PR added two claims that were byte-identical to that pair and cited them as coverage for the ScanOutcome repair, which they never reached; they are deleted and the rationale moved onto the pair that carries it.

Witnesses may freely construct and test the disposition — it carries no receipt and authorizes nothing. What they cannot mint is the authoritative ScanOutcome that binds a disposition to a scan receipt. That is the wall working, not lost coverage — the live route that would justify minting one is still missing, and the header says so.

🤖 Generated with Claude Code

Review 67692 found three, and all three are real. Two of them are the same mistake
wearing different clothes: a field filled with whatever was in reach, and a wall
built where nothing could reach it.

THE BODY DIGEST HASHED THE QUERY. scan_observation stored
content_hash_atom(value: query) into a field the record type documents as "what
makes the stored bytes checkable without re-reading them". Every record a scan
emitted therefore carried the SAME digest, and a reader checking stored bytes
against it would have got a green establishing nothing about the bytes. That is
section 5's fabricated plausible output exactly -- not a wrong number, a number that
cannot be wrong because it was never about the thing it names.

THE REPAIR IS TO SAY IT CANNOT BE TAKEN, one field over from where this module
already says so honestly. ObservationDigestStanding = DigestUnobservable | DigestObserved,
beside the ObservationBudgetStanding that already carries BudgetUnobservable for the
same transport for the same reason: this transport hands back a DECODED shape and
exposes no raw body, so for a decoded read there are no bytes to hash. The reason
row says that, and says why a hash of the request or of the decoded value would
check a different thing while reading as a body digest.

THE MODULE'S PRODUCT WAS UNREACHABLE. scan_partition returned a ScanReceipt and
DROPPED walked.hits; scan_hits_if_declared_population(receipt, hits) then asked a
caller for a List<CodeSearchHit> that no caller could obtain from this module. The
one function that existed to hand out a population was uninvokable, and the gate it
wrapped was unreachable by construction -- section 3c dangling, and it was the
stated product.

THE ANNOTATION WAS RIGHT AND THE SHAPE WAS WRONG, which is why this is a
construction rather than a plumbing fix. It argued the hits should not be a bare
receipt field because a reader handed a list cannot see the standing. True, and the
answer is a coproduct: ScanOutcome = ScanDeclaredPopulation { receipt, hits } |
ScanNotAPopulation { receipt }. The standing is now the thing you MATCH ON to reach
the hits, so a caller cannot hold the population without passing through the arm
that says it is one, and the failing arm still carries the receipt because a caller
that got nothing needs to know why. The gate function is deleted; nothing validates
what the type makes unconstructible.

THE PAIRING OBLIGATION WAS ASSERTED IN PROSE AND IS NOT DISCHARGED. The witness
header said it was "met by scan_partition, which calls the same folds against
perform_code_search_page: the real route still executes". No claim in this module
invokes scan_partition; nothing in the corpus does; and an annotation is never
evidence that a machine claim holds. The test the obligation sets is that DELETING
THE INTEGRATION MUST MAKE A CONTROL FAIL, and deleting that call site today leaves
every claim green.

I have not manufactured a discharge. The annotation now states the gap, why it
cannot be closed in a lane with no network and no GitHub credential, and exactly
what closes it: one inhabitance claim executed against the live endpoint asserting
the ROUTE -- a real CodeSearchPage reaching scan_observation, and the record
carrying the query it was asked for. What the claims below establish is stated at
its real level: they discriminate where the MEANING is decided, and establish
nothing about whether GitHub emits the shapes they supply.

TWO CLAIMS ADDED for the new construction, a wall and its control:
a_declared_population_hands_out_its_hits, and
a_saturated_walk_withholds_its_hits_and_keeps_the_receipt -- the second is the arm
that matters, because handing a saturated walk's hits out as a population is how a
lower bound gets reported as a total, which this lane has already done once with the
occupancy figures. Both green by execution, with the two pre-existing population
claims re-run beside them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Customer Acquisition Three scan-producer defects that #11564 merged without Sep 18, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 18, 2026 20:09
Review 67936 is right: scan_outcome_receipt had no consumer. git grep returned only
its definition -- both new claims destructure ScanOutcome inline, and no production
module reads it. The PR body stated no trigger for it either, so it was the third
honest state, dangling, rather than a declared frontier.

DELETED RATHER THAN ROUTED, and the choice is worth a sentence because the review
offered both. Routing the two claims through it would have given it an executed call
site, but the only caller would still be a test: no production code needs "the
receipt regardless of arm" today. An accessor whose sole consumer is the witness that
was written to justify it is the redundant work section 2 names, and the claims
already assert the property directly -- ScanNotAPopulation carries the receipt and
the claim reads it. If a real consumer appears, it arrives with them.

The two things the review checked and declined to flag are both right and I am not
touching them: DigestObserved is unconstructed because this transport cannot fill it,
which is the arm's honest shape rather than a dangling declaration; and
scan_partition having no caller is pre-existing from gunbc#11564, named explicitly in
the witness header this PR rewrites rather than papered over.

Both claims re-run green after the deletion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Right — scan_outcome_receipt had no consumer. git grep returns only its definition; both claims destructure ScanOutcome inline and no production module reads it, and the PR body stated no trigger, so it was the third honest state rather than a declared frontier. Deleted in 956eccd.

Deleted rather than routed, since you offered both and the choice is worth stating. Routing the two claims through it would have given it an executed call site, but the only caller would still be a test — no production code needs "the receipt regardless of arm" today. An accessor whose sole consumer is the witness written to justify it is the redundant work §2 names, and the claims already assert the property directly: ScanNotAPopulation carries the receipt and a_saturated_walk_withholds_its_hits_and_keeps_the_receipt reads it. If a real consumer appears, the accessor arrives with them.

Both claims re-run green after the deletion.

On the two you checked and declined to flag — both readings are right and I've left them alone. DigestObserved is unconstructed because this transport genuinely cannot fill it; that's the arm's honest shape, and it's the slot a header-reading transport would fill. And scan_partition having no caller is pre-existing from #11564 rather than introduced here — which is exactly what the rewritten witness header now says out loud instead of the prose that had claimed the pairing obligation was discharged.

One thing worth flagging on this PR's provenance, since it explains why it exists at all: #11564 merged at a superseded head. The fix commit was pushed at 13:20 UTC, the merge ran at 18:55 UTC, and it took a sha from 02:44. The branch tip carries the fix and is not an ancestor of main, so main went live with all three defects from review 67692. This PR is that commit cherry-picked onto current main plus this deletion — no new work beyond it.

— sent from zesty-crane-846

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HOLD — source-reviewed exact head 956eccd8ba8f1b1c10076363a65dc7b602735742.

The digest correction is right, and the witness header now states the undischarged effectful pairing honestly. The population binding is still not structural, however.

scan_outcome(receipt, hits) is an exported pure mint over two independently supplied, freely constructible values. A caller can take a green receipt for population A, pass hits from population B, and receive ScanDeclaredPopulation; it can also construct either ScanOutcome arm directly because the coproduct is not sealed. scan_partition now passes its own walked.hits, which fixes the honest production call, but the module's public construction still admits the exact receipt/population mismatch the repair says is unrepresentable. The new witnesses demonstrate the pure mint over fixtures; they do not bind the positive carrier to the effectful walk.

Separate ordinary judgment from authority: keep a freely testable population disposition, but make the positive outcome sole-constructed and mint it only from scan_partition (or admit that mint solely to the effectful producer). The receipt and hits should have one producer provenance; an exported fn(ScanReceipt, List<CodeSearchHit>) -> ScanOutcome cannot provide it.

History correction before merge: the evidence does not establish a stale merge-queue head. #11564's recorded PR head was branch census/scan-and-observation at 5e5f060b…; commit 0a904e85… is the head of a different branch, census/scan-observation-record. The queue merged the SHA attached to the PR. Please correct the PR body so this is recorded as a sibling-branch routing error, not a queue failure.

Brian Searls and others added 2 commits September 19, 2026 00:03
Side-chat HOLD on 956eccd, and the finding is that my repair fixed the honest call
and left the dishonest one writable.

Two revisions got this wrong in opposite directions. The first kept the hits off the
receipt and offered a gate taking (receipt, hits) -- but scan_partition dropped
walked.hits, so no caller could obtain the list and the gate was uninvokable. The
second replaced it with ScanOutcome and an EXPORTED MINT over two independently
supplied values. scan_partition now passes walked.hits, which is the honest
production call -- but ScanReceipt is freely constructible and ScanOutcome was not
sole_constructor, so a caller could still pair a green receipt for population A with
hits from population B and get ScanDeclaredPopulation. Colocated, not bound. The new
witnesses DEMONSTRATED the mint accepting an authored receipt beside an
independently authored list, which is the tell I wrote and did not read.

THE CARRIER IS NOW sole_constructor AND IS MINTED ONLY INSIDE scan_partition, in the
fold that HAS the walk state -- the receipt and the hits come from one `walked` and
cannot come from anywhere else. scan_outcome is deleted; the branch is inline.

THE CLAIMS MOVE TO THE JUDGEMENT, WHICH IS WHERE THEY BELONG. What is ordinary and
freely testable is scan_is_a_declared_population over a supplied receipt; what is
authority is the carrier. a_saturated_walk_is_not_a_declared_population is the wall
and an_exhausted_enumerable_walk_is_a_declared_population the control, both green,
with the two pre-existing population claims exercising the same fold beside them.

That the witnesses can no longer construct ScanDeclaredPopulation is the wall
working rather than a coverage gap: the live route that would justify minting one is
still missing, and the header this PR already rewrote says so instead of claiming
otherwise.

Main merged in; the PR still contributes only its three files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE APPROVE — exact head bf3d2ece505efbf722f19372c224e85471715d2a.

GitHub will not let this connected account formally approve its own PR, so this COMMENT is the explicit side-chat source sign-off.

The prior HOLD is closed at the construction boundary, not merely for the honest caller:

  • ScanOutcome is now sole_constructor.
  • The only production-positive mint is inline inside scan_partition, after one walk, using receipt and walked.hits from that same walked value.
  • The exported (receipt, hits) -> ScanOutcome mint is gone, so a receipt for population A can no longer authorize hits from population B.
  • Hermetic claims now exercise the ordinary judgment scan_is_a_declared_population; they do not receive authority to manufacture ScanDeclaredPopulation.
  • The false query-as-body-digest is replaced by DigestUnobservable, and the still-missing live route pairing is stated as missing rather than discharged in prose.

No blocking source finding on this head.

Landing gate: this approval is SHA-specific. The exact-head witnesses run is still nonterminal as I write this; do not merge until required CI is terminal-success on this SHA and the PR head still equals this SHA.

Nonblocking provenance correction: the PR body still calls #11564 a merge-queue/superseded-head incident. GitHub's history showed the 13:20 fix on sibling branch census/scan-observation-record, while PR #11564's head branch was census/scan-and-observation. The queue merged the PR head it was given. Please correct that incident description so this does not become evidence of a queue hazard it did not establish.

…ched

Review 68013, and this one is worth stating exactly because the defect is in the
EVIDENCE rather than the code.

The two claims I added were byte-identical in subject, inputs and expectation to
claims already in this file. a_saturated_walk_is_not_a_declared_population is the
same call as an_exhausted_walk_over_a_saturated_query_is_not_a_population;
an_exhausted_enumerable_walk_is_a_declared_population is the same call as
an_exhausted_walk_over_an_enumerable_query_is_a_population. Two names, one fact, run
twice -- section 2 duplicated work and section 3 nicknaming, at the claim layer.

WORSE THAN REDUNDANT, THEY WERE CITED AS COVERAGE THEY DID NOT PROVIDE. The PR body
and the comment above them called them the wall and control FOR THE ScanOutcome
REPAIR, and neither claim mentions or reaches ScanOutcome or scan_partition. No
assertion in that diff discriminated anything the base branch did not already
discriminate, while the body said it did. That is the review tell section 5 names:
evidence cited as coverage that carries no information -- and it is the same shape as
the vacuous check I deleted from gunbc#11596 earlier today, arrived at from the other
direction. There I wrote a check that could not go red; here I wrote checks that were
already green somewhere else and claimed them as new.

The honest position is that the pre-existing pair ALREADY IS the judgement's wall and
control, and what the ScanOutcome repair changes is that no claim can construct the
carrier at all. Both claims deleted; the rationale moved onto the pair that actually
carries it, and now says plainly that being unable to mint ScanDeclaredPopulation
here is the wall working rather than a coverage gap.

Three claims green by execution afterwards, and the diff is 18 lines smaller.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE APPROVE — exact head b9c7b134fcc64cc8d1dbf1ec07296e9a95c6c5f2.

GitHub will not let this connected account formally approve its own PR, so this COMMENT is the explicit side-chat source sign-off for the moved head.

I compared this head directly with the previously approved bf3d2ece505efbf722f19372c224e85471715d2a. The delta is confined to dag/test/claim/ci_workflow_scan_producer_witness_test.dag: the two duplicate judgment claims are removed and their rationale is attached to the pre-existing exhaustive/enumerable wall-control pair. No production declaration, ScanOutcome, scan_partition, digest standing, or effectful route changed.

This is a strict evidence improvement:

  • it removes two names for facts already established;
  • it stops presenting judgment-only claims as coverage of a carrier they cannot construct or a route they cannot reach;
  • it preserves the honest standing that the live network pairing remains undisclosed by the hermetic witness lane.

No blocking source finding on this exact head.

Landing gate: the exact-head witnesses workflow is still nonterminal as I write this. Merge only after required CI is terminal-success on this SHA and the PR head still equals this SHA.

Review 68023, non-blocking. std.content_hash Fnv1a64Structural was imported for
body_digest's old type; replacing it with ObservationDigestStanding left the import as
the only mention of that symbol in the module -- git grep returned the import line
alone. Taken because the file was already open, which is the condition the review
attached to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE APPROVE — exact head 4918b036f2f281dd24c854190f895bf862ecad96.

GitHub will not let this connected account formally approve its own PR, so this COMMENT is the explicit SHA-pinned side-chat sign-off.

The delta from the previously approved b9c7b134fcc64cc8d1dbf1ec07296e9a95c6c5f2 is exactly one deletion: the now-unused std.content_hash.Fnv1a64Structural import in dag/gunbc/ci_workflow_scan_producer.dag. It changes no type, function, carrier, witness, annotation, or production route. Reverting to the prior head would only restore dead residue; do not revert.

No blocking source finding on this exact head.

Landing gate: freeze this SHA. Merge only after required CI is terminal-success on 4918b036f2f281dd24c854190f895bf862ecad96, and re-read the PR head immediately before enqueue/merge to confirm it still equals this SHA. Any further source push invalidates this sign-off.

Review 68029, blocking, and correct. ObservationDigestStanding was added to the
import list when body_digest changed shape, but the module only CALLS
digest_unobservable() and never names the type -- grep returned the import line
alone. Same residue as the Fnv1a64Structural line one above it, introduced in the
same change that removed that one.

AUDITED THE WHOLE IMPORT SET RATHER THAN THE ONE LINE, because two instances of one
defect in consecutive reviews is a population, not a coincidence. Five of the 32
imported symbols are unused: CodeSearchPage, code_search_hits_read,
GithubObservationRequest, ObservationDigestStanding, ObservationBudgetStanding.

ONLY THE FOURTH IS MINE. The other four arrived with gunbc#11564 and are untouched
by this PR. They are NAMED here rather than deleted: this PR's approval is head-
pinned by its reviewer, I have already cost one re-review by taking an optional
cleanup on it, and widening the diff by four pre-existing lines is that same mistake
a second time. They are a real finding and belong in a follow-up, not hidden in a
commit about something else.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Correct and blocking — fixed in 66f97ff. ObservationDigestStanding went into the import list when body_digest changed shape, but the module only calls digest_unobservable() and never names the type. Same residue as the Fnv1a64Structural line directly above it, introduced by the same change that removed that one.

I audited the whole import set rather than the one line, since two instances of one defect in consecutive reviews is a population rather than a coincidence. Five of the 32 imported symbols are unused:

symbol origin
ObservationDigestStanding this PR — deleted
CodeSearchPage #11564, pre-existing
code_search_hits_read #11564, pre-existing
GithubObservationRequest #11564, pre-existing
ObservationBudgetStanding #11564, pre-existing

I deleted only mine, and I want to be explicit about why the other four are named rather than removed. This PR's source approval is head-pinned by its reviewer, and I have already cost one re-review by taking an optional cleanup on it — the Fnv1a64Structural deletion, which was non-blocking and which I took because the review said "if you touch the file again." Widening this diff by four pre-existing lines would be that same mistake a second time, on a PR whose head has now moved four times.

So they are a real finding and they belong in a follow-up, not buried in a commit about something else. If you'd rather they came out here, say so and I'll take them — but I'd be making the same trade I just got wrong.

— sent from zesty-crane-846

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE APPROVE — exact head 66f97ffa3f33e4fdac3e78c5e953766ce7c6a686.

GitHub does not permit this connected account to formally approve its own PR, so this COMMENT is the explicit SHA-pinned source sign-off.

The move from 4918b036… is justified under the landing rule: it removes exactly one unused import, ObservationDigestStanding, in response to a blocking REQUEST_CHANGES. The module calls digest_unobservable() but never names the imported type. The compare contains one file, zero additions, one deletion, and no semantic, witness, carrier, or route change.

The broader audit was handled correctly. CodeSearchPage, code_search_hits_read, GithubObservationRequest, and ObservationBudgetStanding predate this PR; removing them here would widen a head-pinned repair for optional cleanup. Record them for a follow-up rather than taking another push here.

No blocking source finding on this exact head. Freeze it.

Landing gate: merge only when the PR head still equals this full SHA and required CI for this SHA is terminal-success. At review time the exact-head witnesses run was still pending.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE APPROVAL WITHDRAWN — HOLD on exact head 66f97ffa3f33e4fdac3e78c5e953766ce7c6a686. DO NOT QUEUE OR MERGE.

A compiler fact established during #11669 invalidates this PR's central wall: in the current language, sole_constructor is discarded on a coproduct RHS. This PR declares:

type ScanOutcome sole_constructor
  = ScanDeclaredPopulation { receipt: ScanReceipt, hits: List<CodeSearchHit> }
  | ScanNotAPopulation { receipt: ScanReceipt }

The annotation and my prior approval both relied on that coproduct being sealed. It is not. An outside module can still author ScanDeclaredPopulation directly, pairing a green receipt for population A with hits from population B. Therefore the dishonest construction that the PR exists to remove remains writable even though the honest scan_partition route is correct. Green CI cannot discharge this because the compiler carries this coproduct-seal loss as a known expected-red gap.

Required repair: use the construction the language actually enforces — an ordinary, freely testable disposition inside a sole_constructor record, minted only in scan_partition from one walked state. For example:

type ScanDisposition
  = ScanDeclaredPopulation { hits: List<CodeSearchHit> }
  | ScanNotAPopulation

type ScanOutcome sole_constructor {
  receipt: ScanReceipt
  disposition: ScanDisposition
}

The record must be constructed only after the walk, with receipt and walked.hits from that same state; no exported mint may accept them independently.

This supersedes every prior source-approval comment on #11656. The operator should not enqueue this SHA.

Brian Searls and others added 2 commits September 19, 2026 08:57
…oduct

Side-chat SOURCE APPROVAL WITHDRAWN on 66f97ff, and the withdrawal is right. The
compiler fact that broke Cut 1's first attempt breaks this one identically:
sole_constructor is threaded into the anonymous-record arm of parse_type_body_after_eq
and DISCARDED on every other `=` right-hand side, coproducts included -- a documented
hole with its own probe and an expected-red row.

So `type ScanOutcome sole_constructor = <coproduct>` sealed nothing, and an outside
module could still author ScanDeclaredPopulation { receipt: from_population_A, hits:
from_population_B } -- the exact invalid state the seal was introduced to remove. The
honest scan_partition path was correct throughout; the dishonest construction stayed
available beside it, which is the same shape as the gate it replaced.

GREEN CI DID NOT AND COULD NOT DISCHARGE THIS. Build, floor, heal and the aggregate all
passed at that head. The defect is a compiler BEHAVIOUR carried as a known expected-red,
so no lane was ever going to report it, and I had cited that green four times while
asking for the merge.

THE REPAIR IS THE SHAPE THE LANGUAGE ENFORCES:
  ScanDisposition = ScanDeclaredPopulation { hits } | ScanNotAPopulation   ordinary
  ScanOutcome sole_constructor { receipt, disposition }                    sealed record
minted only inside scan_partition, where the receipt and walked.hits come from one walk
state. No exported factory takes a receipt and hits independently, because there is no
exported factory at all.

The two population claims are unchanged and green: they test
scan_is_a_declared_population over a supplied receipt, which is the ordinary judgement
and is exactly what should remain freely testable once the carrier is authority.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review 68327, non-blocking. The annotation described the sole_constructor-on-a-coproduct
hole from the parser's own note -- accurate, but the corpus already carries that fact as
a class: gunbc.recurring_failure_mode modifier_accepted_on_a_shape_its_check_cannot_see,
with its probe and next-rung trigger. Section 3 asks for the symbol rather than a
restatement, because a restatement decays independently of the row it paraphrases.

This is the inverse of the defect gunbc#11669 fixed two commits ago, where I cited a
class that did not exist. Same rule read from the other side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HOLD — exact head 626b44038d2974958814f13c05f2cef3f91dd2a0.

The submitted repair is correct: ScanDisposition is the ordinary coproduct, ScanOutcome is now a sole_constructor record, and the only record constructions are inside scan_partition, where receipt and walked.hits come from the same walked state. The prior cross-population constructor is closed at the language boundary rather than by annotation.

One older scan-producer defect remains blocking, and this is the point to close it before the census route starts consuming the sealed outcome.

P0 — caller-controlled per_page: Int can turn GitHub's silent clamp into a false declared population

scan_partition accepts any Int, and deepest_retrievable_page computes 1000 / per_page from the requested value. GitHub's Search Code endpoint has a maximum page size of 100. GitHub's pagination behavior clamps values above an endpoint maximum rather than necessarily refusing them.

Concrete counterexample:

per_page requested = 1000
bound              = 1000 / 1000 = 1
GitHub effective page size = 100
first page returns 100 of total_count 500
exhausted_if_short(100, 1000) => StoppedExhausted
partition_enumerability(500, 1) => PartitionFullyEnumerable
scan_is_a_declared_population => true

The new sealed record then authoritatively carries ScanDeclaredPopulation with only 100 of 500 hits. This is the exact lower-bound-as-population state the module exists to exclude. per_page = 0 also reaches division by zero; negative and non-domain values remain representable.

The witness annotation saying the derived bound means a caller cannot ask outside the endpoint's serviceable shape is therefore false for the page-size dimension.

Required repair: make effective page size structural before the first request. Prefer either:

  • remove the caller parameter and always use the endpoint's declared max_per_page; or
  • introduce a constructor/refusal for a CodeSearchPageSize in 1..=100, and derive/pass the bound from that admitted value.

Add a wall showing an above-maximum request cannot reach ScanDeclaredPopulation, plus the valid-100 control. Do not merely clamp in one fold while sending the original value on the wire; one admitted value must own both the request and bound.

No other blocking source finding on this exact head. Exact-head CI is still nonterminal as I write this, but this HOLD is source-independent.

Side-chat HOLD on 626b440. The seal repair was accepted; this is the older defect
underneath it, and it matters more now that the result carrier is authoritative.

scan_partition took `per_page: Int` and deepest_retrievable_page computed
retrievable_result_ceiling / per_page with nothing constraining the value. A caller
passing 1000 gets a bound of ONE PAGE. The walk reads that page, finds it short, and
reports StoppedExhausted -- so scan_is_a_declared_population answers TRUE and a
partial first page is handed out as a complete population.

THAT IS THE SAME SHAPE AS EVERYTHING ELSE THIS MODULE IS ABOUT, arriving through a
PARAMETER rather than an observation: a value that cannot support the conclusion drawn
from it, with nothing recording the difference. And the domain was already declared --
extdeps.github.github max_per_page = 100 sat in the corpus while the division ignored
it.

THE ADMISSION LIVES IN extdeps, not in this lane, because 1..max_per_page is the
ENDPOINT'S CONTRACT rather than a policy a caller may choose. CodeSearchPageSize is
sole_constructor, so the admission is its only minter and an unadmitted Int CANNOT
REACH THE DIVISION -- the difference between refusing a bad bound and being unable to
compute one. scan_partition takes the admitted carrier and unwraps it once, inside.

THREE CLAIMS, TWO WALLS AND A CONTROL:
  a_page_size_above_the_endpoint_maximum_is_refused   -- the 1000 case, which used to
    produce a one-page bound
  a_page_size_below_one_is_refused
  the_endpoint_maximum_itself_is_admitted_and_bounds_the_walk  -- the control, without
    which refusing everything would satisfy both walls and make the producer uncallable

the_page_bound_comes_from_the_ceiling is re-shaped rather than deleted: it asserted the
same derivation through the old bare-Int signature, and it now routes through the
admission, so the claim count is unchanged at 16 across that edit.

Sixteen claims green by execution.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE HOLD — exact head eb3b74a7de33433a319a1befb6250a065e0f9069; logic accepted, one stale source claim remains.

The blocking per_page defect is closed correctly:

  • CodeSearchPageSize is a sole_constructor record in the endpoint authority.
  • admit_code_search_page_size is the only constructor and refuses < 1 and > max_per_page.
  • scan_partition accepts the admitted carrier, unwraps it once, sends that same value on the wire, records it in the receipt, and derives the page bound from it.
  • The authoritative ScanOutcome remains a sealed record constructed only inside scan_partition from one walked state.
  • The two refusal claims and valid-maximum control discriminate the repaired boundary.

I found no remaining logic blocker.

One witness annotation still describes the previous shape and is now false. Above an_exhausted_walk_over_an_enumerable_query_is_a_population, it says a claim able to construct ScanDeclaredPopulation could pair a receipt from A with hits from B, and that being unable to mint ScanDeclaredPopulation is the wall. In the repaired design, ScanDeclaredPopulation is deliberately an ordinary ScanDisposition arm and may be constructed freely; that is safe because it carries no receipt. The thing outside modules cannot construct is the authoritative ScanOutcome record that binds a receipt to that disposition.

Please rewrite that block to say, in substance:

ScanDisposition is the ordinary, freely testable judgment. Claims may construct ScanDeclaredPopulation { hits }, but that carries no scan receipt and therefore no population authority. ScanOutcome is the sealed carrier; only scan_partition can bind the receipt and disposition from one walk. The hermetic claims test scan_is_a_declared_population and do not discharge the live route pairing.

The PR body has the same stale sentence — “witnesses can no longer construct ScanDeclaredPopulation” — and should be corrected body-only to “witnesses cannot mint the authoritative ScanOutcome.”

After the source annotation correction, freeze the new head and request exact-head re-review. Required CI on this SHA is still nonterminal, but the HOLD is solely the false source claim above.

Brian Searls and others added 2 commits September 19, 2026 11:08
Side-chat HOLD on eb3b74a, logic approved, one stale annotation. It said a claim able
to construct ScanDeclaredPopulation could pair a receipt for one population with hits
from another, and that being unable to mint it here was the wall.

THAT IS NOW FALSE, AND IT DESCRIBES THE SHAPE THIS PR REPLACED. ScanDeclaredPopulation
is an ORDINARY ScanDisposition arm. Any module may build one, and that is safe
precisely because it carries NO RECEIPT and so authorizes nothing. The unconstructible
thing is ScanOutcome -- the sealed record that BINDS a receipt to a disposition -- so
the invalid state the carrier removes is a receipt from walk A beside hits from walk
B, not the existence of a disposition value.

The note survived the very refactor that made it wrong: I split the coproduct into
disposition-plus-sealed-record and carried forward a sentence written about the sealed
coproduct. Same class as the two annotation defects on gunbc#11669 -- prose describing
a construction the code no longer has -- and the third instance in this lane, which is
why it is worth a commit message rather than a quiet edit.

Claims unchanged at 16, no logic touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review 68391. CodeSearchPageSize and CodeSearchPageSizeAdmission went into the witness
import list when I added the page-size admission, and the module never names either:
every claim destructures the ...Admitted / ...Refused arms, which are separate symbols,
and binds page_size positionally.

THIS IS THE THIRD INSTANCE IN THIS PR OF ONE CLASS. Two earlier commits here fix it one
file over -- "The import I added for a type this module never names" and "Drop the
import whose last use this PR removed" -- and I wrote a sweep for it at the time. I ran
that sweep on the PRODUCER module and never on the witness module, so the instrument
existed and was pointed at one of the two files I had touched.

RAN IT ON THE WITNESS FILE NOW: 45 imported symbols, five unused. Two are mine and are
deleted. Three -- CodeSearchPageComplete, CodeSearchPageTruncated, ObservationCompleteness
-- arrived with gunbc#11564 and are NAMED rather than removed, which is the disposition
the side chat endorsed when the same split came up on the producer: this PR's approval is
head-pinned and widening the diff by pre-existing lines is the trade I already got wrong
once. They belong in the follow-up that also takes the producer's four.

Claims unchanged at 16, no logic touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Correct — deleted in 8465533. CodeSearchPageSize and CodeSearchPageSizeAdmission went into the import list when I added the page-size admission, and the module never names either: every claim destructures the …Admitted/…Refused arms, which are separate symbols, and binds page_size: positionally.

This is the third instance of one class in this PR, and the part worth recording is why it survived. Two earlier commits here fix it one file over — "The import I added for a type this module never names" and "Drop the import whose last use this PR removed" — and at the time I wrote a sweep for exactly this. I ran that sweep on the producer module and never on the witness module, so the instrument existed and was aimed at one of the two files I had touched.

Ran it on the witness file now: 45 imported symbols, five unused.

symbol origin
CodeSearchPageSize this PR — deleted
CodeSearchPageSizeAdmission this PR — deleted
CodeSearchPageComplete #11564, pre-existing
CodeSearchPageTruncated #11564, pre-existing
ObservationCompleteness #11564, pre-existing

The three pre-existing ones are named rather than removed, which is the disposition the side chat endorsed when this same split came up on the producer module: this PR's approval is head-pinned, and widening the diff by pre-existing lines is a trade I already got wrong once today. They belong in the follow-up that also takes the producer's four — seven in total across the two modules, one small PR.

Claims unchanged at 16; no logic touched.

— sent from zesty-crane-846

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOURCE APPROVE — exact head 846553306ee9a2aa4b98493b2579478253e0486a.

GitHub does not permit this connected account to formally approve its own PR, so this COMMENT is the explicit SHA-pinned source sign-off.

Both items from the prior HOLD are closed without changing logic:

  1. The witness annotation now names the correct construction boundary. ScanDeclaredPopulation is an ordinary ScanDisposition arm and may be freely constructed; it carries no receipt and authorizes nothing. The sealed authority is ScanOutcome { receipt, disposition }, whose only constructions remain inside scan_partition, binding one walk's receipt to that same walk's disposition/hits.
  2. CodeSearchPageSize and CodeSearchPageSizeAdmission were unused only in the witness import list and are deleted. The admitted/refused arms and admission function that the claims actually name remain. The three older unused imports are correctly recorded for a follow-up rather than widening this head-pinned repair.

I rechecked the page-size admission and sealed-record repairs at this head. CodeSearchPageSize is admitted in the endpoint authority before division; the same admitted value owns the wire request, bound, and receipt. ScanOutcome is a sole_constructor record, and no exported factory accepts receipt and hits independently.

No blocking source finding remains on this exact head.

Landing gate: freeze this SHA. Merge/queue only after all required checks for 846553306ee9a2aa4b98493b2579478253e0486a reach terminal success and the PR head still equals this SHA. Do not take the seven pre-existing unused-import cleanups in this PR.

@briansrls
briansrls added this pull request to the merge queue Sep 20, 2026
Merged via the queue into main with commit 149c459 Sep 20, 2026
4 checks passed
@briansrls
briansrls deleted the fix/scan-producer-digest-and-outcome branch September 20, 2026 17:39
briansrls pushed a commit that referenced this pull request Sep 20, 2026
Side-chat REWORK. Part 1 (external blockers as prose) was withdrawn after I
traced that startable authorizes closing-contract authoring rather than
implementation dispatch. Parts 2 and 3 stood, and both were my errors.

THE CENSUS ROWS ARE NOT AN AUTHORITY. The page said the 57 transcribed rows
were dissolved by the scan producer. That is materially wrong in two ways.
The economic readings attached to those rows were shown not to have the
meanings assigned to them -- wall duration is not summed runner occupancy, an
admission delay is not a runner queue delay, a provider declaration can
outlive provider execution, and adoption is not spend -- so the derived
runner-minutes and ARM-tier totals do not follow, and "five carry
CostOpportunity" must not be quoted as a finding. And the scan producer is
workflow-level, so it is necessary and NOT sufficient: the facts those rows
need are job-level. The job-level arc is now a roadmap node instead of a
sentence.

ACQUISITION IS MODELED, NOT ACHIEVED. The page called gunbc#11552 an
end-to-end App manifest flow. Its own route tells the operator to paste the
manifest into the create form's manifest field; GitHub exposes no such field
and the manifest protocol needs a form POST. I watched that step fail live in
this session and wrote "end to end" anyway. Registration and INSTALLATION are
also two facts, and gunbc#11677 consumes both rather than creating either.
That is now a node with the remaining work named.

EXTERNAL BLOCKERS ARE GONE. gunbc#11552, #11564, #11656, #11669, #11671,
#11677 and #11679 are all merged. The nodes and the page said otherwise.

The two real prerequisites are now EDGES rather than prose, which is the
repair the reviewer asked for: the installation token depends on the App
existing, and the job-level reprojection depends on the token.

Projection reconciles 146 -> 148: two nodes and their closing-contract
carriers, minus the two carriers the new edges remove from the startable set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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