@kontourai/flow-agents 2.3.0 → 3.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/CODEOWNERS +16 -0
- package/.github/workflows/ci.yml +44 -0
- package/.github/workflows/trust-reconcile.yml +62 -4
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +62 -0
- package/CONTEXT.md +35 -0
- package/README.md +9 -3
- package/agents/dev.json +1 -1
- package/agents/tool-code-reviewer.json +1 -1
- package/agents/tool-planner.json +3 -3
- package/agents/tool-verifier.json +3 -3
- package/build/src/cli/assignment-provider.d.ts +1 -0
- package/build/src/cli/assignment-provider.js +748 -0
- package/build/src/cli/console-learning-projection.js +3 -2
- package/build/src/cli/effective-assignment-provider-settings.d.ts +1 -0
- package/build/src/cli/effective-assignment-provider-settings.js +125 -0
- package/build/src/cli/init.js +104 -21
- package/build/src/cli/kit.js +37 -6
- package/build/src/cli/pull-work-provider.js +1 -1
- package/build/src/cli/usage-feedback.js +3 -3
- package/build/src/cli/validate-hook-influence.js +1 -0
- package/build/src/cli/validate-workflow-artifacts.js +27 -7
- package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
- package/build/src/cli/workflow-sidecar.d.ts +14 -7
- package/build/src/cli/workflow-sidecar.js +938 -168
- package/build/src/cli.js +6 -0
- package/build/src/flow-kit/validate.d.ts +23 -0
- package/build/src/flow-kit/validate.js +67 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -1
- package/build/src/lib/flow-resolver.d.ts +6 -4
- package/build/src/lib/flow-resolver.js +125 -58
- package/build/src/lib/local-artifact-root.d.ts +14 -2
- package/build/src/lib/local-artifact-root.js +22 -5
- package/build/src/lib/workflow-learning-projection.js +2 -2
- package/build/src/runtime-adapters.d.ts +12 -0
- package/build/src/runtime-adapters.js +56 -16
- package/build/src/tools/build-universal-bundles.js +49 -16
- package/build/src/tools/generate-context-map.js +10 -8
- package/build/src/tools/validate-source-tree.js +24 -1
- package/console.telemetry.json +22 -0
- package/context/contracts/artifact-contract.md +40 -7
- package/context/contracts/assignment-provider-contract.md +239 -0
- package/context/contracts/builder-kit-workflow-state-contract.md +5 -2
- package/context/contracts/decision-registry-contract.md +265 -0
- package/context/contracts/delivery-contract.md +3 -1
- package/context/contracts/execution-contract.md +25 -0
- package/context/contracts/governance-adapter-contract.md +2 -0
- package/context/contracts/knowledge-store-contract.md +197 -0
- package/context/contracts/planning-contract.md +4 -1
- package/context/contracts/review-contract.md +7 -3
- package/context/contracts/sandbox-policy.md +2 -0
- package/context/contracts/standing-directives.md +13 -0
- package/context/contracts/verification-contract.md +11 -1
- package/context/contracts/work-item-contract.md +3 -1
- package/context/deferred/parallelization.md +1 -1
- package/context/gate-awareness.md +4 -4
- package/context/scripts/git-status.sh +2 -2
- package/context/scripts/hooks/config-protection.js +502 -2
- package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/context/scripts/hooks/run-hook.js +14 -1
- package/context/scripts/hooks/stop-goal-fit.js +1140 -99
- package/context/scripts/hooks/workflow-steering.js +212 -6
- package/context/settings/assignment-provider-settings.json +33 -0
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
- package/docs/adr/0019-kit-dependency-ownership.md +62 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +463 -0
- package/docs/agent-system-guidebook.md +3 -3
- package/docs/agent-usage-feedback-loop.md +6 -6
- package/docs/context-map.md +10 -7
- package/docs/decisions/decision-records.md +57 -0
- package/docs/decisions/index.md +17 -0
- package/docs/decisions/knowledge-store-provider.md +51 -0
- package/docs/decisions/model-routing.md +63 -0
- package/docs/decisions/promotion-gate.md +52 -0
- package/docs/decisions/standing-directives.md +66 -0
- package/docs/developer-architecture.md +1 -1
- package/docs/fixture-ownership.md +4 -0
- package/docs/flow-kit-repository-contract.md +5 -5
- package/docs/getting-started.md +12 -2
- package/docs/integrations/harness-install.md +2 -1
- package/docs/kit-authoring-guide.md +64 -5
- package/docs/knowledge-kit.md +5 -1
- package/docs/learnings/2026-07-improvement-program.md +203 -0
- package/docs/migrations.md +6 -5
- package/docs/north-star.md +2 -2
- package/docs/operating-layers.md +4 -3
- package/docs/repository-structure.md +5 -5
- package/docs/skills-map.md +8 -8
- package/docs/spec/runtime-hook-surface.md +19 -15
- package/docs/spikes/graph-provider-2026-07.md +155 -0
- package/docs/standards-register.md +7 -7
- package/docs/trust-anchor-adoption.md +105 -4
- package/docs/work-item-adapters.md +1 -1
- package/docs/workflow-artifact-lifecycle.md +72 -9
- package/docs/workflow-eval-strategy.md +3 -3
- package/docs/workflow-shared-contracts.md +3 -2
- package/docs/workflow-usage-guide.md +260 -21
- package/evals/acceptance/DEMO-false-completion.md +20 -11
- package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
- package/evals/acceptance/prove-capture-teeth.sh +11 -11
- package/evals/acceptance/test_kiro_harness.sh +1 -1
- package/evals/ci/antigaming-suite.sh +5 -0
- package/evals/ci/run-baseline.sh +71 -1
- package/evals/fixtures/assignment-provider/actor-a.json +6 -0
- package/evals/fixtures/assignment-provider/actor-b.json +6 -0
- package/evals/fixtures/assignment-provider/github-issue-claimed.json +27 -0
- package/evals/fixtures/assignment-provider/github-issue-unassigned.json +7 -0
- package/evals/fixtures/assignment-provider/liveness-fresh.json +9 -0
- package/evals/fixtures/assignment-provider/liveness-stale.json +9 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
- package/evals/fixtures/hook-influence/cases.json +32 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
- package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
- package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
- package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
- package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
- package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
- package/evals/integration/test_actor_identity.sh +254 -0
- package/evals/integration/test_assignment_provider_github.sh +318 -0
- package/evals/integration/test_assignment_provider_local_file.sh +222 -0
- package/evals/integration/test_builder_step_producers.sh +33 -23
- package/evals/integration/test_bundle_install.sh +22 -16
- package/evals/integration/test_bundle_lifecycle.sh +11 -11
- package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
- package/evals/integration/test_checkpoint_signing.sh +43 -0
- package/evals/integration/test_claim_lookup.sh +4 -4
- package/evals/integration/test_codex_hook_resolution.sh +114 -0
- package/evals/integration/test_command_log_concurrency.sh +8 -8
- package/evals/integration/test_command_log_fork_classification.sh +3 -3
- package/evals/integration/test_command_log_integrity.sh +16 -16
- package/evals/integration/test_console_learning_projection.sh +1 -1
- package/evals/integration/test_critique_supersession_roundtrip.sh +182 -0
- package/evals/integration/test_dual_emit_flow_step.sh +145 -0
- package/evals/integration/test_enforcer_expects_driven.sh +12 -12
- package/evals/integration/test_evidence_capture_hook.sh +14 -13
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_agents_statusline.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +52 -0
- package/evals/integration/test_flow_kit_repository.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -6
- package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
- package/evals/integration/test_gate_bypass_chain.sh +52 -40
- package/evals/integration/test_gate_lockdown.sh +97 -73
- package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
- package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
- package/evals/integration/test_goal_fit_hook.sh +32 -32
- package/evals/integration/test_goal_fit_rederive.sh +9 -9
- package/evals/integration/test_hook_category_behaviors.sh +103 -0
- package/evals/integration/test_hook_influence_cases.sh +1 -0
- package/evals/integration/test_install_merge.sh +262 -1
- package/evals/integration/test_kit_identity_trust.sh +6 -6
- package/evals/integration/test_liveness_conflict_injection.sh +587 -0
- package/evals/integration/test_liveness_heartbeat.sh +677 -0
- package/evals/integration/test_liveness_verdict.sh +394 -0
- package/evals/integration/test_local_flow_kit_install.sh +15 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
- package/evals/integration/test_promote_gate.sh +178 -0
- package/evals/integration/test_publish_delivery.sh +23 -6
- package/evals/integration/test_pull_work_assignment_join.sh +132 -0
- package/evals/integration/test_pull_work_liveness_preflight.sh +394 -0
- package/evals/integration/test_pull_work_provider.sh +2 -2
- package/evals/integration/test_reconcile_soundness.sh +37 -13
- package/evals/integration/test_resolvefirststep_security.sh +22 -0
- package/evals/integration/test_runtime_adapter_activation.sh +87 -18
- package/evals/integration/test_session_resume_roundtrip.sh +147 -0
- package/evals/integration/test_sidecar_field_preservation.sh +249 -0
- package/evals/integration/test_trust_reconcile.sh +11 -10
- package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
- package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +759 -0
- package/evals/integration/test_usage_feedback_global.sh +5 -5
- package/evals/integration/test_validate_artifacts_portability.sh +60 -0
- package/evals/integration/test_verify_cli.sh +2 -2
- package/evals/integration/test_veritas_governance_kit.sh +117 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
- package/evals/integration/test_workflow_artifacts.sh +33 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +802 -74
- package/evals/integration/test_workflow_steering_hook.sh +175 -5
- package/evals/lib/codex-provider.sh +1 -1
- package/evals/lib/node.sh +19 -1
- package/evals/run.sh +32 -0
- package/evals/static/test_decisions.sh +150 -0
- package/evals/static/test_flowdef_codeowners_coverage.sh +62 -0
- package/evals/static/test_knowledge_providers.sh +23 -0
- package/evals/static/test_package.sh +19 -10
- package/evals/static/test_universal_bundles.sh +48 -3
- package/evals/static/test_workflow_skills.sh +41 -8
- package/kits/builder/flows/build.flow.json +3 -74
- package/kits/builder/flows/publish-learn.flow.json +90 -0
- package/kits/builder/kit.json +11 -0
- package/kits/builder/skills/builder-shape/SKILL.md +1 -1
- package/kits/builder/skills/deliver/SKILL.md +32 -11
- package/kits/builder/skills/design-probe/SKILL.md +4 -4
- package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
- package/kits/builder/skills/execute-plan/SKILL.md +2 -2
- package/kits/builder/skills/fix-bug/SKILL.md +2 -0
- package/kits/builder/skills/gate-review/SKILL.md +6 -6
- package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
- package/kits/builder/skills/learning-review/SKILL.md +7 -7
- package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
- package/kits/builder/skills/plan-work/SKILL.md +27 -5
- package/kits/builder/skills/pull-work/SKILL.md +148 -5
- package/kits/builder/skills/release-readiness/SKILL.md +4 -4
- package/kits/builder/skills/review-work/SKILL.md +24 -1
- package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
- package/kits/builder/skills/verify-work/SKILL.md +8 -1
- package/kits/catalog.json +6 -0
- package/kits/knowledge/kit.json +35 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/CONTEXT.md +12 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/old-sprocket-shape.md +13 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/sprocket-shape.md +14 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/widget-format.md +14 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/learnings/fixture-learning.md +7 -0
- package/kits/knowledge/providers/conformance/fixtures/work-item/issues.json +30 -0
- package/kits/knowledge/providers/conformance/suite.test.js +125 -0
- package/kits/knowledge/providers/git-repo/index.js +236 -0
- package/kits/knowledge/providers/health/health-pass.test.js +99 -0
- package/kits/knowledge/providers/health/index.js +153 -0
- package/kits/knowledge/providers/index.js +24 -0
- package/kits/knowledge/providers/lib/model.js +91 -0
- package/kits/knowledge/providers/lib/schema-validate.js +119 -0
- package/kits/knowledge/providers/markdown-vault/index.js +169 -0
- package/kits/knowledge/providers/work-item/index.js +204 -0
- package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
- package/kits/veritas-governance/docs/README.md +75 -0
- package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
- package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
- package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
- package/kits/veritas-governance/kit.json +16 -0
- package/package.json +11 -5
- package/packaging/README.md +2 -2
- package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
- package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
- package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
- package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
- package/packaging/manifest.json +9 -10
- package/schemas/assignment-provider-settings.schema.json +125 -0
- package/schemas/decision-record.schema.json +109 -0
- package/schemas/knowledge/edge.schema.json +54 -0
- package/schemas/knowledge/health-report.schema.json +45 -0
- package/schemas/knowledge/node.schema.json +49 -0
- package/schemas/knowledge/proposal.schema.json +53 -0
- package/schemas/workflow-evidence.schema.json +1 -1
- package/schemas/workflow-state.schema.json +5 -0
- package/scripts/README.md +8 -3
- package/scripts/check-content-boundary.cjs +1 -1
- package/scripts/check-decisions.cjs +356 -0
- package/scripts/ci/derive-claim-status.mjs +74 -0
- package/scripts/ci/trust-reconcile.js +957 -103
- package/scripts/git-status.sh +2 -2
- package/scripts/hooks/claude-telemetry-hook.js +37 -3
- package/scripts/hooks/codex-telemetry-hook.js +36 -2
- package/scripts/hooks/config-protection.js +102 -30
- package/scripts/hooks/evidence-capture.js +3 -3
- package/scripts/hooks/lib/actor-identity.js +368 -0
- package/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
- package/scripts/hooks/lib/liveness-policy.js +127 -0
- package/scripts/hooks/lib/liveness-read.js +105 -12
- package/scripts/hooks/lib/liveness-write.js +46 -0
- package/scripts/hooks/lib/local-artifact-paths.js +12 -6
- package/scripts/hooks/opencode-telemetry-hook.js +27 -1
- package/scripts/hooks/pi-telemetry-hook.js +27 -1
- package/scripts/hooks/stop-goal-fit.js +157 -26
- package/scripts/hooks/workflow-steering.js +77 -3
- package/scripts/install-codex-home.sh +138 -38
- package/scripts/statusline/flow-agents-statusline.js +2 -2
- package/src/cli/assignment-provider.ts +845 -0
- package/src/cli/console-learning-projection.ts +3 -2
- package/src/cli/effective-assignment-provider-settings.ts +112 -0
- package/src/cli/init.ts +101 -21
- package/src/cli/kit.ts +37 -6
- package/src/cli/public-api.test.mjs +58 -6
- package/src/cli/pull-work-provider.ts +1 -1
- package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
- package/src/cli/usage-feedback.ts +3 -3
- package/src/cli/validate-hook-influence.ts +1 -0
- package/src/cli/validate-workflow-artifacts.ts +27 -7
- package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
- package/src/cli/workflow-sidecar.ts +933 -168
- package/src/cli.ts +6 -0
- package/src/flow-kit/validate.ts +74 -1
- package/src/index.ts +6 -2
- package/src/lib/flow-resolver.ts +123 -55
- package/src/lib/local-artifact-root.ts +24 -5
- package/src/lib/workflow-learning-projection.ts +2 -2
- package/src/runtime-adapters.ts +61 -15
- package/src/tools/build-universal-bundles.ts +49 -16
- package/src/tools/generate-context-map.ts +10 -8
- package/src/tools/validate-source-tree.ts +24 -1
|
@@ -18,10 +18,10 @@ echo "=== Layer 2: Flow Agents Statusline ==="
|
|
|
18
18
|
echo ""
|
|
19
19
|
|
|
20
20
|
WORKSPACE="$TMPDIR_EVAL/workspace"
|
|
21
|
-
TASK_DIR="$WORKSPACE/.flow-agents/status-demo"
|
|
21
|
+
TASK_DIR="$WORKSPACE/.kontourai/flow-agents/status-demo"
|
|
22
22
|
mkdir -p "$TASK_DIR"
|
|
23
23
|
|
|
24
|
-
cat >"$WORKSPACE/.flow-agents/current.json" <<'JSON'
|
|
24
|
+
cat >"$WORKSPACE/.kontourai/flow-agents/current.json" <<'JSON'
|
|
25
25
|
{
|
|
26
26
|
"schema_version": "1.0",
|
|
27
27
|
"active_slug": "status-demo",
|
|
@@ -31,6 +31,58 @@ FILE_URL="file://$FIXTURE_REPO"
|
|
|
31
31
|
|
|
32
32
|
echo " (fixture repo: $FILE_URL)"
|
|
33
33
|
|
|
34
|
+
# --- Test 0: default destination honors CODEX_HOME and --dest overrides it ---
|
|
35
|
+
DEFAULT_CODEX_HOME="$TMP_DIR/default-codex-home"
|
|
36
|
+
OVERRIDE_DEST="$TMP_DIR/override-dest"
|
|
37
|
+
mkdir -p "$DEFAULT_CODEX_HOME" "$OVERRIDE_DEST"
|
|
38
|
+
|
|
39
|
+
default_out="$TMP_DIR/default-dest.out"
|
|
40
|
+
if CODEX_HOME="$DEFAULT_CODEX_HOME" flow_agents_node "$CLI" install "$VALID_SRC" >"$default_out" 2>&1 \
|
|
41
|
+
&& [[ -f "$DEFAULT_CODEX_HOME/kits/local/installed-kits.json" ]] \
|
|
42
|
+
&& [[ -d "$DEFAULT_CODEX_HOME/kits/local/repositories/example-kit" ]]; then
|
|
43
|
+
pass "kit install without --dest defaults to CODEX_HOME"
|
|
44
|
+
else
|
|
45
|
+
fail "kit install without --dest did not default to CODEX_HOME"
|
|
46
|
+
sed -n '1,80p' "$default_out"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
list_out="$TMP_DIR/default-list.out"
|
|
50
|
+
if CODEX_HOME="$DEFAULT_CODEX_HOME" flow_agents_node "$CLI" list >"$list_out" 2>&1 \
|
|
51
|
+
&& grep -q "example-kit" "$list_out"; then
|
|
52
|
+
pass "kit list without --dest reads CODEX_HOME"
|
|
53
|
+
else
|
|
54
|
+
fail "kit list without --dest did not read CODEX_HOME"
|
|
55
|
+
sed -n '1,80p' "$list_out"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
status_out="$TMP_DIR/default-status.out"
|
|
59
|
+
if CODEX_HOME="$DEFAULT_CODEX_HOME" flow_agents_node "$CLI" status example-kit >"$status_out" 2>&1 \
|
|
60
|
+
&& grep -q '"id": "example-kit"' "$status_out"; then
|
|
61
|
+
pass "kit status without --dest reads CODEX_HOME"
|
|
62
|
+
else
|
|
63
|
+
fail "kit status without --dest did not read CODEX_HOME"
|
|
64
|
+
sed -n '1,80p' "$status_out"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
activate_out="$TMP_DIR/default-activate.out"
|
|
68
|
+
if CODEX_HOME="$DEFAULT_CODEX_HOME" flow_agents_node "$CLI" activate --source-root "$ROOT" >"$activate_out" 2>&1 \
|
|
69
|
+
&& [[ -f "$DEFAULT_CODEX_HOME/.kontourai/flow-agents/projections/codex/activation.json" ]]; then
|
|
70
|
+
pass "kit activate without --dest writes CODEX_HOME"
|
|
71
|
+
else
|
|
72
|
+
fail "kit activate without --dest did not write CODEX_HOME"
|
|
73
|
+
sed -n '1,80p' "$activate_out"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
override_out="$TMP_DIR/override-dest.out"
|
|
77
|
+
if CODEX_HOME="$DEFAULT_CODEX_HOME" flow_agents_node "$CLI" install "$VALID_SRC" --dest "$OVERRIDE_DEST" >"$override_out" 2>&1 \
|
|
78
|
+
&& [[ -f "$OVERRIDE_DEST/kits/local/installed-kits.json" ]] \
|
|
79
|
+
&& [[ -d "$OVERRIDE_DEST/kits/local/repositories/example-kit" ]]; then
|
|
80
|
+
pass "kit install --dest overrides CODEX_HOME"
|
|
81
|
+
else
|
|
82
|
+
fail "kit install --dest did not override CODEX_HOME"
|
|
83
|
+
sed -n '1,80p' "$override_out"
|
|
84
|
+
fi
|
|
85
|
+
|
|
34
86
|
# --- Test 1: basic install-git from file:// URL ---
|
|
35
87
|
install_out="$TMP_DIR/install-git.out"
|
|
36
88
|
if flow_agents_node "$CLI" install "$FILE_URL" --dest "$DEST" >"$install_out" 2>&1; then
|
|
@@ -54,6 +54,7 @@ expect_fail() {
|
|
|
54
54
|
echo "=== Flow Kit Repository Fixture Checks ==="
|
|
55
55
|
expect_pass "valid-local-kit"
|
|
56
56
|
expect_pass "valid-unknown-extension"
|
|
57
|
+
expect_pass "valid-with-dependency"
|
|
57
58
|
expect_fail "invalid-schema-version" '\.schema_version must be "1\.0"'
|
|
58
59
|
expect_fail "invalid-missing-schema-version" '\.schema_version must be "1\.0"'
|
|
59
60
|
expect_fail "invalid-id" '\.id must be a kebab-case string'
|
|
@@ -66,6 +67,7 @@ expect_fail "invalid-malformed-json" 'invalid JSON'
|
|
|
66
67
|
expect_fail "invalid-asset-section" '\.docs must be a list'
|
|
67
68
|
expect_fail "invalid-missing-extension-asset" 'docs\[0\]\.path points at missing asset'
|
|
68
69
|
expect_fail "invalid-duplicate-flow" "flows\\[1\\]\\.path duplicates"
|
|
70
|
+
expect_fail "invalid-bad-dependency" 'dependencies\[0\]\.kit_id must be a kebab-case'
|
|
69
71
|
|
|
70
72
|
echo ""
|
|
71
73
|
echo "=== Builder Kit Shared Validation Check ==="
|
|
@@ -135,10 +135,10 @@ TAMPER_DIR="$TMP/tamper-verify"
|
|
|
135
135
|
TAMPER_SLUG="tamper-verify-test"
|
|
136
136
|
mkdir -p "$TAMPER_DIR"
|
|
137
137
|
printf '# Test repo\n' > "$TAMPER_DIR/AGENTS.md"
|
|
138
|
-
mkdir -p "$TAMPER_DIR/.flow-agents/$TAMPER_SLUG"
|
|
138
|
+
mkdir -p "$TAMPER_DIR/.kontourai/flow-agents/$TAMPER_SLUG"
|
|
139
139
|
|
|
140
140
|
flow_agents_node "$WRITER" ensure-session \
|
|
141
|
-
--artifact-root "$TAMPER_DIR/.flow-agents" \
|
|
141
|
+
--artifact-root "$TAMPER_DIR/.kontourai/flow-agents" \
|
|
142
142
|
--task-slug "$TAMPER_SLUG" \
|
|
143
143
|
--title "Tamper verify test" \
|
|
144
144
|
--summary "Testing tamper detection at verify step." \
|
|
@@ -146,21 +146,21 @@ flow_agents_node "$WRITER" ensure-session \
|
|
|
146
146
|
--step-id verify \
|
|
147
147
|
--timestamp "2026-06-01T02:00:00Z" >/dev/null 2>&1
|
|
148
148
|
|
|
149
|
-
flow_agents_node "$WRITER" init-plan "$TAMPER_DIR/.flow-agents/$TAMPER_SLUG/$TAMPER_SLUG--deliver.md" \
|
|
149
|
+
flow_agents_node "$WRITER" init-plan "$TAMPER_DIR/.kontourai/flow-agents/$TAMPER_SLUG/$TAMPER_SLUG--deliver.md" \
|
|
150
150
|
--source-request "Test" --summary "Tamper test" \
|
|
151
151
|
--timestamp "2026-06-01T02:00:00Z" >/dev/null 2>&1
|
|
152
152
|
|
|
153
|
-
flow_agents_node "$WRITER" advance-state "$TAMPER_DIR/.flow-agents/$TAMPER_SLUG" \
|
|
153
|
+
flow_agents_node "$WRITER" advance-state "$TAMPER_DIR/.kontourai/flow-agents/$TAMPER_SLUG" \
|
|
154
154
|
--status in_progress --phase verification \
|
|
155
155
|
--summary "At verify." --next-action "Continue." \
|
|
156
156
|
--flow-definition builder.build \
|
|
157
157
|
--timestamp "2026-06-01T02:00:30Z" >/dev/null 2>&1
|
|
158
158
|
|
|
159
159
|
# Write TAMPERED trust.bundle: stored verified, evidence passing=false
|
|
160
|
-
python3 - "$TAMPER_DIR/.flow-agents/$TAMPER_SLUG/trust.bundle" << 'PY'
|
|
160
|
+
python3 - "$TAMPER_DIR/.kontourai/flow-agents/$TAMPER_SLUG/trust.bundle" << 'PY'
|
|
161
161
|
import json, sys
|
|
162
162
|
bundle = {
|
|
163
|
-
"schemaVersion":
|
|
163
|
+
"schemaVersion": 5,
|
|
164
164
|
"source": "flow-agents/workflow-sidecar",
|
|
165
165
|
"claims": [{
|
|
166
166
|
"id": "c1",
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_flowdef_union_floor_regression.sh — Union-floor regression trip-wire for
|
|
3
|
+
# the .kontourai/flow-agents/flowdef-driven-stop-gate posture.
|
|
4
|
+
#
|
|
5
|
+
# PR #215 replaced isSelectedClaim's pure if/else claim-selection predicate
|
|
6
|
+
# with a permanent UNION:
|
|
7
|
+
#
|
|
8
|
+
# ct.startsWith('workflow.') || (declaredClaimTypes != null && declaredClaimTypes.has(ct))
|
|
9
|
+
#
|
|
10
|
+
# ...plus a `gate misconfiguration:` HARD_BLOCK when an active FlowDefinition
|
|
11
|
+
# resolves to an empty expects[] (see ADR 0016, ADR 0018, and the Prior Attempt
|
|
12
|
+
# Post-Mortem in .kontourai/flow-agents/flowdef-driven-stop-gate/plan.md).
|
|
13
|
+
#
|
|
14
|
+
# Wave 1 of this plan extracted declaredClaimTypesFor() as a pure refactor of
|
|
15
|
+
# stop-goal-fit.js — the union form itself was NOT touched. This eval locks
|
|
16
|
+
# that posture in place so a future "refactor" cannot quietly narrow the union
|
|
17
|
+
# back to an if/else (which would reopen the gate-bypass-chain exploit: an
|
|
18
|
+
# empty declaredClaimTypes Set from a tampered/fake FlowDefinition would once
|
|
19
|
+
# again select ZERO claims and bundleEnforcement would silently pass).
|
|
20
|
+
#
|
|
21
|
+
# Three checks:
|
|
22
|
+
# 1. STATIC TRIP-WIRE — the union form is present on the live `return`
|
|
23
|
+
# statement inside isSelectedClaim's function body in
|
|
24
|
+
# scripts/hooks/stop-goal-fit.js (comment lines/trailing comments are
|
|
25
|
+
# stripped first so a decoy comment cannot satisfy the check).
|
|
26
|
+
# 2. EMPTY-EXPECTS GUARD — cross-referenced to evals/integration/
|
|
27
|
+
# test_gate_bypass_chain.sh, which already asserts the empty-expects ->
|
|
28
|
+
# exit 2 `gate misconfiguration:` case end-to-end (see its "Test 2" /
|
|
29
|
+
# "Test 3" sections). Not duplicated here.
|
|
30
|
+
# 3. UNION-IS-LIVE PROOF — two builder.build/verify sessions:
|
|
31
|
+
# 3a. A bundle with a declared builder.verify.tests claim (clean,
|
|
32
|
+
# re-derives verified) alongside a workflow.check.command claim
|
|
33
|
+
# (stored "verified", evidence tampered -> re-derives disputed).
|
|
34
|
+
# workflow.check.command is NOT in builder.build's verify-gate
|
|
35
|
+
# expects[], so this proves the union's `startsWith('workflow.')`
|
|
36
|
+
# baseline is live code, not dead code, for FlowDefinition-driven
|
|
37
|
+
# sessions.
|
|
38
|
+
# 3b. A SECOND bundle where the DECLARED builder.verify.tests claim
|
|
39
|
+
# itself is tampered (stored "verified", evidence re-derives
|
|
40
|
+
# disputed). builder.verify.tests does NOT start with "workflow.",
|
|
41
|
+
# so the ONLY way isSelectedClaim can select it is via the
|
|
42
|
+
# `declaredClaimTypes.has(ct)` branch of the union. Asserting
|
|
43
|
+
# exit 2 + a tamper warning naming builder.verify.tests here is
|
|
44
|
+
# direct, positive proof that declared-claim-type selection
|
|
45
|
+
# (not just the workflow.* baseline) is actually live — closing
|
|
46
|
+
# the "Check 3 can pass vacuously when build/ is absent" gap
|
|
47
|
+
# (3a alone never positively exercises the declared branch; a
|
|
48
|
+
# missing build/ would make declaredClaimTypes null everywhere
|
|
49
|
+
# and 3a's "not flagged" assertion would be trivially satisfied).
|
|
50
|
+
# Both sub-checks require flow-resolver.js (built under build/src/lib/) to exist —
|
|
51
|
+
# loadActiveFlowStep() fails open to null when build/ is absent, which
|
|
52
|
+
# would make the whole of Check 3 pass vacuously. This eval hard-fails
|
|
53
|
+
# loudly instead of silently passing in that case.
|
|
54
|
+
#
|
|
55
|
+
# Deterministic, no model spend, self-cleaning.
|
|
56
|
+
# Usage: bash evals/integration/test_flowdef_union_floor_regression.sh
|
|
57
|
+
|
|
58
|
+
set -uo pipefail
|
|
59
|
+
|
|
60
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
61
|
+
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
62
|
+
GATE_SRC="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
63
|
+
|
|
64
|
+
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|
|
65
|
+
|
|
66
|
+
TMP="$(mktemp -d)"
|
|
67
|
+
errors=0
|
|
68
|
+
_pass() { echo " ✓ $1"; }
|
|
69
|
+
_fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
70
|
+
|
|
71
|
+
cleanup() { [ -n "${TMP:-}" ] && rm -rf "$TMP"; }
|
|
72
|
+
trap cleanup EXIT
|
|
73
|
+
|
|
74
|
+
# --- helper: seed a minimal delivered workflow artifact --------------------
|
|
75
|
+
seed_repo() { # $1=dir $2=slug
|
|
76
|
+
local p="$1" slug="$2"
|
|
77
|
+
mkdir -p "$p/.kontourai/flow-agents/$slug"
|
|
78
|
+
printf '# Repo\n' > "$p/AGENTS.md"
|
|
79
|
+
STATE_FILE="$p/.kontourai/flow-agents/$slug/state.json"
|
|
80
|
+
printf '%s' "{\"schema_version\":\"1.0\",\"task_slug\":\"$slug\",\"status\":\"delivered\",\"phase\":\"done\",\"updated_at\":\"2026-06-30T00:00:00Z\",\"next_action\":{\"status\":\"done\",\"summary\":\"done\"}}" \
|
|
81
|
+
> "$STATE_FILE"
|
|
82
|
+
cat > "$p/.kontourai/flow-agents/$slug/$slug--deliver.md" << MD
|
|
83
|
+
# $slug
|
|
84
|
+
|
|
85
|
+
branch: main
|
|
86
|
+
status: delivered
|
|
87
|
+
type: deliver
|
|
88
|
+
|
|
89
|
+
## Definition Of Done
|
|
90
|
+
- [x] tests pass
|
|
91
|
+
|
|
92
|
+
## Goal Fit Gate
|
|
93
|
+
- [x] acceptance verified
|
|
94
|
+
|
|
95
|
+
### Verdict: PASS
|
|
96
|
+
MD
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# --- Check 1: STATIC TRIP-WIRE - union form present inside isSelectedClaim -
|
|
100
|
+
echo "Check 1: static trip-wire - union form present inside isSelectedClaim() in stop-goal-fit.js"
|
|
101
|
+
|
|
102
|
+
# Isolate the isSelectedClaim function body (from its declaration to its
|
|
103
|
+
# closing brace) rather than grepping the whole file, so this trip-wire fails
|
|
104
|
+
# loudly if the union is removed from the function even if the literal string
|
|
105
|
+
# "startsWith('workflow.')" survives elsewhere (e.g. in a comment or a
|
|
106
|
+
# different, narrower predicate).
|
|
107
|
+
isSelectedClaim_body="$(awk '/const isSelectedClaim = \(claim\)/{flag=1} flag{print} flag && /^ \};/{exit}' "$GATE_SRC")"
|
|
108
|
+
|
|
109
|
+
# Strip comments (full-line comments AND trailing "// ..." comments) from the
|
|
110
|
+
# isolated body before inspecting it, then anchor the check to the live
|
|
111
|
+
# `return` statement specifically. Without this, a decoy comment anywhere in
|
|
112
|
+
# the function body (e.g. `// ct.startsWith('workflow.') || ...` left behind
|
|
113
|
+
# after narrowing the real predicate to an if/else) would still satisfy a
|
|
114
|
+
# plain `grep -q "startsWith('workflow.')"` against the whole body and let
|
|
115
|
+
# this trip-wire pass vacuously.
|
|
116
|
+
isSelectedClaim_body_nocomments="$(echo "$isSelectedClaim_body" | sed 's|//.*$||')"
|
|
117
|
+
isSelectedClaim_return_line="$(echo "$isSelectedClaim_body_nocomments" | grep -E '^[[:space:]]*return\b')"
|
|
118
|
+
|
|
119
|
+
if [ -z "$isSelectedClaim_body" ]; then
|
|
120
|
+
_fail "could not locate isSelectedClaim() in scripts/hooks/stop-goal-fit.js -- function renamed or removed"
|
|
121
|
+
echo " This regresses PR #215 / ADR 0016 / ADR 0018. See the Prior Attempt Post-Mortem in"
|
|
122
|
+
echo " .kontourai/flow-agents/flowdef-driven-stop-gate/plan.md: the union claim-selection"
|
|
123
|
+
echo " predicate must remain a permanent, named, testable function."
|
|
124
|
+
elif [ -n "$isSelectedClaim_return_line" ] \
|
|
125
|
+
&& echo "$isSelectedClaim_return_line" | grep -q "startsWith('workflow.')" \
|
|
126
|
+
&& echo "$isSelectedClaim_return_line" | grep -q "declaredClaimTypes"; then
|
|
127
|
+
_pass "isSelectedClaim()'s return statement contains the workflow.* union baseline (startsWith('workflow.') + declaredClaimTypes, comment-stripped)"
|
|
128
|
+
else
|
|
129
|
+
_fail "isSelectedClaim()'s return statement no longer contains the union baseline -- union narrowed back toward if/else (or moved into a comment)"
|
|
130
|
+
echo " This regresses PR #215 / ADR 0016 / ADR 0018. Per the Prior Attempt Post-Mortem in"
|
|
131
|
+
echo " .kontourai/flow-agents/flowdef-driven-stop-gate/plan.md: isSelectedClaim MUST stay a"
|
|
132
|
+
echo " UNION -- \`ct.startsWith('workflow.') || (declaredClaimTypes != null && declaredClaimTypes.has(ct))\`"
|
|
133
|
+
echo " -- never a pure if/else. An if/else lets an empty (non-null) declaredClaimTypes Set"
|
|
134
|
+
echo " (e.g. from a tampered/fake FlowDefinition with expects:[]) select ZERO claims and"
|
|
135
|
+
echo " silently bypass bundleEnforcement (the original gate-bypass-chain exploit)."
|
|
136
|
+
echo " isSelectedClaim() body found:"
|
|
137
|
+
echo "$isSelectedClaim_body" | sed 's/^/ /'
|
|
138
|
+
echo " comment-stripped return statement found:"
|
|
139
|
+
echo "${isSelectedClaim_return_line:-<none>}" | sed 's/^/ /'
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# --- Check 2: EMPTY-EXPECTS GUARD - cross-referenced, not duplicated -------
|
|
143
|
+
# evals/integration/test_gate_bypass_chain.sh already seeds an active
|
|
144
|
+
# builder.build/verify session whose active FlowDefinition resolves to an
|
|
145
|
+
# empty expects[] (via FLOW_AGENTS_FLOW_DEFS_DIR override to a fake flow) and
|
|
146
|
+
# asserts BOTH exit code 2 AND a `gate misconfiguration:` warning in its
|
|
147
|
+
# "=== 2. Layer 2 -- Empty-Set defense ===" section (test 2b), and again
|
|
148
|
+
# end-to-end in its "=== 3. Full exploit chain ===" section. See AC3 Part 2 in
|
|
149
|
+
# stop-goal-fit.js's bundleEnforcement comment block. Not duplicated here to
|
|
150
|
+
# avoid two evals asserting the same fixture drifting out of sync.
|
|
151
|
+
echo ""
|
|
152
|
+
echo "Check 2: empty-expects guard -- cross-referenced to evals/integration/test_gate_bypass_chain.sh (not duplicated)"
|
|
153
|
+
_pass "empty-expects -> exit 2 'gate misconfiguration:' already covered by test_gate_bypass_chain.sh (Test 2 / Test 3)"
|
|
154
|
+
|
|
155
|
+
# --- Check 3: UNION-IS-LIVE PROOF -------------------------------------------
|
|
156
|
+
echo ""
|
|
157
|
+
echo "Check 3: union-is-live proof -- FlowDefinition-driven claim selection actually runs (not fail-open null)"
|
|
158
|
+
|
|
159
|
+
# Prerequisite: loadActiveFlowStep() in stop-goal-fit.js fails open to null
|
|
160
|
+
# when flow-resolver.js (built under build/src/lib/) is absent (hasBuild guard). If build/
|
|
161
|
+
# is missing, declaredClaimTypes is null for every session below, the
|
|
162
|
+
# declared builder.verify.tests branch of the union is never exercised, and
|
|
163
|
+
# this whole check would pass vacuously (the "not flagged" assertions in 3a
|
|
164
|
+
# are satisfied trivially when nothing can ever be selected via the declared
|
|
165
|
+
# branch). Fail loudly instead of silently passing.
|
|
166
|
+
BUILT_RESOLVER="$ROOT/build/src/li""b/flow-resolver.js"
|
|
167
|
+
if [ ! -f "$BUILT_RESOLVER" ]; then
|
|
168
|
+
echo " ✗ FATAL: build/src/li""b/flow-resolver.js is missing -- this eval requires npm run build; refusing to vacuously pass." >&2
|
|
169
|
+
echo " Without build/, loadActiveFlowStep() fails open to null, declaredClaimTypes is null" >&2
|
|
170
|
+
echo " everywhere, the declared builder.verify.tests claim is never selected via the union's" >&2
|
|
171
|
+
echo " declared-type branch, and Check 3 would pass without ever exercising" >&2
|
|
172
|
+
echo " FlowDefinition-driven claim selection. Run: npm run build" >&2
|
|
173
|
+
exit 1
|
|
174
|
+
fi
|
|
175
|
+
_pass "prerequisite: build/src/li""b/flow-resolver.js is present -- FlowDefinition resolution is live for this run"
|
|
176
|
+
|
|
177
|
+
# --- Check 3a: undeclared workflow.* claim still blocks a builder.build ----
|
|
178
|
+
# session even though workflow.check.command is NOT declared by builder.build's
|
|
179
|
+
# verify-gate expects[] (which only declares builder.verify.tests and
|
|
180
|
+
# builder.verify.policy-compliance -- see kits/builder/flows/build.flow.json).
|
|
181
|
+
echo ""
|
|
182
|
+
echo "Check 3a: undeclared workflow.check.command claim still blocks a builder.build/verify session"
|
|
183
|
+
|
|
184
|
+
T3_DIR="$TMP/t3-union-live"
|
|
185
|
+
seed_repo "$T3_DIR" "union-live-test"
|
|
186
|
+
|
|
187
|
+
CURRENT_FILE="$T3_DIR/.kontourai/flow-agents/current.json"
|
|
188
|
+
printf '%s' '{"artifact_dir":"union-live-test","active_flow_id":"builder.build","active_step_id":"verify"}' \
|
|
189
|
+
> "$CURRENT_FILE"
|
|
190
|
+
|
|
191
|
+
python3 - "$T3_DIR/.kontourai/flow-agents/union-live-test/trust.bundle" << 'PY'
|
|
192
|
+
import json, sys
|
|
193
|
+
bundle = {
|
|
194
|
+
"schemaVersion": 3,
|
|
195
|
+
"source": "flow-agents/workflow-sidecar",
|
|
196
|
+
"claims": [
|
|
197
|
+
{
|
|
198
|
+
# Declared by builder.build's verify-gate expects[] -- clean, must NOT block.
|
|
199
|
+
"id": "c-declared",
|
|
200
|
+
"subjectId": "union-live-test/tests",
|
|
201
|
+
"subjectType": "flow-step",
|
|
202
|
+
"claimType": "builder.verify.tests",
|
|
203
|
+
"fieldOrBehavior": "build/verify tests",
|
|
204
|
+
"value": "pass",
|
|
205
|
+
"impactLevel": "high",
|
|
206
|
+
"status": "verified",
|
|
207
|
+
"createdAt": "2026-06-30T00:00:00Z",
|
|
208
|
+
"updatedAt": "2026-06-30T00:00:00Z"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
# NOT declared by builder.build's verify-gate expects[] -- only reachable via
|
|
212
|
+
# the union's workflow.* baseline. Stored "verified" but tampered: evidence
|
|
213
|
+
# re-derives to disputed. Must BLOCK if (and only if) the union is live.
|
|
214
|
+
"id": "c-undeclared-workflow",
|
|
215
|
+
"subjectId": "union-live-test/unit-tests",
|
|
216
|
+
"subjectType": "workflow-check",
|
|
217
|
+
"claimType": "workflow.check.command",
|
|
218
|
+
"fieldOrBehavior": "unit tests",
|
|
219
|
+
"value": "pass",
|
|
220
|
+
"impactLevel": "high",
|
|
221
|
+
"status": "verified", # tampered: edited from "disputed" -> "verified"
|
|
222
|
+
"createdAt": "2026-06-30T00:00:00Z",
|
|
223
|
+
"updatedAt": "2026-06-30T00:00:00Z"
|
|
224
|
+
}
|
|
225
|
+
],
|
|
226
|
+
"evidence": [
|
|
227
|
+
{
|
|
228
|
+
"id": "ev-declared",
|
|
229
|
+
"claimId": "c-declared",
|
|
230
|
+
"evidenceType": "test_output",
|
|
231
|
+
"method": "validation",
|
|
232
|
+
"sourceRef": "command-log.jsonl",
|
|
233
|
+
"excerptOrSummary": "npm test passed",
|
|
234
|
+
"observedAt": "2026-06-30T00:00:00Z",
|
|
235
|
+
"collectedBy": "harness",
|
|
236
|
+
"passing": True,
|
|
237
|
+
"blocking": False
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"id": "ev-undeclared-workflow",
|
|
241
|
+
"claimId": "c-undeclared-workflow",
|
|
242
|
+
"evidenceType": "test_output",
|
|
243
|
+
"method": "validation",
|
|
244
|
+
"sourceRef": "command-log.jsonl",
|
|
245
|
+
"excerptOrSummary": "npm test failed with exit 1",
|
|
246
|
+
"observedAt": "2026-06-30T00:00:00Z",
|
|
247
|
+
"collectedBy": "harness",
|
|
248
|
+
"passing": False,
|
|
249
|
+
"blocking": True
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
"policies": [],
|
|
253
|
+
"events": [
|
|
254
|
+
{
|
|
255
|
+
"id": "evt-declared",
|
|
256
|
+
"claimId": "c-declared",
|
|
257
|
+
"status": "verified",
|
|
258
|
+
"actor": "agent",
|
|
259
|
+
"method": "workflow-check",
|
|
260
|
+
"evidenceIds": ["ev-declared"],
|
|
261
|
+
"createdAt": "2026-06-30T00:00:00Z"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"id": "evt-undeclared-workflow",
|
|
265
|
+
"claimId": "c-undeclared-workflow",
|
|
266
|
+
"status": "verified",
|
|
267
|
+
"actor": "agent",
|
|
268
|
+
"method": "workflow-check",
|
|
269
|
+
"evidenceIds": ["ev-undeclared-workflow"],
|
|
270
|
+
"createdAt": "2026-06-30T00:00:00Z"
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
json.dump(bundle, open(sys.argv[1], 'w'))
|
|
275
|
+
PY
|
|
276
|
+
|
|
277
|
+
set +e
|
|
278
|
+
t3_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip \
|
|
279
|
+
node "$GATE" 2>&1 <<< "{\"hook_event_name\":\"Stop\",\"cwd\":\"$T3_DIR\"}")"
|
|
280
|
+
t3_exit="$?"
|
|
281
|
+
set -e
|
|
282
|
+
|
|
283
|
+
if [ "$t3_exit" -eq 2 ]; then
|
|
284
|
+
_pass "builder.build/verify session with tampered undeclared workflow.check.command claim BLOCKS (exit 2)"
|
|
285
|
+
else
|
|
286
|
+
_fail "builder.build/verify session did NOT block on the undeclared workflow.* claim: exit=$t3_exit output=$t3_out"
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
if echo "$t3_out" | grep -q "caught false-completion"; then
|
|
290
|
+
_pass "union-is-live: emits caught false-completion"
|
|
291
|
+
else
|
|
292
|
+
_fail "union-is-live: missing caught false-completion: $t3_out"
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
if echo "$t3_out" | grep -q "workflow.check.command"; then
|
|
296
|
+
_pass "union-is-live: warning names the undeclared claimType workflow.check.command"
|
|
297
|
+
else
|
|
298
|
+
_fail "union-is-live: warning does not mention workflow.check.command: $t3_out"
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
if echo "$t3_out" | grep -q "builder.verify.tests"; then
|
|
302
|
+
_fail "union-is-live: the clean declared builder.verify.tests claim was incorrectly flagged too: $t3_out"
|
|
303
|
+
else
|
|
304
|
+
_pass "union-is-live: the clean declared builder.verify.tests claim is not flagged (only the undeclared workflow.* claim blocks)"
|
|
305
|
+
fi
|
|
306
|
+
|
|
307
|
+
# Additive (iteration 5 fix pass, MEDIUM/reviewer): gateLabel()'s FlowDefinition-active
|
|
308
|
+
# branch ("[<flowId>/<gateId>]") had zero eval coverage. This session's current.json
|
|
309
|
+
# names active_flow_id=builder.build / active_step_id=verify (set above), so the Stop
|
|
310
|
+
# hook's stderr must be prefixed with the resolved gate identity instead of the generic
|
|
311
|
+
# "[stop-gate]" fallback -- and since this scenario also produces a claimed-pass-never-
|
|
312
|
+
# captured warning (FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip), the per-gap remediation guidance
|
|
313
|
+
# line is asserted too (cheap, same output, message-assembly only -- no new fixture).
|
|
314
|
+
if echo "$t3_out" | grep -q "\[builder.build/verify-gate\]"; then
|
|
315
|
+
_pass "union-is-live: Stop hook stderr is prefixed with the resolved gate identity [builder.build/verify-gate]"
|
|
316
|
+
else
|
|
317
|
+
_fail "union-is-live: missing the gate-named prefix [builder.build/verify-gate]: $t3_out"
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
if echo "$t3_out" | grep -q ' → run the command in this session'; then
|
|
321
|
+
_pass "union-is-live: per-gap remediation guidance line is present for the claimed-pass-never-captured warning"
|
|
322
|
+
else
|
|
323
|
+
_fail "union-is-live: missing the per-gap remediation guidance line: $t3_out"
|
|
324
|
+
fi
|
|
325
|
+
|
|
326
|
+
# --- Check 3b: tampered DECLARED claim proves declaredClaimTypes selection --
|
|
327
|
+
# is actually live (positive proof, not just "not flagged" by omission). This
|
|
328
|
+
# closes the vacuous-pass gap: 3a alone never forces the declared branch of
|
|
329
|
+
# the union (`declaredClaimTypes.has(ct)`) to fire and block anything, so a
|
|
330
|
+
# broken/dead declared-type selector (or a null declaredClaimTypes from a
|
|
331
|
+
# missing build/) could still make 3a's assertions pass. builder.verify.tests
|
|
332
|
+
# does NOT start with "workflow.", so this claim can ONLY be selected via the
|
|
333
|
+
# declared branch -- if it blocks, the declared branch is demonstrably live.
|
|
334
|
+
echo ""
|
|
335
|
+
echo "Check 3b: tampered DECLARED builder.verify.tests claim blocks -- proves declaredClaimTypes selection is live"
|
|
336
|
+
|
|
337
|
+
T3B_DIR="$TMP/t3b-declared-live"
|
|
338
|
+
seed_repo "$T3B_DIR" "declared-live-test"
|
|
339
|
+
|
|
340
|
+
CURRENT_FILE_3B="$T3B_DIR/.kontourai/flow-agents/current.json"
|
|
341
|
+
printf '%s' '{"artifact_dir":"declared-live-test","active_flow_id":"builder.build","active_step_id":"verify"}' \
|
|
342
|
+
> "$CURRENT_FILE_3B"
|
|
343
|
+
|
|
344
|
+
python3 - "$T3B_DIR/.kontourai/flow-agents/declared-live-test/trust.bundle" << 'PY'
|
|
345
|
+
import json, sys
|
|
346
|
+
bundle = {
|
|
347
|
+
"schemaVersion": 3,
|
|
348
|
+
"source": "flow-agents/workflow-sidecar",
|
|
349
|
+
"claims": [
|
|
350
|
+
{
|
|
351
|
+
# The ONLY claim in this bundle, and it does NOT start with "workflow.".
|
|
352
|
+
# Selecting it at all requires declaredClaimTypes != null && .has(ct) --
|
|
353
|
+
# i.e. requires a live, resolved active FlowDefinition. Stored "verified"
|
|
354
|
+
# but tampered: evidence re-derives to disputed. Must BLOCK if (and only
|
|
355
|
+
# if) the declared-type half of the union is live.
|
|
356
|
+
"id": "c-declared-tampered",
|
|
357
|
+
"subjectId": "declared-live-test/tests",
|
|
358
|
+
"subjectType": "flow-step",
|
|
359
|
+
"claimType": "builder.verify.tests",
|
|
360
|
+
"fieldOrBehavior": "build/verify tests",
|
|
361
|
+
"value": "pass",
|
|
362
|
+
"impactLevel": "high",
|
|
363
|
+
"status": "verified", # tampered: edited from "disputed" -> "verified"
|
|
364
|
+
"createdAt": "2026-06-30T00:00:00Z",
|
|
365
|
+
"updatedAt": "2026-06-30T00:00:00Z"
|
|
366
|
+
}
|
|
367
|
+
],
|
|
368
|
+
"evidence": [
|
|
369
|
+
{
|
|
370
|
+
"id": "ev-declared-tampered",
|
|
371
|
+
"claimId": "c-declared-tampered",
|
|
372
|
+
"evidenceType": "test_output",
|
|
373
|
+
"method": "validation",
|
|
374
|
+
"sourceRef": "command-log.jsonl",
|
|
375
|
+
"excerptOrSummary": "npm test failed with exit 1",
|
|
376
|
+
"observedAt": "2026-06-30T00:00:00Z",
|
|
377
|
+
"collectedBy": "harness",
|
|
378
|
+
"passing": False,
|
|
379
|
+
"blocking": True
|
|
380
|
+
}
|
|
381
|
+
],
|
|
382
|
+
"policies": [],
|
|
383
|
+
"events": [
|
|
384
|
+
{
|
|
385
|
+
"id": "evt-declared-tampered",
|
|
386
|
+
"claimId": "c-declared-tampered",
|
|
387
|
+
"status": "verified",
|
|
388
|
+
"actor": "agent",
|
|
389
|
+
"method": "workflow-check",
|
|
390
|
+
"evidenceIds": ["ev-declared-tampered"],
|
|
391
|
+
"createdAt": "2026-06-30T00:00:00Z"
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
}
|
|
395
|
+
json.dump(bundle, open(sys.argv[1], 'w'))
|
|
396
|
+
PY
|
|
397
|
+
|
|
398
|
+
set +e
|
|
399
|
+
t3b_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip \
|
|
400
|
+
node "$GATE" 2>&1 <<< "{\"hook_event_name\":\"Stop\",\"cwd\":\"$T3B_DIR\"}")"
|
|
401
|
+
t3b_exit="$?"
|
|
402
|
+
set -e
|
|
403
|
+
|
|
404
|
+
if [ "$t3b_exit" -eq 2 ]; then
|
|
405
|
+
_pass "builder.build/verify session with tampered DECLARED builder.verify.tests claim BLOCKS (exit 2) -- declaredClaimTypes selection is live, not vacuous"
|
|
406
|
+
else
|
|
407
|
+
_fail "builder.build/verify session did NOT block on the tampered DECLARED builder.verify.tests claim (declaredClaimTypes selection may be dead or null): exit=$t3b_exit output=$t3b_out"
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
if echo "$t3b_out" | grep -q "builder.verify.tests"; then
|
|
411
|
+
_pass "declared-claim-live: warning names the declared claimType builder.verify.tests"
|
|
412
|
+
else
|
|
413
|
+
_fail "declared-claim-live: warning does not mention builder.verify.tests: $t3b_out"
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
if echo "$t3b_out" | grep -q "tampered" || echo "$t3b_out" | grep -q "caught false-completion"; then
|
|
417
|
+
_pass "declared-claim-live: emits tampered/caught false-completion signal for the declared claim"
|
|
418
|
+
else
|
|
419
|
+
_fail "declared-claim-live: missing tampered/caught false-completion signal: $t3b_out"
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
# --- Summary -----------------------------------------------------------------
|
|
423
|
+
echo ""
|
|
424
|
+
if [ "$errors" -eq 0 ]; then
|
|
425
|
+
echo "Union-floor regression trip-wire passed: PR #215 posture intact (union live, empty-expects guard cross-referenced, declared-claim selection positively proven live)."
|
|
426
|
+
exit 0
|
|
427
|
+
fi
|
|
428
|
+
echo "Union-floor regression trip-wire FAILED: $errors issue(s). This may indicate a regression of PR #215 / ADR 0016 / ADR 0018 -- see .kontourai/flow-agents/flowdef-driven-stop-gate/plan.md Prior Attempt Post-Mortem."
|
|
429
|
+
exit 1
|