docguard-cli 0.40.5 → 0.41.1

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +3246 -0
  2. package/README.md +25 -16
  3. package/cli/assessment.mjs +94 -0
  4. package/cli/commands/ci.mjs +15 -5
  5. package/cli/commands/diagnose.mjs +20 -13
  6. package/cli/commands/fix.mjs +14 -45
  7. package/cli/commands/guard.mjs +53 -25
  8. package/cli/commands/hooks.mjs +51 -10
  9. package/cli/commands/init.mjs +15 -0
  10. package/cli/commands/reconcile.mjs +10 -3
  11. package/cli/commands/report.mjs +5 -1
  12. package/cli/commands/score.mjs +2 -1
  13. package/cli/commands/specs.mjs +15 -4
  14. package/cli/commands/upgrade.mjs +4 -1
  15. package/cli/commands/verify.mjs +9 -2
  16. package/cli/commands/watch.mjs +3 -2
  17. package/cli/config.mjs +23 -0
  18. package/cli/evidence/adapters.mjs +14 -0
  19. package/cli/evidence/manifest.mjs +15 -0
  20. package/cli/evidence/python-literal.mjs +304 -0
  21. package/cli/findings.mjs +17 -3
  22. package/cli/scanners/instruction-audit.mjs +88 -11
  23. package/cli/scanners/js-ast.mjs +156 -18
  24. package/cli/scanners/reconciliation.mjs +56 -6
  25. package/cli/scanners/routes.mjs +84 -9
  26. package/cli/scanners/spec-registry.mjs +29 -0
  27. package/cli/shared-git.mjs +98 -0
  28. package/cli/shared-ignore.mjs +1 -1
  29. package/cli/shared.mjs +30 -1
  30. package/cli/validators/api-doc-smells.mjs +2 -2
  31. package/cli/validators/api-surface.mjs +4 -9
  32. package/cli/validators/diff-suspicion.mjs +3 -2
  33. package/cli/validators/docs-sync.mjs +45 -29
  34. package/cli/validators/environment.mjs +64 -6
  35. package/cli/validators/metrics-consistency.mjs +52 -11
  36. package/cli/validators/reference-existence.mjs +4 -2
  37. package/cli/validators/security.mjs +37 -12
  38. package/cli/validators/spec-registry.mjs +10 -7
  39. package/cli/validators/todo-tracking.mjs +31 -11
  40. package/cli/validators/traceability.mjs +29 -4
  41. package/cli/writers/junit.mjs +3 -3
  42. package/cli/writers/sarif.mjs +13 -9
  43. package/docs/configuration.md +12 -1
  44. package/extensions/spec-kit-docguard/extension.yml +1 -1
  45. package/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +2 -2
  46. package/extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md +2 -2
  47. package/extensions/spec-kit-docguard/skills/docguard-review/SKILL.md +2 -2
  48. package/extensions/spec-kit-docguard/skills/docguard-score/SKILL.md +2 -2
  49. package/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +2 -2
  50. package/extensions/spec-kit-docguard/templates/github-workflows/docguard-autofix.yml +1 -1
  51. package/extensions/spec-kit-docguard/templates/github-workflows/docguard-guard.yml +1 -1
  52. package/package.json +2 -1
  53. package/schemas/docguard-config.schema.json +15 -1
  54. package/schemas/docguard-evidence.schema.json +12 -0
  55. package/templates/ci/github-actions.yml +1 -1
  56. package/templates/evidence-manifest.json +16 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,3246 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.41.1] - 2026-09-15
