@kontourai/flow-agents 3.9.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +8 -0
- package/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/build/src/cli/assignment-provider.js +4 -18
- package/build/src/cli/continuation-adapter.d.ts +10 -8
- package/build/src/cli/continuation-adapter.js +22 -4
- package/build/src/cli/validate-workflow-artifacts.js +21 -1
- package/build/src/cli/workflow-sidecar.js +15 -20
- package/build/src/cli/workflow.js +58 -11
- package/build/src/continuation-driver.d.ts +27 -3
- package/build/src/continuation-driver.js +97 -14
- package/build/src/index.d.ts +2 -2
- package/build/src/index.js +1 -1
- package/build/src/tools/build-universal-bundles.js +52 -25
- package/build/src/tools/validate-source-tree.js +5 -2
- package/context/scripts/hooks/lib/continuation-turn-authority.js +386 -0
- package/context/scripts/hooks/stop-goal-fit.js +244 -73
- package/context/scripts/hooks/workflow-steering.js +24 -15
- package/context/scripts/telemetry/lib/pricing.sh +18 -6
- package/context/scripts/telemetry/lib/transport.sh +139 -37
- package/context/scripts/telemetry/lib/usage.sh +282 -32
- package/context/scripts/telemetry/lib/usage_model_guard.sh +42 -0
- package/context/scripts/telemetry/telemetry.sh +76 -1
- package/docs/coordination-guide.md +21 -5
- package/docs/fixture-ownership.md +2 -1
- package/docs/public-workflow-cli.md +44 -0
- package/docs/spec/runtime-hook-surface.md +8 -4
- package/evals/acceptance/prove-capture-teeth-declared.sh +13 -0
- package/evals/acceptance/prove-capture-teeth.sh +13 -0
- package/evals/ci/run-baseline.sh +2 -0
- package/evals/fixtures/codex-legacy-agents/5273878130bdafc8a024a650bb5b66c9b003f1f859b5dc6e5b588cbf4ab23228.md +25 -0
- package/evals/fixtures/telemetry/usage-transcript-adversarial.jsonl +2 -0
- package/evals/fixtures/telemetry/usage-transcript-malformed-sandwich.jsonl +3 -0
- package/evals/fixtures/telemetry/usage-transcript-negative-tokens.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-oversized-prefix.jsonl +201 -0
- package/evals/fixtures/telemetry/usage-transcript-oversized-tokens.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-prefixed-secret-lower.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-prefixed-secret-upper.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-secret-model-jwt.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-secret-model.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-torn-trailing.jsonl +2 -0
- package/evals/integration/test_actor_identity.sh +63 -0
- package/evals/integration/test_assignment_provider_local_file.sh +34 -0
- package/evals/integration/test_builder_entry_enforcement.sh +5 -1
- package/evals/integration/test_bundle_install.sh +106 -17
- package/evals/integration/test_bundle_lifecycle.sh +17 -3
- package/evals/integration/test_captured_fail_reconciliation.sh +11 -0
- package/evals/integration/test_ci_actor_identity.sh +2 -2
- package/evals/integration/test_command_log_concurrency.sh +11 -0
- package/evals/integration/test_command_log_fork_classification.sh +11 -0
- package/evals/integration/test_command_log_integrity.sh +11 -0
- package/evals/integration/test_current_json_per_actor.sh +416 -21
- package/evals/integration/test_enforcer_expects_driven.sh +11 -0
- package/evals/integration/test_ensure_session_ownership_guard.sh +39 -0
- package/evals/integration/test_evidence_capture_hook.sh +25 -6
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flowdef_union_floor_regression.sh +11 -0
- package/evals/integration/test_gate_bypass_chain.sh +11 -0
- package/evals/integration/test_gate_lockdown.sh +10 -0
- package/evals/integration/test_goal_fit_ghost_session.sh +11 -0
- package/evals/integration/test_goal_fit_hook.sh +257 -9
- package/evals/integration/test_goal_fit_rederive.sh +11 -0
- package/evals/integration/test_install_merge.sh +141 -3
- package/evals/integration/test_liveness_conflict_injection.sh +39 -3
- package/evals/integration/test_liveness_heartbeat.sh +46 -9
- package/evals/integration/test_phase_map_and_gate_claim.sh +10 -1
- package/evals/integration/test_public_workflow_cli.sh +6 -6
- package/evals/integration/test_session_resume_roundtrip.sh +30 -0
- package/evals/integration/test_stop_hook_release.sh +111 -11
- package/evals/integration/test_telemetry_tool_usage.sh +394 -0
- package/evals/integration/test_verify_hold.sh +64 -1
- package/evals/integration/test_workflow_sidecar_writer.sh +10 -1
- package/evals/integration/test_workflow_steering_hook.sh +20 -4
- package/evals/run.sh +2 -0
- package/evals/static/test_universal_bundles.sh +123 -0
- package/package.json +1 -1
- package/packaging/README.md +21 -0
- package/packaging/codex-legacy-agents-fingerprints.json +33 -0
- package/scripts/README.md +2 -1
- package/scripts/audit-codex-legacy-agents.js +43 -0
- package/scripts/classify-codex-legacy-agents.js +71 -0
- package/scripts/hooks/evidence-capture.js +18 -6
- package/scripts/hooks/lib/actor-identity.js +62 -29
- package/scripts/hooks/lib/continuation-turn-authority.js +386 -0
- package/scripts/hooks/lib/current-pointer.js +114 -12
- package/scripts/hooks/lib/liveness-heartbeat.js +15 -12
- package/scripts/hooks/stop-goal-fit.js +244 -73
- package/scripts/hooks/workflow-steering.js +24 -15
- package/scripts/install-codex-home.sh +8 -7
- package/scripts/telemetry/lib/pricing.sh +18 -6
- package/scripts/telemetry/lib/transport.sh +71 -0
- package/scripts/telemetry/lib/usage.sh +282 -32
- package/scripts/telemetry/lib/usage_model_guard.sh +42 -0
- package/scripts/telemetry/telemetry.sh +76 -1
- package/src/cli/assignment-provider.ts +5 -26
- package/src/cli/builder-flow-runtime.test.mjs +93 -6
- package/src/cli/continuation-adapter.ts +33 -7
- package/src/cli/continuation-driver.test.mjs +741 -2
- package/src/cli/public-api.test.mjs +1 -0
- package/src/cli/validate-workflow-artifacts.ts +19 -1
- package/src/cli/workflow-sidecar.ts +18 -23
- package/src/cli/workflow.ts +71 -11
- package/src/continuation-driver.ts +125 -19
- package/src/index.ts +4 -0
- package/src/tools/build-universal-bundles.ts +61 -25
- package/src/tools/validate-source-tree.ts +5 -2
|
@@ -11,6 +11,10 @@ set -uo pipefail
|
|
|
11
11
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
12
12
|
CAPTURE="$ROOT/scripts/hooks/evidence-capture.js"
|
|
13
13
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
14
|
+
CURRENT_POINTER_HELPER="$ROOT/scripts/hooks/lib/current-pointer.js"
|
|
15
|
+
# #440: every fixture this file builds is "owned" by this one constant actor, once a given
|
|
16
|
+
# invocation below applies FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" to it (see seed_repo/capture()).
|
|
17
|
+
EVIDENCE_ACTOR="eval-evidence-capture-actor"
|
|
14
18
|
|
|
15
19
|
# Disable the block escape hatch so repeated independent assertions never trip it.
|
|
16
20
|
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|
|
@@ -41,10 +45,21 @@ type: deliver
|
|
|
41
45
|
|
|
42
46
|
### Verdict: PASS
|
|
43
47
|
MD
|
|
48
|
+
# #440 FIXTURE-GAP: seed EVIDENCE_ACTOR's own per-actor current pointer for this repo/slug,
|
|
49
|
+
# unconditionally (harmless/unused for any invocation below that does NOT set
|
|
50
|
+
# FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR") -- mirroring workflow-sidecar.ts's real writeCurrent()
|
|
51
|
+
# dual-write via current-pointer.js's own writePerActorCurrent, so #440's ownership-scoped
|
|
52
|
+
# resolveArtifactDir/preferredArtifactDir find this fixture's session exactly like a real
|
|
53
|
+
# ensure-session'd one would.
|
|
54
|
+
CP_HELPER_ARG="$CURRENT_POINTER_HELPER" FLOW_AGENTS_DIR_ARG="$p/.kontourai/flow-agents" \
|
|
55
|
+
SLUG_ARG="$slug" ACTOR_ARG="$EVIDENCE_ACTOR" node - <<'NODE'
|
|
56
|
+
const { writePerActorCurrent } = require(process.env.CP_HELPER_ARG);
|
|
57
|
+
writePerActorCurrent(process.env.FLOW_AGENTS_DIR_ARG, process.env.ACTOR_ARG, { active_slug: process.env.SLUG_ARG });
|
|
58
|
+
NODE
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
capture() { # stdin = payload json
|
|
47
|
-
node "$CAPTURE" >/dev/null 2>&1
|
|
62
|
+
FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" node "$CAPTURE" >/dev/null 2>&1
|
|
48
63
|
}
|
|
49
64
|
|
|
50
65
|
# ============================================================================
|
|
@@ -103,7 +118,7 @@ B="$TMP/contradict"; seed_repo "$B" t1
|
|
|
103
118
|
printf '%s' '{"schema_version":"1.0","task_slug":"t1","verdict":"pass","checks":[{"id":"unit-tests","kind":"command","status":"pass","command":"npm test","summary":"tests passed"}]}' > "$B/.kontourai/flow-agents/t1/evidence.json"
|
|
104
119
|
printf '%s\n' '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-23T00:00:00Z","source":"postToolUse-capture"}' > "$B/.kontourai/flow-agents/t1/command-log.jsonl"
|
|
105
120
|
|
|
106
|
-
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip node "$GATE" >/dev/null 2>"$TMP/b1.err" <<JSON
|
|
121
|
+
if FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip node "$GATE" >/dev/null 2>"$TMP/b1.err" <<JSON
|
|
107
122
|
{"hook_event_name":"Stop","cwd":"$B"}
|
|
108
123
|
JSON
|
|
109
124
|
then _fail "gate should BLOCK when capture log contradicts claimed pass"
|
|
@@ -124,7 +139,11 @@ printf '%s\n' '{"command":"npm test","observedResult":"pass","exitCode":0,"captu
|
|
|
124
139
|
# A poisoned npm on PATH proves the gate does NOT re-run when the log confirms.
|
|
125
140
|
POISON="$TMP/poison"; mkdir -p "$POISON"
|
|
126
141
|
printf '#!/usr/bin/env bash\necho "npm should not run" >&2\nexit 99\n' > "$POISON/npm"; chmod +x "$POISON/npm"
|
|
127
|
-
|
|
142
|
+
# #440 FIX 2 (de-vacuate, independent review): apply EVIDENCE_ACTOR so the gate actually resolves
|
|
143
|
+
# repo C's session (seed_repo already seeded EVIDENCE_ACTOR's own pointer for it) and reaches the
|
|
144
|
+
# capture cross-reference / confirmed-pass-trusts-the-log logic, not the outer "no artifactDir at
|
|
145
|
+
# all" early-return (which would also never re-run npm, for an unrelated reason).
|
|
146
|
+
PATH="$POISON:$PATH" FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" FLOW_AGENTS_GOAL_FIT_MODE=block node "$GATE" >/dev/null 2>"$TMP/b2.err" <<JSON
|
|
128
147
|
{"hook_event_name":"Stop","cwd":"$C"}
|
|
129
148
|
JSON
|
|
130
149
|
if rg -q 'CONTRADICTS|backstop|npm should not run' "$TMP/b2.err"; then
|
|
@@ -140,7 +159,7 @@ printf '%s' '{"name":"x","scripts":{"test":"exit 7"}}' > "$D/package.json"
|
|
|
140
159
|
printf '%s' '{"schema_version":"1.0","task_slug":"t1","verdict":"pass","checks":[{"id":"unit-tests","kind":"command","status":"pass","command":"npm test","summary":"tests passed"}]}' > "$D/.kontourai/flow-agents/t1/evidence.json"
|
|
141
160
|
# command-log.jsonl intentionally absent — the command was never actually run.
|
|
142
161
|
|
|
143
|
-
if FLOW_AGENTS_GOAL_FIT_MODE=block node "$GATE" >/dev/null 2>"$TMP/b3.err" <<JSON
|
|
162
|
+
if FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" FLOW_AGENTS_GOAL_FIT_MODE=block node "$GATE" >/dev/null 2>"$TMP/b3.err" <<JSON
|
|
144
163
|
{"hook_event_name":"Stop","cwd":"$D"}
|
|
145
164
|
JSON
|
|
146
165
|
then _fail "gate should BLOCK when trusted backstop re-run of declared manifest target fails"
|
|
@@ -159,7 +178,7 @@ E="$TMP/notverified"; seed_repo "$E" t1
|
|
|
159
178
|
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"}}' > "$E/.kontourai/flow-agents/t1/state.json"
|
|
160
179
|
printf '%s' '{"schema_version":"1.0","task_slug":"t1","verdict":"pass","checks":[{"id":"custom","kind":"command","status":"pass","command":"./my-thing.sh","summary":"ran custom"}]}' > "$E/.kontourai/flow-agents/t1/evidence.json"
|
|
161
180
|
|
|
162
|
-
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_RECHECK=false node "$GATE" >/dev/null 2>"$TMP/b4.err" <<JSON
|
|
181
|
+
if FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_RECHECK=false node "$GATE" >/dev/null 2>"$TMP/b4.err" <<JSON
|
|
163
182
|
{"hook_event_name":"Stop","cwd":"$E"}
|
|
164
183
|
JSON
|
|
165
184
|
then _fail "gate should not silently pass an un-captured, un-verifiable claimed-pass command"
|
|
@@ -182,7 +201,7 @@ F="$TMP/recheck"; seed_repo "$F" t1
|
|
|
182
201
|
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"
|
|
183
202
|
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"
|
|
184
203
|
# Opt-in ON (in-flight): the model's free-form "exit 5" is re-run and fails → block.
|
|
185
|
-
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_RECHECK=true node "$GATE" >/dev/null 2>"$TMP/b5.err" <<JSON
|
|
204
|
+
if FLOW_AGENTS_ACTOR="$EVIDENCE_ACTOR" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_RECHECK=true node "$GATE" >/dev/null 2>"$TMP/b5.err" <<JSON
|
|
186
205
|
{"hook_event_name":"Stop","cwd":"$F"}
|
|
187
206
|
JSON
|
|
188
207
|
then _fail "with RECHECK=true the failing model command should block"
|
|
@@ -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")" == "20" ]] && 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")" == "20" ]] && 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");
|
|
@@ -59,6 +59,17 @@ set -uo pipefail
|
|
|
59
59
|
|
|
60
60
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
61
61
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
62
|
+
|
|
63
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
64
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
65
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
66
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
67
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
68
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
69
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
70
|
+
# global-scan discovery every assertion below was written against).
|
|
71
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
72
|
+
export NODE_ENV=test
|
|
62
73
|
GATE_SRC="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
63
74
|
|
|
64
75
|
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|
|
@@ -33,6 +33,17 @@ set -uo pipefail
|
|
|
33
33
|
|
|
34
34
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
35
35
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
36
|
+
|
|
37
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
38
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
39
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
40
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
41
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
42
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
43
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
44
|
+
# global-scan discovery every assertion below was written against).
|
|
45
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
46
|
+
export NODE_ENV=test
|
|
36
47
|
RESOLVER="$ROOT/build/src/li""b/flow-resolver.js"
|
|
37
48
|
|
|
38
49
|
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|
|
@@ -26,6 +26,16 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
|
26
26
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
27
27
|
PROT="$ROOT/scripts/hooks/config-protection.js"
|
|
28
28
|
|
|
29
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
30
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
31
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
32
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
33
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate-lockdown mechanics, not #440's
|
|
34
|
+
# ownership scoping, so forcing the documented test-only unresolved-actor escape hatch restores
|
|
35
|
+
# EXACTLY this suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged
|
|
36
|
+
# legacy-fallback/global-scan discovery every assertion below was written against).
|
|
37
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
38
|
+
export NODE_ENV=test
|
|
29
39
|
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|
|
30
40
|
|
|
31
41
|
TMP="$(mktemp -d)"
|
|
@@ -17,6 +17,17 @@ set -uo pipefail
|
|
|
17
17
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
18
18
|
HOOK="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
19
19
|
|
|
20
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
21
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
22
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
23
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
24
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
25
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
26
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
27
|
+
# global-scan discovery every assertion below was written against).
|
|
28
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
29
|
+
export NODE_ENV=test
|
|
30
|
+
|
|
20
31
|
TMP="$(mktemp -d)"
|
|
21
32
|
errors=0
|
|
22
33
|
_pass() { echo " PASS: $1"; }
|
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
set -uo pipefail
|
|
4
4
|
|
|
5
5
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
6
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
7
|
+
# and never establish a per-actor current pointer for the invoking actor (no ensure-session/
|
|
8
|
+
# workflow-start call anywhere in this file) -- under a RESOLVED ambient actor (ancestry-derived
|
|
9
|
+
# locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's analyze() now scopes to
|
|
10
|
+
# that actor's own (nonexistent) pointer and never reaches the fixture-under-test at all. This
|
|
11
|
+
# suite is about goal-fit gate mechanics, not #440's ownership scoping, so forcing the documented
|
|
12
|
+
# test-only unresolved-actor escape hatch restores EXACTLY this suite's pre-#440 behavior (D3
|
|
13
|
+
# compat: an unresolved actor keeps the unchanged legacy-fallback/global-scan discovery every
|
|
14
|
+
# assertion below was written against).
|
|
15
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
16
|
+
export NODE_ENV=test
|
|
17
|
+
|
|
6
18
|
source "$ROOT/evals/lib/node.sh"
|
|
7
19
|
|
|
8
20
|
# These checks exercise the block mechanism repeatedly against the same workspace
|
|
@@ -977,30 +989,31 @@ else
|
|
|
977
989
|
_fail "hook leaked tsc error into goal-fit output"
|
|
978
990
|
fi
|
|
979
991
|
|
|
980
|
-
# Part 2 of fix: when the
|
|
981
|
-
#
|
|
992
|
+
# Part 2 of fix: when the hook-owned build is absent, the hook must skip cleanly
|
|
993
|
+
# without executing npm or any other PATH-discovered fallback.
|
|
982
994
|
mv "$ROOT/build" "$ROOT/build-absent"
|
|
983
995
|
|
|
984
996
|
SPAWN_FAIL_DIR="$TMPDIR_EVAL/spawn-fail"
|
|
997
|
+
SPAWN_FAIL_MARKER="$TMPDIR_EVAL/path-npm-was-executed"
|
|
985
998
|
mkdir -p "$SPAWN_FAIL_DIR"
|
|
986
|
-
printf '#!/usr/bin/env bash\
|
|
999
|
+
printf '#!/usr/bin/env bash\nprintf "ran\\n" > "$SPAWN_FAIL_MARKER"\nexit 127\n' > "$SPAWN_FAIL_DIR/npm"
|
|
987
1000
|
chmod +x "$SPAWN_FAIL_DIR/npm"
|
|
988
1001
|
|
|
989
|
-
if PATH="$SPAWN_FAIL_DIR:$PATH" FLOW_AGENTS_GOAL_FIT_STRICT=true FLOW_AGENTS_REQUIRE_SIDECARS=true \
|
|
1002
|
+
if PATH="$SPAWN_FAIL_DIR:$PATH" SPAWN_FAIL_MARKER="$SPAWN_FAIL_MARKER" FLOW_AGENTS_GOAL_FIT_STRICT=true FLOW_AGENTS_REQUIRE_SIDECARS=true \
|
|
990
1003
|
node "$ROOT/scripts/hooks/stop-goal-fit.js" \
|
|
991
1004
|
>"$TMPDIR_EVAL/npm-install-env-err.out" 2>"$TMPDIR_EVAL/npm-install-env-err.err" <<JSON
|
|
992
1005
|
{"hook_event_name":"Stop","cwd":"$NPM_INSTALL_REPO"}
|
|
993
1006
|
JSON
|
|
994
1007
|
then
|
|
995
|
-
_pass "strict hook does not block when
|
|
1008
|
+
_pass "strict hook does not block when its hook-owned validator build is unavailable"
|
|
996
1009
|
else
|
|
997
|
-
_fail "strict hook must not block when validator
|
|
1010
|
+
_fail "strict hook must not block when its validator build is unavailable: $(cat "$TMPDIR_EVAL/npm-install-env-err.err")"
|
|
998
1011
|
fi
|
|
999
1012
|
|
|
1000
|
-
if rg -q 'sidecar validation skipped' "$TMPDIR_EVAL/npm-install-env-err.err"; then
|
|
1001
|
-
_pass "
|
|
1013
|
+
if [ ! -e "$SPAWN_FAIL_MARKER" ] && rg -q 'sidecar validation skipped' "$TMPDIR_EVAL/npm-install-env-err.err"; then
|
|
1014
|
+
_pass "unavailable validator is disclosed without executing a PATH-provided npm fallback"
|
|
1002
1015
|
else
|
|
1003
|
-
_fail "hook
|
|
1016
|
+
_fail "hook executed PATH npm or hid the unavailable-validator warning"
|
|
1004
1017
|
fi
|
|
1005
1018
|
|
|
1006
1019
|
# Restore build/ so subsequent evals are unaffected.
|
|
@@ -2764,6 +2777,241 @@ else
|
|
|
2764
2777
|
_fail "strict goal-fit hook did not report malformed canonical Flow state: $(cat "$TMPDIR_EVAL/canonical-malformed.err")"
|
|
2765
2778
|
fi
|
|
2766
2779
|
|
|
2780
|
+
# A live driver turn may return from one ordinary active Flow gate, but the
|
|
2781
|
+
# exception is strictly record-bound. It must not release assignment/liveness
|
|
2782
|
+
# (releaseOnNonTerminalStop sees the active canonical run) or hide a hard
|
|
2783
|
+
# evidence failure.
|
|
2784
|
+
AUTHORITY_REPO="$TMPDIR_EVAL/continuation-authority-repo"
|
|
2785
|
+
AUTHORITY_SESSION="$AUTHORITY_REPO/.kontourai/flow-agents/continuation-authority"
|
|
2786
|
+
mkdir -p "$AUTHORITY_SESSION/continuation-driver/locks" "$AUTHORITY_REPO/.kontourai/flow/runs/continuation-authority"
|
|
2787
|
+
printf '# Test Repo\n' > "$AUTHORITY_REPO/AGENTS.md"
|
|
2788
|
+
cat > "$AUTHORITY_SESSION/continuation-authority--deliver.md" <<'MARKDOWN'
|
|
2789
|
+
# Continuation authority fixture
|
|
2790
|
+
|
|
2791
|
+
status: planned
|
|
2792
|
+
type: deliver
|
|
2793
|
+
MARKDOWN
|
|
2794
|
+
cat > "$AUTHORITY_SESSION/state.json" <<'JSON'
|
|
2795
|
+
{
|
|
2796
|
+
"schema_version": "1.0",
|
|
2797
|
+
"task_slug": "continuation-authority",
|
|
2798
|
+
"status": "planned",
|
|
2799
|
+
"phase": "planning",
|
|
2800
|
+
"updated_at": "2026-07-13T00:00:00.000Z",
|
|
2801
|
+
"flow_run": { "status": "active", "run_id": "continuation-authority", "definition_id": "builder.build", "definition_version": "1.0", "current_step": "pull-work", "run_ref": ".kontourai/flow/runs/continuation-authority", "open_gate_ids": ["pull-work-gate"] },
|
|
2802
|
+
"next_action": { "status": "continue", "summary": "Continue the canonical gate." }
|
|
2803
|
+
}
|
|
2804
|
+
JSON
|
|
2805
|
+
cat > "$AUTHORITY_REPO/.kontourai/flow-agents/current.json" <<'JSON'
|
|
2806
|
+
{ "active_slug": "continuation-authority" }
|
|
2807
|
+
JSON
|
|
2808
|
+
cat > "$AUTHORITY_REPO/.kontourai/flow/runs/continuation-authority/state.json" <<'JSON'
|
|
2809
|
+
{ "run_id": "continuation-authority", "definition_id": "builder.build", "definition_version": "1.0", "status": "active", "current_step": "pull-work" }
|
|
2810
|
+
JSON
|
|
2811
|
+
cat > "$AUTHORITY_REPO/.kontourai/flow/runs/continuation-authority/definition.json" <<'JSON'
|
|
2812
|
+
{ "id": "builder.build", "version": "1.0", "steps": [{ "id": "pull-work" }, { "id": "design-probe" }] }
|
|
2813
|
+
JSON
|
|
2814
|
+
AUTHORITY_PID="$$"
|
|
2815
|
+
AUTHORITY_TOKEN="authority-lock"
|
|
2816
|
+
AUTHORITY_ENV="$TMPDIR_EVAL/continuation-authority-env.json"
|
|
2817
|
+
AUTHORITY_REPO="$AUTHORITY_REPO" AUTHORITY_SESSION="$AUTHORITY_SESSION" AUTHORITY_PID="$AUTHORITY_PID" AUTHORITY_TOKEN="$AUTHORITY_TOKEN" AUTHORITY_ENV="$AUTHORITY_ENV" AUTHORITY_ROOT="$ROOT" node - <<'NODE'
|
|
2818
|
+
const fs = require('fs');
|
|
2819
|
+
const path = require('path');
|
|
2820
|
+
const issued = new Date();
|
|
2821
|
+
const lock = { schema_version: '1.0', pid: Number(process.env.AUTHORITY_PID), token: process.env.AUTHORITY_TOKEN, created_at: issued.toISOString() };
|
|
2822
|
+
fs.writeFileSync(path.join(process.env.AUTHORITY_SESSION, 'continuation-driver', 'locks', `${lock.pid}-${lock.token}.lock`), `${JSON.stringify(lock)}\n`);
|
|
2823
|
+
fs.writeFileSync(path.join(process.env.AUTHORITY_SESSION, 'continuation-driver', 'state.json'), JSON.stringify({
|
|
2824
|
+
schema_version: '1.0', run_id: 'continuation-authority', definition_id: 'builder.build', max_turns: 2,
|
|
2825
|
+
adapter_command_identity: 'adapter-identity', status: 'active', turns_started: 1, active_turn_step: 'pull-work', pending_barrier: null,
|
|
2826
|
+
}));
|
|
2827
|
+
const actor = { runtime: 'explicit-override', session_id: 'driver-actor', host: 'fixture-host', human: null };
|
|
2828
|
+
const assignment = path.join(process.env.AUTHORITY_REPO, '.kontourai', 'flow-agents', 'assignment', 'continuation-authority.json');
|
|
2829
|
+
fs.mkdirSync(path.dirname(assignment), { recursive: true });
|
|
2830
|
+
fs.writeFileSync(assignment, JSON.stringify({ schema_version: '1.0', role: 'AssignmentClaimRecord', subject_id: 'continuation-authority', actor, actor_key: 'driver-actor', artifact_dir: 'continuation-authority', status: 'claimed' }));
|
|
2831
|
+
const authority = require(path.join(process.env.AUTHORITY_ROOT, 'scripts', 'hooks', 'lib', 'continuation-turn-authority.js'));
|
|
2832
|
+
const turn = authority.issueActiveTurnAuthority({ sessionDir: process.env.AUTHORITY_SESSION, runId: 'continuation-authority', definitionId: 'builder.build', currentStep: 'pull-work', iteration: 1, maxTurns: 2, adapterCommandIdentity: 'adapter-identity', assignmentActor: 'driver-actor', assignmentActorStruct: actor, lock, timeoutMs: 60_000 });
|
|
2833
|
+
const missionFile = path.join(process.env.AUTHORITY_SESSION, 'continuation-driver', 'state.json');
|
|
2834
|
+
const mission = JSON.parse(fs.readFileSync(missionFile, 'utf8'));
|
|
2835
|
+
fs.writeFileSync(missionFile, JSON.stringify({ ...mission, active_turn_public_key_digest: turn.publicKeyDigest }));
|
|
2836
|
+
fs.writeFileSync(process.env.AUTHORITY_ENV, JSON.stringify({ runId: turn.runId, turnSecret: turn.turnSecret }));
|
|
2837
|
+
NODE
|
|
2838
|
+
AUTHORITY_TURN_SECRET="$(node -p "require(process.argv[1]).turnSecret" "$AUTHORITY_ENV")"
|
|
2839
|
+
AUTHORITY_RUN_ID="$(node -p "require(process.argv[1]).runId" "$AUTHORITY_ENV")"
|
|
2840
|
+
cat > "$AUTHORITY_REPO/.kontourai/flow/runs/continuation-authority/state.json" <<'JSON'
|
|
2841
|
+
{ "run_id": "continuation-authority", "definition_id": "builder.build", "definition_version": "1.0", "status": "active", "current_step": "design-probe" }
|
|
2842
|
+
JSON
|
|
2843
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-valid.out" 2>"$TMPDIR_EVAL/authority-valid.err" <<JSON
|
|
2844
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2845
|
+
JSON
|
|
2846
|
+
then
|
|
2847
|
+
_pass "a matching live continuation authority makes only the ordinary active Flow gate advisory"
|
|
2848
|
+
else
|
|
2849
|
+
_fail "matching continuation authority did not return control to the driver: $(cat "$TMPDIR_EVAL/authority-valid.err")"
|
|
2850
|
+
fi
|
|
2851
|
+
if grep -q 'continuation driver active turn is authorized' "$TMPDIR_EVAL/authority-valid.err"; then
|
|
2852
|
+
_pass "authorized continuation turn remains observable in Goal Fit output"
|
|
2853
|
+
else
|
|
2854
|
+
_fail "authorized continuation turn was not disclosed: $(cat "$TMPDIR_EVAL/authority-valid.err")"
|
|
2855
|
+
fi
|
|
2856
|
+
AUTHORITY_CONSUMER_MARKER="$TMPDIR_EVAL/authority-consumer-validator-ran"
|
|
2857
|
+
mkdir -p "$AUTHORITY_REPO/build/src/cli"
|
|
2858
|
+
cat > "$AUTHORITY_REPO/package.json" <<'JSON'
|
|
2859
|
+
{
|
|
2860
|
+
"name": "@kontourai/flow-agents",
|
|
2861
|
+
"private": true,
|
|
2862
|
+
"scripts": {
|
|
2863
|
+
"test": "node --test",
|
|
2864
|
+
"workflow:validate-artifacts": "node -e \"require('fs').writeFileSync(process.env.AUTHORITY_CONSUMER_MARKER, 'ran')\""
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
JSON
|
|
2868
|
+
cat > "$AUTHORITY_REPO/build/src/cli/validate-workflow-artifacts.js" <<'JS'
|
|
2869
|
+
require('fs').writeFileSync(process.env.AUTHORITY_CONSUMER_MARKER, 'ran');
|
|
2870
|
+
process.exit(0);
|
|
2871
|
+
JS
|
|
2872
|
+
if AUTHORITY_CONSUMER_MARKER="$AUTHORITY_CONSUMER_MARKER" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-consumer-package.out" 2>"$TMPDIR_EVAL/authority-consumer-package.err" <<JSON
|
|
2873
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2874
|
+
JSON
|
|
2875
|
+
then
|
|
2876
|
+
if [ ! -e "$AUTHORITY_CONSUMER_MARKER" ]; then
|
|
2877
|
+
_pass "authorized continuation uses only the hook-owned validator, never a same-name consumer package"
|
|
2878
|
+
else
|
|
2879
|
+
_fail "hook executed a consumer-controlled same-name validator"
|
|
2880
|
+
fi
|
|
2881
|
+
else
|
|
2882
|
+
_fail "consumer package.json trapped an authorized continuation turn: $(cat "$TMPDIR_EVAL/authority-consumer-package.err")"
|
|
2883
|
+
fi
|
|
2884
|
+
printf '{}\n' > "$AUTHORITY_SESSION/handoff.json"
|
|
2885
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-validator-finding.out" 2>"$TMPDIR_EVAL/authority-validator-finding.err" <<JSON
|
|
2886
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2887
|
+
JSON
|
|
2888
|
+
then
|
|
2889
|
+
_fail "authorized continuation bypassed a real hook-owned validator finding"
|
|
2890
|
+
elif [[ "$?" -eq 2 ]] && grep -q 'sidecar validation:' "$TMPDIR_EVAL/authority-validator-finding.err"; then
|
|
2891
|
+
_pass "authorized continuation preserves real hook-owned validator findings as hard blocks"
|
|
2892
|
+
else
|
|
2893
|
+
_fail "hook-owned validator finding returned an unexpected result: $(cat "$TMPDIR_EVAL/authority-validator-finding.err")"
|
|
2894
|
+
fi
|
|
2895
|
+
rm -f "$AUTHORITY_SESSION/handoff.json"
|
|
2896
|
+
AUTHORITY_BUNDLE_DIST="$TMPDIR_EVAL/continuation-authority-bundles"
|
|
2897
|
+
if (cd "$ROOT" && FLOW_AGENTS_DIST_DIR="$AUTHORITY_BUNDLE_DIST" node build/src/cli.js build-bundles) >"$TMPDIR_EVAL/authority-bundle-build.out" 2>"$TMPDIR_EVAL/authority-bundle-build.err"; then
|
|
2898
|
+
_pass "continuation authority fixture builds the shipped Codex bundle layout"
|
|
2899
|
+
else
|
|
2900
|
+
_fail "continuation authority fixture could not build a Codex bundle: $(cat "$TMPDIR_EVAL/authority-bundle-build.err")"
|
|
2901
|
+
fi
|
|
2902
|
+
AUTHORITY_INSTALLED_HOME="$AUTHORITY_BUNDLE_DIST/codex"
|
|
2903
|
+
AUTHORITY_FAKE_PATH="$TMPDIR_EVAL/authority-hostile-path"
|
|
2904
|
+
AUTHORITY_PATH_MARKER="$TMPDIR_EVAL/authority-path-validator-ran"
|
|
2905
|
+
mkdir -p "$AUTHORITY_FAKE_PATH"
|
|
2906
|
+
cat > "$AUTHORITY_FAKE_PATH/flow-agents" <<'SH'
|
|
2907
|
+
#!/usr/bin/env bash
|
|
2908
|
+
printf 'ran\n' > "$AUTHORITY_PATH_MARKER"
|
|
2909
|
+
SH
|
|
2910
|
+
chmod +x "$AUTHORITY_FAKE_PATH/flow-agents"
|
|
2911
|
+
if PATH="$AUTHORITY_FAKE_PATH:$PATH" AUTHORITY_PATH_MARKER="$AUTHORITY_PATH_MARKER" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$AUTHORITY_INSTALLED_HOME/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-installed-hook.out" 2>"$TMPDIR_EVAL/authority-installed-hook.err" <<JSON
|
|
2912
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2913
|
+
JSON
|
|
2914
|
+
then
|
|
2915
|
+
if [ ! -e "$AUTHORITY_PATH_MARKER" ] && [ ! -e "$AUTHORITY_CONSUMER_MARKER" ] && ! grep -q 'Flow Agents validator is unavailable' "$TMPDIR_EVAL/authority-installed-hook.err"; then
|
|
2916
|
+
_pass "bundle-installed continuation hook uses its own compiled validator and ignores PATH code"
|
|
2917
|
+
else
|
|
2918
|
+
_fail "bundle-installed hook used untrusted code or failed to recognize its compiled validator"
|
|
2919
|
+
fi
|
|
2920
|
+
else
|
|
2921
|
+
_fail "installed continuation hook trapped a signed driver handback: $(cat "$TMPDIR_EVAL/authority-installed-hook.err")"
|
|
2922
|
+
fi
|
|
2923
|
+
rm -f "$AUTHORITY_REPO/package.json"
|
|
2924
|
+
rm -rf "$AUTHORITY_REPO/build"
|
|
2925
|
+
mv "$AUTHORITY_SESSION/continuation-authority--deliver.md" "$AUTHORITY_SESSION/continuation-authority--deliver.md.saved"
|
|
2926
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-no-markdown.out" 2>"$TMPDIR_EVAL/authority-no-markdown.err" <<JSON
|
|
2927
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2928
|
+
JSON
|
|
2929
|
+
then
|
|
2930
|
+
_pass "a matching continuation authority returns control before any workflow markdown exists"
|
|
2931
|
+
else
|
|
2932
|
+
_fail "matching continuation authority still required workflow markdown before returning control: $(cat "$TMPDIR_EVAL/authority-no-markdown.err")"
|
|
2933
|
+
fi
|
|
2934
|
+
printf '{"verdict":"fail","checks":[]}\n' > "$AUTHORITY_SESSION/evidence.json"
|
|
2935
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-no-markdown-hard.out" 2>"$TMPDIR_EVAL/authority-no-markdown-hard.err" <<JSON
|
|
2936
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2937
|
+
JSON
|
|
2938
|
+
then
|
|
2939
|
+
_fail "a no-markdown continuation session bypassed a non-markdown evidence hard block"
|
|
2940
|
+
elif [[ "$?" -eq 2 ]] && grep -q 'evidence verdict:fail' "$TMPDIR_EVAL/authority-no-markdown-hard.err"; then
|
|
2941
|
+
_pass "a no-markdown continuation session still enforces non-markdown evidence hard blocks"
|
|
2942
|
+
else
|
|
2943
|
+
_fail "no-markdown evidence hard block returned an unexpected result: $(cat "$TMPDIR_EVAL/authority-no-markdown-hard.err")"
|
|
2944
|
+
fi
|
|
2945
|
+
rm -f "$AUTHORITY_SESSION/evidence.json"
|
|
2946
|
+
mv "$AUTHORITY_SESSION/continuation-authority--deliver.md.saved" "$AUTHORITY_SESSION/continuation-authority--deliver.md"
|
|
2947
|
+
AUTHORITY_SESSION="$AUTHORITY_SESSION" node - <<'NODE' >/dev/null 2>"$TMPDIR_EVAL/authority-terminal-sidecar-setup.err"
|
|
2948
|
+
const fs = require('fs');
|
|
2949
|
+
const path = require('path');
|
|
2950
|
+
const session = process.env.AUTHORITY_SESSION;
|
|
2951
|
+
const state = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
2952
|
+
fs.writeFileSync(path.join(session, 'state.json'), JSON.stringify({ ...state, status: 'delivered', phase: 'release' }));
|
|
2953
|
+
fs.writeFileSync(path.join(session, 'evidence.json'), JSON.stringify({ verdict: 'pass', checks: [], not_verified_gaps: ['terminal authority FULL_BLOCK-only regression'] }));
|
|
2954
|
+
NODE
|
|
2955
|
+
if AUTHORITY_SESSION="$AUTHORITY_SESSION" AUTHORITY_REPO="$AUTHORITY_REPO" AUTHORITY_TURN_SECRET="$AUTHORITY_TURN_SECRET" AUTHORITY_RUN_ID="$AUTHORITY_RUN_ID" AUTHORITY_ROOT="$ROOT" FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=10 FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node - <<'NODE' >"$TMPDIR_EVAL/authority-terminal-sidecar.out" 2>"$TMPDIR_EVAL/authority-terminal-sidecar.err"
|
|
2956
|
+
const assert = require('assert/strict');
|
|
2957
|
+
const hook = require(`${process.env.AUTHORITY_ROOT}/scripts/hooks/stop-goal-fit.js`);
|
|
2958
|
+
(async () => {
|
|
2959
|
+
const analyzed = await hook.analyze(process.env.AUTHORITY_REPO);
|
|
2960
|
+
assert.equal(analyzed.activeTurnAuthority, true, 'fixture authority remains valid');
|
|
2961
|
+
assert.equal(analyzed.blocking, true, 'authorized terminal sidecar evaluates FULL_BLOCK-only gaps');
|
|
2962
|
+
assert.ok(analyzed.warnings.some((warning) => warning.includes('NOT_VERIFIED gap')), 'fixture produced a FULL_BLOCK-only warning');
|
|
2963
|
+
const result = await hook.run(JSON.stringify({ hook_event_name: 'Stop', cwd: process.env.AUTHORITY_REPO }));
|
|
2964
|
+
assert.equal(result.exitCode, 2, 'run preserves the terminal FULL_BLOCK-only block');
|
|
2965
|
+
assert.match(result.stderr, /NOT_VERIFIED gap/);
|
|
2966
|
+
})().catch((error) => { console.error(error.stack || error); process.exitCode = 1; });
|
|
2967
|
+
NODE
|
|
2968
|
+
then
|
|
2969
|
+
_pass "valid continuation authority still blocks a terminal sidecar FULL_BLOCK-only warning through analyze and run"
|
|
2970
|
+
else
|
|
2971
|
+
_fail "authorized terminal sidecar did not preserve the FULL_BLOCK-only warning: $(cat "$TMPDIR_EVAL/authority-terminal-sidecar.out" "$TMPDIR_EVAL/authority-terminal-sidecar.err" "$TMPDIR_EVAL/authority-terminal-sidecar-setup.err")"
|
|
2972
|
+
fi
|
|
2973
|
+
rm -f "$AUTHORITY_SESSION/evidence.json"
|
|
2974
|
+
AUTHORITY_SESSION="$AUTHORITY_SESSION" node - <<'NODE' >/dev/null 2>"$TMPDIR_EVAL/authority-terminal-sidecar-restore.err"
|
|
2975
|
+
const fs = require('fs');
|
|
2976
|
+
const path = require('path');
|
|
2977
|
+
const session = process.env.AUTHORITY_SESSION;
|
|
2978
|
+
const state = JSON.parse(fs.readFileSync(path.join(session, 'state.json'), 'utf8'));
|
|
2979
|
+
fs.writeFileSync(path.join(session, 'state.json'), JSON.stringify({ ...state, status: 'planned', phase: 'planning' }));
|
|
2980
|
+
NODE
|
|
2981
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_ACTOR=driver-actor FLOW_AGENTS_CONTINUATION_TURN_SECRET="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-wrong-secret.out" 2>"$TMPDIR_EVAL/authority-wrong-secret.err" <<JSON
|
|
2982
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2983
|
+
JSON
|
|
2984
|
+
then
|
|
2985
|
+
_fail "wrong continuation secret bypassed active Flow Stop blocking"
|
|
2986
|
+
elif [[ "$?" -eq 2 ]]; then
|
|
2987
|
+
_pass "wrong continuation secret preserves active Flow Stop blocking"
|
|
2988
|
+
else
|
|
2989
|
+
_fail "wrong continuation secret returned an unexpected Stop exit code"
|
|
2990
|
+
fi
|
|
2991
|
+
cat > "$AUTHORITY_SESSION/evidence.json" <<'JSON'
|
|
2992
|
+
{ "verdict": "fail", "checks": [] }
|
|
2993
|
+
JSON
|
|
2994
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=1 FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-hard-block.out" 2>"$TMPDIR_EVAL/authority-hard-block.err" <<JSON
|
|
2995
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
2996
|
+
JSON
|
|
2997
|
+
then
|
|
2998
|
+
_fail "active continuation authority bypassed an evidence hard block"
|
|
2999
|
+
elif [[ "$?" -eq 2 ]] && grep -q 'evidence verdict:fail' "$TMPDIR_EVAL/authority-hard-block.err"; then
|
|
3000
|
+
_pass "active continuation authority preserves evidence hard blocking"
|
|
3001
|
+
else
|
|
3002
|
+
_fail "active continuation authority did not preserve the evidence hard block: $(cat "$TMPDIR_EVAL/authority-hard-block.err")"
|
|
3003
|
+
fi
|
|
3004
|
+
if FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=1 FLOW_AGENTS_CONTINUATION_TURN_SECRET="$AUTHORITY_TURN_SECRET" FLOW_AGENTS_CONTINUATION_RUN_ID="$AUTHORITY_RUN_ID" node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMPDIR_EVAL/authority-hard-block-repeat.out" 2>"$TMPDIR_EVAL/authority-hard-block-repeat.err" <<JSON
|
|
3005
|
+
{"hook_event_name":"Stop","cwd":"$AUTHORITY_REPO"}
|
|
3006
|
+
JSON
|
|
3007
|
+
then
|
|
3008
|
+
_fail "nonordinary FULL_BLOCK escaped through max-block release"
|
|
3009
|
+
elif [[ "$?" -eq 2 ]] && grep -q 'max-blocks reached but the block' "$TMPDIR_EVAL/authority-hard-block-repeat.err"; then
|
|
3010
|
+
_pass "nonordinary FULL_BLOCK cannot burn through max-block release"
|
|
3011
|
+
else
|
|
3012
|
+
_fail "nonordinary FULL_BLOCK did not remain hard after max blocks: $(cat "$TMPDIR_EVAL/authority-hard-block-repeat.err")"
|
|
3013
|
+
fi
|
|
3014
|
+
|
|
2767
3015
|
if cmp -s "$ROOT/scripts/hooks/stop-goal-fit.js" "$ROOT/context/scripts/hooks/stop-goal-fit.js"; then
|
|
2768
3016
|
_pass "canonical Stop hook source and shipped context mirror remain byte-identical"
|
|
2769
3017
|
else
|
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
set -uo pipefail
|
|
17
17
|
|
|
18
18
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
19
|
+
|
|
20
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
21
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
22
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
23
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
24
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
25
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
26
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
27
|
+
# global-scan discovery every assertion below was written against).
|
|
28
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
29
|
+
export NODE_ENV=test
|
|
19
30
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
20
31
|
|
|
21
32
|
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|