Eight proposals grouped by category, each with problem statement,
concrete plan, and risks: property-based testing over the
protocol-shaped core (chunk streams, event logs, schema DSL);
mutation testing as the counterweight to the 100%-coverage gate;
deterministic tests + a universal replay-invariant fixture + nightly
race stress; architectural conformance (dependency-cruiser rules and
the LlmAdapter conformance kit); runtime arg validation at the model
boundary with a structured error taxonomy and dev-mode invariants;
doc-sync enforcement (typechecked doc snippets, API reports);
supply-chain checks and nightly vendor-drift verification against the
manifest; and deep-readonly public surfaces (logged-vs-in-flight
mutability boundary). AGENTS.md points at docs/adr and docs/rfc.
Seven ADRs capturing the why behind decisions already made: vendoring
Cordis as source with a guarded manifest; the microkernel event
taxonomy with one swappable concrete loop; event-sourced sessions
with derived history and the append-before-emit ordering contract;
the provider-neutral content-block vocabulary (and why not
OpenAI/Anthropic shapes); the custom tool-schema DSL over schemastery;
tool schemas living in the prompt assembly; and mechanical quality
gates over prose guidelines (the agents-write-the-code rationale).
The architecture cookbook's tool-plugin example now uses defineTool
with typed args (the raw-JSON-Schema + `args: any` example contradicted
the type-safety policy it sits next to); a note explains raw schemas
remain the MCP interop path. The echo-agent README's mock-llm row now
matches the code (registerAdapter(['mock-echo'])) and the echo-tool
row mentions the typed registration.
High (loop pipeline): agent/step-result now runs before the
assistant/message append so the session log records what tool dispatch
actually uses; abort is honored between tool calls, not just
mid-stream; steering drains at step start, pending steering overrides
a negative turn-continuation decision (/goal pattern), and leftover
steering is re-enqueued as queued messages so it is never stranded;
exceptions from turn-continuation listeners and session/flush are
contained to the turn (error event + agent/error) instead of killing
the driver loop.
Medium: disposal emits agent/status('disposed') and mid-turn disposal
records reason 'disposed'; duplicate LLM adapter registration throws
(all-or-nothing); SessionEvent is a real discriminated union (casts
removed); model-less agents fail with a clear actionable error unless
agent/request supplies a model.
Low: agent/queued and agent/steering carry the resolved MessageSource;
streamBlocks() yields strictly in stream order and flushes delta-only
blocks (matches generate()); BlockAssembler freezes blocks on
block-end and ignores stragglers from malformed streams; turn
numbering is a counter seeded from the log (fork-safe); LoopAgent's
stop disposer is infallible (a throwing status listener cannot skip
registry cleanup); AgentLoop.create uses a generator effect so stop
and unregister are independent disposables; SessionStore wires
onAppend inside its effect.
21 regression tests added (review-fixes.spec.ts), organized by
finding. Docs updated: loop pseudocode (status emissions, ordering,
error containment, steering guarantees) and waterfall composition
caveat in docs/architecture.md; AGENTS.md notes that excessive tests
are welcome.
docs/architecture.md: layering, service map, event taxonomy, the
session/turn/step lifecycle, Cordis waterfall semantics, an extension
cookbook, the plugin sanity checklist mapping every MVP feature to its
extension mechanism, and the deferred-work TODO list (sub-agents,
persistence backends, compaction, DeepSeek V4 adapter, parallel tool
execution, streaming-protocol review).
AGENTS.md: repo layout, commands, conventions (dsh-* naming, ESM,
effect-based registrations, declaration merging, waterfall semantics),
and the vendoring policy pointer.