Skip to content
Back to skills

Doc Enforce Truth

ASecurity

SDD documentation truth-check / source-of-truth enforcement — the canonical cross-agent contract. Runs Pass 8 (verification truth-check), Pass 9 (Implements-vs-AC cross-walk), Pass 10 (stale code-block detection), Pass 11 (content-preservation on trim), Pass 12 (stranger cold-read), Pass 15 (doc source-anchor truth-check, ALWAYS runs). Invoked conditionally by doc-enforce when Implemented REQ docs are touched OR scope=all.

  • 25 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 18, 2026
developmentjavascriptgojavanodegitapibackendsecuritydocumentation

Works with

  • api
  • mcp

Security analysis

A100/100

Scanned October 18, 2026

npx -y skills add nikolanovoselec/codeflare --skill doc-enforce-truth --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Doc Enforce Truth?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Doc Enforce Truth
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nikolanovoselec-doc-enforce-truth/badge)](https://www.skillsdirectory.com/skills/nikolanovoselec-doc-enforce-truth)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: doc-enforce-truth
description: SDD documentation truth-check / source-of-truth enforcement — the canonical cross-agent contract. Runs Pass 8 (verification truth-check), Pass 9 (Implements-vs-AC cross-walk), Pass 10 (stale code-block detection), Pass 11 (content-preservation on trim), Pass 12 (stranger cold-read), Pass 15 (doc source-anchor truth-check, ALWAYS runs). Invoked conditionally by doc-enforce when Implemented REQ docs are touched OR scope=all.
version: 4.0.0
---

# Documentation Enforcement — Truth-check passes

This skill cross-references documentation against source code, tests, and REQs to catch stale, mismatched, or lying prose. Invoked by `doc-enforce` (the spine) when Implemented REQ docs are touched or scope=all.

## Inputs

- `purpose`: `review` | `clean` (inherited from parent — `review` reports only; `clean` may fix unambiguous drift but escalates uncertain truth)
- `diff`: git diff against base
- `scope`: `all` | `diff`
- `mode`: `interactive` | `auto` | `unleashed`
- `src_globs`: from `sdd/config.yml`
- `test_globs`: from `sdd/config.yml`

Operate on the direct-impact set from `doc-enforce`; `scope=all` supplies the full corpus. Consume the parent packet without reconstructing the diff or printing whole files. Pass 15 always runs whenever an in-scope doc or changed source can affect an anchor.

## Output

Returns findings array + auto-fix actions. Writes evidence-count rows back to the spine's manifest:
- `Pass 8 — Verification truth-check`: `ran (V fields, F files, M findings)`
- `Pass 9 — Implements-vs-AC cross-walk`: `ran (I fields, M findings)`
- `Pass 10 — Stale code-block detection`: `ran (B blocks, M findings)`
- `Pass 11 — Content-preservation on trim`: `ran (T ops, M findings)` or `inert (no trim ops)`
- `Pass 12 — Stranger cold-read`: `ran (T tasks, M findings)` or `ran (cached, hit on SHA <sha>)`
- `Pass 15 — Doc source-anchor truth-check`: `ran (D docs, A anchors verified, V drift, B broader-than-source, O orphaned, U unanchored)` — ALWAYS runs, never inert. `A anchors verified` counts anchors that RESOLVED; it is not a truth count.

**Layout-awareness.** Doc file discovery uses `documentation/lanes/**/*.md` and `documentation/decisions/**/*.md` when the nested layout exists; falls back to `documentation/*.md` and `documentation/decisions/*.md` on flat layout.

## Pass 8 — Verification truth-check

For every `**Verification:** <test-file>` field, open the cited file and check:

1. The section's `**Implements:** REQ-X-NNN` ID appears in a `describe`/`test`/`it` block name within the cited file.
2. At least one content-word token (>=4 chars, stopwords excluded) from the section's `**Threat:**` or `**Mitigation:**` prose appears anywhere in the cited file.

Neither match: MEDIUM `verification-field-cites-unrelated-test`. The cited file existing on disk is necessary but not sufficient.

Multiple files (comma- or `+`-separated) evaluated independently; if at least one passes, the field passes; first file is load-bearing.

Auto-fix in `auto`/`unleashed`: rewrite failing field to `**Verification:** {kept-files}` (drop unrelated). If every file failed, replace with `**Verification:** audit pending — see documentation/.doc-coverage.md` and append entry.

## Pass 9 — Implements-vs-AC cross-walk

For every `**Implements:** REQ-X-NNN` (or `REQ-X-NNN AC N`) field, read the linked REQ's Intent and ACs and classify the section-vs-REQ relationship:

| Classification | Severity | Auto-fix |
|---|---|---|
| (a) Section describes a specific AC's behaviour, cited AC matches | no finding | Accept |
| (b) Section describes generic REQ context, field cites REQ without AC suffix | no finding | Accept |
| (b') Section describes generic context but field cites specific AC | MEDIUM `implements-field-too-narrow` | Strip AC suffix |
| (c) Section describes behaviour outside every AC of linked REQ | HIGH `implements-field-mismatched` | Replace with better-match REQ or mark audit pending |

If multiple ACs plausibly match: MEDIUM `implements-field-low-confidence` rather than auto-rewrite. Under-flag rather than over-rewrite.

## Pass 10 — Stale code-block detection

For every fenced code block, `**Path:** /api/foo` field, function signature in body, JSON shape example, resolve against `src_globs` from `sdd/config.yml`:

1. **Route paths**: any `**Path:**` or fenced block whose first line is HTTP method + path. Resolve via filename convention. HIGH `route-not-in-source` if no handler resolves; MEDIUM `route-handler-renamed` if near-match at sibling path.
2. **Function signatures**: any `function foo(...)` etc. in body prose or fenced TS/JS. Resolve via `src/**` grep. MEDIUM `function-signature-drift` if different params/types. HIGH `function-removed` if no longer exported.
3. **JSON shape examples**: any fenced `json` block paired with `**Response:**`/`**Request:**`. Compare top-level keys against matching TS type. MEDIUM `json-example-shape-drift`. Prefer `tests/fixtures/` fixture when present.
4. **Env var references**: any `**Variable:** FOO_BAR` or `env.FOO_BAR`. Grep `src/**`. HIGH `env-var-removed-from-source` if no consumer.

Auto-fix in `auto`/`unleashed`: for shape-drift, regenerate from source. Never delete a stale block silently; replace or flag.

## Pass 11 — Content-preservation on trim

When the spine proposes a Pass 1 trim, tokenise removed content clause-by-clause. For each removed clause, check whether its content tokens reappear in: the kept body, surrounding prose, parent section's `**Rationale:**`/`**Consequences:**`/`**Context:**`, or linked ADR body.

Three outcomes:
- All removed clauses match elsewhere: trim commits as-is.
- Some clauses are context-loss but relocation exists (adjacent paragraph, ADR, parent prose): promote with leading `Trimmed from <bullet/section> on <date>:` marker, then commit. Commit body lists `trimmed N clauses; preserved K; promoted M to {target}`.
- Clauses are context-loss with no relocation target: trim is REVERTED. MEDIUM `trim-would-lose-load-bearing-content` listing the bullet and clauses. Cap violation persists; content preserved.

## Pass 12 — Stranger cold-read

For each top-level canonical file, dispatch a fresh subagent (`general-purpose` subtype; **not** `doc-updater`, must come in cold) with: (i) only the contents of the one doc file, (ii) a simulated task. Default task registry:

| File | Simulated task |
|---|---|
| `api-reference.md` | "Call the most-used public endpoint and parse the response. Output the exact curl command + field list." |
| `api-reference-admin.md` | "Manually trigger a backend job listed in this file. Output exact request + success signal." |
| `architecture.md` | "Find the source file that owns request authentication for admin endpoints. Output the path." |
| `configuration.md` | "List every env var the dev-bypass code path consumes. Output: name, type, default, consumed where." |
| `deployment.md` | "Roll back the last production deploy. Output exact commands in order + verification between steps." |
| `security.md` | "External researcher claims session cookie is readable from JavaScript on prod. Refute or confirm using only the doc; output load-bearing sentence." |
| `troubleshooting.md` | "User reports 500 after login. Output first three diagnostic steps from the doc." |
| `decisions/README.md` | "Why was the most recent ADR raised? Output ADR ID and one-line reason." |

Subagent reports `succeeded` / `partial` / `failed`. Partial and failed: MEDIUM `stranger-cold-read-gap` naming the specific information the doc failed to surface.

Project-overridable via `documentation/.cold-read-tasks.yml`. Pass runs at most once per PR-boundary trigger (caches on commit SHA + file mtime). No auto-fix; signal only; written to `documentation/.doc-coverage.md` under `## Cold-read gaps`.

## Pass 15 — Doc source-anchor truth-check (ALWAYS runs)

Pass 15 is the doc-lane mirror of `spec-enforce-truth` CQ-SOURCE. It enforces the Truth guarantee for documentation: every load-bearing fact in a lane file must trace to source either via inline `<!-- @impl: <path>::<symbol>[ = <value-pattern>] -->` anchor OR via REQ backlink to a spec REQ whose AC carries an anchor (transitive verification).

**This pass runs unconditionally** — independent of `enforce_tdd`, independent of SDD transition state. Doc content that lies about source is the failure mode this guarantee exists to prevent.

### Scope and detection

Walk every `documentation/lanes/**/*.md` file (or `documentation/*.md` flat) plus `documentation/decisions/README.md`. Within each file, identify load-bearing facts:

1. **Build-constants tables** in `configuration.md` (rows like `kMaxRetries | constants.dart | 3`).
2. **Persistence claims** in `architecture.md` (lines like "├─ persist to shared_preferences (UUID key)", "stored in D1 column session_version").
3. **Lifecycle arrows** in `architecture.md` Request Lifecycles sections.
4. **ADR `Context:` blocks** in `documentation/decisions/README.md` (the chosen-path Context paragraph).
5. **Per-endpoint contracts** in `api-reference*.md` (Method/Path triplets).
6. **Per-control claims** in `security.md` (Threat → Mitigation citing specific source mechanism).
7. **Per-signal entries** in `observability.md` (event names from the structured-log emitter).

Each load-bearing fact must satisfy ONE of:

- (a) Carries inline `<!-- @impl: <path>::<symbol>[ = <value-pattern>] -->` HTML comment trailing the fact (single line) or trailing the section's title line (section-wide anchor).
- (b) Section header carries `(REQ-X-NNN)` backlink AND the linked REQ's AC carries an anchor that CQ-SOURCE has validated.

### Validation contract — Phase 7a is the canonical implementation

During `/sdd init`, anchor validation across both `sdd/**/*.md` and `documentation/**/*.md` is performed by the Phase 7a verifier (`~/.claude/skills/sdd-init/references/verify-source-anchors.py`). Pass 15 consumes the resulting JSON (`.verify-anchors.json`) rather than re-deriving — see `sdd-init/SKILL.md` step 7. The agent never claims "I checked the doc anchors" without the verifier output line in the commit body; that self-attestation is **CRITICAL `phase-7a-self-attestation`** (catalogued in `sdd-init`).

Outside `/sdd init` (steady-state doc-updater on existing lane files), Pass 15 performs the checks inline using the same algorithm:

For each direct `<!-- @impl: ... -->` comment in a doc file:

1. **Resolve symbol** via `mcp__graphify__get_node(<symbol>)`. Fallback: grep `<symbol>` in `<path>`. Symbol not resolved → HIGH `doc-anchor-orphaned` listing file, section, anchor.
2. **Verify value (when `<value-pattern>` present).** Grep symbol body for literal pattern. Not found → HIGH `doc-value-drift`.
3. **Verify behaviour overlap (when no `<value-pattern>`).** Token overlap between the fact's surrounding prose (≥4-char content words) and the symbol body must be ≥3. Below threshold → MEDIUM `doc-behavior-orphaned`.
4. **Verify the claim, not the vocabulary.** Overlap answers "is this the right symbol"; it never answers "is the documented fact true", and passing it discharges nothing. Read the resolved body and check what the prose actually claims — especially its scope words. A fact claiming *every*, *any*, *all* or *always* against a body that handles some is MEDIUM `doc-claim-broader-than-source`, listing file, the claim and the case the source does not cover. Documentation stating a narrower truth is never a finding; documentation stating a wider one is, because a reader takes the wider claim and stops checking. This is the doc mirror of CQ-SOURCE's `spec-claim-contradicted`, and it fails the same way: the overlap is strongest exactly where the prose enumerates the cases, which is where an over-broad claim is written.

For each load-bearing fact WITHOUT direct anchor AND WITHOUT REQ backlink: MEDIUM `doc-fact-not-anchored` listing file, section, the fact. Auto-fix in `auto`/`unleashed`: best-effort retrofit — attempt to source-scan the fact's noun phrase against the project source via graphify; on plausible match, insert `<!-- @impl: ... -->`. On no plausible match, escalate to `documentation/.doc-coverage.md` under `## Anchor gaps`.

### Block-emit at /sdd init time

When Pass 15 runs as part of `/sdd init`'s Phase 7a (and downstream step 8 iterate-to-clean), any HIGH finding blocks the file write. Doc-updater retries: source-scan for plausible anchors, regenerate the section, attempt emit again. On second-pass failure, the section content becomes a `sdd/spec/.review-queue.md` entry instead of being emitted. The Phase 7a verifier is the deterministic source of these findings — see `sdd-init/SKILL.md` step 7 for the CRITICAL anti-substitution catalogue.

The block-emit rule is `/sdd init`-specific because that's the one moment where the agent can hold the entire lane file in-memory and choose not to commit a fabricated fact. Steady-state doc-updater on existing files cannot rewrite history; it flags and escalates.

### Cross-reference: spec CQ-SOURCE

CQ-SOURCE (in `spec-enforce-truth`) verifies the spec side. Pass 15 verifies the doc side. They share the `@impl` convention but operate independently. The cleanest signal that the framework is truthful end-to-end: both pass with zero HIGH findings.

## Severity application

| Severity | Definition |
|---|---|
| **HIGH** | `route-not-in-source`, `function-removed`, `env-var-removed-from-source`, `implements-field-mismatched` (Pass 9 case c), `doc-anchor-orphaned`, `doc-value-drift` |
| **MEDIUM** | `verification-field-cites-unrelated-test`, `route-handler-renamed`, `function-signature-drift`, `json-example-shape-drift`, `implements-field-too-narrow`, `implements-field-low-confidence`, `trim-would-lose-load-bearing-content`, `stranger-cold-read-gap`, `doc-behavior-orphaned`, `doc-fact-not-anchored` |
| **LOW** | none in this skill |

Mode-dependent action mirrors the spine. Pass 15 HIGH findings (`doc-anchor-orphaned`, `doc-value-drift`) NEVER silently rewrite — Truth findings always escalate to `documentation/.doc-coverage.md` (or `sdd/spec/.review-queue.md` when fired during `/sdd init`).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.