@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,681 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// INV-115 enforcement (generated by arbiter): extracts hard prohibitions
|
|
4
|
+
// (NEVER / MUST NOT / DO NOT / 🛑 / `No <tok>` / `never <tok>`) from this project's
|
|
5
|
+
// governance docs and classifies each as COVERED (verified enforcer), ENFORCED-BY-SCAN
|
|
6
|
+
// (derivable token, live-grepped), or UNENFORCEABLE (triage). Mirrors the self-repo gate
|
|
7
|
+
// (scripts/check-constraint-scan.mjs); extends CANON-09 to free-text governance.
|
|
8
|
+
// Usage: node scripts/check-constraint-scan.mjs [--docs=a,b] [--src=dir] [--map=path]
|
|
9
|
+
// [--enforce[=true|false]] [--baseline=path] [--update-baseline] [--help]
|
|
10
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'node:fs'
|
|
11
|
+
import { resolve, join } from 'node:path'
|
|
12
|
+
import { createHash } from 'node:crypto'
|
|
13
|
+
import { isMainModule } from './lib/run-helpers.mjs'
|
|
14
|
+
|
|
15
|
+
// Generated default: WARN on un-covered derivable prohibitions (start-warn-promote-later).
|
|
16
|
+
// Curate `constraint-map.json`, then run with --enforce=true to hard-fail in CI.
|
|
17
|
+
const ENFORCE_DEFAULT = false
|
|
18
|
+
|
|
19
|
+
// Is a readable baseline REQUIRED for the ratchet to be considered armed? FALSE here and true in
|
|
20
|
+
// arbiter's own copy, deliberately: `arbiter init` emits no coverage baseline, so requiring one
|
|
21
|
+
// would hard-fail a generated project's very first gate run on a file it was never given. A
|
|
22
|
+
// consumer arms the ratchet when ready, with `--update-baseline`; until then the RATCHET-UNSET
|
|
23
|
+
// notice below says plainly that coverage is not yet pinned.
|
|
24
|
+
const RATCHET_REQUIRED = false
|
|
25
|
+
|
|
26
|
+
// AC-3 ratchet (#2384): the covered/unenforceable ratio is pinned in a committed
|
|
27
|
+
// baseline so triage cannot silently drift back. Same one-way shape as
|
|
28
|
+
// scripts/debt-baseline.json — --update-baseline only ever tightens.
|
|
29
|
+
const BASELINE_DEFAULT = 'scripts/data/constraint-coverage-baseline.json'
|
|
30
|
+
const PROSE_PREFIX = 'prose:'
|
|
31
|
+
// An acceptance is a claim that no mechanism can carry this rule. It costs a written
|
|
32
|
+
// reason, or it is a loophole: too-short rationales are MAP-INVALID, never ACCEPTED.
|
|
33
|
+
const MIN_RATIONALE = 40
|
|
34
|
+
|
|
35
|
+
const HELP = `Usage: node scripts/check-constraint-scan.mjs [options]
|
|
36
|
+
|
|
37
|
+
Extracts hard prohibitions from governance docs and classifies each:
|
|
38
|
+
COVERED — mapped to an existing, verified enforcer (gate/hook/inv/lint/template)
|
|
39
|
+
ENFORCED-BY-SCAN — derivable code token, live-grepped against --src every run
|
|
40
|
+
ACCEPTED — judgment-level prose, explicitly triaged with a written rationale
|
|
41
|
+
UNENFORCEABLE — prose / path / non-code token, NOT yet triaged (the backlog)
|
|
42
|
+
A map entry naming a non-existent enforcer is MAP-FICTION and always fails; a
|
|
43
|
+
"prose:<verbatim line>" entry matching no extracted prohibition is MAP-DEAD; an
|
|
44
|
+
"accepted" entry without a written rationale is MAP-INVALID. Both also fail.
|
|
45
|
+
|
|
46
|
+
Options:
|
|
47
|
+
--docs=<a,b,c> Comma-separated governance docs (default: AGENTS.md,docs/SYSTEM/CANON.md,.claude/CLAUDE.md)
|
|
48
|
+
--src=<dir> Source root to scan for live hits (default: src)
|
|
49
|
+
--map=<path> Constraint map JSON (default: scripts/constraint-map.json)
|
|
50
|
+
--enforce[=bool] Hard-fail on ENFORCED-BY-SCAN live hits (default: ${ENFORCE_DEFAULT})
|
|
51
|
+
--baseline=<p> Coverage ratchet baseline (default: ${BASELINE_DEFAULT})
|
|
52
|
+
--update-baseline Tighten the baseline; REFUSES to record a regression
|
|
53
|
+
--help, -h Show this help and exit
|
|
54
|
+
`
|
|
55
|
+
|
|
56
|
+
function parseArgs(argv) {
|
|
57
|
+
const get = (name) => {
|
|
58
|
+
const flag = argv.find((a) => a === `--${name}` || a.startsWith(`--${name}=`))
|
|
59
|
+
if (!flag) return undefined
|
|
60
|
+
const eq = flag.indexOf('=')
|
|
61
|
+
return eq === -1 ? '' : flag.slice(eq + 1)
|
|
62
|
+
}
|
|
63
|
+
const docs = get('docs')
|
|
64
|
+
const src = get('src')
|
|
65
|
+
const map = get('map')
|
|
66
|
+
const enforceRaw = get('enforce')
|
|
67
|
+
const baseline = get('baseline')
|
|
68
|
+
return {
|
|
69
|
+
help: argv.includes('--help') || argv.includes('-h'),
|
|
70
|
+
baseline: baseline || BASELINE_DEFAULT,
|
|
71
|
+
updateBaseline: argv.includes('--update-baseline'),
|
|
72
|
+
// The ratchet measures THIS project's governance corpus against THIS project's map.
|
|
73
|
+
// A run pointed at fixture docs or a fixture map measures something else, so it is
|
|
74
|
+
// not ratcheted unless the caller named a baseline explicitly.
|
|
75
|
+
ratchetScoped: baseline !== undefined || (docs === undefined && map === undefined),
|
|
76
|
+
docs: docs
|
|
77
|
+
? docs.split(',').map((s) => s.trim()).filter(Boolean)
|
|
78
|
+
: ['AGENTS.md', 'docs/SYSTEM/CANON.md', '.claude/CLAUDE.md'],
|
|
79
|
+
src: src || 'src',
|
|
80
|
+
map: map || 'scripts/constraint-map.json',
|
|
81
|
+
enforce: enforceRaw === undefined ? ENFORCE_DEFAULT : enforceRaw !== 'false',
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function escapeRegExp(s) {
|
|
86
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const NEVER_BLOCK_HEADER = /^\s*\*\*(Never|Don't|Do ?not)\b[^*]*\*\*\s*$/i
|
|
90
|
+
const EXCLUDED_FIELD =
|
|
91
|
+
/^\s*(>|(?:[-*]\s+)?(?:\*\*|_)(Why|Source|Sources|Enforcement|Promoted|Extended|Tradeoff)\b)/i
|
|
92
|
+
const BULLET = /^\s*[-*]\s+/
|
|
93
|
+
const INLINE_MARKERS = [
|
|
94
|
+
/MUST\s+NOT\b/i,
|
|
95
|
+
/MUST\s+NEVER\b/i,
|
|
96
|
+
/DO\s+NOT\b/i,
|
|
97
|
+
/🛑/,
|
|
98
|
+
/^\s*[-*]?\s*No\s+(?=`)/,
|
|
99
|
+
/\bnever\b/i,
|
|
100
|
+
]
|
|
101
|
+
// #2582: the passive/adjectival register — "X is forbidden", "Y are prohibited", "prohibited: Z",
|
|
102
|
+
// "not permitted", "not allowed", "disallowed". The banned thing usually PRECEDES the marker, so
|
|
103
|
+
// tokens are derived from the clause before it (or after a lead "prohibited:" colon). Counted only
|
|
104
|
+
// at entry level: a nested sub-bullet under an entry is that entry's elaboration (mechanics, scope,
|
|
105
|
+
// enforcement notes), where this register describes context rather than states a rule (AC-4).
|
|
106
|
+
const PASSIVE_MARKER = /\b(?:forbidden|prohibited|disallowed|not\s+(?:permitted|allowed))\b/i
|
|
107
|
+
const NESTED_BULLET = /^\s{2,}[-*]\s+/
|
|
108
|
+
// A negated passive ("nothing is prohibited", "not forbidden") states the absence of a rule.
|
|
109
|
+
const NEGATED_PASSIVE = /\b(?:nothing|not|no longer)\s+(?:is\s+|are\s+)?(?:forbidden|prohibited|disallowed)\b/i
|
|
110
|
+
|
|
111
|
+
function tokensIn(text) {
|
|
112
|
+
const out = []
|
|
113
|
+
const re = /`([^`]+)`/g
|
|
114
|
+
let m
|
|
115
|
+
while ((m = re.exec(text))) out.push(m[1])
|
|
116
|
+
return out
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Every backtick token AFTER the marker is a prohibited symbol — `MUST NOT use `a` or `b``
|
|
120
|
+
// bans both. Tokens BEFORE the marker (e.g. the approved wrapper in "use `x`, never `y`") are
|
|
121
|
+
// excluded by construction. Returns [] when no token follows (→ UNENFORCEABLE).
|
|
122
|
+
function tokensAfter(line, markerRe) {
|
|
123
|
+
const m = markerRe.exec(line)
|
|
124
|
+
if (!m) return []
|
|
125
|
+
let tail = line.slice(m.index + m[0].length)
|
|
126
|
+
const boundary = tail.indexOf('. ')
|
|
127
|
+
if (boundary !== -1) tail = tail.slice(0, boundary + 1)
|
|
128
|
+
return tokensIn(tail)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Tokens for the passive register: after a lead "prohibited:" colon, otherwise the clause before
|
|
132
|
+
// the marker, clipped to its own sentence so an earlier clause's tokens are not swept in.
|
|
133
|
+
function tokensAround(line, markerRe) {
|
|
134
|
+
const m = markerRe.exec(line)
|
|
135
|
+
if (!m) return []
|
|
136
|
+
const after = line.slice(m.index + m[0].length)
|
|
137
|
+
if (/^\s*:/.test(after)) return tokensAfter(line, markerRe)
|
|
138
|
+
let before = line.slice(0, m.index)
|
|
139
|
+
// Clause boundary: the approved alternative in "use `x`; `y` is forbidden" must not be swept in.
|
|
140
|
+
const boundary = Math.max(before.lastIndexOf('. '), before.lastIndexOf('; '))
|
|
141
|
+
if (boundary !== -1) before = before.slice(boundary + 2)
|
|
142
|
+
return tokensIn(before)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function pushProhibition(out, doc, line, text, toks) {
|
|
146
|
+
if (toks.length === 0) out.push({ doc, line, text: text.trim(), token: null })
|
|
147
|
+
else for (const tk of toks) out.push({ doc, line, text: text.trim(), token: tk })
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function extractProhibitions(docPath, body) {
|
|
151
|
+
const lines = body.split('\n')
|
|
152
|
+
const out = []
|
|
153
|
+
let inBlock = false
|
|
154
|
+
let blockHasBullet = false
|
|
155
|
+
for (let i = 0; i < lines.length; i++) {
|
|
156
|
+
const line = lines[i]
|
|
157
|
+
if (NEVER_BLOCK_HEADER.test(line)) {
|
|
158
|
+
inBlock = true
|
|
159
|
+
blockHasBullet = false
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
if (inBlock) {
|
|
163
|
+
if (line.trim() === '') {
|
|
164
|
+
if (blockHasBullet) inBlock = false
|
|
165
|
+
continue
|
|
166
|
+
}
|
|
167
|
+
if (BULLET.test(line)) {
|
|
168
|
+
blockHasBullet = true
|
|
169
|
+
let toks = []
|
|
170
|
+
let markerFound = false
|
|
171
|
+
for (const marker of INLINE_MARKERS) {
|
|
172
|
+
if (marker.test(line)) {
|
|
173
|
+
toks = tokensAfter(line, marker)
|
|
174
|
+
markerFound = true
|
|
175
|
+
break
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (!markerFound) toks = tokensIn(line)
|
|
179
|
+
if (toks.length === 0) out.push({ doc: docPath, line: i + 1, text: line.trim(), token: null })
|
|
180
|
+
else for (const tk of toks) out.push({ doc: docPath, line: i + 1, text: line.trim(), token: tk })
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
183
|
+
inBlock = false
|
|
184
|
+
}
|
|
185
|
+
if (EXCLUDED_FIELD.test(line)) continue
|
|
186
|
+
const marker = INLINE_MARKERS.find((re) => re.test(line))
|
|
187
|
+
if (marker) {
|
|
188
|
+
pushProhibition(out, docPath, i + 1, line, tokensAfter(line, marker))
|
|
189
|
+
} else if (
|
|
190
|
+
!NESTED_BULLET.test(line) &&
|
|
191
|
+
PASSIVE_MARKER.test(line) &&
|
|
192
|
+
!NEGATED_PASSIVE.test(line)
|
|
193
|
+
) {
|
|
194
|
+
pushProhibition(out, docPath, i + 1, line, tokensAround(line, PASSIVE_MARKER))
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return out
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const DERIVABLE_KEYWORDS = new Set(['var', 'any', 'eval'])
|
|
201
|
+
function isDerivable(tok) {
|
|
202
|
+
const t = tok.trim()
|
|
203
|
+
if (DERIVABLE_KEYWORDS.has(t)) return true
|
|
204
|
+
if (t.length < 3) return false
|
|
205
|
+
if (t.includes('/')) return false
|
|
206
|
+
if (/\.(json|mjs|cjs|ts|tsx|js|jsx|md|txt|ya?ml|toml|lock)\b/i.test(t)) return false
|
|
207
|
+
if (/\s/.test(t)) return false
|
|
208
|
+
if (t.includes('(')) return true
|
|
209
|
+
if (/[_]/.test(t) || /[A-Z]/.test(t)) {
|
|
210
|
+
if (t.includes('-')) return false
|
|
211
|
+
return true
|
|
212
|
+
}
|
|
213
|
+
return false
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function tokenToRegExp(tok) {
|
|
217
|
+
const esc = escapeRegExp(tok)
|
|
218
|
+
return /^[A-Za-z_$][\w$]*$/.test(tok) ? new RegExp(`\\b${esc}\\b`) : new RegExp(esc)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const CODE_EXT = /\.(ts|tsx|js|jsx|mjs|cjs)$/
|
|
222
|
+
let scanIncomplete = false
|
|
223
|
+
function walk(dir, acc) {
|
|
224
|
+
let entries
|
|
225
|
+
try {
|
|
226
|
+
entries = readdirSync(dir)
|
|
227
|
+
} catch (err) {
|
|
228
|
+
process.stderr.write(`[SCAN-INCOMPLETE] cannot read dir ${dir}: ${err.message}\n`)
|
|
229
|
+
scanIncomplete = true
|
|
230
|
+
return acc
|
|
231
|
+
}
|
|
232
|
+
for (const e of entries) {
|
|
233
|
+
if (e === 'node_modules' || e === '.git' || e === 'dist' || e === 'coverage') continue
|
|
234
|
+
const full = join(dir, e)
|
|
235
|
+
let st
|
|
236
|
+
try {
|
|
237
|
+
st = statSync(full)
|
|
238
|
+
} catch (err) {
|
|
239
|
+
process.stderr.write(`[SCAN-INCOMPLETE] cannot stat ${full}: ${err.message}\n`)
|
|
240
|
+
scanIncomplete = true
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
if (st.isDirectory()) walk(full, acc)
|
|
244
|
+
else if (CODE_EXT.test(e)) acc.push(full)
|
|
245
|
+
}
|
|
246
|
+
return acc
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function enforcerExists(enforcer, kind, root) {
|
|
250
|
+
switch (kind) {
|
|
251
|
+
case 'hook':
|
|
252
|
+
return existsSync(join(root, '.claude/hooks', enforcer))
|
|
253
|
+
case 'script':
|
|
254
|
+
return existsSync(join(root, 'scripts', enforcer))
|
|
255
|
+
case 'gate': {
|
|
256
|
+
const gate = join(root, 'scripts/check-all.mjs')
|
|
257
|
+
return existsSync(gate) && readFileSync(gate, 'utf8').includes(enforcer)
|
|
258
|
+
}
|
|
259
|
+
case 'inv': {
|
|
260
|
+
const cat = join(root, 'src/invariants/catalog.ts')
|
|
261
|
+
return existsSync(cat) && readFileSync(cat, 'utf8').includes(enforcer)
|
|
262
|
+
}
|
|
263
|
+
case 'lint': {
|
|
264
|
+
// Require the rule to be ACTIVE (error/2), not merely present — a disabled rule
|
|
265
|
+
// (`"no-var": "off"`) must not read as COVERED. Works for both JSON (.eslintrc*) and
|
|
266
|
+
// flat-config (eslint.config.js) since both spell it `<rule>: 'error'` / `: 2` / `['error'`.
|
|
267
|
+
const configs = readdirSync(root).filter((f) => /eslint/i.test(f) && /\.(json|js|cjs|mjs|yaml|yml)$/i.test(f))
|
|
268
|
+
const activeRe = new RegExp(`${escapeRegExp(enforcer)}["']?\\s*[:=]\\s*\\[?\\s*["']?(error|2)\\b`)
|
|
269
|
+
return configs.some((c) => {
|
|
270
|
+
try {
|
|
271
|
+
return activeRe.test(readFileSync(join(root, c), 'utf8'))
|
|
272
|
+
// FAIL-OPEN-INTENT: unreadable config just means THIS candidate can't vouch for the rule — other readable candidates in `configs` are still checked, nothing here drops a real violation.
|
|
273
|
+
} catch {
|
|
274
|
+
return false
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
case 'githook':
|
|
279
|
+
return existsSync(join(root, '.githooks', enforcer))
|
|
280
|
+
case 'template':
|
|
281
|
+
return existsSync(join(root, enforcer))
|
|
282
|
+
default:
|
|
283
|
+
return false
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ─── Coverage ratchet (AC-3, #2384; retirement-safe + tamper-closed, #2520) ──────────────
|
|
288
|
+
// #2520 root cause: `covered` was ratcheted as an absolute "may only rise" floor, but the
|
|
289
|
+
// denominator (how many prohibitions even exist) is not fixed — a prohibition can be
|
|
290
|
+
// LEGITIMATELY RETIRED (removed from the docs and its map entry together), which shrinks
|
|
291
|
+
// `covered` without anything losing enforcement. The old floor could not tell that apart
|
|
292
|
+
// from a real regression, so retiring a covered prohibition made the ratchet unsatisfiable
|
|
293
|
+
// by any honest means (hand-edit the baseline, leave the gate permanently red, or never
|
|
294
|
+
// retire a prohibition again).
|
|
295
|
+
//
|
|
296
|
+
// Fix: `covered` is recorded for visibility only (like `accepted` already was) and is no
|
|
297
|
+
// longer itself a ratchet floor. The ONLY regression signal is `unenforceable` (the
|
|
298
|
+
// uncovered/untriaged backlog) rising — unchanged from before, lower-is-better. This
|
|
299
|
+
// correctly distinguishes the two cases a bare `covered` count could not:
|
|
300
|
+
// - retire a COVERED prohibition (removed from docs + map together): `unenforceable` is
|
|
301
|
+
// untouched, so nothing is flagged — exactly the legitimate case.
|
|
302
|
+
// - drop or break a prohibition's MAPPING while the prohibition itself still stands (the
|
|
303
|
+
// doc corpus is unchanged): the prohibition falls out of `covered` and into
|
|
304
|
+
// `unenforceable`, `unenforceable` rises, and the ratchet still refuses — exactly the
|
|
305
|
+
// regression case, caught the same way a direct rise always was.
|
|
306
|
+
// `--update-baseline` still REFUSES to write when `unenforceable` rose.
|
|
307
|
+
//
|
|
308
|
+
// Tamper-closed (#2520): a hand-edited baseline is, on its face, indistinguishable from a
|
|
309
|
+
// real one. Every WRITE stamps an `integrityHash` — a sha256 digest over the exact
|
|
310
|
+
// `{version, capturedAt, metrics}` payload — and every READ verifies it. A baseline missing
|
|
311
|
+
// the hash, or carrying one that does not match its own recorded values, was not produced
|
|
312
|
+
// by this tool and is untrusted: fail-closed at exit 2, never merely exit 1.
|
|
313
|
+
export function computeBaselineIntegrityHash(payload) {
|
|
314
|
+
return createHash('sha256')
|
|
315
|
+
.update(JSON.stringify({ version: payload.version, capturedAt: payload.capturedAt, metrics: payload.metrics }))
|
|
316
|
+
.digest('hex')
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function metricValue(metrics, key, fallback) {
|
|
320
|
+
const raw = metrics && typeof metrics === 'object' ? metrics[key] : undefined
|
|
321
|
+
const value = raw && typeof raw === 'object' ? raw.value : undefined
|
|
322
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : fallback
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// A baseline the tool did not write is untrusted, full stop — a missing hash and a
|
|
326
|
+
// mismatched hash are the same failure (not-tool-authored), reported identically.
|
|
327
|
+
function verifyBaselineIntegrity(base) {
|
|
328
|
+
if (base == null || typeof base !== 'object' || Array.isArray(base)) return false
|
|
329
|
+
const { integrityHash } = base
|
|
330
|
+
if (typeof integrityHash !== 'string' || integrityHash === '') return false
|
|
331
|
+
return integrityHash === computeBaselineIntegrityHash(base)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// #2384: a well-formed, correctly-signed baseline recording no floor for the metric the ratchet
|
|
335
|
+
// enforces used to fall back to the permissive +Infinity, so `{"version":1,"metrics":{}}` was a
|
|
336
|
+
// silent full disarm that still passed the integrity check. A floor that is not recorded is not
|
|
337
|
+
// a floor. Generated projects leave RATCHET_REQUIRED false until they seed a baseline, so this
|
|
338
|
+
// refusal is inert for them and the RATCHET-UNSET path stays their behaviour.
|
|
339
|
+
//
|
|
340
|
+
// Scoped to `unenforceable` alone, deliberately: #2520 retired the `covered` floor (written as
|
|
341
|
+
// `direction: 'informational'` and read by nothing), because a covered-count floor breaks every
|
|
342
|
+
// time a rule is legitimately retired. Demanding a floor the tool no longer enforces would be
|
|
343
|
+
// demanding a fiction — the invariant kept here is that the ENFORCED floor must be present.
|
|
344
|
+
function refuseFloorlessBaseline(path, baseUnenf) {
|
|
345
|
+
if (!RATCHET_REQUIRED) return
|
|
346
|
+
if (baseUnenf !== null) return
|
|
347
|
+
process.stdout.write(
|
|
348
|
+
`[RATCHET-MISSING] ${path} records no unenforceable floor — a baseline without metrics ` +
|
|
349
|
+
`disarms the ratchet silently; re-seed it with --update-baseline\n`,
|
|
350
|
+
)
|
|
351
|
+
process.exit(1)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Reads the committed baseline's ratchet floor. `trusted: false` (unreadable, malformed, or
|
|
355
|
+
// missing/mismatched integrityHash) is the caller's decision to act on: a plain read (no
|
|
356
|
+
// --update-baseline) must fail closed at exit 2 — a ratchet that cannot verify its floor
|
|
357
|
+
// must never silently pass. `--update-baseline` instead treats it as no verifiable floor at
|
|
358
|
+
// all and self-heals by re-signing fresh (same as the file-absent seed path) — that is
|
|
359
|
+
// exactly the deliberate, reviewed action meant to fix it, mirroring how a missing baseline
|
|
360
|
+
// is seeded rather than refused.
|
|
361
|
+
function readBaselineBounds(path) {
|
|
362
|
+
let base
|
|
363
|
+
try {
|
|
364
|
+
base = JSON.parse(readFileSync(path, 'utf8'))
|
|
365
|
+
} catch (err) {
|
|
366
|
+
process.stderr.write(`[constraint-scan] invalid baseline JSON at ${path}: ${err.message}\n`)
|
|
367
|
+
return { trusted: false }
|
|
368
|
+
}
|
|
369
|
+
if (!verifyBaselineIntegrity(base)) return { trusted: false }
|
|
370
|
+
const baseUnenf = metricValue(base.metrics, 'unenforceable', null)
|
|
371
|
+
refuseFloorlessBaseline(path, baseUnenf)
|
|
372
|
+
return {
|
|
373
|
+
trusted: true,
|
|
374
|
+
baseUnenf: baseUnenf ?? Number.POSITIVE_INFINITY,
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function ratchetOk(args, root, covered, accepted, unenforceable) {
|
|
379
|
+
if (!args.ratchetScoped) return true
|
|
380
|
+
const path = resolve(root, args.baseline)
|
|
381
|
+
const payload = {
|
|
382
|
+
version: 1,
|
|
383
|
+
capturedAt: new Date().toISOString(),
|
|
384
|
+
metrics: {
|
|
385
|
+
covered: { value: covered, unit: 'count', direction: 'informational' },
|
|
386
|
+
accepted: { value: accepted, unit: 'count', direction: 'informational' },
|
|
387
|
+
unenforceable: { value: unenforceable, unit: 'count', direction: 'lower-is-better' },
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
const write = (p) => {
|
|
391
|
+
const integrityHash = computeBaselineIntegrityHash(p)
|
|
392
|
+
writeFileSync(path, `${JSON.stringify({ ...p, integrityHash }, null, 2)}\n`)
|
|
393
|
+
}
|
|
394
|
+
if (!existsSync(path)) {
|
|
395
|
+
if (args.updateBaseline) {
|
|
396
|
+
write(payload)
|
|
397
|
+
process.stdout.write(
|
|
398
|
+
`[RATCHET-UPDATED] ${args.baseline} seeded at ${covered} covered / ${unenforceable} uncovered\n`,
|
|
399
|
+
)
|
|
400
|
+
return true
|
|
401
|
+
}
|
|
402
|
+
if (RATCHET_REQUIRED) {
|
|
403
|
+
process.stdout.write(
|
|
404
|
+
`[RATCHET-MISSING] no baseline at ${args.baseline} — the ratchet is unarmed; seed it with ` +
|
|
405
|
+
`--update-baseline (deleting the baseline must not be a way to pass)\n`,
|
|
406
|
+
)
|
|
407
|
+
return false
|
|
408
|
+
}
|
|
409
|
+
process.stdout.write(
|
|
410
|
+
`[RATCHET-UNSET] no baseline at ${args.baseline} — coverage is not ratcheted yet\n`,
|
|
411
|
+
)
|
|
412
|
+
return true
|
|
413
|
+
}
|
|
414
|
+
const bounds = readBaselineBounds(path)
|
|
415
|
+
if (!bounds.trusted) {
|
|
416
|
+
if (args.updateBaseline) {
|
|
417
|
+
write(payload)
|
|
418
|
+
process.stdout.write(
|
|
419
|
+
`[RATCHET-UPDATED] ${args.baseline} was not produced by this tool (missing/mismatched ` +
|
|
420
|
+
`integrityHash) — re-signed fresh at ${covered} covered / ${unenforceable} uncovered\n`,
|
|
421
|
+
)
|
|
422
|
+
return true
|
|
423
|
+
}
|
|
424
|
+
process.stderr.write(
|
|
425
|
+
`[constraint-scan] baseline at ${path} has a missing or mismatched integrityHash — it ` +
|
|
426
|
+
`was not produced by this tool, so its recorded values cannot be trusted. Regenerate ` +
|
|
427
|
+
`it with:\n node scripts/check-constraint-scan.mjs --update-baseline\n`,
|
|
428
|
+
)
|
|
429
|
+
process.exit(2)
|
|
430
|
+
}
|
|
431
|
+
const { baseUnenf } = bounds
|
|
432
|
+
let regressed = false
|
|
433
|
+
if (unenforceable > baseUnenf) {
|
|
434
|
+
process.stdout.write(
|
|
435
|
+
`[RATCHET] uncovered (unenforceable) rose ${baseUnenf} -> ${unenforceable} (${args.baseline})\n`,
|
|
436
|
+
)
|
|
437
|
+
regressed = true
|
|
438
|
+
}
|
|
439
|
+
if (args.updateBaseline) {
|
|
440
|
+
if (regressed) {
|
|
441
|
+
process.stdout.write(
|
|
442
|
+
'[RATCHET] refusing to update the baseline with a regression — triage the prohibitions instead\n',
|
|
443
|
+
)
|
|
444
|
+
return false
|
|
445
|
+
}
|
|
446
|
+
payload.metrics.unenforceable.value = Math.min(unenforceable, baseUnenf)
|
|
447
|
+
write(payload)
|
|
448
|
+
process.stdout.write(
|
|
449
|
+
`[RATCHET-UPDATED] ${args.baseline}: ${payload.metrics.covered.value} covered, ` +
|
|
450
|
+
`${payload.metrics.unenforceable.value} uncovered\n`,
|
|
451
|
+
)
|
|
452
|
+
return true
|
|
453
|
+
}
|
|
454
|
+
return !regressed
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function main() {
|
|
458
|
+
const args = parseArgs(process.argv.slice(2))
|
|
459
|
+
if (args.help) {
|
|
460
|
+
process.stdout.write(HELP)
|
|
461
|
+
process.exit(0)
|
|
462
|
+
}
|
|
463
|
+
const root = process.cwd()
|
|
464
|
+
|
|
465
|
+
const arbiterJsonPath = resolve(root, 'arbiter.json')
|
|
466
|
+
if (existsSync(arbiterJsonPath)) {
|
|
467
|
+
let arbiterCfg
|
|
468
|
+
try {
|
|
469
|
+
arbiterCfg = JSON.parse(readFileSync(arbiterJsonPath, 'utf8'))
|
|
470
|
+
} catch (err) {
|
|
471
|
+
process.stderr.write(`[check-constraint-scan] invalid arbiter.json: ${err.message}\n`)
|
|
472
|
+
process.exit(2)
|
|
473
|
+
}
|
|
474
|
+
if (arbiterCfg?.governance?.constraintScan === 'off') {
|
|
475
|
+
process.stdout.write(
|
|
476
|
+
'[check-constraint-scan] SKIP — governance.constraintScan is "off" in arbiter.json\n',
|
|
477
|
+
)
|
|
478
|
+
// #2052: recognized marker so runCheck surfaces SKIP, not PASS, in the gate summary.
|
|
479
|
+
process.stdout.write('[SKIP] governance.constraintScan is "off" in arbiter.json\n')
|
|
480
|
+
process.exit(0)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
let map = {}
|
|
485
|
+
const mapPath = resolve(root, args.map)
|
|
486
|
+
if (existsSync(mapPath)) {
|
|
487
|
+
try {
|
|
488
|
+
map = JSON.parse(readFileSync(mapPath, 'utf8'))
|
|
489
|
+
} catch (err) {
|
|
490
|
+
process.stderr.write(`[constraint-scan] invalid map JSON at ${mapPath}: ${err.message}\n`)
|
|
491
|
+
process.exit(2)
|
|
492
|
+
}
|
|
493
|
+
if (map === null || typeof map !== 'object' || Array.isArray(map)) {
|
|
494
|
+
process.stderr.write(
|
|
495
|
+
`[constraint-scan] invalid map JSON at ${mapPath}: expected an object, got ` +
|
|
496
|
+
`${Array.isArray(map) ? 'array' : map === null ? 'null' : typeof map}\n`,
|
|
497
|
+
)
|
|
498
|
+
process.exit(2)
|
|
499
|
+
}
|
|
500
|
+
map = Object.fromEntries(Object.entries(map).filter(([key]) => !key.startsWith('//')))
|
|
501
|
+
for (const [tok, entry] of Object.entries(map)) {
|
|
502
|
+
if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
503
|
+
process.stderr.write(
|
|
504
|
+
`[constraint-scan] invalid map JSON at ${mapPath}: entry "${tok}" must be an ` +
|
|
505
|
+
`object with enforcer/kind, got ${entry === null ? 'null' : typeof entry}\n`,
|
|
506
|
+
)
|
|
507
|
+
process.exit(2)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
} else {
|
|
511
|
+
process.stderr.write(
|
|
512
|
+
`[check-constraint-scan] FAIL — ${args.map} missing; run \`arbiter update\` to scaffold it, ` +
|
|
513
|
+
`or set governance.constraintScan:"off" in arbiter.json\n`,
|
|
514
|
+
)
|
|
515
|
+
process.exit(1)
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const prohibitions = []
|
|
519
|
+
let docsScanned = 0
|
|
520
|
+
for (const d of args.docs) {
|
|
521
|
+
const p = resolve(root, d)
|
|
522
|
+
if (!existsSync(p)) continue
|
|
523
|
+
docsScanned++
|
|
524
|
+
prohibitions.push(...extractProhibitions(d, readFileSync(p, 'utf8')))
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Fail-closed against vacuous green: a constraint gate that finds NO governance docs is
|
|
528
|
+
// misconfigured, not compliant. Zero docs found must never read as "all prohibitions enforced".
|
|
529
|
+
if (docsScanned === 0) {
|
|
530
|
+
process.stderr.write(
|
|
531
|
+
`[check-constraint-scan] no governance docs found (looked for: ${args.docs.join(', ')}) — misconfigured\n`,
|
|
532
|
+
)
|
|
533
|
+
process.exit(1)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
let srcFiles = null
|
|
537
|
+
const srcRoot = resolve(root, args.src)
|
|
538
|
+
function liveHit(tok) {
|
|
539
|
+
if (srcFiles === null) srcFiles = existsSync(srcRoot) ? walk(srcRoot, []) : []
|
|
540
|
+
const re = tokenToRegExp(tok)
|
|
541
|
+
for (const f of srcFiles) {
|
|
542
|
+
let content
|
|
543
|
+
try {
|
|
544
|
+
content = readFileSync(f, 'utf8')
|
|
545
|
+
} catch (err) {
|
|
546
|
+
process.stderr.write(`[SCAN-INCOMPLETE] cannot read ${f}: ${err.message}\n`)
|
|
547
|
+
scanIncomplete = true
|
|
548
|
+
continue
|
|
549
|
+
}
|
|
550
|
+
if (re.test(content)) return f.startsWith(root) ? f.slice(root.length + 1) : f
|
|
551
|
+
}
|
|
552
|
+
return null
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
let fiction = 0
|
|
556
|
+
let invalid = 0
|
|
557
|
+
let violations = 0
|
|
558
|
+
const seenCovered = new Set()
|
|
559
|
+
const seenAccepted = new Set()
|
|
560
|
+
const seenUnenf = new Set()
|
|
561
|
+
const usedProseKeys = new Set()
|
|
562
|
+
|
|
563
|
+
for (const pr of prohibitions) {
|
|
564
|
+
const tok = pr.token
|
|
565
|
+
if (tok && Object.prototype.hasOwnProperty.call(map, tok)) {
|
|
566
|
+
const { enforcer, kind } = map[tok]
|
|
567
|
+
if (enforcerExists(enforcer, kind, root)) {
|
|
568
|
+
if (!seenCovered.has(tok)) {
|
|
569
|
+
process.stdout.write(`[COVERED] ${tok} → ${kind}:${enforcer}\n`)
|
|
570
|
+
seenCovered.add(tok)
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
process.stdout.write(
|
|
574
|
+
`[MAP-FICTION] ${tok} → ${kind}:${enforcer} (enforcer not found) — ${pr.doc}:${pr.line}\n`,
|
|
575
|
+
)
|
|
576
|
+
fiction++
|
|
577
|
+
}
|
|
578
|
+
continue
|
|
579
|
+
}
|
|
580
|
+
// A prose entry triages one WHOLE LINE by its verbatim text — the only stable key a
|
|
581
|
+
// token-less prohibition has. It is consulted before token derivation because an explicit
|
|
582
|
+
// human triage decision for the line supersedes any token scan on that same line.
|
|
583
|
+
const proseKey = PROSE_PREFIX + pr.text
|
|
584
|
+
if (Object.prototype.hasOwnProperty.call(map, proseKey)) {
|
|
585
|
+
usedProseKeys.add(proseKey)
|
|
586
|
+
const { enforcer, kind, rationale } = map[proseKey]
|
|
587
|
+
const label = pr.text.slice(0, 60)
|
|
588
|
+
if (kind === 'accepted') {
|
|
589
|
+
if (typeof rationale !== 'string' || rationale.trim().length < MIN_RATIONALE) {
|
|
590
|
+
process.stdout.write(
|
|
591
|
+
`[MAP-INVALID] ${label} — accepted needs a rationale of >=${MIN_RATIONALE} chars ` +
|
|
592
|
+
`(${pr.doc}:${pr.line})\n`,
|
|
593
|
+
)
|
|
594
|
+
invalid++
|
|
595
|
+
} else if (!seenAccepted.has(proseKey)) {
|
|
596
|
+
process.stdout.write(`[ACCEPTED] ${label} — ${pr.doc}:${pr.line} — ${rationale}\n`)
|
|
597
|
+
seenAccepted.add(proseKey)
|
|
598
|
+
}
|
|
599
|
+
} else if (enforcerExists(enforcer, kind, root)) {
|
|
600
|
+
if (!seenCovered.has(proseKey)) {
|
|
601
|
+
process.stdout.write(`[COVERED] ${label} → ${kind}:${enforcer} — ${pr.doc}:${pr.line}\n`)
|
|
602
|
+
seenCovered.add(proseKey)
|
|
603
|
+
}
|
|
604
|
+
} else {
|
|
605
|
+
process.stdout.write(
|
|
606
|
+
`[MAP-FICTION] ${label} → ${kind}:${enforcer} (enforcer not found) — ` +
|
|
607
|
+
`${pr.doc}:${pr.line}\n`,
|
|
608
|
+
)
|
|
609
|
+
fiction++
|
|
610
|
+
}
|
|
611
|
+
continue
|
|
612
|
+
}
|
|
613
|
+
if (tok && isDerivable(tok)) {
|
|
614
|
+
const hit = liveHit(tok)
|
|
615
|
+
if (hit) {
|
|
616
|
+
if (args.enforce) {
|
|
617
|
+
process.stdout.write(`[VIOLATION] ${tok} @ ${hit} (prohibited by ${pr.doc}:${pr.line})\n`)
|
|
618
|
+
violations++
|
|
619
|
+
} else {
|
|
620
|
+
process.stdout.write(`[WARN-SCAN] ${tok} @ ${hit} (prohibited by ${pr.doc}:${pr.line})\n`)
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
continue
|
|
624
|
+
}
|
|
625
|
+
const sig = tok || pr.text.slice(0, 60)
|
|
626
|
+
if (!seenUnenf.has(sig)) {
|
|
627
|
+
process.stdout.write(`[UNENFORCEABLE] ${sig} — ${pr.doc}:${pr.line}\n`)
|
|
628
|
+
seenUnenf.add(sig)
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// A prose entry matching nothing is rot: the line it triaged was reworded or deleted, and
|
|
633
|
+
// the entry now silently vouches for a prohibition the docs no longer make.
|
|
634
|
+
for (const key of Object.keys(map)) {
|
|
635
|
+
if (!key.startsWith(PROSE_PREFIX) || usedProseKeys.has(key)) continue
|
|
636
|
+
process.stdout.write(
|
|
637
|
+
`[MAP-DEAD] ${key.slice(PROSE_PREFIX.length).slice(0, 60)} — matches no prohibition\n`,
|
|
638
|
+
)
|
|
639
|
+
invalid++
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (fiction > 0) {
|
|
643
|
+
process.stdout.write(`[check-constraint-scan] FAIL: ${fiction} map-fiction entry(ies)\n`)
|
|
644
|
+
process.exit(1)
|
|
645
|
+
}
|
|
646
|
+
if (invalid > 0) {
|
|
647
|
+
process.stdout.write(`[check-constraint-scan] FAIL: ${invalid} invalid/dead map entry(ies)\n`)
|
|
648
|
+
process.exit(1)
|
|
649
|
+
}
|
|
650
|
+
if (violations > 0) {
|
|
651
|
+
process.stdout.write(`[check-constraint-scan] FAIL: ${violations} unenforced prohibition violation(s)\n`)
|
|
652
|
+
process.exit(1)
|
|
653
|
+
}
|
|
654
|
+
if (scanIncomplete && args.enforce) {
|
|
655
|
+
process.stdout.write('[check-constraint-scan] FAIL: scan incomplete — some source files could not be read\n')
|
|
656
|
+
process.exit(1)
|
|
657
|
+
}
|
|
658
|
+
const summary =
|
|
659
|
+
`${seenCovered.size} covered, ${seenAccepted.size} accepted, ` +
|
|
660
|
+
`${seenUnenf.size} unenforceable (triage)`
|
|
661
|
+
if (!ratchetOk(args, root, seenCovered.size, seenAccepted.size, seenUnenf.size)) {
|
|
662
|
+
process.stdout.write(`[check-constraint-scan] FAIL: coverage ratchet — ${summary}
|
|
663
|
+
`)
|
|
664
|
+
process.exit(1)
|
|
665
|
+
}
|
|
666
|
+
process.stdout.write(
|
|
667
|
+
`[check-constraint-scan] OK — ${docsScanned} doc(s), ${prohibitions.length} prohibition(s): ` +
|
|
668
|
+
`${summary}
|
|
669
|
+
`,
|
|
670
|
+
)
|
|
671
|
+
process.exit(0)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (isMainModule(import.meta.url)) {
|
|
675
|
+
try {
|
|
676
|
+
main()
|
|
677
|
+
} catch (err) {
|
|
678
|
+
process.stderr.write(`[check-constraint-scan] unexpected error: ${err instanceof Error ? err.stack : String(err)}\n`)
|
|
679
|
+
process.exit(1)
|
|
680
|
+
}
|
|
681
|
+
}
|