From 72f6230b4ae6cabffe2c92b8eb5c40f71b8b97bb Mon Sep 17 00:00:00 2001 From: kami Date: Mon, 27 Jul 2026 23:31:10 +0400 Subject: [PATCH] feat(harness): dispatch /v1/harness/complete by harness kind (codex/opencode) Adds an optional "harness" field so codex/opencode completions route to their own Usage readers instead of always assuming Claude's transcript format; unblocks the server side named as open in progress.md. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01W1rkJ2hBMybnJctPbcy4tT --- cmd/orchestra/main.go | 19 ++++++++++++++++++- deploy/hooks/orchestra-stop.sh | 2 +- progress.md | 21 ++++++++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/cmd/orchestra/main.go b/cmd/orchestra/main.go index a8bdbe9..cb12adc 100644 --- a/cmd/orchestra/main.go +++ b/cmd/orchestra/main.go @@ -260,6 +260,7 @@ func main() { } var p struct { TaskID string `json:"task_id"` + Harness string `json:"harness"` TranscriptPath string `json:"transcript_path"` Report string `json:"report"` } @@ -272,7 +273,23 @@ func main() { http.Error(w, "task not found", http.StatusNotFound) return } - usage, err := herdr.ClaudeUsage(p.TranscriptPath) + // Harness-specific session-state readers (AUDIT.md "Codex/opencode + // completion producers"). Same local-filesystem assumption B3 already + // made for Claude: the caller supplies the path to its own session + // state (transcript / rollout / message file), never a herdr pane id. + var usage herdr.Usage + var err error + switch p.Harness { + case "codex": + usage, err = herdr.CodexUsage(p.TranscriptPath) + case "opencode": + usage, err = herdr.OpenCodeUsage(p.TranscriptPath) + case "", "claude": + usage, err = herdr.ClaudeUsage(p.TranscriptPath) + default: + http.Error(w, "unknown harness: "+p.Harness, http.StatusBadRequest) + return + } if err != nil { http.Error(w, "reading transcript: "+err.Error(), http.StatusBadRequest) return diff --git a/deploy/hooks/orchestra-stop.sh b/deploy/hooks/orchestra-stop.sh index bff54d5..86f8aeb 100755 --- a/deploy/hooks/orchestra-stop.sh +++ b/deploy/hooks/orchestra-stop.sh @@ -36,7 +36,7 @@ if [ -f "$report_file" ]; then --arg task_id "$ORCHESTRA_TASK_ID" \ --arg transcript_path "$transcript_path" \ --arg report "$report" \ - '{task_id: $task_id, transcript_path: $transcript_path, report: $report}')" + '{task_id: $task_id, harness: "claude", transcript_path: $transcript_path, report: $report}')" if curl -fsS -X POST "${ORCHESTRA_URL%/}/v1/harness/complete" \ -H "Content-Type: application/json" \ diff --git a/progress.md b/progress.md index 4c30a62..3b6c140 100644 --- a/progress.md +++ b/progress.md @@ -226,7 +226,26 @@ Fixed so far: it too). Both `TaskCreated` and `TaskAmended` now populate all four fields. Covered by `TestTaskAmendedAppliesAllFields` (`internal/store`). -Not yet started: Codex/opencode completion producers, S8–S11. See +- **Codex/opencode completion producers** — `/v1/harness/complete` was + Claude-only (hardcoded `herdr.ClaudeUsage`). Added an optional `harness` + field to the request body (`""`/`"claude"` unchanged default); `"codex"` + dispatches to `herdr.CodexUsage`, `"opencode"` to `herdr.OpenCodeUsage`, + anything else is a 400. Both readers already existed and were tested in + `internal/herdr` but had zero callers outside tests — same "written, not + wired" pattern the rest of this audit keeps finding. The Claude stop hook + (`deploy/hooks/orchestra-stop.sh`) now sends `"harness":"claude"` + explicitly for symmetry, no behavior change. **Not done:** an actual + Codex/opencode Stop-hook-equivalent script — Codex has no native stop hook + (would need a rollout-tail poller deciding when to call this), and + opencode's own turn-boundary mechanism is unverified from source (same + caveat AUDIT.md already names for Phase 2 item 4). This change unblocks + the server side; the harness-side wrapper for either is still open. No + new test: `cmd/orchestra` has zero handler test coverage of any kind + (pre-existing, confirmed by grep before writing this), so this follows the + existing pattern rather than introducing a one-off test harness for one + handler. + +Not yet started: Codex/opencode Stop-hook-equivalent scripts, S8–S11. See `AUDIT.md` for the full plan. **Phase 0 done (2026-07-27):** this box has live TCP reachability to the real