docguard-cli 0.14.0__tar.gz → 0.14.1__tar.gz
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.
- {docguard_cli-0.14.0/extensions/spec-kit-docguard → docguard_cli-0.14.1/.agent}/skills/docguard-fix/SKILL.md +2 -2
- {docguard_cli-0.14.0/extensions/spec-kit-docguard → docguard_cli-0.14.1/.agent}/skills/docguard-guard/SKILL.md +2 -2
- {docguard_cli-0.14.0/extensions/spec-kit-docguard → docguard_cli-0.14.1/.agent}/skills/docguard-review/SKILL.md +2 -2
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/docguard-score/SKILL.md +2 -2
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/docguard-sync/SKILL.md +1 -1
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/CHANGELOG.md +38 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/PKG-INFO +1 -1
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/cross-reference.mjs +43 -5
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/metrics-consistency.mjs +28 -4
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/writers/mechanical.mjs +33 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/extension.yml +1 -1
- {docguard_cli-0.14.0/.agent → docguard_cli-0.14.1/extensions/spec-kit-docguard}/skills/docguard-fix/SKILL.md +2 -2
- {docguard_cli-0.14.0/.agent → docguard_cli-0.14.1/extensions/spec-kit-docguard}/skills/docguard-guard/SKILL.md +2 -2
- {docguard_cli-0.14.0/.agent → docguard_cli-0.14.1/extensions/spec-kit-docguard}/skills/docguard-review/SKILL.md +2 -2
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/skills/docguard-score/SKILL.md +2 -2
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +1 -1
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/package.json +1 -1
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/pyproject.toml +1 -1
- docguard_cli-0.14.1/tests/anchor-autofix.test.mjs +144 -0
- docguard_cli-0.14.1/tests/metrics-dedup.test.mjs +112 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.analyze.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.checklist.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.clarify.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.constitution.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.implement.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.plan.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.specify.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.tasks.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/commands/speckit.taskstoissues.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-analyze/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-checklist/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-clarify/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-constitution/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-implement/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-plan/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-specify/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-tasks/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.agent/skills/speckit-taskstoissues/SKILL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.docguard.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.docguardignore +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/dependabot.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/scripts/patch-catalog.py +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/workflows/ci.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/workflows/release.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/workflows/supply-chain.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.github/workflows/sync-speckit-catalog.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.gitignore +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.jules/bolt.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.jules/palette.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.jules/sentinel.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.npmignore +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.npmrc +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/extensions/.cache/catalog-ebf165086500aab1-metadata.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/extensions/.cache/catalog-ebf165086500aab1.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/extensions/.cache/catalog-metadata.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/extensions/.cache/catalog.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/init-options.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/memory/constitution.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/scripts/bash/common.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/scripts/bash/setup-plan.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/templates/agent-file-template.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/templates/checklist-template.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/templates/constitution-template.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/templates/plan-template.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/templates/spec-template.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/.specify/templates/tasks-template.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/AGENTS.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/CODE_OF_CONDUCT.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/COMPARISONS.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/CONTRIBUTING.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/DRIFT-LOG.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/LICENSE +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/PHILOSOPHY.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/ROADMAP.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/SECURITY.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/STANDARD.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/SUPPLY-CHAIN-AUDIT.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/SUPPORT.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/action.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/agents.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/badge.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/ci.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/diagnose.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/diff.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/fix.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/generate.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/guard.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/hooks.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/impact.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/init.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/llms.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/publish.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/score.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/setup.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/sync.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/trace.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/upgrade.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/commands/watch.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/docguard.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/ensure-skills.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/api-doc.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/cdk.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/doc-tools.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/frontend.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/iac.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/integrations.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/memory-plan.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/project-type.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/routes.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/schemas.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/scanners/speckit.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/shared-git.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/shared-ignore.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/shared-source.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/shared.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/api-surface.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/architecture.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/changelog.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/doc-quality.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/docs-coverage.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/docs-diff.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/docs-sync.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/drift.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/environment.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/freshness.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/generated-staleness.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/metadata-sync.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/schema-sync.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/security.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/structure.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/test-spec.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/todo-tracking.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/validators/traceability.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/writers/api-reference.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/writers/fix-memory.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/cli/writers/sections.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/commands/docguard.fix.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/commands/docguard.guard.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/commands/docguard.review.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/commands/docguard.score.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/configs/fastify.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/configs/generic.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/configs/nextjs.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/configs/python.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docguard_cli/__init__.py +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docguard_cli/wrapper.py +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/ai-integration.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/commands.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/configuration.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/doc-sections.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/faq.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/installation.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/profiles.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs/quickstart.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs-canonical/ARCHITECTURE.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs-canonical/CI-RECIPES.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs-canonical/DATA-MODEL.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs-canonical/ENVIRONMENT.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs-canonical/SECURITY.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/docs-canonical/TEST-SPEC.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/01-express-api/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/01-express-api/package.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/01-express-api/server.js +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/02-python-flask/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/02-python-flask/app.py +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/02-python-flask/docs-canonical/ARCHITECTURE.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/02-python-flask/requirements.txt +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/CHANGELOG.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/docs-canonical/ARCHITECTURE.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/docs-canonical/TEST-SPEC.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/package.json +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/src/index.js +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/03-spec-kit-project/tests/basic.test.js +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/examples/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/LICENSE +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/diagnose.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/fix.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/generate.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/guard.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/init.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/score.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/sync.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/commands/trace.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/scripts/bash/common.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/scripts/bash/docguard-check-docs.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/scripts/bash/docguard-init-doc.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/scripts/bash/docguard-suggest-fix.sh +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/templates/extensions.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/templates/github-workflows/docguard-autofix.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/extensions/spec-kit-docguard/templates/github-workflows/docguard-guard.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/pr_description.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/001-fix-ignore-validators/plan.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/001-fix-ignore-validators/spec.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/001-fix-ignore-validators/tasks.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/002-fix-test-discovery/plan.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/002-fix-test-discovery/spec.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/002-fix-test-discovery/tasks.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/003-v011-false-positives/plan.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/003-v011-false-positives/spec.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/specs/003-v011-false-positives/tasks.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/ADR.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/AGENTS.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/ARCHITECTURE.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/CHANGELOG.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/CURRENT-STATE.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/DATA-MODEL.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/DEPLOYMENT.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/DRIFT-LOG.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/ENVIRONMENT.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/KNOWN-GOTCHAS.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/REQUIREMENTS.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/ROADMAP.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/RUNBOOKS.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/SECURITY.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/TEST-SPEC.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/TROUBLESHOOTING.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/VENDOR-BUGS.md.template +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/ci/github-actions.yml +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/commands/docguard.fix.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/commands/docguard.guard.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/commands/docguard.init.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/commands/docguard.review.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/templates/commands/docguard.update.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/test-draft.js +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/test-metrics.js +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/api-doc.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/api-surface.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/api-write.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/architecture.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/backup-failure.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/cdk-detection.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/changed-only-scoping.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/changed-only.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/changelog.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/commands.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/cross-reference.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/doc-quality.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/docguardignore.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/docs-coverage.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/docs-diff.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/docs-sync.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/drift.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/environment.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/fix-memory.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/fix-suppression.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/fixture-projects.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/freshness.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/frontend-deep.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/frontend.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/generated-staleness.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/guard-classify.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/guard-no-throw.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/hooks.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/i18n.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/impact.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/integrations.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/mechanical.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/memory-plan.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/metadata-sync.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/metrics-consistency.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/monorepo-scanning.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/multi-spec.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/patch-0.11.2.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/profile-flag.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/project-type.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/regenerate-section.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/routes-multilang.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/schema-sync.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/schemas-multilang.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/schemas.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/sections.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/security.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/severity.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/shared-git.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/shared-source.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/structure.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/sweep-nudge.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/sync-since.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/sync.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/test-spec.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/todo-tracking.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/trace-reverse.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/traceability.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/upgrade-pr.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/tests/upgrade.test.mjs +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/vscode-extension/.vscodeignore +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/vscode-extension/README.md +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/vscode-extension/extension.js +0 -0
- {docguard_cli-0.14.0 → docguard_cli-0.14.1}/vscode-extension/package.json +0 -0
|
@@ -6,10 +6,10 @@ description: AI-driven documentation repair with structured research workflow, t
|
|
|
6
6
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
7
7
|
metadata:
|
|
8
8
|
author: docguard
|
|
9
|
-
version: 0.14.
|
|
9
|
+
version: 0.14.1
|
|
10
10
|
source: extensions/spec-kit-docguard/skills/docguard-fix
|
|
11
11
|
---
|
|
12
|
-
<!-- docguard:version: 0.14.
|
|
12
|
+
<!-- docguard:version: 0.14.1 -->
|
|
13
13
|
|
|
14
14
|
# DocGuard Fix Skill
|
|
15
15
|
|
|
@@ -7,10 +7,10 @@ description: Run DocGuard guard validation against Canonical-Driven Development
|
|
|
7
7
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
8
8
|
metadata:
|
|
9
9
|
author: docguard
|
|
10
|
-
version: 0.14.
|
|
10
|
+
version: 0.14.1
|
|
11
11
|
source: extensions/spec-kit-docguard/skills/docguard-guard
|
|
12
12
|
---
|
|
13
|
-
<!-- docguard:version: 0.14.
|
|
13
|
+
<!-- docguard:version: 0.14.1 -->
|
|
14
14
|
|
|
15
15
|
# DocGuard Guard Skill
|
|
16
16
|
|
|
@@ -6,10 +6,10 @@ description: Cross-document consistency analysis and quality assessment. Perform
|
|
|
6
6
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
7
7
|
metadata:
|
|
8
8
|
author: docguard
|
|
9
|
-
version: 0.14.
|
|
9
|
+
version: 0.14.1
|
|
10
10
|
source: extensions/spec-kit-docguard/skills/docguard-review
|
|
11
11
|
---
|
|
12
|
-
<!-- docguard:version: 0.14.
|
|
12
|
+
<!-- docguard:version: 0.14.1 -->
|
|
13
13
|
|
|
14
14
|
# DocGuard Review Skill
|
|
15
15
|
|
|
@@ -6,10 +6,10 @@ description: CDD maturity assessment with category-aware improvement roadmap. Ru
|
|
|
6
6
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
7
7
|
metadata:
|
|
8
8
|
author: docguard
|
|
9
|
-
version: 0.14.
|
|
9
|
+
version: 0.14.1
|
|
10
10
|
source: extensions/spec-kit-docguard/skills/docguard-score
|
|
11
11
|
---
|
|
12
|
-
<!-- docguard:version: 0.14.
|
|
12
|
+
<!-- docguard:version: 0.14.1 -->
|
|
13
13
|
|
|
14
14
|
# DocGuard Score Skill
|
|
15
15
|
|
|
@@ -4,7 +4,7 @@ description: Keep canonical documentation ALWAYS UP TO DATE. Refreshes code-trut
|
|
|
4
4
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
5
5
|
metadata:
|
|
6
6
|
author: docguard
|
|
7
|
-
version: 0.14.
|
|
7
|
+
version: 0.14.1
|
|
8
8
|
source: extensions/spec-kit-docguard/skills/docguard-sync
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.14.1] - 2026-05-26
|
|
11
|
+
|
|
12
|
+
Patch + small feature release responding to the wu-whatsappinbox v0.12 feedback.
|
|
13
|
+
**492 tests** (was 481, +11). 22 validators.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **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 wu-whatsappinbox. 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 wu-whatsappinbox.**
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **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 wu broken-anchor cases in v0.12.0 were "heading renamed, link not updated" — those are now `fix --write`-resolvable.**
|
|
22
|
+
|
|
23
|
+
### Note to wu — the "still open" suggestions are all already shipped
|
|
24
|
+
|
|
25
|
+
The S-1, S-11, S-12 items in the v0.12 feedback letter all shipped earlier. The user just needs to upgrade:
|
|
26
|
+
|
|
27
|
+
- **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.
|
|
28
|
+
- **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.
|
|
29
|
+
- **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.
|
|
30
|
+
|
|
31
|
+
Run `docguard upgrade --apply` (or `npm i -g docguard-cli@latest`) to pick all of these up.
|
|
32
|
+
|
|
33
|
+
### Internal
|
|
34
|
+
|
|
35
|
+
- **2 new test files**: `tests/metrics-dedup.test.mjs` (4) and `tests/anchor-autofix.test.mjs` (7). **Total: 481 → 492 tests (+11).**
|
|
36
|
+
- **New mechanical fix type**: `replace-anchor`. The APPLIERS registry now lists 6 types.
|
|
37
|
+
- **New helper** in `cli/validators/cross-reference.mjs`: `isUnambiguousSuggestion()` — gates the auto-fix on edit distance ≤ 2 AND single close candidate.
|
|
38
|
+
- No new NPM deps.
|
|
39
|
+
|
|
40
|
+
### Out of scope (deferred to v0.15)
|
|
41
|
+
|
|
42
|
+
Same backlog as v0.14:
|
|
43
|
+
- Generated-Staleness perf optimization (33% of validator time).
|
|
44
|
+
- Shared tree walk.
|
|
45
|
+
- Cross-validator `config.changedFiles` opt-in.
|
|
46
|
+
- `upgrade --pr` battle-test.
|
|
47
|
+
|
|
10
48
|
## [0.14.0] - 2026-05-26
|
|
11
49
|
|
|
12
50
|
Feature release closing the v0.13 backlog (4 features) + 2 quality investments
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docguard-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.1
|
|
4
4
|
Summary: The enforcement tool for Canonical-Driven Development (CDD). Audit, generate, and guard your project documentation. Zero dependencies.
|
|
5
5
|
Project-URL: Homepage, https://github.com/raccioly/docguard
|
|
6
6
|
Project-URL: Documentation, https://github.com/raccioly/docguard#readme
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
30
|
-
import { resolve, join, dirname, basename } from 'node:path';
|
|
30
|
+
import { resolve, join, dirname, basename, relative } from 'node:path';
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Slugify a heading the way GitHub's markdown anchors work.
|
|
@@ -294,6 +294,7 @@ function collectCanonicalDocs(projectDir) {
|
|
|
294
294
|
export function validateCrossReferences(projectDir, _config = {}) {
|
|
295
295
|
const errors = [];
|
|
296
296
|
const warnings = [];
|
|
297
|
+
const fixes = [];
|
|
297
298
|
let passed = 0;
|
|
298
299
|
let total = 0;
|
|
299
300
|
|
|
@@ -364,13 +365,27 @@ export function validateCrossReferences(projectDir, _config = {}) {
|
|
|
364
365
|
if (!matches) {
|
|
365
366
|
const where = targetPath === docPath ? 'same doc' : basename(targetPath);
|
|
366
367
|
// S-12: suggest the closest matching anchor when there's a near-miss.
|
|
367
|
-
// Three of five wu user-fixes were "heading renamed, link not updated"
|
|
368
|
-
// — a suggested-slug hint makes those deterministic-fixable.
|
|
369
368
|
const suggestion = anchors ? suggestAnchor(normalizedAnchor, anchors) : null;
|
|
370
369
|
const hint = suggestion ? ` (did you mean #${suggestion}?)` : '';
|
|
370
|
+
// v0.14.1-S12+: when the suggestion is HIGH-CONFIDENCE — unambiguous
|
|
371
|
+
// and very close (edit distance <= 2) — emit a mechanical fix so
|
|
372
|
+
// `docguard fix --write` resolves it without AI. Other near-misses
|
|
373
|
+
// still get the hint but no fix (the user needs to verify intent).
|
|
374
|
+
const isHighConfidence = suggestion && isUnambiguousSuggestion(normalizedAnchor, suggestion, anchors);
|
|
371
375
|
warnings.push(
|
|
372
|
-
`${docName}:${ref.line} — broken anchor: "#${ref.anchor}" in ${where} doesn't match any heading${hint}`
|
|
376
|
+
`${docName}:${ref.line} — broken anchor: "#${ref.anchor}" in ${where} doesn't match any heading${hint}` +
|
|
377
|
+
(isHighConfidence ? ' [auto-fixable]' : '')
|
|
373
378
|
);
|
|
379
|
+
if (isHighConfidence) {
|
|
380
|
+
fixes.push({
|
|
381
|
+
type: 'replace-anchor',
|
|
382
|
+
doc: relative(projectDir, docPath),
|
|
383
|
+
line: ref.line,
|
|
384
|
+
from: ref.anchor,
|
|
385
|
+
to: suggestion,
|
|
386
|
+
summary: `${docName}:${ref.line} #${ref.anchor} → #${suggestion}`,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
374
389
|
continue;
|
|
375
390
|
}
|
|
376
391
|
}
|
|
@@ -379,5 +394,28 @@ export function validateCrossReferences(projectDir, _config = {}) {
|
|
|
379
394
|
}
|
|
380
395
|
}
|
|
381
396
|
|
|
382
|
-
return { errors, warnings, passed, total };
|
|
397
|
+
return { errors, warnings, passed, total, fixes };
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* v0.14.1-S12+ — is the suggested anchor an unambiguous, high-confidence
|
|
402
|
+
* match? Two criteria, both must hold:
|
|
403
|
+
* 1. Edit distance between the broken anchor and the suggestion is <= 2
|
|
404
|
+
* (catches typos and minor renames, refuses major slug rewrites).
|
|
405
|
+
* 2. The suggestion is the ONLY anchor that close — no other anchor
|
|
406
|
+
* within distance <= 2. Avoids fixing to the wrong candidate when
|
|
407
|
+
* multiple are similar.
|
|
408
|
+
*/
|
|
409
|
+
function isUnambiguousSuggestion(broken, suggestion, anchors) {
|
|
410
|
+
if (!broken || !suggestion || !anchors) return false;
|
|
411
|
+
const sugDist = editDistance(broken, suggestion);
|
|
412
|
+
if (sugDist > 2) return false;
|
|
413
|
+
// Count other anchors that are also within the same tight budget.
|
|
414
|
+
let closeCandidates = 0;
|
|
415
|
+
for (const a of anchors) {
|
|
416
|
+
if (a === suggestion) continue;
|
|
417
|
+
if (editDistance(broken, a) <= 2) closeCandidates++;
|
|
418
|
+
if (closeCandidates > 0) return false; // ambiguous
|
|
419
|
+
}
|
|
420
|
+
return true;
|
|
383
421
|
}
|
|
@@ -64,6 +64,14 @@ export function validateMetricsConsistency(projectDir, config, guardResults) {
|
|
|
64
64
|
{ key: 'validators', regex: /(?<!\d\/)\b(\d{2,})\s+validators?\b/gi, label: 'validators' },
|
|
65
65
|
];
|
|
66
66
|
|
|
67
|
+
// v0.14.1-N1: dedup by (file, label, found) — a file that mentions the
|
|
68
|
+
// stale number multiple times produces ONE warning, not one per occurrence.
|
|
69
|
+
// The replace-count applier already uses replace-all semantics, so a single
|
|
70
|
+
// fix per (file, label) is sufficient. Previously: "X.md" appearing 2× with
|
|
71
|
+
// the same drift would generate 2 warnings + 2 fixes (the second a no-op).
|
|
72
|
+
const reportedDrift = new Set(); // key: `${relPath}|${label}|${found}`
|
|
73
|
+
const reportedPass = new Set(); // key: `${relPath}|${label}` — only count one pass per (file, label)
|
|
74
|
+
|
|
67
75
|
for (const mdFile of mdFiles) {
|
|
68
76
|
const relPath = relative(projectDir, mdFile);
|
|
69
77
|
// Skip changelog (historical numbers are fine by definition)
|
|
@@ -79,16 +87,32 @@ export function validateMetricsConsistency(projectDir, config, guardResults) {
|
|
|
79
87
|
|
|
80
88
|
regex.lastIndex = 0;
|
|
81
89
|
let match;
|
|
90
|
+
// Collect distinct (found-value) instances within THIS file first,
|
|
91
|
+
// then emit ONE warning per distinct value. A file that says "20" on
|
|
92
|
+
// line 5 and "20" on line 50 is the same drift; "20" on line 5 and
|
|
93
|
+
// "19" on line 50 are two distinct drifts.
|
|
94
|
+
const distinctFoundInFile = new Set();
|
|
82
95
|
while ((match = regex.exec(content)) !== null) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
distinctFoundInFile.add(parseInt(match[1], 10));
|
|
97
|
+
}
|
|
98
|
+
if (distinctFoundInFile.size === 0) continue;
|
|
99
|
+
|
|
100
|
+
for (const found of distinctFoundInFile) {
|
|
101
|
+
if (found > 0 && found !== actuals[key]) {
|
|
102
|
+
const driftKey = `${relPath}|${label}|${found}`;
|
|
103
|
+
if (reportedDrift.has(driftKey)) continue;
|
|
104
|
+
reportedDrift.add(driftKey);
|
|
105
|
+
total++;
|
|
86
106
|
warnings.push(
|
|
87
107
|
`${relPath} says "${found} ${label}" but actual count is ${actuals[key]}. Fix with \`docguard fix --write\``
|
|
88
108
|
);
|
|
89
|
-
// Deterministic, surgical token replacement — safe to auto-apply.
|
|
90
109
|
fixes.push({ type: 'replace-count', file: relPath, label, found, actual: actuals[key] });
|
|
91
110
|
} else {
|
|
111
|
+
// Matches the actual count — one pass per (file, label), not per occurrence.
|
|
112
|
+
const passKey = `${relPath}|${label}`;
|
|
113
|
+
if (reportedPass.has(passKey)) continue;
|
|
114
|
+
reportedPass.add(passKey);
|
|
115
|
+
total++;
|
|
92
116
|
passed++;
|
|
93
117
|
}
|
|
94
118
|
}
|
|
@@ -143,12 +143,45 @@ function applyRegenerateSection(projectDir, fix) {
|
|
|
143
143
|
return { applied: true, detail: `${fix.doc}: regenerated § ${fix.sectionId}` };
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* v0.14.1-S12+ — replace-anchor: rewrite a broken markdown anchor with a
|
|
148
|
+
* high-confidence suggested slug. Emitted by Cross-Reference when its
|
|
149
|
+
* fuzzy match is unambiguous (edit distance <= 2, no other close candidates).
|
|
150
|
+
*
|
|
151
|
+
* fix shape: { type: 'replace-anchor', doc, from, to, line?, summary? }
|
|
152
|
+
*
|
|
153
|
+
* Bounded: only rewrites occurrences of `](#${from})` and `](#X${from})`-like
|
|
154
|
+
* forms — won't touch the broken slug if it happens to appear as plain text.
|
|
155
|
+
* Idempotent: if no occurrence is found (already fixed), no-op.
|
|
156
|
+
*/
|
|
157
|
+
function applyReplaceAnchor(projectDir, fix) {
|
|
158
|
+
if (!fix.doc || !fix.from || !fix.to) {
|
|
159
|
+
return { applied: false, skipped: 'replace-anchor needs doc, from, to' };
|
|
160
|
+
}
|
|
161
|
+
const full = resolve(projectDir, fix.doc);
|
|
162
|
+
if (!existsSync(full)) return { applied: false, skipped: `doc not found: ${fix.doc}` };
|
|
163
|
+
const content = readFileSync(full, 'utf-8');
|
|
164
|
+
|
|
165
|
+
// Match an anchor inside a markdown link: `](#from)` OR `](path#from)`.
|
|
166
|
+
// Use a regex that captures the prefix and suffix so we only touch the
|
|
167
|
+
// anchor part — leaving the link text and path intact.
|
|
168
|
+
const fromEsc = esc(fix.from);
|
|
169
|
+
const re = new RegExp(`(\\]\\([^)]*#)${fromEsc}([)\\s])`, 'g');
|
|
170
|
+
const next = content.replace(re, `$1${fix.to}$2`);
|
|
171
|
+
if (next === content) {
|
|
172
|
+
return { applied: false, skipped: `${fix.doc}: anchor #${fix.from} not found (already fixed?)` };
|
|
173
|
+
}
|
|
174
|
+
writeFileSync(full, next, 'utf-8');
|
|
175
|
+
return { applied: true, detail: `${fix.doc}: #${fix.from} → #${fix.to}` };
|
|
176
|
+
}
|
|
177
|
+
|
|
146
178
|
const APPLIERS = {
|
|
147
179
|
'replace-count': applyReplaceCount,
|
|
148
180
|
'replace-version': applyReplaceVersion,
|
|
149
181
|
'insert-changelog-unreleased': applyInsertChangelogUnreleased,
|
|
150
182
|
'remove-endpoint': applyRemoveEndpoint,
|
|
151
183
|
'regenerate-section': applyRegenerateSection,
|
|
184
|
+
'replace-anchor': applyReplaceAnchor,
|
|
152
185
|
};
|
|
153
186
|
|
|
154
187
|
export const MECHANICAL_FIX_TYPES = Object.keys(APPLIERS);
|
|
@@ -3,7 +3,7 @@ schema_version: "1.0"
|
|
|
3
3
|
extension:
|
|
4
4
|
id: "docguard"
|
|
5
5
|
name: "DocGuard — CDD Enforcement"
|
|
6
|
-
version: "0.14.
|
|
6
|
+
version: "0.14.1"
|
|
7
7
|
description: "Canonical-Driven Development enforcement as a true spec-kit extension. LLM-first design with 19 automated validators, 4 AI behavior skills, spec-kit skill chaining, and workflow hooks. Zero NPM runtime dependencies."
|
|
8
8
|
author: "Ricardo Accioly"
|
|
9
9
|
repository: "https://github.com/raccioly/docguard"
|
|
@@ -6,10 +6,10 @@ description: AI-driven documentation repair with structured research workflow, t
|
|
|
6
6
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
7
7
|
metadata:
|
|
8
8
|
author: docguard
|
|
9
|
-
version: 0.14.
|
|
9
|
+
version: 0.14.1
|
|
10
10
|
source: extensions/spec-kit-docguard/skills/docguard-fix
|
|
11
11
|
---
|
|
12
|
-
<!-- docguard:version: 0.14.
|
|
12
|
+
<!-- docguard:version: 0.14.1 -->
|
|
13
13
|
|
|
14
14
|
# DocGuard Fix Skill
|
|
15
15
|
|
|
@@ -7,10 +7,10 @@ description: Run DocGuard guard validation against Canonical-Driven Development
|
|
|
7
7
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
8
8
|
metadata:
|
|
9
9
|
author: docguard
|
|
10
|
-
version: 0.14.
|
|
10
|
+
version: 0.14.1
|
|
11
11
|
source: extensions/spec-kit-docguard/skills/docguard-guard
|
|
12
12
|
---
|
|
13
|
-
<!-- docguard:version: 0.14.
|
|
13
|
+
<!-- docguard:version: 0.14.1 -->
|
|
14
14
|
|
|
15
15
|
# DocGuard Guard Skill
|
|
16
16
|
|
|
@@ -6,10 +6,10 @@ description: Cross-document consistency analysis and quality assessment. Perform
|
|
|
6
6
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
7
7
|
metadata:
|
|
8
8
|
author: docguard
|
|
9
|
-
version: 0.14.
|
|
9
|
+
version: 0.14.1
|
|
10
10
|
source: extensions/spec-kit-docguard/skills/docguard-review
|
|
11
11
|
---
|
|
12
|
-
<!-- docguard:version: 0.14.
|
|
12
|
+
<!-- docguard:version: 0.14.1 -->
|
|
13
13
|
|
|
14
14
|
# DocGuard Review Skill
|
|
15
15
|
|
|
@@ -6,10 +6,10 @@ description: CDD maturity assessment with category-aware improvement roadmap. Ru
|
|
|
6
6
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
7
7
|
metadata:
|
|
8
8
|
author: docguard
|
|
9
|
-
version: 0.14.
|
|
9
|
+
version: 0.14.1
|
|
10
10
|
source: extensions/spec-kit-docguard/skills/docguard-score
|
|
11
11
|
---
|
|
12
|
-
<!-- docguard:version: 0.14.
|
|
12
|
+
<!-- docguard:version: 0.14.1 -->
|
|
13
13
|
|
|
14
14
|
# DocGuard Score Skill
|
|
15
15
|
|
|
@@ -4,7 +4,7 @@ description: Keep canonical documentation ALWAYS UP TO DATE. Refreshes code-trut
|
|
|
4
4
|
compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
|
|
5
5
|
metadata:
|
|
6
6
|
author: docguard
|
|
7
|
-
version: 0.14.
|
|
7
|
+
version: 0.14.1
|
|
8
8
|
source: extensions/spec-kit-docguard/skills/docguard-sync
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "docguard-cli"
|
|
7
|
-
version = "0.14.
|
|
7
|
+
version = "0.14.1"
|
|
8
8
|
description = "The enforcement tool for Canonical-Driven Development (CDD). Audit, generate, and guard your project documentation. Zero dependencies."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.14.1-S12+ — high-confidence anchor matches auto-fix via `fix --write`.
|
|
3
|
+
*
|
|
4
|
+
* @req SC-S12X-001 — Cross-Reference emits a replace-anchor fix for unambiguous matches
|
|
5
|
+
* @req SC-S12X-002 — NO fix emitted when multiple anchors are equally close
|
|
6
|
+
* @req SC-S12X-003 — NO fix emitted when the only candidate is far (distance > 2)
|
|
7
|
+
* @req SC-S12X-004 — replace-anchor applier rewrites only the anchor inside link form
|
|
8
|
+
* @req SC-S12X-005 — replace-anchor is idempotent (no double-apply)
|
|
9
|
+
* @req SC-S12X-006 — applier won't touch raw-text occurrences of the slug
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, afterEach } from 'node:test';
|
|
12
|
+
import { strict as assert } from 'node:assert';
|
|
13
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'node:fs';
|
|
14
|
+
import { join, resolve } from 'node:path';
|
|
15
|
+
import { tmpdir } from 'node:os';
|
|
16
|
+
|
|
17
|
+
import { validateCrossReferences } from '../cli/validators/cross-reference.mjs';
|
|
18
|
+
import { applyMechanicalFix, MECHANICAL_FIX_TYPES } from '../cli/writers/mechanical.mjs';
|
|
19
|
+
|
|
20
|
+
function makeRepo(files) {
|
|
21
|
+
const dir = mkdtempSync(join(tmpdir(), 'docguard-anchor-fix-'));
|
|
22
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
23
|
+
const full = join(dir, rel);
|
|
24
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
25
|
+
writeFileSync(full, content);
|
|
26
|
+
}
|
|
27
|
+
return dir;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('replace-anchor is registered', () => {
|
|
31
|
+
it('appears in MECHANICAL_FIX_TYPES', () => {
|
|
32
|
+
assert.ok(MECHANICAL_FIX_TYPES.includes('replace-anchor'));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('Cross-Reference emits replace-anchor for high-confidence matches', () => {
|
|
37
|
+
let dir;
|
|
38
|
+
afterEach(() => { if (dir) rmSync(dir, { recursive: true, force: true }); });
|
|
39
|
+
|
|
40
|
+
it('typo: single-char edit distance produces an auto-fix', () => {
|
|
41
|
+
dir = makeRepo({
|
|
42
|
+
'docs-canonical/ARCHITECTURE.md':
|
|
43
|
+
'# A\n\nSee [setup](#authentication).\n\n## Authenticatio\nstub\n',
|
|
44
|
+
// Heading "Authenticatio" slugifies to `authenticatio`. Link says `authentication` (1 char extra). Distance = 1.
|
|
45
|
+
});
|
|
46
|
+
const r = validateCrossReferences(dir, {});
|
|
47
|
+
assert.ok(Array.isArray(r.fixes));
|
|
48
|
+
const fix = r.fixes.find(f => f.type === 'replace-anchor');
|
|
49
|
+
assert.ok(fix, `expected a replace-anchor fix; warnings: ${r.warnings.join(' | ')}`);
|
|
50
|
+
assert.equal(fix.from, 'authentication');
|
|
51
|
+
assert.equal(fix.to, 'authenticatio');
|
|
52
|
+
// The warning should mark it as auto-fixable so the user sees the hint
|
|
53
|
+
assert.ok(r.warnings[0].includes('[auto-fixable]'),
|
|
54
|
+
'high-confidence warning should be tagged [auto-fixable]');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('does NOT emit a fix when match distance > 2 (low confidence)', () => {
|
|
58
|
+
dir = makeRepo({
|
|
59
|
+
'docs-canonical/ARCHITECTURE.md':
|
|
60
|
+
'# A\n\nSee [foo](#totally-different-name).\n\n## Setup\nstub\n',
|
|
61
|
+
});
|
|
62
|
+
const r = validateCrossReferences(dir, {});
|
|
63
|
+
// Either no suggestion at all, or no high-confidence fix
|
|
64
|
+
assert.ok(
|
|
65
|
+
!r.fixes.some(f => f.type === 'replace-anchor'),
|
|
66
|
+
'low-confidence match must NOT produce a fix'
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('does NOT emit a fix when multiple anchors are equally close (ambiguous)', () => {
|
|
71
|
+
dir = makeRepo({
|
|
72
|
+
'docs-canonical/ARCHITECTURE.md':
|
|
73
|
+
'# A\n\nSee [setup](#config).\n\n' +
|
|
74
|
+
'## configg\nstub\n' + // distance 1 from "config"
|
|
75
|
+
'## configs\n' + // also distance 1 from "config"
|
|
76
|
+
'stub\n',
|
|
77
|
+
});
|
|
78
|
+
const r = validateCrossReferences(dir, {});
|
|
79
|
+
assert.ok(
|
|
80
|
+
!r.fixes.some(f => f.type === 'replace-anchor'),
|
|
81
|
+
'ambiguous match (two close candidates) must NOT auto-fix'
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('applyReplaceAnchor — mechanical', () => {
|
|
87
|
+
let dir;
|
|
88
|
+
afterEach(() => { if (dir) rmSync(dir, { recursive: true, force: true }); });
|
|
89
|
+
|
|
90
|
+
it('rewrites the anchor inside a markdown link', () => {
|
|
91
|
+
dir = makeRepo({
|
|
92
|
+
'docs-canonical/X.md':
|
|
93
|
+
'# X\n\nSee [setup](#old-anchor).\n\n## new-anchor\nstub\n',
|
|
94
|
+
});
|
|
95
|
+
const r = applyMechanicalFix(dir, {
|
|
96
|
+
type: 'replace-anchor',
|
|
97
|
+
doc: 'docs-canonical/X.md',
|
|
98
|
+
from: 'old-anchor',
|
|
99
|
+
to: 'new-anchor',
|
|
100
|
+
}, { recordHistory: false });
|
|
101
|
+
assert.equal(r.applied, true);
|
|
102
|
+
const result = readFileSync(resolve(dir, 'docs-canonical/X.md'), 'utf-8');
|
|
103
|
+
assert.match(result, /\(#new-anchor\)/);
|
|
104
|
+
assert.doesNotMatch(result, /\(#old-anchor\)/);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('is idempotent: second apply is a no-op (skipped)', () => {
|
|
108
|
+
dir = makeRepo({
|
|
109
|
+
'docs-canonical/X.md':
|
|
110
|
+
'# X\n\nSee [setup](#new-anchor).\n\n## new-anchor\nstub\n',
|
|
111
|
+
});
|
|
112
|
+
const r = applyMechanicalFix(dir, {
|
|
113
|
+
type: 'replace-anchor',
|
|
114
|
+
doc: 'docs-canonical/X.md',
|
|
115
|
+
from: 'old-anchor',
|
|
116
|
+
to: 'new-anchor',
|
|
117
|
+
}, { recordHistory: false });
|
|
118
|
+
// No #old-anchor in file → applier should report skipped
|
|
119
|
+
assert.equal(r.applied, false);
|
|
120
|
+
assert.match(r.skipped, /not found/);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('does NOT touch plain-text occurrences of the slug', () => {
|
|
124
|
+
dir = makeRepo({
|
|
125
|
+
'docs-canonical/X.md':
|
|
126
|
+
'# X\n\n' +
|
|
127
|
+
'The slug `old-anchor` appears in prose here.\n' +
|
|
128
|
+
'See [setup](#old-anchor).\n' +
|
|
129
|
+
'## new-anchor\n',
|
|
130
|
+
});
|
|
131
|
+
const r = applyMechanicalFix(dir, {
|
|
132
|
+
type: 'replace-anchor',
|
|
133
|
+
doc: 'docs-canonical/X.md',
|
|
134
|
+
from: 'old-anchor',
|
|
135
|
+
to: 'new-anchor',
|
|
136
|
+
}, { recordHistory: false });
|
|
137
|
+
assert.equal(r.applied, true);
|
|
138
|
+
const result = readFileSync(resolve(dir, 'docs-canonical/X.md'), 'utf-8');
|
|
139
|
+
// The plain-text backticked `old-anchor` must STAY
|
|
140
|
+
assert.match(result, /`old-anchor` appears in prose/);
|
|
141
|
+
// The link anchor MUST be updated
|
|
142
|
+
assert.match(result, /\(#new-anchor\)/);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.14.1-N1 — Metrics-Consistency dedup.
|
|
3
|
+
*
|
|
4
|
+
* Reported by wu-whatsappinbox: a file that mentions a stale validator/check
|
|
5
|
+
* count multiple times (e.g. once in a heading, once in a body table) was
|
|
6
|
+
* producing one warning per occurrence — "4 warnings for 2 files".
|
|
7
|
+
*
|
|
8
|
+
* @req SC-N1-001 — same drift in one file → one warning (not one per match)
|
|
9
|
+
* @req SC-N1-002 — distinct drift values in one file are separate warnings
|
|
10
|
+
* @req SC-N1-003 — replace-count fix is emitted exactly once per (file, label)
|
|
11
|
+
* @req SC-N1-004 — passed count uses unique-per-(file,label), not per-match
|
|
12
|
+
*/
|
|
13
|
+
import { describe, it, afterEach } from 'node:test';
|
|
14
|
+
import { strict as assert } from 'node:assert';
|
|
15
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { tmpdir } from 'node:os';
|
|
18
|
+
|
|
19
|
+
import { validateMetricsConsistency } from '../cli/validators/metrics-consistency.mjs';
|
|
20
|
+
|
|
21
|
+
function makeRepo(files) {
|
|
22
|
+
const dir = mkdtempSync(join(tmpdir(), 'docguard-metrics-dedup-'));
|
|
23
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
24
|
+
const full = join(dir, rel);
|
|
25
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
26
|
+
writeFileSync(full, content);
|
|
27
|
+
}
|
|
28
|
+
return dir;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Simulate guard results so Metrics-Consistency knows what the "actual" count is.
|
|
32
|
+
function fakeGuardResults(validatorCount, checkTotal) {
|
|
33
|
+
// Build N validators with checkTotal/N checks each (approx) so totals add up.
|
|
34
|
+
const validators = [];
|
|
35
|
+
const each = Math.floor(checkTotal / validatorCount);
|
|
36
|
+
for (let i = 0; i < validatorCount; i++) {
|
|
37
|
+
validators.push({ status: 'pass', total: each, passed: each });
|
|
38
|
+
}
|
|
39
|
+
// Pad last one to hit the exact target
|
|
40
|
+
validators[validators.length - 1].total += checkTotal - each * validatorCount;
|
|
41
|
+
return validators;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('Metrics-Consistency — dedup per (file, label, found)', () => {
|
|
45
|
+
let dir;
|
|
46
|
+
afterEach(() => { if (dir) rmSync(dir, { recursive: true, force: true }); });
|
|
47
|
+
|
|
48
|
+
it('same drift mentioned twice in one file → ONE warning, not two', () => {
|
|
49
|
+
dir = makeRepo({
|
|
50
|
+
'README.md':
|
|
51
|
+
'# Project\n\n' +
|
|
52
|
+
'## What\n\nDocGuard ships **21 validators** out of the box.\n\n' +
|
|
53
|
+
'## Reference\n\nSee the [21 validators table](#table) below.\n',
|
|
54
|
+
});
|
|
55
|
+
// Actual count is 22 (one more than the doc claims)
|
|
56
|
+
const r = validateMetricsConsistency(dir, { projectName: 't' }, fakeGuardResults(22, 100));
|
|
57
|
+
const driftWarnings = r.warnings.filter(w => /21 validators/.test(w) && /README\.md/.test(w));
|
|
58
|
+
assert.equal(driftWarnings.length, 1,
|
|
59
|
+
`expected 1 warning for README.md, got ${driftWarnings.length}: ${driftWarnings.join(' | ')}`);
|
|
60
|
+
const driftFixes = (r.fixes || []).filter(f => f.file === 'README.md' && f.label === 'validators');
|
|
61
|
+
assert.equal(driftFixes.length, 1,
|
|
62
|
+
`expected 1 replace-count fix for README.md, got ${driftFixes.length}`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('two DIFFERENT stale values in one file produce two warnings', () => {
|
|
66
|
+
dir = makeRepo({
|
|
67
|
+
'README.md':
|
|
68
|
+
'# Project\n\n' +
|
|
69
|
+
'DocGuard says **20 validators** here.\n' +
|
|
70
|
+
'But over here it says **19 validators**.\n',
|
|
71
|
+
});
|
|
72
|
+
const r = validateMetricsConsistency(dir, { projectName: 't' }, fakeGuardResults(22, 100));
|
|
73
|
+
const driftWarnings = r.warnings.filter(w => /README\.md/.test(w) && /validators/.test(w));
|
|
74
|
+
// Two distinct stale values → two warnings (one per value)
|
|
75
|
+
assert.equal(driftWarnings.length, 2);
|
|
76
|
+
const driftFixes = (r.fixes || []).filter(f => f.file === 'README.md' && f.label === 'validators');
|
|
77
|
+
assert.equal(driftFixes.length, 2,
|
|
78
|
+
'two distinct drifts → two fixes (each fixes a different "found" value)');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('same number mentioned twice in correct form → ONE passed credit, not two', () => {
|
|
82
|
+
// The validator counts itself (+1) so 21 fake guards → "actual = 22 validators".
|
|
83
|
+
dir = makeRepo({
|
|
84
|
+
'README.md':
|
|
85
|
+
'# Project\n\n' +
|
|
86
|
+
'22 validators in total.\n' +
|
|
87
|
+
'See the 22 validators table.\n',
|
|
88
|
+
});
|
|
89
|
+
const r = validateMetricsConsistency(dir, { projectName: 't' }, fakeGuardResults(21, 100));
|
|
90
|
+
// README has TWO "22 validators" occurrences but only one pass should be credited.
|
|
91
|
+
assert.equal(r.warnings.filter(w => /README\.md/.test(w)).length, 0,
|
|
92
|
+
'matching number should not produce a warning');
|
|
93
|
+
// Validators-pattern contribution should be exactly 1 pass for README (not 2).
|
|
94
|
+
// We can't assert total directly because other patterns/files also contribute,
|
|
95
|
+
// but we can verify the README-validators key was deduped via the internal state.
|
|
96
|
+
// Workaround: assert total <= 2 (validators pattern + checks pattern at most once each).
|
|
97
|
+
assert.ok(r.total <= 2,
|
|
98
|
+
`README contributes at most 2 totals (validators + checks once each); got total=${r.total}`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('distinct files with the same stale value each get their own warning', () => {
|
|
102
|
+
dir = makeRepo({
|
|
103
|
+
'README.md': '# A\n\n21 validators.\n',
|
|
104
|
+
'AGENTS.md': '# B\n\n21 validators.\n',
|
|
105
|
+
'docs/quickstart.md': '# C\n\n21 validators.\n',
|
|
106
|
+
});
|
|
107
|
+
const r = validateMetricsConsistency(dir, { projectName: 't' }, fakeGuardResults(22, 100));
|
|
108
|
+
const driftWarnings = r.warnings.filter(w => /21 validators/.test(w));
|
|
109
|
+
assert.equal(driftWarnings.length, 3,
|
|
110
|
+
'one warning per FILE that has the drift (3 distinct files = 3 warnings)');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|