Section 11.4 step 4 says "régénère le code émis", and step 3 lists what a
synchronization writes: spec/, rules.lock, spec/PROVENANCE.md and the
prose contracts. Neither reaches a second kind of generated code that at least
two engines carry: the code a schema compiler emits from rules.proto,
conformance.proto and testee.proto.
That code is not emitted by the engine's own generator. It is emitted by
protoc plus a language plugin, from a copy of the schemas laid out in the
package-shaped tree protoc requires. 2026.08.38 moved the Protobuf package
from libbusinessid.* to entid.*, so both the tree and the emitted symbols
had to move — and section 11.4 gives a synchronization no reason to touch
either.
Measured on entid-org/entid-swift, release v2026.08.38
Ran the engine's own synchronization on v2026.08.38, then reproduced the tree
it produces before any hand step, in a worktree: the new spec/, the new
proto/entid/**, the new rules.lock, the emitted rule code regenerated by
step 4 — and the committed *.pb.swift still the ones generated from
libbusinessid.ir.v1, under their old file names.
./Tools/verify-lock.sh -> 11 checks ok, exit 0
swift test -> 261 tests in 32 suites passed
make conformance -> rules 2026.08.38: 676 cases, 676 matched, 0 differed
The section 12.6 entry point is green on a tree whose wire code was generated
from a schema the release replaced. It is green for a sound reason: a package
rename does not change the wire format, and nothing outside the emitted file
names the package. Regenerating turned out to be byte-for-byte the old file with
the names substituted — which is exactly why nothing failed.
The only job that notices is a separate Protobuf job that runs protoc and
compares. That job does not run on a synchronization pull request: it is opened
with the repository's own GITHUB_TOKEN, which starts no pull_request
workflow — the same cut section 11.4 already documents for the required check.
So the drift merges on green.
Why the engine cannot simply do it
Section 11.4's own argument applies twice over. Regeneration needs the engine's
toolchain, which is why the release does not push; a schema compiler is a
third toolchain, which the synchronization runner does not have either. This
engine's runner has SwiftPM but no protoc and no protoc-gen-swift, and
installing them on every nightly run to notice a change that happens once a year
is not obviously the right trade.
What is missing from the text
-
Step 3 does not name the engine-side schema tree. An engine that keeps a
copy of the schemas for its compiler has to move it when the package moves,
and nothing says so. This engine had a literal path in its digest check; on
this release it compared the new schema against a copy that was no longer the
one its compiler reads, and refused the release at the end of a
synchronization that had passed every digest and every attestation. The fix
here was to derive the path from the package the attested schema declares,
but that reading is invented, not specified.
-
Step 4 does not say how far "le code émis" reaches. If it includes
schema-derived code, section 11.4 needs to say what an engine does when its
synchronization runner cannot produce it — go red, or install the compiler.
If it does not, the specification should say that this code is outside the
automated path and name what is supposed to catch it, because a pull request
opened by GITHUB_TOKEN cannot rely on a second workflow.
A suggestion for 1: state that the schemas an engine vendors are located by the
package they declare, so a package rename relocates them by construction. It
costs one sentence and it removes the literal path from four engines.
A suggestion for 2: make step 4 name schema-derived code explicitly, and require
the synchronization to fail rather than to skip it — a red pull request on the
release that renames a package is precisely the sorting section 11.4 describes.
Section 11.4 step 4 says "régénère le code émis", and step 3 lists what a
synchronization writes:
spec/,rules.lock,spec/PROVENANCE.mdand theprose contracts. Neither reaches a second kind of generated code that at least
two engines carry: the code a schema compiler emits from
rules.proto,conformance.protoandtestee.proto.That code is not emitted by the engine's own generator. It is emitted by
protocplus a language plugin, from a copy of the schemas laid out in thepackage-shaped tree
protocrequires.2026.08.38moved the Protobuf packagefrom
libbusinessid.*toentid.*, so both the tree and the emitted symbolshad to move — and section 11.4 gives a synchronization no reason to touch
either.
Measured on
entid-org/entid-swift, releasev2026.08.38Ran the engine's own synchronization on
v2026.08.38, then reproduced the treeit produces before any hand step, in a worktree: the new
spec/, the newproto/entid/**, the newrules.lock, the emitted rule code regenerated bystep 4 — and the committed
*.pb.swiftstill the ones generated fromlibbusinessid.ir.v1, under their old file names.The section 12.6 entry point is green on a tree whose wire code was generated
from a schema the release replaced. It is green for a sound reason: a package
rename does not change the wire format, and nothing outside the emitted file
names the package. Regenerating turned out to be byte-for-byte the old file with
the names substituted — which is exactly why nothing failed.
The only job that notices is a separate
Protobufjob that runsprotocandcompares. That job does not run on a synchronization pull request: it is opened
with the repository's own
GITHUB_TOKEN, which starts nopull_requestworkflow — the same cut section 11.4 already documents for the required check.
So the drift merges on green.
Why the engine cannot simply do it
Section 11.4's own argument applies twice over. Regeneration needs the engine's
toolchain, which is why the release does not push; a schema compiler is a
third toolchain, which the synchronization runner does not have either. This
engine's runner has SwiftPM but no
protocand noprotoc-gen-swift, andinstalling them on every nightly run to notice a change that happens once a year
is not obviously the right trade.
What is missing from the text
Step 3 does not name the engine-side schema tree. An engine that keeps a
copy of the schemas for its compiler has to move it when the package moves,
and nothing says so. This engine had a literal path in its digest check; on
this release it compared the new schema against a copy that was no longer the
one its compiler reads, and refused the release at the end of a
synchronization that had passed every digest and every attestation. The fix
here was to derive the path from the
packagethe attested schema declares,but that reading is invented, not specified.
Step 4 does not say how far "le code émis" reaches. If it includes
schema-derived code, section 11.4 needs to say what an engine does when its
synchronization runner cannot produce it — go red, or install the compiler.
If it does not, the specification should say that this code is outside the
automated path and name what is supposed to catch it, because a pull request
opened by
GITHUB_TOKENcannot rely on a second workflow.A suggestion for 1: state that the schemas an engine vendors are located by the
packagethey declare, so a package rename relocates them by construction. Itcosts one sentence and it removes the literal path from four engines.
A suggestion for 2: make step 4 name schema-derived code explicitly, and require
the synchronization to fail rather than to skip it — a red pull request on the
release that renames a package is precisely the sorting section 11.4 describes.