Commit Graph
52 Commits
Author SHA1 Message Date
Dudu-0223 bfc89ed4a9 fix(team): reuse compatible owner-name checkpoints 2026-11-04 11:56:50 +08:00
imccyu eb1713f856 fix(session-projection): keep released units in checkpoints (#7754)
* fix(session-projection): keep released units in checkpoints

Since the Cordis rc.11 teardown order unloads the Web layer before the
base layer, Session Controller and harness-dev-context release their
projection units before their live Sessions detach. The projection
cache is still alive at that point and wrote a checkpoint holding only
the units that were still registered, replacing the complete record.
A blank Session then lost sessionListMetadata and listed as an untitled
conversation after every graceful restart.

A released unit now stays in the registry as a predecessor: it leaves
event drives, snapshots, restores, and change notifications, while
checkpoint() keeps each Session's last cell of it without advancing it.
Registering the same key again replaces the predecessor and refolds
the log. The projection cache keeps replacing whole records.

* test(session-projection): assert frozen released units across unload tests

Update the remaining unload tests that still expected a released unit
to vanish from checkpoint(): user-approval, agent-loop inbox and scope
lifecycle, time-context, and the agent registry now assert that the
same Session keeps its pre-unload row, that a later event does not
advance it, and that a Session created after the unload has no row.
The token-meter and goal unload tests also append an event after the
unload.

Document that a retained handle read still advances a released cell
that checkpoint() serves, and that restore() folds only live units, so
its refreshed rows omit released units.

* docs(session-projection): sync the ProjectionHandle type-equiv block

* docs(session-projection): record frozen released units and their upgrade

Add the upgrade guide for checkpoint() keeping a released unit's last
row, update the registration-handles Agent Note with the frozen-cell
decision and the retained predecessor, list both consequences under the
registry README's known limitations, note in the projection cache README
that a stored row can be frozen at its unit's release, and say that
restoreFloor() ignores released predecessors.

Update the agent-loop resource-lifecycle unload test, which read
checkpoints through an alias, to the frozen-row semantics.

* docs(upgrade-guide): mark the released-checkpoint snippet ignore-check

* docs(session-projection): state the retained-handle path and narrow a rejected alternative

* docs(upgrade-guide): re-record the released-checkpoint guide pairing
2026-11-03 11:07:09 +08:00
imccyu d3f7b8abe7 Merge pull request #7701 from deepseek-harness/fix/empty-session-sidebar-0.2.2
[0.2.2] fix(session-projection): compute exactly the requested projections for hot session summaries
2026-11-02 17:05:09 +08:00
imccyu 945006c984 perf(session): send one projection frame per committed event (#7587)
* perf(session): send one projection frame per committed event

* fix(session): deliver keys changed before a drive failure; address review

* perf(session): carry projection frame changes as key and val entries
2026-10-30 14:14:03 +08:00
Magolorand_Kerman fcca540841 refactor(session): unify runtime projection reads (#7347)
* refactor(session): bind runtime projection reads to one session

* refactor(session): expose session-bound readers on projection handles

---------

Co-authored-by: _Kerman <[email protected]>
2026-10-27 09:50:22 +00:00
imccyu 499c2e347f docs(session-projection): correct compatibility statements
Describe async generator yields, key-conflict reads, and macrotask timing as implemented, restore the API controller and mods bridge sentence in the upgrade guide, record the rejected plugin-disposal alternative, and pin the async generator behavior with a test.
2026-10-20 01:09:43 +08:00
imccyu 33101ad29f fix(session-projection): log unobserved legacy registration rejections
A legacy plugin may store the registration result as a disposer or ignore it,
so a failed registration became an unhandled rejection that ends a dsh process.
The registry now attaches its own handler: once the current turn ends, a
rejection nobody observed through then/catch/finally is logged through the
calling plugin's logger while the plugin stays active, and one whose owner is
no longer loading or active is dropped. Observed rejections are unchanged.
2026-10-20 00:31:55 +08:00
imccyu f415c83579 refactor(session-projection): simplify legacy registration compatibility
- register() returns the registration's effect disposer with then/catch/finally
  attached; the original body moves unchanged into a private acquire(), keeping
  synchronous installation and the asynchronous handle handoff.
- Legacy stateOf(session, key) logs one ctx.logger.warn per key per registry;
  registration and calls to its result no longer warn.
- Containing an ignored legacy registration failure is deferred and recorded
  under Known Limitations.
2026-10-20 00:18:25 +08:00
_Kerman b3b82021d5 fix(session-projection): handle canceled legacy registrations 2026-10-19 23:24:59 +08:00
_Kerman 5224454492 fix(session-projection): restore legacy keyed read materialization 2026-10-19 23:15:11 +08:00
_Kerman 746c2a4acd fix(session-projection): preserve legacy plugin runtime calls 2026-10-19 22:55:02 +08:00
_Kerman 955e600031 Merge master into session projection registration handles 2026-10-19 11:21:16 +08:00
imccyu 6292808bf9 fix(session-controller): keep the list summary contract honest 2026-10-19 10:20:10 +08:00
imccyu af2fa50f8a docs(session-projection): stop describing a removed interlock 2026-10-19 03:00:08 +08:00
imccyu f230fc2fc2 refactor(session-projection): review fixes for the summary key set
- 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.
2026-10-19 01:13:24 +08:00
imccyu 92f9e79fac perf(session-projection): serve session-list rows from a summary key set
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.
2026-10-18 22:13:18 +08:00
_Kerman ff731c72de refactor(session-projection): remove the host state map 2026-10-15 21:01:00 +08:00
_Kerman a9bbe0c220 fix(session-projection): always return a promise from handle disposal 2026-10-12 13:08:25 +08:00
_Kerman 5ecf33aab1 refactor(session-projection): acquire retained readers during activation 2026-10-12 12:03:36 +08:00
_Kerman bff2d40dee fix(agent-loop): keep shutdown ownership local to the loop 2026-10-08 15:13:50 +08:00
_Kerman 5578ecf655 refactor(session-projection): return the exact change-feed disposer 2026-10-08 11:22:31 +08:00
_Kerman 1e1735a440 fix(session-projection): preserve composable registration disposers 2026-10-04 16:10:06 +08:00
_Kerman 37abcb74c5 chore(session): permit existing deprecated history reads 2026-09-09 12:33:53 +08:00
Turtle bec6805d6a refactor(session-persistence)!: handle-based seam with a lifecycle-owned write path
The persistence seam is now create/open/stat/list returning per-session
SessionHandles (read/append/flush/close); every log read and write flows
through the owning handle. The seam package exports only the service and
handle contracts, consumer-visible errors, and pure durable-data
validation helpers; each backend owns its complete storage runtime, and
the shared contract suites pin equivalent observable behavior. The
backend routes published sessions' live events by id into the active
write handle; agent-loop only acquires, seeds, and closes the handle.
Resume appends interruptedTurnClosers through its write handle;
session-query owns the revision-keyed cold cache. Legacy-only surfaces
are removed in the same swap: locate/readRaw/supportsRawArtifacts, the
legacy event-shape read migration, zstd torn-frame salvage,
DSH_SESSION_JSONL, and hook transcript_path population; a torn final
zstd frame is discarded whole; the session-list cold blank probe returns
on stat metadata (eventCount derived from the last physical row,
sizeBytes). The WebUI ZIP export serializes the logical log from a read
handle, so both backends export identically.

Refs #3245
2026-09-01 23:19:02 +08:00
Tianyi Cui 27bf1039db refactor(session)!: distinguish event seqs from log offsets 2026-09-01 20:36:00 +08:00
Turtle d68ff7e66f Merge remote-tracking branch 'origin/master' into turtle/omit-unneeded-invariants
# Conflicts:
#	docs/module-graph.i18n.yaml
#	docs/module-graph.md
#	docs/module-graph.zh.md
#	packages/session/session-projection/src/invariant.ts
#	tsconfig.base.json
2026-09-01 11:18:11 +08:00
_Kerman ad02fa37b4 Merge remote-tracking branch 'github/master' into xtr/session-log-read-api 2026-08-31 20:50:19 +08:00
imccyu 9ba9a35c72 test(session-projection): cover view transition matrix 2026-08-31 20:30:43 +08:00
imccyu 6f0daff1dd fix(session-projection): compare observed live views 2026-08-31 19:59:54 +08:00
Yichen Jiang 12bef3b577 perf(session-projection): memoize raw views by state identity
Review follow-up: the per-step gate recomputed view(previous) on every
changed apply — a property read for identity-stable views, but a fresh
throwaway object per change for computing views. The registry now keeps a
WeakMap from state object to raw view: the previous state's view was
cached when that state was current, so each distinct state's view computes
exactly once (gate and snapshot share the memo) and the quiet path
allocates nothing. Unlike the earlier lastView record, an entry is keyed
by the state itself — the view of that exact state by the pure-view
contract — so no stamping discipline exists to get wrong. Primitive
states bypass the WeakMap and compute directly.
2026-08-31 19:46:56 +08:00
Yichen Jiang a2437db180 revert(session-projection): drop the viewKey token, keep the per-step raw-view gate
Review consensus: for the only declaring unit the token function was
literally the view function, so the extra wire member bought nothing —
default raw-view comparison produces the identical Object.is on
state.turns at the identical cost (one property read per side). The
per-step gate stays: it holds the no-stored-baseline property, and its
measured overhead (~ns per changed state) is four orders of magnitude
below the push path it guards.
2026-08-31 19:46:56 +08:00
Yichen Jiang 9836fdbbd7 docs(session-projection): describe the change feed by its viewKey token 2026-08-31 19:46:56 +08:00
Yichen Jiang acc23f6d9c feat(session-projection): unit-declared viewKey change token
Review follow-up (imccyu): comparing view(previous) recomputes the view on
every quiet change. The wire block now takes an optional viewKey(state)
declaring the cheap comparison token; the drive compares tokens across the
previous and next states and calls view only for an actual push. Default
stays the raw view output. turnOutline declares viewKey: state => state.turns,
making the identity-stable-turns convention an explicit contract; the
registration erasure forwards viewKey (dropping it silently reverted the
gate to the fallback, caught by the new view-call-counting test).
2026-08-31 19:46:55 +08:00
Yichen Jiang 9069a8b6f8 refactor(session-projection): compare per-step views instead of storing a dedup baseline
Review suggestion (imccyu): the drive holds both the previous and next
state, so the identity gate can compute view(previous) and view(next) in
the driving step and compare them directly. The stored lastView cell field
and its stamp-on-every-change rule are deleted; with no dedup memory,
nothing can go stale across listener generations by construction, and a
rebuilt cell no longer pushes an unchanged view on its first live event.
Costs one extra pure view() call per changed state.
2026-08-31 19:46:55 +08:00
Yichen Jiang 8322f804cb fix(session-projection): advance the view dedup baseline on every change
The change feed stamped lastView only when a listener was subscribed, so a
value change during a listener-free window (HMR swap) froze the baseline
and a later transition back to the old value was silently deduplicated.
The baseline now advances on every changed state, heard or not; broadcast
still only happens with listeners. Docs, catalog, and the feature note
follow the corrected semantics.
2026-08-31 19:46:55 +08:00
Yichen Jiang ceadd90e71 feat(session-projection): identity-gated change feed
The feed previously fired on every changed state reference of a
client-visible unit; it now also compares the raw view output against
the last delivered one and stays quiet when Object.is-identical, so a
unit can buffer working fields in state behind an identity-stable
projection. Units whose views build fresh objects per call are
unaffected.
2026-08-31 19:46:54 +08:00
_Kerman 5660f44d29 perf(session): separate indexed and snapshot log reads 2026-08-28 13:25:58 +08:00
Turtle 15f2997bcb cleanup: omit unneeded invariant companions 2026-08-28 13:12:52 +08:00
_Kerman 96c1c762d5 fix(session-projection): preserve optional registrations 2026-08-26 16:51:36 +08:00
_Kerman a6c7c70d4f fix(session-projection): close review findings from the fold migration
- permission-presets: register the permissions unit synchronously before the
  existing-session sweep, so a remount reads folded knob state instead of
  treating every session as fresh; add a regression test for that path
- sandbox-policy/terminal-bash: mount the projection registry in the 5 pwsh
  terminal tests, the sdk-minimal bundle, and the e2b fixture composition;
  declare the new package dependency in both manifests
- plan-mode: restore .strict() on the plan unit state schema and drop the
  deleted foldPlanMode from the bilingual READMEs
- session-title/session-projection: sync bilingual READMEs to the mandatory
  projection seam and re-record translation pairing
- docs: turnBoundary reader contract, subagent schema comment, token-meter
  import comment, sandbox-policy module docstring
2026-08-26 14:13:42 +08:00
imccyu 7fb2ca07e4 feat(session-query): add shared projected observations 2026-08-25 06:06:03 +08:00
imccyu d26acfa2e3 refactor(session): move APIs into Session Controller 2026-08-23 16:16:02 +08:00
Tianyi Cui 934976732d docs: purge residual chain-of-thought leakage 2026-08-22 13:10:23 +08:00
_Kerman 327b86d2ea refactor(session-projection): checkpoint every projection unit uniformly
Drop the persist?: boolean opt-in: every unit's state — client-visible and
host-only alike — is now written to the projection cache. A unit can no
longer silently skip the durable cache, host-only units no longer need an
explicit flag to participate in cold restore, and the persist-sharing
conflict check disappears with the field.

- ProjectionDefinition/ErasedDefinition lose persist; register overloads
  simplify; checkpoint/restoreFloor/restore fold every registered unit.
- Registry and cache tests drop the persist:true fixtures and the
  persistence-policy sharing test.
- READMEs and the state-and-client-views note record the uniform rule;
  cordis API catalog and subsystem signatures regenerated.
2026-08-19 16:55:10 +08:00
_Kerman 9127d7e8b7 fix(session-projection): keep host state off wire 2026-08-19 14:32:48 +08:00
_Kerman 4c421ec882 refactor(session-projection): separate state from client views 2026-08-19 13:11:05 +08:00
imccyu ec601ca13d build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.

Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.

The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.

Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
2026-08-10 22:04:13 +08:00
Turtle a27efdef36 docs: make technical prose concrete 2026-08-10 16:34:20 +08:00
Yichen Jiang f80d2a742e Merge remote-tracking branch 'origin/stack/agent-profiles-1-seam' into stack/agent-profiles-3-wire
# Conflicts:
#	docs/module-graph.md
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/tsconfig.json
2026-08-09 20:33:55 +08:00
Turtle dda02250f5 docs: reserve seam for complete capabilities 2026-08-09 17:26:57 +08:00