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 +59 -106
- package/README.md +23 -1
- package/cli/commands/diagnose.mjs +157 -52
- package/cli/commands/fix.mjs +113 -1
- package/cli/commands/generate.mjs +91 -0
- package/cli/commands/hooks.mjs +40 -2
- package/cli/commands/score.mjs +22 -0
- package/cli/commands/sync.mjs +123 -0
- package/cli/docguard.mjs +22 -0
- package/cli/scanners/frontend.mjs +438 -0
- package/cli/scanners/integrations.mjs +116 -0
- package/cli/scanners/memory-plan.mjs +242 -0
- package/cli/scanners/project-type.mjs +310 -0
- package/cli/scanners/routes.mjs +149 -0
- package/cli/scanners/schemas.mjs +174 -1
- package/cli/validators/api-surface.mjs +112 -37
- package/cli/validators/changelog.mjs +3 -2
- package/cli/validators/metadata-sync.mjs +6 -1
- package/cli/validators/metrics-consistency.mjs +5 -2
- package/cli/writers/api-reference.mjs +101 -0
- package/cli/writers/mechanical.mjs +116 -0
- package/cli/writers/sections.mjs +148 -0
- package/commands/docguard.fix.md +19 -3
- package/docs/doc-sections.md +37 -0
- package/extensions/spec-kit-docguard/README.md +7 -4
- package/extensions/spec-kit-docguard/commands/fix.md +74 -0
- package/extensions/spec-kit-docguard/commands/generate.md +25 -2
- package/extensions/spec-kit-docguard/commands/sync.md +62 -0
- package/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +11 -1
- package/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +111 -0
- package/package.json +1 -1
package/PHILOSOPHY.md
CHANGED
|
@@ -1,172 +1,125 @@
|
|
|
1
1
|
# The Philosophy of Canonical-Driven Development
|
|
2
2
|
|
|
3
|
-
> Why
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
13
|
+
This is the **comprehension crisis of the AI era:**
|
|
14
14
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
35
|
+
### Pillar 2: Two tiers — derived truth and human reasoning
|
|
52
36
|
|
|
53
|
-
CDD separates documentation into two
|
|
37
|
+
CDD separates documentation into two kinds of content, and treats them differently:
|
|
54
38
|
|
|
55
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
-
- Pretending the docs are still accurate (lying)
|
|
61
|
-
- Silently updating docs to match the broken code (losing intent)
|
|
46
|
+
### Pillar 3: Generate AND Guard — bidirectional, continuous
|
|
62
47
|
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
81
|
-
|
|
82
|
-
Three forces are converging in 2025-2026 that make CDD necessary:
|
|
60
|
+
## Complete + Accurate = Trustworthy
|
|
83
61
|
|
|
84
|
-
|
|
62
|
+
A memory is only useful if you can trust it. DocGuard measures two things:
|
|
85
63
|
|
|
86
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
##
|
|
89
|
+
## The Lifecycle
|
|
133
90
|
|
|
134
|
-
|
|
91
|
+
```
|
|
92
|
+
generate ──▶ guard ──▶ sync ──▶ guard ──▶ …
|
|
93
|
+
(build) (verify) (keep (verify)
|
|
94
|
+
current)
|
|
95
|
+
```
|
|
135
96
|
|
|
136
|
-
**Day 1
|
|
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
|
-
|
|
101
|
+
---
|
|
139
102
|
|
|
140
|
-
|
|
103
|
+
## CDD and Other Methodologies
|
|
141
104
|
|
|
142
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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)
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
|
232
|
-
action: fixInfo.action,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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(),
|