One record per contract: dissolve ref/, and make server/spec/v1.md true - #863
Open
fujibee wants to merge 4 commits into
Open
One record per contract: dissolve ref/, and make server/spec/v1.md true#863fujibee wants to merge 4 commits into
fujibee wants to merge 4 commits into
Conversation
Nothing checked them. docs/spec/vectors/age-v1-vectors.json ships a profile_document pointing at a path that does not exist, and the vectors are what a second implementation reads first. On this commit the check is RED and names eleven pointers: five in ADR 0003, which 75b8b1c moved out of docs/adr/ref/ without adjusting its relative depth; five from the age-v1 profile to its own conformance vectors, which sit outside ref/ while the profile does not; and the vectors' own pointer back. The following commits close all eleven. Both halves refuse to pass on an empty match, so a matcher that stops matching, or a renamed JSON field, reports itself instead of going quiet.
It carried a SUPERSEDED banner, which is an ADR mechanism: ADRs are immutable and get superseded, specs get edited (CONTRIBUTING.md). Marked rather than corrected, it left the contract with four records - this file, the remote-sync design, a spec under ref/ that says not to cite it, and a comment in remote-sync.mjs naming errors.ts the definition because this file was dead. Rewritten from the implementation. The endpoint list was eight, of which POST /v1/pairing/exchange and POST /v1/credentials/<id>/revoke do not exist and four that do were absent; it is now the ten server/src/app.ts registers. The pairing and per-device-credential section described a removed model and is replaced by the four registration and lookup endpoints, taken from connectSchema, resolveTeamsByName and getTeamSnapshot. Authorization: Bearer was required on everything but health; the server's only mention of that header is redacting it from logs. The reason it carries no credential, and the two consequences that rest on it - a repeat connect writing nothing, and the network being the trust boundary - are stated where a reader meets them. The error table listed six codes for the removed model and omitted three the server emits. It is now the set derived from every ProtocolError construction, and says what it does not cover rather than leaving 502/503/504 looking protocol-defined.
ref/README.md said nobody builds toward anything under it and that no document there may be cited. Eleven documents lived there; nine describe shipped code and were cited 34 times from outside, including by scripts/key.sh, scripts/remote-sync.sh, sqlite-sync.sh and server/spec/v1.md. Making the distinction visible from the path did not stop anyone citing them, so the directory goes rather than the warning getting louder. Promoted nine: the Stage-1 contract, the age-v1 profile, read-state, retention-gap and opaque-envelope specs, ADRs 0005-0007, and the adaptive-catchup design that remote-sync.mjs names in its own comments. Deleted two: device-pairing, which has no implementation and no subcommand, and remote-sync-dogfood, which asked to be deleted once integration/remote reached main (17d0ba7) and taught a connect --token-stdin that no longer parses. Promotion is not a move. Statuses said proposed or dogfood, which was the vocabulary of the directory they sat in; the specs are current and the ADRs accepted, edited first where they still described the pairing and per-device-credential model the server no longer has. Editing them is what the ADR rule allows while they are proposed and unadopted, and leaving that text under docs/adr/ would have shipped a wrong record rather than an unfinished one. The last promotion out of ref/ (75b8b1c, ADR 0003) left five relative links pointing one directory too deep and nothing noticed. All 38 links this move invalidated were rewritten by resolving each basename against the tree, and the checker added in the first commit is what enumerated them. Prose and code paths are a separate instrument: 28 more references live in security.md, security.ja.md and three script headers, where no link checker can see them.
The rewrite fixed the href and left the label reading ../spec/age-v1-profile.md, a path that no longer exists. A link checker reads the target and never the text, so this is the shape it cannot see; swept the tree for label/href basename disagreement and this was the only one.
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.
Affects existing users only as documentation. No behaviour change: the one code edit is a comment in
scripts/internal/remote-sync.mjs, and three script headers change a path in a comment. Everything else isdocs/andserver/spec/. This is the "something broken is repaired" kind — a reader following these documents was being sent to a removed model or a dead path.What was wrong
One contract had four records, and the one with the authoritative filename was the dead one.
server/spec/v1.mddocs/design/remote-sync.mddocs/spec/ref/stage-1-remote-sync.mdref/, whose README says do not cite one as the reason something is the way it isscripts/internal/remote-sync.mjs:1472errorBody()… is the definition, sinceserver/spec/v1.mdis marked SUPERSEDED"supersededis an ADR mechanism.CONTRIBUTING.md:52states it: a later ADR supersedes an earlier one, and ADRs are immutable history. Specs get edited. Marking a spec superseded instead of correcting it is what let the implementation become the definition by default.server/spec/v1.mdRewritten from the implementation rather than patched paragraph by paragraph.
POST /v1/pairing/exchangeandPOST /v1/credentials/<id>/revokedo not exist anywhere inserver/src; four that the server does register were absent. It now lists the tenserver/src/app.tsregisters. Cross-checked by extracting both sets and diffing: 0 difference.Authorization: Beareron everything but health, in eleven places. The server's only mention of that header is redacting it from logs. The reason there is no credential — reaching the server is the permission, the network is the trust boundary — now sits where a reader meets it, along with the two things that rest on it: a repeatPOST /v1/connectwriting nothing, and the requirement not to expose a server to a network whose reachability you would not treat as authorization.connectSchema,connectTeam,resolveTeamsByNameandgetTeamSnapshot— including409 team-already-existsand why a credential-free route depends on it writing nothing at all.401 unauthenticated,401 invalid-pairing-token,403 forbidden,403 credential-scope-violation,409 pairing-token-consumed,410 pairing-token-expired); three the server emits were missing (team-already-exists,cipher-profile-mismatch,team-name-match-limit-exceeded). It is now the set derived from everyProtocolErrorconstruction, and says explicitly what it does not cover, so502/503/504stop looking protocol-defined.ref/is dissolvedref/README.md— one blob copied into three directories — said "Nobody is building toward anything in aref/directory" and "Do not implement from a document underref/. Do not cite one as the reason something is the way it is." Eleven documents lived there and were cited 34 times from outside, including fromscripts/key.sh,scripts/remote-sync.sh,scripts/drivers/storage/sqlite-sync.shandserver/spec/v1.md. Making the distinction visible from the path did not stop anyone citing them.Promoted nine, each measured against the implementation first:
docs/spec/stage-1-remote-sync.mdstorage_sync_*operations implemented;stage1-resyncadvertised by sqlite and not by jsonl, exactly as the spec's "optional capability" saysdocs/spec/age-v1-profile.mdage-v1102 occurrences,X255198; its conformance vectors already sat outsideref/docs/spec/read-state-synchronization.mddocs/spec/retention-gap-resynchronization.mdresync-requiredinremote-sync.mjs,storage.ts,errors.ts, plus three test filesdocs/spec/server-opaque-envelope.mdkey_id/cipher/blobinprotocol.ts,storage.ts,001_initial.sqldocs/adr/0005-remote-sync-contract.mddocs/adr/0006-composite-read-state-frontier.mdfrontier45 occurrencesdocs/adr/0007-stable-member-and-roster-identity.mdmember_id321 occurrencesdocs/design/adaptive-sync-catchup-v1.mdremote-sync.mjs:2876-3135, which cites this document by name in three comments; 23 lines of testsDeleted two.
device-pairing.md(811 lines):pair-v1andSASappear nowhere in the tree andkey.shhas norequest/approvesubcommand.remote-sync-dogfood.md(177 lines): it asked to be deleted onceintegration/remotereachedmain, which17d0ba7did, and its runbook teachesconnect --token-stdin, a flagremote.shno longer parses — one comment is all that survives of it.Promotion is not a move
Statuses said
proposedordogfood— the vocabulary of the directory they sat in. Left alone, the documents would have been half-promoted: authoritative location, provisional label. The specs are nowcurrentand the ADRsaccepted.Two ADRs could not be marked accepted as they stood, because they still described the pairing and per-device-credential model the server no longer has:
manifest-terminal-acknowledgement mechanism, which has no implementation. Its "key epoch" is written askey_id, the name the protocol actually uses.Editing them is what the ADR rule permits while a document is
proposedand unadopted (AGENTS.md: squash while single-owner and unmerged; the supersede chain becomes mandatory only aftermain). Flagging it anyway, because it is the judgement call in this PR — the alternative was to shipdocs/adr/containing paragraphs I had measured to be describing a removed mechanism.stage-1-remote-sync.mdalso contradicted itself — line 37 said SQLite is the Stage-1 implementation, line 229 said SQLite and JSONL both implement it. It now names both and what each advertises.The guard, and why it is the first commit
There was no link checker. That is why
docs/spec/vectors/age-v1-vectors.jsonhas been shipping"profile_document": "../age-v1-profile.md"— a path that did not exist, because the vectors already pointed at where the profile would live after promotion.The first commit adds the checker and is red, naming eleven pointers before anything is repaired:
docs/adr/0003, which75b8b1cmoved out ofdocs/adr/ref/without adjusting its relative depth — the last promotion out ofref/broke five links and nothing noticed;Landing it red first is the positive control. A checker introduced alongside the fix is green from birth and no one has seen it fail.
Both halves refuse to pass on an empty match, so a matcher that stops matching, or a renamed JSON field, reports itself rather than going quiet.
Verification
ref/directoriesref/pathref/references, path and name instrumentsv1.mdvs registered inapp.tsThe move invalidated 38 relative links. All were rewritten by resolving each basename against the tree, with the checker enumerating them before and confirming after — no link was fixed by hand and hoped over.
A link checker is not enough on its own: 28 further references live in prose and code —
docs/security.mdanddocs/security.ja.mdcite the age-v1 profile by path with line numbers twelve times each, and three script headers name it in comments. No markdown link checker can see those, so they were swept with a second, path-and-name instrument and rewritten too. That is why the residual-reference row above is measured with both.Suites run locally on this head (macOS):
test_doc_links,test_type_registry,test_claude_template— 26 ok, 0 not ok.test_bin_agmsg,test_remote_setup_doc,test_storage_contractin CI'sxargs batsform.docs/spec/vectors/verify-age-v1-vectors.mjsexits 0.test_remote_sync_enginepasses. Local form is not CI's shard form.Destination drift re-measured at commit time:
origin/mainisf7de22aand the merge base isf7de22a.