docs(rfc): record follow-up cleanup seams
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
Status: implemented (see [ADR 0018](../adr/0018-session-persistence.md))
|
||||
|
||||
> **Historical proposal note:** this RFC is preserved as the design trail. The implemented crash-recovery semantics are the ADR 0018 version: load preserves an interrupted final turn and durably closes it with synthetic boundary events instead of truncating back to the last `turn/end`; both JSONL and SQLite backends now implement that contract.
|
||||
|
||||
## Problem
|
||||
|
||||
Sessions live only in memory. The example `session-jsonl.ts` plugin (duplicated byte-for-byte in both `examples/coding-agent` and `examples/echo-agent`) is write-only telemetry: it buffers `session/event` and appends JSON lines, but has no read/replay path, no crash-safety (no fsync, no atomic write, and a fire-and-forget dispose drain), no listing, and no format versioning. [ADR 0003](../adr/0003-event-sourced-sessions.md) and [docs/architecture.md](../architecture.md) both park "real persistence backends (JSONL session dirs, sqlite)" and the session-event-vocabulary review as deferred TODOs "once the loop and the first persistence plugin coexist" — that time is now.
|
||||
|
||||
@@ -8,6 +8,8 @@ Status: proposed
|
||||
|
||||
RFC 010 ships ACP support with a single active session per connection: a second `session/new` is rejected. Editors expect to run several conversations over one agent subprocess — a user opens multiple threads, or a client pre-warms sessions. The single-session guard is a deliberate MVP scope cut, not an architectural limit; this RFC lifts it.
|
||||
|
||||
This paragraph is historical: the multi-session bridge has landed. The remaining proposed work is per-session permission ownership plus the lifecycle seams now tracked in [RFC 014](014-agent-lifecycle-and-ownership-seams.md).
|
||||
|
||||
## Proposal
|
||||
|
||||
The harness core already supports many agents (`AgentRegistry.list()` and `AgentLoop.create` impose no count limit), so multiplexing is a bridge-layer change in `@deepseek-ai/dsh-acp`, not a loop or core change.
|
||||
|
||||
26
docs/rfc/014-agent-lifecycle-and-ownership-seams.md
Normal file
26
docs/rfc/014-agent-lifecycle-and-ownership-seams.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# RFC 014: Agent lifecycle and ownership seams
|
||||
|
||||
Status: proposed
|
||||
|
||||
## Problem
|
||||
|
||||
Several ACP and tool-bash limitations are symptoms of the same missing seam: plugins can create or resume agents through `ctx.agents`, but they cannot own and dispose one agent independently, and long-running bash tasks carry no stable owner in the executor itself. ACP currently aborts and awaits agents on disconnect, but cannot unregister just that session's agent; `session/cancel` cannot cancel queued-but-not-yet-started work; and `tool-bash` keeps task ownership in a plugin-local `Map`, so an HMR reload can make an old task look unowned.
|
||||
|
||||
## Proposal
|
||||
|
||||
Add explicit lifecycle ownership to the agent factory and explicit ownership metadata to background tasks.
|
||||
|
||||
1. `ctx.agents.create/resume` should return an `AgentHandle` (or add an adjacent method) that exposes the `Agent` plus an async disposer. The disposer unregisters the agent, aborts queued/running work, and resolves only when the driver loop reaches quiescence.
|
||||
2. Add a queue-aware cancel primitive to the `Agent` interface. It must clear queued work that has not started, abort the current step if one exists, and make `whenIdle()` wait for the post-cancel quiescent state. ACP `session/cancel` and bridge teardown then become honest cancellation, not best-effort pre-step cancellation.
|
||||
3. Move background task ownership into the bash seam. `BashExecSpec` or `BashTask` should carry a stable owner token, preferably the session id rather than the `Agent` object identity. `bash_output`/`bash_kill` then ask the executor for ownership rather than relying on a `tool-bash` instance-local map.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- ACP disconnect/session close leaves no registered agent for that session, even when `session/load` races teardown.
|
||||
- `session/cancel` before a queued prompt starts prevents that prompt from running and cannot batch the next prompt into the cancelled turn.
|
||||
- A `tool-bash` HMR reload does not make an existing background task readable or killable by a different session.
|
||||
- Existing non-ACP demos still work without managing handles explicitly; config-created agents remain owned by the `AgentLoop` plugin fiber.
|
||||
|
||||
## Risks
|
||||
|
||||
This touches public interfaces (`Agent`, `AgentFactory`, and the bash seam), so it should not be smuggled into a local ACP patch. The compatibility trap is preserving the simple synchronous `Agent.send()` ergonomics while adding a robust async lifecycle path for owners that need it.
|
||||
24
docs/rfc/015-shared-persistence-write-coordinator.md
Normal file
24
docs/rfc/015-shared-persistence-write-coordinator.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# RFC 015: Shared persistence write coordinator
|
||||
|
||||
Status: proposed
|
||||
|
||||
## Problem
|
||||
|
||||
`dsh-session-persistence-jsonl` and `dsh-session-persistence-sqlite` intentionally prove the same `SessionPersistence` contract over different storage media, but their write-path orchestration is now duplicated: per-session state, `session/created` adoption, seed-prefix collision checks, write-behind buffers, serialized flush chains, HMR seeding, and dispose drains. That code is correctness-heavy and already receives the same fixes twice.
|
||||
|
||||
## Proposal
|
||||
|
||||
Extract a backend-agnostic coordinator into `dsh-session-persistence`. The coordinator owns live-session adoption, buffering, cursor filtering, per-id serialization, and disposal quiescence. Concrete backends provide small hooks for durable operations: create lazy state, find/load stored prefix, append a contiguous batch, update summary, delete, and list.
|
||||
|
||||
The public `SessionPersistence` service shape can stay the same. The coordinator can be an internal exported helper or protected base class used by first-party backends; third-party backends may still implement the abstract service directly if their write path is different.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- JSONL and SQLite keep passing the existing shared `runPersistenceContract`.
|
||||
- HMR/adoption/collision tests move to a shared coordinator test suite and run once for each backend through hook-driven fixtures.
|
||||
- Backend-specific tests focus on storage mechanics only: JSONL path safety/fsync/sidecar behavior and SQLite schema/WAL/transaction behavior.
|
||||
- A future backend does not need to copy the current `session/event` → buffer → flush orchestration.
|
||||
|
||||
## Risks
|
||||
|
||||
The current duplication is verbose but explicit. A coordinator must not hide storage-specific durability semantics or make unusual backends fight an inheritance hierarchy. Prefer narrow hooks and contract tests over a large framework.
|
||||
@@ -12,8 +12,10 @@ Proposals for substantial future work — reviewed before implementation, unlike
|
||||
| [006](006-doc-sync-and-api-reports.md) | Doc-sync enforcement and API extractor reports | implemented (pts 1-2; pt 3 deferred) |
|
||||
| [007](007-supply-chain-and-vendor-drift.md) | Supply chain checks and vendor drift verification | proposed |
|
||||
| [008](008-immutable-public-surfaces.md) | Deep-readonly public surfaces | implemented (revised) |
|
||||
| [009](009-session-persistence-and-resumability.md) | Durable session persistence — abstract, append-only, event-based store | proposed |
|
||||
| [009](009-session-persistence-and-resumability.md) | Durable session persistence — abstract, append-only, event-based store | implemented |
|
||||
| [010](010-acp-agent-client-protocol.md) | Agent Client Protocol (ACP) support for external editors | proposed |
|
||||
| [011](011-acp-multi-session.md) | Multiplex concurrent ACP sessions over one connection | proposed |
|
||||
| [012](012-optional-code-mode.md) | Optional Code Mode — model writes TypeScript against an SDK of all tools | proposed |
|
||||
| [013](013-typed-event-schemas.md) | Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern) | proposed |
|
||||
| [014](014-agent-lifecycle-and-ownership-seams.md) | Agent lifecycle and ownership seams | proposed |
|
||||
| [015](015-shared-persistence-write-coordinator.md) | Shared persistence write coordinator | proposed |
|
||||
|
||||
Reference in New Issue
Block a user