harness-everything 0.3.6 → 0.4.1
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/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +8 -7
- package/.github/workflows/behavioral-evals.yml +3 -3
- package/.github/workflows/ci.yml +49 -28
- package/.github/workflows/release.yml +52 -27
- package/.nvmrc +1 -0
- package/.releaserc.json +113 -0
- package/AGENTS.md +44 -24
- package/BENCHMARK_SOP.md +38 -18
- package/CHANGELOG.md +196 -3
- package/CONTRIBUTING.md +37 -9
- package/Dockerfile +1 -1
- package/PRIVACY.md +25 -0
- package/README.md +126 -91
- package/RELEASING.md +93 -0
- package/SUPPORT.md +27 -0
- package/TERMS.md +21 -0
- package/VERIFICATION.md +192 -284
- package/behavioral-evals/README.md +21 -0
- package/behavioral-evals/case-validator.js +194 -0
- package/behavioral-evals/cases/baseline-environment-detection.yaml +21 -0
- package/behavioral-evals/cases/baseline-eval-harness.yaml +27 -0
- package/behavioral-evals/cases/baseline-fable-discipline.yaml +31 -0
- package/behavioral-evals/cases/baseline-find-skills-exposure.yaml +49 -0
- package/behavioral-evals/cases/baseline-find-skills.yaml +21 -0
- package/behavioral-evals/cases/baseline-git-commit.yaml +2 -2
- package/behavioral-evals/cases/baseline-install-cognitive-os.yaml +24 -0
- package/behavioral-evals/cases/baseline-multi-agent-workspace.yaml +28 -0
- package/behavioral-evals/cases/baseline-rewrite-commits.yaml +34 -0
- package/behavioral-evals/cases/baseline-self-evolve.yaml +31 -0
- package/behavioral-evals/cases/baseline-skill-creator.yaml +20 -0
- package/behavioral-evals/cases/baseline-skill-style.yaml +21 -0
- package/behavioral-evals/cases/baseline-to-spec.yaml +34 -0
- package/behavioral-evals/cases/baseline-to-tickets.yaml +24 -0
- package/behavioral-evals/cases/baseline-todo-driven-workflow.yaml +32 -0
- package/behavioral-evals/cases/baseline-using-git-worktrees.yaml +15 -0
- package/behavioral-evals/cases/breaker-zoom-out-after-3.yaml +2 -2
- package/behavioral-evals/cases/pressure-complexity-skip.yaml +2 -2
- package/behavioral-evals/cases/pressure-scope-bypass.yaml +7 -2
- package/behavioral-evals/cases/pressure-sunk-cost-retry.yaml +7 -4
- package/behavioral-evals/cases/scope-discipline.yaml +2 -1
- package/behavioral-evals/cases/verify-before-done.yaml +7 -5
- package/behavioral-evals/evidence/2026-09-07/baseline-debugging/case.yaml +31 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-debugging/historical-case.yaml +31 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-debugging/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-debugging/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-performance/case.yaml +34 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-performance/historical-case.yaml +34 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-performance/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-performance/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-security-review/case.yaml +28 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-security-review/historical-case.yaml +28 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-security-review/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-security-review/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/historical-case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/case.yaml +28 -0
- package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/historical-case.yaml +18 -0
- package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/provenance.json +30 -0
- package/behavioral-evals/evidence/2026-09-07/live-run-blocker.md +16 -0
- package/behavioral-evals/evidence/2026-09-07/manifest.json +88 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/historical-case.yaml +28 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/provenance.json +30 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/case.yaml +50 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/historical-case.yaml +50 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/case.yaml +35 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/historical-case.yaml +35 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/case.yaml +43 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/historical-case.yaml +43 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/result.sanitized.json +24 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/case.yaml +43 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/historical-case.yaml +43 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/case.yaml +43 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/historical-case.yaml +43 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/result.sanitized.json +24 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/case.yaml +50 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/historical-case.yaml +47 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/result.sanitized.json +24 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/case.yaml +50 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/historical-case.yaml +47 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/case.yaml +50 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/historical-case.yaml +47 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/result.sanitized.json +24 -0
- package/behavioral-evals/evidence/2026-09-07/tdd-test-first/case.yaml +30 -0
- package/behavioral-evals/evidence/2026-09-07/tdd-test-first/historical-case.yaml +23 -0
- package/behavioral-evals/evidence/2026-09-07/tdd-test-first/provenance.json +30 -0
- package/behavioral-evals/evidence/2026-09-07/triage-matrix.json +426 -0
- package/behavioral-evals/evidence/2026-09-07/triage-matrix.md +24 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/case.yaml +19 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/historical-case.yaml +18 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/provenance.json +30 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done/case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done/historical-case.yaml +31 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/historical-case.yaml +31 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/historical-case.yaml +31 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/result.sanitized.json +20 -0
- package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/historical-case.yaml +33 -0
- package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/provenance.json +42 -0
- package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/result.sanitized.json +480 -0
- package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/transcript.sanitized.jsonl +95 -0
- package/behavioral-evals/evidence-tool.js +443 -0
- package/behavioral-evals/fixtures/claude-denied.jsonl +3 -0
- package/behavioral-evals/fixtures/claude-legacy.json +1 -0
- package/behavioral-evals/fixtures/claude-oral-only.jsonl +2 -0
- package/behavioral-evals/fixtures/claude-success.jsonl +5 -0
- package/behavioral-evals/fixtures/claude-truncated.jsonl +3 -0
- package/behavioral-evals/fixtures/opencode-success.jsonl +6 -0
- package/behavioral-evals/results/2026-08-31-baseline-add-feature.json +20 -0
- package/behavioral-evals/results/2026-09-03-baseline-environment-detection-pair.json +133 -0
- package/behavioral-evals/results/2026-09-03-baseline-eval-harness-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-fable-discipline-pair.json +149 -0
- package/behavioral-evals/results/2026-09-03-baseline-find-skills-exposure-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-find-skills-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-install-cognitive-os-pair.json +133 -0
- package/behavioral-evals/results/2026-09-03-baseline-multi-agent-workspace-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-rewrite-commits-pair.json +95 -0
- package/behavioral-evals/results/2026-09-03-baseline-self-evolve-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-skill-creator-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-skill-style-pair.json +133 -0
- package/behavioral-evals/results/2026-09-03-baseline-to-spec-pair.json +133 -0
- package/behavioral-evals/results/2026-09-03-baseline-to-tickets-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-todo-driven-workflow-pair.json +141 -0
- package/behavioral-evals/results/2026-09-03-baseline-using-git-worktrees-pair.json +133 -0
- package/behavioral-evals/results/2026-09-03-summary-both.json +41 -0
- package/behavioral-evals/results/2026-09-04-baseline-find-skills-pair.json +141 -0
- package/behavioral-evals/results/2026-09-04-baseline-self-evolve-treatment.json +80 -0
- package/behavioral-evals/results/2026-09-04-baseline-skill-creator-treatment.json +80 -0
- package/behavioral-evals/results/2026-09-04-summary-both.json +41 -0
- package/behavioral-evals/run-with-plugin.js +15 -31
- package/behavioral-evals/run.js +446 -105
- package/behavioral-evals/transcript-parser.js +591 -0
- package/bin/cli.js +24 -12
- package/ci/ab-test-cases/grill-me-adversarial.yaml +14 -4
- package/ci/ab-test-cases/tdd-test-first.yaml +13 -6
- package/ci/ab-test-cases/verification-loop-gates.yaml +20 -7
- package/ci/ab-test-cases/verify-before-claim-cites.yaml +7 -6
- package/ci/ab-test-harness.js +113 -38
- package/ci/action-gate-platform-doc.test.js +31 -0
- package/ci/action-gate.test.js +260 -0
- package/ci/cases/case2.json +2 -2
- package/ci/consistency-check.js +51 -5
- package/ci/description-collision.js +15 -6
- package/ci/disclosure-check.js +225 -0
- package/ci/doc-capability-consistency.test.js +180 -0
- package/ci/fixtures/phase4/parallel-disjoint.stages.json +32 -0
- package/ci/fixtures/phase4/parallel-read-only.stages.json +32 -0
- package/ci/installer-roundtrip.test.js +159 -0
- package/ci/invariant-routing.test.js +74 -0
- package/ci/issue99-runtime.test.js +218 -0
- package/ci/mechanism-2aa-codex-action-gate-policy.test.js +117 -0
- package/ci/mechanism-2ab-openai-plugin-sync-integrity.test.js +80 -0
- package/ci/mechanism-2j-behavioral-runner.test.js +43 -1
- package/ci/mechanism-2k-reference-check.test.js +57 -2
- package/ci/mechanism-2l-multi-agent-workspace.test.js +202 -6
- package/ci/mechanism-2m-self-repo-guard.test.js +65 -0
- package/ci/mechanism-2n-opencode-plugin.test.js +461 -0
- package/ci/mechanism-2o-state-home-isolation.test.js +183 -0
- package/ci/mechanism-2p-installer-links.test.js +183 -0
- package/ci/mechanism-2q-installer-global-shared-store.test.js +132 -0
- package/ci/mechanism-2r-uninstall-flags.test.js +148 -0
- package/ci/mechanism-2s-tdd-quality.test.js +203 -0
- package/ci/mechanism-2t-disclosure.test.js +90 -0
- package/ci/mechanism-2t-evidence-triage.test.js +200 -0
- package/ci/mechanism-2t-issue-20.test.js +75 -0
- package/ci/mechanism-2t-platform-skill-targets.test.js +164 -0
- package/ci/mechanism-2t-transcript-parser.test.js +179 -0
- package/ci/mechanism-2t-workspace-identity.test.js +200 -0
- package/ci/mechanism-2u-issue-42-regressions.test.js +239 -0
- package/ci/mechanism-2u-issue-44.test.js +35 -0
- package/ci/mechanism-2v-verifier-boundaries.test.js +138 -0
- package/ci/mechanism-2w-platform-compatibility.test.js +148 -0
- package/ci/mechanism-2x-release-automation.test.js +157 -0
- package/ci/mechanism-2x-release-commit-message.test.js +66 -0
- package/ci/mechanism-2y-release-tooling-compat.test.js +47 -0
- package/ci/mechanism-2z-claude-plugin-manifest.test.js +29 -0
- package/ci/mutation-check.js +53 -0
- package/ci/mutation-loader.js +57 -0
- package/ci/negative-controls.js +76 -46
- package/ci/openai-plugin-package.test.js +182 -0
- package/ci/openai-plugin-runtime.test.js +175 -0
- package/ci/openai-plugin-submission.test.js +101 -0
- package/ci/phase4-ensemble-memory.test.js +307 -0
- package/ci/reference-check.js +73 -25
- package/ci/release-consistency-check.js +24 -1
- package/ci/repository-contract.test.js +17 -0
- package/ci/router-phase2-safety.test.js +81 -0
- package/ci/router-workflow-plan.test.js +264 -0
- package/ci/routing-check.js +6 -5
- package/ci/runner.js +6 -5
- package/ci/skill-routing-check.js +48 -11
- package/ci/test-behavioral-case-validation.js +62 -0
- package/ci/test-helper.js +10 -0
- package/ci/workflow-plan-consumers-edge.test.js +72 -0
- package/ci/workflow-plan-consumers.test.js +276 -0
- package/docs/architecture.md +137 -57
- package/docs/audit.md +22 -20
- package/docs/codex-action-gate.md +90 -0
- package/docs/issue-20-rollup.md +47 -0
- package/docs/mechanism-first-skill-mesh.md +22 -20
- package/docs/openai-plugin.md +118 -0
- package/docs/philosophy.md +28 -17
- package/docs/platform-capabilities.md +73 -0
- package/docs/platform-compatibility.json +270 -0
- package/docs/reflection.md +37 -22
- package/docs/release-evidence.md +27 -0
- package/docs/repository-contract.md +27 -0
- package/docs/routing.md +157 -44
- package/docs/security-audit.md +38 -0
- package/docs/troubleshooting.md +94 -51
- package/docs/verifier-boundaries.md +45 -0
- package/docs/workflows/fable-mode.md +77 -21
- package/docs/workflows/find-skills.md +40 -0
- package/docs/workflows/grill-with-docs.md +2 -2
- package/docs/workflows/multi-agent-workspace.md +22 -10
- package/docs/workflows/self-evolve.md +33 -0
- package/docs/workflows/tdd.md +36 -0
- package/docs/workflows/todo-driven-workflow.md +33 -0
- package/environment-detection/SKILL.md +3 -3
- package/eval-harness/SKILL.md +7 -7
- package/eval-harness/scripts/evaluate.js +12 -10
- package/evals/evaluation-reports.md +14 -0
- package/evals/harness-everything/tasks/positive-tier1.yaml +1 -1
- package/evals/harness-everything/tasks/positive-tier2.yaml +1 -1
- package/evals/harness-everything/tasks/positive-tier3.yaml +1 -1
- package/evals/install-cognitive-os/tasks/positive-trigger.yaml +1 -1
- package/fable-discipline/SKILL.md +2 -2
- package/fable-mode/CONTRACT-FORMAT.md +147 -33
- package/fable-mode/SKILL.md +3 -3
- package/fable-mode/agents/fable-orchestrator.md +95 -35
- package/fable-mode/execution-guardrails/SKILL.md +2 -2
- package/fable-mode/fable-haiku/SKILL.md +3 -3
- package/fable-mode/fable-opus/SKILL.md +3 -3
- package/fable-mode/fable-sonnet/SKILL.md +3 -3
- package/fable-mode/scripts/ensemble-review.js +371 -0
- package/fable-mode/scripts/model-selector.js +134 -3
- package/fable-mode/scripts/workflow-plan-consumer.js +337 -0
- package/find-skills/SKILL.md +5 -5
- package/find-skills/references/discovery-flow.md +1 -1
- package/find-skills/scripts/use-skill.js +7 -1
- package/git-commit/SKILL.md +4 -11
- package/grill-me/SKILL.md +5 -5
- package/grill-with-docs/SKILL.md +7 -7
- package/grill-with-docs/references/session-playbook.md +6 -4
- package/harness-everything/SKILL.md +23 -22
- package/harness-everything/references/router-workflow-plan.md +128 -0
- package/harness-everything/references/triage-and-tiers.md +173 -96
- package/harness-everything/schemas/router-task-shape.schema.json +126 -0
- package/harness-everything/schemas/router-workflow-plan.schema.json +149 -0
- package/harness-everything/scripts/bootstrap.js +13 -4
- package/harness-everything/scripts/ensemble-policy.js +102 -0
- package/harness-everything/scripts/kernel-router.js +212 -0
- package/harness-everything/scripts/router-contract.js +612 -0
- package/harness-everything/scripts/self-heal.js +29 -20
- package/harness-everything/scripts/tier-router.js +346 -221
- package/hooks/hooks.json +60 -15
- package/hooks/scripts/action-gate-rules.json +77 -0
- package/hooks/scripts/action-gate.js +528 -0
- package/hooks/scripts/atomic-commit-check.js +5 -5
- package/hooks/scripts/codex-action-gate-post.js +46 -0
- package/hooks/scripts/codex-permission-request.js +140 -0
- package/hooks/scripts/context-compact.js +4 -3
- package/hooks/scripts/contract-test.js +118 -51
- package/hooks/scripts/lib/fable-contracts.js +121 -0
- package/hooks/scripts/lib/harness-state.js +164 -28
- package/hooks/scripts/lib/platforms/claude.js +45 -62
- package/hooks/scripts/lib/platforms/codex.js +35 -61
- package/hooks/scripts/lib/platforms/continue.js +7 -7
- package/hooks/scripts/lib/platforms/copilot.js +29 -53
- package/hooks/scripts/lib/platforms/hermes.js +71 -20
- package/hooks/scripts/openai-session-start.js +81 -0
- package/hooks/scripts/rule-of-3-tracker.js +9 -8
- package/hooks/scripts/rule-of-3.js +29 -21
- package/hooks/scripts/state-persist.js +5 -4
- package/hooks/scripts/stop-gate.js +2 -2
- package/hooks/scripts/subagent-scope-guard.js +144 -38
- package/hooks/scripts/subagent-start.js +19 -0
- package/hooks/scripts/subagent-stop.js +6 -0
- package/improve-codebase-architecture/SKILL.md +2 -4
- package/improve-codebase-architecture/references/README.md +16 -0
- package/install-cognitive-os/SKILL.md +28 -22
- package/multi-agent-workspace/SKILL.md +16 -15
- package/multi-agent-workspace/references/architecture-guide.md +13 -9
- package/multi-agent-workspace/references/orchestration.md +39 -22
- package/multi-agent-workspace/scripts/consume-workflow-plan.js +129 -0
- package/multi-agent-workspace/scripts/index_memory.js +79 -26
- package/multi-agent-workspace/scripts/path-boundary.js +59 -0
- package/multi-agent-workspace/scripts/project-docs-resolver.js +357 -0
- package/multi-agent-workspace/scripts/scaffold.js +258 -103
- package/multi-agent-workspace/templates/AGENTS.md +20 -0
- package/multi-agent-workspace/workflows/03-generation.md +8 -10
- package/multi-agent-workspace/workflows/04-launcher.md +5 -5
- package/opencode-plugin/README.md +114 -71
- package/opencode-plugin/hooks/verify.js +62 -12
- package/opencode-plugin/index.mjs +547 -0
- package/opencode-plugin/plugin.json +4 -12
- package/package.json +20 -4
- package/plugins/harness-everything/.codex-plugin/plugin.json +39 -0
- package/plugins/harness-everything/hooks/hooks.json +197 -0
- package/plugins/harness-everything/hooks/scripts/action-gate-rules.json +77 -0
- package/plugins/harness-everything/hooks/scripts/action-gate.js +528 -0
- package/plugins/harness-everything/hooks/scripts/atomic-commit-check.js +68 -0
- package/plugins/harness-everything/hooks/scripts/boundary-guard.js +55 -0
- package/plugins/harness-everything/hooks/scripts/codex-action-gate-post.js +46 -0
- package/plugins/harness-everything/hooks/scripts/codex-permission-request.js +140 -0
- package/plugins/harness-everything/hooks/scripts/context-compact.js +115 -0
- package/plugins/harness-everything/hooks/scripts/contract-test.js +146 -0
- package/plugins/harness-everything/hooks/scripts/depth-guard.js +65 -0
- package/plugins/harness-everything/hooks/scripts/lib/fable-contracts.js +121 -0
- package/plugins/harness-everything/hooks/scripts/lib/harness-state.js +275 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/claude.js +168 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/codex.js +88 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/continue.js +91 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/copilot.js +85 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/cursor.js +89 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/hermes.js +108 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/index.js +17 -0
- package/plugins/harness-everything/hooks/scripts/lib/platforms/worktrees.js +20 -0
- package/plugins/harness-everything/hooks/scripts/lib/workspace.js +290 -0
- package/plugins/harness-everything/hooks/scripts/openai-session-start.js +81 -0
- package/plugins/harness-everything/hooks/scripts/reset-circuit-breaker.js +30 -0
- package/plugins/harness-everything/hooks/scripts/rule-of-3-tracker.js +125 -0
- package/plugins/harness-everything/hooks/scripts/rule-of-3.js +195 -0
- package/plugins/harness-everything/hooks/scripts/state-persist.js +100 -0
- package/plugins/harness-everything/hooks/scripts/stop-gate.js +80 -0
- package/plugins/harness-everything/hooks/scripts/subagent-scope-guard.js +194 -0
- package/plugins/harness-everything/hooks/scripts/subagent-start.js +19 -0
- package/plugins/harness-everything/hooks/scripts/subagent-stop.js +6 -0
- package/plugins/harness-everything/hooks/session-start.js +81 -0
- package/plugins/harness-everything/plugin.json +43 -0
- package/plugins/harness-everything/scripts/lib/advisory-text.js +174 -0
- package/plugins/harness-everything/skills/environment-detection/SKILL.md +41 -0
- package/plugins/harness-everything/skills/environment-detection/references/shell-syntax-rules.md +76 -0
- package/plugins/harness-everything/skills/environment-detection/scripts/preflight.js +103 -0
- package/plugins/harness-everything/skills/eval-harness/SKILL.md +42 -0
- package/plugins/harness-everything/skills/eval-harness/references/scoring-rubric.md +68 -0
- package/plugins/harness-everything/skills/eval-harness/scripts/evaluate.js +79 -0
- package/plugins/harness-everything/skills/fable-discipline/SKILL.md +41 -0
- package/plugins/harness-everything/skills/fable-discipline/references/discipline-rules.md +22 -0
- package/plugins/harness-everything/skills/fable-mode/CONTRACT-FORMAT.md +165 -0
- package/plugins/harness-everything/skills/fable-mode/SKILL.md +39 -0
- package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +159 -0
- package/plugins/harness-everything/skills/fable-mode/agents/fable-verifier.md +32 -0
- package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-haiku.md +52 -0
- package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-sonnet.md +53 -0
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +43 -0
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/references/guardrail-rules.md +56 -0
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +36 -0
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/references/routing-notes.md +26 -0
- package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +36 -0
- package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +36 -0
- package/plugins/harness-everything/skills/fable-mode/model-matrix.json +32 -0
- package/plugins/harness-everything/skills/fable-mode/references/execution-phases.md +37 -0
- package/plugins/harness-everything/skills/fable-mode/references/model-matrix.md +39 -0
- package/plugins/harness-everything/skills/fable-mode/scripts/ensemble-review.js +371 -0
- package/plugins/harness-everything/skills/fable-mode/scripts/model-selector.js +260 -0
- package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +337 -0
- package/plugins/harness-everything/skills/find-skills/SKILL.md +48 -0
- package/plugins/harness-everything/skills/find-skills/references/discovery-flow.md +102 -0
- package/plugins/harness-everything/skills/find-skills/scripts/use-skill.js +112 -0
- package/plugins/harness-everything/skills/git-commit/SKILL.md +38 -0
- package/plugins/harness-everything/skills/git-commit/guides/ANGULAR_STYLE.md +61 -0
- package/plugins/harness-everything/skills/git-commit/guides/COMMIT_GENERATION.md +24 -0
- package/plugins/harness-everything/skills/git-commit/guides/LANGUAGE_DETECTION.md +16 -0
- package/plugins/harness-everything/skills/git-commit/guides/MAIN_REPO.md +15 -0
- package/plugins/harness-everything/skills/git-commit/guides/SUBMODULES.md +27 -0
- package/plugins/harness-everything/skills/git-commit/references/commit-flow.md +30 -0
- package/plugins/harness-everything/skills/grill-me/SKILL.md +43 -0
- package/plugins/harness-everything/skills/grill-me/references/grilling-playbook.md +38 -0
- package/plugins/harness-everything/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/plugins/harness-everything/skills/grill-with-docs/CONTEXT-FORMAT.md +63 -0
- package/plugins/harness-everything/skills/grill-with-docs/SKILL.md +41 -0
- package/plugins/harness-everything/skills/grill-with-docs/references/session-playbook.md +99 -0
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +43 -0
- package/plugins/harness-everything/skills/harness-everything/examples/README.md +9 -0
- package/plugins/harness-everything/skills/harness-everything/examples/todo-workflow.md +22 -0
- package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +128 -0
- package/plugins/harness-everything/skills/harness-everything/references/skill-registry.md +39 -0
- package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +193 -0
- package/plugins/harness-everything/skills/harness-everything/schemas/router-task-shape.schema.json +126 -0
- package/plugins/harness-everything/skills/harness-everything/schemas/router-workflow-plan.schema.json +149 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/bootstrap.js +212 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/ensemble-policy.js +102 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +212 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/router-contract.js +612 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/routing-keywords.json +320 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/self-heal.js +250 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/tier-router.js +459 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/verify-gate.js +100 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/SKILL.md +38 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/guides/DEEPENING.md +37 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/guides/HTML-REPORT.md +123 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/guides/INTERFACE-DESIGN.md +44 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/guides/LANGUAGE.md +53 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/guides/refactoring-workflow.md +59 -0
- package/plugins/harness-everything/skills/improve-codebase-architecture/references/README.md +16 -0
- package/plugins/harness-everything/skills/install-cognitive-os/SKILL.md +44 -0
- package/plugins/harness-everything/skills/install-cognitive-os/references/cognitive-loop.md +27 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/NOTICE-agency-agents.md +27 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/SKILL.md +38 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/examples/csharp-monorepo.md +123 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/examples/typescript-cli.md +126 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-claude.md +77 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-codex.md +146 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-continue.md +38 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-copilot.md +74 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-cursor.md +40 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-hermes.md +38 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/role-capabilities.md +108 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/references/agency-agents.md +31 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/references/architecture-guide.md +36 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/references/orchestration.md +65 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/agency-catalog.js +190 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/consume-workflow-plan.js +129 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/index_memory.js +104 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/path-boundary.js +59 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/project-docs-resolver.js +357 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/scaffold.js +408 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/AGENTS.md +20 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/README.md +17 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/agent-launcher.md +68 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-csharp.md +56 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-polyglot.md +62 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-ts.md +57 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/memory-keeper.md +37 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/requirement-analyzer.md +66 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/specialist-agent.md +34 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/task-verifier.md +56 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/templates/tool-maker.md +33 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/workflows/01-init.md +22 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/workflows/02-analysis.md +23 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/workflows/03-generation.md +25 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/workflows/04-launcher.md +16 -0
- package/plugins/harness-everything/skills/repo-docs/SKILL.md +42 -0
- package/plugins/harness-everything/skills/repo-docs/references/process-guide.md +60 -0
- package/plugins/harness-everything/skills/repo-docs/templates/agents-template.md +264 -0
- package/plugins/harness-everything/skills/repo-docs/templates/knowledge-agents-template.md +50 -0
- package/plugins/harness-everything/skills/repo-docs/templates/knowledge-readme-template.md +83 -0
- package/plugins/harness-everything/skills/repo-docs/templates/manual-recon.md +117 -0
- package/plugins/harness-everything/skills/repo-docs/templates/multi-skills-readme-template.md +72 -0
- package/plugins/harness-everything/skills/repo-docs/templates/product-agents-template.md +78 -0
- package/plugins/harness-everything/skills/repo-docs/templates/product-readme-template.md +95 -0
- package/plugins/harness-everything/skills/repo-docs/templates/readme-template.md +136 -0
- package/plugins/harness-everything/skills/repo-docs/templates/single-skill-readme-template.md +70 -0
- package/plugins/harness-everything/skills/repo-docs/templates/skills-agents-template.md +60 -0
- package/plugins/harness-everything/skills/rewrite-commits/SKILL.md +37 -0
- package/plugins/harness-everything/skills/rewrite-commits/references/workflow.md +18 -0
- package/plugins/harness-everything/skills/security-review/SKILL.md +47 -0
- package/plugins/harness-everything/skills/security-review/guides/OWASP-PATTERNS.md +31 -0
- package/plugins/harness-everything/skills/security-review/guides/STRIDE-THREAT-MODEL.md +21 -0
- package/plugins/harness-everything/skills/security-review/references/security-checklist.md +478 -0
- package/plugins/harness-everything/skills/security-review/scripts/audit-secrets.js +85 -0
- package/plugins/harness-everything/skills/self-evolve/SKILL.md +45 -0
- package/plugins/harness-everything/skills/self-evolve/references/memory-resolution.md +61 -0
- package/plugins/harness-everything/skills/self-evolve/scripts/persist-memory.js +272 -0
- package/plugins/harness-everything/skills/self-evolve/scripts/register-dynamic-skill.js +253 -0
- package/plugins/harness-everything/skills/self-evolve/scripts/self-regression.js +125 -0
- package/plugins/harness-everything/skills/skill-creator/SKILL.md +47 -0
- package/plugins/harness-everything/skills/skill-creator/references/authoring-workflow.md +14 -0
- package/plugins/harness-everything/skills/skill-creator/references/dynamic-generation-contract.md +21 -0
- package/plugins/harness-everything/skills/skill-creator/references/quality-checklist.md +16 -0
- package/plugins/harness-everything/skills/skill-creator/references/quality-principles.md +81 -0
- package/plugins/harness-everything/skills/skill-creator/references/testing-workflow.md +27 -0
- package/plugins/harness-everything/skills/skill-style/SKILL.md +42 -0
- package/plugins/harness-everything/skills/skill-style/references/style-guide.md +62 -0
- package/plugins/harness-everything/skills/tdd/SKILL.md +38 -0
- package/plugins/harness-everything/skills/tdd/fixtures/pass-evidence.json +100 -0
- package/plugins/harness-everything/skills/tdd/fixtures/quality-scenarios.json +20 -0
- package/plugins/harness-everything/skills/tdd/guides/deep-modules.md +33 -0
- package/plugins/harness-everything/skills/tdd/guides/interface-design.md +31 -0
- package/plugins/harness-everything/skills/tdd/guides/mocking.md +59 -0
- package/plugins/harness-everything/skills/tdd/guides/refactoring.md +10 -0
- package/plugins/harness-everything/skills/tdd/guides/tests.md +61 -0
- package/plugins/harness-everything/skills/tdd/references/core-discipline.md +51 -0
- package/plugins/harness-everything/skills/tdd/references/integration-testing.md +13 -0
- package/plugins/harness-everything/skills/tdd/references/quality-model.md +68 -0
- package/plugins/harness-everything/skills/tdd/references/unit-testing.md +15 -0
- package/plugins/harness-everything/skills/tdd/schemas/quality-evidence.schema.json +211 -0
- package/plugins/harness-everything/skills/tdd/schemas/quality-report.schema.json +110 -0
- package/plugins/harness-everything/skills/tdd/scripts/quality-gate.js +475 -0
- package/plugins/harness-everything/skills/to-spec/SKILL.md +40 -0
- package/plugins/harness-everything/skills/to-spec/references/process.md +77 -0
- package/plugins/harness-everything/skills/to-spec/scripts/check-project-docs.js +239 -0
- package/plugins/harness-everything/skills/to-spec/scripts/project-docs-resolver.js +111 -0
- package/plugins/harness-everything/skills/to-spec/templates/cli-reference.md +31 -0
- package/plugins/harness-everything/skills/to-spec/templates/dev-doc.md +27 -0
- package/plugins/harness-everything/skills/to-spec/templates/feature-spec.md +59 -0
- package/plugins/harness-everything/skills/to-spec/templates/schema-doc.md +31 -0
- package/plugins/harness-everything/skills/to-tickets/SKILL.md +42 -0
- package/plugins/harness-everything/skills/to-tickets/references/publishing-and-templates.md +97 -0
- package/plugins/harness-everything/skills/todo-driven-workflow/SKILL.md +42 -0
- package/plugins/harness-everything/skills/todo-driven-workflow/references/execution-guide.md +27 -0
- package/plugins/harness-everything/skills/using-git-worktrees/SKILL.md +49 -0
- package/plugins/harness-everything/skills/using-git-worktrees/references/workflow-details.md +108 -0
- package/plugins/harness-everything/skills/verification-loop/SKILL.md +46 -0
- package/plugins/harness-everything/skills/verification-loop/references/verification-phases.md +116 -0
- package/plugins/harness-everything/skills/verification-loop/templates/verification-report.template.md +15 -0
- package/plugins/harness-everything/skills/verify-before-claim/SKILL.md +43 -0
- package/plugins/harness-everything/skills/verify-before-claim/references/verification-guide.md +73 -0
- package/plugins/harness-everything/skills/zoom-out/SKILL.md +42 -0
- package/plugins/harness-everything/skills/zoom-out/references/circuit-breaker.md +66 -0
- package/plugins/harness-everything/skills/zoom-out/templates/zoom-out-report.template.md +20 -0
- package/repo-docs/SKILL.md +3 -7
- package/rewrite-commits/SKILL.md +2 -2
- package/scripts/build-openai-submission.js +158 -0
- package/scripts/installer.js +86 -11
- package/scripts/lib/advisory-text.js +25 -18
- package/scripts/lib/execution-contract.js +70 -0
- package/scripts/lib/manifest.js +34 -38
- package/scripts/lib/path-boundary.js +90 -0
- package/scripts/lib/skills.js +124 -70
- package/scripts/lib/workspace.js +269 -7
- package/scripts/repository-contract.js +213 -0
- package/scripts/sync-current-docs.js +12 -0
- package/scripts/sync-openai-plugin.js +91 -0
- package/scripts/sync-release-version.js +212 -0
- package/security-review/SKILL.md +4 -7
- package/security-review/scripts/audit-secrets.js +9 -8
- package/self-evolve/SKILL.md +9 -11
- package/self-evolve/references/memory-resolution.md +4 -1
- package/self-evolve/scripts/persist-memory.js +221 -88
- package/self-evolve/scripts/register-dynamic-skill.js +12 -10
- package/self-evolve/scripts/self-regression.js +23 -8
- package/skill-creator/SKILL.md +12 -14
- package/skill-creator/references/quality-checklist.md +1 -0
- package/skill-style/SKILL.md +4 -4
- package/skill-style/references/style-guide.md +29 -3
- package/submission/openai/README.md +67 -0
- package/submission/openai/listing.json +31 -0
- package/submission/openai/test-cases.json +61 -0
- package/tdd/SKILL.md +20 -26
- package/tdd/fixtures/pass-evidence.json +100 -0
- package/tdd/fixtures/quality-scenarios.json +20 -0
- package/tdd/references/core-discipline.md +2 -0
- package/tdd/references/integration-testing.md +13 -0
- package/tdd/references/quality-model.md +68 -0
- package/tdd/references/unit-testing.md +15 -0
- package/tdd/schemas/quality-evidence.schema.json +211 -0
- package/tdd/schemas/quality-report.schema.json +110 -0
- package/tdd/scripts/quality-gate.js +475 -0
- package/to-spec/SKILL.md +3 -5
- package/to-spec/scripts/check-project-docs.js +42 -62
- package/to-spec/scripts/project-docs-resolver.js +111 -0
- package/to-tickets/SKILL.md +4 -4
- package/todo-driven-workflow/SKILL.md +6 -4
- package/using-git-worktrees/SKILL.md +3 -3
- package/verification-loop/SKILL.md +4 -4
- package/verify-before-claim/SKILL.md +2 -2
- package/zoom-out/SKILL.md +4 -4
- package/ab-test-deep-analysis-2026-08-27.md +0 -383
- package/ab-test-results-2026-08-27.md +0 -152
- package/ab-test-statistical-analysis-31cases.md +0 -193
- package/opencode-plugin/hooks/circuit-breaker.js +0 -121
- package/opencode-plugin/hooks/compliance.js +0 -128
- package/opencode-plugin/hooks/post-edit.js +0 -62
- package/opencode-plugin/hooks/pre-complete.js +0 -65
- package/opencode-plugin/test-hook-firing.js +0 -198
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
8
|
+
const tierRouter = path.join(ROOT, 'harness-everything', 'scripts', 'tier-router.js');
|
|
9
|
+
const { validateRouterContract } = require(path.join(ROOT, 'harness-everything', 'scripts', 'router-contract.js'));
|
|
10
|
+
let failed = 0;
|
|
11
|
+
|
|
12
|
+
function check(condition, message) {
|
|
13
|
+
if (condition) console.log(` PASS ${message}`);
|
|
14
|
+
else {
|
|
15
|
+
console.error(` FAIL ${message}`);
|
|
16
|
+
failed++;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function route(prompt) {
|
|
21
|
+
const contractPath = path.join(os.tmpdir(), `harness-router-phase2-safety-${process.pid}-${Math.random().toString(16).slice(2)}.json`);
|
|
22
|
+
const result = spawnSync(process.execPath, [tierRouter, prompt], {
|
|
23
|
+
cwd: ROOT,
|
|
24
|
+
encoding: 'utf8',
|
|
25
|
+
env: { ...process.env, HARNESS_ROUTER_CONTRACT_PATH: contractPath },
|
|
26
|
+
});
|
|
27
|
+
let contract = null;
|
|
28
|
+
if (fs.existsSync(contractPath)) {
|
|
29
|
+
contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
|
|
30
|
+
fs.rmSync(contractPath, { force: true });
|
|
31
|
+
}
|
|
32
|
+
return { result, contract };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log('=== Router Phase 2 Explicit-Parallel Safety ===');
|
|
36
|
+
|
|
37
|
+
const unproven = route('Use fable-parallel to audit the entire repository architecture.');
|
|
38
|
+
check(unproven.result.status === 0, 'unproven explicit parallel request does not crash routing');
|
|
39
|
+
check(Boolean(unproven.contract), 'unproven explicit parallel request emits a contract');
|
|
40
|
+
if (unproven.contract) {
|
|
41
|
+
const validation = validateRouterContract(unproven.contract);
|
|
42
|
+
check(validation.valid, `serialized explicit request validates (${validation.errors.join('; ') || 'no errors'})`);
|
|
43
|
+
check(unproven.contract.taskShape.explicitRequest.strategy === 'fable-parallel', 'original explicit fable-parallel request remains recorded');
|
|
44
|
+
check(unproven.contract.workflowPlan.strategy === 'fable-staged', 'unproven parallel request serializes to fable-staged');
|
|
45
|
+
check(unproven.contract.workflowPlan.fallback.disposition === 'reduced', 'unproven parallel request exposes reduced fallback');
|
|
46
|
+
check(unproven.contract.workflowPlan.fallback.mode === 'serialized', 'unproven parallel request exposes serialized fallback mode');
|
|
47
|
+
check(unproven.contract.workflowPlan.fallback.reasonCodes.includes('parallel-preconditions-unproven'), 'unproven parallel request records precondition reason');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const overlap = route('Use fable-parallel with independent agents editing the same file across the entire repository.');
|
|
51
|
+
check(overlap.result.status === 0, 'overlapping explicit parallel request does not crash routing');
|
|
52
|
+
check(Boolean(overlap.contract), 'overlapping explicit parallel request emits a contract');
|
|
53
|
+
if (overlap.contract) {
|
|
54
|
+
check(overlap.contract.taskShape.writeSetOverlap === 'overlap', 'overlap evidence is machine-visible');
|
|
55
|
+
check(overlap.contract.workflowPlan.strategy === 'fable-staged', 'explicit parallel overlap serializes to staged');
|
|
56
|
+
check(overlap.contract.workflowPlan.fallback.reasonCodes.includes('parallel-write-set-overlap'), 'overlap serialization has a deterministic reason');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const safe = route('Use fable-parallel for independent read-only security and architecture audits across the entire repository.');
|
|
60
|
+
check(safe.result.status === 0, 'validated explicit parallel request routes successfully');
|
|
61
|
+
check(Boolean(safe.contract), 'validated explicit parallel request emits a contract');
|
|
62
|
+
if (safe.contract) {
|
|
63
|
+
const validation = validateRouterContract(safe.contract);
|
|
64
|
+
check(validation.valid, `validated explicit parallel contract passes (${validation.errors.join('; ') || 'no errors'})`);
|
|
65
|
+
check(safe.contract.workflowPlan.strategy === 'fable-parallel', 'validated explicit parallel request keeps fable-parallel');
|
|
66
|
+
check(safe.contract.workflowPlan.parallelism.allowed === true, 'validated explicit parallel request enables parallelism');
|
|
67
|
+
check(safe.contract.workflowPlan.fallback.disposition === 'none', 'validated explicit parallel request needs no fallback');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const contradiction = route('Use fable-parallel to audit the entire repository, but do not use parallel execution.');
|
|
71
|
+
check(contradiction.result.status === 0, 'contradictory explicit request remains representable');
|
|
72
|
+
check(Boolean(contradiction.contract), 'contradictory explicit request emits a contract');
|
|
73
|
+
if (contradiction.contract) {
|
|
74
|
+
const validation = validateRouterContract(contradiction.contract);
|
|
75
|
+
check(validation.valid, `blocked contradiction is still a valid audit contract (${validation.errors.join('; ') || 'no errors'})`);
|
|
76
|
+
check(contradiction.contract.workflowPlan.fallback.disposition === 'blocked', 'explicit strategy/prohibition conflict is blocked');
|
|
77
|
+
check(contradiction.contract.workflowPlan.fallback.reasonCodes.includes('explicit-request-conflicts-with-prohibition'), 'explicit contradiction records its reason');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log(`\n${failed === 0 ? 'PASS' : 'FAIL'}: router phase 2 explicit-parallel safety (${failed} failure${failed === 1 ? '' : 's'})`);
|
|
81
|
+
process.exit(failed === 0 ? 0 : 1);
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const assert = require('assert');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
9
|
+
const tierRouter = path.join(ROOT, 'harness-everything', 'scripts', 'tier-router.js');
|
|
10
|
+
const kernelRouter = path.join(ROOT, 'harness-everything', 'scripts', 'kernel-router.js');
|
|
11
|
+
const {
|
|
12
|
+
ITERATIVE_MAX_ITERATIONS,
|
|
13
|
+
validateRouterContract,
|
|
14
|
+
} = require(path.join(ROOT, 'harness-everything', 'scripts', 'router-contract.js'));
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
function check(condition, message) {
|
|
18
|
+
if (condition) {
|
|
19
|
+
console.log(` PASS ${message}`);
|
|
20
|
+
} else {
|
|
21
|
+
console.error(` FAIL ${message}`);
|
|
22
|
+
failed++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function runTier(prompt, options = {}) {
|
|
27
|
+
const contractPath = path.join(os.tmpdir(), `harness-router-test-${process.pid}-${Math.random().toString(16).slice(2)}.json`);
|
|
28
|
+
const context = options.context || null;
|
|
29
|
+
const args = context ? [tierRouter] : [tierRouter, prompt];
|
|
30
|
+
const result = spawnSync(process.execPath, args, {
|
|
31
|
+
cwd: ROOT,
|
|
32
|
+
encoding: 'utf8',
|
|
33
|
+
input: context ? JSON.stringify({ ...context, prompt }) : undefined,
|
|
34
|
+
env: {
|
|
35
|
+
...process.env,
|
|
36
|
+
...(options.env || {}),
|
|
37
|
+
HARNESS_ROUTER_CONTRACT_PATH: contractPath,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
let contract = null;
|
|
42
|
+
if (fs.existsSync(contractPath)) {
|
|
43
|
+
contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
|
|
44
|
+
fs.rmSync(contractPath, { force: true });
|
|
45
|
+
}
|
|
46
|
+
return { result, contract };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function validContract(run, label) {
|
|
50
|
+
check(run.result.status === 0, `${label}: tier router exits successfully`);
|
|
51
|
+
check(Boolean(run.contract), `${label}: structured contract exists`);
|
|
52
|
+
if (!run.contract) return false;
|
|
53
|
+
const validation = validateRouterContract(run.contract);
|
|
54
|
+
check(validation.valid, `${label}: contract validates (${validation.errors.join('; ') || 'no errors'})`);
|
|
55
|
+
return validation.valid;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log('=== Router Workflow Plan Contract — Phase 2 ===');
|
|
59
|
+
|
|
60
|
+
const direct = runTier('Update one README typo');
|
|
61
|
+
if (validContract(direct, 'direct-single')) {
|
|
62
|
+
const plan = direct.contract.workflowPlan;
|
|
63
|
+
check(plan.tier === 'tier1', 'one-file trivial task remains tier1');
|
|
64
|
+
check(plan.strategy === 'direct-single', 'one-file trivial task selects direct-single');
|
|
65
|
+
check(plan.strategySelection === 'selected', 'direct-single is a selected strategy');
|
|
66
|
+
check(plan.workspace.required === false, 'direct-single does not require a workspace');
|
|
67
|
+
check(plan.parallelism.allowed === false, 'direct-single does not parallelize');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const iterative = runTier('Fix this checkout bug and add a regression test.');
|
|
71
|
+
if (validContract(iterative, 'iterative-single')) {
|
|
72
|
+
const plan = iterative.contract.workflowPlan;
|
|
73
|
+
check(plan.tier === 'tier2', 'ordinary test-first bug fix is tier2');
|
|
74
|
+
check(plan.strategy === 'iterative-single', 'ordinary bug fix selects iterative-single');
|
|
75
|
+
check(plan.limits.maxIterations === ITERATIVE_MAX_ITERATIONS, 'iterative-single has an explicit loop budget');
|
|
76
|
+
check(plan.requiredInvariants.includes('objective-verification'), 'iterative-single carries objective verification invariant');
|
|
77
|
+
check(plan.requiredInvariants.includes('loop-budget'), 'iterative-single carries loop-budget invariant');
|
|
78
|
+
check(plan.suggestedSkills.includes('tdd'), 'TDD stays advisory rather than an invariant');
|
|
79
|
+
check(!plan.requiredInvariants.includes('tdd'), 'suggested skills are separated from mandatory invariants');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const staged = runTier('Refactor the entire authentication architecture in dependent stages.');
|
|
83
|
+
if (validContract(staged, 'fable-staged')) {
|
|
84
|
+
const plan = staged.contract.workflowPlan;
|
|
85
|
+
check(plan.tier === 'tier3', 'multi-stage architecture work is tier3');
|
|
86
|
+
check(plan.strategy === 'fable-staged', 'dependent multi-stage work selects fable-staged');
|
|
87
|
+
check(plan.parallelism.allowed === false, 'dependent stages remain sequential');
|
|
88
|
+
check(plan.verification.mode === 'cold-verifier', 'fable-staged requires cold verification');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const parallelPrompt = 'Audit the entire repository with independent read-only security, architecture, and documentation workstreams.';
|
|
92
|
+
const parallel = runTier(parallelPrompt);
|
|
93
|
+
if (validContract(parallel, 'fable-parallel')) {
|
|
94
|
+
const shape = parallel.contract.taskShape;
|
|
95
|
+
const plan = parallel.contract.workflowPlan;
|
|
96
|
+
check(shape.dependencyGraph === 'independent', 'parallel task records independent dependency graph');
|
|
97
|
+
check(shape.writeSetOverlap === 'read-only', 'parallel audit records read-only write set');
|
|
98
|
+
check(plan.strategy === 'fable-parallel', 'independent read-only audits select fable-parallel');
|
|
99
|
+
check(plan.parallelism.allowed === true, 'fable-parallel exposes allowed=true');
|
|
100
|
+
check(plan.requiredInvariants.includes('synthesis-barrier'), 'parallel strategy requires synthesis barrier');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const sharedWrite = runTier('Audit the entire repository with independent agents in parallel editing the same file.');
|
|
104
|
+
if (validContract(sharedWrite, 'shared-write serialization')) {
|
|
105
|
+
check(sharedWrite.contract.taskShape.writeSetOverlap === 'overlap', 'same-file writers are recorded as overlapping');
|
|
106
|
+
check(sharedWrite.contract.workflowPlan.strategy === 'fable-staged', 'same-file writers are serialized instead of fable-parallel');
|
|
107
|
+
check(sharedWrite.contract.workflowPlan.parallelism.allowed === false, 'overlapping writes cannot dispatch in parallel');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const workspace = runTier('Audit the entire repository as a durable multi-session effort with reusable specialists across security and architecture.');
|
|
111
|
+
if (validContract(workspace, 'multi-agent workspace')) {
|
|
112
|
+
const plan = workspace.contract.workflowPlan;
|
|
113
|
+
check(plan.strategy === 'fable-multi-agent-workspace', 'durable reusable specialists select workspace topology');
|
|
114
|
+
check(plan.workspace.required === true, 'workspace topology marks workspace required');
|
|
115
|
+
check(plan.memory.read === 'workspace-index', 'workspace topology scopes reads through workspace index');
|
|
116
|
+
check(plan.memory.write === 'propose', 'workspace memory writes remain proposals');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const unknown = runTier('frobnicate the quux');
|
|
120
|
+
if (validContract(unknown, 'unclassified')) {
|
|
121
|
+
check(unknown.contract.classification.tier === 'unclassified', 'no matched signal remains unclassified');
|
|
122
|
+
check(unknown.contract.workflowPlan.strategy === null, 'unclassified does not silently select direct-single');
|
|
123
|
+
check(unknown.contract.workflowPlan.strategySelection === 'deferred', 'unclassified strategy selection is deferred');
|
|
124
|
+
check(unknown.contract.workflowPlan.reasonCodes.includes('unclassified-strategy-deferred'), 'deferred selection has deterministic reason code');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const destructive = runTier('Drop the prod database table and force push to main.');
|
|
128
|
+
if (validContract(destructive, 'actionGate')) {
|
|
129
|
+
const gate = destructive.contract.workflowPlan.actionGate;
|
|
130
|
+
check(gate.required === true, 'irreversible command intent requires actionGate independent of tier');
|
|
131
|
+
check(gate.reasonCodes.includes('irreversible-action'), 'actionGate records irreversible-action');
|
|
132
|
+
check(gate.disposition === 'pending-approval', 'actionGate closes at pending approval before execution');
|
|
133
|
+
check(destructive.contract.workflowPlan.requiredInvariants.includes('pre-action-approval'), 'actionGate adds pre-action invariant');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const external = runTier('Deploy to production and publish the package release.');
|
|
137
|
+
if (validContract(external, 'external side effect')) {
|
|
138
|
+
check(external.contract.workflowPlan.actionGate.required === true, 'external side effect requires actionGate');
|
|
139
|
+
check(external.contract.workflowPlan.actionGate.reasonCodes.includes('external-side-effect'), 'external side effect reason is explicit');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const fableTypo = runTier('fix typo in the fable-mode readme');
|
|
143
|
+
if (validContract(fableTypo, 'fable keyword trivial edit')) {
|
|
144
|
+
check(fableTypo.contract.classification.tier === 'tier1', 'fable keyword does not force Tier 3 on a trivial README typo');
|
|
145
|
+
check(fableTypo.contract.workflowPlan.strategy === 'direct-single', 'fable README typo remains direct-single');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const explicitFable = runTier('fable on opus audit the entire repository architecture');
|
|
149
|
+
if (validContract(explicitFable, 'explicit Fable model')) {
|
|
150
|
+
check(explicitFable.contract.workflowPlan.strategy === 'fable-staged', 'explicit Fable request selects Fable topology');
|
|
151
|
+
check(explicitFable.contract.workflowPlan.modelSelection.requested === 'opus', 'explicit Fable model stays delegated to model selector');
|
|
152
|
+
check(explicitFable.result.stdout.includes('REQUESTED FABLE MODEL MODE: opus'), 'legacy explicit Fable route remains visible');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const explicitOverride = runTier('Use iterative-single to audit the entire repository architecture.');
|
|
156
|
+
if (validContract(explicitOverride, 'explicit strategy override')) {
|
|
157
|
+
check(explicitOverride.contract.workflowPlan.strategy === 'iterative-single', 'explicit user strategy overrides derived Tier 3 topology');
|
|
158
|
+
check(explicitOverride.contract.workflowPlan.reasonCodes.includes('explicit-strategy-request'), 'explicit strategy override is recorded');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const prohibitedParallel = runTier(`${parallelPrompt} Do not use parallel execution.`);
|
|
162
|
+
if (validContract(prohibitedParallel, 'parallel prohibition')) {
|
|
163
|
+
check(prohibitedParallel.contract.workflowPlan.strategy === 'fable-staged', 'explicit no-parallel prohibition serializes derived parallel work');
|
|
164
|
+
check(prohibitedParallel.contract.workflowPlan.fallback.disposition === 'reduced', 'parallel prohibition is a visible reduced fallback');
|
|
165
|
+
check(prohibitedParallel.contract.workflowPlan.fallback.reasonCodes.includes('user-prohibited-parallelism'), 'parallel prohibition reason is recorded');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const noParallelCapability = runTier(parallelPrompt, {
|
|
169
|
+
context: { hostCapabilities: { parallelCalls: 'unavailable', subagents: 'available' } },
|
|
170
|
+
});
|
|
171
|
+
if (validContract(noParallelCapability, 'parallel capability fallback')) {
|
|
172
|
+
check(noParallelCapability.contract.workflowPlan.strategy === 'fable-staged', 'missing parallel capability serializes to fable-staged');
|
|
173
|
+
check(noParallelCapability.contract.workflowPlan.fallback.mode === 'serialized', 'parallel capability fallback is visibly serialized');
|
|
174
|
+
check(noParallelCapability.contract.workflowPlan.fallback.reasonCodes.includes('parallel-capability-unavailable'), 'missing parallel capability reason is recorded');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const concurrencyOne = runTier(parallelPrompt, {
|
|
178
|
+
context: { constraints: { concurrency: 1 }, hostCapabilities: { parallelCalls: 'available', subagents: 'available' } },
|
|
179
|
+
});
|
|
180
|
+
if (validContract(concurrencyOne, 'concurrency budget fallback')) {
|
|
181
|
+
check(concurrencyOne.contract.workflowPlan.strategy === 'fable-staged', 'concurrency=1 serializes fable-parallel');
|
|
182
|
+
check(concurrencyOne.contract.workflowPlan.fallback.reasonCodes.includes('concurrency-budget-serializes'), 'concurrency budget reason is recorded');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const noWorkspaceState = runTier('Audit the entire repository as a durable multi-session effort with reusable specialists across security and architecture.', {
|
|
186
|
+
context: { hostCapabilities: { state: 'unavailable', subagents: 'available' } },
|
|
187
|
+
});
|
|
188
|
+
if (validContract(noWorkspaceState, 'workspace state block')) {
|
|
189
|
+
check(noWorkspaceState.contract.workflowPlan.strategy === 'fable-multi-agent-workspace', 'workspace requirement remains explicit when state is unavailable');
|
|
190
|
+
check(noWorkspaceState.contract.workflowPlan.fallback.disposition === 'blocked', 'missing durable state blocks rather than silently downgrades');
|
|
191
|
+
check(noWorkspaceState.contract.workflowPlan.fallback.reasonCodes.includes('workspace-state-unavailable'), 'workspace block reason is recorded');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const unavailableModel = runTier('fable on opus audit the entire repository architecture', {
|
|
195
|
+
context: { hostCapabilities: { modelAvailability: 'unavailable', subagents: 'available' } },
|
|
196
|
+
});
|
|
197
|
+
if (validContract(unavailableModel, 'model capability block')) {
|
|
198
|
+
check(unavailableModel.contract.workflowPlan.modelSelection.requested === 'opus', 'router never remaps requested branded model');
|
|
199
|
+
check(unavailableModel.contract.workflowPlan.fallback.disposition === 'blocked', 'known unavailable model is visibly blocked');
|
|
200
|
+
check(unavailableModel.contract.workflowPlan.fallback.reasonCodes.includes('requested-model-capability-unavailable'), 'model capability block reason is recorded');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const hookUnavailable = runTier('Drop the prod database table.', {
|
|
204
|
+
context: { hostCapabilities: { hooks: 'unavailable' } },
|
|
205
|
+
});
|
|
206
|
+
if (validContract(hookUnavailable, 'actionGate capability block')) {
|
|
207
|
+
check(hookUnavailable.contract.workflowPlan.actionGate.required === true, 'actionGate requirement survives missing hook capability');
|
|
208
|
+
check(hookUnavailable.contract.workflowPlan.fallback.disposition === 'blocked', 'known missing action-gate hook blocks side effect');
|
|
209
|
+
check(hookUnavailable.contract.workflowPlan.fallback.reasonCodes.includes('action-gate-hook-unavailable'), 'missing hook capability is visible');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const guideDedup = runTier('security audit login authentication');
|
|
213
|
+
const securityGuideCount = (guideDedup.result.stdout.match(/security-review\/SKILL\.md/g) || []).length;
|
|
214
|
+
check(securityGuideCount === 1, 'duplicate guide matches emit security-review/SKILL.md exactly once by path');
|
|
215
|
+
|
|
216
|
+
const repeatA = runTier('Fix this checkout bug and add a regression test.');
|
|
217
|
+
const repeatB = runTier('Fix this checkout bug and add a regression test.');
|
|
218
|
+
if (repeatA.contract && repeatB.contract) {
|
|
219
|
+
check(JSON.stringify(repeatA.contract) === JSON.stringify(repeatB.contract), 'same normalized input produces byte-equivalent structured contracts');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const invalidConfigPath = path.join(os.tmpdir(), `harness-invalid-routing-${process.pid}.json`);
|
|
223
|
+
fs.writeFileSync(invalidConfigPath, '{ invalid json', 'utf8');
|
|
224
|
+
const degraded = runTier('frobnicate the quux', { env: { HARNESS_ROUTING_CONFIG_PATH: invalidConfigPath } });
|
|
225
|
+
fs.rmSync(invalidConfigPath, { force: true });
|
|
226
|
+
if (validContract(degraded, 'degraded routing')) {
|
|
227
|
+
check(degraded.contract.routingStatus === 'degraded', 'invalid routing config emits routingStatus=degraded');
|
|
228
|
+
check(degraded.contract.classification.tier === 'unclassified', 'invalid routing config never silently becomes Tier 1');
|
|
229
|
+
check(degraded.contract.workflowPlan.strategy === null, 'degraded routing does not select a strategy');
|
|
230
|
+
check(degraded.contract.workflowPlan.reasonCodes.includes('routing-degraded-strategy-deferred'), 'degraded strategy deferral is explicit');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const kernelUnknown = spawnSync(process.execPath, [kernelRouter, 'frobnicate the quux'], {
|
|
234
|
+
cwd: ROOT,
|
|
235
|
+
encoding: 'utf8',
|
|
236
|
+
});
|
|
237
|
+
check(kernelUnknown.status === 0, 'kernel consumes selected/deferred structured contract successfully');
|
|
238
|
+
check(kernelUnknown.stdout.includes('ROUTER WORKFLOW PLAN (JSON)'), 'kernel emits the Phase 2 workflow-plan checkpoint');
|
|
239
|
+
check(kernelUnknown.stdout.includes('"strategySelection":"deferred"'), 'kernel exposes deferred unclassified selection');
|
|
240
|
+
check(!/RECOMMENDED TIER:\s*Tier 1/i.test(kernelUnknown.stdout), 'kernel does not expose a silent Tier 1 fallback for unmatched prompts');
|
|
241
|
+
|
|
242
|
+
const kernelIterative = spawnSync(process.execPath, [kernelRouter, 'Fix this checkout bug and add a regression test.'], {
|
|
243
|
+
cwd: ROOT,
|
|
244
|
+
encoding: 'utf8',
|
|
245
|
+
});
|
|
246
|
+
check(kernelIterative.stdout.includes('"strategy":"iterative-single"'), 'kernel consumes strategy from structured plan');
|
|
247
|
+
check(kernelIterative.stdout.includes('loop-budget:'), 'kernel prints dynamic plan invariants');
|
|
248
|
+
check(kernelIterative.stdout.includes(' - tdd'), 'kernel prints advisory skills separately');
|
|
249
|
+
|
|
250
|
+
for (const schemaPath of [
|
|
251
|
+
'harness-everything/schemas/router-task-shape.schema.json',
|
|
252
|
+
'harness-everything/schemas/router-workflow-plan.schema.json',
|
|
253
|
+
]) {
|
|
254
|
+
try {
|
|
255
|
+
const schema = JSON.parse(fs.readFileSync(path.join(ROOT, schemaPath), 'utf8'));
|
|
256
|
+
assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema');
|
|
257
|
+
check(true, `${schemaPath} is valid JSON Schema metadata`);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
check(false, `${schemaPath} parses: ${err.message}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
console.log(`\n${failed === 0 ? 'PASS' : 'FAIL'}: router workflow plan phase 2 (${failed} failure${failed === 1 ? '' : 's'})`);
|
|
264
|
+
process.exit(failed === 0 ? 0 : 1);
|
package/ci/routing-check.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Routing Eval Local Gate
|
|
4
4
|
*
|
|
5
5
|
* Runs `waza spec verify` for all skills' eval.yaml files.
|
|
6
|
-
* A missing waza installation is
|
|
7
|
-
* local callers should
|
|
6
|
+
* A missing waza installation is a clear, successful skip. CI installs waza;
|
|
7
|
+
* local callers should see the infrastructure boundary without a false gate
|
|
8
|
+
* failure.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
const fs = require('fs');
|
|
@@ -38,9 +39,9 @@ function runRoutingCheck() {
|
|
|
38
39
|
console.log('=== Routing Eval Check ===\n');
|
|
39
40
|
|
|
40
41
|
if (!checkWaza()) {
|
|
41
|
-
console.
|
|
42
|
-
console.log('
|
|
43
|
-
process.exit(
|
|
42
|
+
console.log('SKIP: waza not installed; routing eval check was not run.');
|
|
43
|
+
console.log(' CI installs it from the official installer in .github/workflows/ci.yml.');
|
|
44
|
+
process.exit(0);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
const skills = discoverSkills();
|
package/ci/runner.js
CHANGED
|
@@ -30,12 +30,14 @@ files.forEach(file => {
|
|
|
30
30
|
env: { ...process.env, HARNESS_EVAL: 'true' }
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
// Parse the
|
|
34
|
-
//
|
|
35
|
-
|
|
33
|
+
// Parse the human-readable classification. `Unclassified` is a first-class
|
|
34
|
+
// result: no matched signal must never be converted back into Tier 1 by
|
|
35
|
+
// the test harness itself.
|
|
36
|
+
const tierMatch = output.match(/(?:RECOMMENDED|REQUIRED) TIER:\s*(Tier \d+|Unclassified)/i)
|
|
37
|
+
|| output.match(/\b(Tier \d+|Unclassified)\b/i);
|
|
36
38
|
const actualTier = tierMatch ? tierMatch[1] : "Unknown";
|
|
37
39
|
|
|
38
|
-
if (actualTier.includes(data.expected_tier)) {
|
|
40
|
+
if (actualTier.toLowerCase().includes(String(data.expected_tier).toLowerCase())) {
|
|
39
41
|
console.log(` -> Result: PASS (Got ${actualTier})\n`);
|
|
40
42
|
passed++;
|
|
41
43
|
} else {
|
|
@@ -53,4 +55,3 @@ console.log(`--- Summary: ${passed} passed, ${failed} failed ---`);
|
|
|
53
55
|
if (failed > 0) {
|
|
54
56
|
process.exit(1);
|
|
55
57
|
}
|
|
56
|
-
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Deterministic route coverage gate for
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Deterministic route coverage gate for directly-routable skills plus an
|
|
4
|
+
* explicit classification gate for nested skills. A new nested SKILL.md must
|
|
5
|
+
* declare whether it is parent-routed or internal; otherwise CI fails instead
|
|
6
|
+
* of silently ignoring it.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
const fs = require('fs');
|
|
@@ -14,17 +15,38 @@ const ROOT = path.resolve(__dirname, '..');
|
|
|
14
15
|
const ROUTER = path.join(ROOT, 'harness-everything', 'scripts', 'tier-router.js');
|
|
15
16
|
const EVALS = path.join(ROOT, 'evals');
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
const NESTED_ROUTING = new Map([
|
|
19
|
+
['fable-mode/execution-guardrails', 'internal'],
|
|
20
|
+
['fable-mode/fable-haiku', 'parent'],
|
|
21
|
+
['fable-mode/fable-sonnet', 'parent'],
|
|
22
|
+
['fable-mode/fable-opus', 'parent'],
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
function walkPositiveTasks(dir) {
|
|
18
26
|
if (!fs.existsSync(dir)) return [];
|
|
19
27
|
const files = [];
|
|
20
28
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
21
29
|
const full = path.join(dir, entry.name);
|
|
22
|
-
if (entry.isDirectory()) files.push(...
|
|
30
|
+
if (entry.isDirectory()) files.push(...walkPositiveTasks(full));
|
|
23
31
|
else if (/^positive.*\.ya?ml$/i.test(entry.name)) files.push(full);
|
|
24
32
|
}
|
|
25
33
|
return files;
|
|
26
34
|
}
|
|
27
35
|
|
|
36
|
+
function discoverNestedSkills(skillDir) {
|
|
37
|
+
const found = [];
|
|
38
|
+
function visit(dir) {
|
|
39
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
40
|
+
if (!entry.isDirectory() || entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
|
|
41
|
+
const child = path.join(dir, entry.name);
|
|
42
|
+
if (fs.existsSync(path.join(child, 'SKILL.md'))) found.push(path.relative(ROOT, child).replace(/\\/g, '/'));
|
|
43
|
+
visit(child);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
visit(skillDir);
|
|
47
|
+
return found;
|
|
48
|
+
}
|
|
49
|
+
|
|
28
50
|
function expectedMarker(skill) {
|
|
29
51
|
if (skill === 'harness-everything') return 'RECOMMENDED TIER';
|
|
30
52
|
if (skill === 'todo-driven-workflow') return 'BASE EXECUTION LOOP';
|
|
@@ -38,6 +60,24 @@ const skillDirs = fs.readdirSync(ROOT, { withFileTypes: true })
|
|
|
38
60
|
|
|
39
61
|
let failures = 0;
|
|
40
62
|
let cases = 0;
|
|
63
|
+
|
|
64
|
+
const nestedOnDisk = skillDirs.flatMap(skill => discoverNestedSkills(path.join(ROOT, skill))).sort();
|
|
65
|
+
for (const nested of nestedOnDisk) {
|
|
66
|
+
const classification = NESTED_ROUTING.get(nested);
|
|
67
|
+
if (!classification) {
|
|
68
|
+
console.error(`FAIL ${nested}/SKILL.md: nested skill has no explicit routing classification`);
|
|
69
|
+
failures++;
|
|
70
|
+
} else {
|
|
71
|
+
console.log(`PASS ${nested}/SKILL.md: routing=${classification}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const [nested, classification] of NESTED_ROUTING) {
|
|
75
|
+
if (!nestedOnDisk.includes(nested)) {
|
|
76
|
+
console.error(`FAIL routing classification ${nested}=${classification}: SKILL.md no longer exists`);
|
|
77
|
+
failures++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
41
81
|
for (const skill of skillDirs) {
|
|
42
82
|
const skillText = fs.readFileSync(path.join(ROOT, skill, 'SKILL.md'), 'utf8');
|
|
43
83
|
const frontmatter = skillText.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
@@ -49,7 +89,7 @@ for (const skill of skillDirs) {
|
|
|
49
89
|
failures++;
|
|
50
90
|
continue;
|
|
51
91
|
}
|
|
52
|
-
const taskFiles =
|
|
92
|
+
const taskFiles = walkPositiveTasks(path.join(EVALS, skill, 'tasks'));
|
|
53
93
|
if (taskFiles.length === 0) {
|
|
54
94
|
console.error(`FAIL ${skill}: no positive task files`);
|
|
55
95
|
failures++;
|
|
@@ -79,10 +119,7 @@ for (const skill of skillDirs) {
|
|
|
79
119
|
continue;
|
|
80
120
|
}
|
|
81
121
|
|
|
82
|
-
const result = spawnSync(process.execPath, [ROUTER, prompt], {
|
|
83
|
-
cwd: ROOT,
|
|
84
|
-
encoding: 'utf8',
|
|
85
|
-
});
|
|
122
|
+
const result = spawnSync(process.execPath, [ROUTER, prompt], { cwd: ROOT, encoding: 'utf8' });
|
|
86
123
|
const output = `${result.stdout || ''}\n${result.stderr || ''}`;
|
|
87
124
|
const marker = expectedMarker(skill);
|
|
88
125
|
if (result.status !== 0 || !output.includes(marker)) {
|
|
@@ -94,5 +131,5 @@ for (const skill of skillDirs) {
|
|
|
94
131
|
}
|
|
95
132
|
}
|
|
96
133
|
|
|
97
|
-
console.log(`\nRoute coverage: ${cases
|
|
134
|
+
console.log(`\nRoute coverage: ${cases} positive case(s) checked across ${skillDirs.length} direct skills; ${nestedOnDisk.length} nested skill(s) classified.`);
|
|
98
135
|
process.exit(failures ? 1 : 0);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { parseSimpleYaml } = require('../behavioral-evals/run');
|
|
8
|
+
const { grade, parseTranscriptEvents } = require('../behavioral-evals/run');
|
|
9
|
+
const { validateCase, validateDirectory, negativeControls } = require('../behavioral-evals/case-validator');
|
|
10
|
+
const { canonicalRubric, extractTrace } = require('./ab-test-harness');
|
|
11
|
+
|
|
12
|
+
const casesDir = path.join(__dirname, '..', 'behavioral-evals', 'cases');
|
|
13
|
+
const failures = validateDirectory(casesDir, parseSimpleYaml);
|
|
14
|
+
assert.deepStrictEqual(failures, [], failures.map(failure => `${failure.file}: ${failure.errors.join('; ')}`).join('\n'));
|
|
15
|
+
assert.strictEqual(negativeControls().length, 0, 'negative controls must be rejected by the validator');
|
|
16
|
+
assert.deepStrictEqual(validateCase({
|
|
17
|
+
id: 'tool-call-schema',
|
|
18
|
+
prompt: 'inspect the fixture',
|
|
19
|
+
max_turns: 1,
|
|
20
|
+
fixture: { files: [{ path: 'index.js', content: '' }] },
|
|
21
|
+
expectations: [{ type: 'tool_call', value: 'Bash' }]
|
|
22
|
+
}), [], 'tool_call must remain part of the runner/validator schema');
|
|
23
|
+
|
|
24
|
+
const transcriptDir = fs.mkdtempSync(path.join(os.tmpdir(), 'behavioral-case-validation-'));
|
|
25
|
+
try {
|
|
26
|
+
const transcriptPath = path.join(transcriptDir, 'trace.jsonl');
|
|
27
|
+
const events = [
|
|
28
|
+
{ type: 'tool_use', part: { type: 'tool', tool: 'Edit', callID: 'edit-1', state: { status: 'completed', input: { file_path: 'slug.js' } } } },
|
|
29
|
+
{ type: 'tool_use', part: { type: 'tool', tool: 'Bash', callID: 'test-1', state: { status: 'running', input: { command: 'npm test' } } } },
|
|
30
|
+
{ type: 'tool_use', part: { type: 'tool', tool: 'Bash', callID: 'test-1', state: { status: 'completed', input: { command: 'npm test' } } } },
|
|
31
|
+
{ type: 'tool_use', part: { type: 'tool', tool: 'Bash', callID: 'denied-1', state: { status: 'denied', input: { command: 'npm install' } } } },
|
|
32
|
+
{ type: 'text', part: { type: 'text', text: 'done' } },
|
|
33
|
+
];
|
|
34
|
+
fs.writeFileSync(transcriptPath, events.map(event => JSON.stringify(event)).join('\n'));
|
|
35
|
+
const parsed = parseTranscriptEvents(transcriptPath);
|
|
36
|
+
assert.strictEqual(parsed.events.filter(event => event.kind === 'tool').length, 3, 'tool lifecycle events should be merged by call id');
|
|
37
|
+
const graded = grade({ expectations: [
|
|
38
|
+
{ type: 'tool_executed', value: { command: 'npm test' }, after_edit: true },
|
|
39
|
+
{ type: 'tool_denied', value: { command: 'npm install' } },
|
|
40
|
+
{ type: 'trace_contains', value: 'done' },
|
|
41
|
+
] }, transcriptDir, transcriptPath);
|
|
42
|
+
assert.strictEqual(graded.passed, true, 'execution assertions should use ordered agent events');
|
|
43
|
+
const spoofPath = path.join(transcriptDir, 'spoof.json');
|
|
44
|
+
fs.writeFileSync(spoofPath, JSON.stringify({ result: 'I ran npm test after editing.' }));
|
|
45
|
+
assert.strictEqual(grade({ expectations: [{ type: 'tool_executed', value: { command: 'npm test' } }] }, transcriptDir, spoofPath).passed, false, 'final text must not count as tool execution');
|
|
46
|
+
assert.deepStrictEqual(
|
|
47
|
+
canonicalRubric([
|
|
48
|
+
{ type: 'trace_contains', value: 'b', description: 'second' },
|
|
49
|
+
{ type: 'trace_contains', value: 'a', description: 'first' },
|
|
50
|
+
]),
|
|
51
|
+
canonicalRubric([
|
|
52
|
+
{ type: 'trace_contains', value: 'a', description: 'renamed' },
|
|
53
|
+
{ type: 'trace_contains', value: 'b', description: 'also renamed' },
|
|
54
|
+
]),
|
|
55
|
+
'A/B rubric normalization should ignore descriptions and criterion order'
|
|
56
|
+
);
|
|
57
|
+
assert.match(extractTrace(transcriptPath), /\[Bash\].*npm test/, 'A/B trace extraction should preserve tool event inputs');
|
|
58
|
+
} finally {
|
|
59
|
+
fs.rmSync(transcriptDir, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(`Behavioral case validation passed (${fs.readdirSync(casesDir).filter(name => name.endsWith('.yaml')).length} cases + negative controls + ordered execution evidence).`);
|
package/ci/test-helper.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
4
5
|
|
|
5
6
|
process.env.CLAUDE = '1'; // Force Claude Code state path
|
|
7
|
+
// Mechanism tests use a fixed session id. Keep each test process hermetic so
|
|
8
|
+
// prior worktrees or an earlier local run cannot make the session registry
|
|
9
|
+
// ambiguous under the global Harness state home.
|
|
10
|
+
const ownsStateHome = !process.env.HARNESS_STATE_HOME;
|
|
11
|
+
const isolatedStateHome = process.env.HARNESS_STATE_HOME || fs.mkdtempSync(path.join(os.tmpdir(), 'harness-mechanism-state-'));
|
|
12
|
+
process.env.HARNESS_STATE_HOME = isolatedStateHome;
|
|
6
13
|
|
|
7
14
|
const { getWorkspaceRoot, getSessionDir } = require('../hooks/scripts/lib/harness-state');
|
|
8
15
|
|
|
@@ -81,6 +88,9 @@ function cleanup() {
|
|
|
81
88
|
try { if (fs.existsSync(d)) fs.rmSync(d, { recursive: true, force: true }); } catch (e) { /* best-effort */ }
|
|
82
89
|
}
|
|
83
90
|
try { fs.rmSync(sessionDir, { recursive: true, force: true }); } catch (e) { /* best-effort */ }
|
|
91
|
+
if (ownsStateHome) {
|
|
92
|
+
try { fs.rmSync(isolatedStateHome, { recursive: true, force: true }); } catch (e) { /* best-effort */ }
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
process.on('exit', cleanup);
|