Skip to content

Service config values face the reference judgment: per-field, with the unjudged set typed and counted - #9028

Merged
briansrls merged 10 commits into
mainfrom
session/merry-wolf-442
Aug 24, 2026
Merged

briansrls merged 10 commits into
mainfrom
session/merry-wolf-442

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

What was wrong

infer_item sent every service config { .. } property to
infer_auth_source_properties, which inferred a property if its name was
svc_auth_source
and otherwise returned it unchanged with diagnostics: [].
Five of the six config fields were therefore never asked a question of any kind
— not "does this name resolve", not "does it resolve to one thing", not
anything. The function name declared the narrowing honestly; nothing else did,
and no count existed.

That else-arm is DESIGN §5's absorbing fallback in its quietest form:
not-applicable rendered as nothing-wrong. It reads as "nothing to do for this
property" and means "this property is not judged".

The headline specimen — verifiable in two greps

auth: Bearer.

  • Bearer is a declared variant of AuthScheme in dag/std/types.dag
    (Bearer | Header { name } | Basic { username } | ApiKey).
  • The files using it already carry import std.types { .., AuthScheme } —
    extdeps/github/pulls, extdeps/github/gists, extdeps/sec/edgar_rest,
    extdeps/tailscale/acl_api all list it explicitly.

23 occurrences (21 Bearer, 2 Header) of a correct reference to a declared,
imported coproduct, never once checked. No missing declaration, no missing
import, no ambiguity, no grammar question — every confounder removed. The
defect is the traversal and nothing else.

What this changes

The judgment is per FIELD, not per block. A config block is not one kind of
thing. Inside a single block: endpoint: default_api_base is a module-level
reference to a real data row; auth: Bearer a declared variant; auth_input: access_token names a service-scoped input whose binder kind nothing tracks;
requests: 5000 an ordinary literal. So "walk the block" and "walk none of it"
are wrong for the same reason — both answer at block grain a question decided
per field.

infer_service_config_properties judges svc_endpoint, svc_auth and
svc_auth_source.

The unjudged set stops being silent. A field the judgment does not yet reach
emits ServiceConfigReferenceJudgmentDeferred — typed, located, carrying its
own next-rung trigger, non-blocking (DESIGN §4b FrontierAccepted: the phase
result is still Accepted). The empty diagnostic list destroyed the deficit's
frequency by construction; this restores it. The variant is added to
cli_run.rs's advisory allowlist deliberately: a non-blocking variant absent
from that list is counted by neither predicate, which is the
frontier-claiming-to-be-counted failure that file's own comment names.

Two deferrals, each with its trigger stated in the diagnostic:

field trigger
svc_auth_input the referent is a service-scoped input; the binder authority carries no service/operation parameter kind to resolve it against
svc_rate_limit per and scope are bare identifiers with no declaration; judged once grounded as cited rows in the extdeps module that publishes the limit

Two deletions, and why they are deletions rather than groundings

retry: is deleted at the root — the ServiceConfig field, the parse arm,
service_config_properties' parameter, the service_config_retry accessor, and
21 corpus blocks.

  • Zero consumers, measured. service_config_retry had no callers anywhere
    in the tree. 05_emit_rust.dag contains no occurrence of retry or
    backoff. v1_interpreter.rs (16,976 lines, the REST realization) has one
    match for either word and it is an unrelated doc comment. Neither
    realization retries anything.
    Nothing in this PR changes that, and nobody
    should read a runtime into the carrier's removal.
  • Wrong layer. max_attempts: 3 is our policy authored inside a cited
    upstream module. §3 puts business policy in the workflow layer and names the
    tell exactly: a literal carried where a parameter should be received. So
    grounding these atoms would have landed a §3 inversion inside the diff
    repairing a §3 gap.
  • rate_limit is deliberately kept: GitHub publishes its 5000/hour core
    limit, so a request ceiling is a fact about the dependency and belongs in
    extdeps. Its grounding is the deferral row above, not this PR.

8 auth: None lines deleted. AuthScheme has no None variant, but auth
is already Node? — absence already is the representation for "this service
has no auth", and six services already demonstrate it. A NoAuth variant would
be two spellings of one fact (§3) with the arm reading as
not-applicable-rendered-as-a-value.

Ordering: why the traversal is not simply switched on for every field

svc_auth_input and svc_rate_limit are deferred rather than judged because
neither has a referent to resolve to. auth_input: names a service-scoped
input and the binder authority carries no service/operation parameter kind;
per: and scope: are bare identifiers with no declaration anywhere in the
corpus. Turning the judgment on for those fields today would produce reds with
no repair available to the author — 32 occurrences whose only closing move
would be to quote the word, which is string anemia and is exactly the
substitution this work exists to prevent.

