Replies: 1 comment
|
Checked this against current upstream master (c291e79, 2026-09-10) and every part of your diagnosis holds up. list.ts still has the exact short-circuit you quoted: header.isSeeded ? undefined : cache?.cachedSnapshot(...) ?? cache?.cachedPredecessorTitle(...), only in the session === undefined cold branch. The inheritedEventCount-not-persisted claim checks out at the lowest level I could find it. session-format-v1-to-v2/src/codec.ts's encodeHeader takes inheritedEventCount as a parameter, uses it only to validate cut !== 0 for an unseeded header, then returns an object literal that never includes the field at all. session-persistence-jsonl/src/format.ts's HEADER_KEYS set, the full list of required and optional header keys, has no inheritedEventCount entry either. And fromHeaderLine, the function that turns a decoded header line back into SessionStorageMetadata for the cold read path, hardcodes inheritedEventCount: SessionLogOffset(0) instead of reading it from the line, since there is nothing there to read. session-projection-cache/src/index.ts's lifecycleIdentityMatches does require exact equality on inheritedEventCount. So a seeded session whose real inherited cut is nonzero will always mismatch against a cold-read identity built with a hardcoded 0, exactly as you describe. Both gates are real and independent, confirmed at the source level, not just from the symptom. Your fix direction, drop the isSeeded short-circuit, add a narrow zero-I/O fallback keyed on the immutable createdAt plus cwd, and eventually persist inheritedEventCount in a future header version so the strict match can work cold too, looks like the right shape. The maintainers would know if there was a deliberate reason to keep inheritedEventCount out of the header line in the first place. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
After a cold start of
dsh web, every seeded session (fork / sub-agent / compact-inherited — header carriesisSeeded) is shown in the sidebar with the basename of the workspace folder instead of its real title. Opening the session once restores the correct title (it becomes live and does a full cold read), but the regression returns on every restart. Plain, unseeded sessions are never affected.Two independent gates jointly cause it, and fixing either one alone is insufficient.
Evidence
@deepseek-ai/dsh-api-session-controller,projectionsFor(header, session)— the cold branch (session === undefined) short-circuits seeded sessions before trying the listing fallback:With
block === undefined, the clientdisplayTitleOf(title, cwd, id)falls back to the cwd basename.inheritedEventCountbut does not write it to the header JSON (the real cut only exists later as a bodyend-seed { inherited: true }marker), and the cold header path suppliesinheritedEventCount = 0;lifecycleIdentityMatchesrequires equality on every field, so it always rejects;isSeededidentity field.So even after removing the short-circuit in (1), the strict lookup still refuses these records. The correlation is exact: all seeded cold sessions lose their title, all non-seeded ones keep theirs.
Minimal reproduction
dsh webcold; do not open that session.Environment
macOS (Apple Silicon), Node v26,
@deepseek-ai/dsh@0.1.5-rc.1, single DSH_HOME, sequential hosts (not concurrent).Workaround
Opening each affected session once restores its title for the live session. Locally we confirmed the split is exactly
isSeeded(every seeded cold session affected, every unseeded one fine), and patched around it with no change to live/hydration paths.Suggested fix
Drop the
isSeededshort-circuit and add a deliberately narrow, zero-I/O listing-only title fallback: pin the lifecycle slot with the immutablecreatedAt + cwdknown to the cold header, ignoreformatVersiondirection and the unavailableinheritedEventCount, tolerate a missing legacyisSeededonly, and expose just the title row (still version-gated). The cleaner long-term fix is to persistinheritedEventCountin a future header version (and backfill on migration), after which the cold list can match strictly and the fallback can be removed.All reactions