docs: record the day the archive learned to come back

Batch 10 closed, and with #58 the tracker has no open issue for the first time.
The entry carries the two things that would otherwise be re-derived: a test
premise that was wrong in the direction of passing, and a KDoc claim about
`clearAllTables` that was confidently wrong until it was checked against the
bytecode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
null 2026-08-21 02:29:02 -05:00
parent 0ae92bd134
commit ebe5ab8d6f
1 changed files with 89 additions and 0 deletions

View File

@ -32,6 +32,95 @@ written and stay true. It is exempt from review for the same reason a receipt is
## Entries
### 2026-08-21 — The export stops being a one-way door; the tracker is empty
`#58` was the last open issue in the repository, and it closed the loop the
export left open: the app offered a copy of everything and nothing could read
one back. A user changing phone started the prediction model from zero, and the
archive's own prose — *"Keep this file. A future version of the app will be able
to read it back"* — was a promise nothing checked.
**What shipped** (`0ae92bd`). `ExportReader` mirrors `ExportDocument.render` in
the same module, over a hand-written strict `Json.kt`: no library, because
`core/export` has two dependencies and their narrowness is the point, and strict
because a parser that accepts a trailing comma is a parser that will one day
accept somebody else's file as a cycle history. Refusals are typed —
`NotOurFile`, `NewerFormat(v)`, `Damaged` — and unknown *keys* are ignored,
which is rule 2's other half and the only reason the format can ever grow.
`CycleRepository.importHistory` is a deliberate third write path rather than a
loop over `confirmPeriodStart`, and the reason is worth carrying forward: an
archive is history the app never forecast, so scoring any of it fills §16's
figures with numbers the app invented about itself. The backfill guard catches
most of that by date and **not all of it** — a file exported this morning
carries this morning's period, which would sail through. The test names that
case explicitly.
**Two things learned the hard way, both recorded so nobody re-derives them:**
- **A test premise can be wrong in the direction of passing.** The first
atomicity test fed the importer a file naming the same day twice, expecting
the UNIQUE index to abort mid-import. It never threw: the importer's own
dedupe skipped the duplicate, so the test was measuring a successful import.
Rewritten to fail the *last* step — the recalculation — via a counting engine
that can be told to throw.
- **A comment can be confidently wrong about a library.** The first version of
`replaceEverything`'s KDoc said `clearAllTables` "ends the transaction it is
called in", which sounded right and was not: nesting it under Robolectric
rolled back cleanly. What is actually true, checked against room-runtime 2.8.4
bytecode rather than the documentation, is that `performClear` opens with
`assertNotSuspendingTransaction()` and runs its work through
`runBlockingUninterruptible` — a blocking coroutine of its own — and finishes
with a `VACUUM` SQLite forbids inside a transaction. So the function stays, on
a claim that can be checked, and Delete My Data keeps `deleteEverything` and
its VACUUM. Replacing a history is not erasing one.
**Recorded decisions.** The archive cannot touch the app lock: it carries
`biometricUnlock` and the importer does not apply it, because there is no PIN in
the file and there cannot be. Merge leaves a date already recorded on this phone
exactly as it is rather than merging field by field — §14 forbids a file
rewriting a record she made here. And the choice between add and replace is
asked **before** the picker, not after the file is read where the app could have
said how much was in it: the screen that would ask is the screen a re-lock
destroys.
**One correction to a thing filed yesterday.** `#58` was titled "Restore from an
encrypted export" and its body said `DataExporter` "writes an encrypted
archive". It does not, and never did — `ExportCopy.PROTECTION_BODY` and the
file's own `aboutThisFile` both say so in as many words. The issue was wrong when
filed; what shipped reads the plaintext archive the app actually writes.
**Device evidence** (PeriodQA, emulator-5554, debug build of `0ae92bd`): Settings
→ Restore from a file → Add to what is here → Downloads →
`records-2026-08-19.json` gives *"Restored. 4 periods and 2 spotting days
added."*; Insights then shows three cycles with accuracy still unscored; the same
file a second time gives *"Everything in that file was already recorded here, so
nothing changed."* `uiautomator dump` rather than screenshots — FLAG_SECURE
returns black.
**Also in this commit:** `LockSettingsViewModelTest`'s hang budget went from 60
seconds to three minutes. It passed alone and failed when `:app`, `:core:data`,
`:core:export` and `:core:datastore` ran in one invocation — three real PBKDF2
derivations at 210,000 iterations. The budget catches a stuck coroutine, not a
slow one, and a flaky guard is one people learn to ignore.
- **Closed:** #58. `Batch 10 — Show what you already know` closed with it.
**Every issue in the tracker is now closed**, and Batches 09, 10, 11 and 12
all landed since yesterday morning.
- **Next action:** A release, or the next batch — and the decision between them
is Kaspa's. What argues for cutting one now: no known defect is outstanding,
both P0 release-blockers found yesterday are fixed and verified on a device,
and `./gradlew check` is green including `checkNoHealthLogging` and
`checkPermissions`. What argues against: `SECURITY_CHECKLIST.md`'s device rows
have been *written* rather than *walked* for the biometric-only and reminder
paths, and nothing in this project has ever run on an API 26 device, which is
its own `minSdk`. Recommendation: walk the checklist on a 26 image and on
PeriodQA before the image is cut, then release.
- **Blockers:** Unchanged and both need a person, not an agent — #8's three
branding marks, which must not be faked, and #9's Command Center webhook URL
and secret, which are not readable from this machine. Until it is registered an
opened `P0` raises no alert at all.
### 2026-08-20 (evening) — Two release-blockers, and the trap that was reported
Kaspa reported one bug — *"on the settings page, if you go to app lock you can't