docguard-cli 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PHILOSOPHY.md CHANGED
@@ -1,172 +1,125 @@
1
1
  # The Philosophy of Canonical-Driven Development
2
2
 
3
- > Why documentation must come first in the age of AI agents.
3
+ > Why every codebase needs a living, machine-readable memory and how DocGuard builds and maintains one.
4
4
 
5
5
  ---
6
6
 
7
7
  ## The Problem We're Solving
8
8
 
9
- In 2026, AI coding agents can write thousands of lines of code in minutes. They can scaffold entire applications, implement complex features, and refactor entire codebases.
9
+ In 2026, AI coding agents can write thousands of lines of code in minutes. But they have a fatal flaw: **they don't remember.**
10
10
 
11
- But they have a fatal flaw: **they don't remember.**
11
+ Every new session, every new agent, every new conversation starts from zero. The agent re-reads your code, re-derives how the system works, makes assumptions, and builds on them. Humans hit the same wall: a new contributor faces 500 files and a 50-line README.
12
12
 
13
- Every new session, every new agent, every new conversation starts from zero. The agent reads your code, makes assumptions, and builds on those assumptions. If the assumptions are wrong, the code drifts. If the code drifts long enough, nobody — human or AI — knows what the system was supposed to do in the first place.
13
+ This is the **comprehension crisis of the AI era:**
14
14
 
15
- This is the **documentation crisis of the AI era:**
16
-
17
- > The faster AI writes code, the faster projects lose their design intent.
15
+ > The faster AI writes code, the faster everyone loses the map of what was built.
18
16
 
19
17
  ---
20
18
 
21
19
  ## The Insight
22
20
 
23
- The solution isn't to write better code. It's to write better **canonical documentation** and make it machine-enforceable.
21
+ A project needs a **canonical memory** — a complete, structured, always-current description of what the system *is*: every endpoint, screen, entity, the architecture, the tech stack, the setup. Written so an AI agent (or a human) can load it in seconds and understand the whole project without re-reading the code.
24
22
 
25
- > **Canonical** (adj.): accepted as being accurate and authoritative; the standard form.
23
+ DocGuard's job is to **build that memory from the code, keep it true as the code changes, and protect the human reasoning inside it.**
26
24
 
27
- When every AI agent starts by reading canonical documentation that describes what the system IS, what it SHOULD do, and where it has DRIFTED — the agent doesn't need to guess. It doesn't need to reverse-engineer intent from code. It has the source of truth, in a format it can understand instantly.
25
+ > **Canonical** (adj.): accepted as accurate and authoritative; the standard form.
28
26
 
29
27
  ---
30
28
 
31
29
  ## The Three Pillars of CDD
32
30
 
33
- ### Pillar 1: Documentation IS the Source of Truth
34
-
35
- In traditional development, code is the source of truth. Documentation is an afterthought — written after code (if at all), rarely updated, and quickly stale.
36
-
37
- In CDD, this is inverted:
38
-
39
- | Traditional | CDD |
40
- |-------------|-----|
41
- | Code first, docs maybe | Docs first, code conforms |
42
- | Docs describe code | Code implements docs |
43
- | Docs rot silently | Drift is tracked explicitly |
44
- | Docs are optional | Docs are required and validated |
31
+ ### Pillar 1: Documentation is a first-class, validated artifact
45
32
 
46
- This doesn't mean you write a 500-page specification before writing any code. It means:
47
- - When starting a project, write `ARCHITECTURE.md` before `index.ts`
48
- - When adding a feature, update `FEATURES.md` before opening your editor
49
- - When the code deviates, log it in `DRIFT-LOG.md` instead of pretending the docs are wrong
33
+ In traditional development, docs are an afterthought — written late (if at all), never updated, quickly stale. CDD makes documentation a **required, validated, and maintained** artifact, on the same footing as tests. If it isn't validated on every change, it rots; so DocGuard validates it.
50
34
 
51
- ### Pillar 2: Two Tiers, Two Purposes
35
+ ### Pillar 2: Two tiers derived truth and human reasoning
52
36
 
53
- CDD separates documentation into two tiers:
37
+ CDD separates documentation into two kinds of content, and treats them differently:
54
38
 
55
- **Canonical docs** (`docs-canonical/`) are the blueprint. They represent design intent what we WANT the system to be. They're updated deliberately, through design decisions, not as a side effect of coding.
39
+ - **Code-derived** (endpoints, entities, screens, tech stack, env vars): DocGuard generates and re-generates these *from the code*. They are mechanical, and DocGuard owns them.
40
+ - **Human reasoning** (the "why", design intent, trade-offs, gotchas): authored by people (or an AI agent), and **never overwritten** by the tool.
56
41
 
