Merge remote-tracking branch 'origin/master' into worktree/schedule-conversational-after

This commit is contained in:
Tianyi Cui
2026-08-09 22:39:09 +08:00
10 changed files with 369 additions and 33 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority; # 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: # after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-09-committed-artifact-citations.md # pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-09-committed-artifact-citations.md
2026-08-09-committed-artifact-citations.md: 31b2d52b423a080579b3ca95cf077859d0bf4c91 2026-08-09-committed-artifact-citations.md: 181378aab12a4423d9ac5216bac5304f3cfca11c
2026-08-09-committed-artifact-citations.zh.md: b69bb8743d10e2d1e194905d6d0de2d3d3667b1d 2026-08-09-committed-artifact-citations.zh.md: 36f32bb1fd0d6991919959e1ebe6482bf7b19b32

View File

@@ -18,7 +18,7 @@ Durable prose — comments, JSDoc, docs, notes, test comments and titles — cit
- Implemented notes state shipped reality: a "deferred to a later PR" claim whose target shipped names the shipped note instead. - Implemented notes state shipped reality: a "deferred to a later PR" claim whose target shipped names the shipped note instead.
- Recorded fixtures, snapshots, and archived notes are exempt: recorded model output and sealed history keep their original voice. Inside a note's change-story sections, a historical stage name ("the first cut shipped X") is current-state-safe; indexical stamps ("this cut") stay banned everywhere. - Recorded fixtures, snapshots, and archived notes are exempt: recorded model output and sealed history keep their original voice. Inside a note's change-story sections, a historical stage name ("the first cut shipped X") is current-state-safe; indexical stamps ("this cut") stay banned everywhere.
One repo-wide purge applied these rules across the prose surfaces, including the generator-owned templates (`scripts/gen-doc-graphs.ts`, `scripts/gen-tool-catalog.ts`, the typert generator's page notice) with regeneration, the type-equiv source JSDoc with page re-pastes, and the bilingual counterparts with pair re-records. One repo-wide purge applied these rules across the prose surfaces, including the generator-owned templates (`scripts/gen-doc-graphs.ts`, `scripts/gen-tool-catalog.ts`, the typert generator's page notice) with regeneration, the type-equiv source JSDoc with page re-pastes, and the bilingual counterparts with pair re-records. The [dsh-trim-cot-leakage skill](../../../skills/dsh-trim-cot-leakage/SKILL.md) operationalizes these rules: the audit taxonomy, the committed recall batteries, and few-shot calibration for the keep/delete boundary.
## Alternatives considered ## Alternatives considered
@@ -28,7 +28,7 @@ One repo-wide purge applied these rules across the prose surfaces, including the
## Verification ## Verification
The audit's grep batteries (English and Chinese, comments and prose, `--hidden` for `.agents/`) return no design-ordinal citations outside recorded fixtures and archived notes; `verify-type-equiv`, the `gen-*` freshness checks, and `verify-translation-pairing` pin the regenerated and re-recorded surfaces. Coverage gap: no gate rejects a new ordinal citation — review owns the rule. The audit's grep batteries (English and Chinese, comments and prose, `--hidden` for `.agents/`) return no design-ordinal citations outside recorded fixtures, archived notes, and the trim skill's own calibration examples; `verify-type-equiv`, the `gen-*` freshness checks, and `verify-translation-pairing` pin the regenerated and re-recorded surfaces. Coverage gap: no gate rejects a new ordinal citation — review owns the rule.
## Consequences ## Consequences

View File

