Replies: 6 comments
|
Root cause confirmed, and I can add two measured things. The gate is identical in 0.1.5-rc.3 and 0.1.7-rc.2. From the published tarballs of The offline fix exists today, and I measured it against that same gate. session-surgeon normalizes On the blast radius — agreed, and it is worth naming: because the persistence observer feeds every stored v0 session through the gate, one offending artifact fails every query (
We have not touched your files; every measurement above is on constructed samples. |
|
Verified against freshly packed tarballs of both versions — exact match: This is a day-one contract gap, not a regression. The released inventory has only ever accepted descriptor version 3, while the writer has only ever emitted 2 — on my machine, 27/27 sessions back to 2026-08-23 carry On the two remediation paths, I'd order them:
Third path for affected users, no file edits at all: Same conclusion on blast radius, from the other side: with the plugin bypassing the index and your surgeon enumerating it offline, the remaining gap is exactly the upstream gate — the one fix that helps every user without asking them to install or repair anything. |
|
One measurement that bears on which fix upstream should ship — because "accept 2" and "normalize 2 to 3" are not equivalent, and the rest of the chain already has an opinion. Downstream already believes versions 1, 2 and 3 are valid. In const known = isSessionFormatJsonObject(descriptor) && [1, 2, 3].includes(descriptor["version"]);
if (count !== 1 || !known) return void 0;
if (descriptor["version"] !== 1 && descriptor["mode"] !== "continuable" && descriptor["mode"] !== "one-shot") throw …Version 1 even gets a special case ( The intervening stages never look at descriptors at all. And 2 and 3 are indistinguishable there, which is what makes our normalization safe: both take the same branch in the two tests above (only So the two proposals are compatible rather than competing: relaxing the v0 gate is consistent with the rest of the chain, and normalizing to 3 is lossless for the same reason. The one thing that would be wrong is relaxing the gate and passing 2 through to a consumer that assumes the writer's version field means what it says — which is the situation today. Shipped our side of it in |
|
All three code claims verified against the published And I can now close the loop with real-store data instead of constructed samples: I scanned the actual store that motivated this thread (89 session logs, 26 That also sharpens your closing caution into something measurable: within the shipped chain there is no consumer today for which passing raw 2 through is wrong — the "assumes the version field means what it says" consumer is hypothetical. The caution still stands for forward-compat, and the same measurement points at where the next instance of this family would come from: the Compatible-not-competing is the right call, and the store data says both are safe today — the residual risk is entirely in future vocabulary drift, which is the argument for fixing the gate (or normalizing) and naming the vocabularies in one place. |
|
Thanks for running it against the store that motivated the thread — 26 descriptors, every one On the forward-compat point: the boundary you predict is already the boundary of our repair, and we have hit it. One detail on where |
|
Agreed on all three points, and the report-don't-guess stance at the mode boundary is the right one. One concrete addition to "where the next instance would show up", from the same file: the vocabulary asymmetry has a sibling sixteen lines down. The catalog-fact check at That also makes your framing measurable: when the next one lands, the refusal will name |
Uh oh!
There was an error while loading. Please reload this page.
TL;DR
Every session-search call on this machine fails with
SESSION_QUERY_PERSISTENCE_FAILED. The persistence observer feeds each stored v0 session through the v0→v1 migration, anddsh-session-format-v0-to-v1throws on anysubagent/descriptorevent whosedata.version !== 3. The problem: every realsubagent/descriptorevent I can find — 27 sessions spanning 2026-08-23 → 2026-09-26, including sessions created under the current 0.1.5-rc.3 — carriesversion: 2. None carries3. So every session that ever spawned a subagent is unindexable, and one such session fails all searches, not just its own.Environment
~/.dsh/sessions/<workspace>/<session-id>/session.jsonl.zstdrecalltool surface)The failure
Deterministic; repeats for every query until the offending session leaves the store.
The offending event
From the raw log of the session named in the error (created 2026-08-23):
{"type":"subagent/descriptor","seq":6,"time":1787489897542,"data":{"version":2,"mode":"one-shot","provider":"spawn","label":"扫描Python仓库文档机会"}}Root cause
dsh-session-format-v0-to-v1, insideassertReleasedEventPayload(the payload gate for the frozen v0 event inventory):Two observations:
subagent/descriptorevents; all 27 carryversion: 2; zero carry3. The newest was created 2026-09-26 00:13 by the currently installed 0.1.5-rc.3. Unless some writer out there emits 3, this gate rejects 100% of real-world subagent sessions.returns — the event passes through unvalidated. Only the v0 arm throws. That asymmetry inside one function suggests the hard failure is an oversight rather than a deliberate policy; at minimum the two arms should agree.Downstream,
dsh-session-querywraps the observer failure asSESSION_QUERY_PERSISTENCE_FAILEDand the whole call aborts. The message correctly notes the source artifact is left unchanged — but there is no per-session isolation: one unobservable session takes down every query against the store.Blast radius
Fix directions
Either layer restores search here; both are worth having:
Auditing your own store
A single affected session is enough to fail all searches in that store on 0.1.5-rc.3.
Verified against the 0.1.5-rc.3 runtime; happy to re-check against master if this gate has moved. I can prepare a fork patch with regression tests (a v0 artifact with a v2 descriptor migrates cleanly; the observer quarantines an unparseable session without failing the query) if the direction sounds right — the analysis stands on its own either way.
All reactions