fix(session): close the review gaps the boundary opened

- `SessionSummary.updatedAt`'s wire doc still said "Persisted file mtime",
  which stopped being true for attached sessions.
- The core invariant let `session/inherited` fall through the merge-extensible
  default. It is core-owned, so it gets an explicit case; an unbalanced seed
  legally places it inside an open turn, which the relation permits.
- The Agent Note claimed the boundary reaches disk via `live.pending`/
  `scheduleDrain`. Verified false: the constructor append precedes `enter()`,
  so it never publishes on `session/event` and rides the creation seed instead.
  Attaching is therefore a write where none happened before — recorded, since
  only `load()` stays a pure read.
- The deferred-index proposal asserted this change documented the cold-mtime
  skew on `dsh-host-apiproxy`. It did not; the README entry now exists.
- `firstLiveSeq`'s firehose gap runs through its own seq, not below it.
- The boundary is not always at `firstLiveSeq` (the idempotence guard), so
  consumers scan for the last one.
- `lastActivityTime` excludes by type, so a pickup time still leaks onto a
  synthetic closer when a boundary ends an open turn. Documented.
- Pin the fork claim end-to-end: a child inherits a still-running parent's
  open bracket below its own boundary, while the parent has none. Fails if the
  write moves back to the load path.
- Fix the telemetry title that contradicted its own assertions.

The `/status` call site cannot be pinned the way the other two are: the
command appends its own `command/run` before rendering, so the boundary is
never the log tail there. Its fixture now at least renders over a
boundary-bearing log.
This commit is contained in:
Hypatia May
2026-07-30 13:59:08 +08:00
parent a00786362f
commit 39ebd8f745
26 changed files with 115 additions and 23 deletions

View File

@@ -127,7 +127,11 @@ export interface SessionModels {
/** Session list entry (v1 builds no index: list does readdir+stat). */
export interface SessionSummary {
sessionId: SessionId
/** Persisted file mtime. */
/**
* Last activity. Attached: the last non-`session/inherited` event, since a
* pickup is not activity. Cold: the log's mtime, or `createdAt` for a backend
* with no per-session file (README Known Limitations covers the skew).
*/
updatedAt: number
/** Status of the attached agent; always false for cold (unattached) sessions. */
running: boolean