chore(deps)!: repin core 0.21.0, archive→retire - #358
Draft
LKSNDRTMLKV wants to merge 4 commits into
Draft
LKSNDRTMLKV wants to merge 4 commits into
LKSNDRTMLKV wants to merge 4 commits into
Conversation
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🚧 Draft until dpp-core 0.21.0 is on crates.io. The pin in
[workspace.dependencies]is already0.21.0, so CI is red until that versionpublishes — there is nothing to fix in the meantime. Verified green locally
against the unreleased core via
just core-local:just check, 1251/1251.Repins to dpp-core 0.21.0 and carries the two renames that version forces, plus
the gate that stops the third one happening again.
The problem this ends
archivenamed three unrelated things in this workspace:archivedretiredArchivePort,ARCHIVE_S3_*,trustMode.archiveBackupCopyPort,BACKUP_S3_*,trustMode.backupPassportVersion,ArchivingPassportRepo,GET /versionsThe third is the one the standard defines, and it is one of the six cited by
Commission Implementing Decision (EU) 2026/1736. While all three wore the word,
anyone mapping this system onto EN 18221 by name ticked a box that was not
ticked — which is exactly how the clause 4.2 gap survived: the name looked
taken. #352 built the thing; this makes the name true.
Nothing was removed. Archiving is a live obligation and it keeps its word.
What it no longer shares is a wire surface with two other concepts.
Two further uses are compound, unambiguous in context, and deliberately
untouched: the keystore's archived keys, and a seal's archival timestamp
(ETSI's own term). So is
retireon facilities and operator identifiers — adifferent object, and a retire-not-delete record rather than a status.
Breaking surface
POST /vault/api/v1/dpp/{dppId}/archivePOST …/retirearchiveDppretireDpp"archived""retired"— and"archived"is refused with a message that says where the word wentdpp.passport.archiveddpp.passport.retired"archived""retired"(new entries only — see below)trustMode.archivetrustMode.backupARCHIVE_S3_*BACKUP_S3_*odal passport archiveodal passport retireports::archive::ArchivePort+ 4 typesports::backup::BackupCopyPort+ 4 (core #292)🚨 The migration rewrites one table and deliberately not the other
ops/pg/0041_retired_status.sql.passport.statusis current state, so it is rewritten and the CHECK narrowsonto
retired.passport_audit.actionis history and is not rewritten.action,prevStatusandnewStatusare all inside the hashed payload(
dpp_types::audit, chained since 0015), so anUPDATEwould breakverify_audit_chainfrom the edited row onward and every later entry wouldread as tampered. So the CHECK only widens:
retiredis added,archivedstays. One permanently permitted legacy value, spent to keep the trail
verifiable. An entry that says
archivedis a true record of a transitionperformed while that was the word.
What the rename turned up on its own
The CLI called a superseded passport "retired".
Supersession.retired, andRetired: <id>in the output of bothamendandsupersede, for a recordwhose status is
superseded. Harmless whileretiredmeant nothing; the momentit became a status, that line names the wrong one. Renamed to
supersededthroughout, which is what the field's own doc already said it held.
Two stale ESPR citations.
s3_archive.rsanddpp-types::snapshotbothattributed the back-up copy to Art. 13. Art. 13 is the registry. The
obligation is Art. 10(4), which core's own port module has said for some time.
A requirement stated on a method that cannot express it.
ArchivePort::update_archiverequired the provider to "store the new versionwhile preserving the full version history", which reads as clause 4.2 already
being satisfied by wiring a back-up adapter. It never was.
🚨 It is not, however, a duty on the wrong actor — my first reading of this
was wrong and is corrected here and in core #292. EN 18221's Annex ZA puts
ESPR Art. 10(4) at clauses 4.3 and 4.5, not 4.2, and clause 4.2 expects archived
versions to be held by the back-up provider as well as by the main one. A
provider is not exempt. What separates the two is shape:
BackupCopyPortcarries one copy per passport and no series at all, so nothing about clause 4.2
is expressible through it, whoever owes it.
The corrected wording is applied at every place this repo states the
distinction —
s3_backup.rs,PassportVersionStore, the vault service'sversionsfield,ops/pg/0041and the CHANGELOG entry — so the looser versionis not the one somebody finds first.
ops/pg/0040's header still contrasts thistable with
status = 'archived', a status that no longer exists; an appliedmigration cannot be edited without breaking sqlx's checksum, so
0041carriesthat correction instead.
The gate
scripts/vocabulary-check.sh, wired intojust check. Three absolute rules —no allow-list, because clause 4.2 archiving needs none: it is served at
/versionsand names no route, path file or subject after itself.archivapi/paths/file name containsarchivarchivscripts/vocabulary-check.test.shreintroduces each collision in a synthetictree and asserts the gate refuses it, plus a clean-tree case so the other four
cannot pass against a gate that rejects everything. 5/5, and the four rejections
were watched to fail before being trusted.
Verification
just check— green, 1251 tests, against../dpp-coreat the 0.21.0content via
just core-local.just openapi-bundle— re-bundled;openapi.bundled.{yaml,json}carryretireDppand no stalearchivedstatus.place those execute, and it cannot run until core publishes.
Cargo.lockis deliberately untouchedjust core-localrewrites it to point everydpp-*crate at the local path,with the registry checksums stripped. Committing that would break CI in a way
that reads as a dependency problem. It is restored to its
maincontents here,so it is stale by one version — harmless, because nothing in CI builds
--locked, and it cannot be made correct before 0.21.0 has a checksum oncrates.io.
Release-day order
review-ready.which is held for the same reason.