@getarbiter/cli 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +713 -0
- package/LICENSE +202 -0
- package/NOTICE +31 -0
- package/PRIVACY.md +111 -0
- package/README.md +237 -0
- package/THIRD_PARTY_LICENSES.md +472 -0
- package/dist/.src-manifest.json +1 -0
- package/dist/capabilities/host-probe.js +3 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +87 -0
- package/dist/commands/adopt-policy.js +3 -0
- package/dist/commands/configure-interactive.js +3 -0
- package/dist/commands/configure.js +5 -0
- package/dist/commands/cross-model-review.js +3 -0
- package/dist/commands/diff.js +20 -0
- package/dist/commands/doc-set.js +3 -0
- package/dist/commands/doctor/clean.js +2 -0
- package/dist/commands/doctor/fail-open-census.js +12 -0
- package/dist/commands/doctor/health.js +11 -0
- package/dist/commands/doctor/prove-gates.js +13 -0
- package/dist/commands/doctor/recover-lock.js +12 -0
- package/dist/commands/doctor/repair-state.js +6 -0
- package/dist/commands/doctor/tool-pin-extract.js +4 -0
- package/dist/commands/doctor/tool-pins.js +9 -0
- package/dist/commands/doctor-interactive.js +2 -0
- package/dist/commands/doctor.js +2 -0
- package/dist/commands/explain.js +19 -0
- package/dist/commands/gate-exec.js +4 -0
- package/dist/commands/gold-audit.js +14 -0
- package/dist/commands/graph.js +5 -0
- package/dist/commands/init/build-arbiter-config.js +1 -0
- package/dist/commands/init/generate.js +42 -0
- package/dist/commands/init/github-setup.js +5 -0
- package/dist/commands/init/maturity-gates.js +10 -0
- package/dist/commands/init/resolve-config.js +3 -0
- package/dist/commands/init/toolchain.js +10 -0
- package/dist/commands/init/types.js +1 -0
- package/dist/commands/init.js +17 -0
- package/dist/commands/method-interactive.js +4 -0
- package/dist/commands/method.js +11 -0
- package/dist/commands/obsidian.js +2 -0
- package/dist/commands/plugin.js +8 -0
- package/dist/commands/pr-merged.js +2 -0
- package/dist/commands/retire-policy.js +3 -0
- package/dist/commands/review-diff.js +3 -0
- package/dist/commands/settings.js +7 -0
- package/dist/commands/ship-config.js +2 -0
- package/dist/commands/ship-profile.js +2 -0
- package/dist/commands/ship-review.js +1 -0
- package/dist/commands/ship-tier.js +2 -0
- package/dist/commands/ship-train.js +2 -0
- package/dist/commands/task-mark.js +2 -0
- package/dist/commands/task-note.js +3 -0
- package/dist/commands/task-record-red.js +2 -0
- package/dist/commands/task-record-tech-debt.js +4 -0
- package/dist/commands/task-ship.js +3 -0
- package/dist/commands/task-state.js +6 -0
- package/dist/commands/task.js +59 -0
- package/dist/commands/update.js +60 -0
- package/dist/commands/upgrade-level-interactive.js +2 -0
- package/dist/commands/upgrade-level.js +7 -0
- package/dist/commands/verify-plan.js +8 -0
- package/dist/commands/verify-tdd.js +2 -0
- package/dist/commands/verify.js +7 -0
- package/dist/commands/wizard/coherence.js +1 -0
- package/dist/commands/worktree-prune.js +4 -0
- package/dist/commands/worktree.js +39 -0
- package/dist/compatibility/cross-language-matrix.json +540 -0
- package/dist/compatibility/index.d.ts +4 -0
- package/dist/compatibility/index.js +2 -0
- package/dist/compatibility/matcher.js +1 -0
- package/dist/compatibility/matrix.json +27 -0
- package/dist/compatibility/parsers.d.ts +38 -0
- package/dist/compatibility/parsers.js +1 -0
- package/dist/compatibility/probe.d.ts +41 -0
- package/dist/compatibility/probe.js +4 -0
- package/dist/compatibility/report.js +2 -0
- package/dist/compatibility/schema.d.ts +80 -0
- package/dist/compatibility/schema.js +1 -0
- package/dist/compatibility/skills-matrix.json +98 -0
- package/dist/compatibility/skills-validator.d.ts +30 -0
- package/dist/compatibility/skills-validator.js +4 -0
- package/dist/compatibility/tooling-proposals.json +5 -0
- package/dist/config/arbiter-ignore.js +3 -0
- package/dist/config/collaboration-mode-defaults.js +1 -0
- package/dist/config/diff.js +1 -0
- package/dist/config/env-overrides.js +3 -0
- package/dist/config/env-registry.js +2 -0
- package/dist/config/levels.js +1 -0
- package/dist/config/migrations/index.js +2 -0
- package/dist/config/migrations/v0-to-v1.js +2 -0
- package/dist/config/migrations/v1-to-v2.js +2 -0
- package/dist/config/migrations/v2-to-v3.js +2 -0
- package/dist/config/migrations/v3-to-v4.js +2 -0
- package/dist/config/override-resolver.js +2 -0
- package/dist/config/resolve-project-config.js +2 -0
- package/dist/config/resolve-project-name.js +2 -0
- package/dist/config/schema.d.ts +480 -0
- package/dist/config/schema.js +1 -0
- package/dist/config/test-pyramid-profiles.js +1 -0
- package/dist/config/thresholds.js +2 -0
- package/dist/conformance/dimensions.js +3 -0
- package/dist/conformance/engine.js +7 -0
- package/dist/conformance/gate-proofs.js +4 -0
- package/dist/conformance/shared.js +2 -0
- package/dist/detectors/axis.js +1 -0
- package/dist/detectors/build.js +2 -0
- package/dist/detectors/existing.js +2 -0
- package/dist/detectors/external-model.js +2 -0
- package/dist/detectors/framework.js +2 -0
- package/dist/detectors/git.js +11 -0
- package/dist/detectors/github.js +2 -0
- package/dist/detectors/lanes.js +5 -0
- package/dist/detectors/language-hooks.js +117 -0
- package/dist/detectors/language.js +2 -0
- package/dist/detectors/package-manager.js +2 -0
- package/dist/detectors/package.js +2 -0
- package/dist/detectors/scaffold-wiring.js +2 -0
- package/dist/detectors/workflow-collision.js +4 -0
- package/dist/evidence/gate-binding.js +4 -0
- package/dist/evidence/git-checks.js +3 -0
- package/dist/evidence/load.js +2 -0
- package/dist/evidence/provenance.js +2 -0
- package/dist/evidence/summary.js +2 -0
- package/dist/evidence/tdd-reexecute.js +2 -0
- package/dist/evidence/tdd.js +4 -0
- package/dist/experimental/index.js +2 -0
- package/dist/experimental/parse-argv.js +2 -0
- package/dist/experimental/registry.js +2 -0
- package/dist/generators/agents-claude.js +2 -0
- package/dist/generators/agents-md.js +2 -0
- package/dist/generators/anti-drift-validators.js +3 -0
- package/dist/generators/anti-proforma.js +2 -0
- package/dist/generators/api-e2e.js +2 -0
- package/dist/generators/api-middleware.js +2 -0
- package/dist/generators/archunit.js +2 -0
- package/dist/generators/audit-toolchain.js +2 -0
- package/dist/generators/auth.js +2 -0
- package/dist/generators/behavioral-tests.js +2 -0
- package/dist/generators/boundaries.js +2 -0
- package/dist/generators/check-all.js +2 -0
- package/dist/generators/check-stack-conformity.js +2 -0
- package/dist/generators/ci-five-lane.js +2 -0
- package/dist/generators/ci-tier.js +2 -0
- package/dist/generators/claude.js +3 -0
- package/dist/generators/codex-hooks.js +2 -0
- package/dist/generators/codex-known-limitations.js +2 -0
- package/dist/generators/codex.js +15 -0
- package/dist/generators/commit-footer.js +2 -0
- package/dist/generators/compliance-menu.js +2 -0
- package/dist/generators/compliance.js +2 -0
- package/dist/generators/conformance.js +2 -0
- package/dist/generators/contract-testing.js +2 -0
- package/dist/generators/coverage.js +2 -0
- package/dist/generators/debt-gates.js +24 -0
- package/dist/generators/debt-ratchet.js +2 -0
- package/dist/generators/derived-class.js +2 -0
- package/dist/generators/doc-set.js +4 -0
- package/dist/generators/docs.js +2 -0
- package/dist/generators/duplication.js +2 -0
- package/dist/generators/e2e-constitution.js +2 -0
- package/dist/generators/env-template.js +2 -0
- package/dist/generators/evidence-retention.js +2 -0
- package/dist/generators/feature-matrix.js +2 -0
- package/dist/generators/frontend-governance.js +2 -0
- package/dist/generators/frontend-quality.js +2 -0
- package/dist/generators/gap.js +2 -0
- package/dist/generators/gdpr.js +2 -0
- package/dist/generators/githooks.js +2 -0
- package/dist/generators/github-setup.js +2 -0
- package/dist/generators/github.js +2 -0
- package/dist/generators/gitignore.js +2 -0
- package/dist/generators/global-invariants.js +3 -0
- package/dist/generators/go-boundaries.js +2 -0
- package/dist/generators/gold-kit.js +2 -0
- package/dist/generators/infra.js +2 -0
- package/dist/generators/integration-testing.js +7 -0
- package/dist/generators/iso27001.js +2 -0
- package/dist/generators/iso9001.js +2 -0
- package/dist/generators/labels.js +2 -0
- package/dist/generators/local-wrapper.js +2 -0
- package/dist/generators/modulith.js +2 -0
- package/dist/generators/mutation.js +2 -0
- package/dist/generators/observability.js +2 -0
- package/dist/generators/operations.js +2 -0
- package/dist/generators/perf-k6.js +2 -0
- package/dist/generators/pharma.js +2 -0
- package/dist/generators/playwright-python.js +2 -0
- package/dist/generators/playwright-ts.js +2 -0
- package/dist/generators/pr-tooling.js +2 -0
- package/dist/generators/python-boundaries.js +2 -0
- package/dist/generators/quality.js +2 -0
- package/dist/generators/registry.js +2 -0
- package/dist/generators/regulated.js +2 -0
- package/dist/generators/resilience.js +2 -0
- package/dist/generators/risk-register.js +2 -0
- package/dist/generators/root.js +2 -0
- package/dist/generators/rust-boundaries.js +2 -0
- package/dist/generators/safety-class.js +2 -0
- package/dist/generators/security.js +2 -0
- package/dist/generators/seed.js +2 -0
- package/dist/generators/self-validation.js +2 -0
- package/dist/generators/ship-driver.js +2 -0
- package/dist/generators/skill-names.json +17 -0
- package/dist/generators/skills.js +2 -0
- package/dist/generators/smoke-journeys.js +2 -0
- package/dist/generators/solo-exception.js +2 -0
- package/dist/generators/ssot.js +2 -0
- package/dist/generators/stride-enforcement.js +2 -0
- package/dist/generators/suppressions.js +2 -0
- package/dist/generators/test-pyramid-manifest.js +3 -0
- package/dist/generators/test-taxonomy.js +2 -0
- package/dist/generators/wiki.js +2 -0
- package/dist/github/branch-protection.js +2 -0
- package/dist/github/classify-gh-error.js +2 -0
- package/dist/github/labels.js +2 -0
- package/dist/github/project-board.js +2 -0
- package/dist/graph/builders/adr.js +4 -0
- package/dist/graph/builders/ast.js +3 -0
- package/dist/graph/builders/canon.js +2 -0
- package/dist/graph/builders/evidence.js +2 -0
- package/dist/graph/builders/inv.js +1 -0
- package/dist/graph/builders/req.js +3 -0
- package/dist/graph/builders/test-nodes.js +3 -0
- package/dist/graph/builders/utils.js +2 -0
- package/dist/graph/load.js +2 -0
- package/dist/graph/model.js +2 -0
- package/dist/graph/query.js +3 -0
- package/dist/graph/store.js +1 -0
- package/dist/i18n/en.json +293 -0
- package/dist/i18n/index.js +4 -0
- package/dist/i18n/types.js +2 -0
- package/dist/integrations/companions.js +2 -0
- package/dist/integrations/external-review.js +10 -0
- package/dist/integrations/plugin-schema.js +2 -0
- package/dist/integrations/skill-detector.js +7 -0
- package/dist/integrations/skills-matrix.js +2 -0
- package/dist/integrations/types.d.ts +23 -0
- package/dist/integrations/types.js +2 -0
- package/dist/internal/cli-deprecation-registry.js +2 -0
- package/dist/internal/deprecate.js +3 -0
- package/dist/internal/experimental-warn.js +3 -0
- package/dist/invariants/catalog.d.ts +2 -0
- package/dist/invariants/catalog.js +1 -0
- package/dist/invariants/filter.d.ts +28 -0
- package/dist/invariants/filter.js +1 -0
- package/dist/invariants/index.d.ts +4 -0
- package/dist/invariants/index.js +2 -0
- package/dist/invariants/tiers.js +1 -0
- package/dist/invariants/types.d.ts +1 -0
- package/dist/invariants/types.js +1 -0
- package/dist/kit/applicability.js +3 -0
- package/dist/kit/audit-report.js +3 -0
- package/dist/kit/brownfield-detect.js +4 -0
- package/dist/kit/canonical-mapping.json +1 -0
- package/dist/kit/catalog.js +2 -0
- package/dist/kit/catalog.json +1 -0
- package/dist/kit/derived.json +1 -0
- package/dist/kit/emit-issues.js +8 -0
- package/dist/kit/measure.js +5 -0
- package/dist/kit/redaction.js +3 -0
- package/dist/kit/schema.js +2 -0
- package/dist/kit/taxonomy.js +2 -0
- package/dist/kit/thresholds.d.ts +12 -0
- package/dist/kit/thresholds.js +2 -0
- package/dist/kit/wave-engine.js +1 -0
- package/dist/recipes/loader.js +6 -0
- package/dist/recipes/schema.js +2 -0
- package/dist/risk/classifier.js +2 -0
- package/dist/risk/sha-check.js +2 -0
- package/dist/state/backups.js +2 -0
- package/dist/state/envelope.js +2 -0
- package/dist/state/generated-manifest.js +3 -0
- package/dist/state/manifest-key.js +2 -0
- package/dist/state/migrations/index.js +1 -0
- package/dist/state/migrations/v0-to-v1.js +2 -0
- package/dist/state/retired-renders.js +2 -0
- package/dist/templates/.nvmrc.ejs +1 -0
- package/dist/templates/HANDOFF.template.md +45 -0
- package/dist/templates/__tests__/contract/error-shape.contract.test.ts.ejs +47 -0
- package/dist/templates/agents-md/AGENTS.md.ejs +517 -0
- package/dist/templates/api-e2e/README.md.ejs +33 -0
- package/dist/templates/api-e2e/go-httptest.go.ejs +43 -0
- package/dist/templates/api-e2e/java-restassured.java.ejs +28 -0
- package/dist/templates/api-e2e/kotlin-restassured.kt.ejs +30 -0
- package/dist/templates/api-e2e/manifest.json.ejs +8 -0
- package/dist/templates/api-e2e/postman.collection.json.ejs +30 -0
- package/dist/templates/api-e2e/python-httpx.py.ejs +17 -0
- package/dist/templates/api-e2e/run.sh.ejs +61 -0
- package/dist/templates/api-e2e/ts-supertest.test.ts.ejs +18 -0
- package/dist/templates/archunit/AntiCyclicTest.java.ejs +29 -0
- package/dist/templates/archunit/AntiProformaExempt.java.ejs +35 -0
- package/dist/templates/archunit/AntiProformaTest.java.ejs +104 -0
- package/dist/templates/archunit/ArchitectureTest.java.ejs +87 -0
- package/dist/templates/archunit/DependencyFlowTest.java.ejs +55 -0
- package/dist/templates/archunit/DomainPurityTest.java.ejs +47 -0
- package/dist/templates/archunit/NamingConventionsTest.java.ejs +54 -0
- package/dist/templates/archunit/NoH2ArchTest.java.ejs +30 -0
- package/dist/templates/archunit/NoMockMvcTest.java.ejs +71 -0
- package/dist/templates/archunit/PortsIndependenceTest.java.ejs +55 -0
- package/dist/templates/archunit/RestAssuredArchTest.java.ejs +32 -0
- package/dist/templates/archunit/RestAssuredBaseIT.java.ejs +66 -0
- package/dist/templates/archunit/TestCoverageArchTest.java.ejs +29 -0
- package/dist/templates/archunit/arch-test-deps-maven.md.ejs +42 -0
- package/dist/templates/archunit/arch-test-deps.gradle.ejs +14 -0
- package/dist/templates/audit/gdpr/check-gdpr-controls.mjs.ejs +102 -0
- package/dist/templates/audit/gdpr/controls-to-gates.md.ejs +42 -0
- package/dist/templates/audit/gdpr/data-flow-map.md.ejs +30 -0
- package/dist/templates/audit/gdpr/dpia.md.ejs +45 -0
- package/dist/templates/audit/generic/audit-gate-rules.md.ejs +24 -0
- package/dist/templates/audit/generic/audit-trail-policy.md.ejs +38 -0
- package/dist/templates/audit/iso27001/iso27001-controls-gate-map.md.ejs +60 -0
- package/dist/templates/auth/setup.md.ejs +661 -0
- package/dist/templates/behavioral-tests/ExampleBehavioralTest.java.ejs +67 -0
- package/dist/templates/behavioral-tests/TESTING_POLICY.md.ejs +116 -0
- package/dist/templates/behavioral-tests/bdd/ExampleBddIT.java.ejs +19 -0
- package/dist/templates/behavioral-tests/bdd/ExampleSteps.java.ejs +61 -0
- package/dist/templates/behavioral-tests/bdd/example.feature.ejs +14 -0
- package/dist/templates/behavioral-tests/bdd/example.steps.ts.ejs +37 -0
- package/dist/templates/behavioral-tests/bdd/example_bdd_test.rs.ejs +64 -0
- package/dist/templates/behavioral-tests/bdd/example_test.go.ejs +80 -0
- package/dist/templates/behavioral-tests/bdd/test_example_bdd.py.ejs +47 -0
- package/dist/templates/behavioral-tests/eslint-playwright.json.ejs +10 -0
- package/dist/templates/behavioral-tests/eslint.config.playwright.mjs.ejs +29 -0
- package/dist/templates/behavioral-tests/example.behavioral.test.ts.ejs +47 -0
- package/dist/templates/behavioral-tests/example_behavioral_test.go.ejs +51 -0
- package/dist/templates/behavioral-tests/example_behavioral_test.rs.ejs +47 -0
- package/dist/templates/behavioral-tests/test_example_behavioral.py.ejs +40 -0
- package/dist/templates/boundaries/.eslintrc-boundaries.cjs.ejs +81 -0
- package/dist/templates/boundaries/.eslintrc-frontend-spa.cjs.ejs +79 -0
- package/dist/templates/boundaries/.importlinter.ejs +48 -0
- package/dist/templates/boundaries/check-boundaries-go.mjs.ejs +94 -0
- package/dist/templates/boundaries/check-boundaries-python.mjs.ejs +118 -0
- package/dist/templates/boundaries/check-boundaries-rust.mjs.ejs +111 -0
- package/dist/templates/boundaries/check-boundaries.mjs.ejs +34 -0
- package/dist/templates/boundaries/clippy.toml.ejs +50 -0
- package/dist/templates/boundaries/deny.toml.ejs +56 -0
- package/dist/templates/boundaries/eslint.config.boundaries.mjs.ejs +112 -0
- package/dist/templates/boundaries/eslint.config.frontend-spa.mjs.ejs +93 -0
- package/dist/templates/boundaries/golangci-boundaries.yml.ejs +70 -0
- package/dist/templates/boundaries/ruff-boundaries.toml.ejs +32 -0
- package/dist/templates/claude/CLAUDE.md.ejs +78 -0
- package/dist/templates/claude/agents/agent-write-classes.json +30 -0
- package/dist/templates/claude/agents/bridge-reviewer.md.ejs +68 -0
- package/dist/templates/claude/agents/codebase-scanner.md.ejs +69 -0
- package/dist/templates/claude/agents/context-checker.md.ejs +73 -0
- package/dist/templates/claude/agents/red-team.md.ejs +134 -0
- package/dist/templates/claude/commands/close-gold-gap.md.ejs +43 -0
- package/dist/templates/claude/commands/drain.md.ejs +81 -0
- package/dist/templates/claude/commands/gold-audit.md.ejs +43 -0
- package/dist/templates/claude/commands/impact.md.ejs +39 -0
- package/dist/templates/claude/commands/levelup.md.ejs +61 -0
- package/dist/templates/claude/commands/ship.md.ejs +902 -0
- package/dist/templates/claude/commands/tabletop.md.ejs +46 -0
- package/dist/templates/claude/commands/task.md.ejs +87 -0
- package/dist/templates/claude/commands/wt-close.md.ejs +58 -0
- package/dist/templates/claude/commands/wt-list.md.ejs +48 -0
- package/dist/templates/claude/commands/wt-open.md.ejs +61 -0
- package/dist/templates/claude/commands/wt-prune.md.ejs +38 -0
- package/dist/templates/claude/hooks/check-circular-deps.mjs.ejs +56 -0
- package/dist/templates/claude/hooks/check-no-orphan-todo.mjs.ejs +45 -0
- package/dist/templates/claude/hooks/check-no-pii.mjs.ejs +121 -0
- package/dist/templates/claude/hooks/check-no-placeholders.mjs.ejs +71 -0
- package/dist/templates/claude/hooks/check-no-skipped-tests.mjs +80 -0
- package/dist/templates/claude/hooks/check-no-unused-exports.mjs +62 -0
- package/dist/templates/claude/hooks/closer-mode-guard.mjs.ejs +102 -0
- package/dist/templates/claude/hooks/debug-state-on-failure.mjs.ejs +98 -0
- package/dist/templates/claude/hooks/enforce-gate-before-pr.mjs +142 -0
- package/dist/templates/claude/hooks/enforce-read-only.mjs +28 -0
- package/dist/templates/claude/hooks/exitplanmode-banner.mjs.ejs +43 -0
- package/dist/templates/claude/hooks/guard-done-evidence.mjs.ejs +85 -0
- package/dist/templates/claude/hooks/guard-task-completion.mjs.ejs +56 -0
- package/dist/templates/claude/hooks/hooks.mjs.ejs +127 -0
- package/dist/templates/claude/hooks/lib.mjs.ejs +523 -0
- package/dist/templates/claude/hooks/post-brainstorm-stop.mjs +48 -0
- package/dist/templates/claude/hooks/post-commit-check.mjs.ejs +65 -0
- package/dist/templates/claude/hooks/post-commit-checklists/go/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/go/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/go/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/java/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/java/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/java/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/python/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/python/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/python/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/rust/backend.ejs +5 -0
- package/dist/templates/claude/hooks/post-commit-checklists/rust/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/rust/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/ts/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/ts/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/ts/frontend.ejs +5 -0
- package/dist/templates/claude/hooks/post-edit-dispatch.mjs.ejs +73 -0
- package/dist/templates/claude/hooks/post-subagent-release.mjs +80 -0
- package/dist/templates/claude/hooks/pre-compact.mjs.ejs +79 -0
- package/dist/templates/claude/hooks/pre-edit-plan-anchor.mjs.ejs +225 -0
- package/dist/templates/claude/hooks/pre-edit-ssot-guard.mjs +204 -0
- package/dist/templates/claude/hooks/pre-spawn-worktree-guard.mjs +129 -0
- package/dist/templates/claude/hooks/skill-forced-eval.mjs.ejs +281 -0
- package/dist/templates/claude/hooks/stop-dangerous.mjs +86 -0
- package/dist/templates/claude/hooks/stop-evidence-guard.mjs.ejs +245 -0
- package/dist/templates/claude/hooks/stop-finding-loss.mjs.ejs +168 -0
- package/dist/templates/claude/hooks/wiki-on-commit.mjs.ejs +38 -0
- package/dist/templates/claude/knowledge-map.json.ejs +26 -0
- package/dist/templates/claude/rules/05-agent-lifecycle.md +7 -0
- package/dist/templates/claude/rules/25-todo-folder-policy.md +5 -0
- package/dist/templates/claude/rules/40-context-economy.md +32 -0
- package/dist/templates/claude/rules/45-mcp-fallback.md +25 -0
- package/dist/templates/claude/rules/50-batch-execution.md +75 -0
- package/dist/templates/claude/rules/55-brainstorm-terminal-state.md +44 -0
- package/dist/templates/claude/rules/60-incidental-capture.md +43 -0
- package/dist/templates/claude/rules/75-impact-vault-reading.md +43 -0
- package/dist/templates/claude/rules/90-exec-protocol.md.ejs +40 -0
- package/dist/templates/claude/rules/95-closer-mode.md +45 -0
- package/dist/templates/claude/settings.json.ejs +165 -0
- package/dist/templates/claude/skills/architect-review/SKILL.md.ejs +82 -0
- package/dist/templates/claude/skills/brainstorming/SKILL.md.ejs +86 -0
- package/dist/templates/claude/skills/clean-code/SKILL.md.ejs +39 -0
- package/dist/templates/claude/skills/close-gold-gap/SKILL.md.ejs +58 -0
- package/dist/templates/claude/skills/codebase-audit/SKILL.md.ejs +88 -0
- package/dist/templates/claude/skills/configure/SKILL.md.ejs +72 -0
- package/dist/templates/claude/skills/epic-decompose/SKILL.md.ejs +86 -0
- package/dist/templates/claude/skills/gold-audit/SKILL.md.ejs +91 -0
- package/dist/templates/claude/skills/impact/SKILL.md.ejs +104 -0
- package/dist/templates/claude/skills/levelup/SKILL.md.ejs +146 -0
- package/dist/templates/claude/skills/tabletop/SKILL.md.ejs +118 -0
- package/dist/templates/claude/skills/tdd/SKILL.md.ejs +157 -0
- package/dist/templates/claude/skills/understand-code/SKILL.md.ejs +93 -0
- package/dist/templates/claude/skills/verification/SKILL.md.ejs +68 -0
- package/dist/templates/claude/skills/wave-drain/SKILL.md.ejs +491 -0
- package/dist/templates/codex/CODEX.md.ejs +140 -0
- package/dist/templates/codex/codex-adapter.mjs +132 -0
- package/dist/templates/codex/config.toml.ejs +189 -0
- package/dist/templates/compliance/compliance-mapping.md.ejs +124 -0
- package/dist/templates/compliance/compliance-menu.md.ejs +89 -0
- package/dist/templates/contract-testing/CONTRACTS_POLICY.md.ejs +30 -0
- package/dist/templates/contract-testing/api-snapshots/config-keys-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/config-response-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/enum-values-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/error-shape-baseline.json.ejs +6 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-baseline.json.ejs +12 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-content-types-baseline.json.ejs +3 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-paths-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-required-fields-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-response-status-baseline.json.ejs +3 -0
- package/dist/templates/contract-testing/api-snapshots/test-snapshot.json.ejs +4 -0
- package/dist/templates/contract-testing/env/.env.pact.ejs +4 -0
- package/dist/templates/contract-testing/graphql/GraphqlSchemaTest.java.ejs +29 -0
- package/dist/templates/contract-testing/graphql/graphql-inspector.test.ts.ejs +20 -0
- package/dist/templates/contract-testing/graphql/graphql_schema_test.go.ejs +27 -0
- package/dist/templates/contract-testing/graphql/graphql_schema_test.rs.ejs +27 -0
- package/dist/templates/contract-testing/graphql/test_graphql_schema.py.ejs +21 -0
- package/dist/templates/contract-testing/grpc/GrpcContractTest.java.ejs +23 -0
- package/dist/templates/contract-testing/grpc/buf-breaking.yml.ejs +6 -0
- package/dist/templates/contract-testing/grpc/buf.yaml.ejs +11 -0
- package/dist/templates/contract-testing/grpc/grpc-contract.test.ts.ejs +16 -0
- package/dist/templates/contract-testing/grpc/grpc_contract_test.go.ejs +22 -0
- package/dist/templates/contract-testing/grpc/grpc_contract_test.rs.ejs +22 -0
- package/dist/templates/contract-testing/grpc/test_grpc_contract.py.ejs +18 -0
- package/dist/templates/contract-testing/message-queue/SchemaRegistryCheckIT.java.ejs +44 -0
- package/dist/templates/contract-testing/message-queue/schema-registry-check.ts.ejs +42 -0
- package/dist/templates/contract-testing/message-queue/schema_registry_test.go.ejs +71 -0
- package/dist/templates/contract-testing/message-queue/schema_registry_test.rs.ejs +61 -0
- package/dist/templates/contract-testing/message-queue/test_schema_registry.py.ejs +31 -0
- package/dist/templates/contract-testing/pact-samples/assignment-response.json.ejs +7 -0
- package/dist/templates/contract-testing/pact-samples/availability-response.json.ejs +13 -0
- package/dist/templates/contract-testing/pact-samples/availability-rule-response.json.ejs +8 -0
- package/dist/templates/contract-testing/pact-samples/capacity-response.json.ejs +11 -0
- package/dist/templates/contract-testing/pact-samples/fully-booked-response.json.ejs +6 -0
- package/dist/templates/contract-testing/pact-samples/schedule-override-response.json.ejs +7 -0
- package/dist/templates/contract-testing/rest-owned/PactVerificationIT.java.ejs +31 -0
- package/dist/templates/contract-testing/rest-owned/pact-consumer.test.ts.ejs +36 -0
- package/dist/templates/contract-testing/rest-owned/pact-deps.gradle.ejs +15 -0
- package/dist/templates/contract-testing/rest-owned/pact_consumer_test.go.ejs +48 -0
- package/dist/templates/contract-testing/rest-owned/pact_consumer_test.rs.ejs +23 -0
- package/dist/templates/contract-testing/rest-owned/test_pact_consumer.py.ejs +35 -0
- package/dist/templates/contract-testing/rest-public/OpenApiDiffIT.java.ejs +44 -0
- package/dist/templates/contract-testing/rest-public/export-openapi-java.gradle.ejs +13 -0
- package/dist/templates/contract-testing/rest-public/export-openapi.mjs.ejs +21 -0
- package/dist/templates/contract-testing/rest-public/export_openapi.go.ejs +30 -0
- package/dist/templates/contract-testing/rest-public/export_openapi.py.ejs +27 -0
- package/dist/templates/contract-testing/rest-public/export_openapi.rs.ejs +32 -0
- package/dist/templates/contract-testing/rest-public/openapi-diff.ts.ejs +42 -0
- package/dist/templates/contract-testing/rest-public/openapi_diff_test.go.ejs +35 -0
- package/dist/templates/contract-testing/rest-public/openapi_diff_test.rs.ejs +36 -0
- package/dist/templates/contract-testing/rest-public/test_openapi_diff.py.ejs +32 -0
- package/dist/templates/coverage/.coveragerc.ejs +26 -0
- package/dist/templates/coverage/.tarpaulin.toml.ejs +30 -0
- package/dist/templates/coverage/Cargo.toml.profile.release.ejs +24 -0
- package/dist/templates/coverage/jacoco-maven-setup.md.ejs +72 -0
- package/dist/templates/coverage/jacoco.gradle.ejs +49 -0
- package/dist/templates/coverage/kover.gradle.ejs +35 -0
- package/dist/templates/coverage/vitest.browser.config.ts.ejs +47 -0
- package/dist/templates/coverage/vitest.config.ts.ejs +47 -0
- package/dist/templates/docs/CODING_STANDARDS.md.ejs +81 -0
- package/dist/templates/docs/FEATURE_MATRIX.md.ejs +84 -0
- package/dist/templates/docs/GAP.md.ejs +58 -0
- package/dist/templates/docs/ISO27001_ANNEX_A.md.ejs +144 -0
- package/dist/templates/docs/MASTER_TEST_PLAN.md.ejs +52 -0
- package/dist/templates/docs/POST_MERGE_REVIEW_TEMPLATE.md.ejs +63 -0
- package/dist/templates/docs/SECURE_CODING_CHECKLIST.md.ejs +61 -0
- package/dist/templates/docs/adr/ADR-000_template.md.ejs +28 -0
- package/dist/templates/docs/bugs/bug-analysis.md.ejs +47 -0
- package/dist/templates/docs/bugs/bug-report.md.ejs +51 -0
- package/dist/templates/docs/bugs/bug-verification.md.ejs +42 -0
- package/dist/templates/docs/runbooks/deployment.md.ejs +119 -0
- package/dist/templates/docs/runbooks/prod-checklist.md.ejs +90 -0
- package/dist/templates/docs/runbooks/rollback.md.ejs +124 -0
- package/dist/templates/docs/runbooks/troubleshooting.md.ejs +130 -0
- package/dist/templates/docs/skeletons/arc42-canvas.md.ejs +46 -0
- package/dist/templates/docs/skeletons/arc42-full.md.ejs +59 -0
- package/dist/templates/docs/skeletons/decision-registry.md.ejs +38 -0
- package/dist/templates/docs/skeletons/er-model.md.ejs +19 -0
- package/dist/templates/docs/skeletons/glossary.md.ejs +8 -0
- package/dist/templates/docs/skeletons/governance.md.ejs +13 -0
- package/dist/templates/docs/skeletons/slo.md.ejs +21 -0
- package/dist/templates/docs/skeletons/technical-debt.md.ejs +8 -0
- package/dist/templates/docs/skeletons/test-strategy.md.ejs +14 -0
- package/dist/templates/docs/skeletons/threat-model-4q.md.ejs +20 -0
- package/dist/templates/docs/skeletons/threat-model-stride.md.ejs +22 -0
- package/dist/templates/docs/specs/atomic-task-list.md.ejs +57 -0
- package/dist/templates/docs/steering/product.md.ejs +44 -0
- package/dist/templates/docs/steering/structure.md.ejs +49 -0
- package/dist/templates/docs/steering/tech.md.ejs +53 -0
- package/dist/templates/documentation/cli-catalog.md.ejs +21 -0
- package/dist/templates/e2e/E2E_CONSTITUTION.md.ejs +77 -0
- package/dist/templates/e2e/playwright-python/conftest.py.ejs +22 -0
- package/dist/templates/e2e/playwright-python/run_axe.py.ejs +99 -0
- package/dist/templates/e2e/playwright-python/test_a11y.py.ejs +38 -0
- package/dist/templates/e2e/playwright-python/test_smoke.py.ejs +28 -0
- package/dist/templates/e2e/playwright-ts/a11y.spec.ts.ejs +20 -0
- package/dist/templates/e2e/playwright-ts/render-smoke.spec.ts.ejs +90 -0
- package/dist/templates/e2e/playwright-ts/run-axe.ts.ejs +74 -0
- package/dist/templates/e2e/smoke-journeys/journeys.spec.ts.ejs +53 -0
- package/dist/templates/evidence-files.json.ejs +13 -0
- package/dist/templates/frontend/FE_DESIGN_PRINCIPLES.md.ejs +115 -0
- package/dist/templates/frontend/FRONTEND_CONSTITUTION.md.ejs +170 -0
- package/dist/templates/frontend/design-tokens.json.ejs +107 -0
- package/dist/templates/frontend/vrt-setup.md.ejs +83 -0
- package/dist/templates/githooks/commit-msg.ejs +60 -0
- package/dist/templates/githooks/pre-commit.ejs +95 -0
- package/dist/templates/githooks/pre-push.ejs +251 -0
- package/dist/templates/githooks/setup-hooks.sh.ejs +8 -0
- package/dist/templates/github/PULL_REQUEST_TEMPLATE.md +37 -0
- package/dist/templates/github/PULL_REQUEST_TEMPLATE.md.ejs +52 -0
- package/dist/templates/github/actions/build-cache/action.yml.ejs +84 -0
- package/dist/templates/github/actions/nas-ssh/action.yml.ejs +53 -0
- package/dist/templates/github/actions/setup-java-maven/action.yml.ejs +53 -0
- package/dist/templates/github/actions/setup-node-pnpm/action.yml.ejs +39 -0
- package/dist/templates/github/actions/sign-and-attest/action.yml.ejs +53 -0
- package/dist/templates/github/dependabot.yml.ejs +66 -0
- package/dist/templates/github/extended-ci-paths.txt.ejs +38 -0
- package/dist/templates/github/issue-templates/bug-report.yml +72 -0
- package/dist/templates/github/issue-templates/compliance-item.yml.ejs +75 -0
- package/dist/templates/github/issue-templates/config.yml +2 -0
- package/dist/templates/github/issue-templates/epic.yml +66 -0
- package/dist/templates/github/issue-templates/feature-request.yml +24 -0
- package/dist/templates/github/issue-templates/task-brief.yml.ejs +125 -0
- package/dist/templates/github/labels.yml.ejs +161 -0
- package/dist/templates/github/scripts/sticky-failure-issue.sh.ejs +61 -0
- package/dist/templates/github/workflows/01-pr-fast.yml.ejs +1089 -0
- package/dist/templates/github/workflows/02-pr-extended.yml.ejs +512 -0
- package/dist/templates/github/workflows/03-human-approval.yml.ejs +76 -0
- package/dist/templates/github/workflows/04-deploy-test.yml.ejs +425 -0
- package/dist/templates/github/workflows/05-release.yml.ejs +813 -0
- package/dist/templates/github/workflows/06-nightly-lite.yml.ejs +125 -0
- package/dist/templates/github/workflows/06-nightly.yml.ejs +25 -0
- package/dist/templates/github/workflows/07-weekly-lite.yml.ejs +221 -0
- package/dist/templates/github/workflows/07-weekly.yml.ejs +23 -0
- package/dist/templates/github/workflows/08-monthly.yml.ejs +23 -0
- package/dist/templates/github/workflows/09-heartbeat.yml.ejs +268 -0
- package/dist/templates/github/workflows/10-deploy-prod.yml.ejs +144 -0
- package/dist/templates/github/workflows/11-k6-on-demand.yml.ejs +43 -0
- package/dist/templates/github/workflows/12-mutation-scheduled.yml.ejs +100 -0
- package/dist/templates/github/workflows/13-archunit-extended.yml.ejs +33 -0
- package/dist/templates/github/workflows/14-license-scan.yml.ejs +45 -0
- package/dist/templates/github/workflows/15-codeql.yml.ejs +117 -0
- package/dist/templates/github/workflows/16-frontend-quality.yml.ejs +154 -0
- package/dist/templates/github/workflows/17-ossf-scorecard.yml.ejs +46 -0
- package/dist/templates/github/workflows/18-frontend-lane.yml.ejs +50 -0
- package/dist/templates/github/workflows/_ai-draft-check.yml.ejs +44 -0
- package/dist/templates/github/workflows/_contract-postman.yml.ejs +93 -0
- package/dist/templates/github/workflows/_cosign-copy/aws-ecs.ejs +90 -0
- package/dist/templates/github/workflows/_cosign-copy/azure-container-app.ejs +97 -0
- package/dist/templates/github/workflows/_cosign-copy/gcp-cloud-run.ejs +102 -0
- package/dist/templates/github/workflows/_cosign-copy/ghcr.ejs +76 -0
- package/dist/templates/github/workflows/_cosign-copy/nas-compose.ejs +69 -0
- package/dist/templates/github/workflows/_deploy/aws-ecs.ejs +78 -0
- package/dist/templates/github/workflows/_deploy/azure-container-app.ejs +59 -0
- package/dist/templates/github/workflows/_deploy/gcp-cloud-run.ejs +71 -0
- package/dist/templates/github/workflows/_deploy/ghcr.ejs +19 -0
- package/dist/templates/github/workflows/_deploy/nas-compose.ejs +45 -0
- package/dist/templates/github/workflows/_k6-runner.yml.ejs +107 -0
- package/dist/templates/github/workflows/_label-on-approve.yml.ejs +44 -0
- package/dist/templates/github/workflows/_label-sync.yml.ejs +58 -0
- package/dist/templates/github/workflows/_monthly.yml.ejs +343 -0
- package/dist/templates/github/workflows/_nightly.yml.ejs +826 -0
- package/dist/templates/github/workflows/_notify.yml.ejs +96 -0
- package/dist/templates/github/workflows/_partials/macos-keychain-bypass.ejs +6 -0
- package/dist/templates/github/workflows/_partials/macos-keychain-restore.ejs +6 -0
- package/dist/templates/github/workflows/_partials/scheduled-heavy-jobs.ejs +117 -0
- package/dist/templates/github/workflows/_partials/sigstore-preflight.ejs +8 -0
- package/dist/templates/github/workflows/_partials/trivy-fs-java.ejs +27 -0
- package/dist/templates/github/workflows/_post-merge-notify.yml.ejs +228 -0
- package/dist/templates/github/workflows/_pr-staleness.yml.ejs +85 -0
- package/dist/templates/github/workflows/_shared-security.yml.ejs +132 -0
- package/dist/templates/github/workflows/_sigstore-retry-sign.yml.ejs +102 -0
- package/dist/templates/github/workflows/_weekly.yml.ejs +313 -0
- package/dist/templates/github/workflows/drift-shadow.yml.ejs +51 -0
- package/dist/templates/github/workflows/five-lane/ci.yml.ejs +54 -0
- package/dist/templates/github/workflows/five-lane/nightly.yml.ejs +70 -0
- package/dist/templates/github/workflows/five-lane/release.yml.ejs +53 -0
- package/dist/templates/github/workflows/five-lane/weekly.yml.ejs +72 -0
- package/dist/templates/github/workflows/issue-state.yml.ejs +93 -0
- package/dist/templates/global-invariants/GLOBAL_INVARIANTS.md.ejs +34 -0
- package/dist/templates/governance/RACI.md.ejs +21 -0
- package/dist/templates/governance/ci-mental-model.md.ejs +268 -0
- package/dist/templates/governance/contract-integrity-policy.md.ejs +116 -0
- package/dist/templates/governance/enterprise-compliance-baseline.md.ejs +111 -0
- package/dist/templates/governance/evidence-retention.md.ejs +43 -0
- package/dist/templates/governance/gdpr-erasure-runbook.md.ejs +165 -0
- package/dist/templates/governance/qa-audit-phases.md.ejs +129 -0
- package/dist/templates/governance/risk-assessment-template.md.ejs +105 -0
- package/dist/templates/governance/risk-register.md.ejs +76 -0
- package/dist/templates/governance/solo-dev-exception.md.ejs +96 -0
- package/dist/templates/governance/validation-evidence.md.ejs +131 -0
- package/dist/templates/infra/azure/containerapp.tpl.yaml.ejs +74 -0
- package/dist/templates/infra/nas-compose/deploy.sh.ejs +114 -0
- package/dist/templates/integration-testing/AbstractIntegrationTest.java.ejs +36 -0
- package/dist/templates/integration-testing/NoH2ArchTest.java.ejs +24 -0
- package/dist/templates/integration-testing/conftest.py.ejs +20 -0
- package/dist/templates/integration-testing/db_fixture.rs.ejs +48 -0
- package/dist/templates/integration-testing/eslint-no-fake-db.json.ejs +19 -0
- package/dist/templates/integration-testing/eslint.config.no-fake-db.mjs.ejs +46 -0
- package/dist/templates/integration-testing/main_test.go.ejs +53 -0
- package/dist/templates/integration-testing/main_test_sqlite.go.ejs +37 -0
- package/dist/templates/integration-testing/test-setup.ts.ejs +26 -0
- package/dist/templates/integration-testing/testcontainers-deps.gradle.ejs +9 -0
- package/dist/templates/java/DeprecationInterceptor.java.ejs +50 -0
- package/dist/templates/java/archunit-hexagonal.ejs +69 -0
- package/dist/templates/java/modulith/ApplicationModulesTest.java.ejs +21 -0
- package/dist/templates/java/modulith/modulith-deps.gradle.ejs +13 -0
- package/dist/templates/java/modulith/modulith-maven-setup.md.ejs +21 -0
- package/dist/templates/java/pharma/AuditEvent.java.ejs +138 -0
- package/dist/templates/java/pharma/AuditMapper.java.ejs +60 -0
- package/dist/templates/java/pharma/archunit-pharma.ejs +128 -0
- package/dist/templates/kit/GLOBAL_KIT.md.ejs +11 -0
- package/dist/templates/kit/dim.md.ejs +33 -0
- package/dist/templates/llms-txt.config.json.ejs +22 -0
- package/dist/templates/local-wrapper/.env.example.ejs +15 -0
- package/dist/templates/local-wrapper/Makefile.ejs +44 -0
- package/dist/templates/local-wrapper/run.sh.ejs +5 -0
- package/dist/templates/middleware/410-gone-handler.ts.ejs +41 -0
- package/dist/templates/middleware/correlation-id.ts.ejs +32 -0
- package/dist/templates/middleware/deprecation.ts.ejs +45 -0
- package/dist/templates/middleware/error-handler.ts.ejs +73 -0
- package/dist/templates/middleware/payload-size-limit.ts.ejs +51 -0
- package/dist/templates/mutation/README.md.ejs +67 -0
- package/dist/templates/mutation/cargo-mutants.toml.ejs +9 -0
- package/dist/templates/mutation/mutmut-config.toml.ejs +7 -0
- package/dist/templates/mutation/parse-mutants.mjs.ejs +44 -0
- package/dist/templates/mutation/parse-mutmut.py.ejs +44 -0
- package/dist/templates/mutation/pitest-l2-setup.md.ejs +66 -0
- package/dist/templates/mutation/pitest-maven-setup.md.ejs +64 -0
- package/dist/templates/mutation/pitest.gradle.ejs +23 -0
- package/dist/templates/mutation/stryker.conf.json.ejs +17 -0
- package/dist/templates/observability/setup.md.ejs +495 -0
- package/dist/templates/operations/handbook.md.ejs +217 -0
- package/dist/templates/perf/bundle-budget.json.ejs +29 -0
- package/dist/templates/perf/k6/reports/csv-report.py.ejs +91 -0
- package/dist/templates/perf/k6/reports/html-report.py.ejs +114 -0
- package/dist/templates/perf/k6/reports/json-report.py.ejs +74 -0
- package/dist/templates/perf/k6/scenarios/breakpoint.js.ejs +26 -0
- package/dist/templates/perf/k6/scenarios/burst.js.ejs +43 -0
- package/dist/templates/perf/k6/scenarios/endurance.js.ejs +36 -0
- package/dist/templates/perf/k6/scenarios/load.js.ejs +26 -0
- package/dist/templates/perf/k6/scenarios/ramp-down.js.ejs +29 -0
- package/dist/templates/perf/k6/scenarios/ramp-up.js.ejs +32 -0
- package/dist/templates/perf/k6/scenarios/smoke.js.ejs +23 -0
- package/dist/templates/perf/k6/scenarios/soak.js.ejs +26 -0
- package/dist/templates/perf/k6/scenarios/spike.js.ejs +29 -0
- package/dist/templates/perf/k6/scenarios/steady-state.js.ejs +31 -0
- package/dist/templates/perf/k6/scenarios/stress.js.ejs +29 -0
- package/dist/templates/perf/k6/scenarios/volume.js.ejs +36 -0
- package/dist/templates/perf/k6/seed/test-data.sql.ejs +59 -0
- package/dist/templates/perf/lighthouserc.json.ejs +41 -0
- package/dist/templates/quality/iso9001/CAPA_LOG.md.ejs +36 -0
- package/dist/templates/quality/iso9001/DOCUMENT_CONTROL.md.ejs +36 -0
- package/dist/templates/quality/iso9001/REQUIREMENTS_TRACEABILITY.md.ejs +61 -0
- package/dist/templates/regulated/overlay.json.ejs +26 -0
- package/dist/templates/regulated/regulated-overlay.md.ejs +40 -0
- package/dist/templates/resilience/RESILIENCE.md.ejs +310 -0
- package/dist/templates/root/.gitignore.ejs +85 -0
- package/dist/templates/root/CODEOWNERS.ejs +18 -0
- package/dist/templates/root/CONTRIBUTING.md.ejs +62 -0
- package/dist/templates/root/SECURITY.md.ejs +19 -0
- package/dist/templates/root/TEST_TAXONOMY.md.ejs +100 -0
- package/dist/templates/root/commitlint.config.js.ejs +4 -0
- package/dist/templates/root/docs/METHOD/CANONICAL_PATHS.md.ejs +24 -0
- package/dist/templates/root/docs/METHOD/ENGINEERING_DEFAULTS.md.ejs +136 -0
- package/dist/templates/root/docs/METHOD/KNOWLEDGE_MAP.md.ejs +90 -0
- package/dist/templates/root/docs/METHOD/PATTERNS_CATALOG.md.ejs +51 -0
- package/dist/templates/root/docs/METHOD/REUSE_REGISTRY.md.ejs +26 -0
- package/dist/templates/root/docs/METHOD/REUSE_REGISTRY_SPEC.md.ejs +80 -0
- package/dist/templates/root/docs/METHOD/SSOT_CORE_SET.md.ejs +62 -0
- package/dist/templates/root/docs/METHOD/TRACK_ROUTER.md.ejs +39 -0
- package/dist/templates/root/docs/SYSTEM/CANON.md.ejs +359 -0
- package/dist/templates/root/docs/SYSTEM/FAIL_CLOSED.md.ejs +171 -0
- package/dist/templates/root/editorconfig.ejs +39 -0
- package/dist/templates/root/tsconfig.json.ejs +21 -0
- package/dist/templates/rust/clippy.toml.ejs +14 -0
- package/dist/templates/schemas/milestone.schema.json.ejs +164 -0
- package/dist/templates/schemas/rtm-verdict.schema.json.ejs +52 -0
- package/dist/templates/schemas/source-record.schema.json.ejs +91 -0
- package/dist/templates/schemas/tabletop-evidence.schema.json.ejs +53 -0
- package/dist/templates/schemas/use-case.schema.json.ejs +59 -0
- package/dist/templates/scripts/apply-branch-protection.mjs.ejs +70 -0
- package/dist/templates/scripts/audit-toolchain.mjs.ejs +112 -0
- package/dist/templates/scripts/bg-run.sh.ejs +59 -0
- package/dist/templates/scripts/capacity-probe.mjs.ejs +147 -0
- package/dist/templates/scripts/capture-debt-baseline.mjs.ejs +99 -0
- package/dist/templates/scripts/check-acceptance.mjs.ejs +298 -0
- package/dist/templates/scripts/check-action-pins.mjs.ejs +215 -0
- package/dist/templates/scripts/check-agent-return.mjs.ejs +177 -0
- package/dist/templates/scripts/check-all.mjs.ejs +1746 -0
- package/dist/templates/scripts/check-anti-fake-green.mjs.ejs +80 -0
- package/dist/templates/scripts/check-anti-proforma.mjs.ejs +547 -0
- package/dist/templates/scripts/check-api-e2e.mjs.ejs +106 -0
- package/dist/templates/scripts/check-arc42-slots.mjs.ejs +25 -0
- package/dist/templates/scripts/check-assertion-delta.mjs.ejs +287 -0
- package/dist/templates/scripts/check-audit-dry-pass.mjs.ejs +176 -0
- package/dist/templates/scripts/check-bundle-size.mjs.ejs +151 -0
- package/dist/templates/scripts/check-canonical-paths.mjs.ejs +39 -0
- package/dist/templates/scripts/check-ci-tiers.mjs.ejs +111 -0
- package/dist/templates/scripts/check-claude-md-lint.mjs.ejs +142 -0
- package/dist/templates/scripts/check-collab-mode-wired.mjs.ejs +60 -0
- package/dist/templates/scripts/check-commit-footer-rationale.mjs.ejs +170 -0
- package/dist/templates/scripts/check-constraint-scan.mjs.ejs +681 -0
- package/dist/templates/scripts/check-consumer-audit.mjs.ejs +414 -0
- package/dist/templates/scripts/check-continue-on-error.mjs.ejs +227 -0
- package/dist/templates/scripts/check-cross-model-review.mjs.ejs +458 -0
- package/dist/templates/scripts/check-decision-registry.mjs.ejs +101 -0
- package/dist/templates/scripts/check-doc-freshness.mjs.ejs +17 -0
- package/dist/templates/scripts/check-doc-links.mjs.ejs +98 -0
- package/dist/templates/scripts/check-doc-set.mjs.ejs +18 -0
- package/dist/templates/scripts/check-docs.mjs.ejs +71 -0
- package/dist/templates/scripts/check-domain-api-surface.mjs.ejs +80 -0
- package/dist/templates/scripts/check-drift.mjs.ejs +167 -0
- package/dist/templates/scripts/check-duplication.mjs.ejs +45 -0
- package/dist/templates/scripts/check-e2e-escalation.mjs.ejs +199 -0
- package/dist/templates/scripts/check-e2e-quarantine.mjs.ejs +68 -0
- package/dist/templates/scripts/check-emission-parity.mjs.ejs +91 -0
- package/dist/templates/scripts/check-exit-code-contract.mjs.ejs +138 -0
- package/dist/templates/scripts/check-fail-closed-audit.mjs.ejs +389 -0
- package/dist/templates/scripts/check-fe-boundaries.mjs.ejs +184 -0
- package/dist/templates/scripts/check-feature-matrix.mjs.ejs +835 -0
- package/dist/templates/scripts/check-frontend-lane.mjs.ejs +73 -0
- package/dist/templates/scripts/check-grace-window.mjs.ejs +102 -0
- package/dist/templates/scripts/check-handoff-doc.mjs.ejs +192 -0
- package/dist/templates/scripts/check-hook-routing.mjs.ejs +224 -0
- package/dist/templates/scripts/check-image-pins.mjs.ejs +90 -0
- package/dist/templates/scripts/check-inline-suppressions.mjs.ejs +153 -0
- package/dist/templates/scripts/check-iso9001.mjs.ejs +146 -0
- package/dist/templates/scripts/check-knowledge-map.mjs.ejs +49 -0
- package/dist/templates/scripts/check-local-ci-parity.mjs.ejs +382 -0
- package/dist/templates/scripts/check-m16-handoff.mjs.ejs +112 -0
- package/dist/templates/scripts/check-merge-method.mjs.ejs +92 -0
- package/dist/templates/scripts/check-milestones.mjs.ejs +678 -0
- package/dist/templates/scripts/check-min-test-execution.mjs.ejs +225 -0
- package/dist/templates/scripts/check-muted-test.mjs.ejs +270 -0
- package/dist/templates/scripts/check-no-stub-redirects.mjs.ejs +154 -0
- package/dist/templates/scripts/check-no-tracked-artifacts.mjs.ejs +134 -0
- package/dist/templates/scripts/check-oracle-discrimination.mjs.ejs +244 -0
- package/dist/templates/scripts/check-pii-scan.mjs.ejs +67 -0
- package/dist/templates/scripts/check-pipe-tee-hazard.mjs.ejs +85 -0
- package/dist/templates/scripts/check-pr-size-gate.mjs.ejs +85 -0
- package/dist/templates/scripts/check-refutation-verdicts.mjs.ejs +256 -0
- package/dist/templates/scripts/check-regulated-overlay.mjs.ejs +158 -0
- package/dist/templates/scripts/check-render-smoke.mjs.ejs +100 -0
- package/dist/templates/scripts/check-reuse-registry.mjs.ejs +44 -0
- package/dist/templates/scripts/check-review-completion.mjs.ejs +708 -0
- package/dist/templates/scripts/check-safety-adopt-ratchet.mjs.ejs +142 -0
- package/dist/templates/scripts/check-secret-presence.mjs.ejs +191 -0
- package/dist/templates/scripts/check-secret-scan.mjs.ejs +82 -0
- package/dist/templates/scripts/check-skip-critical-e2e.mjs.ejs +142 -0
- package/dist/templates/scripts/check-smoke-journeys.mjs.ejs +272 -0
- package/dist/templates/scripts/check-solo-reactivation.mjs.ejs +102 -0
- package/dist/templates/scripts/check-sources.mjs.ejs +245 -0
- package/dist/templates/scripts/check-ssot-core.mjs.ejs +45 -0
- package/dist/templates/scripts/check-stack-conformity.mjs.ejs +160 -0
- package/dist/templates/scripts/check-stride-traceability.mjs.ejs +101 -0
- package/dist/templates/scripts/check-suppression-expiry.mjs.ejs +79 -0
- package/dist/templates/scripts/check-suppression-rationale.mjs.ejs +76 -0
- package/dist/templates/scripts/check-suppressions.mjs.ejs +150 -0
- package/dist/templates/scripts/check-tabletop-evidence.mjs.ejs +499 -0
- package/dist/templates/scripts/check-tdd-evidence.mjs.ejs +381 -0
- package/dist/templates/scripts/check-test-naming.mjs.ejs +151 -0
- package/dist/templates/scripts/check-test-pyramid.mjs.ejs +170 -0
- package/dist/templates/scripts/check-test-scope-tier.mjs.ejs +208 -0
- package/dist/templates/scripts/check-tier-coverage.mjs.ejs +71 -0
- package/dist/templates/scripts/check-todo-max-age.mjs.ejs +205 -0
- package/dist/templates/scripts/check-touched-vs-manifest.mjs.ejs +179 -0
- package/dist/templates/scripts/check-unwired-guards.mjs.ejs +367 -0
- package/dist/templates/scripts/check-use-cases.mjs.ejs +345 -0
- package/dist/templates/scripts/check-validator-helptext.mjs.ejs +80 -0
- package/dist/templates/scripts/check-wiki-lint.mjs.ejs +162 -0
- package/dist/templates/scripts/check-workflow-docs-sync.mjs.ejs +91 -0
- package/dist/templates/scripts/check-workflow-job-naming.mjs.ejs +102 -0
- package/dist/templates/scripts/check-workflow-perms.mjs.ejs +54 -0
- package/dist/templates/scripts/check-workflow-runners.mjs.ejs +87 -0
- package/dist/templates/scripts/check-workflow-sha-pinning.mjs.ejs +89 -0
- package/dist/templates/scripts/check-workflow-test-integrity.mjs.ejs +235 -0
- package/dist/templates/scripts/checks/check-rust-no-unsafe.mjs.ejs +58 -0
- package/dist/templates/scripts/checks/check-rust-no-unwrap.mjs.ejs +61 -0
- package/dist/templates/scripts/ci-classify-changes.mjs.ejs +119 -0
- package/dist/templates/scripts/conformance.mjs.ejs +37 -0
- package/dist/templates/scripts/constraint-map.json.ejs +25 -0
- package/dist/templates/scripts/debt-lib.mjs.ejs +1015 -0
- package/dist/templates/scripts/debt-report.mjs.ejs +199 -0
- package/dist/templates/scripts/domain-api-surface.json.ejs +23 -0
- package/dist/templates/scripts/done-evidence.mjs.ejs +359 -0
- package/dist/templates/scripts/evidence-collect.mjs.ejs +264 -0
- package/dist/templates/scripts/evidence-prune.mjs.ejs +96 -0
- package/dist/templates/scripts/evidence-rotate.mjs.ejs +53 -0
- package/dist/templates/scripts/evidence-writer.sh.ejs +220 -0
- package/dist/templates/scripts/gate-registry.yml.ejs +286 -0
- package/dist/templates/scripts/gen-doc-index.mjs.ejs +19 -0
- package/dist/templates/scripts/gen-gap.mjs.ejs +153 -0
- package/dist/templates/scripts/gen-llms-txt.mjs.ejs +18 -0
- package/dist/templates/scripts/gen-wiki.mjs.ejs +196 -0
- package/dist/templates/scripts/gh-cleanup-expired-artifacts.mjs.ejs +134 -0
- package/dist/templates/scripts/gold-audit.mjs.ejs +19 -0
- package/dist/templates/scripts/i18n-literal-scanner.mjs.ejs +175 -0
- package/dist/templates/scripts/ingest-zap-report.mjs.ejs +107 -0
- package/dist/templates/scripts/inject-pact-samples.sh.ejs +96 -0
- package/dist/templates/scripts/issue-readiness.mjs.ejs +84 -0
- package/dist/templates/scripts/knowledge-map-update.mjs.ejs +32 -0
- package/dist/templates/scripts/lib/acceptance-criteria.mjs.ejs +213 -0
- package/dist/templates/scripts/lib/agent-return-validate.mjs.ejs +481 -0
- package/dist/templates/scripts/lib/coverage-gate.mjs.ejs +54 -0
- package/dist/templates/scripts/lib/e2e-reliability.mjs.ejs +207 -0
- package/dist/templates/scripts/lib/ephemeral-server.mjs.ejs +148 -0
- package/dist/templates/scripts/lib/evidence-binding.mjs.ejs +140 -0
- package/dist/templates/scripts/lib/exact-sha-policy.mjs.ejs +233 -0
- package/dist/templates/scripts/lib/gate-args.mjs.ejs +20 -0
- package/dist/templates/scripts/lib/gate-evidence.mjs.ejs +622 -0
- package/dist/templates/scripts/lib/gate-mutex.mjs.ejs +340 -0
- package/dist/templates/scripts/lib/glob-walk.mjs.ejs +148 -0
- package/dist/templates/scripts/lib/run-helpers.mjs.ejs +416 -0
- package/dist/templates/scripts/lib/seed-common.sh.ejs +105 -0
- package/dist/templates/scripts/lib/waiter-count.mjs.ejs +62 -0
- package/dist/templates/scripts/muted-tests-baseline.json.ejs +4 -0
- package/dist/templates/scripts/optional-emissions.json.ejs +117 -0
- package/dist/templates/scripts/oracle-discrimination-baseline.json.ejs +6 -0
- package/dist/templates/scripts/pid-watch.sh.ejs +78 -0
- package/dist/templates/scripts/pii-scan.mjs.ejs +125 -0
- package/dist/templates/scripts/pr-merge-watch.mjs.ejs +445 -0
- package/dist/templates/scripts/record-agent-return.mjs.ejs +279 -0
- package/dist/templates/scripts/record-journey-evidence.mjs.ejs +69 -0
- package/dist/templates/scripts/rework-log.mjs.ejs +172 -0
- package/dist/templates/scripts/run-postman-tests.sh.ejs +112 -0
- package/dist/templates/scripts/schemas/agent-return-external.schema.json +74 -0
- package/dist/templates/scripts/schemas/agent-return.schema.json.ejs +181 -0
- package/dist/templates/scripts/schemas/cross-model-dispatch.schema.json +95 -0
- package/dist/templates/scripts/seed-test-data.sh.ejs +99 -0
- package/dist/templates/scripts/self-validation.mjs.ejs +126 -0
- package/dist/templates/scripts/setup-repo.sh.ejs +78 -0
- package/dist/templates/scripts/spotbugs-baseline.json.ejs +4 -0
- package/dist/templates/scripts/test-gate-layering.mjs.ejs +92 -0
- package/dist/templates/scripts/validate-api-snapshots.mjs.ejs +86 -0
- package/dist/templates/scripts/validate-k6-scenarios.mjs.ejs +96 -0
- package/dist/templates/scripts/validate-openapi-field-types.mjs.ejs +124 -0
- package/dist/templates/scripts/validate-postman-collection.mjs.ejs +159 -0
- package/dist/templates/scripts/verify-fe-coverage.mjs.ejs +138 -0
- package/dist/templates/scripts/verify-i18n-parity.mjs.ejs +114 -0
- package/dist/templates/scripts/verify-module-coverage.mjs.ejs +207 -0
- package/dist/templates/scripts/verify-mutation-baseline.mjs.ejs +209 -0
- package/dist/templates/scripts/verify-spotbugs.mjs.ejs +216 -0
- package/dist/templates/scripts/verify-tokens.mjs.ejs +177 -0
- package/dist/templates/security/RISK_ASSESSMENT.md.ejs +35 -0
- package/dist/templates/security/STRIDE.md.ejs +24 -0
- package/dist/templates/security/gitleaks.toml.ejs +21 -0
- package/dist/templates/security/zap/baseline-auth.context.ejs +58 -0
- package/dist/templates/security/zap/rules.tsv.ejs +100 -0
- package/dist/templates/ship/TICK_PROMPT.md.ejs +55 -0
- package/dist/templates/ship/supervisor.sh.ejs +46 -0
- package/dist/templates/smoke-journeys/manifest.json.ejs +1 -0
- package/dist/templates/sonar-project.properties.ejs +25 -0
- package/dist/templates/standards/doc-profile.ejs +27 -0
- package/dist/templates/standards/gold-doc-set.yml.ejs +528 -0
- package/dist/templates/standards/gold-registry.java.yml.ejs +266 -0
- package/dist/templates/standards/gold-registry.typescript.yml.ejs +104 -0
- package/dist/templates/standards/gold-registry.yml.ejs +119 -0
- package/dist/templates/standards/thresholds.yml.ejs +86 -0
- package/dist/templates/static-analysis/.dependency-cruiser.cjs.ejs +78 -0
- package/dist/templates/static-analysis/.golangci.yml.ejs +70 -0
- package/dist/templates/static-analysis/.shellcheckrc.ejs +13 -0
- package/dist/templates/static-analysis/.yamllint.yml.ejs +41 -0
- package/dist/templates/static-analysis/checkstyle.xml.ejs +83 -0
- package/dist/templates/static-analysis/detekt.yml.ejs +26 -0
- package/dist/templates/static-analysis/eslint.config.mjs.ejs +54 -0
- package/dist/templates/static-analysis/eslint.config.static.mjs.ejs +38 -0
- package/dist/templates/static-analysis/eslintrc-static.json.ejs +30 -0
- package/dist/templates/static-analysis/jscpd.json.ejs +25 -0
- package/dist/templates/static-analysis/knip.json.ejs +26 -0
- package/dist/templates/static-analysis/pmd-ruleset.xml.ejs +92 -0
- package/dist/templates/static-analysis/prettierignore.ejs +59 -0
- package/dist/templates/static-analysis/prettierrc.json.ejs +10 -0
- package/dist/templates/static-analysis/requirements-dev.txt.ejs +11 -0
- package/dist/templates/static-analysis/ruff.toml.ejs +40 -0
- package/dist/templates/static-analysis/rustfmt.toml.ejs +3 -0
- package/dist/templates/static-analysis/spotbugs-exclude.xml.ejs +120 -0
- package/dist/templates/static-analysis/spotbugs.gradle.ejs +18 -0
- package/dist/templates/static-analysis/spotless.gradle.ejs +38 -0
- package/dist/templates/static-analysis/stylelintrc.json.ejs +16 -0
- package/dist/templates/suppressions/archunit-baseline.json.ejs +1 -0
- package/dist/templates/suppressions/consumer-audit-allowlist.json.ejs +1 -0
- package/dist/templates/suppressions/gitleaksignore.ejs +20 -0
- package/dist/templates/suppressions/pii-allowlist.json.ejs +1 -0
- package/dist/templates/suppressions/suppressions-schema.json.ejs +39 -0
- package/dist/templates/suppressions/trivyignore.ejs +17 -0
- package/dist/templates/testing/test-taxonomy.md.ejs +120 -0
- package/dist/test/example.behavioral.test.js +2 -0
- package/dist/types/memory.d.ts +19 -0
- package/dist/types/memory.js +1 -0
- package/dist/types/plan.d.ts +102 -0
- package/dist/types/plan.js +2 -0
- package/dist/types/plugin.d.ts +45 -0
- package/dist/types/plugin.js +1 -0
- package/dist/utils/canon-loader.js +2 -0
- package/dist/utils/channel.js +1 -0
- package/dist/utils/config.d.ts +79 -0
- package/dist/utils/config.js +5 -0
- package/dist/utils/confirm-downgrade.js +5 -0
- package/dist/utils/env.js +2 -0
- package/dist/utils/error-catalog.js +2 -0
- package/dist/utils/errors.js +2 -0
- package/dist/utils/evidence-log.js +3 -0
- package/dist/utils/file-lock.js +2 -0
- package/dist/utils/first-run.js +8 -0
- package/dist/utils/fs.js +3 -0
- package/dist/utils/github-issue-helper.js +4 -0
- package/dist/utils/gradle.js +21 -0
- package/dist/utils/json-output.js +2 -0
- package/dist/utils/logger-config.js +4 -0
- package/dist/utils/logger.js +3 -0
- package/dist/utils/maturity-check.js +2 -0
- package/dist/utils/pkg.js +3 -0
- package/dist/utils/platform.js +2 -0
- package/dist/utils/plugin-loader.js +2 -0
- package/dist/utils/plugin-worker.js +2 -0
- package/dist/utils/prettier-format.js +2 -0
- package/dist/utils/profiler.js +2 -0
- package/dist/utils/render.js +2 -0
- package/dist/utils/replay.js +3 -0
- package/dist/utils/run-cli.js +6 -0
- package/dist/utils/run-id.js +3 -0
- package/dist/utils/safe-read.js +2 -0
- package/dist/utils/task-id.js +2 -0
- package/dist/utils/today.js +2 -0
- package/dist/utils/tty.js +2 -0
- package/dist/utils/walk-dir.js +2 -0
- package/dist/verify/rules/drive-by-scope.js +1 -0
- package/dist/verify/rules/orphan-todos.js +1 -0
- package/dist/verify/rules/registry.js +1 -0
- package/dist/verify/rules/skip-patterns.js +1 -0
- package/dist/verify/rules/types.d.ts +15 -0
- package/dist/verify/rules/types.js +1 -0
- package/dist/verify/rules/ui-language.js +1 -0
- package/dist/verify/run.js +3 -0
- package/dist/wizard/archetype-defaults.js +1 -0
- package/dist/wizard/presets.js +1 -0
- package/dist/wizard/prompts.js +44 -0
- package/dist/wizard/types.d.ts +637 -0
- package/dist/wizard/types.js +1 -0
- package/dist/worktree/harvest.js +2 -0
- package/dist/worktree/links.js +2 -0
- package/dist/worktree/paths.js +2 -0
- package/dist/worktree/validate.js +3 -0
- package/package.json +124 -0
- package/scripts/check-arc42-slots.mjs +738 -0
- package/scripts/check-doc-freshness.mjs +236 -0
- package/scripts/check-doc-set.mjs +243 -0
- package/scripts/check-doc-style.mjs +228 -0
- package/scripts/gold-audit.mjs +319 -0
- package/scripts/lib/doc-gate-allowlist.mjs +123 -0
- package/scripts/lib/doc-set-resolve.mjs +274 -0
- package/scripts/lib/glob-walk.mjs +148 -0
- package/scripts/lib/gold-audit-lib.mjs +1260 -0
- package/scripts/lib/run-helpers.mjs +413 -0
|
@@ -0,0 +1,835 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// <%= projectName %> — docs/FEATURE_MATRIX.md gate (INV-112, CANON-23)
|
|
4
|
+
// Generated by arbiter (src/templates/scripts/check-feature-matrix.mjs.ejs)
|
|
5
|
+
//
|
|
6
|
+
// Ported from arbiter's own scripts/check-feature-matrix.mjs (#1887-B). This
|
|
7
|
+
// target-portable version drops the KIT-dimension coverage check (section 2)
|
|
8
|
+
// and the L4 audit_trail-category DoD check (section 5 of the original) —
|
|
9
|
+
// both depend on arbiter's own internal KIT catalog (src/kit/catalog.json),
|
|
10
|
+
// which has no equivalent in an arbitrary target project. Everything else
|
|
11
|
+
// (status-ladder validation, ref-existence checks, counter integrity, L3+
|
|
12
|
+
// test_ref DoD, governance-visibility warning) ports over unchanged. The
|
|
13
|
+
// source_ref upward-resolution and tests_ref glob-ban rules added for #2163
|
|
14
|
+
// are not KIT-specific either, so they port over unchanged too — only the
|
|
15
|
+
// anchor-resolution target paths differ (docs/PRD.md, docs/adr/ directory
|
|
16
|
+
// listing instead of arbiter's own internal docs/PRODUCT/PRD.md and
|
|
17
|
+
// docs/internal/ADR/README.md index).
|
|
18
|
+
/**
|
|
19
|
+
* check-feature-matrix.mjs — docs/FEATURE_MATRIX.md gate (INV-112, CANON-23)
|
|
20
|
+
*
|
|
21
|
+
* Modes:
|
|
22
|
+
* --check (default) validate status ladder, counter integrity, level DoD, verification_tier enum
|
|
23
|
+
* --write regenerate the summary roll-up section (not the data rows)
|
|
24
|
+
*
|
|
25
|
+
* Exit codes (INV-53):
|
|
26
|
+
* 0 = PASS (clean)
|
|
27
|
+
* 1 = FAIL (drift, false-status, counter mismatch, DoD violation)
|
|
28
|
+
* 2 = ERROR (file missing, parse failure, malformed schema)
|
|
29
|
+
*
|
|
30
|
+
* Level injection: --level L1|L2|L3|L4 or ARBITER_MATRIX_LEVEL env (defaults to arbiter.json).
|
|
31
|
+
*
|
|
32
|
+
* NOTE: This script runs without a build step and cannot import from src/.
|
|
33
|
+
*/
|
|
34
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs'
|
|
35
|
+
import { resolve, dirname } from 'node:path'
|
|
36
|
+
import { fileURLToPath } from 'node:url'
|
|
37
|
+
import { createHash } from 'node:crypto'
|
|
38
|
+
|
|
39
|
+
const ROOT = process.cwd()
|
|
40
|
+
|
|
41
|
+
// ─── CLI args ────────────────────────────────────────────────────────────────
|
|
42
|
+
const args = process.argv.slice(2)
|
|
43
|
+
const UPDATE_BASELINE = args.includes('--update-baseline')
|
|
44
|
+
const CHECK = !args.includes('--write')
|
|
45
|
+
const _levelEqArg = args.find((a) => a.startsWith('--level='))?.split('=')[1] ?? null
|
|
46
|
+
const _levelIdx = args.indexOf('--level')
|
|
47
|
+
const _levelNextArg = _levelIdx >= 0 ? (args[_levelIdx + 1] ?? null) : null
|
|
48
|
+
const levelArg = _levelEqArg ?? (_levelNextArg?.match(/^L[1-4]$/) ? _levelNextArg : null)
|
|
49
|
+
const MATRIX_PATH = resolve(ROOT, 'docs', 'FEATURE_MATRIX.md')
|
|
50
|
+
const GLOB_BASELINE_PATH = resolve(ROOT, '.feature-matrix-glob-baseline.json')
|
|
51
|
+
const AGENTS_MD_PATH = resolve(ROOT, 'AGENTS.md')
|
|
52
|
+
const ADR_DIR_PATH = resolve(ROOT, 'docs', 'adr')
|
|
53
|
+
const PRD_PATH = resolve(ROOT, 'docs', 'PRD.md')
|
|
54
|
+
|
|
55
|
+
// ─── Sentinel markers ────────────────────────────────────────────────────────
|
|
56
|
+
const START_MARKER = '<!-- FEATURE_MATRIX_START -->'
|
|
57
|
+
const END_MARKER = '<!-- FEATURE_MATRIX_END -->'
|
|
58
|
+
|
|
59
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
/** Resolve effective governance level: CLI arg > env > arbiter.json */
|
|
62
|
+
function resolveLevel() {
|
|
63
|
+
if (levelArg && /^L[1-4]$/.test(levelArg)) return levelArg
|
|
64
|
+
const envLevel = process.env.ARBITER_MATRIX_LEVEL
|
|
65
|
+
if (envLevel && /^L[1-4]$/.test(envLevel)) return envLevel
|
|
66
|
+
const arbiterJsonPath = resolve(ROOT, 'arbiter.json')
|
|
67
|
+
if (existsSync(arbiterJsonPath)) {
|
|
68
|
+
try {
|
|
69
|
+
const cfg = JSON.parse(readFileSync(arbiterJsonPath, 'utf-8'))
|
|
70
|
+
if (cfg.governanceLevel && /^L[1-4]$/.test(cfg.governanceLevel)) return cfg.governanceLevel
|
|
71
|
+
} catch (err) {
|
|
72
|
+
process.stdout.write(
|
|
73
|
+
` check-feature-matrix: WARN — cannot parse arbiter.json at ${arbiterJsonPath}, defaulting to L2: ${err instanceof Error ? err.message : String(err)}\n`,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return 'L2' // default
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const LEVEL_RANK = { L1: 1, L2: 2, L3: 3, L4: 4 }
|
|
81
|
+
function levelAtLeast(effective, required) {
|
|
82
|
+
return (LEVEL_RANK[effective] ?? 0) >= (LEVEL_RANK[required] ?? 99)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Strip anchor, line refs, and leading/trailing whitespace from a ref cell value. */
|
|
86
|
+
function normalizeRef(cell) {
|
|
87
|
+
return cell
|
|
88
|
+
.trim()
|
|
89
|
+
.replace(/#[^,\s]*$/, '')
|
|
90
|
+
.replace(/:\d+$/, '')
|
|
91
|
+
.trim()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Split comma-separated ref cell into individual paths, normalized. */
|
|
95
|
+
function splitRefs(cell) {
|
|
96
|
+
if (!cell || !cell.trim()) return []
|
|
97
|
+
return cell.split(',').map(normalizeRef).filter(Boolean)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Split a ref cell into RAW refs, anchors intact — the span check needs what normalizeRef drops. */
|
|
101
|
+
|
|
102
|
+
// RTM axis 2 (#2480): a `Verified` row must carry a verification envelope under
|
|
103
|
+
// .arbiter/evidence/rtm/<REQ-NNN>.json — verdict PROVEN, a justification, the command that was
|
|
104
|
+
// actually run, and a transcript digest. Ported verbatim from arbiter's own gate: the rule needs
|
|
105
|
+
// no arbiter-internal catalog, only the schema emitted beside this file. `Verified` was previously
|
|
106
|
+
// a word someone typed; this makes it a claim with a transcript behind it.
|
|
107
|
+
//
|
|
108
|
+
// Citations reuse axis 1's pinned-span grammar above, so a citation that drifts is reported
|
|
109
|
+
// OUTDATED by the same mechanism rather than a second one.
|
|
110
|
+
const RTM_EVIDENCE_DIR = ['.arbiter', 'evidence', 'rtm']
|
|
111
|
+
const RTM_BASELINE_REL = ['scripts', 'data', 'rtm-verdict-baseline.json']
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Read the monotone ratchet. Both failure modes resolve to 0 — tolerate nothing — because the
|
|
115
|
+
* alternative, tolerating whatever happens to exist, is how a ratchet quietly stops ratcheting.
|
|
116
|
+
* But ABSENT and CORRUPT are different claims and only one of them is routine: a missing baseline
|
|
117
|
+
* is a project that has not needed one, while an unreadable baseline is a defect the operator
|
|
118
|
+
* should hear about rather than discover as an unexplained strictness.
|
|
119
|
+
*/
|
|
120
|
+
function rtmBaseline(projectRoot) {
|
|
121
|
+
const path = resolve(projectRoot, ...RTM_BASELINE_REL)
|
|
122
|
+
if (!existsSync(path)) return 0
|
|
123
|
+
try {
|
|
124
|
+
const raw = JSON.parse(readFileSync(path, 'utf-8'))
|
|
125
|
+
const n = raw?.verifiedWithoutEnvelope
|
|
126
|
+
if (typeof n === 'number' && Number.isInteger(n) && n >= 0) return n
|
|
127
|
+
process.stderr.write(
|
|
128
|
+
`check-feature-matrix: rtm baseline has no integer verifiedWithoutEnvelope — treating as 0, ` +
|
|
129
|
+
`which tolerates nothing\n`,
|
|
130
|
+
)
|
|
131
|
+
return 0
|
|
132
|
+
} catch (err) {
|
|
133
|
+
process.stderr.write(
|
|
134
|
+
`check-feature-matrix: rtm baseline is unreadable (${err.message}) — treating as 0, which ` +
|
|
135
|
+
`tolerates nothing\n`,
|
|
136
|
+
)
|
|
137
|
+
return 0
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Validate one Verified row's envelope. Returns { failures, missing } — `missing` marks the row as
|
|
143
|
+
* counting against the grandfathering ratchet rather than failing outright, so the four rows that
|
|
144
|
+
* predate this rule are tolerated without inventing evidence for claims nobody recorded.
|
|
145
|
+
*/
|
|
146
|
+
function checkRtmEnvelope(row, projectRoot, schema, validateSchema) {
|
|
147
|
+
const id = row.featureId
|
|
148
|
+
const path = resolve(projectRoot, ...RTM_EVIDENCE_DIR, `${id}.json`)
|
|
149
|
+
if (!existsSync(path)) return { failures: [], missing: true }
|
|
150
|
+
let doc
|
|
151
|
+
try {
|
|
152
|
+
doc = JSON.parse(readFileSync(path, 'utf-8'))
|
|
153
|
+
} catch (err) {
|
|
154
|
+
// Surfaced as well as returned: the returned string becomes the gate verdict, but the audit
|
|
155
|
+
// (INV-96) reads a swallowed catch as fail-open, and it is right to — a reader of this code
|
|
156
|
+
// should be able to see the error escape without tracing the caller's reporting.
|
|
157
|
+
process.stderr.write(`check-feature-matrix: ${id} envelope parse failed — ${err.message}\n`)
|
|
158
|
+
return {
|
|
159
|
+
failures: [`${id}: verification envelope is not valid JSON — ${err.message}`],
|
|
160
|
+
missing: false,
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
failures: [
|
|
165
|
+
...validateSchema(doc, schema, schema, `${id} envelope`).map(
|
|
166
|
+
(v) => `${id}: verification envelope — ${v}`,
|
|
167
|
+
),
|
|
168
|
+
...envelopeIdentityFailures(doc, id),
|
|
169
|
+
...envelopeCitationFailures(doc, id, projectRoot),
|
|
170
|
+
],
|
|
171
|
+
missing: false,
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** The envelope must be ABOUT this row, and must record the one verdict that admits `Verified`. */
|
|
176
|
+
function envelopeIdentityFailures(doc, id) {
|
|
177
|
+
const failures = []
|
|
178
|
+
if (doc?.feature_id && doc.feature_id !== id) {
|
|
179
|
+
failures.push(
|
|
180
|
+
`${id}: verification envelope declares feature_id "${doc.feature_id}" — evidence copied ` +
|
|
181
|
+
`from another requirement proves that other requirement, not this one`,
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
if (doc?.verdict && doc.verdict !== 'PROVEN') {
|
|
185
|
+
failures.push(
|
|
186
|
+
`${id}: status Verified requires verdict PROVEN, envelope records "${doc.verdict}"`,
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
return failures
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Citations ride axis 1's pinned-span grammar, so a drifted citation is OUTDATED, not a new rule. */
|
|
193
|
+
function envelopeCitationFailures(doc, id, projectRoot) {
|
|
194
|
+
const failures = []
|
|
195
|
+
for (const citation of Array.isArray(doc?.citations) ? doc.citations : []) {
|
|
196
|
+
const err = checkRefSpan(String(citation), projectRoot)
|
|
197
|
+
if (err) failures.push(`${id}: verification envelope citation — ${err}`)
|
|
198
|
+
}
|
|
199
|
+
return failures
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Apply the rule across the matrix and adjudicate the ratchet. A fall is free; a rise fails and
|
|
204
|
+
* names both numbers, because the whole point of a monotone counter is that growth has to be
|
|
205
|
+
* deliberate and visible in the diff.
|
|
206
|
+
*/
|
|
207
|
+
function checkRtmEnvelopes(rows, projectRoot, schema, validateSchema) {
|
|
208
|
+
const failures = []
|
|
209
|
+
const uncovered = []
|
|
210
|
+
for (const row of rows) {
|
|
211
|
+
if (row.status !== 'Verified') continue
|
|
212
|
+
const result = checkRtmEnvelope(row, projectRoot, schema, validateSchema)
|
|
213
|
+
failures.push(...result.failures)
|
|
214
|
+
if (result.missing) uncovered.push(row.featureId)
|
|
215
|
+
}
|
|
216
|
+
const baseline = rtmBaseline(projectRoot)
|
|
217
|
+
if (uncovered.length > baseline) {
|
|
218
|
+
// Name the rows. "N rows lack evidence" tells a reader there is work; naming them tells the
|
|
219
|
+
// reader WHERE, which is the difference between a defect report and a statistic.
|
|
220
|
+
failures.push(
|
|
221
|
+
`RTM verdict ratchet: ${uncovered.length} Verified row(s) carry no verification envelope ` +
|
|
222
|
+
`(${uncovered.join(', ')}), baseline ${baseline}. A Verified row needs ` +
|
|
223
|
+
`.arbiter/evidence/rtm/<REQ-NNN>.json — status is not evidence. Falls are free; a rise ` +
|
|
224
|
+
`must be hand-edited into scripts/data/rtm-verdict-baseline.json in the same change that ` +
|
|
225
|
+
`earns it.`,
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
return failures
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function splitRawRefs(cell) {
|
|
232
|
+
if (!cell || !cell.trim()) return []
|
|
233
|
+
return cell
|
|
234
|
+
.split(',')
|
|
235
|
+
.map((r) => r.trim())
|
|
236
|
+
.filter(Boolean)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Span-pinned refs (#2480). Ref EXISTENCE and ref ACCURACY are different claims: normalizeRef
|
|
240
|
+
// strips `#L10-L20` before the file test, so a span could point past the end of the file, or at
|
|
241
|
+
// lines that have since become something else, while the row still read Verified. Not KIT-specific,
|
|
242
|
+
// so it ports to a governed project unchanged — like the source_ref and glob rules before it.
|
|
243
|
+
const SPAN_RE = /^(?<path>[^#]+)#L(?<from>\d+)-L(?<to>\d+)(?:@(?<pin>[0-9a-f]{12}))?$/
|
|
244
|
+
|
|
245
|
+
function spanPin(content, from, to) {
|
|
246
|
+
return createHash('sha256')
|
|
247
|
+
.update(content.split('\n').slice(from - 1, to).join('\n'))
|
|
248
|
+
.digest('hex')
|
|
249
|
+
.slice(0, 12)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function checkRefSpan(rawRef, projectRoot) {
|
|
253
|
+
const m = SPAN_RE.exec(rawRef.trim())
|
|
254
|
+
if (!m || !m.groups) return null
|
|
255
|
+
const { path: relPath, pin } = m.groups
|
|
256
|
+
const from = Number(m.groups['from']), to = Number(m.groups['to'])
|
|
257
|
+
if (from < 1 || to < from) return `invalid line span (from > to, or zero): ${rawRef}`
|
|
258
|
+
const abs = resolve(projectRoot, relPath)
|
|
259
|
+
if (!existsSync(abs)) return null
|
|
260
|
+
const content = readFileSync(abs, 'utf-8')
|
|
261
|
+
const lines = content.split('\n').length
|
|
262
|
+
if (to > lines) return `line span runs past end of file (${lines} line(s)): ${rawRef}`
|
|
263
|
+
if (!pin) return null
|
|
264
|
+
const actual = spanPin(content, from, to)
|
|
265
|
+
if (actual !== pin) {
|
|
266
|
+
return (
|
|
267
|
+
`OUTDATED — the cited span no longer hashes to its pin, so the citation no longer proves ` +
|
|
268
|
+
`what this row claims (pinned ${pin}, now ${actual}): ${rawRef}`
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
return null
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// --pin: produce a pinned ref. Without a producer the syntax is theatre — nobody hand-computes a
|
|
275
|
+
// sha256 prefix, so nobody adopts it and the OUTDATED rule guards an empty set.
|
|
276
|
+
{
|
|
277
|
+
const pinIndex = args.indexOf('--pin')
|
|
278
|
+
if (pinIndex >= 0) {
|
|
279
|
+
const target = (args[pinIndex + 1] || '').trim()
|
|
280
|
+
const m = /^([^#]+)#L(\d+)-L(\d+)(?:@[0-9a-f]{12})?$/.exec(target)
|
|
281
|
+
if (!m) {
|
|
282
|
+
process.stderr.write(`check-feature-matrix: --pin expects <path>#L<from>-L<to>, got "${target}"\n`)
|
|
283
|
+
process.exit(2)
|
|
284
|
+
}
|
|
285
|
+
const [, relPath, fromRaw, toRaw] = m
|
|
286
|
+
const from = Number(fromRaw), to = Number(toRaw)
|
|
287
|
+
const abs = resolve(process.cwd(), relPath)
|
|
288
|
+
if (!existsSync(abs)) {
|
|
289
|
+
process.stderr.write(`check-feature-matrix: --pin cannot read ${relPath}\n`)
|
|
290
|
+
process.exit(2)
|
|
291
|
+
}
|
|
292
|
+
const content = readFileSync(abs, 'utf-8')
|
|
293
|
+
const lines = content.split('\n').length
|
|
294
|
+
if (from < 1 || to < from || to > lines) {
|
|
295
|
+
process.stderr.write(
|
|
296
|
+
`check-feature-matrix: --pin span L${from}-L${to} is outside ${relPath} (${lines} line(s))\n`,
|
|
297
|
+
)
|
|
298
|
+
process.exit(2)
|
|
299
|
+
}
|
|
300
|
+
process.stdout.write(`${relPath}#L${from}-L${to}@${spanPin(content, from, to)}\n`)
|
|
301
|
+
process.exit(0)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Check that a ref is valid: non-URL, non-glob, exists on disk. Returns error string or null. */
|
|
306
|
+
function checkRefExists(ref, projectRoot) {
|
|
307
|
+
if (/^https?:\/\//i.test(ref)) return `URL ref requires 'url:' prefix: ${ref}`
|
|
308
|
+
if (ref.includes('*')) {
|
|
309
|
+
// Glob: skip existence check for now (would need glob library)
|
|
310
|
+
return null
|
|
311
|
+
}
|
|
312
|
+
const absPath = resolve(projectRoot, ref)
|
|
313
|
+
if (!existsSync(absPath)) return `File not found: ${ref}`
|
|
314
|
+
return null
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function checkAllRefs(row, projectRoot, failures, id) {
|
|
318
|
+
for (const [label, value] of [
|
|
319
|
+
['code_ref', row.codeRef],
|
|
320
|
+
['test_ref', row.testRef],
|
|
321
|
+
['doc_ref', row.docRef],
|
|
322
|
+
]) {
|
|
323
|
+
for (const ref of splitRefs(value)) {
|
|
324
|
+
const err = checkRefExists(ref, projectRoot)
|
|
325
|
+
if (err) failures.push(`${id}: ${label} — ${err}`)
|
|
326
|
+
}
|
|
327
|
+
for (const raw of splitRawRefs(value)) {
|
|
328
|
+
const err = checkRefSpan(raw, projectRoot)
|
|
329
|
+
if (err) failures.push(`${id}: ${label} — ${err}`)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ─── verification_tier enum (12th column, #2242) ────────────────────────────
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* SCAFFOLD|GATE|E2E — GAMP IQ/OQ/PQ mapped to arbiter's real 3-tier V&V (see
|
|
338
|
+
* "Verification tier" doc section). Validated whenever the cell is non-empty,
|
|
339
|
+
* same backward-compatible optional-trailing-column posture as source_ref
|
|
340
|
+
* (#2163) — an older 10/11-column matrix (no tier column at all) is unaffected.
|
|
341
|
+
*/
|
|
342
|
+
const TIER_VALUES = new Set(['SCAFFOLD', 'GATE', 'E2E'])
|
|
343
|
+
|
|
344
|
+
function checkVerificationTier(row, failures) {
|
|
345
|
+
const tier = row.verificationTier.trim()
|
|
346
|
+
if (!tier) return
|
|
347
|
+
if (!TIER_VALUES.has(tier)) {
|
|
348
|
+
failures.push(
|
|
349
|
+
`${row.featureId}: verification_tier — invalid value "${tier}" (expected SCAFFOLD|GATE|E2E)`,
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ─── source_ref upward resolution (D1-D3, #2163) ────────────────────────────
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Split a source_ref cell into individual anchors. Deliberately NOT
|
|
358
|
+
* normalizeRef/splitRefs (D1): those strip trailing `#...`/`:\d+` file-ref
|
|
359
|
+
* suffixes, which would silently mangle an issue-form anchor (`#123`) into
|
|
360
|
+
* an empty string for the wrong reason.
|
|
361
|
+
*/
|
|
362
|
+
function splitSourceRefs(cell) {
|
|
363
|
+
if (!cell || !cell.trim()) return []
|
|
364
|
+
return cell
|
|
365
|
+
.split(',')
|
|
366
|
+
.map((s) => s.trim())
|
|
367
|
+
.filter(Boolean)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Classify a source_ref anchor into one of the three canonical resolvable
|
|
372
|
+
* forms (D2). Anything else (issue form `#NNN`, free prose, an unrecognized
|
|
373
|
+
* numbering scheme) is `kind: null` — format-only, never resolved, never a
|
|
374
|
+
* false red (AC-3).
|
|
375
|
+
*/
|
|
376
|
+
function classifySourceAnchor(anchor) {
|
|
377
|
+
let m
|
|
378
|
+
if ((m = /^INV-(\d+)$/.exec(anchor))) return { kind: 'inv', num: m[1] }
|
|
379
|
+
if ((m = /^ADR-(\d+)$/.exec(anchor))) return { kind: 'adr', num: m[1] }
|
|
380
|
+
if ((m = /^PRD\s*§\s*(\d+(?:\.\d+)*)$/.exec(anchor))) return { kind: 'prd', num: m[1] }
|
|
381
|
+
return { kind: null }
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let _agentsMdCache
|
|
385
|
+
function readAgentsMdOnce() {
|
|
386
|
+
if (_agentsMdCache === undefined) {
|
|
387
|
+
_agentsMdCache = existsSync(AGENTS_MD_PATH) ? readFileSync(AGENTS_MD_PATH, 'utf-8') : null
|
|
388
|
+
}
|
|
389
|
+
return _agentsMdCache
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let _prdCache
|
|
393
|
+
function readPrdOnce() {
|
|
394
|
+
if (_prdCache === undefined) {
|
|
395
|
+
_prdCache = existsSync(PRD_PATH) ? readFileSync(PRD_PATH, 'utf-8') : null
|
|
396
|
+
}
|
|
397
|
+
return _prdCache
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** heading text (post `#+` strip) starts with the numeric anchor, e.g. "5.7 Foo" for anchor "5.7". */
|
|
401
|
+
function prdHasNumberedHeading(text, num) {
|
|
402
|
+
const escaped = num.replace(/\./g, '\\.')
|
|
403
|
+
const headingRe = new RegExp(`^${escaped}\\.?(\\s|$)`)
|
|
404
|
+
return text.split('\n').some((line) => {
|
|
405
|
+
const m = /^#+\s*(.*)$/.exec(line.trim())
|
|
406
|
+
return m !== null && headingRe.test(m[1].trim())
|
|
407
|
+
})
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Target projects get only a single `docs/adr/ADR-000_template.md` scaffold
|
|
412
|
+
* (no generated index), so the portable resolution is a directory-listing
|
|
413
|
+
* prefix match instead of arbiter-internal's README index-table scan (D3).
|
|
414
|
+
*/
|
|
415
|
+
function adrDirHasMatchingFile(num) {
|
|
416
|
+
if (!existsSync(ADR_DIR_PATH)) return false
|
|
417
|
+
let entries
|
|
418
|
+
try {
|
|
419
|
+
entries = readdirSync(ADR_DIR_PATH)
|
|
420
|
+
} catch {
|
|
421
|
+
return false
|
|
422
|
+
}
|
|
423
|
+
const prefixRe = new RegExp(`^ADR-0*${num}[-_]`, 'i')
|
|
424
|
+
return entries.some((name) => prefixRe.test(name))
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Resolve one source_ref anchor against its target document (D3's portable
|
|
429
|
+
* path column) and push a failure naming the row and anchor on a miss
|
|
430
|
+
* (AC-1). No-op for non-canonical anchors (D2/AC-3).
|
|
431
|
+
*
|
|
432
|
+
* ponytail: a target project with a genuinely different convention (e.g. a
|
|
433
|
+
* single-file `## ADR-NNN: Title` doc instead of one-file-per-ADR) needs a
|
|
434
|
+
* configurable path/format (arbiter.json) — out of scope here.
|
|
435
|
+
*/
|
|
436
|
+
function checkSourceRefAnchor(anchor, id, failures) {
|
|
437
|
+
const classified = classifySourceAnchor(anchor)
|
|
438
|
+
if (classified.kind === null) return
|
|
439
|
+
|
|
440
|
+
const failure = sourceAnchorFailure(classified, anchor, id)
|
|
441
|
+
if (failure !== null) failures.push(failure)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function sourceAnchorFailure(classified, anchor, id) {
|
|
445
|
+
const { kind, num } = classified
|
|
446
|
+
const checks = {
|
|
447
|
+
inv: () => {
|
|
448
|
+
const text = readAgentsMdOnce()
|
|
449
|
+
return text !== null && text.includes(`**INV-${num}:**`)
|
|
450
|
+
},
|
|
451
|
+
adr: () => adrDirHasMatchingFile(num),
|
|
452
|
+
prd: () => {
|
|
453
|
+
const text = readPrdOnce()
|
|
454
|
+
return text !== null && prdHasNumberedHeading(text, num)
|
|
455
|
+
},
|
|
456
|
+
}
|
|
457
|
+
const descriptions = {
|
|
458
|
+
inv: `no matching **INV-${num}:** entry in AGENTS.md`,
|
|
459
|
+
adr: `no matching ADR-${num} file in docs/adr/`,
|
|
460
|
+
prd: `no matching "${num}" heading in docs/PRD.md`,
|
|
461
|
+
}
|
|
462
|
+
return checks[kind]() ? null : `${id}: source_ref ${anchor} — ${descriptions[kind]}`
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// ─── tests_ref glob ban (D4, #2163) ──────────────────────────────────────────
|
|
466
|
+
|
|
467
|
+
/** Load the committed glob-ratchet baseline as a Set of "featureId::ref" keys. Missing file → empty (no grandfathering). Corrupt JSON → exit 2. */
|
|
468
|
+
function loadGlobBaseline(path) {
|
|
469
|
+
if (!existsSync(path)) return new Set()
|
|
470
|
+
try {
|
|
471
|
+
const raw = JSON.parse(readFileSync(path, 'utf-8'))
|
|
472
|
+
return new Set(Array.isArray(raw?.entries) ? raw.entries : [])
|
|
473
|
+
} catch (err) {
|
|
474
|
+
process.stdout.write(
|
|
475
|
+
` check-feature-matrix: ERROR — cannot read/parse glob baseline at ${path}: ${err instanceof Error ? err.message : String(err)}\n`,
|
|
476
|
+
)
|
|
477
|
+
process.exit(2)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* A glob test_ref matches always, making forward coverage infalsifiable.
|
|
483
|
+
* Verified rows are NEVER baseline-exemptible (D4) — the one rule that
|
|
484
|
+
* actually closes the class of bug #2163 describes. Only Done rows can be
|
|
485
|
+
* grandfathered via a committed baseline entry keyed `${featureId}::${ref}`.
|
|
486
|
+
*/
|
|
487
|
+
function checkTestRefGlobBan(rows, baselineSet, failures) {
|
|
488
|
+
for (const row of rows) {
|
|
489
|
+
if (row.status !== 'Done' && row.status !== 'Verified') continue
|
|
490
|
+
for (const ref of splitRefs(row.testRef)) {
|
|
491
|
+
if (!ref.includes('*')) continue
|
|
492
|
+
if (row.status === 'Verified') {
|
|
493
|
+
failures.push(
|
|
494
|
+
`${row.featureId}: test_ref glob ban — Verified status forbids a glob test_ref (never baseline-exemptible): ${ref}`,
|
|
495
|
+
)
|
|
496
|
+
continue
|
|
497
|
+
}
|
|
498
|
+
const key = `${row.featureId}::${ref}`
|
|
499
|
+
if (!baselineSet.has(key)) {
|
|
500
|
+
failures.push(`${row.featureId}: test_ref glob ban — new glob test_ref not in baseline: ${ref}`)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** Recompute the glob baseline from current Done-status glob test_refs, sorted, deterministic. */
|
|
507
|
+
function computeGlobBaseline(rows) {
|
|
508
|
+
const entries = []
|
|
509
|
+
for (const row of rows) {
|
|
510
|
+
if (row.status !== 'Done') continue
|
|
511
|
+
for (const ref of splitRefs(row.testRef)) {
|
|
512
|
+
if (ref.includes('*')) entries.push(`${row.featureId}::${ref}`)
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
entries.sort()
|
|
516
|
+
return entries
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** Parse the table rows from within the sentinel block. */
|
|
520
|
+
function parseTableRows(text) {
|
|
521
|
+
const start = text.indexOf(START_MARKER)
|
|
522
|
+
const end = text.indexOf(END_MARKER)
|
|
523
|
+
if (start === -1 || end === -1 || end <= start) return null
|
|
524
|
+
|
|
525
|
+
const block = text.slice(start + START_MARKER.length, end)
|
|
526
|
+
const lines = block.split('\n')
|
|
527
|
+
const rows = []
|
|
528
|
+
|
|
529
|
+
for (const line of lines) {
|
|
530
|
+
const trimmed = line.trim()
|
|
531
|
+
if (!trimmed.startsWith('|')) continue
|
|
532
|
+
const cells = trimmed
|
|
533
|
+
.split('|')
|
|
534
|
+
.map((c) => c.trim())
|
|
535
|
+
.filter((_, i) => i > 0)
|
|
536
|
+
if (cells.length < 10) continue
|
|
537
|
+
// Skip header and separator rows
|
|
538
|
+
if (cells[0] === 'feature_id' || cells[0] === '---' || /^-+$/.test(cells[0])) continue
|
|
539
|
+
|
|
540
|
+
const [
|
|
541
|
+
featureId,
|
|
542
|
+
capability,
|
|
543
|
+
kitDimsRaw,
|
|
544
|
+
level,
|
|
545
|
+
status,
|
|
546
|
+
codeRef,
|
|
547
|
+
testRef,
|
|
548
|
+
docRef,
|
|
549
|
+
issueRef,
|
|
550
|
+
note,
|
|
551
|
+
] = cells
|
|
552
|
+
if (!featureId || !status) continue
|
|
553
|
+
// 11th column, optional (D1): today's 10-column rows already produce a
|
|
554
|
+
// trailing empty cell artifact at this index (verified empirically), so
|
|
555
|
+
// this is backward compatible with every existing row — zero migration.
|
|
556
|
+
const sourceRef = cells[10] ?? ''
|
|
557
|
+
// 12th column, optional (#2242): same backward-compat posture as source_ref.
|
|
558
|
+
const verificationTier = cells[11] ?? ''
|
|
559
|
+
|
|
560
|
+
rows.push({
|
|
561
|
+
featureId: featureId ?? '',
|
|
562
|
+
capability: capability ?? '',
|
|
563
|
+
kitDims: (kitDimsRaw ?? '')
|
|
564
|
+
.split(',')
|
|
565
|
+
.map((d) => d.trim())
|
|
566
|
+
.filter(Boolean),
|
|
567
|
+
level: level ?? '',
|
|
568
|
+
status: status ?? '',
|
|
569
|
+
codeRef: codeRef ?? '',
|
|
570
|
+
testRef: testRef ?? '',
|
|
571
|
+
docRef: docRef ?? '',
|
|
572
|
+
issueRef: issueRef ?? '',
|
|
573
|
+
note: note ?? '',
|
|
574
|
+
sourceRef,
|
|
575
|
+
verificationTier,
|
|
576
|
+
})
|
|
577
|
+
}
|
|
578
|
+
return rows
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** Parse summary counts from the Summary section. */
|
|
582
|
+
function parseSummaryCounts(text) {
|
|
583
|
+
const counts = {}
|
|
584
|
+
const summaryMatch = /## Summary[\s\S]*?(?=\n---|\n##|$)/.exec(text)
|
|
585
|
+
if (!summaryMatch) return counts
|
|
586
|
+
const summaryBlock = summaryMatch[0]
|
|
587
|
+
for (const line of summaryBlock.split('\n')) {
|
|
588
|
+
const m = /^\|\s*\*?\*?(\w+)\*?\*?\s*\|\s*\*?\*?(\d+)\*?\*?\s*\|/.exec(line)
|
|
589
|
+
if (m) {
|
|
590
|
+
const key = m[1].toLowerCase()
|
|
591
|
+
counts[key] = parseInt(m[2], 10)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return counts
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
598
|
+
|
|
599
|
+
if (!existsSync(MATRIX_PATH)) {
|
|
600
|
+
process.stdout.write(
|
|
601
|
+
` check-feature-matrix: ERROR — FEATURE_MATRIX.md not found at ${MATRIX_PATH}\n`,
|
|
602
|
+
)
|
|
603
|
+
process.exit(2)
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
let text
|
|
607
|
+
try {
|
|
608
|
+
text = readFileSync(MATRIX_PATH, 'utf-8')
|
|
609
|
+
} catch (err) {
|
|
610
|
+
process.stdout.write(
|
|
611
|
+
` check-feature-matrix: ERROR — cannot read ${MATRIX_PATH}: ${err.message}\n`,
|
|
612
|
+
)
|
|
613
|
+
process.exit(2)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const rows = parseTableRows(text)
|
|
617
|
+
if (rows === null) {
|
|
618
|
+
process.stdout.write(
|
|
619
|
+
` check-feature-matrix: ERROR — sentinel markers (${START_MARKER}) not found\n`,
|
|
620
|
+
)
|
|
621
|
+
process.exit(2)
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (rows.length === 0) {
|
|
625
|
+
process.stdout.write(` check-feature-matrix: ERROR — no data rows parsed from sentinel block\n`)
|
|
626
|
+
process.exit(2)
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// ─── --update-baseline: its own top-level action (D4), checked before --write ──
|
|
630
|
+
if (UPDATE_BASELINE) {
|
|
631
|
+
const entries = computeGlobBaseline(rows)
|
|
632
|
+
const payload = {
|
|
633
|
+
schema: 'arbiter-feature-matrix-glob-baseline-v1',
|
|
634
|
+
generated_at: new Date().toISOString(),
|
|
635
|
+
doctrine:
|
|
636
|
+
'INV-112 / #2163 — grandfathered Done-status test_ref globs at baseline freeze. ' +
|
|
637
|
+
'Verified rows are NEVER exemptible (a promoted-to-Verified glob is always a FAIL). ' +
|
|
638
|
+
'Regenerate deliberately with `node scripts/check-feature-matrix.mjs --update-baseline`.',
|
|
639
|
+
entries,
|
|
640
|
+
}
|
|
641
|
+
mkdirSync(dirname(GLOB_BASELINE_PATH), { recursive: true })
|
|
642
|
+
writeFileSync(GLOB_BASELINE_PATH, JSON.stringify(payload, null, 2) + '\n', 'utf-8')
|
|
643
|
+
process.stdout.write(
|
|
644
|
+
` check-feature-matrix: baseline updated → ${GLOB_BASELINE_PATH} (${entries.length} entries)\n`,
|
|
645
|
+
)
|
|
646
|
+
process.exit(0)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// ─── WRITE mode: regenerate summary section ───────────────────────────────────
|
|
650
|
+
if (!CHECK) {
|
|
651
|
+
const statusCounts = { Verified: 0, Done: 0, Partial: 0, Missing: 0 }
|
|
652
|
+
for (const row of rows) {
|
|
653
|
+
if (row.status in statusCounts) statusCounts[row.status]++
|
|
654
|
+
}
|
|
655
|
+
const total = rows.length
|
|
656
|
+
const summaryTable = [
|
|
657
|
+
'## Summary',
|
|
658
|
+
'',
|
|
659
|
+
'| Status | Count |',
|
|
660
|
+
'|---|---|',
|
|
661
|
+
`| Verified | ${statusCounts.Verified} |`,
|
|
662
|
+
`| Done | ${statusCounts.Done} |`,
|
|
663
|
+
`| Partial | ${statusCounts.Partial} |`,
|
|
664
|
+
`| Missing | ${statusCounts.Missing} |`,
|
|
665
|
+
`| **Total** | **${total}** |`,
|
|
666
|
+
].join('\n')
|
|
667
|
+
|
|
668
|
+
const replaced = text.replace(/## Summary[\s\S]*?(?=\n---|\n##|$)/, summaryTable + '\n')
|
|
669
|
+
writeFileSync(MATRIX_PATH, replaced, 'utf-8')
|
|
670
|
+
process.stdout.write(` check-feature-matrix: WROTE — summary updated (${total} rows)\n`)
|
|
671
|
+
process.exit(0)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ─── CHECK mode ───────────────────────────────────────────────────────────────
|
|
675
|
+
const effectiveLevel = resolveLevel()
|
|
676
|
+
const failures = []
|
|
677
|
+
|
|
678
|
+
// 1. Status ladder (fail-closed)
|
|
679
|
+
for (const row of rows) {
|
|
680
|
+
const id = row.featureId
|
|
681
|
+
const status = row.status
|
|
682
|
+
const projectRoot = ROOT
|
|
683
|
+
|
|
684
|
+
// source_ref upward resolution (D1): validated whenever the cell is
|
|
685
|
+
// non-empty, regardless of row status — a stale source anchor is a real
|
|
686
|
+
// defect on a Partial row too, not just a promotion-gated one.
|
|
687
|
+
for (const anchor of splitSourceRefs(row.sourceRef)) {
|
|
688
|
+
checkSourceRefAnchor(anchor, id, failures)
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// verification_tier enum (#2242): same posture as source_ref — checked
|
|
692
|
+
// whenever non-empty, independent of status ladder outcome below.
|
|
693
|
+
checkVerificationTier(row, failures)
|
|
694
|
+
|
|
695
|
+
// AC-1 (#2413): ref existence is checked for EVERY status whenever a
|
|
696
|
+
// code_ref/test_ref/doc_ref cell is non-empty, not just Done/Verified — a
|
|
697
|
+
// stale ref on a Partial row is just as false as one on a Done row.
|
|
698
|
+
checkAllRefs(row, projectRoot, failures, id)
|
|
699
|
+
|
|
700
|
+
if (!['Missing', 'Partial', 'Done', 'Verified'].includes(status)) {
|
|
701
|
+
failures.push(`${id}: unknown status "${status}"`)
|
|
702
|
+
continue
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (status === 'Missing') {
|
|
706
|
+
if (!row.issueRef || !/^#\d+$/.test(row.issueRef.trim())) {
|
|
707
|
+
failures.push(
|
|
708
|
+
`${id}: Missing status requires issue_ref matching #\\d+ (offline format check)`,
|
|
709
|
+
)
|
|
710
|
+
}
|
|
711
|
+
continue
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (status === 'Partial') {
|
|
715
|
+
if (!row.codeRef.trim()) {
|
|
716
|
+
failures.push(`${id}: Partial status requires non-empty code_ref`)
|
|
717
|
+
}
|
|
718
|
+
continue
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (status === 'Done') {
|
|
722
|
+
if (!row.codeRef.trim()) failures.push(`${id}: Done requires code_ref`)
|
|
723
|
+
if (!row.testRef.trim()) failures.push(`${id}: Done requires test_ref`)
|
|
724
|
+
if (!row.docRef.trim()) failures.push(`${id}: Done requires doc_ref`)
|
|
725
|
+
continue
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (status === 'Verified') {
|
|
729
|
+
if (!row.codeRef.trim()) failures.push(`${id}: Verified requires code_ref`)
|
|
730
|
+
if (!row.testRef.trim()) failures.push(`${id}: Verified requires test_ref`)
|
|
731
|
+
if (!row.docRef.trim()) failures.push(`${id}: Verified requires doc_ref`)
|
|
732
|
+
if (!row.issueRef.trim()) failures.push(`${id}: Verified requires issue_ref`)
|
|
733
|
+
// test_ref title parsing: check that the referenced test file exists (presence proxy)
|
|
734
|
+
// Full title parsing would require reading test files — presence is the enforceable signal.
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// 2. Counter integrity: summary counts == actual row counts
|
|
739
|
+
const summaryCounts = parseSummaryCounts(text)
|
|
740
|
+
const actualCounts = { verified: 0, done: 0, partial: 0, missing: 0 }
|
|
741
|
+
for (const row of rows) {
|
|
742
|
+
if (row.status === 'Verified') actualCounts.verified++
|
|
743
|
+
else if (row.status === 'Done') actualCounts.done++
|
|
744
|
+
else if (row.status === 'Partial') actualCounts.partial++
|
|
745
|
+
else if (row.status === 'Missing') actualCounts.missing++
|
|
746
|
+
}
|
|
747
|
+
const actualTotal = rows.length
|
|
748
|
+
|
|
749
|
+
for (const [key, actual] of Object.entries(actualCounts)) {
|
|
750
|
+
const declared = summaryCounts[key] ?? -1
|
|
751
|
+
if (declared !== actual) {
|
|
752
|
+
failures.push(`Counter mismatch: Summary ${key}=${declared} but actual=${actual}`)
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
if ((summaryCounts['total'] ?? -1) !== actualTotal) {
|
|
756
|
+
failures.push(
|
|
757
|
+
`Counter mismatch: Summary total=${summaryCounts['total'] ?? '?'} but actual=${actualTotal}`,
|
|
758
|
+
)
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// 3. Level DoD at L3+: Done/Verified rows must have test_ref file existing
|
|
762
|
+
if (levelAtLeast(effectiveLevel, 'L3')) {
|
|
763
|
+
for (const row of rows) {
|
|
764
|
+
if (row.status === 'Done' || row.status === 'Verified') {
|
|
765
|
+
const testRefs = splitRefs(row.testRef)
|
|
766
|
+
for (const ref of testRefs) {
|
|
767
|
+
const err = checkRefExists(ref, ROOT)
|
|
768
|
+
if (err) failures.push(`${row.featureId}: L3+ DoD — test_ref ${err}`)
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// 4. Governance visibility: Partial rows lacking a tracked follow-up issue_ref (warn-only, INV-112)
|
|
775
|
+
const partialNoIssue = rows.filter((r) => r.status === 'Partial' && !/#\d+/.test(r.issueRef.trim()))
|
|
776
|
+
if (partialNoIssue.length > 0) {
|
|
777
|
+
const totalPartial = rows.filter((r) => r.status === 'Partial').length
|
|
778
|
+
process.stdout.write(
|
|
779
|
+
` check-feature-matrix: WARN — ${partialNoIssue.length}/${totalPartial} Partial rows lack a tracked issue_ref (governance gap, non-blocking): ${partialNoIssue.map((r) => r.featureId).join(', ')}\n`,
|
|
780
|
+
)
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// 5. tests_ref glob ban (D4, #2163): infalsifiable glob coverage on Done/Verified rows
|
|
784
|
+
const globBaseline = loadGlobBaseline(GLOB_BASELINE_PATH)
|
|
785
|
+
checkTestRefGlobBan(rows, globBaseline, failures)
|
|
786
|
+
|
|
787
|
+
// 6. RTM axis 2 (#2480): a Verified row must carry a PROVEN verification envelope. The schema is
|
|
788
|
+
// emitted beside this gate. An ABSENT schema with Verified rows present is an ERROR, never a silent
|
|
789
|
+
// skip — a rule that quietly stops applying is the failure this gate exists to prevent.
|
|
790
|
+
if (rows.some((row) => row.status === 'Verified')) {
|
|
791
|
+
// The rule needs two files emitted BESIDE this one: the schema, and the shared validator that
|
|
792
|
+
// another generator owns (#1578 — exactly one generator writes each path). Both are loaded here
|
|
793
|
+
// rather than imported at the top, because a static import of a file this generator does not
|
|
794
|
+
// emit turns "the validator is missing" into MODULE_NOT_FOUND before the gate reads a single
|
|
795
|
+
// row — the #2335 failure, a Track-B claim that renders and cannot run. A missing dependency is
|
|
796
|
+
// a loud FAILURE, never a silent skip: a rule that quietly stops applying is what this gate
|
|
797
|
+
// exists to prevent. Nothing is loaded when no row claims `Verified`, so a project that never
|
|
798
|
+
// uses the rule never pays for it.
|
|
799
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
800
|
+
const schemaPath = resolve(here, '..', 'schemas', 'rtm-verdict.schema.json')
|
|
801
|
+
let validator = null
|
|
802
|
+
try {
|
|
803
|
+
validator = await import('./lib/agent-return-validate.mjs')
|
|
804
|
+
} catch {
|
|
805
|
+
validator = null
|
|
806
|
+
}
|
|
807
|
+
if (!existsSync(schemaPath)) {
|
|
808
|
+
failures.push(
|
|
809
|
+
'RTM axis 2: schemas/rtm-verdict.schema.json is missing, so no Verified row can be ' +
|
|
810
|
+
'adjudicated. Restore it (arbiter update) rather than letting the rule lapse silently.',
|
|
811
|
+
)
|
|
812
|
+
} else if (!validator) {
|
|
813
|
+
failures.push(
|
|
814
|
+
'RTM axis 2: scripts/lib/agent-return-validate.mjs is missing, so no Verified row can be ' +
|
|
815
|
+
'adjudicated. Restore it (arbiter update) rather than letting the rule lapse silently.',
|
|
816
|
+
)
|
|
817
|
+
} else {
|
|
818
|
+
failures.push(
|
|
819
|
+
...checkRtmEnvelopes(rows, ROOT, validator.loadSchema(schemaPath), validator.validateSchema),
|
|
820
|
+
)
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// ─── Report ──────────────────────────────────────────────────────────────────
|
|
825
|
+
failures.sort() // D5: deterministic output regardless of row order
|
|
826
|
+
|
|
827
|
+
if (failures.length === 0) {
|
|
828
|
+
process.stdout.write(` check-feature-matrix: OK — ${rows.length} rows, level=${effectiveLevel}\n`)
|
|
829
|
+
process.exit(0)
|
|
830
|
+
} else {
|
|
831
|
+
for (const f of failures) {
|
|
832
|
+
process.stdout.write(` check-feature-matrix: FAIL — ${f}\n`)
|
|
833
|
+
}
|
|
834
|
+
process.exit(1)
|
|
835
|
+
}
|