So each is a declared, counted deferral carrying the grounding that closes it.
The three fields whose values ARE already grounded are judged now.

Measured, with the discriminating RED

Instrument: gunbc compile --entry <file> --target dag, scoped to one module and its
transitive import closure. Every closure carries 52 pre-existing hard diagnostics from
dag/test/manual/command_runner_local_argv_receipt_test.dag (annotation-names-no-subject),
excluded by name below so they cannot mask the subject.

On dag/extdeps/github/checks.dag:

arm hard diagnostics delta
baseline 52 —
auth: Bearer → auth: NotADeclaredScheme 53 undefined variable 'NotADeclaredScheme' (dag/extdeps/github/checks.dag:3784-3802)
control restored 52 refusal gone

52 → 53 → 52, and the delta is exactly one located refusal naming the mutated token. The
svc_auth field is judged now and demonstrably was not before.

Two results that settle open questions: auth: Bearer produces no diagnostic at
baseline, so all 23 Bearer/Header occurrences resolve — the declaration and the import
were both present the whole time and only the judgment was missing. And
endpoint: production_api_base, declared in both extdeps.ebay.ebay and
extdeps.tcgplayer.tcgplayer, compiles clean from both sides with no ambiguity refusal:
listed imports bind ahead of the bare-name census, so there is no misresolution here.

An advisory arm measured by a hard-diagnostic instrument reads zero in both worlds

Worth stating generally, because the whole non-blocking population sits in this trap and
this PR adds a sixth member to it. gunbc compile prints hard diagnostics only. The
deferral is non-blocking by design. So that instrument reports zero deferrals whether the
arm fires on every service in the corpus or never fires at all — the zero carries no
information, and reading it as "clean" would have been a vacuous green.

The way out: flip the variant to blocking in a scratch build so the same occurrences
become printable, and count those. That is what produced the table below — and what caught
the defect in the section after it.

entry hard deferrals when made visible
extdeps/github/checks.dag 52 → 55 svc_rate_limit 1
extdeps/cloud/gcp/iam.dag 52 → 62 svc_auth_input 3, svc_rate_limit 1
extdeps/ebay/oauth.dag 52 → 55 svc_rate_limit 1
extdeps/tcgplayer/catalog.dag 52 → 56 svc_auth_input 1

A related instrument failure from the same night, same family: the first run of this
measurement reported nothing because it piped through head -40, and the 52 pre-existing
diagnostics consumed the window. A filter that truncates — like a log that buffers — renders
"it did not happen" and "you could not see it happen" identically.

What that measurement caught in this change itself

The counts above also carried namespace_root (5 on gcp/iam.dag) and sole_constructor,
reported by an earlier revision of this function as deferred service config fields.
They are nothing of the sort.

item.properties is not a service-config channel. 02_parse.dag mints namespace_root (a
module-scope String literal) and sole_constructor (a Bool literal on a type) onto the
same list the config { } block writes to. So the arm was wrong in two directions, and the
second is worse than the miscategorisation: those values are parser-minted literals with
no authored reference in them, so no reference judgment is owed at all. Rendering
not-applicable as unjudged is precisely the conflation this function exists to remove,
recreated one layer out inside the fix for it.

The reviewable question this generalises to — and it is askable without running
anything, which is why it is worth writing down: what else lands on this channel?
item.properties reads like "this item's properties" and is in fact a shared mint target
for at least three unrelated producers. The channel's denominator is not what its name
suggests, and that is true of every List<Node> side-channel in the tree.

Fixed as shape, not filter: service_config_field_judgment is a total classification
returning FieldJudged | FieldDeferred { trigger } | FieldCarriesNoReference over the
closed set service_config_properties mints, so a new service-config field fails to compile
there rather than silently inheriting whichever arm a wildcard happened to name.

The floor caught a defect in this PR's own cleanup

Worth recording, because 14 of 15 failures were mine and the 15th was the change working.

The first floor run reported failed=15. Fourteen were no field 'auth' on type '' across
cache_layer_planner, hermetic_fixture_realization, reconcile_in_process_cache and
floor_drain_retention — caused by the auth: None removal, which used a line regex
that matched any such line in the corpus. Six of its eight hits were not service config at
all: they are auth fields of CacheInterfaceCatalogFacts record literals under
dag/extdeps/realization/, where None is a legitimate declared variant of that field's
type. All six restored; only the two genuine docker service configs remain removed.

