Skip to content

fix(T13867): a snapshot-only store is never up to date while the journal moved past the head - #2355

Merged
kryptobaseddev merged 2 commits into
mainfrom
fix/T13867-journal-unread-stale
Oct 18, 2026
Merged

kryptobaseddev merged 2 commits into
mainfrom
fix/T13867-journal-unread-stale

Conversation

@kryptobaseddev

Copy link
Copy Markdown
Owner

T13867 (under T12323). Local runs pending axiom hold: the touched test file, typecheck, build, gate 38 and gate 39 run here after "axiom slot released". Until then, CI is the test evidence.

Problem

A device that reads only snapshots (released 10.19, or a new build that restored and never joined the journal) holds only the newest checkpoint of a journal (v3) stream. Other devices' journal segments past that checkpoint are missing, yet cloud pull said up-to-date and cloud verify said match. Gate evidence: device m on 10.19 had 0 of 10 tasks.

Fix (this repo)

  • Detection: journalUnread counts the segments past a v3 head's coversSeq (headSeq - coversSeq). It applies only to a store that is not on the journal.
    • A store is on the journal only when it holds a genesis cut for the stream AND sync.push or sync.pull is on.
    • A cut on its own, as a restored bundle could carry, does not count.
  • cloud pull: where it said up-to-date, it now refuses with E_NEXUS_VAULT_BEHIND, naming the missing segments. The fix text is cleo sync enable push, or a vault push from a device that writes the journal (its push checkpoints the journal).
  • cloud verify: the verdict is behind, with the same remedy.
  • Restore: warns with W_NEXUS_VAULT_JOURNAL_UNREAD.
  • Verify fold-in (from T13777): on a journal head, tables only snapshots carry (zz_vault_files, other databases, row-identity-exempt tables such as nexus_devices and nexus_project_*) are listed but no longer decide the verdict. A W_NEXUS_VAULT_SNAPSHOT_ONLY warning names them. This removes the gate's spurious ahead.
  • Header: every request sends NEXUS_STREAM_READER_HEADER (x-cleo-stream-reader: 3), one exported constant in cloud/http.ts.

Released 10.19 needs the server (T13876)

10.19 decides pull and verify from the checkpoint list alone and sends no version or capability header. No client change can make it report stale.

  • The fix is T13876 in cleo-nexus apps/api/src/routes/streams.ts.
  • GET /v1/streams/:streamId/checkpoints and the head GET refuse a v3 stream with 409 E_STREAM_VERSION when the request lacks that header.
  • It ships only after a CLEO release that sends the header.

Tests (nexus-vault.test.ts)

The test fake now has streamReaderRequired, which applies the T13876 rule.

  • Snapshot-only store on a journal stream:
    • With the rule on, A journals and B restores the genesis without joining.
    • Control: B's pull says up-to-date and its verify says match.
    • The test checks that the restored store carries no genesis cut.
    • After A writes a segment, B's pull refuses with E_NEXUS_VAULT_BEHIND and its verify says behind, both naming cleo sync enable push.
    • Cut only: with a genesis cut written into B's store, as a bundle could carry, B is still behind.
    • A, which is on the journal, still verifies match.
    • A request without the header gets 409 E_STREAM_VERSION.
  • Snapshot-only table: a tasks_goal row on a journal store is listed as differing, the verdict stays match, and the warning names the table.

Gates

  • Pass: biome on the changed files, changesets, and gates 28, 32 and 36 (--base origin/main).
  • Pending the axiom hold: gate 38, typecheck, build and gate 39 locally. CI runs typecheck, build, gate 39 and the nexus-vault shards.

🤖 Generated with Claude Code

kryptobaseddev and others added 2 commits October 17, 2026 09:59
…nal moved past the head

On a checkpoint/v3 head, a store that is not on the change journal (no
genesis cut with sync.push or sync.pull on) holds only the snapshot. Pull
now refuses with E_NEXUS_VAULT_BEHIND, verify says behind and restore warns,
naming the missing segments and the way forward. On a journal head, tables
only snapshots carry no longer decide the verify verdict. Every request
sends NEXUS_STREAM_READER_HEADER so a server can refuse v3 reads to clients
that cannot read the journal (T13876).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a creates (T13885)

tasks_goal comes from a legacy migration the fixture store lacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kryptobaseddev
kryptobaseddev merged commit 9fa2827 into main Oct 18, 2026
41 checks passed
@kryptobaseddev
kryptobaseddev deleted the fix/T13867-journal-unread-stale branch October 18, 2026 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant