Found while synchronizing entid-go onto v2026.08.38, then demonstrated by
accident an hour later.
The gap
Section 11.4 step 3 requires a synchronization to write the prose contracts:
- écrit
spec/, rules.lock et spec/PROVENANCE.md — les contrats en prose
compris, spec.md, engine.md et son engine-<langage>.md, que la release
publie et atteste au même titre que les schémas.
The manifest carries a digest field for every other vendored file — rulesProtoSha256,
conformanceProtoSha256, testeeProtoSha256, irDocSha256, featuresDocSha256,
and the two artifacts. It carries none for spec.md, engine.md or
engine-<langage>.md.
Section 16 then closes the lock:
rules.lock porte exactement ces champs, dans cet ordre :
Twelve fields, plus attestation_identity. So an engine that vendors the three
prose contracts, as step 3 requires, has nowhere to record what they hashed to,
and its verification entry point (section 12.6, "empreintes du lock") cannot
re-check them. They are verified once, at download, and never again.
The demonstration
While entid-go was being synchronized, tools/sync_engines.sh was run from
this repository by accident and copied a newer, unreleased spec/engine.md into
the engine's tree. The engine's own guard caught nothing, because there is
nothing to catch it with:
make verify checks eight digests. engine.md is not one of them, and cannot
be, because no manifest field and no lock field exists for it;
- the file was read afterwards, as a normative source, for section numbering and
for the list in section 16;
- the tree was restored by hand, and the engine only established that its
committed copy is the released one by re-downloading SHA256SUMS out of band:
99bc6e72095841d40c6ee3bbb2df00b16e1d4572311ab9deb630a81f448a756d engine.md
58335ea2aeedf444f49a1133dfe179ad26ac8bfcc5473b9fa34eed00cac64f30 spec.md
85e07d332830db928c46dfd2a5d210865ee1dd9e13277fcaf9405768720bb47b engine-go.md
Nothing was lost this time. What the incident measures is that the engine had no
way of knowing that from inside its own verification, and that the answer had to
come from the release rather than from the repository.
This matters more now than it did before v2026.08.38, because engine.md stopped
being documentation an engine merely reads: section 16's ```lock-fields block
is normative, and entid-go asserts its rules.lock against it by parsing the
vendored copy — deliberately, so that two engines compare against one source
rather than two hand-copied lists. A vendored normative source that nothing
re-verifies is a worse position than a vendored document nobody parses.
What would settle it
Three digest fields in the manifest — specDocSha256, engineDocSha256,
engineLangDocSha256 — and the matching lock fields in the section 16 list, so
that the files step 3 requires are covered by the same mechanism as the files it
requires beside them. That is a normative change to a closed list, which is why
it is an issue here rather than a decision taken in an engine: a fourteenth field
invented by one engine is the failure section 16 already documents, where
conformance_jsonl_sha256 existed on one side only and the first release shipped
seven digests where four engines checked eight.
If the answer is instead that the prose contracts are deliberately outside the
verified set, section 11.4 step 3 should say so, so that no engine parses one as
a normative source.
Found while synchronizing
entid-goontov2026.08.38, then demonstrated byaccident an hour later.
The gap
Section 11.4 step 3 requires a synchronization to write the prose contracts:
The manifest carries a digest field for every other vendored file —
rulesProtoSha256,conformanceProtoSha256,testeeProtoSha256,irDocSha256,featuresDocSha256,and the two artifacts. It carries none for
spec.md,engine.mdorengine-<langage>.md.Section 16 then closes the lock:
Twelve fields, plus
attestation_identity. So an engine that vendors the threeprose contracts, as step 3 requires, has nowhere to record what they hashed to,
and its verification entry point (section 12.6, "empreintes du lock") cannot
re-check them. They are verified once, at download, and never again.
The demonstration
While
entid-gowas being synchronized,tools/sync_engines.shwas run fromthis repository by accident and copied a newer, unreleased
spec/engine.mdintothe engine's tree. The engine's own guard caught nothing, because there is
nothing to catch it with:
make verifychecks eight digests.engine.mdis not one of them, and cannotbe, because no manifest field and no lock field exists for it;
for the list in section 16;
committed copy is the released one by re-downloading
SHA256SUMSout of band:Nothing was lost this time. What the incident measures is that the engine had no
way of knowing that from inside its own verification, and that the answer had to
come from the release rather than from the repository.
This matters more now than it did before
v2026.08.38, becauseengine.mdstoppedbeing documentation an engine merely reads: section 16's
```lock-fieldsblockis normative, and
entid-goasserts itsrules.lockagainst it by parsing thevendored copy — deliberately, so that two engines compare against one source
rather than two hand-copied lists. A vendored normative source that nothing
re-verifies is a worse position than a vendored document nobody parses.
What would settle it
Three digest fields in the manifest —
specDocSha256,engineDocSha256,engineLangDocSha256— and the matching lock fields in the section 16 list, sothat the files step 3 requires are covered by the same mechanism as the files it
requires beside them. That is a normative change to a closed list, which is why
it is an issue here rather than a decision taken in an engine: a fourteenth field
invented by one engine is the failure section 16 already documents, where
conformance_jsonl_sha256existed on one side only and the first release shippedseven digests where four engines checked eight.
If the answer is instead that the prose contracts are deliberately outside the
verified set, section 11.4 step 3 should say so, so that no engine parses one as
a normative source.