Smoke test plan: what's testable on main today #149
Replies: 3 comments
|
Walked lanes 1, 4, 11 on an isolated daemon — port What workedLane 1 — Daemon control
Lane 4 — Orchestrator sessions (partial — see "broke" below)
Lane 11 — HTTP API surface
What brokeLane 4.1 — SQLite migration is at version 7 (so not the §3.3 stale-migration footgun), and the Lane 11 — Same opaque-500 pattern (no log detail). For comparison, Lane 1.3 — What was unclear
|
|
Walked lanes 2, 3, 5, 7, 9, 10 on an isolated daemon — port What worked
What broke / discrepancies
What was unclear
|
|
Walked lanes 6 (SCM observer) and 8 (PR claim) on an isolated daemon — port What workedLane 6 — SCM observer
Lane 8 — PR claim
What broke1. §8.2 rollback is incomplete.
2. §6.6 — 3. §6.3 — missing log line. Spec says: with no token, expect 4. 5. Spawn returns opaque
Daemon log shows only the request line + 500 status; no error message. Caller can't tell whether it's a worktree collision, a missing ref, or something else — yet another instance of the "Known issues / What was unclear
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This is a manual smoke-test runbook for what is actually shipped on
maintoday — the lanes the rewrite already exposes end-to-end (daemon, projects, sessions, spawn, SCM observer, agent activity hooks, PR claim, reaper, CDC, HTTP API). It is intended as a 1–3 hour walk-through before more wiring lands, so we can catch lane-level regressions while the surface is still small enough to cover by hand.Anyone is welcome to walk a section, report findings as a reply (what worked, what broke, what was unclear), or call out a capability that should have been listed but isn't.
AO smoke-test checklist — what's testable on
maintodayA manual runbook for validating the AO rewrite end-to-end. Walk the lanes in order — earlier lanes set up state used later. Target wall-clock: 1–3 hours.
CLI shape was captured against the current
main(commitb13f413); flag names are copy-pasteable.0. One-time prerequisites
go≥ 1.22,git≥ 2.25.0 (worktree-capable),zellij≥ the version pinned inbackend/internal/adapters/runtime/zellij,gh≥ 2.0.gh auth logincomplete, ORAO_GITHUB_TOKEN/GITHUB_TOKENexported (needed for SCM observer + claim-pr lanes).originremote points at github.com.claude,codex, oropencode.Build the binary once
Isolated data dir (mirrors the issue-#89 recipe)
Keep this env exported in every shell you use. Use the same
/tmp/ao_smokebinary throughout so the daemon and CLI agree on the schema.1. Daemon control
1.1
ao start{state: "ready", port: 4101, pid: <int>}.cat /tmp/ao-smoke-running.jsonshows the same PID;curl -fsS http://127.0.0.1:4101/healthzreturns{"status":"ok"...};curl -fsS http://127.0.0.1:4101/readyzreturns{"status":"ready"...}.1.2
ao statusstate: "ready", port matches, no error string.running.json.1.3
ao doctorrunDoctor()(backend/internal/cli/doctor.go):config,data-dir,data-dir-write,sqlite,daemon— all PASS.gitPASS (≥ 2.25.0),zellijPASS.claude-codeandcodex— PASS if installed, WARN if not.github-tokenPASS ifgh auth loginorAO_GITHUB_TOKENresolves to a valid token; WARN if neither present.PATH=/usr/bin:/bin /tmp/ao_smoke doctor(stripgit/zellij) → expect FAIL on git, WARN on zellij.AO_GITHUB_TOKEN= GITHUB_TOKEN= PATH=/usr/bin:/bin /tmp/ao_smoke doctor→ expect WARN on github-token with a "no GitHub token found" message.chmod -w "$AO_DATA_DIR"(then revert) → expect FAIL ondata-dir-write.1.4
ao version/tmp/ao_smoke --versionworks.1.5
ao stop/tmp/ao-smoke-running.jsonis absent or marked stopped.kill -0 <pid>returns 1;ao statusreportsnot_running.Restart with
/tmp/ao_smoke start --json --log-file /tmp/ao-smoke.logbefore continuing.2. Project management
2.1
ao project addPre-stage two git repos on disk: a clean clone of your test GH repo (
/tmp/ao-smoke-repo) and a throwaway local-only repo (/tmp/ao-smoke-local,git initthen commit a file).repo(mapped from the internalRepoOriginURLcolumn byprojectFromRow):https://github.com/<owner>/<repo>.gitURL. For the local-only repo it will be"".2.2
ao project ls2.3
ao project get--jsonyou get the full record includingrepoOriginURL.2.4
ao project rmDefer until teardown — sessions in later lanes need these projects.
3. Spawn / session lifecycle
3.1
ao spawn(worker)ws-01. A new worktree at~/.agent-orchestrator/projects/<project>/worktrees/<session-id>/exists and is on branchao/smoke-1.ls $AO_DATA_DIR/ao.dbexists./tmp/ao_smoke session ls --jsonshows the session withkind: "worker"andstate: "active"(or whichever the lifecycle reduces to once the runtime is up).ZELLIJ_SOCKET_DIR=/tmp/ao-zellij-$(id -u) zellij list-sessions— the AO session should be listed.3.2
--agent/--harnessselectionTop-level help shows
--harnessis also documented as--agent. Spawn one of each:session getJSON'sharnessfield).AO_AGENT=opencode /tmp/ao_smoke spawn --project <gh-project-id> --prompt "noop" --branch ao/smoke-env. The daemon's default agent comes fromAO_AGENT(config.go); confirm the spawned session reportsharness=opencode.3.3 Agent registry coverage
Confirm the registry exposes the eight adapters added by #119 and #145 (claude-code, codex, opencode, grok, cursor, qwen, copilot, kimi). The four newest don't ship hook installers; spawning is enough to confirm the registry accepts them.
Binary-freshness precondition. Migration
0007_allow_implemented_harnesses.sqlwidens thesessions.harnessCHECK constraint to include the new harnesses. If/tmp/ao_smokewas built before #119 landed, migration 0007 isn't embedded and all five spawns below fail withINTERNAL_ERRORin <1ms (the daemon log shows only the request line — see "Known issues"). Verify before running the loop:If it's
6, rebuild and restart:3.4
ao session ls--include-terminatedadds any sessions you killed.3.5
ao session getactivity/ state fields — used in lane §8.-p <project>is supported but optional.3.6
ao session renamesession get --jsonshows updateddisplayName. HTTP path isPATCH /api/v1/sessions/{id}.3.7
ao session killsession lsno longer shows it without--include-terminated; zellij session has been destroyed; the worktree directory is preserved (cleanup is a separate step).3.8
ao session restoresession getshows it active again.3.9
ao session cleanupgit -C ~/.agent-orchestrator/projects/<project> worktree listthat pruned ones are gone.4. Orchestrator sessions
4.1 Spawn via API (no CLI shortcut for spawn)
{orchestrator:{id, projectId}}.4.2
ao orchestrator lsGET /api/v1/orchestratorsreturns the same set;GET /api/v1/orchestrators/{id}returns one; querying with a non-orchestrator id returns 404 (SESSION_NOT_FOUND).5. Inter-session messaging (
ao send)5.1 Plain send
zellij attach <session>) shows the message piped to the harness.5.2 PR #85 sender-prefix behavior
The CLI prepends
[from <sender>]whenAO_SESSION_IDis set (seebackend/internal/cli/send.go:46):[from aa-orchestrator] ping. Confirm in the pane.5.3 Validation
--message→ 400 withMESSAGE_REQUIRED.MESSAGE_TOO_LONG.stripUnsafeControlChars).6. SCM observer (issues #76 + #108 + #114 + #115)
6.1 Pre-conditions
repoOriginURLis non-empty inproject get --json.AO_GITHUB_TOKEN,GITHUB_TOKEN, orgh auth token.--branch <pr-head-branch>, or--claim-pr <pr-url>to immediately attach (lane §9).6.2 Discovery + initial nudge
Wait ≥ 30s (default tick =
DefaultTickIntervalinbackend/internal/observe/scm/observer.go:25).zellij attach): a CI-failing observation should send a single CI-failure message to the agent.6.3 No-token graceful no-op
Stop the daemon, unset every token, restart:
scm observer disabled: provider credentials unavailableand observer loop becomes a no-op (o.disabled = true). No nudges fire. Restore the token /ghconfig when done.6.4 Dedup across restart
With a live token and a still-red PR:
/tmp/ao_smoke stop→/tmp/ao_smoke start.CIHash/MetadataHash/ReviewHash).6.5 RepoOriginURL backfill
For the local-only project you registered without origin (lane §2),
repoOriginURLis empty. Add anoriginremote pointing at your GH repo, then spawn a worker on it. The observer'sdiscoverSubjectsrunsgit remote get-url originand backfills + persists the URL (observer.go:451-459).project get <local-project-id> --json | jq .project.reponow matches the configured remote.6.6 Review-thread polling
Pick a PR with at least one unresolved review thread.
DefaultReviewInterval), threads appear viaGET /api/v1/sessions/<id>/pr(reviewComments).resolved. Confirm via the CDC log (§10) — apr_review_thread_resolvedevent lands.7. Agent activity hooks (issue #113, #119)
7.1 Hook config installed in workspace
Spawn a fresh
claude-codeworker, then in the worktree:backend/internal/adapters/agent/claudecode/hooks.go. Entries point atao hooks claudecode <event>.Spawn a
codexworker; expect<worktree>/.codex/hooks.jsonwith similar entries (backend/internal/adapters/agent/codex/hooks.go). Forcursor, expect<worktree>/.cursor/hooks.json.opencodeandgrokhave no native hook config — note "no-op" in your run log.7.2 Activity transitions land in the daemon
From inside an active session, trigger the hook manually (the harness will do this naturally too):
/api/v1/sessions/{id}/activitywith one ofactive|idle|waiting_input|exited.sqlite3 $AO_DATA_DIR/ao.db 'select type,payload from change_log order by seq desc limit 5;'shows a recentsession_updatedevent reflecting the activity column.8. PR claim (#101)
8.1
ao session claim-prSpawn a worker; in parallel, you have an open PR on the test repo.
branchChangedandtakenOverFrom. The worktree's branch may flip to the PR's head branch (branchChanged: true).session get --jsonshows the PR attached;git -C <worktree> rev-parse --abbrev-ref HEADmatches PR head branch.8.2
ao spawn --claim-pr(single-step)session ls --include-terminateddoes not show a leftover. The orchestrator-spawn path rolls back the half-spawned session.8.3
--no-takeoverWith a PR already claimed by an active session, run claim from a different session without
--no-takeoverand expect takeover; rerun with--no-takeoverand expect aPR_CLAIMED_BY_ACTIVE_SESSION409 (seewriteSessionPRError).9. Reaper
9.1 External kill
Spawn a session. From a separate shell:
session ls --include-terminatedshows the session terminated with a reaper-attributed reason;session get --jsonshows the runtime gone. The reaper transitions the row without racing the activity hook (lane §7's single lifecycle.Manager guarantee — seesessions.go:260-263).10. CDC events
10.1
change_logtable directlybackend/internal/cdc/event.go):session_created,session_updatedpr_created,pr_updated,pr_check_recorded,pr_session_changedpr_review_thread_added,pr_review_thread_resolved10.2 SSE replay stream
text/event-streamresponse with the same events, in order, then live updates as you trigger more actions. TheLast-Event-ID/?after=cursor is honored (issue feat(cdc): add SSE event stream replay #106).11. HTTP API surface
Verify each route accepts the documented verbs. Source of truth:
backend/internal/httpd/controllers/{projects,sessions,prs}.goandbackend/internal/httpd/{api,router,events}.go. OpenAPI:GET /api/v1/openapi.yaml./healthz/readyz/shutdown/api/v1/openapi.yaml/api/v1/projects/api/v1/projects/{id}/api/v1/sessionsprojectIdrequired)/api/v1/sessions/cleanup?project=filter/api/v1/sessions/{id}displayNamerequired)/api/v1/sessions/{id}/pr/api/v1/sessions/{id}/pr/claim{pr, allowTakeover})/api/v1/sessions/{id}/restore/api/v1/sessions/{id}/kill/api/v1/sessions/{id}/send/api/v1/sessions/{id}/activitystate∈ active/idle/waiting_input/exited)/api/v1/orchestrators/api/v1/orchestrators/{id}/api/v1/prs/{id}/merge/api/v1/prs/{id}/resolve-comments{commentIds}optional)/api/v1/events?after=<seq>orLast-Event-ID)/muxSmoke them with
curlfor OPTIONS/wrong verb on a couple to confirm the locked envelope: e.g.curl -X PUT http://127.0.0.1:4101/api/v1/projects/abc→ 405METHOD_NOT_ALLOWED; unknown route → 404ROUTE_NOT_FOUND, both JSON.Teardown
Known issues that will distort tests
/tmp/ao-zellij-<uid>(zellij.DefaultSocketDir). If you overrideZELLIJ_SOCKET_DIRto anything deep (e.g. inside$TMPDIR), spawns fail with "session name must be less than 0 characters." Symptom:Create runtimeerrors at spawn time on macOS.checkCredentialsflips the observer todisabledfor the lifetime of the process. Subsequent token availability is not re-detected — restart the daemon after fixing the token, otherwise observer-dependent lanes (§6, §10's pr_* events) will silently produce nothing.INTERNAL_ERRORwith no daemon-log reason —envelope.WriteErrorreturnsINTERNAL_ERRORfor any non-apierr.Errorand does not log the wrapped err. If a spawn/kill/etc. returns 500 in <1ms and the log only shows the HTTP request line, suspect a SQLite CHECK-constraint violation (e.g. stale migration onsessions.harness— see §3.3 binary-freshness check) or another low-level store error. Diagnose viasqlite3 "$AO_DATA_DIR/ao.db" 'SELECT max(version_id) FROM goose_db_version;'and comparing tobackend/internal/storage/sqlite/migrations/.ao hooksexits silently ifAO_SESSION_IDis unset — only run from within an agent process (or set it manually as shown in §7.2).ao session cleanupis a no-op on a worktree with uncommitted changes. Either commit/discard inside the worktree orrm -rfit manually.Not yet testable (designed but not on
main)frontend/is a placeholder; no UI to walk through.notifier-openclaw/slack/webhooklog lines at daemon startup are no-ops until reconfigured.ao plugin,ao events,ao update,ao migrate-storageare intentionally absent onmain; don't test them.How to participate
Pick a lane (§1 through §11). Walk the steps top to bottom. Reply on this thread with:
ao status --json/ao doctor --jsonoutput.Mention which OS, zellij version, and
ao versionyou ran against.Related
rewriteAll reactions