session-orchestrator 5.6.0 → 5.8.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.
Files changed (207) hide show
  1. package/.agents/skills/architecture/SKILL.md +3 -0
  2. package/.agents/skills/architecture/agents/openai.yaml +5 -0
  3. package/.agents/skills/claude-md-drift-check/SKILL.md +1 -0
  4. package/.agents/skills/eval/SKILL.md +1 -1
  5. package/.agents/skills/frontmatter-guard/SKILL.md +1 -0
  6. package/.agents/skills/gitlab-portfolio/SKILL.md +1 -0
  7. package/.agents/skills/hook-development/SKILL.md +1 -0
  8. package/.agents/skills/mcp-builder/SKILL.md +1 -0
  9. package/.agents/skills/tmux-layout/SKILL.md +3 -0
  10. package/.agents/skills/tmux-layout/agents/openai.yaml +5 -0
  11. package/.agents/skills/vault-mirror/SKILL.md +1 -0
  12. package/.agents/skills/vault-sync/SKILL.md +1 -0
  13. package/.agents/skills/write-executable-plan/SKILL.md +3 -0
  14. package/.agents/skills/write-executable-plan/agents/openai.yaml +5 -0
  15. package/.claude-plugin/marketplace.json +1 -1
  16. package/.claude-plugin/plugin.json +1 -1
  17. package/.codex-plugin/plugin.json +1 -1
  18. package/.codex-plugin/skills/architecture/SKILL.md +3 -0
  19. package/.codex-plugin/skills/architecture/agents/openai.yaml +5 -0
  20. package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -0
  21. package/.codex-plugin/skills/eval/SKILL.md +1 -1
  22. package/.codex-plugin/skills/frontmatter-guard/SKILL.md +1 -0
  23. package/.codex-plugin/skills/gitlab-portfolio/SKILL.md +1 -0
  24. package/.codex-plugin/skills/hook-development/SKILL.md +1 -0
  25. package/.codex-plugin/skills/mcp-builder/SKILL.md +1 -0
  26. package/.codex-plugin/skills/tmux-layout/SKILL.md +3 -0
  27. package/.codex-plugin/skills/tmux-layout/agents/openai.yaml +5 -0
  28. package/.codex-plugin/skills/vault-mirror/SKILL.md +1 -0
  29. package/.codex-plugin/skills/vault-sync/SKILL.md +1 -0
  30. package/.codex-plugin/skills/write-executable-plan/SKILL.md +3 -0
  31. package/.codex-plugin/skills/write-executable-plan/agents/openai.yaml +5 -0
  32. package/.cursor/commands/architecture.md +13 -0
  33. package/.cursor/commands/eval.md +1 -1
  34. package/.cursor/commands/tmux-layout.md +13 -0
  35. package/.cursor/commands/write-executable-plan.md +13 -0
  36. package/.cursor/skills/architecture/SKILL.md +0 -1
  37. package/.cursor/skills/eval/SKILL.md +1 -1
  38. package/.cursor/skills/tmux-layout/SKILL.md +0 -1
  39. package/.cursor/skills/write-executable-plan/SKILL.md +0 -1
  40. package/.cursor-plugin/plugin.json +1 -1
  41. package/CHANGELOG.md +75 -0
  42. package/README.md +10 -10
  43. package/agents/eval-judge.md +5 -5
  44. package/docs/USER-GUIDE.md +1 -1
  45. package/docs/baseline.md +4 -3
  46. package/docs/codex-setup.md +6 -4
  47. package/docs/components.md +5 -4
  48. package/docs/events-schema.md +4 -3
  49. package/docs/github-mirror-protection.md +3 -2
  50. package/docs/install.md +39 -3
  51. package/docs/pi-setup.md +1 -1
  52. package/docs/rule-authoring.md +12 -2
  53. package/docs/session-config-reference.md +8 -6
  54. package/docs/session-config-template.md +4 -3
  55. package/evals/README.md +60 -0
  56. package/evals/instruction-ablation/README.md +147 -0
  57. package/evals/instruction-ablation/cases/psa-003-foreign-work.json +34 -0
  58. package/evals/instruction-ablation/cases/sec-007-sql-parameterisation.json +32 -0
  59. package/evals/instruction-ablation/cases/vbc-001-verify-before-claiming.json +41 -0
  60. package/evals/instruction-ablation/run.mjs +336 -0
  61. package/evals/psa-003-foreign-work/case.yaml +16 -0
  62. package/evals/psa-003-foreign-work/fixture.sh +12 -0
  63. package/evals/psa-003-foreign-work/graders/foreign-file-intact.md +7 -0
  64. package/evals/psa-003-foreign-work/graders/names-foreign-work.md +6 -0
  65. package/evals/psa-003-foreign-work/graders/no-destructive-git.md +8 -0
  66. package/evals/psa-003-foreign-work/graders/ran-git.md +7 -0
  67. package/evals/psa-003-foreign-work/prompt.md +6 -0
  68. package/hooks/_lib/hook-import-set.json +10 -2
  69. package/hooks/hooks-codex.json +1 -1
  70. package/hooks/hooks.json +1 -1
  71. package/hooks/post-tool-batch-wave-signal.mjs +1 -0
  72. package/hooks/post-tooluse-frontend-slop.mjs +11 -1
  73. package/hooks/pre-task-scope-disjoint.mjs +8 -6
  74. package/hooks/wave-scope-commit-guard.mjs +41 -10
  75. package/monitors/monitors.json +1 -1
  76. package/package.json +3 -1
  77. package/pi/prompts/architecture.md +11 -0
  78. package/pi/prompts/eval.md +1 -1
  79. package/pi/prompts/tmux-layout.md +11 -0
  80. package/pi/prompts/write-executable-plan.md +11 -0
  81. package/scripts/backfill-abandoned-sessions.mjs +6 -8
  82. package/scripts/backfill-learnings-from-vault.mjs +17 -6
  83. package/scripts/backfill-sessions.mjs +9 -7
  84. package/scripts/codex-install.mjs +108 -23
  85. package/scripts/emit-session.mjs +15 -2
  86. package/scripts/fleet-auflagen.mjs +54 -0
  87. package/scripts/generate-agents-skills.mjs +9 -16
  88. package/scripts/generate-codex-skills.mjs +8 -6
  89. package/scripts/generate-cursor-adapter.mjs +9 -74
  90. package/scripts/generate-pi-prompts.mjs +8 -74
  91. package/scripts/github-protection-audit.mjs +8 -0
  92. package/scripts/lib/auto-dialectic.mjs +10 -9
  93. package/scripts/lib/auto-dream.mjs +8 -10
  94. package/scripts/lib/autopilot/telemetry.mjs +12 -6
  95. package/scripts/lib/bootstrap-lock-refresh.mjs +8 -12
  96. package/scripts/lib/config/drift-check.mjs +1 -1
  97. package/scripts/lib/config/frontend-slop-hook.mjs +6 -0
  98. package/scripts/lib/config.mjs +5 -1
  99. package/scripts/lib/convergence-monitor.mjs +5 -3
  100. package/scripts/lib/dispatcher/rank.mjs +5 -1
  101. package/scripts/lib/ecosystem-health.mjs +5 -3
  102. package/scripts/lib/eval/engine.mjs +61 -27
  103. package/scripts/lib/eval/judge.mjs +14 -8
  104. package/scripts/lib/eval/session-resolve.mjs +7 -2
  105. package/scripts/lib/events-retention-banner.mjs +5 -2
  106. package/scripts/lib/events.mjs +81 -54
  107. package/scripts/lib/fleet-protocol.mjs +98 -1
  108. package/scripts/lib/instruction-budget-guard.mjs +25 -18
  109. package/scripts/lib/io.mjs +181 -39
  110. package/scripts/lib/learnings/candidates.mjs +14 -44
  111. package/scripts/lib/learnings/io.mjs +7 -2
  112. package/scripts/lib/learnings/judgment.mjs +5 -8
  113. package/scripts/lib/learnings/select.mjs +3 -3
  114. package/scripts/lib/maintenance-due-banner.mjs +2 -2
  115. package/scripts/lib/memory-proposals/sink.mjs +5 -6
  116. package/scripts/lib/memory-proposals/store.mjs +12 -7
  117. package/scripts/lib/mirror-issues-banner.mjs +11 -1
  118. package/scripts/lib/native-command.mjs +48 -0
  119. package/scripts/lib/orphan-reaper/scan.mjs +29 -3
  120. package/scripts/lib/peer-cards/writer.mjs +6 -18
  121. package/scripts/lib/platform.mjs +113 -4
  122. package/scripts/lib/plugin-package-stage.mjs +169 -0
  123. package/scripts/lib/plugin-surface.mjs +121 -0
  124. package/scripts/lib/quality-gate.mjs +30 -25
  125. package/scripts/lib/reconcile/idempotency.mjs +9 -10
  126. package/scripts/lib/reconcile/rule-expiry-sweep.mjs +97 -8
  127. package/scripts/lib/reconcile/writer.mjs +11 -17
  128. package/scripts/lib/rule-loader.mjs +32 -6
  129. package/scripts/lib/scope-echo.mjs +12 -2
  130. package/scripts/lib/scope-gate.mjs +2 -1
  131. package/scripts/lib/session-close-backfill.mjs +21 -4
  132. package/scripts/lib/session-id.mjs +2 -1
  133. package/scripts/lib/session-record-repair.mjs +9 -13
  134. package/scripts/lib/session-schema/constants.mjs +20 -5
  135. package/scripts/lib/session-start-probes.mjs +2 -2
  136. package/scripts/lib/sessions-staleness-banner.mjs +2 -3
  137. package/scripts/lib/skill-evolution/engine.mjs +6 -9
  138. package/scripts/lib/skill-evolution/idempotency.mjs +8 -10
  139. package/scripts/lib/slopcheck.mjs +9 -7
  140. package/scripts/lib/sunset/walker.mjs +3 -3
  141. package/scripts/lib/telemetry/sync.mjs +3 -1
  142. package/scripts/lib/telemetry-flush-health-banner.mjs +2 -2
  143. package/scripts/lib/test-sibling-coverage.mjs +167 -0
  144. package/scripts/lib/tmux-layout/telemetry-stats.mjs +5 -7
  145. package/scripts/lib/tmux-layout/telemetry.mjs +8 -10
  146. package/scripts/lib/user-invocable-skills.mjs +37 -10
  147. package/scripts/lib/ux-grill/run-record.mjs +5 -3
  148. package/scripts/lib/validate/check-banner-parity.mjs +1 -0
  149. package/scripts/lib/validate/check-skills.mjs +12 -2
  150. package/scripts/lib/validate/check-test-fixture-shapes.mjs +3 -3
  151. package/scripts/lib/validate/check-test-value-bans.mjs +12 -2
  152. package/scripts/lib/validate/check-unicode-safety.mjs +1 -1
  153. package/scripts/lib/validate/check-unwired-features.mjs +1 -1
  154. package/scripts/lib/vault-archive.mjs +2 -4
  155. package/scripts/lib/vault-mirror/process.mjs +585 -72
  156. package/scripts/lib/vault-mirror/prune.mjs +413 -0
  157. package/scripts/lib/vault-mirror/render-sessions.mjs +13 -5
  158. package/scripts/lib/vault-mirror/retention.mjs +388 -0
  159. package/scripts/lib/vault-mirror/utils.mjs +16 -1
  160. package/scripts/lib/vault-status/board-writer.mjs +6 -6
  161. package/scripts/lib/vault-sync-baseline.mjs +9 -8
  162. package/scripts/lib/wave-transcript-tail.mjs +19 -6
  163. package/scripts/lib/worktree/meta.mjs +7 -3
  164. package/scripts/mcp-server.mjs +158 -0
  165. package/scripts/migrate-sessions-jsonl.mjs +7 -5
  166. package/scripts/migrate-vault-paths.mjs +7 -4
  167. package/scripts/print-applicable-rules.mjs +1 -25
  168. package/scripts/print-learnings-index.mjs +2 -1
  169. package/scripts/release.mjs +4 -0
  170. package/scripts/relocate-vault-corpus.mjs +5 -3
  171. package/scripts/run-migrate-v2-cross-repo.mjs +9 -7
  172. package/scripts/self-update.mjs +179 -39
  173. package/scripts/site-numbers.mjs +4 -3
  174. package/scripts/sweep-expired-learnings.mjs +6 -4
  175. package/scripts/sync-vault-schema.mjs +3 -7
  176. package/scripts/vault-mirror-prune.mjs +145 -0
  177. package/scripts/vault-mirror.mjs +77 -12
  178. package/scripts/windows-setup.mjs +45 -0
  179. package/skills/_shared/fleet-protocol.md +8 -0
  180. package/skills/architecture/SKILL.md +1 -0
  181. package/skills/bootstrap/_shared-template.md +5 -2
  182. package/skills/claude-md-drift-check/SKILL.md +4 -1
  183. package/skills/claude-md-drift-check/checker.mjs +89 -26
  184. package/skills/discovery/probes/ssot-code-diff.mjs +3 -3
  185. package/skills/eval/SKILL.md +12 -13
  186. package/skills/eval/rubric-v3.md +521 -0
  187. package/skills/frontmatter-guard/SKILL.md +1 -0
  188. package/skills/gitlab-portfolio/SKILL.md +1 -0
  189. package/skills/hook-development/SKILL.md +1 -0
  190. package/skills/mcp-builder/SKILL.md +1 -0
  191. package/skills/repo-audit/SKILL.md +2 -2
  192. package/skills/session-end/SKILL.md +32 -1
  193. package/skills/session-end/vault-operations.md +12 -2
  194. package/skills/session-start/SKILL.md +2 -2
  195. package/skills/session-start/phase-7-1-premise-check.md +2 -1
  196. package/skills/session-start/references/operations-contract.md +4 -1
  197. package/skills/tmux-layout/SKILL.md +1 -0
  198. package/skills/vault-mirror/SKILL.md +28 -2
  199. package/skills/vault-sync/SKILL.md +6 -6
  200. package/skills/vault-sync/validator.sh +29 -10
  201. package/skills/wave-executor/references/wave-loop-scope-manifest.md +5 -3
  202. package/skills/write-executable-plan/SKILL.md +1 -0
  203. package/hooks/agent-teams-h3-test.sh +0 -362
  204. package/scripts/spikes/h3-agent-teams/preflight.sh +0 -53
  205. package/scripts/spikes/h3-agent-teams/run-h3.sh +0 -112
  206. package/scripts/spikes/h3-agent-teams/setup.sh +0 -137
  207. package/scripts/spikes/h3-agent-teams/toggle.sh +0 -38
