oh-my-opencode 4.11.1 → 4.12.1
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/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
- package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
- package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
- package/.agents/skills/work-with-pr/SKILL.md +19 -5
- package/.opencode/skills/work-with-pr/SKILL.md +19 -5
- package/dist/agents/types.d.ts +7 -6
- package/dist/cli/index.js +460 -309
- package/dist/cli-node/index.js +460 -309
- package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
- package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
- package/dist/index.js +593 -310
- package/dist/plugin/tool-execute-before.d.ts +2 -0
- package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
- package/dist/skills/ultraresearch/SKILL.md +11 -2
- package/dist/skills/ulw-plan/SKILL.md +2 -1
- package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
- package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
- package/dist/tools/background-task/constants.d.ts +1 -1
- package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
- package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
- package/dist/tui.js +25 -10
- package/package.json +13 -13
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +24 -2
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +25 -9
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +336 -173
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +284 -33
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +47 -5
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -5
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +58 -96
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +12 -92
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
- package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
- package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
- package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
- package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
- package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/test-support/package-smoke-fixture.ts +158 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
- package/packages/omo-codex/plugin/package-lock.json +30 -22
- package/packages/omo-codex/plugin/package.json +2 -1
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +15 -11
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
- package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
- package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
- package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
- package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +70 -33
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +6 -2
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +14 -1
- package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
- package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -3
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
- package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +31 -19
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
- package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
- package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
- package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +398 -206
- package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
- package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
- package/packages/omo-codex/scripts/install-local.mjs +1 -0
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/hooks/hooks.json +0 -214
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
# or routes correctly through the live listener (FIXED).
|
|
8
8
|
#
|
|
9
9
|
# Two assertion modes:
|
|
10
|
-
# --expect reproduced exit 0 if
|
|
11
|
-
# --expect fixed exit 0 if
|
|
10
|
+
# --expect reproduced exit 0 if terminal_stops>1 OR child_task_sessions>1 OR mechanism arm true
|
|
11
|
+
# --expect fixed exit 0 if terminal_stops==1, child_task_sessions==1,
|
|
12
|
+
# fixed branch counts hold, and route logs show live dispatch
|
|
12
13
|
#
|
|
13
14
|
# Usage:
|
|
14
15
|
# serve-wake-split-probe.sh [--expect reproduced|fixed] [--evidence-dir DIR]
|
|
@@ -45,10 +46,18 @@ FAKE_LLM_LOG="" # set after evidence dir is known
|
|
|
45
46
|
while [ $# -gt 0 ]; do
|
|
46
47
|
case "$1" in
|
|
47
48
|
--expect)
|
|
49
|
+
if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then
|
|
50
|
+
printf 'error: --expect requires reproduced or fixed\n' >&2
|
|
51
|
+
exit 2
|
|
52
|
+
fi
|
|
48
53
|
EXPECT_MODE="$2"
|
|
49
54
|
shift 2
|
|
50
55
|
;;
|
|
51
56
|
--evidence-dir)
|
|
57
|
+
if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then
|
|
58
|
+
printf 'error: --evidence-dir requires a directory\n' >&2
|
|
59
|
+
exit 2
|
|
60
|
+
fi
|
|
52
61
|
EVIDENCE_DIR="$2"
|
|
53
62
|
shift 2
|
|
54
63
|
;;
|
|
@@ -81,6 +90,22 @@ fi
|
|
|
81
90
|
swsp_log() { printf '%s\n' "$*" >&2; }
|
|
82
91
|
swsp_info() { printf '[swsp] %s\n' "$*" >&2; }
|
|
83
92
|
|
|
93
|
+
swsp_tail_log_since_offset() {
|
|
94
|
+
local offset="$1"
|
|
95
|
+
local log_path="$2"
|
|
96
|
+
if [ ! -f "$log_path" ]; then
|
|
97
|
+
return 0
|
|
98
|
+
fi
|
|
99
|
+
local current_size
|
|
100
|
+
current_size="$(wc -c <"$log_path" 2>/dev/null | tr -d ' ')" || current_size=0
|
|
101
|
+
current_size="${current_size:-0}"
|
|
102
|
+
if [ "$offset" -gt "$current_size" ] 2>/dev/null; then
|
|
103
|
+
return 0
|
|
104
|
+
else
|
|
105
|
+
tail -c "+$((offset + 1))" "$log_path" 2>/dev/null || true
|
|
106
|
+
fi
|
|
107
|
+
}
|
|
108
|
+
|
|
84
109
|
# Start the fake-LLM server; sets FAKE_SERVER_PID + FAKE_SERVER_PORT.
|
|
85
110
|
swsp_start_fake_llm() {
|
|
86
111
|
local log_file="$1"
|
|
@@ -203,9 +228,9 @@ JSONC
|
|
|
203
228
|
swsp_info "opencode.jsonc written to $cfg_dir/opencode/opencode.jsonc"
|
|
204
229
|
}
|
|
205
230
|
|
|
206
|
-
# Poll the sandbox DB for
|
|
231
|
+
# Poll the sandbox DB for parent assistant step metrics on a message matching a LIKE pattern.
|
|
207
232
|
# Args: db_path like_pattern timeout_s
|
|
208
|
-
# Outputs: "<
|
|
233
|
+
# Outputs: "<parent_assistant_messages> <parent_tool_call_turns> <terminal_stops> <child_task_sessions>" on stdout
|
|
209
234
|
swsp_poll_db_metrics() {
|
|
210
235
|
local db="$1"
|
|
211
236
|
local like_pat="$2"
|
|
@@ -222,17 +247,28 @@ swsp_poll_db_metrics() {
|
|
|
222
247
|
),
|
|
223
248
|
counts AS (
|
|
224
249
|
SELECT
|
|
225
|
-
count(a.id) AS
|
|
226
|
-
sum(CASE WHEN json_extract(a.data, '\$.finish') = '
|
|
250
|
+
count(a.id) AS parent_assistant_messages,
|
|
251
|
+
sum(CASE WHEN json_extract(a.data, '\$.finish') = 'tool-calls' THEN 1 ELSE 0 END) AS parent_tool_call_turns,
|
|
252
|
+
sum(CASE WHEN json_extract(a.data, '\$.finish') = 'stop' THEN 1 ELSE 0 END) AS terminal_stops
|
|
227
253
|
FROM target t
|
|
228
254
|
LEFT JOIN message a
|
|
229
255
|
ON a.session_id = t.session_id
|
|
230
256
|
AND json_extract(a.data, '\$.parentID') = t.user_id
|
|
231
257
|
GROUP BY t.user_id
|
|
258
|
+
),
|
|
259
|
+
child_task_sessions AS (
|
|
260
|
+
SELECT count(DISTINCT m.session_id) AS child_task_sessions
|
|
261
|
+
FROM message m
|
|
262
|
+
JOIN part p ON p.message_id = m.id
|
|
263
|
+
WHERE json_extract(m.data, '\$.role') = 'user'
|
|
264
|
+
AND json_extract(p.data, '\$.type') = 'text'
|
|
265
|
+
AND json_extract(p.data, '\$.text') LIKE '%SPLIT_CHILD_TASK:%'
|
|
232
266
|
)
|
|
233
|
-
SELECT printf('%d %d',
|
|
234
|
-
coalesce((SELECT max(
|
|
235
|
-
coalesce((SELECT max(
|
|
267
|
+
SELECT printf('%d %d %d %d',
|
|
268
|
+
coalesce((SELECT max(parent_assistant_messages) FROM counts), 0),
|
|
269
|
+
coalesce((SELECT max(parent_tool_call_turns) FROM counts), 0),
|
|
270
|
+
coalesce((SELECT max(terminal_stops) FROM counts), 0),
|
|
271
|
+
coalesce((SELECT child_task_sessions FROM child_task_sessions), 0)
|
|
236
272
|
);
|
|
237
273
|
"
|
|
238
274
|
|
|
@@ -245,13 +281,15 @@ swsp_poll_db_metrics() {
|
|
|
245
281
|
local result
|
|
246
282
|
result="$(sqlite3 "$db" "$metrics_query" 2>/dev/null)" || true
|
|
247
283
|
|
|
248
|
-
local
|
|
249
|
-
|
|
250
|
-
|
|
284
|
+
local parent_assistant_messages parent_tool_call_turns terminal_stops child_task_sessions
|
|
285
|
+
parent_assistant_messages="$(printf '%s' "$result" | awk '{print $1}')"
|
|
286
|
+
parent_tool_call_turns="$(printf '%s' "$result" | awk '{print $2}')"
|
|
287
|
+
terminal_stops="$(printf '%s' "$result" | awk '{print $3}')"
|
|
288
|
+
child_task_sessions="$(printf '%s' "$result" | awk '{print $4}')"
|
|
251
289
|
|
|
252
290
|
# Return once we have at least 1 stop (parent session finished)
|
|
253
|
-
if [ -n "$
|
|
254
|
-
printf '%s %s' "$
|
|
291
|
+
if [ -n "$terminal_stops" ] && [ "${terminal_stops:-0}" -ge 1 ] 2>/dev/null; then
|
|
292
|
+
printf '%s %s %s %s' "$parent_assistant_messages" "$parent_tool_call_turns" "$terminal_stops" "$child_task_sessions"
|
|
255
293
|
return 0
|
|
256
294
|
fi
|
|
257
295
|
sleep 0.5
|
|
@@ -260,7 +298,7 @@ swsp_poll_db_metrics() {
|
|
|
260
298
|
# Return whatever we have on timeout
|
|
261
299
|
local result
|
|
262
300
|
result="$(sqlite3 "$db" "$metrics_query" 2>/dev/null)" || true
|
|
263
|
-
printf '%s' "${result:-0 0}"
|
|
301
|
+
printf '%s' "${result:-0 0 0 0}"
|
|
264
302
|
}
|
|
265
303
|
|
|
266
304
|
# Wait until a session is no longer in the server's active status map.
|
|
@@ -291,11 +329,9 @@ swsp_count_plugin_inits() {
|
|
|
291
329
|
printf '0'
|
|
292
330
|
return 0
|
|
293
331
|
fi
|
|
294
|
-
|
|
295
|
-
tail -c "+$((offset + 1))" "$log_path" 2>/dev/null \
|
|
332
|
+
swsp_tail_log_since_offset "$offset" "$log_path" \
|
|
296
333
|
| grep "ENTRY - plugin loading" \
|
|
297
|
-
|
|
|
298
|
-
|| printf '0'
|
|
334
|
+
| awk -v sandbox_dir="$sandbox_dir" 'index($0, sandbox_dir) { count += 1 } END { print count + 0 }'
|
|
299
335
|
}
|
|
300
336
|
|
|
301
337
|
# Detect WAKE_DISPATCHED_DURING_PARENT_TURN:
|
|
@@ -321,7 +357,7 @@ swsp_detect_wake_during_parent() {
|
|
|
321
357
|
|
|
322
358
|
# Check for gate dispatch log line with parent-wake source since offset
|
|
323
359
|
local dispatch_line
|
|
324
|
-
dispatch_line="$(
|
|
360
|
+
dispatch_line="$(swsp_tail_log_since_offset "$offset" "$omo_log" \
|
|
325
361
|
| grep "promptAsync dispatching" \
|
|
326
362
|
| grep -i "parent-wake\|background-agent-parent-wake" \
|
|
327
363
|
| head -1)" || true
|
|
@@ -350,10 +386,97 @@ swsp_detect_wake_during_parent() {
|
|
|
350
386
|
fi
|
|
351
387
|
}
|
|
352
388
|
|
|
389
|
+
swsp_has_session_live_dispatch() {
|
|
390
|
+
local route_prov="$1"
|
|
391
|
+
local session_id="$2"
|
|
392
|
+
[ -n "$session_id" ] || return 1
|
|
393
|
+
printf '%s\n' "$route_prov" \
|
|
394
|
+
| grep -F "dispatch via live listener" \
|
|
395
|
+
| grep -F "\"sessionID\":\"${session_id}\"" >/dev/null 2>&1
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
swsp_is_nonnegative_int() {
|
|
399
|
+
case "${1:-}" in
|
|
400
|
+
''|*[!0-9]*) return 1 ;;
|
|
401
|
+
*) return 0 ;;
|
|
402
|
+
esac
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
swsp_fixed_topology_observed() {
|
|
406
|
+
local parent_assistant_messages="$1"
|
|
407
|
+
local parent_tool_call_turns="$2"
|
|
408
|
+
local terminal_stops="$3"
|
|
409
|
+
local child_task_sessions="$4"
|
|
410
|
+
local parent_tool_call_branches="$5"
|
|
411
|
+
local parent_hold_branches="$6"
|
|
412
|
+
local child_branches="$7"
|
|
413
|
+
local wake_branches="$8"
|
|
414
|
+
local default_branches="$9"
|
|
415
|
+
local has_live_dispatch="${10}"
|
|
416
|
+
|
|
417
|
+
swsp_is_nonnegative_int "$parent_assistant_messages" || return 1
|
|
418
|
+
swsp_is_nonnegative_int "$parent_tool_call_turns" || return 1
|
|
419
|
+
swsp_is_nonnegative_int "$terminal_stops" || return 1
|
|
420
|
+
swsp_is_nonnegative_int "$child_task_sessions" || return 1
|
|
421
|
+
swsp_is_nonnegative_int "$parent_tool_call_branches" || return 1
|
|
422
|
+
swsp_is_nonnegative_int "$parent_hold_branches" || return 1
|
|
423
|
+
swsp_is_nonnegative_int "$child_branches" || return 1
|
|
424
|
+
swsp_is_nonnegative_int "$wake_branches" || return 1
|
|
425
|
+
swsp_is_nonnegative_int "$default_branches" || return 1
|
|
426
|
+
|
|
427
|
+
[ "$has_live_dispatch" = "true" ] || return 1
|
|
428
|
+
|
|
429
|
+
if [ "${terminal_stops:-0}" -ne 1 ] \
|
|
430
|
+
|| [ "${child_task_sessions:-0}" -ne 1 ] \
|
|
431
|
+
|| [ "${parent_tool_call_turns:-0}" -ne 2 ] \
|
|
432
|
+
|| [ "${parent_assistant_messages:-0}" -ne 3 ] \
|
|
433
|
+
|| [ "${parent_tool_call_branches:-0}" -ne 1 ] \
|
|
434
|
+
|| [ "${parent_hold_branches:-0}" -ne 1 ] \
|
|
435
|
+
|| [ "${child_branches:-0}" -ne 1 ] \
|
|
436
|
+
|| [ "${default_branches:-0}" -lt 1 ] \
|
|
437
|
+
|| [ "${wake_branches:-0}" -ne 0 ] 2>/dev/null; then
|
|
438
|
+
return 1
|
|
439
|
+
fi
|
|
440
|
+
|
|
441
|
+
return 0
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
swsp_collect_route_provenance() {
|
|
445
|
+
local offset="$1"
|
|
446
|
+
local log_path="$2"
|
|
447
|
+
local project_dir="$3"
|
|
448
|
+
local session_id="$4"
|
|
449
|
+
local output_file="$5"
|
|
450
|
+
local all_output_file="$6"
|
|
451
|
+
local timeout_s="${7:-0}"
|
|
452
|
+
local deadline
|
|
453
|
+
deadline=$(( $(date +%s) + timeout_s ))
|
|
454
|
+
|
|
455
|
+
while :; do
|
|
456
|
+
local route_prov_all="" route_prov=""
|
|
457
|
+
if [ -f "$log_path" ]; then
|
|
458
|
+
route_prov_all="$(swsp_tail_log_since_offset "$offset" "$log_path" \
|
|
459
|
+
| grep -E "live-server-route" || true)"
|
|
460
|
+
route_prov="$(printf '%s\n' "$route_prov_all" \
|
|
461
|
+
| awk -v dir="$project_dir" -v sid="\"sessionID\":\"${session_id}\"" 'index($0, dir) || index($0, sid)' || true)"
|
|
462
|
+
fi
|
|
463
|
+
printf '%s' "$route_prov" >"$all_output_file"
|
|
464
|
+
printf '%s' "$route_prov" >"$output_file"
|
|
465
|
+
if swsp_has_session_live_dispatch "$route_prov" "$session_id"; then
|
|
466
|
+
return 0
|
|
467
|
+
fi
|
|
468
|
+
if [ "$timeout_s" -le 0 ] || [ "$(date +%s)" -ge "$deadline" ]; then
|
|
469
|
+
return 1
|
|
470
|
+
fi
|
|
471
|
+
sleep 0.25
|
|
472
|
+
done
|
|
473
|
+
}
|
|
474
|
+
|
|
353
475
|
# Verify branch-count guard: all required branches fired.
|
|
354
476
|
# Returns 0 if OK, 1 if any required branch missing (also sets RESULT=HARNESS_ERROR).
|
|
355
477
|
swsp_check_branch_counts() {
|
|
356
478
|
local fake_log="$1"
|
|
479
|
+
local mode="${2:-}"
|
|
357
480
|
local ptc pc cc wc
|
|
358
481
|
ptc="$(grep -c "branch=parent-tool-call" "$fake_log" 2>/dev/null | tr -d '[:space:]')"; ptc="${ptc:-0}"
|
|
359
482
|
pc="$(grep -c "branch=parent-hold" "$fake_log" 2>/dev/null | tr -d '[:space:]')"; pc="${pc:-0}"
|
|
@@ -364,7 +487,7 @@ swsp_check_branch_counts() {
|
|
|
364
487
|
|
|
365
488
|
swsp_info "branch counts: parent-tool-call=$ptc parent-hold=$pc child=$cc wake=$wc"
|
|
366
489
|
|
|
367
|
-
if [ "$ptc" -lt 1 ] || [ "$pc" -lt 1 ] || [ "$cc" -lt 1 ]
|
|
490
|
+
if [ "$ptc" -lt 1 ] || [ "$pc" -lt 1 ] || [ "$cc" -lt 1 ]; then
|
|
368
491
|
printf 'RESULT=HARNESS_ERROR branch_counts parent-tool-call=%s parent-hold=%s child=%s wake=%s\n' \
|
|
369
492
|
"$ptc" "$pc" "$cc" "$wc"
|
|
370
493
|
return 1
|
|
@@ -400,6 +523,33 @@ swsp_self_test() {
|
|
|
400
523
|
fi
|
|
401
524
|
fi
|
|
402
525
|
|
|
526
|
+
local missing_expect_out missing_expect_err missing_evidence_out missing_evidence_err
|
|
527
|
+
missing_expect_out="$(mktemp -t swsp-missing-expect-out.XXXXXX)"
|
|
528
|
+
missing_expect_err="$(mktemp -t swsp-missing-expect-err.XXXXXX)"
|
|
529
|
+
missing_evidence_out="$(mktemp -t swsp-missing-evidence-out.XXXXXX)"
|
|
530
|
+
missing_evidence_err="$(mktemp -t swsp-missing-evidence-err.XXXXXX)"
|
|
531
|
+
OQA_TMPDIRS+=("$missing_expect_out" "$missing_expect_err" "$missing_evidence_out" "$missing_evidence_err")
|
|
532
|
+
|
|
533
|
+
if bash "${BASH_SOURCE[0]}" --expect >"$missing_expect_out" 2>"$missing_expect_err"; then
|
|
534
|
+
swsp_log "FAIL: missing --expect operand unexpectedly succeeded"
|
|
535
|
+
fails=$((fails+1))
|
|
536
|
+
elif grep -q "error: --expect requires reproduced or fixed" "$missing_expect_err"; then
|
|
537
|
+
swsp_info "PASS: missing --expect operand fails with usage error"
|
|
538
|
+
else
|
|
539
|
+
swsp_log "FAIL: missing --expect operand did not emit usage error"
|
|
540
|
+
fails=$((fails+1))
|
|
541
|
+
fi
|
|
542
|
+
|
|
543
|
+
if bash "${BASH_SOURCE[0]}" --evidence-dir --self-test >"$missing_evidence_out" 2>"$missing_evidence_err"; then
|
|
544
|
+
swsp_log "FAIL: missing --evidence-dir operand unexpectedly succeeded"
|
|
545
|
+
fails=$((fails+1))
|
|
546
|
+
elif grep -q "error: --evidence-dir requires a directory" "$missing_evidence_err"; then
|
|
547
|
+
swsp_info "PASS: missing --evidence-dir operand fails with usage error"
|
|
548
|
+
else
|
|
549
|
+
swsp_log "FAIL: missing --evidence-dir operand did not emit usage error"
|
|
550
|
+
fails=$((fails+1))
|
|
551
|
+
fi
|
|
552
|
+
|
|
403
553
|
# Sandbox + opencode serve
|
|
404
554
|
if ! oqa_start_server; then
|
|
405
555
|
swsp_log "FAIL: opencode serve did not start"
|
|
@@ -433,16 +583,117 @@ swsp_self_test() {
|
|
|
433
583
|
fi
|
|
434
584
|
fi
|
|
435
585
|
|
|
586
|
+
local route_fixture
|
|
587
|
+
route_fixture='[2026-06-19T00:00:00.000Z] [live-server-route] dispatch via live listener {"sessionID":"ses_other","source":"background-agent-parent-wake"}
|
|
588
|
+
[2026-06-19T00:00:01.000Z] [live-server-route] dispatch via live listener {"sessionID":"ses_probe","source":"background-agent-parent-wake"}'
|
|
589
|
+
if swsp_has_session_live_dispatch "$route_fixture" "ses_probe" \
|
|
590
|
+
&& ! swsp_has_session_live_dispatch "$route_fixture" "ses_missing"; then
|
|
591
|
+
swsp_info "PASS: live dispatch detection is scoped to the probe session"
|
|
592
|
+
else
|
|
593
|
+
swsp_log "FAIL: live dispatch detection accepted an unrelated session"
|
|
594
|
+
fails=$((fails+1))
|
|
595
|
+
fi
|
|
596
|
+
|
|
597
|
+
local branch_log
|
|
598
|
+
branch_log="$(mktemp -t swsp-branch-log.XXXXXX)"
|
|
599
|
+
OQA_TMPDIRS+=("$branch_log")
|
|
600
|
+
{
|
|
601
|
+
printf '[2026-06-19T00:00:00.000Z] branch=parent-tool-call\n'
|
|
602
|
+
printf '[2026-06-19T00:00:01.000Z] branch=parent-hold\n'
|
|
603
|
+
printf '[2026-06-19T00:00:02.000Z] branch=child\n'
|
|
604
|
+
} >"$branch_log"
|
|
605
|
+
if swsp_check_branch_counts "$branch_log" reproduced >/dev/null 2>&1; then
|
|
606
|
+
swsp_info "PASS: reproduced branch guard accepts mechanism-only evidence"
|
|
607
|
+
else
|
|
608
|
+
swsp_log "FAIL: reproduced branch guard still requires wake branch"
|
|
609
|
+
fails=$((fails+1))
|
|
610
|
+
fi
|
|
611
|
+
|
|
612
|
+
if swsp_fixed_topology_observed 3 2 1 1 1 1 1 0 1 true; then
|
|
613
|
+
swsp_info "PASS: fixed topology accepts scoped live dispatch plus deterministic DB/provider evidence"
|
|
614
|
+
else
|
|
615
|
+
swsp_log "FAIL: fixed topology rejected scoped live dispatch plus deterministic DB/provider evidence"
|
|
616
|
+
fails=$((fails+1))
|
|
617
|
+
fi
|
|
618
|
+
|
|
619
|
+
if swsp_fixed_topology_observed 3 2 1 1 1 1 1 0 1 false; then
|
|
620
|
+
swsp_log "FAIL: fixed topology accepted missing scoped live dispatch"
|
|
621
|
+
fails=$((fails+1))
|
|
622
|
+
else
|
|
623
|
+
swsp_info "PASS: fixed topology rejects missing scoped live dispatch"
|
|
624
|
+
fi
|
|
625
|
+
|
|
626
|
+
if swsp_fixed_topology_observed bad 2 1 1 1 1 1 0 1 true; then
|
|
627
|
+
swsp_log "FAIL: fixed topology accepted malformed numeric evidence"
|
|
628
|
+
fails=$((fails+1))
|
|
629
|
+
else
|
|
630
|
+
swsp_info "PASS: fixed topology rejects malformed numeric evidence"
|
|
631
|
+
fi
|
|
632
|
+
|
|
633
|
+
if swsp_fixed_topology_observed 3 2 2 1 1 1 1 0 1 true; then
|
|
634
|
+
swsp_log "FAIL: fixed topology accepted duplicate terminal stop"
|
|
635
|
+
fails=$((fails+1))
|
|
636
|
+
else
|
|
637
|
+
swsp_info "PASS: fixed topology rejects duplicate terminal stop"
|
|
638
|
+
fi
|
|
639
|
+
|
|
640
|
+
local stale_log stale_scoped stale_all
|
|
641
|
+
stale_log="$(mktemp -t swsp-stale-log.XXXXXX)"
|
|
642
|
+
stale_scoped="$(mktemp -t swsp-stale-scoped.XXXXXX)"
|
|
643
|
+
stale_all="$(mktemp -t swsp-stale-all.XXXXXX)"
|
|
644
|
+
OQA_TMPDIRS+=("$stale_log" "$stale_scoped" "$stale_all")
|
|
645
|
+
printf '[2026-06-19T00:00:00.000Z] [live-server-route] dispatch via live listener {"sessionID":"ses_unrelated","source":"background-agent-parent-wake"}\n' >"$stale_log"
|
|
646
|
+
swsp_collect_route_provenance 999999 "$stale_log" "/probe" "ses_probe" "$stale_scoped" "$stale_all" 0 || true
|
|
647
|
+
if [ ! -s "$stale_scoped" ] && [ ! -s "$stale_all" ]; then
|
|
648
|
+
swsp_info "PASS: stale log offset does not persist unrelated route provenance"
|
|
649
|
+
else
|
|
650
|
+
swsp_log "FAIL: stale log offset persisted unrelated route provenance"
|
|
651
|
+
fails=$((fails+1))
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
local scoped_log scoped_out scoped_all
|
|
655
|
+
scoped_log="$(mktemp -t swsp-scoped-log.XXXXXX)"
|
|
656
|
+
scoped_out="$(mktemp -t swsp-scoped-out.XXXXXX)"
|
|
657
|
+
scoped_all="$(mktemp -t swsp-scoped-all.XXXXXX)"
|
|
658
|
+
OQA_TMPDIRS+=("$scoped_log" "$scoped_out" "$scoped_all")
|
|
659
|
+
{
|
|
660
|
+
printf '[2026-06-19T00:00:00.000Z] [live-server-route] dispatch via live listener {"sessionID":"ses_other","source":"background-agent-parent-wake"}\n'
|
|
661
|
+
printf '[2026-06-19T00:00:01.000Z] [live-server-route] dispatch via live listener {"sessionID":"ses_probe","source":"background-agent-parent-wake"}\n'
|
|
662
|
+
} >"$scoped_log"
|
|
663
|
+
swsp_collect_route_provenance 0 "$scoped_log" "/probe" "ses_probe" "$scoped_out" "$scoped_all" 0 || true
|
|
664
|
+
if grep -q "ses_probe" "$scoped_all" && ! grep -q "ses_other" "$scoped_all"; then
|
|
665
|
+
swsp_info "PASS: route provenance artifact excludes unrelated sessions"
|
|
666
|
+
else
|
|
667
|
+
swsp_log "FAIL: route provenance artifact included unrelated sessions"
|
|
668
|
+
fails=$((fails+1))
|
|
669
|
+
fi
|
|
670
|
+
|
|
671
|
+
local route_wait_log route_wait_scoped route_wait_all
|
|
672
|
+
route_wait_log="$(mktemp -t swsp-route-wait-log.XXXXXX)"
|
|
673
|
+
route_wait_scoped="$(mktemp -t swsp-route-wait-scoped.XXXXXX)"
|
|
674
|
+
route_wait_all="$(mktemp -t swsp-route-wait-all.XXXXXX)"
|
|
675
|
+
OQA_TMPDIRS+=("$route_wait_log" "$route_wait_scoped" "$route_wait_all")
|
|
676
|
+
printf '[2026-06-19T00:00:00.000Z] [live-server-route] registered {"directory":"/probe","hasServerUrl":true}\n' >"$route_wait_log"
|
|
677
|
+
(
|
|
678
|
+
sleep 0.5
|
|
679
|
+
printf '[2026-06-19T00:00:01.000Z] [live-server-route] dispatch via live listener {"sessionID":"ses_wait","source":"background-agent-parent-wake"}\n' >>"$route_wait_log"
|
|
680
|
+
) &
|
|
681
|
+
local route_wait_pid=$!
|
|
682
|
+
if swsp_collect_route_provenance 0 "$route_wait_log" "/probe" "ses_wait" "$route_wait_scoped" "$route_wait_all" 3; then
|
|
683
|
+
swsp_info "PASS: route provenance waits for delayed session dispatch"
|
|
684
|
+
else
|
|
685
|
+
swsp_log "FAIL: route provenance did not wait for delayed session dispatch"
|
|
686
|
+
fails=$((fails+1))
|
|
687
|
+
fi
|
|
688
|
+
wait "$route_wait_pid" 2>/dev/null || true
|
|
689
|
+
|
|
690
|
+
local st_fake_pid="$FAKE_SERVER_PID"
|
|
436
691
|
swsp_stop_fake_llm
|
|
437
692
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
orphan_count="$(pgrep -f "fake-openai-server" 2>/dev/null | wc -l | tr -d ' ')" || orphan_count=0
|
|
441
|
-
if [ "${orphan_count:-0}" -eq 0 ]; then
|
|
442
|
-
swsp_info "PASS: no orphan fake-openai-server processes"
|
|
693
|
+
if [ -n "$st_fake_pid" ] && ! kill -0 "$st_fake_pid" 2>/dev/null; then
|
|
694
|
+
swsp_info "PASS: fake-openai server process stopped"
|
|
443
695
|
else
|
|
444
|
-
swsp_log "FAIL:
|
|
445
|
-
pkill -f "fake-openai-server" 2>/dev/null || true
|
|
696
|
+
swsp_log "FAIL: fake-openai server process still running"
|
|
446
697
|
fails=$((fails+1))
|
|
447
698
|
fi
|
|
448
699
|
|
|
@@ -573,29 +824,38 @@ swsp_run_probe() {
|
|
|
573
824
|
2>/dev/null)" || prompt_response=""
|
|
574
825
|
swsp_info "prompt_async response: $prompt_response"
|
|
575
826
|
|
|
576
|
-
# Step 7: Poll sandbox DB for children/stops; also wait for session idle
|
|
577
827
|
swsp_info "polling DB for wake-split metrics (up to 120s)..."
|
|
578
828
|
local metrics
|
|
579
|
-
metrics="$(swsp_poll_db_metrics "$sandbox_db" '%
|
|
580
|
-
local
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
829
|
+
metrics="$(swsp_poll_db_metrics "$sandbox_db" '%Run the split probe:%' 120)"
|
|
830
|
+
local parent_assistant_messages parent_tool_call_turns terminal_stops child_task_sessions
|
|
831
|
+
parent_assistant_messages="$(printf '%s' "$metrics" | awk '{print $1}')"
|
|
832
|
+
parent_tool_call_turns="$(printf '%s' "$metrics" | awk '{print $2}')"
|
|
833
|
+
terminal_stops="$(printf '%s' "$metrics" | awk '{print $3}')"
|
|
834
|
+
child_task_sessions="$(printf '%s' "$metrics" | awk '{print $4}')"
|
|
835
|
+
parent_assistant_messages="${parent_assistant_messages:-0}"
|
|
836
|
+
parent_tool_call_turns="${parent_tool_call_turns:-0}"
|
|
837
|
+
terminal_stops="${terminal_stops:-0}"
|
|
838
|
+
child_task_sessions="${child_task_sessions:-0}"
|
|
839
|
+
swsp_info "DB metrics: parent_assistant_messages=$parent_assistant_messages parent_tool_call_turns=$parent_tool_call_turns terminal_stops=$terminal_stops child_task_sessions=$child_task_sessions"
|
|
586
840
|
|
|
587
841
|
# Wait for parent session to go idle
|
|
588
842
|
swsp_info "waiting for parent session to go idle..."
|
|
589
843
|
swsp_wait_session_idle "$OQA_SERVER_URL" "$pass" "$ses_id" 60
|
|
590
844
|
|
|
591
845
|
# Re-read metrics after idle
|
|
592
|
-
metrics="$(swsp_poll_db_metrics "$sandbox_db" '%
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
846
|
+
metrics="$(swsp_poll_db_metrics "$sandbox_db" '%Run the split probe:%' 10)"
|
|
847
|
+
parent_assistant_messages="$(printf '%s' "$metrics" | awk '{print $1}')"
|
|
848
|
+
parent_tool_call_turns="$(printf '%s' "$metrics" | awk '{print $2}')"
|
|
849
|
+
terminal_stops="$(printf '%s' "$metrics" | awk '{print $3}')"
|
|
850
|
+
child_task_sessions="$(printf '%s' "$metrics" | awk '{print $4}')"
|
|
851
|
+
parent_assistant_messages="${parent_assistant_messages:-0}"
|
|
852
|
+
parent_tool_call_turns="${parent_tool_call_turns:-0}"
|
|
853
|
+
terminal_stops="${terminal_stops:-0}"
|
|
854
|
+
child_task_sessions="${child_task_sessions:-0}"
|
|
855
|
+
swsp_info "final DB metrics: parent_assistant_messages=$parent_assistant_messages parent_tool_call_turns=$parent_tool_call_turns terminal_stops=$terminal_stops child_task_sessions=$child_task_sessions"
|
|
856
|
+
printf 'parent_assistant_messages=%s parent_tool_call_turns=%s terminal_stops=%s child_task_sessions=%s\n' \
|
|
857
|
+
"$parent_assistant_messages" "$parent_tool_call_turns" "$terminal_stops" "$child_task_sessions" \
|
|
858
|
+
>"$evidence_dir/marker-metrics.txt"
|
|
599
859
|
|
|
600
860
|
# Step 8: Plugin-init count
|
|
601
861
|
local plugin_inits
|
|
@@ -606,11 +866,15 @@ swsp_run_probe() {
|
|
|
606
866
|
|
|
607
867
|
# Step 9: Route provenance
|
|
608
868
|
local route_prov=""
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
869
|
+
swsp_collect_route_provenance \
|
|
870
|
+
"$omo_log_offset" \
|
|
871
|
+
"$omo_log" \
|
|
872
|
+
"$OQA_PROJ" \
|
|
873
|
+
"$ses_id" \
|
|
874
|
+
"$evidence_dir/route-provenance.log" \
|
|
875
|
+
"$evidence_dir/route-provenance-all.log" \
|
|
876
|
+
10 || true
|
|
877
|
+
route_prov="$(cat "$evidence_dir/route-provenance.log" 2>/dev/null || true)"
|
|
614
878
|
swsp_info "route-provenance lines: $(printf '%s' "$route_prov" | wc -l | tr -d ' ')"
|
|
615
879
|
|
|
616
880
|
# WAKE_DISPATCHED_DURING_PARENT_TURN mechanism signal
|
|
@@ -618,16 +882,30 @@ swsp_run_probe() {
|
|
|
618
882
|
wake_during_parent="$(swsp_detect_wake_during_parent "$omo_log_offset" "$fake_llm_log" "$OQA_PROJ")"
|
|
619
883
|
swsp_info "WAKE_DISPATCHED_DURING_PARENT_TURN=$wake_during_parent"
|
|
620
884
|
|
|
885
|
+
local real_db_count_after=""
|
|
886
|
+
if [ -n "$real_db_path" ] && [ "$real_db_path" != "(not found)" ] && [ -f "$real_db_path" ]; then
|
|
887
|
+
real_db_count_after="$(sqlite3 "$real_db_path" 'SELECT count(*) FROM session' 2>/dev/null || echo "0")"
|
|
888
|
+
else
|
|
889
|
+
real_db_count_after="$real_db_count_before"
|
|
890
|
+
fi
|
|
891
|
+
printf 'after=%s unchanged=%s\n' \
|
|
892
|
+
"$real_db_count_after" \
|
|
893
|
+
"$([ "$real_db_count_after" = "$real_db_count_before" ] && echo yes || echo NO)" \
|
|
894
|
+
>>"$evidence_dir/isolation-receipt.txt"
|
|
895
|
+
swsp_info "isolation: real DB before=$real_db_count_before after=$real_db_count_after"
|
|
896
|
+
|
|
897
|
+
sqlite3 "$sandbox_db" ".backup '$evidence_dir/sandbox-opencode.db'" 2>/dev/null || true
|
|
898
|
+
|
|
621
899
|
# Step 10: Branch-count guard
|
|
622
|
-
if ! swsp_check_branch_counts "$fake_llm_log" >&2; then
|
|
900
|
+
if ! swsp_check_branch_counts "$fake_llm_log" "$EXPECT_MODE" >&2; then
|
|
623
901
|
# Branch counts not met — HARNESS_ERROR
|
|
624
902
|
local ptc pc cc wc
|
|
625
|
-
ptc="$(grep -c "branch=parent-tool-call" "$fake_llm_log" 2>/dev/null ||
|
|
626
|
-
pc="$(grep -c "branch=parent-hold" "$fake_llm_log" 2>/dev/null ||
|
|
627
|
-
cc="$(grep -c "branch=child" "$fake_llm_log" 2>/dev/null ||
|
|
628
|
-
wc="$(grep -c "branch=wake" "$fake_llm_log" 2>/dev/null ||
|
|
903
|
+
ptc="$(grep -c "branch=parent-tool-call" "$fake_llm_log" 2>/dev/null || true)"; ptc="${ptc:-0}"
|
|
904
|
+
pc="$(grep -c "branch=parent-hold" "$fake_llm_log" 2>/dev/null || true)"; pc="${pc:-0}"
|
|
905
|
+
cc="$(grep -c "branch=child" "$fake_llm_log" 2>/dev/null || true)"; cc="${cc:-0}"
|
|
906
|
+
wc="$(grep -c "branch=wake" "$fake_llm_log" 2>/dev/null || true)"; wc="${wc:-0}"
|
|
629
907
|
local verdict_line
|
|
630
|
-
verdict_line="RESULT=HARNESS_ERROR
|
|
908
|
+
verdict_line="RESULT=HARNESS_ERROR parent_assistant_messages=${parent_assistant_messages} parent_tool_call_turns=${parent_tool_call_turns} terminal_stops=${terminal_stops} child_task_sessions=${child_task_sessions} plugin_inits=${plugin_inits} WAKE_DISPATCHED_DURING_PARENT_TURN=${wake_during_parent} branch_counts=parent-tool-call:${ptc},parent-hold:${pc},child:${cc},wake:${wc}"
|
|
631
909
|
printf '%s\n' "$verdict_line" | tee -a "$harness_log"
|
|
632
910
|
swsp_stop_fake_llm
|
|
633
911
|
return 1
|
|
@@ -636,29 +914,45 @@ swsp_run_probe() {
|
|
|
636
914
|
# Step 11: Determine verdict
|
|
637
915
|
local result="INCONCLUSIVE"
|
|
638
916
|
local exit_code=1
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
917
|
+
local ptc pc cc wc
|
|
918
|
+
ptc="$(grep -c "branch=parent-tool-call" "$fake_llm_log" 2>/dev/null || true)"; ptc="${ptc:-0}"
|
|
919
|
+
pc="$(grep -c "branch=parent-hold" "$fake_llm_log" 2>/dev/null || true)"; pc="${pc:-0}"
|
|
920
|
+
cc="$(grep -c "branch=child" "$fake_llm_log" 2>/dev/null || true)"; cc="${cc:-0}"
|
|
921
|
+
wc="$(grep -c "branch=wake" "$fake_llm_log" 2>/dev/null || true)"; wc="${wc:-0}"
|
|
922
|
+
local dc
|
|
923
|
+
dc="$(grep -c "branch=default" "$fake_llm_log" 2>/dev/null || true)"; dc="${dc:-0}"
|
|
924
|
+
|
|
925
|
+
if [ "${terminal_stops:-0}" -gt 1 ] || [ "${child_task_sessions:-0}" -gt 1 ] 2>/dev/null; then
|
|
642
926
|
result="REPRODUCED"
|
|
643
927
|
fi
|
|
644
928
|
|
|
645
929
|
# Arm 2: Mechanism signal (wake dispatched during parent turn + in-process path)
|
|
646
930
|
# in-process path: no live-server-route dispatch line for this wake
|
|
647
931
|
local has_live_dispatch=false
|
|
648
|
-
if
|
|
932
|
+
if swsp_has_session_live_dispatch "$route_prov" "$ses_id"; then
|
|
649
933
|
has_live_dispatch=true
|
|
650
934
|
fi
|
|
651
935
|
if [ "$wake_during_parent" = "true" ] && [ "$has_live_dispatch" = "false" ]; then
|
|
652
936
|
result="REPRODUCED"
|
|
653
937
|
fi
|
|
654
938
|
|
|
655
|
-
|
|
656
|
-
|
|
939
|
+
if [ "$result" = "INCONCLUSIVE" ] \
|
|
940
|
+
&& swsp_fixed_topology_observed \
|
|
941
|
+
"$parent_assistant_messages" \
|
|
942
|
+
"$parent_tool_call_turns" \
|
|
943
|
+
"$terminal_stops" \
|
|
944
|
+
"$child_task_sessions" \
|
|
945
|
+
"$ptc" \
|
|
946
|
+
"$pc" \
|
|
947
|
+
"$cc" \
|
|
948
|
+
"$wc" \
|
|
949
|
+
"$dc" \
|
|
950
|
+
"$has_live_dispatch"; then
|
|
657
951
|
result="FIXED"
|
|
658
952
|
fi
|
|
659
953
|
|
|
660
954
|
local verdict_line
|
|
661
|
-
verdict_line="RESULT=${result}
|
|
955
|
+
verdict_line="RESULT=${result} parent_assistant_messages=${parent_assistant_messages} parent_tool_call_turns=${parent_tool_call_turns} terminal_stops=${terminal_stops} child_task_sessions=${child_task_sessions} plugin_inits=${plugin_inits} WAKE_DISPATCHED_DURING_PARENT_TURN=${wake_during_parent} route_live_dispatch=${has_live_dispatch} branch_counts=parent-tool-call:${ptc},parent-hold:${pc},child:${cc},wake:${wc},default:${dc}"
|
|
662
956
|
printf '%s\n' "$verdict_line" | tee -a "$harness_log"
|
|
663
957
|
|
|
664
958
|
# Determine exit code based on expected mode
|
|
@@ -674,34 +968,17 @@ swsp_run_probe() {
|
|
|
674
968
|
exit_code=0 # no expectation: just report
|
|
675
969
|
fi
|
|
676
970
|
|
|
677
|
-
# Step 12: Isolation receipt — verify real DB count unchanged
|
|
678
|
-
local real_db_count_after=""
|
|
679
|
-
if [ -n "$real_db_path" ] && [ "$real_db_path" != "(not found)" ] && [ -f "$real_db_path" ]; then
|
|
680
|
-
real_db_count_after="$(sqlite3 "$real_db_path" 'SELECT count(*) FROM session' 2>/dev/null || echo "0")"
|
|
681
|
-
else
|
|
682
|
-
real_db_count_after="$real_db_count_before"
|
|
683
|
-
fi
|
|
684
|
-
printf 'after=%s unchanged=%s\n' \
|
|
685
|
-
"$real_db_count_after" \
|
|
686
|
-
"$([ "$real_db_count_after" = "$real_db_count_before" ] && echo yes || echo NO)" \
|
|
687
|
-
>>"$evidence_dir/isolation-receipt.txt"
|
|
688
|
-
swsp_info "isolation: real DB before=$real_db_count_before after=$real_db_count_after"
|
|
689
|
-
|
|
690
|
-
# Preserve the sandbox DB for post-hoc inspection before the trap removes it
|
|
691
|
-
sqlite3 "$sandbox_db" ".backup '$evidence_dir/sandbox-opencode.db'" 2>/dev/null || true
|
|
692
|
-
|
|
693
971
|
# Cleanup receipt
|
|
972
|
+
local stopped_fake_pid="$FAKE_SERVER_PID"
|
|
694
973
|
swsp_stop_fake_llm
|
|
695
974
|
printf 'fake_llm=stopped opencode_serve=stopping\n' >"$evidence_dir/cleanup-receipt.txt"
|
|
696
975
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
pkill -f "fake-openai-server" 2>/dev/null || true
|
|
976
|
+
if [ -n "$stopped_fake_pid" ] && kill -0 "$stopped_fake_pid" 2>/dev/null; then
|
|
977
|
+
swsp_log "WARNING: fake-openai server process $stopped_fake_pid still running after cleanup"
|
|
978
|
+
printf 'fake_llm_pid_alive=yes pid=%s\n' "$stopped_fake_pid" >>"$evidence_dir/cleanup-receipt.txt"
|
|
979
|
+
else
|
|
980
|
+
printf 'fake_llm_pid_alive=no pid=%s\n' "$stopped_fake_pid" >>"$evidence_dir/cleanup-receipt.txt"
|
|
703
981
|
fi
|
|
704
|
-
printf 'orphan_fake_llm=%s\n' "${orphan_count:-0}" >>"$evidence_dir/cleanup-receipt.txt"
|
|
705
982
|
|
|
706
983
|
return "$exit_code"
|
|
707
984
|
}
|