@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,622 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// Gate schema v3 binds task, HEAD, branch, source tree, physical checkout,
|
|
4
|
+
// Node/toolchain and expiry. Start/end identity must match (#2328/#2427).
|
|
5
|
+
// Missing facts reject. Local JSON binds identity, not author authenticity;
|
|
6
|
+
// CI independently reruns the gates.
|
|
7
|
+
// CLI, hooks and pre-push use this copy. The installed engine independently
|
|
8
|
+
// implements the same contract in src/evidence/gate-binding.ts; parity tests
|
|
9
|
+
// exercise both verifiers. Never delegate engine acceptance to project scripts.
|
|
10
|
+
import { createHash } from 'node:crypto'
|
|
11
|
+
import { execFileSync } from 'node:child_process'
|
|
12
|
+
import { existsSync, mkdtempSync, readFileSync, realpathSync, rmSync } from 'node:fs'
|
|
13
|
+
import { tmpdir } from 'node:os'
|
|
14
|
+
import { join, resolve, isAbsolute } from 'node:path'
|
|
15
|
+
import { isMainModule } from './run-helpers.mjs'
|
|
16
|
+
|
|
17
|
+
export const GATE_EVIDENCE_SCHEMA = 'arbiter-gate-pass-v3'
|
|
18
|
+
export const GATE_EVIDENCE_DEFAULT_TTL_MIN = 240
|
|
19
|
+
export const GATE_EVIDENCE_LEVEL_RANK = Object.freeze({ L0: 0, L1: 1, L2: 2, L3: 3 })
|
|
20
|
+
|
|
21
|
+
/** Fields that must be present AND non-blank before any comparison happens. */
|
|
22
|
+
export const GATE_EVIDENCE_STRING_FIELDS = Object.freeze([
|
|
23
|
+
'schema',
|
|
24
|
+
'head_sha',
|
|
25
|
+
'branch',
|
|
26
|
+
'task_id',
|
|
27
|
+
'timestamp',
|
|
28
|
+
'level',
|
|
29
|
+
'node_version',
|
|
30
|
+
'tree_hash',
|
|
31
|
+
'checkout_root',
|
|
32
|
+
'toolchain_fingerprint',
|
|
33
|
+
// #2427 — identity as it stood when the gate STARTED. Present-and-non-blank is
|
|
34
|
+
// checked before anything is compared, so a v2 marker (which has no start at
|
|
35
|
+
// all) is a rejection rather than a marker whose start axis silently vanishes.
|
|
36
|
+
'gate_started_at',
|
|
37
|
+
'start_head_sha',
|
|
38
|
+
'start_tree_hash',
|
|
39
|
+
])
|
|
40
|
+
|
|
41
|
+
// Repo-resident toolchain identity, hashed by CONTENT — never by `--version`
|
|
42
|
+
// output, which is chatty, PATH-sensitive and identical across a swapped
|
|
43
|
+
// binary. `node_modules/.package-lock.json` is npm's hidden lockfile: it
|
|
44
|
+
// describes the tree that is actually INSTALLED (versions + integrity), so a
|
|
45
|
+
// reinstall that diverges from package-lock.json is caught too.
|
|
46
|
+
//
|
|
47
|
+
// The interpreter binary is deliberately NOT hashed. `process.execPath` is not
|
|
48
|
+
// stable across the four consumers — a sanitized environment resolves `node`
|
|
49
|
+
// to /usr/bin/node while an interactive shell resolves it to the version
|
|
50
|
+
// manager's build — so hashing it would turn the gate permanently red instead
|
|
51
|
+
// of catching anything. `node_version` covers the interpreter axis and is
|
|
52
|
+
// compared separately by verifyGateEvidence.
|
|
53
|
+
// arbiter ships this verifier into Java/Python/Go/Rust projects too, so the
|
|
54
|
+
// list is a fixed CROSS-LANGUAGE superset: a Node-only list would make the
|
|
55
|
+
// fingerprint the constant sha256(absent, absent, …) in every non-Node repo —
|
|
56
|
+
// an axis that can never flip red, which is the very failure this issue is
|
|
57
|
+
// about. An absent file contributes an `absent` sentinel, so the list stays
|
|
58
|
+
// deterministic across all four consumers whatever the project is.
|
|
59
|
+
export const GATE_EVIDENCE_TOOLCHAIN_INPUTS = Object.freeze([
|
|
60
|
+
// Node
|
|
61
|
+
'package.json',
|
|
62
|
+
'package-lock.json',
|
|
63
|
+
'node_modules/.package-lock.json',
|
|
64
|
+
'yarn.lock',
|
|
65
|
+
'pnpm-lock.yaml',
|
|
66
|
+
'.nvmrc',
|
|
67
|
+
// Java
|
|
68
|
+
'pom.xml',
|
|
69
|
+
'build.gradle',
|
|
70
|
+
'build.gradle.kts',
|
|
71
|
+
'gradle/wrapper/gradle-wrapper.properties',
|
|
72
|
+
// Python
|
|
73
|
+
'pyproject.toml',
|
|
74
|
+
'poetry.lock',
|
|
75
|
+
'uv.lock',
|
|
76
|
+
'requirements.txt',
|
|
77
|
+
'requirements-dev.txt',
|
|
78
|
+
// Go
|
|
79
|
+
'go.mod',
|
|
80
|
+
'go.sum',
|
|
81
|
+
// Rust
|
|
82
|
+
'Cargo.toml',
|
|
83
|
+
'Cargo.lock',
|
|
84
|
+
])
|
|
85
|
+
|
|
86
|
+
/** Clock skew tolerated before a marker counts as stamped in the future. */
|
|
87
|
+
export const GATE_EVIDENCE_FUTURE_SKEW_MIN = 2
|
|
88
|
+
|
|
89
|
+
/** Git's first line, or null: callers reject unresolvable identity. */
|
|
90
|
+
function gitLine(root, args, env = process.env) {
|
|
91
|
+
try {
|
|
92
|
+
const out = execFileSync('git', args, {
|
|
93
|
+
cwd: root,
|
|
94
|
+
env,
|
|
95
|
+
encoding: 'utf-8',
|
|
96
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
97
|
+
}).trim()
|
|
98
|
+
return out === '' ? null : out
|
|
99
|
+
// FAIL-OPEN-INTENT: null is the REJECTING value, not a default.
|
|
100
|
+
} catch {
|
|
101
|
+
return null
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Physical path of the checkout `root` belongs to, symlinks resolved. */
|
|
106
|
+
export function computeCheckoutRoot(root) {
|
|
107
|
+
const top = gitLine(root, ['rev-parse', '--show-toplevel'])
|
|
108
|
+
if (top === null) return null
|
|
109
|
+
try {
|
|
110
|
+
return realpathSync(top)
|
|
111
|
+
// Writer and verifier must agree on ONE spelling of the checkout root, so there
|
|
112
|
+
// is deliberately no un-realpath'd fallback here.
|
|
113
|
+
// FAIL-OPEN-INTENT: null rejects at both ends (no marker / unverifiable).
|
|
114
|
+
} catch {
|
|
115
|
+
return null
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Content identity of the WORKING TREE — tracked, staged and untracked-but-not
|
|
121
|
+
* -ignored files alike — as a git tree object written through a throwaway
|
|
122
|
+
* index, so neither the real index nor HEAD is touched.
|
|
123
|
+
*
|
|
124
|
+
* `.arbiter/` is excluded: it is arbiter's own runtime state (the marker being
|
|
125
|
+
* written lives there), and including it would make the stamp invalidate
|
|
126
|
+
* itself. Committed content under `.arbiter/` is still covered by `head_sha`.
|
|
127
|
+
*/
|
|
128
|
+
export function computeTreeHash(root) {
|
|
129
|
+
const top = computeCheckoutRoot(root)
|
|
130
|
+
if (top === null) return null
|
|
131
|
+
let indexDir = null
|
|
132
|
+
try {
|
|
133
|
+
indexDir = mkdtempSync(join(tmpdir(), 'arbiter-tree-index-'))
|
|
134
|
+
const env = { ...process.env, GIT_INDEX_FILE: join(indexDir, 'index') }
|
|
135
|
+
execFileSync('git', ['add', '-A'], { cwd: top, env, stdio: 'ignore' })
|
|
136
|
+
// Drop `.arbiter/` from the throwaway index rather than excluding it via
|
|
137
|
+
// pathspec: `git add -- ':(exclude).arbiter'` names the path explicitly and
|
|
138
|
+
// errors out ("paths are ignored by one of your .gitignore files") in every
|
|
139
|
+
// repo that gitignores its own runtime state — which is the normal case.
|
|
140
|
+
execFileSync('git', ['rm', '-r', '--cached', '--ignore-unmatch', '-q', '.arbiter'], {
|
|
141
|
+
cwd: top,
|
|
142
|
+
env,
|
|
143
|
+
stdio: 'ignore',
|
|
144
|
+
})
|
|
145
|
+
return gitLine(top, ['write-tree'], env)
|
|
146
|
+
// buildGateEvidence refuses to emit a marker AT ALL when this is null — its
|
|
147
|
+
// null-guard is the local guarantee (proven by "refuses to build evidence when
|
|
148
|
+
// the tree hash cannot be computed"), so the safety does not live downstream.
|
|
149
|
+
// The verifier independently reports `unverifiable`. No path treats it as a match.
|
|
150
|
+
// FAIL-OPEN-INTENT: null means "tree unhashable" and is rejected by its caller here.
|
|
151
|
+
} catch {
|
|
152
|
+
return null
|
|
153
|
+
} finally {
|
|
154
|
+
if (indexDir !== null) rmSync(indexDir, { recursive: true, force: true })
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** sha256 over the BYTES of the repo-resident toolchain inputs, in fixed order. */
|
|
159
|
+
export function computeToolchainFingerprint(root) {
|
|
160
|
+
const top = computeCheckoutRoot(root) ?? root
|
|
161
|
+
const outer = createHash('sha256')
|
|
162
|
+
for (const rel of GATE_EVIDENCE_TOOLCHAIN_INPUTS) {
|
|
163
|
+
const path = join(top, ...rel.split('/'))
|
|
164
|
+
let entry = 'absent'
|
|
165
|
+
try {
|
|
166
|
+
if (existsSync(path)) {
|
|
167
|
+
entry = createHash('sha256').update(readFileSync(path)).digest('hex')
|
|
168
|
+
}
|
|
169
|
+
// The 'unreadable' sentinel can never equal a real sha256, so an unreadable
|
|
170
|
+
// input makes the fingerprint MISMATCH and the marker is rejected. Skipping the
|
|
171
|
+
// entry instead would be the real fail-open: it silently shrinks the axis.
|
|
172
|
+
// FAIL-OPEN-INTENT: the sentinel is the rejecting value.
|
|
173
|
+
} catch {
|
|
174
|
+
entry = 'unreadable'
|
|
175
|
+
}
|
|
176
|
+
outer.update(`${rel}\n${entry}\n`)
|
|
177
|
+
}
|
|
178
|
+
return `sha256:${outer.digest('hex')}`
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Tracked-tree cleanliness at run time; untracked ('??') ignored, errors → false. */
|
|
182
|
+
function treeWasClean(root) {
|
|
183
|
+
try {
|
|
184
|
+
const porcelain = execFileSync('git', ['status', '--porcelain'], {
|
|
185
|
+
cwd: root,
|
|
186
|
+
encoding: 'utf-8',
|
|
187
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
188
|
+
})
|
|
189
|
+
return porcelain.split('\n').every((line) => line === '' || line.startsWith('??'))
|
|
190
|
+
// verifyGateEvidence requires tree_was_clean_at_run_time === true, so a stamp
|
|
191
|
+
// that cannot prove cleanliness is never honoured.
|
|
192
|
+
// FAIL-OPEN-INTENT: false is the REJECTING value.
|
|
193
|
+
} catch {
|
|
194
|
+
return false
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** A non-blank string, or `fallback`. */
|
|
199
|
+
function orFallback(value, fallback) {
|
|
200
|
+
return typeof value === 'string' && value.trim() !== '' ? value : fallback
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** A positive finite number, or `fallback`. */
|
|
204
|
+
function orPositive(value, fallback) {
|
|
205
|
+
const n = Number(value)
|
|
206
|
+
return Number.isFinite(n) && n > 0 ? n : fallback
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* #2427 — the identity of the tree a gate is ABOUT to measure, captured before
|
|
211
|
+
* its first check runs.
|
|
212
|
+
*
|
|
213
|
+
* `buildGateEvidence` used to sample head_sha and tree_hash at STAMP time only,
|
|
214
|
+
* which is why an orphaned gate could run for twenty minutes against one tree,
|
|
215
|
+
* see the branch move underneath it, and then stamp a green marker naming the
|
|
216
|
+
* tree it had never tested. Whatever a gate measures, it must have started
|
|
217
|
+
* measuring it.
|
|
218
|
+
*
|
|
219
|
+
* Returns null when either fact is unresolvable — never a partial start, because
|
|
220
|
+
* a half-known start is indistinguishable downstream from no start at all.
|
|
221
|
+
*/
|
|
222
|
+
export function captureGateStart(root) {
|
|
223
|
+
const headSha = gitLine(root, ['rev-parse', 'HEAD'])
|
|
224
|
+
const treeHash = computeTreeHash(root)
|
|
225
|
+
if (headSha === null || treeHash === null) return null
|
|
226
|
+
return { head_sha: headSha, tree_hash: treeHash, started_at: new Date().toISOString() }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Build v3 evidence only when all identity facts resolve and match gate start. */
|
|
230
|
+
export function buildGateEvidence({ root, level, taskId, ttlMinutes, start } = {}) {
|
|
231
|
+
const facts = {
|
|
232
|
+
checkoutRoot: computeCheckoutRoot(root),
|
|
233
|
+
headSha: gitLine(root, ['rev-parse', 'HEAD']),
|
|
234
|
+
branch: gitLine(root, ['rev-parse', '--abbrev-ref', 'HEAD']),
|
|
235
|
+
treeHash: computeTreeHash(root),
|
|
236
|
+
}
|
|
237
|
+
if (Object.values(facts).some((fact) => fact === null)) return null
|
|
238
|
+
|
|
239
|
+
// The whole point of #2427: end identity must equal start identity.
|
|
240
|
+
if (typeof start !== 'object' || start === null) return null
|
|
241
|
+
const startedAt = start.started_at
|
|
242
|
+
if (typeof startedAt !== 'string' || startedAt.trim() === '') return null
|
|
243
|
+
if (start.head_sha !== facts.headSha || start.tree_hash !== facts.treeHash) return null
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
schema: GATE_EVIDENCE_SCHEMA,
|
|
247
|
+
head_sha: facts.headSha,
|
|
248
|
+
branch: facts.branch,
|
|
249
|
+
gate_started_at: startedAt,
|
|
250
|
+
start_head_sha: start.head_sha,
|
|
251
|
+
start_tree_hash: start.tree_hash,
|
|
252
|
+
task_id: orFallback(taskId, 'unknown'),
|
|
253
|
+
timestamp: new Date().toISOString(),
|
|
254
|
+
level: orFallback(level, 'unknown'),
|
|
255
|
+
ttl_minutes: orPositive(ttlMinutes, GATE_EVIDENCE_DEFAULT_TTL_MIN),
|
|
256
|
+
node_version: process.version,
|
|
257
|
+
git_user: gitLine(root, ['config', 'user.name']) ?? 'unknown',
|
|
258
|
+
checkout_root: facts.checkoutRoot,
|
|
259
|
+
tree_hash: facts.treeHash,
|
|
260
|
+
toolchain_fingerprint: computeToolchainFingerprint(root),
|
|
261
|
+
tree_was_clean_at_run_time: treeWasClean(root),
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Presence FIRST: an absent or blank field must never read as unconstrained,
|
|
267
|
+
* which is what makes a pre-v2 marker a rejection rather than a free pass.
|
|
268
|
+
*/
|
|
269
|
+
function shapeProblem(marker) {
|
|
270
|
+
for (const field of GATE_EVIDENCE_STRING_FIELDS) {
|
|
271
|
+
const value = marker[field]
|
|
272
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
273
|
+
return (
|
|
274
|
+
`gate-pass marker field "${field}" is missing or empty — evidence from an older ` +
|
|
275
|
+
'arbiter is not honoured; re-run the gate to stamp a current marker'
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (marker.schema !== GATE_EVIDENCE_SCHEMA) {
|
|
280
|
+
return `gate-pass marker schema mismatch: expected "${GATE_EVIDENCE_SCHEMA}", got "${marker.schema}"`
|
|
281
|
+
}
|
|
282
|
+
if (marker.tree_was_clean_at_run_time !== true) {
|
|
283
|
+
return 'gate-pass marker tree_was_clean_at_run_time must be true'
|
|
284
|
+
}
|
|
285
|
+
return null
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** Gate level: an unknown level is never "good enough". */
|
|
289
|
+
function levelProblem(marker, minLevel) {
|
|
290
|
+
const rank = GATE_EVIDENCE_LEVEL_RANK[marker.level]
|
|
291
|
+
const required = GATE_EVIDENCE_LEVEL_RANK[minLevel]
|
|
292
|
+
if (typeof rank !== 'number') {
|
|
293
|
+
return `gate-pass marker level "${marker.level}" is not a known gate level`
|
|
294
|
+
}
|
|
295
|
+
if (typeof required !== 'number')
|
|
296
|
+
return `required gate level "${minLevel}" is not a known gate level`
|
|
297
|
+
if (rank < required) {
|
|
298
|
+
return `gate-pass marker level "${marker.level}" is below the required "${minLevel}"`
|
|
299
|
+
}
|
|
300
|
+
return null
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Age. A marker may NARROW the consumer budget with its own ttl, never widen it. */
|
|
304
|
+
function agingProblem(marker, maxAgeMin, now) {
|
|
305
|
+
if (!Number.isFinite(maxAgeMin) || maxAgeMin <= 0) {
|
|
306
|
+
return `gate-pass age budget must be a positive number, got ${JSON.stringify(maxAgeMin)}`
|
|
307
|
+
}
|
|
308
|
+
const ttl = marker.ttl_minutes
|
|
309
|
+
if (typeof ttl !== 'number' || !Number.isFinite(ttl) || ttl <= 0) {
|
|
310
|
+
return `gate-pass marker ttl_minutes must be a positive finite number, got ${JSON.stringify(ttl)}`
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const stampedAt = Date.parse(marker.timestamp)
|
|
314
|
+
if (!Number.isFinite(stampedAt)) {
|
|
315
|
+
return `gate-pass marker timestamp is not a valid date: "${marker.timestamp}"`
|
|
316
|
+
}
|
|
317
|
+
const ageMin = (now - stampedAt) / 60_000
|
|
318
|
+
if (ageMin < -GATE_EVIDENCE_FUTURE_SKEW_MIN) {
|
|
319
|
+
return `gate-pass marker timestamp is in the future: "${marker.timestamp}"`
|
|
320
|
+
}
|
|
321
|
+
const budget = Math.min(maxAgeMin, ttl)
|
|
322
|
+
if (ageMin > budget) {
|
|
323
|
+
return `gate-pass marker expired: ${Math.round(ageMin)} min old, budget ${budget} min`
|
|
324
|
+
}
|
|
325
|
+
return null
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Commit, branch and task correlation (the #1441 anti-replay axis included). */
|
|
329
|
+
function commitProblem(root, marker, taskId) {
|
|
330
|
+
const head = gitLine(root, ['rev-parse', 'HEAD'])
|
|
331
|
+
if (head === null) return 'gate-pass marker unverifiable: HEAD does not resolve'
|
|
332
|
+
if (marker.head_sha !== head) {
|
|
333
|
+
return `gate-pass marker head_sha mismatch: expected "${head}", got "${marker.head_sha}"`
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const branch = gitLine(root, ['rev-parse', '--abbrev-ref', 'HEAD'])
|
|
337
|
+
if (branch === null) return 'gate-pass marker unverifiable: branch does not resolve'
|
|
338
|
+
if (marker.branch !== branch) {
|
|
339
|
+
return `gate-pass marker branch mismatch: expected "${branch}", got "${marker.branch}"`
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (typeof taskId === 'string' && taskId.trim() !== '' && marker.task_id !== taskId) {
|
|
343
|
+
return `gate-pass marker task_id "${marker.task_id}" does not match the current task "${taskId}" (anti-replay)`
|
|
344
|
+
}
|
|
345
|
+
return null
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* #2427 — the axis that catches a gate which did not measure one tree.
|
|
350
|
+
*
|
|
351
|
+
* A marker whose start and end identities disagree describes a run that saw the
|
|
352
|
+
* tree change underneath it; nothing it reports can be attributed to either
|
|
353
|
+
* tree, so it is UNVERIFIABLE rather than merely stale. The writer already
|
|
354
|
+
* refuses to emit one, so this is the second line of defence: it also rejects a
|
|
355
|
+
* marker that was hand-edited or produced by a writer that skipped the refusal.
|
|
356
|
+
*/
|
|
357
|
+
function startEndProblem(marker) {
|
|
358
|
+
if (marker.start_head_sha !== marker.head_sha) {
|
|
359
|
+
return (
|
|
360
|
+
'gate-pass marker is unverifiable: the gate started on commit ' +
|
|
361
|
+
`"${marker.start_head_sha}" and finished on "${marker.head_sha}" — it did not ` +
|
|
362
|
+
'measure one tree from start to finish'
|
|
363
|
+
)
|
|
364
|
+
}
|
|
365
|
+
if (marker.start_tree_hash !== marker.tree_hash) {
|
|
366
|
+
return (
|
|
367
|
+
'gate-pass marker is unverifiable: the working tree changed while the gate ran ' +
|
|
368
|
+
`(started at tree "${marker.start_tree_hash}", finished at "${marker.tree_hash}")`
|
|
369
|
+
)
|
|
370
|
+
}
|
|
371
|
+
return null
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** The three axes #2328 added: checkout, toolchain and working-tree content. */
|
|
375
|
+
function identityProblem(root, marker) {
|
|
376
|
+
if (marker.node_version !== process.version) {
|
|
377
|
+
return `gate-pass marker node_version mismatch: expected "${process.version}", got "${marker.node_version}"`
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const checkoutRoot = computeCheckoutRoot(root)
|
|
381
|
+
if (checkoutRoot === null) {
|
|
382
|
+
return 'gate-pass marker unverifiable: checkout root does not resolve'
|
|
383
|
+
}
|
|
384
|
+
if (marker.checkout_root !== checkoutRoot) {
|
|
385
|
+
return (
|
|
386
|
+
`gate-pass marker checkout_root mismatch: evidence was produced in "${marker.checkout_root}", ` +
|
|
387
|
+
`this checkout is "${checkoutRoot}" — evidence does not travel between worktrees`
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (marker.toolchain_fingerprint !== computeToolchainFingerprint(root)) {
|
|
392
|
+
return (
|
|
393
|
+
'gate-pass marker toolchain_fingerprint mismatch — a lockfile or the installed ' +
|
|
394
|
+
'toolchain changed since the gate ran'
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const treeHash = computeTreeHash(root)
|
|
399
|
+
if (treeHash === null) return 'gate-pass marker unverifiable: tree hash does not resolve'
|
|
400
|
+
if (marker.tree_hash !== treeHash) {
|
|
401
|
+
return 'gate-pass marker tree_hash mismatch — the working tree changed since the gate ran'
|
|
402
|
+
}
|
|
403
|
+
return null
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Verify a marker against the tree it claims to describe.
|
|
408
|
+
*
|
|
409
|
+
* Ordered cheapest-first, and shape FIRST so a missing or blank field is a
|
|
410
|
+
* rejection before any comparison can read it as unconstrained.
|
|
411
|
+
*
|
|
412
|
+
* @returns `{ ok: true }` or `{ ok: false, reason }` — never throws.
|
|
413
|
+
*/
|
|
414
|
+
export function verifyGateEvidence(marker, opts = {}) {
|
|
415
|
+
if (typeof marker !== 'object' || marker === null || Array.isArray(marker)) {
|
|
416
|
+
return { ok: false, reason: 'gate-pass marker must be a JSON object' }
|
|
417
|
+
}
|
|
418
|
+
const root = opts.root ?? process.cwd()
|
|
419
|
+
const checks = [
|
|
420
|
+
() => shapeProblem(marker),
|
|
421
|
+
() => levelProblem(marker, opts.minLevel ?? 'L2'),
|
|
422
|
+
() =>
|
|
423
|
+
agingProblem(
|
|
424
|
+
marker,
|
|
425
|
+
Number(opts.maxAgeMin ?? GATE_EVIDENCE_DEFAULT_TTL_MIN),
|
|
426
|
+
typeof opts.now === 'number' ? opts.now : Date.now(),
|
|
427
|
+
),
|
|
428
|
+
() => commitProblem(root, marker, opts.taskId),
|
|
429
|
+
() => identityProblem(root, marker),
|
|
430
|
+
// LAST on purpose: commit/identity answer "does this marker describe THIS
|
|
431
|
+
// tree", start↔end answers "did one gate measure ONE tree". A marker that
|
|
432
|
+
// fails both deserves the first, more specific, diagnosis.
|
|
433
|
+
() => startEndProblem(marker),
|
|
434
|
+
]
|
|
435
|
+
|
|
436
|
+
for (const check of checks) {
|
|
437
|
+
const reason = check()
|
|
438
|
+
if (reason !== null) return { ok: false, reason }
|
|
439
|
+
}
|
|
440
|
+
return { ok: true }
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** Read + verify in one step; a missing or unparseable marker fails closed. */
|
|
444
|
+
export function verifyGateEvidenceFile(markerPath, opts = {}) {
|
|
445
|
+
let parsed
|
|
446
|
+
try {
|
|
447
|
+
parsed = JSON.parse(readFileSync(markerPath, 'utf-8'))
|
|
448
|
+
// A missing or corrupt marker is refused, with the parse error surfaced verbatim
|
|
449
|
+
// to the caller in the rejection reason.
|
|
450
|
+
// FAIL-OPEN-INTENT: not a swallow — this catch RETURNS A REJECTION.
|
|
451
|
+
} catch (err) {
|
|
452
|
+
return { ok: false, reason: `gate-pass marker unreadable at ${markerPath}: ${err.message}` }
|
|
453
|
+
}
|
|
454
|
+
return verifyGateEvidence(parsed, opts)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function sanitizeTaskId(raw) {
|
|
458
|
+
const cleaned = String(raw)
|
|
459
|
+
.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
460
|
+
.slice(0, 64)
|
|
461
|
+
return cleaned.length > 0 ? cleaned : 'unknown'
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function runtimeProblem(receipt, archetype) {
|
|
465
|
+
const rc = receipt.reality_contact
|
|
466
|
+
if (
|
|
467
|
+
rc === null ||
|
|
468
|
+
typeof rc !== 'object' ||
|
|
469
|
+
Array.isArray(rc) ||
|
|
470
|
+
typeof rc.required !== 'boolean'
|
|
471
|
+
) {
|
|
472
|
+
return 'done receipt reality_contact is missing or malformed'
|
|
473
|
+
}
|
|
474
|
+
if (rc.required === true && rc.passed !== true)
|
|
475
|
+
return 'done receipt required reality contact did not pass'
|
|
476
|
+
if (rc.required === false && rc.passed !== null)
|
|
477
|
+
return 'done receipt optional reality contact must be null'
|
|
478
|
+
return runtimeArchetypeProblem(rc, archetype)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function runtimeArchetypeProblem(rc, archetype) {
|
|
482
|
+
if (
|
|
483
|
+
archetype === 'backend-web-db' &&
|
|
484
|
+
(rc.required !== true || rc.passed !== true || rc.suite !== 'live-api-e2e')
|
|
485
|
+
) {
|
|
486
|
+
return 'done receipt must record a passing live-api-e2e reality contact for backend-web-db'
|
|
487
|
+
}
|
|
488
|
+
if (
|
|
489
|
+
archetype === 'frontend-spa' &&
|
|
490
|
+
(rc.required !== true ||
|
|
491
|
+
rc.passed !== true ||
|
|
492
|
+
!['render-smoke', 'visual-regression'].includes(rc.suite))
|
|
493
|
+
) {
|
|
494
|
+
return 'done receipt must record a passing render-smoke or visual-regression reality contact for frontend-spa'
|
|
495
|
+
}
|
|
496
|
+
return null
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export function verifyDoneEvidenceReceipt({
|
|
500
|
+
root = process.cwd(),
|
|
501
|
+
taskId,
|
|
502
|
+
maxAgeMin,
|
|
503
|
+
archetype,
|
|
504
|
+
} = {}) {
|
|
505
|
+
const receiptPath = join(root, '.arbiter', 'evidence', 'done', `${sanitizeTaskId(taskId)}.json`)
|
|
506
|
+
let receipt
|
|
507
|
+
try {
|
|
508
|
+
receipt = JSON.parse(readFileSync(receiptPath, 'utf-8'))
|
|
509
|
+
// FAIL-OPEN-INTENT: explicit failure returned; CLI and hooks reject ok:false.
|
|
510
|
+
} catch (err) {
|
|
511
|
+
return { ok: false, reason: `done receipt unreadable at ${receiptPath}: ${err.message}` }
|
|
512
|
+
}
|
|
513
|
+
if (receipt?.version !== 2 || receipt.task_id !== taskId || receipt.state !== 'passed') {
|
|
514
|
+
return { ok: false, reason: 'done receipt is not a current v2 PASS for this task' }
|
|
515
|
+
}
|
|
516
|
+
if (receipt.all_green !== true || receipt.no_overclaim !== true || receipt.gate_level !== 'L3') {
|
|
517
|
+
return {
|
|
518
|
+
ok: false,
|
|
519
|
+
reason: 'done receipt does not prove an all-green L3 capture without overclaim',
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
const markerPath = join(root, '.arbiter', 'gate-pass.json')
|
|
523
|
+
let markerBytes
|
|
524
|
+
let marker
|
|
525
|
+
try {
|
|
526
|
+
markerBytes = readFileSync(markerPath)
|
|
527
|
+
marker = JSON.parse(markerBytes)
|
|
528
|
+
// FAIL-OPEN-INTENT: explicit failure returned; CLI and hooks reject ok:false.
|
|
529
|
+
} catch (err) {
|
|
530
|
+
return { ok: false, reason: `gate-pass marker unreadable at ${markerPath}: ${err.message}` }
|
|
531
|
+
}
|
|
532
|
+
if (marker === null || typeof marker !== 'object' || Array.isArray(marker)) {
|
|
533
|
+
return { ok: false, reason: 'gate-pass marker must be a JSON object' }
|
|
534
|
+
}
|
|
535
|
+
if (receipt.gate_marker_sha256 !== createHash('sha256').update(markerBytes).digest('hex')) {
|
|
536
|
+
return {
|
|
537
|
+
ok: false,
|
|
538
|
+
reason: 'done receipt gate_marker_sha256 does not match the exact marker bytes',
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
for (const field of [
|
|
542
|
+
'head_sha',
|
|
543
|
+
'tree_hash',
|
|
544
|
+
'checkout_root',
|
|
545
|
+
'toolchain_fingerprint',
|
|
546
|
+
'node_version',
|
|
547
|
+
]) {
|
|
548
|
+
if (receipt[field] !== marker[field])
|
|
549
|
+
return { ok: false, reason: `done receipt ${field} does not match gate-pass marker` }
|
|
550
|
+
}
|
|
551
|
+
const markerVerdict = verifyGateEvidence(marker, { root, minLevel: 'L3', maxAgeMin, taskId })
|
|
552
|
+
if (!markerVerdict.ok) return markerVerdict
|
|
553
|
+
if (!Array.isArray(receipt.pinned_files) || receipt.pinned_files.length === 0) {
|
|
554
|
+
return { ok: false, reason: 'done receipt pinned_files is missing or empty' }
|
|
555
|
+
}
|
|
556
|
+
for (const entry of receipt.pinned_files) {
|
|
557
|
+
if (
|
|
558
|
+
!entry ||
|
|
559
|
+
typeof entry.path !== 'string' ||
|
|
560
|
+
typeof entry.sha256 !== 'string' ||
|
|
561
|
+
isAbsolute(entry.path) ||
|
|
562
|
+
entry.path.split('/').includes('..')
|
|
563
|
+
) {
|
|
564
|
+
return { ok: false, reason: 'done receipt has a malformed pinned file entry' }
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
if (realpathSync(join(root, entry.path)) !== resolve(realpathSync(root), entry.path)) {
|
|
568
|
+
return { ok: false, reason: `done receipt pinned file traverses symlinks: ${entry.path}` }
|
|
569
|
+
}
|
|
570
|
+
const actual = createHash('sha256')
|
|
571
|
+
.update(readFileSync(join(root, entry.path)))
|
|
572
|
+
.digest('hex')
|
|
573
|
+
if (actual !== entry.sha256)
|
|
574
|
+
return { ok: false, reason: `done receipt pinned file drift: ${entry.path}` }
|
|
575
|
+
// FAIL-OPEN-INTENT: explicit failure returned; CLI and hooks reject ok:false.
|
|
576
|
+
} catch (err) {
|
|
577
|
+
return {
|
|
578
|
+
ok: false,
|
|
579
|
+
reason: `done receipt pinned file unreadable: ${entry.path} (${err.message})`,
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
const runtime = runtimeProblem(receipt, archetype)
|
|
584
|
+
if (runtime !== null) return { ok: false, reason: runtime }
|
|
585
|
+
return { ok: true }
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// ── CLI: `node scripts/lib/gate-evidence.mjs verify [flags]` ────────────────
|
|
589
|
+
// Exit 0 + a one-line summary on stdout when the evidence binds; exit 1 + the
|
|
590
|
+
// reason on stderr otherwise. `.githooks/pre-push` consumes this.
|
|
591
|
+
function flag(argv, name, fallback) {
|
|
592
|
+
const index = argv.indexOf(`--${name}`)
|
|
593
|
+
if (index === -1 || index + 1 >= argv.length) return fallback
|
|
594
|
+
return argv[index + 1]
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function main(argv) {
|
|
598
|
+
if (argv[0] !== 'verify') {
|
|
599
|
+
process.stderr.write('usage: gate-evidence.mjs verify [--root d] [--min-level L2]')
|
|
600
|
+
process.stderr.write(' [--max-age-min n] [--task-id id] [--marker path]\n')
|
|
601
|
+
process.exit(2)
|
|
602
|
+
}
|
|
603
|
+
const root = flag(argv, 'root', process.cwd())
|
|
604
|
+
const markerPath = flag(argv, 'marker', join(root, '.arbiter', 'gate-pass.json'))
|
|
605
|
+
const result = verifyGateEvidenceFile(markerPath, {
|
|
606
|
+
root,
|
|
607
|
+
minLevel: flag(argv, 'min-level', 'L2'),
|
|
608
|
+
maxAgeMin: Number(flag(argv, 'max-age-min', GATE_EVIDENCE_DEFAULT_TTL_MIN)),
|
|
609
|
+
taskId: flag(argv, 'task-id', undefined),
|
|
610
|
+
})
|
|
611
|
+
if (!result.ok) {
|
|
612
|
+
process.stderr.write(`${result.reason}\n`)
|
|
613
|
+
process.exit(1)
|
|
614
|
+
}
|
|
615
|
+
const marker = JSON.parse(readFileSync(markerPath, 'utf-8'))
|
|
616
|
+
const ageMin = Math.round((Date.now() - Date.parse(marker.timestamp)) / 60_000)
|
|
617
|
+
process.stdout.write(
|
|
618
|
+
`${marker.level} evidence for ${String(marker.head_sha).slice(0, 12)} (verified ${ageMin} min ago)`,
|
|
619
|
+
)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (isMainModule(import.meta.url)) main(process.argv.slice(2))
|