Skip to content

Join the OCI model to the fleet: dissolve the ContainerRuntime nickname and make a customer-supplied container image expressible - #9394

Merged
briansrls merged 5 commits into
mainfrom
session/swift-fox-301
Aug 27, 2026
Merged

briansrls merged 5 commits into
mainfrom
session/swift-fox-301

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

gunbc had two container vocabularies. The good one — nine OCI modules under dag/extdeps/container/oci, cited to the spec, closed coproducts with typed accept/reject — was consumed by nothing that ships. The one everything used was gunbc.fleet_intent's

type ContainerRuntime = Docker | Podman | Gvisor | Ubicloud | GcloudRun

This joins the first and deletes the second.

The nickname, and why five members were three concepts

ContainerRuntime fused container engines (Docker, Podman), a sandbox whose entire value is the isolation guarantee it adds (gVisor), and two companies that rent you a machine (Ubicloud, Google Cloud Run). Adding an engine and adding a supplier both widened one enum — the case DESIGN's external-upstream-decomposition section rules out with "adding Opera must not widen a generic browser-product enum".

The dissolution splits it along the seams that were already there:

  • extdeps.container.engine — the agnostic hub. Defines what a container engine is and enumerates no product; adding one is a new file, never an edit here.
  • extdeps.container.docker_engine — the one member that had a live consumer, as a cited product row (extdeps.vendor.docker_inc, and extdeps.software for the Vendor<Software> domain the tree lacked). Its Ubuntu apt distribution keeps its own module: how you install it is not what it is.
  • gVisor is a guarantee question — product.fabric.isolation already owns what a tenant is promised and deliberately names no mechanism.
  • Ubicloud and Cloud Run are suppliers, with homes in extdeps.cloud.ubicloud / product.supplier.

Four members get no replacement row, and that is delete-first working rather than a loss: Podman, gVisor, Ubicloud and GcloudRun had zero constructors anywhere in the corpus, so nothing refused when they went. Inventing four uncited catalog rows to preserve the shape would have been re-invention, not decomposition.

The surface now carries strictly more truth than Docker did. ExecutionSurface.container_engine: ContainerEngineDeployment? is the cited product plus the privilege mode this host runs it in — the property that decides whether a job escaping its container owns the machine, and the one thing the old enum could not say. srv1 runs rootless. A mode the product does not declare yields no deployment, not a surface asserting one.

The customer-supplied image

product.fabric.customer_image is the first executing consumer of the OCI model. A CustomerSuppliedImage is a reference, a manifest and a configuration; admit_customer_image folds it against an ExecutionTarget and returns admitted-or-a-typed-cause.

The isolation mechanism is not in that file, and its absence is the point. CustomerSuppliedImage has no field naming a runtime or a boundary and no constructor that could carry one — a tenant cannot select the mechanism because there is nowhere to put the selection. The mechanism arrives on the target side, chosen by us.

New in extdeps: extdeps.container.oci.reference, because nothing modelled how a party refers to an image — the only spelling available was a String. It carries the distribution-spec grammar (path-component separators enumerated exactly: ., _, __, -+, so a..b and a___b refuse) and both identifier arms including the mutable one. A tag is a real thing the spec defines; refusing to run one is policy, and policy in an extdeps module is a layer inversion. The spec says what may be written; product.fabric.customer_image says what it will accept.

The refusal that justifies the join module existing at all is LayerCountDisagreement. image-spec requires rootfs.diff_ids to correspond one-for-one with the manifest's layers; accept_image_manifest sees only the first list and accept_image_configuration only the second, so each accepts a pair that disagrees — which is what a substituted layer looks like. Only the join sees it.

Green by execution, with discriminating reds