57
- **Implementation docs** (`docs-implementation/`) are the map. They represent current state — what we HAVE built. They're updated as code changes, reflecting reality.
42
+ DocGuard keeps these in the same readable markdown using section markers
43
+ (`<!-- docguard:section id=… source=code -->`), so it can refresh the derived
44
+ parts surgically while leaving your writing untouched.
58
45
 
59
- The gap between these two tiers is **drift** and drift is not a bug, it's a feature. Real projects always have some gap between intent and reality. CDD acknowledges this and provides a structured way to track it (`DRIFT-LOG.md`), instead of the traditional approach of either:
60
- - Pretending the docs are still accurate (lying)
61
- - Silently updating docs to match the broken code (losing intent)
46
+ ### Pillar 3: Generate AND Guardbidirectional, continuous
62
47
 
63
- ### Pillar 3: Machine-Enforceable, Not Machine-Generated
48
+ Earlier versions of this document framed CDD as "validate code against docs, never generate docs from code." Experience proved that too narrow. The tool people actually want does **both directions, continuously:**
64
49
 
65
- Many tools generate docs from code. CDD does the opposite: it validates code against docs.
50
+ | Direction | Mode | What it does |
51
+ |-----------|------|--------------|
52
+ | code → docs | **Generate** | Reverse-engineer a complete canonical memory from any codebase. DocGuard scans and builds the code-truth skeleton; an AI agent writes the prose. |
53
+ | code ↔ docs | **Sync** | When code changes, refresh the affected doc sections automatically — mechanical where deterministic, agent-assisted for prose. |
54
+ | docs ↔ code | **Guard** | Validate that the memory still matches reality. Catch documented-but-deleted endpoints, undocumented routes, missing tests, unlogged drift. |
66
55
 
67
- This is a fundamental philosophical difference:
68
-
69
- | Generated Docs (traditional) | Enforced Docs (CDD) |
70
- |------------------------------|---------------------|
71
- | Machine reads code → produces docs | Machine reads docs → validates code |
72
- | Docs always match code (including bugs) | Docs represent intent (bugs are caught as drift) |
73
- | Docs are disposable artifacts | Docs are authoritative sources |
74
- | No governance, no warnings | Validators catch misalignment |
75
-
76
- DocGuard CAN generate docs from existing codebases (for adoption). But the intent is that once generated, those docs become the canonical source — and future code must conform to them.
56
+ The CLI orchestrates (scan, structure, verify); the AI agent does the language-specific writing. Together they keep the memory both **complete** and **accurate**.
77
57
 
78
58
  ---
79
59
 
80
- ## Why Now?
81
-
82
- Three forces are converging in 2025-2026 that make CDD necessary:
60
+ ## Complete + Accurate = Trustworthy
83
61
 
84
- ### 1. AI Agents Are Becoming Primary Developers
62
+ A memory is only useful if you can trust it. DocGuard measures two things:
85
63
 
86
- AI agents (Claude, Gemini, Copilot, Cursor) are writing an increasing share of production code. These agents need structured context to work effectively. The better the documentation, the better the output.
64
+ - **Completeness** is the map whole? (No missing chapters: architecture, data model, API surface, screens, environment.)
65
+ - **Accuracy** — does the map match the territory? (The documented endpoints exist; the documented env vars are used; the schemas match the models.)
87
66
 
88
- ### 2. Multi-Agent Development Is Real
89
-
90
- It's common for a single project to be worked on by Claude Code, Copilot, Cursor, and a human — sometimes in the same week. Each agent needs a common source of truth. `AGENTS.md` provides behavioral rules; canonical docs provide design knowledge.
91
-
92
- ### 3. The Documentation Crisis Is Accelerating
93
-
94
- AI makes it trivially easy to add code. Nobody is making it easy to maintain documentation. The result: projects with 100,000 lines of code and a 50-line README. CDD addresses this by making documentation a first-class, validated artifact.
67
+ A document can be beautifully formatted and completely wrong. DocGuard's validators that compare docs against **code truth** are what make a green check mean something — and when a check has nothing to validate, it says so honestly instead of showing a misleading pass.
95
68
 
96
69
  ---
97
70
 