That is the same class as the namespace_root defect above — a name is not a denominator —
arriving through tooling instead of code. The population had already been enumerated
correctly with a brace-matching parser scoped to config { } blocks; the edit then used a
second, unscoped mechanism, and the two were never asserted to agree. Two mechanisms over
one population is a second representation of the denominator
, and it decays silently at the
seam while both halves look correct in isolation.

The verification that catches it is a structural diff over the whole diff, not a count
over the rows you meant to touch — a census can only count what it can see. Classify every
removed and added line and assert every loss is in the intended population and nothing is
gained unintentionally. Run on this PR:

kind count
retry blocks removed 21
auth: None removed (both docker service configs) 2
blank-line tidying 20
lines added 1 (the fixture import below)
unexpected 0

The fifteenth failure, rest_axes_emit_dual_auth_refuses, is a true positive of the new
wall
. Its fixture is a standalone module source string carrying auth: Bearer with no
import, so the newly-judged field correctly refuses an unresolved name and the emit produces
no file for the witness to read. Three sibling fixtures in the adjacent witness (re1d,
re1d_header, re3b) already carry import std.types { AuthScheme } and this one alone did
not — an asymmetry, which is evidence, as against forming an opinion about whether the wall
should have fired. It now carries the same import; the witness's subject is unchanged. The
judgment was not relaxed and the witness was not marked expected-red.

Final state

required-ci: phases_run=4 failed=0, and the floor executed rather than passing vacuously:

required-floor: planned=10789 executed=10789 terminal=10789 passed=10518 known_red_held=35 failed=0
required-regen: first_generation_equal=true

Mirrors are converged against the authority after merging main.

One hole named rather than covered

FieldCarriesNoReference emits nothing, and that is not a silent arm to be closed — it is
genuinely not-applicable, with its reason stated where the arm is. But if a future property
minted onto Node.properties does carry an authored reference, it lands in that arm and
goes unjudged. That is a real hole. It is not one this brief covers, and it belongs to
whoever owns the Node.properties channel — the shape is declared in src/v1/00_core.dag
and the non-service producers are minted in src/v1/02_parse.dag, so the repair sits with
that channel's shape rather than with the service-config judgment.

Widening this diagnostic to cover it would have been the absorbing fallback wearing the
fix's clothes.

Ordering: why the traversal is not simply switched on for every field

svc_auth_input and svc_rate_limit are deferred rather than judged because
neither has a referent to resolve to. auth_input: names a service-scoped
input and the binder authority carries no service/operation parameter kind;
per: and scope: are bare identifiers with no declaration anywhere in the
corpus. Turning the judgment on for those fields today would produce reds with
no repair available to the author — 32 occurrences whose only closing move
would be to quote the word, which is string anemia and is exactly the
substitution this work exists to prevent.

So each is a declared, counted deferral carrying the grounding that closes it.
The three fields whose values ARE already grounded are judged now.

The deferral must not become the conflation one layer out

A counted deferral is only an improvement if nothing downstream reads it as a
pass. Two things keep that honest here, and a reviewer should check both rather
than take the count as coverage:

  • The diagnostic says so in its own text — "This is a counted deferral, not a
    pass: nothing has established that '' names anything" — so a reader who
    meets one occurrence cannot mistake it for a clean judgment.
  • It is non-blocking, which means a green compile-clean run does not assert
    that service config references were checked. It asserts that the three judged
    fields were. If any consumer's else-arm ever treats "no blocking diagnostic"
    as "this position was checked", the deferral has recreated the original
    conflation at one remove — harder to see the second time, because the count
    exists and looks like coverage.

v1 seed admission

00_core.dag, 02_parse.dag and 04_infer.dag are v1 seed files under the
freeze. Admitted under the purpose test in gunbc.v1_maintenance_standing
v1_seed_standing: the change serves the v2 self-host program by closing a
reference-resolution gap in ordinary semantic acceptance. It adds no growth
surface to the seed — it removes one (retry).

Build-surface finding, recorded here so the next lane can find it

Not a fact about this change; a fact about the build surface, and it cost two dead runs
before I understood it. Searchable phrase: ERROR: Remote run exceeded timeout (45m0s).

ctrl-build dispatches BuildBuddy with --timeout ${CTRL_BUILD_TIMEOUT:-45m}. A stage0
seed regen (claim_executor --required-regen) does not fit in 45 minutes, and neither
does a whole-tree compile_clean_diagnostic_histogram. Both of mine were killed mid-run.
Pass ctrl-build --remote --timeout 3h for anything that emits or compiles the corpus.

