Skip to content

Write down the stage0 mirror fixed point: one regeneration is never enough - #9116

Merged
briansrls merged 3 commits into
mainfrom
session/witty-badger-734-mirror-protocol
Aug 24, 2026
Merged

briansrls merged 3 commits into
mainfrom
session/witty-badger-734-mirror-protocol

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Docs-only. Instrument knowledge this lane produced by having CI reject a PR, written down so the next lane touching a src/v1/*.dag compiler authority does not re-derive it.

The trap

--required-regen refuses a .dag authority edit until its regenerated stage0 mirror is committed. The obvious move — regenerate once, commit the result — is wrong, and for a reason that is the bootstrap rather than a bug: the first candidate is the new .dag emitted by the OLD compiler. Committing it means the compiler built from that mirror now carries the new behaviour, so when it regenerates it re-emits every other module the change reaches.

On #9101, whose change altered how folds with an unused element emit:

generation 1   drift: v1_compiler_emit_rust.rs   <- the edited authority itself
generation 2   drift: std_types.rs               <- a module the new emitter now emits differently
generation 3   first_generation_equal=true

std_types.rs list_length is itself a fold with an unused element. It is not unrelated cleanup riding along with the fix — it is the same change reaching a module generation one had not yet re-emitted. The generation-one delta is not the mirror change, and a PR carrying only it passes locally and refuses in CI. That is exactly what happened to me.

What the note records

  • the loop, and the stop condition (RC=0 / first_generation_equal=true);
  • the verification steps that make "these are the compiler's bytes" checkable rather than asserted — changed-path list, decoded byte count against the producer's own count, git apply --check. The mirror's only sanctioned author is the compiler, and a hand-authored mirror is indistinguishable from a regenerated one in the diff alone;
  • the diff-transport trick for when the loop cannot run where the commit happens (remote runner without push credentials, local v1-compiler build unaffordable in a shared memory slice, mirror files too large for a log): move the diff, not the files;
  • the branch-vs-merge-ref ruling, with its honest limit.

On that last point

CI regenerates on the merge ref; the loop runs on the branch tree. Different trees whenever the base has moved, so convergence on one does not entail convergence on the other. The note says: iterate against the branch tree while authoring, and treat merge-ref convergence as a separate acceptance fact supplied by CI.

#9101 is one instance where the transfer held. The note says that establishes it can, not that it is automatic — a base moving under a branch can require another round, and the honest response is another iteration rather than an assumption that the branch result carries.

One accuracy note carried in the doc itself: the three-row table is the sequence across the whole exercise, not one command's output. Generation 1 was committed on its own before CI refused with drift: std_types.rs; the loop then reported the remaining two rounds numbered from where it started. The doc says so rather than presenting a reconstruction as a transcript.

🤖 Generated with Claude Code

Brian Searls and others added 3 commits August 24, 2026 15:13
…the expensive way

A .dag compiler-authority edit refuses until its regenerated mirror is committed, and the
obvious move -- regenerate once, commit -- is wrong for a reason that is the bootstrap
rather than a bug: the first candidate is the new .dag emitted by the OLD compiler, so
committing it changes what the compiler emits and the next generation differs again.
gunbc#9101 took two rounds and my first attempt was rejected by CI carrying only
generation one.

Records the loop, the verification steps that make "these are the compiler's bytes"
checkable rather than asserted, the diff-transport trick for when the loop cannot run
where the commit happens, and the branch-versus-merge-ref ruling with its honest limit --
one instance of transfer establishes that it can hold, not that it is automatic.

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

Both from review in the side thread, both real defects in the note.

1. The note generalized #9101's three-generation history into "one round is never
enough". A behaviour change no other seed module exercises can leave generation two
identical to generation one -- no second drift, and the second regeneration is STILL
mandatory because it is what proves equality. The law is about the equality check, not
about expecting a second drift: one drift-producing regeneration may be enough; one
regeneration without a subsequent equality check never is.

2. The note claimed a byte count makes "these are the compiler's bytes" checkable. It
does not, and this is the step the entire no-hand-authoring claim rests on. A count
proves transport length and catches truncation; two different patches can share one, and
git apply --check proves applicability rather than equality to the producer's output. A
SHA-256 beside the count closes it, and the note now carries the full evidence chain.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit 3985222 into main Aug 24, 2026
1 check passed
@briansrls
briansrls deleted the session/witty-badger-734-mirror-protocol branch August 24, 2026 18:03
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