@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,738 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// CATALOG: arc42 is twelve enumerable slots, not twelve paragraphs. This gate turns the
|
|
4
|
+
// CATALOG: architecture document into an addressable structure: it parses the arc42 doc into
|
|
5
|
+
// CATALOG: ARC-01..ARC-12, reports which slots the project's document actually carries, and fails when
|
|
6
|
+
// CATALOG: a project has LOST a slot its own skeleton provides. The stub count — a slot whose body
|
|
7
|
+
// CATALOG: is nothing but the skeleton's prompt comment — rides a monotone ratchet, so a project
|
|
8
|
+
// CATALOG: may leave sections unfilled but may never add an unfilled one.
|
|
9
|
+
// CATALOG: rejected a keyword scan for TODO/TBD markers, which was the first design: run over
|
|
10
|
+
// CATALOG: arbiter's own arc42 it produced three false positives, all of them prose ABOUT todo
|
|
11
|
+
// CATALOG: gates and a technical-debt count. A stub is recognised structurally instead — the body,
|
|
12
|
+
// CATALOG: with HTML comments and whitespace removed, is empty or is exactly one placeholder token.
|
|
13
|
+
// CATALOG: rejected inventing a per-tier list of required sections: src/generators/doc-set.ts
|
|
14
|
+
// CATALOG: already decides which skeleton a tier receives (canvas for solo/small, full for
|
|
15
|
+
// CATALOG: enterprise). The required set is READ from that skeleton, so this gate can never hold a
|
|
16
|
+
// CATALOG: second opinion about what a tier owes, and adding a section to a skeleton automatically
|
|
17
|
+
// CATALOG: makes it required of the projects that receive it. The converse is guarded by a second
|
|
18
|
+
// CATALOG: ratchet over the skeleton's OWN gaps against canonical ARC-01..ARC-12: without it, deleting a
|
|
19
|
+
// CATALOG: section from a skeleton would quietly lower the bar for every project that receives it,
|
|
20
|
+
// CATALOG: and the gate would report the weakened bar as a pass.
|
|
21
|
+
// CATALOG: rejected fold-in into check-doc-set.mjs because that gate answers "does the
|
|
22
|
+
// CATALOG: architecture document exist and is it fresh" — a presence question over 55 rows. This
|
|
23
|
+
// CATALOG: one answers "is the document structurally complete", for exactly one row, and folding
|
|
24
|
+
// CATALOG: them would make a missing file and a hollow file the same failure.
|
|
25
|
+
//
|
|
26
|
+
// scripts/check-arc42-slots.mjs
|
|
27
|
+
// L1 gate (INV-144): the architecture document is a filled structure, not a surviving skeleton.
|
|
28
|
+
//
|
|
29
|
+
// Usage: node scripts/check-arc42-slots.mjs [--dir <repo>] [--json] [--update-baseline]
|
|
30
|
+
// --dir names the tree to AUDIT; the arc42 skeletons are read from this script's own install root
|
|
31
|
+
// (override with --skeleton-root, which exists so the split is an explicit seam rather than an
|
|
32
|
+
// implicit one), so auditing a governed project holds it to the skeleton it was generated from.
|
|
33
|
+
// There is deliberately no --allow-increase: a rise in the stub count is legitimised by
|
|
34
|
+
// hand-editing scripts/data/arc42-baseline.json in the same PR as the section that caused it.
|
|
35
|
+
// Exit: 0 pass, 1 violation, 2 error (INV-53).
|
|
36
|
+
//
|
|
37
|
+
// Exports for unit tests: SLOTS, normalizeHeading, slotForHeading, splitSections, isStub,
|
|
38
|
+
// analyzeDocument, skeletonSlots, skeletonGaps
|
|
39
|
+
|
|
40
|
+
import { readRegularFileSync } from './lib/run-helpers.mjs'
|
|
41
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
42
|
+
import { dirname, join, resolve } from 'node:path'
|
|
43
|
+
import { fileURLToPath } from 'node:url'
|
|
44
|
+
import { parse as parseYaml } from 'yaml'
|
|
45
|
+
import {
|
|
46
|
+
loadOverlays,
|
|
47
|
+
loadTierColumn,
|
|
48
|
+
resolveEffectiveColumn,
|
|
49
|
+
resolvePresentPaths,
|
|
50
|
+
} from './lib/doc-set-resolve.mjs'
|
|
51
|
+
|
|
52
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url))
|
|
53
|
+
const SELF_ROOT = resolve(scriptDir, '..')
|
|
54
|
+
const MANIFEST_REL = join('standards', 'gold-doc-set.yml')
|
|
55
|
+
const BASELINE_REL = join('scripts', 'data', 'arc42-baseline.json')
|
|
56
|
+
const SKELETON_FILE_FOR_COLUMN = {
|
|
57
|
+
solo: 'arc42-canvas.md.ejs',
|
|
58
|
+
small: 'arc42-canvas.md.ejs',
|
|
59
|
+
enterprise: 'arc42-full.md.ejs',
|
|
60
|
+
}
|
|
61
|
+
// Two layouts, and the gate must read the right one in each. A dev checkout has `src/templates`
|
|
62
|
+
// (the source of truth) AND a `dist/templates` copy that `npm run build` refreshes — reading dist
|
|
63
|
+
// there would grade an edited skeleton against a stale build. The published package has only
|
|
64
|
+
// `dist/`, because `npm run build` does `cp -r src/templates dist/templates` and `src/` is not in
|
|
65
|
+
// package.json `files` — which is why a constant pointing at `src/templates/...` resolved in this
|
|
66
|
+
// checkout and NOWHERE else, a silent permanent SKIP for every consumer. Source first, shipped
|
|
67
|
+
// second: correct in both, and the fallback is what makes the consumer case work at all.
|
|
68
|
+
const SKELETON_ROOTS = [join('src', 'templates'), join('dist', 'templates')]
|
|
69
|
+
/** Formats the arc42 doc-set row admits that are NOT arc42 and must not be graded as one. */
|
|
70
|
+
const NON_ARC42_ALIASES = /(^|\/)(blueprint|c4-model)\.md$/i
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The twelve arc42 slots. `names` are anchored patterns matched against a NORMALIZED heading,
|
|
74
|
+
* so a document may number its sections, use `&`, or use the short form, and still resolve.
|
|
75
|
+
* A heading matching no slot is an ADDITION, which arc42 explicitly permits and this gate ignores.
|
|
76
|
+
*/
|
|
77
|
+
export const SLOTS = [
|
|
78
|
+
{
|
|
79
|
+
id: 'ARC-01',
|
|
80
|
+
title: 'Introduction and Goals',
|
|
81
|
+
// `goals` and `purpose` are deliberately NOT standalone aliases: arc42's own subsection 1.2
|
|
82
|
+
// is "Quality goals", and a `## 1.2 Quality goals` has its numbering stripped and would then
|
|
83
|
+
// satisfy a slot, letting a filled subsection mask a hollow parent section.
|
|
84
|
+
names:
|
|
85
|
+
/^(introduction|introduction and goals|about|introduzione e obiettivi|requisiti e obiettivi)$/,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'ARC-02',
|
|
89
|
+
title: 'Constraints',
|
|
90
|
+
names: /^(((architecture|architectural|technical) )?constraints|vincoli( architetturali)?)$/,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'ARC-03',
|
|
94
|
+
title: 'Context and Scope',
|
|
95
|
+
// arc42 v8 splits section 3 into "Business Context" and "Technical Context"; both are the
|
|
96
|
+
// same slot. Bare `scope` is dropped — it is a common subsection heading inside section 1.
|
|
97
|
+
names:
|
|
98
|
+
/^(context|context and scope|scope and context|system context|system scope|business context|technical context|contesto e ambito)$/,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'ARC-04',
|
|
102
|
+
title: 'Solution Strategy',
|
|
103
|
+
names: /^(solution strategy|strategy|strategia di soluzione)$/,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'ARC-05',
|
|
107
|
+
title: 'Building Block View',
|
|
108
|
+
names: /^(building blocks?|building blocks? view|vista a blocchi)$/,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'ARC-06',
|
|
112
|
+
title: 'Runtime View',
|
|
113
|
+
names: /^(runtime|runtime view|runtime scenarios|vista di runtime)$/,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'ARC-07',
|
|
117
|
+
title: 'Deployment View',
|
|
118
|
+
names: /^(deployment|deployment view|infrastructure|vista di dispiegamento)$/,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'ARC-08',
|
|
122
|
+
title: 'Crosscutting Concepts',
|
|
123
|
+
names: /^(cross ?cutting( concepts)?|concetti trasversali)$/,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'ARC-09',
|
|
127
|
+
title: 'Architecture Decisions',
|
|
128
|
+
names: /^(((architecture|architectural|design) )?decisions|decisioni architetturali)$/,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'ARC-10',
|
|
132
|
+
title: 'Quality Requirements',
|
|
133
|
+
// `quality goals` dropped for the same reason as ARC-01's: it is arc42's subsection 1.2.
|
|
134
|
+
names: /^(quality|quality requirements|quality scenarios|quality tree|requisiti di qualità)$/,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'ARC-11',
|
|
138
|
+
title: 'Risks and Technical Debt',
|
|
139
|
+
// Plural `debts` is the official arc42 v8 EN title; a document copied verbatim from
|
|
140
|
+
// arc42.org failed this gate until it was added.
|
|
141
|
+
names: /^(risks?|risks? and technical debts?|technical debts?|rischi e debito tecnico)$/,
|
|
142
|
+
},
|
|
143
|
+
{ id: 'ARC-12', title: 'Glossary', names: /^(glossary|terminology|glossario)$/ },
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
/** A body that is exactly one of these, and nothing else, is a placeholder rather than content. */
|
|
147
|
+
const PLACEHOLDER_BODY =
|
|
148
|
+
/^(tbd|todo|t\.b\.d|n\/a|na|none|nothing|xxx|to be determined|to be defined|\?+|[\u2010-\u2015-]+|_+)$/
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Heading text -> comparable token: drop leading section numbering (`3.`, `3.1`, `ARC-03 —`),
|
|
152
|
+
* spell `&` as `and`, drop trailing punctuation, lowercase, collapse whitespace.
|
|
153
|
+
*/
|
|
154
|
+
export function normalizeHeading(raw) {
|
|
155
|
+
return (
|
|
156
|
+
raw
|
|
157
|
+
.replace(/^\s*(?:(?:ARC-)?[Aa]?\d+(?:\.\d+)*)\s*[.):—–-]*\s*/i, '')
|
|
158
|
+
.replace(/&/g, ' and ')
|
|
159
|
+
// Hyphens are a typographic choice, not a semantic one: `Cross-cutting`, `Cross cutting` and
|
|
160
|
+
// `Crosscutting` are the same arc42 slot, and a slot matcher that disagreed would be a bug
|
|
161
|
+
// that reads as a missing section.
|
|
162
|
+
.replace(/[\u2010-\u2015-]+/g, ' ')
|
|
163
|
+
.replace(/[.:;,]+\s*$/, '')
|
|
164
|
+
.trim()
|
|
165
|
+
.toLowerCase()
|
|
166
|
+
.replace(/\s+/g, ' ')
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** The slot id a heading fills, or null when the heading is an addition. */
|
|
171
|
+
export function slotForHeading(raw) {
|
|
172
|
+
// A numbered subsection cannot replace its parent, even at the same Markdown level.
|
|
173
|
+
if (/^\s*(?:ARC-)?[Aa]?\d+\.\d/i.test(raw)) return null
|
|
174
|
+
const norm = normalizeHeading(raw)
|
|
175
|
+
const hit = SLOTS.find((s) => s.names.test(norm))
|
|
176
|
+
return hit ? hit.id : null
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Split markdown into sections. Three things this must get right, each of which was a live defeat:
|
|
181
|
+
*
|
|
182
|
+
* - HTML comments are stripped FIRST. A document wrapped entirely in `<!-- ... -->` renders as
|
|
183
|
+
* nothing, but slicing it into sections before stripping gave every slot a body containing the
|
|
184
|
+
* unbalanced `-->` residue, which `isStub` then read as content: a blank page scored 12/12.
|
|
185
|
+
* - The section level is DETECTED, not assumed. arc42's own single-file markdown template uses
|
|
186
|
+
* `# 1. Introduction and Goals`; assuming `##` scored such a document 0, which after the
|
|
187
|
+
* score-0 rule became a hard failure on a textbook-correct file.
|
|
188
|
+
* - Fenced blocks are skipped so a `## ` inside an example is not a section, and an UNTERMINATED
|
|
189
|
+
* fence is ignored rather than swallowing every heading after it.
|
|
190
|
+
*/
|
|
191
|
+
export function splitSections(markdown) {
|
|
192
|
+
const text = markdown.replace(/<!--[\s\S]*?-->/g, '')
|
|
193
|
+
const level = detectSectionLevel(text)
|
|
194
|
+
return sectionsAtLevel(text, level)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Headings at one level, fenced regions excluded. */
|
|
198
|
+
/** Fence state after a line: null when open text, else the open fence. CommonMark closes a fence
|
|
199
|
+
* only with a run of the SAME char at least as long as the opener, so a ``` cannot close a ````. */
|
|
200
|
+
function nextFenceState(fence, line, i) {
|
|
201
|
+
const hit = /^\s*(```+|~~~+)/.exec(line)
|
|
202
|
+
if (!hit) return { fence, isFenceLine: false }
|
|
203
|
+
if (fence === null)
|
|
204
|
+
return { fence: { char: hit[1][0], len: hit[1].length, at: i }, isFenceLine: true }
|
|
205
|
+
const closes = hit[1][0] === fence.char && hit[1].length >= fence.len
|
|
206
|
+
return { fence: closes ? null : fence, isFenceLine: true }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function headingsAtLevel(text, level) {
|
|
210
|
+
const re = new RegExp(`^ {0,3}#{${level}}\\s+(.*\\S?)\\s*$`)
|
|
211
|
+
const lines = text.split('\n')
|
|
212
|
+
const readHeading = (i) => {
|
|
213
|
+
const m = re.exec(lines[i])
|
|
214
|
+
return m ? { line: i, heading: m[1].replace(/\s+#+\s*$/, '') } : null
|
|
215
|
+
}
|
|
216
|
+
const out = []
|
|
217
|
+
let fence = null
|
|
218
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
219
|
+
const step = nextFenceState(fence, lines[i], i)
|
|
220
|
+
fence = step.fence
|
|
221
|
+
if (step.isFenceLine || fence !== null) continue
|
|
222
|
+
const h = readHeading(i)
|
|
223
|
+
if (h) out.push(h)
|
|
224
|
+
}
|
|
225
|
+
// An unterminated fence must not swallow the rest of the document: re-scan from its opener as
|
|
226
|
+
// ordinary text rather than reporting every later section as absent.
|
|
227
|
+
if (fence !== null) {
|
|
228
|
+
for (let i = fence.at + 1; i < lines.length; i += 1) {
|
|
229
|
+
const h = readHeading(i)
|
|
230
|
+
if (h) out.push(h)
|
|
231
|
+
}
|
|
232
|
+
out.sort((a, b) => a.line - b.line)
|
|
233
|
+
}
|
|
234
|
+
return out
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** The heading level this document actually uses for its arc42 sections. */
|
|
238
|
+
function detectSectionLevel(text) {
|
|
239
|
+
// `##` is the default and the tie-breaker: it is what both arbiter skeletons and the great
|
|
240
|
+
// majority of arc42 documents use. Another level wins only by matching STRICTLY more slots, so
|
|
241
|
+
// a document whose headings match nothing (or match equally) is still read at `##` rather than
|
|
242
|
+
// silently reinterpreted at a level that happens to find nothing.
|
|
243
|
+
const scoreAt = (level) =>
|
|
244
|
+
headingsAtLevel(text, level).filter((h) => slotForHeading(h.heading) !== null).length
|
|
245
|
+
let best = 2
|
|
246
|
+
let bestScore = scoreAt(2)
|
|
247
|
+
for (const level of [1, 3]) {
|
|
248
|
+
const score = scoreAt(level)
|
|
249
|
+
if (score > bestScore) {
|
|
250
|
+
bestScore = score
|
|
251
|
+
best = level
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return best
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function sectionsAtLevel(text, level) {
|
|
258
|
+
const lines = text.split('\n')
|
|
259
|
+
const heads = headingsAtLevel(text, level)
|
|
260
|
+
return heads.map((h, i) => ({
|
|
261
|
+
heading: h.heading,
|
|
262
|
+
body: lines
|
|
263
|
+
.slice(h.line + 1, i + 1 < heads.length ? heads[i + 1].line : lines.length)
|
|
264
|
+
.join('\n'),
|
|
265
|
+
}))
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** A section is a stub when nothing but the skeleton's own prompt comment survives stripping. */
|
|
269
|
+
export function isStub(body) {
|
|
270
|
+
const stripped = body
|
|
271
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
272
|
+
.replace(/^\s*#{3,}\s.*$/gm, '')
|
|
273
|
+
.trim()
|
|
274
|
+
const bare = stripped.toLowerCase().replace(/[.!]+$/, '')
|
|
275
|
+
return stripped === '' || PLACEHOLDER_BODY.test(bare)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Slot ids a markdown document carries, and which of those are stubs. */
|
|
279
|
+
export function analyzeDocument(markdown) {
|
|
280
|
+
const present = new Map()
|
|
281
|
+
for (const section of splitSections(markdown)) {
|
|
282
|
+
const slot = slotForHeading(section.heading)
|
|
283
|
+
if (slot === null) continue
|
|
284
|
+
// A slot claimed twice (e.g. `## Risks` and `## Technical debt`) counts as filled if EITHER
|
|
285
|
+
// half carries content — splitting a slot across two headings is a formatting choice, not a gap.
|
|
286
|
+
const stub = isStub(section.body)
|
|
287
|
+
if (!present.has(slot) || present.get(slot) === true) present.set(slot, stub)
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
slots: [...present.keys()].sort(),
|
|
291
|
+
stubs: [...present.entries()]
|
|
292
|
+
.filter(([, stub]) => stub)
|
|
293
|
+
.map(([id]) => id)
|
|
294
|
+
.sort(),
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** The slot ids the skeleton for a tier column provides — the required set, read not invented. */
|
|
299
|
+
export function skeletonSlots(root, column) {
|
|
300
|
+
const file = SKELETON_FILE_FOR_COLUMN[column] ?? SKELETON_FILE_FOR_COLUMN.enterprise
|
|
301
|
+
for (const base of SKELETON_ROOTS) {
|
|
302
|
+
const rel = join(base, 'docs', 'skeletons', file)
|
|
303
|
+
if (existsSync(join(root, rel))) {
|
|
304
|
+
return { rel, slots: analyzeDocument(readRegularFileSync(join(root, rel), 'utf-8')).slots }
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { rel: join(SKELETON_ROOTS[0], 'docs', 'skeletons', file), slots: null }
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Every skeleton, not just this repo's column — ratchet #2 must protect the ones we do not run. */
|
|
311
|
+
export function allSkeletonSlots(root) {
|
|
312
|
+
const out = {}
|
|
313
|
+
for (const column of Object.keys(SKELETON_FILE_FOR_COLUMN)) {
|
|
314
|
+
out[column] = skeletonSlots(root, column).slots
|
|
315
|
+
}
|
|
316
|
+
return out
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Canonical slots a skeleton does NOT provide. A gap is legitimate — the Canvas column drops
|
|
321
|
+
* Crosscutting and Glossary on purpose — but it is RATCHETED, so dropping one more is a decision
|
|
322
|
+
* that has to be written down rather than a side effect of editing a template.
|
|
323
|
+
*/
|
|
324
|
+
export function skeletonGaps(slots) {
|
|
325
|
+
return SLOTS.filter((s) => !slots.includes(s.id)).map((s) => s.id)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Gaps for EVERY column, not just the one this repo audits under. A single scalar keyed nothing:
|
|
330
|
+
* it was measured on enterprise (0 gaps) while the Canvas really drops two, so a solo/small repo
|
|
331
|
+
* was told a slot "was dropped" that never was, and arbiter's own CI never evaluated the Canvas at
|
|
332
|
+
* all — leaving ratchet #2 inert for exactly the skeleton it exists to protect.
|
|
333
|
+
*/
|
|
334
|
+
export function gapsByColumn(perColumnSlots) {
|
|
335
|
+
const out = {}
|
|
336
|
+
for (const [column, slots] of Object.entries(perColumnSlots)) {
|
|
337
|
+
// A MISSING skeleton is every slot gapped, not a column to quietly drop. Omitting it removed
|
|
338
|
+
// that column from the ratchet entirely, so deleting a skeleton file did not lower the bar —
|
|
339
|
+
// it deleted the bar.
|
|
340
|
+
out[column] = slots === null ? SLOTS.map((x) => x.id) : skeletonGaps(slots)
|
|
341
|
+
}
|
|
342
|
+
return out
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function loadObject(path, label, parse = JSON.parse) {
|
|
346
|
+
try {
|
|
347
|
+
const value = parse(readRegularFileSync(path, 'utf-8'))
|
|
348
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
349
|
+
throw new Error('expected an object')
|
|
350
|
+
}
|
|
351
|
+
return { value }
|
|
352
|
+
} catch (err) {
|
|
353
|
+
process.stderr.write(`check-arc42-slots: ERROR — ${label}: ${err.message}\n`)
|
|
354
|
+
return { code: 2 }
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function resolveArc42Path(root) {
|
|
359
|
+
const manifestPath = join(root, MANIFEST_REL)
|
|
360
|
+
if (!existsSync(manifestPath)) return { skip: `no manifest at ${MANIFEST_REL}` }
|
|
361
|
+
const loaded = loadObject(manifestPath, MANIFEST_REL, parseYaml)
|
|
362
|
+
if (loaded.code !== undefined) return loaded
|
|
363
|
+
const manifest = loaded.value
|
|
364
|
+
// The path list is READ from the arc42 row rather than restated here, so this gate and
|
|
365
|
+
// check-doc-set.mjs can never disagree about where a project's architecture document lives.
|
|
366
|
+
const row = (manifest.checks || []).find((c) => c.template === 'arc42')
|
|
367
|
+
if (!row) return { skip: `no arc42 row in ${MANIFEST_REL}` }
|
|
368
|
+
const found = resolvePresentPaths(row, root)
|
|
369
|
+
if (found.length === 0)
|
|
370
|
+
return { skip: 'no architecture document present (check-doc-set owns absence)' }
|
|
371
|
+
// accept_any is an unordered set of aliases, so the first entry is NOT the arc42 — in arbiter's
|
|
372
|
+
// own tree it resolves to a reading-order hub page. Score every present candidate and take the
|
|
373
|
+
// one carrying the most slots: the document that is most arc42-shaped IS the arc42.
|
|
374
|
+
const scored = found
|
|
375
|
+
.map((rel) => ({
|
|
376
|
+
rel,
|
|
377
|
+
slots: analyzeDocument(readRegularFileSync(join(root, rel), 'utf-8')).slots,
|
|
378
|
+
}))
|
|
379
|
+
.sort((a, b) => b.slots.length - a.slots.length || a.rel.localeCompare(b.rel))
|
|
380
|
+
// The manifest's arc42 row deliberately admits non-arc42 formats too — `blueprint.md` and
|
|
381
|
+
// `**/c4-model.md` are listed in its accept_any. Grading a C4 model against arc42's twelve slots
|
|
382
|
+
// would hard-fail a project that legitimately chose C4, so those resolve to a SKIP: presence is
|
|
383
|
+
// check-doc-set's business, and this gate has nothing to say about a format it does not model.
|
|
384
|
+
if (NON_ARC42_ALIASES.test(scored[0].rel) && scored[0].slots.length === 0) {
|
|
385
|
+
return {
|
|
386
|
+
skip:
|
|
387
|
+
`${scored[0].rel} is a non-arc42 architecture format the manifest admits ` +
|
|
388
|
+
`(blueprint / c4-model) — check-doc-set owns its presence`,
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// Otherwise a zero-scoring candidate is NOT a skip. Replacing an arc42 with "# Architecture /
|
|
392
|
+
// See the wiki." scored 0, skipped, exited 0 — and check-doc-set stayed green because the file
|
|
393
|
+
// exists, so the two gates together certified "architecture documented" for a document with no
|
|
394
|
+
// architecture in it. Report the score and let the caller turn it into a violation.
|
|
395
|
+
return {
|
|
396
|
+
path: scored[0].rel,
|
|
397
|
+
score: scored[0].slots.length,
|
|
398
|
+
candidates: scored.map((c) => `${c.rel}:${c.slots.length}`),
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function report(violations, summary, json) {
|
|
403
|
+
if (json) {
|
|
404
|
+
process.stdout.write(`${JSON.stringify({ ...summary, violations }, null, 2)}\n`)
|
|
405
|
+
} else if (violations.length > 0) {
|
|
406
|
+
process.stderr.write(`check-arc42-slots: FAIL — ${violations.length} violation(s)\n`)
|
|
407
|
+
for (const v of violations) process.stderr.write(` - ${v}\n`)
|
|
408
|
+
} else {
|
|
409
|
+
process.stdout.write(
|
|
410
|
+
`check-arc42-slots: PASS — ${summary.doc}: ${summary.filled}/${summary.required} required ` +
|
|
411
|
+
`slots filled, ${summary.stubs.length} stub(s) (baseline ${summary.baseline})\n`,
|
|
412
|
+
)
|
|
413
|
+
}
|
|
414
|
+
return violations.length > 0 ? 1 : 0
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* The required slot set, and where it came from. Inside arbiter the EJS skeleton is authoritative;
|
|
419
|
+
* a governed project does not ship the skeletons, so the emitted `required` list in the baseline
|
|
420
|
+
* is. When both exist they must agree — a divergence means the set governed projects are held to
|
|
421
|
+
* has drifted from the skeleton they were built from, and that is reported, not reconciled.
|
|
422
|
+
*/
|
|
423
|
+
function resolveRequired(fromSkeleton, fromBaseline, skeletonRel) {
|
|
424
|
+
const drift =
|
|
425
|
+
fromSkeleton !== null && fromBaseline !== null && fromSkeleton.join() !== fromBaseline.join()
|
|
426
|
+
? [
|
|
427
|
+
`${BASELINE_REL}: \`required\` is [${fromBaseline.join(', ')}] but ${skeletonRel} provides ` +
|
|
428
|
+
`[${fromSkeleton.join(', ')}] — the set governed projects are held to has drifted from ` +
|
|
429
|
+
`the skeleton they receive. Run --update-baseline.`,
|
|
430
|
+
]
|
|
431
|
+
: []
|
|
432
|
+
return { required: fromSkeleton ?? fromBaseline, drift }
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/** The two ratchet verdicts: hollow slots in the document, canonical gaps in the skeleton. */
|
|
436
|
+
function ratchetViolations({ docPath, stubs, allowed, gapsByCol, allowedByCol }) {
|
|
437
|
+
const out = []
|
|
438
|
+
if (stubs.length > allowed) {
|
|
439
|
+
out.push(
|
|
440
|
+
`${docPath}: ${stubs.length} hollow slot(s) (${stubs.join(', ')}), baseline allows ` +
|
|
441
|
+
`${allowed} — a section may be left unfilled, but a new unfilled one may not be added.`,
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
// Every column, not just this repo's: a scalar keyed to the auditing column left the Canvas
|
|
445
|
+
// skeleton — which arbiter's own CI never resolves — completely unguarded.
|
|
446
|
+
for (const [col, gaps] of Object.entries(gapsByCol)) {
|
|
447
|
+
const permitted = allowedByCol[col]
|
|
448
|
+
if (typeof permitted !== 'number') {
|
|
449
|
+
out.push(`${BASELINE_REL}: skeletonGaps has no entry for the "${col}" column`)
|
|
450
|
+
continue
|
|
451
|
+
}
|
|
452
|
+
if (gaps.length > permitted) {
|
|
453
|
+
out.push(
|
|
454
|
+
`the "${col}" arc42 skeleton omits ${gaps.length} canonical slot(s) (${gaps.join(', ')}), ` +
|
|
455
|
+
`baseline allows ${permitted} — a slot dropped from a skeleton lowers the bar for every ` +
|
|
456
|
+
`project that receives it, so the drop lands in the baseline diff or not at all.`,
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return out
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** Slots the document owes its skeleton and does not carry. */
|
|
464
|
+
function missingSlotViolations(required, carried, docPath, column, source) {
|
|
465
|
+
return required
|
|
466
|
+
.filter((id) => !carried.has(id))
|
|
467
|
+
.map((id) => {
|
|
468
|
+
const slot = SLOTS.find((s) => s.id === id) ?? { title: 'unknown slot id' }
|
|
469
|
+
return (
|
|
470
|
+
`${docPath}: slot ${id} (${slot.title}) is absent, but ${source} — the skeleton this ` +
|
|
471
|
+
`project's "${column}" column receives — provides it. Either the section was removed from ` +
|
|
472
|
+
`the document, or the column rose (a promoted collaborationMode or tier_floor raises the ` +
|
|
473
|
+
`bar and does not backfill the document). Both are real gaps; add the section.`
|
|
474
|
+
)
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Write the baseline, creating `scripts/data/` if absent — a generated project has `scripts/` but
|
|
480
|
+
* not `scripts/data/`, so the unguarded write was an ENOENT reported as a document violation.
|
|
481
|
+
*/
|
|
482
|
+
function persistBaseline(baselinePath, next) {
|
|
483
|
+
mkdirSync(dirname(baselinePath), { recursive: true })
|
|
484
|
+
writeFileSync(baselinePath, `${JSON.stringify(next, null, 2)}\n`)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function updateBaseline(baselinePath, baseline, required, stubs, gapsByCol, allowed, allowedByCol) {
|
|
488
|
+
const risen = []
|
|
489
|
+
if (stubs > allowed) risen.push(`stubs ${allowed} -> ${stubs}`)
|
|
490
|
+
const nextGaps = {}
|
|
491
|
+
for (const [col, gaps] of Object.entries(gapsByCol)) {
|
|
492
|
+
nextGaps[col] = gaps.length
|
|
493
|
+
const permitted = allowedByCol[col]
|
|
494
|
+
if (typeof permitted === 'number' && gaps.length > permitted) {
|
|
495
|
+
risen.push(`skeletonGaps.${col} ${permitted} -> ${gaps.length}`)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (risen.length > 0) {
|
|
499
|
+
process.stderr.write(
|
|
500
|
+
`check-arc42-slots: refusing --update-baseline — ${risen.join(', ')}. ` +
|
|
501
|
+
`Raise the number by hand, in the same PR as the section that needs it.\n`,
|
|
502
|
+
)
|
|
503
|
+
return 1
|
|
504
|
+
}
|
|
505
|
+
persistBaseline(baselinePath, { ...baseline, required, stubs, skeletonGaps: nextGaps })
|
|
506
|
+
process.stdout.write(
|
|
507
|
+
`check-arc42-slots: baseline updated — stubs ${stubs}, skeletonGaps ${JSON.stringify(nextGaps)}\n`,
|
|
508
|
+
)
|
|
509
|
+
return 0
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* The four things argv decides. `--dir` is the tree to AUDIT and defaults to cwd, exactly as
|
|
514
|
+
* check-doc-set.mjs is run by `arbiter doc-set`; `--skeleton-root` is where the arc42 skeletons
|
|
515
|
+
* come from and defaults to arbiter's own install — the two are separate because in production
|
|
516
|
+
* they ARE separate, and conflating them would hold a governed project to a skeleton it carries.
|
|
517
|
+
*/
|
|
518
|
+
function parseArgs(argv) {
|
|
519
|
+
const dirIdx = argv.indexOf('--dir')
|
|
520
|
+
const skelIdx = argv.indexOf('--skeleton-root')
|
|
521
|
+
return {
|
|
522
|
+
root: dirIdx === -1 ? process.cwd() : resolve(argv[dirIdx + 1]),
|
|
523
|
+
skeletonRoot: skelIdx === -1 ? SELF_ROOT : resolve(argv[skelIdx + 1]),
|
|
524
|
+
updateBaseline: argv.includes('--update-baseline'),
|
|
525
|
+
json: argv.includes('--json'),
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* What the ratchet currently permits. With NO baseline file the gate records where the tree is
|
|
531
|
+
* rather than failing it: a freshly generated project's arc42 is hollow by construction, and a
|
|
532
|
+
* gate that made `arbiter init` produce a red repo would only teach people to delete the gate.
|
|
533
|
+
* Deleting the baseline later to reset is possible and deliberate — it lands in the diff.
|
|
534
|
+
*/
|
|
535
|
+
/** A ratchet counter is a finite, non-negative integer — never Infinity, a float, or a string. */
|
|
536
|
+
function isCount(v) {
|
|
537
|
+
return typeof v === 'number' && Number.isInteger(v) && v >= 0
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/** Validate a DECLARED skeletonGaps map: right shape, every shipped column, no unknown column. */
|
|
541
|
+
function validateDeclaredGaps(declared, gapCount) {
|
|
542
|
+
if (declared === undefined) return null
|
|
543
|
+
if (typeof declared !== 'object' || declared === null || Array.isArray(declared)) {
|
|
544
|
+
return (
|
|
545
|
+
`${BASELINE_REL}: "skeletonGaps" is ${JSON.stringify(declared)}, not a per-column object ` +
|
|
546
|
+
`— a scalar or array here left every column but the auditing one unguarded`
|
|
547
|
+
)
|
|
548
|
+
}
|
|
549
|
+
for (const col of Object.keys(declared)) {
|
|
550
|
+
// Object.hasOwn, not `in`: `'__proto__' in obj` is true for every object, so `in` let an
|
|
551
|
+
// unknown key named __proto__ straight through.
|
|
552
|
+
if (!Object.hasOwn(gapCount, col)) {
|
|
553
|
+
return `${BASELINE_REL}: skeletonGaps names unknown column "${col}"`
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
for (const col of Object.keys(gapCount)) {
|
|
557
|
+
if (!isCount(declared[col])) {
|
|
558
|
+
return (
|
|
559
|
+
`${BASELINE_REL}: skeletonGaps."${col}" is ${JSON.stringify(declared[col])}, not a whole ` +
|
|
560
|
+
`count — every shipped column must be pinned, or the unpinned one is unguarded`
|
|
561
|
+
)
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return null
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function allowancesFrom(baseline, stubCount, gapCount) {
|
|
568
|
+
// A COUNT, not merely a number. `"0"` is a string; `1e999` is Infinity and would permit any
|
|
569
|
+
// number of hollow slots forever; a float is not a count. Each looks innocuous in a diff and
|
|
570
|
+
// each disabled the ratchet permanently while --json kept reporting health.
|
|
571
|
+
if (baseline.stubs !== undefined && !isCount(baseline.stubs)) {
|
|
572
|
+
return {
|
|
573
|
+
error: `${BASELINE_REL}: "stubs" is ${JSON.stringify(baseline.stubs)}, not a whole count`,
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const declared = baseline.skeletonGaps
|
|
577
|
+
const gapsError = validateDeclaredGaps(declared, gapCount)
|
|
578
|
+
if (gapsError !== null) return { error: gapsError }
|
|
579
|
+
|
|
580
|
+
const allowedByCol = {}
|
|
581
|
+
for (const [col, gaps] of Object.entries(gapCount)) {
|
|
582
|
+
// With no baseline at all, bootstrap from what we measured — the ONLY backfill allowed. A
|
|
583
|
+
// DECLARED map is complete by the check above, so a missing key can never re-permit today's
|
|
584
|
+
// count silently, which was the same laundering as a non-numeric counter one level down.
|
|
585
|
+
allowedByCol[col] = declared === undefined ? gaps.length : declared[col]
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
allowed: typeof baseline.stubs === 'number' ? baseline.stubs : stubCount,
|
|
589
|
+
allowedByCol,
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/** The document exists but carries no arc42 at all — check-doc-set cannot see this. */
|
|
594
|
+
function emptyDocumentViolation(located) {
|
|
595
|
+
if (located.score !== 0) return []
|
|
596
|
+
return [
|
|
597
|
+
`${located.path}: carries none of the twelve arc42 slots (candidates scored: ` +
|
|
598
|
+
`${located.candidates.join(', ')}) — the document exists, so check-doc-set is green, but ` +
|
|
599
|
+
`there is no architecture in it. A file that answers no arc42 question is not an arc42.`,
|
|
600
|
+
]
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Arm the ratchet on a clean first run. Tolerating the count only in memory meant no governed
|
|
605
|
+
* project ever grew a baseline, so `allowed` was recomputed as "whatever it is today" every run
|
|
606
|
+
* and the ratchet was inert everywhere except this repo.
|
|
607
|
+
*
|
|
608
|
+
* No `required` in the seed: it is column-SPECIFIC, so seeding it under one column and later
|
|
609
|
+
* promoting the tier reported a "drift" when only the column had changed. And a write failure is
|
|
610
|
+
* a warning, never a failure — an audit gate must not need write access to reach a verdict it has
|
|
611
|
+
* already computed (read-only checkouts, hardened containers).
|
|
612
|
+
*/
|
|
613
|
+
function seedBaselineIfAbsent(baselinePath, stubs, gapsByCol) {
|
|
614
|
+
if (existsSync(baselinePath)) return
|
|
615
|
+
const seeded = {}
|
|
616
|
+
for (const [col, gaps] of Object.entries(gapsByCol)) seeded[col] = gaps.length
|
|
617
|
+
try {
|
|
618
|
+
persistBaseline(baselinePath, { stubs, skeletonGaps: seeded })
|
|
619
|
+
// stderr, not stdout: under --json stdout must stay a single parseable document.
|
|
620
|
+
process.stderr.write(`check-arc42-slots: seeded ${BASELINE_REL} — the ratchet is now armed\n`)
|
|
621
|
+
} catch (err) {
|
|
622
|
+
process.stderr.write(
|
|
623
|
+
`check-arc42-slots: could not seed ${BASELINE_REL} (${err.message}) — verdict stands, but ` +
|
|
624
|
+
`the ratchet stays unarmed until this file exists and is committed\n`,
|
|
625
|
+
)
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function skip(why) {
|
|
630
|
+
process.stdout.write(`check-arc42-slots: SKIP — ${why}\n`)
|
|
631
|
+
// #2052: recognized marker so runCheck surfaces SKIP, not PASS, in the gate summary.
|
|
632
|
+
process.stdout.write(`[SKIP] ${why}\n`)
|
|
633
|
+
return 0
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/** The tier column, the skeleton it names, and the baseline — or an exit code saying why not. */
|
|
637
|
+
function loadContext(root, skeletonRoot) {
|
|
638
|
+
// The EFFECTIVE column, floor included — check-doc-set.mjs resolves it the same way, and a gate
|
|
639
|
+
// that read the derived column alone would demand the Canvas of a repo the doc-set treats as
|
|
640
|
+
// enterprise.
|
|
641
|
+
const { tierFloor } = loadOverlays(root, join('standards', 'doc-profile'))
|
|
642
|
+
const column = resolveEffectiveColumn(loadTierColumn(root), tierFloor)
|
|
643
|
+
const { rel: skeletonRel, slots: fromSkeleton } = skeletonSlots(skeletonRoot, column)
|
|
644
|
+
|
|
645
|
+
const baselinePath = join(root, BASELINE_REL)
|
|
646
|
+
const loaded = existsSync(baselinePath) ? loadObject(baselinePath, BASELINE_REL) : { value: {} }
|
|
647
|
+
if (loaded.code !== undefined) return { code: loaded.code }
|
|
648
|
+
return {
|
|
649
|
+
column,
|
|
650
|
+
skeletonRel,
|
|
651
|
+
fromSkeleton,
|
|
652
|
+
baselinePath,
|
|
653
|
+
baseline: loaded.value,
|
|
654
|
+
fromBaseline: Array.isArray(loaded.value.required) ? loaded.value.required : null,
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function main() {
|
|
659
|
+
const { root, skeletonRoot, updateBaseline: doUpdate, json } = parseArgs(process.argv.slice(2))
|
|
660
|
+
|
|
661
|
+
const located = resolveArc42Path(root)
|
|
662
|
+
if (located.code !== undefined) return located.code
|
|
663
|
+
if (located.skip) return skip(located.skip)
|
|
664
|
+
|
|
665
|
+
const ctx = loadContext(root, skeletonRoot)
|
|
666
|
+
if (ctx.code !== undefined) return ctx.code
|
|
667
|
+
const { column, skeletonRel, fromSkeleton, baselinePath, baseline, fromBaseline } = ctx
|
|
668
|
+
|
|
669
|
+
const { required, drift } = resolveRequired(fromSkeleton, fromBaseline, skeletonRel)
|
|
670
|
+
if (required === null) {
|
|
671
|
+
return skip(`neither ${skeletonRel} nor a \`required\` list in ${BASELINE_REL} is present`)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const doc = analyzeDocument(readRegularFileSync(join(root, located.path), 'utf-8'))
|
|
675
|
+
const carried = new Set(doc.slots)
|
|
676
|
+
// Every skeleton this arbiter ships, so a column nobody audits still cannot lose a slot.
|
|
677
|
+
const gapsByCol = gapsByColumn(allSkeletonSlots(skeletonRoot))
|
|
678
|
+
const allowances = allowancesFrom(baseline, doc.stubs.length, gapsByCol)
|
|
679
|
+
if (allowances.error !== undefined) {
|
|
680
|
+
process.stderr.write(`check-arc42-slots: ERROR — ${allowances.error}\n`)
|
|
681
|
+
return 2
|
|
682
|
+
}
|
|
683
|
+
const { allowed, allowedByCol } = allowances
|
|
684
|
+
const requiredSource = fromSkeleton !== null ? skeletonRel : BASELINE_REL
|
|
685
|
+
|
|
686
|
+
if (doUpdate) {
|
|
687
|
+
return updateBaseline(
|
|
688
|
+
baselinePath,
|
|
689
|
+
baseline,
|
|
690
|
+
required,
|
|
691
|
+
doc.stubs.length,
|
|
692
|
+
gapsByCol,
|
|
693
|
+
allowed,
|
|
694
|
+
allowedByCol,
|
|
695
|
+
)
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const violations = [
|
|
699
|
+
...drift,
|
|
700
|
+
...missingSlotViolations(required, carried, located.path, column, requiredSource),
|
|
701
|
+
...ratchetViolations({
|
|
702
|
+
docPath: located.path,
|
|
703
|
+
stubs: doc.stubs,
|
|
704
|
+
allowed,
|
|
705
|
+
gapsByCol,
|
|
706
|
+
allowedByCol,
|
|
707
|
+
}),
|
|
708
|
+
]
|
|
709
|
+
violations.unshift(...emptyDocumentViolation(located))
|
|
710
|
+
|
|
711
|
+
const summary = {
|
|
712
|
+
doc: located.path,
|
|
713
|
+
column,
|
|
714
|
+
requiredFrom: requiredSource,
|
|
715
|
+
required: required.length,
|
|
716
|
+
filled: required.filter((id) => carried.has(id) && !doc.stubs.includes(id)).length,
|
|
717
|
+
present: doc.slots,
|
|
718
|
+
stubs: doc.stubs,
|
|
719
|
+
skeletonGaps: gapsByCol,
|
|
720
|
+
baseline: allowed,
|
|
721
|
+
baselineSkeletonGaps: allowedByCol,
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (violations.length === 0) seedBaselineIfAbsent(baselinePath, doc.stubs.length, gapsByCol)
|
|
725
|
+
|
|
726
|
+
return report(violations, summary, json)
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
730
|
+
try {
|
|
731
|
+
process.exit(main())
|
|
732
|
+
} catch (err) {
|
|
733
|
+
process.stderr.write(`check-arc42-slots: ERROR — unexpected: ${err.message}\n`)
|
|
734
|
+
// INV-53: an error is exit 2. Exiting 1 misfiled every EACCES/EISDIR/ENOENT as a document
|
|
735
|
+
// gap — the gate accusing the architecture doc of a defect in the gate's own plumbing.
|
|
736
|
+
process.exit(2)
|
|
737
|
+
}
|
|
738
|
+
}
|