simplify(seams): prune dead methods from the persistence and bash seams

Two capability seams carried abstract methods no production consumer calls.
A method no consumer programs against is not a seam — it is speculative
surface every implementation must still provide and test.

- SessionPersistence: remove has() and delete(), the coordinator's
  has/delete/deleteCore, and the PersistenceBackend.deleteStored hook (with its
  jsonl + sqlite + in-spec memory-stub impls). Surviving service surface:
  create/append/load/list. Production uses only load() (resume) and list()
  (ACP session/list).
- BashExecutor: remove get(id) and list(), the abstract decls and the
  LocalBashExecutor impls. The internal tasks map survives (it backs
  ownerOf/readOutput/kill); get/list were pure public accessors over it with no
  shipping caller and no bash_list tool.
- Migrate tests that reached through ctx.bash.get(id) to the public completion
  seam: a doneFor(id) helper over onTaskDone awaits a task by id, and the
  HMR-reload ownership test now proves task survival through A's own bash_output
  ([status: running]) plus ownerOf + B-rejection — a stronger through-the-tool
  assertion than the removed lookup peek.
- Update seam READMEs (six -> four service methods, drop the deleteStored hook
  and the get/list row) and the two implemented persistence RFCs in place.

Implements docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md
This commit is contained in:
Tianyi Cui
2026-06-21 02:17:27 +08:00
parent 584349f881
commit 7792347c4f
25 changed files with 92 additions and 224 deletions
@@ -11,7 +11,7 @@
* (the `session/event` → buffer → `session/flush` drain, per-session
* serialization, write cursors, fork-seed persistence, HMR live-adoption,
* crash-repair sequencing, dispose quiescence) lives in the backend-agnostic
* {@link PersistenceCoordinator} this class composes. The six public
* {@link PersistenceCoordinator} this class composes. The four public
* {@link SessionPersistence} methods delegate to the coordinator.
*
* @module @deepseek-ai/dsh-session-persistence-jsonl
@@ -101,14 +101,6 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
return this.coordinator.load(id)
}
has(id: SessionId): Promise<boolean> {
return this.coordinator.has(id)
}
delete(id: SessionId): Promise<void> {
return this.coordinator.delete(id)
}
// `list` is BOTH the public service method and the PersistenceBackend hook —
// one method, the bucket walk below. The coordinator adds no orchestration for
// listing (no per-id serialization, no cursor), so it would just call back into
@@ -180,12 +172,6 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
if (closers.length > 0) await this.appendLines(meta, closers)
}
/** Remove a session's log file (the coordinator clears its in-memory state). */
async deleteStored(id: SessionId): Promise<void> {
const file = await this.findLog(id)
if (file) await rm(file.path, { force: true })
}
/** List all stored sessions' metadata (header line only — no full-log parse). */
async list(): Promise<SessionHeader[]> {
const metas: SessionHeader[] = []
@@ -341,9 +327,9 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
/**
* Find a session's log file by id across ALL cwd buckets — the any-cwd scan
* for `loadStored`/`deleteStored` (resume and removal identify a session by id
* alone). The cwd-scoped lookup (`loadLive`) does NOT use this; it goes
* straight to `logPath(cwd)` so a no-cwd session can't match a real-cwd bucket.
* for `loadStored` (resume identifies a session by id alone). The cwd-scoped
* lookup (`loadLive`) does NOT use this; it goes straight to `logPath(cwd)` so
* a no-cwd session can't match a real-cwd bucket.
*/
private async findLog(id: SessionId): Promise<{ path: string; cwd: string | undefined } | undefined> {
const target = encodeSegment(id) + '.jsonl'