|
| 1 | +# v0.2.0 pre-release testing checklist |
| 2 | + |
| 3 | +Ten hands-on checks covering every Phase 10 capability. Run them |
| 4 | +locally before bumping the version and cutting the release. Each |
| 5 | +step lists the command, the expected observable, and the pass/fail |
| 6 | +line. Stop at the first failure — do not publish. |
| 7 | + |
| 8 | +Scope note: codex peer-id routing (P10.9) is **deferred to v0.3** — |
| 9 | +skip any test involving `a2a-bridge codex --id <id>`. `codex` |
| 10 | +itself still works in single-instance mode (`codex:default`). |
| 11 | + |
| 12 | +## 0. Build and install from source |
| 13 | + |
| 14 | +```bash |
| 15 | +cd /home/ubuntu/robtg/a2a-bridge |
| 16 | +git checkout dev && git pull origin dev |
| 17 | +bun install |
| 18 | +bun run check:ci |
| 19 | +``` |
| 20 | + |
| 21 | +Expected: all four check:ci stages green (tsc, depcruise, tests, |
| 22 | +smoke tarball + smoke-e2e). `455 pass 0 fail`. |
| 23 | + |
| 24 | +Then install the freshly-packed tarball into a scratch directory |
| 25 | +so the global npm install of `a2a-bridge@0.1.x` stays untouched |
| 26 | +while you test: |
| 27 | + |
| 28 | +```bash |
| 29 | +npm pack |
| 30 | +mkdir -p /tmp/a2a-v020-test && cd /tmp/a2a-v020-test |
| 31 | +npm init -y >/dev/null |
| 32 | +npm install /home/ubuntu/robtg/a2a-bridge/a2a-bridge-*.tgz |
| 33 | +./node_modules/.bin/a2a-bridge --version |
| 34 | +``` |
| 35 | + |
| 36 | +Expected: `a2a-bridge v0.1.1` (the CHANGELOG is drafted as 0.2.0 |
| 37 | +but the bump hasn't landed yet — that's step after this checklist). |
| 38 | + |
| 39 | +Keep two terminals open. `TEST_DIR=/tmp/a2a-v020-test` below. |
| 40 | + |
| 41 | +## 1. Backward compat: v0.1 single-CC flow still works |
| 42 | + |
| 43 | +```bash |
| 44 | +# Terminal A — fresh daemon |
| 45 | +A2A_BRIDGE_STATE_DIR=/tmp/a2a-v020-test/state-single \ |
| 46 | + $TEST_DIR/node_modules/.bin/a2a-bridge daemon start |
| 47 | + |
| 48 | +$TEST_DIR/node_modules/.bin/a2a-bridge daemon status |
| 49 | +``` |
| 50 | + |
| 51 | +Expected: `daemon status` prints pid, control port 4512, A2A port |
| 52 | +4520. No errors about multi-target. Leave it running. |
| 53 | + |
| 54 | +```bash |
| 55 | +# Terminal B — attach a single CC without any target env vars |
| 56 | +$TEST_DIR/node_modules/.bin/a2a-bridge claude --help | head -5 |
| 57 | +``` |
| 58 | + |
| 59 | +(You don't need a real Claude Code session for this checklist — |
| 60 | +we're validating the wiring, not human-in-the-loop UX. The stub |
| 61 | +CC pattern via `DaemonClient` already covers the CC side in the |
| 62 | +test suite.) |
| 63 | + |
| 64 | +Pass: daemon is live, no startup errors, `daemon status` shows a |
| 65 | +single pid, `daemon logs` shows no `force` / `target` rejections. |
| 66 | + |
| 67 | +## 2. `daemon targets` subcommand (P10.5) |
| 68 | + |
| 69 | +```bash |
| 70 | +$TEST_DIR/node_modules/.bin/a2a-bridge daemon targets |
| 71 | +``` |
| 72 | + |
| 73 | +With no CC attached yet, expected output is |
| 74 | +`no targets registered`. |
| 75 | + |
| 76 | +In a second shell, simulate an attach by running the existing |
| 77 | +conflict-test subprocess (it attaches a stub CC as `claude:ws-a`): |
| 78 | + |
| 79 | +```bash |
| 80 | +cd /home/ubuntu/robtg/a2a-bridge |
| 81 | +bun test src/cli/claude-conflict.test.ts 2>&1 | tail -10 |
| 82 | +``` |
| 83 | + |
| 84 | +Expected: `2 pass 0 fail`. |
| 85 | + |
| 86 | +## 3. Multi-workspace attach + conflict reject (P10.2, P10.3, P10.6) |
| 87 | + |
| 88 | +```bash |
| 89 | +cd /home/ubuntu/robtg/a2a-bridge |
| 90 | +bun test src/runtime-plugin/daemon-client/daemon-client.test.ts |
| 91 | +bun test src/cli/claude-conflict.test.ts |
| 92 | +``` |
| 93 | + |
| 94 | +Expected: |
| 95 | +- `daemon-client.test.ts` — new tests prove `attachClaude(t, true)` |
| 96 | + serializes `force: true`; `connectRejected` / `connectReplaced` |
| 97 | + events fire on incoming frames. |
| 98 | +- `claude-conflict.test.ts` — `2 pass 0 fail`: |
| 99 | + - second attach without `force` receives `connectRejected` |
| 100 | + - second attach with `force: true` evicts the first, which sees |
| 101 | + `connectReplaced` and a socket close. |
| 102 | + |
| 103 | +## 4. `a2a-bridge claude --force` CLI flag (P10.6) |
| 104 | + |
| 105 | +```bash |
| 106 | +cd /home/ubuntu/robtg/a2a-bridge |
| 107 | +bun test src/cli/claude-flags.test.ts |
| 108 | +``` |
| 109 | + |
| 110 | +Expected: `4 pass 0 fail`. The parser strips `--force`, preserves |
| 111 | +argv order, rejects partial matches like `--forceful`. |
| 112 | + |
| 113 | +Manual sanity: |
| 114 | + |
| 115 | +```bash |
| 116 | +$TEST_DIR/node_modules/.bin/a2a-bridge claude --force 2>&1 | head -3 |
| 117 | +``` |
| 118 | + |
| 119 | +Should NOT fail with "unrecognized option". The CLI strips the |
| 120 | +flag and forwards the remaining argv to the native `claude` |
| 121 | +binary; if you don't have Claude Code installed, the error you |
| 122 | +get is about missing `claude`, not about `--force`. |
| 123 | + |
| 124 | +## 5. ACP `--target` flag (P10.4) |
| 125 | + |
| 126 | +```bash |
| 127 | +cd /home/ubuntu/robtg/a2a-bridge |
| 128 | +bun test src/cli/acp-cli.test.ts src/runtime-daemon/inbound/acp/turn-handler.test.ts |
| 129 | +``` |
| 130 | + |
| 131 | +Expected: |
| 132 | +- `acp-cli.test.ts` — `--target`, `-t`, and `--target=` all parse; |
| 133 | + invalid target exits 1 with a descriptive error. |
| 134 | +- `turn-handler.test.ts` — `19 pass`: unattached target → |
| 135 | + `acp_turn_error`; attached target → turn forwards. |
| 136 | + |
| 137 | +## 6. A2A `contextId → TargetId` routing (P10.7) |
| 138 | + |
| 139 | +```bash |
| 140 | +cd /home/ubuntu/robtg/a2a-bridge |
| 141 | +bun test src/runtime-daemon/inbound/a2a-http/server.test.ts |
| 142 | +``` |
| 143 | + |
| 144 | +Expected: the three P10.7 cases pass — mapped contextId routes to |
| 145 | +its TargetId, unmapped falls back to `claude:default`, malformed |
| 146 | +TargetId in the config is a startup error. |
| 147 | + |
| 148 | +Operator sanity: with a daemon running, set the env var and |
| 149 | +verify via `daemon logs`: |
| 150 | + |
| 151 | +```bash |
| 152 | +A2A_BRIDGE_CONTEXT_ROUTES='{"ctx-smoke":"claude:default"}' \ |
| 153 | + $TEST_DIR/node_modules/.bin/a2a-bridge daemon start |
| 154 | +``` |
| 155 | + |
| 156 | +The daemon should start without logging an `ignored` line — if |
| 157 | +you see `A2A_BRIDGE_CONTEXT_ROUTES ignored`, the JSON was |
| 158 | +malformed. |
| 159 | + |
| 160 | +## 7. Outbound `reply` tool target (P10.8) |
| 161 | + |
| 162 | +```bash |
| 163 | +cd /home/ubuntu/robtg/a2a-bridge |
| 164 | +bun test src/cli/reply-target.test.ts |
| 165 | +``` |
| 166 | + |
| 167 | +Expected: `2 pass 0 fail`. |
| 168 | +- **forward**: CC-A replies with `target: claude:ws-b`; CC-B |
| 169 | + receives the text. |
| 170 | +- **unknown target**: descriptive error. |
| 171 | +- **omit target**: falls through to the legacy codex path (errors |
| 172 | + with "Codex is not ready" since the test daemon has no Codex |
| 173 | + adapter attached — proves the absent-target path is unchanged). |
| 174 | +- **malformed target**: error. |
| 175 | + |
| 176 | +## 8. Cross-target isolation — the big one (P10.10) |
| 177 | + |
| 178 | +This is the Phase 10 acceptance test. Two ACP subprocesses, two |
| 179 | +stub CCs, ensures no cross-talk. |
| 180 | + |
| 181 | +```bash |
| 182 | +cd /home/ubuntu/robtg/a2a-bridge |
| 183 | +bun test src/cli/multi-target.test.ts |
| 184 | +``` |
| 185 | + |
| 186 | +Expected: `1 pass 0 fail`. Subprocess A sees only `CC-A:` prefixed |
| 187 | +chunks; subprocess B sees only `CC-B:`; no fallback to the echo |
| 188 | +executor. |
| 189 | + |
| 190 | +## 9. Full check:ci one more time |
| 191 | + |
| 192 | +```bash |
| 193 | +cd /home/ubuntu/robtg/a2a-bridge |
| 194 | +bun run check:ci |
| 195 | +``` |
| 196 | + |
| 197 | +Expected: `455 pass 0 fail`, smoke tarball OK, smoke-e2e OK. |
| 198 | + |
| 199 | +## 10. Docs review |
| 200 | + |
| 201 | +Quick eyeball pass on the updated docs: |
| 202 | + |
| 203 | +- [`README.md`](../../README.md) — "Multi-workspace routing |
| 204 | + (v0.2)" section + env vars table has `WORKSPACE_ID`, |
| 205 | + `FORCE_ATTACH`, `CONTEXT_ROUTES`. |
| 206 | +- [`docs/design/multi-target-routing.md`](../design/multi-target-routing.md) |
| 207 | + — status line says "implemented in v0.2.0". |
| 208 | +- [`docs/guides/rooms.md`](../guides/rooms.md) — TargetId |
| 209 | + precedence table + outbound reply routing section present. |
| 210 | +- [`docs/join.md`](../join.md) — "Multi-workspace (v0.2, |
| 211 | + optional)" section at the bottom. |
| 212 | +- [`CHANGELOG.md`](../../CHANGELOG.md) — `[0.2.0]` block drafted |
| 213 | + with Added / Changed / Deferred / Wire additions. |
| 214 | + |
| 215 | +## After the checklist — version bump + publish |
| 216 | + |
| 217 | +Once every step above passes: |
| 218 | + |
| 219 | +1. Bump `package.json`, `plugins/a2a-bridge/plugin.json`, and |
| 220 | + `plugins/marketplace.json` from `0.1.1` to `0.2.0`. |
| 221 | +2. Change the CHANGELOG header from `## [0.2.0] — unreleased` |
| 222 | + to `## [0.2.0] — <today>`. |
| 223 | +3. Follow [`publish.md`](./publish.md) from step 1 (bump check) — |
| 224 | + it covers `bun scripts/check-plugin-versions.js`, commit + tag |
| 225 | + + push, GitHub Actions release workflow, npm 2FA OTP, and the |
| 226 | + post-publish smoke. |
| 227 | + |
| 228 | +Per CLAUDE.md iron law: none of the bump / publish steps run |
| 229 | +under the autonomous loop. |
| 230 | + |
| 231 | +## Rollback |
| 232 | + |
| 233 | +If publish lands but smoke fails: |
| 234 | + |
| 235 | +```bash |
| 236 | +npm unpublish a2a-bridge@0.2.0 # must be within 72h |
| 237 | +git tag -d v0.2.0 |
| 238 | +git push origin :refs/tags/v0.2.0 |
| 239 | +``` |
| 240 | + |
| 241 | +(Unpublish only works in the 72-hour window — after that, cut |
| 242 | +`0.2.1` instead.) |
0 commit comments