Quellcode durchsuchen

docs: address Codex review of the RFC reorg

- Fix two root-AGENTS.md cross-links that the depth bump left pointing at the
  new docs/AGENTS.md instead of the root file they cite (capability-seams,
  optional-code-mode). These resolved on disk so verify-md-links passed — the
  gate checks existence, not which file you meant; corrected to ../../../.
- Broaden verify-md-links scope to .agents/skills/**/*.md: this PR rewrote the
  dsh-code-review skill's links into the RFC tree, but the skill dir was outside
  the gate, so a broken skill link would have passed silently.
- Percent-decode the path component before the existence check, so a valid
  encoded relative target (My%20File.md) is not falsely reported broken; a
  malformed escape (%zz) is reported broken rather than crashing the gate.
- Drop the merged property-testing RFC's "nightly CI job 100x" claim: that line
  came from the original proposal, not the accepted decision, and CI has only
  push/pull_request triggers — note it as possible future work instead.

doc-sync (incl. verify-md-links over 58 files), doc-typecheck, lint pass.
Tianyi Cui vor 3 Monaten
Ursprung
Commit
27f5f84e3b

+ 1 - 1
docs/rfc/implemented/2026-06-11-property-based-testing.md

@@ -12,7 +12,7 @@ Example-based tests pin the cases we thought of. The harness's core is protocol-
 
 ## Decision
 
-Adopt `fast-check` (a root devDependency) with one `tests/properties.spec.ts` per protocol-shaped package, generators tuned for *realistic-but-adversarial* inputs (not uniform noise) and `numRuns` kept so the suite stays well under ~10s locally, with a nightly CI job running 100× the iterations. Failures print a reproducible seed.
+Adopt `fast-check` (a root devDependency) with one `tests/properties.spec.ts` per protocol-shaped package, generators tuned for *realistic-but-adversarial* inputs (not uniform noise) and `numRuns` kept so the suite stays well under ~10s locally. Failures print a reproducible seed. (The original proposal also sketched a nightly CI job running 100× the iterations; that was not shipped — the property suite runs only in the normal `push`/`pull_request` CI, and a scheduled high-iteration job remains possible future work.)
 
 - **dsh-llm / BlockAssembler:** arbitrary chunk streams (valid + malformed: duplicate indices, stragglers, missing block-start). Invariants: `flushReady()+flushRemaining() ≡ blocks()` in order; the streamed prefix is always a prefix of final `blocks()`; partial count ≤ distinct indices; re-assembly idempotent.
 - **dsh-session:** arbitrary event logs. Invariants: `deriveMessages` deterministic; replay-from-seed identical; seq strictly monotonic; non-message events never affect derived history; derived content is decoupled from the log.

+ 1 - 1
docs/rfc/implemented/2026-06-13-capability-seams.md

@@ -26,4 +26,4 @@ The split is not mandatory when the parts are genuinely one concern: the LLM sea
 
 ## Consequences
 
-More packages and more boilerplate per capability (a `package.json`/`tsconfig`/README trio, the inject wiring). Bought: implementations and consumers ship and version independently, and a new backend never risks the model-facing contract. The rule is documented in [AGENTS.md](../../AGENTS.md) § Conventions ("Capability seams are three packages") and [architecture.md](../../architecture.md) § "Capability seams"; the bash trio is the reference template. When to fold vs. split is a judgment call the architecture doc spells out — this RFC records *why* the default is to split.
+More packages and more boilerplate per capability (a `package.json`/`tsconfig`/README trio, the inject wiring). Bought: implementations and consumers ship and version independently, and a new backend never risks the model-facing contract. The rule is documented in [AGENTS.md](../../../AGENTS.md) § Conventions ("Capability seams are three packages") and [architecture.md](../../architecture.md) § "Capability seams"; the bash trio is the reference template. When to fold vs. split is a judgment call the architecture doc spells out — this RFC records *why* the default is to split.

+ 1 - 1
docs/rfc/implemented/2026-06-18-markdown-cross-link-lint.md

