Expire records on the device by a real window, and say the server's out loud #4

Merged
LNK merged 1 commit from claude/retention into main 2026-09-04 17:34:06 +00:00
Contributor

The last of the review's four foundations. Every manifest, the registry and the console said -1, a test asserted it, and the decisions page called it settled. This reverses that decision on LNK's word, with the old words quoted in the page, and keeps the half of the reason that was true.

What changes. Each manifest now carries two numbers and the console shows them side by side. local_days is how long a record stays on the device once the server has confirmed receiving it: 90 for content (screenshots, typed text, clipboard, shell commands, websites), 365 for timing (window activity, typing rhythm). remote_days stays -1: the server copy is training data and is kept until deleted, declared out loud. The registry carries the local number, contracts-lint holds registry and manifests equal on both and refuses a local window under a day, and here-contract asserts a finite local window and an indefinite, stated server one.

What the gate does. Once at start and hourly, it sweeps by the registry's windows through the same deletion path a person's delete uses, under a receipt marked retention. It does not expire a record the server has not confirmed: the device is a buffer, and a buffer does not discard what has not been read. Those are kept and counted, so a store growing because nothing uploads says so. It sends the server no deletion: local expiry is not erasure. Indicator health rows go after 30 days.

Docs. Decisions page (reversal with the old text quoted), platform-team page, legal note item 7, README invariants, the byte's-journey page.

Proof. Store: an old uploaded frame expires with its pixels, an old unuploaded one and a young one stay, the receipt names the sweep and the server was not asked, a second sweep is a no-op. Gate: the same through the write path with the clock moved. Health log prunes past its window. Sending the server a deletion on expiry fails the store test, checked by making it. Linux verifier on the pinned toolchain: 282 Rust + 86 TypeScript = 368 tests, every stage, exit 0. Not run here: verify.ps1 and the end-to-end suite on Windows.

The numbers are a choice. 90 and 365 are stated assumptions, one line each in a manifest, linted to the registry.

The last of the review's four foundations. Every manifest, the registry and the console said `-1`, a test asserted it, and the decisions page called it settled. This reverses that decision on LNK's word, with the old words quoted in the page, and keeps the half of the reason that was true. **What changes.** Each manifest now carries two numbers and the console shows them side by side. `local_days` is how long a record stays on the device once the server has confirmed receiving it: 90 for content (screenshots, typed text, clipboard, shell commands, websites), 365 for timing (window activity, typing rhythm). `remote_days` stays `-1`: the server copy is training data and is kept until deleted, declared out loud. The registry carries the local number, `contracts-lint` holds registry and manifests equal on both and refuses a local window under a day, and `here-contract` asserts a finite local window and an indefinite, stated server one. **What the gate does.** Once at start and hourly, it sweeps by the registry's windows through the same deletion path a person's delete uses, under a receipt marked `retention`. It does not expire a record the server has not confirmed: the device is a buffer, and a buffer does not discard what has not been read. Those are kept and counted, so a store growing because nothing uploads says so. It sends the server no deletion: local expiry is not erasure. Indicator health rows go after 30 days. **Docs.** Decisions page (reversal with the old text quoted), platform-team page, legal note item 7, README invariants, the byte's-journey page. **Proof.** Store: an old uploaded frame expires with its pixels, an old unuploaded one and a young one stay, the receipt names the sweep and the server was not asked, a second sweep is a no-op. Gate: the same through the write path with the clock moved. Health log prunes past its window. Sending the server a deletion on expiry fails the store test, checked by making it. Linux verifier on the pinned toolchain: 282 Rust + 86 TypeScript = 368 tests, every stage, exit 0. Not run here: `verify.ps1` and the end-to-end suite on Windows. **The numbers are a choice.** 90 and 365 are stated assumptions, one line each in a manifest, linted to the registry.
Every manifest, the registry and the console said `-1`: nothing expires, anywhere, and a test
asserted it. The reason on record was that the data is training data. That is true of the
copy on the server, which is where training happens. It was never a reason for a laptop to
keep a year of screenshots, and the number was doing the work of a policy: every store grew
until the disk did not, and the indicator's health log alone added a third of a million rows
a day, about the pill and not the person, never uploaded.

Each collector manifest now carries two numbers, and the console shows them side by side.
`local_days` is how long a record stays on the device once the server has confirmed
receiving it — 90 for anything that is content, 365 for timing. `remote_days` stays `-1`,
which is the server's decision to make and is declared out loud rather than implied. The
registry carries the local number too, `contracts-lint` holds the two declarations equal and
refuses a local window under a day, and `here-contract` asserts every signal has a finite
local window and an indefinite, stated server one — the same test that used to assert `-1`,
turned round.

The gate keeps the promise. Once at start and then hourly it sweeps by the registry's windows,
through the same deletion path a person's delete uses — tombstone, frames, blobs, digests,
the upload queue — under a receipt whose `requested_by` is `retention`. Two things it will
not do. It does not expire a record the server has not confirmed: the device is a buffer for
the server, and a buffer does not discard what has not been read, so a record past its window
and still waiting is kept and counted, and a store that grows because nothing uploads says
so. And it does not send the server a deletion: local expiry is not erasure. The receipt says
the server copy is kept under its own retention, and the pending-deletions list stays empty.
Indicator health rows go after thirty days.

Reversed in the decisions page with the old words quoted, in the platform team's page, and in
the legal note. What did not change: erasure on request still reaches the server, and nothing
in the client deletes a server copy on a timer.

Tests: at the store, an old uploaded frame expires with its pixels while an old unuploaded one
and a young one stay, the receipt names the sweep, the server was not asked, and a second
sweep does nothing; at the gate, through the write path with the clock moved, the same; and
the health log prunes past its window.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
LNK merged commit 582085ca68 into main 2026-09-04 17:34:06 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
mikebrandon/here-telemetry-rnd!4
No description provided.