@mutagent/helix 0.1.0-alpha.14
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/.claude/skills/mutagent-helix/SKILL.md +113 -0
- package/.claude/skills/mutagent-helix/scripts/cli/codex-transcode.ts +143 -0
- package/.claude/skills/mutagent-helix/scripts/cli/doctor.ts +111 -0
- package/.claude/skills/mutagent-helix/scripts/cli/init.ts +382 -0
- package/.claude/skills/mutagent-helix/scripts/cli/run.sh +61 -0
- package/CLAUDE.md +193 -0
- package/LICENSE +201 -0
- package/NOTICE +22 -0
- package/README.md +209 -0
- package/assets/adl-loop.svg +162 -0
- package/assets/system-status.svg +422 -0
- package/bin/mutagent-cli.mjs +9950 -0
- package/bin/mutagent-helix.mjs +78 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/CLAUDE.md +28 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/SKILL.md +138 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/assets/templates/agentspec.yaml.tpl +247 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/references/frameworks/doc-pins.md +53 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/references/principles.md +91 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/references/requirements.yaml +295 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/references/workflows/orchestrator-protocol.md +302 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/cli/doctor.ts +116 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/cli/init.ts +230 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/cli/run.sh +60 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/config/resolve-spec-dir.ts +199 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/contract/agentspec.schema.ts +455 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/setup/detect.ts +67 -0
- package/mutagent-agentspec/.claude/skills/mutagent-agentspec/scripts/validate/validate-spec.ts +93 -0
- package/mutagent-agentspec/LICENSE +201 -0
- package/mutagent-agentspec/NOTICE +19 -0
- package/mutagent-agentspec/README.md +44 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/SKILL.md +100 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/assets/agents/ai-architect.md +312 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/assets/agents/ai-engineer.md +357 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/assets/templates/build-report.md.tpl +39 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/references/principles.md +31 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/references/workflows/build-protocol.md +61 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/references/workflows/improve-handoff.md +23 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/scripts/cli/run.sh +60 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/scripts/handoff/validate-build-input.ts +72 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/scripts/sync-spec/check-sync-spec.ts +499 -0
- package/mutagent-builder/.claude/skills/mutagent-builder/scripts/verify/spec-impl-coverage.ts +182 -0
- package/mutagent-builder/CLAUDE.md +25 -0
- package/mutagent-builder/README.md +26 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/README.md +192 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/SKILL.md +352 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/agents/ai-architect.md +256 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/agents/ai-engineer.md +344 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/agents/diagnostics-analyzer.md +576 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/agents/discovery.md +425 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/audit.json.tpl +24 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/audit.md.tpl +49 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/config.yaml.tpl +100 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/pr-body.md.tpl +56 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/report.html.tpl +327 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/shared/README.md +27 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/shared/iter-N-handover.md.tpl +125 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/shared/self-diagnosis-contract.v0.1.0.yaml.tpl +234 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/shared/spec.yaml.tpl +152 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/shared/team.yaml.tpl +127 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/templates/shared/wave-N-dashboard.html.tpl +1712 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/diagnostics/WF-2.1-nl-query.md +59 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/diagnostics/WF-2.2-tier0-progress.md +58 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/diagnostics/WF-2.3-analysis-progress.md +44 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/diagnostics/WF-2.4-html-report.md +61 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/diagnostics/WF-2.5-rca-detail.md +69 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/diagnostics/WF-2.6-stale-warning.md +53 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.1-welcome.md +60 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.2-source-platform-picker.md +41 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.3-source-auth.md +75 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.4-target-picker.md +48 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.5-ask-tool.md +43 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.6-config-review.md +57 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.7-filter-defaults.md +52 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/assets/wireframes/onboarding/WF-1.8-first-run.md +59 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/examples/sample-findings.json +92 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/examples/sample-meta.json +47 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/adapter-strategy.md +75 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/config-migration.md +84 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/config.md +159 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/filter-search-matrix.md +66 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/harness-knowledge.md +22 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/memory-format.md +78 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/onboarding-decisions.yaml +187 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/operation-inventory.md +59 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/overview.md +167 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/reference.md +119 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/script-index.md +101 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-adapter-contract.md +93 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/claude-code-transcripts.md +66 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/codex-transcripts.md +78 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/codex.md +145 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/install-paths.md +57 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/langfuse.md +178 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/local-jsonl.md +55 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/openobserve.md +102 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/source-platforms/otel.md +63 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/cloud-rest.md +84 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/local-claude.md +65 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/local-cloud-agent-sdk.md +92 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/local-codex.md +72 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/local-cursor.md +108 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/local-mastra.md +77 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/target-platforms/local-opencode.md +70 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/apply-pr-comment-format.md +82 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/diagnostics.md +35 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/handover-contract.md +247 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/onboarding.md +300 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/orchestrator-protocol.md +1861 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/rca.md +331 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/rendering-anatomy.md +314 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/schedule-prep.md +100 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/scope-model.md +128 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/references/workflows/verification-methodology.md +174 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/aggregate/sort-findings.ts +0 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/awareness/blind-spots.ts +167 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/awareness/llm-sample.ts +681 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/cli/doctor.ts +215 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/cli/init.ts +1013 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/cli/install-agents.ts +350 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/cli/run.sh +61 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/cli/shared-templates.ts +79 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/config/load.ts +392 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/config/resolve-credential.ts +120 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/config/schema.ts +641 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/config/validate.ts +134 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/context/build-diagnosis-context.ts +417 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/context/load-context.ts +105 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/contract/types.ts +166 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/enrich/build-render-input.ts +1964 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/enrich/corpus-severity.ts +172 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/enrich/dismissal-match.ts +270 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/enrich/rank-remedies.ts +75 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/hooks/install-hooks.sh +46 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/hooks/pre-push.sh +78 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/invocation/parse-brief.ts +188 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/library/match.ts +114 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/library/paths.ts +95 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/library/store.ts +535 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/library/types.ts +181 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/lint/template-inline-js.ts +267 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/memory/append.ts +188 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/memory/read.ts +218 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/normalize/platforms/entity-context.ts +686 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/normalize/read-unitf.ts +267 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/normalize/trace.ts +1078 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/normalize/unitf-adapter.ts +0 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/normalize/unitf-types.ts +213 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/report/persist-selections.ts +174 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/report/render.ts +3254 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/run/diagnose.ts +64 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/run/session.ts +167 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/sample/caps.ts +345 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/sample/deep-read-gate.ts +424 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/sample/representative.ts +584 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/scan/objection.ts +224 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/scan/trajectory.ts +489 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/self-diagnostics/dispatch.ts +135 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/self-diagnostics/probe.ts +170 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/setup/detect.ts +307 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/setup/ensure-cli.ts +315 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/setup/reconfigure.ts +77 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/setup/verify-agents.ts +207 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/slicer.ts +166 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/adapters/claude-code.ts +17 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/adapters/codex.ts +11 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/adapters/langfuse.ts +17 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/adapters/local-jsonl.ts +12 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/adapters/otel.ts +12 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/index.ts +54 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/registry.ts +45 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/source/types.ts +86 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/stale-detector.ts +74 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/test/render-playwright.cli.ts +477 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/tier0/claude-code.ts +133 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/tier0/langfuse.ts +143 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/tier0-scan.ts +423 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/completeness-check.ts +436 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/doc-refs.ts +190 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/finalize-gate.ts +417 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/findings-contract.ts +628 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/render-js-syntax.ts +188 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/report-checklist.yaml +217 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/trace-shape.ts +262 -0
- package/mutagent-diagnostics/.claude/skills/mutagent-diagnostics/scripts/validate/wave6-checklist.ts +326 -0
- package/mutagent-diagnostics/CLAUDE.md +41 -0
- package/mutagent-diagnostics/LICENSE +201 -0
- package/mutagent-diagnostics/NOTICE +18 -0
- package/mutagent-diagnostics/README.md +343 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/SKILL.md +548 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/assets/agents/audit-executor.md +169 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/assets/agents/dataset-builder.md +160 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/assets/agents/discovery.md +425 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/assets/agents/evaluator.md +1108 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/assets/brand/theme.css +213 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/assets/brand/wordmark.html +9 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/lenses/context-flow-lens.md +85 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/lenses/data-lens.md +47 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/lenses/decision-lens.md +48 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/lenses/methodology-critic-lens.md +53 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/lenses/trajectory-lens.md +44 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/build-review-interface.md +83 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/edd-loop.md +134 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/error-analysis.md +113 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/eval-audit.md +154 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/eval-stage.md +168 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/generate-synthetic-data.md +81 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/grounded-adjudication.md +221 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/memory-format.md +65 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/methodology.md +201 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/operation-inventory.md +197 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/validate-evaluator.md +125 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/workflows/orchestrator-protocol.md +300 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/references/write-judge-prompt.md +123 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/behavior-tree.schema.yaml +73 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/dataset.schema.yaml +66 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/edd-change-request.schema.yaml +114 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/eval-matrix.schema.yaml +74 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/flow-graph.schema.yaml +69 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/flow-profile.schema.yaml +49 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/methodology-review.schema.yaml +40 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/schemas/scorecard.schema.yaml +85 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/agent-dispatch.ts +0 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/aggregate-discover.ts +543 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/artifact-paths.ts +115 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/assemble-scorecard.ts +172 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/build-dataset.ts +186 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/build-evals.ts +93 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/build-review-ui.ts +393 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/check-method-router.ts +170 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/aggregate.ts +112 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/audit-run.ts +182 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/doctor.ts +211 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/dogfood.ts +133 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/init.ts +601 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/methodology-review.ts +122 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/prep.ts +295 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/profile-subject.ts +165 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/run.sh +56 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cli/variance-check.ts +105 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/code-eval.ts +248 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/code-quality-verdict.ts +285 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/codegen-evals.ts +173 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cold-start-project.ts +151 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/cold-start-sampler.ts +267 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/config/load.ts +343 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/config/schema.ts +380 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/agentspec-evals.ts +85 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/dataset.ts +149 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/eval-engine.ts +118 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/eval-matrix.ts +577 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/eval-types.ts +1074 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/flow-graph.ts +194 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/types.ts +303 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/contracts/validation.ts +193 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/derive-dataset.ts +152 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/determine-outcome.ts +219 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/diff-discriminate.ts +160 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/discover-criteria.ts +348 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/edd/change-request.ts +232 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/edd/edd-types.ts +210 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/edd/variance-gate.ts +186 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/emit-completeness.ts +111 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/eval-engine.ts +160 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/evaluate.ts +333 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/flow-graph.ts +230 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/judge-prompt-template.ts +253 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/judge-provider.ts +135 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/lint-grounding.ts +229 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/lint-uniformity.ts +168 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/living-suite.ts +109 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/load-bundle.ts +203 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/load-profile-vocab.ts +64 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/load-profile.ts +106 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/mask.ts +138 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/materialize-dataset.ts +113 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/matrix-judge.ts +750 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/memory/append.ts +215 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/memory/read.ts +168 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/persist-eval-criteria.ts +232 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/prep-tasks.ts +125 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/profile-subject.ts +310 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/publish-report.ts +131 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/read-unitf-traces.ts +81 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/render-build-cards.ts +195 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/render-discover-report.ts +1640 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/render-eval-report.ts +3838 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/render-report.ts +212 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/resolve-credential.ts +110 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/resolve-ref.ts +98 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/result-verify.ts +129 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/route-failures.ts +330 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/run-deterministic.ts +367 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/run-evaluate.ts +719 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/run-judge.ts +155 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/run-pipeline.ts +175 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/sample-traces.ts +210 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/self-audit.ts +387 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/source-map.ts +106 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/subject-profile.ts +134 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/substrate.ts +162 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/sync-eval-criteria.ts +244 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/ui-slots.ts +119 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/unitf-to-evaltrace.ts +284 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/validate-judge.ts +358 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/scripts/variance-compare.ts +177 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/subjects/mutagent-diagnostics/behavior-tree.yaml +140 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/subjects/mutagent-diagnostics/eval-matrix.yaml +1270 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/subjects/mutagent-diagnostics/methodology-review.yaml +105 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/workflows/audit.workflow.js +82 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/workflows/data-leak.workflow.js +236 -0
- package/mutagent-evaluator/.claude/skills/mutagent-evaluator/workflows/variance.workflow.js +163 -0
- package/mutagent-evaluator/CLAUDE.md +45 -0
- package/mutagent-evaluator/LICENSE +201 -0
- package/mutagent-evaluator/NOTICE +23 -0
- package/mutagent-evaluator/README.md +88 -0
- package/mutagent-optimize/.claude/skills/mutagent-optimize/SKILL.md +287 -0
- package/mutagent-optimize/.claude/skills/mutagent-optimize/scripts/contracts/amend-request.ts +503 -0
- package/mutagent-optimize/.claude/skills/mutagent-optimize/scripts/improve-loop-run.ts +304 -0
- package/mutagent-optimize/.claude/skills/mutagent-optimize/scripts/loop-state-cli.ts +300 -0
- package/mutagent-optimize/.claude/skills/mutagent-optimize/scripts/loop-state.ts +440 -0
- package/mutagent-optimize/CLAUDE.md +49 -0
- package/mutagent-optimize/README.md +26 -0
- package/mutagent-orchestrator/CLAUDE.md +102 -0
- package/mutagent-orchestrator/README.md +20 -0
- package/mutagent-orchestrator/assets/agents/discovery.md +425 -0
- package/mutagent-orchestrator/assets/agents/dogfood-monitor.md +266 -0
- package/mutagent-orchestrator/assets/agents/monitor.md +258 -0
- package/mutagent-orchestrator/orchestrator.md +782 -0
- package/mutagent-orchestrator/references/MONITORING.md +209 -0
- package/mutagent-orchestrator/references/config-fields.md +132 -0
- package/mutagent-orchestrator/references/config-migration.md +132 -0
- package/mutagent-orchestrator/references/index-registry.md +92 -0
- package/mutagent-orchestrator/routing.yaml +391 -0
- package/mutagent-orchestrator/scripts/config-schema.ts +1010 -0
- package/mutagent-orchestrator/scripts/dispatch.ts +439 -0
- package/mutagent-orchestrator/scripts/dogfood/extract-feedback.ts +203 -0
- package/mutagent-orchestrator/scripts/dogfood/reconstruct-trajectory.ts +327 -0
- package/mutagent-orchestrator/scripts/dogfood/render-dogfood-report.ts +347 -0
- package/mutagent-orchestrator/scripts/dogfood/resolve-subagents.ts +160 -0
- package/mutagent-orchestrator/scripts/dogfood/run-report.ts +264 -0
- package/mutagent-orchestrator/scripts/dogfood/slack-thread.ts +106 -0
- package/mutagent-orchestrator/scripts/dogfood/types.ts +257 -0
- package/mutagent-orchestrator/scripts/eval-routing.ts +753 -0
- package/mutagent-orchestrator/scripts/gate.ts +219 -0
- package/mutagent-orchestrator/scripts/handover-contract.ts +362 -0
- package/mutagent-orchestrator/scripts/index/build-index.ts +351 -0
- package/mutagent-orchestrator/scripts/index/render-index.ts +110 -0
- package/mutagent-orchestrator/scripts/monitor/slack-notify.ts +111 -0
- package/mutagent-orchestrator/scripts/monitor/triggers.ts +162 -0
- package/mutagent-orchestrator/scripts/onboarding-check.ts +369 -0
- package/mutagent-orchestrator/scripts/render-roster.ts +308 -0
- package/mutagent-orchestrator/scripts/resolve-credential.ts +185 -0
- package/mutagent-orchestrator/scripts/resolve-paths.ts +114 -0
- package/mutagent-orchestrator/scripts/slack/format.ts +63 -0
- package/mutagent-orchestrator/scripts/slack/post.ts +115 -0
- package/mutagent-orchestrator/scripts/sync-index.ts +311 -0
- package/package.json +64 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scripts/validate/findings-contract.ts
|
|
3
|
+
* W12-07 (OP-6 / CC-09): Findings-contract validator — the enabler.
|
|
4
|
+
*
|
|
5
|
+
* Runs at orchestrator Step 7 (post-aggregate, pre-RCA) over the aggregated
|
|
6
|
+
* findings array. Enforces the CC-09 force-emit field set (was prose-only in
|
|
7
|
+
* handover-contract.md `required_remedy_fields`). On any violation it emits a
|
|
8
|
+
* machine-readable `RESEND <findingId> with <missing fields>` directive and exits
|
|
9
|
+
* non-zero so the orchestrator can re-dispatch the analyzer for the offending
|
|
10
|
+
* finding (handover-contract `on_missing_field`, max_redispatch: 2).
|
|
11
|
+
*
|
|
12
|
+
* This is the upstream guard that keeps a malformed finding from ever reaching
|
|
13
|
+
* the renderer: the contract catches the missing field here, so the renderer
|
|
14
|
+
* never has to crash on optional-field absence.
|
|
15
|
+
*
|
|
16
|
+
* TypeBox over Finding / Remedy / Assumption (defined in scripts/normalize/trace.ts).
|
|
17
|
+
* W12-08 (PR-052 proposed): every remedy must link to a target (`applyTarget`)
|
|
18
|
+
* and focus on an origin; cite the source via `diff` when findable, else carry an
|
|
19
|
+
* explicit `diffStatus` marker — NEVER a fabricated diff.
|
|
20
|
+
*
|
|
21
|
+
* Usage: bun scripts/cli/run.sh scripts/validate/findings-contract.ts <findings.json>
|
|
22
|
+
*
|
|
23
|
+
* Exit 0 = every finding satisfies the contract.
|
|
24
|
+
* Exit 1 = one or more findings violate it (RESEND directives on stdout).
|
|
25
|
+
*
|
|
26
|
+
* Type A — Pure Script (deterministic, no I/O except the CLI argument file).
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { Type } from "@sinclair/typebox";
|
|
30
|
+
import type { TObject } from "@sinclair/typebox";
|
|
31
|
+
import { Value } from "@sinclair/typebox/value";
|
|
32
|
+
import type { Finding } from "../normalize/trace.ts";
|
|
33
|
+
|
|
34
|
+
// ── Field contract — the SINGLE source of truth mirrors handover-contract.md ──
|
|
35
|
+
//
|
|
36
|
+
// Keep these in lock-step with `required_remedy_fields` / `required_finding_fields`
|
|
37
|
+
// in references/workflows/handover-contract.md. The validator is the executable
|
|
38
|
+
// form of that prose contract.
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* CC-09 / W12-08 force-emit remedy fields, each non-null.
|
|
42
|
+
*
|
|
43
|
+
* W13-C (D-1): `cost` + `correctness` join the force-emit set. They are categorical
|
|
44
|
+
* judgments only the analyzer can make from trace evidence, so absence is caught here
|
|
45
|
+
* with a RESEND rather than rendering `cost:undefined` / `correct:undefined` badges.
|
|
46
|
+
* `rank` is deliberately NOT in this set — it is enricher-DERIVED from `cost ×
|
|
47
|
+
* correctness` (orchestrator-protocol §8), never analyzer-supplied. See
|
|
48
|
+
* scripts/enrich/rank-remedies.ts.
|
|
49
|
+
*/
|
|
50
|
+
export const REQUIRED_REMEDY_FIELDS = [
|
|
51
|
+
"applyTarget",
|
|
52
|
+
"targetClass",
|
|
53
|
+
"rationale",
|
|
54
|
+
"whyWorks",
|
|
55
|
+
"applyInstructions",
|
|
56
|
+
"assumptions",
|
|
57
|
+
// W13-C (D-1): the two cost/correctness header-badge inputs — required from the analyzer.
|
|
58
|
+
"cost",
|
|
59
|
+
"correctness",
|
|
60
|
+
] as const;
|
|
61
|
+
|
|
62
|
+
/** Required finding fields (analyzer self-validates before return). */
|
|
63
|
+
export const REQUIRED_FINDING_FIELDS = [
|
|
64
|
+
"findingId",
|
|
65
|
+
"actionable",
|
|
66
|
+
// Phase-1 (W18-problem): descriptive problem statement, REQUIRED. W18-gate additionally
|
|
67
|
+
// enforces it reads as a DESCRIPTION, not a task/remedy (see isTaskPhrasedProblem).
|
|
68
|
+
"problem",
|
|
69
|
+
"failureOrigin",
|
|
70
|
+
"whyChain",
|
|
71
|
+
"sourceTraceIds",
|
|
72
|
+
"referenceIds",
|
|
73
|
+
"audience",
|
|
74
|
+
] as const;
|
|
75
|
+
|
|
76
|
+
// ── TypeBox schemas (structural floor; field-level required-ness below) ───────
|
|
77
|
+
|
|
78
|
+
const AssumptionSchema = Type.Object({
|
|
79
|
+
text: Type.String({ minLength: 1 }),
|
|
80
|
+
status: Type.Union([
|
|
81
|
+
Type.Literal("verified"),
|
|
82
|
+
Type.Literal("unverified"),
|
|
83
|
+
Type.Literal("hypothesis-pending"),
|
|
84
|
+
]),
|
|
85
|
+
basis: Type.String({ minLength: 1 }),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const DiffSchema = Type.Object({
|
|
89
|
+
before: Type.String(),
|
|
90
|
+
after: Type.String(),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const DiffStatusSchema = Type.Union([
|
|
94
|
+
Type.Literal("source-unavailable"),
|
|
95
|
+
Type.Literal("origin-unknown"),
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* W13-C (D-1): the cost / correctness categorical scale. Mirrors the canonical
|
|
100
|
+
* Remedy.cost / Remedy.correctness union in scripts/normalize/trace.ts. Both feed
|
|
101
|
+
* the renderer's header badges AND the enricher's deterministic rank derivation.
|
|
102
|
+
*/
|
|
103
|
+
const CostCorrectnessSchema = Type.Union([
|
|
104
|
+
Type.Literal("low"),
|
|
105
|
+
Type.Literal("medium"),
|
|
106
|
+
Type.Literal("high"),
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* W12-08: the contract-enforced Remedy shape. Fields the operator made HARD-required
|
|
111
|
+
* are non-optional here; `diff` / `diffStatus` are validated by the XOR rule in
|
|
112
|
+
* `remedyFieldViolations` (TypeBox alone cannot express "exactly one of").
|
|
113
|
+
*/
|
|
114
|
+
const RemedyContractSchema = Type.Object({
|
|
115
|
+
remedyId: Type.String({ minLength: 1 }),
|
|
116
|
+
title: Type.String({ minLength: 1 }),
|
|
117
|
+
// applyTarget — HARD-required: every remedy must link to a target.
|
|
118
|
+
applyTarget: Type.String({ minLength: 1 }),
|
|
119
|
+
targetClass: Type.String({ minLength: 1 }),
|
|
120
|
+
rationale: Type.String({ minLength: 1 }),
|
|
121
|
+
whyWorks: Type.String({ minLength: 1 }),
|
|
122
|
+
applyInstructions: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
|
|
123
|
+
// W13-C (D-1): cost + correctness are force-emit categorical scalars.
|
|
124
|
+
cost: CostCorrectnessSchema,
|
|
125
|
+
correctness: CostCorrectnessSchema,
|
|
126
|
+
// diff / diffStatus validated via XOR in remedyFieldViolations (not here).
|
|
127
|
+
diff: Type.Optional(DiffSchema),
|
|
128
|
+
diffStatus: Type.Optional(DiffStatusSchema),
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ── Result shapes ──────────────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
export interface FindingContractViolation {
|
|
134
|
+
findingId: string;
|
|
135
|
+
/** remedyId when the violation is on a remedy; undefined for finding-level. */
|
|
136
|
+
remedyId?: string;
|
|
137
|
+
/** The missing / invalid field names. */
|
|
138
|
+
missingFields: string[];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface FindingsContractResult {
|
|
142
|
+
valid: boolean;
|
|
143
|
+
totalFindings: number;
|
|
144
|
+
violations: FindingContractViolation[];
|
|
145
|
+
/** One machine-readable `RESEND <id> with <fields>` directive per offending finding. */
|
|
146
|
+
resendDirectives: string[];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ── Field-level checks ──────────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
function isNonEmptyString(v: unknown): boolean {
|
|
152
|
+
return typeof v === "string" && v.trim() !== "";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function hasStructuralFloor(schema: TObject, value: unknown): boolean {
|
|
156
|
+
return Value.Check(schema, value);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Collect the missing required-field names for a single remedy. Encodes:
|
|
161
|
+
* - applyTarget HARD-required (link to a target)
|
|
162
|
+
* - targetClass / rationale / whyWorks required (non-empty)
|
|
163
|
+
* - applyInstructions required (≥1 entry)
|
|
164
|
+
* - assumptions required (≥1 structured entry) — this lives on the FINDING in
|
|
165
|
+
* the schema, but the operator-required "≥1 assumption" is enforced at finding
|
|
166
|
+
* level (see findingFieldViolations); remedies do not carry assumptions.
|
|
167
|
+
* - diff XOR diffStatus: exactly one must be present (PR-052 proposed) — never
|
|
168
|
+
* a fabricated diff, never neither.
|
|
169
|
+
*/
|
|
170
|
+
export function remedyFieldViolations(remedy: unknown): string[] {
|
|
171
|
+
const missing: string[] = [];
|
|
172
|
+
const r = (remedy ?? {}) as Record<string, unknown>;
|
|
173
|
+
|
|
174
|
+
if (!isNonEmptyString(r.applyTarget)) missing.push("applyTarget");
|
|
175
|
+
if (!isNonEmptyString(r.targetClass)) missing.push("targetClass");
|
|
176
|
+
if (!isNonEmptyString(r.rationale)) missing.push("rationale");
|
|
177
|
+
if (!isNonEmptyString(r.whyWorks)) missing.push("whyWorks");
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
!Array.isArray(r.applyInstructions) ||
|
|
181
|
+
r.applyInstructions.length === 0 ||
|
|
182
|
+
r.applyInstructions.some((s) => !isNonEmptyString(s))
|
|
183
|
+
) {
|
|
184
|
+
missing.push("applyInstructions");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// W13-C (D-1): cost + correctness force-emit — must be a low|medium|high enum value.
|
|
188
|
+
// (rank is NOT checked: it is enricher-derived from these two, never analyzer-supplied.)
|
|
189
|
+
if (!Value.Check(CostCorrectnessSchema, r.cost)) missing.push("cost");
|
|
190
|
+
if (!Value.Check(CostCorrectnessSchema, r.correctness)) missing.push("correctness");
|
|
191
|
+
|
|
192
|
+
// diff XOR diffStatus — exactly one. Honors feedback_model_intent_sacred:
|
|
193
|
+
// a remedy with no findable source carries the marker, not a guessed diff.
|
|
194
|
+
const hasDiff = Value.Check(DiffSchema, r.diff);
|
|
195
|
+
const hasDiffStatus = Value.Check(DiffStatusSchema, r.diffStatus);
|
|
196
|
+
if (!hasDiff && !hasDiffStatus) {
|
|
197
|
+
missing.push("diff-or-diffStatus");
|
|
198
|
+
} else if (hasDiff && hasDiffStatus) {
|
|
199
|
+
// Ambiguous: a remedy must not claim both a concrete diff and "source not found".
|
|
200
|
+
missing.push("diff-xor-diffStatus(both-present)");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Structural floor catch-all (wrong types on the required scalars).
|
|
204
|
+
if (
|
|
205
|
+
missing.length === 0 &&
|
|
206
|
+
!hasStructuralFloor(RemedyContractSchema, {
|
|
207
|
+
remedyId: r.remedyId,
|
|
208
|
+
title: r.title,
|
|
209
|
+
applyTarget: r.applyTarget,
|
|
210
|
+
targetClass: r.targetClass,
|
|
211
|
+
rationale: r.rationale,
|
|
212
|
+
whyWorks: r.whyWorks,
|
|
213
|
+
applyInstructions: r.applyInstructions,
|
|
214
|
+
cost: r.cost,
|
|
215
|
+
correctness: r.correctness,
|
|
216
|
+
diff: r.diff,
|
|
217
|
+
diffStatus: r.diffStatus,
|
|
218
|
+
})
|
|
219
|
+
) {
|
|
220
|
+
missing.push("remedy(structural)");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return missing;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── W18-gate: problem-statement FORMAT check (first content gate) ────────────────
|
|
227
|
+
//
|
|
228
|
+
// WHY: Phase-1 made `Finding.problem` REQUIRED (trace.ts), but presence ≠ correct
|
|
229
|
+
// shape. Every gate before this one is a SHAPE gate (field present / non-empty / right
|
|
230
|
+
// type). This is the first CONTENT gate: the required `problem` must DESCRIBE the
|
|
231
|
+
// failure + quantified impact, NOT read as a task/remedy. trace.ts documents the
|
|
232
|
+
// format: "<subject> <observed behavior, declarative> — <quantified impact + evidence>"
|
|
233
|
+
// and explicitly bans the todo phrasing ("Make X faster — use a smaller model"). The
|
|
234
|
+
// fix belongs ONLY in `remedies`; a `problem` written in imperative/prescriptive mood
|
|
235
|
+
// leaks the remedy into the description slot. RESEND on violation (file-consistent).
|
|
236
|
+
//
|
|
237
|
+
// FALSE-POSITIVE DISCIPLINE (operator directive — be conservative):
|
|
238
|
+
// We target the IMPERATIVE MOOD (a leading bare verb with no subject), NOT any
|
|
239
|
+
// occurrence of a banned word. The guard rests on two facts:
|
|
240
|
+
// 1. The imperative form is the BARE verb exactly ("reduce", "increase"). Past-tense
|
|
241
|
+
// observations use inflected forms ("reduced", "increased", "reduces") which do
|
|
242
|
+
// NOT match an exact bare-verb token. So "throughput reduced to 12 req/s" — whose
|
|
243
|
+
// FIRST word is the subject "throughput" — is never flagged.
|
|
244
|
+
// 2. We only inspect the FIRST word of the FIRST clause. A descriptive statement
|
|
245
|
+
// leads with its subject; an imperative leads with its verb.
|
|
246
|
+
// Prescriptive modals ("should" / "must" / "needs to") are checked ONLY in the MAIN
|
|
247
|
+
// clause (before the first em-dash that separates the impact/evidence tail), so a
|
|
248
|
+
// quoted impact phrase after the "—" can't trip them.
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Imperative verbs that, as the LEADING bare verb of the problem statement, signal a
|
|
252
|
+
* task/remedy rather than a description. Matched as the exact first token (after
|
|
253
|
+
* lowercasing + stripping trailing punctuation) — never as a substring, never inflected.
|
|
254
|
+
*/
|
|
255
|
+
export const BANNED_LEADING_IMPERATIVE_VERBS = new Set<string>([
|
|
256
|
+
"make",
|
|
257
|
+
"use",
|
|
258
|
+
"cap",
|
|
259
|
+
"add",
|
|
260
|
+
"reduce",
|
|
261
|
+
"switch",
|
|
262
|
+
"replace",
|
|
263
|
+
"enable",
|
|
264
|
+
"fix",
|
|
265
|
+
"consider",
|
|
266
|
+
"try",
|
|
267
|
+
"avoid",
|
|
268
|
+
"ensure",
|
|
269
|
+
"implement",
|
|
270
|
+
"increase",
|
|
271
|
+
"decrease",
|
|
272
|
+
"move",
|
|
273
|
+
"remove",
|
|
274
|
+
"update",
|
|
275
|
+
"set",
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Extract the first word-token of a string: leading whitespace/quotes stripped, then
|
|
280
|
+
* the run of leading letters (so "Make," → "make", "“Use…" → "use"). Returns "" when
|
|
281
|
+
* there is no leading alphabetic token.
|
|
282
|
+
*/
|
|
283
|
+
function leadingWord(s: string): string {
|
|
284
|
+
const m = s.trimStart().match(/^["'“”‘’*_([]*([a-zA-Z]+)/);
|
|
285
|
+
return m ? m[1].toLowerCase() : "";
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The MAIN clause = everything before the first em-dash / " - " hyphen separator that
|
|
290
|
+
* trace.ts uses to split "<description> — <quantified impact + evidence>". Prescriptive
|
|
291
|
+
* modals are searched only here so a legitimately-quoted impact tail can't trip the gate.
|
|
292
|
+
*/
|
|
293
|
+
function mainClause(problem: string): string {
|
|
294
|
+
// Split on em-dash, en-dash, or a spaced hyphen (the documented impact separator).
|
|
295
|
+
return problem.split(/\s+[—–]\s+|\s+-\s+/)[0] ?? problem;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* W18-gate: true when the (already-present, non-empty) problem statement reads like a
|
|
300
|
+
* task/remedy rather than a descriptive problem statement.
|
|
301
|
+
*
|
|
302
|
+
* Two conservative signals:
|
|
303
|
+
* (a) Imperative mood — the FIRST word of the FIRST clause is a bare imperative verb
|
|
304
|
+
* from BANNED_LEADING_IMPERATIVE_VERBS (subject-less directive).
|
|
305
|
+
* (b) Prescription modal in the MAIN clause — "should" / "must" / "needs to" used to
|
|
306
|
+
* prescribe (e.g. "X should be cached"). Bounded to the pre-em-dash clause.
|
|
307
|
+
*/
|
|
308
|
+
export function isTaskPhrasedProblem(problem: unknown): boolean {
|
|
309
|
+
if (typeof problem !== "string") return false;
|
|
310
|
+
const text = problem.trim();
|
|
311
|
+
if (text === "") return false;
|
|
312
|
+
|
|
313
|
+
// (a) Leading bare-verb imperative. Inspect ONLY the first clause's first word so that
|
|
314
|
+
// "throughput reduced to 12 req/s" (subject-first, past tense) is never flagged.
|
|
315
|
+
const firstClause = mainClause(text);
|
|
316
|
+
if (BANNED_LEADING_IMPERATIVE_VERBS.has(leadingWord(firstClause))) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// (b) Prescriptive modals in the main clause only. Word-boundaried; "needs to" requires
|
|
321
|
+
// the infinitive marker so a descriptive "the agent needs three retries" (no "to")
|
|
322
|
+
// does not trip. "should" / "must" are inherently prescriptive when present.
|
|
323
|
+
const clause = firstClause.toLowerCase();
|
|
324
|
+
if (/\b(should|must)\b/.test(clause) || /\bneeds\s+to\b/.test(clause)) {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** The RESEND-facing message for a task-phrased problem (W18-gate). */
|
|
332
|
+
export const PROBLEM_TASK_PHRASED_MESSAGE =
|
|
333
|
+
"Problem reads like a task/remedy — it must DESCRIBE the failure + quantified " +
|
|
334
|
+
"impact; move the fix to remedies.";
|
|
335
|
+
|
|
336
|
+
// ── S3.5 (Wave-15 Block B): no-code-access assumption CONTENT check ──────────────
|
|
337
|
+
//
|
|
338
|
+
// WHY: the Step-7.1 gate previously checked `assumptions.length>0` but NOT content.
|
|
339
|
+
// When `entity.codeAccess === false`, the REQUIRED "no-code-access" assumption (the
|
|
340
|
+
// "source code was not provided; findings are evidence-only" disclaimer) could vanish
|
|
341
|
+
// uncaught — a finding could ship with a different assumption and pass the length
|
|
342
|
+
// check. FIX (operator option A): when codeAccess===false, assert a no-code-access
|
|
343
|
+
// assumption is PRESENT by content (text/status), not just array length. RESEND on
|
|
344
|
+
// violation.
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* S3.5: true when an assumption is the no-code-access disclaimer — matched by
|
|
348
|
+
* SEMANTIC SIGNATURE rather than an exact string, so BOTH the enricher-synthesized
|
|
349
|
+
* form (synthesizeNoCodeAccessAssumption: status "hypothesis-pending", text
|
|
350
|
+
* "Source code for X was not provided; findings are evidence-only.") AND an
|
|
351
|
+
* analyzer-authored equivalent are accepted. Signature:
|
|
352
|
+
* status === "hypothesis-pending" AND
|
|
353
|
+
* text or basis references the no-code-access / source-unavailable concept.
|
|
354
|
+
*/
|
|
355
|
+
function isNoCodeAccessAssumption(a: unknown): boolean {
|
|
356
|
+
if (!Value.Check(AssumptionSchema, a)) return false;
|
|
357
|
+
const asm = a as { text: string; status: string; basis: string };
|
|
358
|
+
if (asm.status !== "hypothesis-pending") return false;
|
|
359
|
+
const haystack = `${asm.text} ${asm.basis}`.toLowerCase();
|
|
360
|
+
// "source code … not provided / unavailable", "no code access", "codeAccess === false",
|
|
361
|
+
// "evidence-only" — any of the recognized no-code-access phrasings.
|
|
362
|
+
const mentionsSource = /\b(source code|source|code access|codeaccess)\b/.test(haystack);
|
|
363
|
+
const mentionsUnavailable =
|
|
364
|
+
/\bnot provided\b|\bunavailable\b|\bno (code )?access\b|\bevidence[- ]only\b|\bcodeaccess\s*===?\s*false\b|\bnot accessible\b/.test(
|
|
365
|
+
haystack
|
|
366
|
+
);
|
|
367
|
+
return mentionsSource && mentionsUnavailable;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Collect the missing required-field names at the finding level, plus the
|
|
372
|
+
* operator-required "≥1 assumption" rule (assumptions live on the Finding).
|
|
373
|
+
*
|
|
374
|
+
* S3.5: when `opts.entityCodeAccess === false`, ALSO require that ≥1 assumption is a
|
|
375
|
+
* no-code-access disclaimer (content check). Omitting `opts` (or leaving
|
|
376
|
+
* entityCodeAccess undefined / true) preserves the prior length-only behavior.
|
|
377
|
+
*/
|
|
378
|
+
export function findingFieldViolations(
|
|
379
|
+
finding: unknown,
|
|
380
|
+
opts: { entityCodeAccess?: boolean } = {}
|
|
381
|
+
): string[] {
|
|
382
|
+
const missing: string[] = [];
|
|
383
|
+
const f = (finding ?? {}) as Record<string, unknown>;
|
|
384
|
+
|
|
385
|
+
if (!isNonEmptyString(f.findingId)) missing.push("findingId");
|
|
386
|
+
if (!isNonEmptyString(f.actionable)) missing.push("actionable");
|
|
387
|
+
if (typeof f.failureOrigin !== "object" || f.failureOrigin === null) {
|
|
388
|
+
missing.push("failureOrigin");
|
|
389
|
+
} else {
|
|
390
|
+
// EV-gate (Wave-15 Block B, gate half of EV-1): Block 0 added the required field
|
|
391
|
+
// `whatHappened: string` to FailureOrigin — the plain-words narration companion to
|
|
392
|
+
// the `evidence` pointer. A finding is REJECTED (RESEND) when the narration is
|
|
393
|
+
// empty/missing, OR when the `evidence` pointer is empty/missing (still required).
|
|
394
|
+
const fo = f.failureOrigin as Record<string, unknown>;
|
|
395
|
+
if (!isNonEmptyString(fo.whatHappened)) missing.push("failureOrigin.whatHappened");
|
|
396
|
+
if (!isNonEmptyString(fo.evidence)) missing.push("failureOrigin.evidence");
|
|
397
|
+
}
|
|
398
|
+
if (!Array.isArray(f.whyChain) || f.whyChain.length === 0) {
|
|
399
|
+
missing.push("whyChain");
|
|
400
|
+
} else {
|
|
401
|
+
// EV-gate: every why-chain step carries the required `whatHappened` narration
|
|
402
|
+
// (Block 0 added it to WhyChainEntry). Reject when ANY step's narration is
|
|
403
|
+
// empty/missing. `evidence` stays required per-step too.
|
|
404
|
+
const badNarration = f.whyChain.some(
|
|
405
|
+
(w) => !isNonEmptyString((w as Record<string, unknown>)?.whatHappened)
|
|
406
|
+
);
|
|
407
|
+
const badEvidence = f.whyChain.some(
|
|
408
|
+
(w) => !isNonEmptyString((w as Record<string, unknown>)?.evidence)
|
|
409
|
+
);
|
|
410
|
+
if (badNarration) missing.push("whyChain[].whatHappened");
|
|
411
|
+
if (badEvidence) missing.push("whyChain[].evidence");
|
|
412
|
+
}
|
|
413
|
+
if (!Array.isArray(f.sourceTraceIds) || f.sourceTraceIds.length === 0) {
|
|
414
|
+
missing.push("sourceTraceIds");
|
|
415
|
+
}
|
|
416
|
+
if (typeof f.referenceIds !== "object" || f.referenceIds === null) {
|
|
417
|
+
missing.push("referenceIds");
|
|
418
|
+
}
|
|
419
|
+
if (!isNonEmptyString(f.audience)) missing.push("audience");
|
|
420
|
+
|
|
421
|
+
// Phase-1 (W18-problem): `problem` is REQUIRED (trace.ts) — must be present + non-empty.
|
|
422
|
+
if (!isNonEmptyString(f.problem)) {
|
|
423
|
+
missing.push("problem");
|
|
424
|
+
} else if (isTaskPhrasedProblem(f.problem)) {
|
|
425
|
+
// W18-gate (this wave): the first CONTENT gate. A present, non-empty problem that
|
|
426
|
+
// reads as a task/remedy (imperative mood / prescriptive modal) is REJECTED so the
|
|
427
|
+
// descriptive-statement contract is actually enforced, not just field presence.
|
|
428
|
+
missing.push("problem(task-phrased)");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Operator-required: ≥1 structured assumption per finding (PR-030 / W12-08).
|
|
432
|
+
const assumptionsValid =
|
|
433
|
+
Array.isArray(f.assumptions) &&
|
|
434
|
+
f.assumptions.length > 0 &&
|
|
435
|
+
f.assumptions.every((a) => Value.Check(AssumptionSchema, a));
|
|
436
|
+
if (!assumptionsValid) {
|
|
437
|
+
missing.push("assumptions");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// S3.5: no-code-access CONTENT check. Only fires when the diagnosed entity has
|
|
441
|
+
// no source access (entity.codeAccess === false). The required disclaimer must be
|
|
442
|
+
// PRESENT — a length-only-valid assumptions array that omits it is rejected.
|
|
443
|
+
if (opts.entityCodeAccess === false) {
|
|
444
|
+
const hasDisclaimer =
|
|
445
|
+
Array.isArray(f.assumptions) && f.assumptions.some(isNoCodeAccessAssumption);
|
|
446
|
+
if (!hasDisclaimer) {
|
|
447
|
+
missing.push("assumptions(no-code-access)");
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Every finding must carry ≥1 remedy.
|
|
452
|
+
if (!Array.isArray(f.remedies) || f.remedies.length === 0) {
|
|
453
|
+
missing.push("remedies");
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return missing;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ── Aggregate validator ─────────────────────────────────────────────────────────
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Options for the aggregate validator.
|
|
463
|
+
* S3.5: `entityCodeAccess` is the diagnosed entity's `EntityContext.codeAccess`.
|
|
464
|
+
* When `false`, every finding must carry a no-code-access disclaimer assumption
|
|
465
|
+
* (content check). Undefined/true ⇒ the content check is skipped (length-only).
|
|
466
|
+
*/
|
|
467
|
+
export interface FindingsContractOptions {
|
|
468
|
+
entityCodeAccess?: boolean;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Validate an aggregated findings array against the contract.
|
|
473
|
+
* One violation row per offending (finding, remedy) pair; one RESEND directive
|
|
474
|
+
* per offending finding (fields merged across the finding + its remedies).
|
|
475
|
+
*/
|
|
476
|
+
export function validateFindingsContract(
|
|
477
|
+
findings: unknown[],
|
|
478
|
+
opts: FindingsContractOptions = {}
|
|
479
|
+
): FindingsContractResult {
|
|
480
|
+
const violations: FindingContractViolation[] = [];
|
|
481
|
+
|
|
482
|
+
for (const finding of findings) {
|
|
483
|
+
const f = (finding ?? {}) as Record<string, unknown>;
|
|
484
|
+
const findingId = isNonEmptyString(f.findingId)
|
|
485
|
+
? (f.findingId as string)
|
|
486
|
+
: "(missing-findingId)";
|
|
487
|
+
|
|
488
|
+
const findingMissing = findingFieldViolations(finding, {
|
|
489
|
+
entityCodeAccess: opts.entityCodeAccess,
|
|
490
|
+
});
|
|
491
|
+
if (findingMissing.length > 0) {
|
|
492
|
+
violations.push({ findingId, missingFields: findingMissing });
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const remedies = Array.isArray(f.remedies) ? f.remedies : [];
|
|
496
|
+
for (const remedy of remedies) {
|
|
497
|
+
const r = (remedy ?? {}) as Record<string, unknown>;
|
|
498
|
+
const remedyMissing = remedyFieldViolations(remedy);
|
|
499
|
+
if (remedyMissing.length > 0) {
|
|
500
|
+
violations.push({
|
|
501
|
+
findingId,
|
|
502
|
+
remedyId: isNonEmptyString(r.remedyId)
|
|
503
|
+
? (r.remedyId as string)
|
|
504
|
+
: "(missing-remedyId)",
|
|
505
|
+
missingFields: remedyMissing,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// One RESEND directive per offending finding (merge field names, dedup).
|
|
512
|
+
const byFinding = new Map<string, Set<string>>();
|
|
513
|
+
for (const v of violations) {
|
|
514
|
+
const set = byFinding.get(v.findingId) ?? new Set<string>();
|
|
515
|
+
for (const field of v.missingFields) {
|
|
516
|
+
// Qualify remedy-level fields so the analyzer knows where to look.
|
|
517
|
+
set.add(v.remedyId ? `remedy:${v.remedyId}.${field}` : field);
|
|
518
|
+
}
|
|
519
|
+
byFinding.set(v.findingId, set);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const resendDirectives = [...byFinding.entries()].map(
|
|
523
|
+
([findingId, fields]) =>
|
|
524
|
+
`RESEND ${findingId} with ${[...fields].join(", ")}`
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
return {
|
|
528
|
+
valid: violations.length === 0,
|
|
529
|
+
totalFindings: findings.length,
|
|
530
|
+
violations,
|
|
531
|
+
resendDirectives,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Guard: throws (with all RESEND directives) if any finding violates the contract.
|
|
537
|
+
* Useful at the Step-7 aggregate boundary before handing findings to RCA/render.
|
|
538
|
+
* S3.5: pass `opts.entityCodeAccess` to enforce the no-code-access content check.
|
|
539
|
+
*/
|
|
540
|
+
export function assertFindingsContract(
|
|
541
|
+
findings: unknown[],
|
|
542
|
+
opts: FindingsContractOptions = {}
|
|
543
|
+
): asserts findings is Finding[] {
|
|
544
|
+
const result = validateFindingsContract(findings, opts);
|
|
545
|
+
if (!result.valid) {
|
|
546
|
+
throw new Error(
|
|
547
|
+
`Findings-contract validation failed (${result.violations.length} violation(s)):\n` +
|
|
548
|
+
result.resendDirectives.map((d) => ` ${d}`).join("\n")
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// ── CLI entrypoint ───────────────────────────────────────────────────────────────
|
|
554
|
+
|
|
555
|
+
if (import.meta.main) {
|
|
556
|
+
const { readFileSync } = await import("fs");
|
|
557
|
+
const { resolve } = await import("path");
|
|
558
|
+
|
|
559
|
+
const argv = process.argv.slice(2);
|
|
560
|
+
const flagVal = (name: string): string | undefined => {
|
|
561
|
+
const i = argv.indexOf(name);
|
|
562
|
+
return i >= 0 ? argv[i + 1] : undefined;
|
|
563
|
+
};
|
|
564
|
+
// Positional findings path = first non-flag arg (preserves the legacy invocation).
|
|
565
|
+
const entityContextPath = flagVal("--entity-context");
|
|
566
|
+
const inputPath = argv.find(
|
|
567
|
+
(a, i) => !a.startsWith("--") && argv[i - 1] !== "--entity-context"
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
if (!inputPath) {
|
|
571
|
+
process.stderr.write(
|
|
572
|
+
"Usage: bun scripts/cli/run.sh scripts/validate/findings-contract.ts <findings.json> [--entity-context <entity-context.json>]\n" +
|
|
573
|
+
"\n" +
|
|
574
|
+
"Validates an aggregated Finding[] against the CC-09 / W12-08 contract.\n" +
|
|
575
|
+
"On violation, prints one `RESEND <findingId> with <fields>` directive per\n" +
|
|
576
|
+
"offending finding and exits non-zero (orchestrator Step 7 re-dispatches).\n" +
|
|
577
|
+
"S3.5: when --entity-context resolves an entity with codeAccess===false, each\n" +
|
|
578
|
+
"finding must carry a no-code-access disclaimer assumption (content check).\n"
|
|
579
|
+
);
|
|
580
|
+
process.exit(1);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
let findings: unknown[];
|
|
584
|
+
try {
|
|
585
|
+
const raw = JSON.parse(readFileSync(resolve(inputPath), "utf8"));
|
|
586
|
+
if (!Array.isArray(raw)) {
|
|
587
|
+
process.stderr.write("Error: input file must contain a JSON array of findings\n");
|
|
588
|
+
process.exit(1);
|
|
589
|
+
}
|
|
590
|
+
findings = raw;
|
|
591
|
+
} catch (err) {
|
|
592
|
+
process.stderr.write(`Error reading ${inputPath}: ${err}\n`);
|
|
593
|
+
process.exit(1);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// S3.5: resolve the diagnosed entity's codeAccess when --entity-context is supplied.
|
|
597
|
+
let entityCodeAccess: boolean | undefined;
|
|
598
|
+
if (entityContextPath) {
|
|
599
|
+
try {
|
|
600
|
+
const ec = JSON.parse(readFileSync(resolve(entityContextPath), "utf8")) as {
|
|
601
|
+
codeAccess?: boolean;
|
|
602
|
+
};
|
|
603
|
+
entityCodeAccess = ec.codeAccess;
|
|
604
|
+
} catch (err) {
|
|
605
|
+
process.stderr.write(`Error reading ${entityContextPath}: ${err}\n`);
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const result = validateFindingsContract(findings, { entityCodeAccess });
|
|
611
|
+
|
|
612
|
+
if (result.valid) {
|
|
613
|
+
process.stderr.write(
|
|
614
|
+
`[findings-contract] PASS — ${result.totalFindings} finding(s) satisfy the contract.\n`
|
|
615
|
+
);
|
|
616
|
+
process.exit(0);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// RESEND directives on stdout (machine-readable — orchestrator re-dispatches).
|
|
620
|
+
for (const directive of result.resendDirectives) {
|
|
621
|
+
process.stdout.write(directive + "\n");
|
|
622
|
+
}
|
|
623
|
+
process.stderr.write(
|
|
624
|
+
`[findings-contract] FAIL — ${result.violations.length} violation(s) across ` +
|
|
625
|
+
`${result.resendDirectives.length} finding(s).\n`
|
|
626
|
+
);
|
|
627
|
+
process.exit(1);
|
|
628
|
+
}
|