11
+
12
+ Automated weekly release — batches everything merged since `v0.41.0`.
13
+
14
+ ### Changed
15
+
16
+ - Anchor lifecycle evidence to main (#400)
17
+ - Anchor R9 lifecycle evidence to main (#399)
18
+ - Fix living spec finalization and close R9 (#398)
19
+
20
+
21
+ ### Fixed
22
+
23
+ - Allow an evidence-complete living specification to finish without creating a
24
+ stale `tasks.md` solely for lifecycle bookkeeping, while continuing to reject
25
+ missing task ledgers for other persistence models and empty or incomplete
26
+ ledgers wherever they are declared. Released living contracts can record later
27
+ maintenance without downgrading their release state.
28
+ - Record the reviewed document-lifecycle maintenance outcome against its exact
29
+ source revision and qualified implementation/test evidence.
30
+ - Close roadmap milestone R9 after independently verifying every v0.41.0
31
+ publication target and record the adoption workflow's reviewed outcome without
32
+ creating a stale task ledger.
33
+ - Anchor the adoption workflow's final maintenance outcome to durable main commit
34
+ `2ff1baa` after the protected merge checks completed.
35
+ - Anchor the document-lifecycle maintenance outcome to durable main commit
36
+ `2a47de5`, completing the post-merge evidence chain.
37
+
38
+ ## [0.41.0] - 2026-09-15
39
+
40
+ Automated weekly release — batches everything merged since `v0.40.5`.
41
+
42
+ ### Changed
43
+
44
+ - fix: harden packed adoption and field precision (#395)
45
+
46
+
47
+ ### Added
48
+
49
+ - Add exact finding-code enforcement through `findingSeverity`, retaining both
50
+ intrinsic and effective severity in guard JSON, SARIF, and JUnit.
51
+ - Add trusted lifecycle-aware traceability deferral for requirements that remain
52
+ planned in a committed, clean schema-v2 specification registry.
53
+ - Add bounded static route resolution for local constants, pathless router
54
+ mounts, import aliases, middleware lists, and multi-router modules.
55
+
56
+ ### Changed
57
+
58
+ - Make reconciliation inventory independent of bounded patch text and disclose
59
+ partial coverage instead of treating diff overflow or failure as no change.
60
+ - Resolve safe instruction pointers by exact path or one unique basename, while
61
+ surfacing ambiguous, unsafe, symlinked, and incomplete-index cases.
62
+ - Distinguish DocGuard-managed hooks from unrelated existing hooks and preserve
63
+ foreign commands when removing a managed block.
64
+ - Make npm README links resolve from the published package and identify the
65
+ current v0.40 release line accurately.
66
+ - Keep API contract omissions review-only: negative route-scan evidence can no
67
+ longer authorize endpoint deletion, including under `--force`.
68
+
69
+ ### Fixed
70
+
71
+ - Prevent malformed finding suggestions from rendering `undefined` and replace
72
+ invalid remediation commands with reviewable actions.
73
+ - Prevent chained HTTP-client calls and test-helper routes from contaminating
74
+ Express API discovery, preserve product routes during deduplication, and
75
+ compose static imported-router mount prefixes transitively.
76
+ - Route `init --with hooks --list` to read-only hook inspection instead of the
77
+ interactive initialization workflow.
78
+ - Fall back to the repository directory name in watch output when project
79
+ metadata does not provide a name.
80
+ - Classify repeated test-input password assertions as low-confidence fixture
81
+ evidence while retaining blocking detection for ordinary credentials.
82
+ - Use the selected authoritative OpenAPI contract and normalized path parameters
83
+ for design-sync checks, and exclude generic frontend utilities from services.
84
+ - Discover package-local environment templates in monorepos and align the
85
+ published config schema with every runtime validator key.
86
+ - Preserve historical metric statements and accept contiguous multiline skip
87
+ reasons instead of proposing changes that would falsify project history.
88
+
89
+ ## [0.40.5] - 2026-09-15
90
+
91
+ Automated weekly release — batches everything merged since `v0.40.4`.
92
+
93
+ ### Changed
94
+
95
+ - test: retry transient freshness cleanup (#393)
96
+ - fix: make Spec Kit command manifest complete (#392)
97
+
98
+
99
+ ### Fixed
100
+
101
+ - Retry removal of temporary Git repositories when the operating system reports
102
+ a transient `ENOTEMPTY`, preventing a completed freshness test from randomly
103
+ blocking the release gate during teardown.
104
+ - Register every command shipped by the Spec Kit extension, route `fix` and
105
+ `review` to their matching command files, keep the manifest description inside
106
+ Spec Kit's 200-character limit, and add release-contract tests that reject
107
+ missing, duplicate, mismatched, undeclared, or divergent metadata.
108
+ - Record the supported `git diff --check` and `gh pr diff --patch` split in the
109
+ project learning log so release self-review does not repeat an invalid CLI call.
110
+
111
+ ## [0.40.4] - 2026-09-15
112
+
113
+ Automated weekly release — batches everything merged since `v0.40.3`.
114
+
115
+ ### Changed
116
+
117
+ - fix: consolidate catalog reminders (#390)
118
+ - docs: finalize durable R8 outcome (#389)
119
+ - docs: close R8 release verification (#388)
120
+
121
+
122
+ ### Changed
123
+
124
+ - Reuse one open Spec Kit catalog reminder across releases and close older
125
+ reminders as superseded, preventing the release workflow from accumulating a
126
+ stale version-specific issue queue.
127
+ - Close the R8 living release contract with exact v0.40.3 evidence: the
128
+ repository-token release PR armed protected native auto-merge, passed the
129
+ approved CI and supply-chain checks, merged automatically, and triggered the
130
+ complete npm, PyPI, GHCR, GitHub Release, extension, MCPB, and catalog flow
131
+ through the scheduler's bounded continuation.
132
+
133
+ ## [0.40.3] - 2026-09-15
134
+
135
+ Automated weekly release — batches everything merged since `v0.40.2`.
136
+
137
+ ### Changed
138
+
139
+ - fix: recover tokenless release publication (#385)
140
+
141
+
142
+ ### Added
143
+
144
+ - Add an hourly tag-driven release recovery sweep. Already tagged versions stop
145
+ after detection, while a merged but unpublished package version enters the
146
+ existing serialized test, tag, and registry publication transaction.
147
+
148
+ ### Fixed
149
+
150
+ - Keep the scheduled release job alive for a bounded ten-minute approval window
151
+ and dispatch publication once native auto-merge completes. This covers the
152
+ normal operator flow without a persistent credential or an always-on poller.
153
+ - Stop relying on the `package.json` push from a native auto-merge armed by
154
+ `GITHUB_TOKEN`; GitHub suppresses downstream push workflows for that merge.
155
+
156
+ ## [0.40.2] - 2026-09-15
157
+
158
+ Automated weekly release — batches everything merged since `v0.40.1`.
159
+
160
+ ### Changed
161
+
162
+ - fix: use protected native release auto-merge (#382)
163
+
164
+
165
+ ### Changed
166
+
167
+ - Prevalidate scheduler-generated release identity, synchronized versions, and
168
+ changed paths before push, then arm GitHub's protected native squash
169
+ auto-merge for both new and reused release PRs.
170
+ - Keep the privileged `workflow_run` auto-merge gate scoped to Dependabot and
171
+ Jules; release publication continues from the merged `package.json` push.
172
+
173
+ ### Fixed
174
+
175
+ - Replace the missing post-approval `workflow_run` continuation discovered by
176
+ release PR #380. GitHub executes an approved `action_required` run without
177
+ emitting a second completion event, so the old listener could not merge an
178
+ otherwise green release PR.
179
+
180
+ ## [0.40.1] - 2026-09-15
181
+
182
+ Automated weekly release — batches everything merged since `v0.40.0`.
183
+
184
+ ### Changed
185
+
186
+ - fix: expose protected release approval boundary (#379)
187
+ - fix: complete tokenless releases in trusted scheduler (#377)
188
+ - docs: complete R8 lifecycle (#375)
189
+ - docs: approve R8 evidence and stabilize Git cleanup (#374)
190
+ - docs: retain release evidence and fix Flask advisory (#373)
191
+ - ci: remove persistent release credential
192
+ - docs: close stale roadmap status text
193
+
194
+
195
+ ### Added
196
+
197
+ - Add a pure release-candidate policy that verifies repository, default branch,
198
+ bot author, branch/title/version agreement, next-version increment, missing
199
+ tag, synchronized release surfaces, changed paths, exact pull-request CI run
200
+ identity, and one successful Node 18/20/22/24 job before privileged merge.
201
+ - Retain a machine-checked live probe for the user-authored `workflow_dispatch`
202
+ fallback. The four-version CI matrix passed, the trusted `workflow_run` gate
203
+ refused the non-release candidate, and the disposable pull request was closed
204
+ without merge. The probe does not claim repository-token provenance.
205
+
206
+ ### Changed
207
+
208
+ - Scheduled releases now use only the ephemeral repository `GITHUB_TOKEN`.
209
+ The scheduler opens or reuses a release PR and refuses orphaned same-name
210
+ branches. A maintainer approves GitHub's held pull-request workflows; the
211
+ metadata-only gate then validates CI, merges, and dispatches publication.
212
+ - A scheduled run now recovers an untagged current package version through the
213
+ idempotent release workflow before considering another version increment.
214
+
215
+ ### Fixed
216
+
217
+ - Correct the release contract after live PRs #376 and #378 proved that a
218
+ repository-token dispatch neither emits the required downstream gate nor
219
+ satisfies protected pull-request checks. The final flow exposes GitHub's one
220
+ maintainer workflow approval instead of weakening branch protection or storing
221
+ a personal or App credential.
222
+ - Retry bounded removal of ephemeral Git repositories in `shared-git` tests so
223
+ Node 18 does not fail an otherwise passing matrix on a transient `.git`
224
+ `ENOTEMPTY` cleanup race.
225
+ - Upgrade the installable Python example from the vulnerable open range
226
+ `flask>=3.0` to exact-pinned `flask==3.1.3`, the upstream security-fix release
227
+ for GHSA-68rp-wp8r-4726, and prevent regression to the affected fixture.
228
+ - Remove stale pre-release status text from the delivered R1, R6, and R7 living
229
+ plans and task lists so agents see verified maintenance contracts instead of
230
+ completed work described as held or in progress.
231
+ - Update the R8 roadmap and task ledgers with exact GitHub run evidence while
232
+ keeping lifecycle completion open until the probe evidence has a durable
233
+ squash-merged revision.
234
+ - Approve the complete R8 evidence set with no accepted deviations after the
235
+ probe fixture landed at durable revision `66d5766`, making the reviewed
236
+ lifecycle transaction ready without referencing a disposable PR commit.
237
+ - Record the R8 implementation outcome at durable approval revision `46531e4`,
238
+ move the completed milestone out of the active roadmap, and retain its spec as
239
+ a living release-verification contract.
240
+
241
+ ## [0.40.0] - 2026-09-14
242
+
243
+ ### Added
244
+
245
+ - Define the reviewed R7 task-specific agent-context contract and frozen
246
+ evaluation protocol. Product behavior remains gated on 27 repeated hidden-test
247
+ trials comparing task-only, existing context-pack, and targeted-packet inputs.
248
+ - Add the frozen R7 benchmark harness, strict manifest/result schemas, and three
249
+ synthetic JavaScript/Python tasks with hidden fail-to-pass checks, pass-to-pass
250
+ controls, reviewed reference behavior, deterministic shuffled ordering,
251
+ resumable observations, and an immutable promotion decision. The experimental
252
+ selector emits bounded provenance-rich evidence or an honest abstention and
253
+ remains outside the public CLI until the recorded trial gate passes.
254
+ - Correct the R7 Codex executor invocation to use `--approve-for-me` as the
255
+ workspace-write selector. Codex CLI rejects that flag when an equivalent
256
+ explicit `--sandbox workspace-write` is also present; the failed zero-step
257
+ diagnostic matrix was discarded before product observations began.
258
+ - Record all 27 frozen R7 trials and the resulting promotion decision. Every
259
+ condition passed nine of nine runs with no requirement or changed-file policy
260
+ violations; targeted packets reduced median steps by 50% and latency by 17%
261
+ against context packs while increasing uncached input tokens by 80%. The
262
+ retained report limits the claim and keeps the interface opt-in.
263
+ - Verify the complete R7 implementation with 1,784 passing tests on Node 18,
264
+ 20, 22, and 24, extracted-package execution without the optional parser,
265
+ frozen fixture/reference replay, and the regression-free 24-case detector
266
+ corpus plus one intentionally unsupported case.
267
+ - Close every R7 task after exact-evidence review and correct the completed R6
268
+ task list's stale “In progress” label to its verified living-contract state.
269
+ - Complete the reviewed R7 lifecycle transaction at the exact implementation
270
+ revision, recording the bounded selector, frozen benchmark, CLI integration,
271
+ canonical documentation, test matrix, package smoke test, and detector corpus
272
+ as delivery evidence with no accepted deviations.
273
+ - Add opt-in `docguard agent --task <text>` context selection after the frozen
274
+ promotion gate passed. Existing `docguard agent` output remains unchanged;
275
+ task mode emits bounded current evidence or an explicit abstention in aligned
276
+ human and deterministic JSON forms.
277
+ - Define the reviewed R6 language and repository coverage contract, including
278
+ explicit false-positive controls for Python imports, Cloudflare bindings,
279
+ mapped document ownership, and monorepo-root guidance.
280
+ - Architecture validation now builds repository-local Python import graphs from
281
+ the optional standard-library AST tier. It resolves regular flat and `src/`
282
+ packages plus explicit relative imports, detects cycles and configured layer
283
+ violations, and keeps dynamic imports, `sys.path` mutation, parse failures,
284
+ interpreter absence, and ambiguous workspace modules visible as partial or
285
+ unsupported coverage.
286
+ - Environment scanning now recognizes current Cloudflare module-handler `env`,
287
+ Pages `context.env`, entrypoint-class `this.env`, and imported
288
+ `cloudflare:workers` `env` forms with lexical alias and shadow tracking.
289
+ Lookalike objects and imports stay excluded, and parser-absent packages expose
290
+ the AST-only forms they could not verify.
291
+ - Mapped documentation layouts now support safe mutation. New or explicitly
292
+ generated single-role targets permit whole-document generation; existing
293
+ human documents permit only unique, well-formed `source=code` section updates
294
+ through generate-plan, sync, and mechanical repair. Commands validate all
295
+ mapped targets before writing, preserve backups and surrounding bytes, reject
296
+ shared or malformed ownership, and never treat `--force` as authorization.
297
+ - Commands launched from an implicitly selected nested package now detect a
298
+ governing ancestor `.docguard.json` or npm/pnpm workspace declaration and
299
+ provide an exact repository-scope rerun. Scope never changes automatically;
300
+ explicit selection, local configuration, exclusions, Git-only ancestry, and
301
+ nested repositories suppress guidance. Machine stdout stays parseable while
302
+ a typed JSON diagnostic is emitted on stderr.
303
+ - R6 verification now records 1,765 passing tests across Node 18, 20, 22, and
304
+ 24, successful packed-package and parser-absent execution, schema and syntax
305
+ checks, and a regression-free frozen corpus. All 24 evaluable cases passed;
306
+ the dynamic-Python control remained explicitly unsupported as designed.
307
+ - Qualified R6 traceability now covers every changed command, validator,
308
+ writer, and neighboring control used by mapped-document and parser-capability
309
+ behavior, allowing lifecycle completion to reject omissions deterministically.
310
+ - The R6 living specification now records its reviewed implementation revision,
311
+ complete evidence set, verified delivery state, and zero accepted deviations.
312
+
313
+ - The active evidence-scoped verification specification defines strict,
314
+ local-only bindings from exact Markdown statements to JSON Pointer values,
315
+ bounded repository collections, saved oasdiff JSON, and saved Buf JSON Lines.
316
+ Its five-state contract distinguishes scoped verification, contradiction,
317
+ stale inputs, inconclusive evidence, and unsupported formats without
318
+ claiming whole-document factual accuracy.
319
+ - `.docguard-evidence.json` can now bind one exact Markdown statement to a
320
+ typed RFC 6901 JSON value, a bounded repository collection, saved oasdiff
321
+ JSON, or saved Buf JSON Lines. `verify --evidence`, guard, score assurance,
322
+ agent context, SARIF, and JUnit preserve scoped verified, contradicted, stale,
323
+ inconclusive, and unsupported states; stale external reports are invalidated
324
+ by declared input hashes and no adapter executes project or third-party code.
325
+
326
+ ### Changed
327
+
328
+ - Mark all five maintained living specifications as released after their reviewed
329
+ implementations shipped across v0.38.0, v0.39.0, and v0.40.0; the roadmap
330
+ now records R1–R7 as delivered rather than leaving stale release-pending state.
331
+ - Document the promoted task-context contract, schema, lifecycle exclusions,
332
+ assurance boundary, benchmark reproduction path, measured tradeoffs, and
333
+ contribution protocol across canonical, public, and agent guidance.
334
+ - Evidence selectors support ATX and Setext Markdown headings while ignoring
335
+ fenced examples, `verify` rejects conflicting modes with a stable JSON error,
336
+ and every Evidence finding is reachable through `docguard explain`.
337
+ - MCP clients can call `docguard_verify_evidence` directly. The existing
338
+ `docguard_verify_claims` tool removes a semantic task only when a unique,
339
+ exact declaration already verified that same claim within scope.
340
+ - Roadmap and command documentation now describe the already-released R2 spec
341
+ completion transaction as current behavior instead of future work.
342
+ - Requirement-qualified implementation and test links now cover every R5
343
+ integration surface used by lifecycle reconciliation, including MCP.
344
+ - The R5 living specification now records its exact reviewed implementation
345
+ revision and complete evidence set through the verified lifecycle transaction.
346
+ - The living-spec maintenance outcome records the post-review source-value
347
+ redaction at its exact revision with no accepted deviations.
348
+
349
+ ### Fixed
350
+
351
+ - The R7 harness now expands its frozen visible-test globs before spawning Node,
352
+ preserving the same checks on Node 18, and binds retained observations to
353
+ exact harness and selector digests for reproducibility.
354
+ - Agent-context promotion now becomes incomplete when any trial has an
355
+ infrastructure failure. Zero-step model-service exits are classified apart
356
+ from agent failures, and bounded diagnostics retain useful trailing errors
357
+ after repetitive CLI startup warnings.
358
+ - R6 regression fixtures now follow the repository's single-newline EOF format,
359
+ keeping release diff checks clean.
360
+ - Evidence results no longer expose raw JSON source values in CLI, guard, MCP,
361
+ or agent output. Comparisons retain values only in process and bind them into
362
+ non-reversible identities, preventing an unsafe declaration from copying a
363
+ secret into logs.
364
+ - Scheduled release pull requests now require a repository-scoped
365
+ `RELEASE_PR_TOKEN`, allowing ordinary pull-request CI to run and the
366
+ fail-closed auto-merge workflow to observe the successful event. The previous
367
+ `GITHUB_TOKEN` plus `workflow_dispatch` workaround produced green checks that
368
+ could not activate auto-merge and forced an administrator merge for v0.39.0.
369
+ - Release, CI, bot, composite-action, supply-chain, and distributed workflow
370
+ actions are pinned to reviewed commit SHAs. Artifact upload moved from the
371
+ Node 20-based v4 action to v7.0.1, and the shipped Spec Kit auto-fix workflow
372
+ now tracks the current DocGuard release instead of v0.25.0.
373
+ - Parser-fallback skipped-test detection now masks strings, templates, and
374
+ comments before matching. Malformed test fixtures containing literal
375
+ `test.skip()` examples no longer become false warnings when Babel is absent;
376
+ executable unexplained skips remain visible.
377
+
378
+ - Canonical architecture, data, security, CI, test, requirements, README, agent
379
+ instructions, Spec Kit commands, and all five distributed AI skills now
380
+ preserve the evidence scope boundary. Agents inspect deterministic evidence
381
+ before heuristic claims and never rewrite approved intent merely because
382
+ current code differs.
383
+
384
+ ## [0.39.0] - 2026-09-14
385
+
386
+ Automated weekly release — batches everything merged since `v0.38.0`.
387
+
388
+ ### Changed
389
+
390
+ - feat: establish evidence-driven precision and feedback loop (#361)
391
+ - fix: authorize automated release pull requests (#360)
392
+
393
+
394
+ ### Added
395
+
396
+ - The active precision-evidence specification defines a reproducible R3/R4
397
+ benchmark, leakage-safe split contract, adjudication taxonomy, public-source
398
+ safety boundary, and contribution-to-regression workflow before implementation.
399
+ - The repository benchmark now has a strict versioned manifest, safe disposable
400
+ fixture runner, exact mutation preconditions, scoped finding identities, and
401
+ deterministic core output separated from runtime observations. Contribution
402
+ inputs reject private or credentialed Git endpoints, unsafe config paths,
403
+ prototype keys, symlinked fixtures, and interactive Git authentication.
404
+ - Precision evidence now reports null-safe TP/FP/FN, precision, recall,
405
+ false-positive density, supported-case abstention, unsupported coverage, and
406
+ reviewed repair outcomes by repository, detector, and parser tier. Baseline
407
+ comparison fails case-first on new misses, noise, abstention, or removed
408
+ evidence; persisted timings stay observational until a controlled paired
409
+ session can apply the repository's greater-than-20-percent materiality policy.
410
+ - Public-repository evidence can be persisted as a review candidate and checked
411
+ case-first against later runs. Reports include Wilson 95% confidence bounds,
412
+ retained cold/warm observations, config and source digests, and validator
413
+ check coverage; Git sources are fetched once per run and copied without their
414
+ repository metadata for paired cases.
415
+ - The evaluation split pins reviewed Express, Fastify, Flask, chi, and Changesets
416
+ revisions. Each public repository has an unmodified SEC005 control and an
417
+ exact-precondition synthetic defect, providing JavaScript, TypeScript
418
+ monorepo, Python, and Go evidence without executing third-party project code.
419
+ - The first reviewed baseline records 24 measured cases across 12 independent
420
+ repository groups: 12/12 seeded defects detected, no observed scoped false
421
+ positives or supported-case abstentions, and one explicit unsupported case.
422
+ Wilson 95% bounds limit the observed precision/recall lower bound to 0.757499
423
+ and the clean-control false-positive case-rate upper bound to 0.242501, so the
424
+ evidence cannot be misread as a universal 100% accuracy claim.
425
+ - Synthetic feedback fixtures now distinguish false positives, false negatives,
426
+ unsupported syntax, ambiguity, and policy disagreement. Strict manifests
427
+ require an exact expected identity, parser tier, explicit interestingness
428
+ predicate, same-path opposite control, bounded configuration, and reviewed
429
+ synthetic/redaction attestations.
430
+ - `docguard feedback --fixture-manifest` verifies the reproduction and control
431
+ in isolated temporary projects. `--reduce` minimizes content deterministically;
432
+ preview returns stable duplicate identity plus all/open/closed searches; and
433
+ `--contribution tests/<name>.test.mjs` emits a test-only regression after
434
+ scope and benchmark-delta evidence passes validation. Submission remains
435
+ entirely opt-in.
436
+
437
+ ### Changed
438
+
439
+ - Canonical architecture, data, test, security, CI, requirement, contribution,
440
+ issue, PR, and roadmap guidance now describes the delivered precision and
441
+ feedback contracts. Superseded “planned benchmark” and incomplete lifecycle
442
+ language was removed from active AI context while living specs retain their
443
+ current operational contract.
444
+
445
+ ### Fixed
446
+
447
+ - Scheduled releases now grant the repository token the `pull-requests: write`
448
+ and `actions: write` scopes required by their existing PR creation and CI
449
+ dispatch steps. Their checkout and Node setup actions are pinned to reviewed
450
+ commit SHAs, so the next automated release can complete without the manual
451
+ recovery used for v0.38.0.
452
+ - Typed TypeScript credential assignments such as `apiKey: string = "…"` can
453
+ no longer bypass hardcoded-secret detection. The precision corpus found and
454
+ reproduces this false negative while preserving an opposite clean control.
455
+ - Persisted benchmark timings no longer produce performance-regression claims
456
+ from matching platform labels alone. Controlled comparisons require at least
457
+ five samples from the same paired session before applying the 20-percent gate,
458
+ preventing host contention from masquerading as a tool slowdown.
459
+ - Benchmark cleanup tests now isolate their temporary parent, so concurrent
460
+ benchmark processes cannot be mistaken for leaked directories. The runner
461
+ rejects missing or symlinked temporary parents before materialization.
462
+ - Baseline comparison now invalidates reviewed evidence when a fixture digest,
463
+ configuration, classification, parser tier, scope, or expected/forbidden
464
+ label changes. Changed evidence can no longer inherit a previously reviewed
465
+ result without explicit re-adjudication and baseline replacement.
466
+ - The reviewed baseline was re-adjudicated after adding qualified ownership to
467
+ 13 synthetic fixture cases. Only source digests changed; all labels, controls,
468
+ scoped outcomes, confidence bounds, and the explicit unsupported case remain
469
+ unchanged.
470
+ - Closeout passed all 1,708 tests independently on Node 18, 20, 22, and 24,
471
+ the 24-case external baseline with zero scoped FP/FN regressions, package
472
+ composition, and a zero-vulnerability production dependency audit. Three
473
+ low-confidence diff-suspicion prompts were reviewed as non-contradictions;
474
+ no detector or repository-wide suppression was added.
475
+ - The R3/R4 living specification is lifecycle-verified against the branch's
476
+ exact merge base. Its registry outcome records the reviewed implementation
477
+ and test evidence, and the task ledger no longer presents completed work as
478
+ active implementation.
479
+ - Generated regression contributions now share the same finding-identity
480
+ normalizer as feedback verification, including structured `{ file, line }`
481
+ locations. Validators that return object locations no longer generate tests
482
+ that compare against `[object Object]`.
483
+ - Verified living specs can now record a new `verified → verified` maintenance
484
+ outcome. The gate requires a linked source, test, canonical-document, or
485
+ decision delta after the prior review and rejects empty repeats caused only by
486
+ generated registry, context, or outcome churn.
487
+ - The document-lifecycle living spec records the maintenance transition at its
488
+ exact reviewed revision, preserving the earlier delivery outcome and current
489
+ active-context policy.
490
+ - The precision-evidence living spec records the structured-location regression
491
+ fix as a second reviewed outcome, linked to its implementation and focused
492
+ tests rather than overwriting the original milestone evidence.
493
+ - The living-maintenance architecture description now states its positive
494
+ eligibility rule directly, keeping the canonical document within its
495
+ negation-load quality threshold.
496
+ - The document-lifecycle registry records that canonical wording review as a
497
+ separate maintenance outcome; the generated history remains append-only.
498
+
499
+ ## [0.38.0] - 2026-09-14
500
+
501
+ Automated weekly release — batches everything merged since `v0.37.1`.
502
+
503
+ ### Changed
504
+
505
+ - feat: close the spec lifecycle reconciliation loop (#357)
506
+
507
+
508
+ ### Added
509
+
510
+ - `docguard reconcile --since <ref>` emits a deterministic JSON review graph
511
+ that separates mechanical facts, approved intent, decisions, unrelated
512
+ changes, and unsupported evidence. Its write mode delegates only mechanical
513
+ generated-section refreshes to `sync`; approved requirements remain unchanged.
514
+ - `docguard specs complete` plans and applies the reviewed
515
+ `in_progress → implemented → verified` transaction. Completion requires a
516
+ clean revision, checked tasks, qualified implementation or test evidence for
517
+ every requirement, affected canonical docs, supported reconciliation, and a
518
+ guard result without errors. It records a bounded outcome and regenerates an
519
+ active-only context projection.
520
+ - The Spec Kit extension includes optional completion review hooks after
521
+ implementation and convergence, using events supported by Spec Kit's current
522
+ extension contract.
523
+
524
+ ### Changed
525
+
526
+ - Spec registry schema v2 adds qualified source implementation evidence and up
527
+ to 20 reviewed reconciliation outcomes. Version 1 remains readable for a
528
+ fail-closed migration through `docguard specs --write`.
529
+ - Retirement and completion use one staged multi-file transaction that restores
530
+ the prior set when mutation or post-write validation fails.
531
+ - R2 source and test ownership is explicitly qualified in the lifecycle
532
+ registry, allowing DocGuard's own reconciliation gate to distinguish reviewed
533
+ implementation from unsupported files.
534
+
535
+ ### Fixed
536
+
537
+ - Completed tasks no longer produce a permanent retirement warning for an
538
+ exact-path spec whose reviewed registry state is current, living, and verified
539
+ or released. Missing, malformed, stale, and non-living registry state still
540
+ fails closed to the review signal.
541
+ - Archive recovery validation now has an independent scanner boundary shared by
542
+ lifecycle, registry, and traceability checks, avoiding cyclic ownership while
543
+ preserving the same fail-closed tombstone contract.
544
+ - Staged lifecycle replacements use a cross-platform overwrite operation, so
545
+ existing registry and Markdown targets do not rely on POSIX rename behavior.
546
+ - Lifecycle documentation now states the transaction's exact durability scope:
547
+ staged writes and in-process rollback, without claiming crash consistency;
548
+ the checked-in registry projection retains the resulting source coordinates.
549
+ - The R2 lifecycle spec now records its reviewed implementation outcome as
550
+ verified while remaining an active living specification. Governing agent,
551
+ architecture, CI, environment, requirements, security, and test documents
552
+ were reviewed against the delivered command and authority boundaries.
553
+
554
+ ## [0.37.1] - 2026-09-14
555
+
556
+ Automated weekly release — batches everything merged since `v0.37.0`.
557
+
558
+ ### Changed
559
+
560
+ - fix: synchronize release version surfaces (#354)
561
+ - fix: clarify lifecycle scope and harden patch releases (#353)
562
+ - fix: enforce Spec Kit catalog form bounds (#352)
563
+ - fix: derive Spec Kit catalog inventory from manifest (#351)
564
+
565
+
566
+ ### Fixed
567
+
568
+ - Spec Kit catalog submissions now derive command and hook counts from the
569
+ extension manifest, avoid hardcoded validator totals, and enforce the form's
570
+ description and tag bounds, preventing stale or invalid release reminders.
571
+ - Lifecycle planning now marks the merged v0.37.0 delivery complete and separates
572
+ its released registry/retirement contract from the still-planned completion
573
+ transaction and post-hoc reconciliation work.
574
+ - `docguard hooks --list` and non-writing `docguard fix` invocations no longer
575
+ enter setup or refresh agent files. Automated releases now synchronize the
576
+ checked-in `.agent` skills with the released extension before verification.
577
+ - Automated releases now update PyPI metadata, MCP registry metadata, Spec Kit
578
+ metadata, AI skill markers, and both copyable CI pins through one fail-closed
579
+ synchronizer before testing or opening a release pull request.
580
+
581
+ ## [0.37.0] - 2026-09-14
582
+
583
+ ### Added
584
+
585
+ - Mandatory Spec Kit lifecycle hooks: `before_specify` loads the committed
586
+ prior-intent briefing and `before_tasks` gates the generated spec through the
587
+ same deterministic `docguard specs preflight` contract used outside Spec Kit.
588
+
589
+ - `docguard retire` introduces a document-lifecycle boundary for specs, plans,
590
+ migrations, and historical audits. Plan mode is read-only; `--check` can gate
591
+ remaining candidates; writes require explicit clean tracked paths and a
592
+ reason. Retired prose stays recoverable from a verified retention ref while
593
+ `.docguard-archive.json` records source commits, blob identities, rationale,
594
+ replacements, evidence documents, retired requirement identities, Git object
595
+ format, and restore commands. Traceability recognizes those identities as
596
+ tombstones, preventing historical test annotations from becoming orphans or
597
+ silently rebinding to a later spec. Incomplete recovery entries cannot supply
598
+ tombstones or suppress lifecycle findings.
599
+ - Guard includes a Document-Lifecycle validator with stable `DLC001`–`DLC004`
600
+ findings. Exact terminal status is high-confidence; `Completed` maturity and a
601
+ fully checked task list remain low-confidence review signals. Incomplete scan
602
+ coverage and manifest/working-tree disagreement cannot produce a false clean.
603
+ Projects outside a Git working tree report the validator as non-applicable,
604
+ and every lifecycle result is discoverable through `docguard explain`.
605
+ - `docguard specs --check|--write` maintains a committed, byte-stable
606
+ `.docguard-specs.json` lifecycle registry. Immutable IDs originate in spec
607
+ metadata; a JSON Schema defines the reviewed lifecycle/lineage/scope boundary,
608
+ derived artifact and task facts, explicitly scoped test evidence, and
609
+ Git-backed retirement tombstones. Invalid or unknown reviewed state fails
610
+ closed instead of being overwritten.
611
+ - `docguard specs preflight` provides the pre-specification lifecycle briefing;
612
+ `--path <spec>` gates a generated draft on registry freshness and unique
613
+ identity while keeping lexical overlap advisory. Guard adds `SPR001`–`SPR005`
614
+ through the Spec-Registry validator. Generic `retire` refuses active registered
615
+ specs so it cannot create a second lifecycle writer.
616
+
617
+ ### Changed
618
+
619
+ - Spec lineage validation now rejects unknown or one-sided relationships and
620
+ requires a superseding target to be approved and current. Empty projects can
621
+ begin their first specification without manufacturing an empty registry.
622
+
623
+ - The roadmap now contains current intent and contribution-ready work only.
624
+ Released specs and historical implementation documents are retired from the
625
+ active tree so AI agents cannot interpret them as current requirements.
626
+ - The active lifecycle specification separates safe mechanical fact refreshes
627
+ from requirement reconciliation: implementation drift never authorizes
628
+ silently rewriting approved intent.
629
+ - The llms.txt generators now use the shared backup-before-write path, including
630
+ when active context indexes are regenerated after archival.
631
+ - Feature completion evidence now requires document-qualified requirement
632
+ annotations. Bare IDs remain available in the repository-wide matrix but
633
+ cannot rebind to a different feature after retirement.
634
+ - Requirement annotations may use immutable `specId#requirementId` identities;
635
+ path-qualified references remain compatible. Traceability and registry
636
+ projection consume one shared evidence scanner, preserving the architecture
637
+ boundary and preventing old bare IDs from certifying a current feature.
638
+
639
+ ## [0.36.2] - 2026-09-14
640
+
641
+ ### Fixed
642
+
643
+ - Requirement identities include the defining document, preventing duplicate IDs across specs from sharing test coverage. Validator and feature scores share resolution; unique bare IDs remain compatible, and qualified references target exactly one document.
644
+
645
+ - Legacy badge command tests run in disposable projects with host setup tooling excluded, preventing source-checkout mutations during the test suite.
646
+
647
+ - `agents --check` preserves the repository and never bootstraps skills or invokes Spec Kit; stale managed files still exit 2, and explicit setup remains available.
648
+ - Documentation coverage honors configured documentation directories and raw role mappings, while excluded/private/symlinked documents cannot supply evidence. Reproduced against a pinned SvelteKit checkout.
649
+ - Configuration path construction and existence checks produce low-confidence review signals instead of asserting that directories are undocumented config files. Parsed comments and example strings do not establish file usage; findings identify the scanned documentation scope.
650
+ - Schema synchronization honors file exclusions and counts each source file once across overlapping roots, preserving separate models with the same name. Verified against a pinned Django checkout.
651
+ - Feature trace scoring uses the validator's explicit test annotations and labels; fixture JSON and incidental source strings no longer inflate requirement linkage. This does not yet solve duplicate requirement identities across specs.
652
+ - Diagnosis preserves freshness as a review task instead of suggesting incomplete or automatic document rewrites, and its AI prompt no longer demands removal of every warning.
653
+
654
+ ## [0.36.1] - 2026-09-11
655
+
656
+ ### Fixed
657
+
658
+ - Removed stale validator counts from the Spec Kit extension installation description, README, and repair skill. Found by installing the published v0.36.0 ZIP in a disposable Spec Kit project. The validation engine is unchanged.
659
+ - The Spec Kit verbose helper reads structured score/guard JSON, preserves PASS/WARN/FAIL, and rejects malformed reports. CLI resolution prefers local installs, quotes paths safely, and requires an installed CLI instead of fetching through npx.
660
+
661
+
662
+ ## [0.36.0] - 2026-09-11
663
+
664
+ ### Fixed
665
+
666
+ - Catalog submission drafts leave verification checkboxes unchecked, remove unsupported exclusivity claims, and require release-specific evidence before submission.
667
+
668
+ - Enterprise precision: preserve implementation evidence when API contracts omit routes; avoid formatting-only drift, negated technology claims, explained-skip noise, and narrowly identified synthetic mock passwords. Paired true-defect controls prevent broad suppression.
669
+
670
+ - **CI scaffolding**: `init --with ci` now writes the maintained workflow instead of executing a CI check; preserves existing files and rejects unsafe paths.
671
+
672
+ - Independent review fixes bound disk-cache promotion, reject malformed cached plans, preserve unknown report states, and report feedback persistence failures explicitly.
673
+ - Memory-plan caches invalidate on relevant source/document/configuration content and scanner changes, including ordinary uncommitted edits and fresh-process reads. Partial identities bypass reuse; disk writes are atomic and cache paths avoid symlink/private targets.
674
+ - Generated Git enforcement hooks parse formatted JSON, prefer installed local tools, and block unavailable or failed runtimes. Warning policy stays explicit. The Spec Kit after-implementation hook matches its mandatory contract.
675
+ - Traceability distinguishes requirement annotations and test labels from fixture strings. Freshness covers configured/nested docs and source additions/deletions, batches history reads, and rejects future review dates. Watch mode handles asynchronous errors and cleans up resources.
676
+ - CI templates use verified action commit pins, a fixed CLI version, full history, and checked JSON/exit status. The repository CI matrix explicitly emits TAP for its runtime budget.
677
+
678
+ ### Changed
679
+
680
+ - Score, diagnose, CI, and report identify the grade as structural maturity and expose unverified factual accuracy. **Machine-contract correction:** score JSON now returns null for memory.accuracy; the former proxy is memory.structuralAlignment. Category axes use structuralAlignment. Numeric score thresholds are unchanged. Consumers must preserve unknown values.
681
+ - Canonical documentation now reflects the Babel dependency, HTTP MCP security boundary, auxiliary files, current score contract, and limits of coverage claims. CI recipes refer to maintained templates; generated audit/probe artifacts have explicit analysis exclusions.
682
+
683
+ ### Added
684
+
685
+ - Explicit validator applicability/check coverage, bounded Worker binding extraction, and canonical document-role mappings for existing Markdown layouts. Custom mappings support validation/read-only plans; legacy automatic writes fail closed.
686
+ - Freshness emits low-confidence review tasks; explicit historical/superseded/deprecated documents retain their recorded intent without currentness assertions.
687
+
688
+ - Feedback selection with --code or --all, including confident findings, plus --preview to skip feedback-record writes. Public issue drafts contain metadata only, and search links help contributors check open and closed issues/PRs. Test-only synthetic reproductions are documented as a contribution path.
689
+ - Stable semantic-claim identifiers and bounded snapshot evidence for agent tasks; revision/dirty metadata and explicit uncertainty in context packs. Hashes identify inputs rather than assert review or correctness.
690
+ - A research-backed trust roadmap with competitor capabilities, proposed evaluations, contribution economics, and staged acceptance criteria.
691
+
692
+ ### Migration
693
+
694
+ - Regenerate installed Git hooks and update installed Spec Kit registrations to receive their new behavior. Enforcement requires an installed local DocGuard or a binary on PATH; hooks no longer fetch a package through npx. Review nullable accuracy handling in JSON consumers before upgrading automation.
695
+
696
+ ## [0.35.0] - 2026-09-11
697
+
698
+ ### Added
699
+
700
+ - **The MCP server image is now published to GHCR** as `ghcr.io/raccioly/docguard` (version tag + `latest`), and documented in the README for the first time. The Dockerfile already existed and worked, but was only ever built *from source* by MCP directory inspectors on every check, and had zero mentions in `README.md` or `docs/` — so it was effectively invisible. A published image means inspectors and CI users pull a prebuilt one instead.
701
+ - **GHCR rather than GitHub's npm registry:** public GHCR images pull with no authentication, whereas `npm.pkg.github.com` requires a PAT even for public packages — mirroring the npm package there would have been strictly worse than npmjs.com and purely cosmetic.
702
+ - The job **smoke-tests the image before pushing**: it feeds a JSON-RPC `initialize` over stdio and requires a valid response, so a container that builds but doesn't serve MCP never reaches the registry. Verified locally end to end before shipping.
703
+ - Authenticates with `GITHUB_TOKEN` — no stored credential, consistent with npm and PyPI now both being credential-free.
704
+ - **Nothing depends on this job**, so a Docker failure cannot block npm, PyPI, the GitHub Release, or the catalog reminder. Deliberately *not* `continue-on-error`, which would report a failed job as successful and hide a broken image behind a green run.
705
+ - Uses the docker CLI rather than third-party actions: two separate action-pin problems bit this pipeline today, and this needs no action versions at all.
706
+
707
+ ## [0.34.9] - 2026-09-11
708
+
709
+ No code changes. Fixes the PyPI publish that v0.34.8 broke, and re-syncs the registries (npm reached 0.34.8; PyPI did not).
710
+
711
+ ### Fixed
712
+
713
+ - **PyPI Trusted Publishing confirmed working; `PYPI_API_TOKEN` deleted.** v0.34.9 published to PyPI with no `TWINE_USERNAME`/`TWINE_PASSWORD` anywhere in the workflow, which means the OIDC path is what authenticated. Both registries and the git tag now serve 0.34.9, and **no workflow references any stored publishing credential** — neither registry depends on something that can expire.
714
+ - **Bumped `pypa/gh-action-pypi-publish` to v1.14.2.** v0.34.8's PyPI publish failed with `InvalidDistribution: Invalid distribution metadata: '2.5' is not a valid metadata version` — the older pin (copied from `raccioly/websec-validator`) bundles a twine too old to understand `Metadata-Version: 2.5`, which current `setuptools`/`build` emits. The failure was in metadata validation, not authentication, so it says nothing either way about the Trusted Publishing migration; that still needs a green run to be confirmed. Pinned by dereferenced **commit** SHA, not the annotated tag object's own SHA — those differ, and pinning the wrong one silently fails to resolve.
715
+ - Note for `websec-validator`: it still carries the old pin and will hit this same wall as soon as its `setuptools` moves forward.
716
+
717
+ ## [0.34.8] - 2026-09-11
718
+
719
+ No code changes. Completes the credential-free release pipeline.
720
+
721
+ ### Changed
722
+
723
+ - **PyPI publishing migrated from a stored API token to Trusted Publishing (OIDC)**, matching what `publish-npm` now does. `PYPI_API_TOKEN` was last rotated 2026-03-15 and was the next stored credential due to expire silently and take the pipeline down — exactly the failure that cost seven releases on the npm side (bug-256/bug-259). `publish-pypi` now runs with `environment: pypi` + `id-token: write` and publishes via `pypa/gh-action-pypi-publish`; the trusted publisher is registered on PyPI as `raccioly` / `docguard` / `release.yml` / environment `pypi`. Mirrors the working setup already in `raccioly/websec-validator`. Neither registry now depends on a credential that can expire.
724
+ - Added an OIDC precondition assert to `publish-pypi` so a missing `id-token: write` fails with a message naming the cause rather than as an opaque auth error.
725
+
726
+ ## [0.34.7] - 2026-09-11
727
+
728
+ **npm publishing is fixed.** First release since v0.34.0 to reach npm, PyPI, and GitHub in sync. Seven releases were needed because three independent faults were stacked, each masking the next.
729
+
730
+ ### Fixed
731
+
732
+ - **Node 24 *and* no `registry-url` together.** Tracing every prior failure showed each run had exactly one of the two blockers, never neither: v0.34.4 (Node 20 + `registry-url`) → `E404`, Node below the 22.14.0 OIDC floor so the empty `_authToken` was used; v0.34.5 (Node 20, no `registry-url`) → `ENEEDAUTH`, no token but Node still too old; v0.34.6 (Node 24 + `registry-url`) → `E404`, Node fine but the empty token `setup-node` writes took the token path. Node ≥ 22.14 clears the OIDC floor and omitting `registry-url` stops an empty `_authToken` being written; npm defaults to registry.npmjs.org regardless.
733
+ - **Added auth-state diagnostics and `--loglevel verbose` to the publish step**, so a further failure reports which auth path npm chose rather than leaving it to inference from a generic 404.
734
+ - **The final fault: the npm trusted publisher was stored with a trailing slash in its Repository field** (`docguard/`), so the saved config read `raccioly/docguard/` and never matched the OIDC claim `raccioly/docguard`. This was invisible until the first two faults were cleared, because only then did npm get far enough to attempt the exchange and say so: `POST /-/npm/v1/oidc/token/exchange/package/docguard-cli → "OIDC token exchange error - package not found"`. Fixed by adding a second trusted publisher with the exact value (additively — never deleting the only publisher on a package mid-repair). The `--loglevel verbose` added in this same release is what surfaced it.
735
+
736
+ ## [0.34.6] - 2026-09-11
737
+
738
+ No code changes. The actual root cause of the npm publish failure, after five wrong diagnoses.
739
+
740
+ ### Fixed
741
+
742
+ - **`publish-npm` now runs Node 24 (was Node 20).** This was the real blocker the whole time. npm Trusted Publishing requires **npm CLI >= 11.5.1 AND Node >= 22.14.0**. The job ran Node 20 for five straight releases, so npm never *attempted* the OIDC exchange — it silently fell through to token auth and failed there. That produced two convincing red herrings in sequence: `E404 "not found or you do not have permission"` while an empty `_authToken` was present, then `ENEEDAUTH` once it wasn't. Neither error names the version floor, which is what made this take so long.
743
+ - **Restored `registry-url` on `setup-node`** — v0.34.5 removed it on a wrong theory (below). npm's documented example sets it; the empty `_authToken` it writes only ever mattered *because* Node 20 had already taken OIDC off the table.
744
+ - **Dropped the `--provenance` flag.** Under Trusted Publishing npm generates and publishes provenance attestations automatically; the flag is redundant.
745
+ - **Replaced the auth-token guard with a precondition assert.** It now verifies Node >= 22.14.0, npm >= 11.5.1, and that `ACTIONS_ID_TOKEN_REQUEST_URL` is present (i.e. `id-token: write` actually took effect) — failing with a message that names the real cause instead of surfacing it as an unrelated-looking auth error three minutes later. Boundary cases verified locally: 22.13.0 blocked / 22.14.0 passes, 11.5.0 blocked / 11.5.1 passes.
746
+
747
+ ## [0.34.5] - 2026-09-11
748
+
749
+ Fifth attempt at the npm publish. **The diagnosis in this entry was wrong** — see v0.34.6 for the actual cause. Tagged, GitHub-released, and on PyPI; never reached npm.
750
+
751
+ ### Fixed
752
+
753
+ - **Fixed the flaky watch-mode test that was blocking releases** (`tests/commands.test.mjs`, "starts watch mode and reacts to file changes"). It waited on `'Watching 5 directories' || 'Watching for changes'` — but the real count is 4, so the first branch never matched and it always fell through to the second, which prints *before* the initial guard run and before the fs watchers are registered. The subsequent file write then landed in that gap and was missed. On a fast runner the guard run finished inside the 500ms buffer and it passed; on a loaded one it didn't — which is why it failed 2 of 3 release runs, on Node 24 and then Node 22. Now waits on `/Watching \d+ directories/`, the marker printed only once watchers are live. Verified 5x clean, plus 3x under deliberate CPU saturation to mimic a loaded runner. *(This fix was real and holds.)*
754
+ - ~~**Removed `registry-url` from the publish job's `setup-node`.**~~ **Incorrect — reverted in v0.34.6.** The theory was that it was breaking Trusted Publishing. `setup-node`'s `registry-url` writes an `.npmrc` containing `//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}`; with `NODE_AUTH_TOKEN` removed in v0.34.3, that expanded to an **empty** token. npm then took the token-auth path holding no token and 404'd, never attempting the OIDC exchange — which is why the log showed provenance signing succeed, no OIDC notice at all, and then `404 ... could not be found or you do not have permission`. npm defaults to `registry.npmjs.org` anyway, so nothing is lost. Verified the npm-side trusted publisher config is correct and saved (`raccioly/docguard` → `release.yml`, with both `npm publish` and `npm stage publish` permissions).
755
+ - ~~**Added a fail-loud guard asserting no `_authToken` exists.**~~ **Superseded in v0.34.6** by a precondition assert on the Node/npm version floors, which is what actually needed guarding. (Worth keeping the detail that led here: `npm config get` refuses on auth keys — "protected" — and `npm config list --json` omits them entirely, so detecting a configured token requires grepping the `.npmrc` files directly.)
756
+ - **`scheduled-release.yml` no longer pushes directly to `main`.** Two stacked blockers made that impossible once branch protection landed: `main` now requires a PR and `github-actions[bot]` has no bypass; and a PR opened with `GITHUB_TOKEN` doesn't trigger workflows, so the required `test (18/20/22/24)` checks would never report and the PR could never merge. It now pushes a `release/vX.Y.Z` branch, opens a PR, and explicitly dispatches `ci.yml` against that branch so the checks do report. `auto-merge.yml` gained a correspondingly narrow rule for these: `github-actions[bot]` PRs merge only from a `release/` branch and only when they touch nothing beyond version, changelog, and generated extension metadata.
757
+
758
+ ## [0.34.4] - 2026-09-11
759
+
760
+ No code changes from v0.34.3 — v0.34.3's own npm-publish fix (below) turned out to have a bug, caught by this very release attempt: `npm install -g npm@latest` resolved to npm 12.0.2, which requires Node `^22.22.2 || ^24.15.0 || >=26.0.0` — newer than the Node 20 this job runs on, so the self-update step itself failed before publish ever ran. Same class of mistake as the `@babel/parser` major bump earlier (bug-255): an unpinned "latest" floated past what the job's Node version supports.
761
+
762
+ ### Fixed
763
+
764
+ - **Pinned the npm self-update to the 11.x line (`npm@11`, not `npm@latest`).** npm 11.x declares `engines: {node: '^20.17.0 || >=22.9.0'}` — compatible with the Node 20.20.2 this job actually runs, and 11.19.1 (what it resolves to) is well past the 11.5.0 floor Trusted Publishing needs. Verified locally in an isolated prefix on Node 20.20.2 (the exact runner version from the failure log) before pushing.
765
+
766
+ ### Added
767
+
768
+ - **Test-runtime budget in CI (`TEST_BUDGET_MS`, 120s).** A test that walks an unintended tree still *passes* — it just takes forever, so no correctness gate catches it. PR #328 did exactly that (a test passed `/` as a project dir): `tests/schemas.test.mjs` went 118ms → >10s and the whole suite ~25s → 190s, green the entire time. CI now fails on the duration instead. Normal runs are ~33s (Node 24) to ~51s (Node 18), so the budget catches catastrophes without tripping on runner jitter.
769
+ - **`auto-merge.yml` — hands-off merging for green bot PRs.** Fires on CI completion, independently re-verifies all four Node legs via the API, then merges. Deliberately does *not* use `gh pr merge --auto`: GitHub's native auto-merge needs repo-level `allow_auto_merge` plus **required** status checks, and without required checks configured it merges immediately without waiting for CI — worse than merging by hand. Policy: dependabot patch/minor auto-merges (majors never — a `@babel/parser` major silently dropped Node 18 and broke a release); Jules PRs auto-merge only when test-only or docs-only, with anything touching `cli/` logic, `.github/`, or `package.json` labeled and held for a human.
770
+ - **`scheduled-release.yml` — weekly batched releases.** Mondays 09:00 UTC (plus `workflow_dispatch` for on-demand, with a patch/minor choice). Bumps the version, generates a changelog entry from the commits since the last tag, re-runs the suite and `guard` before committing, then pushes — which triggers `release.yml` to do the actual tag/GitHub Release/npm/PyPI publish. No-ops when nothing releasable has landed (`.wolf/` bookkeeping alone never justifies a release), so it won't cut empty versions.
771
+
772
+ ### Changed
773
+
774
+ - **`jules-triage.yml` now detects duplicates by changed-file overlap, not just normalized titles.** Title-equality was too strict: #324 ("add tests for untested shared-ignore utilities"), #325 ("add missing tests for shared-ignore functions") and #329 ("Add unit tests for shared-ignore detection utilities") were the same work, all three sat open, and two would have collided on the same import block if merged together. Still metadata-only — never checks out PR code.
775
+
776
+ ## [0.34.3] - 2026-09-11
777
+
778
+ No functional code changes from v0.34.2 — this release was meant to exercise the Trusted Publishing fix end to end (a re-run of a past workflow job uses the workflow file as it existed at that run's commit, so testing a workflow-file fix requires a fresh run) but its own fix had a bug — see v0.34.4. Tag, GitHub release, and PyPI landed; npm did not.
779
+
780
+ ### Fixed
781
+
782
+ - **npm publish switched from a stored `NODE_AUTH_TOKEN` to Trusted Publishing (OIDC).** The token that broke v0.34.1/v0.34.2's npm publish (see their entries below) is retired — `publish-npm` now authenticates via the `id-token: write` OIDC token exchanged directly with npm's registry, matched against a trusted-publisher connection configured on npmjs.com (raccioly/docguard, `release.yml`). Nothing here can expire the way a stored token did; a short-lived token is minted per run.
783
+ - v0.34.1 and v0.34.2 remain permanently missing from npm (tag/GitHub release/PyPI all landed for both) — not worth backfilling now that publishing works again going forward. v0.34.3 joined them for a different reason (see above); v0.34.4 is the one to actually check landed.
784
+
785
+ ## [0.34.2] - 2026-09-11
786
+
787
+ ### Fixed
788
+
789
+ - **`@babel/parser` 7.29.7 → 7.29.8** — the newest 7.x patch, confirmed Node-18-compatible. Supersedes dependabot's repeat proposal of the 8.0.4 major bump (already reverted once in 0.34.1 — see below) with the correct fix. (#333)
790
+ - **`docs-diff`'s `collectCodeTests` ignored `.docguardignore`/`config.ignore` during recursive test-directory scans**, so excluded test files could still count toward test-coverage validation, producing false positives on projects that explicitly excluded fixture/generated test dirs. Both recursive walkers now filter through `shouldIgnore` before collecting. (#334)
791
+ - Doc example for `generate --dir` used a non-existent absolute path (`/path/to/project`), which fails with `EACCES` if anyone actually runs it verbatim. Now a relative path. (#338)
792
+
793
+ ### Changed
794
+
795
+ - Bumped the `osv-scanner-action` reusable workflows (supply-chain scanning) from v2.3.8 to v2.5.1. (#336)
796
+ - **`.github/dependabot.yml`: added an ignore rule for `@babel/parser` major-version bumps.** The 8.x line requires Node `^22.18.0 || >=24.11.0`, silently dropping Node 18 (which this project supports and CI gates on) — confirmed twice now (#331 in 0.34.1, #335 closed this release) that dependabot will keep proposing it every cycle since it can't see the `engines` mismatch. Patches/minors on the 7.x line still flow through normally.
797
+
798
+ ### Tests
799
+
800
+ - Added coverage for previously-untested exports: `surfaceConfidence`, `astTierAvailable`, `parseCheckedTasks`, `compileGlob`, `isRunnerEnvVar`. (#337, #339)
801
+
802
+ ### Known issue
803
+
804
+ - **npm publish is blocked on an expired `NPM_TOKEN`.** `v0.34.1`'s npm publish failed identically three times (Aug 28 ×2, Sep 11) with a `404` on the registry PUT immediately after successful provenance signing — not a registry incident (npm status green throughout, `docguard-cli` package unaffected on the registry). The token was last rotated 2026-05-22 and last worked for the 2026-08-13 (v0.34.0) publish; the failure window is consistent with npm's ~90-day Automation-token expiration. `v0.34.1` and `v0.34.2` are both tagged, GitHub-released, and on PyPI, but missing from npm until the token is rotated.
805
+
806
+ ## [0.34.1] - 2026-08-28
807
+
808
+ ### Fixed
809
+
810
+ - **OpenAPI schema field with no `type` crashed schema sync.** `extractOpenAPIRelationships` called `.toLowerCase()` on `field.type` unconditionally — a field with no `type` (valid OpenAPI, e.g. a bare `$ref`) threw instead of being skipped. (#328)
811
+ - **TODO-Tracking never recognized Python/Go/Ruby test-file naming.** The test-file exclusion regex only matched the dotted JS convention (`foo.test.py`), which nobody writes — real Python/Go/Ruby test files are `test_foo.py`, `foo_test.py`, `foo_test.go`, `foo_spec.rb`. TODOs inside those files' actual test functions were flagged as untracked source TODOs. Now recognizes the idiomatic naming for all three. (#328)
812
+
813
+ ### Changed
814
+
815
+ - Bumped `actions/setup-node` and `actions/setup-python` to v7 in CI/release workflows. (#330)
816
+
817
+ ### Reverted
818
+
819
+ - **`@babel/parser` 8.0.4 → back to 7.29.7.** Dependabot's major-bump PR (#331) tested green locally and merged, but `8.0.4` requires Node `^22.18.0 || >=24.11.0` — it silently dropped Node 18 (and, per its own `engines` field, isn't really supported on 20 either, though it happened to run there). This project declares `"engines": {"node": ">=18.0.0"}` and CI gates all four Node versions; the release pipeline itself caught it — `test (18)` failed with 20 broken AST-parsing tests while 20/22/24 passed, so nothing published (npm/PyPI publish correctly never ran). Reverted and re-verified locally across Node 18, 20, 22, and 24 before re-releasing. Lesson: a major bump of a parsing library needs the full supported-version matrix tested, not just the developer's local Node version — `engines` mismatches don't show up as install failures, they show up as silent behavioral differences.
820
+
821
+ ### Tests
822
+
823
+ - Added coverage for `walkFiles`, `isNonProductDir`, and `isNonProductPath` in `shared-ignore.mjs`. (#324)
824
+
825
+ ## [0.34.0] - 2026-08-13
826
+
827
+ ### Fixed
828
+
829
+ - **Canonical docs in subfolders were invisible across 19 call sites (`listCanonicalDocs`).** Every consumer of `docs-canonical/` enumerated it by hand with a flat `readdirSync(...).filter(f => f.endsWith('.md'))`, so a project that groups its canonical docs — `docs-canonical/01-architecture/MODULE-MAP.md`, a common convention past a handful of files — was scanned as if those docs did not exist. Replaced all 19 with one shared recursive enumerator (`listCanonicalDocs` in `shared-ignore.mjs`, built on the existing `walkFiles`), which honors `.docguardignore` per-doc against the full relative path, skips dot-directories while keeping dot-markdown files, and returns sorted project-relative POSIX paths.
830
+
831
+ First pass (5 sites) fixed the worst offenders: **docs-sync** reported services as undocumented while the documentation sat right there (an *unfixable* DSY002 — editing the nested doc could never clear it); `docguard:validator … n/a` **markers** in nested docs were dropped, so a validator declared N/A ran anyway; **semantic-claims** never scanned nested docs for unverified claims; **agent-readability** scored an empty set; **ALCOA** reported "all docs updated within 30 days" against zero documents, so a stale nested tree scored green.
832
+
833
+ Second pass (14 more sites, across `impact`, `init`, `llms`, `memory`, `trace`, `hooks`, and the `api-doc-smells`/`cross-reference`/`diff-suspicion`/`doc-quality`/`docs-coverage`/`generated-staleness`/`reference-existence`/`traceability` validators) closed the rest. The standout: **generated-staleness**'s cheap pre-flight check missed a nested `docguard:section source=code` marker and concluded "nothing to do" — the *entire validator* silently never ran, disabling drift detection outright rather than just under-reporting it. Also fixed: `trace --reverse <file>` falsely reporting no canonical doc references a file documented only in a nested doc; `reference-existence` never indexing symbol references made from nested docs; `init`'s re-init detection treating an already-initialized nested-docs project as first-run; a post-commit hook nudge that couldn't find docs referencing an edited file; and orphaned-doc detection in `traceability` that was blind to strays outside the top level.
834
+
835
+ Two behavior notes: `.md` matching is now uniformly case-insensitive (some call sites lowercased, some didn't — one tool must not hold two opinions about what a canonical doc is), and projects with nested canonical docs will see freshness, readability, and claim counts move as those documents become visible for the first time. Where a site's message or `location` text is user-visible (validator findings, CLI output), the fix preserves the exact flat-tree wording — only visibility into nested docs changed, not the format of existing output. Verified against DocGuard's own repo (flat `docs-canonical/`, so a correct fix must produce identical output): `guard`/`score` JSON byte-identical apart from timings across both passes (282/291, 0 errors, 14 warnings). 18 regression tests across `tests/canonical-docs-nested.test.mjs` and `tests/canonical-docs-nested-phase2.test.mjs`; 9 of them fail against the previous release, proving they actually catch the bug.
836
+
837
+ ## [0.33.1] - 2026-07-16
838
+
839
+ ### Added
840
+
841
+ - **Claude Desktop one-click extension (`.mcpb`).** Each release now attaches `docguard-v<version>.mcpb` — the official MCP Bundle format: drag into Claude Desktop → Settings → Extensions, pick the project folder, done. No npm, no JSON editing. Built by the new `build-mcpb` release job from the exact npm-pack payload (manifest template in `mcpb/`, packed with `@anthropic-ai/mcpb`). README gained one-click install badges for Cursor and VS Code (MCP deeplinks) alongside the Claude Code and registry paths.
842
+
843
+ - **npm provenance attestation.** Releases now publish with `npm publish --provenance` (OIDC + Sigstore): every tarball carries a signed statement that it was built by this repo's GitHub Actions from a specific commit. This is what "unknown package" legitimacy checks (Claude Code, socket.dev, npm's Provenance badge) verify — DocGuard installs are now cryptographically attributable.
844
+ - **PRIVACY.md** — the short, honest policy: DocGuard collects nothing, all analysis is local, no telemetry; the three explicit user-initiated outbound paths (`feedback` URL, `gh`-backed PR commands, opt-in HTTP transport) are enumerated. Ships in the npm package and unblocks Anthropic Connectors Directory submission (a missing privacy policy is an instant rejection there).
845
+ - **FAQ**: why AI agents flag DocGuard as "unknown" on first install, and how to pre-trust it (project `.mcp.json`, Always allow, managed-settings allowlist).
846
+
847
+ ## [0.33.0] - 2026-07-16
848
+
849
+ ### Added
850
+
851
+ - **Adoption baseline — `guard --update-baseline` + committed `.docguard.baseline.json`.** The ESLint/semgrep-style brownfield pattern: freeze a legacy repo's existing findings once, commit the file, and guard/ci gate only NEW drift from then on — no red pipeline on adoption day. Fingerprints are content-addressed (finding code + location path with line numbers stripped + message with digit-runs normalized), so they survive line churn and volatile counts ("21 commits since…") — and they carry **occurrence counts**: freezing one hardcoded-secret finding in a file suppresses exactly one; a second instance of the same class surfaces and gates (the ESLint-baseline semantics). Suppression is never silent: the summary prints "N pre-existing finding(s) suppressed", `baselineSuppressed` rides the JSON contract, and `--no-baseline` (or `"baseline": false` in `.docguard.json`) shows everything. A malformed baseline is treated as absent — corruption can never un-gate CI. Applied inside `runGuardInternal`, so guard, ci, report, SARIF/JUnit outputs, and the MCP tools all honor it uniformly. Also: DocGuard's own files (`.docguard.json`, `.docguardignore`, `.docguard.baseline.json`) are exempt from Docs-Coverage's undocumented-config check — writing the baseline no longer instantly creates a DCV001 about the baseline.
852
+
853
+ - **`guard --format junit` — JUnit XML for the rest of the CI world.** SARIF covers GitHub Code Scanning; JUnit covers GitLab (`artifacts:reports:junit`), Jenkins (`junit` step), Azure DevOps, and CircleCI. One testcase per validator: error findings render as `<failure>` (red in every CI UI), a crashed validator renders as `<error>` (also red — never a silent pass), warn-only validators pass with findings in `<system-out>`, skipped/N/A validators map to `<skipped/>`. Strict XML escaping, exit codes identical to `guard`'s json/sarif branches, banner-free stdout. GitLab and Jenkins recipes added to CI-RECIPES (Recipe 1b).
854
+
855
+ - **`docguard_report` MCP tool.** The compliance-evidence bundle is now callable by agents: same payload as `docguard report --format json` (guard verdict, findings by code, score, ALCOA+, fix history, integrity hash), read-only annotations, over both stdio and HTTP transports. MCP tool count 5 → 6.
856
+
857
+ - **Score history + `score --trend`.** Every `docguard ci` run appends one line to `.docguard/history.jsonl` ({timestamp, commit, score, grade, guard counts, status}); `docguard score --trend` renders the trajectory — sparkline, first→latest delta, and the last 10 runs with commit stamps (`--format json` for the raw series). Opt out per run with `ci --no-history`. Local-first: `.docguard/` stays gitignored; in ephemeral CI, persist the file across runs with a cache/artifact step (see CI-RECIPES). The append is silent-on-failure — recording history never fails the pipeline it records.
858
+
859
+ - **`docguard report` — compliance-evidence bundle for audits.** Runs guard + score internally and emits a deterministic evidence report: tool version, git commit/branch/dirty state, per-validator guard verdict, findings grouped by stable code, CDD score with categories, the ALCOA+ data-integrity attribute table, and the mechanical-fix history from `.docguard/fixed.json`. The bundle carries a tamper-evident `sha256` integrity hash over the git-stable sections of the payload (the generation timestamp and the ALCOA+ block are excluded — the latter's Contemporaneous attribute is mtime/wall-clock-relative — so the same commit always reproduces the same hash, including on a fresh clone). Markdown to stdout by default, `--format json` for the machine bundle, `--out <file>` to write either to a file. Report is **evidence, not a gate**: it always exits 0 — `guard` and `ci` remain the commands that fail builds, so evidence collection never self-censors. Headless in both formats (stdout is the artifact; no banner bytes). Enterprise rationale: docs platforms ship no audit logs at any tier — DocGuard now generates a documentation audit trail from the repo itself.
860
+
861
+ ### Fixed
862
+
863
+ - **Pre-release adversarial review — 12 findings fixed before ship.** An independent review pass over this release's batch caught and fixed, among others: `ci` missing from the read-only command set (a bare text-mode `ci` still scaffolded skills into the workspace it gates); baseline fingerprints suppressing NEW same-class findings in the same file (now occurrence-counted); `report`/`ci` not disclosing baseline suppression (now in the payload, the markdown summary, and history entries); JUnit rendering a crashed validator as a passing testcase; `ci` gating on raw instead of severity-aware counts (it now matches `guard` exactly); threshold failures recorded as `PASS` in history; `--update-baseline --changed-only` shrinking the committed baseline to the lite validator subset (now refused); and a non-atomic history trim. Every fix ships with a regression test.
864
+
865
+ - **`docguard ci` un-deprecated and made safe for pipelines.** The v0.20 consolidation routed `ci` through `init --with ci`, which (a) scaffolded missing canonical docs INTO the CI workspace — a validate command mutating the tree it validates — and (b) printed the deprecation warning + init chrome into `--format json` stdout, corrupting it for parsers. `ci` now dispatches straight to the gate (guard + score, read-only, machine-clean) and is a first-class command again; `init --with ci` still runs the gate once after init. `runCI` also moved off `console.log + process.exit` to `stdout.write + process.exitCode` — the >8 KB pipe-truncation class fixed for `guard --format json` in v0.28.
866
+
867
+ ## [0.32.0] - 2026-07-11
868
+
869
+ Graph-informed release — detection improvements and integration surfaces
870
+ adapted from patterns proven in
871
+ [graphify](https://github.com/Graphify-Labs/graphify) (MIT), rebuilt
872
+ zero-dependency and deterministic for DocGuard. The detectors were empirically
873
+ validated read-only against five real production repos before shipping: zero
874
+ false positives; the indirect-impact analysis surfaced genuine, explainable
875
+ chains on two of them. Validator count unchanged (27).
876
+
877
+ ### Added
878
+ - **VALIDATION.md** — an honest benchmarks-style page documenting the
879
+ empirical method every detector goes through before shipping enabled
880
+ (read-only corpus runs on real production repos, keep/cut/tune, dogfooding)
881
+ and the measured v0.31/v0.32 results, including what DocGuard does NOT
882
+ claim. Linked from the README header.
883
+ - **PR doc-conflict analysis — `docguard impact --prs`.** Maps every open
884
+ PR's changed files to the canonical docs they impact (same reference index
885
+ as regular impact; a PR editing a canonical doc directly counts too) and
886
+ reports pairs of PRs impacting the SAME doc — a merge-order risk: whichever
887
+ lands second must re-verify the shared doc. Uses the `gh` CLI (no token
888
+ handling in DocGuard); degrades to a clear message when `gh` is missing or
889
+ the repo isn't on GitHub. Capped at 20 open PRs per scan. The
890
+ graph-community version of this idea ships in graphify's `prs --conflicts`;
891
+ this is the doc-integrity equivalent.
892
+ - **MCP Streamable HTTP transport — `docguard mcp --transport http`.** One
893
+ shared process can now serve the DocGuard tools to a whole team: JSON-RPC
894
+ over POST (single + batch), 202 for notification-only bodies, session id
895
+ issued on initialize (stateless server — accepted, never required), GET
896
+ correctly 405s (no SSE stream offered). Zero-dep (`node:http`). Security
897
+ posture: binds `127.0.0.1` by default; binding any non-loopback host
898
+ REFUSES to start without `--api-key`/`DOCGUARD_API_KEY`; when a key is set
899
+ every request must carry it (`Authorization: Bearer` or `X-API-Key`);
900
+ browser cross-site origins are rejected (DNS-rebinding guard); 4 MiB body
901
+ cap. Flags: `--port` (default 8585), `--host`, `--api-key`, `--path`
902
+ (default `/mcp`). The stdio transport is unchanged and remains the default;
903
+ both share one JSON-RPC dispatcher.
904
+ - **Agent nudge hook — `docguard hooks --claude`** (graphify's always-on-hook
905
+ distribution pattern, pointed at doc integrity). Registers a `PostToolUse`
906
+ hook in the project's `.claude/settings.json`: after the agent edits a
907
+ canonical/agent doc it is nudged to run `docguard guard --changed-only`;
908
+ after it edits a code file the docs reference, it is nudged toward
909
+ `docguard impact`. Merge-safe (only DocGuard's own entry is added/removed;
910
+ an unparseable settings.json is never touched), idempotent, throttled (one
911
+ nudge per file per 30 min via `.docguard/nudge-state.json`), and the
912
+ `docguard nudge-hook` runtime is silent-on-error by contract — it can never
913
+ break an agent session. Explicit opt-in; `init`/`ensureSkills` never install
914
+ it. Remove with `docguard hooks --claude --remove`.
915
+ - **ADR-citation check (REF002, reference-existence)** — the code→doc direction
916
+ of reference existence. A code comment citing a decision record (uppercase
917
+ `ADR-` + number in a comment) is now verified against the ADR documents the
918
+ repo actually defines (single-file `ADR.md` sections, `ADR-*.md` filenames,
919
+ and madr-style `docs/adr/0007-*.md`). Numbers compare as integers
920
+ (`ADR-0011` matches `ADR-11`). Citations only count inside comments — string
921
+ literals and identifiers are ignored — and tests/fixtures are excluded
922
+ (non-product scoping). IETF RFC citations are deliberately out of scope
923
+ (external registry — would false-positive on every `RFC 793` comment). Soft
924
+ (`confidence: low`), capped at 10 findings, suppressible with
925
+ `// docguard:ignore REF002`, disable with
926
+ `referenceExistence.adrCitations: false`.
927
+ - **Obsidian wikilink support (Cross-Reference + impact)** — `[[Doc]]`,
928
+ `[[Doc#Heading]]`, and `[[Doc|alias]]` are now validated like inline links
929
+ (broken target → XRF001, broken heading → XRF002), and `impact`'s doc→doc
930
+ blast radius sees wikilink dependents. Precision-gated: wikilinks are only
931
+ validated when the repo demonstrably uses them as FILE links (`.obsidian/`
932
+ exists, or at least one wikilink target resolves) — repos using `[[name]]`
933
+ as a non-file convention are skipped silently. Image embeds `![[x.png]]`
934
+ never count. Wikilink targets resolve sibling-first, then vault-wide by
935
+ basename across the project's doc homes.
936
+ - **Indirect impact via the import graph (`docguard impact`)** — a changed file
937
+ with no doc references can still invalidate docs about the modules that
938
+ IMPORT it. `impact` now walks the reverse import graph (reusing the
939
+ Architecture validator's graph builder — one builder, not two) up to 2 hops
940
+ and reports docs describing an importer of a changed file, with the
941
+ explainable chain (`doc describes X, which imports changed Y`). Hub modules
942
+ (>15 imports, e.g. a CLI dispatcher) are suppressed — their docs would flag
943
+ on every dependency change. Docs already directly affected are not repeated.
944
+ JSON adds `indirectDocs`; disable with `--no-indirect`. JS/TS import graphs
945
+ only (the graph builder's scope).
946
+ - **Graphify knowledge-graph interop (Traceability)** — teams that commit
947
+ `graphify-out/graph.json` (a tree-sitter knowledge graph) get its doc↔code
948
+ edges counted as linkage evidence before an "unlinked doc" (TRC002) is
949
+ raised. Trust rules: only `EXTRACTED` edges count (never the LLM-derived
950
+ `INFERRED`/`AMBIGUOUS` tiers), at least one linked code file must still
951
+ exist (a stale graph can't vouch), and the graph is evidence-only — it can
952
+ turn a warning into a pass but never produces a finding. Zero-dependency:
953
+ one JSON read; malformed graphs are silently ignored.
954
+
955
+ ### Fixed
956
+ - **Cross-Reference link parsing** — query strings are stripped before target
957
+ resolution (`./DOC.md?plain=1#anchor` now resolves to `DOC.md` instead of a
958
+ phantom file), and CommonMark angle-bracket targets with spaces
959
+ (`[t](<my doc.md>)`) are resolved instead of being silently skipped.
960
+ - **Semantic-claim extractor honors `.docguardignore`** — a doc the user
961
+ explicitly excluded from validation no longer feeds the "unverified claims"
962
+ pool (guard notice, `verify --semantic`, the ALCOA `Accurate` pillar). On
963
+ DocGuard's own repo an ignored historical audit contributed 28 of 39
964
+ reported claims, burying the actionable ones.
965
+
966
+ ## [0.31.0] - 2026-07-07
967
+
968
+ Accuracy release — six research-backed detectors that make drift detection
969
+ change-aware and language-agnostic, built on one shared diff foundation. Every
970
+ new check was empirically tuned read-only against six real production repos
971
+ (TypeScript + Python) before shipping; all are deterministic (no LLM at
972
+ validation time) and soft (`confidence: low`, never break CI). Validator count
973
+ 24 → 27.
974
+
975
+ ### Added
976
+ - **`docguard impact` — doc→doc blast radius + agent-instruction files** (feat 1).
977
+ Agent-instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are now indexed, so a
978
+ changed code file they reference is surfaced. New: when a canonical/agent doc
979
+ changes, the docs that reference it — including agent-instruction files — are
980
+ flagged as a "blast radius" (`{ changedDocs, blastRadius }` in JSON). No
981
+ verified competitor propagates doc staleness across the doc graph. Proven on a
982
+ real repo: an ARCHITECTURE.md change flags the AGENTS.md/CLAUDE.md that cite it.
983
+ - **Diff-Suspicion validator (DSP001)** (feat 3) — change-driven. A doc that BOTH
984
+ references a code file changed since the ref AND shares domain tokens removed
985
+ in that diff is flagged for review. Deterministic diff-overlap rule
986
+ (arXiv 2010.01625, F1 74.7); path/module refs + domain-token filtering +
987
+ per-doc cap keep it quiet at PR granularity.
988
+ - **Reference-Existence validator (REF001)** (feat 2) — two-revision check. A
989
+ compound code identifier backticked in a doc that existed when the doc was last
990
+ updated but has ZERO matches at HEAD is flagged as outdated (arXiv 2212.01479).
991
+ In-memory HEAD identifier set + authoritative git-grep confirmation; zero false
992
+ positives across the corpus.
993
+ - **API-Doc-Smells validator (APS001 Bloated / APS002 Lazy)** (feat 4) —
994
+ deterministic length signals on signature-headed doc units (F1 0.90 / 0.95).
995
+ - **IR-based traceability soft-matching** (feat 5) — `cli/shared-ir.mjs`
996
+ (zero-dep TF-IDF + cosine). An untraced requirement now surfaces the
997
+ TF-IDF-closest test file ("X may already cover it — add @req there"),
998
+ reducing false "no coverage" for tests that lack the annotation.
999
+ - **`docguard verify --since <ref>` — change-aware staging** (feat 6). Attaches
1000
+ an activity-labeled (ordered replace/delete/add) structured diff to the staged
1001
+ agent-judgment tasks and flags which claims are about just-changed code —
1002
+ CARL-CCI showed the structured-diff representation drives judgment accuracy
1003
+ (arXiv 2512.19883).
1004
+ - **`cli/shared-diff.mjs`** — zero-dependency unified-diff parser + identifier-
1005
+ aware tokenizer + activity-labeled diff, the shared foundation for feats 1/2/3/6.
1006
+
1007
+ ### Fixed
1008
+ - `hooks` crash from a `core.hooksPath` edge and other pre-ship bugs caught by
1009
+ dogfooding DocGuard on itself (a `walkFiles`-vs-`git grep` dot-directory
1010
+ asymmetry that fabricated reference-existence false positives; a `.map(basename)`
1011
+ index-as-suffix crash in verify).
1012
+ - **Self-counting consistency** — `canonical-sync` and `metrics-consistency` now
1013
+ agree on the validator count (both 27); a default-off validator previously made
1014
+ them disagree.
1015
+
1016
+ ### Changed
1017
+ - New validators default ON except where noted; all are soft warnings.
1018
+ - README, ARCHITECTURE.md, quickstart, CI-RECIPES, AGENTS.md updated to 27
1019
+ validators (historical version-log counts preserved).
1020
+
1021
+ ## [0.30.1] - 2026-07-06
1022
+
1023
+ Patch release: a hooks crash fix that unblocks sandboxed CI/agent environments,
1024
+ plus two portability/robustness hardenings.
1025
+
1026
+ ### Fixed
1027
+ - **`hooks` and `init --with hooks` crashed under `core.hooksPath=/dev/null`**
1028
+ (bug-200). `getHooksDir` resolved the literal `/dev/null` that
1029
+ `git rev-parse --git-path hooks` returns when hooks are disabled that way, so
1030
+ callers wrote `/dev/null/pre-commit` → `ENOTDIR: not a directory`. It now
1031
+ guards the pseudo-path and falls back to `.git/hooks`. This unblocks the
1032
+ Google Jules sandbox VM (which sets that config) and anyone who disables hooks
1033
+ via `core.hooksPath=/dev/null`. Regression test added.
1034
+
1035
+ ### Changed
1036
+ - **`score`: dropped the shell `| wc -l` pipe** in the commit-churn estimate
1037
+ (`estimateDocTax`) in favor of `execFileSync` + counting in JS — no shell,
1038
+ portable to Windows (no `wc`), matching the pattern `freshness.mjs` already
1039
+ uses.
1040
+ - **`.jules-setup.sh` hardened** so Google Jules stops aborting with "Working
1041
+ tree is dirty" after setup: `npm install` → `npm ci` (never rewrites
1042
+ `package-lock.json`), and `git clean -fd` → `git reset --hard HEAD &&
1043
+ git clean -fd` (discards the tracked `.agent/skills` regeneration that
1044
+ `--version` triggers; `-fd` respects `.gitignore`, so `node_modules` survives).
1045
+
1046
+ ## [0.30.0] - 2026-07-04
1047
+
1048
+ Competitive-adoption batch (from the spec-kit catalog scan — the best ideas of
1049
+ 45 doc/validation extensions, rebuilt on DocGuard's deterministic engine) plus
1050
+ the distribution-channel expansion.
1051
+
1052
+ ### Added
1053
+ - **Spec-Kit: phantom-completion detection (SPK008/SPK009)** — tasks marked
1054
+ `[x]` in `tasks.md` whose named deliverables don't exist and carry no
1055
+ implementation evidence (repo file names, code symbols, plan/spec artifacts,
1056
+ task-ID annotations, git log) are flagged, capped at 10 per run with an
1057
+ elision note. A checked task with no artifact is memory corruption for
1058
+ agents. Precision-first: calibrated against this repo's own 57 checked tasks
1059
+ (0 false positives) — prose-only and ID-only tasks are never accused. Opt
1060
+ out via `specKit.phantomCheck: false`.
1061
+ - **`verify --instructions` — agent-instruction drift audit** (MemoryLint-
1062
+ inspired). Extracts imperative rules from AGENTS.md/CLAUDE.md, flags exact
1063
+ duplicates, never-vs-always contradiction pairs, stale file pointers, and
1064
+ unknown `docguard` command references deterministically, then stages
1065
+ topically-clustered rule pairs (cross-file prioritized, capped 40) as agent
1066
+ judgment tasks — the same extraction/judgment split as `verify --semantic`.
1067
+ Mirrors generated by `agents --sync` are skipped. Dogfooded: found a real
1068
+ stale pointer in DocGuard's own AGENTS.md on first run (fixed).
1069
+ - **`trace --features` — per-feature spec-adherence report** (retrospective-
1070
+ inspired). Every spec-kit feature scored individually: requirement-ID test
1071
+ coverage (40%), task completion (25%), checked-task file evidence (20%),
1072
+ artifact completeness (15%) — graded A–F, worst-first, one fix hint each;
1073
+ unmeasurable signals are neutral (weights renormalize), never punitive.
1074
+ `--format json` for CI.
1075
+ - **Distribution channels** — `.pre-commit-hooks.yaml` (validated with the
1076
+ official pre-commit validator; changed-only guard per commit + full guard
1077
+ for pre-push), official MCP Registry manifest (`server.json`, 2025-12-11
1078
+ schema, ajv-validated; `mcpName` ownership proof added to package.json),
1079
+ Smithery config, GitLab CI/CD Catalog component
1080
+ (`templates/ci/gitlab-component.yml`, SARIF artifact), Homebrew formula with
1081
+ the real npm-tarball sha256 (`packaging/homebrew/`), and a full submission
1082
+ playbook (`packaging/submissions.md`). awesome-mcp-servers listing PR
1083
+ submitted upstream.
1084
+
1085
+ ### Changed
1086
+ - The spec-kit catalog submission description (next release's prefill) now
1087
+ leads with the differentiators: MCP server, SARIF output, deterministic
1088
+ zero-LLM core, 24 validators with stable finding codes.
1089
+ - README: `verify --instructions` / `trace --features` / integrate-via
1090
+ pre-commit/MCP/GitLab/Homebrew rows; the long-shipped Mermaid ER-diagram
1091
+ generation is finally documented.
1092
+
1093
+ ## [0.29.0] - 2026-07-03
1094
+
1095
+ Closes both gaps from LLM field report #6 (a downstream adopter reported guard
1096
+ **A+ / "Accurate: 100%" while a watched doc stated a wrong count** — the one
1097
+ false-negative a documentation-integrity tool must not have). Diagnosis held up:
1098
+ the literal cause was a domain noun missing from a hardcoded vocabulary, and an
1099
+ ALCOA pillar named "Accurate" that was computed from structure/markers, not facts.
1100
+ The fix is precision-first (the tool's existing philosophy), not the report's
1101
+ recall-maximizing "validate every claim in every doc" — which prior field reports
1102
+ already showed floods false positives.
1103
+
1104
+ ### Added — AI integration surface
1105
+ The detection core is the moat; this batch makes the output consumable by
1106
+ everything that isn't a human reading a terminal (the gap vs. Swimm/Mintlify/
1107
+ Context7 identified in the platform review).
1108
+
1109
+ - **`docguard mcp` — Model Context Protocol server** over stdio (JSON-RPC 2.0,
1110
+ zero dependencies, `node:readline`). Five tools: `docguard_guard`,
1111
+ `docguard_score`, `docguard_explain`, `docguard_verify_claims`,
1112
+ `docguard_diagnose` — DocGuard's read-only core as native agent tools for
1113
+ Claude, Cursor, and any MCP client (`claude mcp add docguard -- npx
1114
+ docguard-cli mcp`). Config loads per call; a malformed `.docguard.json`
1115
+ becomes an `isError` tool result instead of killing the session (loadConfig's
1116
+ process.exit is defused by pre-parsing); stdout is the pure transport
1117
+ (registered in both the headless gate and READ_ONLY_COMMANDS, so no banner
1118
+ and no scaffolding side effects).
1119
+ - **Action: inline PR annotations + sticky doc-impact comment** — `guard` runs
1120
+ now annotate each finding on the PR diff (`annotations` input, default on,
1121
+ capped at 50) and maintain a single sticky PR comment (`pr-comment`, default
1122
+ on) with the guard verdict, top findings, and the canonical docs impacted by
1123
+ the PR's changed files (`diff --since origin/<base>`). Purely additive steps
1124
+ gated on `always()` (feedback must appear exactly when guard fails); degrade
1125
+ gracefully on fork tokens, shallow clones, and missing permissions; existing
1126
+ outputs and exit codes untouched.
1127
+ - **SARIF 2.1.0 output** — `docguard guard --format sarif` maps the structured
1128
+ findings 1:1 onto SARIF (codes → rules with title/help from the registry,
1129
+ locations → physicalLocation/region, low-confidence → property bags,
1130
+ validator crashes → synthesized `DOCGUARD-<KEY>` results, exit codes
1131
+ unchanged). Drops straight into GitHub Code Scanning and enterprise SARIF
1132
+ dashboards. `sarif` joins `json` in the machine-format gate, so stdout is the
1133
+ pure artifact — no banner.
1134
+ - **`docguard llms --full`** — generates `llms-full.txt` (the Mintlify-style
1135
+ full-content companion to the `llms.txt` index): every canonical + optional
1136
+ doc inlined under one fetch, per-doc 400-line cap with truncation notes.
1137
+ - **`docguard memory --pack`** — writes `.docguard/context-pack.md`, a compact
1138
+ (<200 lines) code-truth-stamped session-start context for AI agents: guard
1139
+ status, scanner-derived surface counts (modules/endpoints/entities/env
1140
+ vars/tests), canonical-doc index with last-reviewed dates, the Rules/Workflow
1141
+ sections of AGENTS.md verbatim, and known-drift summary. Everything derived
1142
+ from scanners — regenerable, hallucination-free.
1143
+ - **`docguard agents --sync` / `--check`** — AGENTS.md becomes the CANONICAL
1144
+ source for the whole agent-file family (CLAUDE.md, GEMINI settings,
1145
+ `.github/copilot-instructions.md`, `.cursor/rules/`, `.clinerules`,
1146
+ `.windsurfrules`). Generated variants carry a source-hash marker; `--sync`
1147
+ regenerates marked/missing variants (never touches unmarked hand-written
1148
+ files without `--force`); `--check` is the CI gate (exit 2 on stale). Kills
1149
+ the hand-duplicated-agent-file drift class entirely.
1150
+ - **Agent Readability score axis** — `docguard score` now measures how well AI
1151
+ consumers can read the repo (display-only, like ALCOA+ — the gating grade is
1152
+ untouched): agent entry file presence, entry-file token budget, section
1153
+ addressability (quotable-alone + unique headings), structured-content
1154
+ density, machine-marker presence, llms.txt, and entry-file link integrity.
1155
+ Deterministic, zero-LLM. Dogfooded: found real defects in DocGuard's own
1156
+ docs (duplicate headings, an unmarked doc) on first run.
1157
+
1158
+ ### Added
1159
+ - **Auto-detected documentation homes** — clearly-named doc folders (`docs/`,
1160
+ `doc/`, `documentation/`, `guides/`, `guide/`, `handbook/`, `manual/`, `wiki/`,
1161
+ plus `docs-canonical/`, `docs-implementation/`, `extensions/`, and Docusaurus
1162
+ `website/docs/`) are now claim-scanned and counted as "tracked" **without being
1163
+ enrolled** in `requiredFiles.canonical`. A folder literally named `documentation/`
1164
+ is unambiguously a doc home DocGuard governs; this stays distinct from the
1165
+ arbitrary-subdir walk the wu-whatsappinbox scoping fix removed (a number buried
1166
+ in `security/wolf-archive/` is still never scanned). `config.docs.dirs` EXTENDS
1167
+ the set with non-standard homes (it never replaces auto-detection); use
1168
+ `.docguardignore` to exclude a conventional dir. The doc-home set is now a single
1169
+ source of truth (`resolveDocDirs`) shared by the claim scanner and the coverage
1170
+ map, so "tracked" provably means "actually scanned." New optional `docs.dirs` key
1171
+ in the schema.
1172
+ - **Project collections** — `config.collections` maps a documentation noun (e.g.
1173
+ `extractors`) to a glob whose matching-file count is the source of truth.
1174
+ Metrics-Consistency now flags a documented count that disagrees ("16 extractors"
1175
+ in prose vs 19 files on disk) **deterministically, in `guard`, with no LLM** —
1176
+ catching the exact class that bit the adopter. A declared collection is the
1177
+ opt-in binding, so it does not need the `docguard`-on-the-line subject bind the
1178
+ built-in checks/validators counts use; reserved nouns (checks/validators/tests)
1179
+ keep their built-in meaning; an unresolved glob (0 matches) is skipped, never
1180
+ asserting a false "0". Complements `surfaceSync` (WHICH members drift) with a
1181
+ count check (HOW MANY). New optional key in `docguard-config.schema.json`.
1182
+ - **Coverage line in `guard`** — every run now reports how many Markdown files are
1183
+ canonical / tracked / ignored / outside any tier, turning silent non-coverage
1184
+ (the "I forgot to enroll this doc" trap) into a visible count. Calm by default:
1185
+ the count shows every run; the file list is one `--verbose` away (loud-by-default
1186
+ would just train users to ignore it). Also exposed on the `guard --format json`
1187
+ contract as `coverage`.
1188
+ - **Unverified-claims notice in `guard`** — the deterministic semantic-claim
1189
+ extractor (previously only reachable via `verify --semantic`) now runs in `guard`
1190
+ and reports how many documented counts/limits/enums remain unverified against
1191
+ code, so a green run states plainly that structure is sound, *not* that the
1192
+ numbers still match. Exposed as `semanticClaims` on the JSON contract.
1193
+
1194
+ ### Changed
1195
+ - **ALCOA+ "Accurate" no longer overclaims.** It gains a third, honest state —
1196
+ `unverified` (cyan 🔍) — shown when structure passes but documented factual
1197
+ claims haven't been checked against code. Previously it read ✅ "100%" purely
1198
+ from drift markers + prose quality, which is how an adopter saw "Accurate: 100%"
1199
+ over a doc that stated the wrong number. `unverified` counts as not-met for the
1200
+ ALCOA compliance percentage (so it stops overclaiming) but renders neutrally, not
1201
+ as a failure. **Display-only: the gating CDD maturity grade (`score` / `ci`
1202
+ threshold) is unchanged.**
1203
+ - Extended the semantic claim-extractor vocabulary with the common
1204
+ pluggable-architecture nouns (`extractors`, `plugins`, `detectors`, `scanners`,
1205
+ `commands`, `rules`, `hooks`, `handlers`, `agents`, `skills`, …). The missing
1206
+ `extractors` was the literal root cause of the field report.
1207
+
1208
+ ### Internal hardening (project-review batch)
1209
+ - **ONE walker, ONE anchored glob compiler.** Sixteen private recursive
1210
+ directory walkers (13 validators + guard coverage + diff + generate) and three
1211
+ divergent glob→regex implementations are consolidated into
1212
+ `shared-ignore.mjs`: `walkFiles(dir, cb, {ignoreDirs, keepDot, onError})` and
1213
+ `compileGlob()` (superset: `**/`, `**`, `*`, `?`, `{a,b}`). Per-validator
1214
+ IGNORE_DIRS sets stay local **by design** — they carry intentional variance
1215
+ (drift excludes `cli/` because DocGuard's own regexes contain `DRIFT:`;
1216
+ docs-sync excludes `__tests__`), and the load-bearing dot-entry exceptions are
1217
+ preserved via `keepDot` (security must scan `.env`; traceability keeps
1218
+ `.env*`, `.gitignore`, `.github/`). The ignore-side `globToRegex` keeps its
1219
+ documented unanchored semantics — different contract, own bug history.
1220
+ - **Partial-walk counts are now fail-safe.** `countGlobFiles` returns −1 when
1221
+ the walk was incomplete (permission-denied subtree), so a collection count
1222
+ can never silently under-count and "correct" a right doc number to a wrong
1223
+ one. Callers treat ≤0 as "don't assert".
1224
+ - **Findings migration COMPLETE — all 24 validators.** Every validator now
1225
+ emits structured findings with stable, `explain`-able, inline-suppressible
1226
+ codes; the legacy hand-built errors/warnings strings are gone from the
1227
+ validator layer (`resultFromFindings` derives them from the same array, so
1228
+ messages are byte-identical and counts/exit codes are unchanged). The CODES
1229
+ registry grew from 8 (SEC only) to **91** across 21 prefixes: STR, CHG, MET,
1230
+ FRS (freshness, via a new guard adapter — its array contract is preserved),
1231
+ ENV, TSP, DRF, DSY, DDF, DCV, MDS, TRC, TDO, SCH, ARC, CSY, SPK (implemented
1232
+ in scanners/speckit.mjs behind the validator shim), XRF, GST, SSY, plus full
1233
+ first-time migrations of API (api-surface) and DQ (doc-quality), which turned
1234
+ out to be fully legacy rather than partial. `confidence: 'low'` is set only
1235
+ where the pre-existing message already hedged (TSP003, API003, API004's
1236
+ code-scan variant). Guard's rich rendering (`[CODE]` tags, `→ suggestion`
1237
+ lines, low-confidence markers, `docguard feedback` reporting) now covers the
1238
+ entire validator surface.
1239
+ - **Docs truth pass**: SURFACE-AUDIT.md gets a "historical snapshot — findings
1240
+ resolved" banner (its v0.18.1 counts were being read as current); STANDARD.md
1241
+ §8 no longer embeds a validator table (it had drifted 16 validators behind —
1242
+ points at the machine-governed README list instead); README leads with a
1243
+ compact "Why DocGuard?" and moves "What's New" below CI/CD; ROADMAP Phase 4.5
1244
+ updated through v0.28; CONTRIBUTING gains the **surface rule** (a new
1245
+ user-facing command must retire one or justify growth) and the **findings
1246
+ rule** (new validators must emit findings); pyproject.toml no longer claims
1247
+ "zero dependencies" (now: "no Python dependencies, requires Node 18+").
1248
+ - **Hygiene**: removed tracked scratch files (`test-draft.js`,
1249
+ `test-metrics.js`, `pr_description.md`) and a dead `IGNORE_DIRS` set in
1250
+ freshness.mjs.
1251
+ - **`generate.mjs` split (1530 → 559 lines).** The generate command now has
1252
+ three coherent modules: `cli/writers/generate-io.mjs` (backup/safe-write/
1253
+ doc-registration/citation helpers, 142 lines) and
1254
+ `cli/writers/doc-generators.mjs` (the 7 document builders, 853 lines), with
1255
+ command flow + stack detection + project scanning staying in
1256
+ `cli/commands/generate.mjs`. Pure code motion — bodies byte-identical,
1257
+ verified by the full suite plus `generate`/`generate --plan` smoke runs.
1258
+ - **CI flake fix (watch spawn tests).** The two `docguard watch` tests polled
1259
+ with a fixed 2-second cap — a hair-trigger race against CLI startup that
1260
+ intermittently failed on slow runners and passed on re-run. Replaced with a
1261
+ 15-second `waitFor` deadline; assertions unchanged (a genuinely broken watch
1262
+ still fails, just not a slow-booting one).
1263
+
1264
+ ### Remediation policy (suggest vs. auto-update)
1265
+ DocGuard detects **divergence**, not which side is right — a doc claim that no
1266
+ longer matches code can mean the doc is stale OR the code regressed and the doc is
1267
+ the correct intent (the CDD premise: canonical docs are the spec). So:
1268
+ - **Auto-fix only the provably-mechanical class** — a number bound to a code
1269
+ collection (`collections`), where the true value is known and the code is
1270
+ definitionally the source. These emit a `fix` object applied **only** via an
1271
+ explicit `docguard fix --write`, with `actualSource` provenance, fail-closed,
1272
+ and reversible via git. **Never silent.**
1273
+ - **Everything semantic/prose is SUGGEST-only** — surfaced as a finding (and via
1274
+ `verify --semantic` for agent judgment), never auto-rewritten. DocGuard's
1275
+ deterministic core can't author correct prose and must not assume code is always
1276
+ the source of truth. Enrichment/rewriting is an agent task the human approves —
1277
+ not a validator silently editing docs.
1278
+
1279
+ ## [0.28.0] - 2026-06-22
1280
+
1281
+ Closes the detection-gap items deferred from LLM field report #3 — the checks
1282
+ regex/AST couldn't make before — plus a latent CI-correctness bug surfaced by
1283
+ dogfooding.
1284
+
1285
+ ### Added
1286
+ - **`docguard verify --semantic`** (field report #5) — extracts the semantic
1287
+ claims in the canonical docs (documented numbers, limits, and enums: retention
1288
+ days, rate limits, GSI/role counts, status enums) as a structured verification
1289
+ task list with each claim's doc:line, section, and nearest cited code path. The
1290
+ highest-value bug class (a doc value drifted from code) and the one regex/AST
1291
+ can't judge — so DocGuard does the deterministic discovery and the agent does
1292
+ the comparison (the `docguard agent` division of labour). Precision-first:
1293
+ numbers count only with a recognized unit, enums only as 2+ UPPER_SNAKE values
1294
+ in a status/state context; version strings, dates, and code-fenced numbers are
1295
+ ignored.
1296
+ - **`docguard sync --tests`** (field report #10) — reconciles the hand-maintained
1297
+ TEST-SPEC Source-to-Test Map from disk: drops ghost-source rows (source file
1298
+ deleted), appends newly-covered co-located source↔test pairs, and reports ghost
1299
+ test references for the human (never auto-edits a curated status/notes cell).
1300
+ Preview by default; `--write` applies.
1301
+
1302
+ ### Fixed
1303
+ - **Dynamic `import()` no longer counted as an import cycle** (field report #2) —
1304
+ the Architecture validator excludes runtime `await import()` edges from cycle
1305
+ detection (a dynamic import is the canonical way to BREAK a load-time cycle).
1306
+ Static `import`/`require` edges still count, and dynamic edges still count for
1307
+ layer-boundary checks.
1308
+ - **API-Surface diffs the OpenAPI spec against the registered routes** (field
1309
+ report #4) — when a spec is the authoritative surface, the API-REFERENCE doc
1310
+ reconciles against the spec, so a spec that declares a phantom endpoint (no
1311
+ Express/Fastify route registers it) passed clean. It's now flagged. Conservative:
1312
+ only runs when code routes are actually scannable.
1313
+ - **Freshness markers stamped on `init`** (field report #11) — the SECURITY,
1314
+ ENVIRONMENT, TEST-SPEC, and REQUIREMENTS templates gained the standard
1315
+ `docguard:last-reviewed` header, and `init` stamps every canonical doc with a
1316
+ today-dated marker (belt-and-suspenders for future templates). Freshness is now
1317
+ marker-based and consistent from day one — and satisfiable in a pre-commit
1318
+ review loop. `explain freshness` now documents the marker > git-mtime precedence.
1319
+ - **`guard --format json` no longer truncates large reports** — replaced
1320
+ `console.log(...) + process.exit()` with `process.exitCode` + a drained write.
1321
+ A JSON payload over ~8 KB written to a pipe flushes asynchronously, so the
1322
+ immediate `process.exit()` cut it off mid-string — a CI consumer parsing stdout
1323
+ got "Unterminated string in JSON" on exactly the big reports that matter.
1324
+ (Surfaced by dogfooding this release.)
1325
+
1326
+ ### Notes
1327
+ - Tests 813 → 825 (new `tests/field-report-3-deferred.test.mjs`, each fix with a
1328
+ non-vacuous control). All field-report-3 items are now addressed.
1329
+
1330
+ ## [0.27.0] - 2026-06-19
1331
+
1332
+ Acting on a third end-to-end LLM field report (a coding agent ran DocGuard on a
1333
+ Vite+Vitest WhatsApp-inbox repo). The headline is architectural: DocGuard is a
1334
+ tool *for LLMs*, so every run should end with a suggested next action and every
1335
+ finding it surfaces should be addressable, suppressible, and — when uncertain —
1336
+ reportable. This release introduces structured **findings** (stable codes +
1337
+ confidence + a built-in suggestion), wires them through `guard`/`explain`, adds a
1338
+ local-first **feedback** loop, and fixes the group-A false positives the report
1339
+ flagged.
1340
+
1341
+ ### Added
1342
+ - **Structured findings with stable codes** (`cli/findings.mjs`) — a validator
1343
+ can now emit `Finding[]` (code like `SEC001`, `high`/`low` confidence, and a
1344
+ machine-readable `suggestion`) via `resultFromFindings(...)`. Fully
1345
+ backward-compatible: the legacy `{errors,warnings,passed,total}` shape is
1346
+ derived from the same array, so non-migrated validators are unchanged. Security
1347
+ is the first fully-migrated validator.
1348
+ - **Every guard run ends with a suggested next step** — issues render with an
1349
+ inline `→ suggestion` (fix command or suppression pragma); a clean run points
1350
+ at the next workflow step. `guard --format json` now carries a stable
1351
+ `findings` / `reportable` / `nextStep` contract for agents in hooks/CI.
1352
+ - **`docguard feedback`** — collects the low-confidence findings of a guard run
1353
+ (likely false positives, and anything DocGuard flagged uncertainly), writes a
1354
+ full local record under `.docguard/feedback/`, and prints a **1-click,
1355
+ prefilled, redacted, length-capped** GitHub issue URL (zero typing; no source
1356
+ code or secret values; capped well under GitHub's ~8 KB URL limit — the failure
1357
+ mode of commit `3b600fd`).
1358
+ - **`docguard explain <CODE>`** — `explain` now resolves a finding code
1359
+ (`docguard explain SEC001`) to its meaning, inline-suppression snippet, and the
1360
+ feedback path, alongside the existing validator/warning lookup.
1361
+ - **Inline secret suppression** — `// docguard:ignore SEC001 — reason` (or
1362
+ `// docguard:ignore-secret`, or `docguard:ignore SEC*`) on the flagged line or
1363
+ the line above silences a single finding, instead of blinding the whole file
1364
+ via `securityIgnore`. (field report #8)
1365
+ - **Read-only skills nudge** — when an agent has no `/docguard.*` commands
1366
+ installed, `guard` *suggests* `docguard init` (it never writes — scaffolding
1367
+ stays on `init`).
1368
+
1369
+ ### Fixed
1370
+ - **Natural-language values no longer flagged as hardcoded passwords** — a
1371
+ `password`-style key whose value reads like prose (a validation message / UI
1372
+ copy) is downgraded from a blocking error to a low-confidence, suppressible,
1373
+ reportable warning. Still surfaced (no false-green); a genuine single-token
1374
+ secret like `"SuperSecretPassword!"` stays a blocking error. (field report #1)
1375
+ - **`score` recognises modern test-runner config** — Vitest configured inside
1376
+ `vite.config.*` (`vitest/config` import or a `test:` block), a `scripts.test`
1377
+ that runs a known runner (`vitest`/`jest`/`mocha`/`ava`/…), and runner configs
1378
+ in workspace subdirs (`backend/`, `frontend/`, …). A fully-tested Vite+Vitest
1379
+ repo is no longer docked 15 points and told to "add a test runner". (field
1380
+ report #3)
1381
+ - **TODO-Tracking scans `docs-canonical/{ROADMAP,CURRENT-STATE,BACKLOG,TODO}.md`**
1382
+ — a TODO tracked in the canonical roadmap is no longer reported as untracked.
1383
+ (field report #6)
1384
+ - **Env validator ignores runner/CI/SDK vars** — `VITEST`, `CI`, `GITHUB_*`,
1385
+ `RUNNER_*`, `JEST_*`, `AWS_SESSION_TOKEN`, etc. are no longer reported as
1386
+ undocumented (they're injected by the runner, not product config). `NODE_ENV`
1387
+ is deliberately still treated as app config. (field report #7)
1388
+ - **Doc-Quality passive-voice has a per-doc override** — parity with
1389
+ negation-load: `<!-- docguard:quality passive-voice off — reason -->` (or a
1390
+ numeric threshold) silences the warning on legitimately passive sequence/flow
1391
+ docs. (field report #9)
1392
+
1393
+ ### Notes
1394
+ - Tests 794 → 813 (new `tests/field-report-3.test.mjs`, each fix paired with a
1395
+ non-vacuous control).
1396
+ - The detection-gap items from the report (semantic number/enum drift `verify
1397
+ --semantic`, dynamic-import cycle breaks, spec-declares-but-no-route, `sync
1398
+ --tests`, freshness precedence) are deliberately deferred — each is its own
1399
+ design and would bloat this release.
1400
+
1401
+ ## [0.26.0] - 2026-06-10
1402
+
1403
+ Acting on a second end-to-end LLM field report (a coding agent ran DocGuard on a
1404
+ stdlib-only Python security CLI). The report verified that the v0.25.0 "all
1405
+ fixed" claim was real but narrow — it patched the specific repros, not the
1406
+ general class — so several issues recurred. This round fixes the *class* and
1407
+ adds regression tests that assert the agent's actual scenario.
1408
+
1409
+ ### Fixed
1410
+ - **Read-only commands are strictly side-effect-free** — `guard`/`score`/`diff`/
1411
+ `impact`/`diagnose`/`trace`/`explain`/`memory`/`demo` no longer run
1412
+ `ensureSkills` (auto-init Spec Kit, spawn `specify`, write `.agent/.specify`).
1413
+ A validate command must never mutate the tree. Scaffolding stays on
1414
+ `init`/`generate`/`init --with`. (Bug #3)
1415
+ - **Surface detection ignores test fixtures by default** — a stdlib CLI was
1416
+ documented as an Express/Flask/AWS web app because the manifest/route/env
1417
+ scanners ingested the tool's own `tests/fixtures/`. Non-product dirs
1418
+ (fixtures/tests/examples/testdata/samples) are now excluded from detection by
1419
+ default (no `.docguardignore` required), overridable via
1420
+ `detection.includeNonProduct`, and never applied to guard's structural checks. (Bug #1)
1421
+ - **Metrics-Consistency no longer corrupts correct numbers** — it only validates
1422
+ a "N checks/validators" claim bound to DocGuard, stamps `actualSource`
1423
+ provenance on every fix, and the auto-fix applier is fail-closed: it refuses to
1424
+ overwrite a number without provenance and only rewrites DocGuard-bound lines.
1425
+ (Previously "10 checks" describing a proof harness would be "fixed" to
1426
+ DocGuard's own count.) (Bug #2)
1427
+ - **Project name comes from the manifest, not the directory** — reads
1428
+ `pyproject [project].name` / `package.json` / `Cargo.toml` / `composer.json` /
1429
+ `go.mod` before falling back to the dir basename (which is an auto-generated
1430
+ slug inside a git worktree). (Bug #4)
1431
+ - **`generate` respects the active profile's doc set** — a `cli`/`library`
1432
+ profile no longer proposes API-REFERENCE/INTEGRATIONS/SCREENS from an
1433
+ incidental surface; suppressed docs surface a recoverable note. (Bug #5)
1434
+ - **Freshness warning states both remedies** (commit *or* a `last-reviewed`
1435
+ marker) and is suppressed for docs marked `<!-- docguard:status approved -->`
1436
+ in the same session. (Bug #6)
1437
+ - **Env-var detection counts reads, not mentions** — a single-pass lexer skips
1438
+ env tokens inside comments and string literals (e.g. a detection signature
1439
+ like `r"os.environ.get('JWT_SECRET')"`) and inside test dirs, so only genuine
1440
+ runtime reads are reported. (Bug #7)
1441
+
1442
+ ### Added
1443
+ - **Pre-filled code-truth in `generate`** — the `source:"code"` sections now ship
1444
+ real extracted content instead of empty templates: an ARCHITECTURE **Component
1445
+ Map** (real source modules) and a **TEST-SPEC** doc with a pre-filled test
1446
+ inventory (files + per-file case counts). The agent annotates responsibilities
1447
+ instead of hand-grepping the structure.
1448
+ - **`docguard agent`** — a one-shot, dependency-ordered agent task graph
1449
+ (`--format json` for the machine artifact). Phases `config → canonical-docs →
1450
+ verify`; each task is `code-truth` (ships pre-filled content) or
1451
+ `human-judgment` (instruction + grounding, never a committed guess), carries an
1452
+ acceptance/verify command, and propagates confidence. Collapses ~10 manual
1453
+ round-trips into one. `--profile <name>` previews a profile without running
1454
+ `init` first.
1455
+
1456
+ ## [0.25.1] - 2026-06-09
1457
+
1458
+ Patch release fixing a spec-kit extension install/update failure reported in
1459
+ [#229](https://github.com/raccioly/docguard/issues/229).
1460
+
1461
+ ### Fixed
1462
+ - **spec-kit extension installs again** — the `extension.yml` manifest declared
1463
+ `aliases` identical to their own command names (`guard`, `fix`, `review`,
1464
+ `score`). spec-kit registers the command name and each alias in one namespace,
1465
+ so a name-equal alias self-collided and was rejected as a duplicate command,
1466
+ breaking `specify extension add/update docguard` on v0.23.0–v0.25.0. Removed
1467
+ the four self-referential aliases. (#229)
1468
+
1469
+ ### Changed
1470
+ - **Spec Kit catalog publishing goes through the Extension Submission issue
1471
+ template** — per maintainer guidance ([github/spec-kit#2707](https://github.com/github/spec-kit/pull/2707))
1472
+ and the Extension Publishing Guide. The release pipeline no longer opens a
1473
+ direct PR against `catalog.community.json`; it builds a prefilled
1474
+ `issues/new` form link (`.github/scripts/speckit-submission.py`) and opens a
1475
+ one-click reminder issue in this repo so the submission is made through the
1476
+ form (which auto-applies labels and assigns a maintainer). Removed the
1477
+ orphaned `patch-catalog.py`.
1478
+
1479
+ ## [0.25.0] - 2026-06-03
1480
+
1481
+ Field-report follow-up from dogfooding v0.24.0 on a real stdlib-only Python CLI
1482
+ (websec-validator). Fixes the bugs that bit a first run and adds CLI/library
1483
+ ergonomics. The headline is a silent `.docguardignore` failure: a gitignore-style
1484
+ `dir/` pattern matched nothing, so "ignored" directories were still scanned.
1485
+
1486
+ ### Fixed
1487
+ - **`.docguardignore` honors `dir/` patterns** — a trailing-slash directory
1488
+ pattern (`tests/`, `base-research/`) silently matched nothing, so every
1489
+ `shouldIgnore`/`buildIgnoreFilter` consumer kept scanning the directory.
1490
+ `globToRegex` now normalizes the trailing slash so `dir`, `dir/`, and `dir/**`
1491
+ behave identically. Security-relevant: an excluded secret-bearing directory is
1492
+ now actually excluded. (B1a)
1493
+ - **`project-type` framework detection honors ignore** — the manifest walk now
1494
+ skips ignored dirs, so a fixture `package.json`/`requirements.txt` under
1495
+ `tests/` no longer misclassifies the stack (e.g. a CLI reported as "Express,
1496
+ Flask"). (B1b)
1497
+ - **`generate --write` no longer crashes (ENOENT)** — the `--plan --write` loop
1498
+ created only `docs-canonical/`, then crashed writing the first
1499
+ `docs-implementation/` doc. It now creates each parent directory and snapshots
1500
+ a `.bak`. (B2)
1501
+ - **`init --fix` works headless** — `--fix` was documented ("auto-create missing
1502
+ files from templates") but read nowhere, so it dropped into an interactive
1503
+ prompt and failed with no TTY. It now creates missing required docs
1504
+ non-interactively. (B3)
1505
+ - **`generate --plan` has no side effects** — a bare `--plan` preview triggered
1506
+ `ensureSkills`, scaffolding `.agent/` and `.specify/` into the tree. `--plan`
1507
+ is now treated as a read-only preview. (B4)
1508
+ - **Generator/validator agreement** — `generate` registers the canonical docs it
1509
+ emits in `.docguard.json` `requiredFiles`, so `guard` no longer flags the
1510
+ generator's own output as an unlinked doc. (B7)
1511
+
1512
+ ### Added
1513
+ - **`pinned` section marker** — add `pinned="reason"` to a
1514
+ `<!-- docguard:section … -->` marker to exempt an intentionally hand-maintained
1515
+ `source=code` section from Generated-Staleness, and stop `sync --write` from
1516
+ reverting it. (B5)
1517
+ - **Per-command help** — `docguard <command> --help` lists that command's own
1518
+ flags and examples (e.g. `generate --plan --write`, `init --skeleton`). (B6)
1519
+ - **Low-confidence surface flag** — for `cli`/`library`/unknown-kind projects,
1520
+ `generate --plan` flags auto-extracted HTTP/SDK/route surface as low-confidence
1521
+ (it may be pattern-strings in a scanner/tool's own source, not real usage). It
1522
+ is flagged, never suppressed; `--plan --format json` gains `surface.confidence`. (F1)
1523
+ - **`cli` and `library` profiles** — non-web-centric required-doc sets, so a CLI
1524
+ or library isn't forced into HTTP-API/database doc shape. (F3)
1525
+
1526
+ ## [0.24.0] - 2026-05-31
1527
+
1528
+ Hardening pass from a full external review. Theme: make the green check *mean*
1529
+ something — close the false-green paths, fix the security gaps, and stop the
1530
+ tool from lying about itself. Relaxes the zero-dependency constraint to add an
1531
+ exact-pinned `@babel/parser` (optional-load, regex fallback) and a `python3`
1532
+ AST tier (optional, regex fallback), promoting JavaScript/TypeScript and Python
1533
+ to full-support languages. Field-tested read-only against real Next.js, Express,
1534
+ Python, and AWS/AppSync projects.
1535
+
1536
+ ### Added
1537
+ - **Express mount-prefix resolution** — DocGuard now follows `app.use('/api/users',
1538
+ userRoutes)` across files, so a route declared as `router.get('/:id')` in the
1539
+ mounted file is reported at its REAL URL `/api/users/:id`. Previously the
1540
+ per-file scan emitted the bare `/:id`, the documented full path never matched,
1541
+ and every mounted route double-fired (documented-but-absent AND undocumented).
1542
+ Resolution is receiver-aware: a same-file `app.use('/api', router)` prefixes
1543
+ only that router's routes, never a sibling `app.get('/health')`. A router
1544
+ mounted at several prefixes yields one path per prefix; an unmounted file keeps
1545
+ its bare path. Known limits (documented, not silently wrong): transitive
1546
+ composition (`app.use('/api', api)` → `api.use('/x', x)`) and dynamic
1547
+ (non-string-literal) prefixes are not resolved.
1548
+ - **AST-based HTTP route extraction for JS/TS** (Express/Fastify/Hono/Koa-style
1549
+ `<router>.<method>('/path', …)`). Replaces the regex that only matched
1550
+ `app`/`router`/`server` receivers on a single line: the AST path matches ANY
1551
+ router identifier (`userRouter.get`, `v1.post`, …), survives multi-line calls,
1552
+ and reads template-literal paths — while a `/`-or-`*` path requirement keeps
1553
+ non-route `.get()` calls (`map.get('key')`, `headers.get(…)`) out. Regex
1554
+ remains the fallback when `@babel/parser` can't parse a file. **Fastify and
1555
+ Hono scanners now use this AST path too**, and Fastify additionally
1556
+ understands the **declarative object form** `fastify.route({ method, url })`
1557
+ (including `method: ['GET','POST']` arrays and the `path:` alias) — which the
1558
+ old regex never matched at all.
1559
+ - **AST-based React Router screen extraction** (feeds `docguard generate`). The
1560
+ `<Route path element={…}>` and route-object (`{ path, element }` /
1561
+ `{ path, Component }`) forms are now parsed structurally, so a screen wrapped
1562
+ in auth guards / layouts / `Suspense` across several lines is identified
1563
+ correctly instead of by a 400-char window heuristic that could truncate or
1564
+ mis-pick. Regex window remains the fallback on parse failure.
1565
+ - **Python AST parsing tier** — Python is now a full-support language, parsed by
1566
+ the developer's own `python3` (no pip/npm dependency; new
1567
+ `cli/scanners/py-ast.mjs`). One subprocess parses every `.py` file and returns
1568
+ FastAPI/APIRouter + Flask routes (multi-line decorators, `methods=[…]` arrays)
1569
+ and Pydantic/SQLAlchemy models with their full field lists, types, optional
1570
+ flags, and relationships — accuracy the line-by-line regex could not promise
1571
+ (an undercounted model is what makes a data-model validator falsely pass on a
1572
+ stale `DATA-MODEL.md`). Loads OPTIONALLY exactly like the JS tier: if `python3`
1573
+ is absent or a file won't parse, the scanners fall back to the regex (beta)
1574
+ tier per file. Never load-bearing for the CLI to run.
1575
+ - **AST-accurate JS/TS parsing tier**, powered by `@babel/parser` — the project's
1576
+ first runtime dependency (exact-pinned `7.29.7`). It loads **optionally** with a
1577
+ regex fallback, so the CLI never hard-crashes if it's absent. New
1578
+ `cli/scanners/js-ast.mjs`. This fixes silent brace-truncation in Zod/Drizzle/
1579
+ Mongoose schema extraction, where a nested `{…}` truncated the object body and
1580
+ dropped fields — making the data-model validators falsely pass on stale docs.
1581
+ - **Inline whole-validator N/A marker** — declare a validator intentionally
1582
+ non-applicable, visibly and in-repo:
1583
+ `<!-- docguard:validator testSpec n/a — POC, no automated tests yet -->`
1584
+ (read from canonical docs / `AGENTS.md` / `README.md`). Renders as
1585
+ `➖ [N/A] (declared N/A: …)`, not a silent skip or fake pass. Unlike the
1586
+ `validators:{k:false}` config switch, the rationale lives next to the
1587
+ declaration and travels with the repo. Key matching is case/separator-tolerant
1588
+ (`test-spec` works); a mistyped key is reported, not silently ignored. A POC
1589
+ with no tests can mark `testSpec` + `traceability` N/A in one place — so this
1590
+ also covers the "no-tests project" need without a dedicated profile.
1591
+
1592
+ ### Fixed
1593
+ - **Freshness honors a same-day review.** A `<!-- docguard:last-reviewed YYYY-MM-DD -->`
1594
+ header was compared from midnight, so a doc reviewed *today* was still flagged
1595
+ stale whenever >10 code commits also landed today — undermining the very
1596
+ explicit-review signal the validator claims to honor. A header date now means
1597
+ "reviewed on this day" and covers that day's commits (only later days count).
1598
+ - **Metrics-Consistency no longer scans the whole repo for stray numbers**
1599
+ (found by field-testing against a real backend): it previously walked the
1600
+ *entire* project root recursively, so a "N validators / N checks" mention in
1601
+ any markdown anywhere — OpenWolf session archives under `security/wolf-archive/`,
1602
+ a vendored toolkit's `README.md` — was reported as the user's documentation
1603
+ drift. On one real repo that was **~39 false warnings** the author could not
1604
+ act on. It now scans only the docs DocGuard governs: root-level markdown, the
1605
+ configured `requiredFiles.canonical` (wherever they live), and the `docs/`,
1606
+ `docs-canonical/`, `extensions/` trees. Code/tooling directories are excluded.
1607
+ - **Docs-Coverage no longer demands documentation for generated tool artifacts**
1608
+ (found by field-testing against a real Python project): pytest's `.coverage`
1609
+ SQLite data file (and its parallel-mode `.coverage.<host>.<pid>` siblings,
1610
+ `.eslintcache`, `.stylelintcache`, `.tsbuildinfo`) are generated, not config a
1611
+ human authors, so flagging them as "undocumented config files" was a false
1612
+ positive. Also skips `.dockerignore`, `.python-version`, `.tool-versions`,
1613
+ `.ruby-version`, `.gitkeep`/`.keep`.
1614
+ - **API-Surface no longer double-flags every dynamic route** (found by field-
1615
+ testing against a real Next.js app): `normalizePath` now collapses Next.js
1616
+ `[id]`/`[...slug]`/`[[...slug]]` brackets to the same `{}` placeholder it
1617
+ already used for `:id` and `{id}`. Previously a route documented as
1618
+ `/api/jobs/[jobId]` never matched the code-scan's `/api/jobs/:jobId`, so it
1619
+ fired as BOTH "documented-but-absent" AND "undocumented" — on one real repo,
1620
+ 16 of 20 API-Surface warnings were this pure noise (now 1, a genuine finding).
1621
+ - **`guard` headline status now matches its exit code.** The status word was
1622
+ computed from raw counts while the exit code used severity-adjusted counts, so a
1623
+ `severity: high` validator with only warnings printed "WARN" yet exited 1 (FAIL),
1624
+ and a `low` one printed "WARN" yet exited 0.
1625
+ - **`guard --changed-only` no longer silently drops a `severity: high` validator.**
1626
+ The lite set now unions in any validator the team escalated, so the gate can't
1627
+ pass on the very drift it was configured to block (e.g. a committed secret).
1628
+ - **Secret scan inspects every match, not just the first** — a real hardcoded key
1629
+ below an `EXAMPLE` placeholder of the same kind is no longer missed.
1630
+ - **Section parsing can't corrupt human prose** — a malformed/missing close marker
1631
+ now abandons the unclosed section instead of swallowing prose and the next
1632
+ section into one body that a later regen would overwrite.
1633
+ - **Freshness: future-dated `last-reviewed` headers are ignored** (a typo'd
1634
+ `2099-…` could otherwise mark a stale doc "fresh" forever). Its git plumbing
1635
+ no longer shells out to `wc`/`grep` (not portable), and the DRIFT-comment
1636
+ detector counts only *added* lines on the current branch, not deletions/context
1637
+ across all branches.
1638
+ - **Metadata-sync: the `@version` check is anchored to the package name** (a bare
1639
+ `/@\d+\.\d+\.\d+/` over-matched `node@18.2.0`, `@types/node@1.2.3`, etc.), and
1640
+ two-part versions like `1.2` no longer disable the comparison via `NaN`.
1641
+ - **Next.js route scanner strips route groups** — `app/api/(admin)/users` now
1642
+ emits `/api/users`, not `/api/(admin)/users` (matching the frontend scanner),
1643
+ and optional catch-all `[[...slug]]` maps to `:slug*` instead of leaking
1644
+ brackets. Both previously caused false "undocumented endpoint" drift.
1645
+ - **Cross-platform path handling** — a shared `relPosix()` helper replaces the
1646
+ `projectDir + '/'` strip that broke on Windows and on prefix-colliding sibling
1647
+ dirs (which silently disabled `--changed-only` scoping).
1648
+ - **`hooks` works inside git worktrees** — resolves the hooks dir via
1649
+ `git rev-parse --git-path hooks` rather than assuming `.git/hooks` (a file, not a
1650
+ dir, in a linked worktree).
1651
+ - **Honest failure on unparseable input** (the second half of the false-green
1652
+ fix): an OpenAPI spec that declares `paths:` but parses to **0 endpoints** is
1653
+ now flagged and surfaced as an API-Surface warning (it falls back to code
1654
+ scanning) instead of silently reporting "no API surface." And a malformed
1655
+ `package.json` no longer throws out of `detectDocTools` — the unguarded
1656
+ `JSON.parse` calls (TypeDoc/JSDoc/Swagger detectors) are now fail-soft, so one
1657
+ bad manifest can't abort the whole scan into empty "truth" that every
1658
+ validator then passes.
1659
+ - **Scanners honor `.docguardignore` / `config.ignore`** — the route, schema,
1660
+ and frontend scanners now filter their results by the project's ignore globs,
1661
+ so a fixtures/sample dir with fake routes/schemas/components no longer pollutes
1662
+ the API surface or data model (previously only the env-var grep honored
1663
+ ignores). Their divergent local `IGNORE_DIRS` sets were also unified onto the
1664
+ shared `DEFAULT_IGNORE_DIRS`, so build/VCS dirs are skipped consistently.
1665
+ - **CI hardening** — CI now runs `npm ci` (required since `@babel/parser` was
1666
+ added; the AST-tier tests need it), `node --check`s *every* `cli/**/*.mjs`
1667
+ (the lint gate that would have caught the VS Code extension's parse error),
1668
+ and smoke-imports the Python wrapper. Previously CI only exercised the JS
1669
+ entry point and the npm-pack tarball.
1670
+ - **Validator false-positive polish** — (a) Traceability no longer treats prose
1671
+ like `T300`/`T1000` as spec-kit task IDs: the bare `T\d{3,4}` pattern is now
1672
+ anchored to where real task IDs live (a `- [ ] T001` checklist marker, or a
1673
+ `@req`/`@task` annotation in tests). (b) Surface-Sync's bold-table-cell scan
1674
+ only reads the name cell (first cell, or second after a numeric cell), so a
1675
+ bold status column like `| guard | **High** |` no longer pollutes the surface
1676
+ set with "High". (c) TODO-Tracking's `TEMP` keyword excludes `TEMPLATE`,
1677
+ `TEMPORARY`, `TEMPO`, `TEMPEST` (was only the first two).
1678
+ - **Python wrapper prefers a pinned local install over `npx @latest`** — its
1679
+ `find_local_cli()` returned `None` whenever `npx` existed (i.e. always), so a
1680
+ project that pinned `docguard-cli` still got `npx -y docguard-cli@latest` from
1681
+ the network. It now resolves `node_modules/docguard-cli/cli/docguard.mjs`
1682
+ (walking up from cwd, cross-platform) first — offline-friendly and
1683
+ reproducible. Falls back to npx only when there's no local install.
1684
+ - **Scanners skip oversized + generated files** — a new size-capped
1685
+ `readScannable()` (shared) caps reads at 1.5 MB and skips `.min.js`,
1686
+ `*.bundle/chunk.js`, `*.generated.*`, and `*.d.ts`. A checked-in bundle or
1687
+ generated client used to be read whole and run through every scanner's regex
1688
+ set (and now Babel) — a DoS-by-accident. Wired into routes/schemas/frontend
1689
+ scanners and the env-var grep.
1690
+ - **Schema version is single-sourced** — `init`/`setup` now write
1691
+ `CURRENT_SCHEMA_VERSION` from `shared.mjs` instead of hardcoded `'0.5'`/`'0.4'`
1692
+ literals, so bumping the constant can't leave freshly-created configs reading
1693
+ as instantly "needs upgrade." (`config.mjs`'s `'0.2'` is documented as the
1694
+ legacy missing-version fallback, intentionally distinct.)
1695
+ - **Metrics-Consistency ignores DocGuard's own installed command docs** — it no
1696
+ longer scans `commands/docguard.*.md` (DocGuard's slash-command docs, which it
1697
+ installs into the project) for count claims. A stale "N validators" baked into
1698
+ those shipped docs was being reported as the *user's* drift in every project
1699
+ that had them (field test: quick-recon-tool, hugocross). A user's own
1700
+ `commands/<name>.md` is unaffected.
1701
+ - **Dogfooding closure** — Canonical-Sync now scans **AGENTS.md** in addition to
1702
+ README for "ships N commands"/"N validators" surface claims (it only checked
1703
+ README, which is why DocGuard's own AGENTS.md counts drifted unnoticed), and
1704
+ its command-count check inspects *all* matches rather than just the first (so
1705
+ a correct claim in one file can't mask a stale one in the other). AGENTS.md's
1706
+ own command section was regenerated to match the real `--help` surface and no
1707
+ longer hard-codes drift-prone totals.
1708
+
1709
+ #### Field-report hardening (two external field tests: a Python uv/pytest project and a Node/AWS POC)
1710
+ - **`explain`** is now exhaustive (7 missing validator entries backfilled, pinned
1711
+ to the live registry by a test), documents Traceability's unlinked-doc check,
1712
+ resolves guard's exact casing, and gained per-validator "tune it" guidance.
1713
+ - **`score`** "Top improvements" is derived from the actual failing sub-check
1714
+ (not a static per-category template); detects pytest config in
1715
+ `pyproject.toml` / `tox.ini`.
1716
+ - **Doc-section heading matching is synonym- and arc42-section-number-tolerant**
1717
+ (`docHasSection`), so well-structured docs stop scoring *worse* than the blank
1718
+ skeleton. (Retires the "emit exact canonical H2" idea as moot.)
1719
+ - **Trace/Traceability exclude `.md` docs from doc→code matching**, so DocGuard's
1720
+ own command docs are no longer mis-read as the project's auth modules.
1721
+ - **Environment validator recognizes schema-defined env vars** (Zod / envalid /
1722
+ convict), not just `process.env.X` reads.
1723
+ - **`generate --help` (and every command) shows usage** instead of executing.
1724
+ - **`ensure-skills`** content-equality gate stops per-command skill-rewrite churn;
1725
+ config warns on invalid `severity` values.
1726
+ - **Test-Spec guidance aligned with the 4-column table** `generate` emits.
1727
+ - **Test-Spec Source-to-Test Map parsing is now column-header-aware** (#9): it
1728
+ locates the source/status/test columns by header name and verifies *every*
1729
+ test-file column — so the generated table's **Integration Test** column is
1730
+ checked too (previously only one column was), and a blank cell no longer
1731
+ shifts the column alignment (the old empty-cell filtering did).
1732
+
1733
+ ### Security
1734
+ - **GitHub Action (`action.yml`): closed a shell-injection vector.** All inputs —
1735
+ including the attacker-controllable PR `head.ref` — now flow through `env:`
1736
+ instead of being spliced into `run:`/`github-script` bodies.
1737
+ - **Removed `doc-quality`'s unpinned `understanding` PATH lookup/exec** (dead,
1738
+ unwired code that was a path-hijack surface). The prose validator now has zero
1739
+ process-execution capability.
1740
+
1741
+ ### Removed
1742
+ - **Deleted the VS Code extension.** It had been shipping non-functional: a
1743
+ parse-time `await`-in-non-`async` error, every command registered under the wrong
1744
+ `specguard.*` namespace, and a shell-out to a nonexistent `specguard` npm
1745
+ package. All references scrubbed.
1746
+
1747
+ ### Changed
1748
+ - **Dependency posture: "zero dependencies" → "one pinned, vetted, optional-load
1749
+ dependency."** Updated ~14 docs and the constitution's Principle II to reflect
1750
+ `@babel/parser`. New dependencies remain governed by exact-pinning and
1751
+ supply-chain vetting (>10k downloads/wk, >1 maintainer, >30 days old).
1752
+ - **`init --profile starter` is now genuinely minimal** (field report #1): it
1753
+ skips the heavy Spec Kit framework scaffold (`.specify/` templates/scripts/
1754
+ memory, ~30 files) that contradicted its "for side projects" description. It
1755
+ still installs the canonical docs and DocGuard's own lightweight agent skills
1756
+ and commands. Opt the framework back in with `docguard init --profile starter
1757
+ --spec-kit`. Other profiles are unchanged (spec-kit on by default).
1758
+ - **DocGuard slash-command docs install to `.agent/commands/`, not root
1759
+ `commands/`** (field report #2, #11) — consistent with `.agent/skills/`, the
1760
+ generic spec-kit path agents already discover, and no longer polluting the
1761
+ project namespace or being mis-scanned as source. Existing root `commands/`
1762
+ is left untouched (already excluded from scans); new installs use `.agent/`.
1763
+
1764
+ ## [0.23.0] - 2026-05-29
1765
+
1766
+ Validator-hardening minor release, driven by external field feedback and a full
1767
+ self-audit. Theme: make the validators **fit real projects** and **tell the
1768
+ truth**, rather than forcing ceremony or over-claiming. Honest fixes only — no
1769
+ doc-gaming. Self-audit guard warnings went 20 → 0-of-ours (the only remaining
1770
+ warning is a parallel session's untracked file).
1771
+
1772
+ ### Added
1773
+ - **Language-aware guard Traceability** (field Issue 3) — the guard-time
1774
+ Traceability validator now understands Python, Go, Rust, Java/Kotlin, Ruby,
1775
+ and PHP layouts, not just JS/TS. The multilingual `TEST_PATTERNS` + `TRACE_MAP`
1776
+ live in one shared module (`cli/shared-trace-patterns.mjs`) consumed by both
1777
+ `docguard trace` and the validator, so they can't drift apart. (The README
1778
+ previously claimed this but only the standalone `trace` command delivered it.)
1779
+ - **Per-doc negation-load override** (field Issue 14) — `<!-- docguard:quality
1780
+ negation-load off — reason -->` (or a numeric threshold), plus a project-wide
1781
+ `docQuality.negationLoadThreshold` config. Security/operational/audit docs
1782
+ legitimately use "never"/"must not"/"cannot"; this stops false flags without
1783
+ weakening the check for tutorials.
1784
+ - **Bugfix/lightweight spec type** — `<!-- docguard:spec-type bugfix -->` makes
1785
+ the Spec-Kit validator check a defect spec for Root Cause + Fix instead of the
1786
+ full feature template (User Scenarios + FR/SC IDs). Narrower check, not a free
1787
+ pass.
1788
+ - **`docguard explain canonical-sync`** — the count-level companion validator
1789
+ was missing from the explainer (field Issue 10).
1790
+
1791
+ ### Changed
1792
+ - **`loadConfig` extracted to `cli/config.mjs`** — breaks the demo↔docguard
1793
+ import cycle the Architecture validator flagged (byte-for-byte move, no logic
1794
+ change). New modules import config from there, not the CLI entry point.
1795
+ - **Docs-Diff** test-file drift now recognises the documented glob convention
1796
+ (`tests/*.test.mjs`) instead of demanding every test file be enumerated.
1797
+ - **Diff loops pre-compile their regexes** (community PR) — O(N·M) → O(N) on the
1798
+ test-file comparison.
1799
+ - **Test-Spec** "no mappings" note now points to the expected table format and
1800
+ `docguard explain` (field Issue 4).
1801
+ - **Canonical docs refreshed** — ARCHITECTURE (config.mjs, 24 validators, 11
1802
+ scanners, shared-trace-patterns), SECURITY (real `execFileSync`+allowlist
1803
+ subprocess posture), ROADMAP (Phase 4.5 hardening). Genuine review, not
1804
+ date-stamping.
1805
+
1806
+ ### Related (shipped separately)
1807
+ - VS Code extension `DocGuard.docguard-vscode` published to the Marketplace
1808
+ (v0.4.1), including a command-injection fix in `execSpecguard` (#207).
1809
+
1810
+ ## [0.22.1] - 2026-05-29
1811
+
1812
+ Self-audit + field-feedback patch. Honest fixes only — no doc-gaming. The
1813
+ remaining guard warnings (Spec-Kit on bugfix specs, negation-load, docs-diff
1814
+ test files, freshness lag, the demo↔docguard import cycle) are deferred to
1815
+ v0.23.0 because the *correct* fix is improving the validators, not papering
1816
+ over the docs. `sync --write` confirmed the freshness warnings are git-age
1817
+ lag, not real code-truth drift, so they were left honest rather than date-bumped.
1818
+
1819
+ ### Fixed
1820
+ - **Stale validator counts in scaffolded files** — `extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md`
1821
+ ("19-validator") and `extensions/spec-kit-docguard/commands/guard.md` ("19-validator", "20 total")
1822
+ hardcoded counts that drift every release and shipped into user projects. Reworded to be count-free,
1823
+ matching the already-fixed `templates/commands/docguard.guard.md`. (Field report, Issue 1.)
1824
+ - **REQUIREMENTS.md non-functional requirements were unfilled web-service boilerplate**
1825
+ ("200ms p95", "99.9% uptime SLA") — nonsensical for a zero-dependency CLI and untraced.
1826
+ Rewrote NFR-001/002/003 to DocGuard's real, test-backed NFRs (injection-safe subprocess
1827
+ spawns, zero runtime deps, cross-process plan cache) and traced each to its regression test
1828
+ via `@req` tags. Clears the 3 Traceability warnings honestly.
1829
+ - **`specs/002-fix-test-discovery/plan.md`** — added the Spec-Kit-mandated `Summary` and
1830
+ `Project Structure` sections (real content).
1831
+
1832
+ ### Added / Improved
1833
+ - **`docguard explain canonical-sync`** — the count-level companion validator was missing from
1834
+ the explainer table; added it. (Field report, Issue 10.)
1835
+ - **Test-Spec validator note** now points to the expected table format and `docguard explain` when
1836
+ it finds no service-to-test mappings, instead of a dead-end message. (Field report, Issue 4.)
1837
+
1838
+ ### Docs
1839
+ - **README "What's New" no longer over-claims language-aware trace mapping for `guard`.** The
1840
+ multilingual patterns live in the standalone `docguard trace` command; the guard-time
1841
+ Traceability validator is JS/TS-first today, with language parity on the v0.23 roadmap.
1842
+ (Field report, Issue 3 — honesty fix pending the full validator port.)
1843
+
1844
+ ## [0.22.0] - 2026-05-28
1845
+
1846
+ ### Added — Surface-Sync validator (item-level enumerable drift)
1847
+
1848
+ `canonical-sync` already checks NUMERIC count claims in the README (ships
1849
+ N commands, N validators, mermaid diagram counts). But running the docguard
1850
+ repo through itself showed `canonical-sync` passing 3/3 while the README's
1851
+ command table silently omitted `demo` — the count matched, the table was
1852
+ wrong, the user hit "command not found" anyway. Count-level checks miss
1853
+ item-level drift.
1854
+
1855
+ **Surface-Sync** is the item-level complement. For each configured surface
1856
+ (commands, validators, slash commands, templates — anything enumerable), it
1857
+ compares code-truth (from a glob) against the names appearing in table rows
1858
+ and bullet items in target docs. Warns on items present in code but missing
1859
+ from the doc, and on items listed in the doc but missing from code.
1860
+
1861
+ Key behaviors:
1862
+
1863
+ - **N/A by default.** Returns "nothing to validate" unless the project's
1864
+ `.docguard.json` declares at least one surface under `surfaceSync.surfaces`.
1865
+ Existing docguard projects upgrade safely with zero new noise.
1866
+ - **Section-scoped scanning.** Each surface can specify a `section` heading;
1867
+ the validator restricts scanning to that section so a README containing
1868
+ both a Commands table and a Validators table doesn't produce cross-table
1869
+ false positives.
1870
+ - **Format-aware extraction.** Recognises documented entries written as
1871
+ `` `name` ``, `**Name**`, `| `name` |`, `| N | **Name** |`, and bullet
1872
+ items. Strips leading `docguard ` / `/` prefixes and folds case so README's
1873
+ `**API-Surface**` matches file basename `api-surface.mjs`.
1874
+ - **Code-block immune.** Fenced code blocks are stripped before scanning so
1875
+ shell examples don't inflate the documented set.
1876
+ - **`ignore` list per surface.** Known deprecation aliases, scaffolders
1877
+ behind `init --with`, and display-name-vs-filename mismatches can be
1878
+ silenced without disabling the surface entirely.
1879
+
1880
+ Config shape (in `.docguard.json`):
1881
+
1882
+ ```json
1883
+ {
1884
+ "surfaceSync": {
1885
+ "surfaces": [
1886
+ {
1887
+ "name": "commands",
1888
+ "glob": "cli/commands/*.mjs",
1889
+ "extract": "basename-no-ext",
1890
+ "ignore": ["setup", "impact"],
1891
+ "docs": ["README.md"],
1892
+ "section": "Usage"
1893
+ }
1894
+ ]
1895
+ }
1896
+ }
1897
+ ```
1898
+
1899
+ DocGuard's own `.docguard.json` now declares three surfaces (commands,
1900
+ validators, slash-commands) so the project polices its own README on every
1901
+ `guard` run. Run `docguard explain surfaceSync` for fix guidance.
1902
+
1903
+ ### Fixed — eight field-test bugs from v0.20.0
1904
+
1905
+ Confirmed running v0.20.0 against two real projects (a Python codebase for
1906
+ the v0.20.0 cycle and a Next.js 15 App Router codebase). All eight were
1907
+ reproduced in the source, fixed surgically, and pinned with regression
1908
+ tests. Specs: `specs/004-v020-env-var-false-negative/`, `specs/005-hugocross-next-bugs/`.
1909
+
1910
+ - **API-Surface emits wrong path for Next.js App Router with `src/` layout**
1911
+ — `src/app/api/health/route.ts` was reported as `GET /app/api/health`
1912
+ instead of `GET /api/health`. Caused the validator to fire two false
1913
+ warnings per route (documented-missing + undocumented-in-code) on every
1914
+ `src/app/api/` file. `cli/scanners/routes.mjs`.
1915
+
1916
+ - **Freshness validator ignored `<!-- docguard:last-reviewed YYYY-MM-DD -->`**
1917
+ — header was generated into every template, recommended in the freshness
1918
+ fix text itself, checked by `score` for ALCOA+, but never read by
1919
+ `validateFreshness`. The reviewer's explicit "I reviewed this" signal
1920
+ had zero effect. The header now overrides the git-log fallback.
1921
+ `cli/validators/freshness.mjs`.
1922
+
1923
+ - **Environment-vars in pipe-table rows (no backticks) were treated as
1924
+ undocumented** — projects using `| VAR_NAME | description | required |`
1925
+ table syntax were silently flagged for every var. The doc parser only
1926
+ matched backtick-quoted names; it now also extracts the first column of
1927
+ markdown pipe-table rows. `cli/validators/environment.mjs`.
1928
+
1929
+ - **Docs-Diff warning was unactionable** — emitted `"N documented but not
1930
+ found in code"` with no filename. Now lists up to 5 paths inline with
1931
+ `(+N more)` for the long-tail. `cli/validators/docs-diff.mjs`.
1932
+
1933
+ - **Traceability ignored `// @doc` annotations AND missed Next.js App
1934
+ Router paths** — templates told users `// @doc API-REFERENCE.md` would
1935
+ link a source file to a canonical doc; the scanner never read the
1936
+ annotation. Compound: the `API-REFERENCE.md` TRACE_MAP only matched
1937
+ `routes/`, `controllers/`, `handlers/`, `openapi/swagger`, and
1938
+ `middleware/` — none of which cover `app/api/`. Added an annotation
1939
+ scanner (top-of-file, multi-language comment syntax) and an
1940
+ `(app|pages)/api/` glob. `cli/validators/traceability.mjs`.
1941
+
1942
+ - **`docguard upgrade --apply` silently broke Metrics-Consistency** — when
1943
+ a CLI upgrade added or removed validators, the project's hardcoded "N
1944
+ validators" counts in markdown went stale and the very next
1945
+ `docguard guard` failed Metrics-Consistency. The user did nothing wrong.
1946
+ `upgrade --apply` now prints an explicit nudge to run `fix --write`
1947
+ using the just-installed binary (the current process holds the OLD CLI's
1948
+ validator list, so it cannot apply the fix itself). `cli/commands/upgrade.mjs`.
1949
+
1950
+ - **Python env-vars were never scanned at all** — `grepEnvUsage` walked
1951
+ `.py` files but the regex list was JS-only (`process.env.*`,
1952
+ `import.meta.env.*`). Every documented Python env var read as "in docs,
1953
+ not in code". Added patterns for `os.environ["X"]`, `os.environ.get("X")`,
1954
+ and `os.getenv("X")`. The `explain` command's claim that Python was
1955
+ supported now actually holds. `cli/shared-source.mjs`.
1956
+
1957
+ - **`docguard memory` "Accuracy" overlapped `docguard score` "Accuracy"
1958
+ with different denominators** — same word, same project, wildly different
1959
+ numbers. Renamed the per-claim metric in `memory` to **"Claim match
1960
+ rate"** (matched claims / total claims) so it no longer collides with
1961
+ the score's weighted accuracy axis across all signals. JSON field name
1962
+ unchanged for backward compatibility. `cli/commands/memory.mjs`.
1963
+
1964
+ ## [0.21.1] - 2026-05-26
1965
+
1966
+ **Security patch — closes issue #190.** Command injection vulnerability in
1967
+ `docguard init` via the `ai` field of `.specify/init-options.json` is fixed.
1968
+
1969
+ ### Security
1970
+
1971
+ - **Issue #190: command injection in `cli/commands/init.mjs` and
1972
+ `cli/ensure-skills.mjs`.** The `detectAIAgent()` helper returned the
1973
+ `ai` field from `.specify/init-options.json` without validation, and
1974
+ that value was then shell-interpolated into an `execSync` invocation:
1975
+ ```js
1976
+ const aiFlag = `--ai ${detectedAgent}`;
1977
+ execSync(`specify init ... ${aiFlag} ...`);
1978
+ ```
1979
+ A local attacker with file-system write access to a victim's repo
1980
+ could plant `{"ai": "claude; touch /tmp/pwned;"}` and trigger
1981
+ arbitrary command execution on the victim's next `docguard init`.
1982
+
1983
+ **Severity:** Medium (requires local file-system access; pre-fix
1984
+ `detectAIAgent` consumed configs from any project DocGuard ran in).
1985
+
1986
+ **Discovered:** 23 duplicate auto-generated draft PRs from the
1987
+ "Sentinel" AI agent flagged this during the v0.19 cleanup sweep.
1988
+ The drafts were closed as noise but the underlying finding was
1989
+ tracked in #190 — fixed properly here.
1990
+
1991
+ **Fix (two layers, defense in depth):**
1992
+ 1. `getDetectedAgent()` now allowlist-validates the `ai` field against
1993
+ `/^[a-zA-Z0-9_-]{1,32}$/`. Anything else (shell metacharacters,
1994
+ non-strings, oversized values) returns `null`.
1995
+ 2. New `safeSpawnSpecify(args, opts)` helper uses `execFileSync` with
1996
+ args passed as an array — no shell interpolation possible. Both
1997
+ unsafe call sites (`init.mjs` and `ensure-skills.mjs`) now use
1998
+ this helper. Cross-platform (POSIX direct exec / Windows
1999
+ `cmd.exe /c specify.cmd`).
2000
+
2001
+ ### Tests
2002
+
2003
+ - 596 → **610** (+14): `tests/security-init-injection.test.mjs` pins
2004
+ both defense layers. Tests every shell metacharacter (`;`, backtick,
2005
+ `$()`, `|`, `&&`, newline), oversized values, non-string types,
2006
+ malformed JSON, missing config files. Asserts the legitimate
2007
+ allowlist (claude, cursor-agent, gemini, agy, copilot, windsurf,
2008
+ codex, roo, amp, kiro-cli, tabnine, underscore-bearing future names).
2009
+
2010
+ ### Audit
2011
+
2012
+ `grep -rn execSync cli/` was re-run; remaining call sites are all
2013
+ hardcoded literals (no attacker-influenced interpolation): freshness
2014
+ git probes, score's git probe, setup/doc-quality `which`-style
2015
+ detection. Documented in commit message.
2016
+
2017
+ ## [0.21.0] - 2026-05-26
2018
+
2019
+ **Time-to-value.** The funnel-unblocker release. Until v0.21, a dev shopping
2020
+ for documentation tools had to install DocGuard, run `init`, write some
2021
+ canonical docs, and only then could they see what the tool actually does.
2022
+ v0.21 compresses that to **30 seconds, zero install**:
2023
+
2024
+ ```bash
2025
+ npx docguard-cli demo
2026
+ ```
2027
+
2028
+ Plus: `docguard init` now auto-detects existing projects and switches to
2029
+ "scan and propose" mode (reverse-engineering canonical docs from your code)
2030
+ instead of dumping a blank skeleton. The blank-skeleton path is still one
2031
+ flag away (`--skeleton`).
2032
+
2033
+ ### Added
2034
+
2035
+ - **`docguard demo`** — the marquee feature of this release. Copies a baked-in
2036
+ fixture (`templates/demo-fixture/` — a 4-service payments API with
2037
+ intentional drift) to a temp directory, git-inits it, runs guard + score
2038
+ against it, then prints a **curated narrative**: top-5 findings spanning
2039
+ multiple validators, each annotated with the real-world impact ("Your AI
2040
+ agent reads the architecture doc and gives wrong answers about how the
2041
+ system works"), the CDD maturity score, and a clear three-line CTA showing
2042
+ both `npm install -g` and `npx` paths. Temp fixture is cleaned up on exit
2043
+ (or kept via `--keep` for inspection). Total time: ~0.5s for the guard
2044
+ run; total experience: ~30s from `npx` to the install CTA.
2045
+ - **`templates/demo-fixture/`** — ships with the package (already in
2046
+ `files: ["templates/"]`). 12-file pretend "acme-payments" project with
2047
+ drift across 7 validator categories: undocumented 4th service, missing
2048
+ API endpoint in reference, env var drift between `.env.example` and
2049
+ `ENVIRONMENT.md`, `CHANGELOG` missing `[Unreleased]`, README sections
2050
+ per Standard README spec missing, etc.
2051
+ - **`docguard init --skeleton`** — explicit opt-in to the v0.20 blank-template
2052
+ behavior. For greenfield projects where the scan would find nothing.
2053
+ - **`docguard demo --keep`** — preserves the temp fixture and reports its
2054
+ path. Useful for poking around what a real-world DocGuard-managed project
2055
+ looks like.
2056
+
2057
+ ### Changed
2058
+
2059
+ - **Smart `docguard init` first-run.** When `init` runs in a directory that
2060
+ has existing source code (`cli/`, `src/`, `lib/`, `app/`, or 10+ source
2061
+ files at top level) AND no `docs-canonical/`, it automatically dispatches
2062
+ to `runGenerate` with `--plan` — the "scan and propose" path. Heuristic
2063
+ opts out for: `--skeleton`, `--wizard`, `--skip-prompts` (CI), explicit
2064
+ `--profile`, or projects that already have canonical docs (re-init case).
2065
+ Result: the 80% of adopters who arrive with an existing codebase get
2066
+ immediate value from the very first command, instead of staring at a
2067
+ blank skeleton.
2068
+ - **`--help` updates.** New top section: "First-time? Try the demo (no
2069
+ install, no setup): `npx docguard-cli demo`". `demo` listed in Tools.
2070
+ `init` description updated to mention the new auto-detect behavior and
2071
+ the `--skeleton` opt-out.
2072
+ - **README.** New CTA block at the top under the H1, above the Table of
2073
+ Contents: prominent `npx docguard-cli demo` callout drives the funnel.
2074
+ Validator/command counts updated by `canonical-sync` to 14 commands.
2075
+
2076
+ ### Tests
2077
+
2078
+ - 582 → **596 tests** (+14):
2079
+ - `tests/demo-command.test.mjs` (6): demo exits 0; output contains banner
2080
+ + findings + score + CTA; `--quiet` suppresses banner; temp fixture is
2081
+ cleaned up by default; `--keep` preserves it; top-5 findings span 3+
2082
+ distinct validators (variety, not noise).
2083
+ - `tests/init-smart-detection.test.mjs` (8): empty dir → skeleton; dir
2084
+ with `src/` → smart mode; dir with `cli/` → smart mode; `--skeleton`
2085
+ forces skeleton even with code present; `--skip-prompts` keeps skeleton
2086
+ (CI determinism); pre-existing canonical docs skip smart mode; 10+
2087
+ top-level Python files trigger smart mode; <10 + no code dir → skeleton.
2088
+
2089
+ ### Strategic context
2090
+
2091
+ This is item #2 from the v0.19 SURFACE-AUDIT's adoption-friction analysis
2092
+ ("no demo path — devs have to install, init, write docs, run guard just to
2093
+ see what we do"). v0.20 closed friction #1 (surface sprawl); v0.21 closes
2094
+ #2 (time-to-value). Next up per the 5-release arc: v0.22 — AI-native fix
2095
+ loop (`docguard fix --apply` calls Claude/Codex and opens a PR with the
2096
+ fix end-to-end).
2097
+
2098
+ ## [0.20.0] - 2026-05-26
2099
+
2100
+ **Consolidation.** 21 user-facing commands become 13. The promise from
2101
+ v0.19's SURFACE-AUDIT delivered in full — without breaking any existing
2102
+ user. Eight v0.19 commands keep working with deprecation warnings; one
2103
+ permanent alias (`audit → guard`) stays forever; ten cute aliases nobody
2104
+ documented are removed.
2105
+
2106
+ This is the cleanup release. **No new functionality** — every behavior
2107
+ that worked in v0.19 still works in v0.20. The win is cognitive surface:
2108
+ new users see four clear sections in `--help` instead of seven muddled
2109
+ ones, and the "Daily 5" framing tells them exactly what to learn first.
2110
+
2111
+ ### Changed — surface shape
2112
+
2113
+ - **`docguard init --with <name>`** is the new entry point for the
2114
+ six one-shot scaffolders. Names: `agents`, `hooks`, `ci`, `badge`,
2115
+ `llms`, `publish`. Comma-separated for chaining
2116
+ (`docguard init --with agents,hooks,badge,ci`). The original six
2117
+ commands (`docguard agents`, `docguard hooks`, …) still work — they
2118
+ emit a yellow stderr deprecation warning and dispatch through
2119
+ `init --with` internally.
2120
+ - **`docguard init --wizard`** replaces `docguard setup`. Same 7-step
2121
+ interactive flow; `setup` is now a deprecation alias.
2122
+ - **`docguard diff --since <ref>`** replaces `docguard impact`. The
2123
+ underlying impact analyzer is the same code path. `impact` is now a
2124
+ deprecation alias.
2125
+ - **`docguard --help` reorganized** into four sections: **The Daily 5**
2126
+ (init, guard, diff, sync, score), **Tools** (8 situational verbs),
2127
+ **`init --with <name>`** (the six scaffolders), and **Deprecation
2128
+ aliases** (a footnote with the v1.0 timeline). Down from seven
2129
+ alphabetically-organized sections.
2130
+
2131
+ ### Removed — cute aliases (the ten dropped)
2132
+
2133
+ These were in the router but never in `--help`. None of them had
2134
+ documentation. v0.20 errors with a one-line hint to the canonical
2135
+ command:
2136
+
2137
+ `onboard` · `gen` · `badges` · `pipeline` · `repair` · `dx` ·
2138
+ `pub` · `traceability` · `help-warning` · `update`
2139
+
2140
+ Try `docguard onboard` in v0.20 and you'll get:
2141
+ ```
2142
+ Unknown command: onboard
2143
+ Hint: this alias was removed in v0.20. Try docguard setup
2144
+ (deprecated) — try `docguard init --wizard`.
2145
+ See docs-implementation/MIGRATION-v0.20.md for the full list.
2146
+ ```
2147
+
2148
+ ### Kept permanently
2149
+
2150
+ - **`audit → guard`** — the one alias that stays forever. Older blog
2151
+ posts, tutorials, and CI scripts reference it. No deprecation warning,
2152
+ no removal planned.
2153
+
2154
+ ### Added
2155
+
2156
+ - **`docs-implementation/MIGRATION-v0.20.md`** — full migration guide.
2157
+ Before/after table for every renamed command, the deprecation
2158
+ timeline, a grep recipe to detect old usage in your repo, common
2159
+ questions, and concrete examples (CI workflow, pre-commit hook,
2160
+ fresh-project bootstrap, post-commit "what docs am I responsible
2161
+ for?").
2162
+ - **`canonical-sync` validator (v0.19) now counts user-facing commands**,
2163
+ not just files in `cli/commands/`. It parses `cli/docguard.mjs` to
2164
+ find names in the Daily 5 + Tools sections, so the README's
2165
+ "ships 13 commands" claim stays accurate across renames without
2166
+ counting deprecation aliases.
2167
+ - **`tests/v020-consolidation.test.mjs`** — 24 tests covering: every
2168
+ `--with` target dispatches; multi-scaffolder runs in order; unknown
2169
+ `--with` targets error; every deprecation alias still works and
2170
+ warns; `--quiet` suppresses the warning; all ten dropped aliases
2171
+ error with a hint; `audit` is silent.
2172
+
2173
+ ### Fixed
2174
+
2175
+ - **Spec-Kit extension aliases now satisfy the
2176
+ `speckit.{extension}.{command}` schema** (issue #1, reported by
2177
+ `c05m1x`). `extensions/spec-kit-docguard/extension.yml` previously
2178
+ declared aliases as `docguard.guard` / `docguard.fix` /
2179
+ `docguard.review` / `docguard.score`, which spec-kit rejects with
2180
+ *"Validation Error: Invalid alias 'docguard.guard': must follow
2181
+ pattern 'speckit.{extension}.{command}'"*. All four aliases now
2182
+ match the canonical names (`speckit.docguard.guard` etc.), letting
2183
+ `specify extension add docguard` succeed cleanly. The reporter's
2184
+ secondary complaint about `--from` path-resolution is a separate
2185
+ upstream spec-kit issue and tracked there.
2186
+
2187
+ ### Workflow hygiene
2188
+
2189
+ - **`workflow_dispatch:` added to `ci.yml` and `supply-chain.yml`** so
2190
+ admin-bypass pushes that don't auto-trigger workflows can be
2191
+ recovered manually. (Came out of the v0.19.0 publish incident where
2192
+ a branch-protection bypass appears to have suppressed the auto-trigger.)
2193
+
2194
+ ### Tests
2195
+
2196
+ - 558 → **582 tests** (+24 from `tests/v020-consolidation.test.mjs`).
2197
+ - Canonical-Sync re-runs clean (`23 validators · 13 user-facing commands`).
2198
+
2199
+ ### Deprecation timeline
2200
+
2201
+ - **v0.20.x → v0.x**: deprecated commands work with yellow warning.
2202
+ - **v1.0.0**: deprecated commands removed. At least 2-3 months out.
2203
+ - **forever**: `audit → guard` stays.
2204
+
2205
+ The v0.20 migration guide is preserved through `.docguard-archive.json` and Git
2206
+ history.
2207
+
2208
+ ## [0.19.0] - 2026-05-26
2209
+
2210
+ **Self-aware.** The headline change: until v0.19, `guard` could not see
2211
+ when the README lied about DocGuard's own surface. v0.18.1 shipped with
2212
+ "ships 19 commands" while the codebase had 21, and the architecture
2213
+ diagram had drifted across five releases without anyone noticing —
2214
+ because no validator was checking. v0.19 closes that gap.
2215
+
2216
+ Triggered by a surface audit (see `docs-canonical/SURFACE-AUDIT.md`) that
2217
+ found three different command counts in three different places, six
2218
+ commands that exist in the router but were never surfaced in `--help`,
2219
+ and 11 undocumented alias variants. This release fixes the *self-policing*
2220
+ piece. The actual consolidation of the 21-command surface down to ~13
2221
+ verbs is staged for v0.20 with a migration guide.
2222
+
2223
+ ### Added
2224
+
2225
+ - **A — `canonical-sync` validator.** New 23rd validator that runs on
2226
+ every `guard` and asserts: (1) README "ships N commands" matches
2227
+ `cli/commands/*.mjs` file count; (2) README "N validators" matches the
2228
+ live runtime count; (3) architecture-diagram `Commands (N)` and
2229
+ `Validators (N)` mermaid labels match reality. Gated by
2230
+ `package.json` name === "docguard-cli" — returns N/A in every other
2231
+ project. Counts itself per SURFACE-AUDIT §8.5 (current claim is "23
2232
+ validators" = 22 files + 1 inlined Doc Sections, where Canonical-Sync
2233
+ is among the 22). Severity high. 9 unit tests, all green.
2234
+ - **B — Six ghost commands surfaced in `--help`.** `explain`, `impact`,
2235
+ `llms`, `memory`, `upgrade` now appear under their natural sections
2236
+ (Analysis, Memory, CI/CD, Utilities). The historical `audit → guard`
2237
+ alias is documented in a new "Aliases" footnote — kept permanently for
2238
+ backwards-compat with older CI scripts.
2239
+ - **P1 — `tests/npm-pack-smoke.test.mjs`.** Builds the actual tarball
2240
+ that would be published to npm, extracts it, and runs the CLI against
2241
+ a tiny fixture. Catches the class of bugs where a needed file is
2242
+ missing from `package.json`'s `files:` array. Opt-out via
2243
+ `NPM_PACK_SMOKE=0` but on by default — v0.15.0 nearly shipped with a
2244
+ missing `schemas/` directory until we added it to the files array, and
2245
+ this gate would have caught that.
2246
+
2247
+ ### Changed
2248
+
2249
+ - **C — README counts corrected to reality.** "ships 19 commands" → "ships
2250
+ 21 commands". Architecture diagram `Commands (19)` → `(21)`,
2251
+ `Validators (22)` → `(23)`. "any of the 22 validators" → "23 validators"
2252
+ in the What's-New section. Validators section now lists 23 with
2253
+ Canonical-Sync added between Generated-Staleness and Metrics-Consistency.
2254
+ Going forward, `canonical-sync` enforces these stay accurate.
2255
+ - **D — `Spec-Kit` validator moved to `cli/validators/`.** Was previously
2256
+ exported from `cli/scanners/speckit.mjs` — architecturally backwards
2257
+ (scanners read state, validators have severity/pass-fail semantics).
2258
+ New thin file at `cli/validators/spec-kit.mjs` re-exports the function;
2259
+ scanner logic stays where it lives. Now `ls cli/validators/*.mjs \| wc -l`
2260
+ matches the validator surface (22 files + 1 for Doc Sections inlined).
2261
+ - **P2 — Node-based `gh` stub for upgrade-pr e2e.** v0.18.0's shell-script
2262
+ stub passed on macOS but failed on Linux CI runners because of PATH
2263
+ interaction with the runner's `/usr/bin/gh`. v0.18.1 gated the test
2264
+ behind `E2E=1`. v0.19 rewrites the stub in Node (the runtime — present
2265
+ on every platform DocGuard supports). Net result: upgrade --pr e2e now
2266
+ runs in regular CI on every platform with no opt-in required.
2267
+
2268
+ ### Documentation
2269
+
2270
+ - **`docs-canonical/SURFACE-AUDIT.md`** (new).** Full survey of the 21
2271
+ commands, 23 validators, and every count claim in every canonical doc.
2272
+ Sections cover: hard data, every drift, overlap matrix between commands,
2273
+ proposed target surface for v0.20 (~13 verbs after consolidation),
2274
+ migration plan with deprecation aliases, the canonical-sync spec, and
2275
+ open questions answered. Maintainer-facing — refresh quarterly or when
2276
+ surface changes by more than ±3 commands.
2277
+
2278
+ ### Notes / Deferred
2279
+
2280
+ - The consolidation itself (folding `agents`/`badge`/`ci`/`hooks`/`llms`/
2281
+ `publish` into `init --with`; renaming `setup` → `init --wizard`;
2282
+ renaming `impact` → `diff --since`; dropping the 11 cute aliases) is
2283
+ intentionally **deferred to v0.20.0** with a migration guide. v0.19
2284
+ establishes the self-policing first so the v0.20 surface changes can't
2285
+ silently break the docs.
2286
+ - P4 (Generated-Staleness depth optimization) was superseded by v0.18-P2's
2287
+ cross-process disk cache, which covers the same scenario at the
2288
+ plan-cache layer for all validators.
2289
+
2290
+ ## [0.18.1] - 2026-05-26
2291
+
2292
+ Hotfix: v0.18.0 publish failed because the new `upgrade --pr` end-to-end test (which used a shell-script stub `gh`) was platform-specific — passed on macOS, failed on Linux CI runners due to interaction with the runner's existing `/usr/bin/gh`. Gated the test behind `E2E=1` (same pattern as the stress test) so the regular CI suite stays green. The production `upgrade --pr` code path is still covered by `tests/upgrade-pr.test.mjs`. v0.19 will switch to a Node-based gh stub.
2293
+
2294
+ All v0.18.0 features ship intact:
2295
+ - P1 Generated-Staleness fast-path (30% faster guard)
2296
+ - P2 cross-process plan cache (.docguard/plan.cache.json)
2297
+ - P3 `score --diff` per-category drill-down
2298
+ - P4 upgrade-pr battle-test (now opt-in via E2E=1)
2299
+
2300
+ ## [0.18.0] - 2026-05-26
2301
+
2302
+ Performance + drill-down release. Closes the four v0.18 backlog items:
2303
+ Generated-Staleness fast-path (**30% faster guard runs**), cross-process
2304
+ plan cache, `score --diff` drill-down, and an end-to-end battle-test for
2305
+ `upgrade --apply --pr`. **546 tests** (was 537, +9). 22 validators.
2306
+
2307
+ ### Performance
2308
+
2309
+ - **P1 — Generated-Staleness fast-path.** The validator used to call `buildMemoryPlan` (~400ms) on EVERY guard run, even on projects with no `<!-- docguard:section source=code -->` markers and no `status: draft` docs (i.e. most projects today). New cheap pre-flight: scan canonical docs for either signal first; if neither is present, return N/A in <5ms. **Result on the client repo: total validator time 1431ms → 998ms — a 30% reduction.** Generated-Staleness dropped from "slowest validator at 26-33% of guard time" to "doesn't appear in the slow-list at all".
2310
+ - **P2 — Cross-process plan cache (`.docguard/plan.cache.json`).** The v0.15-P1 in-process cache only helped within a single process. CI flows that run guard → sync → fix as separate processes each rebuilt the plan. v0.18 adds a disk-backed L2 cache keyed by a tree-state hash (git HEAD + manifest mtimes). Cache invalidates automatically when source files change. Disabled with `config.diskCache: false`; survives corrupt files silently; never the only cache layer — L1 (in-process) still wins for same-run flows. Cuts the typical 3-step CI flow from 3× to 1× build time.
2311
+
2312
+ ### Added
2313
+
2314
+ - **P3 — `docguard score --diff` per-category drill-down.** Symmetric to v0.17's `memory --diff`. The score headline ("Architecture: 80/100") used to require source-spelunking to understand. New `--diff` mode joins the score categories to live guard validator warnings and shows the underlying errors/warnings per weak category. Cap of 5 per category + "N more" pointer. Plus an inline tip: `docguard explain "<warning>"` for full per-warning help.
2315
+
2316
+ ### Internal
2317
+
2318
+ - **P4 — End-to-end battle-test for `upgrade --apply --pr`.** The v0.14-P4 PR flow shipped without ever being exercised end-to-end. New `tests/upgrade-pr-e2e.test.mjs` wires up a local bare-repo remote + a stub `gh` binary on a fresh PATH directory and asserts: branch created, migration applied, commit landed on remote, `gh pr create` invoked with `--title` + `--body`. No real GitHub credentials needed; lives in regular CI from now on.
2319
+ - **3 new test files**: `tests/plan-disk-cache.test.mjs` (7), `tests/upgrade-pr-e2e.test.mjs` (2). Existing test suites already covered Generated-Staleness and score behavior. **Total: 537 → 546 tests (+9 new).**
2320
+ - **New helpers** in `cli/scanners/memory-plan.mjs`: `_treeStateHash`, `_readDiskCache`, `_writeDiskCache`, `_DISK_CACHE_PATH`, `_DISK_CACHE_VERSION`.
2321
+ - **New helpers** in `cli/validators/generated-staleness.mjs`: `_quickScan` (cheap marker pre-flight).
2322
+ - **New helpers** in `cli/commands/score.mjs`: `_SCORE_TO_VALIDATORS` mapping, `_showScoreDiff`.
2323
+ - **`buildMemoryPlan` cache strategy**: L1 (per-process Map) → L2 (per-tree disk file) → fresh build. Tree-state hash uses `git rev-parse HEAD` + manifest mtimes (package.json, pyproject.toml, Cargo.toml, etc.) for invalidation.
2324
+ - **Dry-run on client repo**: env accuracy still 80/82, 672/672 PASS, validator time 1431ms → 998ms.
2325
+ - No new NPM deps.
2326
+
2327
+ ### Backlog for v0.19
2328
+
2329
+ - **F6** stale score cache (still low repro confidence)
2330
+ - Deeper Generated-Staleness optimization for projects that DO use markers (the v0.18 fast-path only helps projects without)
2331
+ - README polish — the README has aged through ~14 releases and could use a refresh
2332
+ - A pre-release smoke gate that runs against multiple synthetic fixture projects before publishing
2333
+
2334
+ ## [0.17.1] - 2026-05-26
2335
+
2336
+ Patch responding to a client-project feedback round: 1 real bug (B-7) and
2337
+ a discoverability improvement that helps users on older versions find the
2338
+ features they're asking for. **537 tests** (was 530, +7). 22 validators.
2339
+
2340
+ ### Fixed
2341
+
2342
+ - **B-7: `diff` and `guard.Environment` disagreed on env-var coverage.** My v0.16-P4 `SYSTEM_ENV_VARS` denylist was over-broad: `NODE_ENV`, `CI`, `GITHUB_TOKEN`, `GITHUB_REF`, `GITHUB_SHA` are legitimately app env vars (apps read `process.env.NODE_ENV` for production/dev branching, `process.env.CI` to detect CI runs, etc.). The denylist stripped them from the doc side of `diff` only, so a project that documented `NODE_ENV` in BOTH `ENVIRONMENT.md` AND `.env.example` would correctly pass the `Environment` validator but `diff` would falsely flag it as "in code but not documented". Trimmed the denylist to truly-system-only vars (PATH, HOME, SHELL, TERM, etc. — the names no sane app would treat as runtime config). Reported by the client project running v0.16.0; their env-var accuracy went 79/82 → 80/82 with the bogus `NODE_ENV` flag gone. New `tests/b7-node-env-symmetry.test.mjs` locks in the symmetry.
2343
+
2344
+ ### Added
2345
+
2346
+ - **What's-new highlights on the guard footer.** When `.docguard.json` carries a `docguardVersion` pin and the running CLI is newer, the guard footer now prints a short "New since v<pin>" list of headline features from intermediate releases. Top 5 inline, "N more in CHANGELOG.md" pointer when there's more. Closes the recurring pattern of users asking for features that shipped one or two releases ago — `sync --since`, `docguard impact`, `docguard explain`, `memory --diff`, `--quiet`, and Cross-Reference anchor hints all appear in the table.
2347
+
2348
+ ### Note to readers asking about S-1, S-11, S-12
2349
+
2350
+ These three features are **already shipped** as of the listed releases. The v0.17.1 what's-new nudge surfaces them inline for any project still pinned to v0.12 or earlier. Quick recap:
2351
+
2352
+ - **S-1: `docguard sync --since <ref>`** — shipped in **v0.13.0** as L-1. Refreshes only canonical doc sections touched by code changes in the diff range. Run `docguard sync --write --since main` on a feature branch to skip unrelated doc churn.
2353
+ - **S-11: `docguard impact --since <ref>`** — shipped in **v0.13.1**. Post-commit "changed files → affected canonical doc sections" map. Run `docguard impact --since HEAD~1` after a commit; JSON mode for CI bots.
2354
+ - **S-12: Anchor "did you mean...?" hints** — shipped in **v0.13.1** + extended in **v0.14.1** so high-confidence matches (edit distance ≤ 2, single close candidate) are now `[auto-fixable]` via `docguard fix --write`.
2355
+
2356
+ Upgrade with `docguard upgrade --apply` or `npm i -g docguard-cli@latest` to pick them up.
2357
+
2358
+ ### Internal
2359
+
2360
+ - **2 new test files**: `tests/b7-node-env-symmetry.test.mjs` (4 — diff/validator symmetry), `tests/whats-new.test.mjs` (3 — highlights surface). **Total: 530 → 537 tests (+7 new).**
2361
+ - **`SYSTEM_ENV_VARS`** trimmed in both `cli/commands/diff.mjs` and `cli/validators/environment.mjs` (single source of truth would be better; deferred).
2362
+ - **New highlight table** `_RELEASE_HIGHLIGHTS` in `cli/commands/guard.mjs` — add an entry per release going forward.
2363
+ - **Dry-run on the client project**: env accuracy 80/82, the 2 remaining mismatches are genuine doc-only drift (not bugs in our tool). Full guard still 672/672 PASS.
2364
+ - No new NPM deps.
2365
+
2366
+ ## [0.17.0] - 2026-05-26
2367
+
2368
+ Feature release picking up the 4 deferred items from v0.16 — **reproducibility
2369
+ (version pin), accuracy drill-down (memory --diff), self-scaffolding drift fix,
2370
+ and naming flexibility (kebab + camel both accepted)**. **530 tests** (was 519,
2371
+ +11). 22 validators.
2372
+
2373
+ ### Added
2374
+
2375
+ - **P1: Version pin in `.docguard.json` (F8).** CDD reproducibility. Add `docguardVersion: "0.17.0"` to your config and `docguard guard` will nudge if the running CLI differs (newer or older). New `docguard guard --pin` action records the running CLI version after a passing run — opt-in, never automatic, refuses on FAIL status so you don't pin a broken state. Closes the "same project, different score across versions" surprise reported by a Python user.
2376
+ - **P2: `docguard memory --diff` (F10).** The memory-accuracy headline (e.g. "Accuracy: 83%") no longer requires source-spelunking to explain. New `docguard memory` shows per-domain accuracy (Endpoints / Entities / Env vars / Tech stack); add `--diff` for the drill-down listing *which* claims don't match code in each domain. JSON mode for tooling. Reuses the existing diff helpers — no new scanning logic.
2377
+ - **P3: Drift-proofed validator-count language in templates (F7).** Templates in `commands/`, `extensions/spec-kit-docguard/commands/`, `extensions/spec-kit-docguard/skills/`, and CI workflow examples no longer bake in "N validators" — replaced with "all validators" or "the full validator suite". User's own docs that legitimately quote a count are still validated by Metrics-Consistency; only DocGuard's own scaffolding (which would drift on every new validator) is detached from the number.
2378
+ - **P4: Validator naming consistency (additive, N1).** `.docguard.json` now accepts both kebab-case (`"test-spec": false`) and camelCase (`testSpec: false`) for both `validators` and `severity` maps. Normalized to camelCase internally before merge. Pre-existing configs keep working unchanged; new configs can use whichever style matches their team's convention. No breaking change.
2379
+
2380
+ ### Internal
2381
+
2382
+ - **2 new test files**: `tests/version-pin.test.mjs` (6 — nudge behavior + `--pin` action), `tests/validator-naming.test.mjs` (5 — both casings accepted). **Total: 519 → 530 tests (+11 new).**
2383
+ - **New module**: `cli/commands/memory.mjs` (~140 lines).
2384
+ - **Exported from `cli/commands/diff.mjs`**: `diffRoutes`, `diffEntities`, `diffEnvVars`, `diffTechStack` so `memory.mjs` can reuse them without duplicating logic.
2385
+ - **New helpers in `cli/docguard.mjs`**: `normalizeConfig()`, `_kebabToCamel()`, `_KNOWN_VALIDATORS`.
2386
+ - **New helpers in `cli/commands/guard.mjs`**: `_parseSemver`, `_semverCompare`, `_checkVersionPin`, `_updateVersionPin`.
2387
+ - **Templates scrubbed** of numeric validator counts (6 files).
2388
+ - Dry-run on a real client project: 99% memory accuracy, 3 specific env-var mismatches surfaced by `memory --diff`.
2389
+ - No new NPM deps.
2390
+
2391
+ ### Out of scope (deferred to v0.18)
2392
+
2393
+ - **F6** stale score cache — still low repro confidence; deferred until we get a reliable reproducer.
2394
+ - **Bigger items**: deeper Generated-Staleness optimization (still ~26% of guard time on large repos), `upgrade --pr` battle-test against a real GitHub remote, cross-process plan cache.
2395
+
2396
+ ## [0.16.0] - 2026-05-26
2397
+
2398
+ Feature release driven entirely by feedback from a real Python project running
2399
+ DocGuard for the first time. **8 user-reported items shipped, 519 tests** (was
2400
+ 497, +22). 22 validators. The Python user's top two asks (language-aware
2401
+ TRACE_MAP, hook-overwrite protection) are both in.
2402
+
2403
+ ### Fixed
2404
+
2405
+ - **P1 — JSON+ANSI bleed in `score`/`trace`/`diff` `--format json`.** Critical CI bug. The v0.12 headless-mode fix only covered `guard` and (later) `diagnose`; three other commands leaked colored banners before the JSON body, breaking `jq` / `python -c "json.loads(...)"` pipelines. All five JSON-emitting commands now produce clean parseable output.
2406
+ - **P4 — `docguard diff` false positive on system env vars.** Backticked mentions of `PATH`, `HOME`, `USER`, `SHELL`, etc. inside ENVIRONMENT.md prose ("the venv `PATH`") were flagged as documented-but-not-implemented user env vars. Added a `SYSTEM_ENV_VARS` denylist to both `diff` and the `Environment` validator. The 30-name list covers OS/shell/CI vars; user-app names (`DATABASE_URL`, `API_KEY`, etc.) still count as documented.
2407
+
2408
+ ### Added
2409
+
2410
+ - **P2 — Language-aware `TRACE_MAP`** (top user ask). The original JS/TS-only patterns false-negatived on Python (`test_*.py`), Rust (`tests/*.rs`), Go (`*_test.go`), Java (`*Test.java`), Ruby (`*_spec.rb`), and PHP test layouts. Every `TRACE_MAP` entry — Test files, Entry points, Config files, Schemas, Env files — now matches the equivalent patterns across ecosystems. New `tests/trace-multilang.test.mjs` (16 tests) locks the cross-language matching in.
2411
+ - **P3 — Hook overwrite protection** (2nd user ask). `docguard hooks --type pre-commit` previously clobbered user customizations on re-install. Now wraps DocGuard's content in `# BEGIN DOCGUARD MANAGED — do not edit between these markers` / `# END DOCGUARD MANAGED` markers and **splices only the managed block** on re-install, preserving everything around it. Legacy pre-v0.16 hooks (no markers) prompt the user to re-run with `--force` to upgrade. Third-party pre-existing hooks refuse to clobber without `--force`.
2412
+ - **P5 — `--quiet` / `-q` flag.** Suppresses the banner + ensureSkills decorative line. Useful inside git hooks and CI loops where the 5-line banner becomes 30 lines of noise. Doesn't affect validator output itself.
2413
+ - **P6 — `docguard explain <warning>` command** (user wishlist). Paste any warning text and get back: which validator emitted it, what triggered it, how to fix, a passing example, and the standard it references. Cuts source-spelunking time from 5-10 minutes to seconds. Covers all 16 validators. Also accepts a validator key directly (`docguard explain freshness`). JSON mode for tooling.
2414
+ - **P7 — N/A markers for required doc sections.** A project that legitimately has no auth (CLI, library, internal tool) can now declare it via `<!-- docguard:section authentication n/a — CLI tool, no user accounts -->` instead of writing "Absent by design" boilerplate. The marker requires a reason (non-empty after the dash) so it can't be a silent opt-out. Doc-Sections counts the marked section as passed.
2415
+ - **P8 — `--no-spec-kit` flag for `init`.** Default-on stays for discoverability, but minimalist library projects can now skip the `.specify/`, `.agent/`, `commands/` scaffolding entirely with `docguard init --no-spec-kit`.
2416
+
2417
+ ### Internal
2418
+
2419
+ - **3 new test files**: `tests/trace-multilang.test.mjs` (16), `tests/section-na-markers.test.mjs` (5), plus expanded `tests/hooks.test.mjs` (+2 for managed-block). **Total: 497 → 519 tests (+22 new).**
2420
+ - New top-level command: `cli/commands/explain.mjs` with a 16-validator explainer table.
2421
+ - New helpers in `cli/commands/hooks.mjs`: `wrapManaged()`, `spliceManagedBlock()`, `BEGIN_MARKER`, `END_MARKER`.
2422
+ - New `SYSTEM_ENV_VARS` constant exported from `cli/commands/diff.mjs` (mirrored in `cli/validators/environment.mjs`).
2423
+ - Headless-mode flag check (`flags.quiet`) added to the main dispatcher.
2424
+ - No new NPM deps.
2425
+
2426
+ ### Out of scope (deferred to v0.17)
2427
+
2428
+ User feedback items NOT addressed in this release:
2429
+
2430
+ - **F6 — Score "Top improvements" cache** (low repro confidence — user cleared on the next run, may have been observer effect).
2431
+ - **F7 — Validator count drift in tool's own scaffolding** (philosophical: counts ARE accurate per-run; the issue is that DocGuard's OWN docs mention the count and naturally drift as validators are added. Could compute at runtime; defer for now.)
2432
+ - **F8 — Version pin in `.docguard.json`** (CDD reproducibility — record the DocGuard version that last passed). Medium effort, real value.
2433
+ - **F10 — Memory accuracy drill-down** (`docguard memory --diff` to show which claims don't match code). Bigger feature.
2434
+ - **N1 — Validator naming consistency** (`testSpec` JSON key / `test-spec` CLI flag / `Test-Spec` display). Breaking change; needs migration story.
2435
+ - **N3 — `--tax` fold** (philosophical: `--tax` does add information, just not enough to feel different).
2436
+
2437
+ ## [0.15.3] - 2026-05-26
2438
+
2439
+ Repo hygiene release — scrubbed a client-specific project name from public artifacts.
2440
+ No code-behavior changes.
2441
+
2442
+ ### Changed
2443
+
2444
+ - **Removed client-specific project references from public-facing artifacts**: CHANGELOG.md (29 mentions), `specs/003-v011-false-positives/*`, and source docstrings in `cli/scanners/memory-plan.mjs`, `cli/commands/upgrade.mjs`, `cli/validators/freshness.mjs`. Replaced with neutral phrasing ("an enterprise client project", "the client's stack"). The fact that v0.11.2 → v0.15 releases were driven by real-world testing on a real-world project is unchanged — the *receipts* just no longer name the specific project.
2445
+ - Test files retain references for internal traceability — `// REASON:` comments and `@req` markers stay as-is. Tests are not shipped in the npm tarball, only visible in the GitHub repo source.
2446
+
2447
+ ### Why this matters
2448
+
2449
+ DocGuard is a public OSS tool on npm + PyPI. Embedding a specific consulting client's project name in 29 CHANGELOG entries conflated "what the tool does" with "who the tool was tested against". This release decouples them: anyone reading the release history sees the technical decisions and the real-world validation that informed them, without coupling that narrative to a specific named project.
2450
+
2451
+ ### Internal
2452
+
2453
+ - 497 tests still pass (no test logic changed).
2454
+ - 22 validators unchanged.
2455
+ - Self-guard unchanged.
2456
+ - No new NPM deps.
2457
+
2458
+ ## [0.15.2] - 2026-05-26
2459
+
2460
+ Patch release responding to a `/docguard.diagnose` self-audit run on canonical-spec-kit.
2461
+ Fixes one real bug (case-sensitive applier) and 9 traceability/freshness/dedup warnings
2462
+ through targeted doc + test edits. **497 tests** (unchanged). 22 validators.
2463
+
2464
+ ### Fixed
2465
+
2466
+ - **`applyReplaceCount` was case-sensitive — couldn't fix capitalized labels.** Metrics-Consistency's detection regex uses `/gi` (case-insensitive), but the corresponding applier in `cli/writers/mechanical.mjs` was built with `/g` only. Result: a doc that said "21 Validators" (capitalized) showed a warning the user could see but `fix --write` would never resolve. Now the applier mirrors the validator's flags. Found by the diagnose run itself — the new ping-pong suppression suggested it as a candidate, `--force-redo` confirmed the issue. Closed-loop discovery.
2467
+
2468
+ ### Improved
2469
+
2470
+ - **5 freshness counters reset** — DATA-MODEL, SECURITY, TEST-SPEC, ENVIRONMENT, ROADMAP all updated with current `<!-- docguard:last-reviewed -->` dates reflecting the v0.12-v0.15 review cycle.
2471
+ - **5 traceability gaps closed** — added `@req FR-012/FR-013/FR-014/SC-006/SC-008` markers to existing tests (`tests/architecture.test.mjs`, `tests/docguardignore.test.mjs`, `tests/todo-tracking.test.mjs`, `tests/patch-0.11.2.test.mjs`) that already exercised those requirements but weren't tagged.
2472
+ - **DRIFT-LOG updated** with 3 new entries covering v0.15's drift-marker usage (test fixtures, the v0.15.1 defensive `includeTestFiles` flag, and the v0.12-v0.15 release-note prose). All marked Info / by design.
2473
+ - **TODO-Tracking false-positive eliminated** — the validator's own test file no longer trips itself by containing literal `test.skip(...)` in the outer scope. Fixed via string-concat token hiding, same pattern as the v0.15.1 DRIFT fixture fix.
2474
+
2475
+ ### Internal
2476
+
2477
+ - Self-guard: **218/227 → 224/231** (more checks pass, fewer warnings). 10 → 4 actionable warnings remaining (down from 17 at start of diagnose).
2478
+ - Remaining warnings are pre-existing: Docs-Diff test-file count (62), Doc-Quality CI-RECIPES negation density (legitimate prose), Spec-Kit plan-template sections in `specs/002-fix-test-discovery/` (historical artifact).
2479
+ - No new NPM deps. No code-behavior changes outside the applier fix.
2480
+
2481
+ ## [0.15.1] - 2026-05-26
2482
+
2483
+ Feature + performance release. **497 tests** (was 492, +5). 22 validators.
2484
+ Headline: full `--changed-only` set now covers **5 validators in ~100ms** on
2485
+ both an enterprise client project AND a synthetic 1000-file repo. New `.docguard.json`
2486
+ JSON Schema for IDE autocomplete.
2487
+
2488
+ > **Note**: v0.15.0 was committed but never published — the CI self-guard
2489
+ > failed because the new `tests/scoping-extended.test.mjs` had literal
2490
+ > `// DRIFT:` strings inside JS fixture data that Drift-Comments treated as
2491
+ > real drift comments. v0.15.1 includes a two-part fix: the test uses string
2492
+ > concatenation so the literal marker isn't in source, AND Drift-Comments
2493
+ > now skips test files by default (matching TODO-Tracking's pattern; opt in
2494
+ > via `config.drift.includeTestFiles`). Everything else in this release was
2495
+ > ready in v0.15.0 — see the v0.15.0-planned features below.
2496
+
2497
+ ### Fixed (v0.15.1 hotfix)
2498
+
2499
+ - **Drift-Comments false-positives from test fixtures.** Test files commonly carry literal `// DRIFT:` strings inside JS string fixtures (`'// DRIFT: example\n'`). Reading the test as source treated those as real drift comments. Drift-Comments now skips test files by default — same defensive posture TODO-Tracking adopted in v0.11.2 for the same reason. New `config.drift.includeTestFiles` opt-in for projects that genuinely use DRIFT markers in test code.
2500
+
2501
+ ### Added
2502
+
2503
+ - **P3: Drift-Comments + TODO-Tracking honor `config.changedFiles`.** Extending the v0.13 N-1 + v0.14-P2 lite-mode scoping. Now 5 of 22 validators scope to changed files in `--changed-only` mode (was 3). `CHANGED_ONLY_VALIDATORS` updated to include `drift` and `todoTracking`. **Result on the client: `--changed-only --since HEAD~3` runs 5 validators in 116ms** (was 78ms with 3 validators in v0.14 — adding two more validators cost only ~40ms because each is scoped). **Result on synthetic 1000-file repo: 91ms** (verified via new stress test).
2504
+ - **P4: JSON Schema for `.docguard.json`.** New `schemas/docguard-config.schema.json` shipped in the npm package. `docguard init` now writes `$schema` reference into newly-created configs so VS Code / IntelliJ / any JSON-Schema-aware editor gets autocomplete + inline validation for every config field. Includes types, descriptions, enums (severity = high/medium/low; profile = starter/standard/enterprise; projectType = cli/library/webapp/api/unknown), and field-level help text. Zero runtime impact — DocGuard ignores the `$schema` field itself.
2505
+ - **Q: Stress-test fixture.** New `tests/stress-test.test.mjs` builds a synthetic 1000-file monorepo (500 services + 500 routes + 1000 doc references) and asserts:
2506
+ - `--changed-only` finishes in **< 500ms** (actual: ~91ms).
2507
+ - Full guard finishes in **< 5s** (actual: ~755ms).
2508
+ Opt-in via `STRESS=1` to keep `npm test` fast. Catches regressions where any scoping path accidentally devolves to a full tree walk.
2509
+
2510
+ ### Performance
2511
+
2512
+ - **P1: `buildMemoryPlan` cache.** Memoizes the memory plan per (projectDir + scanner-relevant config) within a single process. Helps cross-command flows where `guard` then `sync` would otherwise rebuild the plan twice. New `clearMemoryPlanCache()` export for tests. Single-`guard` runs see no change (only one caller per process).
2513
+ - **P2: `walkDir` cache in `cli/scanners/schemas.mjs`.** `walkDir` was called 8× inside `scanSchemasDeep` for different entity types (Pydantic, Mongoose, Prisma, SQLAlchemy, Sequelize, GORM, Sqlx, Hibernate). Now caches the file list per directory; subsequent callers iterate an array instead of re-traversing. Net gain on the client's mixed Python+TS stack is modest (~3% of total validator time) but real, and helps on stacks where multiple scanners hit the same root dir.
2514
+ - **Combined P1+P2+P3 result on the client**: full guard 1456ms → 1431ms (~2%). `--changed-only` covers 5/22 validators in 116ms (vs 1456ms full = **12.6× faster**).
2515
+
2516
+ ### Internal
2517
+
2518
+ - **2 new test files**: `tests/scoping-extended.test.mjs` (4 tests covering P3) and `tests/stress-test.test.mjs` (2 stress tests + 1 always-passes smoke). **Total: 492 → 497 tests (+5 — stress tests opt-in via STRESS=1).**
2519
+ - New helpers: `clearMemoryPlanCache()`, `clearWalkDirCache()`, `_scanTodoFile()`.
2520
+ - `schemas/docguard-config.schema.json` is the first non-code file under `schemas/` — added to `package.json#files` so it ships in the npm tarball.
2521
+ - `.docguard.json` now self-documents via `$schema` reference when created by `init`.
2522
+ - Dry-run on the client: **672/672 PASS in 1.43s**.
2523
+ - No new NPM deps.
2524
+
2525
+ ### Out of scope (deferred to v0.16)
2526
+
2527
+ - **Deeper Generated-Staleness optimization** — still the slowest validator at 26% of guard time on the client. The cache helps cross-command flows but not single-guard runs. Next attack vector: stream `buildMemoryPlan` so it yields partial results as scanners complete, letting the validator early-exit on the first non-stale section.
2528
+ - **`upgrade --apply --pr` battle-test** on a real GitHub repo. Logic shipped in v0.14; end-to-end PR creation hasn't been tested against a live remote with branch protections.
2529
+ - **Cross-process memoization** — if guard / sync / fix runs in CI sequentially, they each rebuild the plan. A serialized cache under `.docguard/plan.cache.json` (keyed by a tree-state hash) would share across processes.
2530
+ - **Tree-state hashing for plan cache invalidation** — currently the in-process cache assumes the tree doesn't change mid-run. A proper hash would let long-running `watch` mode keep a stable cache that only invalidates on actual file changes.
2531
+
2532
+ ## [0.14.1] - 2026-05-26
2533
+
2534
+ Patch + small feature release responding to the an enterprise client project v0.12 feedback.
2535
+ **492 tests** (was 481, +11). 22 validators.
2536
+
2537
+ ### Fixed
2538
+
2539
+ - **N-1: Metrics-Consistency double-counted warnings.** When a doc mentioned the stale validator/check count multiple times (e.g. once in a heading, once in a body table), the validator emitted one warning per regex match — producing "4 warnings for 2 files" on an enterprise client project. Now dedupes by `(file, label, found-value)` so a single file contributes ONE warning per distinct drift value. The `replace-count` mechanical fix already uses replace-all semantics, so one fix per (file, label) is sufficient. **Reported by an enterprise client project.**
2540
+
2541
+ ### Added
2542
+
2543
+ - **S-12+: High-confidence anchor matches now auto-fix via `fix --write`.** v0.13.1 added "did you mean #X?" hints when Cross-Reference flagged a broken anchor. v0.14.1 takes the next step: when the suggested anchor is **unambiguous** (edit distance ≤ 2 AND no other candidates within the same distance), the warning is tagged `[auto-fixable]` and the validator emits a `replace-anchor` mechanical fix. New `replace-anchor` applier in `cli/writers/mechanical.mjs` rewrites only the anchor inside markdown link form `](#X)`, leaves plain-text occurrences and link text alone, is idempotent. **Three of five the client broken-anchor cases in v0.12.0 were "heading renamed, link not updated" — those are now `fix --write`-resolvable.**
2544
+
2545
+ ### Note to the client — the "still open" suggestions are all already shipped
2546
+
2547
+ The S-1, S-11, S-12 items in the v0.12 feedback letter all shipped earlier. The user just needs to upgrade:
2548
+
2549
+ - **S-1** (`sync --since <ref>` surgical refresh) → shipped in **v0.13.0** as L-1. Run `docguard sync --write --since main` to refresh only sections touched by code in the diff.
2550
+ - **S-11** (changed-file → affected-doc map) → shipped in **v0.13.1** as the `docguard impact` command. Run `docguard impact --since HEAD~1` after a commit; JSON mode for CI bots.
2551
+ - **S-12** (anchor "did you mean..." hints) → shipped in **v0.13.1**. Extended in this release (v0.14.1) so high-confidence matches are auto-fixable.
2552
+
2553
+ Run `docguard upgrade --apply` (or `npm i -g docguard-cli@latest`) to pick all of these up.
2554
+
2555
+ ### Internal
2556
+
2557
+ - **2 new test files**: `tests/metrics-dedup.test.mjs` (4) and `tests/anchor-autofix.test.mjs` (7). **Total: 481 → 492 tests (+11).**
2558
+ - **New mechanical fix type**: `replace-anchor`. The APPLIERS registry now lists 6 types.
2559
+ - **New helper** in `cli/validators/cross-reference.mjs`: `isUnambiguousSuggestion()` — gates the auto-fix on edit distance ≤ 2 AND single close candidate.
2560
+ - No new NPM deps.
2561
+
2562
+ ### Out of scope (deferred to v0.15)
2563
+
2564
+ Same backlog as v0.14:
2565
+ - Generated-Staleness perf optimization (33% of validator time).
2566
+ - Shared tree walk.
2567
+ - Cross-validator `config.changedFiles` opt-in.
2568
+ - `upgrade --pr` battle-test.
2569
+
2570
+ ## [0.14.0] - 2026-05-26
2571
+
2572
+ Feature release closing the v0.13 backlog (4 features) + 2 quality investments
2573
+ (multi-fixture harness, `--timings` profiler). **481 tests** (was 448, +33).
2574
+ 22 validators. Headline wins: pre-commit lite went from 2s → **78ms** on
2575
+ an enterprise client project, and Generated-Doc Staleness now CLOSES THE LOOP by emitting
2576
+ structured fixes that `fix --write` consumes.
2577
+
2578
+ ### Added
2579
+
2580
+ - **P1: Fix-history ping-pong suppression** (completes M-2). `fix --write` now skips fixes that have been applied >= N times before (default 2) — catches the "user keeps reverting, bot keeps re-applying" loop. Override with the new `--force-redo` flag. `applyCount` and `firstAppliedAt` added to each `.docguard/fixed.json` entry for an accurate audit trail.
2581
+ - **P2: Environment + API-Surface honor `config.changedFiles`** (extends N-1). When `--changed-only` is set:
2582
+ - `grepEnvUsage` scans only the listed files instead of the whole source tree.
2583
+ - `validateApiSurface` returns N/A when no route/spec/controller files are in the changed set.
2584
+ - **Result on an enterprise client project: `--changed-only --since HEAD~3` runs in 78ms — a 25× speedup from v0.13.**
2585
+ - **P3: Generated-Doc Staleness emits structured fixes**. M-1 (v0.13) only warned; now it ALSO produces a `fixes[]` array with new `regenerate-section` fix type that `fix --write` consumes mechanically. **Closes the loop: detect drift → fix without AI.** The applier rewrites only the named section's body, leaves surrounding prose alone, and is idempotent.
2586
+ - **P4: `docguard upgrade --apply --pr`** for team-wide schema rollouts. Creates a branch, applies the migration, commits as "chore(docguard): migrate schema X → Y", pushes, opens a PR via `gh` CLI. Pre-flight checks `gh` is installed; clear error if not. Useful when `.docguard.json` is branch-protected.
2587
+ - **Q1: Multi-fixture test harness** — `tests/fixture-projects.test.mjs`. Runs full guard against 5 real-world project shapes (Next.js webapp, Vite frontend, Express backend, Python CLI, Rust lib). Cross-cutting "no validator throws a developer error" assertion across every fixture. The harness that would have caught B-5 (v0.13.0 Freshness crash) before release.
2588
+ - **Q2: `docguard guard --timings`** — per-validator wall-time profile, sorted slowest-first, with `data.validators[].durationMs` in JSON output. Honest delivery on the "perf pass" item: instead of speculative refactoring, ship the measurement tool. Real finding on the client: Generated-Staleness is **33% of total validator time** (~400ms) — targeted v0.15 optimization candidate.
2589
+
2590
+ ### Changed
2591
+
2592
+ - **`docguard fix --write` records `applyCount`** in `.docguard/fixed.json`. Re-applying the same fix bumps the counter; suppression engages at count >= 2.
2593
+ - **`docguard fix --history`** display unchanged but now reads richer entries (applyCount, firstAppliedAt).
2594
+ - **`docguard guard --format json`** includes `durationMs` per validator.
2595
+
2596
+ ### Internal
2597
+
2598
+ - **5 new test files**: `tests/fix-suppression.test.mjs` (9), `tests/changed-only-scoping.test.mjs` (6), `tests/regenerate-section.test.mjs` (6), `tests/upgrade-pr.test.mjs` (3), `tests/fixture-projects.test.mjs` (6), `tests/profile-flag.test.mjs` (3). **Total: 448 → 481 tests (+33 new).**
2599
+ - New mechanical fix type: `regenerate-section`. APPLIERS registry now lists 5 types.
2600
+ - `cli/writers/mechanical.mjs` got a top-level lazy-loaded `_shouldSuppress` and `_sectionsModule` to support the new applier without circular deps.
2601
+ - `cli/commands/upgrade.mjs` got `openUpgradePR()` — gates on `gh` CLI availability.
2602
+ - `cli/commands/guard.mjs` per-validator timing via `performance.now()`.
2603
+ - Dry-run on an enterprise client project: **674/674 PASS in 1.48s** (full guard), **78ms** for `--changed-only --since HEAD~3` (P2 scoping in action), Generated-Staleness identified as biggest perf hog at 33% of validator time (v0.15 target).
2604
+ - No new NPM deps.
2605
+
2606
+ ### Out of scope (deferred to v0.15)
2607
+
2608
+ - **Generated-Staleness optimization**: 33% of validator time is the obvious target. Likely fix: memoize `buildMemoryPlan` across `--write` flows so it's not re-computed by the validator AND the writer.
2609
+ - **Shared tree walk**: the original Q2 ambition. Now that we have `--timings`, future PRs can MEASURE the gain instead of speculating.
2610
+ - **Cross-validator config.changedFiles**: only Docs-Sync, Environment, API-Surface opt in so far. Could extend to Drift-Comments, TODO-Tracking, Generated-Staleness for further `--changed-only` wins.
2611
+ - **`upgrade --pr` polish**: dry-run on a real GitHub repo with a real bot identity. The flag is wired and gated, but the actual end-to-end PR creation hasn't been battle-tested in the wild.
2612
+
2613
+ ## [0.13.1] - 2026-05-26
2614
+
2615
+ Patch + small feature release responding to the an enterprise client project v0.12/v0.13
2616
+ feedback. Fixes 2 bugs (B-5, B-6), ships 3 new features (S-7, S-11, S-12),
2617
+ and adds a cross-cutting "no validator throws" safety net. **22 validators,
2618
+ 448 tests (was 434, +14 new).** New `docguard impact` command.
2619
+
2620
+ ### Fixed
2621
+
2622
+ - **B-5: Freshness validator crashed with `getLastCommitDate is not defined`.** A an enterprise client project install of v0.13.0 produced this ReferenceError despite all the imports being correct in source — we couldn't reproduce locally, but the user's report was clear. Fix: defensive dynamic import in `freshness.mjs` that falls back to the pre-v0.13 inline implementation if `../shared-git.mjs` ever fails to load. Worst-case behavior is now "rename detection silently disabled" instead of "validator crashes with useless message". Also added an inline fallback for the same defensive layering. Reported by an enterprise client project.
2623
+ - **B-6: Cross-Reference didn't URL-decode link target paths.** A markdown link like `[name](../WU%20Documentation/foo.md)` (where the directory has a space) was looked up with `existsSync('../WU%20Documentation/foo.md')` literally — the filesystem stores the decoded form. Now: `resolveTarget` tries BOTH the literal path (for paths that legitimately contain `%`) and the URL-decoded form. **Effect on an enterprise client project: Cross-Reference went from 28/28 to 101/101 checks — 73 previously-broken refs now resolve correctly.** Reported by an enterprise client project.
2624
+ - **Cross-cutting safety net**: new `tests/guard-no-throw.test.mjs` runs guard against a fixture repo and asserts no validator leaks a ReferenceError / TypeError / "is not defined" / "is not a function" / "Cannot read properties of undefined" pattern into user-facing output. Found a *second* lurking bug while writing the test: Structure validator threw `Cannot read properties of undefined (reading 'some')` when `config.requiredFiles.agentFile` was missing — fixed with defensive array-or-string coercion + skip-when-missing for `changelog` too. This safety net runs in CI, catching the entire class of developer-error-leaks before release.
2625
+
2626
+ ### Added
2627
+
2628
+ - **S-12: Cross-Reference suggests the closest anchor on near-miss.** When the validator flags a broken anchor, it now appends `(did you mean #athena-setup-aws-only?)` when a heading in the target doc is a close match. Two-pass matcher: (1) substring containment with ≥4-char minimum and ≥50% overlap to avoid spurious matches, (2) Levenshtein edit distance within a `max(3, len/5)` budget. **Three of the five the client user-fixes in v0.12.0 were "heading renamed, link not updated" — now deterministic-fixable from the warning text.** Reported by an enterprise client project.
2629
+ - **S-7: Draft-staleness check in Generated-Doc Staleness validator.** A `docguard:generated` doc with `status: draft` (either YAML frontmatter or `<!-- status: draft -->` inline marker) that hasn't been modified in `> draftStalenessDays` days (default 14) now warns. Catches forgotten skeletons that stall before the AI fills them in. Threshold configurable via `config.draftStalenessDays`. Validator returns N/A only when there's NOTHING to check (no source=code sections AND no draft docs). Reported by an enterprise client project.
2630
+ - **S-11: New `docguard impact` command.** After a commit (or before a PR), runs `git diff --name-only --since=<ref>` and shows which canonical doc sections reference any of the changed code files. Three match strategies (direct path / basename / backticked module name — same as L-2 trace --reverse). Highlights orphaned files (code that changed but no doc references it) so reviewers know what's undocumented. JSON mode emits `{ since, changedFiles, ignoredFiles, affectedDocs }` for CI bots. Designed as a post-commit hook companion to K-1's auto-fix Action. Reported by an enterprise client project.
2631
+
2632
+ ### Internal
2633
+
2634
+ - **+3 new test files**: `tests/guard-no-throw.test.mjs` (2 — cross-cutting safety), `tests/impact.test.mjs` (5 — S-11), plus 5 new test cases in `cross-reference.test.mjs` (S-12 + B-6) and `generated-staleness.test.mjs` (S-7). **Total: 434 → 448 tests (+14 new).**
2635
+ - **New module**: `cli/commands/impact.mjs` (~140 lines).
2636
+ - **Hardened**: `cli/validators/freshness.mjs` (defensive shared-git import), `cli/validators/structure.mjs` (defensive config-shape handling), `cli/validators/cross-reference.mjs` (URL-decode + anchor suggestion).
2637
+ - **Dry-run on an enterprise client project before push** (read-only): 670/674 PASS in 1.8s with all 22 validators. Cross-Reference jumped from 28/28 to **101/101 checks** — B-6 fix unlocked 73 previously-broken refs.
2638
+ - No new NPM deps.
2639
+
2640
+ ### Note on the client's v0.12 feedback
2641
+
2642
+ Several "still open" suggestions from the an enterprise client project v0.12 feedback were already shipped:
2643
+
2644
+ - **S-2 (sweep-needed nudge)** → shipped in v0.12.0 as K-6.
2645
+ - **S-3 (trace --reverse)** → shipped in v0.13.0 as L-2.
2646
+ - **S-4 (`git log --follow`)** → shipped in v0.13.0 as L-3.
2647
+ - **S-5 (.docguardignore at init)** → shipped in v0.12.0 as K-3.
2648
+ - **S-6 (per-validator severity)** → shipped in v0.12.0 as K-4.
2649
+ - **S-9 (pre-commit lite)** → shipped in v0.12.0 as K-5.
2650
+ - **S-10 (`.docguard/fixed.json`)** → shipped in v0.13.0 as M-2.
2651
+
2652
+ Upgrade with `docguard upgrade --apply` (or `npm i -g docguard-cli@latest`) to get all of these. **The the client report header said v0.12.0 but the B-5 error pattern indicates an in-flight v0.13.0 install** — either way, this patch makes both versions resilient to the regression.
2653
+
2654
+ ## [0.13.0] - 2026-05-26
2655
+
2656
+ Feature release — full backlog cleanup. **Phase L** (sync intelligence: 3 features), **Phase M** (bigger validators: 2 features), **Phase N** (polish: 2 fixes), and a new `shared-git.mjs` module that gives every git-touching validator rename-aware history. **22 validators total** (was 21). 434 tests, +34 from v0.12.
2657
+
2658
+ ### Added
2659
+
2660
+ - **L-1 / S-1: `sync --since <ref>` surgical refresh.** `sync` now uses the git diff against the given ref to decide which code-truth doc sections actually need refreshing. Sections whose underlying source files weren't in the diff are explicitly skipped (with a `skipped` entry naming the section). When the diff contains no code files at all (e.g. PRs that touch only markdown), sync is a fast no-op. Saves wall-clock time on large monorepos.
2661
+ - **L-2 / S-3: `trace --reverse <code-path>`.** Mirror of the forward trace — given a code file path, finds every canonical doc that references it. Three match strategies (direct path, basename, backticked module name) with a per-doc summary in text mode or full match list in JSON mode. Surfaces "is this file documented anywhere?" in one command.
2662
+ - **L-3 / S-4: Rename detection via `git log --follow`.** New `cli/shared-git.mjs` module centralises every git-log call. All file-scoped queries now pass `--follow` so a `git mv` no longer resets the file's history. Freshness, Test-Spec, Traceability — anything that asks git "when was this file last touched?" — now answers correctly across renames.
2663
+ - **M-1 / S-7: Generated-Doc Staleness validator** (22nd validator). New validator re-runs the memory-plan scanner and compares each `source=code` section's expected body against on-disk content. Flags sections where the doc and the scanner disagree — i.e. either code changed without `sync --write` running, or someone hand-edited a machine-owned section. Warning includes a "first drift at line N" hint that names the diff site.
2664
+ - **M-2 / S-10: `.docguard/fixed.json` fix-history audit log.** Every mechanical fix `fix --write` applies is appended to a small JSON log under `.docguard/`. Entries are fingerprinted by `type+file+summary` and deduped (re-applying the same fix updates the timestamp instead of growing the file). Rolls over at 500 entries. New `docguard fix --history` command pretty-prints the log grouped by day. Also recorded: `appliedBy` (so K-1's `docguard-bot` auto-commits are distinguishable from human runs).
2665
+ - **N-1: Per-file scoping of `--changed-only`.** The `--changed-only` lite mode now computes the actually-changed files (`git diff --name-only HEAD~1 HEAD`, configurable with `--since`) and passes them as `config.changedFiles` to validators that opt in. Docs-Sync is the first opt-in: routes and services outside the changed set are skipped entirely. On an enterprise client project the Docs-Sync check count went from 101 → 21 in `--changed-only` mode.
2666
+ - **N-2: 4 broken README anchors fixed** (caught by K-7's Cross-Reference validator). `[Commands](#-commands)` → `[Usage](#usage)`. `CONTRIBUTING.md` added to the validator's standard-docs lookup list (along with CODE_OF_CONDUCT.md, SECURITY.md, PHILOSOPHY.md, STANDARD.md, COMPARISONS.md) so cross-doc refs to those resolve.
2667
+
2668
+ ### Changed
2669
+
2670
+ - **22 validators total** (was 21). Auto-fix bumped 6 doc references from "21 validators" → "22 validators" during the version bump.
2671
+ - **Trace command** (existing) now honors `--reverse` to switch to the new reverse mode; the forward mode is unchanged.
2672
+ - **`docguard guard` JSON output** for `--format json` no longer prints the banner or `ensureSkills` line — same headless fix as v0.12, extended to `trace --reverse --format json` and other JSON-mode commands.
2673
+
2674
+ ### Internal
2675
+
2676
+ - **6 new test files**: `tests/shared-git.test.mjs` (11), `tests/sync-since.test.mjs` (3), `tests/trace-reverse.test.mjs` (5), `tests/generated-staleness.test.mjs` (4), `tests/fix-memory.test.mjs` (11), plus updates to `tests/changed-only.test.mjs`. **Total: 434 tests passing (was 400, +34 new).**
2677
+ - **New modules**: `cli/shared-git.mjs` (centralized git plumbing with --follow), `cli/validators/generated-staleness.mjs` (M-1), `cli/writers/fix-memory.mjs` (M-2). New helpers exported from sync.mjs: section→file matcher table for surgical refresh.
2678
+ - **Action / CLI dual-fix from v0.12** is now coordinated: K-1's auto-fix Action records to `.docguard/fixed.json` via `appliedBy: 'docguard-bot'`, giving teams a permanent record of which fixes the bot applied without diving into git history.
2679
+ - **Dry-run on an enterprise client project before push** (read-only): 670/674 PASS in 1.82s with all 22 validators. 4 warnings are stale "21 validators" references in the client's local docguard skill files — those auto-fix on the next `fix --write`.
2680
+ - Bumped extension files via auto-fix (6 files: extension.yml + 5 SKILL.md).
2681
+ - No new NPM dependencies. Still zero deps.
2682
+
2683
+ ### Out of scope (deferred to v0.14)
2684
+
2685
+ - **Fix-history suppression**: M-2 currently records but doesn't suppress. v0.14 will let `fix --write` skip fixes that were applied + reverted (avoiding ping-pong loops).
2686
+ - **More validators opt-into `config.changedFiles`**: N-1 only wires Docs-Sync. Environment and API-Surface could also benefit from path-level scoping.
2687
+ - **`generate-staleness` per-section auto-fix**: M-1 only warns; a future enhancement could emit structured fixes that `sync --write` consumes.
2688
+ - **`docguard upgrade --apply` for cross-machine teams**: currently in-place; could grow a "team-wide" mode that opens a PR.
2689
+
2690
+ ## [0.12.0] - 2026-05-26
2691
+
2692
+ Feature release — Phase K (7 features). Schema bump to **0.5**. Adds the
2693
+ PR-time auto-fix GitHub Action, `docguard upgrade` command + post-guard
2694
+ nudge, `.docguardignore` support, per-validator severity overrides,
2695
+ pre-commit-lite mode, sweep-needed nudge, and the new Cross-Reference
2696
+ validator (21 validators total, up from 20). Plus 4 papercut fixes
2697
+ caught during the an enterprise client project dry-run.
2698
+
2699
+ ### Added
2700
+
2701
+ - **K-1: PR-time auto-fix GitHub Action.** Extended `action.yml` with `command: fix` and `command: sync`, plus new inputs `auto-commit`, `comment-on-pr`, `commit-message`, `bot-name`, `bot-email`, and new outputs `fixes-applied`, `changed-files`, `committed`. The action commits any mechanical fixes back to the PR branch as `docguard-bot` and posts a summary comment. Fork PRs are skipped (head.repo != repository). Two ready-to-copy workflow templates ship under `extensions/spec-kit-docguard/templates/github-workflows/`: `docguard-guard.yml` (mandatory CI gate) and `docguard-autofix.yml` (PR auto-fix). Full recipe matrix in the new `docs-canonical/CI-RECIPES.md`.
2702
+ - **K-2: `docguard upgrade` command + post-guard schema-behind nudge.** New `docguard upgrade` checks installed CLI vs latest npm version (3-second-timeout fetch, fails open if offline) and project schema vs `CURRENT_SCHEMA_VERSION`. Flags: `--check-only` (exit 1 if behind, for CI), `--apply` (runs `npm i -g docguard-cli@latest` and migrates `.docguard.json`). `docguard guard` now appends a yellow `↑` nudge when the project's schema is behind. Aliased as `docguard update`.
2703
+ - **K-3: `.docguardignore` template at init (S-5).** New gitignore-style file (`one pattern per line, # comments`) merged into `config.ignore` at config-load time so every validator honors it. `docguard init` drops a starter `.docguardignore` covering common build outputs, generated code, and lock files. Loader (`loadDocguardIgnore`) + merger (`mergeIgnoreFile`) live in `cli/shared-ignore.mjs` — missing/unreadable file is a no-op.
2704
+ - **K-4: Per-validator severity overrides in `.docguard.json` (S-6).** New `severity` map: `{ severity: { todoTracking: "high", freshness: "low" } }`. `'high'` promotes that validator's warnings to fail-CI status (exit 1). `'low'` demotes them to info (no exit-code effect). `'medium'` (default) keeps existing exit-2 behavior. Display is unchanged — severity only affects CI. New `data.effectiveErrors` and `data.effectiveWarnings` fields in the JSON output reflect the severity-aware counts. The CLI prints a one-line note when overrides shifted the exit code.
2705
+ - **K-5: Pre-commit lite mode (S-9).** `docguard guard --changed-only` runs only the 3 fastest, highest-signal validators: Docs-Sync + Environment + API-Surface. Designed to complete in under 2 seconds for husky/lefthook pre-commit hooks. Validator list exported as `CHANGED_ONLY_VALIDATORS` for tooling. Recipe 5 in CI-RECIPES documents the integration.
2706
+ - **K-6: Sweep-needed nudge from Freshness counters (S-2).** When 2+ canonical docs are stale (10+ commits since last update), the guard footer now emits a single `↻` line recommending `docguard sync --write` to refresh all code-truth sections in one pass. Aggregates individual freshness warnings into one actionable recommendation. Suppressed in `--format json` mode.
2707
+ - **K-7: Cross-Reference validator (S-8) — 21st validator.** New `Cross-Reference` validator scans canonical docs for cross-references (markdown links like `[text](./OTHER.md#section)` and intra-doc anchors `#anchor`) and warns when they don't resolve. Extracts headings and computes GFM-compatible slugs. Skips external URLs (http/https/mailto), code-fenced examples, inline backtick code, and non-markdown link targets. URL-decodes anchors before comparison so `%EF%B8%8F`-encoded variation selectors resolve. Caught **14 broken refs in our own README** during the dry-run (4 remain after slugifier fixes — those are real bugs for a future doc cleanup PR).
2708
+ - **Antigravity / Kiro / Windsurf / GEMINI signal aliases (also in v0.11.2).** `cli/ensure-skills.mjs` detects these agent ecosystems via additional signal files. Doc-only mention here for visibility — code shipped in v0.11.2.
2709
+
2710
+ ### Changed
2711
+
2712
+ - **Schema bumped from 0.4 → 0.5.** Migration is purely additive: `severity: {}` field appears on existing configs. Run `docguard upgrade --apply` to migrate (or hand-edit). The post-guard nudge fires until you do.
2713
+ - **`docguard init` writes schema version `0.5`** with an empty `severity: {}` block and now also creates `.docguardignore`.
2714
+ - **`docguard guard` JSON output** includes new fields: `effectiveErrors`, `effectiveWarnings`, and per-validator `severity`.
2715
+
2716
+ ### Fixed
2717
+
2718
+ - **Docs-Coverage Check 5 silent-fail** (also in v0.11.2) — recommended README sections no longer bump `total` without emitting a message. Now a true bonus: present = +1, missing = no-op.
2719
+ - **Papercut #1 — `upgrade` missed pre-0.4 schemas.** A `.docguard.json` that exists but has no `version` field (the 2024-era format used by `an enterprise client project`, with `project` instead of `projectName`) was silently treated as "no config". Now: `readProjectSchemaVersion` returns the sentinel `'0.0'` for pre-0.4 schemas, and the migration registry has a `0.0 → 0.4` recipe that renames `project → projectName` while stamping the version. The user-facing label is friendlier too ("pre-0.4 (no version field)" instead of "Schema 0.0").
2720
+ - **Papercut #2 — `--format json` was unparseable.** The banner and `ensureSkills` install message wrote to stdout BEFORE the JSON body, so `JSON.parse` failed on every consumer. New `jsonMode` + `headless` detection in `main()` skips both for `--format json`, `--write`, `--check-only`, and `--changed-only`. Affects every Action recipe using `format: json` (Score-on-PR was broken).
2721
+ - **Papercut #3 — auto-fix Action counted CLI side effects as "fixes".** `ensureSkills` writes to `.agent/`, `.specify/`, `commands/` on first run; the Action's `git status --porcelain` diff was treating those as mechanical fixes and committing them. Two-part fix: (1) the new headless-mode skips `ensureSkills` so the side effects don't appear, and (2) the Action's bash filter excludes `.agent/`, `.specify/`, `commands/`, `.docguard/`, `.wolf/`, `.claude/` from the changed-files detection as belt-and-suspenders.
2722
+ - **Papercut #4 — slugifier didn't match GitHub's GFM.** The Cross-Reference validator's first iteration false-positived on every emoji-prefixed heading (`## ⚡ Quick Start` → GitHub produces `#-quick-start` with a leading dash, but my code produced `#quick-start`). Also collapsed `--` to `-` which GitHub keeps. Three bugs fixed; tests now lock in GFM compatibility for emoji-prefixed headings and stripped-punctuation cases.
2723
+
2724
+ ### Internal
2725
+
2726
+ - 6 new test files: `tests/upgrade.test.mjs` (12 tests), `tests/docguardignore.test.mjs` (11 tests), `tests/severity.test.mjs` (9 tests), `tests/changed-only.test.mjs` (4 tests), `tests/sweep-nudge.test.mjs` (3 tests), `tests/cross-reference.test.mjs` (22 tests). **Total: 400 tests passing (was 339, +61 new).**
2727
+ - Cross-Reference validator added (21 total validators, up from 20). Metrics-Consistency picked up the new count and `fix --write` auto-bumped 8 doc references from "20 validators" → "21 validators" in one pass — eating our own dogfood.
2728
+ - Dry-run on `an enterprise client project` (read-only) before push surfaced the 4 papercuts above. All fixed in this release.
2729
+ - New modules: `cli/commands/upgrade.mjs`, `loadDocguardIgnore` + `mergeIgnoreFile` exports in `cli/shared-ignore.mjs`, `CURRENT_SCHEMA_VERSION` + `SEVERITY_LEVELS` + `resolveSeverity` + `compareVersions` + `parseVersion` exports in `cli/shared.mjs`, `CHANGED_ONLY_VALIDATORS` + `liteValidatorsConfig` in `cli/commands/guard.mjs`.
2730
+ - New docs: `docs-canonical/CI-RECIPES.md` (5 recipes + permissions cheatsheet + full action inputs/outputs reference).
2731
+ - `action.yml` grew from 166 → 323 lines (+157) with the auto-commit/comment flow.
2732
+ - No new NPM runtime dependencies. Still zero deps. Node 18+ for built-in `fetch` (used by `upgrade` to check the npm registry).
2733
+
2734
+ ### Out of scope (deferred to v0.13)
2735
+
2736
+ - **Phase L (sync intelligence)**: S-1 `sync --since` surgical refresh (currently only reports diff as context), S-2 sweep-needed nudge from freshness counters, S-3 `trace --reverse` (code → doc-section map), S-4 rename detection via `git log --follow`.
2737
+ - **Phase M (bigger validators)**: S-7 generated-doc-in-draft staleness validator, S-8 cross-reference validator (broken `§X` anchors), S-10 `.docguard/fixed.json` memory of past fixes.
2738
+ - **K-5 enhancement**: scope each lite-mode validator to changed files only (currently the 3 validators run against the whole repo — fast enough but not optimal). Tracked for v0.13.
2739
+
2740
+ ## [0.11.2] - 2026-05-25
2741
+
2742
+ Patch release addressing the four bugs (B-1..B-4) reported from the v0.11.1 audit of `an enterprise client project` (score 98/100, 572/575 passed, 1 warning), plus Antigravity/Kiro/Windsurf agent-routing aliases and a Docs-Coverage silent-fail fix that the new B-4 nudge itself exposed.
2743
+
2744
+ ### Fixed
2745
+ - **B-1: Vite intrinsics no longer reported as user env vars.** `grepEnvUsage` in `cli/shared-source.mjs` now skips `DEV`, `PROD`, `MODE`, `BASE_URL`, and `SSR` on `import.meta.env.*` — these are injected by Vite at build time, not user-configured. Real user vars like `VITE_API_URL` are still captured. (Reported by an enterprise client project v0.11.1 audit.)
2746
+ - **B-2: `docguard diff` Data Entities now uses real exported names, not file basenames.** Previously the entity diff walked filenames and reported the stem (e.g. `models.py` → "models"), missing all the actual classes inside. Now uses `scanSchemasDeep` — the same code-side scanner the rest of DocGuard uses — which extracts real Pydantic/Dataclass/Mongoose/Prisma/Zod/Sequelize/Sqlx/SQLAlchemy/JPA entity names. (Reported by an enterprise client project v0.11.1 audit.)
2747
+ - **B-3: Literal `` `VITE_` `` prefix in prose no longer captured as an env var name.** Tightened the env-var name regex across `shared-source.mjs`, `validators/environment.mjs`, and `commands/diff.mjs` from `[A-Z][A-Z0-9_]*` to `[A-Z][A-Z0-9_]*[A-Z0-9]` (must end with letter/digit, not underscore). Documentation like ``All vars start with `VITE_` (Vite convention)`` no longer triggers a "missing `VITE_`" warning. (Reported by an enterprise client project v0.11.1 audit.)
2748
+ - **B-4 nudge surfaced: Docs-Coverage Check 5 (`checkReadmeSections`) silent-fail fixed.** The "recommended sections" loop bumped `total` without emitting a message when missing — exactly the anti-pattern B-4 flags. Recommended sections are now a true bonus: present = +1 to both passed/total, missing = no-op. Restores honest scoring on the README checker. (Found by the B-4 nudge running on the an enterprise client project fixture.)
2749
+
2750
+ ### Added
2751
+ - **B-4: `--show-failing` flag and validator-bug nudge.** `docguard guard --show-failing` shows warnings/errors for every non-passing validator even if the overall status would have suppressed them. New nudge fires when a validator has `passed < total` but emits no warning or error messages — points at a likely silent-fail validator bug for the user to file an issue. (Reported by an enterprise client project v0.11.1 audit.)
2752
+ - **Antigravity / Kiro / Windsurf / GEMINI agent signals.** `cli/ensure-skills.mjs` now detects these agent ecosystems via additional signal files (`.agents`, `.antigravity`, `ANTIGRAVITY.md`, `.kiro`, `.windsurf`, `GEMINI.md`) so the right skills are installed for each. Antigravity was already wired via `.agents → agy`; this expands the alias surface so neither side-by-side IDEs nor Spec Kit's `.agents` convention break detection.
2753
+
2754
+ ### Internal
2755
+ - New test file: `tests/patch-0.11.2.test.mjs` with regression coverage for B-1 (Vite intrinsics skip), B-2 (Pydantic class names, not file basename), and B-3 (literal `VITE_` not captured). **Total: 339 tests passing (was 336, +3 new).**
2756
+ - No new NPM dependencies. Zero schema or config-file changes. Bumped `pyproject.toml` from `0.11.0 → 0.11.2` to re-sync the PyPI publish (the previous patch released to npm but skipped PyPI version bump).
2757
+
2758
+ ### Out of scope (deferred to v0.12)
2759
+ - S-1 (`sync --since` surgical refresh), S-2 (sweep-needed nudge from freshness counters), S-3 (`trace --reverse` code→doc map), S-4 (rename detection via `git log --follow`), S-5 (`.docguardignore` template at init), S-6 (per-validator severity in `.docguard.json`), S-7 (generated-doc-in-draft staleness validator), S-8 (cross-reference validator for broken `§X` anchors), S-9 (pre-commit lite on changed files only), S-10 (`.docguard/fixed.json` memory of past fixes).
2760
+
2761
+ Credit: feedback from running v0.11.1 on the `an enterprise client project` enterprise monorepo (audit score 98/100, 572/575 passed).
2762
+
2763
+ ## [0.11.1] - 2026-05-25
2764
+
2765
+ Patch release addressing false positives surfaced by the v0.11.0 audit of the `an enterprise client project` enterprise monorepo, generalized into a multi-tool IaC detector, plus several DocGuard self-audit improvements. Spec: `specs/003-v011-false-positives/`.
2766
+
2767
+ ### Fixed
2768
+ - **Docs-Sync no longer misclassifies frontend API clients as backend routes.** Dropped the ambiguous bare `'api'` from the route-directory convention list. `src/api/client.ts` (frontend axios) and similar are no longer scanned as Express/Next.js routes (FP-1). For Next.js App Router (`src/app/api`, `app/api`), only files matching the strict `route.{ts,tsx,js,jsx,mjs}` filename convention are counted — helper files in the same tree are skipped (FR-001, FR-002).
2769
+ - **Test files are no longer flagged as undocumented services or routes.** The docs-sync route and service loops now skip paths under `__tests__/` and filenames matching `*.{test,spec}.{ts,tsx,js,jsx,mjs,py,java,go}` (FP-2, FR-003, FR-004). Eliminates ~7 spurious warnings per monorepo with co-located tests.
2770
+ - **Build outputs no longer flagged as undocumented source.** Added `cdk.out`, `out`, `.nuxt`, `.claude` to the docs-coverage `IGNORE_DIRS` set (FP-3, FR-005).
2771
+ - **`config.ignore` is now honored by Docs-Coverage's source-directory scan** (FP-3, FR-006 / IR-5). Closes a long-standing inconsistency where other validators respected the user's ignore but the source-dir scan did not. Patterns like `**/cdk.out/**` now match the directory itself as well as files inside it.
2772
+ - **Worktree copies no longer double-counted.** `globMatch` in `cli/shared-ignore.mjs` now rejects paths under `.claude/worktrees/`, `.git/worktrees/`, and `.jj/` at any depth — same treatment as `node_modules` (FP-4, FR-007). Affects every Claude-Code project using parallel-agent worktrees.
2773
+ - **Check 1 (config files) no longer flags build-cache dotdirs as undocumented configs.** Now skips directories — `.nuxt`, `.claude`, etc. are excluded by `IGNORE_DIRS` for the source-dir scan instead.
2774
+ - **Check 1 (config files) now honors `config.ignore` too.** Originally fixed only for the source-directory scan; a follow-up audit reproduced the same FP-3 class with `.local` in `ignore` still being flagged. Both Docs-Coverage scans now call `shouldIgnore(entry, config) || shouldIgnore(entry + '/', config)`. Closes FR-015 (audit-confirmed gap).
2775
+ - **Test-Spec validator parses multi-path Journey rows correctly.** Previously a Journey cell like `` `path/a.test.ts`, `path/b.test.ts` `` was stripped of all backticks then `existsSync()`d as one string — a 100% false-positive rate on multi-path rows. Now: split on commas outside backticks, strip backticks per segment, evaluate each independently. Row passes if ANY referenced file has evidence. Glob entries (`foo_*.test.ts`) are expanded; `(N suites)` / `(N tests)` annotations are accepted as the author's explicit coverage claim. Closes FP-6 and FR-016.
2776
+ - **TODO-Tracking validator no longer false-positives on its own keyword list.** Previously the regex matched `TEMP(?!late|orar)` inside its own source. Two-part fix: (1) match restricted to text following a comment marker (`//`, `#`, `/*`, `<!--`, block `*`), (2) the validator skips its own source file (`cli/validators/todo-tracking.mjs`) since the docstring legitimately names the keywords.
2777
+ - **TODO-Tracking validator no longer false-positives on test fixture strings.** Test files commonly contain `// TODO:` inside template literals (`writeFileSync(..., '// TODO:')`) that single-line heuristics can't distinguish from real comments. Test files are now skipped by default; opt back in with `config.todoTracking.includeTestFiles = true`.
2778
+ - **Traceability validator's own fixtures no longer leak as orphan refs.** `tests/traceability.test.mjs` previously contained literal `REQ-001`/`REQ-002`/`REQ-003` strings that the validator scanned and reported as orphaned test references. Fixtures now build the IDs from parts so the validator's pattern doesn't match.
2779
+
2780
+ ### Added
2781
+ - **Multi-tool IaC detector + consolidated documentation reminder.** New `cli/scanners/iac.mjs` identifies projects shipping any of: **AWS CDK** (`cdk.json`), **Terraform** (`*.tf` files), **Pulumi** (`Pulumi.yaml`), **AWS SAM** (`template.yaml` with `AWS::Serverless::`), and **Serverless Framework** (`serverless.yml`). When an IaC project's ARCHITECTURE.md has no Infrastructure heading, DocGuard emits ONE actionable warning per detected tool naming the marker file location and the expected source layout — instead of multiple generic per-directory warnings (FR-009, FR-010, FR-011). The generic per-dir warnings inside IaC packages (`bin/`, `lib/`, `modules/`, `stacks/`, `constructs/`, `handlers/`, etc.) are suppressed in favor of these consolidated messages. The legacy `cli/scanners/cdk.mjs` is preserved as a thin re-export for backward compatibility.
2782
+ - **`## Infrastructure (IaC)` section in `templates/ARCHITECTURE.md.template`.** New projects initialized via `docguard init` start with placeholder tables for AWS CDK, Terraform, and Pulumi/SAM/Serverless layouts plus a Deployment Pipeline subsection (FR-012). Explicitly skippable for non-IaC projects via a header comment.
2783
+ - **`DEFAULT_IGNORE_DIRS`** exported from `cli/shared-ignore.mjs` — canonical shared ignore set covering build outputs (`dist`, `build`, `out`, `cdk.out`, `target`, `.gradle`), VCS internals (`.git`, `.jj`, `.hg`, `.svn`), package caches (`node_modules`, `vendor`, `.venv`, `__pycache__`), and framework synth outputs (`.next`, `.nuxt`, `.turbo`, `.vercel`, `.cache`, `.svelte-kit`) (FR-008). Added `target` (Rust/Java), `.gradle`, and `.svelte-kit` per the updated an enterprise client project audit. Available for any future validator to import; existing per-validator `IGNORE_DIRS` sets are left in place (deferred migration).
2784
+
2785
+ ### Changed
2786
+ - **DocGuard package version bumped to 0.11.1** across `package.json` and all `extensions/spec-kit-docguard/` files (extension.yml + 5 SKILL.md files were referencing stale `v0.9.9`/`v0.10.0`).
2787
+ - **`docs-canonical/ARCHITECTURE.md`** updated to add `cli/writers/` and `cli/shared-*.mjs` to the Component Map and Layer Boundaries — closes a real doc gap surfaced by dogfooding (the writers/ directory has shipped for several releases without being documented).
2788
+ - **`specs/003-v011-false-positives/plan.md`** restructured to match the spec-kit `plan-template.md` shape (added Summary, Technical Context, Constitution Check, Project Structure sections). `tasks.md` rewritten with the spec-kit phased T### convention.
2789
+
2790
+ ### Internal
2791
+ - New test files: `tests/cdk-detection.test.mjs` (CDK + multi-tool IaC detector tests + `globMatch` worktree rejection + `DEFAULT_IGNORE_DIRS` shape). Existing test suites extended with regression cases for FP-1..FP-5, TODO-tracking false-positive guards, and IaC-tool detection across Terraform/Pulumi/SAM/Serverless. New tests are annotated with `// @req FR-NNN` / `// @req SC-NNN` comments for traceability. **Total: 329 tests passing (was 306, +23 new).**
2792
+ - **DocGuard self-audit improvements**: ran `docguard guard` on the repo as part of this release. Warnings dropped from **57 → 15** across the session by fixing real drift (stale extension versions, missing `cli/writers/` mention, traceability gaps) and reducing self-referential false positives (TODO validator scanning its own keyword list).
2793
+ - **Round 2 fixes after a second audit report**: FP-3 part B (`checkConfigFiles` honoring `config.ignore`), FP-6 (Test-Spec multi-path Journey row parsing with glob and `(N suites)` annotation support), additional `DEFAULT_IGNORE_DIRS` entries for Rust/Java/SvelteKit. **Total tests passing: 336** (was 306).
2794
+ - No new NPM dependencies. Zero schema or config-file changes.
2795
+
2796
+ ### Out of scope (deferred to v0.12)
2797
+ - Feature requests IR-1..IR-4, IR-6..IR-8 (per-validator severity, `--diff-only`, draft-staleness warning, `sync --section`, `.docguardignore` template at init, extended Next.js detection, `routesGlob`/`servicesGlob` overrides). IR-5 (honor ignore in source-dir scan) shipped as part of this release alongside FP-3.
2798
+ - Migrating all 17 modules that define their own `IGNORE_DIRS` constant to import `DEFAULT_IGNORE_DIRS` — mechanical, large diff, tracked separately.
2799
+ - Multi-line string-literal detection in TODO-Tracking — current heuristic still false-positives on `// TODO:` inside multi-line template literals. Workaround: keep test files out of TODO scanning (now default) or use `config.todoIgnore` globs.
2800
+
2801
+ Credit: feedback from running v0.11.0 on the `an enterprise client project` enterprise monorepo (audit score 98/100, 40 warnings).
2802
+
2803
+ ## [0.11.0] - 2026-05-22
2804
+
2805
+ This release reshapes DocGuard from a documentation linter into an **AI-readable, always-current project memory builder** — for any language project, not just JS/web. The four-mode lifecycle (`generate → guard → sync → fix`) is now coherent end-to-end.
2806
+
2807
+ ### Added — AI-powered Generate
2808
+ - **`docguard generate --plan`** — the "killer feature" from the v2 vision, now real. Scans any project (JS/TS, Python, Rust, Go, Java/Kotlin, Ruby, PHP, C#; polyglot/monorepo-aware) and emits a **structured agent task manifest** + writes the code-truth skeleton inside `<!-- docguard:section -->` markers. The AI agent writes the prose grounded in scanned facts; human writing is preserved.
2809
+ - **`--plan --format json`** machine-readable manifest for agent consumption.
2810
+ - **`--plan --write`** scaffolds the skeleton docs (code sections filled, prose sections as agent-task placeholders).
2811
+ - Language-aware doc set: a Rust CLI gets ARCHITECTURE; a webapp gets ARCHITECTURE + API-REFERENCE + SCREENS + FEATURES + INTEGRATIONS + ENVIRONMENT + docs-implementation/{KNOWN-GOTCHAS,CURRENT-STATE,RUNBOOKS}.
2812
+
2813
+ ### Added — Always-up-to-date Sync
2814
+ - **`docguard sync`** — refreshes `source=code` doc sections in place when code changes. Mechanical, idempotent, **preserves human prose**. Flags the prose sections to review when their adjacent code changed.
2815
+ - `--since <ref>` adds git-diff context. `--write` applies; default is a dry-run preview. `--force` overrides the `docguard:generated` marker gate.
2816
+
2817
+ ### Added — Section-addressable docs
2818
+ - **`cli/writers/sections.mjs`** — marker format `<!-- docguard:section id=X source=code|human -->`. `parseSections` / `replaceSection` / `upsertSection` for surgical regen that never clobbers human prose. The keystone the rest of the program builds on.
2819
+
2820
+ ### Added — Language-agnostic project intelligence
2821
+ - **`cli/scanners/project-type.mjs`** detects every ecosystem from manifests: `package.json`, `pyproject.toml`/`requirements.txt`/`setup.py`/`Pipfile`, `Cargo.toml`, `go.mod`, `pom.xml`/`build.gradle`, `Gemfile`, `composer.json`, `*.csproj`. Polyglot-aware: returns each ecosystem's language, framework, kind, deps, entry points.
2822
+ - **Multi-language route scanners** in `routes.mjs`: Spring Boot (Java/Kotlin, class-level base + verb annotations), Rails (verb DSL + `resources` 7-action expansion), Go (Gin/Echo/Chi/Fiber/mux), Rust (Axum, Actix, Rocket).
2823
+ - **Multi-language schema/model scanners** in `schemas.mjs`: Python (SQLAlchemy + relationships + Pydantic/SQLModel), Rust Diesel `table!`, Go structs with `json`/`gorm`/`db` tags, Java/Kotlin JPA `@Entity`, Rails ActiveRecord `create_table` migrations.
2824
+
2825
+ ### Added — Deep frontend capture
2826
+ - **`cli/scanners/frontend.mjs`** captures the UI surface: screens/routes (React Router, Next App + Pages with wrapper-unwrapping), components, **state stores** (Zustand/Redux Toolkit/Jotai/MobX), **custom hooks** (incl. `export { X as useY }` aliases), **React Contexts**, **API-client→endpoint mapping** (axios/fetch/custom client), and **i18n keys** (used vs. defined in locale files, with missing-keys reported as drift).
2827
+
2828
+ ### Added — External integrations
2829
+ - **`cli/scanners/integrations.mjs`** — 30+ SDK registry covering Cloud (AWS, GCP, Azure, Cloudflare), Databases, Payments (Stripe/Braintree), Auth (Auth0/Clerk/NextAuth/Cognito), AI (OpenAI/Anthropic/LangChain), Messaging (Twilio/SendGrid/Slack/MessageBird), Observability (Sentry/Datadog/OpenTelemetry), Search, Queues, Storage. Surfaces as `INTEGRATIONS.md` in the memory plan.
2830
+
2831
+ ### Added — Mechanical fix registry
2832
+ - **`cli/writers/mechanical.mjs`** generalizes `docguard fix --write` into a deterministic, no-LLM applier covering: `remove-endpoint` (API-Surface), `replace-count` (Metrics-Consistency stale "N validators"), `replace-version` (Metadata-Sync stale refs — only in actionable contexts, never prose), `insert-changelog-unreleased`.
2833
+ - Validators emit structured `fixes[]` arrays surfaced through `guard --format json`, `diagnose --format json`, and applied by `fix --write` / `diagnose --auto`. The 9 previously detect-only validators now have real `FIX_INSTRUCTIONS` routes (no more generic "Manual review needed").
2834
+
2835
+ ### Added — Spec Kit extension parity
2836
+ - New extension commands: `extensions/spec-kit-docguard/commands/fix.md`, `commands/sync.md`. `generate.md` updated to document `--plan`.
2837
+ - New skill: `extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md` — teaches the agent the refresh-and-review-prose loop. Extension README modernized to the memory-first vocabulary.
2838
+
2839
+ ### Changed
2840
+ - **PHILOSOPHY.md rewritten** from v1 governance-first ("not machine-generated") to the v2 memory-first reality (generate + guard + sync, bidirectional, language-agnostic). Honest about what the tool actually does.
2841
+ - **`docguard score`** displays **`Memory: Completeness X% · Accuracy Y%`** derived from the existing category scores; `--format json` adds `memory.{completeness, accuracy}` and per-category `axis` field. No weight changes.
2842
+ - CLI `--help` reframed around the memory lifecycle (audit/generate/guard/sync).
2843
+
2844
+ ### Fixed
2845
+ - Tightened a self-inflicted false positive (a literal `TODO` in a generate.mjs placeholder string was tripping DocGuard's own TODO-Tracking validator).
2846
+ - Fixed several scanner bugs caught by new tests: React Router wrapper-component unwrapping (`<RequireAuth><XPage/>`), Next.js base-path double-append, Go single-line struct regex, Spring Boot `@RequestMapping` class-level vs method-level disambiguation, locale-dir deduplication.
2847
+
2848
+ ### Infrastructure
2849
+ - CI: bumped `actions/checkout` and `actions/setup-node` to `@v5` across all four workflows (ahead of the June 2026 Node 24 default).
2850
+
2851
+ ### Tests
2852
+ - **Tests: 175 → 285 (+110)**. New test files: `api-doc`, `api-surface`, `shared-source`, `guard-classify`, `monorepo-scanning`, `sections`, `frontend`, `frontend-deep`, `i18n`, `project-type`, `memory-plan`, `integrations`, `routes-multilang`, `schemas-multilang`, `mechanical`, `api-write`, `multi-spec`, `sync`. All green.
2853
+
2854
+ ## [0.10.0] - 2026-05-22
2855
+
2856
+ ### Added
2857
+ - **API-Surface validator** (`cli/validators/api-surface.mjs`) — compares endpoints documented in `docs-canonical/API-REFERENCE.md` against the project's real API surface (OpenAPI spec, monorepo-aware code route scan). Flags documented-but-deleted endpoints (HIGH/error when confirmed by a spec; warning on heuristic code-scan) and present-but-undocumented endpoints (warning). Brings the validator count to **20**.
2858
+ - **`N/A` result state** in `guard` — a validator that finds nothing to check now renders a neutral `➖ [N/A]` with a reason instead of a misleading green ✅. "Nothing to check" is no longer indistinguishable from "checked and clean". Exposed via `classifyResult()`; surfaced in text, `--format json`, `diagnose`, and `ci`.
2859
+ - **`cli/shared-source.mjs`** — monorepo-aware source resolution honoring `config.sourceRoot`, npm `workspaces`, and `pnpm-workspace.yaml`: `resolveSourceRoots()`, `collectPackageJsons()`, `detectDocker()`, `grepEnvUsage()`.
2860
+ - **`cli/scanners/api-doc.mjs`** — robust API-REFERENCE.md parser (headings + table rows) with path normalization (`:id ≡ {id}`, strips backticks/pipes/trailing slashes) and exact-match endpoint comparison.
2861
+ - **`docguard fix --doc api-reference`** — generates an AI prompt to reconcile API-REFERENCE.md with the real API surface.
2862
+ - **39 new tests** (api-doc, api-surface, shared-source, monorepo-scanning, guard-classify). Total: **214**.
2863
+
2864
+ ### Changed
2865
+ - **Monorepo awareness across validators** — `schema-sync`, `docs-coverage`, `docs-sync`, `test-spec`, `metadata-sync`, and test-file discovery now honor `config.sourceRoot`/workspaces instead of hardcoded root-relative paths. Previously these silently passed on monorepos whose code lives under e.g. `backend/src`.
2866
+ - **Environment validator now checks code truth** — compares documented env vars against actual `process.env` / `import.meta.env` usage (`.env.example` counts as documentation), replacing the prior section-heading-presence heuristic.
2867
+ - **Test-Spec verifies files, not glyphs** — a Source-to-Test/Journey row passes only if the referenced test file actually exists; the author-typed ✅ is no longer trusted as proof of coverage.
2868
+ - **Changelog validator** now implements the documented staged-change check: warns when staged code files exist but `CHANGELOG.md` is not staged (git-aware; N/A otherwise).
2869
+ - **`Drift` validator renamed to `Drift-Comments`** to clarify it checks `// DRIFT:` comment ↔ DRIFT-LOG.md bookkeeping, not doc/code drift. Config key (`drift`) is unchanged.
2870
+ - **Doc Sections** uses anchored heading matching instead of substring (no longer satisfied by a table-of-contents link or code block).
2871
+
2872
+ ### Fixed
2873
+ - **`guard` no longer reports a confident green ✅ for checks that validated nothing** — removed hand-rolled `passed=1/total=1` auto-passes in `drift`, `architecture`, `test-spec`, and `security` (empty scan).
2874
+ - **Eliminated false positives** that previously masked real drift: tech-stack/env-var "documented but not found" on monorepos, parser-garbage "data entities" (`table`, `index`, `foreign`), the greedy route regex emitting `/api/` + stray backticks, and the test-file path/basename and glob-pattern mismatches ("N documented but not found"). Documented endpoints/tests that genuinely no longer exist are now reported as real drift.
2875
+ - **Security scan** anchored to a scanned-file count — an empty scan now warns ("no source files were scanned") instead of reporting a false "no secrets" pass.
2876
+
2877
+ ## [0.9.11] - 2026-03-18
2878
+
2879
+ ### Added
2880
+ - **`globMatch()` in `shared-ignore.mjs`** — Purpose-built positive file matching with hardcoded `node_modules` exclusion at any depth. Distinct from `buildIgnoreFilter()` (which is for ignore/skip filtering).
2881
+ - **6 new tests** — `globMatch` node_modules rejection (2), valid path matching (1), multi-pattern (1), CI detection (1), function load (1). Total tests: 46.
2882
+
2883
+ ### Fixed
2884
+ - **Docs-Diff no longer scans `node_modules` for test files** — `getTestFilesFromPatterns()` now uses `globMatch()` instead of repurposing `buildIgnoreFilter()`. The `**` glob no longer matches through `node_modules/` directories.
2885
+ - **CI detection supports enterprise systems** — `calcTestingScore()` now recognizes `buildspec.yml`, `amplify.yml`, `Jenkinsfile`, `.circleci/config.yml`, `.gitlab-ci.yml`, `.travis.yml`, and `turbo.json` with a `"test"` task.
2886
+ - **Multi-pattern test resolution works correctly** — `testPatterns` array resolves files from all patterns with proper deduplication via Set.
2887
+
2888
+ ## [0.9.10] - 2026-03-18
2889
+
2890
+ ### Added — Unified Ignore System & Scorer Alignment
2891
+ - **`cli/shared-ignore.mjs`** — New shared ignore utility with `buildIgnoreFilter()` and `shouldIgnore()`. All validators now share consistent glob matching for `config.ignore`, `securityIgnore`, and `todoIgnore`.
2892
+ - **`testPatterns` config** — New array field in `.docguard.json` for multiple test location patterns. Backward-compatible: `testPattern` (string) auto-normalizes to `testPatterns` (array).
2893
+ - **7 new tests** — Shared ignore utility (4 unit tests), securityIgnore integration (1), placeholder exclusions (1), testPatterns config (1). Total tests: 40.
2894
+
2895
+ ### Fixed
2896
+ - **`securityIgnore` globs now functional** — Security validator reads and applies `securityIgnore` patterns from `.docguard.json`. Previously, all ignore config was silently discarded. (Bug #1)
2897
+ - **`todoIgnore` globs now functional** — TODO-tracking validator reads and applies `todoIgnore` patterns. (Bug #2)
2898
+ - **Docs-Diff no longer scans `node_modules`** — Test file discovery uses `testPatterns` config and shared ignore filter instead of unchecked recursive walk. (Bug #3)
2899
+ - **Testing score reflects co-located tests** — `calcTestingScore()` now detects `__tests__/` under `backend/`, `server/`, `packages/` in addition to `src/`. Also checks `testPatterns` config. (Bug #4 & #5)
2900
+ - **Security score aligns with guard** — `calcSecurityScore()` now runs `validateSecurity()` inline and deducts points for findings. 100% security score is no longer possible when guard reports secret detections. (Bug #6)
2901
+ - **Placeholder/example values not flagged** — Security scanner skips AWS example keys (`AKIAIOSFODNN7EXAMPLE`), HTML `placeholder=` attributes, OpenAPI `example:` blocks, and `password123` test fixtures. (Bug #7)
2902
+ - **ROADMAP.md matching improved** — TODO-tracking now matches full text + file location context instead of a 30-char substring. (Bug #8)
2903
+ - **Architecture respects `ignore` array** — Architecture validator filters files through `config.ignore` before building import graph. (Bug #9)
2904
+
2905
+ ### Changed
2906
+ - **Constitution v1.0.0 → v1.1.0** — Principle IV updated: validators MAY import shared utility modules for infrastructure (file walking, ignore filtering). Commands MAY compose validator results.
2907
+ - **Security scoring weights** — Redistributed from 30/20/20/15/15 to 25/15/15/10/10/25 (25 pts now from actual secret scanning).
2908
+ - **Testing suggestion** — Context-aware: suggests `testPatterns` config instead of "Add tests/ directory" when co-located tests exist.
2909
+ - **`findColocatedTests()`** — Source roots expanded: `backend/`, `server/` added alongside `src/`, `app/`, `lib/`, `packages/`, `modules/`.
2910
+
2911
+ ## [0.9.9] - 2026-03-17
2912
+
2913
+ ### Added — Extension-First Architecture & Spec-Kit Integration Gate
2914
+
2915
+ #### Spec-Kit Integration Gate
2916
+ - **`ensureSpecKit()`** — Runs on every command. Auto-initializes spec-kit when `specify` CLI is available. Shows a prominent yellow-box reminder every time when spec-kit is not installed (persistent, no dismiss).
2917
+ - **`detectAIAgent(projectDir)`** — Maps 12 filesystem signals to spec-kit `--ai` flag values: `.cursor/` → `cursor-agent`, `.claude/` or `CLAUDE.md` → `claude`, `.gemini/` → `gemini`, `.agents/` → `agy` (Antigravity), `.github/copilot-instructions.md` → `copilot`, `.windsurf/` → `windsurf`, `.codex/` → `codex`, `.roo/` → `roo`, `.amp/` → `amp`, `.kiro/` → `kiro-cli`, `.tabnine/` → `tabnine`. Falls back to `--ai generic` when no agent detected.
2918
+ - **Strong init push** — `docguard init` now shows a prominent red-bordered box when spec-kit is missing, listing exactly what users miss: 9 AI skills, constitution, SDD workflow, agent detection. Provides both `uv` and `pip` install commands.
2919
+ - **Guard footer reminder** — `docguard guard` shows a 1-line spec-kit install nudge after results when not initialized.
2920
+ - **Skill auto-update** — `ensureSkills()` now compares installed SKILL.md `docguard:version` against package version. Automatically overwrites stale skills on DocGuard update.
2921
+
2922
+ #### LLM-First Output
2923
+ - **`detectAgentMode(projectDir)`** — Returns `'llm'` or `'cli'` based on filesystem signals and `.specify/init-options.json`. All adaptive commands check this.
2924
+ - **`diagnose.mjs`** — All `FIX_INSTRUCTIONS` now include `llmCommand` fields (e.g., `/docguard.fix --doc architecture`). Issue collection propagates `llmCommand` to output. Remediation plan, verification checklist, and debate prompts all adapt to agent mode.
2925
+ - **`guard.mjs`** — "Next step" hint now shows `/docguard.diagnose` in LLM mode.
2926
+ - **`init.mjs`** — Next steps show skill commands (`/docguard.guard`, `/docguard.fix`) in LLM mode, CLI commands (`docguard diagnose`) in CLI mode.
2927
+ - **`setup.mjs`** — Next steps adapt to agent mode.
2928
+
2929
+ #### Spec-Kit Skill Chaining
2930
+ - **`docguard-guard` SKILL.md** — Now chains to `/speckit.specify`, `/speckit.plan`, `/speckit.clarify`, and checks `constitution.md`.
2931
+ - **`docguard-review` SKILL.md** — Offers spec-kit skills for specification-level issues.
2932
+ - **`extension.yml`** — Declares `framework: spec-kit` and `specify` as optional tool.
2933
+
2934
+ ### Fixed
2935
+ - **`npx docguard guard`** → `npx docguard-cli guard` — The npm package name is `docguard-cli`, not `docguard`. Fixed in `hooks.mjs`, `setup.mjs`, `fix.mjs`, `docguard.mjs` (pre-existing bug).
2936
+ - **Hardcoded `--ai agy`** → Dynamic `detectAIAgent()` — `init.mjs` and `setup.mjs` no longer hardcode Antigravity as the agent.
2937
+ - **`llmCommand` never propagated** — `collectIssues()` in `diagnose.mjs` was not copying `llmCommand` from `FIX_INSTRUCTIONS` to issue objects, so LLM-first fix hints silently fell back to CLI commands.
2938
+ - **Debate prompt not LLM-aware** — `outputDebatePrompt()` now receives `agentMode` and adapts verification commands.
2939
+ - **Basic-tier checklist hardcoded** — Verification checklist for basic-tier agents now adapts to LLM/CLI mode.
2940
+ - **Stale "Zero dependencies" doc comments** — Updated 6 files to "Zero NPM runtime dependencies" matching the constitution.
2941
+ - **Platform-aware `--script`** — `specify init` now uses `--script ps` on Windows, `--script sh` on Unix.
2942
+
2943
+ ### Changed
2944
+ - **Constitution** — Principle II amended from "Zero Dependencies" to "Zero NPM Runtime Dependencies" (spec-kit is a framework convention, not a code dependency).
2945
+ - **SKILL.md metadata** — All 4 skills updated from `0.9.5`/`0.9.8` to `0.9.9`. Added `docguard:version` comment for auto-update mechanism.
2946
+ - **`ensure-skills.mjs`** — Full rewrite: 6 exports (`ensureSkills`, `ensureSpecKit`, `detectAgentMode`, `detectAIAgent`, `getDetectedAgent`, `isSpecKitAvailable`, `isSpecKitInitialized`).
2947
+ - **22 files changed**, +567/−203 lines.
2948
+
2949
+ ## [0.9.6] - 2026-03-14
2950
+
2951
+ ### Added — Enterprise AI Skills Architecture
2952
+
2953
+ #### AI Skills (Spec Kit Extension)
2954
+ - **4 enterprise-grade SKILL.md files** modeled after spec-kit's AI behavior protocol pattern:
2955
+ - `docguard-guard` (155 lines) — 6-step execution with severity triage matrix, structured reporting
2956
+ - `docguard-fix` (195 lines) — 7-step research workflow with per-document codebase research, 3-iteration validation loops
2957
+ - `docguard-review` (170 lines) — Read-only semantic cross-document analysis with 6 analysis passes
2958
+ - `docguard-score` (165 lines) — CDD maturity assessment with ROI-based improvement roadmap
2959
+ - Skills differ from commands: commands tell agents **what to run**, skills tell agents **how to think, validate, and iterate**
2960
+
2961
+ #### Bash Orchestration Scripts
2962
+ - `common.sh` — Shared utilities (root detection, CLI detection, JSON helpers)
2963
+ - `docguard-check-docs.sh` — Discover project docs, return JSON inventory with metadata
2964
+ - `docguard-suggest-fix.sh` — Run guard, parse results, output prioritized fixes as JSON
2965
+ - `docguard-init-doc.sh` — Initialize canonical doc with metadata header and template
2966
+
2967
+ #### Workflow Chaining & Hooks
2968
+ - All 10 commands upgraded with YAML `handoffs` for workflow chaining (guard → fix → review → score)
2969
+ - 3 spec-kit workflow hooks: `after_implement` (mandatory guard), `before_tasks` (optional review), `after_tasks` (optional score)
2970
+ - `extensions.yml` template for spec-kit hook registration
2971
+
2972
+ #### Extension Structure
2973
+ - `extension.yml` updated with `skills`, `scripts`, and `hooks` sections
2974
+ - Extension README rewritten with complete skills, scripts, hooks, and workflow documentation
2975
+ - `extensions/` directory now included in npm package (`package.json` files array)
2976
+
2977
+ ## [0.9.5] - 2026-03-14
2978
+
2979
+ ### Added — Spec Kit Alignment (Mega Release)
2980
+
2981
+ #### Spec Kit Scanner Rewrite
2982
+ - **Correct file paths**: Now checks `.specify/specs/NNN-feature/spec.md` (v3+ standard) with fallback to legacy `specs/*/spec.md`
2983
+ - **Constitution detection**: Checks `.specify/memory/constitution.md` (v3+) with fallback to root `constitution.md`
2984
+ - **Spec quality validation**: Validates mandatory sections (User Scenarios, Requirements, Success Criteria), FR-IDs, SC-IDs per spec-kit spec-template.md
2985
+ - **Plan quality validation**: Checks for Summary, Technical Context, Project Structure sections
2986
+ - **Tasks quality validation**: Verifies phased breakdown (Phase 1, 2+) and T-xxx task IDs
2987
+ - **Informational warning**: Spec-Kit validator now suggests `specify init` when no spec-kit artifacts found (was silent `0/0`)
2988
+
2989
+ #### Traceability Enhancement
2990
+ - **SC-xxx** (Success Criteria) added to requirement ID patterns — aligns with spec-kit SC-001 format
2991
+ - **T-xxx** (Task IDs) added — recognizes spec-kit T001, T002 task identifiers
2992
+ - Scans `.specify/specs/` path in addition to legacy `specs/`
2993
+
2994
+ #### Slash Commands (Spec Kit Extension)
2995
+ - New `commands/` directory with 4 AI agent slash commands: `/docguard.guard`, `/docguard.review`, `/docguard.fix`, `/docguard.score`
2996
+ - Shipped as part of npm package — available via `specify extension add docguard`
2997
+ - Works with Claude Code, Copilot, Cursor, Gemini, Antigravity, and more
2998
+
2999
+ #### REQUIREMENTS.md Template
3000
+ - New `REQUIREMENTS.md.template` aligned with spec-kit FR-xxx, SC-xxx, Given/When/Then standards
3001
+ - Added to `docguard init` template catalog (defaultYes: true)
3002
+
3003
+ #### Python Support (PyPI)
3004
+ - `pyproject.toml` and `docguard_cli/wrapper.py` for `pip install docguard-cli`
3005
+ - Thin Python wrapper delegates to `npx docguard-cli` — requires Node.js 18+
3006
+ - Python developers can now use `docguard guard`, `docguard score`, etc.
3007
+
3008
+ ### Fixed
3009
+ - `speckit.mjs` writeFileSync → safeWrite (backup safety, same as v0.9.4 pattern)
3010
+
3011
+ ## [0.9.4] - 2026-03-13
3012
+
3013
+ ### Fixed — Critical: Generate File Safety (Data Loss Prevention)
3014
+ - **`diagnose --auto` no longer passes `--force` to `generate`**: This was the root cause of silent doc overwriting. `diagnose --auto` now only creates missing files, never overwrites existing ones.
3015
+ - **`.bak` backup on `--force`**: When `generate --force` is explicitly used, all existing files are backed up as `.bak` before being overwritten. Content is never permanently lost.
3016
+ - **`--force` warning banner**: Shows how many existing files will be overwritten before proceeding.
3017
+ - **`safeWrite()` helper**: All 9 write operations in generate now go through a single safety wrapper.
3018
+
3019
+ ## [0.9.3] - 2026-03-13
3020
+
3021
+ ### Changed — Prose-Only Extraction Engine (Breaking improvement)
3022
+ - **`extractProse()` replaces `stripMarkdown()`**: Instead of stripping markdown and measuring residue (where table cells became "146-word sentences"), the new engine identifies and extracts only actual prose paragraphs. Reference docs (mostly tables/code) with <50 words of prose skip readability scoring entirely.
3023
+ - **Technical vocabulary normalization**: 80+ tech terms (DynamoDB, WebSocket, middleware, TypeScript, etc.) are treated as simple 2-syllable words for Flesch scoring. Known terms don't penalize readability.
3024
+ - **Markdown-aware sentence detection**: File paths (`src/auth.ts`), version numbers (`v0.9.2`), URLs, and abbreviations (`e.g.`, `i.e.`) no longer cause false sentence splits.
3025
+ - **Relaxed thresholds for technical docs**: Flesch 30→15, grade 16→18, sentence length 25→30, passive voice 20→25%, negation 15→20%.
3026
+ - **Impact**: Doc-Quality scores improved from 81% (13/16) to 95% (38/40) on DocGuard itself. API reference docs that scored 0/100 now skip gracefully or score fairly.
3027
+
3028
+ ## [0.9.2] - 2026-03-13
3029
+
3030
+ ### Fixed
3031
+ - **Flesch readability false positives**: Improved `stripMarkdown()` to remove mermaid diagrams, HTML tags, definition-style lines, and lines with >60% special characters. Docs with tables no longer score 0/100.
3032
+ - **Flesch threshold**: Lowered from 30→20 for technical documentation — developer docs inherently score lower than prose.
3033
+ - **NUL file on macOS**: `findUnderstandingCli()` used Windows `2>NUL` redirect which created a stray `NUL` file on Mac/Linux. Now uses platform-specific `which`/`where`.
3034
+ - **Unused import**: Removed `mkdirSync` from `diagnose.mjs` (was imported but never used).
3035
+
3036
+ ### Verified
3037
+ - `diagnose` is read-only by default — file creation only happens with explicit `--auto` flag.
3038
+ - `metrics-consistency` properly reads `.docguardignore` patterns.
3039
+
3040
+ ## [0.9.1] - 2026-03-13
3041
+
3042
+ ### Fixed
3043
+ - **Test detection**: `calcTestingScore` now detects co-located tests in `src/`, `app/`, `lib/`, `packages/`, `modules/` — not just top-level `tests/` directories. Projects using `src/**/__tests__/` or `src/**/*.test.*` patterns now score correctly.
3044
+ - **Test-spec fallback**: Validator fallback check now scans for co-located test files and checks vitest/jest config presence.
3045
+ - **Vitest config support**: Score calculation now reads `vitest.config.ts`/`jest.config.ts` include patterns to detect custom test directories.
3046
+
3047
+ ## [0.9.0] - 2026-03-13
3048
+
3049
+ ### Added
3050
+ - **Doc Quality Validator** — 8 deterministic writing quality metrics (passive voice, readability, atomicity, sentence length, negation/conditional load). Inspired by IEEE 830/ISO 29148.
3051
+ - **Understanding Integration** — Optional deep scan via the [Understanding](https://github.com/Testimonial/understanding) CLI for full 31-metric doc quality analysis. Runs automatically when `understanding` CLI is installed, providing actionable insights alongside DocGuard's native 8 metrics. Credit: Testimonial/understanding project.
3052
+ - **Spec Kit Integration** — Auto-detects [Spec Kit](https://github.com/github/spec-kit) projects (`.specify/`, `specs/`, `constitution.md`, `memory/`), maps Spec Kit artifacts to CDD canonical docs, and supports `docguard generate --from-speckit` for one-command conversion. Validates spec.md requirement IDs trace to tests. Credit: GitHub Spec Kit framework.
3053
+ - **Requirement Traceability (V-Model)** — scans docs for requirement IDs (REQ-001, FR-001, US-001, etc.) and validates they trace to test files. Opt-in by convention: just add IDs and DocGuard auto-enforces. Inspired by [spec-kit-v-model](https://github.com/leocamello/spec-kit-v-model) and IEEE 1016.
3054
+ - **TODO/FIXME Tracking** — detects untracked code annotations and skipped tests without explanation. Inspired by [spec-kit-cleanup](https://github.com/dsrednicki/spec-kit-cleanup).
3055
+ - **Schema Sync Validator** — detects database models from 7 ORM frameworks (Prisma, Drizzle, TypeORM, Sequelize, Knex, Django, Rails) and validates they're documented in DATA-MODEL.md.
3056
+ - **`docguard llms` command** — generates `llms.txt` from canonical docs following the [llms.txt standard](https://llmstxt.org/) (Jeremy Howard, Answer.AI, 2024).
3057
+ - **ALCOA+ Compliance Scoring** — maps existing validators to the 9 FDA data integrity attributes (Attributable, Legible, Contemporaneous, Original, Accurate, Complete, Consistent, Enduring, Available). Always shown in `docguard score` output with per-attribute evidence, gaps, and fix recommendations.
3058
+ - **`enterprise-ai` profile** — EU AI Act Annex IV compliance profile with stricter freshness (14-day threshold), required DATA-MODEL.md, and Risk Assessment section in SECURITY.md.
3059
+ - **OpenAPI cross-check** — if route files and an OpenAPI spec exist, validates routes have matching paths in the spec. Warns to re-run spec generator if out of sync.
3060
+
3061
+ ### Changed
3062
+ - Validator count: 14 → 18 validators, 108 → 130+ automated checks
3063
+ - `docguard score` now always shows ALCOA+ compliance breakdown
3064
+
3065
+ ## [0.8.2] - 2026-03-13
3066
+
3067
+ ### Added
3068
+ - **Docs-Coverage Validator** — detects undocumented code features: config files on disk, code-referenced configs (resolve/existsSync calls), source dirs not in ARCHITECTURE.md, README section completeness per Standard README spec.
3069
+ - **Metadata-Sync Validator** — cross-checks package.json version against extension.yml and markdown file references; context-aware matching (URLs, install commands, YAML only).
3070
+ - **Metrics-Consistency Validator** — catches stale hardcoded numbers in docs ("92 checks" when actual is 114); requires 2+ digit numbers and negative lookbehind for ratio patterns.
3071
+ - **`.docguardignore` support** — per-project file exclusions (like `.gitignore`), parsed by `loadIgnorePatterns()` in `shared.mjs`, integrated with Metrics-Consistency and Metadata-Sync validators.
3072
+
3073
+ ### Fixed
3074
+ - **Co-located test detection** — `generate` now recursively scans `src/**/__tests__/` and `*.test.*`/`*.spec.*` files; reads `vitest.config.ts`/`jest.config.ts` for custom patterns.
3075
+ - **Test files as source files** — test files are now filtered out of all source lists (services, routes, models, components, middlewares) before mapping.
3076
+ - **Diagnose suggest-only** — `diagnose` no longer auto-creates files by default; pass `--auto` to enable auto-fix. Shows actionable suggestions when not in auto mode.
3077
+ - **Diagnose score cap** — target score in AI prompt now capped at 100 (was showing 105/100).
3078
+
3079
+ ### Changed
3080
+ - **Guard checks** — increased from 86 to 114 with 5 new validators (docs-coverage, metadata-sync, metrics-consistency, docs-diff, freshness).
3081
+ - **Validators** — increased from 9 to 14.
3082
+
3083
+ ## [0.8.0] - 2026-03-13
3084
+
3085
+ ### Added
3086
+ - **Docs-Diff Validator** — New validator checks for entity/route/field drift between code and canonical docs. Integrated into `guard` and `diagnose` runs.
3087
+ - **File Existence Checks** — `test-spec` validator now verifies that source files and test files referenced in the Source-to-Test Map actually exist on disk (catches stale references).
3088
+ - **Dynamic Score Suggestions** — Score output now shows specific, AI-actionable suggestions per doc (e.g., "TEST-SPEC.md: missing section: ## Coverage Rules → Run `docguard fix --doc test-spec`") instead of generic advice.
3089
+ - **Recommended Test Patterns** — TEST-SPEC.md template now includes guidance on config-awareness tests, regression guards, edge cases.
3090
+ - **Mermaid Diagram** — ARCHITECTURE.md now includes a visual architecture diagram.
3091
+
3092
+ ### Fixed
3093
+ - **Scoring: Config-Awareness** — `calcEnvironmentScore` and `calcSecurityScore` now respect `needsEnvExample: false` — CLI projects no longer penalized for missing `.env.example`.
3094
+ - **Scoring: node:test Recognition** — `calcTestingScore` now checks `.docguard.json` `testFramework` and `package.json` scripts for `node --test`, giving full marks for built-in test runners.
3095
+ - **Scoring: Fake Bonus Removed** — Removed `docguard:version` metadata bonus from `calcDocQualityScore` — it was inflating scores by awarding points for a non-existent feature.
3096
+ - **Circular Dependencies** — Extracted `c` (colors) and `PROFILES` into new `cli/shared.mjs`, breaking 14 circular import cycles between `docguard.mjs` and all command files.
3097
+ - **CI Workflow** — Fixed failing CI by removing deleted `audit` command steps, adding `--force` to interactive `init`, and adding `diagnose` step.
3098
+
3099
+ ### Changed
3100
+ - **`audit` command** — Now an alias for `guard` (old `audit.mjs` deleted).
3101
+ - **Architecture + Security validators** — Enabled by default in `.docguard.json`.
3102
+ - **Guard checks** — Increased from 52 to 86 with all validators enabled.
3103
+ - **Test suite** — 30 → 33 tests, including config-awareness and regression guards.
3104
+
3105
+ ## [0.7.3] - 2026-03-13
3106
+
3107
+ ### Added
3108
+ - **Spec-Kit Extension** — DocGuard is now available as a GitHub Spec Kit community extension. 6 commands registered (`guard`, `diagnose`, `score`, `trace`, `generate`, `init`) with `after_tasks` hook for automatic validation. Located in `extensions/spec-kit-docguard/`.
3109
+
3110
+ ## [0.7.2] - 2026-03-13
3111
+
3112
+ ### Added
3113
+ - **Config-aware traceability** — `guard`, `diagnose`, and `trace` now respect `.docguard.json` `requiredFiles.canonical`. Excluded docs are skipped entirely.
3114
+ - **Orphan detection** — Warns when files exist in `docs-canonical/` but are excluded from config, with actionable cleanup instructions: "Delete them or add to .docguard.json".
3115
+
3116
+ ### Fixed
3117
+ - Trace no longer hardcodes all 6 docs — only evaluates what the user's config requires.
3118
+
3119
+ ## [0.7.1] - 2026-03-13
3120
+
3121
+ ### Added
3122
+ - **Traceability Validator** — New `validateTraceability` runs automatically in `guard` and `diagnose`. Checks that each canonical doc (ARCHITECTURE, DATA-MODEL, TEST-SPEC, SECURITY, ENVIRONMENT) has matching source code artifacts. Reports PARTIAL/UNLINKED/MISSING coverage.
3123
+ - **DocGuard in Generated Tech Stacks** — `docguard generate` now always includes DocGuard in the Documentation Tools table of generated ARCHITECTURE.md.
3124
+
3125
+ ### Fixed
3126
+ - **Guard warnings resolved** — TEST-SPEC.md `watch.mjs` partial coverage justified with ISO 29119 §7.2; DRIFT-LOG.md populated with template-string entries.
3127
+ - **Test file regex** — `.test.mjs` and `.spec.mjs` files now match in traceability and trace commands.
3128
+ - **51 guard checks** (was 46) — all passing on DocGuard itself.
3129
+
3130
+ ## [0.7.0] - 2026-03-13
3131
+
3132
+ ### Added
3133
+ - **Quality Labels in Guard** — Each validator now displays `[HIGH]`, `[MEDIUM]`, or `[LOW]` quality labels for actionable triage. Inspired by CJE quality stratification (Lopez et al., TRACE, IEEE TMLCN 2026).
3134
+ - **Standards Citations in Generated Docs** — All 6 generated canonical docs now include a standards reference footer citing the governing industry standard (arc42/C4, ISO 29119, OWASP ASVS, OpenAPI 3.1, 12-Factor App). Inspired by RAG-grounded standards alignment (Lopez et al., AITPG, IEEE TSE 2026).
3135
+ - **`docguard trace` Command** — New requirements traceability matrix generator. Maps canonical docs ↔ source code ↔ tests with TRACED/PARTIAL/UNLINKED/MISSING coverage signals. Supports `--format json`.
3136
+ - **`docguard score --signals` Flag** — Multi-signal quality breakdown showing per-signal contribution bars with quality labels. Inspired by CJE composite scoring.
3137
+ - **`docguard diagnose --debate` Flag** — Multi-perspective AI prompts using three-agent Advocate/Challenger/Synthesizer pattern. Inspired by AITPG multi-agent role specialization and TRACE adversarial debate.
3138
+ - **Agent-Aware Prompt Complexity** — `diagnose` auto-detects AI agent tier from AGENTS.md and adjusts prompt verbosity (concise for advanced models, step-by-step for smaller models). Inspired by CJE equalizer effect (Lopez et al., TRACE 2026).
3139
+ - **Research & Academic Credits** — Added full IEEE-style citations for AITPG and TRACE papers, ORCID, and concept attribution table to CONTRIBUTING.md. Added research credits to README.md and academic foundations to PHILOSOPHY.md.
3140
+
3141
+ ### Changed
3142
+ - **15 commands total**: added `trace` (alias: `traceability`)
3143
+ - **Version bump**: 0.6.0 → 0.7.0
3144
+
3145
+ ## [0.6.0] - 2026-03-13
3146
+
3147
+ ### Added
3148
+ - **Doc Tool Detection** — `generate` now detects 8 existing doc tools (OpenAPI, TypeDoc, JSDoc, Storybook, Docusaurus, Mintlify, Redocly, Swagger). Built-in YAML parser for OpenAPI specs (zero deps). Leverages existing tools instead of replacing them.
3149
+ - **Deep Route Scanning** — Parses actual route definitions from source code across 6 frameworks: Next.js (App Router + Pages Router), Express, Fastify, Hono, Django, FastAPI. OpenAPI-first: uses spec if available, falls back to code scanning.
3150
+ - **Deep Schema Scanning** — Parses schema definitions from 4 ORMs: Prisma (fields, types, relations, enums), Drizzle, Zod, Mongoose. Generates mermaid ER diagrams automatically.
3151
+ - **`API-REFERENCE.md` Generator** — New canonical doc generated from deep route scanning. Groups endpoints by resource, shows auth status, handler names, and per-endpoint parameter/response tables.
3152
+ - **`docguard publish --platform mintlify`** — Scaffolds Mintlify v2 docs from canonical documentation. Generates `docs.json`, `introduction.mdx`, `quickstart.mdx`, and maps all canonical docs to `.mdx` pages with proper frontmatter.
3153
+ - **AGENTS.md Standard Compliance** — Enhanced AGENTS.md template with Permissions & Guardrails section, Monorepo Support, Safety Rules, and `agents.md` standard tags.
3154
+ - **Scanner Modules** — New `cli/scanners/` directory with `doc-tools.mjs`, `routes.mjs`, `schemas.mjs`.
3155
+
3156
+ ### Changed
3157
+ - **ARCHITECTURE.md** — Now arc42-aligned (all 12 sections: §1-§12) with C4 Model mermaid diagrams (Level 1 Context, Level 2 Container), Runtime View sequence diagrams, Deployment View, and Glossary.
3158
+ - **DATA-MODEL.md** — Enhanced with field-level detail from ORM parsing (types, required, PK/UK, defaults), relationship tables, enum sections, and auto-generated mermaid ER diagrams.
3159
+ - **Dynamic Version** — Banner and `--version` now read from `package.json` (no more stale hardcoded version strings).
3160
+ - **Version bump**: 0.5.2 → 0.6.0
3161
+ - **14 commands total**: added `publish` (alias: `pub`)
3162
+
3163
+ ## [0.5.0] - 2026-03-13
3164
+
3165
+ ### Added
3166
+ - **`docguard diagnose`** — The AI orchestrator. Chains guard→fix in one command. Runs all validators, maps every failure to an AI-actionable fix prompt, and outputs a complete remediation plan. Three output modes: `text` (default), `json` (for automation), `prompt` (AI-ready). Alias: `dx`.
3167
+ - **`guard --format json`** — Structured JSON output for CI/CD and AI agents. Includes profile, validator results, and timestamps.
3168
+ - **Compliance Profiles** — Three presets (`starter`, `standard`, `enterprise`) that adjust required docs and validators. Set via `--profile` flag on init or `"profile"` in `.docguard.json`.
3169
+ - **`score --tax`** — Documentation tax estimate: tracks doc count, code churn, and outputs estimated weekly maintenance time with LOW/MEDIUM/HIGH rating.
3170
+ - **`init --profile starter`** — Minimal CDD setup (just ARCHITECTURE.md + CHANGELOG) for side projects.
3171
+ - **GitHub Actions CI template** — Ships in `templates/ci/github-actions.yml`, ready-to-use workflow.
3172
+ - **`watch --auto-fix`** — When guard finds issues, auto-outputs AI fix prompts.
3173
+ - **Init auto-populate** — After creating skeletons, outputs `docguard diagnose` prompt instead of manual instructions.
3174
+ - **Guard → Diagnose hint** — Guard output now prompts `Run docguard diagnose` when issues exist.
3175
+
3176
+ ### Changed
3177
+ - **Guard refactored**: `runGuardInternal()` extracted for reuse by diagnose, CI, and watch (no subprocess needed).
3178
+ - **CI rewritten**: Uses `runGuardInternal` directly instead of spawning subprocess. Includes profile and validator data in JSON.
3179
+ - **Watch rewritten**: Uses `runGuardInternal` (no process.exit killing the watcher). Proper debounced re-runs.
3180
+ - **Version bump**: 0.4.0 → 0.5.0
3181
+ - **13 commands total**: audit, init, guard, score, diagnose, diff, agents, generate, hooks, badge, ci, fix, watch
3182
+ - **30 tests** across 17 suites (up from 24/14)
3183
+
3184
+ ## [0.4.0] - 2026-03-12
3185
+
3186
+ ### Added
3187
+ - **`docguard badge`** — Generate shields.io CDD score badges for README (score, type, guarded-by)
3188
+ - **`docguard ci`** — Single command for CI/CD pipelines (guard + score, JSON output, exit codes)
3189
+ - `.npmignore` for clean npm publish
3190
+ - `--threshold <n>` flag for minimum CI score enforcement
3191
+ - `--fail-on-warning` flag for strict CI mode
3192
+ - npm publish dry-run in CI workflow on tag push
3193
+
3194
+ ### Changed
3195
+ - Score command refactored with `runScoreInternal` for reuse by badge/ci
3196
+ - CI workflow now runs actual test suite + dogfoods DocGuard on itself
3197
+ - 10 total commands (audit, init, guard, score, diff, agents, generate, hooks, badge, ci)
3198
+
3199
+ ## [0.3.0] - 2026-03-12
3200
+
3201
+ ### Added
3202
+ - **`docguard hooks`** — Install pre-commit (guard), pre-push (score enforcement), and commit-msg (conventional commits) git hooks
3203
+ - **GitHub Action** (`action.yml`) — Reusable marketplace action with score thresholds, PR comments, and fail-on-warning support
3204
+ - **Import analysis** in architecture validator — Builds full import graph, detects circular dependencies (DFS), auto-parses layer boundaries from ARCHITECTURE.md
3205
+ - **Project type intelligence** — Auto-detect cli/library/webapp/api from package.json
3206
+ - `.docguard.json` with `projectTypeConfig` (needsE2E, needsEnvVars, etc.)
3207
+ - 15 real tests covering all commands (node:test)
3208
+
3209
+ ### Changed
3210
+ - Architecture validator now auto-detects layer violations from ARCHITECTURE.md (no config needed)
3211
+ - Validators respect projectTypeConfig — no false positives for CLI tools
3212
+
3213
+ ### Fixed
3214
+ - Environment validator no longer warns about .env.example for CLI tools
3215
+ - Test-spec validator no longer warns about E2E journeys for CLI tools
3216
+
3217
+ ## [0.2.0] - 2026-03-12
3218
+
3219
+ ### Added
3220
+ - **`docguard score`** — Weighted CDD maturity score (0-100) with bar charts, grades A+ through F
3221
+ - **`docguard diff`** — Compares canonical docs against actual code (routes, entities, env vars)
3222
+ - **`docguard agents`** — Auto-generates agent-specific config files for Cursor, Copilot, Cline, Windsurf, Claude Code, Gemini
3223
+ - **`docguard generate`** — Reverse-engineer canonical docs from existing codebase (15+ frameworks, 8+ databases, 6 ORMs)
3224
+ - **Freshness validator** — Uses git commit history to detect stale documentation
3225
+ - **Full document type registry** — All 16 CDD document types with required/optional flags and descriptions
3226
+ - 8 new templates: KNOWN-GOTCHAS, TROUBLESHOOTING, RUNBOOKS, VENDOR-BUGS, CURRENT-STATE, ADR, DEPLOYMENT, ROADMAP
3227
+
3228
+ ### Fixed
3229
+ - Diff command false positives — entity extraction no longer picks up table headers
3230
+
3231
+ ## [0.1.0] - 2026-03-12
3232
+
3233
+ ### Added
3234
+ - Initial release of DocGuard CLI
3235
+ - `docguard audit` — Scan project, report documentation status
3236
+ - `docguard init` — Initialize CDD docs from professional templates
3237
+ - `docguard guard` — Validate project against canonical documentation
3238
+ - 9 validators: structure, doc-sections, docs-sync, drift, changelog, test-spec, environment, security, architecture
3239
+ - 8 core templates with docguard metadata headers
3240
+ - Stack-specific configs: Next.js, Fastify, Python, generic
3241
+ - Zero dependencies — pure Node.js
3242
+ - GitHub CI workflow (Node 18/20/22 matrix)
3243
+ - MIT license
3244
+
3245
+ ### Fixed
3246
+ - Added missing tests for the `watch` CLI command to verify it runs and reacts properly.