chore(docs): add session store research corpus and cross-product synthesis - #499
Conversation
yordis
commented
Jul 23, 2026
- Grounds the upcoming event-sourced Session Store design in industry prior art, so persistence, resume, rewind, fork, and retention decisions are evidence-based rather than invented.
- Follows the same method as the agent-platform corpus so both research bodies stay comparable and auditable as frozen decision-time input.
…hesis Grounds the event-sourced Session Store design in industry prior art so persistence and resume decisions are evidence-based. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
PR SummaryLow Risk Overview
The dossiers are large, source-anchored writeups (docs/API and/or pinned repo commits) that reconstruct each product’s durable session contract and end with “what this implies for our Session Store” plus open questions—no runtime or application code changes. Reviewed by Cursor Bugbot for commit f190bac. Bugbot is set up for automated code reviews on this repo. Configure here. |
WalkthroughAdds a reproducible Session Store research corpus with a shared prompt, nine product dossiers, an index, and a synthesis describing common patterns, differences, and proposed event-sourced design requirements. ChangesSession Store Research Corpus
Estimated code review effort: 3 (Moderate) | ~30 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new “Session Store Research” documentation corpus intended to ground an upcoming event-sourced Session Store design in audited, cross-product prior art, with a synthesis that extracts convergence/divergence axes and design implications (with ADRs remaining authoritative where they conflict).
Changes:
- Adds a reusable research prompt and a new index for the session-store study corpus.
- Adds a cross-product synthesis capturing common patterns (append-only logs + projections) and key divergence axes (identity, compaction artifacts, retention, multi-host).
- Adds multiple product dossiers (e.g., T3 Code, LangGraph, Hermes, Grok Build, Goose, etc.) documenting each product’s on-disk/session model.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| docs/research/session-store/index.md | Introduces the corpus landing page and links to dossiers + synthesis. |
| docs/research/session-store/RESEARCH_PROMPT.md | Defines the repeatable methodology and per-product output skeleton. |
| docs/research/session-store/synthesis.md | Cross-product analysis and working definition for “stored session” in the corpus. |
| docs/research/session-store/products/t3code.md | T3 Code dossier describing its event-log + projection architecture (CQRS/event-sourced). |
| docs/research/session-store/products/langgraph.md | LangGraph dossier describing checkpoint-chain persistence and saver interface. |
| docs/research/session-store/products/hermes-agent.md | Hermes dossier describing mutable SQLite session/message model + operational behaviors. |
| docs/research/session-store/products/grok-build.md | Grok Build dossier describing filesystem event-log + derived caches/indexes. |
| docs/research/session-store/products/goose.md | Goose dossier describing mutable SQLite store + compaction/rewind/fork behaviors. |
| docs/research/session-store/products/gemini-cli.md | Gemini CLI dossier describing JSONL replay-reducer storage model + markers. |
| docs/research/session-store/products/codex-cli.md | Codex CLI dossier describing authoritative JSONL log + derived SQLite projection. |
| docs/research/session-store/products/claude-agent-sdk.md | Claude Agent SDK/Claude Code dossier describing local JSONL source-of-truth + mirror store contract. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| The event row is the source of truth | ||
| (`apps/server/src/persistence/Migrations/001_OrchestrationEvents.ts:8-23`): | ||
|
|
||
| ```sql |
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/research/session-store/products/claude-agent-sdk.md`:
- Around line 480-485: Revise the session-store description around the “Both
surfaces converge” passage so only projections derivable from the mirrored
transcript are described as rebuilt from the append-only log. Remove
file-content checkpoints and liveness registry from that projection list, and
document them separately as non-mirrored file state and per-process/per-host
liveness artifacts.
- Around line 504-505: Update the delivery semantics statement in the
session-store documentation to describe delivery as best-effort rather than
at-least-once, explicitly noting possible loss and duplicates, and recommend
UUID-based deduplication at the adapter boundary instead of claiming idempotent
append guarantees.
In `@docs/research/session-store/products/goose.md`:
- Around line 482-488: Remove the claim that transactional compaction and fork
rewrites can leave a torn transcript. Update the discussion around
replace_conversation and the downstream synthesis to describe supported risks
instead, such as rollback cost, contention, or incomplete fork creation when
work spans transactions, while preserving the valid O(history) copy and
rewind-history observations.
- Around line 277-287: Update the scalability sentence in the Enumeration
description to acknowledge that grouping the joined message history can scan and
aggregate all matching messages before keyset pagination, rather than implying
cost is limited to returned-page rows. Preserve the existing query and
pagination details, and replace only the “scales with rows matched, not total
history” claim with qualified wording about matched message-history cost.
In `@docs/research/session-store/products/hermes-agent.md`:
- Around line 177-179: Update the consistency-guarantees statement to
distinguish the Python threading.Lock as protection for access within a single
process, and identify SQLite transactions and retries as providing serialization
across processes sharing state.db. Preserve the existing single-writer,
ordering, and no-precondition guarantees.
- Around line 303-309: Update the “Store interpretation” description to call the
autoincrement id a row-identity field rather than a deduplication field.
Preserve the separate reference to the in-memory _DB_PERSISTED_MARKER for
live-agent deduplication and the later statement that Hermes lacks a durable
deduplication key.
In `@docs/research/session-store/products/langgraph.md`:
- Around line 312-319: Correct the fork description in the LangGraph
session-store documentation to remove the claim that source and target threads
share immutable, content-addressed ancestor blobs; describe copying as
preserving the complete parent chain under the new thread ID, with deduplication
limited to a single thread. Apply the same wording correction to the
corresponding fork discussion in the synthesis document.
- Around line 175-182: Update the `put` description in the LangGraph
session-store documentation to qualify “immutable snapshot”: state that fresh
checkpoint IDs make normal writes append-like, while reusing an existing
checkpoint ID allows the upsert to replace or update its contents. Preserve the
existing SQLite/Postgres upsert references and parent-checkpoint details.
In `@docs/research/session-store/products/opencode.md`:
- Around line 499-518: Qualify the multi-host safety statement in the session
synchronization discussion: distinguish the instance HTTP replay path, which
uses strictOwner: true, from the workspace sync loop’s live/reconnect replay
calls, which provide only ownerID. Do not claim that all live synchronization
paths reject owner mismatches unless verified elsewhere; narrow the conclusion
to the ownership guarantees directly supported by the cited code.
In `@docs/research/session-store/RESEARCH_PROMPT.md`:
- Around line 163-174: Make the evidence-record contract mandatory by adding a
required “## Evidence excerpts” section to the dossier output skeleton,
including fields for quote, direct URL or repository path and line, symbol or
section, version or commit, retrieval date, archive or snapshot URL, and content
digest. Update the “Method” instructions to explicitly require every captured
quote to be recorded in that section, preserving the existing auditability
requirements.
In `@docs/research/session-store/synthesis.md`:
- Around line 385-394: Clarify the fork invariant in the section beginning “Fork
always mints a new stream/session id”: distinguish copied event identity fields,
which must be rewritten to the new stream/session id, from an optional immutable
shared-prefix lineage reference, which may explicitly retain the source stream
id. Present physical-copy and shared-prefix implementations as alternatives
without implying that lineage references violate the copied-event identity rule.
- Around line 61-75: Revise the universal convergence claims in
docs/research/session-store/synthesis.md:61-75 to include LangGraph as a
non-marker model that selects an older checkpoint; update
docs/research/session-store/synthesis.md:103-117 to note Gemini’s nested child
files and path-based parent linkage alongside Claude; and change “every product”
to “most products” in docs/research/session-store/synthesis.md:119-129,
explicitly identifying Claude and Gemini as cascading-deletion exceptions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 8f604db9-2aad-4e4c-87fe-658f50249385
📒 Files selected for processing (12)
docs/research/session-store/RESEARCH_PROMPT.mddocs/research/session-store/index.mddocs/research/session-store/products/claude-agent-sdk.mddocs/research/session-store/products/codex-cli.mddocs/research/session-store/products/gemini-cli.mddocs/research/session-store/products/goose.mddocs/research/session-store/products/grok-build.mddocs/research/session-store/products/hermes-agent.mddocs/research/session-store/products/langgraph.mddocs/research/session-store/products/opencode.mddocs/research/session-store/products/t3code.mddocs/research/session-store/synthesis.md
| Both surfaces converge on the same shape: **a stored session is an append-only, | ||
| per-key log of opaque JSON entries plus derived projections (a summary/read | ||
| model, a message-chain view, a file-content checkpoint store, and a liveness | ||
| registry) rebuilt from that log.** That is within one small step of an | ||
| event-sourced Session Store, and the SDK interface is already stream-shaped: | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Do not describe file checkpoints and liveness state as log-rebuildable projections.
The dossier states that checkpoint blobs are not mirrored (Lines 386-387) and that the liveness registry is per-process/per-host (Lines 438-439). Narrow this inference to projections actually derivable from the mirrored transcript; model file state and liveness should be documented as separate artifacts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/claude-agent-sdk.md` around lines 480 -
485, Revise the session-store description around the “Both surfaces converge”
passage so only projections derivable from the mirrored transcript are described
as rebuilt from the append-only log. Remove file-content checkpoints and
liveness registry from that projection list, and document them separately as
non-mirrored file state and per-process/per-host liveness artifacts.
| - Delivery is at-least-once with client-generated `uuid`, so our backing needs | ||
| idempotent append rather than exactly-once transport. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Change “at-least-once” to best-effort delivery.
The documented behavior allows loss: timed-out appends are not retried, and batches are dropped after retry exhaustion (Lines 249-254). Retries also permit duplicates. Describe this as best-effort delivery with duplicate risk, with UUID deduplication recommended at the adapter boundary.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/claude-agent-sdk.md` around lines 504 -
505, Update the delivery semantics statement in the session-store documentation
to describe delivery as best-effort rather than at-least-once, explicitly noting
possible loss and duplicates, and recommend UUID-based deduplication at the
adapter boundary instead of claiming idempotent append guarantees.
| - **Enumeration** is a single grouped SQL query over `sessions LEFT JOIN | ||
| messages`, grouping by `s.id`, computing `message_count` and | ||
| `last_message_timestamp`, and ordering by a `sort_timestamp = COALESCE(MAX(msg | ||
| ts), updated_at)` then `id` (`list_sessions_matching`, | ||
| `session_manager.rs:1849-1950`). Pagination is **keyset**: the cursor is | ||
| `(sort_at, session_id)` and the query fetches `page_size + 1` rows to derive | ||
| `next_cursor` (`list_sessions_paged`, `1963-2005`; cursor type `318-322`). | ||
| Supporting indexes: `idx_sessions_updated`, `idx_sessions_type`, | ||
| `idx_sessions_parent`, `idx_messages_session` (`1001-1020`). No scale numbers | ||
| are quoted in-source; cost is a per-page grouped join, so it scales with rows | ||
| matched, not total history. |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win
Qualify the listing-query scalability claim.
Because the query groups the joined sessions and messages rows before applying keyset pagination, it may scan and aggregate all matching history, not only the returned page. Replace “scales with rows matched, not total history” with wording that acknowledges the matched message-history cost.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/goose.md` around lines 277 - 287, Update
the scalability sentence in the Enumeration description to acknowledge that
grouping the joined message history can scan and aggregate all matching messages
before keyset pagination, rather than implying cost is limited to returned-page
rows. Preserve the existing query and pagination details, and replace only the
“scales with rows matched, not total history” claim with qualified wording about
matched message-history cost.
| - **Where it validates our direction**: the pain points our design avoids are | ||
| visible here. Compaction and fork both go through a `DELETE`-all + | ||
| re-`INSERT` (`replace_conversation`, `session_manager.rs:1800-1838`), so a | ||
| crash mid-rewrite risks a torn transcript, fork is O(history) copy, and rewind | ||
| destroys the pre-cutoff turns (`truncate_*`, `2344-2385`). An append-only log | ||
| with derived projections gets crash-safe rewind, cheap shared-prefix forks, and | ||
| intact history for free. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Remove the incorrect “torn transcript” crash claim.
The dossier states that compaction/fork rewrites risk a torn transcript, but it also documents that these multi-statement operations run inside SQLite transactions. A crash during the transaction should generally leave the pre-write or committed state, not a partially rewritten transcript. Describe the actual risks—rollback cost, contention, or incomplete fork creation if operations span transactions—and update the downstream synthesis accordingly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/goose.md` around lines 482 - 488, Remove
the claim that transactional compaction and fork rewrites can leave a torn
transcript. Update the discussion around replace_conversation and the downstream
synthesis to describe supported risks instead, such as rollback cost,
contention, or incomplete fork creation when work spans transactions, while
preserving the valid O(history) copy and rewind-history observations.
| Consistency guarantees for all of the above: single writer connection guarded by a | ||
| Python `threading.Lock` plus SQLite `BEGIN IMMEDIATE` (`hermes_state.py:2018-2019`); | ||
| ordering by autoincrement `id`; no expected-version precondition on any operation. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Distinguish process-local locking from cross-process coordination.
threading.Lock only protects threads within one process. Since the dossier later describes multiple processes sharing state.db, state that the Python lock covers intra-process access while SQLite transactions/retries provide inter-process serialization.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/hermes-agent.md` around lines 177 - 179,
Update the consistency-guarantees statement to distinguish the Python
threading.Lock as protection for access within a single process, and identify
SQLite transactions and retries as providing serialization across processes
sharing state.db. Preserve the existing single-writer, ordering, and
no-precondition guarantees.
| - **Fork is a first-class metadata concept.** `CheckpointMetadata.source` includes | ||
| `"fork"` — "The checkpoint was created as a copy of another checkpoint" | ||
| (`:41-48`), and `parents` maps namespace → parent checkpoint id (`:56-60`). A | ||
| fork produces a new checkpoint whose `parent_checkpoint_id`/`parents` point at | ||
| the branch point, sharing the (immutable, content-addressed) ancestor blobs. | ||
| `copy_thread(source, target)` copies an entire thread's checkpoints + writes to | ||
| a new thread id, and its docstring **requires copying the complete parent | ||
| chain** so `DeltaChannel` state remains reconstructable (`:350-372`). |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Do not claim that forks share blobs across thread IDs.
The documented Postgres blob key includes thread_id (lines 60-68), while copy_thread creates a new thread ID. That supports deduplication within a thread, not shared blob rows across source and target threads. Please correct this wording here and in docs/research/session-store/synthesis.md:323-335.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/langgraph.md` around lines 312 - 319,
Correct the fork description in the LangGraph session-store documentation to
remove the claim that source and target threads share immutable,
content-addressed ancestor blobs; describe copying as preserving the complete
parent chain under the new thread ID, with deduplication limited to a single
thread. Apply the same wording correction to the corresponding fork discussion
in the synthesis document.
| - **Multi-host is a first-class path** here, unlike most of the corpus. Sessions | ||
| synchronize across hosts by **replaying events**, gated by owner: | ||
| - Each workspace runs a `syncWorkspaceLoop` that opens an SSE stream to a global | ||
| endpoint and, on each `{type:"sync", syncEvent}` message, calls | ||
| `events.replay(syncEvent, { publish: true, ownerID: space.id })` | ||
| (`packages/opencode/src/control-plane/workspace.ts:395-409`); on connect it | ||
| back-fills via a `syncHistory` fetch that `replay`s each missing event | ||
| (`workspace.ts:345-363`). | ||
| - The instance sync HTTP API exposes `replay` (accept a batch, `replayAll(..., | ||
| { ownerID, strictOwner: true })`), `steal` (reassign a session's owning | ||
| workspace via `session.setWorkspace`), and `history` (return `event` rows the | ||
| caller is missing, computed from a per-aggregate high-water map) | ||
| (`packages/opencode/src/server/routes/instance/httpapi/handlers/sync.ts:34-85`). | ||
| - Ownership transfer uses `events.claim(sessionID, workspaceID)` | ||
| (`workspace.ts:589`). The `strictOwner` replay guard prevents two hosts from | ||
| diverging a shared aggregate (`packages/core/src/event.ts:254-261`). | ||
| The append transaction is `behavior: "immediate"` per DB, and cross-host safety | ||
| rests on **owner claims + idempotent, expected-seq replay**, not on a shared | ||
| filesystem. This is a real distributed event-sync design layered on the same | ||
| append-only log. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Qualify the multi-host safety claim for live synchronization.
The workspace sync loop calls replay with ownerID only (lines 501-506); strictOwner: true appears only on the instance HTTP replay path (lines 507-510). Therefore the cited evidence does not show that every reconnect/live-sync path rejects owner mismatches. Either verify that strict ownership is enforced elsewhere or narrow the claim in lines 515-517.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/products/opencode.md` around lines 499 - 518,
Qualify the multi-host safety statement in the session synchronization
discussion: distinguish the instance HTTP replay path, which uses strictOwner:
true, from the workspace sync loop’s live/reconnect replay calls, which provide
only ownerID. Do not claim that all live synchronization paths reject owner
mismatches unless verified elsewhere; narrow the conclusion to the ownership
guarantees directly supported by the cited code.
| ## Method | ||
|
|
||
| 1. Primary sources first: official docs, API reference, SDK source, config | ||
| schemas, on-disk layouts, official repos. Secondary sources only to | ||
| triangulate. When the source is a repository, pin the exact commit and cite | ||
| `path:line` for each claim. | ||
| 2. Capture each exact quote as a checked-in source excerpt. Record its direct | ||
| URL or repo `path:line`, document section or repository symbol, source | ||
| version or commit when available, and retrieval date. Also record an | ||
| archive or snapshot URL when one exists and a content digest when the source | ||
| publishes or permits one. These evidence records must remain auditable if | ||
| the live URL changes. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Make the evidence-record format mandatory in each dossier.
The method requires every quote to be stored as an auditable source excerpt with URL/path, symbol or section, version/commit, retrieval date, archive URL, and digest. However, the output skeleton has no required section or schema for those records, so a dossier can satisfy the documented headings while omitting the corpus’s core reproducibility evidence.
Add a required ## Evidence excerpts section to the skeleton and point the method at it.
Proposed contract update
-2. Capture each exact quote as a checked-in source excerpt. Record its direct
+2. Capture each exact quote in the dossier's required Evidence excerpts
+ section. Record its direct
URL or repo `path:line`, document section or repository symbol, source
version or commit when available, and retrieval date. Also record an
archive or snapshot URL when one exists and a content digest when the source
publishes or permits one.
...
## Output skeleton (per product file)
...
- {additional anchors}
+## Evidence excerpts
+<!-- Each excerpt must include the quote, source URL or repo path:line,
+ section/symbol, version or commit, retrieval date, and optional
+ archive URL and content digest. -->
+
## The storage modelAlso applies to: 187-214
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/RESEARCH_PROMPT.md` around lines 163 - 174, Make
the evidence-record contract mandatory by adding a required “## Evidence
excerpts” section to the dossier output skeleton, including fields for quote,
direct URL or repository path and line, symbol or section, version or commit,
retrieval date, archive or snapshot URL, and content digest. Update the “Method”
instructions to explicitly require every captured quote to be recorded in that
section, preserving the existing auditability requirements.
| **3. Rewind is implemented as an appended marker interpreted at replay, not | ||
| a destructive edit, everywhere except the pure-SQL stores.** Claude Agent | ||
| SDK's `/rewind` menu is "a non-destructive view operation over an | ||
| append-only log." Codex CLI's `ThreadRolledBack` event means "skip the next | ||
| N user-turn segments we finalize"; nothing is deleted. Gemini CLI's | ||
| `$rewindTo` line means the reducer "deletes it plus everything after" only | ||
| from the in-memory fold, not the file. Grok Build: "Every prompt is a | ||
| checkpoint, the list always contains [0, 1, ..., N-1]..."; separately, the | ||
| dossier notes nothing is deleted and replay applies dead-branch filtering. | ||
| T3 Code: "exactly | ||
| the append-marker-replayed pattern (as opposed to Hermes's in-place flag | ||
| mutation)." OpenCode's v2 `revert.commit` truncates only the *projection*; | ||
| "the underlying event rows are not deleted." The two exceptions prove the | ||
| axis: Goose's rewind is "a destructive delete" (`truncate_conversation`), | ||
| and Hermes's is an in-place flag flip (`active=0`). |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Narrow the universal convergence claims to match the documented exceptions.
docs/research/session-store/synthesis.md#L61-L75: include LangGraph as a non-marker rewind model; its documented behavior selects an older checkpoint.docs/research/session-store/synthesis.md#L103-L117: Gemini also uses nested child files and path-based parent linkage, so Claude is not the sole structural exception.docs/research/session-store/synthesis.md#L119-L129: Claude and Gemini document cascading deletion; change “every product” to “most products” and identify those exceptions.
📍 Affects 1 file
docs/research/session-store/synthesis.md#L61-L75(this comment)docs/research/session-store/synthesis.md#L103-L117docs/research/session-store/synthesis.md#L119-L129
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/synthesis.md` around lines 61 - 75, Revise the
universal convergence claims in docs/research/session-store/synthesis.md:61-75
to include LangGraph as a non-marker model that selects an older checkpoint;
update docs/research/session-store/synthesis.md:103-117 to note Gemini’s nested
child files and path-based parent linkage alongside Claude; and change “every
product” to “most products” in docs/research/session-store/synthesis.md:119-129,
explicitly identifying Claude and Gemini as cascading-deletion exceptions.
| 5. **Fork always mints a new stream/session id and rewrites identity | ||
| fields in the copied prefix; it must never let a copy reference the | ||
| source id.** Industry's answer: unanimous outside LangGraph (Claude | ||
| Agent SDK's explicit rationale for not using `CopyObject`; Codex CLI's | ||
| `history_base` prefix-pointer as the efficient variant of the same | ||
| rule). Decide whether fork is a physical copy (T3 Code, Goose, Hermes: | ||
| O(history) per fork) or a shared-prefix reference (Codex CLI's | ||
| `history_base`, LangGraph's shared content-addressed blobs); the | ||
| shared-prefix design is strictly cheaper and available to us because | ||
| events are immutable. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Separate fork identity rewriting from shared-prefix lineage references.
This requirement says a fork must never reference the source id, but immediately presents Codex’s history_base shared-prefix pointer as a valid alternative. Clarify the invariant: copied events must receive the new stream identity, while an immutable shared-prefix implementation may retain an explicit source-stream lineage reference.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/research/session-store/synthesis.md` around lines 385 - 394, Clarify the
fork invariant in the section beginning “Fork always mints a new stream/session
id”: distinguish copied event identity fields, which must be rewritten to the
new stream/session id, from an optional immutable shared-prefix lineage
reference, which may explicitly retain the source stream id. Present
physical-copy and shared-prefix implementations as alternatives without implying
that lineage references violate the copied-event identity rule.