dag/test/claim/customer_image_admission_witness_test.dag drives the real fold. The target is the real fleet (fleet_container_execution_target() — architecture read from srv1's declared Ampere CPU, engine from the surface), not a target authored to make the test pass, so the amd64 refusal is a claim about what this fleet would actually do. Each refusal case differs from the admitted case in exactly the fact its refusal names.

A fixture that cannot be built returns Absent and every witness fails on it rather than passing vacuously.

Measured, not asserted — claim_batch --claim-run over the 13 rows, all PASS, and the entry closure compiles with 0 blocking diagnostics. Re-derive with:

claim_batch --source-root dag --source-root src/v2 --claim-run \
  --entry dag/test/claim/customer_image_admission_witness_test.dag --functions <the test fns>

The reds were executed, not assumed. Three separate deletions in the admission fold — the layer-count join always agreeing, the digest-pin test skipped, the architecture comparison skipped — each turned exactly one witness red and left the other twelve green. Nothing agrees with the fold's shape instead of testing its decision, and no single defect is reported three times. The procedure is recorded in the witness module so it can be re-derived rather than trusted.

What the first executing consumer immediately found

image_config_entrypoint was written as match c.config { null => [] ; cfg => match cfg.Entrypoint { ... } }. The bare arm binds the Optional, not its payload, so the inner field read refuses at runtime with NoSuchField { type_name: "Optional", field: "Entrypoint" }. It typechecked, it had witnesses, and it was wrong — surfaced the first time anything called it. image_config_first_exposed_port and image_config_has_exposed_port carried the identical defect and are repaired in the same change rather than left for the next consumer.

That is the point of the caution in the brief, arriving on schedule: a join that only typechecked would have reproduced the condition it was fixing.

Named residue, not claimed closed

  • IsolationBoundary in fleet_intent still describes our own surface beside product.fabric.isolation's guarantee vocabulary. That is a separate question and is untouched here.
  • The KernelFamily / Os fork is compiler-enforced and could not be bridged. An image config's os is extdeps.toolchain.types Os; a ComputeHost's surface carries std.os.types KernelFamily. Any module importing both is refused: variant 'Linux' appears in both 'Os' and 'KernelFamily'. So the bridging match cannot be written anywhere. I did not route around it — the target OS is stated by the caller in the vocabulary the image speaks, the mismatch still refuses loudly, nothing widens silently, and the residue is named in gunbc.fleet_container with the exact diagnostic. Dissolving that fork is a real change and is not this one.
  • This makes a customer image expressible and admissible. It does not make CI jobs run in containers; that is gated elsewhere.

@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 27, 2026 03:27
@briansrls
briansrls merged commit 6635135 into main Aug 27, 2026
3 checks passed
@briansrls
briansrls deleted the session/swift-fox-301 branch August 27, 2026 04:54
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
…ed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING. THE CALLER WAS.

From the 2026-08-15 floor cut until this change, the only route that ASKED it was
`claim_executor`'s behavioural-receipt census, which asks only about paths of the
form `src/v1/stage0/src/<mirror>` because its subject is emitted Rust mirrors.
Every committed artifact that is not a Rust mirror -- `DESIGN.md`, `ROADMAP.md`,
the workflow YAML, `.gitignore`, `.gitattributes`, the githooks, the plans -- was
computed by nothing and compared by nothing. DESIGN's own CI paragraph named the
generated-artifact drift gates on the re-add queue that cut created; this is the
first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, which is the argument for it. Green
over an unguarded corpus would have been the more suspicious result:

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

  drifted DESIGN.md                                  (this change's own authority edit)
  drifted docs/plans/realization-measurement-loop.md (an authority change never installed:
                                                      #9394 dissolved the ContainerRuntime
                                                      nickname and the projection still
                                                      named it)
  absent  docs/plans/v2-corpus-self-host.md          (rostered, never written)
  absent  docs/plans/import-namespace-program.md     (rostered, never written)

All four are regenerated here by the sanctioned route (`main_wet` on
`dag/tools/generated_artifact_gate.dag`), and the phase is green after.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit`
once and asks it for BOTH the roster (`committed_generated_artifact_paths`) and
each body, so an artifact added to `generated_artifact_registry` is enrolled with
no edit to the host and a path list in Rust -- the second roster DESIGN 3
forbids -- does not exist. Production precedes adjudication in the TYPE: every
verdict is reached through the produced population, so "refused, having compared
nothing" has no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names -- an unreached
observation reading as a pass -- and the discriminating unit test asserts exactly
that: an outcome whose every verdict matched is NOT clean while one member is
unadjudicated, and is still not reported as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned
move is unavailable does not stop the line, it launders a hand edit -- the trap
this repository has now recorded three times.

`gunbc.design_document` records the phase and takes the generated-artifact drift
gates off the unguarded list; DESIGN.md is its regenerated projection.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
…nrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
…nrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
…nrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
…nrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

THE SEED-GROWTH OBLIGATION FOR THE NEW HOST RUST (codex/gpt-5.6-sol, review 56588).
The registration in `stage0_crate_layout` acknowledges the file; it does not
reconcile it with DESIGN 7's shrinking-seed mandate, and that reconciliation is
what the gate requires. `gunbc.generated_artifact_boundary_seed_growth` now
carries it, joined into `gunbc.seed_growth_admission`'s roster: 19 declarations
enumerated at identity grain rather than counted, the reason Rust is needed at
all (the comparison is against BYTES ON DISK, a host effect the hermetic floor
refuses by construction), the rejected alternative and why (running the existing
gate through the interpreter in Wet mode makes the interpreter load-bearing for a
NEW required phase while two lanes delete it, and would drag in
`artifact_extra_valid`'s `ci_yml_parses` as a second unasked subject), the owning
lane (`v1-hand-queue-drain`), and a trigger that names the capability rather than
an artifact: delete all 19 when a modeled operation can read a committed file's
bytes inside the required envelope.

THE FOUR INHERENT METHODS BECAME FREE FUNCTIONS TO PAY THAT OBLIGATION HONESTLY.
`std.decl_ref` offers `WholeDeclaration` or `NamedField` and neither names a
method on an `impl` block, so every method would have been an item this roster
could not cite -- growing exactly the uncitable-item class
`gunbc.seed_growth_admission` counts. There is now no `impl` block in the file
and zero of the 19 rows are uncitable.

NET, STATED SO THE ROSTER IS NOT MISREAD AS A DIFF: three of the 19
(`GeneratedArtifactPathBody`, `generated_artifact_ctx`,
`generated_artifact_body_for_path`) are DELETED from `bin/claim_executor.rs` in
this same change, so the corpus-wide delta for those three is zero and only their
home moved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
…nrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

THE SEED-GROWTH OBLIGATION FOR THE NEW HOST RUST (codex/gpt-5.6-sol, review 56588).
The registration in `stage0_crate_layout` acknowledges the file; it does not
reconcile it with DESIGN 7's shrinking-seed mandate, and that reconciliation is
what the gate requires. `gunbc.generated_artifact_boundary_seed_growth` now
carries it, joined into `gunbc.seed_growth_admission`'s roster: 19 declarations
enumerated at identity grain rather than counted, the reason Rust is needed at
all (the comparison is against BYTES ON DISK, a host effect the hermetic floor
refuses by construction), the rejected alternative and why (running the existing
gate through the interpreter in Wet mode makes the interpreter load-bearing for a
NEW required phase while two lanes delete it, and would drag in
`artifact_extra_valid`'s `ci_yml_parses` as a second unasked subject), the owning
lane (`v1-hand-queue-drain`), and a trigger that names the capability rather than
an artifact: delete all 19 when a modeled operation can read a committed file's
bytes inside the required envelope.

THE FOUR INHERENT METHODS BECAME FREE FUNCTIONS TO PAY THAT OBLIGATION HONESTLY.
`std.decl_ref` offers `WholeDeclaration` or `NamedField` and neither names a
method on an `impl` block, so every method would have been an item this roster
could not cite -- growing exactly the uncitable-item class
`gunbc.seed_growth_admission` counts. There is now no `impl` block in the file
and zero of the 19 rows are uncitable.

NET, STATED SO THE ROSTER IS NOT MISREAD AS A DIFF: three of the 19
(`GeneratedArtifactPathBody`, `generated_artifact_ctx`,
`generated_artifact_body_for_path`) are DELETED from `bin/claim_executor.rs` in
this same change, so the corpus-wide delta for those three is zero and only their
home moved.

THE PROJECTION DECISION DESCENDS INSTEAD OF COLLAPSING (codex/gpt-5.6-sol,
review 56610). The first cut of `PlanProjection` carried a
`plan_projects_committed_markdown(p) -> Bool` predicate that matched the coproduct
into true/false, and `artifact_commit_policy` then branched on the Bool. That is
the predicate residue DESIGN 6 forbids, and it is also the "total at the level
examined, blind one level down" shape one entry over: a second projection state
would have had to pick an existing Bool rather than failing to compile at the
decision. The predicate is DELETED and `artifact_commit_policy` matches
`plan.projection` directly, so a new `PlanProjection` variant fails to compile
exactly where the commit policy is decided.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 27, 2026
…a required CI phase — the writer exists and is run by hand, so the gap is enrolment, not a missing regenerator (#9415)

* No route checked DESIGN.md or ROADMAP.md against their authorities: enrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

THE SEED-GROWTH OBLIGATION FOR THE NEW HOST RUST (codex/gpt-5.6-sol, review 56588).
The registration in `stage0_crate_layout` acknowledges the file; it does not
reconcile it with DESIGN 7's shrinking-seed mandate, and that reconciliation is
what the gate requires. `gunbc.generated_artifact_boundary_seed_growth` now
carries it, joined into `gunbc.seed_growth_admission`'s roster: 19 declarations
enumerated at identity grain rather than counted, the reason Rust is needed at
all (the comparison is against BYTES ON DISK, a host effect the hermetic floor
refuses by construction), the rejected alternative and why (running the existing
gate through the interpreter in Wet mode makes the interpreter load-bearing for a
NEW required phase while two lanes delete it, and would drag in
`artifact_extra_valid`'s `ci_yml_parses` as a second unasked subject), the owning
lane (`v1-hand-queue-drain`), and a trigger that names the capability rather than
an artifact: delete all 19 when a modeled operation can read a committed file's
bytes inside the required envelope.

THE FOUR INHERENT METHODS BECAME FREE FUNCTIONS TO PAY THAT OBLIGATION HONESTLY.
`std.decl_ref` offers `WholeDeclaration` or `NamedField` and neither names a
method on an `impl` block, so every method would have been an item this roster
could not cite -- growing exactly the uncitable-item class
`gunbc.seed_growth_admission` counts. There is now no `impl` block in the file
and zero of the 19 rows are uncitable.

NET, STATED SO THE ROSTER IS NOT MISREAD AS A DIFF: three of the 19
(`GeneratedArtifactPathBody`, `generated_artifact_ctx`,
`generated_artifact_body_for_path`) are DELETED from `bin/claim_executor.rs` in
this same change, so the corpus-wide delta for those three is zero and only their
home moved.

THE PROJECTION DECISION DESCENDS INSTEAD OF COLLAPSING (codex/gpt-5.6-sol,
review 56610). The first cut of `PlanProjection` carried a
`plan_projects_committed_markdown(p) -> Bool` predicate that matched the coproduct
into true/false, and `artifact_commit_policy` then branched on the Bool. That is
the predicate residue DESIGN 6 forbids, and it is also the "total at the level
examined, blind one level down" shape one entry over: a second projection state
would have had to pick an existing Bool rather than failing to compile at the
decision. The predicate is DELETED and `artifact_commit_policy` matches
`plan.projection` directly, so a new `PlanProjection` variant fails to compile
exactly where the commit policy is decided.

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

* Regenerate two plan projections the merge left behind

`docs/plans/budget-tree.md` and `docs/plans/ci-humming.md` are projections of
`gunbc.plans.budget_tree` and `gunbc.plans.ci_humming`, both of which git
auto-merged when main came in. The regeneration ran, but its output was left
UNSTAGED and `git commit` on a merge commits the index -- so the merge commit
carried the merged authorities and the pre-merge projections.

Caught by the `generated-artifact` phase this branch adds, on its own branch,
naming both paths. That is the phase doing exactly what it exists for, on the
class it exists for, against its own author.

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

* An empty roster reported clean: refuse it at the producer and at the predicate

Found in review (codex/gpt-5.6-sol, review 56696), and it is a real defect in
exactly the class this phase exists to close. `boundary_is_clean` required that
every verdict matched and nothing was unadjudicated -- both VACUOUSLY TRUE of an
outcome carrying zero members. So a run that adjudicated NOTHING rendered
identically to a run that adjudicated seventy paths and found them all correct,
and neither reporting branch in the phase body fired, so the line did not stop.

That is the empty-observation narrow DESIGN names -- bottom-as-answer conflated
with bottom-as-ignorance -- and it is strictly worse than the widen 5 already
forbids: a widen is merely expensive, a narrow is silently uncovered. The PR body
claimed "nothing was asked cannot appear clean". It could.

CLOSED AT THREE LEVELS, none of them redundant with the others because each is
reachable where the next is not:

  PRODUCER. `run_generated_artifact_boundary` refuses an empty roster with a
  typed cause. `committed_generated_artifacts` filters a module-scope literal, so
  empty is never a fact about the tree -- it means the projection or this bridge
  lost sight of the population, which is ignorance and must refuse.

  PREDICATE. `boundary_is_clean` no longer admits an empty population. This
  covers any outcome VALUE, including one a caller or a fixture builds by hand,
  which is the only boundary at which the state is still expressible now that the
  producer refuses it -- and therefore the only boundary at which its RED is
  authorable, which is what 4b requires before a check is worth writing.

  PHASE. The phase's verdict now derives from `boundary_is_clean` alone; the two
  reporting branches name WHAT went wrong, they no longer decide WHETHER anything
  did. A state neither branch happens to describe refuses with an explicit
  unnamed-cause line rather than falling between them. A second definition of
  clean beside the carrier's is the fork that lets a ledger and a gate disagree
  about one run.

THE DISCRIMINATING RED IS AUTHORED AND CARRIES ITS POSITIVE CONTROL:
`an_empty_population_is_not_clean_even_though_no_verdict_disagreed` asserts the
empty outcome is not clean AND that a single matching member still is, so the
conjunct is emptiness rather than a blanket refusal. It returns green under the
previous code, which is the state it exists to forbid. Five tests pass.

The seed-growth roster grows by one to 20 and its trigger is re-counted.

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

* Regenerate DESIGN.md against main's recurring-failure-mode addition

#9414 added a row to `gunbc.recurring_failure_mode` on main. That module is an
input to `gunbc.design_document`, so the merge result's authority no longer
matches the committed projection.

WORTH RECORDING BECAUSE IT IS A PROPERTY OF THE PHASE AND NOT A ONE-OFF: CI
adjudicates the PULL REQUEST MERGE COMMIT, not the branch head, so the phase
compares the projection against the MERGED authorities. A branch that is
internally consistent goes red the moment main lands an authority change under
it -- which is correct, since the post-merge tree is what would sit on main --
and the remedy is always the same: merge and regenerate, never hand-edit.

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

* Install the regenerated stage0 layout mirror: the merge resolution took main's copy, which predates this branch's host registration

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

---------

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