Skip to content

fix(protocol): chat-sync preservation — null reader floor, publisher-derived invariant, drop the dead clone seed - #1252

Merged
hdkshingala merged 4 commits into
mainfrom
traycer/chat-preservation-train
Aug 17, 2026
Merged

hdkshingala merged 4 commits into
mainfrom
traycer/chat-preservation-train

Conversation

@tanveergill

Copy link
Copy Markdown
Contributor

Protocol half of the chat field-preservation train (companion host PR in the internal repo pins this branch).

What

  • Null reader floor: the chat-head writer schema no longer pins `minReaderVersion` to the 1.1 floor — it inherits nullable/default-null. The 1.1 schema additions are additive and read-safe for a 1.0 reader, and per `COMPATIBILITY.md` preservation is never a reason to raise the floor. `CHAT_SYNC_1_1_READER_FLOOR` is kept (also the cut-plan completeness threshold) and re-documented as the mechanism for a future deliberate raise.
  • Publisher-derived invariant: `COMPATIBILITY.md` §6/§7 and the captured-levels manifest now state that parts, `cdc`, and `hostPrivateShard` are publisher-derived levels that must never carry durable chat data — re-derivable from the owner's op log, with the only round-trip through the owner's own predecessor head.
  • Drop the dead clone seed: `clients/shared/cloud-chat/clone.ts` (`buildChatCloneSeed` / `chatCloneResidualsOf`) had no production consumer; the host's chat-sync record adapter is the surviving exhaustive cross-boundary consumer of the captured-levels manifest, now referenced by role.

Verification

  • `bun run --filter @traycer/protocol test`: 162 files / 2594 tests green
  • `bun run --filter @traycer-clients/shared test`: 65 files / 1035 tests green
  • Writer-floor mechanisms ablation-verified in the host suites (companion PR)

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 988cbc1e-8aa7-4311-a19a-65bf10db52a4

📥 Commits

Reviewing files that changed from the base of the PR and between 00a7147 and facf7be.

📒 Files selected for processing (9)
  • clients/shared/cloud-chat/__tests__/__fixtures__/published-cloud-chat.ts
  • clients/shared/cloud-chat/__tests__/cloud-chat-clone.test.ts
  • clients/shared/cloud-chat/clone.ts
  • protocol/src/persistence/COMPATIBILITY.md
  • protocol/src/persistence/chat-sync/__tests__/__fixtures__/chat-sync-schema-surface.ts
  • protocol/src/persistence/chat-sync/__tests__/__fixtures__/published-chat.ts
  • protocol/src/persistence/chat-sync/__tests__/chat-sync-head.test.ts
  • protocol/src/persistence/chat-sync/captured-levels.ts
  • protocol/src/persistence/chat-sync/head.ts
💤 Files with no reviewable changes (2)
  • clients/shared/cloud-chat/tests/cloud-chat-clone.test.ts
  • clients/shared/cloud-chat/clone.ts

Included review availability: 0 reviews are currently available. Based on recent review activity, included reviews refill at 1 per hour.


Summary by CodeRabbit

  • Compatibility

    • Updated chat synchronization metadata to support an optional reader-version requirement.
    • Newer chat publications remain readable and re-publishable by compatible older readers.
    • Publisher-derived planning metadata can now be regenerated without data loss.
  • Documentation

    • Clarified residual capture, re-publication, and compatibility behavior.

Walkthrough

The chat-sync head schema now defaults minReaderVersion to null and accepts compatible explicit floors. Publication fixtures and tests reflect this behavior. Compatibility documentation classifies publisher-derived metadata as re-creatable planning data. Cloud-chat clone code and tests were removed.

Changes

Chat-sync compatibility

Layer / File(s) Summary
Nullable head contract
protocol/src/persistence/chat-sync/__tests__/__fixtures__/chat-sync-schema-surface.ts, protocol/src/persistence/chat-sync/head.ts
Storage, domain, and writer schemas now allow a nullable minReaderVersion with a default of null.
Publication behavior and validation
protocol/src/persistence/chat-sync/__tests__/__fixtures__/published-chat.ts, clients/shared/cloud-chat/__tests__/__fixtures__/published-cloud-chat.ts, protocol/src/persistence/chat-sync/__tests__/chat-sync-head.test.ts
Fixtures emit no reader floor by default. Tests cover absent floors, explicit compatible floors, and acceptance by a 1.0-shaped reader.
Publisher-derived metadata policy
protocol/src/persistence/COMPATIBILITY.md, protocol/src/persistence/chat-sync/captured-levels.ts
Head planning metadata is documented as re-creatable and excluded from durable residual capture.
Removed cloud-chat clone path
clients/shared/cloud-chat/clone.ts, clients/shared/cloud-chat/__tests__/cloud-chat-clone.test.ts
The clone seed implementation, clone result types, and related test coverage were deleted.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to facf7

This change adjusts chat-sync compatibility metadata and removes unused clone code; no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

Suggested labels: protocol-compat-override

Poem

I’m a rabbit with a nullable floor,
No fixed version blocks the door.
Heads can travel, plans can sprout,
Old readers safely hop about.
Clone paths rest beneath the moon.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the null reader floor, publisher-derived preservation rule, and removal of unused clone code.
Description check ✅ Passed The description directly explains the protocol changes, compatibility rules, removed clone code, and verification results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch traycer/chat-preservation-train

Comment @coderabbitai help to get the list of available commands.

…o the 1.1 floor

The writer shape narrowed minReaderVersion to z.literal(1)/z.literal(1), which
made two things true that should not have been:

