Merge remote-tracking branch 'origin/master' into worktree-plugin-config-guideline

Master's docs-overhaul stack (#142-#144) rewrote AGENTS.md into the
slim budget-gated form and repointed the review skill's citations.
Resolutions:
- AGENTS.md: master's rewrite wins; the no-hardcoded-tunables
  convention is re-added as one terse bullet in the new style, after
  'Explicit > implicit at package seams'. Within the verify-doc-budgets
  ceiling, so no displacement or raise needed.
- dsh-code-review SKILL.md: master's repointed citations win; the
  hardcoded-tunables reviewer check and the Conventions keyword are
  re-applied on top.
- packages/README.md: master replaced the hand-maintained dependency
  list (which carried this branch's chars-per-token wording) with a
  pointer to the generated module graph — master's side taken whole;
  the estimator wording lives on in the compact package READMEs.
This commit is contained in:
Tianyi Cui
2026-07-04 18:32:52 +08:00
46 changed files with 530 additions and 586 deletions

View File

@@ -22,8 +22,8 @@ Independent judgment governs *what to look at* and *how to apply a rule to this
These define the conventions and gates this repo is checked against, and they are authoritative. Read them at the source so this skill never drifts out of sync — and apply judgment in *interpreting* them for the case at hand, not in deciding whether they apply.
- **[AGENTS.md](../../../AGENTS.md) § Conventions** — effect-based registrations, declaration-merging for events/ctx keys, waterfall `next()` discipline, discriminated-union match-don't-chain, explicit-over-implicit at seams, no hardcoded tunables in plugins, the empty-`catch` rule, symmetry.
- **AGENTS.md § Defensive patterns (hard-won)** — each bullet is a bug class that bit us. Reviewing anything touching process lifecycle, async/await, disposal, or adapter error paths? Re-read this first — then look for the *adjacent* mistake it doesn't name.
- **AGENTS.md § Type Safety and Documentation** — the doc-sync rule (code change ⇒ update README + JSDoc in the SAME commit) and the no-hard-wrap markdown convention.
- **[docs/defensive-patterns.md](../../../docs/defensive-patterns.md)** — each section is a bug class that bit us. Reviewing anything touching process lifecycle, async/await, disposal, or adapter error paths? Re-read this first — then look for the *adjacent* mistake it doesn't name.
- **AGENTS.md § Type safety and documentation + [docs/AGENTS.md](../../../docs/AGENTS.md)** — the doc-sync rule (code change ⇒ update README + JSDoc in the SAME commit) and the writing rules (current-state-never-history, one line per paragraph, one home per fact, the word-budget gate).
- **[packages/AGENTS.md](../../../packages/AGENTS.md)** — per-package conventions (file layout, the HMR-safety test requirement).
- **[docs/i18n/translation-rules.md](../../../docs/i18n/translation-rules.md) and [docs/i18n/terminology.md](../../../docs/i18n/terminology.md)** — the authoritative standard for bilingual-doc review: faithfulness, structure, typography, and the binding terminology table. For PRs touching translated docs or pending terms, read these before judging the translation; [dsh-translate-docs](../dsh-translate-docs/SKILL.md) is the translator workflow.
- **[RFC index](../../../docs/rfc/README.md)** — the *why* behind the architecture. Especially [quality gates](../../../docs/rfc/implemented/process/2026-06-11-quality-gates.md) (what a PR must pass) and [capability seams](../../../docs/rfc/implemented/architecture/2026-06-13-capability-seams.md) (the three-package split). If a change seems to fight an RFC, that's a discussion, not a silent override — and not an automatic veto either: an RFC can be wrong for this case, so reason about it.
@@ -35,20 +35,20 @@ These come straight from the source docs above. They are not discretionary; abse
1. **Docs in sync.** If the PR changes a config key, default, error code, wire field, or event name, it must update the package README + module/JSDoc in the same diff. The `doc-sync` gate (check #4) does not catch prose drift in config keys, defaults, error codes, or wire fields — that is on the reviewer, but it is still required, not optional.
2. **Core-data-structures catalog in sync.** If the PR adds, removes, or reshapes a type the [core-data-structures catalog](../../../docs/core-data-structures/core.md) documents — a new `…Map` variant, a new content-block/session-event type, a field on `GenerateOptions`/`Agent`/`ToolDefinition`/a bash type, or a whole new core/seam type — it must update that catalog in the same diff (prose + any verbatim ` ```ts type-equiv ` block + the 1:1 `scripts/type-equiv.manifest.json`). The `verify-type-equiv` gate (part of `doc-sync`) catches a *drifted paste* of an already-documented type, but it cannot tell you a brand-new core type went undocumented — that judgment is yours. Confirm a genuinely spine-level type landed in core.md and a new capability's vocabulary on a sub-page, per the spine-vs-seam line in [core.md § What counts as "core"](../../../docs/core-data-structures/core.md#what-counts-as-core). A pure internal type with no cross-package reach needs no catalog entry — say so if it's a judgment call.
3. **HMR-safety test.** Any new registry/registration needs a test that disposes the contributing fiber and asserts cleanup (packages/AGENTS.md). Its absence blocks merge.
4. **Quality gates pass.** typecheck, lint, test, test:coverage (100% per-file on `packages/*/src`), knip, build, publint, constraints, `doc-sync` (doc-typecheck + verify-cordis-catalog + verify-tool-catalog + verify-md-wrap + verify-md-links + verify-doc-refs + verify-package-paths + verify-rfc-classification + verify-type-equiv + verify-translation-pairing), module-graph freshness (the quality-gates RFC). Don't re-review what a gate already enforces — trust the gate and spend attention on what it can't check. Note that the `doc-sync` gate only covers compilable `ts` blocks, the generated cordis events/services catalog, markdown wrapping/links, verbatim type-equiv blocks, and the bilingual pairing contract ([docs/i18n/README.md](../../../docs/i18n/README.md)); prose drift (checks #1 and #2) and translation *quality* (the [dsh-translate-docs](../dsh-translate-docs/SKILL.md) rules) are *additional* manual review on top of it, not covered by it.
4. **Quality gates pass.** typecheck, lint, test, test:coverage (100% per-file on `packages/*/src`), knip, build, publint, constraints, `doc-sync` (the full gate list is the `doc-sync` script in the root `package.json`), module-graph freshness (the quality-gates RFC). Don't re-review what a gate already enforces — trust the gate and spend attention on what it can't check. Note that `doc-sync` only covers compilable `ts` blocks, generated-catalog freshness, markdown wrapping/links/refs, verbatim type-equiv blocks, word budgets, and the bilingual pairing contract ([docs/i18n/README.md](../../../docs/i18n/README.md)); prose drift (checks #1 and #2) and translation *quality* (the [dsh-translate-docs](../dsh-translate-docs/SKILL.md) rules) are *additional* manual review on top of it, not covered by it.
## Reviewer-only checks (gates can't catch these — judgment required)
Where your independent reasoning earns its keep. Start here, then keep going across the broader aspects above.
- **e2e verifies the world, not the agent's self-report.** For real-API tests, confirm the assertion re-runs the command/checks the file externally — a keyword probe lets a cheating agent pass (see AGENTS.md e2e bullet). For a behavior change to the agent's real flows, a no-key/mock test alone is usually insufficient: a with-key e2e (especially a smoke test that boots the real example and checks the world) is cheap here and catches "green units, broken product" — encourage it rather than treating real-API tests as expensive (see AGENTS.md § Secrets / .env).
- **e2e verifies the world, not the agent's self-report.** For real-API tests, confirm the assertion re-runs the command/checks the file externally — a keyword probe lets a cheating agent pass. For a behavior change to the agent's real flows, a no-key/mock test alone is usually insufficient: a with-key e2e (especially a smoke test that boots the real example and checks the world) is cheap here and catches "green units, broken product" — encourage it rather than treating real-API tests as expensive (see [docs/testing.md](../../../docs/testing.md)).
- **Plugin export shape + real-loader coverage.** A new/changed `cordis.yml`-loaded plugin: is it a function/namespace plugin (`name`/`inject`/`Config`/`apply` named exports) with NO `export default`? A stray default export makes the Loader's `unwrapExports` drop `inject` and the plugin crashes at load with `cannot get property … without inject` — invisible to hand-built `ctx.plugin({...})` tests and to line coverage. Confirm there's a test driving it through the REAL loader path (the no-key subprocess e2e for ACP is the model). And any opportunistic read of a service NOT in `static inject` should use `ctx.get(name)`, not `ctx.<name>` (the property proxy throws through a foreign shadow). See [packages/AGENTS.md](../../../packages/AGENTS.md) and [docs/postmortem/0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md).
- **Seam discipline.** New swappable capability? Check it's split per the capability-seams RFC (interface / impl / consumer), and that the consumer injects the interface key, never an implementation type.
- **Hardcoded tunables that should be plugin config.** A literal timeout, grace period, output/truncation cap, result-count limit, retry count, buffer size, model name, API base URL, user agent, or filesystem path introduced inside a plugin belongs on the plugin's schemastery `Config` with the shipped value as its default (AGENTS.md § Conventions "No hardcoded tunables in plugins"). A named `DEFAULT_*` constant or a test-only injection seam is not configurability — the question to ask is whether a `cordis.yml` deployment can change the value without a code edit. Protocol/wire constants, semantic constants, values pinned by an external spec, and security invariants are exempt; a new `Config` field also needs its README row and range validation. No gate detects a hardcoded tunable — this check is entirely on the reviewer.
- **Test quality — sufficiency, not just coverage.** 100% per-file coverage and a green suite are necessary, not sufficient: they prove the lines *ran*, not that the feature *works the way it ships*. Judge whether the tests are sufficient on two axes. (1) **Would they fail if the behavior regressed?** A test that passes but asserts the wrong thing — or restates the implementation instead of the contract (events fired, disposal reached, the world changed) — is worse than none. (2) **Do they exercise the REAL thing, the way it's actually used?** Prefer the genuine collaborator over a fake, drive the change through its real entry path (the cordis Loader, the ACP bridge, a booted subprocess — not a hand-built `ctx.plugin({...})` that bypasses `unwrapExports`), and verify the WORLD (re-read the file/log/registry externally), not the agent's self-report. A test that fakes the inputs just enough to cover every line will agree with whatever the author assumed; the real thing won't. When a test sets up a *clean/happy* path to reach a line, ask whether the line's PURPOSE is exercised — e.g. a durability/teardown path "tested" by a fully-completed turn never proves the mid-flight teardown it exists for; a torn-tail recovery branch covered by a well-formed log never proves recovery. Flag tests that hit the line but not the scenario. See AGENTS.md § Defensive patterns "Line coverage is not behavior coverage" and "Prefer the REAL implementation over a mock/stand-in in tests".
- **Test quality — sufficiency, not just coverage.** 100% per-file coverage and a green suite are necessary, not sufficient: they prove the lines *ran*, not that the feature *works the way it ships*. Judge whether the tests are sufficient on two axes. (1) **Would they fail if the behavior regressed?** A test that passes but asserts the wrong thing — or restates the implementation instead of the contract (events fired, disposal reached, the world changed) — is worse than none. (2) **Do they exercise the REAL thing, the way it's actually used?** Prefer the genuine collaborator over a fake, drive the change through its real entry path (the cordis Loader, the ACP bridge, a booted subprocess — not a hand-built `ctx.plugin({...})` that bypasses `unwrapExports`), and verify the WORLD (re-read the file/log/registry externally), not the agent's self-report. A test that fakes the inputs just enough to cover every line will agree with whatever the author assumed; the real thing won't. When a test sets up a *clean/happy* path to reach a line, ask whether the line's PURPOSE is exercised — e.g. a durability/teardown path "tested" by a fully-completed turn never proves the mid-flight teardown it exists for; a torn-tail recovery branch covered by a well-formed log never proves recovery. Flag tests that hit the line but not the scenario. See [docs/testing.md](../../../docs/testing.md) § "Test the real entry path" and § "Prefer the real implementation over a mock".
- **Snapshot coverage for transcript/UX changes.** If the PR changes the editor-facing transcript or end-to-end agent UX — the ACP bridge's event→update translation, the agent loop's observable output, tool presentation, or anything an editor renders — it must add or update a snapshot scenario (`examples/*/tests/**/*.snapshot.ts`, goldens under `examples/acp-agent/tests/snapshots/`) or note explicitly why none applies (AGENTS.md § Conventions). Review the golden diff itself: a changed `stdout.golden.txt` / `session.golden.txt` is a behavior change in disguise — confirm it's intended, not an accidental regression someone re-recorded away. A pure internal refactor with no observable-output change is exempt, but the PR should say so. See [docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md](../../../docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md).
- **Bilingual docs: review translation quality, not just pairing.** If the PR adds or edits a doc pair, read the changed English and Chinese sides and compare the meaning, not only the mechanical diff. Verify terms against [terminology.md](../../../docs/i18n/terminology.md), including first-occurrence annotations and "do not translate as" prohibitions; if a new term has no established precedent, the PR should keep it in English, list it under `待定术语`, and update the terminology table once the rendering is decided. A green `verify-translation-pairing` only proves hashes, switchers, and structure were recorded — it does not prove the translation is faithful, natural, or correctly termed. Treat [translation-rules.md](../../../docs/i18n/translation-rules.md) MUST/MUST NOT violations as blocking.
- **Intent and contracts.** Does the change do what the PR says, and honor the documented contract on *both* sides of every seam it touches (see AGENTS.md "Honor cross-seam contracts on BOTH sides")?
- **Intent and contracts.** Does the change do what the PR says, and honor the documented contract on *both* sides of every seam it touches (see [docs/defensive-patterns.md](../../../docs/defensive-patterns.md) "Honor cross-seam contracts on BOTH sides")?
## How to respond

View File

@@ -0,0 +1,47 @@
---
name: dsh-doc-standards
description: 'Use when writing, moving, reviewing, or auditing documentation in the deepseek-harness repo — choosing where content belongs, trimming doc slop, responding to a verify-doc-budgets gate failure, or requests like "improve the docs", "audit the docs for slop", "where should this be documented", "this doc is too long".'
---
# Applying the DeepSeek Harness Documentation Standard
The contract lives in [docs/AGENTS.md](../../../docs/AGENTS.md) — the tier taxonomy, the word budgets, and the slop checklist. This skill is the workflow for applying it: placing content, auditing the corpus, and handling a red budget gate. It is guidance, not a script; keep judgment active and prefer a few well-proven fixes over a mass rewording pass.
## Sources of truth (read, don't re-summarize)
- [docs/AGENTS.md](../../../docs/AGENTS.md) — the taxonomy ("one home per fact"), budgets, slop checklist.
- [docs/rfc/README.md](../../../docs/rfc/README.md) — when a decision earns an RFC and how to file it; [docs/postmortem/README.md](../../../docs/postmortem/README.md) — when an incident earns a postmortem.
- [docs/i18n/README.md](../../../docs/i18n/README.md) — the bilingual pairing contract; editing either side of a pair obligates the counterpart in the same change.
- Root [AGENTS.md](../../../AGENTS.md) — the standing orders whose budget discipline this skill protects.
## Placing content
Run the placement test in the standard's taxonomy table, then check the constraints that make a placement expensive or wrong:
- Paired docs (`pnpm run verify-translation-pairing --list`) cost a zh counterpart update and a `--write` re-record on every edit — prefer an unpaired home for content that will churn.
- Generated catalogs are never hand-edited; if the fact belongs there, change the generator's source.
- Before renaming or moving any doc, grep for inbound references: `verify-md-links` catches Markdown links, `verify-doc-refs` catches `docs/*.md` citations in TypeScript comments, but nothing catches heading-anchor fragments — grep `#the-heading` across the repo yourself (one anchor is hardcoded in `scripts/gen-cordis-catalog.ts`).
- A move is atomic: remove from the old home, add to the new home, and fix every inbound link in the same change.
## Auditing the corpus
The audit is a hunt for the standard's slop checklist, cheapest probes first:
1. Measure: `pnpm run verify-doc-budgets --list`, then `git ls-files '*.md' | grep -v '^vendor/' | xargs wc -w | sort -rn | head -30` to spot unbudgeted outliers.
2. Hunt narrated history: `rg -n -g '!vendor' -t md "no longer|used to|previously|was moved|renamed"` — judge each hit; some are legitimate (quoting a contrast against a live alternative), most are drift.
3. Hunt duplication: take each standing-doc rule, grep one distinctive phrase from it across all Markdown; more than one home means all but one become links.
4. Hunt catalog restatement: compare README event/tool tables against the generated catalogs and JSDoc; hand copies get replaced by links.
5. Hunt spec-speak in `implemented/` RFCs: migration plans, test checklists, future-tense "should" — an implemented RFC describes what is.
6. Classify each finding: a mechanical trim lands as a small PR; a restructure or removal that changes what a doc promises gets a proposed RFC first (follow [dsh-find-simplifications](../dsh-find-simplifications/SKILL.md) for the RFC shape).
Compression discipline: every load-bearing rule survives — as one to three lines plus a link to the home that carries its why. Cut stories, duplicates, and status annotations; never silently drop a rule. If a cut rule has no durable home to link, create it (usually an RFC or postmortem) in the same change.
## When verify-doc-budgets goes red
1. Relocate: does the new content belong in a linked home (RFC, postmortem, cookbook, README) with a one-line pointer left behind?
2. Condense: can existing prose in the doc pay for the addition — a story compressed to its rule, a duplicate converted to a link?
3. Only then raise the ceiling: edit `scripts/doc-budgets.manifest.json` and justify the raise explicitly in the PR description. After any rewrite that shrinks a budgeted doc, ratchet its ceiling down to the new size plus working headroom (at least 5%) in the same PR.
## Validation and PR hygiene
For docs-only changes run at least `pnpm run doc-sync`, `pnpm run lint`, and `git diff --check`; if a paired doc was touched, update the counterpart (see [dsh-translate-docs](../dsh-translate-docs/SKILL.md)) and re-record with `pnpm run verify-translation-pairing --write`. Open a draft PR while the audit is still expanding; in the PR body, list what was trimmed/moved with word deltas, what was deliberately kept long and why, and which checks ran. The first audit cycle's deferred work list lives in [the doc-tiers-and-budgets RFC](../../../docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md) § Deferred work.

View File

@@ -9,7 +9,7 @@ This skill helps turn a broad "find things to simplify" request into evidence-ba
## Start With Repo Context
- Read `AGENTS.md`, especially the pre-release stance, tests-document-behavior section, conventions, defensive patterns, and Type Safety and Documentation section.
- Read `AGENTS.md`, especially the pre-release stance and the conventions (including the tests-are-not-golden-truth and RFCs-are-not-golden-truth doctrines), plus [docs/defensive-patterns.md](../../../docs/defensive-patterns.md) and [docs/testing.md](../../../docs/testing.md).
- Skim [docs/architecture.md](../../../docs/architecture.md) before judging anything under `packages/`; simplifications that fight the service map or event taxonomy need extra evidence.
- Use the RFC index ([docs/rfc/README.md](../../../docs/rfc/README.md)) to understand intentional architecture. The most relevant implemented examples are [drop mutable session summary](../../../docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md), [shared persistence write coordinator](../../../docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md), [capability seams](../../../docs/rfc/implemented/architecture/2026-06-13-capability-seams.md), and the twin adapter / dual persistence backend RFCs.
- Treat dual LLM adapters and dual persistence backends as intentional by default. Do not propose deleting either twin/backend as "low effort" unless the user explicitly overrides that constraint. Removing an unused method or hook inside a protected seam can still be valid if it does not collapse the protected design.