The reason it costs two runs rather than one is the same conflation this PR is about, one
layer down: the remote log is fully buffered, so nothing streams until the run ends.
"This run is still going" and "this run was killed twenty minutes ago" render identically
for the run's entire life. Print date -u timestamps between steps instead of piping
through tail, which buffers away the very progress that would distinguish them.

Two smaller traps in the same neighbourhood, both self-inflicted here:

  • ctrl-build checks the runner out at your branch head and applies the worktree diff on
    top, so git checkout -- <file> on the runner restores your commit, not main. It
    cannot undo an edit you already committed — which is exactly what the bootstrap ordering
    below needs. Strip the hunk by pattern instead.
  • echo "$(ts) build rc=$?" reports the exit status of the $(...) substitution, not the
    build. A failed build cheerfully printed rc=0 directly above BUILD_FAILED.

Bootstrap ordering (why the first CI run could not have been green)

This diff adds a CompilerDiagnostic variant to the .dag authority and consumes it
from hand-written cli_run.rs. The committed v1_std_core.rs is the generated mirror of
that authority, so until it is regenerated the hand-Rust references a variant the mirror
does not contain — error[E0599]: no variant named ServiceConfigReferenceJudgmentDeferred.
The fix is a regen, and the regenerated mirrors are part of this PR. The mirror is
generated: hand-adding the variant to it to make the build pass is the laundering the regen
gate exists to refuse, and the next regen would revert it.

Scope held

No dag/test/claim expected-red rosters touched. #9020's NamesNothingKnown
disposition unchanged; the refusal belongs in ordinary semantic acceptance, not
in a workflow preparation helper.

gunbc-ci-auto-heal and others added 2 commits August 23, 2026 15:21
…h the unjudged set typed and counted

infer_item sent every service `config { .. }` property to
infer_auth_source_properties, which inferred a property IF ITS NAME WAS
`svc_auth_source` and otherwise returned it unchanged with `diagnostics: []`.
Five of the six fields were therefore never asked a question of any kind.

The headline specimen: `auth: Bearer`. `Bearer` is a declared variant of
`AuthScheme` in dag/std/types.dag, and the files using it already carry
`import std.types { .., AuthScheme }`. 23 occurrences of a correct reference
to a declared, imported coproduct, never once checked — no missing
declaration, no missing import, no grammar question. Only the traversal.

- infer_service_config_properties judges per FIELD, because a config block is
  not one kind of thing: `endpoint:` is a module-level `data` reference,
  `auth:` a declared variant, `auth_input:` a service-scoped input with no
  binder kind, `requests:` an ordinary literal.
- The unjudged set stops being silent. A field the judgment does not yet reach
  emits ServiceConfigReferenceJudgmentDeferred — located, carrying its own
  next-rung trigger, non-blocking (DESIGN §4b FrontierAccepted). The empty
  diagnostic list destroyed the frequency signal; this restores it.
- `retry:` is DELETED at the root — field, accessor, parse arm and 21 corpus
  blocks. service_config_retry had zero callers, and neither realization
  retries: 05_emit_rust.dag has no occurrence of retry or backoff and the
  interpreter's only match is an unrelated doc comment. It was also a §3 layer
  inversion — `max_attempts: 3` is our policy authored inside a cited upstream
  module. rate_limit is deliberately kept: a published request ceiling is a
  fact about the dependency.
- 8 `auth: None` lines deleted. `auth` is already `Node?`, so absence already
  means no auth; a NoAuth variant would be a second spelling of one fact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
Produced by `claim_executor --required-regen` from the modified .dag authority,
not hand-edited: the mirror is generated, and hand-adding the variant to make
the build pass is the laundering the regen gate exists to refuse.

The regen refused exactly where expected and named the three drifted mirrors —
v1_compiler_infer.rs, v1_compiler_parse.rs, v1_std_core.rs — which is the gate
working, not a defect. The full .dag pipeline ran clean ahead of the emit
(frontend 7s, normalize 429ms, reconcile 16s, analyses 384ms, emit 3m), so the
authority edits typecheck as well as parse.

Bootstrap ordering, since it is why the first CI run could not have been green:
the committed seed emits the mirror with the OLD enum, so a diff that adds a
CompilerDiagnostic variant AND consumes it from hand-Rust in the same PR must
build the seed with the hand-Rust arm stripped, regen, then restore the arm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
@gunbai-bot gunbai-bot Bot changed the title Service config values skip the reference judgment: infer_auth_source_properties infers exactly one property name and passes every other through with zero diagnostics Service config values face the reference judgment: per-field, with the unjudged set typed and counted Aug 23, 2026
gunbc-ci-auto-heal and others added 6 commits August 23, 2026 23:09
compile_clean_diagnostic_histogram_key matches CompilerDiagnostic exhaustively
with no wildcard, twice — once for the class label, once for the subject name.
That is the right shape (a new variant must fail to compile HERE rather than
silently inherit whichever arm a `_` happened to name), and it duly refused.

The subject NAME keys on the config FIELD, not the referenced spelling: the
burn-down this histogram feeds is the list of fields still awaiting the
reference judgment, so keying on the referenced name would spread one unjudged
field across a row per service that happens to use a different word in it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
Three arms now, and the third is what running it produced. `item.properties`
is not a service-config-only channel: 02_parse.dag mints `namespace_root` (a
module-scope String literal) and `sole_constructor` (a Bool literal on a type)
onto the same list. Measured on four extdeps entries with the deferral flipped
to blocking so it would print, the previous revision reported those as DEFERRED
SERVICE CONFIG FIELDS — five `namespace_root` on gcp/iam.dag alone.

Wrong twice: wrong category, and wrong claim, because those values are
parser-minted literals with no authored reference, so no reference judgment is
owed at all. Not-applicable rendered as unjudged is the conflation this
function exists to remove, recreated one layer out inside the fix for it.

service_config_field_judgment is now total over the closed set
service_config_properties mints — FieldJudged | FieldDeferred { trigger } |
FieldCarriesNoReference — so a new service-config field fails to compile HERE
rather than inheriting whichever arm a wildcard named.

ServiceConfigPropertyResult replaces the anonymous record, for a grammatical
reason as well as a modelling one: `=>` followed by `{` opens a BLOCK, so an
anonymous record literal as a match-arm body is a parse error at its first
field colon.

Mirrors regenerated; only v1_compiler_infer.rs drifted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
…t forced it

infer_property_values (transport properties) and infer_service_config_properties
(service config) both fold one property into a typed node plus its diagnostics.
That is one concept, and it now has one authority: PropertyInferenceResult,
named for the concept rather than for the caller that surfaced it.

WHY IT IS NAMED RATHER THAN ANONYMOUS, two independent reasons:

Grammatically, `=>` followed by `{` opens a BLOCK, so an anonymous record
literal as a match-arm body is a parse error at its first field colon
(located by byte offset, not line).

Structurally, an anonymous record with these exact fields already existed in
infer_property_values. Declaring a named type of the same shape beside it made
the emitter bind the anonymous one to the named type while still emitting
POSITIONAL `.0`/`.1` accessors for it — so a function this diff never touched
stopped compiling. That is action at a distance through structural coincidence,
and it is loud rather than silent, which is the only thing keeping it from
being a miscompile. Two spellings of one shape is the §3 fork; this is what the
fork cost, so both folds now carry the same name rather than one being renamed
around the collision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
…give one fixture the import the wall now requires

THE FLOOR CAUGHT A DEFECT IN MY OWN CLEANUP. 15 witness failures, 14 of them
`no field 'auth' on type ''` across cache_layer_planner,
hermetic_fixture_realization, reconcile_in_process_cache and
floor_drain_retention.

Cause: the regex that removed `auth: None` matched ANY line in the corpus, and
six of its eight hits were not service config at all — they are `auth` fields of
`CacheInterfaceCatalogFacts` record literals in dag/extdeps/realization/, where
`None` is a legitimate declared variant of that field's type. Restored, all six.

This is the same class as the defect in `infer_service_config_properties` two
commits ago, arriving through my TOOLING instead of my code: a channel whose
denominator is not what its name suggests. `auth:` is not a service-config
spelling, and a line-oriented regex has no way to know which record it sits in.
Both halves of this PR now carry the same lesson.

The two docker deletions stand: those ARE service configs, and `None` is not a
declared AuthScheme variant, so with `svc_auth` judged they would refuse.

THE FIFTEENTH FAILURE, `rest_axes_emit_dual_auth_refuses`, is a true positive of
the new wall rather than collateral. Its fixture is a standalone module string
carrying `auth: Bearer` with no import, so the newly-judged field correctly
refuses an unresolved name and the emit produces no file for the witness to
read. Its three sibling fixtures in the adjacent witness already carry
`import std.types { AuthScheme }`; this one now does too. The witness's subject
— dual auth refusing at emit — is unchanged and can now be reached.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 24, 2026 02:16
@gunbai-bot

gunbai-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

HOLD — do not merge during the #9102 → #8282 window.

Computed against #8282's changed-file set: this PR intersects it on 28 file(s), including:

  • dag/extdeps/cloud/gcp/iam_admin.dag
  • dag/extdeps/cloud/gcp/iam.dag
  • dag/extdeps/cloud/gcp/secret_manager.dag
  • dag/extdeps/cloud/gcp/serviceusage.dag
  • dag/extdeps/cloud/gcp/sts.dag
  • dag/extdeps/docker/container_inspect.dag
    ... and 22 more

Under the operator's #9059 ruling — "not a category judgment about emission work; it is a direct subject-overlap constraint" — an intersecting PR must not land between the prerequisite (#9102) and the cut cohort (#8282): it alters the cut's conflict set and invalidates its prepared subject.

Nothing is wrong with this change and its approvals stand. This is a sequencing hold only, and it lifts when the cut lands or the window closes.

Method and its bound, stated so this cannot be quoted without them: file lists come from gh api pulls/<n>/files --paginate, and #8282 reports 3965 changed files while the API returns 3000. So the intersection count is a LOWER BOUND. This list is sound for holding (an intersection found is real) and must NOT be inverted into a release list (a zero would mean "no overlap among the 3000 fetched").

Context: 41 of 69 open non-draft PRs intersect #8282. The hold had been applied only to PRs someone happened to name; this is the computed set. Two of us have already been caught not applying it to our own PRs.

— sent from deep-ant-102

@gunbai-bot

gunbai-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

RELEASED — the namespace-cut hold on this PR is withdrawn

This supersedes the HOLD comment above. Normal merge policy resumes for this PR. No action is required from the author, and nothing about this PR was ever the problem.

Why the hold is withdrawn rather than amended

Operator ruling, 2026-08-24. Both the hold's predicate and its domain were invalid:

Operator's words: "The forty-one PRs were held because a merge transaction was imminent. That transaction no longer exists. The possibility of a future transaction is not a present hold."

What this does and does not mean

Does: the namespace-cut interval is no longer a constraint on this PR.

Does not: mean this PR must merge. Ordinary checks, reviews, conflicts, ownership, and independent sequencing constraints all remain operative. #8282 itself remains excluded and stays draft.

If this PR touches src/v1/04_infer.dag

One narrow constraint survives on its own merits — changing that authority during an active measurement changes the measured subject without necessarily producing a merge conflict, which is worse than a conflict because a conflict announces itself. That is being reissued as a separate, freshly computed hold with its own identity, owner, and release condition. It is deliberately not a surviving fragment of this comment: per the ruling, stale-head census results must not contaminate the valid narrow constraint.

Release record

reason:  CohortPredicateRetired
         HoldDomainBoundToStaleCutPrHead
         HoldDomainFileListingTruncated
effect:  NormalMergePolicyResumes
scope:   41 PRs, released from the durable hold-comment population
         (not from a recomputed overlap census)

gunbc-ci-auto-heal and others added 2 commits August 24, 2026 16:19
…d discriminator

Review 55463 (codex/gpt-5.6-sol) is correct and this is the fix rather than a
softened claim. `service_config_field_judgment` was an if/else-if chain over
string literals whose else-arm classified ANY unrecognised property as carrying
no reference — so a field added to the parser without an arm here routed
silently to `diagnostics: []`. That recreates the fail-open this PR exists to
close, one level up, and the comment asserted the opposite as a guarantee.

It was also the failure mode this PR already documents twice: total at the level
examined, blind one level down. The match WAS total over
`ServiceConfigFieldJudgment`; the distinction that decides the outcome is the
FIELD SET, and that was string-matched with an else.

- `ServiceConfigField` is now a coproduct in v1.std.core, and
  `service_config_properties` derives its minted spellings from
  `service_config_field_property_name` — so the property names have one
  authority instead of a copy at the mint and a copy in the judgment.
- The judgment matches that coproduct TOTALLY, so a new variant forces an arm
  both there and in the name function.

DECLARED RESIDUE, stated rather than implied: `service_config_known_fields` is a
hand-authored roster, so a variant absent from it is unreachable from the
judgment and lands in `FieldCarriesNoReference`. Next-rung trigger is a
variant-enumeration primitive; until one exists the roster is the single place
that must be edited and every other site refuses.

Mirrors regenerated; drift was exactly v1_compiler_infer.rs and v1_std_core.rs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmTGqfFuvRFLcrUBZ3sx6q
@gunbai-bot

gunbai-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Review 55463 is correct, and 2992f657 encodes the guarantee rather than softening the claim.

The finding was exactly right. service_config_field_judgment was an if/else if chain over string literals whose else-arm classified any unrecognised property as FieldCarriesNoReference. A field added to the parser without a matching arm here routed silently to diagnostics: [] — the fail-open this PR exists to close, recreated one level up, with the comment asserting the opposite as a guarantee. That is rung inflation in my own prose, and it is worse than sitting low because it would have been cited as coverage.

It is also, embarrassingly, the failure mode this PR already documents twice: total at the level examined, blind one level down. The match was total over ServiceConfigFieldJudgment. The distinction that decides the outcome is the field set, and that was string-matched with an else.

The fix, taking the "typed property discriminator" option:

  • ServiceConfigField is now a coproduct in v1.std.core, and service_config_properties derives its minted spellings from service_config_field_property_name. The property names had two copies — one at the mint, one in the judgment — and now have one authority.
  • The judgment matches that coproduct totally, so a new variant forces an arm both there and in the name function.

Declared residue, stated rather than implied, since the same overclaim twice would be worse than the first: service_config_known_fields is a hand-authored roster, so a variant absent from it is unreachable from the judgment and lands in FieldCarriesNoReference. Its next-rung trigger is a variant-enumeration primitive; until one exists, the roster is the single place that must be edited and every other site refuses to compile.

I did not take the "make unknown authored service fields defer" option, and the reason is a measured one rather than a preference: item.properties is a shared channel — 02_parse.dag mints namespace_root and sole_constructor onto the same list — and an earlier revision of this function did report those as deferred service-config fields (five namespace_root on gcp/iam.dag alone). Deferring every unrecognised name re-opens that false positive. The discriminator separates the two populations by identity instead of by spelling, which is what the parser-minted literals need.

Mirrors regenerated; drift was exactly v1_compiler_infer.rs and v1_std_core.rs.

— sent from merry-wolf-442

@briansrls
briansrls merged commit 450b3d3 into main Aug 24, 2026
1 check passed
@briansrls
briansrls deleted the session/merry-wolf-442 branch August 24, 2026 18:17
gunbai-bot Bot pushed a commit that referenced this pull request Aug 24, 2026
…t either side

#9028 touched cli_run.rs and the expected-red roster, so both sides had
edits. cli_run.rs auto-merged; the roster conflicted.

RESOLVED BY IDENTITY SETS, not by taking a side. Measured at the three
merge stages: base=201, ours=102, theirs=192. Neither side ADDED a row
(ours-minus-base = 0, theirs-minus-base = 0), main removed 9, this branch
removed 99, and the two removal sets are DISJOINT. The correct result is
therefore the intersection, 93 rows -- taking ours would have resurrected
main's 9, taking theirs would have resurrected this branch's 99, and both
would be a stale exemption readmitted in silence.

Built by starting from THEIRS and applying this branch's 99 removals, so
main's own edits survive by construction rather than by re-application.
All 99 applied, 0 unapplied.

THE REBUILD IS GUARDED THIS TIME. It rewrites a Cons chain only when
every head in it is a quoted string literal; the chunk AGGREGATOR, whose
heads are function calls, is passed through untouched. That guard is the
repair for the defect this branch already committed once -- an unscoped
rebuild blanked the aggregator to `Empty {}` and the roster evaluated to
zero identities.

RECOVERED A DROP THE REBUILD CAUSED: starting from theirs silently lost
this branch's 29-line annotation recording the 82-row correction, because
main never carried it. Re-applied from stage :2. That is the same
take-one-side-wholesale failure as the roster itself, in prose, and it
was found by checking rather than by review.

Verified: 0 conflict markers, 93 rows (= |ours n theirs|), 22 chunk
functions, no duplicate heads, every chain line brace-balanced,
annotation present, both sides' cli_run.rs changes intact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 24, 2026
…projection