98
- ## CDD and Other Methodologies
99
-
100
- CDD doesn't replace existing methodologies. It enhances them:
101
-
102
- ### CDD + TDD (Test-Driven Development)
103
- Write canonical docs first. The TEST-SPEC.md in your canonical docs declares what tests must exist. TDD then drives the implementation of those tests. CDD governs the test policy; TDD governs the test implementation.
104
-
105
- ### CDD + BDD (Behavior-Driven Development)
106
- Behavior specifications can live in `docs-canonical/FEATURES.md`. BDD's Given/When/Then scenarios become part of the canonical record. DocGuard can validate that corresponding E2E tests exist.
71
+ ## Any language, any project
107
72
 
108
- ### CDD + SDD (Spec-Driven Development)
109
- SDD tools like GitHub Spec Kit handle the generation phase (spec code). CDD adds the governance phase (code ↔ spec, continuously). Use Spec Kit for Phase 1-2 of the CDD lifecycle, then DocGuard for Phase 3-4.
110
-
111
- ### CDD + Agile/Scrum
112
- Canonical docs don't need to be waterfall-length documents. A 30-line `ARCHITECTURE.md` is valid. The key is that it EXISTS, is MAINTAINED, and is VALIDATED. Sprint-by-sprint, canonical docs grow alongside the codebase.
73
+ DocGuard documents **any** project, not just web/JS. It detects the ecosystem
74
+ (JavaScript/TypeScript, Python, Rust, Go, Java/Kotlin, Ruby, PHP, C#) and any
75
+ polyglot/monorepo mix, then builds a memory shaped for that project: a Rust CLI
76
+ gets a Rust-shaped doc set; a Django app a Django-shaped one; a React app gets
77
+ its screens and components.
113
78
 
114
79
  ---
115
80
 
116
- ## The CDD Promise
117
-
118
- If your project follows CDD:
119
-
120
- 1. **Any AI agent can onboard** to your project in seconds — not minutes of code analysis, but seconds of reading structured documentation.
121
-
122
- 2. **Design intent is never lost** — even when the original developer leaves, the canonical docs preserve WHY the system was designed the way it was.
123
-
124
- 3. **Drift is conscious** — every deviation from the plan is documented, justified, and trackable. No silent rot.
125
-
126
- 4. **Quality is enforceable** — DocGuard validators run in CI/CD, catching missing tests, undocumented routes, and unlogged drift before code ships.
81
+ ## Why Now?
127
82
 
128
- 5. **Documentation stays alive** because it's validated on every commit, docs can't rot. If code changes, DocGuard catches the misalignment.
83
+ 1. **AI agents are primary developers.** They need structured context to work well. A canonical memory is the highest-leverage context you can give them.
84
+ 2. **Multi-agent development is real.** Claude Code, Copilot, Cursor, and humans touch the same repo in the same week. They need one shared, current source of truth.
85
+ 3. **Code volume is exploding; comprehension isn't keeping up.** AI makes adding code trivial. DocGuard makes *understanding* it trivial — and keeps that understanding current.
129
86
 
130
87
  ---
131
88
 
132
- ## Getting Started
89
+ ## The Lifecycle
133
90
 
134
- CDD is designed for progressive adoption:
91
+ ```
92
+ generate ──▶ guard ──▶ sync ──▶ guard ──▶ …
93
+ (build) (verify) (keep (verify)
94
+ current)
95
+ ```
135
96
 
136
- **Day 1**: Create `AGENTS.md` and `docs-canonical/ARCHITECTURE.md`. Two files. That's CDD.
97
+ - **Day 1:** `docguard generate --plan` a complete first-draft memory of your repo (agent fills the prose).
98
+ - **Every change:** `docguard sync` refreshes the derived sections; `docguard guard` verifies; the agent updates prose where flagged.
99
+ - **Forever:** the memory stays complete and true. Any agent or human can understand your project in seconds.
137
100
 
138
- **Week 1**: Add `DATA-MODEL.md`, `SECURITY.md`, `TEST-SPEC.md`, `ENVIRONMENT.md`. Run `docguard audit` to see your score.
101
+ ---
139
102
 
140
- **Month 1**: Add `DRIFT-LOG.md`, `CHANGELOG.md`. Run `docguard guard` in your pre-commit hook. You're now fully CDD-compliant.
103
+ ## CDD and Other Methodologies
141
104
 
142
- **Forever**: Every commit is validated. Every drift is logged. Every agent understands your project.
105
+ - **+ Spec Kit (SDD):** Spec Kit generates code from specs (the build phase); DocGuard maintains the living memory and governance afterward. DocGuard ships as a Spec Kit extension.
106
+ - **+ TDD/BDD:** `TEST-SPEC.md` declares what must be tested; DocGuard verifies the tests exist; TDD/BDD drive their implementation.
107
+ - **+ Agile:** the memory grows sprint by sprint alongside the code. A 30-line `ARCHITECTURE.md` that is complete, current, and validated beats a 300-page document that's stale.
143
108
 
144
109
  ---
145
110
 
146
111
  ## Academic Foundations
147
112
 
148
- CDD is a practitioner methodology, but its core patterns align with peer-reviewed research in AI-driven documentation and quality evaluation:
149
-
150
- ### The Three-Stage Pipeline
151
-
152
- DocGuard's architecture follows a **generate → validate → evaluate** pipeline inspired by the AITPG framework (Lopez et al., IEEE TSE 2026), which demonstrated that multi-agent debate over RAG-grounded standards produces 32% more comprehensive documentation while maintaining semantic alignment with expert references.
153
-
154
- ### Calibrated Quality Evaluation
113
+ CDD is a practitioner methodology whose patterns align with peer-reviewed research:
155
114
 
156
- DocGuard's quality scoring (HIGH/MEDIUM/LOW labels, multi-signal composite scores) adapts the Calibrated Judge Evaluation (CJE) framework from TRACE (Lopez et al., IEEE TMLCN 2026), which showed that weighted multi-signal scoring with confidence intervals provides actionable quality gating for enterprise deployment.
115
+ - **Generate validate evaluate pipeline** inspired by the AITPG framework (Lopez et al., IEEE TSE 2026): multi-agent generation grounded in standards produces more comprehensive documentation while staying semantically aligned with expert references.
116
+ - **Calibrated quality evaluation** — DocGuard's HIGH/MEDIUM/LOW labels and multi-signal scoring adapt the CJE framework from TRACE (Lopez et al., IEEE TMLCN 2026).
117
+ - **Standards-grounded generation** — each canonical document maps to a relevant standard (arc42, C4, OWASP ASVS, ISO 29119, OpenAPI, 12-Factor App).
157
118
 
158
- ### Standards-Grounded Generation
159
-
160
- Both AITPG and TRACE demonstrate that grounding AI-generated content in vectorized standards (ISO 29119, 3GPP) dramatically improves output quality. DocGuard applies this principle by mapping each canonical document to its relevant industry standard (arc42, C4, OWASP ASVS, ISO 29119, OpenAPI 3.1, 12-Factor App).
161
-
162
- > **Full citations**: See [CONTRIBUTING.md — Research & Academic Credits](CONTRIBUTING.md#research--academic-credits)
163
- >
164
119
  > **Lead researcher**: [Martin Manuel Lopez](https://github.com/martinmanuel9) · [ORCID 0009-0002-7652-2385](https://orcid.org/0009-0002-7652-2385), University of Arizona
165
120
 
166
121
  ---
167
122
 
168
123
  ## License
169
124
 
170
- This philosophy document and the CDD methodology are released under the [MIT License](https://opensource.org/licenses/MIT).
171
-
172
- CDD is an open methodology. Anyone can adopt, adapt, and contribute to it.
125
+ This philosophy document and the CDD methodology are released under the [MIT License](https://opensource.org/licenses/MIT). CDD is an open methodology — anyone can adopt, adapt, and contribute.
package/README.md CHANGED
@@ -130,7 +130,28 @@ diagnose → AI reads prompts → AI fixes docs → guard verifies
130
130
  └───────────────── issues found? ←──────────────────────┘
131
131
  ```
132
132
 
133
- `diagnose` is the primary command. It runs all validators, maps every failure to an AI-actionable fix prompt, and outputs a remediation plan. Your AI agent runs it, fixes the docs, and runs `guard` to verify. Zero human intervention required.
133
+ `diagnose` is the primary command. It runs all validators, maps every failure to an AI-actionable fix prompt, and outputs a remediation plan. Your AI agent runs it, fixes the docs, and runs `guard` to verify.
134
+
135
+ ### Mechanical vs. agent fixes
136
+
137
+ DocGuard splits drift into two kinds and is explicit about which is which:
138
+
139
+ | Kind | Example | How it's fixed |
140
+ |------|---------|----------------|
141
+ | **Mechanical** (deterministic) | An endpoint documented in `API-REFERENCE.md` that the OpenAPI spec confirms is gone | `docguard fix --write` deletes the row + detail block itself — **no AI** |
142
+ | **Agent** (needs judgment) | Rewriting an X-Ray prose section as CloudWatch; writing a new endpoint's request/response | Routed to an AI agent via `diagnose` / `fix --doc` prompts |
143
+
144
+ `docguard fix --write` only touches docs marked `<!-- docguard:generated true -->` (override with `--force`), is idempotent, and prints exactly what changed. It never rewrites prose — that stays with the agent.
145
+
146
+ ### Hands-off loop (set and forget)
147
+
148
+ ```
149
+ guard ──▶ fix --write (mechanical, auto) ──▶ guard ──▶ diagnose (agent prompts for the rest)
150
+ ```
151
+
152
+ - **CI / pre-commit:** `docguard hooks --type pre-commit --auto-fix` installs a hook that applies mechanical fixes, re-stages the docs, then runs `guard`; anything left is surfaced as agent prompts.
153
+ - **Agent-driven:** `docguard diagnose --auto` scaffolds missing docs **and** applies mechanical fixes, then emits prompts for the content rewrites that remain.
154
+ - **JSON for automation:** `guard`/`diagnose --format json` include a `mechanicalFixes` array and tag each issue `mechanical` vs `agent`, so an agent can apply or delegate precisely.
134
155
 
135
156
  ---
136
157
 
@@ -192,6 +213,7 @@ DocGuard ships **13 commands**:
192
213
  | `init` | Initialize CDD docs from templates (interactive) |
193
214
  | `score` | CDD maturity score (0–100) with weighted breakdown |
194
215
  | `fix --doc <name>` | Generate AI prompt for a specific document |
216
+ | `fix --write` | Apply deterministic fixes (remove stale documented endpoints) — no AI |
195
217
  | `diff` | Compare canonical docs vs actual code artifacts |
196
218
  | `agents` | Generate agent-specific config files |
197
219
  | `trace` | Requirements traceability matrix |
@@ -21,6 +21,7 @@ import { existsSync, readFileSync } from 'node:fs';
21
21
  import { resolve, dirname } from 'node:path';
22
22
  import { fileURLToPath } from 'node:url';
23
23
  import { execSync, execFileSync } from 'node:child_process';
24
+ import { applyAllMechanicalFixes } from './fix.mjs';
24
25
 
25
26
  // Map validator failures to the right fix --doc target
26
27
  const VALIDATOR_TO_DOC = {
@@ -65,13 +66,6 @@ const FIX_INSTRUCTIONS = {
65
66
  description: 'A // DRIFT: code comment has no matching DRIFT-LOG.md entry. Add the entry or remove the comment.',
66
67
  autoFixable: false,
67
68
  },
68
- 'API-Surface': {
69
- action: 'Reconcile API-REFERENCE.md with the actual API surface',
70
- command: 'docguard fix --doc api-reference',
71
- llmCommand: '/docguard.fix --doc api-reference',
72
- description: 'docs-canonical/API-REFERENCE.md documents endpoints that no longer exist in code (or omits real ones). Remove deleted endpoints and add missing ones to match the OpenAPI spec / route definitions, then log the change in CHANGELOG.md and DRIFT-LOG.md.',
73
- autoFixable: false,
74
- },
75
69
  'Changelog': {
76
70
  action: 'Update CHANGELOG.md',
77
71
  description: 'CHANGELOG.md is missing or has no [Unreleased] section. Add recent changes.',
@@ -112,6 +106,78 @@ const FIX_INSTRUCTIONS = {
112
106
  description: 'Documents haven\'t been reviewed since recent code changes. Re-run fix --doc for each stale doc.',
113
107
  autoFixable: false,
114
108
  },
109
+ // ── Routed (Phase F): these used to fall through to a generic "Manual review needed" ──
110
+ 'Metrics-Consistency': {
111
+ action: 'Update stale number(s) in docs',
112
+ command: 'docguard fix --write',
113
+ llmCommand: 'docguard fix --write',
114
+ description: 'A doc claims a different count than the actual. Mechanical replace — no AI needed.',
115
+ autoFixable: true,
116
+ },
117
+ 'Metadata-Sync': {
118
+ action: 'Update stale version reference(s)',
119
+ command: 'docguard fix --write',
120
+ llmCommand: 'docguard fix --write',
121
+ description: 'Docs reference an older version than the manifest. Mechanical replace — no AI needed.',
122
+ autoFixable: true,
123
+ },
124
+ 'Docs-Sync': {
125
+ action: 'Reference the route/service in a canonical doc',
126
+ command: 'docguard fix --doc architecture',
127
+ llmCommand: '/docguard.fix --doc architecture',
128
+ description: 'A code file under routes/services is not referenced by any canonical doc. Add it (or its module) to ARCHITECTURE.md.',
129
+ autoFixable: false,
130
+ },
131
+ 'Docs-Diff': {
132
+ action: 'Reconcile the documented vs. real surface',
133
+ command: 'docguard diff',
134
+ llmCommand: '/docguard.fix',
135
+ description: 'Tech stack or test files documented but not found in code (or vice versa). Inspect with `docguard diff`.',
136
+ autoFixable: false,
137
+ },
138
+ 'Docs-Coverage': {
139
+ action: 'Reference the missing config/dotfile/source dir in docs',
140
+ command: 'docguard fix --doc architecture',
141
+ llmCommand: '/docguard.fix --doc architecture',
142
+ description: 'A project config/source dir is undocumented. Add a reference to the appropriate canonical doc.',
143
+ autoFixable: false,
144
+ },
145
+ 'Doc-Quality': {
146
+ action: 'Improve readability / structure of the flagged doc',
147
+ command: 'docguard fix --doc',
148
+ llmCommand: '/docguard.fix --doc',
149
+ description: 'Passive voice, low atomicity, or weak structure detected. Re-run fix --doc for the affected file.',
150
+ autoFixable: false,
151
+ },
152
+ 'TODO-Tracking': {
153
+ action: 'Track or remove the TODO/FIXME',
154
+ description: 'An untracked TODO/FIXME in source. Add it to ROADMAP.md / CURRENT-STATE.md, open an issue, or remove it.',
155
+ autoFixable: false,
156
+ },
157
+ 'Traceability': {
158
+ action: 'Link the requirement ID to its test(s)',
159
+ description: 'A documented requirement ID has no matching reference in any test file. Add `@req FR-XXX` to the test that verifies it.',
160
+ autoFixable: false,
161
+ },
162
+ 'Schema-Sync': {
163
+ action: 'Document the model in DATA-MODEL.md',
164
+ command: 'docguard fix --doc data-model',
165
+ llmCommand: '/docguard.fix --doc data-model',
166
+ description: 'A database model in code is not documented in DATA-MODEL.md. Add an Entity entry for it.',
167
+ autoFixable: false,
168
+ },
169
+ 'Spec-Kit': {
170
+ action: 'Add the missing Spec Kit artifact / section',
171
+ description: 'A Spec Kit artifact (spec.md / plan.md / tasks.md) is missing a required section, FR-ID, or phased task structure. Edit the spec to match the standard.',
172
+ autoFixable: false,
173
+ },
174
+ 'API-Surface': {
175
+ action: 'Reconcile API-REFERENCE.md with the real API surface',
176
+ command: 'docguard fix --write',
177
+ llmCommand: 'docguard fix --write',
178
+ description: 'Documented-but-absent endpoints can be deleted mechanically with `docguard fix --write`. Undocumented-in-code endpoints need an agent to write the request/response block (`/docguard.fix --doc api-reference`).',
179
+ autoFixable: true,
180
+ },
115
181
  };
116
182
 
117
183
  export function runDiagnose(projectDir, config, flags) {
@@ -127,29 +193,34 @@ export function runDiagnose(projectDir, config, flags) {
127
193
 
128
194
  // ── Step 3: Auto-fix (only with --auto flag) or suggest fixes ──
129
195
  const shouldAutoFix = flags.auto && flags.format !== 'json';
196
+ // Mechanical fixes = deterministic, no-LLM edits (e.g. remove a documented
197
+ // endpoint the spec confirms is gone). Surfaced by the API-Surface validator.
198
+ const mechanicalCount = countMechanicalFixes(guardData);
130
199
  if (issues.length > 0) {
131
200
  const autoFixable = issues.filter(i => i.autoFixable);
132
201
  const hasStructural = issues.some(i => i.validator === 'Structure');
133
202
 
134
- if (shouldAutoFix && (hasStructural || autoFixable.length > 0)) {
135
- // Run init to create missing files
203
+ if (shouldAutoFix && (hasStructural || autoFixable.length > 0 || mechanicalCount > 0)) {
204
+ // 1. init create missing files
136
205
  try {
137
206
  const cliPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'docguard.mjs');
138
- execFileSync(process.execPath, [cliPath, 'init', '--dir', projectDir], {
139
- encoding: 'utf-8',
140
- stdio: 'pipe',
141
- });
207
+ execFileSync(process.execPath, [cliPath, 'init', '--dir', projectDir], { encoding: 'utf-8', stdio: 'pipe' });
142
208
  } catch { /* init may partially succeed */ }
143
209
 
144
- // Run generate to fill in MISSING content only (never --force, which would overwrite existing docs)
210
+ // 2. generate fill MISSING content only (never --force; won't overwrite existing docs)
145
211
  try {
146
212
  const cliPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'docguard.mjs');
147
- execFileSync(process.execPath, [cliPath, 'generate', '--dir', projectDir], {
148
- encoding: 'utf-8',
149
- stdio: 'pipe',
150
- });
213
+ execFileSync(process.execPath, [cliPath, 'generate', '--dir', projectDir], { encoding: 'utf-8', stdio: 'pipe' });
151
214
  } catch { /* generate may partially succeed */ }
152
215
 
216
+ // 3. mechanical fixes — apply ALL deterministic edits (no LLM):
217
+ // endpoint removal, stale counts, stale versions, changelog header.
218
+ let mechApplied = 0;
219
+ try {
220
+ const r = applyAllMechanicalFixes(projectDir, config, { force: flags.force });
221
+ mechApplied = r.applied.length;
222
+ } catch { /* best-effort */ }
223
+
153
224
  // Re-run guard to see what's still broken
154
225
  guardData = runGuardInternal(projectDir, config);
155
226
  issues = collectIssues(guardData);
@@ -157,20 +228,30 @@ export function runDiagnose(projectDir, config, flags) {
157
228
  if (!flags.format || flags.format === 'text') {
158
229
  const fixedCount = autoFixable.length - issues.filter(i => i.autoFixable).length;
159
230
  if (fixedCount > 0) {
160
- console.log(` ${c.green}⚡ Auto-fixed ${fixedCount} issue(s)${c.reset} (created/regenerated docs)\n`);
231
+ console.log(` ${c.green}⚡ Auto-fixed ${fixedCount} issue(s)${c.reset} (created/regenerated docs)`);
161
232
  }
233
+ if (mechApplied > 0) {
234
+ console.log(` ${c.green}⚡ Applied ${mechApplied} mechanical fix(es)${c.reset} (removed stale API endpoints)`);
235
+ }
236
+ if (fixedCount > 0 || mechApplied > 0) console.log('');
237
+ }
238
+ } else if (!shouldAutoFix && (!flags.format || flags.format === 'text')) {
239
+ // Suggest-only mode — be accurate about what each path does.
240
+ if (mechanicalCount > 0) {
241
+ console.log(` ${c.green}🔧 ${mechanicalCount} issue(s) are mechanically fixable — no AI needed.${c.reset} Apply with:`);
242
+ console.log(` ${c.cyan}docguard fix --write${c.reset}${c.dim} (removes stale documented endpoints)${c.reset}`);
162
243
  }
163
- } else if (!shouldAutoFix && (hasStructural || autoFixable.length > 0) && (!flags.format || flags.format === 'text')) {
164
- // Suggest-only mode: tell user what they can do (LLM-first)
165
- console.log(` ${c.yellow}💡 ${autoFixable.length + (hasStructural ? 1 : 0)} issue(s) can be auto-fixed.${c.reset} Run with ${c.cyan}--auto${c.reset} to create/regenerate docs, or manually:`);
166
- if (agentMode === 'llm') {
167
- if (hasStructural) console.log(` ${c.dim}/docguard.init${c.reset}`);
168
- if (autoFixable.length > 0) console.log(` ${c.dim}/docguard.fix${c.reset}`);
169
- } else {
170
- if (hasStructural) console.log(` ${c.dim}docguard init --dir .${c.reset}`);
171
- if (autoFixable.length > 0) console.log(` ${c.dim}docguard generate --dir . --force${c.reset}`);
244
+ if (hasStructural || autoFixable.length > 0) {
245
+ console.log(` ${c.yellow}💡 ${autoFixable.length + (hasStructural ? 1 : 0)} issue(s) can be scaffolded/regenerated.${c.reset} Run ${c.cyan}docguard diagnose --auto${c.reset} (creates missing docs + applies mechanical fixes), or:`);
246
+ if (agentMode === 'llm') {
247
+ if (hasStructural) console.log(` ${c.dim}/docguard.init${c.reset}`);
248
+ if (autoFixable.length > 0) console.log(` ${c.dim}/docguard.fix${c.reset}`);
249
+ } else {
250
+ if (hasStructural) console.log(` ${c.dim}docguard init --dir .${c.reset}`);
251
+ if (autoFixable.length > 0) console.log(` ${c.dim}docguard generate --dir . --force${c.reset}`);
252
+ }
172
253
  }
173
- console.log('');
254
+ if (mechanicalCount > 0 || hasStructural || autoFixable.length > 0) console.log('');
174
255
  }
175
256
  }
176
257
 
@@ -201,46 +282,65 @@ export function runDiagnose(projectDir, config, flags) {
201
282
  }
202
283
  }
203
284
 
285
+ /** Count deterministic (no-LLM) fixes available across guard results. */
286
+ function countMechanicalFixes(guardData) {
287
+ let n = 0;
288
+ for (const v of guardData.validators) {
289
+ if (Array.isArray(v.fixes)) n += v.fixes.length;
290
+ }
291
+ return n;
292
+ }
293
+
294
+ /**
295
+ * A documented-but-absent endpoint is MECHANICALLY fixable (deterministic
296
+ * removal via `docguard fix --write`) — distinct from drift that needs an agent.
297
+ */
298
+ function isMechanicalMessage(validator, message) {
299
+ return validator === 'API-Surface' && /not found in code/i.test(message);
300
+ }
301
+
204
302
  /**
205
303
  * Collect issues from guard results with fix metadata.
206
304
  */
207
305
  function collectIssues(guardData) {
208
306
  const issues = [];
209
307
  for (const v of guardData.validators) {
210
- if (v.status === 'skipped' || v.status === 'pass') continue;
308
+ if (v.status === 'skipped' || v.status === 'pass' || v.status === 'na') continue;
211
309
 
212
310
  const fixInfo = FIX_INSTRUCTIONS[v.name] || { action: `Review ${v.name}`, description: 'Manual review needed.', autoFixable: false };
213
311
  const docTarget = VALIDATOR_TO_DOC[v.name];
214
312
 
215
- for (const err of v.errors) {
216
- issues.push({
217
- severity: 'error',
218
- validator: v.name,
219
- message: err,
220
- action: fixInfo.action,
221
- command: fixInfo.command || null,
222
- llmCommand: fixInfo.llmCommand || null,
223
- docTarget,
224
- autoFixable: fixInfo.autoFixable || false,
225
- });
226
- }
227
- for (const warn of v.warnings) {
228
- issues.push({
229
- severity: 'warning',
313
+ const mkIssue = (severity, message) => {
314
+ const mechanical = isMechanicalMessage(v.name, message);
315
+ return {
316
+ severity,
230
317
  validator: v.name,
231
- message: warn,
232
- action: fixInfo.action,
233
- command: fixInfo.command || null,
234
- llmCommand: fixInfo.llmCommand || null,
235
- docTarget,
318
+ message,
319
+ action: mechanical ? 'Remove stale endpoint from API-REFERENCE.md' : fixInfo.action,
320
+ // Mechanical fixes point at the deterministic CLI applier, not an LLM.
321
+ command: mechanical ? 'docguard fix --write' : (fixInfo.command || null),
322
+ llmCommand: mechanical ? null : (fixInfo.llmCommand || null),
323
+ mechanical,
324
+ docTarget: mechanical ? null : docTarget,
236
325
  autoFixable: fixInfo.autoFixable || false,
237
- });
238
- }
326
+ };
327
+ };
328
+
329
+ for (const err of v.errors) issues.push(mkIssue('error', err));
330
+ for (const warn of v.warnings) issues.push(mkIssue('warning', warn));
239
331
  }
240
332
  return issues;
241
333
  }
242
334
 
243
335
  function outputJSON(guardData, scoreData, issues) {
336
+ // Structured, deterministic fix actions an agent or `--write` can apply directly.
337
+ const mechanicalFixes = [];
338
+ for (const v of guardData.validators) {
339
+ if (Array.isArray(v.fixes)) {
340
+ for (const f of v.fixes) mechanicalFixes.push({ validator: v.name, ...f });
341
+ }
342
+ }
343
+
244
344
  const result = {
245
345
  project: guardData.project,
246
346
  profile: guardData.profile,
@@ -254,8 +354,13 @@ function outputJSON(guardData, scoreData, issues) {
254
354
  message: i.message,
255
355
  action: i.action,
256
356
  command: i.command,
357
+ // 'mechanical' = deterministic CLI fix (docguard fix --write);
358
+ // 'agent' = needs an AI agent to write content.
359
+ fixKind: i.mechanical ? 'mechanical' : 'agent',
257
360
  docTarget: i.docTarget,
258
361
  })),
362
+ // Deterministic actions consumable by `docguard fix --write` or an agent.
363
+ mechanicalFixes,
259
364
  // Unique fix commands for automation
260
365
  fixCommands: [...new Set(issues.filter(i => i.command).map(i => i.command))],
261
366
  timestamp: new Date().toISOString(),