Skip to content

The emitter declares the population it produced: one at-rest authority for which stage0 .rs files it owns - #8696

Merged
briansrls merged 9 commits into
mainfrom
session/smart-otter-309-emit-manifest
Aug 21, 2026
Merged

briansrls merged 9 commits into
mainfrom
session/smart-otter-309-emit-manifest

Conversation

@briansrls

@briansrls briansrls commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

The emitter declares the population it produced

v1.compiler.emit_rust has the complete emitted population in hand at exactly one point, as a
value:

let all_mod_files = concat(module_files, v2_std_text_stub, v2_std_integer_stub, [rt_file], dry_run_file)
let lib_file      = emit_lib_rs_from_files(all_module_files: all_mod_files, ...)
let files         = concat([cargo, lib_file, main_file], all_mod_files, compiler_tests_file, test_files)

And then discarded it. Every consumer downstream rebuilt that fact from whatever residue it
could see — the // Generated by v1 compiler banner, the complement of the crate-layout claim,
a directory listing, lib.rs. Those reconstructions agree until they drift, which is when they
are load-bearing. #8674 deleted a producerless roster and replaced it with one such
reconstruction; the rung drop it declared exists because none of them can separate the emitter
produces this
from nobody registered this.

This PR writes the fact down. src/v1/stage0/src/emitted_population.rs is emitted by the
emitter, from files, listing every path it produced.

