From aa36b3b36bcb46ef3c9d37b23c3145439fd7bf1a Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sat, 4 Jul 2026 13:53:43 +0800 Subject: [PATCH 1/4] feat(doc-standards): documentation tiers, budgets, and the ceiling gate 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. --- .agents/skills/dsh-doc-standards/SKILL.md | 47 ++++++++++++ docs/AGENTS.md | 55 +++++++++++--- docs/development.i18n.yaml | 4 +- docs/development.md | 3 +- docs/development.zh.md | 3 +- docs/rfc/README.md | 1 + .../2026-07-04-doc-tiers-and-budgets.md | 36 +++++++++ package.json | 3 +- scripts/doc-budgets.manifest.json | 8 ++ scripts/verify-doc-budgets.ts | 76 +++++++++++++++++++ 10 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 .agents/skills/dsh-doc-standards/SKILL.md create mode 100644 docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md create mode 100644 scripts/doc-budgets.manifest.json create mode 100644 scripts/verify-doc-budgets.ts diff --git a/.agents/skills/dsh-doc-standards/SKILL.md b/.agents/skills/dsh-doc-standards/SKILL.md new file mode 100644 index 0000000000..f981af9ace --- /dev/null +++ b/.agents/skills/dsh-doc-standards/SKILL.md @@ -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 modest headroom 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. diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 7571209aa2..52ac672225 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -1,15 +1,50 @@ -# AGENTS.md — Docs +# AGENTS.md — The documentation standard -Conventions for authoring everything under `docs/` (architecture, RFCs, cookbook, ADRs-now-RFCs). The repo-wide Markdown rules in the root [AGENTS.md](../AGENTS.md) § "Type Safety and Documentation" still apply (one physical line per paragraph, fenced `ts` blocks must compile); the points below are docs-specific. +This file is the contract for every Markdown surface in the repo: what each documentation tier is for, what belongs elsewhere, and the word budgets the `verify-doc-budgets` gate enforces. The repo-wide writing rules live in the root [AGENTS.md](../AGENTS.md) § "Type Safety and Documentation" and apply to everything here. The audit/apply workflow is the [dsh-doc-standards](../.agents/skills/dsh-doc-standards/SKILL.md) skill; the decision record is [the doc-tiers-and-budgets RFC](rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md). + +## The tier taxonomy: one home per fact + +Every fact has exactly one home — the tier whose job it is — and every other place that needs it links there instead of restating it. A rule restated in two files drifts word-by-word until the copies disagree; a link cannot drift, and `verify-md-links` keeps it resolving. + +| Tier | Job | Does NOT belong there | +|---|---|---| +| Root `AGENTS.md` | Standing orders: rules an agent needs in context in every session, one to three lines each, linking its home | Stories, worked examples, situational procedures, anything restated from a linked home | +| Subtree `AGENTS.md` (`packages/`, `examples/`, `docs/`) | Orders specific to that subtree | Repo-wide rules the root file already carries | +| [architecture.md](architecture.md) | The system map: layering, services, the loop, extension seams — read before changing `packages/` | Type shapes (→ core-data-structures), per-package detail (→ package READMEs), decision rationale (→ RFCs), implementation-status annotations | +| [core-data-structures/](core-data-structures/core.md) | The type catalog: literal shapes and semantics of the spine and seam vocabulary | Behavior narration (→ architecture.md) | +| [rfc/](rfc/README.md) | Decision records: the why and the what-was-given-up; `implemented/` RFCs describe shipped reality in present tense | Migration plans, test checklists, and spec-speak ("should…") once the decision has shipped | +| [postmortem/](postmortem/README.md) | Incident stories — the only tier where war-story narrative belongs | — | +| [cookbook/](cookbook/adding-a-package.md) | Step-by-step how-tos with numbered verify steps | Design rationale (→ the RFC each guide links) | +| Package README | The per-package contract: config, semantics, limitations, extension points | JSDoc restatement, generated-catalog restatement (event/tool tables), other packages' concerns | +| [development.md](development.md) | Human-facing setup and daily workflow; a bilingual pair under the [i18n contract](i18n/README.md) | Gate-by-gate enumerations that drift from `package.json` scripts | +| Generated catalogs: [cordis-catalog](cordis-catalog/events-and-services.md), [tool-catalog](tool-catalog/tools.md), [module-graph.md](module-graph.md) | Exhaustive enumerations regenerated from source, freshness-gated | Hand edits of any kind | +| Skills (`.agents/skills/`) | Workflows: how to carry out a recurring task against the contracts | The contracts themselves (→ docs) | + +Placement test: a story about a bug → postmortem. Why we chose X → RFC. How to do task Y → cookbook. What type Z looks like → core-data-structures. What package P promises → its README. A rule every agent must always obey → root AGENTS.md, one line, linking the home that holds the why. + +## Budgets and the ceiling gate + +Standing docs accrete: every PR has a lesson it wants to append, and without displacement pressure nothing ever leaves. The gate is that pressure. [scripts/doc-budgets.manifest.json](../scripts/doc-budgets.manifest.json) lists the accretion-prone standing docs with a word ceiling each; `pnpm run verify-doc-budgets` (part of `doc-sync`, so CI and pre-push run it) fails when a doc exceeds its ceiling, and fails when a budgeted file is missing so a rename cannot orphan its budget. + +- Ceilings are an enforcement frontier: a ceiling starts at the doc's current size (freezing further growth) and ratchets down as the doc is brought to its target. Target budgets: root `AGENTS.md` ≤ 1,500 words; `architecture.md` ≤ 1,800; each subtree `AGENTS.md` ≤ 600, except this file (which carries the standard) ≤ 1,000; `packages/README.md` ≤ 600. +- When the gate goes red, the fix is to relocate or condense per the taxonomy above. Raising a ceiling is the last resort: the PR description must justify it, and the manifest diff is the reviewable act. +- Unbudgeted tiers (package READMEs, RFCs, reference matrices) have no ceiling — length is legitimate there when every row is a fact. Review and the slop checklist govern them instead. + +## The slop checklist + +Hunt these in any doc you write or review; the [dsh-doc-standards](../.agents/skills/dsh-doc-standards/SKILL.md) skill runs this list as an audit: + +- The same rule stated in more than one home. Grep a distinctive phrase; keep one home, convert the rest to links. +- Narrated history: "previously", "now", "no longer", "used to", "renamed", "was moved", references to PRs or commits. State the current fact; the why belongs in an RFC, the story in a postmortem or git. +- A war story told inline where a one-line rule plus a postmortem/RFC link would do. +- Implementation-status annotations in prose or diagrams ("implemented!", "future: …"). Status rots; the repo layout and package manifests carry it. +- Hand-restating a generated catalog or JSDoc: event tables, tool arg tables, method signatures. Link instead. +- Paragraph walls: one paragraph carrying several rules and parenthetical asides. Split it, or demote the detail to the linked home. +- Emphasis inflation: bold, CAPS, or "critically" everywhere means nothing stands out. Reserve emphasis for the clause that changes behavior. +- Spec-speak in `implemented/` RFCs: "should", migration plans, acceptance checklists. An implemented RFC describes what is, per [rfc/implemented/AGENTS.md](rfc/implemented/AGENTS.md). ## Cross-reference with machine-checkable links, never free prose -When one doc refers to another doc, an RFC, a package README, or any file in the repo, link it with a **relative Markdown link** to the actual path — `[capability seams](rfc/implemented/architecture/2026-06-13-capability-seams.md)`, `[architecture.md](architecture.md)`. Do NOT refer to it by bare prose or by a number ("see ADR 0009", "per RFC 005"): a number is not checkable, goes stale the moment a file is renamed, and forces the reader to go hunting. A relative link is verified mechanically — `pnpm run verify-md-links` (part of `doc-sync`, see [the cross-link lint RFC](rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md)) fails CI and the pre-push hook if any relative target does not exist, so a rename that orphans a link is caught before review rather than rotting silently. +When one doc refers to another doc, an RFC, a package README, or any file in the repo, link it with a relative Markdown link to the actual path — never bare prose or a number ("see RFC 005"), which is uncheckable and rots on rename. `pnpm run verify-md-links` (part of `doc-sync`; see [the cross-link lint RFC](rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md)) fails when a relative target does not exist, so a rename that orphans a link is caught before review. This is also why RFC files carry dates and topics instead of stable numbers: they survive moves between lifecycle and class folders without dangling references. -This is why the RFC tree carries no stable numbers: files are named `yyyy-mm-dd-topic-title.md` and referred to by link, so they survive moves between lifecycle folders (`proposed/`/`implemented/`/`rejected/`) and class folders without a dangling reference. When you move or rename a doc, the gate tells you every inbound link you still need to fix. - -The gate checks file *existence*, not `#anchor` validity — a link to a real file with a wrong heading fragment still passes. Prefer linking the file (and a heading when it helps the reader), but don't rely on the gate to catch a stale anchor. - -## RFCs - -Design decisions and proposals live in [rfc/](rfc/) — one kind of doc, grouped by lifecycle (`proposed/`/`implemented/`/`rejected/`) then by class (`feature`/`bug-fix`/`simplification`/`architecture`/`process`/`testing`). See [rfc/README.md](rfc/README.md) for the class definitions, the naming scheme, and when to write one. +The gate checks file existence, not `#anchor` validity — a stale heading fragment on a real file still passes, so verify anchors yourself when linking to one. diff --git a/docs/development.i18n.yaml b/docs/development.i18n.yaml index 4b9823584b..d8f76162db 100644 --- a/docs/development.i18n.yaml +++ b/docs/development.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -development.md: 3e11ae594759e6251e46f3bf9e0b021d9e1555c5 -development.zh.md: e8cea20a713767411304c2a3c97099004b9392c3 +development.md: 28babca2b59c844690750d767c242c08c37bf702 +development.zh.md: b34c52cebd3f333b6554ca2b5ebd66463e436572 diff --git a/docs/development.md b/docs/development.md index 3e11ae5947..28babca2b5 100644 --- a/docs/development.md +++ b/docs/development.md @@ -100,7 +100,8 @@ pnpm run gen-cordis-catalog # regenerate docs/cordis-catalog/events-and-serv pnpm run verify-cordis-catalog # fail if the cordis events/services catalog is stale pnpm run verify-md-wrap # fail on hard-wrapped prose paragraphs in docs/README markdown pnpm run verify-type-equiv # fail if a ```ts type-equiv doc block drifts from its source type -pnpm run doc-sync # doc-typecheck, cordis-catalog freshness, markdown wrap/link, and type-equiv verification +pnpm run verify-doc-budgets # fail if a budgeted standing doc exceeds its word ceiling +pnpm run doc-sync # all Markdown/doc gates; see the doc-sync script in package.json for the full list pnpm run gen-module-graph # regenerate docs/module-graph.md from package peerDeps pnpm run verify-module-graph # fail if docs/module-graph.md is stale pnpm run build # emit lib/types intermediates, then bundle lib/index.* runtime files diff --git a/docs/development.zh.md b/docs/development.zh.md index e8cea20a71..b34c52cebd 100644 --- a/docs/development.zh.md +++ b/docs/development.zh.md @@ -100,7 +100,8 @@ pnpm run gen-cordis-catalog # regenerate docs/cordis-catalog/events-and-serv pnpm run verify-cordis-catalog # fail if the cordis events/services catalog is stale pnpm run verify-md-wrap # fail on hard-wrapped prose paragraphs in docs/README markdown pnpm run verify-type-equiv # fail if a ```ts type-equiv doc block drifts from its source type -pnpm run doc-sync # doc-typecheck, cordis-catalog freshness, markdown wrap/link, and type-equiv verification +pnpm run verify-doc-budgets # fail if a budgeted standing doc exceeds its word ceiling +pnpm run doc-sync # all Markdown/doc gates; see the doc-sync script in package.json for the full list pnpm run gen-module-graph # regenerate docs/module-graph.md from package peerDeps pnpm run verify-module-graph # fail if docs/module-graph.md is stale pnpm run build # emit lib/types intermediates, then bundle lib/index.* runtime files diff --git a/docs/rfc/README.md b/docs/rfc/README.md index e534080bf4..df1894ab57 100644 --- a/docs/rfc/README.md +++ b/docs/rfc/README.md @@ -154,6 +154,7 @@ Do NOT write one for a mechanical or local choice (a variable name, a one-file r | [Classify RFCs by kind via path-encoded subdirectories](implemented/process/2026-06-20-rfc-classification.md) | 2026-06-20 | | [Generated tool-schema catalog (boot-and-harvest)](implemented/process/2026-07-02-tool-schema-catalog.md) | 2026-07-02 | | [Bilingual documentation via paired sibling files and a pairing gate](implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md) | 2026-07-02 | +| [Documentation tiers, budgets, and the ceiling gate](implemented/process/2026-07-04-doc-tiers-and-budgets.md) | 2026-07-04 | ### Testing diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md new file mode 100644 index 0000000000..8c5c62ed58 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md @@ -0,0 +1,36 @@ +# Documentation tiers, budgets, and the ceiling gate + +## Context + +The repo's standing docs accrete. Root `AGENTS.md` reached 8,130 words through 50 commits in two and a half weeks — each PR appending its own lesson, none displacing anything — until the same rule was stated two or three times inside one file (the pushed-branch rewrite ban ~600 words across two sections; the with-key e2e policy ~400 words across two), an incident already recorded in [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) was retold inline at ~750 words, and the per-package one-liner map existed in five places. [architecture.md](../../../architecture.md) grew the same way: paragraph walls re-narrating RFCs it already links, plus implementation-status annotations that were stale the week after they were written. The writing rules that forbid this (document current state, never history) predate the drift and sat in the very file violating them — prose rules alone do not hold against accretion pressure. The repo's standing answer to an invariant of this kind is a mechanical check ([quality gates](2026-06-11-quality-gates.md), [doc-sync enforcement](2026-06-11-doc-sync-enforcement.md)). + +## Decision + +- **A tier taxonomy with one home per fact.** [docs/AGENTS.md](../../../AGENTS.md) is the documentation standard: it assigns every Markdown tier a single job (standing orders, system map, type catalog, decision records, incident stories, how-tos, per-package contracts, generated catalogs, workflows), forbids restating a fact outside its home tier (link instead), and carries the slop checklist used when writing or reviewing any doc. +- **A narrow, hard budget gate.** [scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) joins `doc-sync`: every doc listed in [scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) must stay under its word ceiling (`wc -w` semantics, whole file), and a budgeted file that is missing fails the gate so a rename cannot silently orphan its budget. Scope is deliberately only the accretion-prone standing docs — the root and subtree `AGENTS.md` files, `architecture.md`, `packages/README.md`. Reference docs, RFCs, and package READMEs are unbudgeted: length is legitimate there when every row is a fact, and review plus the slop checklist govern them. +- **Ceilings are an enforcement frontier that ratchets.** A ceiling starts at the doc's current size, freezing growth from day one, and ratchets down as the doc is brought to its target budget (root `AGENTS.md` ≤ 1,500 words; `architecture.md` ≤ 1,800; subtree `AGENTS.md` ≤ 600; `packages/README.md` ≤ 600) — the same rollout mechanism as the [translation-pairing `required` list](2026-07-02-bilingual-docs-and-pairing-gate.md). When the gate goes red the fix is to relocate or condense per the taxonomy; raising a ceiling is permitted only with explicit justification in the PR description, the manifest diff being the reviewable act. +- **A thin workflow skill, contracts in docs.** [.agents/skills/dsh-doc-standards](../../../../.agents/skills/dsh-doc-standards/SKILL.md) carries the placement/audit/red-gate workflow and defers to the standard as its source of truth, the same split as [dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md) over the i18n contract. + +## Alternatives considered + +- **Skill and review discipline without a gate** — rejected: the accretion above happened while the current-state rule and reviewer attention already existed; a prose rule with no mechanical backstop demonstrably does not hold here, and this repo's own [quality-gates stance](2026-06-11-quality-gates.md) says invariants worth keeping are worth encoding. +- **A broad gate over every doc tier** — rejected: a blanket ceiling punishes exactly the right kind of long doc (a feature matrix or type catalog where every row is a fact, e.g. `packages/ui/acp/acp-feature-support.md`) and generates per-file override churn that trains contributors to rubber-stamp raises. +- **Housing the standard inside the skill** — rejected: contracts live in docs and workflows in skills; a standard packed into SKILL.md is invisible to an agent that edits docs without invoking the skill, and `docs/AGENTS.md` already loads as subtree instructions for anyone working under `docs/`. + +## Consequences + +- Adding to a budgeted doc now requires displacement: relocate the addition to its taxonomy home with a pointer, or condense existing prose to pay for it. Growth without pruning fails CI. +- The bring-under-target rewrites land as stacked follow-ups that ratchet the manifest down as they merge; until each lands, its doc's frozen ceiling only prevents further growth. +- Word count is a crude proxy accepted deliberately: it cannot judge quality, but it forces the relocation decision at exactly the moment content is being added, which is when the author has the context to place it correctly. + +## Deferred work + +The first audit cycle under the standard, in rough priority order (evidence gathered in the survey that motivated this RFC): + +- Root `AGENTS.md` rewrite to the ≤ 1,500-word target: rules stay as one-liners plus links; situational clusters move to `docs/testing.md`, `docs/defensive-patterns.md`, and a cookbook guide for responding to review across a stacked PR chain; doc-authoring rules consolidate into `docs/AGENTS.md`. +- `architecture.md` rewrite to the ≤ 1,800-word target: seam narration compressed to pointers, the MVP feature-to-mechanism checklist moved de-statused into [the extension cookbook](../../../cookbook/extension-cookbook.md), the stale layering-diagram row fixed. +- `packages/README.md` reduced to the group table plus the dependency rule; the hand-maintained ASCII dependency graph yields to the generated [module-graph.md](../../../module-graph.md); group READMEs become the canonical per-package map. +- Package README trims where generated catalogs or JSDoc are restated or history is narrated: `packages/ui/acp`, `packages/core/tools`, `packages/bash/tool-bash`, `packages/core/session`, `packages/compact/compact-basic`, `packages/session-persistence/session-persistence`. +- [The web capability seam RFC](../architecture/2026-06-24-web-capability-seam.md) converted from spec-speak to shipped reality (drop the migration plan and test enumeration, "should" → "is"). +- `docs/core-data-structures/core.md`: drop the JSDoc walls from the `Agent`/`GenerateOptions` type-equiv pastes per that page's own stated rule. +- [Postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md): merge the overlapping Executive summary and Summary sections. diff --git a/package.json b/package.json index 893b0059f6..9257eb2ac9 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "verify-rfc-classification": "tsx scripts/verify-rfc-classification.ts", "verify-type-equiv": "tsx scripts/verify-type-equiv.ts", "verify-translation-pairing": "tsx scripts/verify-translation-pairing.ts", + "verify-doc-budgets": "tsx scripts/verify-doc-budgets.ts", "verify-node-next-types": "tsx scripts/verify-node-next-types.ts", "gen-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts", "verify-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts --check", @@ -40,7 +41,7 @@ "gen-module-graph": "tsx scripts/gen-module-graph.ts", "verify-module-graph": "tsx scripts/gen-module-graph.ts --check", "constraints": "tsx scripts/check-workspace-constraints.ts", - "doc-sync": "pnpm run doc-typecheck && pnpm run verify-cordis-catalog && pnpm run verify-tool-catalog && pnpm run verify-md-wrap && pnpm run verify-md-links && pnpm run verify-doc-refs && pnpm run verify-package-paths && pnpm run verify-rfc-classification && pnpm run verify-type-equiv && pnpm run verify-translation-pairing", + "doc-sync": "pnpm run doc-typecheck && pnpm run verify-cordis-catalog && pnpm run verify-tool-catalog && pnpm run verify-md-wrap && pnpm run verify-md-links && pnpm run verify-doc-refs && pnpm run verify-package-paths && pnpm run verify-rfc-classification && pnpm run verify-type-equiv && pnpm run verify-translation-pairing && pnpm run verify-doc-budgets", "hygiene": "pnpm run knip && pnpm run publint && pnpm run constraints && pnpm run verify-node-next-types", "demo:echo": "node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/echo-agent/cordis.yml", "demo:repl": "node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/coding-agent/cordis.yml", diff --git a/scripts/doc-budgets.manifest.json b/scripts/doc-budgets.manifest.json new file mode 100644 index 0000000000..0f0e3b40bf --- /dev/null +++ b/scripts/doc-budgets.manifest.json @@ -0,0 +1,8 @@ +{ + "AGENTS.md": 8200, + "docs/AGENTS.md": 1000, + "docs/architecture.md": 3950, + "examples/AGENTS.md": 600, + "packages/AGENTS.md": 600, + "packages/README.md": 1900 +} diff --git a/scripts/verify-doc-budgets.ts b/scripts/verify-doc-budgets.ts new file mode 100644 index 0000000000..a64275e9fa --- /dev/null +++ b/scripts/verify-doc-budgets.ts @@ -0,0 +1,76 @@ +/** + * Doc-sync gate: enforce word-count ceilings on the standing docs that accrete + * (docs/AGENTS.md § "Budgets and the ceiling gate"). Instruction files and the + * architecture overview grow a paragraph per PR unless something pushes back; + * this gate is the pushback — when a ceiling is hit, the fix is to relocate or + * condense per the documentation standard, not to raise the ceiling. Raising a + * ceiling is allowed but is a deliberate, reviewable manifest diff that the PR + * description must justify. + * + * Scope is deliberately NARROW: only the files listed in + * scripts/doc-budgets.manifest.json (path → max words). Reference docs, RFCs, + * and package READMEs are unbudgeted — length is legitimate there (a feature + * matrix is the right kind of long), and the standard governs them through + * review, not a ceiling. + * + * The manifest is an enforcement frontier, i18n-rollout style: ceilings start + * at a doc's current size (freezing further growth) and ratchet DOWN as the + * doc is brought to its target budget. A manifest entry whose file is missing + * fails the gate, so a rename cannot silently orphan its budget. + * + * Words are counted `wc -w` style over the whole file (whitespace-delimited + * tokens, fenced code included) so a ceiling is reproducible with standard + * tools. This is a checker, not a formatter: it reports and never rewrites. + * + * Run: `tsx scripts/verify-doc-budgets.ts` (or `--list` to print every + * budgeted doc's current count vs ceiling without failing). + */ + +import { existsSync, readFileSync } from 'node:fs' +import { resolve } from 'node:path' + +const root = resolve(import.meta.dirname, '..') + +const MANIFEST_PATH = resolve(root, 'scripts/doc-budgets.manifest.json') + +/** `wc -w` equivalent: count whitespace-delimited tokens. */ +function countWords(text: string): number { + return text.split(/\s+/).filter(Boolean).length +} + +const manifest = JSON.parse(readFileSync(MANIFEST_PATH, 'utf8')) as Record + +const listOnly = process.argv.includes('--list') +const failures: string[] = [] +const rows: string[] = [] + +for (const [path, ceiling] of Object.entries(manifest)) { + if (!Number.isInteger(ceiling) || ceiling <= 0) { + failures.push(`${path}: ceiling must be a positive integer, got ${ceiling}`) + continue + } + const abs = resolve(root, path) + if (!existsSync(abs)) { + failures.push(`${path}: budgeted file does not exist (renamed or deleted? update scripts/doc-budgets.manifest.json in the same change)`) + continue + } + const words = countWords(readFileSync(abs, 'utf8')) + rows.push(`${words <= ceiling ? 'ok ' : 'OVER'} ${String(words).padStart(6)} / ${String(ceiling).padEnd(6)} ${path}`) + if (words > ceiling) { + failures.push(`${path}: ${words} words exceeds the ${ceiling}-word ceiling — relocate or condense per docs/AGENTS.md (raising the ceiling requires justification in the PR)`) + } +} + +if (listOnly) { + console.log(rows.join('\n')) + process.exit(0) +} + +if (failures.length > 0) { + console.error('verify-doc-budgets failed:\n') + for (const failure of failures) console.error(` ${failure}`) + console.error('\nSee docs/AGENTS.md for the documentation standard and the relocation-first rule.') + process.exit(1) +} + +console.log(`verify-doc-budgets: ${Object.keys(manifest).length} budgeted docs within ceiling.`) From 65690d8cf10c3904d8c1477647fe1c8e7c716162 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sat, 4 Jul 2026 14:27:49 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix(doc-budgets):=20address=20Codex=20revie?= =?UTF-8?q?w=20=E2=80=94=20exact-freeze=20ceilings,=20list=20missing=20ent?= =?UTF-8?q?ries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The manifest now freezes each budgeted doc at its exact current wc -w count, matching the documented policy (a ceiling starts at the doc's current size); the headroom that contradicted the freeze claim is gone. Post-rewrite ratchets may still land at new-size-plus-headroom, per the skill's ratchet rule — that is a different moment than the initial freeze. - --list now renders MISS/BAD rows for missing files and malformed ceilings instead of silently dropping them (gate mode already failed correctly; the report mode no longer under-reports). --- scripts/doc-budgets.manifest.json | 12 ++++++------ scripts/verify-doc-budgets.ts | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/doc-budgets.manifest.json b/scripts/doc-budgets.manifest.json index 0f0e3b40bf..afcff11e2c 100644 --- a/scripts/doc-budgets.manifest.json +++ b/scripts/doc-budgets.manifest.json @@ -1,8 +1,8 @@ { - "AGENTS.md": 8200, - "docs/AGENTS.md": 1000, - "docs/architecture.md": 3950, - "examples/AGENTS.md": 600, - "packages/AGENTS.md": 600, - "packages/README.md": 1900 + "AGENTS.md": 8130, + "docs/AGENTS.md": 982, + "docs/architecture.md": 3897, + "examples/AGENTS.md": 579, + "packages/AGENTS.md": 577, + "packages/README.md": 1856 } diff --git a/scripts/verify-doc-budgets.ts b/scripts/verify-doc-budgets.ts index a64275e9fa..fb27e84473 100644 --- a/scripts/verify-doc-budgets.ts +++ b/scripts/verify-doc-budgets.ts @@ -46,11 +46,13 @@ const rows: string[] = [] for (const [path, ceiling] of Object.entries(manifest)) { if (!Number.isInteger(ceiling) || ceiling <= 0) { + rows.push(`BAD ${'—'.padStart(6)} / ${String(ceiling).padEnd(6)} ${path}`) failures.push(`${path}: ceiling must be a positive integer, got ${ceiling}`) continue } const abs = resolve(root, path) if (!existsSync(abs)) { + rows.push(`MISS ${'—'.padStart(6)} / ${String(ceiling).padEnd(6)} ${path}`) failures.push(`${path}: budgeted file does not exist (renamed or deleted? update scripts/doc-budgets.manifest.json in the same change)`) continue } From 5f21d4bf6c1201ede913689834bbcc725b4fdfc5 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sat, 4 Jul 2026 14:46:34 +0800 Subject: [PATCH 3/4] fix(doc-standards): include verify-doc-budgets in AGENTS.md's doc-sync enumerations The gate joined the doc-sync chain in this PR; the root file's two enumerations of that chain must name it in the same change. The frozen ceiling re-records the exact new count (8134). --- AGENTS.md | 4 ++-- scripts/doc-budgets.manifest.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ee5eb7d6f0..fd78bc6e27 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -199,7 +199,7 @@ pnpm run verify-translation-pairing # assert the bilingual pairing contract # re-records a pair after you bring both sides in line pnpm run verify-node-next-types # assert built declarations typecheck for a # standard external NodeNext ESM TypeScript consumer -pnpm run 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 (CI runs this) +pnpm run 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 + verify-doc-budgets (CI runs this) pnpm run demo:echo # run examples/echo-agent (no API key; type "echo hi" to # see a tool call) — the mock skeleton pnpm run demo:repl # run examples/coding-agent — the REPL agent demo @@ -296,7 +296,7 @@ This codebase aims to be **very type-safe and well documented** for maintainabil In the **core** packages (`packages/llm/llm`, `packages/core/tools`, `packages/core/agent`, `packages/core/agent-loop`, `packages/core/session`, `packages/core/system-prompt`), **type gymnastics are acceptable when they improve the DX of plugin authors** for common plugin types. The `defineTool` typed schema DSL in `dsh-tools` is the canonical example: the `SchemaSpec` to `InferArgs` type-level mapping gives tool authors zero-cast typed `execute` args, and the cost of the conditional types stays inside the core package. -Verbose documentation is fine **as long as docs and code stay strictly in sync**. Out-of-sync docs are worse than no docs. **When you change code, update its docs in the SAME change** — grep the package README and the module/JSDoc comments for the old behavior (config keys, defaults, error codes, wire field names, event names) and fix every hit. CI runs `pnpm run 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`), which typechecks every fenced `ts` block in `README.md`, `docs/**/*.md`, and `packages/*/*.md`, regenerates the cordis events/services catalog from source and fails if the committed copy is stale, asserts no hard-wrapped prose paragraphs, checks that every relative Markdown cross-link resolves, checks that every `docs/*.md` path cited in a source comment resolves, checks that every `packages/` reference naming a real package resolves, checks that every RFC is filed under a valid class folder and listed in its index, checks that every ` ```ts type-equiv ` doc block still matches its source type, and checks the bilingual pairing contract (required docs have a complete, consistency-recorded EN/ZH pair — see [docs/i18n/README.md](docs/i18n/README.md)) — across those files plus `AGENTS.md` / `packages/AGENTS.md` — but that scope does NOT catch prose drift in `AGENTS.md` / `packages/AGENTS.md` / `packages/README.md` (config keys, defaults, error codes), so keeping those in sync remains on the author. The same-change rule extends to translations: **editing either side of a paired doc means updating the counterpart and re-recording the pair in the SAME change** (run the [dsh-translate-docs](.agents/skills/dsh-translate-docs/SKILL.md) skill, then `pnpm run verify-translation-pairing --write`); the pairing gate goes red otherwise. Every module has a module-level doc comment explaining its role. Every exported class, interface, type, function, and non-obvious method has a JSDoc that explains semantics (not just the name) — contracts (what events fire when), disposal behavior, error behavior, and extension intent. Internal helpers get docs only where non-obvious. Prefer one-liners when one line suffices. +Verbose documentation is fine **as long as docs and code stay strictly in sync**. Out-of-sync docs are worse than no docs. **When you change code, update its docs in the SAME change** — grep the package README and the module/JSDoc comments for the old behavior (config keys, defaults, error codes, wire field names, event names) and fix every hit. CI runs `pnpm run 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` + `verify-doc-budgets`), which typechecks every fenced `ts` block in `README.md`, `docs/**/*.md`, and `packages/*/*.md`, regenerates the cordis events/services catalog from source and fails if the committed copy is stale, asserts no hard-wrapped prose paragraphs, checks that every relative Markdown cross-link resolves, checks that every `docs/*.md` path cited in a source comment resolves, checks that every `packages/` reference naming a real package resolves, checks that every RFC is filed under a valid class folder and listed in its index, checks that every ` ```ts type-equiv ` doc block still matches its source type, and checks the bilingual pairing contract (required docs have a complete, consistency-recorded EN/ZH pair — see [docs/i18n/README.md](docs/i18n/README.md)) — across those files plus `AGENTS.md` / `packages/AGENTS.md` — but that scope does NOT catch prose drift in `AGENTS.md` / `packages/AGENTS.md` / `packages/README.md` (config keys, defaults, error codes), so keeping those in sync remains on the author. The same-change rule extends to translations: **editing either side of a paired doc means updating the counterpart and re-recording the pair in the SAME change** (run the [dsh-translate-docs](.agents/skills/dsh-translate-docs/SKILL.md) skill, then `pnpm run verify-translation-pairing --write`); the pairing gate goes red otherwise. Every module has a module-level doc comment explaining its role. Every exported class, interface, type, function, and non-obvious method has a JSDoc that explains semantics (not just the name) — contracts (what events fire when), disposal behavior, error behavior, and extension intent. Internal helpers get docs only where non-obvious. Prefer one-liners when one line suffices. **Tag every new event with `@mode`.** The cordis events/services catalog ([docs/cordis-catalog/events-and-services.md](docs/cordis-catalog/events-and-services.md)) is GENERATED from source by `scripts/gen-cordis-catalog.ts` — never hand-edit it; run `pnpm run gen-cordis-catalog` and commit the result. When you add an event to an `interface Events` block, its JSDoc MUST carry a `@mode emit|waterfall|parallel|serial` tag (the generator hard-errors without it): use `waterfall` when the signature ends with a `next: () => …` parameter (the listener transforms or vetoes via `next()`), `parallel` when the loop awaits a fan-out and must run every listener (e.g. an awaited `Promise | void` checkpoint like `session/flush`), `serial` when the loop awaits listeners in registration order and should isolate side effects (e.g. an ordered surface-mutation checkpoint like `agent/pre-step`; Cordis stops early if a listener returns a bail value, so `void` serial listeners must not return a semantic veto), and `emit` for plain fire-and-forget notifications. The generator also cross-checks the tag against the signature where the shape is conclusive (a trailing `next` ⇒ waterfall) and hard-errors on a contradiction. Write the rest of the event's JSDoc to stand alone — it is the catalog entry's prose. diff --git a/scripts/doc-budgets.manifest.json b/scripts/doc-budgets.manifest.json index afcff11e2c..a302493b9c 100644 --- a/scripts/doc-budgets.manifest.json +++ b/scripts/doc-budgets.manifest.json @@ -1,5 +1,5 @@ { - "AGENTS.md": 8130, + "AGENTS.md": 8134, "docs/AGENTS.md": 982, "docs/architecture.md": 3897, "examples/AGENTS.md": 579, From cada16c701168b31b35332514af92face82dd2a8 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sat, 4 Jul 2026 17:20:18 +0800 Subject: [PATCH 4/4] docs(budgets): ceilings carry at least 5% working headroom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .agents/skills/dsh-doc-standards/SKILL.md | 2 +- docs/AGENTS.md | 2 +- .../process/2026-07-04-doc-tiers-and-budgets.md | 2 +- scripts/doc-budgets.manifest.json | 12 ++++++------ scripts/verify-doc-budgets.ts | 7 ++++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.agents/skills/dsh-doc-standards/SKILL.md b/.agents/skills/dsh-doc-standards/SKILL.md index f981af9ace..7506ca5eb0 100644 --- a/.agents/skills/dsh-doc-standards/SKILL.md +++ b/.agents/skills/dsh-doc-standards/SKILL.md @@ -40,7 +40,7 @@ Compression discipline: every load-bearing rule survives — as one to three lin 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 modest headroom in the same PR. +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 diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 52ac672225..e66175ffd9 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -26,7 +26,7 @@ Placement test: a story about a bug → postmortem. Why we chose X → RFC. How Standing docs accrete: every PR has a lesson it wants to append, and without displacement pressure nothing ever leaves. The gate is that pressure. [scripts/doc-budgets.manifest.json](../scripts/doc-budgets.manifest.json) lists the accretion-prone standing docs with a word ceiling each; `pnpm run verify-doc-budgets` (part of `doc-sync`, so CI and pre-push run it) fails when a doc exceeds its ceiling, and fails when a budgeted file is missing so a rename cannot orphan its budget. -- Ceilings are an enforcement frontier: a ceiling starts at the doc's current size (freezing further growth) and ratchets down as the doc is brought to its target. Target budgets: root `AGENTS.md` ≤ 1,500 words; `architecture.md` ≤ 1,800; each subtree `AGENTS.md` ≤ 600, except this file (which carries the standard) ≤ 1,000; `packages/README.md` ≤ 600. +- Ceilings are an enforcement frontier with working headroom: a ceiling sits at least 5% above the doc's current size — routine wording edits pass, real growth trips the gate — and ratchets down (keeping the margin) as the doc is brought to target. Target budgets: root `AGENTS.md` ≤ 1,500 words; `architecture.md` ≤ 1,800; each subtree `AGENTS.md` ≤ 600, except this file (which carries the standard) ≤ 1,000; `packages/README.md` ≤ 600. - When the gate goes red, the fix is to relocate or condense per the taxonomy above. Raising a ceiling is the last resort: the PR description must justify it, and the manifest diff is the reviewable act. - Unbudgeted tiers (package READMEs, RFCs, reference matrices) have no ceiling — length is legitimate there when every row is a fact. Review and the slop checklist govern them instead. diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md index 8c5c62ed58..428de5deaa 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md @@ -8,7 +8,7 @@ The repo's standing docs accrete. Root `AGENTS.md` reached 8,130 words through 5 - **A tier taxonomy with one home per fact.** [docs/AGENTS.md](../../../AGENTS.md) is the documentation standard: it assigns every Markdown tier a single job (standing orders, system map, type catalog, decision records, incident stories, how-tos, per-package contracts, generated catalogs, workflows), forbids restating a fact outside its home tier (link instead), and carries the slop checklist used when writing or reviewing any doc. - **A narrow, hard budget gate.** [scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) joins `doc-sync`: every doc listed in [scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) must stay under its word ceiling (`wc -w` semantics, whole file), and a budgeted file that is missing fails the gate so a rename cannot silently orphan its budget. Scope is deliberately only the accretion-prone standing docs — the root and subtree `AGENTS.md` files, `architecture.md`, `packages/README.md`. Reference docs, RFCs, and package READMEs are unbudgeted: length is legitimate there when every row is a fact, and review plus the slop checklist govern them. -- **Ceilings are an enforcement frontier that ratchets.** A ceiling starts at the doc's current size, freezing growth from day one, and ratchets down as the doc is brought to its target budget (root `AGENTS.md` ≤ 1,500 words; `architecture.md` ≤ 1,800; subtree `AGENTS.md` ≤ 600; `packages/README.md` ≤ 600) — the same rollout mechanism as the [translation-pairing `required` list](2026-07-02-bilingual-docs-and-pairing-gate.md). When the gate goes red the fix is to relocate or condense per the taxonomy; raising a ceiling is permitted only with explicit justification in the PR description, the manifest diff being the reviewable act. +- **Ceilings are an enforcement frontier that ratchets.** A ceiling sits at least 5% above the doc's current size — working headroom, so routine wording edits pass while real growth still trips the gate — and ratchets down, keeping that margin, as the doc is brought to its target budget (root `AGENTS.md` ≤ 1,500 words; `architecture.md` ≤ 1,800; subtree `AGENTS.md` ≤ 600; `packages/README.md` ≤ 600) — the same rollout mechanism as the [translation-pairing `required` list](2026-07-02-bilingual-docs-and-pairing-gate.md). When the gate goes red the fix is to relocate or condense per the taxonomy; raising a ceiling is permitted only with explicit justification in the PR description, the manifest diff being the reviewable act. - **A thin workflow skill, contracts in docs.** [.agents/skills/dsh-doc-standards](../../../../.agents/skills/dsh-doc-standards/SKILL.md) carries the placement/audit/red-gate workflow and defers to the standard as its source of truth, the same split as [dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md) over the i18n contract. ## Alternatives considered diff --git a/scripts/doc-budgets.manifest.json b/scripts/doc-budgets.manifest.json index a302493b9c..bd972fad7a 100644 --- a/scripts/doc-budgets.manifest.json +++ b/scripts/doc-budgets.manifest.json @@ -1,8 +1,8 @@ { - "AGENTS.md": 8134, - "docs/AGENTS.md": 982, - "docs/architecture.md": 3897, - "examples/AGENTS.md": 579, - "packages/AGENTS.md": 577, - "packages/README.md": 1856 + "AGENTS.md": 8545, + "docs/AGENTS.md": 1050, + "docs/architecture.md": 4095, + "examples/AGENTS.md": 610, + "packages/AGENTS.md": 610, + "packages/README.md": 1950 } diff --git a/scripts/verify-doc-budgets.ts b/scripts/verify-doc-budgets.ts index fb27e84473..1ace894410 100644 --- a/scripts/verify-doc-budgets.ts +++ b/scripts/verify-doc-budgets.ts @@ -13,9 +13,10 @@ * matrix is the right kind of long), and the standard governs them through * review, not a ceiling. * - * The manifest is an enforcement frontier, i18n-rollout style: ceilings start - * at a doc's current size (freezing further growth) and ratchet DOWN as the - * doc is brought to its target budget. A manifest entry whose file is missing + * The manifest is an enforcement frontier, i18n-rollout style: a ceiling sits + * at least 5% above the doc's current size (working headroom, so routine + * wording edits pass while real growth trips the gate) and ratchets DOWN, + * keeping that margin, as the doc is brought to its target budget. A manifest entry whose file is missing * fails the gate, so a rename cannot silently orphan its budget. * * Words are counted `wc -w` style over the whole file (whitespace-delimited