Repository navigation
Pass bidirectional Cyd Bluesky archive v2 conformance and enable the writer - #119
Merged
Merged
Conversation
Mobile built its version 2 writer before the readers that consume it, and kept export behind __DEV__ until an archive it wrote could be proven readable — by Mobile and by Desktop. This is that proof, and the gate that keeps it true. The matrix names every conformance row the writer's release depends on and ties each to the tests that prove it. It fails two ways: a row gone red, and a row whose evidence was renamed or deleted out from under it. Evidence spread across eighty test files is evidence nobody can audit. Both directions are new. A canonical Desktop archive now goes all the way through intake, restore and merge and is read back through Mobile's own browse queries; that restored account is then re-exported through Mobile's writer and handed to the contract's own checker. The round trip is lossy in ways Mobile cannot help, so each loss is asserted as a loss — an unasserted one is indistinguishable from a regression. Export is now "Export Bluesky archive" in the app-wide menu, beside import, because the two halves of moving your data between Cyd installations belong side by side. The menu has no account in hand, so which account is the export's own first question — asked only when there is more than one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review found the gate's own weak spot: a row proven by substring-matching a describe block stays green when the one test carrying its claim is deleted, which is the rot the matrix exists to catch. Evidence now carries a count, so a deletion fails the row and whoever made it has to say so there. Two claims were also wider than their evidence. Offline browsing asserted media_asset rows; it now asks the query Browse itself runs, which meant lifting that query out beside buildFirstPageQuery so something other than a phone can run it. And only the complete fixture made the round trip, so an incomplete archive coming back looking complete — worse than the missing file — was unproven. Both fixtures go both ways now. Readers and the writer ship in one version rather than two: nobody can export before installing the version that added export, and that version reads archives. What the ordering rule actually guards is an archive existing before anything can read one, so that is a check now instead of a sentence in an ADR — every tag and the working tree, by module rather than by commit. The rest is what review named: glossary terms the CONTEXT.md entries tell us to avoid, a docblock left describing the wrong constant, and the sheet and handle treatment the two archive modals had each grown their own copy of. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Closes #100.
Mobile built its version 2 writer before the readers that consume it (ADR 0004) and kept export behind
__DEV__until an archive it wrote could be proven readable — by Mobile and by Desktop. This is that proof, the gate that keeps it true, and the export it unblocks.The matrix
npm run test:archive-matrixnames 21 conformance rows across the three acceptance criteria of #100 and ties each to the tests that prove it. It fails three ways, each verified by breaking it on purpose:least=count, because substring-matching a describe is convenient and weak on its own.It runs in CI on every push and subsumes the
test:archive-contractandtest:archive-conformancesteps, which are now local-only npm scripts.Beyond Jest it runs the contract's own Python checker over archives Mobile's writer produced — the two committed real-data fixtures and the archives the round-trip test writes — plus the checker's mutation cases, so the thing doing the checking is known to still reject what it should.
Both directions
services/__tests__/archive-contract-exchange.test.ts, gated on the pinned canonical bundle:The round trip is lossy in seven ways Mobile cannot help. Each is asserted as a loss, under "what a Mobile round trip loses, on purpose": an unasserted loss is indistinguishable from a regression, and fixing one is meant to fail its test. Two of the seven — a like's own CID, and the bookmark record — were not written down before and are now in
docs/bluesky-archive-fixtures.md.No bugs turned up in the writer or the readers: they already interoperated with the canonical fixtures.
The writer
Export is now "Export Bluesky archive" in the app-wide menu beside import, because the two halves of moving your data between Cyd installations belong side by side. The menu has no account in hand, so which account is the export's own first question — asked only when the device holds more than one.
DevArchiveExportCardand its__DEV__gate are gone.Readers and the writer ship in the same version rather than two. Nobody can export before installing the version that added export, and that version reads archives. What the ordering rule actually guards is an archive existing before anything can read one, so that is a check now rather than a sentence in an ADR: the
readers-releasedrow walks every tag and the working tree and fails any that offers export withoutarchive-import,archive-restoreandarchive-merge. It is written against modules rather than commits, so a rebase cannot retire it and the next archive version inherits it unchanged. ADR 0004 records the reasoning.Known gap, not addressed here
iOS import/export staging is still eligible for device backup. ADR 0014 says it should be excluded and
plugins/android-backup-rules.jsdoes that for Android, but there is no iOS equivalent, soDocuments/archive-intake/andDocuments/archive-export/go to iCloud.expo-file-system57 exposes no API forNSURLIsExcludedFromBackupKey, so closing it needs a config plugin or a small native module. It predates this branch (#91/#99 territory); thedevice-backuprow proves the Android half. Worth its own issue.Verification
npm run lint(eslint + tsc) cleannpm test— 959 tests, 82 suites greennpm run test:archive-matrix— 21/21 rows against the bundle pinned atcbd2614🤖 Generated with Claude Code