@@ -1,362 +0,0 @@
1
- #!/usr/bin/env bash
2
- # hooks/agent-teams-h3-test.sh — Empirical H3 hook-seam test harness for Agent Teams Adapter
3
- #
4
- # Per ADR 0002 (issue #484): verify that a TaskCompleted exit-2 hook reliably blocks
5
- # task completion + feeds back to the teammate across 3 repeat runs (lagging-task-status race).
6
- #
7
- # This is a DRY-RUN harness. Live Agent Teams execution is interactive and cannot be
8
- # fully automated from bash. The script:
9
- # 1. Verifies preconditions (claude-code version, experimental flag availability)
10
- # 2. Sets up the test team scaffold at ~/.claude/teams/h3-test-deep3/
11
- # 3. Prints the manual 3-run procedure for the operator to execute
12
- # 4. Generates a JSONL log template for capturing results
13
- #
14
- # Exit codes:
15
- # 0 — preconditions met, scaffold created, ready for manual 3-run
16
- # 1 — preconditions failed (version too low, flag unrecognized, etc.)
17
- # 2 — scaffold creation failed (permission/path issue)
18
-
19
- set -euo pipefail
20
-
21
- TEAM_NAME="h3-test-deep3"
22
- TEAM_DIR="${HOME}/.claude/teams/${TEAM_NAME}"
23
- LOG_TEMPLATE_PATH=".orchestrator/research/h3-hook-seam-test-template.jsonl"
24
- MIN_CLAUDE_VERSION="2.1.32"
25
-
26
- # ---------------------------------------------------------------------------
27
- # Helpers
28
- # ---------------------------------------------------------------------------
29
-
30
- print_header() {
31
- echo ""
32
- echo "============================================================"
33
- echo " H3 Hook-Seam Test Harness — Agent Teams Adapter (ADR 0002)"
34
- echo "============================================================"
35
- echo ""
36
- echo "Purpose: Verify that a TaskCompleted exit-2 hook reliably blocks"
37
- echo " task completion and delivers feedback to the teammate,"
38
- echo " across 3 repeat runs (lagging-task-status race check)."
39
- echo ""
40
- echo "This is a DRY-RUN setup harness. Live execution is interactive."
41
- echo ""
42
- }
43
-
44
- version_gte() {
45
- # Returns 0 if $1 >= $2 (semver comparison, major.minor.patch)
46
- local actual="$1"
47
- local required="$2"
48
- # Use sort -V to compare; if the required version comes first (or is equal),
49
- # the actual version is sufficient.
50
- local lowest
51
- lowest="$(printf '%s\n%s\n' "$actual" "$required" | sort -V | head -n1)"
52
- [ "$lowest" = "$required" ]
53
- }
54
-
55
- # ---------------------------------------------------------------------------
56
- # Step 1: Precondition check
57
- # ---------------------------------------------------------------------------
58
-
59
- precondition_check() {
60
- echo "=== Step 1: Precondition Check ==="
61
- echo ""
62
-
63
- local failed=0
64
-
65
- # 1a. claude-code binary present
66
- if ! command -v claude >/dev/null 2>&1; then
67
- echo "[FAIL] 'claude' binary not found on PATH."
68
- echo " Install Claude Code >= ${MIN_CLAUDE_VERSION} and ensure it is on your PATH."
69
- failed=1
70
- else
71
- # 1b. Version check
72
- local raw_version
73
- raw_version="$(claude --version 2>/dev/null | head -n1)" || true
74
- # Extract the semver portion (e.g. "2.1.144" from "2.1.144 (Claude Code)")
75
- local actual_version
76
- actual_version="$(echo "${raw_version}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)" || true
77
-
78
- if [ -z "${actual_version}" ]; then
79
- echo "[FAIL] Could not parse version from: '${raw_version}'"
80
- echo " Expected format: '2.1.144 (Claude Code)'"
81
- failed=1
82
- elif version_gte "${actual_version}" "${MIN_CLAUDE_VERSION}"; then
83
- echo "[PASS] claude version: ${actual_version} >= ${MIN_CLAUDE_VERSION} (minimum required)"
84
- else
85
- echo "[FAIL] claude version: ${actual_version} < ${MIN_CLAUDE_VERSION} (minimum required)"
86
- echo " Please upgrade Claude Code before running the H3 test."
87
- failed=1
88
- fi
89
- fi
90
-
91
- # 1c. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS recognized in binary
92
- # We check via 'strings' (available on macOS/Linux) rather than actually
93
- # setting the env-var, since setting it alone has no side effects but
94
- # we want to confirm the flag is compiled in — not just accepted silently.
95
- echo ""
96
- echo "Checking CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS flag recognition..."
97
- local claude_bin
98
- claude_bin="$(command -v claude 2>/dev/null)" || true
99
-
100
- if [ -n "${claude_bin}" ] && command -v strings >/dev/null 2>&1; then
101
- local flag_hits
102
- flag_hits="$(strings "${claude_bin}" 2>/dev/null | grep -c 'CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS' || true)"
103
- if [ "${flag_hits}" -ge 1 ]; then
104
- echo "[PASS] CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS is compiled into the binary (${flag_hits} occurrences)"
105
- else
106
- echo "[WARN] Could not confirm flag in binary via 'strings'. This may be a macOS SIP or binary format issue."
107
- echo " Proceeding; flag may still be recognized at runtime."
108
- fi
109
- else
110
- echo "[INFO] 'strings' not available or claude binary not found — skipping binary flag scan."
111
- echo " Flag recognition was confirmed empirically at W1 D2 (session 2026-05-19-deep-2)."
112
- fi
113
-
114
- # 1d. No existing ~/.claude/teams/ team with this name (avoid clobber)
115
- echo ""
116
- if [ -d "${TEAM_DIR}" ]; then
117
- echo "[WARN] ${TEAM_DIR} already exists. Scaffold step will skip overwriting existing files."
118
- else
119
- echo "[INFO] ${TEAM_DIR} does not exist — scaffold will create it fresh."
120
- fi
121
-
122
- echo ""
123
- if [ "${failed}" -eq 1 ]; then
124
- echo "[FAIL] One or more preconditions not met. Resolve issues above before proceeding."
125
- return 1
126
- fi
127
-
128
- echo "[PASS] All preconditions met."
129
- return 0
130
- }
131
-
132
- # ---------------------------------------------------------------------------
133
- # Step 2: Scaffold the test team directory
134
- # ---------------------------------------------------------------------------
135
-
136
- scaffold_team_dir() {
137
- echo "=== Step 2: Team Scaffold ==="
138
- echo ""
139
- echo "Creating team scaffold at: ${TEAM_DIR}"
140
- echo ""
141
-
142
- # Use a subshell so set -e applies; any failure returns 2 to caller via trap
143
- if ! mkdir -p "${TEAM_DIR}"; then
144
- echo "[FAIL] Could not create ${TEAM_DIR} — check permissions."
145
- return 2
146
- fi
147
-
148
- # Write the hooks config that will exercise the H3 seam.
149
- # NOTE: This is the INTENDED config shape; the operator must verify that
150
- # the actual Agent Teams schema in their claude-code version matches this
151
- # before live execution. The machine-owned config.json is NOT created here
152
- # (that is generated by claude-code on first team spawn).
153
- local hooks_file="${TEAM_DIR}/hooks.json"
154
- if [ ! -f "${hooks_file}" ]; then
155
- cat >"${hooks_file}" <<'HOOKS_JSON'
156
- {
157
- "_comment": "H3 test hook config — NOT machine-owned config.json. Verify schema with your claude-code version.",
158
- "_warning": "config.json for Agent Teams is machine-owned; do not hand-edit it. This hooks.json is reference only.",
159
- "teamHooks": {
160
- "TaskCompleted": [
161
- {
162
- "hooks": [
163
- {
164
- "type": "command",
165
- "command": "npm run typecheck",
166
- "_rationale": "Exit-2 on typecheck failure blocks task completion + feeds back to teammate. H3 test seam."
167
- }
168
- ]
169
- }
170
- ],
171
- "TeammateIdle": [
172
- {
173
- "hooks": [
174
- {
175
- "type": "command",
176
- "command": "echo '[H3] TeammateIdle hook fired — teammate is idle'",
177
- "_rationale": "Witness hook to confirm TeammateIdle seam fires. No blocking behavior for H3."
178
- }
179
- ]
180
- }
181
- ]
182
- }
183
- }
184
- HOOKS_JSON
185
- echo "[DONE] Created ${hooks_file} (reference hook config — NOT the machine-owned config.json)"
186
- else
187
- echo "[SKIP] ${hooks_file} already exists — not overwritten."
188
- fi
189
-
190
- # Write the test task definition (reference only)
191
- local task_file="${TEAM_DIR}/h3-test-task.json"
192
- if [ ! -f "${task_file}" ]; then
193
- cat >"${task_file}" <<'TASK_JSON'
194
- {
195
- "_comment": "Reference task definition for H3 manual test run. Adapt to your team lead's task-creation flow.",
196
- "id": "h3-ts-error-task",
197
- "subject": "Introduce a deliberate TypeScript error in a scratch file, then confirm typecheck blocks completion",
198
- "description": "Add 'const x: number = \"not-a-number\";' to src/scratch/h3-test.ts. This guarantees a typecheck failure. The TaskCompleted hook (npm run typecheck) must exit 2, blocking the teammate and delivering the error message as feedback. Verify the teammate sees the block, reads the feedback, corrects the file, and retries.",
199
- "expectedOutcome": {
200
- "hookFires": true,
201
- "exitCode": 2,
202
- "taskBlocked": true,
203
- "feedbackDelivered": true,
204
- "teammateRetries": true
205
- }
206
- }
207
- TASK_JSON
208
- echo "[DONE] Created ${task_file} (reference task definition)"
209
- else
210
- echo "[SKIP] ${task_file} already exists — not overwritten."
211
- fi
212
-
213
- echo ""
214
- echo "[PASS] Scaffold complete: ${TEAM_DIR}"
215
- return 0
216
- }
217
-
218
- # ---------------------------------------------------------------------------
219
- # Step 3: Generate JSONL log template
220
- # ---------------------------------------------------------------------------
221
-
222
- generate_log_template() {
223
- echo "=== Step 3: JSONL Log Template ==="
224
- echo ""
225
-
226
- local log_dir
227
- log_dir="$(dirname "${LOG_TEMPLATE_PATH}")"
228
-
229
- if [ ! -d "${log_dir}" ]; then
230
- echo "[INFO] Creating directory: ${log_dir}"
231
- if ! mkdir -p "${log_dir}"; then
232
- echo "[WARN] Could not create ${log_dir} — skipping log template generation."
233
- return 0
234
- fi
235
- fi
236
-
237
- if [ -f "${LOG_TEMPLATE_PATH}" ]; then
238
- echo "[SKIP] ${LOG_TEMPLATE_PATH} already exists — not overwritten."
239
- return 0
240
- fi
241
-
242
- cat >"${LOG_TEMPLATE_PATH}" <<'JSONL_TEMPLATE'
243
- {"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":1,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 1 — PENDING. Fill after manual execution."}
244
- {"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":2,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 2 — PENDING. Fill after manual execution."}
245
- {"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":3,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 3 — PENDING. Fill after manual execution."}
246
- JSONL_TEMPLATE
247
-
248
- echo "[DONE] Created log template: ${LOG_TEMPLATE_PATH}"
249
- echo ""
250
- echo "Schema per row:"
251
- echo " timestamp — ISO-8601 UTC timestamp of the run"
252
- echo " run_n — 1, 2, or 3"
253
- echo " hook_exit_code — observed exit code from the TaskCompleted hook (expect 2 on TS error)"
254
- echo " task_status — 'blocked' | 'completed' | 'error'"
255
- echo " blocked — true if teammate saw the task blocked; false otherwise"
256
- echo " feedback_delivered — true if teammate received the typecheck error message; false otherwise"
257
- echo " teammate_retried — true if teammate corrected the error and retried; false otherwise"
258
- echo " notes — free-text observations (race condition signs, UI behaviour, etc.)"
259
- return 0
260
- }
261
-
262
- # ---------------------------------------------------------------------------
263
- # Step 4: Print manual 3-run procedure
264
- # ---------------------------------------------------------------------------
265
-
266
- print_manual_procedure() {
267
- echo ""
268
- echo "=== Step 4: Manual 3-Run Procedure ==="
269
- echo ""
270
- echo "Complete the following steps manually in a terminal with an interactive Claude Code session."
271
- echo "Run the full procedure 3 times, logging results to: ${LOG_TEMPLATE_PATH}"
272
- echo ""
273
- echo "--- Pre-run setup (once) ---"
274
- echo ""
275
- echo " 1. Export the Agent Teams flag:"
276
- echo " export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"
277
- echo ""
278
- echo " 2. Create the scratch TypeScript file for the test task:"
279
- echo " mkdir -p src/scratch"
280
- echo " echo 'const x: number = \"not-a-number\";' > src/scratch/h3-test.ts"
281
- echo ""
282
- echo "--- Per-run procedure (repeat 3 times) ---"
283
- echo ""
284
- echo " Run N (replace N with 1, 2, 3):"
285
- echo ""
286
- echo " Step 1. Launch Claude Code in team lead mode:"
287
- echo " claude (with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in env)"
288
- echo ""
289
- echo " Step 2. In the Claude Code session, use /team to configure the team:"
290
- echo " - Team name: ${TEAM_NAME}"
291
- echo " - Spawn 1 teammate (e.g., named 'impl-agent')"
292
- echo " - Attach the TaskCompleted hook: 'npm run typecheck' (exit-2 blocks)"
293
- echo " Reference hooks config: ${TEAM_DIR}/hooks.json"
294
- echo ""
295
- echo " Step 3. Assign the teammate the H3 test task:"
296
- echo " 'Implement src/scratch/h3-test.ts — it currently has a TypeScript error."
297
- echo " The task is complete when typecheck passes. Task ID: h3-ts-error-task.'"
298
- echo " Reference task definition: ${TEAM_DIR}/h3-test-task.json"
299
- echo ""
300
- echo " Step 4. Observe TaskCompleted hook behavior:"
301
- echo " - Hook fires 'npm run typecheck'"
302
- echo " - Does the hook exit 2? (typecheck should fail on the deliberate error)"
303
- echo " - Is the task marked 'blocked' (not 'completed') in the task list?"
304
- echo " - Does the teammate receive the typecheck error output as feedback?"
305
- echo ""
306
- echo " Step 5. Observe teammate correction:"
307
- echo " - Does the teammate read the feedback and correct src/scratch/h3-test.ts?"
308
- echo " - Does the teammate retry task completion after correction?"
309
- echo " - Does the hook exit 0 on the corrected file?"
310
- echo " - Is the task marked 'completed'?"
311
- echo ""
312
- echo " Step 6. Log results:"
313
- echo " Edit ${LOG_TEMPLATE_PATH} and fill in row N with observed values."
314
- echo ""
315
- echo "--- Promotion criteria (from ADR 0002) ---"
316
- echo ""
317
- echo " PASS: All 3 runs show hook_exit_code=2, blocked=true, feedback_delivered=true"
318
- echo " → H3 PASS → Agent Teams backend spike proceeds (#484)"
319
- echo ""
320
- echo " FAIL: Any run shows blocked=false OR feedback_delivered=false"
321
- echo " → H3 FAIL → Spike closed won't-do, ADR 0002 collapses to Stay"
322
- echo ""
323
- echo " After recording results, update \"Agent Teams H3 Hook-Seam Test — Empirical Research Note\""
324
- echo " (#484; archived in the private Meta-Vault)"
325
- echo " § Results and § Status with the outcome."
326
- echo ""
327
- echo "--- Cleanup ---"
328
- echo ""
329
- echo " After all 3 runs:"
330
- echo " rm -f src/scratch/h3-test.ts"
331
- echo " # Team dir ${TEAM_DIR} can be left for H4 config-overwrite test"
332
- echo ""
333
- }
334
-
335
- # ---------------------------------------------------------------------------
336
- # Main
337
- # ---------------------------------------------------------------------------
338
-
339
- main() {
340
- print_header
341
-
342
- precondition_check || exit 1
343
- echo ""
344
-
345
- scaffold_team_dir || exit 2
346
- echo ""
347
-
348
- generate_log_template
349
- echo ""
350
-
351
- print_manual_procedure
352
-
353
- echo "============================================================"
354
- echo " Harness setup complete — ready for manual 3-run execution"
355
- echo " Log template: ${LOG_TEMPLATE_PATH}"
356
- echo " Team scaffold: ${TEAM_DIR}"
357
- echo "============================================================"
358
- echo ""
359
- exit 0
360
- }
361
-
362
- main "$@"
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env bash
2
- # preflight.sh — NON-claude smoke test of the H3 hook seam's command contract.
3
- #
4
- # Builds the fixture if missing, then runs `npm run --silent typecheck` in both
5
- # toggle states and asserts the exit codes the TaskCompleted hook depends on:
6
- # pass-state → exit 0 (hook would allow completion)
7
- # fail-state → exit 2 (hook would BLOCK completion)
8
- #
9
- # This validates the seam's command contract WITHOUT spawning any claude
10
- # session — only node/npm in /tmp. Exit 0 iff both assertions pass.
11
- set -uo pipefail
12
-
13
- HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
- FIXTURE="/tmp/h3-agent-teams-test"
15
- FAILED=0
16
-
17
- echo "=== H3 preflight — hook-seam command contract (no claude session) ==="
18
-
19
- # Build fixture if missing.
20
- if [ ! -f "${FIXTURE}/package.json" ]; then
21
- echo "[preflight] fixture missing — running setup.sh"
22
- bash "${HERE}/setup.sh"
23
- fi
24
-
25
- run_assert() {
26
- local state="$1" expected="$2"
27
- bash "${HERE}/toggle.sh" "${state}" >/dev/null
28
- local out exit_code
29
- out="$(cd "${FIXTURE}" && npm run --silent typecheck 2>&1)"
30
- exit_code=$?
31
- if [ "${exit_code}" -eq "${expected}" ]; then
32
- echo "PASS: ${state}-state → exit ${exit_code} (expected ${expected}) | ${out}"
33
- else
34
- echo "FAIL: ${state}-state → exit ${exit_code} (expected ${expected}) | ${out}"
35
- FAILED=1
36
- fi
37
- }
38
-
39
- run_assert pass 0
40
- run_assert fail 2
41
-
42
- # Leave the fixture in PASS state for run 1 (operator toggles to fail before runs 2-3).
43
- bash "${HERE}/toggle.sh" pass >/dev/null
44
-
45
- echo "=== preflight result ==="
46
- if [ "${FAILED}" -eq 0 ]; then
47
- echo "ALL ASSERTIONS PASSED — hook command contract verified (exit 0 pass / exit 2 fail)"
48
- echo "Fixture left in PASS state at ${FIXTURE} (ready for run 1)."
49
- exit 0
50
- else
51
- echo "ONE OR MORE ASSERTIONS FAILED — do not proceed to the interactive runs."
52
- exit 1
53
- fi
@@ -1,112 +0,0 @@
1
- #!/usr/bin/env bash
2
- # run-h3.sh — operator harness for the #484-H3 Agent-Teams hook-seam test.
3
- #
4
- # This script does NOT spawn claude. It ensures the fixture exists and prints
5
- # the exact per-run procedure the operator follows interactively. Agent Teams
6
- # are interactive-only; on this host (Ghostty, no tmux) split-pane is
7
- # unsupported, so `--teammate-mode in-process` is mandatory.
8
- #
9
- # Usage:
10
- # ./run-h3.sh # print the full 3-run procedure
11
- # ./run-h3.sh 1|2|3 # print the procedure for a single run
12
- # ./run-h3.sh cleanup # remove fixture + team/task state
13
- set -euo pipefail
14
-
15
- HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
- FIXTURE="/tmp/h3-agent-teams-test"
17
-
18
- TEAM="h3-test-484"
19
- PROMPT="Create an agent team named ${TEAM} with one teammate called impl-agent. Assign impl-agent a single task: 'Make npm run typecheck pass for src/h3.ts, then mark the task complete.' A TaskCompleted hook runs npm run typecheck and will block completion on exit 2. Do not fix the file yourself — let the teammate do it."
20
-
21
- LAUNCH="cd ${FIXTURE} && export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 && claude --teammate-mode in-process"
22
-
23
- ensure_fixture() {
24
- if [ ! -f "${FIXTURE}/package.json" ]; then
25
- echo "[run-h3] fixture missing — building it"
26
- bash "${HERE}/setup.sh"
27
- fi
28
- }
29
-
30
- print_run() {
31
- local n="$1" state expected
32
- if [ "${n}" -eq 1 ]; then state="pass"; expected="completes UNBLOCKED (hook exit 0)"; else state="fail"; expected="BLOCKED (hook exit 2), then teammate retries to pass"; fi
33
-
34
- cat <<EOF
35
-
36
- ────────────────────────────────────────────────────────────────────────────
37
- RUN ${n} — required src/h3.ts state: ${state} → expected: ${expected}
38
- ────────────────────────────────────────────────────────────────────────────
39
- 1. Toggle the source state:
40
- ${HERE}/toggle.sh ${state}
41
-
42
- 2. Launch (in-process mode — split-pane unsupported in Ghostty):
43
- ${LAUNCH}
44
-
45
- 3. Paste this prompt to the lead:
46
- ${PROMPT}
47
-
48
- 4. Observe (keys inside the claude TUI):
49
- - Shift+Down → focus/scroll the teammate pane (read its actions + hook feedback)
50
- - Ctrl+T → toggle the task list (watch the task status transition)
51
- Look for: the TaskCompleted hook firing, its exit code, whether the task is
52
- blocked vs completed, whether the typecheck error reached the teammate as
53
- feedback, and whether the teammate retried after reading it.
54
-
55
- 5. Record one JSONL line into ${FIXTURE}/h3-results.jsonl
56
- (shape: ${FIXTURE}/RESULTS-TEMPLATE.jsonl):
57
- run 1 expect → hook_exit_code:0, task_status:"completed", blocked:false
58
- runs 2-3 expect → hook_exit_code:2, blocked:true, feedback_delivered:true,
59
- teammate_retried:true, then task_status:"completed" after retry
60
-
61
- 6. Reset before the NEXT run (fresh team each run):
62
- ${HERE}/run-h3.sh cleanup # or just remove the team/task dirs (see cleanup)
63
- ${HERE}/setup.sh # rebuild a clean fixture
64
- EOF
65
- }
66
-
67
- cleanup() {
68
- echo "[run-h3] cleaning fixture + team/task state"
69
- rm -rf "${FIXTURE}" "${HOME}/.claude/teams/${TEAM}" "${HOME}/.claude/tasks/${TEAM}"
70
- echo "[run-h3] removed:"
71
- echo " ${FIXTURE}"
72
- echo " ${HOME}/.claude/teams/${TEAM}"
73
- echo " ${HOME}/.claude/tasks/${TEAM}"
74
- }
75
-
76
- case "${1:-all}" in
77
- cleanup)
78
- cleanup
79
- ;;
80
- 1|2|3)
81
- ensure_fixture
82
- print_run "$1"
83
- ;;
84
- all)
85
- ensure_fixture
86
- cat <<EOF
87
- ============================================================================
88
- #484-H3 Agent-Teams hook-seam test — operator harness
89
- Fixture: ${FIXTURE} Team: ${TEAM} Mode: --teammate-mode in-process
90
- Run preflight.sh FIRST to confirm the command contract (exit 0 pass / 2 fail).
91
- 3-run matrix: run 1 = pass (must complete unblocked)
92
- run 2 = fail (must block, then retry to pass)
93
- run 3 = fail (must block, then retry to pass)
94
- ============================================================================
95
- EOF
96
- print_run 1
97
- print_run 2
98
- print_run 3
99
- cat <<EOF
100
-
101
- ────────────────────────────────────────────────────────────────────────────
102
- CLEANUP (after all 3 runs):
103
- rm -rf ${FIXTURE} ${HOME}/.claude/teams/${TEAM} ${HOME}/.claude/tasks/${TEAM}
104
- (or: ${HERE}/run-h3.sh cleanup)
105
- ────────────────────────────────────────────────────────────────────────────
106
- EOF
107
- ;;
108
- *)
109
- echo "usage: $0 [1|2|3|cleanup]" >&2
110
- exit 1
111
- ;;
112
- esac
@@ -1,137 +0,0 @@
1
- #!/usr/bin/env bash
2
- # setup.sh — idempotent fixture builder for the #484-H3 Agent-Teams hook-seam test.
3
- #
4
- # Builds /tmp/h3-agent-teams-test: a minimal, self-contained TypeScript-ish
5
- # fixture whose `npm run typecheck` is a zero-dependency node script. The
6
- # TaskCompleted hook (in .claude/settings.json) runs that typecheck and is
7
- # expected to exit 2 (block) when src/h3.ts is in its FAIL state.
8
- #
9
- # Spawns NO claude session — only node/npm/git in /tmp. Re-running is safe:
10
- # it rewrites the fixture files deterministically and re-commits only if dirty.
11
- set -euo pipefail
12
-
13
- FIXTURE="/tmp/h3-agent-teams-test"
14
-
15
- # Symlink guard (#627 codex review, HIGH — CWE-377/CWE-61). The fixture path is
16
- # fixed and predictable, so a pre-planted symlink at ${FIXTURE} (e.g. -> $HOME)
17
- # would make the `cat >` writes below follow out-of-dir and clobber files
18
- # outside /tmp. Refuse to proceed if ${FIXTURE} exists as a symlink. The fixed
19
- # path is intentional (shared across setup/toggle/preflight/run-h3 + the
20
- # operator runbook's cleanup commands), so we harden in place rather than switch
21
- # to mktemp -d, which would break that cross-script + runbook contract.
22
- if [ -L "${FIXTURE}" ]; then
23
- echo "[setup] REFUSING: ${FIXTURE} is a symlink (possible symlink-following attack)." >&2
24
- echo "[setup] remove it and re-run: rm -f \"${FIXTURE}\"" >&2
25
- exit 1
26
- fi
27
-
28
- echo "[setup] building H3 fixture at ${FIXTURE}"
29
- mkdir -p "${FIXTURE}/src" "${FIXTURE}/.claude"
30
-
31
- # --- package.json -----------------------------------------------------------
32
- cat > "${FIXTURE}/package.json" <<'JSON'
33
- {
34
- "name": "h3-agent-teams-fixture",
35
- "version": "0.0.0",
36
- "private": true,
37
- "scripts": {
38
- "typecheck": "node ./typecheck.mjs"
39
- }
40
- }
41
- JSON
42
-
43
- # --- typecheck.mjs (self-contained, no deps) --------------------------------
44
- # Exit 2 when src/h3.ts is missing, contains FAIL_MARKER, or assigns a string
45
- # literal to a `: number` annotation. Exit 0 otherwise. Diagnostics on stderr.
46
- cat > "${FIXTURE}/typecheck.mjs" <<'MJS'
47
- #!/usr/bin/env node
48
- // Self-contained typecheck gate for the #484-H3 fixture. NO external deps —
49
- // this is deliberately NOT tsgo/tsc so the fixture needs no install step.
50
- import { readFileSync } from 'node:fs';
51
-
52
- const TARGET = 'src/h3.ts';
53
-
54
- let source;
55
- try {
56
- source = readFileSync(new URL(`./${TARGET}`, import.meta.url), 'utf8');
57
- } catch {
58
- process.stderr.write(`typecheck: ${TARGET} missing\n`);
59
- process.exit(2);
60
- }
61
-
62
- const hasFailMarker = source.includes('FAIL_MARKER');
63
- const stringToNumber = /:\s*number\s*=\s*["']/.test(source);
64
-
65
- if (hasFailMarker || stringToNumber) {
66
- process.stderr.write(
67
- `typecheck FAILED: type error in ${TARGET} (string assigned to number / FAIL_MARKER present)\n`,
68
- );
69
- process.exit(2);
70
- }
71
-
72
- process.stdout.write('typecheck PASSED: 0 errors\n');
73
- process.exit(0);
74
- MJS
75
-
76
- # --- src/h3.ts — initial PASS state -----------------------------------------
77
- cat > "${FIXTURE}/src/h3.ts" <<'TS'
78
- export const x: number = 42;
79
- TS
80
-
81
- # --- .claude/settings.json --------------------------------------------------
82
- # Enables the experimental Agent-Teams flag AND wires the TaskCompleted hook
83
- # to the typecheck gate. settings.json must be committed for hooks to load.
84
- cat > "${FIXTURE}/.claude/settings.json" <<'JSON'
85
- {
86
- "env": {
87
- "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
88
- },
89
- "hooks": {
90
- "TaskCompleted": [
91
- {
92
- "matcher": "",
93
- "hooks": [
94
- {
95
- "type": "command",
96
- "command": "npm run --silent typecheck",
97
- "timeout": 60
98
- }
99
- ]
100
- }
101
- ]
102
- }
103
- }
104
- JSON
105
-
106
- # --- results log + template -------------------------------------------------
107
- # Results log the operator appends to; template documents the shape.
108
- # Create-if-absent ONLY — never truncate. The between-run reset rebuilds the
109
- # fixture (run-h3.sh cleanup → setup.sh); truncating here would destroy the
110
- # run-N evidence the operator was told (run-h3.sh step 5) to append before
111
- # run-N+1 (#627 codex review, MEDIUM). A fresh `run-h3.sh cleanup` removes the
112
- # whole fixture dir, which is the intended full reset.
113
- if [ ! -f "${FIXTURE}/h3-results.jsonl" ]; then
114
- : > "${FIXTURE}/h3-results.jsonl"
115
- fi
116
-
117
- cat > "${FIXTURE}/RESULTS-TEMPLATE.jsonl" <<'JSON'
118
- {"timestamp":"<ISO>","run_n":1,"src_state":"pass|fail","hook_exit_code":0,"task_status":"completed|blocked|stuck","blocked":false,"feedback_delivered":false,"teammate_retried":false,"transcript_excerpt":"...","notes":"..."}
119
- JSON
120
-
121
- # --- git init + initial commit ----------------------------------------------
122
- if [ ! -d "${FIXTURE}/.git" ]; then
123
- git -C "${FIXTURE}" init -q
124
- git -C "${FIXTURE}" config user.email "h3-fixture@example.invalid"
125
- git -C "${FIXTURE}" config user.name "H3 Fixture"
126
- fi
127
- # Ensure the experimental hooks settings are tracked & committed (idempotent).
128
- git -C "${FIXTURE}" add -A
129
- if ! git -C "${FIXTURE}" diff --cached --quiet; then
130
- git -C "${FIXTURE}" commit -q -m "chore(h3): fixture state (settings.json + typecheck gate + src/h3.ts)"
131
- echo "[setup] committed fixture state"
132
- else
133
- echo "[setup] fixture already committed (no changes)"
134
- fi
135
-
136
- echo "[setup] DONE — fixture ready at ${FIXTURE}"
137
- echo "[setup] next: run ./preflight.sh to smoke-test the seam (no claude session)"