# Orchestra — session notes & next steps, 2026-07-31 Scope of this session: acted on `REVIEW.md` (the 2026-07-30 senior review), then on seven operator review comments left on Gitea PR #1. Two commits on `webui-and-audit-reconciliation`, pushed, not merged at time of writing. **Nothing was deployed. No live herdr or pane was touched.** --- ## What landed ### `56f5aac` — reconcile docs, module graph, token compare, health | Finding | Action | |---|---| | REVIEW.md 1 | `CLAUDE.md`/`AGENTS.md` federation drift fixed; `clients/` tracked (later reversed — see below) | | REVIEW.md 2 | `progress.md` references removed from `CLAUDE.md`, `AGENTS.md`, `rotation_test.go`, `deploy/hooks/orchestra-codex-poll.sh` | | REVIEW.md 4 | `web/go.mod` stub added — ends the parent module's package graph at `web/` | | REVIEW.md 5 | `orchestra-worker` untracked (still on disk); both binaries gitignored | | REVIEW.md 7 | `subtle.ConstantTimeCompare` in `cmd/orchestra/main.go` | | REVIEW.md 3 | (already fixed in the review's own pass — `SessionHealth.LastError` + `Observed`) | ### `97a9c65` — delete Design A, hook completion path, retired deploy files Deleted: `clients/` (3 files), `deploy/hooks/` (3 scripts), `deploy/config.example.json`, `deploy/orchestra.service`, `deploy/redeploy.sh`, `deploy/docker-api-entrypoint.sh`, the `/v1/harness/complete` route, the unmounted `harnessCompletion` handler, and that handler's test. Changed: `Dockerfile.api` now `ENTRYPOINT ["/app/orchestra"]`; docs updated across `CLAUDE.md`, `AGENTS.md`, `AUDIT.md`, `deploy/DEPLOYMENT.md`, `deploy/orchestra.env.example`, `deploy/config.example.jsonc`, `.gitignore`. --- ## Ground truth established this session Worth keeping — each of these corrected a documented claim. 1. **`orchestra-worker` owns completion, end to end.** It watches for `.orchestra/done` in the worktree, confirms via `AgentStatus` that the agent is not busy (a marker alone is intent, not proof), then finalizes and posts through `/v1/federation/*` with **both** lease epoch and expected version. `cmd/orchestra-worker/main.go:385-412`. 2. **The `deploy/hooks/` scripts were vestigial, not partly-needed.** They used a different, older convention (`.orchestra-report.md`) and posted to `/v1/harness/complete`, which was already a 410 stub — so that path could not have completed a task. It never fired because the live OpenCode QA run went through the worker. `/v1/harness/turn` is a separate, still-live endpoint and was not touched. 3. **Env vars reach the API container via `env_file: .env`** in `~/docker-apps/orchestra-web-ui/compose.yaml` — that is where the Gitea/ntfy/web tokens and the bcrypt operator hash live. Only a single file, `config.jsonc`, is bind-mounted into `/etc/orchestra/` (via `compose.override.yaml`). CLAUDE.md previously claimed the container mounted `/etc/orchestra:ro` and that its entrypoint sourced the env file. Both wrong. 4. **`ORCHESTRA_DATA`/`ORCHESTRA_PORT` are baked into the image** at `Dockerfile.api` line 17, independent of compose — which is why deleting the entrypoint script is behavior-neutral. 5. **`tea` cannot infer this repo.** `origin` is `ssh://git@192.168.1.104:2222/...` while the login knows `gitea.kvmx.ru`, so every `tea` call needs `--login homesrv --repo kami/orchestra`. Also: this Gitea rejects `tea pr reply` (405) and `tea pr resolve` ("comment is not a review comment"), so review threads must be answered with a conversation comment and resolved in the browser. 6. **zsh does not word-split unquoted variables** — `$FLAGS` holding `--login homesrv --repo kami/orchestra` arrives as one argument. --- ## `REVIEW.md` is less reliable than it claims Its second pass asserts every independently checkable claim held up. Six did not. Treat it as a strong lead, not a verified record. 1. `AUDIT.md` never contained the false "Design B has zero clients" claim — `AGENTS.md` was the real second copy. 2. The non-local-herdr guardrail is at `orchestrator.go:312`, not `:309`. 3. The `progress.md` reference list missed `deploy/hooks/orchestra-codex-poll.sh:6`. 4. Finding 5's "untrack both" was half-actionable; `orchestra` was already gitignored. 5. Finding 4's blast radius was overstated — `Dockerfile.api` builds `./cmd/orchestra` by explicit path and `.dockerignore` already excluded `node_modules`, so it was a local/CI break, never a production-image break. 6. It claims that pass "corrected a comment that still described the retired `/v1/harness/complete` as handling completion." It had not; `main.go:556-561` still did, and was fixed in `97a9c65`. It also missed `TOKEN_MINIMAL_WORKFLOW_PLAN.md` and `WEB_UI_PLAN.md` entirely. --- ## Next steps, in order ### 1. Rebuild the deployed image — nothing above is live yet ```sh cd /home/kami/docker-apps/orchestra-web-ui revision=$(git -C /home/kami/apps/orchestra rev-parse HEAD) build_time=$(date -u +%Y-%m-%dT%H:%M:%SZ) docker compose -f compose.yaml -f compose.live.yaml build \ --build-arg BUILD_REVISION="$revision" \ --build-arg BUILD_TIME="$build_time" \ --build-arg BUILD_DIRTY=false orchestra-api docker compose -f compose.yaml -f compose.live.yaml up -d --build docker logs orchestra-api | tail -30 ``` **Watch this one.** It is the first container boot without `docker-api-entrypoint.sh`. Expected: the process starts, reads config from the bind-mounted `config.jsonc`, and picks up secrets from `.env`. Confirm provenance afterwards at `GET /v1/admin/diagnostics` — its `build` object should match `97a9c65`, not an older revision. ### 2. Vikunja 350 — the single controlled live OpenCode continuity run Still the project's real blocker: every "Closed" row in `AUDIT.md` rests on unit tests. Prerequisites: - Probe herdr reachability **directly**. `main.go` logs connection *failures* only and never logs success, so absence of a log line means up, not down. - Check whether the stuck task is still stuck: workspace `wA`, id `06FT6CKD9Y98AZRX6X8K3QXFZG`, opencode, pane `wA:p1`, `agent_status: "blocked"`. Code fixes do not unstick an orphaned pane; it needs a manual kill/restart, and `CLAUDE.md` requires asking before destructive herdr calls. ### 3. Vikunja 353 — constant-time compares in `internal/federation` `federation.go:368` (per-worker bearer token, checked on every authenticated worker call — hottest path), `:343` (admission shared secret). `:346` is a re-registration equality check, arguably not an auth decision. Use the inline `subtle.ConstantTimeCompare` idiom from `internal/authz/authz.go:111,241`, and preserve the empty-token-means-disabled semantics. Note `internal/provider/provider.go:333` is already correct (`hmac.Equal`). ### 4. Reconcile `TOKEN_MINIMAL_WORKFLOW_PLAN.md` against `AUDIT.md` 534 lines, dated 2026-07-29, status "proposed" — describes the target unattended workflow (Vikunja ingest → router → worker syncs checkout → immutable `TASK.md` → deterministic gates → push → Vikunja reflection) with an explicit model-token boundary. Never audited. `WEB_UI_PLAN.md` is in the same position. Decide for each: current plan, or obsolete. ### 5. Vikunja 351 — extract `main.go`'s route closures (deferred) `97a9c65` removed ~80 lines, so this is marginally less pressing. Do it incrementally, next time a route is added. --- ## Dead code left deliberately in place `herdr.ClaudeStopHookUsage` (`internal/herdr/occupancy.go:106`) and `herdr.OpenCodeStatus` (`:263`) have no non-test callers now that the hook scripts are gone. Kept as quota-source plumbing a future harness path may want. If nothing claims them, they are a clean deletion. ## Still-open assumption `REVIEW.md` assumed `clients/herdr-bridge.go` was deployed; the operator confirmed on 2026-07-31 that it is not, now that workers carry cross-machine work. The deletion in `97a9c65` rests on that confirmation, not on a probe — all six herdrs were unreachable as of 2026-07-29 and no probe was run this session. If a bridge process turns up running on homesrv, it is running from an installed binary with no source in the repo; recover it from `56f5aac`, which tracked the files before `97a9c65` removed them.