- Export `ProjectionKeySelection` (the read faces' key selection) and reuse it
from the projection cache instead of restating the union twice. The Cordis
catalog can now resolve the type its generated signatures reference.
- Make `wire.summary` a plain boolean: omitted means `true`, and a key whose
map entry carries the summary mark declares `false` so the runtime key set
and the client view type agree. The type no longer forbids a declaration.
- Describe the mark accurately: it has no runtime representation; `wire.view`
and `viewSchema` are typed with `SessionProjectionViewValue`, which strips it,
so the registration erase only widens the state type.
- Say plainly in the package README, the subsystem page, the client field
comments, and the Agent Note that a list row carries the summary projection
and never the full projection: a connected Session's store may hold more
values, but those are outside the list contract.
- Document the summary vocabulary on the subsystem page with `ts type-equiv`
blocks for the mark, its stripping, the excluded-key test, the summary value
type, and the key selection; split the prose paragraph.
- Revert the behavior-neutral cache-double refactors in three specs, and record
in the Agent Note why no upgrade guide accompanies the wire change and how a
consumer migrates.
A Session-list row no longer carries every registered client view: the three
units whose values a list row never renders (`turnOutline`, `sessionStats`,
and `todos`) are excluded, which removes the whole-log turn outline and the
figure and todo payloads from every row. An opened Session is unchanged —
`session/follow`, the `session/control` baseline, and `session.projections`
still serve every projected key.
The exclusion is one type-level mark plus one registration interlock:
`SessionProjectionSummaryExcluded<T>` marks a map entry, and
`ProjectionDefinition.wire` requires `summary: false` exactly on a marked key
and rejects it everywhere else, so the mark and the declaration cannot drift.
A nullable entry keeps `null` outside the wrapper, so `todos` stays
`TodoItem[] | null`. `summaryKeys()` returns the derived set, stable until a
registration or its disposal changes the key table, and the existing
key-taking read faces (`cachedSnapshot`, `viewCheckpoint`) accept that set
directly, so summaries need no separate read face and no per-read key copy.
`packages/api/session-controller/src/list.ts` passes the set to the live and
cold cached faces; `cachedPredecessorTitle` is untouched.
Client types only: `SessionSummary.projectionValues` narrows to
`SessionProjectionSummaryValues`, `SessionProjectionSnapshot.values` keeps
every view value with the mark stripped, and no wire field or client name
changed. The cache, subsystem page, and package README document the summary
rule and the two read faces.
The composer keeps a sent message, its references, and its attachments
read-only in a sending phase until session/prompt resolves, so an
admission listener can hold or refuse a prompt before it appears as sent.
The Session publishes the local echo and leaves the blank layout only
after acceptance; a refusal or failure keeps the draft, and
session/prompt-rejected with presented: true adds no toast.
This carries the client half of deepseek-harness/deepseek-harness#6178.
Folding on the next message reserved the whole closing height as bottom
room and kept scrollTop whenever the input had no transcript echo on this
page: a message from another tab, a queued message delivered after the
previous Turn, or a send from a subagent child in the right Sidebar. A
reader below the fold was left on an empty viewport.
Every batch of closing rows now runs on the viewport's frame-clock driver.
It lands at the tail for this client's own input or a following reader and
otherwise keeps the reader's content still, installing only the room the
landing lacks. Subagent child sends register a local echo and pass its
request id to subagents.prompt, so the child's recorded message retires it.
session.create resolved the requested preset before queueing on the named
identity, so a later request whose preset resolved first could run first, and
an undeclared preset masked the directory conflict the README promises.
Queue first, check the named Session's directory and ownership, then resolve
the preset inside the queue, and report the preset each request left the
Session running instead of reading it after the queue moved on. The no-roster
conflict message now names its actual cause.
session.create treats a named sessionId as a blank Session to reuse while
the Host can verify it is still reusable: no turn has started, it belongs to
the requested directory, it is an unarchived member of the requested
Workspace, and no other owner writes it. The reused Session runs the
requested agentPreset or the configured default; its recorded preset is not
resolved, so a blank recorded under a preset that is no longer declared no
longer breaks New Session or startup restoration. A change is logged as
agent-preset/selected before the Agent is published. A candidate that is no
longer reusable stays unchanged and the Host creates a new Session, which
replaces the client's writer-held fallback.
The Web client restores a saved draft with its recorded preset and falls back
to the default when that preset is missing or fails to activate, passes the
creator entry's preset through creation instead of issuing a concurrent
select, and reloads the projections of a declined candidate so a stale blank
hint no longer hides a started conversation.
Related to #2566
Address review: retention now has a single definition (retainedIds) shared by
the list-refresh sweep and the single-id prune, an already-engaged identity
skips the redundant row mutation, and the ledger documents why Host-asserted
running is recorded before any holder exists while the client-local acceptance
callback requires one.
The session-controller README, the per-session store JSDoc, and the projcache predecessor-recovery and durable-web-queue-recovery notes described one higher-seq-wins rule and the asOfSeq -1 title hint. They now state that higher-seq-wins applies among Host-sequenced values, that cached list blocks yield to the connected Session's baseline, and that the predecessor title carries its stored row's watermark under kind: 'cached'.
A `sequenced` list block merges key by key under higher-seq-wins like any Host-computed value, so a delayed control baseline at a lower cut can neither overwrite nor clear a newer live-session list value. Only a `cached` block goes through applyCached and yields to every sequenced write. The projection store's module docs describe the two row kinds.
ProjectionValueStore rows are either cached (viewed from the persisted checkpoint by the session list, no comparable seq) or sequenced (computed by the connected Host, seq comparable within the connection). Cached values fill empty keys only; every baseline discards cached rows before seeding, and every frame replaces them regardless of seq, so a connected Session's values always supersede list hints. The list response and api-session/added blocks write cached rows.
Merge a2acc7d3eb620bb52f09f7ea3b5a3a1c23353e18 after preserving the earlier
master checkpoint and its successful CI. Carry current provider input-history
handling, UI controls, agent targeting, and runner-concurrency changes into
the integration base without changing the Session migration feature layers.
Keep durable direct-child catalog semantics alongside the upstream running /
inactive vocabulary. Resolve the snapshot description conflicts by retaining
that upstream status text and the existing descendants-only diagnostic rule;
the source and all 53 JSON tool descriptions agree. Preserve parent-session
availability handling with the upstream stale-blank and batched-history fixes.
The merged application builds, all 41 documentation gates pass, and focused
provider, tool-control, and Session Controller tests pass (98, 29, and 125).
Recorded input changes come from master: one refreshed v3 list-agents sample
and three new v3 scenarios; no migration bumps an existing snapshot generation.
Merge master 62b700bba7bb71e66d2d5a3b850ba8f4dd0fd6b4 into release/session-log-v4 at 4825bc01a999f564e79172a6af28e34fc757c540. Preserve this pinned integration checkpoint before any later upstream movement so the dependent session-format repairs have an immutable rebase base.
Keep release projection-backed child catalogs, independent Session references, exact fork behavior, V4 writer, and existing migration data. Adapt the incoming subagent sidebar chat to refreshProjections rather than the removed dedicated catalog API, preserve title projections in complete projection fixtures, and retain both sidebar actions and release lineage/status behavior. Remove the duplicate SessionProjectionMap import introduced by automatic merging.
Preserve both disjoint archive seals without changing any existing hash. Regenerate current Cordis and documentation catalogs from the combined source, retaining release session methods plus master slot factories. The frozen V0-V3 runtime paths are unchanged. Initial validation passed the full build, 93 focused Client tests, and all 1905 archived artifact seals; remaining integration and snapshot checks follow on this checkpoint.