@@ -16,7 +16,7 @@ A fourth `doc-sync` gate, `verify-md-links` (`scripts/verify-md-links.ts`), mirr
 - Check a target only when it is a **relative path**. Skip scheme-qualified URLs (`https:`, `mailto:`, …), protocol-relative (`//host`), root-absolute (`/path` — no stable base in a checkout), and pure in-page anchors (`#section`). Strip any `#fragment`/`?query`, resolve the path against the linking file's directory, and assert it exists on disk.
 - Report and never rewrite; exit non-zero on the first broken link found.
 
-Scope matches the other gates plus the AGENTS.md pair: `README.md`, `docs/**/*.md`, `packages/*/README.md`, `AGENTS.md`, `packages/AGENTS.md`, deduped by real path (the `CLAUDE.md` symlinks resolve onto the AGENTS.md files). It is wired into the `doc-sync` script that the lefthook pre-push hook and CI both run, so a broken link fails locally before a push — consistent with [mechanical quality gates](2026-06-11-quality-gates.md).
+Scope matches the other gates plus the AGENTS.md pair and the repo-authored agent-skill Markdown under `.agents/skills/` (those skill files cross-link into the docs tree, so this reorg rewrote links in them too): `README.md`, `docs/**/*.md`, `packages/*/README.md`, `AGENTS.md`, `packages/AGENTS.md`, `.agents/skills/**/*.md`, deduped by real path (the `CLAUDE.md` symlinks resolve onto the AGENTS.md files). It is wired into the `doc-sync` script that the lefthook pre-push hook and CI both run, so a broken link fails locally before a push — consistent with [mechanical quality gates](2026-06-11-quality-gates.md).
 
 This gate checks *existence*, not anchor validity: a link to a real file with a `#wrong-heading` fragment still passes (the file resolves; the fragment is stripped). Anchor-level checking is a heavier, lower-value follow-up — file-level dead links are the failure that actually bit us.
 

+ 1 - 1
docs/rfc/proposed/2026-06-15-optional-code-mode.md

@@ -38,7 +38,7 @@ Per the "explicit > implicit at seams" convention, the request spells out every
 
 These are illustrations of the seam's reach, **not commitments** — the MVP ships only the TypeScript path. The honest caveat is that the *execution* contract is language-agnostic but the *presentation* is not: the SDK-generation pipeline below (§3a and the `jsonSchemaToTs` codegen, which emits a TypeScript `.d.ts`) is TypeScript-specific, so a non-TS backend pairs the shared `CodeRuntime` contract with its own language-appropriate SDK generator and system-prompt section (a `.pyi` stub and Python usage instructions for the Python backend, AssemblyScript-flavored types for that one). The runtime seam is reused as-is; only the codegen/prompt half is per-language.
 
