gen-cordis-catalog.ts now emits docs/cordis-catalog/events.md and
docs/cordis-catalog/services.md instead of the combined
events-and-services.md: a reader is either finding what to listen to or
what to call, and each axis now scans and deep-links as its own page.
Headings promote one level (scopes and ctx.<key> entries become H2), the
dispatch-mode legend lives on the events page, and the inherited tier
splits accordingly. --check verifies both files and names whichever is
stale.
Every reference updated in the same change (no compat redirects,
pre-release stance): architecture.md, AGENTS.md, docs/AGENTS.md tier row,
filesystem/subagent core-data-structures pages (the ctx.fs anchor
survives — slugs are heading-level-independent), fs README, four RFCs,
the tool-catalog and persistence-catalog generator intros (both
regenerated), and the bilingual development.md pair (re-recorded).
- The owning top-level interface SessionEventMap must now be the SINGLE
EXPORTED declaration in @deepseek-ai/dsh-session: a non-exported local
interface (even inside the owning package) and a second exported copy
are hard errors, so a same-named helper can no longer be catalogued as
the on-disk vocabulary.
- Any SessionEventMap declaration carrying an extends clause is a hard
error: inherited keys join keyof SessionEventMap but have no catalog
row, so heritage is a silent-skip path the gate must reject.
Three new spec cases; RFC and module doc updated to match.
- A SessionEventMap member that is not a property signature with an
explicit payload type is now a hard error instead of silently skipped —
a method-form or type-less member joins keyof SessionEventMap and must
not escape the catalog.
- A top-level interface SessionEventMap outside @deepseek-ai/dsh-session
(ownership read from the package manifest) is now a hard error — an
unrelated same-named local interface was previously catalogued as the
on-disk vocabulary.
- JSDoc tag detection runs on the trimmed line, so an extra-indented
'* @mode' can no longer bypass the forbidden-tag check and leak into
prose.
Four new spec cases cover these; RFC and module doc updated to describe
the enforced (not just assumed) invariants.
docs/persistence-catalog/log-events.md enumerates every SessionEventMap
member — the owning dsh-session vocabulary plus the dsh-compact and
dsh-hook-protocol declaration merges — with payload, surface/log-only badge,
JSDoc prose, and declaration site. scripts/gen-persistence-catalog.ts is a
pure AST pass in the gen-cordis-catalog mold: verify-persistence-catalog
(--check) joins doc-sync, so a stale committed catalog fails pre-push and CI.
The walk enforces JSDoc completeness (every member needs description prose;
@mode is rejected as a category error — log events do not dispatch on the
cordis bus), derives the surface badge from the SurfaceEventType union with a
stale-member cross-check, and hard-errors on duplicate declarations. Payloads
render through the TypeScript printer so newline-separated multi-line type
literals still emit valid one-line fragments.
Documented the five previously JSDoc-less core events (turn/step boundaries,
tool/call), removed the two stray @mode tags on the hook/* merges, and
replaced the hand-restated event enumerations (session.md hook/* table,
compact README table, hook-protocol README bullets, session README name-list
— whose merge note had already drifted) with links to the catalog. RFC:
docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md.
gen-cordis-catalog now hard-errors (aggregated, not fail-fast) when an
event lacks description prose or a payload @param, or a public service
method lacks JSDoc, a @param per parameter, a @returns on a non-void
result, or an explicit return type annotation. The this receiver and the
trailing waterfall next are exempt on events (mode machinery owned by
@mode); a stale @param naming no real parameter errors, mirroring the
@mode contradiction check. parseJsDoc now ends prose at the first block
tag (standard JSDoc semantics), so the tags never change the rendered
catalog — only Source: line pointers moved.
Fills the ~139 gaps found across the 15 surface files, extends the spec
with negative-path fixtures for every new guard plus the exemptions,
records the decision as an implemented process RFC, and extends the
AGENTS.md typed-events bullet with the authoring rule. Runs inside
verify-cordis-catalog -> doc-sync, so CI and pre-push enforce it with
zero new wiring.
Exact-size ceilings turned every two-word wording fix into a gate
event. The policy amends to: a ceiling sits at least 5% above the
doc's current size (pre-rewrite) and keeps that margin when ratcheted
to target — routine edits pass, real growth still trips the gate.
Amended together in all four policy homes (docs/AGENTS.md § Budgets,
the doc-tiers RFC, the gate script's module comment, the skill's
ratchet rule) plus the manifest values, so prose and mechanics stay
consistent.
The definitive sweep (audit every AGENTS.md mention in packages/, docs/,
examples/, scripts/) found thirteen more citations of relocated policy
and two citations of rules that never existed as quoted:
- with-key policy comments (web deepseek/perplexity e2e headers) ->
docs/testing.md; real-impl-over-mock comments (acp harness, load,
stream-update specs) -> docs/testing.md; defensive-pattern quotes
(acp index.ts x3, stream-update) -> docs/defensive-patterns.md.
- md-tier repoints: real-api-e2e RFC, tool-schema-catalog RFC,
postmortem 0001 guardrail row, adding-a-package cookbook,
drop-bash-output-spill-files RFC, acp-subagent-backend RFC phrasing.
- Two false attributions dropped in favor of self-contained reasoning:
tool-todo's 'don't validate scenarios that can't happen' and the
bash-stdin-env RFC's 'Don't add features beyond what the task
requires' (neither rule ever existed under those names).
- Citations of the two 'not golden truth' doctrines stay: those bullets
survive verbatim in the root conventions.
Note: packages/support/ui-stdio readline TTY spec flakes under full
coverage on a heavily loaded box (passes standalone and passed the
same tree's coverage run minutes earlier); untouched by this stack.
- Restore the universal JSDoc rule the rewrite dropped (module doc
comment + semantic JSDoc on every export), in root AGENTS.md § Type
safety and documentation — the generated-catalog RFC cites it as the
rule the generator enforces at the source.
- Repoint the six remaining citations of moved content that the
section-name grep missed (rule-title quotes and prose references):
agent-loop agent.ts, acp index.ts, acp turns.spec.ts, the Exa e2e
header, the real-api-e2e RFC, the doc-sync-enforcement RFC amendment,
and rfc/implemented/AGENTS.md's section-name casing.
- Fix two docs/testing.md overstatements: the unit tier also runs
examples/*/tests specs, and keyless-by-nature examples have no
with-key smoke.
- Displacement trims keep root AGENTS.md at 1,498/1,500.
docs/rfc/README.md's per-lifecycle tables are now generated between
gen-rfc-index marker comments from each RFC's path (lifecycle/class),
H1 title (optional 'RFC: ' prefix stripped), and filename date, sorted
by date then filename — the one docs region every proposal wave edits
and every concurrent branch conflicts on becomes derived state.
scripts/rfc-index.ts owns the shared walker (closed lifecycle/class
sets, structure rules, parseable-H1 requirement) and the renderer;
gen-rfc-index.ts is the writer CLI; verify-rfc-classification.ts keeps
the structure check and asserts the committed regions byte-match a
fresh render (freshness subsumes the index-completeness check, since a
generated-from-disk table is definitionally complete and correctly
headed). A malformed H1 is a hard error in both directions, so the H1
is now load-bearing as the title source — the one nonconforming H1
(a status suffix duplicating the path) is normalized.
Implements docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md
(moved from proposed/ and amended to the shipped mechanics); the
classification RFC's verify-only stance carries the supersession
cross-link per implemented/AGENTS.md.
architecture.md is the behavior map: layering, service map, seam
pattern, and the loop — everything else defers to its owning tier.
- Seam narrations compress to two-to-four sentences plus links to the
RFC and type-catalog homes that carry the detail (turn-end variant
semantics -> session.md, derivation mapping -> session.md, StreamChunk
conventions -> llm-streaming.md + source).
- The MVP feature-to-mechanism checklist moves de-statused into the
extension cookbook as 'The feature -> mechanism map' — mechanisms
only, no implementation-status bolding to rot; the microkernel RFC's
proof-obligation pointer follows it.
- The layering diagram describes layers by family instead of
enumerating packages (the stale 'future plugins: hooks, compaction'
row is gone); the dependency rule defers to packages/README.md.
- The loop pseudocode, the three externally-cited anchors (the
vocabulary, event taxonomy, waterfall semantics), and the filename
are unchanged.
- Budget ratchet: docs/architecture.md 3897 -> 1800 (now 1,797 words);
the doc-tiers RFC's deferred list prunes the item this ships.
Applies the documentation standard to its biggest offender. Every rule
survives as one to three lines plus a link to its durable home; the
stories, duplicate statements, and re-narrations go:
- Situational clusters evict to new homes: docs/testing.md (tiers,
with-key policy, real-over-mock, world-verification, real-entry-path
guards), docs/defensive-patterns.md (the bug-class rules), and
docs/cookbook/responding-to-pr-review-on-a-stack.md (the stacked-PR
review procedure).
- Doc-authoring rules consolidate into docs/AGENTS.md § Writing rules
(current-state-never-history, md-wrap, ts-block compilation, @mode,
catalog same-change, pair same-change).
- packages/README.md drops to the group table + the extension-vs-bundle
dependency rule; the hand ASCII graph yields to the generated
module-graph.md; group READMEs are the canonical per-package map.
- packages/AGENTS.md keeps only its packages-specific rules (export
shape, ctx.get, real-Loader coverage); examples/AGENTS.md repoints
its with-key-policy link; rfc/README.md loses a narrated-history
aside; dsh-code-review / dsh-find-simplifications / verify-md-wrap
references follow the moved content.
- Budget manifest ratchets: AGENTS.md 8200 -> 1500 (now 1,495 words),
packages/README.md 1900 -> 600, packages/AGENTS.md 600 -> 450; the
two new eviction docs join the budget set (testing 800, defensive
550); docs/AGENTS.md raises 1000 -> 1250 for the absorbed writing
rules (the one justified increase). The doc-tiers RFC's deferred list
prunes the two items this change ships.
Standing docs accrete a paragraph per PR with nothing pushing back; the
root AGENTS.md reached 8,130 words in 50 commits with the same rule
stated two and three times. This encodes the counter-pressure:
- docs/AGENTS.md becomes the documentation standard: the tier taxonomy
(one home per fact), target word budgets, and the slop checklist.
- verify-doc-budgets joins doc-sync: word ceilings for the six
accretion-prone standing docs, manifest-driven, frozen at current
sizes and ratcheted down as each doc is brought to target.
- .agents/skills/dsh-doc-standards: the thin placement/audit/red-gate
workflow over the standard, mirroring the dsh-translate-docs split.
- RFC (implemented/process) records the decision, alternatives, and
the first audit cycle's deferred work list.
The gate's first catch was the standard itself (1,057 > 1,000); it
ships condensed to 984 words rather than with a raised ceiling.
Redesign per review: neither language is canonical. A pair is three
sibling files — foo.md, foo.zh.md, foo.i18n.yaml — and either language
may be authored first (a Chinese-first RFC is as legitimate as an
English-first one). The sidecar record holds the FULL git blob hash of
both sides as of the last confirmed-consistent state, replacing the
in-file one-directional fingerprint; editing either side without
re-confirming the pair goes red. New --write mode re-records a pair
after both sides are brought in line, making the confirmation a
reviewable yaml diff. Pairs merge whole (completeness enforced).
- gate rewritten around pair anchors (union of .zh.md and .i18n.yaml
remnants) so half-deleted pairs are caught from either side; red/green
proven for en-only edit, zh-only edit, missing record, and a record
for an excluded file
- verify-rfc-classification now skips .zh.md counterparts (same RFC,
indexed via its English filename; the pairing gate owns consistency)
- docs/i18n/README.md + translation-rules.md reframed bidirectionally
(terminology table binds both directions; typography section governs
the Chinese side); zh counterparts updated; skill workflow updated
- RFC amended to the shipped design, records the English-canonical
in-file-fingerprint model as considered-and-revised; RFC translated
(docs/rfc/.../2026-07-02-bilingual-docs-and-pairing-gate.zh.md) and
added to the required frontier
- generated docs stay excluded with the follow-up recorded: teach the
generators to emit Chinese, then de-list
Establish EN->ZH bilingual documentation for the README and docs tree:
- docs/i18n/README.md — the pairing contract: sibling foo.md <-> foo.zh.md,
English canonical, blob-hash source fingerprints, language switchers,
scope/exclusions, and a manifest-driven rollout ratchet.
- docs/i18n/translation-rules.md — how to translate: faithfulness, structure
preservation, terminology discipline over docs/i18n/terminology.md, and
typography rules grounded in MDN/K8s/Vue/clreq conventions.
- .agents/skills/dsh-translate-docs — the committed agent workflow, following
the dsh-code-review pattern of deferring to docs as sources of truth.
- scripts/verify-translation-pairing.ts + manifest — a doc-sync gate: required
pairs exist; every existing .zh.md is fresh (fingerprint = current source
blob), switcher-linked, structure-matched, and non-orphaned; excluded
(generated) docs stay unpaired. --list prints the translation work list.
- RFC (implemented/process) recording the decision and the alternatives.
- Dogfood: README.zh.md and the two i18n docs translated under their own rules.
Gates: doc-sync green including the new gate; red/green proven for stale
fingerprint, orphan, and excluded-file violations.
Replace the "bag of optional fields" tool-presentation types
(ToolCallPresentation / ToolResultPresentation / ToolTerminal) with a
card-tagged discriminated union — the standing FIXME(tool-presentation).
A tool declares one render intent per call/result and the ACP bridge
switches on `card`:
ToolCallView = generic | terminal | diff
ToolResultView = generic | terminal
The `diff` card is new: fs write/edit now emit an ACP {type:'diff'}
content block (an editor's inline diff), which the old shapes could not
express. The bridge also relativizes a file card's title against the
session cwd (mirroring claude-agent-acp's toDisplayPath) while keeping
locations/diff paths raw, and derives the no-capability fenced console
fallback from a terminal result's output. read gains the window-in-title
(`Read foo.txt (5 - 8)`) and an always-set location line, matching the
reference adapter field-for-field.
Migrates all three producer families (tool-fs, tool-bash, tool-todo) and
the sole consumer (the ACP bridge) together — the source does not compile
piecewise. Adds snapshot coverage for the terminal _meta path (a new
capability-advertising scenario) and re-records the fs goldens to show the
diff cards. Applied-hunk (result-time, context-line) diffs need a new
result/event shape and are a follow-up.
RFC: docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md
Round-1 Codex review findings on the tool-schema catalog:
(A) The shipped coding-agent / acp-agent configs load dsh-tool-subagent twice —
as `subagent` (spawn backend) and `subagent_fork` (fork backend) — so the model
sees a `subagent_fork` tool the catalog never mentioned, while the intro claimed
to list "the exact name the model receives". The registered name is the plugin's
load-time `toolName` config, not a package fact, so rather than bake an
example-app config into a packages-scoped generator, add a per-package deployment
`note`: the subagent entry now records the `subagent_fork` alias and points at the
leaf configs. Intro and RFC scope reworded to state the unit is the package (at
its default config), with aliases noted — no longer overclaiming. A test asserts
the note names `subagent_fork`, covering the config-driven-name path.
(B) collectToolCatalog only disposed the context on the success path; a throw from
mount/schemas() after earlier plugins mounted would leak the fiber. Move
`ctx.fiber.dispose()` into a `finally` per the repo's dispose-to-quiescence rule.
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
Honor cancellation and disposal around async pre-step setup before the loop can open a step or call the model.
Route compaction summarization through agent/request so router agents can select the model, and remove the stale model argument from agent/pre-step.
Document serial events and the approximate convergence bound, regenerate the Cordis catalog, and add regression coverage for router compaction, HMR cleanup, and assembly/pre-step interruption.
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.