@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,225 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// scripts/check-min-test-execution.mjs — generated by arbiter (anti-fake-green, INV-25).
|
|
4
|
+
//
|
|
5
|
+
// No-empty-suite / min-execution guard. A test tier that collects ZERO tests yet exits 0 is the
|
|
6
|
+
// classic false-green ("100 tests, 0 executed = green"): the gate is green while no test body ever
|
|
7
|
+
// ran. The runner's own exit code does not catch it — `vitest run --passWithNoTests`,
|
|
8
|
+
// `pytest` on an empty tree (exit 5 swallowed), and a `go test ./...` over a package with no test
|
|
9
|
+
// files all report success on zero tests. This guard asks the project's test runner how many tests
|
|
10
|
+
// it would run and FAILS when that count is 0.
|
|
11
|
+
//
|
|
12
|
+
// It uses each runner's COLLECT / LIST mode (no test bodies execute), so it is cheap and never
|
|
13
|
+
// double-runs the suite:
|
|
14
|
+
// - vitest : `vitest list` → one line per collected test (the " > " test-id form)
|
|
15
|
+
// - jest : `jest --listTests` → one line per test FILE (file-level proxy)
|
|
16
|
+
// - pytest : `pytest --collect-only -q` → "<N> tests collected" / "no tests collected"
|
|
17
|
+
// - go : `go test -list '.*' ./...` → one line per Test/Example/Benchmark/Fuzz function
|
|
18
|
+
//
|
|
19
|
+
// Semantics:
|
|
20
|
+
// - no recognized runner → NA (exit 0) — nothing to assert.
|
|
21
|
+
// - runner recognized, not installed→ SKIP (exit 0) — deps not present yet (fresh greenfield);
|
|
22
|
+
// the real test gate would fail first if this mattered.
|
|
23
|
+
// - collection errored (build/import
|
|
24
|
+
// failure, unexpected exit) → ERROR(exit 2) — surfaced loudly, never masked as "0 tests".
|
|
25
|
+
// - collected 0 tests → FAIL (exit 1) — the empty-suite false-green.
|
|
26
|
+
// - collected > 0 tests → PASS (exit 0).
|
|
27
|
+
//
|
|
28
|
+
// This guard targets the EMPTY-collection false-green. Whether an all-skipped suite trips it is the
|
|
29
|
+
// runner's call: `vitest list` omits skipped tests (so an all-skipped suite collects 0 and FAILS
|
|
30
|
+
// here), while `pytest --collect-only` counts them (so it passes here and is left to the muted-test
|
|
31
|
+
// guard, check-muted-test). The two guards overlap by design — defense in depth, never a gap.
|
|
32
|
+
//
|
|
33
|
+
// Usage: node scripts/check-min-test-execution.mjs [--help]
|
|
34
|
+
// Exit codes (INV-53): 0=PASS/NA/SKIP, 1=FAIL (empty suite), 2=ERROR (collector failure / self).
|
|
35
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
36
|
+
import { join } from 'node:path'
|
|
37
|
+
import { spawnSync } from 'node:child_process'
|
|
38
|
+
|
|
39
|
+
const args = process.argv.slice(2)
|
|
40
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
41
|
+
process.stdout.write(
|
|
42
|
+
'Usage: node scripts/check-min-test-execution.mjs\n' +
|
|
43
|
+
' Fails when the project test runner collects 0 tests (the empty-suite false-green).\n' +
|
|
44
|
+
' Uses the runner collect/list mode (no execution). NA when no recognized runner.\n',
|
|
45
|
+
)
|
|
46
|
+
process.exit(0)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Test seam (INV / anti-vacuous): `--parse <runner>` reads collect output on stdin and prints the
|
|
50
|
+
// parsed count (or "null"). Lets the parsers be exercised against real captured runner output
|
|
51
|
+
// without invoking the runner — keeping the guard's own test deterministic and toolchain-free.
|
|
52
|
+
const parseIdx = args.indexOf('--parse')
|
|
53
|
+
if (parseIdx !== -1) {
|
|
54
|
+
const runner = args[parseIdx + 1]
|
|
55
|
+
const counters = { vitest: countVitest, jest: countJest, pytest: countPytest, go: countGo }
|
|
56
|
+
const counter = counters[runner]
|
|
57
|
+
if (!counter) {
|
|
58
|
+
process.stderr.write(`check-min-test-execution: unknown runner "${runner}"\n`)
|
|
59
|
+
process.exit(2)
|
|
60
|
+
}
|
|
61
|
+
let stdin = ''
|
|
62
|
+
try {
|
|
63
|
+
stdin = readFileSync(0, 'utf-8')
|
|
64
|
+
} catch {
|
|
65
|
+
stdin = ''
|
|
66
|
+
}
|
|
67
|
+
const n = counter(stdin)
|
|
68
|
+
process.stdout.write(`${n == null ? 'null' : n}\n`)
|
|
69
|
+
process.exit(0)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const ROOT = process.cwd()
|
|
73
|
+
const IS_CI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true'
|
|
74
|
+
const IS_WIN = process.platform === 'win32'
|
|
75
|
+
|
|
76
|
+
function readJson(path) {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(readFileSync(path, 'utf-8'))
|
|
79
|
+
} catch {
|
|
80
|
+
return null
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function localBin(name) {
|
|
85
|
+
const bin = join(ROOT, 'node_modules', '.bin', IS_WIN ? `${name}.cmd` : name)
|
|
86
|
+
return existsSync(bin) ? bin : null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function hasAnyDep(pkg, names) {
|
|
90
|
+
const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) }
|
|
91
|
+
return names.some((n) => Object.prototype.hasOwnProperty.call(deps, n))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function hasConfig(prefixes, exts) {
|
|
95
|
+
for (const p of prefixes) {
|
|
96
|
+
for (const e of exts) {
|
|
97
|
+
if (existsSync(join(ROOT, `${p}${e}`))) return true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── Runner detection ──────────────────────────────────────────────────────────
|
|
104
|
+
// Returns { runner, bin, cmd, args } or null (NA). `bin === null` ⇒ recognized but not installed.
|
|
105
|
+
function detectRunner() {
|
|
106
|
+
const pkgPath = join(ROOT, 'package.json')
|
|
107
|
+
if (existsSync(pkgPath)) {
|
|
108
|
+
const pkg = readJson(pkgPath)
|
|
109
|
+
const usesVitest =
|
|
110
|
+
hasAnyDep(pkg, ['vitest']) || hasConfig(['vitest.config'], ['.ts', '.js', '.mjs', '.cts', '.mts'])
|
|
111
|
+
// 'src' scope mirrors the generated `test:unit` script (#1840 F4 tranche-3):
|
|
112
|
+
// an unscoped `vitest list` also collects tests/api and tests/e2e (live-server
|
|
113
|
+
// / browser suites with their OWN runner, never `vitest run`), so this guard
|
|
114
|
+
// must count the SAME scope the unit-test gate step actually executes.
|
|
115
|
+
if (usesVitest) return { runner: 'vitest', bin: localBin('vitest'), args: ['list', 'src'] }
|
|
116
|
+
const usesJest =
|
|
117
|
+
hasAnyDep(pkg, ['jest']) ||
|
|
118
|
+
pkg?.jest != null ||
|
|
119
|
+
hasConfig(['jest.config'], ['.ts', '.js', '.mjs', '.cjs', '.json'])
|
|
120
|
+
if (usesJest) return { runner: 'jest', bin: localBin('jest'), args: ['--listTests'] }
|
|
121
|
+
// No JS runner in THIS package.json — do NOT early-return NA: a polyglot repo (JS frontend +
|
|
122
|
+
// a Go/Python backend at root) still has a backend suite the empty-suite guard must assert.
|
|
123
|
+
// Fall through to the go.mod / Python markers below; NA is reached only when NO runner matches.
|
|
124
|
+
}
|
|
125
|
+
if (existsSync(join(ROOT, 'go.mod'))) {
|
|
126
|
+
return { runner: 'go', bin: 'go', args: ['test', '-list', '.*', './...'] }
|
|
127
|
+
}
|
|
128
|
+
const pyMarker =
|
|
129
|
+
existsSync(join(ROOT, 'pyproject.toml')) ||
|
|
130
|
+
existsSync(join(ROOT, 'pytest.ini')) ||
|
|
131
|
+
existsSync(join(ROOT, 'setup.cfg')) ||
|
|
132
|
+
existsSync(join(ROOT, 'tox.ini')) ||
|
|
133
|
+
existsSync(join(ROOT, 'conftest.py'))
|
|
134
|
+
if (pyMarker) return { runner: 'pytest', bin: 'pytest', args: ['--collect-only', '-q'] }
|
|
135
|
+
return null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── Count parsers (per runner) ──────────────────────────────────────────────────
|
|
139
|
+
// Each returns a non-negative integer, or null when the output cannot be parsed.
|
|
140
|
+
function countVitest(stdout) {
|
|
141
|
+
// `vitest list` prints one collected test per line as "file > [suite > ] name".
|
|
142
|
+
return stdout.split('\n').filter((l) => l.includes(' > ')).length
|
|
143
|
+
}
|
|
144
|
+
function countJest(stdout) {
|
|
145
|
+
// `jest --listTests` prints one absolute test-FILE path per line.
|
|
146
|
+
return stdout.split('\n').filter((l) => l.trim().length > 0).length
|
|
147
|
+
}
|
|
148
|
+
function countPytest(stdout) {
|
|
149
|
+
if (/no tests (collected|ran)/i.test(stdout)) return 0
|
|
150
|
+
let m = stdout.match(/(\d+)\s+tests?\s+(?:collected|selected)/i)
|
|
151
|
+
if (m) return Number(m[1])
|
|
152
|
+
m = stdout.match(/collected\s+(\d+)\s+items?/i)
|
|
153
|
+
if (m) return Number(m[1])
|
|
154
|
+
return null
|
|
155
|
+
}
|
|
156
|
+
function countGo(stdout) {
|
|
157
|
+
// `go test -list` prints one Test/Example/Benchmark/Fuzz function name per line, plus per-package
|
|
158
|
+
// status lines ("ok pkg", "? pkg [no test files]") which are NOT test names.
|
|
159
|
+
return stdout.split('\n').filter((l) => /^(Test|Example|Benchmark|Fuzz)\w*\s*$/.test(l.trim()))
|
|
160
|
+
.length
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function pass(msg) {
|
|
164
|
+
process.stdout.write(`check-min-test-execution: ${msg}\n`)
|
|
165
|
+
process.exit(0)
|
|
166
|
+
}
|
|
167
|
+
function fail(msg) {
|
|
168
|
+
process.stderr.write(`check-min-test-execution: FAIL — ${msg}\n`)
|
|
169
|
+
process.exit(1)
|
|
170
|
+
}
|
|
171
|
+
function error(msg) {
|
|
172
|
+
process.stderr.write(`check-min-test-execution: ERROR — ${msg}\n`)
|
|
173
|
+
process.exit(2)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function main() {
|
|
177
|
+
const det = detectRunner()
|
|
178
|
+
if (!det) pass('no recognized test runner — NA')
|
|
179
|
+
if (!det.bin) {
|
|
180
|
+
// Recognized runner but the binary is absent. In CI the toolchain is installed, so an absent
|
|
181
|
+
// runner is itself suspicious — but the actual test gate fails first; we stay advisory here.
|
|
182
|
+
pass(`${det.runner} not installed — SKIP (deps not present)${IS_CI ? ' [CI]' : ''}`)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const r = spawnSync(det.bin, det.args, {
|
|
186
|
+
cwd: ROOT,
|
|
187
|
+
encoding: 'utf-8',
|
|
188
|
+
shell: false,
|
|
189
|
+
timeout: 120_000,
|
|
190
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
191
|
+
})
|
|
192
|
+
if (r.error && r.error.code === 'ENOENT') pass(`${det.runner} not installed — SKIP`)
|
|
193
|
+
if (r.error) error(`${det.runner} collect failed to spawn: ${r.error.message}`)
|
|
194
|
+
const out = `${r.stdout ?? ''}\n${r.stderr ?? ''}`
|
|
195
|
+
|
|
196
|
+
// pytest signals "no tests" with exit 5 — that is a legitimate empty collection, not an error.
|
|
197
|
+
const pytestEmpty = det.runner === 'pytest' && r.status === 5
|
|
198
|
+
if (!pytestEmpty && r.status !== 0) {
|
|
199
|
+
error(`${det.runner} collect exited ${r.status} (collection error, not an empty suite):\n${out}`)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const counters = {
|
|
203
|
+
vitest: countVitest,
|
|
204
|
+
jest: countJest,
|
|
205
|
+
pytest: countPytest,
|
|
206
|
+
go: countGo,
|
|
207
|
+
}
|
|
208
|
+
const count = counters[det.runner](out)
|
|
209
|
+
if (count == null) {
|
|
210
|
+
error(`could not parse ${det.runner} collect output:\n${out}`)
|
|
211
|
+
}
|
|
212
|
+
if (count === 0) {
|
|
213
|
+
fail(
|
|
214
|
+
`${det.runner} collected 0 tests — an empty suite that reports success is a false-green. ` +
|
|
215
|
+
'Add a real test, or remove the empty tier from the gate.',
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
pass(`${det.runner} collects ${count} test(s) — OK`)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
main()
|
|
223
|
+
} catch (e) {
|
|
224
|
+
error(e?.message ?? String(e))
|
|
225
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// scripts/check-muted-test.mjs — generated by arbiter (anti-fake-green, #1497).
|
|
4
|
+
//
|
|
5
|
+
// Muted-gate-test guard. A GATE test silenced by a skip/disable marker is a fake-green: the
|
|
6
|
+
// suite goes green because the test that would catch the regression never runs. This guard greps
|
|
7
|
+
// gate test dirs for cross-stack skip markers and FAILS CLOSED:
|
|
8
|
+
// it.skip/test.skip/describe.skip, xit/xtest/xdescribe, .todo/.failing — JS/TS
|
|
9
|
+
// @Disabled / @Ignore, assume-style aborts (assumeTrue/assumeFalse/abort) — JVM
|
|
10
|
+
// #[ignore] — Rust
|
|
11
|
+
// @pytest.mark.skip / @unittest.skip — Python
|
|
12
|
+
// t.Skip( — Go
|
|
13
|
+
// An AUDITED `// arbiter-allow-skip: <reason>` marker (on the skip line or the line above) makes a
|
|
14
|
+
// skip explicit, greppable, and reasoned, and opts it out; an UNMARKED skip still fails. NO-DATA
|
|
15
|
+
// (no test dir / no test files) is a SKIP at exit 0 — an explicit no-data signal, NEVER a
|
|
16
|
+
// manufactured pass.
|
|
17
|
+
//
|
|
18
|
+
// BROWNFIELD BASELINE (same policy shape as spotbugs-baseline.json): a legacy repo can carry
|
|
19
|
+
// dozens of pre-existing @Disabled tests that are not fixable in one adoption step. Running
|
|
20
|
+
// `--update-baseline` grandfathers the CURRENT counts (per file, per marker kind) into
|
|
21
|
+
// muted-tests-baseline.json; from then on the gate fails ONLY on NEW muted tests — a new marker
|
|
22
|
+
// in a new file, or a count above the baselined count in a grandfathered file. Removing muted
|
|
23
|
+
// tests never fails; re-run --update-baseline to ratchet the baseline down.
|
|
24
|
+
//
|
|
25
|
+
// Exit codes (INV-53): 0=PASS / NO-DATA-skip, 1=FAIL (muted gate test found), 2=ERROR.
|
|
26
|
+
// Usage: node scripts/check-muted-test.mjs [--dir <path>] [--update-baseline] [--help]
|
|
27
|
+
import { readdirSync, statSync, readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
28
|
+
import { join, resolve, relative } from 'node:path'
|
|
29
|
+
|
|
30
|
+
const args = process.argv.slice(2)
|
|
31
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
32
|
+
process.stdout.write(
|
|
33
|
+
'Usage: node scripts/check-muted-test.mjs [--dir <path>] [--update-baseline]\n' +
|
|
34
|
+
' Fails closed when a gate test is silenced by a skip/disable marker (incl. JVM assume-\n' +
|
|
35
|
+
' style aborts: assumeTrue/assumeFalse/abort). Add `// arbiter-allow-skip: <reason>` on\n' +
|
|
36
|
+
' the marker line or the line above to audit-exempt a legitimate skip. NO-DATA (no test\n' +
|
|
37
|
+
' dir / no test files) is a SKIP at exit 0, never a pass.\n' +
|
|
38
|
+
' --update-baseline grandfathers CURRENT muted tests into muted-tests-baseline.json\n' +
|
|
39
|
+
' (brownfield adoption); afterwards only NEW muted tests fail the gate.\n',
|
|
40
|
+
)
|
|
41
|
+
process.exit(0)
|
|
42
|
+
}
|
|
43
|
+
const dirArgIdx = args.indexOf('--dir')
|
|
44
|
+
const ROOT = dirArgIdx >= 0 && args[dirArgIdx + 1] ? resolve(args[dirArgIdx + 1]) : process.cwd()
|
|
45
|
+
const UPDATE_BASELINE = args.includes('--update-baseline')
|
|
46
|
+
const BASELINE_PATH = join(ROOT, 'muted-tests-baseline.json')
|
|
47
|
+
|
|
48
|
+
// #1840 F4 tranche-3: '.venv'/'venv'/'__pycache__' — a Python dependency's
|
|
49
|
+
// bundled test suite inside site-packages (e.g. greenlet) must never be
|
|
50
|
+
// scanned as if it were project code (mirrors lib/glob-walk.mjs's SKIP_DIRS).
|
|
51
|
+
const SKIP_DIRS = new Set([
|
|
52
|
+
'node_modules',
|
|
53
|
+
'.git',
|
|
54
|
+
'dist',
|
|
55
|
+
'build',
|
|
56
|
+
'coverage',
|
|
57
|
+
'.coverage',
|
|
58
|
+
'.venv',
|
|
59
|
+
'venv',
|
|
60
|
+
'__pycache__',
|
|
61
|
+
])
|
|
62
|
+
|
|
63
|
+
// A file is a gate test if its name matches one of these (JS/TS/JVM/Rust/Python/Go conventions).
|
|
64
|
+
// JS/TS/Rust/Python/Go tests are identified by filename; bare `.java`/`.kt` files are dir-gated to
|
|
65
|
+
// a JVM test tree (src/test/**) inside collectTestFiles via the `inJvmTestTree` flag below.
|
|
66
|
+
function isTestFile(name) {
|
|
67
|
+
return (
|
|
68
|
+
/\.(test|spec)\.(ts|tsx|js|jsx|mjs|cjs)$/.test(name) ||
|
|
69
|
+
/Test\.(java|kt)$/.test(name) ||
|
|
70
|
+
/\.(java|kt)$/.test(name) /* JVM tests live under src/test → dir-gated below */ ||
|
|
71
|
+
/_test\.(rs|go|py)$/.test(name) ||
|
|
72
|
+
/^test_.*\.py$/.test(name) ||
|
|
73
|
+
/_spec\.rb$/.test(name)
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Cross-stack skip / disable markers, anchored to STATEMENT/ANNOTATION position so a string
|
|
78
|
+
// literal that merely mentions a marker (e.g. expect(x).toContain('it.skip(')) is NOT a violation.
|
|
79
|
+
const MUTE_PATTERNS = [
|
|
80
|
+
{ re: /^(?:await\s+|return\s+)?(?:it|test|describe)\.skip\s*\(/, label: 'js/ts .skip()' },
|
|
81
|
+
{ re: /^(?:await\s+|return\s+)?x(?:it|test|describe)\s*\(/, label: 'js/ts xit/xtest/xdescribe' },
|
|
82
|
+
{
|
|
83
|
+
re: /^(?:await\s+|return\s+)?(?:it|test|describe)\.(?:todo|failing)\s*\(/,
|
|
84
|
+
label: 'js/ts .todo/.failing()',
|
|
85
|
+
},
|
|
86
|
+
{ re: /^@Disabled\b/, label: 'jvm @Disabled' },
|
|
87
|
+
{ re: /^@Ignore\b/, label: 'jvm @Ignore' },
|
|
88
|
+
// Assume-style aborts silently skip the rest of a JVM test when their predicate is unmet — a
|
|
89
|
+
// gate test that aborts is just as muted as one annotated @Disabled.
|
|
90
|
+
{
|
|
91
|
+
re: /^(?:Assumptions?|Assume)?\.?assume(?:True|False|NotNull|That)\s*\(/,
|
|
92
|
+
label: 'jvm assume-abort',
|
|
93
|
+
},
|
|
94
|
+
{ re: /^(?:Assumptions?\.)?abort\s*\(/, label: 'jvm assume abort()' },
|
|
95
|
+
{ re: /^#\[ignore\]/, label: 'rust #[ignore]' },
|
|
96
|
+
{ re: /^@(?:pytest\.mark\.skip|unittest\.skip)/, label: 'python skip' },
|
|
97
|
+
{ re: /^t\.Skip\s*\(/, label: 'go t.Skip()' },
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
// Audited inline opt-out for an intentionally-skipped gate test. A legitimate skip must be
|
|
101
|
+
// EXPLICIT, greppable, and carry a reason: `// arbiter-allow-skip: <reason>` on the marker line or
|
|
102
|
+
// the line above. The marker MUST sit in a real comment (a `//`, `#`, or `*` delimiter precedes
|
|
103
|
+
// the token) — this blocks the fake-green of burying the token in a STRING LITERAL to silence the
|
|
104
|
+
// guard. An UNMARKED skip, or a marker with no reason, still fails closed.
|
|
105
|
+
const EXEMPT_RE = /(?:^|\s)(?:\/\/+|#+|\*)\s*(?:arbiter-allow-skip|muted-test-exempt):\s*\S/
|
|
106
|
+
|
|
107
|
+
/** Recursively collect gate-test file paths, gating JVM files to src/test/** dirs. */
|
|
108
|
+
function collectTestFiles(dir, acc, inJvmTestTree) {
|
|
109
|
+
let entries
|
|
110
|
+
try {
|
|
111
|
+
entries = readdirSync(dir)
|
|
112
|
+
} catch {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
if (SKIP_DIRS.has(entry)) continue
|
|
117
|
+
const full = join(dir, entry)
|
|
118
|
+
let st
|
|
119
|
+
try {
|
|
120
|
+
st = statSync(full)
|
|
121
|
+
} catch {
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
if (st.isDirectory()) {
|
|
125
|
+
const nextJvm = inJvmTestTree || entry === 'test' || entry === 'tests'
|
|
126
|
+
collectTestFiles(full, acc, nextJvm)
|
|
127
|
+
} else if (isTestFile(entry)) {
|
|
128
|
+
// Bare .java/.kt only count when inside a test tree (src/test/**), to avoid main sources.
|
|
129
|
+
if (/\.(java|kt)$/.test(entry) && !/Test\.(java|kt)$/.test(entry) && !inJvmTestTree) continue
|
|
130
|
+
acc.push(full)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ── Brownfield baseline (grandfathered muted tests) ─────────────────────────
|
|
136
|
+
// Shape: { policy, baselined: { "<repo-relative file>": { "<marker label>": count } } }.
|
|
137
|
+
// Line numbers are deliberately NOT part of the fingerprint — they drift on every
|
|
138
|
+
// edit; per-file per-label COUNTS are stable and still catch every NEW mute
|
|
139
|
+
// (new file, new marker kind, or count above the grandfathered count).
|
|
140
|
+
|
|
141
|
+
function loadBaseline() {
|
|
142
|
+
if (!existsSync(BASELINE_PATH)) return {}
|
|
143
|
+
let parsed
|
|
144
|
+
try {
|
|
145
|
+
parsed = JSON.parse(readFileSync(BASELINE_PATH, 'utf-8'))
|
|
146
|
+
} catch (e) {
|
|
147
|
+
// Fail CLOSED: an unparseable baseline must never silently disable the gate.
|
|
148
|
+
throw new Error(`muted-tests-baseline.json is invalid JSON: ${e?.message ?? e}`)
|
|
149
|
+
}
|
|
150
|
+
const baselined = parsed?.baselined
|
|
151
|
+
if (baselined === undefined || baselined === null) return {}
|
|
152
|
+
if (typeof baselined !== 'object' || Array.isArray(baselined)) {
|
|
153
|
+
throw new Error('muted-tests-baseline.json: "baselined" must be an object map')
|
|
154
|
+
}
|
|
155
|
+
return baselined
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function writeBaseline(counts) {
|
|
159
|
+
const sorted = {}
|
|
160
|
+
for (const file of Object.keys(counts).sort()) {
|
|
161
|
+
sorted[file] = {}
|
|
162
|
+
for (const label of Object.keys(counts[file]).sort()) {
|
|
163
|
+
sorted[file][label] = counts[file][label]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const doc = {
|
|
167
|
+
policy:
|
|
168
|
+
'pre-existing muted tests grandfathered via --update-baseline; NEW muted gate tests always fail',
|
|
169
|
+
baselined: sorted,
|
|
170
|
+
}
|
|
171
|
+
writeFileSync(BASELINE_PATH, JSON.stringify(doc, null, 2) + '\n')
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function main() {
|
|
175
|
+
const files = []
|
|
176
|
+
collectTestFiles(ROOT, files, false)
|
|
177
|
+
|
|
178
|
+
if (files.length === 0) {
|
|
179
|
+
// NO-DATA: no gate test files discovered. Explicit skip, never a manufactured pass.
|
|
180
|
+
process.stdout.write('check-muted-test: SKIP — no gate test files found (NO-DATA)\n')
|
|
181
|
+
return 0
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** @type {{ file: string; rel: string; line: number; label: string; text: string }[]} */
|
|
185
|
+
const findings = []
|
|
186
|
+
for (const file of files) {
|
|
187
|
+
let content
|
|
188
|
+
try {
|
|
189
|
+
content = readFileSync(file, 'utf-8')
|
|
190
|
+
} catch {
|
|
191
|
+
continue
|
|
192
|
+
}
|
|
193
|
+
const rel = relative(ROOT, file).split('\\').join('/')
|
|
194
|
+
const lines = content.split('\n')
|
|
195
|
+
for (let i = 0; i < lines.length; i++) {
|
|
196
|
+
const trimmed = lines[i].trim()
|
|
197
|
+
const prev = i > 0 ? lines[i - 1] : ''
|
|
198
|
+
if (EXEMPT_RE.test(lines[i]) || EXEMPT_RE.test(prev)) continue
|
|
199
|
+
for (const { re, label } of MUTE_PATTERNS) {
|
|
200
|
+
if (re.test(trimmed)) {
|
|
201
|
+
findings.push({ file, rel, line: i + 1, label, text: trimmed })
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Group by file+label — the baseline unit.
|
|
208
|
+
/** @type {Record<string, Record<string, number>>} */
|
|
209
|
+
const counts = {}
|
|
210
|
+
for (const f of findings) {
|
|
211
|
+
counts[f.rel] = counts[f.rel] ?? {}
|
|
212
|
+
counts[f.rel][f.label] = (counts[f.rel][f.label] ?? 0) + 1
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (UPDATE_BASELINE) {
|
|
216
|
+
writeBaseline(counts)
|
|
217
|
+
process.stdout.write(
|
|
218
|
+
`check-muted-test: baseline updated — ${findings.length} muted test(s) grandfathered ` +
|
|
219
|
+
`across ${Object.keys(counts).length} file(s) → ${BASELINE_PATH}\n`,
|
|
220
|
+
)
|
|
221
|
+
return 0
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const baseline = loadBaseline()
|
|
225
|
+
const violations = []
|
|
226
|
+
let grandfathered = 0
|
|
227
|
+
for (const [rel, labels] of Object.entries(counts)) {
|
|
228
|
+
for (const [label, count] of Object.entries(labels)) {
|
|
229
|
+
const allowed = typeof baseline[rel]?.[label] === 'number' ? baseline[rel][label] : 0
|
|
230
|
+
if (count <= allowed) {
|
|
231
|
+
grandfathered += count
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
const lines = findings.filter((f) => f.rel === rel && f.label === label)
|
|
235
|
+
violations.push(
|
|
236
|
+
` ${rel}: ${count} × ${label}` +
|
|
237
|
+
(allowed > 0 ? ` (baseline allows ${allowed} — new mute added)` : '') +
|
|
238
|
+
'\n' +
|
|
239
|
+
lines.map((f) => ` ${f.file}:${f.line}: ${f.text}`).join('\n'),
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (violations.length > 0) {
|
|
245
|
+
process.stderr.write(
|
|
246
|
+
`check-muted-test: muted gate test(s) over baseline — a silenced gate test is a fake-green:\n`,
|
|
247
|
+
)
|
|
248
|
+
for (const v of violations) process.stderr.write(v + '\n')
|
|
249
|
+
process.stderr.write(
|
|
250
|
+
'Fix the test, add `// arbiter-allow-skip: <reason>`, or (brownfield adoption only)\n' +
|
|
251
|
+
'grandfather the CURRENT state via: node scripts/check-muted-test.mjs --update-baseline\n',
|
|
252
|
+
)
|
|
253
|
+
return 1
|
|
254
|
+
}
|
|
255
|
+
process.stdout.write(
|
|
256
|
+
`check-muted-test: OK — ${files.length} gate test file(s)` +
|
|
257
|
+
(grandfathered > 0
|
|
258
|
+
? `, ${grandfathered} muted test(s) grandfathered by muted-tests-baseline.json`
|
|
259
|
+
: ', no skip markers') +
|
|
260
|
+
'\n',
|
|
261
|
+
)
|
|
262
|
+
return 0
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
process.exit(main())
|
|
267
|
+
} catch (e) {
|
|
268
|
+
process.stderr.write(`check-muted-test: ERROR — ${e?.message ?? e}\n`)
|
|
269
|
+
process.exit(2)
|
|
270
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// scripts/check-no-stub-redirects.mjs — generated by arbiter (anti-fake-green, #1497).
|
|
4
|
+
//
|
|
5
|
+
// No-stub-redirects guard. A stale "Moved → X" stub .md is a fake-green for docs: the link checker
|
|
6
|
+
// passes and the page "exists", but it is a redirect husk with no real content — a green doc signal
|
|
7
|
+
// not backed by a real doc. This guard flags a .md that is (a) a heading/leading line with a
|
|
8
|
+
// redirect VERB (Moved / Relocated / Renamed / has moved / see instead), (b) a short body, and
|
|
9
|
+
// (c) exactly one .md link. Allowlist (.stub-redirects-allowlist) entries REQUIRE a hard
|
|
10
|
+
// `EXPIRES: YYYY-MM-DD` date — an open-ended or lapsed exemption is itself a fake-green, so it
|
|
11
|
+
// fails closed. NO-DATA (no docs) is a PASS (nothing to flag), not a manufactured fail.
|
|
12
|
+
//
|
|
13
|
+
// Exit codes (INV-53): 0=PASS, 1=FAIL (un-allowlisted stub / bad allowlist), 2=ERROR.
|
|
14
|
+
// Usage: node scripts/check-no-stub-redirects.mjs [--dir <path>] [--help]
|
|
15
|
+
import { readdirSync, statSync, readFileSync, existsSync } from 'node:fs'
|
|
16
|
+
import { join, resolve, relative } from 'node:path'
|
|
17
|
+
|
|
18
|
+
const args = process.argv.slice(2)
|
|
19
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
20
|
+
process.stdout.write(
|
|
21
|
+
'Usage: node scripts/check-no-stub-redirects.mjs [--dir <path>]\n' +
|
|
22
|
+
' Fails on a stale "Moved → X" stub .md unless allowlisted with a future EXPIRES: date.\n' +
|
|
23
|
+
' Allowlist file: .stub-redirects-allowlist (one "path EXPIRES: YYYY-MM-DD # note" per line).\n',
|
|
24
|
+
)
|
|
25
|
+
process.exit(0)
|
|
26
|
+
}
|
|
27
|
+
const dirArgIdx = args.indexOf('--dir')
|
|
28
|
+
const ROOT = dirArgIdx >= 0 && args[dirArgIdx + 1] ? resolve(args[dirArgIdx + 1]) : process.cwd()
|
|
29
|
+
const ALLOWLIST = '.stub-redirects-allowlist'
|
|
30
|
+
|
|
31
|
+
// #1840 F4 tranche-3: '.venv'/'venv'/'__pycache__' — a Python dependency's
|
|
32
|
+
// bundled test suite inside site-packages must never be scanned as project
|
|
33
|
+
// code (mirrors lib/glob-walk.mjs's SKIP_DIRS).
|
|
34
|
+
const SKIP_DIRS = new Set([
|
|
35
|
+
'node_modules',
|
|
36
|
+
'.git',
|
|
37
|
+
'dist',
|
|
38
|
+
'build',
|
|
39
|
+
'coverage',
|
|
40
|
+
'.coverage',
|
|
41
|
+
'.venv',
|
|
42
|
+
'venv',
|
|
43
|
+
'__pycache__',
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
// A redirect VERB anchoring a stub. Matched against the leading non-empty lines of the doc.
|
|
47
|
+
const REDIRECT_VERB_RE =
|
|
48
|
+
/\b(?:moved|relocated|renamed|has moved|now lives|see (?:instead|the new)|redirect(?:ed)? to)\b/i
|
|
49
|
+
const MD_LINK_RE = /\[[^\]]*\]\(([^)]+\.md[^)]*)\)/g
|
|
50
|
+
// A stub is "short": few non-trivial body words after stripping markdown punctuation.
|
|
51
|
+
const SHORT_BODY_WORDS = 40
|
|
52
|
+
|
|
53
|
+
function isStub(content) {
|
|
54
|
+
const lines = content.split('\n')
|
|
55
|
+
const nonEmpty = lines.map((l) => l.trim()).filter((l) => l.length > 0)
|
|
56
|
+
if (nonEmpty.length === 0) return false
|
|
57
|
+
// The redirect verb must appear in the first few lines (heading or lead paragraph).
|
|
58
|
+
const head = nonEmpty.slice(0, 4).join(' ')
|
|
59
|
+
if (!REDIRECT_VERB_RE.test(head)) return false
|
|
60
|
+
// Exactly one .md link in the whole body.
|
|
61
|
+
const links = [...content.matchAll(MD_LINK_RE)]
|
|
62
|
+
if (links.length !== 1) return false
|
|
63
|
+
// Short body: count words excluding markdown link/heading punctuation.
|
|
64
|
+
const words = content
|
|
65
|
+
.replace(MD_LINK_RE, ' ')
|
|
66
|
+
.replace(/[#>*_`[\]()]/g, ' ')
|
|
67
|
+
.split(/\s+/)
|
|
68
|
+
.filter((w) => w.length > 0)
|
|
69
|
+
return words.length <= SHORT_BODY_WORDS
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Parse the allowlist into { relPath → { expires: Date|null } }. */
|
|
73
|
+
function loadAllowlist() {
|
|
74
|
+
const abs = join(ROOT, ALLOWLIST)
|
|
75
|
+
if (!existsSync(abs)) return new Map()
|
|
76
|
+
const map = new Map()
|
|
77
|
+
for (const raw of readFileSync(abs, 'utf-8').split('\n')) {
|
|
78
|
+
const line = raw.replace(/#.*$/, '').trim()
|
|
79
|
+
if (line.length === 0) continue
|
|
80
|
+
const m = /^(\S+)\s*(?:EXPIRES:\s*(\d{4}-\d{2}-\d{2}))?\s*$/.exec(line)
|
|
81
|
+
if (!m) continue
|
|
82
|
+
const expires = m[2] ? new Date(m[2] + 'T00:00:00Z') : null
|
|
83
|
+
map.set(m[1].replace(/\\/g, '/'), { expires, raw: line })
|
|
84
|
+
}
|
|
85
|
+
return map
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function collectMd(dir, acc) {
|
|
89
|
+
let entries
|
|
90
|
+
try {
|
|
91
|
+
entries = readdirSync(dir)
|
|
92
|
+
} catch {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
if (SKIP_DIRS.has(entry)) continue
|
|
97
|
+
const full = join(dir, entry)
|
|
98
|
+
let st
|
|
99
|
+
try {
|
|
100
|
+
st = statSync(full)
|
|
101
|
+
} catch {
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
if (st.isDirectory()) collectMd(full, acc)
|
|
105
|
+
else if (entry.endsWith('.md')) acc.push(full)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function main() {
|
|
110
|
+
const allow = loadAllowlist()
|
|
111
|
+
const now = Date.now()
|
|
112
|
+
const files = []
|
|
113
|
+
collectMd(ROOT, files)
|
|
114
|
+
|
|
115
|
+
const violations = []
|
|
116
|
+
for (const file of files) {
|
|
117
|
+
let content
|
|
118
|
+
try {
|
|
119
|
+
content = readFileSync(file, 'utf-8')
|
|
120
|
+
} catch {
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
if (!isStub(content)) continue
|
|
124
|
+
const rel = relative(ROOT, file).replace(/\\/g, '/')
|
|
125
|
+
const entry = allow.get(rel)
|
|
126
|
+
if (entry) {
|
|
127
|
+
if (entry.expires === null || Number.isNaN(entry.expires.getTime())) {
|
|
128
|
+
violations.push(` ${rel}: allowlisted but missing a valid EXPIRES: YYYY-MM-DD date`)
|
|
129
|
+
} else if (entry.expires.getTime() < now) {
|
|
130
|
+
violations.push(` ${rel}: allowlist EXPIRES ${entry.raw} has lapsed — remove the stub`)
|
|
131
|
+
}
|
|
132
|
+
// else: future EXPIRES → permitted, no violation.
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
violations.push(` ${rel}: stale "Moved →" stub (redirect husk) — restore content or delete`)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (violations.length > 0) {
|
|
139
|
+
process.stderr.write(
|
|
140
|
+
`check-no-stub-redirects: ${violations.length} stub redirect(s) — a redirect husk is a fake-green:\n`,
|
|
141
|
+
)
|
|
142
|
+
for (const v of violations) process.stderr.write(v + '\n')
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
process.stdout.write(`check-no-stub-redirects: OK — ${files.length} .md file(s), no stub husks\n`)
|
|
146
|
+
return 0
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
process.exit(main())
|
|
151
|
+
} catch (e) {
|
|
152
|
+
process.stderr.write(`check-no-stub-redirects: ERROR — ${e?.message ?? e}\n`)
|
|
153
|
+
process.exit(2)
|
|
154
|
+
}
|