Carry the vault's filing and its staged facts through backup and restore - #819
Merged
Conversation
`DocumentConditionLink` and `ExtractedFact` were classified as backed up and came back from no restore. The register said a restored vault is unsorted and that the facts are re-derivable by re-running the extraction. The first is right; the second understates it. What a re-run cannot produce is the REVIEW DECISION on each fact, and every column holding one defaults to "nobody has looked at this yet". `POST /api/documents/inbound/[id]/confirm` acts only on a PENDING fact and commits it into the structured store, so a restore that let those columns default would offer an already-committed reading for approval a second time and write a second lab result behind it. Both ends live in `src/lib/export/document-filing-backup.ts`, beside each other like the Coach, reminder and vaccination sections. `status`, `needsReview`, `confidence` and the commitment pair are carried and restored verbatim, and the wire schema requires the first three rather than defaulting them. Ordering: the section runs after the documents, the condition episodes, the lab results and the medications. The first two are real foreign keys, unlike the Coach's bare id columns, so an unresolvable value there does not cost one edge, it aborts the transaction and the operator gets none of the account back. The last two are what `committedRecordId` resolves against. The builder therefore carries a filing or a fact only when both of its ends are carried, and the restore still checks and drops what a hand-edited file leaves unresolvable. `committedRecordId` is nulled together with its type, because a type with no id claims a commitment the row cannot name. The round trip seeds a second condition and files the page under it, so a restore that kept the count and lost the pairing fails rather than handing back a lab report filed under a head cold. A third case breaks both references in a saved file to prove the drop path runs and still answers 200. Three new skip catalogues arrive with it, and with them labels for the three that had none: a dropped Coach attachment had been reaching the operator's screen labelled "mood factor" since it was added. The label chain is exhaustive now, so the next catalogue without one stops the build.
MBombeck
force-pushed
the
work/backup-docs
branch
from
August 22, 2026 08:24
e98b9b1 to
d5dde3e
Compare
The scoped-sharing spec routes `/api/auth/me`, and the account switch it drives ends in a full reload. The reload cancels whatever call is in flight, Playwright marks the route handled, and the handler's `fulfill` then lands on it with "Route is already handled!". With `failOnFlakyTests` on CI that turns the whole shard red over a teardown race rather than over anything the test is checking. Same guard the record-session-fence spec and this file's own accessibility sibling already use. The `fetch` is guarded too, because a request cancelled mid-flight rejects there rather than at the fulfill, and the earlier of the two is the one that decides which error the run reports.
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.
DocumentConditionLinkandExtractedFactcome off the coverage register, and the second one turned out to be more than lost history.The review decision is the part that cannot be re-derived
The register called the facts "re-derivable only by re-running the extraction against a provider, at the operator's cost". That understates it. What a re-run cannot produce is the review decision:
status,needsReview,confidence, and the paircommittedRecordId/committedRecordType. Every one of them has a schema default meaning "nobody has looked at this yet".POST /api/documents/inbound/[id]/confirmacts only on a PENDING fact and commits it into the structured store. So a restore that let those columns default returns the right number of facts and puts an already committed reading back in the review queue. Approving it a second time writes a second lab result. The wire schema requires those fields rather than defaulting them.Both references are real foreign keys
Unlike the Coach's bare id columns, an unresolvable value here aborts the whole transaction rather than dangling. The builder therefore carries a row only when both of its ends are carried, mirroring how
records-backup.tsscopes documents and episodes, and the restore still checks against what it actually wrote for the hand-edited file.committedRecordIdis the one bare id, and it is nulled together with its type: a type with no id claims a commitment it cannot name.Ordering is stated at the call site: after documents and episodes for the keys, and after lab results and medications for what the commitment resolves against. Resolving earlier would null every commitment and still report success.
A reporting defect found on the way
catalogueLabelin the admin backups view ended in an unguarded fall-through, soreminderReference,coachAttachmentandcoachReferencehad been reaching the operator's screen labelled "Mood factor" ever since they were added. The skip report was reporting, and reporting wrong.Fixed, with labels for all six unlabelled catalogues across the six locales, and the chain now ends in
const unlabelled: never = catalogueso the next catalogue without a label is a compile error instead of a wrong label.Also corrected
BackupSummaryunder-counted; both new models are in it, the same gap v1.37.19 closed for visits.link-surface-guard.test.tscaught the new module. Added to the frozen exemptions under the same standing rule as the visits and vaccinations sections: a restore preserves the original filing instant, which the service signature cannot express.Proof
Four mutations, each reverted and re-run green. Forcing
status: "PENDING"fails on the reviewed fact coming back up for review. Filing the page under the wrong episode fails by condition name. NullingcommittedRecordIdfails by id. Writing the foreign key unchecked fails a third test withexpected 500 to be 200, which is what makes the constraint claim empirical rather than theoretical.Register: 9 models remaining. Refs #186.