feat(session): project the inherited-history boundary into the log
A plugin owning a standalone open/close bracket cannot tell a dead marker from a live one: an unmatched `compact/start` reads identically whether the previous writer died mid-compaction or a compaction is running now. `Session.firstLiveSeq` already holds that answer exactly, but only in memory. Append the log-only `session/inherited` event at that seq from the seeded constructor — the single waist all six seeded-start paths pass through (resume, configured startup on a persisted id, `sessions.fork()`, a subagent fork child, `adopt()`'s live prefix, and a bare seeded `create`). Read it through the new `isInheritedSeq(events, seq)`. The constructor placement means persistence needs no changes: the marker is already in `events` when a backend captures the creation seed, so it rides the ordinary seed path with no load-time write. It also covers fork, where the inherited bracket's owner may still be running — the case a persistence-layer boundary could not reach. Activity ordering excludes the boundary through `lastActivityTime()`, since lazy resume makes browsing a pickup and the three call sites would otherwise float every opened session to the top of a picker or list.
This commit is contained in:
@@ -78,7 +78,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
}[T]
|
||||
```
|
||||
|
||||
Sources: [`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:263`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:292`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:324`](../packages/core/session/src/types.ts)
|
||||
Sources: [`packages/core/session/src/types.ts:276`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:283`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:312`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:344`](../packages/core/session/src/types.ts)
|
||||
|
||||
## Events
|
||||
|
||||
@@ -404,6 +404,33 @@ Source: [`packages/sandbox/sandbox-policy/src/session-mode.ts:33`](../packages/s
|
||||
|
||||
### `session/*`
|
||||
|
||||
#### `session/inherited` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* The log-only durable projection of {@link Session.firstLiveSeq}: everything
|
||||
* BELOW it was inherited through a constructor seed — resume, fork, or replay
|
||||
* — and no writer in this session's lifecycle produced it. Appended as the
|
||||
* first live event of every seeded session.
|
||||
*
|
||||
* A plugin owning a standalone open/close bracket (`compact/start` …
|
||||
* `compact/end`) needs it because inherited history and live work are
|
||||
* otherwise byte-identical: an unmatched opening marker below this boundary
|
||||
* belongs to an ended lifecycle, so it is dead whether the writer crashed,
|
||||
* the process succeeded it, or the events were forked out of a parent that is
|
||||
* still running. Read it through `isInheritedSeq`.
|
||||
*
|
||||
* NOT a liveness signal about other writers: a concurrently live session may
|
||||
* hold an open bracket over the same stored history with its own boundary
|
||||
* elsewhere, so tolerating concurrent writers needs a signal beyond the log.
|
||||
*
|
||||
* The payload is empty by design — position and `time` carry the meaning.
|
||||
*/
|
||||
'session/inherited': Record<string, never>
|
||||
```
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:272`](../packages/core/session/src/types.ts)
|
||||
|
||||
#### `session/title` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
|
||||
Reference in New Issue
Block a user