Files
orchestra/HANDOFF-2026-07-31.md
T
kami 7f12c7fc37 v3 workflow: intent, phases, review, submission, enforcement, burn-in
The v3 stack, previously an uncommitted working tree, plus this session's two
units and the burn-in instrument. This commit is the burn-in build identity:
coordinator and worker must both report this revision before a task is created.

Workflow (earlier sessions, uncommitted until now): human decision events and
reduction, source cursors and reconcile-before-launch, turn-boundary
reconciliation, internal/agentctx as the single renderer, ace-fca phases with
sealed artifacts, the trajectory gate, bounded grilling, independent review,
task pr enforcement, and human review reflection.

Capability restrictions at the agent boundary: an authz.Agent surface at
GatedWrite may ask and may not act. It also fixes two bugs the unit exposed --
gated surfaces could not reach the two endpoints written for them, and
RequestHumanDecision would block an unowned task while rejecting a question
from the session that did own it.

Turn-boundary reconcile-failure escalation: a streak of consecutive failures
asks the session to hand off, fenced on the lease epoch, with reconcile_failure
as a real handoff reason. The worker was dropping the coordinator's verdict on
the floor; it now acts on it.

Burn-in: herdr.WriteLaunchContext dumps the exact agentctx.Build result to
<worktree>/.orchestra/launch.md at every launch, local and federated. BURNIN.md
is the runbook. deploy/build.sh stamps both binaries from one commit.

go build, go vet and go test ./... pass, 20 packages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 18:31:20 +04:00

8.1 KiB

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

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.