Adding packages/util/brand/ created a new top-level packages/util/ group that
the hierarchy/dependency docs never enumerated. Document it:
- Add packages/util/README.md, the group README (low-level zero-dependency
utilities shared across groups; lists dsh-brand).
- packages/README.md: add the util/ group to the group table, dsh-brand to the
package table, and dsh-brand to the dependency graph. Correct the now-false
"no harness deps" claims — dsh-llm and dsh-bash both depend on dsh-brand
(verified dsh-bash imports Branded from dsh-brand, not dsh-llm; dsh-session
and dsh-agent depend on it too).
- Root AGENTS.md Repository Layout: add the util/ group with brand/.
Align the implemented branded-ids RFC with what shipped: Branded lives in
@deepseek-ai/dsh-brand (packages/util/brand/), and dsh-bash depends only on
that utility package instead of dsh-llm. Fix the BashTaskId import source, the
illustrative snippet, and the opening policy reference (now dsh-brand).
Type-only change (brands are zero-cost casts; no runtime/wire impact). Closes
the two gaps in the "brand ids that cross package boundaries" policy and fixes
the dependency direction so a capability package never pulls in an unrelated one.
- Extract the `Branded<B>` primitive into a new standalone type-only package
`@deepseek-ai/dsh-brand` (packages/util/brand) with no harness-package deps.
dsh-llm keeps its owned CallId but imports Branded from dsh-brand; dsh-session,
dsh-agent, and dsh-bash all import Branded from there. dsh-bash depends on
dsh-brand ALONE — never on dsh-llm or dsh-session (the architectural fix: a
generic execution backend must not couple to the LLM or session vocabulary).
- Mint BashTaskId + OwnerToken in dsh-bash and thread them through BashTask.id,
the get/ownerOf/list/readOutput/kill seam, the bash-local generation site, and
the dsh-tool-bash validate/access surface. OwnerToken is a DISTINCT brand from
SessionId so the seam stays decoupled; dsh-tool-bash is the single boundary
that casts SessionId -> OwnerToken.
- Brand at the SOURCE, not via mid-pipeline casts: agent-loop's Config types
agents[].id as AgentId and resumeSessionId as SessionId, so the brand enters
at the config boundary and the inner create()/resume casts disappear (only the
genuinely-new per-run session-id string is cast).
- Stop brand erosion: propagate CallId/SessionId/AgentId to the registry/store
Map keys and public params/exports (SessionStore, AgentRegistry + factory
options, the ACP session-id surface + ToolPresenter CallId map, the
persistence coordinator, invariants pendingCalls, the pi-ai tool-call maps).
- Docs: document BashTaskId/OwnerToken in bash.md (type-equiv re-pasted), point
the Branded type-equiv at dsh-brand, fix stale param types in the session/
agent/bash READMEs, regenerate the cordis catalog + module graph.
Implements docs/rfc/proposed/architecture/2026-06-20-branded-ids.md
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
The LLM service exposed three call surfaces (stream/streamBlocks/generate) but
the only production consumer — the agent loop — uses stream() exclusively,
feeding raw chunks through its own BlockAssembler for replay fidelity. Drop the
speculative convenience surfaces and the registry-change event that no listener
consumed, leaving stream() as the single model-call contract for both
production and tests.
- Remove LlmService.streamBlocks() and generate(), the llm/generate waterfall,
and GenerateResult.
- Remove the llm/adapter-change event (declaration + emits) and the
listener-throw rollback ordering that existed only to protect it; keep the
HMR rollback disposer.
- Remove BlockAssembler.flushReady()/flushRemaining()/result() and the flushed
cursor — the streaming-flush slice existed only for streamBlocks().
- Adapter tests drive a stream()+BlockAssembler helper (tests/assemble.ts)
instead of generate(), exercising the same path production uses.
- Land the AGENTS.md "RFCs are proposals, not golden truth" principle and move
both RFCs proposed -> implemented.
Implements:
- docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md
- docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md
Self-audited every factual claim against the shipped branch (hierarchy
tree, no group manifests, the dsh-* paths wildcard in both tsconfigs,
publint glob, explicit build references, the two new gates). Phrase the
paths-wildcard bullet as current state, and record the doc-typecheck
JSONC-parse subtlety the wildcard introduced so a future editor does not
reintroduce the regex comment-strip bug.
Add a README to each group dir (core/llm/bash/session-persistence/ui/
support) stating its role and product-vs-support classification, and
rewrite packages/README.md around the hierarchy (group table, grouped
"what goes where", removed the package-hierarchy FIXME).
Move the package-hierarchy RFC to implemented/architecture/ and rewrite
it to describe what shipped (placement rationale, the paths-wildcard and
publint dedup, the two new guardrail gates). Fold the remaining
tsconfig.build.json references dedup into the discover-package-inventory
proposal and fix its cross-link.
Update AGENTS.md: regrouped repo-layout map, depth-2 globs, the new
verify-package-paths gate in the doc-sync listing, and a note that we
lean toward stricter lint in the agentic-coding era (machine-caught
errors and a consistent foundation outweigh the one-time cost).
Add a second axis to every RFC — its class (feature, bug-fix,
simplification, architecture, process, testing) — encoded in the path
as docs/rfc/{lifecycle}/{class}/file.md. The folder is the label, so
the closed set is enforced by structure rather than a parsed field.
Two new doc-sync gates back it:
- verify-rfc-classification: every RFC sits in a valid class folder and
the README index lists it under the matching lifecycle→class heading.
- verify-doc-refs: every docs/*.md path cited in a packages|examples TS
comment resolves — closes a drift class verify-md-links can't see, and
catches the four comment refs this reorg moved.
The README gains a Classification section explaining the taxonomy and
per-class index sub-sections. A self-referential process RFC records why
the scheme is path-encoded and gated.