docs: address prose review findings

This commit is contained in:
Turtle
2026-08-09 16:31:15 +08:00
parent 2f3821c232
commit 93e858faf9
31 changed files with 74 additions and 65 deletions

View File

@@ -221,7 +221,8 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
* (e.g. the `assistant/chunk` seqs that built an `assistant/message`,
* or the surface nodes shadowed by a compaction replace node). An
* `assistant/message` may carry a present empty array for a known empty
* provider stream; omission means the source stream was not recorded.
* provider stream; when the field is absent, the event does not record which
* earlier events produced the message.
*/
sourceEventSeqs?: number[]
/** How this event entered the surface; absent for non-surface events. */
@@ -232,7 +233,7 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
`SessionEventType = keyof SessionEventMap`. Because `SessionEventMap` is merge-extensible, switches over `SessionEvent` must NOT use `assertNever` — a plugin-added variant is a valid unknown value; handle the known cases and fall through `default`.
For `assistant/message`, a present `sourceEventSeqs: []` is a complete known-empty provider stream, while an absent field means the source stream was not recorded in a legacy or foreign event. The loop writes the field for every successful model call; every other surface event requires a non-empty list when the field is present.
For `assistant/message`, a present `sourceEventSeqs: []` is a complete known-empty provider stream, while a legacy or foreign event with no field does not record which earlier events produced the message. The loop writes the field for every successful model call; every other surface event requires a non-empty list when the field is present.
## Surface types
@@ -285,9 +286,9 @@ interface SurfaceIntent {
surfaceOp: SurfaceOp
/**
* Complete set of known source-event seqs. `assistant/message` may use a
* present empty array for a known empty provider stream; omission means its
* source stream was not recorded. Other surface events require a non-empty set
* when this field is present.
* present empty array for a known empty provider stream; when the field is
* absent, the event does not record which earlier events produced the message.
* Other surface events require a non-empty set when this field is present.
*/
sourceEventSeqs?: number[]
}
@@ -295,7 +296,7 @@ interface SurfaceIntent {
Required for `SurfaceEventType` events — every message-producing event must declare how it joins the surface, the sole source of derived model history. A human-facing transcript is the other projection and reads the log's append-origin events instead, because the surface deliberately shadows the ranges a replacement summarizes (`isAppendSurfaceEvent` in [dsh-session](../../packages/core/session/README.md)). Non-surface types reject it at compile time.
Only `assistant/message` may carry a present empty `sourceEventSeqs`; omission means the source stream was not recorded and does not assert that the stream was empty.
Only `assistant/message` may carry a present empty `sourceEventSeqs`; when the field is absent, the event does not record which earlier events produced the message, and the provider may still have emitted chunks.
### `SessionSurface` — the live readonly surface projection
@@ -577,7 +578,7 @@ Activity ordering excludes the boundary through `lastActivityTime(events)`: pick
## Plugin-contributed log-only events
A plugin may declaration-merge extra `SessionEventMap` types. These are **log-only**: NOT `SurfaceEventType`s (they carry no `surfaceOp` and contribute nothing to derived history). Their owner decides whether they belong to an open execution turn or may stand between turns, and enforces any relation in its own invariant companion. The generated [persistence log event catalog](../persistence-catalog.md) enumerates every core and plugin-contributed event with its payload, surface badge, cited source-event seqs, and declaration site; the compaction seam's `compact/*` semantics are discussed on [compaction.md](compaction.md).
A plugin may declaration-merge extra `SessionEventMap` types. These are **log-only**: NOT `SurfaceEventType`s (they carry no `surfaceOp` and contribute nothing to derived history). Their owner decides whether they belong to an open execution turn or may stand between turns, and enforces any relation in its own invariant companion. The generated [persistence log event catalog](../persistence-catalog.md) enumerates every core and plugin-contributed event with its payload, surface badge, and declaration site; the compaction seam's `compact/*` semantics are discussed on [compaction.md](compaction.md).
The hook bridges' `hook/invoked` / `hook/result` pairs (from `@deepseek-ai/dsh-hook-protocol`) correlate by `handlerId`. `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, and `Stop` fire inside the loop's open turn, so their `hook/*` records are turn-enclosed by construction. `SessionStart` gets no `hook/*` record because it runs before turn 1; its context remains pending in the inbox until a waking delivery opens a turn (see [the hook-bridges Agent Note](../../.agents/notes/implemented/feature/2026-06-30-hook-bridges.md)).