-**2. Implementation package `packages/code-runtime-vm/`** — a new package `@deepseek-ai/dsh-code-runtime-vm`, the `node:vm` reference stub. It type-erases the model's TypeScript via the compiler's `transpileModule` (or sucrase) — the types exist only to guide the model; the runtime is plain JS — then wraps the body in an async IIFE for top-level `await` (Cloudflare's `NodeVMExecutor` does literally `new AsyncFunction("codemode", "return await (${code})()")`), runs it in a `vm.Context` whose globals are a capturing `console` and the SDK namespace objects, awaits the IIFE, and captures the return value, the buffered logs, and any thrown error (as `error: string`). It applies an **output cap** (truncate captured logs) and a **timeout tied to `request.signal`**. These caps limit blast radius; **they are not a security boundary**. node:vm is **not** isolation: withholding `require`/`process` does not contain anything (code escapes via `constructor`/prototype reflection), and per [AGENTS.md](../../AGENTS.md) the harness must never hand model output the ambient environment.
+**2. Implementation package `packages/code-runtime-vm/`** — a new package `@deepseek-ai/dsh-code-runtime-vm`, the `node:vm` reference stub. It type-erases the model's TypeScript via the compiler's `transpileModule` (or sucrase) — the types exist only to guide the model; the runtime is plain JS — then wraps the body in an async IIFE for top-level `await` (Cloudflare's `NodeVMExecutor` does literally `new AsyncFunction("codemode", "return await (${code})()")`), runs it in a `vm.Context` whose globals are a capturing `console` and the SDK namespace objects, awaits the IIFE, and captures the return value, the buffered logs, and any thrown error (as `error: string`). It applies an **output cap** (truncate captured logs) and a **timeout tied to `request.signal`**. These caps limit blast radius; **they are not a security boundary**. node:vm is **not** isolation: withholding `require`/`process` does not contain anything (code escapes via `constructor`/prototype reflection), and per [AGENTS.md](../../../AGENTS.md) the harness must never hand model output the ambient environment.
 
 **The unsafe-runtime guard is enforceable, not a README warning.** Because a README caveat is not a control — and AGENTS.md's "never hand model output ambient authority" is a hard rule, not advice — the design makes the danger refuse to run by construction. Two layers:
 

+ 36 - 8
scripts/verify-md-links.ts

@@ -20,10 +20,13 @@
  * resolved against the linking file's directory, and the result must exist on
  * disk. This is checker, not fixer: it reports and never rewrites.
  *
- * Scope mirrors the other doc-sync gates plus the two AGENTS.md files:
- * README.md, docs/** /*.md, packages/* /README.md, AGENTS.md, packages/AGENTS.md.
- * The root and packages/ CLAUDE.md are symlinks to the AGENTS.md files, so they
- * are deduped by real path.
+ * Scope is the other doc-sync gates' set plus the two AGENTS.md files AND the
+ * repo-authored agent-skill Markdown under `.agents/skills/` — those skill
+ * files cross-link into the docs tree (e.g. the dsh-code-review skill cites the
+ * RFC index), so a rename must not silently break them either: README.md,
+ * docs/** /*.md, packages/* /README.md, AGENTS.md, packages/AGENTS.md,
+ * .agents/skills/** /*.md. The root and packages/ CLAUDE.md are symlinks to the
+ * AGENTS.md files, so they are deduped by real path.
  *
  * Run: `tsx scripts/verify-md-links.ts`.
  */
@@ -38,8 +41,18 @@ import type { Nodes } from 'mdast'
 
 const root = resolve(import.meta.dirname, '..')
 
-/** Files to check: doc-typecheck's scope plus the AGENTS.md pair. */
-const PATTERNS = ['README.md', 'docs/**/*.md', 'packages/*/README.md', 'AGENTS.md', 'packages/AGENTS.md']
+/**
+ * Files to check: doc-typecheck's scope, the AGENTS.md pair, and repo-authored
+ * agent-skill Markdown (which this repo's own docs reorg rewrites links in).
+ */
+const PATTERNS = [
+  'README.md',
+  'docs/**/*.md',
+  'packages/*/README.md',
+  'AGENTS.md',
+  'packages/AGENTS.md',
+  '.agents/skills/**/*.md',
+]
 
 /** A broken relative link: a target path that does not resolve to a file. */
 interface Violation {
@@ -62,9 +75,24 @@ function isExternalOrAnchor(url: string): boolean {
   return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(url)
 }
 
-/** Strip the `#fragment` and `?query` from a link target, leaving the path. */
+/**
+ * Strip the `#fragment` and `?query` from a link target, then percent-decode
+ * the remaining path so an encoded target (`My%20File.md`, `READ%4DE.md`)
+ * probes the real filename on disk, the way a Markdown renderer resolves it. A
+ * malformed escape (`%zz`) makes `decodeURIComponent` throw; we keep the raw
+ * path in that case so the link is reported as broken (a `%zz` target is not a
+ * file anyone meant to link) rather than crashing the gate.
+ */
 function pathPart(url: string): string {
-  return url.replace(/[#?].*$/, '')
+  const raw = url.replace(/[#?].*$/, '')
+  try {
+    return decodeURIComponent(raw)
+  } catch {
+    // decodeURIComponent throws only on a malformed percent-escape; the raw
+    // string is then a path no renderer resolves, so fall through to the
+    // existence check, which reports it broken.
+    return raw
+  }
 }
 
 /** Find every broken relative cross-link in one Markdown file via its AST. */