refactor: add canonical transcript assembly seam
This commit is contained in:
@@ -33,7 +33,9 @@ binding-agnostic and does not need a per-binding implementation.
|
||||
`IndexUnit` when correctness requires whole-unit semantics — for example,
|
||||
Codex duplicate reconciliation or Kimi `context.undo` / `context.clear`
|
||||
replay. Each adapter maps its own resume/change semantics onto the existing
|
||||
`mtime` and `lines_processed` cursor pair in `index_state`.
|
||||
`mtime` and `lines_processed` cursor pair in `index_state`. The emitted
|
||||
`TranscriptRecord` stream is also the input to provider-independent session
|
||||
detail assembly; see ADR-0007.
|
||||
- **Persist axis — one shared orchestration.** A single provider-agnostic,
|
||||
binding-agnostic layer consumes records from any adapter and writes them:
|
||||
incremental `index_state` bookkeeping, FTS maintenance, and the canonical
|
||||
@@ -56,9 +58,9 @@ main process migrates to ESM (ADR-0003) to import the shared core. The real work
|
||||
is disentangling the currently interleaved parse-and-write inside `indexJsonl` /
|
||||
`indexCodexJsonl` into (pure adapter parse) + (shared persist).
|
||||
|
||||
The SQLite schema and normalized `IndexRecord` union are the stable center of
|
||||
the design. Provider-only concepts are either projected lossily into that
|
||||
language or ignored; they do not add provider columns or tables. The registry,
|
||||
The normalized `TranscriptRecord` union is the stable center of the design, and
|
||||
SQLite is one serialization adapter for it. Provider-only concepts are either
|
||||
projected lossily into that language or ignored. The registry,
|
||||
not provider switches, drives both indexers, watcher roots, persisted source
|
||||
roots, source catalog/UI labels and colors, and raw-record routing. Adding Pi
|
||||
therefore changes the Pi adapter, its registration, and its conformance tests;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Canonical transcript records are the session-detail seam
|
||||
|
||||
**Context.** Provider adapters originally emitted database-shaped records, while
|
||||
the desktop app reconstructed presentation semantics after querying SQLite.
|
||||
Although that reconstruction had no explicit provider switch, it still inferred
|
||||
metadata from raw message text. As more providers are added, those heuristics
|
||||
would make provider semantics leak into a shared presentation module and allow
|
||||
the direct parse path to drift from the persisted path.
|
||||
|
||||
**Decision.** Every provider adapter emits a canonical `TranscriptRecord`
|
||||
stream. The adapter owns all source-specific interpretation: duplicate raw
|
||||
events, stable identities, tool relationships, message classification, and
|
||||
visibility. `visibility` is separate from `is_meta`: hidden transport context is
|
||||
omitted from session detail, while visible system evidence can remain a metadata
|
||||
card. Presentation-sensitive concepts are explicit canonical fields: tool calls
|
||||
carry a presentation class, Skill instructions carry a content type, and
|
||||
workflows carry their parent tool-call identity.
|
||||
|
||||
The Core `assembleSessionDetail(input)` module is the only session-detail seam.
|
||||
It accepts either a provider's complete transcript stream from a fresh parse
|
||||
(`cursor = null`) or table-shaped rows after a persistence round-trip. A delta
|
||||
parse cannot produce a complete detail snapshot without prior state, so the
|
||||
assembler rejects a `SessionRecord` whose `countMode` is `delta`; incremental UI
|
||||
updates use the existing snapshot/patch seam. Its internal row adapter restores
|
||||
the canonical record language before assembly. The implementation may sort,
|
||||
group thinking, and attach tool results, subagents, and workflows, but it never
|
||||
checks the provider and never parses message text to recover provider semantics.
|
||||
Tool names are likewise display data, not assembly control flow.
|
||||
|
||||
The persist layer only serializes transcript records and cursor state. SQLite is
|
||||
not the source of transcript semantics, and a persistence round-trip must not
|
||||
change the assembled result.
|
||||
|
||||
**Consequences.** A new provider is complete only when its canonical transcript
|
||||
can pass directly through `assembleSessionDetail`. Provider conformance tests
|
||||
cover that seam, while persistence tests verify that canonical classification
|
||||
survives a database round-trip. Codex-owned normalization now classifies hidden
|
||||
context envelopes and structurally removes image wrappers before duplicate
|
||||
reconciliation. Adding another provider does not add branches to the app's
|
||||
session-detail code.
|
||||
Reference in New Issue
Block a user