lib.rs is not this fact and never was. It is one projection of the same value — the
top-level pub mod block of one crate — which is why nine live stage0 modules are absent from
it (reached by mod from a parent, by cross-crate #[path], or by a non-pub mod). The
manifest is a second projection, and a total one. That measurement is wise-boar-649's and it is
what killed the lib.rs-as-manifest design before it was built.

Declared unfiltered

Every path in files, not "the generated ones". Consumers cut it to their own question
(required_regen_host drops non-.rs and hand-maintained; the lifecycle scaffold will want a
different cut). Filtering at the write would bake one consumer's question into the fact and
guarantee the next consumer reconstructs — which is the failure this ends.

The manifest lists itself, because the emitter does produce it. That is a fixed point, not a
circularity: the content is a function of the paths, and the manifest's own path is known
before its content is rendered.

Why it is a .rs of comment lines, and why that is not debris

This shape is load-bearing in both directions, and both halves were established by execution.

Comments, because it must be Rust. Every member of the compared population is
rustfmt-normalized before its digest is taken. An earlier revision made the manifest a .txt
and named it in the membership predicate as an exception; the gate refused it, located:

required-regen: refused: normalize candidate emitted_population.txt:
    error: expected one of `!` or `::`, found `.`

The compared population is Rust-shaped end to end, so an artifact that wants its gating has to
be Rust. As a .rs it enters committed_generated_basenames and
generated_basenames_from_emit with nothing named and no exception — population check,
drift comparison, tree digest and candidate verification all cover it because it is a .rs
under the stage0 root. A comments-only file is also already a rustfmt fixed point, which is the
property DESIGN's two-consumer rule demands of any artifact two consumers normalize.
cargo fmt --all --check is clean on it.

Not a const &[&str], because recovering one requires parsing Rust. The read side is
split-on-separator then strip a literal prefix — no Rust grammar involved. A generated const
would put a Rust parse back on the read path, which is exactly the class #8690 deleted four
hours ago (cssl_assemble's seed lib.rs oracle). The write is prefix ++ path joined by the
separator; the read is split-then-strip. One grammar, both directions.

Deliberately not a module. It is appended to the emitted file list after lib.rs is
rendered, so no pub mod names it and nothing compiles it.

Dissolution is declared on the carrier: when the compared population becomes medium-agnostic
— when the comparison normalizes by declared medium rather than assuming Rust — the manifest
becomes the line-delimited text it wants to be and the .rs goes with it. Until then the
extension is load-bearing, and "cleaning it up" into a const is a silent regression.

The gate needs no new path

generated_basenames_from_emit and committed_generated_basenames each carried their own
copy
of the .rs-and-not-hand-maintained membership rule — two readers of one fact, sitting
inside the file whose job is detecting that class. They now share
is_compared_generated_basename. The manifest is admitted by the rule rather than excepted
into it, so there is no second gate for anyone to forget to keep enrolled.

The basename has one authority

gunbc.stage0_emitted_population_manifest is a leaf module holding the basename, line prefix
and separator. The emitter writes target-relative and the observation will read
repository-relative, so only the parts that are genuinely one fact are shared — hoisting a whole
path would force one end to hold a path in a space it does not speak. Without it the artifact
would have two names for one file, which is the nicknaming failure the manifest exists to end.

Convergence: stable by round 3, fixed point verified

Measured on BuildBuddy, install-and-rebuild to stability:

round 1  refusal: emitted surface has no committed mirror — ["gunbc_stage0_emitted_population_manifest.rs"]
round 2  refusal: emitted surface has no committed mirror — ["emitted_population.rs"]
round 3  required-regen: first_generation_equal=true planned=130 executed=130
fixed pt required-regen-fixed-point: fixed_point_equal=true referenced_first_generation_equal=true
fmt      cargo fmt --all --check — clean

Two rounds of install, no rounds of propagation, and the distinction matters for whoever
edits emit_rust next. Rounds 1 and 2 each introduce one genuinely new emitted file, and #8671's
refusal names one class at a time — that is the sanctioned first-mirror path doing its job, not
the mirror chasing itself. The content never propagated: the binary built from the round-3
mirror emits that same mirror. That is why this differs from #8652/#8677, where main sat
mid-convergence across two PRs: #8614 changed how modules render, so every mirror moved and
the movement re-entered the compiler through its own mirror. This change alters what the
emitter produces
, not how it renders, so the fixed point is reached as soon as the mirror
carrying the new function is installed.

This PR is built on #8671 (666f984ca7), which re-derived the first-mirror producer so the
candidate tree is written before adjudication. An earlier revision of this branch worked around
its absence with committed placeholders; that scaffolding is deleted, not left standing.

Behavioral receipt: EQUIVALENT over 36 derived calls

This PR is the first non-zero selection the per-PR behavioral receipt (#8657) has made, so the
composition — select changed authority → compile candidate → run a derived call corpus against
the committed seed → verdict — executed end to end here for the first time:

behavioral-receipt: changed_authorities=2 selected=2 excluded=0
behavioral-receipt: v1.compiler.emit_rust fn_lines=634 parsed=634 derivable=36 (closed-type=36) refused=598
behavioral-receipt: v1.compiler.emit_rust EQUIVALENT over 36 derived calls
behavioral-receipt: DENOMINATOR v1.compiler.emit_rust — 36 derived calls over 36 of 634 declared
    functions; the other 598 refused and are NOT covered by this verdict

The denominator is quoted with the verdict deliberately: this change adds a projection function
and appends one element to the emitted file list, so nothing in the 36 should have moved and
nothing did — but 598 functions are refused as non-derivable (unbounded String domains,
Node import-closure gaps) and the equivalence says nothing about them.

The receipt phase is nevertheless RED, and not because of anything in this diff. The other
selected authority is gunbc.stage0_emitted_population_manifest — the three-data-row leaf
module this PR adds — which declares zero functions, so there is no corpus to derive and the
mechanism refuses rather than reporting equivalence over zero calls. That refusal is correct as a
statement about coverage; the error is one level up, in selection: a module with no declared
functions has no behaviour that could diverge, so it belongs in excluded= with a typed reason
rather than being selected and then refused. Measured blast radius: 533 of 3740 .dag modules
(14%) declare zero functions
, including core substrate — any diff touching any of them
hard-fails required CI with no author-side remedy short of a model change.

Converting the three data rows to zero-arg fns would green the phase in minutes — zero-arg
functions are exactly the exhaustive(|domain|=1) shape the 36 derived calls are made of — and
that is precisely why it is not done here: a model change made solely to satisfy a gate, with no
reader benefit and no modelling argument, is the workaround class DESIGN §5 names as a line-stop
signal rather than a landing state. The selection defect is routed to the mechanism's lane.

The manifest paid for itself before it had a consumer

Two independent numbers over the same population, which nobody had before:

committed direct-child .rs under src/v1/stage0/src   166
emitted (per the manifest)                           131  (+ Cargo.toml = 132 lines)
committed but NOT emitted                             35
emitted but NOT committed                              0

Those 35 are exactly HAND_MAINTAINED_STAGE0_FILES (36) minus one. The single residue is
main.rs: the crate-layout authority claims it as hand-maintained, and the emitter emits it.

That is not a defect this PR introduces or fixes. required_regen.dag already notes
"hand-maintained DRIFT is expected on a clean tree (main.rs and known emitter gaps)" — and that
sentence is the finding. The emitter produces a main.rs that differs from the committed one,
and membership in HAND_MAINTAINED_STAGE0_FILES is what stops the difference from being seen.
So it is not merely a not-compared list wearing the name of a hand-authored list: it is a
suppressed drift with no counter — a known divergence between authority and artifact, held
quiet by a switch spelled as an authorship claim. Nothing counts it, nothing reports it, its
frequency is zero by construction, and so it can never rank for repair.

The remedy is not to drop main.rs from the list, which would turn the drift red with no fix
available; it is to split the two facts — what is hand-authored, and a separate counted,
declared set of known emitter gaps with per-entry triggers. That is a separate subject with
separate consumers and it is being dispatched as its own lane, not carried here.

This is the manifest's first dividend, and it arrived before the manifest had a consumer. A
real divergence between an authority and the artifact it claims became visible on the day the
declaration landed, using no new machinery — just two independent numbers over one population,
which nobody could take before. Independently corroborated from the other direction: main.rs
carries the emitter's own // Generated by v1 compiler banner while sitting on the
hand-maintained roster.

What is deliberately NOT here

The consumer wiring: RustManifestObserved gaining the emitted population,
gunbc.stage0_rust_source_lifecycle_scaffold's derivation switching onto it, the two RED
controls returning to a direct-child subject, and #8674's declared rung drop deleting. That
is 30 constructor sites across 13 files, each a witness fixture that must state what emit
population it assumes, and it does not belong in the same diff as a regenerated mirror.

The drop block stays standing until a production path reads this manifest. A carrier that
can receive the emit population is not the carrier having it; deleting the block now would
leave green controls implying a closure that does not exist. It is the only thing currently
telling the truth about that population, and it keeps telling it until the follow-up lands.

dashboard node adhoc-03fccc45-ac3

@gunbai-bot gunbai-bot Bot changed the title Restore the emitted-path producer on gunbc.stage0_rust_host_observation and dissolve #8674's declared rung drop — fold in the cssl_assemble text-parse, same root The emitter declares the population it produced: one at-rest authority for which stage0 .rs files it owns Aug 20, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 20, 2026 23:59
Brian Searls and others added 2 commits August 21, 2026 17:21
Merging main added `extdeps_languages_rust_derive_contracts` to the emitted
population, so the committed manifest no longer equalled what the emitter
declares and `--required-regen` refused with `generated surface drift:
emitted_population.rs`.

The candidate tree is installed verbatim (one added line, diff-verified
against `target/stage0-regen-candidate/src/emitted_population.rs`); nothing
here is hand-authored. This is the artifact reporting its own staleness on
the first main merge after it landed, which is what it exists to do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@briansrls
briansrls merged commit 8efca0a into main Aug 21, 2026
1 check passed
@briansrls
briansrls deleted the session/smart-otter-309-emit-manifest branch August 21, 2026 20:52
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