Repository navigation
Check v2 archives against the contract before a reader can - #110
Merged
Merged
Conversation
Mobile now builds its version 2 writer before the reader that consumes it (ADR 0004), which leaves a gap: until #96 lands, nothing in the app can tell a correct archive from a plausible one. #98 would produce the first real-data fixtures with no way to know they were right, and a wrong fixture committed early is one every later reader issue is then built against. conformance.py closes that gap. It checks any .cyd against the pinned canonical schema rather than against Mobile's own idea of the format: ZIP layout and entry types, manifest reconciliation in both directions, metadata shape and its agreement with the archive row, an exact match against schema.sql, foreign keys, asset digests and byte counts, orphan payloads, and completeness being true if and only if every asset is available. A checker that passes everything would be worse than none, so self_test.py mutates the canonical fixture twelve ways and requires each to be rejected. It earned its place immediately by catching a bug here: the entry-type check rejected any entry whose mode carried no file-type bits, which is what zipfile.writestr and plenty of real writers emit. Every case "failed" for that one wrong reason. Cases are resealed with a recomputed manifest, because a broken writer fails while internally consistent, and without resealing the manifest digest catches everything before the deeper checks ever run. check_account_readiness.py covers the other half of the prerequisite, the part only a person with the device can do. Media downloads finish after records land, and a pending download becomes an unavailable asset — so an account that looks saved exports as `incomplete` while claiming to be the `complete` fixture. It also reprints the interchange groups Mobile cannot populate at all, so the fixture's real coverage is visible at the moment it is being made rather than only in the docs. bundle.py is the pin-loading and download code test_bundle.py already had. 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.
Prerequisites for #98, so the first real-data fixtures can be trusted when they land. No product code — Python tooling, a runbook, three npm scripts, one CI step.
Why
Mobile builds its v2 writer before the reader that consumes it (ADR 0004), which leaves a gap: until #96 lands, nothing in the app can tell a correct archive from a plausible one. #98 would produce the first real-data fixtures with no way to know they were right, and a wrong fixture committed early is one every later reader issue is then built against.
What's here
conformance.py.cydagainst the pinned contract — layout, entry types, manifest both directions, metadata vs the archive row, exactschema.sqlmatch, foreign keys, asset digests and byte counts, orphan payloads, completeness iff every asset is availableself_test.pycheck_account_readiness.pydocs/bluesky-archive-fixtures.mdbundle.pytest_bundle.pyalready hadThe self-test earned its place immediately
It caught a bug in the checker on first run: the entry-type check rejected any entry whose mode carried no file-type bits, which is what
zipfile.writestrand plenty of real writers emit. Every mutation "failed" for that one wrong reason, including ones it wasn't testing — and it would have rejected valid archives, quite possibly the exporter's own output.Cases are resealed with a recomputed manifest, because that's how a broken writer actually fails: internally consistent, and wrong. Without resealing, the manifest digest catches everything first and the schema and completeness checks never run at all.
Worth a second look
check_account_readiness.pyis not verified against a real device. It's smoke-tested against a database built from theCREATE TABLEstatements extracted frombluesky-migrations.ts, in both a ready and a failed-download state. The device paths in the runbook are whatBaseAccountController.buildAccountPathsanddevice-storage.tsimply; I couldn't confirm them on hardware.self_test.pyis a script with an exit code rather than a pytest suite, matchingtest_bundle.py.complete.cydis 144 KiB, but it carries 1×1 PNGs where these will carry real JPEGs and an MP4.npm run lintis clean; 725 tests pass;test:archive-contractandtest:archive-conformanceboth pass.🤖 Generated with Claude Code