@kontourai/flow-agents 3.2.0 → 3.4.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/add-to-project.yml +15 -0
- package/.github/workflows/ci.yml +173 -0
- package/CHANGELOG.md +54 -0
- package/CONTEXT.md +5 -1
- package/README.md +19 -8
- package/build/src/builder-flow-run-adapter.d.ts +80 -0
- package/build/src/builder-flow-run-adapter.js +241 -0
- package/build/src/builder-flow-runtime.d.ts +16 -0
- package/build/src/builder-flow-runtime.js +290 -0
- package/build/src/cli/assignment-provider.js +10 -1
- package/build/src/cli/builder-run.d.ts +1 -0
- package/build/src/cli/builder-run.js +27 -0
- package/build/src/cli/effective-backlog-settings.js +70 -2
- package/build/src/cli/init.d.ts +34 -0
- package/build/src/cli/init.js +341 -61
- package/build/src/cli/kit.js +55 -12
- package/build/src/cli/pull-work-provider.js +346 -5
- package/build/src/cli/skill-drift-check.d.ts +1 -0
- package/build/src/cli/skill-drift-check.js +165 -0
- package/build/src/cli/telemetry-doctor.d.ts +37 -0
- package/build/src/cli/telemetry-doctor.js +53 -6
- package/build/src/cli/validate-hook-influence.js +37 -7
- package/build/src/cli/workflow-artifact-cleanup-audit.js +418 -11
- package/build/src/cli/workflow-sidecar.d.ts +310 -1
- package/build/src/cli/workflow-sidecar.js +1914 -126
- package/build/src/cli.js +5 -0
- package/build/src/flow-kit/validate.d.ts +54 -34
- package/build/src/flow-kit/validate.js +237 -26
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/lib/console-connect-options.d.ts +97 -0
- package/build/src/lib/console-connect-options.js +199 -0
- package/build/src/lib/console-telemetry-validate.d.ts +49 -0
- package/build/src/lib/console-telemetry-validate.js +91 -0
- package/build/src/lib/flow-resolver.d.ts +54 -1
- package/build/src/lib/flow-resolver.js +112 -5
- package/build/src/lib/fs.d.ts +17 -0
- package/build/src/lib/fs.js +172 -0
- package/build/src/lib/local-artifact-root.d.ts +44 -1
- package/build/src/lib/local-artifact-root.js +131 -3
- package/build/src/runtime-adapters.d.ts +39 -3
- package/build/src/runtime-adapters.js +77 -31
- package/build/src/tools/build-universal-bundles.js +40 -2
- package/build/src/tools/codex-agent-routing.d.ts +2 -0
- package/build/src/tools/codex-agent-routing.js +49 -0
- package/build/src/tools/generate-context-map.js +1 -0
- package/build/src/tools/validate-source-tree.js +30 -3
- package/context/contracts/artifact-contract.md +16 -2
- package/context/scripts/hooks/lib/kit-catalog.js +235 -0
- package/context/scripts/hooks/lib/runnable-command.js +177 -0
- package/context/scripts/hooks/stop-goal-fit.js +278 -48
- package/context/scripts/hooks/workflow-steering.js +194 -22
- package/context/scripts/package.json +3 -0
- package/context/scripts/telemetry/install-console-config.sh +25 -4
- package/context/scripts/telemetry/lib/config.sh +102 -12
- package/context/scripts/telemetry/lib/pricing.sh +50 -0
- package/context/scripts/telemetry/lib/session.sh +3 -0
- package/context/scripts/telemetry/lib/transport.sh +87 -0
- package/context/scripts/telemetry/lib/usage.sh +205 -4
- package/context/scripts/telemetry/telemetry.conf +6 -0
- package/context/scripts/telemetry/telemetry.sh +48 -0
- package/context/settings/workspace-backlog-provider-settings.example.json +48 -0
- package/docs/agent-usage-feedback-loop.md +35 -0
- package/docs/architecture-engine-and-kits.md +110 -0
- package/docs/context-map.md +2 -0
- package/docs/coordination-guide.md +370 -0
- package/docs/decisions/agent-coordination.md +26 -9
- package/docs/decisions/embeddable-engine.md +152 -0
- package/docs/decisions/index.md +5 -3
- package/docs/decisions/trust-ledger-retention.md +88 -0
- package/docs/decisions/trust-reconcile.md +42 -9
- package/docs/decisions/workflow-enforcement.md +31 -9
- package/docs/fixture-ownership.md +6 -2
- package/docs/implementing-trust-reconciliation.md +129 -0
- package/docs/index.md +23 -9
- package/docs/integrations/flow-agents-console.md +275 -0
- package/docs/integrations/index.md +4 -0
- package/docs/kit-authoring-guide.md +52 -21
- package/docs/spec/builder-flow-runtime.md +80 -0
- package/docs/spec/runtime-hook-surface.md +45 -1
- package/docs/specs/economics-record-contract.md +270 -0
- package/docs/specs/harness-capability-matrix.md +74 -0
- package/docs/specs/learning-review-proposals-contract.md +340 -0
- package/docs/specs/routing-efficiency-review.md +59 -0
- package/docs/verifiable-trust.md +74 -25
- package/docs/workflow-artifact-lifecycle.md +38 -1
- package/docs/workflow-usage-guide.md +10 -0
- package/evals/acceptance/prove-capture-teeth.sh +132 -0
- package/evals/ci/antigaming-suite.sh +2 -0
- package/evals/ci/run-baseline.sh +78 -4
- package/evals/fixtures/economics/acceptance.json +12 -0
- package/evals/fixtures/economics/agents/tool-worker-1/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-2/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-3/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-4/events.jsonl +1 -0
- package/evals/fixtures/economics/agents/tool-worker-5/events.jsonl +2 -0
- package/evals/fixtures/economics/critique.json +22 -0
- package/evals/fixtures/economics/expected-record.json +71 -0
- package/evals/fixtures/economics/session-usage-event.json +1 -0
- package/evals/fixtures/economics/state.json +11 -0
- package/evals/fixtures/economics/transcript.jsonl +3 -0
- package/evals/fixtures/hook-influence/cases.json +7 -7
- package/evals/fixtures/learning-review-proposals/balanced/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/economics.jsonl +5 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-1/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-2/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-3/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-4/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-5/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.json +30 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.md +66 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-5/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-6/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/repeat-window/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/under-threshold/economics.jsonl +3 -0
- package/evals/fixtures/reconcile-preflight/disputed-critique-unsuperseded.json +48 -0
- package/evals/fixtures/reconcile-preflight/standalone-disputed-session-local.json +59 -0
- package/evals/fixtures/telemetry/usage-transcript-sample.jsonl +4 -0
- package/evals/fixtures/trust-reconcile-exploits/mcp-degrade.json +42 -0
- package/evals/integration/test_builder_entry_enforcement.sh +241 -0
- package/evals/integration/test_builder_step_producers.sh +18 -10
- package/evals/integration/test_bundle_install.sh +172 -0
- package/evals/integration/test_checkpoint_signing.sh +10 -2
- package/evals/integration/test_ci_actor_identity.sh +221 -0
- package/evals/integration/test_console_tenant_isolation.sh +167 -0
- package/evals/integration/test_critique_supersession_roundtrip.sh +4 -1
- package/evals/integration/test_dual_emit_flow_step.sh +10 -4
- package/evals/integration/test_economics_record.sh +674 -0
- package/evals/integration/test_effective_backlog_settings.sh +1 -1
- package/evals/integration/test_evidence_capture_hook.sh +17 -2
- package/evals/integration/test_exemption_usage_review.sh +198 -0
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +83 -0
- package/evals/integration/test_flowdef_session_activation.sh +0 -1
- package/evals/integration/test_flowdef_session_history_preservation.sh +13 -3
- package/evals/integration/test_gate_lockdown.sh +7 -0
- package/evals/integration/test_gate_review_inquiry_records.sh +9 -1
- package/evals/integration/test_goal_fit_hook.sh +2031 -0
- package/evals/integration/test_hook_category_behaviors.sh +8 -1
- package/evals/integration/test_hook_influence_cases.sh +25 -1
- package/evals/integration/test_install_merge.sh +227 -2
- package/evals/integration/test_kit_conformance_levels.sh +6 -6
- package/evals/integration/test_learning_review_proposals.sh +329 -0
- package/evals/integration/test_liveness_conflict_injection.sh +26 -22
- package/evals/integration/test_liveness_console_relay.sh +166 -0
- package/evals/integration/test_liveness_heartbeat.sh +17 -17
- package/evals/integration/test_liveness_worktree_root.sh +575 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +6 -1
- package/evals/integration/test_publish_delivery.sh +389 -2
- package/evals/integration/test_pull_work_board.sh +200 -0
- package/evals/integration/test_pull_work_provider.sh +1 -1
- package/evals/integration/test_reconcile_preflight.sh +304 -0
- package/evals/integration/test_record_check.sh +378 -0
- package/evals/integration/test_routing_efficiency.sh +71 -0
- package/evals/integration/test_runtime_adapter_activation.sh +28 -0
- package/evals/integration/test_session_resume_roundtrip.sh +16 -19
- package/evals/integration/test_skill_drift_check.sh +870 -0
- package/evals/integration/test_takeover_protocol.sh +340 -0
- package/evals/integration/test_telemetry.sh +445 -0
- package/evals/integration/test_telemetry_doctor.sh +66 -0
- package/evals/integration/test_telemetry_usage_pipeline.sh +228 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +121 -13
- package/evals/integration/test_trust_reconcile_trailer_diagnostic.sh +247 -0
- package/evals/integration/test_usage_cost.sh +61 -0
- package/evals/integration/test_verify_hold.sh +910 -0
- package/evals/integration/test_veritas_governance_kit.sh +257 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +575 -3
- package/evals/integration/test_workflow_sidecar_writer.sh +1395 -0
- package/evals/integration/test_workflow_steering_hook.sh +157 -16
- package/evals/integration/test_workspace_settings.sh +176 -0
- package/evals/lib/env.sh +26 -0
- package/evals/lib/node.sh +8 -0
- package/evals/run.sh +37 -0
- package/evals/static/test_ci_integration_coverage.sh +115 -0
- package/evals/static/test_declared_scope_forms_documented.sh +114 -0
- package/evals/static/test_universal_bundles.sh +34 -0
- package/evals/static/test_validate_source_kit_asset_scope.sh +259 -0
- package/evals/static/test_workflow_skills.sh +1 -1
- package/kits/builder/flows/build.flow.json +9 -18
- package/kits/builder/flows/publish-learn.flow.json +5 -1
- package/kits/builder/kit.json +120 -0
- package/kits/builder/skills/continue-work/SKILL.md +2 -0
- package/kits/builder/skills/deliver/SKILL.md +115 -0
- package/kits/builder/skills/evidence-gate/SKILL.md +12 -0
- package/kits/builder/skills/execute-plan/SKILL.md +9 -0
- package/kits/builder/skills/learning-review/SKILL.md +51 -0
- package/kits/builder/skills/plan-work/SKILL.md +17 -20
- package/kits/builder/skills/pull-work/SKILL.md +33 -2
- package/kits/builder/skills/release-readiness/SKILL.md +12 -0
- package/kits/knowledge/kit.json +9 -0
- package/kits/veritas-governance/docs/README.md +113 -7
- package/kits/veritas-governance/fixtures/exemption/approved.trust-bundle.json +74 -0
- package/kits/veritas-governance/fixtures/exemption/not-approved.trust-bundle.json +74 -0
- package/kits/veritas-governance/fixtures/exemption-review/mixed-fresh-stale.DECLARED.json +14 -0
- package/kits/veritas-governance/flows/exemption-issuance.flow.json +35 -0
- package/kits/veritas-governance/kit.json +19 -0
- package/kits/veritas-governance/skills/exemption-usage-review/SKILL.md +128 -0
- package/kits/veritas-governance/skills/exemption-usage-review/review-exemptions.mjs +231 -0
- package/package.json +2 -2
- package/packaging/manifest.json +29 -0
- package/schemas/backlog-provider-settings.schema.json +13 -0
- package/schemas/workflow-state.schema.json +44 -0
- package/scripts/README.md +4 -0
- package/scripts/check-content-boundary.cjs +8 -1
- package/scripts/ci/trust-reconcile.js +214 -253
- package/scripts/hooks/codex-hook-adapter.js +77 -2
- package/scripts/hooks/evidence-capture.js +38 -5
- package/scripts/hooks/lib/actor-identity.js +82 -0
- package/scripts/hooks/lib/codex-exit-code.js +316 -0
- package/scripts/hooks/lib/kit-catalog.js +235 -0
- package/scripts/hooks/lib/liveness-write.js +28 -1
- package/scripts/hooks/lib/local-artifact-paths.js +97 -1
- package/scripts/hooks/lib/runnable-command.js +177 -0
- package/scripts/hooks/lib/skill-drift.js +350 -0
- package/scripts/hooks/stop-goal-fit.js +278 -48
- package/scripts/hooks/workflow-steering.js +194 -22
- package/scripts/install-codex-home.sh +97 -47
- package/scripts/install-merge.js +72 -14
- package/scripts/install-owned-files.js +178 -0
- package/scripts/lib/reconcile-shape.js +381 -0
- package/scripts/liveness/relay.sh +84 -0
- package/scripts/telemetry/economics-record.schema.json +145 -0
- package/scripts/telemetry/economics-record.sh +331 -0
- package/scripts/telemetry/install-console-config.sh +25 -4
- package/scripts/telemetry/learning-review-decide.sh +124 -0
- package/scripts/telemetry/learning-review-proposals.schema.json +161 -0
- package/scripts/telemetry/learning-review-proposals.sh +484 -0
- package/scripts/telemetry/lib/config.sh +102 -12
- package/scripts/telemetry/lib/pricing.sh +14 -6
- package/scripts/telemetry/lib/session.sh +3 -0
- package/scripts/telemetry/lib/transport.sh +133 -15
- package/scripts/telemetry/lib/usage.sh +121 -28
- package/scripts/telemetry/routing-efficiency.sh +0 -0
- package/scripts/telemetry/telemetry.conf +6 -0
- package/scripts/telemetry/telemetry.sh +48 -0
- package/src/builder-flow-run-adapter.ts +357 -0
- package/src/builder-flow-runtime.ts +348 -0
- package/src/cli/assignment-provider.ts +12 -1
- package/src/cli/builder-flow-run-adapter.test.mjs +495 -0
- package/src/cli/builder-flow-runtime.test.mjs +213 -0
- package/src/cli/builder-run.ts +28 -0
- package/src/cli/codex-agent-routing.test.mjs +44 -0
- package/src/cli/codex-exit-code.test.mjs +207 -0
- package/src/cli/console-connect-options.test.mjs +329 -0
- package/src/cli/console-telemetry-validate.test.mjs +157 -0
- package/src/cli/effective-backlog-settings.ts +68 -2
- package/src/cli/flow-resolver-composition.test.mjs +72 -0
- package/src/cli/init.test.mjs +161 -0
- package/src/cli/init.ts +407 -62
- package/src/cli/kit-metadata-security.test.mjs +443 -0
- package/src/cli/kit.ts +50 -12
- package/src/cli/pull-work-provider.ts +377 -3
- package/src/cli/sidecar-pure-helpers.test.mjs +64 -0
- package/src/cli/skill-drift-check.ts +196 -0
- package/src/cli/telemetry-doctor.test.mjs +53 -0
- package/src/cli/telemetry-doctor.ts +50 -7
- package/src/cli/validate-hook-influence.ts +37 -6
- package/src/cli/workflow-artifact-cleanup-audit.ts +483 -10
- package/src/cli/workflow-sidecar.ts +1980 -119
- package/src/cli.ts +5 -0
- package/src/flow-kit/validate.ts +277 -38
- package/src/index.ts +19 -0
- package/src/lib/console-connect-options.ts +261 -0
- package/src/lib/console-telemetry-validate.ts +88 -0
- package/src/lib/flow-resolver.ts +117 -4
- package/src/lib/fs.ts +160 -0
- package/src/lib/local-artifact-root.ts +129 -3
- package/src/runtime-adapters.ts +113 -33
- package/src/tools/build-universal-bundles.ts +36 -2
- package/src/tools/codex-agent-routing.ts +48 -0
- package/src/tools/generate-context-map.ts +1 -0
- package/src/tools/validate-source-tree.ts +29 -3
|
@@ -15,7 +15,7 @@ pass() { echo " ✓ $1"; }
|
|
|
15
15
|
fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
16
16
|
|
|
17
17
|
json_value() {
|
|
18
|
-
node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(0,"utf8")); for (const part of process.argv[1].split(".")) cur=Array.isArray(cur) ? cur[Number(part)] : cur[part]; console.log(cur);' "$1"
|
|
18
|
+
NO_COLOR=1 FORCE_COLOR=0 node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(0,"utf8")); for (const part of process.argv[1].split(".")) cur=Array.isArray(cur) ? cur[Number(part)] : cur[part]; console.log(cur);' "$1"
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
echo "=== Effective Backlog Settings ==="
|
|
@@ -56,6 +56,8 @@ echo "Part A: deterministic capture"
|
|
|
56
56
|
printf '{"hook_event_name":"PostToolUse","tool_name":"Bash","cwd":"%s","tool_input":{"command":"npm test"},"tool_response":{"exitCode":0,"stdout":"ok"}}' "$A" | capture
|
|
57
57
|
printf '{"hook_event_name":"PostToolUse","tool_name":"Bash","cwd":"%s","tool_input":{"command":"npm run lint"},"error":"command failed"}' "$A" | capture
|
|
58
58
|
printf '{"hook_event_name":"PostToolUse","tool_name":"Bash","cwd":"%s","tool_input":{"command":"make build"},"tool_response":{"exit_code":2}}' "$A" | capture
|
|
59
|
+
# #470 rule-3 default: no exit code, no error, no stderr → ambiguous (never pass).
|
|
60
|
+
printf '{"hook_event_name":"PostToolUse","tool_name":"Bash","cwd":"%s","tool_input":{"command":"echo status-check"}}' "$A" | capture
|
|
59
61
|
# A non-command tool (Write) must NOT be captured.
|
|
60
62
|
printf '{"hook_event_name":"PostToolUse","tool_name":"Write","cwd":"%s","tool_input":{"file_path":"/tmp/x"}}' "$A" | capture
|
|
61
63
|
|
|
@@ -63,7 +65,7 @@ LOG="$A/.kontourai/flow-agents/t1/command-log.jsonl"
|
|
|
63
65
|
if [[ -f "$LOG" ]]; then _pass "capture writes command-log.jsonl"; else _fail "capture did not write command-log.jsonl"; fi
|
|
64
66
|
|
|
65
67
|
lines=$(wc -l < "$LOG" | tr -d ' ')
|
|
66
|
-
if [[ "$lines" == "
|
|
68
|
+
if [[ "$lines" == "4" ]]; then _pass "capture records 4 command executions (Write tool excluded)"; else _fail "expected 4 log lines, got $lines"; fi
|
|
67
69
|
|
|
68
70
|
if rg -q '"command":"npm test","observedResult":"pass","exitCode":0' "$LOG"; then
|
|
69
71
|
_pass "clean exit 0 recorded as observedResult:pass exitCode:0"
|
|
@@ -77,6 +79,14 @@ if rg -q '"command":"make build","observedResult":"fail","exitCode":2' "$LOG"; t
|
|
|
77
79
|
_pass "non-zero exit recorded as fail with exitCode"
|
|
78
80
|
else _fail "non-zero-exit command not recorded correctly"; fi
|
|
79
81
|
|
|
82
|
+
# #470 rule-3 default: absent any positive success evidence, observedResult is
|
|
83
|
+
# "ambiguous" (never "pass"). The error-bearing case above ("npm run lint" →
|
|
84
|
+
# fail, exitCode:null) already proves rule 2 (isFailureIndicated) is unchanged
|
|
85
|
+
# by the rule-3 flip.
|
|
86
|
+
if rg -q '"command":"echo status-check","observedResult":"ambiguous","exitCode":null' "$LOG"; then
|
|
87
|
+
_pass "no-signal command (no exit code, no error, no stderr) recorded as ambiguous, never pass"
|
|
88
|
+
else _fail "no-signal command not recorded as ambiguous: $(cat "$LOG")"; fi
|
|
89
|
+
|
|
80
90
|
if rg -q '"source":"postToolUse-capture"' "$LOG"; then _pass "records source:postToolUse-capture"; else _fail "missing source field"; fi
|
|
81
91
|
|
|
82
92
|
# Capture is non-blocking: it always exits 0 and echoes stdin.
|
|
@@ -165,8 +175,13 @@ fi
|
|
|
165
175
|
# ============================================================================
|
|
166
176
|
echo "Part B5: free-form model command re-run is opt-in only"
|
|
167
177
|
F="$TMP/recheck"; seed_repo "$F" t1
|
|
178
|
+
# #494: the opt-in RECHECK re-run of model-recorded free-form commands applies to IN-FLIGHT
|
|
179
|
+
# sessions. On terminal delivered/done sessions the model-asserted RECHECK is skipped (captured
|
|
180
|
+
# execution evidence + L2 CI remain the anchors) — terminal-skip is covered in test_goal_fit_hook.sh.
|
|
181
|
+
# seed_repo defaults to delivered/done, so make this session in-flight to exercise the opt-in re-run.
|
|
182
|
+
printf '%s' '{"schema_version":"1.0","task_slug":"t1","status":"in_progress","phase":"verification","updated_at":"2026-06-23T00:00:00Z","next_action":{"status":"continue","summary":"verify command evidence"}}' > "$F/.kontourai/flow-agents/t1/state.json"
|
|
168
183
|
printf '%s' '{"schema_version":"1.0","task_slug":"t1","verdict":"pass","checks":[{"id":"custom","kind":"command","status":"pass","command":"exit 5","summary":"ran custom"}]}' > "$F/.kontourai/flow-agents/t1/evidence.json"
|
|
169
|
-
# Opt-in ON: the model's free-form "exit 5" is re-run and fails → block.
|
|
184
|
+
# Opt-in ON (in-flight): the model's free-form "exit 5" is re-run and fails → block.
|
|
170
185
|
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_RECHECK=true node "$GATE" >/dev/null 2>"$TMP/b5.err" <<JSON
|
|
171
186
|
{"hook_event_name":"Stop","cwd":"$F"}
|
|
172
187
|
JSON
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_exemption_usage_review.sh — Integration eval for the Veritas Governance Kit's
|
|
3
|
+
# exemption-usage-review skill (issue #303, ADR 0022 §3).
|
|
4
|
+
#
|
|
5
|
+
# Proves review-exemptions.mjs correctly:
|
|
6
|
+
# AC1 review-lists-exemptions: parses a delivery/DECLARED fixture and lists every entry
|
|
7
|
+
# with scope, reason, approved_by, and computed age (deterministic via --as-of).
|
|
8
|
+
# AC2 review-flags-stale: against a mixed fresh/stale fixture, flags ONLY the entry
|
|
9
|
+
# outside --stale-days as stale, using exact age math.
|
|
10
|
+
# AC3 review-process-only-no-mutation: running the review does not modify
|
|
11
|
+
# delivery/DECLARED (byte-identical before/after) and does not change
|
|
12
|
+
# scripts/ci/trust-reconcile.js's exit code run against the same fixture tree
|
|
13
|
+
# before/after the review executes.
|
|
14
|
+
# AC9 no-fork: the skill/helper contains no copy of matchesScopeCondition/matchesScope/
|
|
15
|
+
# parseDeclaredMarker function bodies (structural grep, mirrors
|
|
16
|
+
# test_veritas_governance_kit.sh's no-fork assertion pattern).
|
|
17
|
+
# Output shape: --json emits {scope, reason, approved_by, declared_at, age_days, stale}
|
|
18
|
+
# per entry.
|
|
19
|
+
# Exit-0-always-informational: the script's own exit code is 0 regardless of how many
|
|
20
|
+
# entries are flagged stale (staleness is informational, never a script failure).
|
|
21
|
+
#
|
|
22
|
+
# Deterministic (--as-of pins "now"), no model spend, self-cleaning.
|
|
23
|
+
# Usage: bash evals/integration/test_exemption_usage_review.sh
|
|
24
|
+
|
|
25
|
+
set -uo pipefail
|
|
26
|
+
|
|
27
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
28
|
+
KIT="$ROOT/kits/veritas-governance"
|
|
29
|
+
HELPER="$KIT/skills/exemption-usage-review/review-exemptions.mjs"
|
|
30
|
+
SKILL_MD="$KIT/skills/exemption-usage-review/SKILL.md"
|
|
31
|
+
FIXTURE="$KIT/fixtures/exemption-review/mixed-fresh-stale.DECLARED.json"
|
|
32
|
+
RECONCILE="$ROOT/scripts/ci/trust-reconcile.js"
|
|
33
|
+
|
|
34
|
+
errors=0
|
|
35
|
+
TMP_DIR="$(mktemp -d)"
|
|
36
|
+
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
37
|
+
pass() { echo " ✓ $1"; }
|
|
38
|
+
fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
39
|
+
|
|
40
|
+
echo "=== exemption-usage-review skill — integration eval ==="
|
|
41
|
+
|
|
42
|
+
# --- Sanity: required files exist ------------------------------------------------
|
|
43
|
+
if [[ -f "$HELPER" && -f "$SKILL_MD" && -f "$FIXTURE" ]]; then
|
|
44
|
+
pass "helper, SKILL.md, and fixture all exist"
|
|
45
|
+
else
|
|
46
|
+
fail "one or more required files missing (helper=$HELPER skill=$SKILL_MD fixture=$FIXTURE)"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# --- AC1/AC2: listing + staleness math, deterministic via --as-of ----------------
|
|
50
|
+
echo "--- AC1/AC2: listing + staleness flagging ---"
|
|
51
|
+
AS_OF="2026-07-05T00:00:00Z"
|
|
52
|
+
STALE_DAYS=90
|
|
53
|
+
|
|
54
|
+
json_out="$(node "$HELPER" --declared-path "$FIXTURE" --repo-root "$ROOT" --as-of "$AS_OF" --stale-days "$STALE_DAYS" --json 2>&1)"
|
|
55
|
+
json_code=$?
|
|
56
|
+
|
|
57
|
+
if [[ "$json_code" -eq 0 ]]; then
|
|
58
|
+
pass "review-exemptions.mjs exits 0 on a clean run against the mixed fixture"
|
|
59
|
+
else
|
|
60
|
+
fail "review-exemptions.mjs expected exit 0, got $json_code — output: $json_out"
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo "$json_out" > "$TMP_DIR/report.json"
|
|
64
|
+
|
|
65
|
+
if node -e "
|
|
66
|
+
const r = JSON.parse(require('fs').readFileSync('$TMP_DIR/report.json', 'utf8'));
|
|
67
|
+
if (!Array.isArray(r.entries) || r.entries.length !== 2) process.exit(1);
|
|
68
|
+
"; then
|
|
69
|
+
pass "AC1: exactly 2 entries listed from the mixed-fresh-stale fixture"
|
|
70
|
+
else
|
|
71
|
+
fail "AC1: expected exactly 2 entries in the report — output: $json_out"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
if node -e "
|
|
75
|
+
const r = JSON.parse(require('fs').readFileSync('$TMP_DIR/report.json', 'utf8'));
|
|
76
|
+
const [fresh, stale] = r.entries;
|
|
77
|
+
const required = ['scope', 'reason', 'approved_by', 'declared_at', 'age_days', 'stale'];
|
|
78
|
+
for (const e of r.entries) {
|
|
79
|
+
for (const f of required) {
|
|
80
|
+
if (!(f in e)) process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (fresh.age_days !== 15) process.exit(1);
|
|
84
|
+
if (stale.age_days !== 185) process.exit(1);
|
|
85
|
+
"; then
|
|
86
|
+
pass "AC1: age_days computed correctly (15 for the fresh entry, 185 for the stale entry) against as-of $AS_OF"
|
|
87
|
+
else
|
|
88
|
+
fail "AC1: age_days math did not match expected values — output: $json_out"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if node -e "
|
|
92
|
+
const r = JSON.parse(require('fs').readFileSync('$TMP_DIR/report.json', 'utf8'));
|
|
93
|
+
const [fresh, stale] = r.entries;
|
|
94
|
+
if (fresh.stale !== false) process.exit(1);
|
|
95
|
+
if (stale.stale !== true) process.exit(1);
|
|
96
|
+
"; then
|
|
97
|
+
pass "AC2: ONLY the entry outside the $STALE_DAYS-day threshold is flagged stale (fresh entry: false, stale entry: true)"
|
|
98
|
+
else
|
|
99
|
+
fail "AC2: staleness flagging diverged from expected (fresh=false, stale=true) — output: $json_out"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# --- AC2 negative/flip case: lowering the threshold flips the fresh entry too ----
|
|
103
|
+
flip_out="$(node "$HELPER" --declared-path "$FIXTURE" --repo-root "$ROOT" --as-of "$AS_OF" --stale-days 10 --json 2>&1)"
|
|
104
|
+
echo "$flip_out" > "$TMP_DIR/flip.json"
|
|
105
|
+
if node -e "
|
|
106
|
+
const r = JSON.parse(require('fs').readFileSync('$TMP_DIR/flip.json', 'utf8'));
|
|
107
|
+
if (r.entries.length !== 2) process.exit(1);
|
|
108
|
+
if (!r.entries.every((e) => e.stale === true)) process.exit(1);
|
|
109
|
+
"; then
|
|
110
|
+
pass "AC2 threshold-flip: lowering --stale-days to 10 flips BOTH entries to stale (age math is threshold-relative, not hardcoded)"
|
|
111
|
+
else
|
|
112
|
+
fail "AC2 threshold-flip: lowering the threshold did not flip both entries stale — output: $flip_out"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# --- Output-shape: human-readable mode also runs clean ---------------------------
|
|
116
|
+
human_out="$(node "$HELPER" --declared-path "$FIXTURE" --repo-root "$ROOT" --as-of "$AS_OF" --stale-days "$STALE_DAYS" 2>&1)"
|
|
117
|
+
human_code=$?
|
|
118
|
+
if [[ "$human_code" -eq 0 ]] && echo "$human_out" | grep -qF "PROCESS-ONLY: read-only report."; then
|
|
119
|
+
pass "human-readable report mode exits 0 and states the process-only boundary plainly"
|
|
120
|
+
else
|
|
121
|
+
fail "human-readable report mode did not exit 0 or did not state the process-only boundary — output: $human_out"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# --- AC3: process-only, no mutation of delivery/DECLARED or trust-reconcile exit code --
|
|
125
|
+
echo "--- AC3: no-mutation lock (byte-diff DECLARED + reconciler exit-code identity) ---"
|
|
126
|
+
DECLARED_WORK="$TMP_DIR/declared-work"
|
|
127
|
+
mkdir -p "$DECLARED_WORK/delivery"
|
|
128
|
+
cp "$FIXTURE" "$DECLARED_WORK/delivery/DECLARED"
|
|
129
|
+
|
|
130
|
+
sha_before="$(shasum -a 256 "$DECLARED_WORK/delivery/DECLARED" | awk '{print $1}')"
|
|
131
|
+
RECONCILE_CMD="node -e 'process.exit(0)'"
|
|
132
|
+
recon_before_out="$(TRUST_RECONCILE_ACTOR="dependabot[bot]" TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" \
|
|
133
|
+
node "$RECONCILE" --repo-root "$DECLARED_WORK" 2>&1)"
|
|
134
|
+
recon_before_code=$?
|
|
135
|
+
|
|
136
|
+
# Run the review against the SAME fixture tree's DECLARED file (not the read-only source
|
|
137
|
+
# fixture) — this is the file whose byte-identity and reconciler-exit-code-identity we lock.
|
|
138
|
+
review_out="$(node "$HELPER" --declared-path "$DECLARED_WORK/delivery/DECLARED" --repo-root "$DECLARED_WORK" --as-of "$AS_OF" --stale-days "$STALE_DAYS" --json 2>&1)"
|
|
139
|
+
review_code=$?
|
|
140
|
+
|
|
141
|
+
sha_after="$(shasum -a 256 "$DECLARED_WORK/delivery/DECLARED" | awk '{print $1}')"
|
|
142
|
+
recon_after_out="$(TRUST_RECONCILE_ACTOR="dependabot[bot]" TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" \
|
|
143
|
+
node "$RECONCILE" --repo-root "$DECLARED_WORK" 2>&1)"
|
|
144
|
+
recon_after_code=$?
|
|
145
|
+
|
|
146
|
+
if [[ "$review_code" -eq 0 ]]; then
|
|
147
|
+
pass "review-exemptions.mjs itself exits 0 (informational only, regardless of stale entries present)"
|
|
148
|
+
else
|
|
149
|
+
fail "review-exemptions.mjs expected exit 0, got $review_code — output: $review_out"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
if [[ "$sha_before" == "$sha_after" ]]; then
|
|
153
|
+
pass "AC3: delivery/DECLARED bytes are IDENTICAL before/after the review ran (sha256 $sha_before)"
|
|
154
|
+
else
|
|
155
|
+
fail "AC3: delivery/DECLARED bytes CHANGED after the review ran (before=$sha_before after=$sha_after) — review mutated a file it must never touch"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
if [[ "$recon_before_code" == "$recon_after_code" ]]; then
|
|
159
|
+
pass "AC3: trust-reconcile.js's exit code is IDENTICAL before/after the review ran (both: $recon_before_code)"
|
|
160
|
+
else
|
|
161
|
+
fail "AC3: trust-reconcile.js's exit code DIVERGED before ($recon_before_code) vs after ($recon_after_code) the review ran — the audit-vs-enforcement boundary is broken"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# --- AC9: no-fork — helper/SKILL.md contain no copy of the reconciler's scope-matching --
|
|
165
|
+
echo "--- AC9: no-fork (structural grep for vendored reconciler logic) ---"
|
|
166
|
+
if grep -nE "startsWith\('ref:'\)|startsWith\('commit:'\)|startsWith\('author:'\)|startsWith\('branch-prefix:'\)" "$HELPER" >/dev/null 2>&1; then
|
|
167
|
+
fail "AC9: review-exemptions.mjs contains vendored matchesScopeCondition-style branch logic (no-fork violated)"
|
|
168
|
+
else
|
|
169
|
+
pass "AC9: review-exemptions.mjs contains no vendored matchesScopeCondition branch logic"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
if grep -nE "^function (matchesScope|matchesScopeCondition|parseDeclaredMarker)\(" "$HELPER" "$SKILL_MD" >/dev/null 2>&1; then
|
|
173
|
+
fail "AC9: a matchesScope/matchesScopeCondition/parseDeclaredMarker function DEFINITION was found in the skill's own files (no-fork violated)"
|
|
174
|
+
else
|
|
175
|
+
pass "AC9: no matchesScope/matchesScopeCondition/parseDeclaredMarker function definition exists in the skill's own files (references-only, per SKILL.md's explicit non-reuse note)"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# --- kit.json registration sanity (skill is registered, kit still validates) -----
|
|
179
|
+
FLOW_CLI="$ROOT/node_modules/@kontourai/flow/dist/cli.js"
|
|
180
|
+
if node "$FLOW_CLI" kit validate "$KIT" >"$TMP_DIR/kitval.out" 2>&1; then
|
|
181
|
+
pass "kit container still validates with the exemption-usage-review skill present"
|
|
182
|
+
else
|
|
183
|
+
fail "kit container failed validation with the skill present"; sed -n '1,40p' "$TMP_DIR/kitval.out"
|
|
184
|
+
fi
|
|
185
|
+
if grep -q '"id": *"veritas-governance\.exemption-usage-review"' "$KIT/kit.json" && grep -q '"path": *"skills/exemption-usage-review/SKILL.md"' "$KIT/kit.json"; then
|
|
186
|
+
pass "exemption-usage-review skill is registered in kit.json skills[]"
|
|
187
|
+
else
|
|
188
|
+
fail "exemption-usage-review skill is NOT registered in kit.json skills[]"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
echo ""
|
|
192
|
+
if [[ "$errors" -eq 0 ]]; then
|
|
193
|
+
echo "PASS: exemption-usage-review skill (listing, staleness, no-mutation lock, no-fork)"
|
|
194
|
+
exit 0
|
|
195
|
+
else
|
|
196
|
+
echo "FAIL: $errors check(s) failed"
|
|
197
|
+
exit 1
|
|
198
|
+
fi
|
|
@@ -21,9 +21,9 @@ json_query() {
|
|
|
21
21
|
node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); for (const part of process.argv[2].split(".")) cur=Array.isArray(cur) ? cur[Number(part)] : cur[part]; console.log(cur);' "$1" "$2"
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
[[ "$(json_query "$TMPDIR_EVAL/audit.json" "totals.scanned")" == "
|
|
24
|
+
[[ "$(json_query "$TMPDIR_EVAL/audit.json" "totals.scanned")" == "19" ]] && pass "audit scans all fixture groups" || fail "audit scans all fixture groups"
|
|
25
25
|
[[ "$(json_query "$TMPDIR_EVAL/audit.json" "totals.retire_candidates")" == "0" ]] && pass "audit finds no unowned retire candidates" || fail "audit finds no unowned retire candidates"
|
|
26
|
-
[[ "$(json_query "$TMPDIR_EVAL/audit.json" "totals.kept")" == "
|
|
26
|
+
[[ "$(json_query "$TMPDIR_EVAL/audit.json" "totals.kept")" == "19" ]] && pass "audit keeps all owned fixture groups" || fail "audit keeps all owned fixture groups"
|
|
27
27
|
|
|
28
28
|
node - "$TMPDIR_EVAL/audit.json" <<'NODE'
|
|
29
29
|
const fs = require("node:fs");
|
|
@@ -46,6 +46,27 @@ else
|
|
|
46
46
|
sed -n '1,80p' "$default_out"
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
|
+
# Named acceptance outcomes must exercise the real catalog manifests, not only
|
|
50
|
+
# the generic resolver fixture.
|
|
51
|
+
for named_kit in builder knowledge; do
|
|
52
|
+
NAMED_HOME="$TMP_DIR/named-$named_kit-codex-home"
|
|
53
|
+
mkdir -p "$NAMED_HOME"
|
|
54
|
+
named_out="$TMP_DIR/named-$named_kit.out"
|
|
55
|
+
if CODEX_HOME="$NAMED_HOME" flow_agents_node "$CLI" install "$named_kit" >"$named_out" 2>&1 \
|
|
56
|
+
&& [[ -f "$NAMED_HOME/kits/local/repositories/$named_kit/kit.json" ]] \
|
|
57
|
+
&& node - "$NAMED_HOME/kits/local/installed-kits.json" "$named_kit" <<'NODE'
|
|
58
|
+
const fs = require("node:fs");
|
|
59
|
+
const registry = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
|
60
|
+
if (!registry.kits.some((kit) => kit.id === process.argv[3])) process.exit(1);
|
|
61
|
+
NODE
|
|
62
|
+
then
|
|
63
|
+
pass "$named_kit kit install without --dest uses isolated CODEX_HOME"
|
|
64
|
+
else
|
|
65
|
+
fail "$named_kit kit install without --dest did not use isolated CODEX_HOME"
|
|
66
|
+
sed -n '1,100p' "$named_out"
|
|
67
|
+
fi
|
|
68
|
+
done
|
|
69
|
+
|
|
49
70
|
list_out="$TMP_DIR/default-list.out"
|
|
50
71
|
if CODEX_HOME="$DEFAULT_CODEX_HOME" flow_agents_node "$CLI" list >"$list_out" 2>&1 \
|
|
51
72
|
&& grep -q "example-kit" "$list_out"; then
|
|
@@ -205,6 +226,68 @@ else
|
|
|
205
226
|
fail "source kits/catalog.json changed during install-git test"
|
|
206
227
|
fi
|
|
207
228
|
|
|
229
|
+
# --- Security regressions: symlink escapes and local-source overlap ---
|
|
230
|
+
REGISTRY_ESCAPE_DEST="$TMP_DIR/registry-escape-dest"
|
|
231
|
+
REGISTRY_ESCAPE_OUTSIDE="$TMP_DIR/registry-escape-outside.json"
|
|
232
|
+
mkdir -p "$REGISTRY_ESCAPE_DEST/kits/local"
|
|
233
|
+
printf '{"outside":"unchanged"}\n' > "$REGISTRY_ESCAPE_OUTSIDE"
|
|
234
|
+
ln -s "$REGISTRY_ESCAPE_OUTSIDE" "$REGISTRY_ESCAPE_DEST/kits/local/installed-kits.json"
|
|
235
|
+
if flow_agents_node "$CLI" install "$VALID_SRC" --dest "$REGISTRY_ESCAPE_DEST" >"$TMP_DIR/registry-escape.out" 2>&1; then
|
|
236
|
+
fail "symlinked kit registry should fail closed"
|
|
237
|
+
elif grep -q '"outside":"unchanged"' "$REGISTRY_ESCAPE_OUTSIDE"; then
|
|
238
|
+
pass "symlinked kit registry fails closed without outside write"
|
|
239
|
+
else
|
|
240
|
+
fail "symlinked kit registry modified outside file"
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
REPOSITORY_ESCAPE_DEST="$TMP_DIR/repository-escape-dest"
|
|
244
|
+
REPOSITORY_ESCAPE_OUTSIDE="$TMP_DIR/repository-escape-outside"
|
|
245
|
+
mkdir -p "$REPOSITORY_ESCAPE_DEST/kits/local/repositories" "$REPOSITORY_ESCAPE_OUTSIDE"
|
|
246
|
+
printf 'unchanged\n' > "$REPOSITORY_ESCAPE_OUTSIDE/sentinel"
|
|
247
|
+
ln -s "$REPOSITORY_ESCAPE_OUTSIDE" "$REPOSITORY_ESCAPE_DEST/kits/local/repositories/example-kit"
|
|
248
|
+
if flow_agents_node "$CLI" install "$VALID_SRC" --dest "$REPOSITORY_ESCAPE_DEST" >"$TMP_DIR/repository-escape.out" 2>&1; then
|
|
249
|
+
fail "symlinked kit repository should fail closed"
|
|
250
|
+
elif [[ "$(cat "$REPOSITORY_ESCAPE_OUTSIDE/sentinel")" == "unchanged" && ! -e "$REPOSITORY_ESCAPE_OUTSIDE/kit.json" ]]; then
|
|
251
|
+
pass "symlinked kit repository fails closed without outside write"
|
|
252
|
+
else
|
|
253
|
+
fail "symlinked kit repository modified outside directory"
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
SELF_DEST="$TMP_DIR/self-overlap-dest"
|
|
257
|
+
SELF_SOURCE="$SELF_DEST/kits/local/repositories/example-kit"
|
|
258
|
+
mkdir -p "$(dirname "$SELF_SOURCE")"
|
|
259
|
+
cp -R "$VALID_SRC" "$SELF_SOURCE"
|
|
260
|
+
if flow_agents_node "$CLI" install "$SELF_SOURCE" --dest "$SELF_DEST" >"$TMP_DIR/self-overlap.out" 2>&1; then
|
|
261
|
+
fail "exact local-kit self-install should be rejected"
|
|
262
|
+
elif [[ -f "$SELF_SOURCE/kit.json" ]] && grep -q "refusing overlapping paths" "$TMP_DIR/self-overlap.out"; then
|
|
263
|
+
pass "exact local-kit self-install is rejected before source mutation"
|
|
264
|
+
else
|
|
265
|
+
fail "exact local-kit self-install did not preserve its source"
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
DESCENDANT_DEST="$TMP_DIR/descendant-overlap-dest"
|
|
269
|
+
cp -R "$VALID_SRC" "$DESCENDANT_DEST"
|
|
270
|
+
if flow_agents_node "$CLI" install "$DESCENDANT_DEST" --dest "$DESCENDANT_DEST" >"$TMP_DIR/descendant-overlap.out" 2>&1; then
|
|
271
|
+
fail "kit target nested beneath source should be rejected"
|
|
272
|
+
elif [[ -f "$DESCENDANT_DEST/kit.json" ]] && grep -q "refusing overlapping paths" "$TMP_DIR/descendant-overlap.out"; then
|
|
273
|
+
pass "kit target nested beneath source is rejected before mutation"
|
|
274
|
+
else
|
|
275
|
+
fail "source-ancestor overlap did not preserve source"
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
ANCESTOR_DEST="$TMP_DIR/ancestor-overlap-dest"
|
|
279
|
+
ANCESTOR_TARGET="$ANCESTOR_DEST/kits/local/repositories/example-kit"
|
|
280
|
+
ANCESTOR_SOURCE="$ANCESTOR_TARGET/nested-source"
|
|
281
|
+
mkdir -p "$ANCESTOR_TARGET"
|
|
282
|
+
cp -R "$VALID_SRC" "$ANCESTOR_SOURCE"
|
|
283
|
+
if flow_agents_node "$CLI" install "$ANCESTOR_SOURCE" --dest "$ANCESTOR_DEST" >"$TMP_DIR/ancestor-overlap.out" 2>&1; then
|
|
284
|
+
fail "kit source nested beneath target should be rejected"
|
|
285
|
+
elif [[ -f "$ANCESTOR_SOURCE/kit.json" ]] && grep -q "refusing overlapping paths" "$TMP_DIR/ancestor-overlap.out"; then
|
|
286
|
+
pass "kit source nested beneath target is rejected before mutation"
|
|
287
|
+
else
|
|
288
|
+
fail "target-ancestor overlap did not preserve source"
|
|
289
|
+
fi
|
|
290
|
+
|
|
208
291
|
echo ""
|
|
209
292
|
if [[ "$errors" -eq 0 ]]; then
|
|
210
293
|
echo "install-git checks passed."
|
|
@@ -143,7 +143,6 @@ flow_agents_node "$WRITER" ensure-session \
|
|
|
143
143
|
--title "Tamper verify test" \
|
|
144
144
|
--summary "Testing tamper detection at verify step." \
|
|
145
145
|
--flow-id builder.build \
|
|
146
|
-
--step-id verify \
|
|
147
146
|
--timestamp "2026-06-01T02:00:00Z" >/dev/null 2>&1
|
|
148
147
|
|
|
149
148
|
flow_agents_node "$WRITER" init-plan "$TAMPER_DIR/.kontourai/flow-agents/$TAMPER_SLUG/$TAMPER_SLUG--deliver.md" \
|
|
@@ -39,20 +39,25 @@ SLUG="history-flow-test"
|
|
|
39
39
|
SESSION_DIR="$FLOW_AROOT/$SLUG"
|
|
40
40
|
mkdir -p "$FLOW_AROOT"
|
|
41
41
|
|
|
42
|
-
#
|
|
42
|
+
# Start at the declared first step, then establish the verify-state fixture.
|
|
43
43
|
flow_agents_node "$WRITER" ensure-session \
|
|
44
44
|
--artifact-root "$FLOW_AROOT" \
|
|
45
45
|
--task-slug "$SLUG" \
|
|
46
46
|
--title "History preservation test" \
|
|
47
47
|
--summary "Test that declared builder.* claims survive round-trips." \
|
|
48
48
|
--flow-id builder.build \
|
|
49
|
-
--step-id verify \
|
|
50
49
|
--timestamp "2026-06-01T00:00:00Z" >/dev/null 2>&1
|
|
51
50
|
|
|
52
51
|
flow_agents_node "$WRITER" init-plan "$SESSION_DIR/$SLUG--deliver.md" \
|
|
53
52
|
--source-request "Test" --summary "Testing" \
|
|
54
53
|
--timestamp "2026-06-01T00:00:00Z" >/dev/null 2>&1
|
|
55
54
|
|
|
55
|
+
flow_agents_node "$WRITER" advance-state "$SESSION_DIR" \
|
|
56
|
+
--status in_progress --phase verification \
|
|
57
|
+
--summary "Testing at verify." --next-action "Record evidence." \
|
|
58
|
+
--flow-definition builder.build \
|
|
59
|
+
--timestamp "2026-06-01T00:00:30Z" >/dev/null 2>&1
|
|
60
|
+
|
|
56
61
|
# Record a passing check (produces ONLY builder.verify.tests declared claim — no legacy shadow, P-d)
|
|
57
62
|
flow_agents_node "$WRITER" record-evidence "$SESSION_DIR" \
|
|
58
63
|
--verdict pass \
|
|
@@ -196,13 +201,18 @@ flow_agents_node "$WRITER" ensure-session \
|
|
|
196
201
|
--title "Dogfood clean test" \
|
|
197
202
|
--summary "Test evidenceClean/critiqueClean on builder.build session." \
|
|
198
203
|
--flow-id builder.build \
|
|
199
|
-
--step-id verify \
|
|
200
204
|
--timestamp "2026-06-01T20:00:00Z" >/dev/null 2>&1
|
|
201
205
|
|
|
202
206
|
flow_agents_node "$WRITER" init-plan "$DOGFOOD_DIR/$DOGFOOD_SLUG--deliver.md" \
|
|
203
207
|
--source-request "Test" --summary "Testing" \
|
|
204
208
|
--timestamp "2026-06-01T20:00:00Z" >/dev/null 2>&1
|
|
205
209
|
|
|
210
|
+
flow_agents_node "$WRITER" advance-state "$DOGFOOD_DIR" \
|
|
211
|
+
--status in_progress --phase verification \
|
|
212
|
+
--summary "Testing at verify." --next-action "Record evidence." \
|
|
213
|
+
--flow-definition builder.build \
|
|
214
|
+
--timestamp "2026-06-01T20:00:30Z" >/dev/null 2>&1
|
|
215
|
+
|
|
206
216
|
# Record pass evidence (produces builder.verify.tests declared claim, status=verified)
|
|
207
217
|
flow_agents_node "$WRITER" record-evidence "$DOGFOOD_DIR" \
|
|
208
218
|
--verdict pass \
|
|
@@ -872,6 +872,11 @@ cp "$ROOT/scripts/hooks/lib/local-artifact-paths.js" "$ISO_DIR/lib/"
|
|
|
872
872
|
# section is testing.
|
|
873
873
|
cp "$ROOT/scripts/hooks/lib/actor-identity.js" "$ISO_DIR/lib/"
|
|
874
874
|
cp "$ROOT/scripts/hooks/lib/current-pointer.js" "$ISO_DIR/lib/"
|
|
875
|
+
# #412: stop-goal-fit.js now also requires scripts/hooks/lib/runnable-command.js (the shared
|
|
876
|
+
# isRunnableCommandText heuristic, single-sourced with workflow-sidecar.ts) — mirror it too, or
|
|
877
|
+
# the isolated gate crashes on MODULE_NOT_FOUND before it ever reaches the surface-unavailable
|
|
878
|
+
# fail-closed path this section is testing.
|
|
879
|
+
cp "$ROOT/scripts/hooks/lib/runnable-command.js" "$ISO_DIR/lib/"
|
|
875
880
|
printf '# Repo\n' > "$ISO_DIR/repo/AGENTS.md"
|
|
876
881
|
# Non-terminal session (execution phase, in_progress status)
|
|
877
882
|
printf '%s' '{"schema_version":"1.0","task_slug":"surftest","status":"in_progress","phase":"execution","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"in_progress","summary":"running"}}' \
|
|
@@ -921,6 +926,8 @@ cp "$ROOT/scripts/hooks/lib/local-artifact-paths.js" "$ISO2_DIR/lib/"
|
|
|
921
926
|
# #291: same rationale as ISO_DIR above -- mirror the two new scripts/hooks/lib dependencies.
|
|
922
927
|
cp "$ROOT/scripts/hooks/lib/actor-identity.js" "$ISO2_DIR/lib/"
|
|
923
928
|
cp "$ROOT/scripts/hooks/lib/current-pointer.js" "$ISO2_DIR/lib/"
|
|
929
|
+
# #412: see the ISO_DIR mirror above — same requirement applies to this second isolated copy.
|
|
930
|
+
cp "$ROOT/scripts/hooks/lib/runnable-command.js" "$ISO2_DIR/lib/"
|
|
924
931
|
printf '# Repo\n' > "$ISO2_DIR/repo/AGENTS.md"
|
|
925
932
|
printf '%s' '{"schema_version":"1.0","task_slug":"lowtest","status":"in_progress","phase":"execution","updated_at":"2026-06-27T00:00:00Z","next_action":{"status":"in_progress","summary":"running"}}' \
|
|
926
933
|
> "$ISO2_DIR/repo/.kontourai/flow-agents/lowtest/state.json"
|
|
@@ -25,6 +25,14 @@ trap cleanup EXIT
|
|
|
25
25
|
_pass() { echo " ✓ $1"; }
|
|
26
26
|
_fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
27
27
|
|
|
28
|
+
hook_tree_digest() {
|
|
29
|
+
find "$ROOT/scripts/hooks" -type f -print | LC_ALL=C sort | while IFS= read -r file; do
|
|
30
|
+
shasum -a 256 "$file"
|
|
31
|
+
done | shasum -a 256 | awk '{print $1}'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
HOOKS_BEFORE="$(hook_tree_digest)"
|
|
35
|
+
|
|
28
36
|
echo "=== Gate Review InquiryRecord Tests (AC1 + AC2) ==="
|
|
29
37
|
|
|
30
38
|
# ── helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -385,7 +393,7 @@ fi
|
|
|
385
393
|
# ── AC3: no hooks changed ─────────────────────────────────────────────────────
|
|
386
394
|
echo ""
|
|
387
395
|
echo "--- AC3: hooks unchanged ---"
|
|
388
|
-
if
|
|
396
|
+
if [[ "$(hook_tree_digest)" != "$HOOKS_BEFORE" ]]; then
|
|
389
397
|
_fail "AC3: scripts/hooks/ was modified (gate-review must not touch hooks)"
|
|
390
398
|
else
|
|
391
399
|
_pass "AC3: scripts/hooks/ unchanged"
|