@@ -18,7 +18,7 @@ Status: implemented
- 已实现的 Agent Note 陈述已交付的现实:「推迟到后续 PR」的说法若其目标已经交付就改为点名那篇已交付的 note。 - 已实现的 Agent Note 陈述已交付的现实:「推迟到后续 PR」的说法若其目标已经交付就改为点名那篇已交付的 note。
- 已录制的 fixture测试前置数据、快照与已归档的 Agent Note 不受此约束:已录制的模型输出与封存的历史保持原有行文。在 note 的变更故事段落内,历史阶段名称(「首版交付了 X」属于安全的现状表述指示性切次戳"this cut")在任何地方都仍被禁止。 - 已录制的 fixture测试前置数据、快照与已归档的 Agent Note 不受此约束:已录制的模型输出与封存的历史保持原有行文。在 note 的变更故事段落内,历史阶段名称(「首版交付了 X」属于安全的现状表述指示性切次戳"this cut")在任何地方都仍被禁止。
一次全仓库清理把这些规则应用到了各个行文表面,包括生成器持有的模板(`scripts/gen-doc-graphs.ts``scripts/gen-tool-catalog.ts`、typert 生成器的页面提示语改后重新生成、type-equiv 源码 JSDoc改后把文档页重新粘贴以及双语对侧文件改后重新记录配对 一次全仓库清理把这些规则应用到了各个行文表面,包括生成器持有的模板(`scripts/gen-doc-graphs.ts``scripts/gen-tool-catalog.ts`、typert 生成器的页面提示语改后重新生成、type-equiv 源码 JSDoc改后把文档页重新粘贴以及双语对侧文件改后重新记录配对[dsh-trim-cot-leakage 技能](../../../skills/dsh-trim-cot-leakage/SKILL.md)把这些规则落地为可执行工作流:审计分类法、已提交的成批召回检索,以及校准保留/删除边界的少样本示例。
## 曾考虑的替代方案 ## 曾考虑的替代方案
@@ -28,7 +28,7 @@ Status: implemented
## 验证 ## 验证
审计的成批 grep 检索(英文与中文、注释与行文、对 `.agents/``--hidden`)在已录制 fixture已归档 Agent Note 之外没有命中任何设计序号引用;`verify-type-equiv`、各 `gen-*` 新鲜度检查与 `verify-translation-pairing` 把重新生成与重新记录的表面固定下来。覆盖缺口:没有门禁会拒绝新的序号引用,这条规则由评审把关。 审计的成批 grep 检索(英文与中文、注释与行文、对 `.agents/``--hidden`)在已录制 fixture已归档 Agent Note 与该清理技能自带的校准示例之外没有命中任何设计序号引用;`verify-type-equiv`、各 `gen-*` 新鲜度检查与 `verify-translation-pairing` 把重新生成与重新记录的表面固定下来。覆盖缺口:没有门禁会拒绝新的序号引用,这条规则由评审把关。
## 后果 ## 后果

View File

@@ -37,12 +37,11 @@ Then check constraints that make placement expensive or wrong:
After the structural pass, hunt the standard's slop checklist with the cheapest probes first. Verify and fetch the PR's live base, then run `pnpm --silent run change-scope --base <verified-base-ref>` to identify committed and dirty paths before applying semantic judgment. After a retarget or base merge, rerun the report and audit prose introduced by the new base. After the structural pass, hunt the standard's slop checklist with the cheapest probes first. Verify and fetch the PR's live base, then run `pnpm --silent run change-scope --base <verified-base-ref>` to identify committed and dirty paths before applying semantic judgment. After a retarget or base merge, rerun the report and audit prose introduced by the new base.
1. Measure: `pnpm run verify-doc-budgets --list`, then `git ls-files '*.md' ':(exclude)vendor/**' | xargs wc -w | sort -rn | head -30` to spot unbudgeted outliers. 1. Measure: `pnpm run verify-doc-budgets --list`, then `git ls-files '*.md' ':(exclude)vendor/**' | xargs wc -w | sort -rn | head -30` to spot unbudgeted outliers.
2. Hunt narrated history: `rg -n "no longer|used to|previously|was moved|renamed" --glob '*.md' --glob '*.ts' --glob '!vendor/**'` and keep only contrasts against a live alternative. Keep the vendor exclusion last so include globs cannot override it. 2. Hunt reasoning-transcript leakage — narrated history, dead design-session citations, review choreography, control-flow narration, test walkthroughs — with [dsh-trim-cot-leakage](../dsh-trim-cot-leakage/SKILL.md), which owns the taxonomy, recall batteries, and the keep/delete boundary. Preserve only a non-obvious contract or durable rationale; the same rationale repeated beside sibling methods keeps one home.
3. Inspect long comments for reasoning transcripts: control-flow narration, test walkthroughs, proof of obvious branches, review findings, rejected local alternatives, and the same rationale repeated beside sibling methods. Preserve only a non-obvious contract or durable rationale; otherwise delete the comment. 3. Hunt duplication by grepping distinctive phrases. Keep one home and replace other copies with links.
4. Hunt duplication by grepping distinctive phrases. Keep one home and replace other copies with links. 4. Replace hand-written catalogs, test/status inventories, and JSDoc restatements with the authoritative tree, script, or generated reference.
5. Replace hand-written catalogs, test/status inventories, and JSDoc restatements with the authoritative tree, script, or generated reference. 5. In `implemented/` Agent Notes, remove migration plans, acceptance-task checklists, and future-tense spec language. Keep concise verification contracts that identify the behaviors and tiers pinning the shipped decision, plus named coverage gaps.
6. In `implemented/` Agent Notes, remove migration plans, acceptance-task checklists, and future-tense spec language. Keep concise verification contracts that identify the behaviors and tiers pinning the shipped decision, plus named coverage gaps. 6. If removing prose changes a promised behavior rather than its explanation, use a proposed Agent Note first (follow [dsh-find-simplifications](../dsh-find-simplifications/SKILL.md)).
7. If removing prose changes a promised behavior rather than its explanation, use a proposed Agent Note first (follow [dsh-find-simplifications](../dsh-find-simplifications/SKILL.md)).
Exclude `.agents/notes/archived/` from corpus audits and edits. Active prose may repair, redirect, or delete an inbound link, but never follow an archive-wide cleanup into the frozen target. Exclude `.agents/notes/archived/` from corpus audits and edits. Active prose may repair, redirect, or delete an inbound link, but never follow an archive-wide cleanup into the frozen target.

View File

@@ -5,7 +5,7 @@ description: Use when writing, reviewing, restoring, trimming, or auditing prose
# DeepSeek Harness Prose Standard # DeepSeek Harness Prose Standard
Write enough to preserve the contract, then remove reasoning transcripts, repetition, and decoration. This skill owns editorial judgment and required prose coverage; use [dsh-doc-standards](../dsh-doc-standards/SKILL.md) for placement, budgets, bilingual pairs, and documentation gates. It is guidance, not a script. Write enough to preserve the contract, then remove reasoning transcripts, repetition, and decoration. This skill owns editorial judgment and required prose coverage; use [dsh-doc-standards](../dsh-doc-standards/SKILL.md) for placement, budgets, bilingual pairs, and documentation gates, and [dsh-trim-cot-leakage](../dsh-trim-cot-leakage/SKILL.md) for hunting and fixing reasoning-transcript leakage. It is guidance, not a script.
Comments describe non-obvious contracts or rationale that code cannot express; they do not restate what code already implies. Comments describe non-obvious contracts or rationale that code cannot express; they do not restate what code already implies.

View File

@@ -0,0 +1,45 @@
---
name: dsh-trim-cot-leakage
description: Use when auditing or fixing prose that reads like a leaked reasoning transcript — dead design-session citations such as (decision N), audit item codes, or §N of uncommitted drafts; change narration such as "used to", "no longer", "this cut"; stack or review vantage ("a later PR in this stack", "rejected in review"); reviewer-addressed justifications; control-flow narration; or hedged planning residue in comments, JSDoc, docs, or Agent Notes.
---
# Trimming Chain-of-Thought Leakage
Chain-of-thought leakage is prose whose vantage is the authoring session rather than the repository: it cites artifacts only that session could see, narrates the change instead of the state, or argues with a reviewer who has left. The fix is never deletion alone — restate every factual clause so it stands at HEAD, then delete the transcript around it. **REQUIRED BACKGROUND:** [dsh-prose-standard](../dsh-prose-standard/SKILL.md) owns the complete-proposition rule this skill applies; the [committed-artifact-citations note](../../notes/implemented/process/2026-08-09-committed-artifact-citations.md) owns the citation rule's rationale. It is guidance, not a script.
## The one test
For every suspect passage ask: **could a reader at HEAD, with no access to any session transcript, PR thread, or uncommitted draft, resolve every reference and verify every claim?** If yes, it is not leakage, however historical it sounds. If no, restate the surviving facts from the repository's vantage and delete the rest.
## Taxonomy
1. **Dead design-session citations**`(decision 7)`, `(audit C2)`, `design §4.7`, `plan §1.4`, phase labels (`T4`, `W3`, `P-I`), "the design ledger", "(B ruling)". If the decision has a committed owner, cite it by name and path; otherwise delete the citation and restate its factual clause to stand alone.
2. **Stack and PR vantage** — "a later PR in this stack", "this PR adds", "the previous commit". State the shipped mechanism or the extension point; deferred work moves to a `TODO` marker or an issue reference.
3. **Change narration and version stamps** — "used to", "no longer", "the old X", and indexical stamps ("v1", "this cut", "today", "now" contrasting with a past state). State the present behavior; a fixed regression becomes a present-tense counterfactual ("without X, Y happens"), never repo history ("used to Y").
4. **Review choreography** — "Rejected in review:", "the reviewer confirmed", draft ordinals ("v5 of this note"), round attributions. Keep the surviving decision and rationale as plain fact; delete who said it when.
5. **Reviewer-addressed justification** — "the cast is safe — it simply…", "this is correct because…". A comment arguing its own correctness addresses a reviewer, not a maintainer. State the invariant that makes the code safe, or delete the comment if the code shows it.
6. **Restatement and derivation transcripts** — control-flow narration ("first we X, then we Y"), test walkthroughs, proofs of obvious branches. Delete; keep only a non-obvious contract or invariant.
7. **Hedges and planning residue** — "probably fine for now", "should be enough", deferrals with no marker. Promote to `TODO`/`FIXME` or restate as the actual bound; delete the hedge.
8. **Authoring-language slips** — untranslated working-language fragments (端, 设计稿, `---- 私有 ----` separators) in prose whose language is otherwise English, or the reverse in a zh counterpart. Translate or delete.
## What is not leakage
The citation boundary is where unaided passes fail in both directions — deleting durable references and keeping dead ones. Apply these keeps as written; [examples](references/examples.md) calibrates each:
- **Issue references** — `#1470`, `TODO(name):`, "issue #N owns the follow-up" resolve at HEAD; keep them on any surface, including READMEs. Do not relocate them to Agent Notes.
- **Merged-PR and issue citations inside Agent Notes and postmortems** — sanctioned evidence per the [documentation standard](../../../docs/AGENTS.md)'s change-story routing.
- **Suppression justifications** — `oxlint-disable … -- reason`, coverage-ignore reasons, empty-catch explanations are required prose; fix a false reason, never delete it.
- **Counterfactual-present regression pins** — "without X, Y happens", "a naive X would…".
- **Measured bounds** — "(measured: 512 nests ≈ 0.15s)" calibrating a constant; the provenance word "measured" is load-bearing.
- **Runtime old/new states** — "the old connection drains before the new one accepts" is runtime lifecycle, not change history.
- **Historical stage names inside a note's change-story sections** — "the first cut shipped X" is current-state-safe there; indexical stamps ("this cut") stay banned everywhere.
- **External references that resolve outside the repo by design** — standards sections (RFC 9110 §10.1.5), Figma frame names; the §-ban covers uncommitted internal drafts, not external standards or committed docs that own their §-numbering.
- **Project voice and genre forms** — "we" as project voice; a note's Alternatives-considered section.
## Workflow
1. Scope and exclusions per [dsh-prose-standard](../dsh-prose-standard/SKILL.md): require an explicit scope; never touch `vendor/`, `.agents/notes/archived/`, or recorded fixtures and snapshots — recorded model output and sealed history keep their original voice.
2. Audit read-only first: run the [recall batteries](references/recall-batteries.md) (with `--hidden` so `.agents/` is searched), then judge every hit semantically. The batteries are probes, not the definition — each review round of the original purge surfaced shapes the batteries missed, so also read the densest prose in scope (module JSDoc, READMEs, Agent Notes) without a pattern in hand.
3. Fix owner-first per surface: generated catalogs → fix the source JSDoc or generator template, then regenerate; type-equivalence fences → fix the source JSDoc, then re-paste both bilingual pages (`verify-type-equiv` pins them); bilingual pairs → update the counterpart and re-record per [dsh-translate-docs](../dsh-translate-docs/SKILL.md); model-visible strings → wording is behavior, so flag for a snapshot-backed change instead of silently rewording.
4. Before deleting anything, enumerate the passage's propositions (prose-standard) and check the [overcorrection traps](references/examples.md#overcorrection-traps): trims that flip an obligation into an endorsement, promote a hypothetical to a shipped feature, delete a true fact, or drop provenance.
5. Verify: re-run the batteries expecting only sanctioned keeps and this skill's own references; confirm every remaining citation resolves at HEAD; run the gates for touched surfaces (`doc-sync` for docs, `verify-type-equiv`, `verify-translation-pairing`).

View File

@@ -0,0 +1,253 @@
# Few-shot leakage examples
Distilled from the 2026-08 repo-wide purge and its review rounds. Use them to identify the governing principle, not as text templates. This file deliberately quotes leaked shapes as calibration material — the [recall batteries](recall-batteries.md) exclude this directory, and its wording is not a license elsewhere.
## Dead citations
### Decision ordinal with a committed owner
**Leaked:** "Slash input resolves against the visible catalog (decision 21)."
**Fixed:** "Slash input resolves against the visible catalog — the plain-text-reference decision, owned by the web input-machine note."
The ordinal resolves nowhere at HEAD; the decision's name and owning note path do. Name the owning note's path at least once per file; later mentions may use the searchable name alone.
### Decision ordinal without an owner
**Leaked:** "The registry rejects duplicate names (decision 7: names are flat, no namespacing)."
**Fixed:** "The registry rejects duplicate names; names are flat, with no namespacing."
No committed artifact owns "decision 7", so the citation is deleted — but its factual clause (flat names) is restated to stand alone, not deleted with it.
### Audit item codes
**Leaked:** "Rendering is pure: same snapshot, same string (audit R3)."
**Fixed:** "Rendering is pure: same snapshot, same string."
There is no audit document in the repo; the code is pure session shorthand carrying zero propositions.
### Section numbers of uncommitted drafts
**Leaked:** "Layering follows the design (v2 §3.2): `src/core/` is the pure core."
**Fixed:** "Layering: `src/core/` is the pure core."
`§N` of a draft nobody committed is unresolvable. Contrast: "escapes per RFC 9110 §10.1.5" stays — an external standard resolves outside the repo by design, and a committed doc that owns its §-numbering may be cited by section.
### Plan-phase labels
**Leaked:** "`src/client/` is the shell (T4); the P-I migration owns the adapters."
**Fixed:** "`src/client/` is the shell; the adapters live in `src/client/adapters/`."
Phase labels index a plan that never landed. Replace the label with what the phase produced.
## Stack and PR vantage
### Stack position in durable prose
**Leaked:** "A future remote backend implements this interface (the sandbox backend is a later PR in this stack)."
**Fixed:** "A remote backend can implement this interface without changing the render layer."
Durable prose cannot see the stack. Keep the extension-point contract; the pending work's home is the PR itself, a `TODO`, or an issue.
### "This PR" in a README
**Leaked:** "This PR adds cursor-based pagination to the session list."
**Fixed:** "The session list paginates by cursor."
A README outlives every PR; state the mechanism as current fact.
## Change narration and version stamps
### War story with a PR number
**Leaked:** "Colors used to come from `--widget-*` tokens, which nothing defined, so it always rendered the fallbacks; the alias tokens fixed that (PR #88)."
**Fixed:** "Colors come from the alias tokens; an undefined token renders the fallbacks."
Both live facts survive — the current mechanism and the standing failure behavior — restated in the present. The bug's biography belongs to the PR and its Agent Note.
### Removal narration
**Leaked:** "The `probe` field is gone with the removal cut; badges ride the generic projection pair now."
**Fixed:** "Badges use the generic projection pair."
Readers who never saw `probe` learn nothing from its absence. "Now" contrasting with a deleted past is a version stamp.
### Fixed regression → counterfactual present
**Leaked:** "This used to double-encode multibyte labels."
**Fixed:** "Without the byte-length guard, multibyte labels double-encode."
The regression pin survives as a present-tense counterfactual that names the guard; "used to" pins it to repo archaeology instead.
### Indexical version stamps
**Leaked:** "Batch rendering is synchronous this cut; the async path is roadmap work."
**Fixed:** "Batch rendering is synchronous." (The deferral lives in `TODO(widget-batch):` at the call site.)
"This cut" / "v1" / "today" go stale the moment they merge. A historical stage name inside an Agent Note's change-story section ("the first cut shipped X") is current-state-safe; the indexical form never is.
## Review choreography
### Review verdicts as prose
**Leaked:** "Rejected in review: caching the resolved spec. We keep resolution per-call."
**Fixed (in an Agent Note's Alternatives considered):** "**Caching the resolved spec.** Rejected: the spec depends on per-call cwd, so a cache keyed by request would serve stale roots."
The alternatives-considered genre is the sanctioned home; the reviewer and the round are not part of the rationale.
### Draft ordinals
**Leaked:** "As of v5 of this note, the loader also validates manifests."
**Fixed:** "The loader validates manifests."
An implemented note states shipped reality; its own revision history lives in git.
## Reviewer-addressed justification
### Arguing a cast
**Leaked:** "The cast is safe — the SDK constructed the object, it simply doesn't declare the optionals strictly enough."
**Fixed:** "The SDK constructs this object with every optional populated; the declared type is looser than the runtime guarantee."
State the invariant a maintainer must not break. "It simply…" is a voice answering an objection nobody at HEAD raised. If the invariant is visible in the code, delete the comment instead.
### Appeal to review authority
**Leaked:** "This is correct because the reviewer confirmed the wrapping order."
**Fixed:** (deleted; the wrapping order is stated in the function's `@returns`.)
Correctness claims cite invariants or tests, never people.
## Restatement and derivation
### Control-flow narration
**Leaked:** "First we normalize the label, then we truncate it, then we wrap it."
**Fixed:** (deleted.)
The three lines below the comment say the same thing in code.
### Test walkthrough
**Leaked:** "This test creates a session, sends two messages, waits for the second reply, and then asserts the log has four entries."
**Fixed:** "Two round-trips must produce exactly four log entries — the projection dedupes the shared prefix."
Keep only the non-obvious assertion rationale; the walkthrough restates the test body.
## Hedges and planning residue
### Unmarked deferral
**Leaked:** "Probably fine to render eagerly for now."
**Fixed:** (deleted; the deferral already has its `TODO(widget-batch):` marker.)
A hedge without an owner is planning residue. If no marker exists, write one (`TODO(name): coalesce per animation frame`) instead of keeping the hedge.
### Vague sizing
**Leaked:** "A 64 KiB buffer should be enough for most cases."
**Fixed:** "64 KiB holds the largest observed frame (48 KiB) with headroom; a larger frame fails loudly in `decode`."
Replace the hedge with the actual bound and the failure behavior when it is exceeded.
## Authoring-language slips
**Leaked:** "The renderer runs on the client 端; see the 设计稿 for spacing. ---- 私有 ----"
**Fixed:** "The renderer runs on the client side; spacing follows the Figma frame `widget-badges`."
Working-language fragments and session separators are transcription residue. The Figma frame name stays: external provenance that resolves outside the repo by design.
## Keeps
### Issue references are durable on every surface
**Keep:** "The cap applies to the complete rendered value, wrappers included (issue #1470 owns the follow-up)."
An unaided pass deleted this, reasoning that issue citations belong in Agent Notes. Wrong direction: issues resolve at HEAD from any surface, and "#N owns the follow-up" is the sanctioned home for deferred work in a README. What Agent Notes and postmortems additionally sanction is citing *merged PRs* as evidence.
### Dead name-drops are not "naming the owner"
**Delete:** "Badge renderer over the widget seam (see the widget-rendering RFC)."
An unaided pass kept this as "naming the owning document by topic". The test is resolvability, not form: no committed file answers to "the widget-rendering RFC", so the pointer is dead. Retarget it to the committed owner if one exists; otherwise delete it.
### Suppression justifications
**Keep (after fixing):** `// oxlint-disable-next-line no-non-null-assertion -- the one-element literal guarantees index 0.`
The justification clause is required prose. When the stated reason is false (the original said "the loop guard above proves a frame exists" with no loop in sight), fix the reason; never delete it.
### Measured bounds
**Keep:** "Depth cap (measured: 512 nests ≈ 0.15s synchronous; 4096 blocks the loop)."
The measurement pins the constant against uninformed retuning, and "measured" is the provenance that distinguishes data from a guess.
### Runtime old/new is not change history
**Keep:** "The old connection drains before the new one accepts."
"Old" and "new" here name two live runtime objects during handover, not repository states. The change-narration ban is about repo history, not lifecycle vocabulary.
## Overcorrection traps
Every trap below shipped in the original purge and was caught in review. Enumerate a passage's propositions before trimming it.
### Flipping an obligation into an endorsement
**Original:** "These direct registrations are exceptions pending migration to slots."
**Overcorrected:** "These direct registrations are sanctioned exceptions."
**Right:** "These direct registrations are exceptions pending migration to slots."
"Pending migration" is an obligation; "sanctioned" blesses the status quo. The trim inverted the sentence's modality while shortening it.
### Promoting a hypothetical to a shipped feature
**Original:** "A future IPC-based shell subclasses the executor and overrides `spawn`."
**Overcorrected:** "An IPC-based shell subclasses the executor and overrides `spawn`."
**Right:** "A hypothetical IPC-based shell — no such shell exists — would subclass the executor and override `spawn`."
Deleting the future-marker alone turns a design illustration into a claim that the class ships. Mark the hypothetical explicitly instead of just unmarking the future.
### Deleting a true fact with the transcript around it
**Original:** "The gate notice narrates the check order; the notice text is also what `verify-doc-typecheck` compiles against."
**Overcorrected:** "…" (whole sentence deleted as narration.)
**Right:** "The notice text is what `verify-doc-typecheck` compiles against."
Half the sentence was narration; the other half was a load-bearing coupling. Delete clauses, not sentences, when propositions share a line.
### Dropping provenance while keeping the number
**Original:** "The 4 MiB ceiling is measured: the largest generated `py-types` module is 3.1 MiB."
**Overcorrected:** "The ceiling is 4 MiB; the largest generated `py-types` module is 3.1 MiB."
**Right:** keep "measured".
Without "measured" the 3.1 MiB reads as a definition rather than an observation, and nobody re-measures before raising the ceiling.

View File

@@ -0,0 +1,42 @@
# Recall batteries
Probes for [the taxonomy](../SKILL.md#taxonomy), tuned during the 2026-08 purge. Every hit needs semantic judgment — the batteries over-match by design, and they under-match by nature: each review round of the purge found shapes no battery caught, so pair them with an unpatterned read of the densest prose in scope.
## Invocation rules
- Add `--hidden --glob '!.git/**'` so `.agents/` is searched; ripgrep skips dot-directories by default and the purge's biggest miss risk was Agent Notes.
- Exclusions go last so a later include cannot re-admit them: `--glob '!vendor/**' --glob '!node_modules/**' --glob '!.agents/notes/archived/**' --glob '!.agents/skills/dsh-trim-cot-leakage/references/**'` (this directory quotes leaked shapes as calibration), plus recorded fixture and snapshot directories in scope.
- A zero-hit pattern proves nothing until you have seen it match: test it against a known-positive string before trusting the negative.
## English battery
```sh
rg -n --hidden '\(decision \d|\(audit [A-Z]\d|design §|plan §|design ledger|\(B ruling|\bP-I\b|\bW\d\b|\bT\d\b' ...
rg -n --hidden 'this PR|this branch|this stack|later PR|previous commit|this commit' ...
rg -n --hidden 'used to |no longer|previously|the old |was renamed|was moved' ...
rg -n --hidden '\bv1\b|this cut|\bcut \d|\btoday\b|\bfor now\b|roadmap' ...
rg -n --hidden -i 'rejected in review|review round|reviewer|as of v\d' ...
rg -n --hidden 'probably |should be enough|should suffice|it simply|is safe —|is safe --' ...
rg -n --hidden '§\d' ...
```
## Chinese battery
```sh
rg -n --hidden '设计稿|评审|上一?轮|旧版|老的|不再|以前|本版|遗留|私有' ...
rg -n --hidden '(^|[^a-zA-Z])端([^a-zA-Z]|$)' --glob '*.md' ...
```
## Known false-positive families
Judged and kept during the purge; expect them again:
- **Instrumental "used to"** — "the key used to sign requests" is instrumental, not temporal. The temporal form has a subject state before it ("colors used to come from…").
- **Runtime old/new** — "the old connection drains before the new one accepts" names live objects during handover, not repo states.
- **"This PR" in process docs** — documentation *about* PR workflow ("the PR body should…", templates, this repo's process notes) legitimately says "PR"; the ban is on a doc adopting one PR's vantage about the code.
- **`v1` as protocol or path segment** — `/v1/chat` endpoints and wire-format names are identifiers, not version stamps.
- **`§N` with a committed owner** — external standards (RFC 9110 §10.1.5) and committed docs that own their §-numbering stay citable by section.
- **Contrastive "actually" and noun "wait"** — ordinary English, not hedging.
- **"Today" in generated timestamps and CLI output samples** — recorded output keeps its voice.
- **本版本 in zh prose** — a legitimate rendering of "this release" in versioned-artifact contexts; the banned indexical is 本版 as a bare stamp mirroring "this cut".
- **Alternatives-considered sections** — "rejected" inside an Agent Note's genre slot is the sanctioned home, not review choreography.

View File

@@ -251,7 +251,7 @@ describe('rewriteMarkdown', () => {
}) })
describe('docsPages locale routes', () => { describe('docsPages locale routes', () => {
it('publishes every route in both locales and selects paired sources', () => { it('publishes every route in both locales and uses every available Chinese counterpart', () => {
const byRoute = new Map(docsPages.map(page => [page.route, page])) const byRoute = new Map(docsPages.map(page => [page.route, page]))
for (const page of docsPages.filter(page => page.locale === 'root')) { for (const page of docsPages.filter(page => page.locale === 'root')) {
const counterpart = byRoute.get(`en/${page.route}`) const counterpart = byRoute.get(`en/${page.route}`)
@@ -265,6 +265,11 @@ describe('docsPages locale routes', () => {
} else { } else {
expect(counterpart?.source).toBe(page.source) expect(counterpart?.source).toBe(page.source)
expect(counterpart?.contentLocale).toBe(page.contentLocale) expect(counterpart?.contentLocale).toBe(page.contentLocale)
const chineseSource = page.source.replace(/\.md$/, '.zh.md')
expect(
existsSync(resolve(repositoryRoot, chineseSource)),
`${page.route} has a Chinese counterpart but projects English`,
).toBe(false)
} }
} }
}) })
@@ -282,20 +287,16 @@ describe('docsPages locale routes', () => {
} }
}) })
it('projects translated subsystem pages while retaining explicit English fallbacks', () => { it('projects every published subsystem page in Chinese', () => {
const rootPages = docsPages.filter(page => ( const rootPages = docsPages.filter(page => (
page.locale === 'root' && page.route.startsWith('reference/subsystems/') page.locale === 'root' && page.route.startsWith('reference/subsystems/')
)) ))
const translated = rootPages.filter(page => page.contentLocale === 'zh-CN') const translated = rootPages.filter(page => page.contentLocale === 'zh-CN')
const fallbacks = rootPages.filter(page => page.contentLocale === 'en-US') const fallbacks = rootPages.filter(page => page.contentLocale === 'en-US')
expect(translated).toHaveLength(39) expect(translated).toHaveLength(42)
expect(translated.every(page => page.source.endsWith('.zh.md'))).toBe(true) expect(translated.every(page => page.source.endsWith('.zh.md'))).toBe(true)
expect(fallbacks.map(page => page.source).sort()).toEqual([ expect(fallbacks).toEqual([])
'docs/subsystems/commands.md',
'docs/subsystems/goal.md',
'docs/subsystems/pty.md',
])
}) })
it('publishes the Cordis core API under matching locale structures', () => { it('publishes the Cordis core API under matching locale structures', () => {

View File

@@ -226,7 +226,7 @@ const develop = pairedPages([
}, },
]) ])
const cordisTutorial = mirroredPages(([ const cordisTutorial = pairedPages(([
['index.md', 'Cordis 教程', 'Cordis tutorial'], ['index.md', 'Cordis 教程', 'Cordis tutorial'],
['01-first-plugin.md', '1. 第一个插件', '1. Your first plugin'], ['01-first-plugin.md', '1. 第一个插件', '1. Your first plugin'],
['02-lifecycle-and-effects.md', '2. 生命周期与副作用', '2. Lifecycle and effects'], ['02-lifecycle-and-effects.md', '2. 生命周期与副作用', '2. Lifecycle and effects'],
@@ -235,10 +235,9 @@ const cordisTutorial = mirroredPages(([
['05-config.md', '5. 配置', '5. Configuration'], ['05-config.md', '5. 配置', '5. Configuration'],
['06-composition-and-hmr.md', '6. 组合与热重载', '6. Composition and HMR'], ['06-composition-and-hmr.md', '6. 组合与热重载', '6. Composition and HMR'],
['07-into-the-harness.md', '7. 进入 Harness', '7. Into the harness'], ['07-into-the-harness.md', '7. 进入 Harness', '7. Into the harness'],
] as const).map(([file, rootLabel, enLabel], order): MirroredPage => ({ ] as const).map(([file, rootLabel, enLabel], order): PairedPage => ({
source: `docs/cordis-tutorial/${file}`, source: `docs/cordis-tutorial/${file}`,
route: `develop/cordis-tutorial/${file}`, route: `develop/cordis-tutorial/${file}`,
contentLocale: 'en-US',
label: { root: rootLabel, en: enLabel }, label: { root: rootLabel, en: enLabel },
sidebar: { root: 'zh-develop', en: 'en-develop' }, sidebar: { root: 'zh-develop', en: 'en-develop' },
section: { root: 'Cordis 教程', en: 'Cordis tutorial' }, section: { root: 'Cordis 教程', en: 'Cordis tutorial' },
@@ -308,12 +307,11 @@ const subsystemsReference = pairedPages(([
}))) })))
const reference = [ const reference = [
...mirroredPages(([ ...pairedPages(([
['docs/architecture.md', 'reference/index.md', '架构', 'Architecture', 0], ['docs/architecture.md', 'reference/index.md', '架构', 'Architecture', 0],
] as const).map(([source, route, rootLabel, enLabel, order]): MirroredPage => ({ ] as const).map(([source, route, rootLabel, enLabel, order]): PairedPage => ({
source, source,
route, route,
contentLocale: 'en-US',
label: { root: rootLabel, en: enLabel }, label: { root: rootLabel, en: enLabel },
sidebar: { root: 'zh-reference', en: 'en-reference' }, sidebar: { root: 'zh-reference', en: 'en-reference' },
section: { root: '概念', en: 'Concepts' }, section: { root: '概念', en: 'Concepts' },
@@ -369,28 +367,26 @@ const reference = [
section: { root: 'Cordis API', en: 'Cordis Core API' }, section: { root: 'Cordis API', en: 'Cordis Core API' },
order: order + 5, order: order + 5,
}))), }))),
...mirroredPages(([ ...pairedPages(([
['goal.md', '目标', 'Goals', 14], ['goal.md', '目标', 'Goals', 14],
['pty.md', 'PTY 会话', 'PTY sessions', 26], ['pty.md', 'PTY 会话', 'PTY sessions', 26],
['commands.md', '命令', 'Human commands', 38], ['commands.md', '命令', 'Human commands', 38],
] as const).map(([file, rootLabel, enLabel, order]): MirroredPage => ({ ] as const).map(([file, rootLabel, enLabel, order]): PairedPage => ({
source: `docs/subsystems/${file}`, source: `docs/subsystems/${file}`,
route: `reference/subsystems/${file}`, route: `reference/subsystems/${file}`,
contentLocale: 'en-US',
label: { root: rootLabel, en: enLabel }, label: { root: rootLabel, en: enLabel },
sidebar: { root: 'zh-reference', en: 'en-reference' }, sidebar: { root: 'zh-reference', en: 'en-reference' },
section: { root: '子系统', en: 'Subsystems' }, section: { root: '子系统', en: 'Subsystems' },
order, order,
}))), }))),
...mirroredPages(([ ...pairedPages(([
['adding-a-package.md', '新增 Package', 'Adding a package'], ['adding-a-package.md', '新增 Package', 'Adding a package'],
['adding-a-tool.md', '新增 Tool', 'Adding a tool'], ['adding-a-tool.md', '新增 Tool', 'Adding a tool'],
['adding-an-llm-adapter.md', '新增 LLM Adapter', 'Adding an LLM adapter'], ['adding-an-llm-adapter.md', '新增 LLM Adapter', 'Adding an LLM adapter'],
['extension-cookbook.md', '扩展模式', 'Extension patterns'], ['extension-cookbook.md', '扩展模式', 'Extension patterns'],
] as const).map(([file, rootLabel, enLabel], order): MirroredPage => ({ ] as const).map(([file, rootLabel, enLabel], order): PairedPage => ({
source: `docs/cookbook/${file}`, source: `docs/cookbook/${file}`,
route: `reference/cookbook/${file}`, route: `reference/cookbook/${file}`,
contentLocale: 'en-US',
label: { root: rootLabel, en: enLabel }, label: { root: rootLabel, en: enLabel },
sidebar: { root: 'zh-reference', en: 'en-reference' }, sidebar: { root: 'zh-reference', en: 'en-reference' },
section: { root: '开发手册', en: 'Cookbook' }, section: { root: '开发手册', en: 'Cookbook' },