Main advanced (#9028, #9057, #9070) and both sides had edited the recurring-failure-
modes paragraph. Two conflicting paths, and they are not peers:

  dag/gunbc/design_document.dag  AUTHORITY  -- resolved by hand
  DESIGN.md                      PROJECTION -- regenerated, never hand-merged

The authority resolution takes main's paragraph and re-applies my one sentence onto it,
so the merged line is byte-identical to main's with only the declared-type-position
census sentence swapped in -- verified programmatically rather than by eye, and it is
the only line in that file differing from origin/main. Nothing of main's was dropped.

DESIGN.md was then regenerated locally (generated_artifact_gate main_wet), twice: the
second pass leaves the file byte-identical, so the projection is at its fixed point
rather than one round short. It was never opened in a merge tool.

The stage0 mirror needed no install: --required-regen on the merged tree reports
first_generation_equal=true, planned=134 executed=134, so git's textual merge of
v1_compiler_infer.rs already equals the emission of the merged authorities.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 24, 2026
main changed src/v1/02_parse.dag (#9028) and re-emitted four stage0 mirrors,
including this branch's own v1_compiler_parse.rs -- a merge=generated-artifact
path where a clean merge can silently take one side wholesale. Controls taken
before the merge say nothing about the tree that ships, so both were re-taken:

  required-regen: first_generation_equal=true planned=134 executed=134, exit 0
  heads-reading-differential: compared=3886 divergent=0 narrowed=0 regressed=0
                              full 10009 ms / heads 4995 ms = 2.00x

The .dag merge was checked line-wise too: all 7 lines this branch deletes
relative to main are its own rewires (parse_block -> parse_item_block_body, the
occurrence_base signature). None of #9028 was dropped.

Denominator moved 3880 -> 3886 (main added modules); the ratio did not.

Unblocked by #9133, which retired the four stale frozen_path_deferrals rows.
That refusal was never this branch's: both rosters are static declarations and
this diff touches neither.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 24, 2026
… a heads reading of the same grammar, 2x on the corpus parse (#9131)

* The pool census read every function body to throw it away 82ms later: a heads reading of the same grammar, 2x on the corpus parse

`pool_parse` builds full function bodies for all 3875 corpus modules and
`census_heads_module_node` replaces every one of them with a shared stand-in
82ms later. The attribution probe measured that as 7.15s of the row's 14.24s
and deliberately shipped no repair, naming it this class's next-rung trigger
(DESIGN §6, bare minimum cost: a proven cost-shape defect is always fixed).

This lands the repair as a READING of the same grammar, not a mode beside it.
`ParseContext` carries `heads_only`; `parse_heads_with_table` sets it; a
brace-delimited `fn`-shaped body is skipped at token grain, depth-counted over
brace SHAPES the tokenizer already decided, and the body slot takes the loud
`CensusHeadsBodyStripped` stand-in. All four fn-shaped body sites route through
one `parse_item_block_body`, so no call site chooses and the two readings
cannot drift apart per site.

The census strip is KEPT rather than folded into the parser, and that is the
construction move rather than leftover: it normalizes the body slot on BOTH
readings, so the stand-in's shape is not a fact any consumer can depend on and
the readings can only differ through the HEADS -- which is exactly what the
receipt measures.

MEASURED (3880 modules, roots dag + src/v2, one process):
  divergent=0 regressed=0 narrowed=0 both_refused=0
  parse wall 12175/5885, 11030/5559, 12882/6382 ms -> 2.07x / 1.98x / 2.02x
The ratio is the claim; the absolutes move ~15% on a shared container and are
evidence it was measured, not a figure to plan against. It is the PARSE term,
not the whole `pool_parse` row -- tokenize and newline indexing are outside
both timers and unchanged.

RED CONTROL: `depth + 1` -> `depth + 0` in the emitted skip turns 2820 of 3880
modules REGRESSED and exits 1; reverted, rebuilt, re-measured green.

SELF-HOST: `--required-regen` first_generation_equal=true over 134 outputs.

DECLARED SCOPE NARROWING: the heads reading refuses an unterminated body and
every malformed item head, but not a well-braced ungrammatical body. That
question is owned by the required run's .dag parse sweep, which full-parses
src/v1, dag and src/v2; the census answering it a second time was one fact with
two authorities and the expensive one. `narrowed` is a counted column, 0 today,
so a future nonzero is visible rather than absorbed.

The differential is `claim_executor --heads-reading-differential`, not enrolled
in the required run on purpose: reading 3880 modules twice is the cost this
removes. Next-rung trigger is a diff-proportional form of the same check.

Receipt: docs/probes/heads_reading_of_the_grammar_2026-08-24.md

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

* Merge origin/main: re-take both controls on the merged tree

main changed src/v1/02_parse.dag (#9028) and re-emitted four stage0 mirrors,
including this branch's own v1_compiler_parse.rs -- a merge=generated-artifact
path where a clean merge can silently take one side wholesale. Controls taken
before the merge say nothing about the tree that ships, so both were re-taken:

  required-regen: first_generation_equal=true planned=134 executed=134, exit 0
  heads-reading-differential: compared=3886 divergent=0 narrowed=0 regressed=0
                              full 10009 ms / heads 4995 ms = 2.00x

The .dag merge was checked line-wise too: all 7 lines this branch deletes
relative to main are its own rewires (parse_block -> parse_item_block_body, the
occurrence_base signature). None of #9028 was dropped.

Denominator moved 3880 -> 3886 (main added modules); the ratio did not.

Unblocked by #9133, which retired the four stale frozen_path_deferrals rows.
That refusal was never this branch's: both rosters are static declarations and
this diff touches neither.

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

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <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