- a null floor was unpublishable, so the host had to stamp a floor it had no
  justification for. Per COMPATIBILITY.md the minimum is for a change an older
  reader cannot safely INTERPRET, and the 1.1 reshape is additive and read-safe
  - its cut-plan fields ride the residual bags for a reader that does not model
  them. Stamping the floor is what produced the dev-host refusal "requires a
  reader on 1.1; this reader is 1.0" for a chat every 1.0 reader could open;
- the pin was a latent publish-breaker. It matched this contract's own version,
  so bumping CHAT_SYNC_SCHEMA_VERSION to 1.2 would have made a publisher's own
  minReaderVersion stamp fail its own .parse() - breaking every publication on
  the build that shipped the bump.

minReaderVersion now inherits the shared shape's nullable default.
CHAT_SYNC_1_1_READER_FLOOR stays as the documented mechanism for a future
DELIBERATE raise (and as refineClaimedCutPlanCompleteness' 1.1 threshold); its
doc records that no writer stamps it today, and why.

Also codifies the publisher-derived-levels invariant that makes residual
capture's coverage a deliberate boundary rather than an accident: the head's
part entries, cdc and hostPrivateShard are re-derived from the owner's op log on
every publish, so durable chat data must never be added there. Loss across a
host downgrade costs at most one full recut, never data. Recorded in
COMPATIBILITY.md 6, in the bump ritual table, and beside the captured-level
manifest where the next person adding a level will read it.

Fixtures now state what a correct publisher stamps (no floor), which is also
what keeps the store's byte-for-byte republication comparison honest.

Signed-off-by: Tanveer Gill <tanveer@traycer.ai>
…tually true

Two overstatements from the previous commit, both found by cold review, both
the kind a future reader would quote back:

- "the cut-plan fields ride the residual bags" is false for the PER-PART
  fields. `chatHeadPartSchema` is a plain object with no capture site - by the
  same publisher-derived-levels rule this branch codifies - so an older
  republisher strips them. Only head-level `cdc` rides the head's bag. The
  null-floor conclusion is unchanged and now rests on what actually holds: a
  1.0 reader takes each part entry as the address it is and re-derives its own
  cut plan from its op log, so it renders and re-publishes correctly without
  modelling any of it.
- "re-derived from the owner's op log on every publish" is not how two of the
  three levels behave. The extend road re-emits unchanged cohort entries
  verbatim and reads `cdc` back to confirm the plan has not moved. They are
  re-DERIVABLE, and derived afresh on every full recut; the sentence that
  carries the rule is the next one - the only round-trip any of them makes is
  through the owner's own predecessor head.

Signed-off-by: Tanveer Gill <tanveer@traycer.ai>
`buildChatCloneSeed` / `chatCloneResidualsOf` derived a lossless clone seed
client-side and had exactly one consumer: their own test. The clone that
ships goes through the HOST fork path (`epic.createChat`'s `forkSource`),
which now carries preserved raw bodies itself rather than reparsing them
through the live message schema.

Left in place, the module reads as the lossless clone path while being
neither reached nor maintained - the misleading half of dead code. The idea
it existed to state (messages and events cross as the preserved pairs
assembly produced, never rebuilt from their interpreted view) now lives
where the copy actually happens.

Signed-off-by: Tanveer Gill <anay@traycer.ai>
Signed-off-by: Tanveer Gill <tanveer@traycer.ai>
`captured-levels.ts` pointed at `chatCloneResidualsOf` as "the client surface
[that] states the gap explicitly" for the un-carryable `shard` bag. That
function went with the dead cloud-chat clone seed builder, so the contract doc
for the level manifest was naming a symbol that no longer exists.

Rewritten to say the thing the symbol was standing in for: a shard bag never
reaches a re-publishing reader at all, so "we chose not to carry it" and "it
never reached us" are indistinguishable on the other side - which is why the
rule has to be stated here rather than enforced downstream.

The cross-boundary completeness guard is described by ROLE rather than by
symbol. A consumer holding an exhaustive `Record<CapturedResidualLevelId, …>`
still makes a new level a compile error across the package boundary (the
Traycer host's chat-sync record adapter is that consumer today), but this file
lives in a different repository from it and must not depend on its names.

Signed-off-by: Tanveer Gill <anay@traycer.ai>
Signed-off-by: Tanveer Gill <tanveer@traycer.ai>
@tanveergill
tanveergill force-pushed the traycer/chat-preservation-train branch from facf7be to e9657ed Compare August 17, 2026 11:09
@hdkshingala

Copy link
Copy Markdown
Member

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

@hdkshingala
hdkshingala merged commit 75fe3d1 into main Aug 17, 2026
20 checks passed
@hdkshingala
hdkshingala deleted the traycer/chat-preservation-train branch August 17, 2026 11:34
AmiteshwarRandhawa added a commit that referenced this pull request Aug 24, 2026
Two semantic resolutions:

- chat-sync `minReaderVersion`: #1252's null reader floor wins over our 1.1
  pin. Our 1.2 bump adds `chat.imported` through the unknown-variant
  passthrough, which is exactly the additive class that must NOT raise the
  floor, so both fixtures now stamp what a correct publisher on this line
  stamps - `null` in `publishChat`, a deliberate floor only where the test is
  about a deliberate floor.

- `chatSubscribeCommonServerFrameSchemasPreManagedCommand` takes BOTH sides:
  our `event: chatEventSchemaPreImported` freeze and main's
  `action: chatActionSchemaV15`. The freeze pin is unchanged - `chat.subscribe`
  still tops out at the unreleased @1.6, and the newest released baseline is
  still @1.5.

Signed-off-by: Amiteshwar Randhawa <amiteshwar04@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants