@kontourai/flow-agents 3.12.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +76 -0
- package/CHANGELOG.md +41 -0
- package/build/generated/capability-declarations.json +177 -0
- package/build/src/builder-flow-runtime.d.ts +37 -0
- package/build/src/builder-flow-runtime.js +71 -1
- package/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/build/src/builder-gate-action-envelope.js +160 -28
- package/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/build/src/builder-lifecycle-authority.js +38 -0
- package/build/src/cli/builder-run.js +71 -2
- package/build/src/cli/narrative-render.d.ts +95 -0
- package/build/src/cli/narrative-render.js +466 -0
- package/build/src/cli/narrative-sources.d.ts +2 -0
- package/build/src/cli/narrative-sources.js +282 -0
- package/build/src/cli/public-contracts.d.ts +257 -0
- package/build/src/cli/public-contracts.js +87 -0
- package/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/build/src/cli/workflow-sidecar.js +599 -180
- package/build/src/cli/workflow.js +11 -1
- package/build/src/cli.js +8 -0
- package/build/src/continuation-driver.d.ts +12 -0
- package/build/src/continuation-driver.js +16 -2
- package/build/src/continuation-validation.js +324 -8
- package/build/src/flow-kit/action-metadata.js +21 -1
- package/build/src/index.d.ts +33 -2
- package/build/src/index.js +24 -0
- package/build/src/lib/capability-declarations.d.ts +83 -0
- package/build/src/lib/capability-declarations.js +209 -0
- package/build/src/narrative/envelope.d.ts +111 -0
- package/build/src/narrative/envelope.js +590 -0
- package/build/src/narrative/eval-result.d.ts +60 -0
- package/build/src/narrative/eval-result.js +158 -0
- package/build/src/narrative/grounding-validator.d.ts +104 -0
- package/build/src/narrative/grounding-validator.js +472 -0
- package/build/src/narrative/integrity.d.ts +17 -0
- package/build/src/narrative/integrity.js +39 -0
- package/build/src/narrative/intent-economics.d.ts +42 -0
- package/build/src/narrative/intent-economics.js +82 -0
- package/build/src/narrative/intent.d.ts +94 -0
- package/build/src/narrative/intent.js +132 -0
- package/build/src/narrative/policy-filter.d.ts +15 -0
- package/build/src/narrative/policy-filter.js +58 -0
- package/build/src/narrative/projection.d.ts +58 -0
- package/build/src/narrative/projection.js +502 -0
- package/build/src/narrative/readers.d.ts +84 -0
- package/build/src/narrative/readers.js +406 -0
- package/build/src/narrative/render.d.ts +3 -0
- package/build/src/narrative/render.js +83 -0
- package/build/src/narrative/resolver.d.ts +52 -0
- package/build/src/narrative/resolver.js +190 -0
- package/build/src/narrative/snapshot.d.ts +90 -0
- package/build/src/narrative/snapshot.js +325 -0
- package/build/src/narrative/source-ids.d.ts +121 -0
- package/build/src/narrative/source-ids.js +201 -0
- package/build/src/narrative/statements.d.ts +84 -0
- package/build/src/narrative/statements.js +347 -0
- package/build/src/narrative/turn-spine.d.ts +19 -0
- package/build/src/narrative/turn-spine.js +73 -0
- package/build/src/tools/build-universal-bundles.js +8 -0
- package/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/build/src/tools/generate-capability-matrix.js +207 -0
- package/build/src/tools/validate-source-tree.js +5 -1
- package/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/context/scripts/hooks/workflow-steering.js +160 -19
- package/context/scripts/telemetry/lib/session.sh +3 -0
- package/context/scripts/telemetry/lib/transport.sh +12 -3
- package/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/base/build/generated/capability-declarations.json +177 -0
- package/dist/base/build/package.json +1 -1
- package/dist/base/build/src/builder-flow-runtime.d.ts +37 -0
- package/dist/base/build/src/builder-flow-runtime.js +71 -1
- package/dist/base/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/dist/base/build/src/builder-gate-action-envelope.js +160 -28
- package/dist/base/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/dist/base/build/src/builder-lifecycle-authority.js +38 -0
- package/dist/base/build/src/cli/builder-run.js +71 -2
- package/dist/base/build/src/cli/narrative-render.d.ts +95 -0
- package/dist/base/build/src/cli/narrative-render.js +466 -0
- package/dist/base/build/src/cli/narrative-sources.d.ts +2 -0
- package/dist/base/build/src/cli/narrative-sources.js +282 -0
- package/dist/base/build/src/cli/public-contracts.d.ts +257 -0
- package/dist/base/build/src/cli/public-contracts.js +87 -0
- package/dist/base/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/dist/base/build/src/cli/workflow-sidecar.js +599 -180
- package/dist/base/build/src/cli/workflow.js +11 -1
- package/dist/base/build/src/cli.js +8 -0
- package/dist/base/build/src/continuation-driver.d.ts +12 -0
- package/dist/base/build/src/continuation-driver.js +16 -2
- package/dist/base/build/src/continuation-validation.js +324 -8
- package/dist/base/build/src/flow-kit/action-metadata.js +21 -1
- package/dist/base/build/src/index.d.ts +33 -2
- package/dist/base/build/src/index.js +24 -0
- package/dist/base/build/src/lib/capability-declarations.d.ts +83 -0
- package/dist/base/build/src/lib/capability-declarations.js +209 -0
- package/dist/base/build/src/narrative/envelope.d.ts +111 -0
- package/dist/base/build/src/narrative/envelope.js +590 -0
- package/dist/base/build/src/narrative/eval-result.d.ts +60 -0
- package/dist/base/build/src/narrative/eval-result.js +158 -0
- package/dist/base/build/src/narrative/grounding-validator.d.ts +104 -0
- package/dist/base/build/src/narrative/grounding-validator.js +472 -0
- package/dist/base/build/src/narrative/integrity.d.ts +17 -0
- package/dist/base/build/src/narrative/integrity.js +39 -0
- package/dist/base/build/src/narrative/intent-economics.d.ts +42 -0
- package/dist/base/build/src/narrative/intent-economics.js +82 -0
- package/dist/base/build/src/narrative/intent.d.ts +94 -0
- package/dist/base/build/src/narrative/intent.js +132 -0
- package/dist/base/build/src/narrative/policy-filter.d.ts +15 -0
- package/dist/base/build/src/narrative/policy-filter.js +58 -0
- package/dist/base/build/src/narrative/projection.d.ts +58 -0
- package/dist/base/build/src/narrative/projection.js +502 -0
- package/dist/base/build/src/narrative/readers.d.ts +84 -0
- package/dist/base/build/src/narrative/readers.js +406 -0
- package/dist/base/build/src/narrative/render.d.ts +3 -0
- package/dist/base/build/src/narrative/render.js +83 -0
- package/dist/base/build/src/narrative/resolver.d.ts +52 -0
- package/dist/base/build/src/narrative/resolver.js +190 -0
- package/dist/base/build/src/narrative/snapshot.d.ts +90 -0
- package/dist/base/build/src/narrative/snapshot.js +325 -0
- package/dist/base/build/src/narrative/source-ids.d.ts +121 -0
- package/dist/base/build/src/narrative/source-ids.js +201 -0
- package/dist/base/build/src/narrative/statements.d.ts +84 -0
- package/dist/base/build/src/narrative/statements.js +347 -0
- package/dist/base/build/src/narrative/turn-spine.d.ts +19 -0
- package/dist/base/build/src/narrative/turn-spine.js +73 -0
- package/dist/base/build/src/tools/build-universal-bundles.js +8 -0
- package/dist/base/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/dist/base/build/src/tools/generate-capability-matrix.js +207 -0
- package/dist/base/build/src/tools/validate-source-tree.js +5 -1
- package/dist/base/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/base/context/scripts/hooks/workflow-steering.js +160 -19
- package/dist/base/context/scripts/telemetry/lib/session.sh +3 -0
- package/dist/base/context/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/base/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/base/docs/context-map.md +4 -0
- package/dist/base/docs/decisions/index.md +1 -0
- package/dist/base/docs/decisions/writer-observed-execution.md +51 -0
- package/dist/base/docs/fixture-ownership.md +5 -1
- package/dist/base/docs/migrations.md +19 -4
- package/dist/base/docs/public-workflow-cli.md +9 -0
- package/dist/base/docs/spec/builder-flow-runtime.md +49 -8
- package/dist/base/docs/spec/runtime-hook-surface.md +29 -1
- package/dist/base/docs/specs/economics-record-contract.md +1 -1
- package/dist/base/docs/specs/harness-capability-matrix.md +63 -21
- package/dist/base/docs/workflow-usage-guide.md +4 -1
- package/dist/base/evals/ci/run-baseline.sh +38 -0
- package/dist/base/evals/fixtures/narrative-evals/README.md +62 -0
- package/dist/base/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/dist/base/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/dist/base/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/dist/base/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/dist/base/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/dist/base/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/dist/base/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/dist/base/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/dist/base/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/dist/base/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/dist/base/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/dist/base/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/dist/base/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/dist/base/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/dist/base/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/dist/base/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/dist/base/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/dist/base/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/dist/base/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/dist/base/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/dist/base/evals/integration/test_capability_declarations.sh +183 -0
- package/dist/base/evals/integration/test_economics_record.sh +42 -0
- package/dist/base/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/dist/base/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/dist/base/evals/integration/test_goal_fit_hook.sh +13 -5
- package/dist/base/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/dist/base/evals/integration/test_narrative_evals.sh +174 -0
- package/dist/base/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/dist/base/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/dist/base/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/dist/base/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/dist/base/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/dist/base/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/dist/base/evals/integration/test_narrative_source_contract.sh +228 -0
- package/dist/base/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/dist/base/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/dist/base/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/dist/base/evals/integration/test_telemetry_action_class.sh +265 -0
- package/dist/base/evals/integration/test_telemetry_delegation.sh +291 -0
- package/dist/base/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/dist/base/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/dist/base/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/dist/base/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/dist/base/evals/run.sh +12 -0
- package/dist/base/evals/static/test_library_exports.sh +5 -0
- package/dist/base/install.sh +1 -1
- package/dist/base/schemas/grounded-execution-narrative.schema.json +292 -0
- package/dist/base/schemas/narrative-eval-result.schema.json +205 -0
- package/dist/base/schemas/narrative-runtime-projection.schema.json +134 -0
- package/dist/base/schemas/narrative-source-manifest.schema.json +294 -0
- package/dist/base/scripts/check-hachure-boundary.mjs +81 -0
- package/dist/base/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/base/scripts/hooks/workflow-steering.js +160 -19
- package/dist/base/scripts/telemetry/economics-record.schema.json +1 -1
- package/dist/base/scripts/telemetry/economics-record.sh +47 -3
- package/dist/base/scripts/telemetry/lib/session.sh +3 -0
- package/dist/base/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/base/scripts/telemetry/telemetry.sh +480 -59
- package/dist/claude-code/build/generated/capability-declarations.json +177 -0
- package/dist/claude-code/build/package.json +1 -1
- package/dist/claude-code/build/src/builder-flow-runtime.d.ts +37 -0
- package/dist/claude-code/build/src/builder-flow-runtime.js +71 -1
- package/dist/claude-code/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/dist/claude-code/build/src/builder-gate-action-envelope.js +160 -28
- package/dist/claude-code/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/dist/claude-code/build/src/builder-lifecycle-authority.js +38 -0
- package/dist/claude-code/build/src/cli/builder-run.js +71 -2
- package/dist/claude-code/build/src/cli/narrative-render.d.ts +95 -0
- package/dist/claude-code/build/src/cli/narrative-render.js +466 -0
- package/dist/claude-code/build/src/cli/narrative-sources.d.ts +2 -0
- package/dist/claude-code/build/src/cli/narrative-sources.js +282 -0
- package/dist/claude-code/build/src/cli/public-contracts.d.ts +257 -0
- package/dist/claude-code/build/src/cli/public-contracts.js +87 -0
- package/dist/claude-code/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/dist/claude-code/build/src/cli/workflow-sidecar.js +599 -180
- package/dist/claude-code/build/src/cli/workflow.js +11 -1
- package/dist/claude-code/build/src/cli.js +8 -0
- package/dist/claude-code/build/src/continuation-driver.d.ts +12 -0
- package/dist/claude-code/build/src/continuation-driver.js +16 -2
- package/dist/claude-code/build/src/continuation-validation.js +324 -8
- package/dist/claude-code/build/src/flow-kit/action-metadata.js +21 -1
- package/dist/claude-code/build/src/index.d.ts +33 -2
- package/dist/claude-code/build/src/index.js +24 -0
- package/dist/claude-code/build/src/lib/capability-declarations.d.ts +83 -0
- package/dist/claude-code/build/src/lib/capability-declarations.js +209 -0
- package/dist/claude-code/build/src/narrative/envelope.d.ts +111 -0
- package/dist/claude-code/build/src/narrative/envelope.js +590 -0
- package/dist/claude-code/build/src/narrative/eval-result.d.ts +60 -0
- package/dist/claude-code/build/src/narrative/eval-result.js +158 -0
- package/dist/claude-code/build/src/narrative/grounding-validator.d.ts +104 -0
- package/dist/claude-code/build/src/narrative/grounding-validator.js +472 -0
- package/dist/claude-code/build/src/narrative/integrity.d.ts +17 -0
- package/dist/claude-code/build/src/narrative/integrity.js +39 -0
- package/dist/claude-code/build/src/narrative/intent-economics.d.ts +42 -0
- package/dist/claude-code/build/src/narrative/intent-economics.js +82 -0
- package/dist/claude-code/build/src/narrative/intent.d.ts +94 -0
- package/dist/claude-code/build/src/narrative/intent.js +132 -0
- package/dist/claude-code/build/src/narrative/policy-filter.d.ts +15 -0
- package/dist/claude-code/build/src/narrative/policy-filter.js +58 -0
- package/dist/claude-code/build/src/narrative/projection.d.ts +58 -0
- package/dist/claude-code/build/src/narrative/projection.js +502 -0
- package/dist/claude-code/build/src/narrative/readers.d.ts +84 -0
- package/dist/claude-code/build/src/narrative/readers.js +406 -0
- package/dist/claude-code/build/src/narrative/render.d.ts +3 -0
- package/dist/claude-code/build/src/narrative/render.js +83 -0
- package/dist/claude-code/build/src/narrative/resolver.d.ts +52 -0
- package/dist/claude-code/build/src/narrative/resolver.js +190 -0
- package/dist/claude-code/build/src/narrative/snapshot.d.ts +90 -0
- package/dist/claude-code/build/src/narrative/snapshot.js +325 -0
- package/dist/claude-code/build/src/narrative/source-ids.d.ts +121 -0
- package/dist/claude-code/build/src/narrative/source-ids.js +201 -0
- package/dist/claude-code/build/src/narrative/statements.d.ts +84 -0
- package/dist/claude-code/build/src/narrative/statements.js +347 -0
- package/dist/claude-code/build/src/narrative/turn-spine.d.ts +19 -0
- package/dist/claude-code/build/src/narrative/turn-spine.js +73 -0
- package/dist/claude-code/build/src/tools/build-universal-bundles.js +8 -0
- package/dist/claude-code/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/dist/claude-code/build/src/tools/generate-capability-matrix.js +207 -0
- package/dist/claude-code/build/src/tools/validate-source-tree.js +5 -1
- package/dist/claude-code/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/claude-code/context/scripts/hooks/workflow-steering.js +160 -19
- package/dist/claude-code/context/scripts/telemetry/lib/session.sh +3 -0
- package/dist/claude-code/context/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/claude-code/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/claude-code/docs/context-map.md +4 -0
- package/dist/claude-code/docs/decisions/index.md +1 -0
- package/dist/claude-code/docs/decisions/writer-observed-execution.md +51 -0
- package/dist/claude-code/docs/fixture-ownership.md +5 -1
- package/dist/claude-code/docs/migrations.md +19 -4
- package/dist/claude-code/docs/public-workflow-cli.md +9 -0
- package/dist/claude-code/docs/spec/builder-flow-runtime.md +49 -8
- package/dist/claude-code/docs/spec/runtime-hook-surface.md +29 -1
- package/dist/claude-code/docs/specs/economics-record-contract.md +1 -1
- package/dist/claude-code/docs/specs/harness-capability-matrix.md +63 -21
- package/dist/claude-code/docs/workflow-usage-guide.md +4 -1
- package/dist/claude-code/evals/ci/run-baseline.sh +38 -0
- package/dist/claude-code/evals/fixtures/narrative-evals/README.md +62 -0
- package/dist/claude-code/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/dist/claude-code/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/dist/claude-code/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/dist/claude-code/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/dist/claude-code/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/dist/claude-code/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/dist/claude-code/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/dist/claude-code/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/dist/claude-code/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/dist/claude-code/evals/integration/test_capability_declarations.sh +183 -0
- package/dist/claude-code/evals/integration/test_economics_record.sh +42 -0
- package/dist/claude-code/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/dist/claude-code/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/dist/claude-code/evals/integration/test_goal_fit_hook.sh +13 -5
- package/dist/claude-code/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/dist/claude-code/evals/integration/test_narrative_evals.sh +174 -0
- package/dist/claude-code/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/dist/claude-code/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/dist/claude-code/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/dist/claude-code/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/dist/claude-code/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/dist/claude-code/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/dist/claude-code/evals/integration/test_narrative_source_contract.sh +228 -0
- package/dist/claude-code/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/dist/claude-code/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/dist/claude-code/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/dist/claude-code/evals/integration/test_telemetry_action_class.sh +265 -0
- package/dist/claude-code/evals/integration/test_telemetry_delegation.sh +291 -0
- package/dist/claude-code/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/dist/claude-code/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/dist/claude-code/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/dist/claude-code/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/dist/claude-code/evals/run.sh +12 -0
- package/dist/claude-code/evals/static/test_library_exports.sh +5 -0
- package/dist/claude-code/install.sh +1 -1
- package/dist/claude-code/schemas/grounded-execution-narrative.schema.json +292 -0
- package/dist/claude-code/schemas/narrative-eval-result.schema.json +205 -0
- package/dist/claude-code/schemas/narrative-runtime-projection.schema.json +134 -0
- package/dist/claude-code/schemas/narrative-source-manifest.schema.json +294 -0
- package/dist/claude-code/scripts/check-hachure-boundary.mjs +81 -0
- package/dist/claude-code/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/claude-code/scripts/hooks/workflow-steering.js +160 -19
- package/dist/claude-code/scripts/telemetry/economics-record.schema.json +1 -1
- package/dist/claude-code/scripts/telemetry/economics-record.sh +47 -3
- package/dist/claude-code/scripts/telemetry/lib/session.sh +3 -0
- package/dist/claude-code/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/claude-code/scripts/telemetry/telemetry.sh +480 -59
- package/dist/codex/build/generated/capability-declarations.json +177 -0
- package/dist/codex/build/package.json +1 -1
- package/dist/codex/build/src/builder-flow-runtime.d.ts +37 -0
- package/dist/codex/build/src/builder-flow-runtime.js +71 -1
- package/dist/codex/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/dist/codex/build/src/builder-gate-action-envelope.js +160 -28
- package/dist/codex/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/dist/codex/build/src/builder-lifecycle-authority.js +38 -0
- package/dist/codex/build/src/cli/builder-run.js +71 -2
- package/dist/codex/build/src/cli/narrative-render.d.ts +95 -0
- package/dist/codex/build/src/cli/narrative-render.js +466 -0
- package/dist/codex/build/src/cli/narrative-sources.d.ts +2 -0
- package/dist/codex/build/src/cli/narrative-sources.js +282 -0
- package/dist/codex/build/src/cli/public-contracts.d.ts +257 -0
- package/dist/codex/build/src/cli/public-contracts.js +87 -0
- package/dist/codex/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/dist/codex/build/src/cli/workflow-sidecar.js +599 -180
- package/dist/codex/build/src/cli/workflow.js +11 -1
- package/dist/codex/build/src/cli.js +8 -0
- package/dist/codex/build/src/continuation-driver.d.ts +12 -0
- package/dist/codex/build/src/continuation-driver.js +16 -2
- package/dist/codex/build/src/continuation-validation.js +324 -8
- package/dist/codex/build/src/flow-kit/action-metadata.js +21 -1
- package/dist/codex/build/src/index.d.ts +33 -2
- package/dist/codex/build/src/index.js +24 -0
- package/dist/codex/build/src/lib/capability-declarations.d.ts +83 -0
- package/dist/codex/build/src/lib/capability-declarations.js +209 -0
- package/dist/codex/build/src/narrative/envelope.d.ts +111 -0
- package/dist/codex/build/src/narrative/envelope.js +590 -0
- package/dist/codex/build/src/narrative/eval-result.d.ts +60 -0
- package/dist/codex/build/src/narrative/eval-result.js +158 -0
- package/dist/codex/build/src/narrative/grounding-validator.d.ts +104 -0
- package/dist/codex/build/src/narrative/grounding-validator.js +472 -0
- package/dist/codex/build/src/narrative/integrity.d.ts +17 -0
- package/dist/codex/build/src/narrative/integrity.js +39 -0
- package/dist/codex/build/src/narrative/intent-economics.d.ts +42 -0
- package/dist/codex/build/src/narrative/intent-economics.js +82 -0
- package/dist/codex/build/src/narrative/intent.d.ts +94 -0
- package/dist/codex/build/src/narrative/intent.js +132 -0
- package/dist/codex/build/src/narrative/policy-filter.d.ts +15 -0
- package/dist/codex/build/src/narrative/policy-filter.js +58 -0
- package/dist/codex/build/src/narrative/projection.d.ts +58 -0
- package/dist/codex/build/src/narrative/projection.js +502 -0
- package/dist/codex/build/src/narrative/readers.d.ts +84 -0
- package/dist/codex/build/src/narrative/readers.js +406 -0
- package/dist/codex/build/src/narrative/render.d.ts +3 -0
- package/dist/codex/build/src/narrative/render.js +83 -0
- package/dist/codex/build/src/narrative/resolver.d.ts +52 -0
- package/dist/codex/build/src/narrative/resolver.js +190 -0
- package/dist/codex/build/src/narrative/snapshot.d.ts +90 -0
- package/dist/codex/build/src/narrative/snapshot.js +325 -0
- package/dist/codex/build/src/narrative/source-ids.d.ts +121 -0
- package/dist/codex/build/src/narrative/source-ids.js +201 -0
- package/dist/codex/build/src/narrative/statements.d.ts +84 -0
- package/dist/codex/build/src/narrative/statements.js +347 -0
- package/dist/codex/build/src/narrative/turn-spine.d.ts +19 -0
- package/dist/codex/build/src/narrative/turn-spine.js +73 -0
- package/dist/codex/build/src/tools/build-universal-bundles.js +8 -0
- package/dist/codex/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/dist/codex/build/src/tools/generate-capability-matrix.js +207 -0
- package/dist/codex/build/src/tools/validate-source-tree.js +5 -1
- package/dist/codex/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/codex/context/scripts/hooks/workflow-steering.js +160 -19
- package/dist/codex/context/scripts/telemetry/lib/session.sh +3 -0
- package/dist/codex/context/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/codex/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/codex/docs/context-map.md +4 -0
- package/dist/codex/docs/decisions/index.md +1 -0
- package/dist/codex/docs/decisions/writer-observed-execution.md +51 -0
- package/dist/codex/docs/fixture-ownership.md +5 -1
- package/dist/codex/docs/migrations.md +19 -4
- package/dist/codex/docs/public-workflow-cli.md +9 -0
- package/dist/codex/docs/spec/builder-flow-runtime.md +49 -8
- package/dist/codex/docs/spec/runtime-hook-surface.md +29 -1
- package/dist/codex/docs/specs/economics-record-contract.md +1 -1
- package/dist/codex/docs/specs/harness-capability-matrix.md +63 -21
- package/dist/codex/docs/workflow-usage-guide.md +4 -1
- package/dist/codex/evals/ci/run-baseline.sh +38 -0
- package/dist/codex/evals/fixtures/narrative-evals/README.md +62 -0
- package/dist/codex/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/dist/codex/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/dist/codex/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/dist/codex/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/dist/codex/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/dist/codex/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/dist/codex/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/dist/codex/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/dist/codex/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/dist/codex/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/dist/codex/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/dist/codex/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/dist/codex/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/dist/codex/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/dist/codex/evals/integration/test_capability_declarations.sh +183 -0
- package/dist/codex/evals/integration/test_economics_record.sh +42 -0
- package/dist/codex/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/dist/codex/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/dist/codex/evals/integration/test_goal_fit_hook.sh +13 -5
- package/dist/codex/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/dist/codex/evals/integration/test_narrative_evals.sh +174 -0
- package/dist/codex/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/dist/codex/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/dist/codex/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/dist/codex/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/dist/codex/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/dist/codex/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/dist/codex/evals/integration/test_narrative_source_contract.sh +228 -0
- package/dist/codex/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/dist/codex/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/dist/codex/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/dist/codex/evals/integration/test_telemetry_action_class.sh +265 -0
- package/dist/codex/evals/integration/test_telemetry_delegation.sh +291 -0
- package/dist/codex/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/dist/codex/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/dist/codex/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/dist/codex/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/dist/codex/evals/run.sh +12 -0
- package/dist/codex/evals/static/test_library_exports.sh +5 -0
- package/dist/codex/install.sh +1 -1
- package/dist/codex/schemas/grounded-execution-narrative.schema.json +292 -0
- package/dist/codex/schemas/narrative-eval-result.schema.json +205 -0
- package/dist/codex/schemas/narrative-runtime-projection.schema.json +134 -0
- package/dist/codex/schemas/narrative-source-manifest.schema.json +294 -0
- package/dist/codex/scripts/check-hachure-boundary.mjs +81 -0
- package/dist/codex/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/codex/scripts/hooks/workflow-steering.js +160 -19
- package/dist/codex/scripts/telemetry/economics-record.schema.json +1 -1
- package/dist/codex/scripts/telemetry/economics-record.sh +47 -3
- package/dist/codex/scripts/telemetry/lib/session.sh +3 -0
- package/dist/codex/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/codex/scripts/telemetry/telemetry.sh +480 -59
- package/dist/kiro/build/generated/capability-declarations.json +177 -0
- package/dist/kiro/build/package.json +1 -1
- package/dist/kiro/build/src/builder-flow-runtime.d.ts +37 -0
- package/dist/kiro/build/src/builder-flow-runtime.js +71 -1
- package/dist/kiro/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/dist/kiro/build/src/builder-gate-action-envelope.js +160 -28
- package/dist/kiro/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/dist/kiro/build/src/builder-lifecycle-authority.js +38 -0
- package/dist/kiro/build/src/cli/builder-run.js +71 -2
- package/dist/kiro/build/src/cli/narrative-render.d.ts +95 -0
- package/dist/kiro/build/src/cli/narrative-render.js +466 -0
- package/dist/kiro/build/src/cli/narrative-sources.d.ts +2 -0
- package/dist/kiro/build/src/cli/narrative-sources.js +282 -0
- package/dist/kiro/build/src/cli/public-contracts.d.ts +257 -0
- package/dist/kiro/build/src/cli/public-contracts.js +87 -0
- package/dist/kiro/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/dist/kiro/build/src/cli/workflow-sidecar.js +599 -180
- package/dist/kiro/build/src/cli/workflow.js +11 -1
- package/dist/kiro/build/src/cli.js +8 -0
- package/dist/kiro/build/src/continuation-driver.d.ts +12 -0
- package/dist/kiro/build/src/continuation-driver.js +16 -2
- package/dist/kiro/build/src/continuation-validation.js +324 -8
- package/dist/kiro/build/src/flow-kit/action-metadata.js +21 -1
- package/dist/kiro/build/src/index.d.ts +33 -2
- package/dist/kiro/build/src/index.js +24 -0
- package/dist/kiro/build/src/lib/capability-declarations.d.ts +83 -0
- package/dist/kiro/build/src/lib/capability-declarations.js +209 -0
- package/dist/kiro/build/src/narrative/envelope.d.ts +111 -0
- package/dist/kiro/build/src/narrative/envelope.js +590 -0
- package/dist/kiro/build/src/narrative/eval-result.d.ts +60 -0
- package/dist/kiro/build/src/narrative/eval-result.js +158 -0
- package/dist/kiro/build/src/narrative/grounding-validator.d.ts +104 -0
- package/dist/kiro/build/src/narrative/grounding-validator.js +472 -0
- package/dist/kiro/build/src/narrative/integrity.d.ts +17 -0
- package/dist/kiro/build/src/narrative/integrity.js +39 -0
- package/dist/kiro/build/src/narrative/intent-economics.d.ts +42 -0
- package/dist/kiro/build/src/narrative/intent-economics.js +82 -0
- package/dist/kiro/build/src/narrative/intent.d.ts +94 -0
- package/dist/kiro/build/src/narrative/intent.js +132 -0
- package/dist/kiro/build/src/narrative/policy-filter.d.ts +15 -0
- package/dist/kiro/build/src/narrative/policy-filter.js +58 -0
- package/dist/kiro/build/src/narrative/projection.d.ts +58 -0
- package/dist/kiro/build/src/narrative/projection.js +502 -0
- package/dist/kiro/build/src/narrative/readers.d.ts +84 -0
- package/dist/kiro/build/src/narrative/readers.js +406 -0
- package/dist/kiro/build/src/narrative/render.d.ts +3 -0
- package/dist/kiro/build/src/narrative/render.js +83 -0
- package/dist/kiro/build/src/narrative/resolver.d.ts +52 -0
- package/dist/kiro/build/src/narrative/resolver.js +190 -0
- package/dist/kiro/build/src/narrative/snapshot.d.ts +90 -0
- package/dist/kiro/build/src/narrative/snapshot.js +325 -0
- package/dist/kiro/build/src/narrative/source-ids.d.ts +121 -0
- package/dist/kiro/build/src/narrative/source-ids.js +201 -0
- package/dist/kiro/build/src/narrative/statements.d.ts +84 -0
- package/dist/kiro/build/src/narrative/statements.js +347 -0
- package/dist/kiro/build/src/narrative/turn-spine.d.ts +19 -0
- package/dist/kiro/build/src/narrative/turn-spine.js +73 -0
- package/dist/kiro/build/src/tools/build-universal-bundles.js +8 -0
- package/dist/kiro/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/dist/kiro/build/src/tools/generate-capability-matrix.js +207 -0
- package/dist/kiro/build/src/tools/validate-source-tree.js +5 -1
- package/dist/kiro/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/kiro/context/scripts/hooks/workflow-steering.js +160 -19
- package/dist/kiro/context/scripts/telemetry/lib/session.sh +3 -0
- package/dist/kiro/context/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/kiro/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/kiro/docs/context-map.md +4 -0
- package/dist/kiro/docs/decisions/index.md +1 -0
- package/dist/kiro/docs/decisions/writer-observed-execution.md +51 -0
- package/dist/kiro/docs/fixture-ownership.md +5 -1
- package/dist/kiro/docs/migrations.md +19 -4
- package/dist/kiro/docs/public-workflow-cli.md +9 -0
- package/dist/kiro/docs/spec/builder-flow-runtime.md +49 -8
- package/dist/kiro/docs/spec/runtime-hook-surface.md +29 -1
- package/dist/kiro/docs/specs/economics-record-contract.md +1 -1
- package/dist/kiro/docs/specs/harness-capability-matrix.md +63 -21
- package/dist/kiro/docs/workflow-usage-guide.md +4 -1
- package/dist/kiro/evals/ci/run-baseline.sh +38 -0
- package/dist/kiro/evals/fixtures/narrative-evals/README.md +62 -0
- package/dist/kiro/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/dist/kiro/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/dist/kiro/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/dist/kiro/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/dist/kiro/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/dist/kiro/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/dist/kiro/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/dist/kiro/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/dist/kiro/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/dist/kiro/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/dist/kiro/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/dist/kiro/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/dist/kiro/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/dist/kiro/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/dist/kiro/evals/integration/test_capability_declarations.sh +183 -0
- package/dist/kiro/evals/integration/test_economics_record.sh +42 -0
- package/dist/kiro/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/dist/kiro/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/dist/kiro/evals/integration/test_goal_fit_hook.sh +13 -5
- package/dist/kiro/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/dist/kiro/evals/integration/test_narrative_evals.sh +174 -0
- package/dist/kiro/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/dist/kiro/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/dist/kiro/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/dist/kiro/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/dist/kiro/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/dist/kiro/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/dist/kiro/evals/integration/test_narrative_source_contract.sh +228 -0
- package/dist/kiro/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/dist/kiro/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/dist/kiro/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/dist/kiro/evals/integration/test_telemetry_action_class.sh +265 -0
- package/dist/kiro/evals/integration/test_telemetry_delegation.sh +291 -0
- package/dist/kiro/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/dist/kiro/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/dist/kiro/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/dist/kiro/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/dist/kiro/evals/run.sh +12 -0
- package/dist/kiro/evals/static/test_library_exports.sh +5 -0
- package/dist/kiro/install.sh +1 -1
- package/dist/kiro/schemas/grounded-execution-narrative.schema.json +292 -0
- package/dist/kiro/schemas/narrative-eval-result.schema.json +205 -0
- package/dist/kiro/schemas/narrative-runtime-projection.schema.json +134 -0
- package/dist/kiro/schemas/narrative-source-manifest.schema.json +294 -0
- package/dist/kiro/scripts/check-hachure-boundary.mjs +81 -0
- package/dist/kiro/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/kiro/scripts/hooks/workflow-steering.js +160 -19
- package/dist/kiro/scripts/telemetry/economics-record.schema.json +1 -1
- package/dist/kiro/scripts/telemetry/economics-record.sh +47 -3
- package/dist/kiro/scripts/telemetry/lib/session.sh +3 -0
- package/dist/kiro/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/kiro/scripts/telemetry/telemetry.sh +480 -59
- package/dist/opencode/build/generated/capability-declarations.json +177 -0
- package/dist/opencode/build/package.json +1 -1
- package/dist/opencode/build/src/builder-flow-runtime.d.ts +37 -0
- package/dist/opencode/build/src/builder-flow-runtime.js +71 -1
- package/dist/opencode/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/dist/opencode/build/src/builder-gate-action-envelope.js +160 -28
- package/dist/opencode/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/dist/opencode/build/src/builder-lifecycle-authority.js +38 -0
- package/dist/opencode/build/src/cli/builder-run.js +71 -2
- package/dist/opencode/build/src/cli/narrative-render.d.ts +95 -0
- package/dist/opencode/build/src/cli/narrative-render.js +466 -0
- package/dist/opencode/build/src/cli/narrative-sources.d.ts +2 -0
- package/dist/opencode/build/src/cli/narrative-sources.js +282 -0
- package/dist/opencode/build/src/cli/public-contracts.d.ts +257 -0
- package/dist/opencode/build/src/cli/public-contracts.js +87 -0
- package/dist/opencode/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/dist/opencode/build/src/cli/workflow-sidecar.js +599 -180
- package/dist/opencode/build/src/cli/workflow.js +11 -1
- package/dist/opencode/build/src/cli.js +8 -0
- package/dist/opencode/build/src/continuation-driver.d.ts +12 -0
- package/dist/opencode/build/src/continuation-driver.js +16 -2
- package/dist/opencode/build/src/continuation-validation.js +324 -8
- package/dist/opencode/build/src/flow-kit/action-metadata.js +21 -1
- package/dist/opencode/build/src/index.d.ts +33 -2
- package/dist/opencode/build/src/index.js +24 -0
- package/dist/opencode/build/src/lib/capability-declarations.d.ts +83 -0
- package/dist/opencode/build/src/lib/capability-declarations.js +209 -0
- package/dist/opencode/build/src/narrative/envelope.d.ts +111 -0
- package/dist/opencode/build/src/narrative/envelope.js +590 -0
- package/dist/opencode/build/src/narrative/eval-result.d.ts +60 -0
- package/dist/opencode/build/src/narrative/eval-result.js +158 -0
- package/dist/opencode/build/src/narrative/grounding-validator.d.ts +104 -0
- package/dist/opencode/build/src/narrative/grounding-validator.js +472 -0
- package/dist/opencode/build/src/narrative/integrity.d.ts +17 -0
- package/dist/opencode/build/src/narrative/integrity.js +39 -0
- package/dist/opencode/build/src/narrative/intent-economics.d.ts +42 -0
- package/dist/opencode/build/src/narrative/intent-economics.js +82 -0
- package/dist/opencode/build/src/narrative/intent.d.ts +94 -0
- package/dist/opencode/build/src/narrative/intent.js +132 -0
- package/dist/opencode/build/src/narrative/policy-filter.d.ts +15 -0
- package/dist/opencode/build/src/narrative/policy-filter.js +58 -0
- package/dist/opencode/build/src/narrative/projection.d.ts +58 -0
- package/dist/opencode/build/src/narrative/projection.js +502 -0
- package/dist/opencode/build/src/narrative/readers.d.ts +84 -0
- package/dist/opencode/build/src/narrative/readers.js +406 -0
- package/dist/opencode/build/src/narrative/render.d.ts +3 -0
- package/dist/opencode/build/src/narrative/render.js +83 -0
- package/dist/opencode/build/src/narrative/resolver.d.ts +52 -0
- package/dist/opencode/build/src/narrative/resolver.js +190 -0
- package/dist/opencode/build/src/narrative/snapshot.d.ts +90 -0
- package/dist/opencode/build/src/narrative/snapshot.js +325 -0
- package/dist/opencode/build/src/narrative/source-ids.d.ts +121 -0
- package/dist/opencode/build/src/narrative/source-ids.js +201 -0
- package/dist/opencode/build/src/narrative/statements.d.ts +84 -0
- package/dist/opencode/build/src/narrative/statements.js +347 -0
- package/dist/opencode/build/src/narrative/turn-spine.d.ts +19 -0
- package/dist/opencode/build/src/narrative/turn-spine.js +73 -0
- package/dist/opencode/build/src/tools/build-universal-bundles.js +8 -0
- package/dist/opencode/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/dist/opencode/build/src/tools/generate-capability-matrix.js +207 -0
- package/dist/opencode/build/src/tools/validate-source-tree.js +5 -1
- package/dist/opencode/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/opencode/context/scripts/hooks/workflow-steering.js +160 -19
- package/dist/opencode/context/scripts/telemetry/lib/session.sh +3 -0
- package/dist/opencode/context/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/opencode/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/opencode/docs/context-map.md +4 -0
- package/dist/opencode/docs/decisions/index.md +1 -0
- package/dist/opencode/docs/decisions/writer-observed-execution.md +51 -0
- package/dist/opencode/docs/fixture-ownership.md +5 -1
- package/dist/opencode/docs/migrations.md +19 -4
- package/dist/opencode/docs/public-workflow-cli.md +9 -0
- package/dist/opencode/docs/spec/builder-flow-runtime.md +49 -8
- package/dist/opencode/docs/spec/runtime-hook-surface.md +29 -1
- package/dist/opencode/docs/specs/economics-record-contract.md +1 -1
- package/dist/opencode/docs/specs/harness-capability-matrix.md +63 -21
- package/dist/opencode/docs/workflow-usage-guide.md +4 -1
- package/dist/opencode/evals/ci/run-baseline.sh +38 -0
- package/dist/opencode/evals/fixtures/narrative-evals/README.md +62 -0
- package/dist/opencode/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/dist/opencode/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/dist/opencode/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/dist/opencode/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/dist/opencode/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/dist/opencode/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/dist/opencode/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/dist/opencode/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/dist/opencode/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/dist/opencode/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/dist/opencode/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/dist/opencode/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/dist/opencode/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/dist/opencode/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/dist/opencode/evals/integration/test_capability_declarations.sh +183 -0
- package/dist/opencode/evals/integration/test_economics_record.sh +42 -0
- package/dist/opencode/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/dist/opencode/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/dist/opencode/evals/integration/test_goal_fit_hook.sh +13 -5
- package/dist/opencode/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/dist/opencode/evals/integration/test_narrative_evals.sh +174 -0
- package/dist/opencode/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/dist/opencode/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/dist/opencode/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/dist/opencode/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/dist/opencode/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/dist/opencode/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/dist/opencode/evals/integration/test_narrative_source_contract.sh +228 -0
- package/dist/opencode/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/dist/opencode/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/dist/opencode/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/dist/opencode/evals/integration/test_telemetry_action_class.sh +265 -0
- package/dist/opencode/evals/integration/test_telemetry_delegation.sh +291 -0
- package/dist/opencode/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/dist/opencode/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/dist/opencode/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/dist/opencode/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/dist/opencode/evals/run.sh +12 -0
- package/dist/opencode/evals/static/test_library_exports.sh +5 -0
- package/dist/opencode/install.sh +1 -1
- package/dist/opencode/schemas/grounded-execution-narrative.schema.json +292 -0
- package/dist/opencode/schemas/narrative-eval-result.schema.json +205 -0
- package/dist/opencode/schemas/narrative-runtime-projection.schema.json +134 -0
- package/dist/opencode/schemas/narrative-source-manifest.schema.json +294 -0
- package/dist/opencode/scripts/check-hachure-boundary.mjs +81 -0
- package/dist/opencode/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/opencode/scripts/hooks/workflow-steering.js +160 -19
- package/dist/opencode/scripts/telemetry/economics-record.schema.json +1 -1
- package/dist/opencode/scripts/telemetry/economics-record.sh +47 -3
- package/dist/opencode/scripts/telemetry/lib/session.sh +3 -0
- package/dist/opencode/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/opencode/scripts/telemetry/telemetry.sh +480 -59
- package/dist/pi/build/generated/capability-declarations.json +177 -0
- package/dist/pi/build/package.json +1 -1
- package/dist/pi/build/src/builder-flow-runtime.d.ts +37 -0
- package/dist/pi/build/src/builder-flow-runtime.js +71 -1
- package/dist/pi/build/src/builder-gate-action-envelope.d.ts +58 -7
- package/dist/pi/build/src/builder-gate-action-envelope.js +160 -28
- package/dist/pi/build/src/builder-lifecycle-authority.d.ts +26 -0
- package/dist/pi/build/src/builder-lifecycle-authority.js +38 -0
- package/dist/pi/build/src/cli/builder-run.js +71 -2
- package/dist/pi/build/src/cli/narrative-render.d.ts +95 -0
- package/dist/pi/build/src/cli/narrative-render.js +466 -0
- package/dist/pi/build/src/cli/narrative-sources.d.ts +2 -0
- package/dist/pi/build/src/cli/narrative-sources.js +282 -0
- package/dist/pi/build/src/cli/public-contracts.d.ts +257 -0
- package/dist/pi/build/src/cli/public-contracts.js +87 -0
- package/dist/pi/build/src/cli/workflow-sidecar.d.ts +28 -12
- package/dist/pi/build/src/cli/workflow-sidecar.js +599 -180
- package/dist/pi/build/src/cli/workflow.js +11 -1
- package/dist/pi/build/src/cli.js +8 -0
- package/dist/pi/build/src/continuation-driver.d.ts +12 -0
- package/dist/pi/build/src/continuation-driver.js +16 -2
- package/dist/pi/build/src/continuation-validation.js +324 -8
- package/dist/pi/build/src/flow-kit/action-metadata.js +21 -1
- package/dist/pi/build/src/index.d.ts +33 -2
- package/dist/pi/build/src/index.js +24 -0
- package/dist/pi/build/src/lib/capability-declarations.d.ts +83 -0
- package/dist/pi/build/src/lib/capability-declarations.js +209 -0
- package/dist/pi/build/src/narrative/envelope.d.ts +111 -0
- package/dist/pi/build/src/narrative/envelope.js +590 -0
- package/dist/pi/build/src/narrative/eval-result.d.ts +60 -0
- package/dist/pi/build/src/narrative/eval-result.js +158 -0
- package/dist/pi/build/src/narrative/grounding-validator.d.ts +104 -0
- package/dist/pi/build/src/narrative/grounding-validator.js +472 -0
- package/dist/pi/build/src/narrative/integrity.d.ts +17 -0
- package/dist/pi/build/src/narrative/integrity.js +39 -0
- package/dist/pi/build/src/narrative/intent-economics.d.ts +42 -0
- package/dist/pi/build/src/narrative/intent-economics.js +82 -0
- package/dist/pi/build/src/narrative/intent.d.ts +94 -0
- package/dist/pi/build/src/narrative/intent.js +132 -0
- package/dist/pi/build/src/narrative/policy-filter.d.ts +15 -0
- package/dist/pi/build/src/narrative/policy-filter.js +58 -0
- package/dist/pi/build/src/narrative/projection.d.ts +58 -0
- package/dist/pi/build/src/narrative/projection.js +502 -0
- package/dist/pi/build/src/narrative/readers.d.ts +84 -0
- package/dist/pi/build/src/narrative/readers.js +406 -0
- package/dist/pi/build/src/narrative/render.d.ts +3 -0
- package/dist/pi/build/src/narrative/render.js +83 -0
- package/dist/pi/build/src/narrative/resolver.d.ts +52 -0
- package/dist/pi/build/src/narrative/resolver.js +190 -0
- package/dist/pi/build/src/narrative/snapshot.d.ts +90 -0
- package/dist/pi/build/src/narrative/snapshot.js +325 -0
- package/dist/pi/build/src/narrative/source-ids.d.ts +121 -0
- package/dist/pi/build/src/narrative/source-ids.js +201 -0
- package/dist/pi/build/src/narrative/statements.d.ts +84 -0
- package/dist/pi/build/src/narrative/statements.js +347 -0
- package/dist/pi/build/src/narrative/turn-spine.d.ts +19 -0
- package/dist/pi/build/src/narrative/turn-spine.js +73 -0
- package/dist/pi/build/src/tools/build-universal-bundles.js +8 -0
- package/dist/pi/build/src/tools/generate-capability-matrix.d.ts +7 -0
- package/dist/pi/build/src/tools/generate-capability-matrix.js +207 -0
- package/dist/pi/build/src/tools/validate-source-tree.js +5 -1
- package/dist/pi/context/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/pi/context/scripts/hooks/workflow-steering.js +160 -19
- package/dist/pi/context/scripts/telemetry/lib/session.sh +3 -0
- package/dist/pi/context/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/pi/context/scripts/telemetry/telemetry.sh +480 -59
- package/dist/pi/docs/context-map.md +4 -0
- package/dist/pi/docs/decisions/index.md +1 -0
- package/dist/pi/docs/decisions/writer-observed-execution.md +51 -0
- package/dist/pi/docs/fixture-ownership.md +5 -1
- package/dist/pi/docs/migrations.md +19 -4
- package/dist/pi/docs/public-workflow-cli.md +9 -0
- package/dist/pi/docs/spec/builder-flow-runtime.md +49 -8
- package/dist/pi/docs/spec/runtime-hook-surface.md +29 -1
- package/dist/pi/docs/specs/economics-record-contract.md +1 -1
- package/dist/pi/docs/specs/harness-capability-matrix.md +63 -21
- package/dist/pi/docs/workflow-usage-guide.md +4 -1
- package/dist/pi/evals/ci/run-baseline.sh +38 -0
- package/dist/pi/evals/fixtures/narrative-evals/README.md +62 -0
- package/dist/pi/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/dist/pi/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/dist/pi/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/dist/pi/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/dist/pi/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/dist/pi/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/dist/pi/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/dist/pi/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/dist/pi/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/dist/pi/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/dist/pi/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/dist/pi/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/dist/pi/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/dist/pi/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/dist/pi/evals/integration/test_capability_declarations.sh +183 -0
- package/dist/pi/evals/integration/test_economics_record.sh +42 -0
- package/dist/pi/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/dist/pi/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/dist/pi/evals/integration/test_goal_fit_hook.sh +13 -5
- package/dist/pi/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/dist/pi/evals/integration/test_narrative_evals.sh +174 -0
- package/dist/pi/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/dist/pi/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/dist/pi/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/dist/pi/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/dist/pi/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/dist/pi/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/dist/pi/evals/integration/test_narrative_source_contract.sh +228 -0
- package/dist/pi/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/dist/pi/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/dist/pi/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/dist/pi/evals/integration/test_telemetry_action_class.sh +265 -0
- package/dist/pi/evals/integration/test_telemetry_delegation.sh +291 -0
- package/dist/pi/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/dist/pi/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/dist/pi/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/dist/pi/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/dist/pi/evals/run.sh +12 -0
- package/dist/pi/evals/static/test_library_exports.sh +5 -0
- package/dist/pi/install.sh +1 -1
- package/dist/pi/schemas/grounded-execution-narrative.schema.json +292 -0
- package/dist/pi/schemas/narrative-eval-result.schema.json +205 -0
- package/dist/pi/schemas/narrative-runtime-projection.schema.json +134 -0
- package/dist/pi/schemas/narrative-source-manifest.schema.json +294 -0
- package/dist/pi/scripts/check-hachure-boundary.mjs +81 -0
- package/dist/pi/scripts/hooks/stop-goal-fit.js +182 -9
- package/dist/pi/scripts/hooks/workflow-steering.js +160 -19
- package/dist/pi/scripts/telemetry/economics-record.schema.json +1 -1
- package/dist/pi/scripts/telemetry/economics-record.sh +47 -3
- package/dist/pi/scripts/telemetry/lib/session.sh +3 -0
- package/dist/pi/scripts/telemetry/lib/transport.sh +12 -3
- package/dist/pi/scripts/telemetry/telemetry.sh +480 -59
- package/docs/context-map.md +4 -0
- package/docs/decisions/index.md +1 -0
- package/docs/decisions/writer-observed-execution.md +51 -0
- package/docs/fixture-ownership.md +5 -1
- package/docs/migrations.md +19 -4
- package/docs/public-workflow-cli.md +9 -0
- package/docs/spec/builder-flow-runtime.md +49 -8
- package/docs/spec/runtime-hook-surface.md +29 -1
- package/docs/specs/economics-record-contract.md +1 -1
- package/docs/specs/harness-capability-matrix.md +63 -21
- package/docs/workflow-usage-guide.md +4 -1
- package/evals/ci/run-baseline.sh +38 -0
- package/evals/fixtures/narrative-evals/README.md +62 -0
- package/evals/fixtures/narrative-evals/corpus.json +129 -0
- package/evals/fixtures/narrative-evals/scorer.mjs +522 -0
- package/evals/fixtures/narrative-grounding-validator/corpus.json +20 -0
- package/evals/fixtures/narrative-grounding-validator/prompt-injection-adversarial.txt +1 -0
- package/evals/fixtures/narrative-grounding-validator/prompt-injection-control.txt +1 -0
- package/evals/fixtures/narrative-grounding-validator/scorer.mjs +201 -0
- package/evals/fixtures/narrative-prose-renderer/corpus.json +15 -0
- package/evals/fixtures/narrative-prose-renderer/scorer.mjs +201 -0
- package/evals/fixtures/narrative-sources/expected-capture-completeness.json +13 -0
- package/evals/fixtures/narrative-sources/flow/runs/run-fixture/report.json +1 -0
- package/evals/fixtures/narrative-sources/flow/runs/run-fixture/state.json +1 -0
- package/evals/fixtures/narrative-sources/flow/runs/run-runtime/state.json +1 -0
- package/evals/fixtures/narrative-sources/repo/created.txt +1 -0
- package/evals/fixtures/narrative-sources/repo/fixture.txt +1 -0
- package/evals/fixtures/narrative-sources/session/agents/agent-fixture/events.jsonl +2 -0
- package/evals/fixtures/narrative-sources/session/agents/nested-worker/events.jsonl +1 -0
- package/evals/fixtures/narrative-sources/session/trust.bundle +1 -0
- package/evals/fixtures/narrative-sources/telemetry/full.jsonl +3 -0
- package/evals/fixtures/narrative-sources/telemetry/runtime.jsonl +4 -0
- package/evals/fixtures/narrative-sources/transcripts/session.txt +1 -0
- package/evals/integration/test_capability_declarations.sh +183 -0
- package/evals/integration/test_economics_record.sh +42 -0
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_gate_review_inquiry_records.sh +42 -35
- package/evals/integration/test_goal_fit_hook.sh +13 -5
- package/evals/integration/test_goal_fit_narrative_exclusion.sh +68 -0
- package/evals/integration/test_narrative_evals.sh +174 -0
- package/evals/integration/test_narrative_grounded_envelope.sh +280 -0
- package/evals/integration/test_narrative_grounding_validator.sh +166 -0
- package/evals/integration/test_narrative_intent_annotation.sh +205 -0
- package/evals/integration/test_narrative_prose_renderer.sh +239 -0
- package/evals/integration/test_narrative_redaction_failclosed.sh +120 -0
- package/evals/integration/test_narrative_runtime_projection.sh +146 -0
- package/evals/integration/test_narrative_source_contract.sh +228 -0
- package/evals/integration/test_narrative_trust_isolation.sh +408 -0
- package/evals/integration/test_plain_stop_messaging.sh +91 -0
- package/evals/integration/test_session_resume_roundtrip.sh +228 -0
- package/evals/integration/test_telemetry_action_class.sh +265 -0
- package/evals/integration/test_telemetry_delegation.sh +291 -0
- package/evals/integration/test_telemetry_sanitize_usage.sh +155 -0
- package/evals/integration/test_telemetry_task_slug.sh +158 -0
- package/evals/integration/test_telemetry_tool_outcome.sh +279 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +111 -2
- package/evals/run.sh +12 -0
- package/evals/static/test_library_exports.sh +5 -0
- package/package.json +9 -5
- package/schemas/grounded-execution-narrative.schema.json +292 -0
- package/schemas/narrative-eval-result.schema.json +205 -0
- package/schemas/narrative-runtime-projection.schema.json +134 -0
- package/schemas/narrative-source-manifest.schema.json +294 -0
- package/scripts/check-hachure-boundary.mjs +81 -0
- package/scripts/hooks/stop-goal-fit.js +182 -9
- package/scripts/hooks/workflow-steering.js +160 -19
- package/scripts/telemetry/economics-record.schema.json +1 -1
- package/scripts/telemetry/economics-record.sh +47 -3
- package/scripts/telemetry/lib/session.sh +3 -0
- package/scripts/telemetry/lib/transport.sh +12 -3
- package/scripts/telemetry/telemetry.sh +480 -59
- package/src/builder-flow-runtime.ts +102 -1
- package/src/builder-gate-action-envelope.ts +212 -35
- package/src/builder-lifecycle-authority.ts +48 -0
- package/src/cli/builder-flow-runtime.test.mjs +218 -7
- package/src/cli/builder-run.ts +71 -1
- package/src/cli/capability-declarations.test.mjs +117 -0
- package/src/cli/continuation-driver.test.mjs +327 -20
- package/src/cli/kit-metadata-security.test.mjs +90 -2
- package/src/cli/narrative-arch-isolation.test.mjs +198 -0
- package/src/cli/narrative-envelope.test.mjs +367 -0
- package/src/cli/narrative-grounding-validator.test.mjs +322 -0
- package/src/cli/narrative-intent.test.mjs +177 -0
- package/src/cli/narrative-policy-filter.test.mjs +66 -0
- package/src/cli/narrative-projection.test.mjs +236 -0
- package/src/cli/narrative-readers.test.mjs +196 -0
- package/src/cli/narrative-render.test.mjs +221 -0
- package/src/cli/narrative-render.ts +589 -0
- package/src/cli/narrative-resolver.test.mjs +114 -0
- package/src/cli/narrative-snapshot.test.mjs +149 -0
- package/src/cli/narrative-source-ids.test.mjs +84 -0
- package/src/cli/narrative-sources.ts +276 -0
- package/src/cli/narrative-statements.test.mjs +369 -0
- package/src/cli/narrative-turn-spine.test.mjs +74 -0
- package/src/cli/public-api.test.mjs +17 -0
- package/src/cli/public-contracts.ts +95 -0
- package/src/cli/sidecar-pure-helpers.test.mjs +216 -24
- package/src/cli/trust-bundle-policy-order.test.mjs +134 -1
- package/src/cli/workflow-sidecar.ts +563 -167
- package/src/cli/workflow.ts +15 -1
- package/src/cli/writer-observed-execution.test.mjs +102 -0
- package/src/cli.ts +8 -0
- package/src/continuation-driver.ts +32 -3
- package/src/continuation-validation.ts +336 -8
- package/src/flow-kit/action-metadata.ts +20 -1
- package/src/index.ts +241 -0
- package/src/lib/capability-declarations.ts +261 -0
- package/src/narrative/envelope.ts +624 -0
- package/src/narrative/eval-result.ts +175 -0
- package/src/narrative/grounding-validator.ts +610 -0
- package/src/narrative/integrity.ts +53 -0
- package/src/narrative/intent-economics.ts +119 -0
- package/src/narrative/intent.ts +216 -0
- package/src/narrative/policy-filter.ts +66 -0
- package/src/narrative/projection.ts +530 -0
- package/src/narrative/readers.ts +427 -0
- package/src/narrative/render.ts +82 -0
- package/src/narrative/resolver.ts +195 -0
- package/src/narrative/snapshot.ts +365 -0
- package/src/narrative/source-ids.ts +294 -0
- package/src/narrative/statements.ts +423 -0
- package/src/narrative/turn-spine.ts +99 -0
- package/src/tools/build-universal-bundles.ts +8 -0
- package/src/tools/generate-capability-matrix.ts +215 -0
- package/src/tools/validate-source-tree.ts +5 -1
- package/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/build/src/cli/sidecar-claim-explain.js +0 -87
- package/dist/base/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/dist/base/build/src/cli/sidecar-claim-explain.js +0 -87
- package/dist/claude-code/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/dist/claude-code/build/src/cli/sidecar-claim-explain.js +0 -87
- package/dist/codex/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/dist/codex/build/src/cli/sidecar-claim-explain.js +0 -87
- package/dist/kiro/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/dist/kiro/build/src/cli/sidecar-claim-explain.js +0 -87
- package/dist/opencode/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/dist/opencode/build/src/cli/sidecar-claim-explain.js +0 -87
- package/dist/pi/build/src/cli/sidecar-claim-explain.d.ts +0 -45
- package/dist/pi/build/src/cli/sidecar-claim-explain.js +0 -87
- package/src/cli/sidecar-claim-explain.ts +0 -130
|
@@ -14,7 +14,8 @@ import { flowAgentsPackageRoot, flowAgentsPackageVersion } from "../lib/package-
|
|
|
14
14
|
import { pinnedFlowAgentsCommand } from "../lib/pinned-cli-command.js";
|
|
15
15
|
import { runObservedCommand } from "../lib/observed-command.js";
|
|
16
16
|
import { captureReviewWorkspaceSnapshot, startBuilderFlowSession, syncBuilderFlowSession } from "../builder-flow-runtime.js";
|
|
17
|
-
import {
|
|
17
|
+
import { NARRATIVE_NAMESPACE_ROOT } from "./narrative-sources.js";
|
|
18
|
+
import { EVIDENCE_REF_FIELD_SCHEMAS, EVIDENCE_REF_KINDS, EVIDENCE_REF_RULES, NARRATIVE_PROMOTE_OPERATION, WORKFLOW_ACCEPTANCE_STATUSES, WORKFLOW_CRITIQUE_STATUSES, } from "./public-contracts.js";
|
|
18
19
|
// #291 Wave 1 Task 1.1 exports: ensure-session's ownership guard reuses the EXACT same
|
|
19
20
|
// assignment ⋈ liveness join / claim / supersede logic #290 already ships for the
|
|
20
21
|
// `assignment-provider` CLI, rather than reimplementing a second, parallel join (static ESM
|
|
@@ -391,62 +392,23 @@ export async function validateTrustBundle(bundle) {
|
|
|
391
392
|
return { valid: false, errors: [message], available: true };
|
|
392
393
|
}
|
|
393
394
|
}
|
|
394
|
-
// Validate a single InquiryRecord against the hachure inquiry-record.schema.json.
|
|
395
|
-
// Uses a separate AJV instance compiled against that schema (not the trust-bundle schema).
|
|
396
|
-
let _hachureInquiryRecordValidator;
|
|
397
|
-
function getHachureInquiryRecordValidator() {
|
|
398
|
-
if (_hachureInquiryRecordValidator !== undefined)
|
|
399
|
-
return _hachureInquiryRecordValidator;
|
|
400
|
-
try {
|
|
401
|
-
const _require = createRequire(import.meta.url);
|
|
402
|
-
const hachureDir = path.dirname(_require.resolve("hachure"));
|
|
403
|
-
const schemasDir = path.join(hachureDir, "schemas");
|
|
404
|
-
const Ajv = _require("ajv/dist/2020");
|
|
405
|
-
const schemas = {};
|
|
406
|
-
for (const file of fs.readdirSync(schemasDir)) {
|
|
407
|
-
if (!file.endsWith(".schema.json"))
|
|
408
|
-
continue;
|
|
409
|
-
schemas[file] = JSON.parse(fs.readFileSync(path.join(schemasDir, file), "utf8"));
|
|
410
|
-
}
|
|
411
|
-
const inquiryRecordSchema = schemas["inquiry-record.schema.json"];
|
|
412
|
-
if (!inquiryRecordSchema) {
|
|
413
|
-
_hachureInquiryRecordValidator = null;
|
|
414
|
-
return null;
|
|
415
|
-
}
|
|
416
|
-
const ajv = new Ajv({ strict: false, allErrors: true });
|
|
417
|
-
for (const [filename, schema] of Object.entries(schemas)) {
|
|
418
|
-
if (filename === "inquiry-record.schema.json")
|
|
419
|
-
continue;
|
|
420
|
-
ajv.addSchema(schema, filename);
|
|
421
|
-
}
|
|
422
|
-
const validate = ajv.compile(inquiryRecordSchema);
|
|
423
|
-
_hachureInquiryRecordValidator = (record) => {
|
|
424
|
-
const valid = validate(record);
|
|
425
|
-
if (valid)
|
|
426
|
-
return { valid: true, errors: [] };
|
|
427
|
-
const errors = (validate.errors ?? []).map((err) => {
|
|
428
|
-
const loc = err.instancePath || err.schemaPath || "";
|
|
429
|
-
return `${loc} ${err.message ?? "invalid"}`.trim();
|
|
430
|
-
});
|
|
431
|
-
return { valid: false, errors };
|
|
432
|
-
};
|
|
433
|
-
return _hachureInquiryRecordValidator;
|
|
434
|
-
}
|
|
435
|
-
catch {
|
|
436
|
-
_hachureInquiryRecordValidator = null;
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
395
|
/**
|
|
441
|
-
* Validate a record against the canonical
|
|
442
|
-
*
|
|
443
|
-
* Returns `{ valid, errors, available }`. Fail-open when
|
|
396
|
+
* Validate a record against the canonical InquiryRecord schema via
|
|
397
|
+
* @kontourai/surface's `validateInquiryRecord` (symmetric to `validateTrustBundle`).
|
|
398
|
+
* Returns `{ valid, errors, available }`. Fail-open when Surface is unavailable.
|
|
444
399
|
*/
|
|
445
|
-
export function validateInquiryRecord(record) {
|
|
446
|
-
const
|
|
447
|
-
if (!
|
|
400
|
+
export async function validateInquiryRecord(record) {
|
|
401
|
+
const m = await tryLoadSurface();
|
|
402
|
+
if (!m || typeof m.validateInquiryRecord !== "function") {
|
|
448
403
|
return { valid: true, errors: [], available: false };
|
|
449
|
-
|
|
404
|
+
}
|
|
405
|
+
try {
|
|
406
|
+
m.validateInquiryRecord(record);
|
|
407
|
+
return { valid: true, errors: [], available: true };
|
|
408
|
+
}
|
|
409
|
+
catch (err) {
|
|
410
|
+
return { valid: false, errors: [err instanceof Error ? err.message : String(err)], available: true };
|
|
411
|
+
}
|
|
450
412
|
}
|
|
451
413
|
let _surfaceModule; // undefined = not tried yet; null = unavailable
|
|
452
414
|
async function tryLoadSurface() {
|
|
@@ -488,6 +450,15 @@ function criterionStatusToEventStatus(status) {
|
|
|
488
450
|
return "assumed";
|
|
489
451
|
return null; // pending / not_verified → no event → Surface returns "unknown"
|
|
490
452
|
}
|
|
453
|
+
const ACCEPTANCE_CRITERION_STATUSES = new Set(WORKFLOW_ACCEPTANCE_STATUSES);
|
|
454
|
+
const CANONICALLY_OBSERVED_ACCEPTANCE_CRITERIA = new WeakSet();
|
|
455
|
+
function markCanonicallyObservedCriterion(criterion) {
|
|
456
|
+
CANONICALLY_OBSERVED_ACCEPTANCE_CRITERIA.add(criterion);
|
|
457
|
+
return criterion;
|
|
458
|
+
}
|
|
459
|
+
function normalizeCriterionStatus(status) {
|
|
460
|
+
return typeof status === "string" && ACCEPTANCE_CRITERION_STATUSES.has(status) ? status : "pending";
|
|
461
|
+
}
|
|
491
462
|
/**
|
|
492
463
|
* WS8 (ADR 0020): Derive Surface evidence classification (evidenceType + method)
|
|
493
464
|
* from a workflow check's kind, replacing the previous hardcoded `test_output`.
|
|
@@ -599,7 +570,23 @@ export function reduceCaptureLogByCommand(commandLog) {
|
|
|
599
570
|
else
|
|
600
571
|
merged = "ambiguous";
|
|
601
572
|
}
|
|
602
|
-
|
|
573
|
+
// #634 review finding: the exit code must travel with the WINNING status, never a
|
|
574
|
+
// losing entry's — [hook fail exit 1, writer pass exit 0] must fold to fail/1, not
|
|
575
|
+
// fail/0 (contradictory isError:true, exitCode:0 evidence). When both entries carry
|
|
576
|
+
// the winning status, prefer the newer non-null code.
|
|
577
|
+
let mergedExitCode;
|
|
578
|
+
if (!prev) {
|
|
579
|
+
mergedExitCode = exitCode;
|
|
580
|
+
}
|
|
581
|
+
else if (merged === result && merged === prev.observedResult) {
|
|
582
|
+
mergedExitCode = exitCode !== null ? exitCode : prev.exitCode;
|
|
583
|
+
}
|
|
584
|
+
else if (merged === result) {
|
|
585
|
+
mergedExitCode = exitCode;
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
mergedExitCode = prev.exitCode;
|
|
589
|
+
}
|
|
603
590
|
captureByCommand.set(key, { observedResult: merged, exitCode: mergedExitCode });
|
|
604
591
|
}
|
|
605
592
|
return captureByCommand;
|
|
@@ -790,8 +777,6 @@ export async function buildTrustBundle(slug, timestamp, checks, criteria, critiq
|
|
|
790
777
|
// "flow-step". Fallback: first non-decision, non-acceptance entry.
|
|
791
778
|
// check (kind=policy) → expects[] entry whose claimType contains
|
|
792
779
|
// "compliance" or "policy". Fallback: same as non-policy.
|
|
793
|
-
// acceptance criterion → expects[] entry whose subjectType is "flow-step"
|
|
794
|
-
// OR claimType contains "tests" OR "compliance". Fallback: first entry.
|
|
795
780
|
// critique → expects[] entry whose claimType contains "policy"
|
|
796
781
|
// OR "compliance" AND subjectType is "artifact". Fallback: last entry.
|
|
797
782
|
//
|
|
@@ -801,7 +786,7 @@ export async function buildTrustBundle(slug, timestamp, checks, criteria, critiq
|
|
|
801
786
|
// Surface from that evidence (never hand-set).
|
|
802
787
|
//
|
|
803
788
|
// Per-gate producibility (ADR 0016 P-d):
|
|
804
|
-
// (a) Already handled via subjectType=flow-step preference:
|
|
789
|
+
// (a) Already handled via subjectType=flow-step preference for checks:
|
|
805
790
|
// builder.verify.tests (verify-gate, subjectType=flow-step)
|
|
806
791
|
// builder.verify.policy-compliance (verify-gate, kind=policy match)
|
|
807
792
|
// (b) Producible via fallback (non-decision, non-acceptance, first match):
|
|
@@ -818,6 +803,9 @@ export async function buildTrustBundle(slug, timestamp, checks, criteria, critiq
|
|
|
818
803
|
// builder.learn.evidence (learn-gate, subjectType=release)
|
|
819
804
|
// For category (c): record-gate-claim subcommand allows skills to target a specific
|
|
820
805
|
// expects[] entry by --expectation <id>, bypassing this semantic match entirely.
|
|
806
|
+
//
|
|
807
|
+
// Acceptance criteria do not participate in this matching table. They are durable Work Item
|
|
808
|
+
// facts with invariant workflow.acceptance.criterion/flow-step identity across every gate.
|
|
821
809
|
function matchExpectsEntry(kind, checkKindVal, expectationId) {
|
|
822
810
|
if (!activeStep || activeStep.gateExpects.length === 0)
|
|
823
811
|
return null;
|
|
@@ -856,15 +844,6 @@ export async function buildTrustBundle(slug, timestamp, checks, criteria, critiq
|
|
|
856
844
|
return { claimType: fallback.bundle_claim.claimType, subjectType: fallback.bundle_claim.subjectType };
|
|
857
845
|
return null;
|
|
858
846
|
}
|
|
859
|
-
if (kind === "acceptance") {
|
|
860
|
-
const match = expects.find((e) => {
|
|
861
|
-
const ct = e.bundle_claim.claimType.toLowerCase();
|
|
862
|
-
return e.bundle_claim.subjectType === "flow-step" || ct.includes("tests") || ct.includes("compliance");
|
|
863
|
-
});
|
|
864
|
-
if (match)
|
|
865
|
-
return { claimType: match.bundle_claim.claimType, subjectType: match.bundle_claim.subjectType };
|
|
866
|
-
return { claimType: expects[0].bundle_claim.claimType, subjectType: expects[0].bundle_claim.subjectType };
|
|
867
|
-
}
|
|
868
847
|
if (kind === "critique") {
|
|
869
848
|
const match = expects.find((e) => {
|
|
870
849
|
const ct = e.bundle_claim.claimType.toLowerCase();
|
|
@@ -1059,33 +1038,71 @@ export async function buildTrustBundle(slug, timestamp, checks, criteria, critiq
|
|
|
1059
1038
|
continue;
|
|
1060
1039
|
const subjectId = `${slug}/${criterion.id}`;
|
|
1061
1040
|
const fieldOrBehavior = String(criterion.description ?? criterion.id);
|
|
1041
|
+
const normalizedCriterionStatus = normalizeCriterionStatus(criterion.status);
|
|
1062
1042
|
const criterionIdentityVersion = criterion.identity_version === 2 ? 2 : 1;
|
|
1063
1043
|
const criterionVerifiedAt = criterionIdentityVersion === 2 && typeof criterion.verified_at === "string" ? criterion.verified_at : null;
|
|
1044
|
+
const criterionEvidenceRefs = Array.isArray(criterion.evidence_refs) ? criterion.evidence_refs : [];
|
|
1045
|
+
const commandRefs = criterionEvidenceRefs
|
|
1046
|
+
.filter((ref) => ref?.kind === "command")
|
|
1047
|
+
.map((ref) => commandFromEvidenceRef(ref))
|
|
1048
|
+
.filter((command) => command.length > 0);
|
|
1049
|
+
const rawObservedCommands = Array.isArray(criterion._observed_commands) ? criterion._observed_commands : [];
|
|
1050
|
+
const observedCommands = rawObservedCommands.filter((observation) => typeof observation?.command === "string"
|
|
1051
|
+
&& commandRefs.includes(observation.command)
|
|
1052
|
+
&& observation.exit_code === 0
|
|
1053
|
+
&& typeof observation.output_sha256 === "string"
|
|
1054
|
+
&& /^[a-f0-9]{64}$/i.test(observation.output_sha256)
|
|
1055
|
+
&& Number.isSafeInteger(observation.test_count)
|
|
1056
|
+
&& observation.test_count > 0
|
|
1057
|
+
&& observation.execution_proof?.kind === "local-process-exit");
|
|
1058
|
+
const hasObservedCommandProvenance = CANONICALLY_OBSERVED_ACCEPTANCE_CRITERIA.has(criterion)
|
|
1059
|
+
&& criterionIdentityVersion === 2
|
|
1060
|
+
&& criterionVerifiedAt !== null
|
|
1061
|
+
&& Number.isFinite(Date.parse(criterionVerifiedAt))
|
|
1062
|
+
&& observedCommands.length === rawObservedCommands.length
|
|
1063
|
+
&& observedCommands.length > 0
|
|
1064
|
+
&& commandRefs.every((command) => observedCommands.some((observation) => observation.command === command));
|
|
1065
|
+
const criterionStatus = normalizedCriterionStatus === "pass" && !hasObservedCommandProvenance
|
|
1066
|
+
? "pending"
|
|
1067
|
+
: normalizedCriterionStatus;
|
|
1068
|
+
const criterionClaimTimestamp = criterionStatus === "pass" && criterionVerifiedAt ? criterionVerifiedAt : ts;
|
|
1064
1069
|
const claimId = generateClaimId(subjectId, "flow-agents.workflow", criterionVerifiedAt ? `${fieldOrBehavior}::verified::${criterionVerifiedAt}` : fieldOrBehavior);
|
|
1065
|
-
const
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1070
|
+
const claimType = "workflow.acceptance.criterion";
|
|
1071
|
+
const criterionEvidenceIds = [];
|
|
1072
|
+
if (criterionStatus === "pass") {
|
|
1073
|
+
for (const observation of observedCommands) {
|
|
1074
|
+
const evidenceId = `ev:${claimId}:${createHash("sha256").update(observation.command).digest("hex").slice(0, 16)}`;
|
|
1075
|
+
criterionEvidenceIds.push(evidenceId);
|
|
1076
|
+
evidenceItems.push({
|
|
1077
|
+
id: evidenceId,
|
|
1078
|
+
claimId,
|
|
1079
|
+
evidenceType: "test_output",
|
|
1080
|
+
method: "validation",
|
|
1081
|
+
sourceRef: `${slug}/observed-command`,
|
|
1082
|
+
excerptOrSummary: observation.command,
|
|
1083
|
+
observedAt: criterionVerifiedAt,
|
|
1084
|
+
collectedBy: "flow-agents/workflow-sidecar",
|
|
1085
|
+
passing: true,
|
|
1086
|
+
execution: { runner: "bash", label: observation.command, isError: false, exitCode: 0 },
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
const policy = ensurePolicy(claimType, "high", criterionEvidenceIds.length > 0 ? ["test_output"] : []);
|
|
1091
|
+
const evStatus = criterionStatusToEventStatus(criterionStatus);
|
|
1068
1092
|
const claimEvents = [];
|
|
1069
1093
|
if (evStatus) {
|
|
1070
|
-
const evt = { id: `evt:${claimId}`, claimId, status: evStatus, actor: "flow-agents/workflow-sidecar", method: "validation", evidenceIds:
|
|
1094
|
+
const evt = { id: `evt:${claimId}`, claimId, status: evStatus, actor: "flow-agents/workflow-sidecar", method: "validation", evidenceIds: criterionEvidenceIds, createdAt: criterionClaimTimestamp, verifiedAt: criterionClaimTimestamp };
|
|
1071
1095
|
events.push(evt);
|
|
1072
1096
|
claimEvents.push(evt);
|
|
1073
1097
|
}
|
|
1074
|
-
//
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
}
|
|
1083
|
-
else {
|
|
1084
|
-
// No active flow step — only the workflow.* primary claim (legitimate no-flow fallback path).
|
|
1085
|
-
const claimObj = { id: claimId, subjectType: "workflow-acceptance-criterion", subjectId, facet: "flow-agents.workflow", claimType: legacyClaimType, fieldOrBehavior, value: criterion.status, createdAt: ts, updatedAt: ts, impactLevel: "high", verificationPolicyId: policy.id, metadata: { origin: "acceptance", criterion: { id: criterion.id, description: criterion.description ?? criterion.id, status: criterion.status, evidence_refs: Array.isArray(criterion.evidence_refs) ? criterion.evidence_refs : [] } } };
|
|
1086
|
-
const { status: derivedStatus } = deriveClaimStatus({ claim: claimObj, evidence: [], events: claimEvents, policies: [policy] });
|
|
1087
|
-
claims.push({ ...claimObj, status: derivedStatus });
|
|
1088
|
-
}
|
|
1098
|
+
// Acceptance criteria are durable Work Item facts. Their identity must not change when a
|
|
1099
|
+
// bundle is rebuilt at a different active gate. Missing or invalid status is conservatively
|
|
1100
|
+
// projected as pending so direct artifact edits can never manufacture a pass or invalidate
|
|
1101
|
+
// the Hachure claim shape.
|
|
1102
|
+
const claimObj = { id: claimId, subjectType: "flow-step", subjectId, facet: "flow-agents.workflow", claimType, fieldOrBehavior, value: criterionStatus, createdAt: criterionClaimTimestamp, updatedAt: criterionClaimTimestamp, impactLevel: "high", verificationPolicyId: policy.id, metadata: { origin: "acceptance", criterion: { id: criterion.id, description: criterion.description ?? criterion.id, status: criterionStatus, evidence_refs: criterionEvidenceRefs, ...(observedCommands.length > 0 ? { observed_commands: observedCommands } : {}), ...(criterionIdentityVersion === 2 ? { identity_version: 2 } : {}), ...(criterionVerifiedAt ? { verified_at: criterionVerifiedAt } : {}) }, ...(workflowSubjectRef ? { workflow_subject_ref: workflowSubjectRef } : {}) } };
|
|
1103
|
+
const criterionEvidence = evidenceItems.filter((evidence) => evidence.claimId === claimId);
|
|
1104
|
+
const { status: derivedStatus } = deriveClaimStatus({ claim: claimObj, evidence: criterionEvidence, events: claimEvents, policies: [policy] });
|
|
1105
|
+
claims.push({ ...claimObj, status: derivedStatus });
|
|
1089
1106
|
}
|
|
1090
1107
|
// Critique entries → claims + events
|
|
1091
1108
|
for (const c of Array.isArray(critiques) ? critiques : []) {
|
|
@@ -2432,11 +2449,11 @@ function hasNonEmptyString(value) {
|
|
|
2432
2449
|
function hasPositiveInteger(value) {
|
|
2433
2450
|
return Number.isInteger(value) && Number(value) >= 1;
|
|
2434
2451
|
}
|
|
2435
|
-
export function validateEvidenceRef(ref, label) {
|
|
2436
|
-
if (!
|
|
2437
|
-
die(`${label} entry kind must be one of:
|
|
2452
|
+
export function validateEvidenceRef(ref, label, projectRoot = process.cwd()) {
|
|
2453
|
+
if (!EVIDENCE_REF_KINDS.includes(ref.kind))
|
|
2454
|
+
die(`${label} entry kind must be one of: ${EVIDENCE_REF_KINDS.join(", ")}`);
|
|
2438
2455
|
for (const key of Object.keys(ref))
|
|
2439
|
-
if (!
|
|
2456
|
+
if (!Object.hasOwn(EVIDENCE_REF_FIELD_SCHEMAS, key))
|
|
2440
2457
|
die(`${label} entries contain unsupported field: ${key}`);
|
|
2441
2458
|
if (ref.url !== undefined && !hasNonEmptyString(ref.url))
|
|
2442
2459
|
die(`${label} entry url must be a non-empty string`);
|
|
@@ -2450,19 +2467,26 @@ export function validateEvidenceRef(ref, label) {
|
|
|
2450
2467
|
die(`${label} entry line_start must be a positive integer`);
|
|
2451
2468
|
if (ref.line_end !== undefined && !hasPositiveInteger(ref.line_end))
|
|
2452
2469
|
die(`${label} entry line_end must be a positive integer`);
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2470
|
+
rejectNarrativeReference(projectRoot, ref.file, `${label} entry file`);
|
|
2471
|
+
rejectNarrativeReference(projectRoot, ref.url, `${label} entry url`);
|
|
2472
|
+
rejectNarrativeReference(projectRoot, ref.excerpt, `${label} entry excerpt`);
|
|
2473
|
+
const rules = EVIDENCE_REF_RULES[ref.kind];
|
|
2474
|
+
for (const rule of rules) {
|
|
2475
|
+
const present = (field) => field === "line_start" || field === "line_end"
|
|
2476
|
+
? hasPositiveInteger(ref[field])
|
|
2477
|
+
: hasNonEmptyString(ref[field]);
|
|
2478
|
+
const valid = rule.mode === "all" ? rule.fields.every(present) : rule.fields.some(present);
|
|
2479
|
+
if (!valid) {
|
|
2480
|
+
const separator = rule.fields.length > 2 ? ", " : " ";
|
|
2481
|
+
const joined = rule.fields.length > 1
|
|
2482
|
+
? `${rule.fields.slice(0, -1).join(separator)}${rule.fields.length > 2 ? "," : ""} or ${rule.fields.at(-1)}`
|
|
2483
|
+
: rule.fields[0];
|
|
2484
|
+
die(`${label} ${ref.kind} refs require ${rule.mode === "all" && rule.fields.length > 1 ? joined.replace(/ or ([^,]+)$/, " and $1") : joined}`);
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2463
2487
|
return ref;
|
|
2464
2488
|
}
|
|
2465
|
-
export function normalizeEvidenceRefs(raw, label) {
|
|
2489
|
+
export function normalizeEvidenceRefs(raw, label, projectRoot = process.cwd()) {
|
|
2466
2490
|
if (!Array.isArray(raw))
|
|
2467
2491
|
die(`${label} must be an array`);
|
|
2468
2492
|
return raw.map((ref) => {
|
|
@@ -2470,7 +2494,7 @@ export function normalizeEvidenceRefs(raw, label) {
|
|
|
2470
2494
|
die(`${label} entries must be structured evidence reference objects; legacy string refs are not supported`);
|
|
2471
2495
|
if (!ref || typeof ref !== "object" || Array.isArray(ref))
|
|
2472
2496
|
die(`${label} entries must be objects`);
|
|
2473
|
-
return validateEvidenceRef({ ...ref }, label);
|
|
2497
|
+
return validateEvidenceRef({ ...ref }, label, projectRoot);
|
|
2474
2498
|
});
|
|
2475
2499
|
}
|
|
2476
2500
|
function canonicalProjectRootForSession(dir) {
|
|
@@ -2484,14 +2508,180 @@ function canonicalProjectRootForSession(dir) {
|
|
|
2484
2508
|
die("gate evidence project root must be a non-symlink directory");
|
|
2485
2509
|
return projectRoot;
|
|
2486
2510
|
}
|
|
2511
|
+
// #619: the narrative isolation guard must run for EVERY session layout (canonical,
|
|
2512
|
+
// tmp, or legacy .flow-agents/) without imposing the canonical-session requirement that
|
|
2513
|
+
// canonicalProjectRootForSession enforces. It only needs a best-effort project root to
|
|
2514
|
+
// resolve relative evidence paths; the namespace regex and content-shape checks are
|
|
2515
|
+
// location-independent. It mirrors canonicalProjectRootForSession's path computation for a
|
|
2516
|
+
// canonical .kontourai/flow-agents/<slug> session (project root is three levels up), handles
|
|
2517
|
+
// the legacy .flow-agents/<slug> layout (two levels up), and never dies on any layout.
|
|
2518
|
+
function narrativeGuardRoot(dir) {
|
|
2519
|
+
const artifactRoot = path.dirname(dir);
|
|
2520
|
+
const parentRoot = path.dirname(artifactRoot);
|
|
2521
|
+
if (path.basename(artifactRoot) === "flow-agents" && path.basename(parentRoot) === ".kontourai") {
|
|
2522
|
+
return path.dirname(parentRoot);
|
|
2523
|
+
}
|
|
2524
|
+
if (path.basename(artifactRoot) === ".flow-agents") {
|
|
2525
|
+
return parentRoot;
|
|
2526
|
+
}
|
|
2527
|
+
// Unknown/tmp layout: best-effort. Relative-path resolution may be imperfect, but the
|
|
2528
|
+
// namespace regex and content-shape checks are location-independent, so the isolation
|
|
2529
|
+
// guarantee holds regardless.
|
|
2530
|
+
return artifactRoot;
|
|
2531
|
+
}
|
|
2487
2532
|
function pathIsWithinRoot(candidate, root) {
|
|
2488
2533
|
const relative = path.relative(root, candidate);
|
|
2489
2534
|
return relative === "" || (!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative));
|
|
2490
2535
|
}
|
|
2536
|
+
export const NARRATIVE_TRUST_ISOLATION_DIAGNOSTIC = "narrative trust isolation (#619): narrative namespace artifacts cannot be used as workflow evidence";
|
|
2537
|
+
function decodeNarrativeReference(value) {
|
|
2538
|
+
try {
|
|
2539
|
+
return decodeURIComponent(value);
|
|
2540
|
+
}
|
|
2541
|
+
catch {
|
|
2542
|
+
return value;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
function realpathWithExistingPrefix(candidate) {
|
|
2546
|
+
let cursor = path.resolve(candidate);
|
|
2547
|
+
const suffix = [];
|
|
2548
|
+
while (!fs.existsSync(cursor)) {
|
|
2549
|
+
const parent = path.dirname(cursor);
|
|
2550
|
+
if (parent === cursor)
|
|
2551
|
+
break;
|
|
2552
|
+
suffix.unshift(path.basename(cursor));
|
|
2553
|
+
cursor = parent;
|
|
2554
|
+
}
|
|
2555
|
+
let canonical = cursor;
|
|
2556
|
+
try {
|
|
2557
|
+
canonical = (fs.realpathSync.native ?? fs.realpathSync)(cursor);
|
|
2558
|
+
}
|
|
2559
|
+
catch { /* resolved lexical prefix is the fallback */ }
|
|
2560
|
+
return path.resolve(canonical, ...suffix);
|
|
2561
|
+
}
|
|
2562
|
+
export function isNarrativeNamespacePath(projectRoot, resolvedPath) {
|
|
2563
|
+
const decoded = decodeNarrativeReference(resolvedPath);
|
|
2564
|
+
const normalized = decoded.replaceAll("\\", "/").toLowerCase();
|
|
2565
|
+
if (/(?:^|[^a-z0-9._-])\.kontourai(?:\/[^/\s"'`]+)*\/narrative(?:$|[/\s"'`])/.test(normalized))
|
|
2566
|
+
return true;
|
|
2567
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(decoded) && !decoded.toLowerCase().startsWith("file://"))
|
|
2568
|
+
return false;
|
|
2569
|
+
let local = decoded;
|
|
2570
|
+
if (decoded.toLowerCase().startsWith("file://")) {
|
|
2571
|
+
try {
|
|
2572
|
+
local = fileURLToPath(decoded);
|
|
2573
|
+
}
|
|
2574
|
+
catch {
|
|
2575
|
+
return false;
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
const canonicalRoot = realpathWithExistingPrefix(path.resolve(projectRoot, NARRATIVE_NAMESPACE_ROOT)).toLowerCase();
|
|
2579
|
+
const candidate = realpathWithExistingPrefix(path.resolve(projectRoot, local)).toLowerCase();
|
|
2580
|
+
return pathIsWithinRoot(candidate, canonicalRoot);
|
|
2581
|
+
}
|
|
2582
|
+
export function isNarrativeArtifactContent(fileBytes) {
|
|
2583
|
+
const text = Buffer.isBuffer(fileBytes) ? fileBytes.toString("utf8") : fileBytes;
|
|
2584
|
+
try {
|
|
2585
|
+
const parsed = JSON.parse(text);
|
|
2586
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
2587
|
+
return false;
|
|
2588
|
+
const value = parsed;
|
|
2589
|
+
if (value.schema_version === "grounded-execution-narrative/v1")
|
|
2590
|
+
return true;
|
|
2591
|
+
if (value.schema_version === "grounded-runtime-projection/v1")
|
|
2592
|
+
return true;
|
|
2593
|
+
if (value.schema_version === "1.0"
|
|
2594
|
+
&& hasNonEmptyString(value.narrative_id)
|
|
2595
|
+
&& hasNonEmptyString(value.captured_at)
|
|
2596
|
+
&& value.compiler && typeof value.compiler === "object"
|
|
2597
|
+
&& value.capture_completeness && typeof value.capture_completeness === "object"
|
|
2598
|
+
&& Array.isArray(value.sources))
|
|
2599
|
+
return true;
|
|
2600
|
+
return false;
|
|
2601
|
+
}
|
|
2602
|
+
catch {
|
|
2603
|
+
return text.includes("flow-agents-narrative-composer")
|
|
2604
|
+
&& text.includes("# Grounded Execution Narrative")
|
|
2605
|
+
&& text.includes("## Authority provenance");
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
function localPathTokens(value) {
|
|
2609
|
+
const decoded = decodeNarrativeReference(value);
|
|
2610
|
+
const tokens = decoded.match(/(?:file:\/\/[^\s"'`]+)|(?:[A-Za-z]:[\\/][^\s"'`]+)|(?:\.{0,2}[\\/][^\s"'`]+)|(?:[^\s"'`]+[\\/][^\s"'`]+)/g) ?? [];
|
|
2611
|
+
return tokens.map((token) => token.replace(/^[([{<]+/, "").replace(/[\])}>;,]+$/, ""));
|
|
2612
|
+
}
|
|
2613
|
+
function referencesComposedNarrativePath(projectRoot, value) {
|
|
2614
|
+
const decoded = decodeNarrativeReference(value);
|
|
2615
|
+
const folded = decoded.replaceAll("\\", "/").toLowerCase();
|
|
2616
|
+
if (folded.includes(".kontourai/narrative"))
|
|
2617
|
+
return true;
|
|
2618
|
+
// Static shell inspection cannot decide arbitrary runtime variable composition such as
|
|
2619
|
+
// `base=.kontourai; test -f "$base/narrative/..."`. The compensating invariant is that a
|
|
2620
|
+
// command check persists only its command plus exit/observed-output digest; it never reads file
|
|
2621
|
+
// bytes into trust.bundle. Every channel that DOES materialize a file is independently guarded
|
|
2622
|
+
// by canonical path and narrative content shape. Keep that invariant covered end-to-end.
|
|
2623
|
+
const cdPattern = /(?:^|[;&|]\s*)cd\s+(?:"([^"]+)"|'([^']+)'|([^\s;&|]+))\s*&&([\s\S]*)/gi;
|
|
2624
|
+
for (const match of decoded.matchAll(cdPattern)) {
|
|
2625
|
+
const cdTarget = match[1] ?? match[2] ?? match[3] ?? "";
|
|
2626
|
+
const remainder = (match[4] ?? "").replaceAll("\\", "/").toLowerCase();
|
|
2627
|
+
if (!/(?:^|[^a-z0-9._-])narrative\//.test(remainder))
|
|
2628
|
+
continue;
|
|
2629
|
+
const canonicalTarget = realpathWithExistingPrefix(path.resolve(projectRoot, decodeNarrativeReference(cdTarget)))
|
|
2630
|
+
.replaceAll("\\", "/")
|
|
2631
|
+
.toLowerCase();
|
|
2632
|
+
const canonicalKontourai = realpathWithExistingPrefix(path.resolve(projectRoot, ".kontourai"))
|
|
2633
|
+
.replaceAll("\\", "/")
|
|
2634
|
+
.toLowerCase();
|
|
2635
|
+
if (canonicalTarget === canonicalKontourai
|
|
2636
|
+
|| canonicalTarget.startsWith(`${canonicalKontourai}/`)
|
|
2637
|
+
|| /(?:^|\/)\.kontourai(?:\/|$)/.test(canonicalTarget))
|
|
2638
|
+
return true;
|
|
2639
|
+
}
|
|
2640
|
+
return false;
|
|
2641
|
+
}
|
|
2642
|
+
function narrativeCandidateFile(projectRoot, raw) {
|
|
2643
|
+
let decoded = decodeNarrativeReference(raw);
|
|
2644
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(decoded)) {
|
|
2645
|
+
if (!decoded.toLowerCase().startsWith("file://"))
|
|
2646
|
+
return null;
|
|
2647
|
+
try {
|
|
2648
|
+
decoded = fileURLToPath(decoded);
|
|
2649
|
+
}
|
|
2650
|
+
catch {
|
|
2651
|
+
return null;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
const candidate = path.isAbsolute(decoded) ? decoded : path.resolve(projectRoot, decoded);
|
|
2655
|
+
try {
|
|
2656
|
+
const canonical = (fs.realpathSync.native ?? fs.realpathSync)(candidate);
|
|
2657
|
+
const stat = fs.statSync(canonical);
|
|
2658
|
+
return stat.isFile() ? canonical : null;
|
|
2659
|
+
}
|
|
2660
|
+
catch {
|
|
2661
|
+
return null;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
function rejectNarrativeReference(projectRoot, value, label) {
|
|
2665
|
+
if (typeof value !== "string")
|
|
2666
|
+
return;
|
|
2667
|
+
const decoded = decodeNarrativeReference(value);
|
|
2668
|
+
if (referencesComposedNarrativePath(projectRoot, decoded))
|
|
2669
|
+
die(`${label}: ${NARRATIVE_TRUST_ISOLATION_DIAGNOSTIC}`);
|
|
2670
|
+
const candidates = [decoded, ...localPathTokens(decoded)];
|
|
2671
|
+
for (const candidate of new Set(candidates)) {
|
|
2672
|
+
if (isNarrativeNamespacePath(projectRoot, candidate))
|
|
2673
|
+
die(`${label}: ${NARRATIVE_TRUST_ISOLATION_DIAGNOSTIC}`);
|
|
2674
|
+
const file = narrativeCandidateFile(projectRoot, candidate);
|
|
2675
|
+
if (file && isNarrativeArtifactContent(fs.readFileSync(file))) {
|
|
2676
|
+
die(`${label}: ${NARRATIVE_TRUST_ISOLATION_DIAGNOSTIC}`);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2491
2680
|
function validateLocalEvidenceFile(projectRoot, raw, label) {
|
|
2492
2681
|
const candidate = path.resolve(projectRoot, raw);
|
|
2493
2682
|
if (!pathIsWithinRoot(candidate, projectRoot))
|
|
2494
2683
|
die(`${label} must remain inside the canonical project root`);
|
|
2684
|
+
rejectNarrativeReference(projectRoot, raw, label);
|
|
2495
2685
|
let stat;
|
|
2496
2686
|
try {
|
|
2497
2687
|
stat = fs.lstatSync(candidate);
|
|
@@ -2509,6 +2699,12 @@ function globMatches(pattern, relative) {
|
|
|
2509
2699
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("**", "::GLOBSTAR::").replaceAll("*", "[^/]*").replaceAll("::GLOBSTAR::", ".*");
|
|
2510
2700
|
return new RegExp(`^${escaped}$`).test(relative);
|
|
2511
2701
|
}
|
|
2702
|
+
export function rejectOperationBoundExpectation(expectationId, operation) {
|
|
2703
|
+
const completion = operation === NARRATIVE_PROMOTE_OPERATION
|
|
2704
|
+
? "authenticated external narrative provider completion"
|
|
2705
|
+
: "authenticated external ChangeProvider completion";
|
|
2706
|
+
die(`record-gate-claim cannot satisfy operation-bound expectation ${expectationId}; ${operation} requires ${completion}`);
|
|
2707
|
+
}
|
|
2512
2708
|
function expectedGateProducer(flowId, stepId, expectationId) {
|
|
2513
2709
|
const manifest = loadJson(path.join(flowAgentsPackageRoot(), "kits", "builder", "kit.json"));
|
|
2514
2710
|
const actions = Array.isArray(manifest.flow_step_actions) ? manifest.flow_step_actions : [];
|
|
@@ -2520,7 +2716,7 @@ function expectedGateProducer(flowId, stepId, expectationId) {
|
|
|
2520
2716
|
: undefined;
|
|
2521
2717
|
if (binding?.interface === "operation") {
|
|
2522
2718
|
const operation = typeof binding.operation === "string" ? binding.operation : "the declared external operation";
|
|
2523
|
-
|
|
2719
|
+
rejectOperationBoundExpectation(expectationId, operation);
|
|
2524
2720
|
}
|
|
2525
2721
|
const skills = Array.isArray(action.skills) ? action.skills.filter((value) => typeof value === "string") : [];
|
|
2526
2722
|
const roles = Array.isArray(manifest.skill_roles) ? manifest.skill_roles : [];
|
|
@@ -2775,6 +2971,131 @@ async function normalizeObservedCommands(commands, projectRoot, requireTestInten
|
|
|
2775
2971
|
die("every --command requires a corresponding --observed-command-json");
|
|
2776
2972
|
return commands.map((command) => byCommand.get(command));
|
|
2777
2973
|
}
|
|
2974
|
+
// #634: the canonical writer's own execution is a first-class observation. On hosts whose
|
|
2975
|
+
// PostToolUse capture never surfaces exit codes, every hook-captured entry is "ambiguous",
|
|
2976
|
+
// the independent capture can never confirm a pass, and the verify gate dead-ends. The writer
|
|
2977
|
+
// just ran the command itself — a real process exit, not an inference — so it appends that
|
|
2978
|
+
// observation to the SAME hash-chained command-log, under the SAME lock protocol the capture
|
|
2979
|
+
// hook uses, visibly attributed via source: "canonical-writer-execution". Precedence stays
|
|
2980
|
+
// honest in the fold (reduceCaptureLogByCommand): any observed fail beats any pass, so a
|
|
2981
|
+
// writer pass can lift ambiguity but can never bury a hook-observed failure. The append is
|
|
2982
|
+
// fail-open with a stderr note: losing the supplementary observation must never fail the
|
|
2983
|
+
// gate-claim write itself. Decision record: docs/decisions/writer-observed-execution.md.
|
|
2984
|
+
export const WRITER_OBSERVATION_SOURCE = "canonical-writer-execution";
|
|
2985
|
+
const WRITER_LOCK_RETRY_MS = 5;
|
|
2986
|
+
const WRITER_LOCK_MAX_TRIES = 200;
|
|
2987
|
+
const WRITER_LOCK_STALE_MS = 10000;
|
|
2988
|
+
function loadCommandLogChain() {
|
|
2989
|
+
const _req = createRequire(import.meta.url);
|
|
2990
|
+
const chainPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../scripts/lib/command-log-chain.js");
|
|
2991
|
+
return _req(chainPath);
|
|
2992
|
+
}
|
|
2993
|
+
function writerSleepSync(ms) {
|
|
2994
|
+
try {
|
|
2995
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
2996
|
+
}
|
|
2997
|
+
catch { /* SharedArrayBuffer/Atomics unavailable — skip the backoff */ }
|
|
2998
|
+
}
|
|
2999
|
+
function writerAcquireLock(lockFile) {
|
|
3000
|
+
for (let i = 0; i < WRITER_LOCK_MAX_TRIES; i++) {
|
|
3001
|
+
try {
|
|
3002
|
+
const fd = fs.openSync(lockFile, "wx");
|
|
3003
|
+
try {
|
|
3004
|
+
fs.writeSync(fd, String(process.pid));
|
|
3005
|
+
}
|
|
3006
|
+
catch { /* pid is advisory only */ }
|
|
3007
|
+
return fd;
|
|
3008
|
+
}
|
|
3009
|
+
catch (err) {
|
|
3010
|
+
if (!err || err.code !== "EEXIST")
|
|
3011
|
+
return null;
|
|
3012
|
+
try {
|
|
3013
|
+
const st = fs.statSync(lockFile);
|
|
3014
|
+
if (Date.now() - st.mtimeMs > WRITER_LOCK_STALE_MS) {
|
|
3015
|
+
fs.unlinkSync(lockFile);
|
|
3016
|
+
continue;
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
catch {
|
|
3020
|
+
continue;
|
|
3021
|
+
}
|
|
3022
|
+
writerSleepSync(WRITER_LOCK_RETRY_MS);
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
return null;
|
|
3026
|
+
}
|
|
3027
|
+
function writerReadLastChainState(logFile, genesis) {
|
|
3028
|
+
let raw = "";
|
|
3029
|
+
try {
|
|
3030
|
+
raw = fs.readFileSync(logFile, "utf8");
|
|
3031
|
+
}
|
|
3032
|
+
catch {
|
|
3033
|
+
return { seq: -1, hash: genesis };
|
|
3034
|
+
}
|
|
3035
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
3036
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
3037
|
+
let entry;
|
|
3038
|
+
try {
|
|
3039
|
+
entry = JSON.parse(lines[i]);
|
|
3040
|
+
}
|
|
3041
|
+
catch {
|
|
3042
|
+
continue;
|
|
3043
|
+
}
|
|
3044
|
+
if (entry && entry._chain && typeof entry._chain.hash === "string" && typeof entry._chain.seq === "number") {
|
|
3045
|
+
return { seq: entry._chain.seq, hash: entry._chain.hash };
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
return { seq: -1, hash: genesis };
|
|
3049
|
+
}
|
|
3050
|
+
export function appendWriterObservedCommands(dir, observed, timestamp) {
|
|
3051
|
+
if (observed.length === 0)
|
|
3052
|
+
return;
|
|
3053
|
+
try {
|
|
3054
|
+
const chain = loadCommandLogChain();
|
|
3055
|
+
const logFile = path.join(dir, "command-log.jsonl");
|
|
3056
|
+
const lockFile = `${logFile}.lock`;
|
|
3057
|
+
const fd = writerAcquireLock(lockFile);
|
|
3058
|
+
try {
|
|
3059
|
+
let { seq, hash: prevHash } = writerReadLastChainState(logFile, chain.CHAIN_GENESIS);
|
|
3060
|
+
const lines = [];
|
|
3061
|
+
for (const entry of observed) {
|
|
3062
|
+
const record = {
|
|
3063
|
+
command: entry.command,
|
|
3064
|
+
observedResult: entry.exit_code === 0 ? "pass" : "fail",
|
|
3065
|
+
exitCode: entry.exit_code,
|
|
3066
|
+
capturedAt: timestamp,
|
|
3067
|
+
source: WRITER_OBSERVATION_SOURCE,
|
|
3068
|
+
writer: {
|
|
3069
|
+
output_sha256: entry.output_sha256,
|
|
3070
|
+
...(Number.isSafeInteger(entry.test_count) ? { test_count: entry.test_count } : {}),
|
|
3071
|
+
...(entry.execution_proof ? { execution_proof: entry.execution_proof } : {}),
|
|
3072
|
+
},
|
|
3073
|
+
};
|
|
3074
|
+
seq += 1;
|
|
3075
|
+
const hashValue = chain.computeChainHash(prevHash, record);
|
|
3076
|
+
record._chain = { seq, prevHash, hash: hashValue };
|
|
3077
|
+
prevHash = hashValue;
|
|
3078
|
+
lines.push(JSON.stringify(record));
|
|
3079
|
+
}
|
|
3080
|
+
fs.appendFileSync(logFile, `${lines.join("\n")}\n`);
|
|
3081
|
+
}
|
|
3082
|
+
finally {
|
|
3083
|
+
if (fd !== null) {
|
|
3084
|
+
try {
|
|
3085
|
+
fs.closeSync(fd);
|
|
3086
|
+
}
|
|
3087
|
+
catch { /* closed */ }
|
|
3088
|
+
try {
|
|
3089
|
+
fs.unlinkSync(lockFile);
|
|
3090
|
+
}
|
|
3091
|
+
catch { /* removed */ }
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
catch (error) {
|
|
3096
|
+
process.stderr.write(`[record-gate-claim] writer observation append failed (fail-open, capture unaffected): ${error instanceof Error ? error.message : String(error)}\n`);
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
2778
3099
|
function requireObservedCommandRefs(refs, observedCommands, label, requireAll = false) {
|
|
2779
3100
|
const commandRefs = refs.filter((ref) => ref.kind === "command");
|
|
2780
3101
|
if (commandRefs.length === 0)
|
|
@@ -2789,7 +3110,7 @@ function requireObservedCommandRefs(refs, observedCommands, label, requireAll =
|
|
|
2789
3110
|
die(`${label} requires a top-level command evidence ref for every successful observed command`);
|
|
2790
3111
|
}
|
|
2791
3112
|
}
|
|
2792
|
-
function completePassingCriteria(existing, raw, observedCommands, verifiedAt) {
|
|
3113
|
+
function completePassingCriteria(existing, raw, observedCommands, verifiedAt, projectRoot) {
|
|
2793
3114
|
if (raw.length === 0)
|
|
2794
3115
|
die("record-gate-claim requires --criterion-json for a passing tests-evidence claim");
|
|
2795
3116
|
const incoming = raw.map((value) => parseJson(value, "--criterion-json"));
|
|
@@ -2804,21 +3125,24 @@ function completePassingCriteria(existing, raw, observedCommands, verifiedAt) {
|
|
|
2804
3125
|
if (new Set(ids).size !== ids.length || ids.length !== expectedIds.length || ids.some((id) => !expectedIds.includes(id))) {
|
|
2805
3126
|
die(`--criterion-json must cover every declared acceptance criterion exactly once (expected: ${expectedIds.join(", ") || "none"}; received: ${ids.join(", ") || "none"})`);
|
|
2806
3127
|
}
|
|
3128
|
+
const observedCommandNames = new Set(observedCommands.map((observation) => observation.command));
|
|
2807
3129
|
return incoming.map((criterion, index) => {
|
|
2808
3130
|
if (Object.keys(criterion).some((key) => !["id", "status", "evidence_refs"].includes(key)))
|
|
2809
3131
|
die(`criterion ${ids[index]} may update only id, status, and evidence_refs`);
|
|
2810
3132
|
if (criterion.status !== "pass")
|
|
2811
3133
|
die(`criterion ${ids[index]} must have status pass for a passing tests-evidence claim`);
|
|
2812
|
-
const refs = normalizeEvidenceRefs(criterion.evidence_refs, `criterion ${ids[index]} evidence_refs
|
|
3134
|
+
const refs = normalizeEvidenceRefs(criterion.evidence_refs, `criterion ${ids[index]} evidence_refs`, projectRoot);
|
|
2813
3135
|
if (refs.length === 0)
|
|
2814
3136
|
die(`criterion ${ids[index]} requires reviewable evidence_refs`);
|
|
2815
|
-
requireObservedCommandRefs(refs,
|
|
2816
|
-
|
|
3137
|
+
requireObservedCommandRefs(refs, observedCommandNames, `criterion ${ids[index]}`);
|
|
3138
|
+
const referencedCommands = new Set(refs.filter((ref) => ref.kind === "command").map(commandFromEvidenceRef));
|
|
3139
|
+
const criterionObservedCommands = observedCommands.filter((observation) => referencedCommands.has(observation.command));
|
|
3140
|
+
return markCanonicallyObservedCriterion({ ...expectedById.get(ids[index]), status: "pass", evidence_refs: refs, identity_version: 2, verified_at: verifiedAt, _observed_commands: criterionObservedCommands });
|
|
2817
3141
|
});
|
|
2818
3142
|
}
|
|
2819
3143
|
const critiqueStatuses = new Set(WORKFLOW_CRITIQUE_STATUSES);
|
|
2820
3144
|
const safeCritiqueId = /^[a-z][a-z0-9_-]*$/;
|
|
2821
|
-
function normalizeCritiqueLanes(raw) {
|
|
3145
|
+
function normalizeCritiqueLanes(raw, projectRoot) {
|
|
2822
3146
|
if (raw.length === 0)
|
|
2823
3147
|
die("record-critique requires at least one --lane-json");
|
|
2824
3148
|
const lanes = raw.map((value, index) => {
|
|
@@ -2832,7 +3156,7 @@ function normalizeCritiqueLanes(raw) {
|
|
|
2832
3156
|
die(`--lane-json ${index} status must be one of: pass, fail, not_verified`);
|
|
2833
3157
|
if (!hasNonEmptyString(lane.summary))
|
|
2834
3158
|
die(`--lane-json ${index} summary must be non-empty`);
|
|
2835
|
-
const evidenceRefs = normalizeEvidenceRefs(lane.evidence_refs, `--lane-json ${index} evidence_refs
|
|
3159
|
+
const evidenceRefs = normalizeEvidenceRefs(lane.evidence_refs, `--lane-json ${index} evidence_refs`, projectRoot);
|
|
2836
3160
|
if (evidenceRefs.length === 0)
|
|
2837
3161
|
die(`--lane-json ${index} requires structured reviewable evidence_refs`);
|
|
2838
3162
|
return { id: lane.id, status: lane.status, summary: lane.summary, evidence_refs: evidenceRefs };
|
|
@@ -2851,6 +3175,13 @@ function reviewTargetArtifacts(dir, rawPaths, label) {
|
|
|
2851
3175
|
return files.map((file) => ({ file, sha256: createHash("sha256").update(fs.readFileSync(path.join(projectRoot, file))).digest("hex") }));
|
|
2852
3176
|
}
|
|
2853
3177
|
function reviewTargetArtifactsMatch(dir, reviewTarget) {
|
|
3178
|
+
if (reviewTarget && typeof reviewTarget === "object" && !Array.isArray(reviewTarget)) {
|
|
3179
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
3180
|
+
const artifacts = reviewTarget.artifacts;
|
|
3181
|
+
if (Array.isArray(artifacts)) {
|
|
3182
|
+
artifacts.forEach((artifact, index) => rejectNarrativeReference(projectRoot, artifact?.file, `critique review_target artifact ${index}`));
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
2854
3185
|
try {
|
|
2855
3186
|
if (!reviewTarget || typeof reviewTarget !== "object" || Array.isArray(reviewTarget))
|
|
2856
3187
|
return false;
|
|
@@ -2925,7 +3256,7 @@ function critiqueIsCleanAndCurrent(dir, critique) {
|
|
|
2925
3256
|
// BEFORE normalizeCheck runs — see applyGateClaimStamp). This does not weaken new-mint
|
|
2926
3257
|
// enforcement: a NOVEL gate-claim-* id (not already present at all) is still rejected exactly as
|
|
2927
3258
|
// before, and superseding a STAMPED existing id is now rejected too.
|
|
2928
|
-
export function normalizeCheck(raw, allowGateClaimPrefix = false, existingCheckStampById) {
|
|
3259
|
+
export function normalizeCheck(raw, allowGateClaimPrefix = false, existingCheckStampById, projectRoot = process.cwd()) {
|
|
2929
3260
|
const check = { ...raw };
|
|
2930
3261
|
if (!check.id || !check.kind || !check.status || !check.summary)
|
|
2931
3262
|
die("check requires id, kind, status, and summary");
|
|
@@ -2940,18 +3271,21 @@ export function normalizeCheck(raw, allowGateClaimPrefix = false, existingCheckS
|
|
|
2940
3271
|
die("kind must be one of: build, types, lint, test, command, security, diff, browser, runtime, policy, external");
|
|
2941
3272
|
if (!checkStatuses.has(check.status))
|
|
2942
3273
|
die("status must be one of: pass, fail, not_verified, skip");
|
|
3274
|
+
rejectNarrativeReference(projectRoot, check.command, `check ${String(check.id)} command`);
|
|
2943
3275
|
validateRunnableCheckCommand(check, `check ${String(check.id)}`);
|
|
2944
3276
|
if (Array.isArray(check.standard_refs))
|
|
2945
|
-
for (const ref of check.standard_refs)
|
|
3277
|
+
for (const ref of check.standard_refs) {
|
|
2946
3278
|
if (!["junit", "sarif", "coverage", "veritas"].includes(ref.standard))
|
|
2947
3279
|
die("standard must be one of");
|
|
3280
|
+
rejectNarrativeReference(projectRoot, ref.ref, `check ${String(check.id)} standard_ref`);
|
|
3281
|
+
}
|
|
2948
3282
|
if (check.artifact_refs)
|
|
2949
|
-
check.artifact_refs = normalizeEvidenceRefs(check.artifact_refs, "artifact_refs");
|
|
3283
|
+
check.artifact_refs = normalizeEvidenceRefs(check.artifact_refs, "artifact_refs", projectRoot);
|
|
2950
3284
|
if (check.surface_trust_refs)
|
|
2951
|
-
check.surface_trust_refs = normalizeSurfaceRefs(check.surface_trust_refs);
|
|
3285
|
+
check.surface_trust_refs = normalizeSurfaceRefs(check.surface_trust_refs, projectRoot);
|
|
2952
3286
|
return check;
|
|
2953
3287
|
}
|
|
2954
|
-
function normalizeSurfaceRefs(refs) {
|
|
3288
|
+
function normalizeSurfaceRefs(refs, projectRoot) {
|
|
2955
3289
|
if (!Array.isArray(refs))
|
|
2956
3290
|
die("surface_trust_refs must be an array");
|
|
2957
3291
|
// Use the cached @kontourai/surface module for advisory inline validation of referenced
|
|
@@ -2964,6 +3298,7 @@ function normalizeSurfaceRefs(refs) {
|
|
|
2964
3298
|
if (key.toLowerCase().includes("veritas"))
|
|
2965
3299
|
die(`unsupported field in Surface trust ref: ${key}`);
|
|
2966
3300
|
const out = { ...ref };
|
|
3301
|
+
rejectNarrativeReference(projectRoot, out.artifact_ref, "surface trust artifact_ref");
|
|
2967
3302
|
// trust.bundle is the canonical Hachure-aligned artifact kind; TrustReport/Trust Snapshot are legacy aliases
|
|
2968
3303
|
if (!["trust.bundle", "TrustReport", "Trust Snapshot"].includes(out.artifact_kind))
|
|
2969
3304
|
die("artifact_kind must be one of: trust.bundle, TrustReport, Trust Snapshot");
|
|
@@ -3048,17 +3383,19 @@ export function kitIdentityFromBundle(raw, bundleFile) {
|
|
|
3048
3383
|
// 3. Genuinely unknown — never fallback to "builder".
|
|
3049
3384
|
return { claimType: "unknown.trust.bundle", kitId: "unknown", subject: "unknown-kit", gateId: "unknown.trust.bundle" };
|
|
3050
3385
|
}
|
|
3051
|
-
function surfaceCheckFromArtifact(file, index) {
|
|
3052
|
-
|
|
3386
|
+
function surfaceCheckFromArtifact(file, index, projectRoot = process.cwd()) {
|
|
3387
|
+
rejectNarrativeReference(projectRoot, file, `--surface-trust-json ${index}`);
|
|
3388
|
+
const resolvedFile = path.isAbsolute(file) ? file : path.resolve(projectRoot, decodeNarrativeReference(file));
|
|
3389
|
+
const raw = JSON.parse(read(resolvedFile));
|
|
3053
3390
|
const lower = JSON.stringify(raw).toLowerCase();
|
|
3054
3391
|
// Structurally read kit identity from the bundle — never hardcode "builder".
|
|
3055
|
-
const { claimType: bundleClaimType, subject: bundleSubject, gateId: bundleGateId } = kitIdentityFromBundle(raw,
|
|
3392
|
+
const { claimType: bundleClaimType, subject: bundleSubject, gateId: bundleGateId } = kitIdentityFromBundle(raw, resolvedFile);
|
|
3056
3393
|
let ref;
|
|
3057
3394
|
if (lower.includes("provider") && lower.includes("absent")) {
|
|
3058
|
-
ref = { artifact_kind: "trust.bundle", artifact_ref:
|
|
3395
|
+
ref = { artifact_kind: "trust.bundle", artifact_ref: resolvedFile, gate_id: "provider.unavailable", claim_type: bundleClaimType, claim_status: "unknown", subject: bundleSubject, freshness: { status: "unknown", summary: "No trust provider is configured" }, authority: { producer: "unknown", summary: "No trust provider is configured" }, integrity: { status: "unknown", summary: "Unknown" }, status: "not_verified", summary: "No trust provider is configured" };
|
|
3059
3396
|
}
|
|
3060
3397
|
else if (lower.includes("artifact") && lower.includes("absent")) {
|
|
3061
|
-
ref = { artifact_kind: "trust.bundle", artifact_ref:
|
|
3398
|
+
ref = { artifact_kind: "trust.bundle", artifact_ref: resolvedFile, gate_id: "artifact.unavailable", claim_type: bundleClaimType, claim_status: "unknown", subject: bundleSubject, freshness: { status: "unknown", summary: "Artifact not readable" }, authority: { producer: "unknown", summary: "Artifact not readable" }, integrity: { status: "unknown", summary: "Artifact not readable" }, status: "not_verified", summary: "artifact not readable" };
|
|
3062
3399
|
}
|
|
3063
3400
|
else {
|
|
3064
3401
|
const claimStatus = lower.includes("rejected") ? "rejected" : "accepted";
|
|
@@ -3066,7 +3403,7 @@ function surfaceCheckFromArtifact(file, index) {
|
|
|
3066
3403
|
const producer = lower.includes("missing-authority") ? "unknown" : "surface-local";
|
|
3067
3404
|
const integrity = lower.includes("mismatch") ? "mismatch" : "matched";
|
|
3068
3405
|
// Use trust.bundle as the canonical Hachure-aligned artifact_kind for all trust-backed evidence refs
|
|
3069
|
-
ref = { artifact_kind: "trust.bundle", artifact_ref:
|
|
3406
|
+
ref = { artifact_kind: "trust.bundle", artifact_ref: resolvedFile, gate_id: bundleGateId, claim_type: bundleClaimType, claim_status: claimStatus, subject: bundleSubject, freshness: { status: freshness, summary: freshness === "fresh" ? "fresh" : "not currently verifiable" }, authority: { producer, summary: producer === "unknown" ? "missing authority" : "Local Surface trust producer." }, integrity: { status: integrity, summary: integrity === "matched" ? "matched" : "integrity mismatch" } };
|
|
3070
3407
|
ref.status = deriveSurfaceStatus(ref);
|
|
3071
3408
|
ref.summary = ref.status === "pass" ? "accepted" : ref.status === "not_verified" ? "not currently verifiable" : (claimStatus === "rejected" ? "rejected" : producer === "unknown" ? "missing authority" : "integrity mismatch");
|
|
3072
3409
|
}
|
|
@@ -3084,9 +3421,10 @@ function surfaceCheckFromArtifact(file, index) {
|
|
|
3084
3421
|
* not the first thing an agent reaches for.
|
|
3085
3422
|
*/
|
|
3086
3423
|
function validateAcceptanceEvidenceRefs(dir, p) {
|
|
3087
|
-
|
|
3424
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
3425
|
+
const skipRunnabilityGuard = p?.flags.has("skip-evidence-ref-runnability-guard") ?? false;
|
|
3426
|
+
if (skipRunnabilityGuard) {
|
|
3088
3427
|
process.stderr.write("[record-evidence] evidence-ref runnability guard skipped via --skip-evidence-ref-runnability-guard\n");
|
|
3089
|
-
return;
|
|
3090
3428
|
}
|
|
3091
3429
|
const file = path.join(dir, "acceptance.json");
|
|
3092
3430
|
if (!fs.existsSync(file))
|
|
@@ -3098,7 +3436,9 @@ function validateAcceptanceEvidenceRefs(dir, p) {
|
|
|
3098
3436
|
data.criteria.forEach((criterion, index) => {
|
|
3099
3437
|
if (criterion.evidence_refs === undefined)
|
|
3100
3438
|
return;
|
|
3101
|
-
const refs = normalizeEvidenceRefs(criterion.evidence_refs, `acceptance.criteria[${index}].evidence_refs
|
|
3439
|
+
const refs = normalizeEvidenceRefs(criterion.evidence_refs, `acceptance.criteria[${index}].evidence_refs`, projectRoot);
|
|
3440
|
+
if (skipRunnabilityGuard)
|
|
3441
|
+
return;
|
|
3102
3442
|
// #412 (AC8): a kind:"command" ref's command source (excerpt, falling back to url when that
|
|
3103
3443
|
// is where the command string lives) must be a literally runnable shell command, not prose
|
|
3104
3444
|
// describing a manual verification step — reject at RECORD time instead of letting it reach
|
|
@@ -3170,8 +3510,15 @@ function requireStampedClaim(claim, dir) {
|
|
|
3170
3510
|
}
|
|
3171
3511
|
return origin;
|
|
3172
3512
|
}
|
|
3513
|
+
function loadTrustBundleForTrustMachinery(dir) {
|
|
3514
|
+
const bundleFile = path.join(dir, "trust.bundle");
|
|
3515
|
+
if (fs.existsSync(bundleFile) && isNarrativeArtifactContent(fs.readFileSync(bundleFile))) {
|
|
3516
|
+
die(`trust.bundle in ${dir}: ${NARRATIVE_TRUST_ISOLATION_DIAGNOSTIC}; restore a genuine trust.bundle and keep rendered narratives under ${NARRATIVE_NAMESPACE_ROOT}`);
|
|
3517
|
+
}
|
|
3518
|
+
return loadJson(bundleFile);
|
|
3519
|
+
}
|
|
3173
3520
|
function checksFromBundle(dir) {
|
|
3174
|
-
const bundle =
|
|
3521
|
+
const bundle = loadTrustBundleForTrustMachinery(dir);
|
|
3175
3522
|
const allClaims = Array.isArray(bundle.claims) ? bundle.claims : [];
|
|
3176
3523
|
// Validate stamps on every claim up front — any unstamped claim anywhere in the bundle marks
|
|
3177
3524
|
// it pre-supersession, regardless of whether it is check/acceptance/critique-typed.
|
|
@@ -3395,10 +3742,20 @@ function readBundleState(dir) {
|
|
|
3395
3742
|
const acceptance = loadJson(path.join(dir, "acceptance.json"));
|
|
3396
3743
|
const bundledCriteria = criteriaFromBundle(dir);
|
|
3397
3744
|
const acceptedCriteria = Array.isArray(acceptance.criteria) ? acceptance.criteria : [];
|
|
3745
|
+
if (acceptedCriteria.some((criterion) => !hasNonEmptyString(criterion?.id) || !hasNonEmptyString(criterion?.description))) {
|
|
3746
|
+
die("acceptance.json contains a criterion without a non-empty id and description — refusing to rebuild trust.bundle without durable acceptance identity");
|
|
3747
|
+
}
|
|
3748
|
+
const acceptedIds = acceptedCriteria.map((criterion) => String(criterion.id));
|
|
3749
|
+
if (new Set(acceptedIds).size !== acceptedIds.length) {
|
|
3750
|
+
die("acceptance.json criterion ids must be unique — refusing to rebuild trust.bundle with ambiguous acceptance identity");
|
|
3751
|
+
}
|
|
3398
3752
|
const contractSignature = (criteria) => JSON.stringify(criteria.map((criterion) => ({
|
|
3399
3753
|
id: criterion.id ?? null,
|
|
3400
3754
|
description: criterion.description ?? null,
|
|
3401
3755
|
})));
|
|
3756
|
+
// Planning may establish or refine a valid criterion contract after session startup. Once the
|
|
3757
|
+
// signatures agree, the bundle remains authoritative for verified status and observed-command
|
|
3758
|
+
// provenance; artifact status edits alone cannot manufacture completion.
|
|
3402
3759
|
const criteria = acceptedCriteria.length > 0 && contractSignature(acceptedCriteria) !== contractSignature(bundledCriteria)
|
|
3403
3760
|
? acceptedCriteria
|
|
3404
3761
|
: (bundledCriteria.length > 0 ? bundledCriteria : acceptedCriteria);
|
|
@@ -3426,7 +3783,7 @@ function mergeChecksById(existing, incoming) {
|
|
|
3426
3783
|
return [...byId.values()];
|
|
3427
3784
|
}
|
|
3428
3785
|
function critiquesFromBundle(dir) {
|
|
3429
|
-
const bundle =
|
|
3786
|
+
const bundle = loadTrustBundleForTrustMachinery(dir);
|
|
3430
3787
|
if (!Array.isArray(bundle.claims))
|
|
3431
3788
|
return [];
|
|
3432
3789
|
for (const c of bundle.claims)
|
|
@@ -3453,7 +3810,7 @@ function critiquesFromBundle(dir) {
|
|
|
3453
3810
|
});
|
|
3454
3811
|
}
|
|
3455
3812
|
function criteriaFromBundle(dir) {
|
|
3456
|
-
const bundle =
|
|
3813
|
+
const bundle = loadTrustBundleForTrustMachinery(dir);
|
|
3457
3814
|
if (!Array.isArray(bundle.claims))
|
|
3458
3815
|
return [];
|
|
3459
3816
|
for (const claim of bundle.claims)
|
|
@@ -3463,14 +3820,28 @@ function criteriaFromBundle(dir) {
|
|
|
3463
3820
|
.map((claim) => {
|
|
3464
3821
|
const md = claim.metadata && typeof claim.metadata === "object" && !Array.isArray(claim.metadata) ? claim.metadata : {};
|
|
3465
3822
|
const saved = md.criterion && typeof md.criterion === "object" && !Array.isArray(md.criterion) ? md.criterion : {};
|
|
3466
|
-
|
|
3823
|
+
const criterion = {
|
|
3467
3824
|
id: typeof saved.id === "string" ? saved.id : String(claim.subjectId || "").split("/").pop(),
|
|
3468
3825
|
description: typeof saved.description === "string" ? saved.description : (claim.fieldOrBehavior || ""),
|
|
3469
3826
|
status: typeof saved.status === "string" ? saved.status : (claim.value ?? "not_verified"),
|
|
3470
3827
|
evidence_refs: Array.isArray(saved.evidence_refs) ? saved.evidence_refs : [],
|
|
3828
|
+
...(Array.isArray(saved.observed_commands) ? { _observed_commands: saved.observed_commands } : {}),
|
|
3471
3829
|
...(typeof saved.verified_at === "string" ? { verified_at: saved.verified_at } : {}),
|
|
3472
3830
|
...(saved.identity_version === 2 ? { identity_version: 2 } : {}),
|
|
3473
3831
|
};
|
|
3832
|
+
const observedCommands = Array.isArray(saved.observed_commands) ? saved.observed_commands : [];
|
|
3833
|
+
const evidence = Array.isArray(bundle.evidence) ? bundle.evidence.filter((item) => item?.claimId === claim.id) : [];
|
|
3834
|
+
const event = Array.isArray(bundle.events) ? bundle.events.find((item) => item?.claimId === claim.id && item.status === "verified") : null;
|
|
3835
|
+
const evidenceIds = new Set(evidence.map((item) => item.id));
|
|
3836
|
+
const hasCanonicalEvidence = claim.value === "pass"
|
|
3837
|
+
&& claim.status === "verified"
|
|
3838
|
+
&& observedCommands.length > 0
|
|
3839
|
+
&& evidence.length === observedCommands.length
|
|
3840
|
+
&& evidence.every((item) => item.evidenceType === "test_output" && item.passing === true && observedCommands.some((observation) => observation.command === item.execution?.label))
|
|
3841
|
+
&& Array.isArray(event?.evidenceIds)
|
|
3842
|
+
&& event.evidenceIds.length === evidenceIds.size
|
|
3843
|
+
&& event.evidenceIds.every((id) => evidenceIds.has(id));
|
|
3844
|
+
return hasCanonicalEvidence ? markCanonicallyObservedCriterion(criterion) : criterion;
|
|
3474
3845
|
})
|
|
3475
3846
|
.filter((criterion) => typeof criterion.id === "string" && criterion.id.length > 0);
|
|
3476
3847
|
}
|
|
@@ -3508,7 +3879,11 @@ async function recordEvidence(p) {
|
|
|
3508
3879
|
// (not re-read) as _existingState for the compose-safe merge — one readBundleState call.
|
|
3509
3880
|
const _existingState = readBundleState(dir);
|
|
3510
3881
|
const _existingCheckStampById = existingCheckStampMap(_existingState.checks);
|
|
3511
|
-
const
|
|
3882
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
3883
|
+
const _checksRaw = [
|
|
3884
|
+
...opts(p, "check-json").map((v) => normalizeCheck(parseJson(v, "--check-json"), false, _existingCheckStampById, projectRoot)),
|
|
3885
|
+
...opts(p, "surface-trust-json").map((file, index) => surfaceCheckFromArtifact(file, index, projectRoot)),
|
|
3886
|
+
];
|
|
3512
3887
|
// WS8 (AC4, iteration 2): a command-backed check reconciles against CI or fails — it can
|
|
3513
3888
|
// NEVER be waived. Reject --accepted-gap-reason/--waived-by on any check whose evidence
|
|
3514
3889
|
// classifies as test_output (build/types/lint/test/command, and security/browser/runtime
|
|
@@ -3600,6 +3975,7 @@ async function recordCheck(p, commandArgv) {
|
|
|
3600
3975
|
if (commandArgv?.length && commandString)
|
|
3601
3976
|
die("record-check: pass the command via EITHER `-- <command...>` OR --command, not both");
|
|
3602
3977
|
const repoRoot = findRepoRootFromDir(dir);
|
|
3978
|
+
rejectNarrativeReference(repoRoot, commandArgv?.join(" ") ?? commandString, "record-check command");
|
|
3603
3979
|
let displayCommand;
|
|
3604
3980
|
let exitCode;
|
|
3605
3981
|
let stdout = "";
|
|
@@ -3681,7 +4057,7 @@ ${stderr}` : ""}`.trim());
|
|
|
3681
4057
|
status,
|
|
3682
4058
|
summary,
|
|
3683
4059
|
command: displayCommand,
|
|
3684
|
-
}, false, _existingCheckStampById);
|
|
4060
|
+
}, false, _existingCheckStampById, repoRoot);
|
|
3685
4061
|
if (outputSha256)
|
|
3686
4062
|
check._output_sha256 = outputSha256;
|
|
3687
4063
|
const _mergedChecks = mergeChecksById(_existingState.checks, [check]);
|
|
@@ -3792,10 +4168,20 @@ async function recordGateClaim(p) {
|
|
|
3792
4168
|
const observedCommandRaw = opts(p, "observed-command-json");
|
|
3793
4169
|
if (mustRunTests && gateCommands.length === 0)
|
|
3794
4170
|
die("record-gate-claim requires at least one --command for a passing tests-evidence claim");
|
|
3795
|
-
|
|
4171
|
+
// #619: the narrative evidence-ref guards (validateEvidenceRef / normalizeCheck /
|
|
4172
|
+
// completePassingCriteria) need a non-null, location-independent project root that never
|
|
4173
|
+
// dies on a non-canonical session. normalizeObservedCommands still requires the strict
|
|
4174
|
+
// canonical root, but only when there are commands to normalize.
|
|
4175
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
4176
|
+
const canonicalRoot = gateCommands.length > 0 ? canonicalProjectRootForSession(dir) : null;
|
|
4177
|
+
for (const command of gateCommands)
|
|
4178
|
+
rejectNarrativeReference(projectRoot, command, "record-gate-claim command");
|
|
3796
4179
|
const observedCommands = gateCommands.length > 0
|
|
3797
|
-
? await normalizeObservedCommands(gateCommands,
|
|
4180
|
+
? await normalizeObservedCommands(gateCommands, canonicalRoot, mustRunTests, statusVal)
|
|
3798
4181
|
: [];
|
|
4182
|
+
// #634: persist the writer's real executions into the hash-chained command-log so the
|
|
4183
|
+
// capture fold has a deterministic observation even on exit-code-blind hosts.
|
|
4184
|
+
appendWriterObservedCommands(dir, observedCommands, ts);
|
|
3799
4185
|
const observedCommandNames = new Set(observedCommands.map((entry) => entry.command));
|
|
3800
4186
|
let outputSha256 = null;
|
|
3801
4187
|
if (!mustRunTests && gateCommands.length > 1)
|
|
@@ -3826,7 +4212,7 @@ async function recordGateClaim(p) {
|
|
|
3826
4212
|
...(routeReason ? { _gate_claim_route_reason: routeReason } : {}),
|
|
3827
4213
|
};
|
|
3828
4214
|
// Include structured evidence refs if provided
|
|
3829
|
-
const evidenceRefs = opts(p, "evidence-ref-json").map((v) => validateEvidenceRef(parseJson(v, "--evidence-ref-json"), "--evidence-ref-json"));
|
|
4215
|
+
const evidenceRefs = opts(p, "evidence-ref-json").map((v) => validateEvidenceRef(parseJson(v, "--evidence-ref-json"), "--evidence-ref-json", projectRoot));
|
|
3830
4216
|
const producer = expectedGateProducer(exactFlowContext?.flowId ?? activeStep.flowId, activeStep.stepId, targetExpectation.id);
|
|
3831
4217
|
if (statusVal === "pass")
|
|
3832
4218
|
validateReviewableGateEvidence(dir, slug, evidenceRefs, producer, `gate claim ${targetExpectation.id}`);
|
|
@@ -3849,7 +4235,7 @@ async function recordGateClaim(p) {
|
|
|
3849
4235
|
check.command = gateCommand;
|
|
3850
4236
|
if (observedCommands.length > 0)
|
|
3851
4237
|
check._observed_commands = observedCommands;
|
|
3852
|
-
const checkNormalized = normalizeCheck(check, /* allowGateClaimPrefix */ true);
|
|
4238
|
+
const checkNormalized = normalizeCheck(check, /* allowGateClaimPrefix */ true, undefined, projectRoot);
|
|
3853
4239
|
if (outputSha256)
|
|
3854
4240
|
checkNormalized._output_sha256 = outputSha256;
|
|
3855
4241
|
// WS8 (ADR 0020): honor the accepted-gap waiver flags for a gate claim too.
|
|
@@ -3864,7 +4250,7 @@ async function recordGateClaim(p) {
|
|
|
3864
4250
|
// SAME expectation id supersedes the earlier check for that expectation (mergeChecksById); a
|
|
3865
4251
|
// gate claim against a different expectation is additive.
|
|
3866
4252
|
const _existingState = readBundleState(dir);
|
|
3867
|
-
const criteria = mustRunTests ? completePassingCriteria(_existingState.criteria, opts(p, "criterion-json"),
|
|
4253
|
+
const criteria = mustRunTests ? completePassingCriteria(_existingState.criteria, opts(p, "criterion-json"), observedCommands, ts, projectRoot) : _existingState.criteria;
|
|
3868
4254
|
if (mustRunTests) {
|
|
3869
4255
|
const liveCritiques = _existingState.critiques.filter((critique) => !critique.superseded_by);
|
|
3870
4256
|
if (liveCritiques.length === 0 || liveCritiques.some((critique) => !critiqueIsCleanAndCurrent(dir, critique))) {
|
|
@@ -3923,6 +4309,7 @@ async function promote(p) {
|
|
|
3923
4309
|
// repo-relative paths when the ref lives under the repo, so the claim is portable.
|
|
3924
4310
|
const targets = [];
|
|
3925
4311
|
for (const raw of rawPaths) {
|
|
4312
|
+
rejectNarrativeReference(repoRoot, raw, "promote --evidence-path");
|
|
3926
4313
|
const abs = path.isAbsolute(raw) ? raw : path.resolve(repoRoot, raw);
|
|
3927
4314
|
if (!fs.existsSync(abs))
|
|
3928
4315
|
die(`promote --evidence-path does not exist on disk: ${raw} (resolved: ${abs}). Promotion evidence refs must point at durable docs that were actually written.`);
|
|
@@ -4053,21 +4440,27 @@ async function advanceState(p) {
|
|
|
4053
4440
|
}
|
|
4054
4441
|
return 0;
|
|
4055
4442
|
}
|
|
4056
|
-
export function normalizeFinding(raw) {
|
|
4443
|
+
export function normalizeFinding(raw, projectRoot = process.cwd()) {
|
|
4057
4444
|
if (raw.file_refs !== undefined && !Array.isArray(raw.file_refs))
|
|
4058
4445
|
die("file_refs must be an array");
|
|
4446
|
+
for (const ref of raw.file_refs ?? []) {
|
|
4447
|
+
if (typeof ref !== "string")
|
|
4448
|
+
die("file_refs entries must be strings");
|
|
4449
|
+
rejectNarrativeReference(projectRoot, ref, "finding file_ref");
|
|
4450
|
+
}
|
|
4059
4451
|
return raw;
|
|
4060
4452
|
}
|
|
4061
4453
|
async function recordCritique(p) {
|
|
4062
4454
|
const dir = artifactDirFrom(p.positional[0] || die("artifact directory is required"));
|
|
4063
4455
|
const slug = taskSlugFor(dir, opt(p, "task-slug"));
|
|
4456
|
+
const projectRoot = canonicalProjectRootForSession(dir);
|
|
4064
4457
|
const verdict = opt(p, "verdict");
|
|
4065
4458
|
if (!critiqueStatuses.has(verdict))
|
|
4066
4459
|
die("record-critique requires --verdict pass, fail, or not_verified");
|
|
4067
4460
|
const summary = opt(p, "summary");
|
|
4068
4461
|
if (!hasNonEmptyString(summary))
|
|
4069
4462
|
die("record-critique requires --summary");
|
|
4070
|
-
const lanes = normalizeCritiqueLanes(opts(p, "lane-json"));
|
|
4463
|
+
const lanes = normalizeCritiqueLanes(opts(p, "lane-json"), projectRoot);
|
|
4071
4464
|
const reviewArtifacts = reviewTargetArtifacts(dir, opts(p, "artifact-ref"), "record-critique review_target");
|
|
4072
4465
|
if (verdict === "pass" && (lanes.some((lane) => lane.status !== "pass") || reviewArtifacts.length === 0)) {
|
|
4073
4466
|
die("a passing critique requires every lane to pass and at least one local reviewed --artifact-ref");
|
|
@@ -4097,10 +4490,10 @@ async function recordCritique(p) {
|
|
|
4097
4490
|
lanes,
|
|
4098
4491
|
review_target: {
|
|
4099
4492
|
artifacts: reviewArtifacts,
|
|
4100
|
-
workspace_snapshot: captureReviewWorkspaceSnapshot(
|
|
4493
|
+
workspace_snapshot: captureReviewWorkspaceSnapshot(projectRoot, reviewArtifacts.map((artifact) => ({ file: String(artifact.file), sha256: String(artifact.sha256) }))),
|
|
4101
4494
|
},
|
|
4102
4495
|
artifact_refs: reviewArtifacts.map((artifact) => artifact.file),
|
|
4103
|
-
findings: opts(p, "finding-json").map((v) => normalizeFinding(parseJson(v, "--finding-json"))),
|
|
4496
|
+
findings: opts(p, "finding-json").map((v) => normalizeFinding(parseJson(v, "--finding-json"), projectRoot)),
|
|
4104
4497
|
};
|
|
4105
4498
|
if (critique.verdict === "pass" && critique.findings.some((f) => f.status === "open"))
|
|
4106
4499
|
die("required critique must pass");
|
|
@@ -4175,16 +4568,46 @@ async function importCritique(p) {
|
|
|
4175
4568
|
die("required critique must pass");
|
|
4176
4569
|
return result;
|
|
4177
4570
|
}
|
|
4571
|
+
function rejectNarrativeReleaseReferences(projectRoot, value, label, referenceField = false) {
|
|
4572
|
+
if (typeof value === "string") {
|
|
4573
|
+
if (referenceField)
|
|
4574
|
+
rejectNarrativeReference(projectRoot, value, label);
|
|
4575
|
+
return;
|
|
4576
|
+
}
|
|
4577
|
+
if (Array.isArray(value)) {
|
|
4578
|
+
for (const entry of value)
|
|
4579
|
+
rejectNarrativeReleaseReferences(projectRoot, entry, label, referenceField);
|
|
4580
|
+
return;
|
|
4581
|
+
}
|
|
4582
|
+
if (!value || typeof value !== "object")
|
|
4583
|
+
return;
|
|
4584
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
4585
|
+
const isReferenceField = /^(?:refs?|files?|paths?|(?:evidence|artifact|source)_(?:refs?|files?|paths?))$/.test(key);
|
|
4586
|
+
rejectNarrativeReleaseReferences(projectRoot, entry, `${label}.${key}`, isReferenceField);
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4178
4589
|
async function recordRelease(p) {
|
|
4179
4590
|
const dir = artifactDirFrom(p.positional[0] || die("artifact directory is required"));
|
|
4180
4591
|
const slug = taskSlugFor(dir, opt(p, "task-slug"));
|
|
4592
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
4181
4593
|
const decision = opt(p, "decision");
|
|
4182
4594
|
if (!["merge", "release", "deploy", "hold", "rollback_required"].includes(decision))
|
|
4183
4595
|
die("decision must be one of: merge, release, deploy, hold, rollback_required");
|
|
4184
4596
|
const gates = opts(p, "gate-json").map((v) => parseJson(v, "--gate-json"));
|
|
4185
4597
|
if (["merge", "release", "deploy"].includes(decision) && !gates.some((g) => g.name === decision && g.status === "pass"))
|
|
4186
4598
|
die(`positive release decision requires ${decision} gate to pass`);
|
|
4187
|
-
const
|
|
4599
|
+
const evidenceRef = opt(p, "evidence-ref");
|
|
4600
|
+
const rollbackPlan = parseJson(opt(p, "rollback-json", '{"status":"not_required","summary":"Not required.","owner":"maintainer"}'), "--rollback-json");
|
|
4601
|
+
const observabilityPlan = parseJson(opt(p, "observability-json", '{"status":"not_required","summary":"Not required."}'), "--observability-json");
|
|
4602
|
+
const postDeployChecks = opts(p, "post-deploy-json").map((v) => parseJson(v, "--post-deploy-json"));
|
|
4603
|
+
const docs = parseJson(opt(p, "docs-json", '{"status":"not_needed","summary":"Not needed."}'), "--docs-json");
|
|
4604
|
+
rejectNarrativeReference(projectRoot, evidenceRef, "release evidence_ref");
|
|
4605
|
+
rejectNarrativeReleaseReferences(projectRoot, gates, "release gates");
|
|
4606
|
+
rejectNarrativeReleaseReferences(projectRoot, rollbackPlan, "release rollback_plan");
|
|
4607
|
+
rejectNarrativeReleaseReferences(projectRoot, observabilityPlan, "release observability_plan");
|
|
4608
|
+
rejectNarrativeReleaseReferences(projectRoot, postDeployChecks, "release post_deploy_checks");
|
|
4609
|
+
rejectNarrativeReleaseReferences(projectRoot, docs, "release docs");
|
|
4610
|
+
const payload = { ...sidecarBase(slug), decision: opt(p, "decision"), updated_at: opt(p, "timestamp", now()), scope: opt(p, "scope"), evidence_ref: evidenceRef, gates, rollback_plan: rollbackPlan, observability_plan: observabilityPlan, post_deploy_checks: postDeployChecks, docs };
|
|
4188
4611
|
const stateSummary = opt(p, "summary").trim() || `Release readiness recorded for ${decision}.`;
|
|
4189
4612
|
writeJson(path.join(dir, "release.json"), payload);
|
|
4190
4613
|
writeState(dir, slug, "delivered", "release", payload.updated_at, stateSummary);
|
|
@@ -5460,9 +5883,14 @@ function validateLearningPrevention(prevention) {
|
|
|
5460
5883
|
if (!["open", "completed", "accepted", "deferred", "rejected"].includes(value.status))
|
|
5461
5884
|
die("correction.prevention.status must be one of: open, completed, accepted, deferred, rejected");
|
|
5462
5885
|
}
|
|
5463
|
-
export function normalizeLearning(raw, timestamp) {
|
|
5886
|
+
export function normalizeLearning(raw, timestamp, projectRoot = process.cwd()) {
|
|
5464
5887
|
if (!Array.isArray(raw.source_refs))
|
|
5465
5888
|
die("source_refs must be an array");
|
|
5889
|
+
for (const ref of raw.source_refs) {
|
|
5890
|
+
if (typeof ref !== "string")
|
|
5891
|
+
die("source_refs entries must be strings");
|
|
5892
|
+
rejectNarrativeReference(projectRoot, ref, "learning source_ref");
|
|
5893
|
+
}
|
|
5466
5894
|
if (!Array.isArray(raw.facts))
|
|
5467
5895
|
die("facts must be an array");
|
|
5468
5896
|
if (!Array.isArray(raw.routing))
|
|
@@ -5476,7 +5904,8 @@ async function recordLearning(p) {
|
|
|
5476
5904
|
const dir = artifactDirFrom(p.positional[0] || die("artifact directory is required"));
|
|
5477
5905
|
const slug = taskSlugFor(dir, opt(p, "task-slug"));
|
|
5478
5906
|
const timestamp = opt(p, "timestamp", now());
|
|
5479
|
-
const
|
|
5907
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
5908
|
+
const records = opts(p, "record-json").map((v) => normalizeLearning(parseJson(v, "--record-json"), timestamp, projectRoot));
|
|
5480
5909
|
const status = opt(p, "status", "learned");
|
|
5481
5910
|
if (status === "learned" && records.some((r) => r.routing.some((x) => x.status === "open")))
|
|
5482
5911
|
die("learning status learned cannot have open routing");
|
|
@@ -5498,7 +5927,7 @@ function evidenceClean(dir) {
|
|
|
5498
5927
|
// legacy (pre-bundle-era) sessions that never wrote a trust.bundle at all — unrelated to origin
|
|
5499
5928
|
// stamping. When a trust.bundle IS present, every claim must be stamped (requireStampedClaim);
|
|
5500
5929
|
// there is no claimType-derivation fallback for an unstamped claim (#268/#344).
|
|
5501
|
-
const bundle =
|
|
5930
|
+
const bundle = loadTrustBundleForTrustMachinery(dir);
|
|
5502
5931
|
if (Array.isArray(bundle.claims)) {
|
|
5503
5932
|
for (const c of bundle.claims)
|
|
5504
5933
|
requireStampedClaim(c, dir);
|
|
@@ -5520,7 +5949,7 @@ function evidenceClean(dir) {
|
|
|
5520
5949
|
}
|
|
5521
5950
|
function critiqueClean(dir) {
|
|
5522
5951
|
// trust.bundle is the sole critique artifact. Legacy critique.json must not influence gates.
|
|
5523
|
-
const bundle =
|
|
5952
|
+
const bundle = loadTrustBundleForTrustMachinery(dir);
|
|
5524
5953
|
if (Array.isArray(bundle.claims)) {
|
|
5525
5954
|
for (const c of bundle.claims)
|
|
5526
5955
|
requireStampedClaim(c, dir);
|
|
@@ -5545,11 +5974,17 @@ function assertExistingLearningValid(dir) {
|
|
|
5545
5974
|
if (!fs.existsSync(file))
|
|
5546
5975
|
return;
|
|
5547
5976
|
const data = loadJson(file);
|
|
5977
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
5548
5978
|
if (!Array.isArray(data.records))
|
|
5549
5979
|
die("learning records must be an array");
|
|
5550
5980
|
for (const record of data.records) {
|
|
5551
5981
|
if (!Array.isArray(record.source_refs))
|
|
5552
5982
|
die("source_refs must be an array");
|
|
5983
|
+
for (const ref of record.source_refs) {
|
|
5984
|
+
if (typeof ref !== "string")
|
|
5985
|
+
die("source_refs entries must be strings");
|
|
5986
|
+
rejectNarrativeReference(projectRoot, ref, "learning source_ref");
|
|
5987
|
+
}
|
|
5553
5988
|
if (!Array.isArray(record.facts))
|
|
5554
5989
|
die("facts must be an array");
|
|
5555
5990
|
if (!Array.isArray(record.routing))
|
|
@@ -5563,6 +5998,7 @@ async function dogfoodPass(p) {
|
|
|
5563
5998
|
const root = opt(p, "artifact-root") ? path.resolve(opt(p, "artifact-root")) : defaultArtifactRootForRead();
|
|
5564
5999
|
const dir = path.resolve(opt(p, "artifact-dir") || currentDir(root) || "");
|
|
5565
6000
|
requireArtifactDirUnderRoot(dir, root);
|
|
6001
|
+
const projectRoot = narrativeGuardRoot(dir);
|
|
5566
6002
|
assertExistingLearningValid(dir);
|
|
5567
6003
|
const verdict = opt(p, "verdict");
|
|
5568
6004
|
if (verdict === "pass") {
|
|
@@ -5575,7 +6011,7 @@ async function dogfoodPass(p) {
|
|
|
5575
6011
|
// trust.bundle does not yet exist (loadJson falls back to {}), exactly as
|
|
5576
6012
|
// recordEvidence/recordCheck rely on.
|
|
5577
6013
|
const _dogfoodExistingCheckStampById = existingCheckStampMap(readBundleState(dir).checks);
|
|
5578
|
-
const checks = opts(p, "check-json").map((v) => normalizeCheck(parseJson(v, "--check-json"), false, _dogfoodExistingCheckStampById));
|
|
6014
|
+
const checks = opts(p, "check-json").map((v) => normalizeCheck(parseJson(v, "--check-json"), false, _dogfoodExistingCheckStampById, projectRoot));
|
|
5579
6015
|
if (checks.some((c) => c.status !== "pass" && c.status !== "skip"))
|
|
5580
6016
|
die("clean evidence requires all non-skipped checks to pass");
|
|
5581
6017
|
// Phase 4c: evidence check reads from trust.bundle (sole verification artifact); legacy evidence.json fallback in evidenceClean.
|
|
@@ -5591,7 +6027,7 @@ async function dogfoodPass(p) {
|
|
|
5591
6027
|
if (p.flags.has("require-critique") || opt(p, "release-decision")) {
|
|
5592
6028
|
const newCritiqueVerdict = opt(p, "critique-verdict", "pass");
|
|
5593
6029
|
for (const value of opts(p, "finding-json"))
|
|
5594
|
-
normalizeFinding(parseJson(value, "--finding-json"));
|
|
6030
|
+
normalizeFinding(parseJson(value, "--finding-json"), projectRoot);
|
|
5595
6031
|
if (newCritiqueVerdict !== "pass")
|
|
5596
6032
|
die(opt(p, "release-decision") ? "requires clean critique" : "requires clean critique before recording pass evidence");
|
|
5597
6033
|
if (!opt(p, "critique-id") && !critiqueClean(dir))
|
|
@@ -5600,7 +6036,7 @@ async function dogfoodPass(p) {
|
|
|
5600
6036
|
die(opt(p, "release-decision") ? "requires clean critique" : "requires clean critique before recording pass evidence");
|
|
5601
6037
|
}
|
|
5602
6038
|
}
|
|
5603
|
-
const learningRecords = opts(p, "learning-record-json").map((v) => normalizeLearning(parseJson(v, "--learning-record-json"), opt(p, "timestamp", now())));
|
|
6039
|
+
const learningRecords = opts(p, "learning-record-json").map((v) => normalizeLearning(parseJson(v, "--learning-record-json"), opt(p, "timestamp", now()), projectRoot));
|
|
5604
6040
|
if (opt(p, "learning-status") === "learned" && learningRecords.some((r) => r.routing.some((x) => x.status === "open")))
|
|
5605
6041
|
die("learned status cannot have open learning routing");
|
|
5606
6042
|
if (opt(p, "learning-status") === "learned" && learningRecords.some((r) => r.correction === undefined))
|
|
@@ -5710,7 +6146,7 @@ export function gateAdvisoryFix(calibration, claimId, answerStatus) {
|
|
|
5710
6146
|
return `Ensure \`workflow-sidecar record-evidence\` writes a definitive event for claim \`${claimId}\` (currently \`${s}\`) before \`stop-goal-fit\` evaluates. The gate had no resolved evidence to act on.`;
|
|
5711
6147
|
}
|
|
5712
6148
|
/**
|
|
5713
|
-
* Build a schema-conformant InquiryRecord for
|
|
6149
|
+
* Build a schema-conformant InquiryRecord for @kontourai/surface's canonical InquiryRecord schema.
|
|
5714
6150
|
* Strips Surface-internal fields (identityLinkIds, transitiveRuleIds) from
|
|
5715
6151
|
* resolutionPath that are valid in the TS type but not in the JSON schema.
|
|
5716
6152
|
* Sets answer.value to the gate-review value-add: { calibration, advisoryFix, gateFired, sessionSlug }.
|
|
@@ -5888,16 +6324,18 @@ async function gateReview(p) {
|
|
|
5888
6324
|
: [];
|
|
5889
6325
|
}
|
|
5890
6326
|
const records = buildGateInquiryRecords(bundle, blockSignal, slug, expectedCriterionIds, surface);
|
|
5891
|
-
// Validate each record against the
|
|
5892
|
-
const validator = getHachureInquiryRecordValidator();
|
|
6327
|
+
// Validate each record against the canonical InquiryRecord schema via Surface (fail-open)
|
|
5893
6328
|
let schemaValid = true;
|
|
5894
6329
|
const validationErrors = [];
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
6330
|
+
const inquiryValidator = surface?.validateInquiryRecord;
|
|
6331
|
+
if (typeof inquiryValidator === "function") {
|
|
6332
|
+
for (const record of records) {
|
|
6333
|
+
try {
|
|
6334
|
+
inquiryValidator(record);
|
|
6335
|
+
}
|
|
6336
|
+
catch (err) {
|
|
5899
6337
|
schemaValid = false;
|
|
5900
|
-
validationErrors.push(
|
|
6338
|
+
validationErrors.push(`${record["id"] ?? "?"}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5901
6339
|
}
|
|
5902
6340
|
}
|
|
5903
6341
|
}
|
|
@@ -5916,7 +6354,7 @@ async function gateReview(p) {
|
|
|
5916
6354
|
.filter(([, n]) => n > 0)
|
|
5917
6355
|
.map(([k, n]) => `${k}=${n}`)
|
|
5918
6356
|
.join(", ");
|
|
5919
|
-
const schemaTag =
|
|
6357
|
+
const schemaTag = typeof inquiryValidator === "function" ? (schemaValid ? " schema:valid" : " schema:INVALID") : " schema:unavailable";
|
|
5920
6358
|
console.log(`gate-review: ${records.length} InquiryRecord(s) [${summary}]${schemaTag} → ${outputPath}`);
|
|
5921
6359
|
return 0;
|
|
5922
6360
|
}
|
|
@@ -6432,14 +6870,6 @@ async function liveness(p) {
|
|
|
6432
6870
|
die("liveness action must be one of: claim | heartbeat | release | status | whoami | verdict");
|
|
6433
6871
|
return 1;
|
|
6434
6872
|
}
|
|
6435
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6436
|
-
// ─── Claim Lookup — pure helper (promotable to Surface #171) ─────────────────
|
|
6437
|
-
// buildClaimExplanation + its types are extracted to ./sidecar-claim-explain.ts
|
|
6438
|
-
// (ops#22): a PURE projection (report + bundle + id in, structured explanation out)
|
|
6439
|
-
// with no fs/CLI/shared state, unit-tested in isolation. Re-exported here so the
|
|
6440
|
-
// library facade (src/index.ts) and the IO `claimLookup` handler below are unchanged.
|
|
6441
|
-
export { buildClaimExplanation } from "./sidecar-claim-explain.js";
|
|
6442
|
-
import { buildClaimExplanation } from "./sidecar-claim-explain.js";
|
|
6443
6873
|
/**
|
|
6444
6874
|
* claim <id> <dir>
|
|
6445
6875
|
*
|
|
@@ -6476,27 +6906,16 @@ Available claim ids:
|
|
|
6476
6906
|
}
|
|
6477
6907
|
// Load Surface via tryLoadSurface() (ESM, cached, fail-open pattern)
|
|
6478
6908
|
const surface = await tryLoadSurface();
|
|
6479
|
-
if (!surface || typeof surface.buildTrustReport !== "function" || typeof surface.
|
|
6480
|
-
process.stderr.write(`[claim] @kontourai/surface unavailable or missing buildTrustReport/
|
|
6909
|
+
if (!surface || typeof surface.buildTrustReport !== "function" || typeof surface.explainClaim !== "function") {
|
|
6910
|
+
process.stderr.write(`[claim] @kontourai/surface unavailable or missing buildTrustReport/explainClaim (needs >=2.10)
|
|
6481
6911
|
`);
|
|
6482
6912
|
return 0; // fail-open, consistent with gate-review pattern
|
|
6483
6913
|
}
|
|
6484
|
-
// Build TrustReport
|
|
6914
|
+
// Build TrustReport, then the structured explanation — Surface's explainClaim
|
|
6915
|
+
// (#171 lift) composes the derivation drilldown internally, fail-soft, exactly
|
|
6916
|
+
// as the retired local helper + caller-side enrichment did.
|
|
6485
6917
|
const report = surface.buildTrustReport(bundle);
|
|
6486
|
-
|
|
6487
|
-
const explanation = buildClaimExplanation(report, bundle, claimId);
|
|
6488
|
-
// Enrich the why.directInputs/leafClaims/diagnostics from the drilldown
|
|
6489
|
-
try {
|
|
6490
|
-
const drilldown = surface.buildDerivationDrilldown(report, claimId);
|
|
6491
|
-
if (drilldown) {
|
|
6492
|
-
explanation.why.directInputs = Array.isArray(drilldown.directInputs) ? drilldown.directInputs : [];
|
|
6493
|
-
explanation.why.leafClaims = Array.isArray(drilldown.leafClaims) ? drilldown.leafClaims : [];
|
|
6494
|
-
explanation.why.diagnostics = Array.isArray(drilldown.diagnostics) ? drilldown.diagnostics : [];
|
|
6495
|
-
}
|
|
6496
|
-
}
|
|
6497
|
-
catch {
|
|
6498
|
-
// buildDerivationDrilldown threw (e.g. claim not in report) — proceed without drilldown
|
|
6499
|
-
}
|
|
6918
|
+
const explanation = surface.explainClaim(report, claimId);
|
|
6500
6919
|
if (p.flags.has("json")) {
|
|
6501
6920
|
console.log(JSON.stringify(explanation, null, 2));
|
|
6502
6921
|
return 0;
|