# Botmaster + dispatch — open work

audience: AI coding agents first. Owner ruling 2026-08-16: **Claude writes specs and
orchestrates; codex (`gpt-5.6-terra/medium`) writes all code.**

## Status of the delivery channel

- Codex dispatch was dead: the sandbox mangled the credential setup, so codex started
  with no account and exited 10 without writing anything. Fixed and landed
  (`a252b5861`), deployed.
- Inbound steering died again at 02:58 because `packaging/install-botmaster-proxy.sh`
  truncates `~/.config/overdeck/botmaster-proxy.env` on every deploy, wiping the
  hand-set `OVERDECK_BOTMASTER_OWNER_USER_ID`. Preservation landed (`1d63349dc`) but
  **is not deployed yet** — deploy was interrupted. Until it deploys, every deploy
  turns owner steering off silently.

## Closed 2026-08-16

- **Codex dispatch, two defects.** `-m <model>/<effort>` is rejected by the API; the
  accepted form is `-m gpt-5.6-terra -c model_reasoning_effort=medium`. Separately, the
  offload pushed its result ref without `--force`, so a stale scratch ref rejected the
  push and stranded every run's work on the node (`6e6bbe1b1`).
- **Idle wake (was item 1).** The tmux pane parser put the whole record into the pane-id
  field, so `%355` never matched itself (`0094822e7`).
- **Sessions announced as "user" (was item 2).** `basename(cwd)` on `/home/user` produced
  "user". The invented fallbacks are gone; an unresolvable session now says so.
- **Wake/deliver split brain (found while proving the above).** The waker polled the DB
  while the hook delivered from a marker file on disk, so a row with no marker was both
  permanently undeliverable and permanently wake-triggering — one such row poked this
  session ~57 times with nothing behind it. The DB is now authoritative, the marker is
  rebuilt from it, the give-up path sets `escalated_at` as a terminal state, and wakes are
  bounded (`af36237b4`). Proven live: a DB row with an empty marker directory delivered on
  the first attempt.

## Open items

### 1. Idle wake — CLOSED, see above
`[waker] <sid>: pane %355 is gone`, yet `tmux -S ~/.local/state/human-session/tmux.sock
list-panes -a` from an identical environment (same PATH, under `systemd-run --user`)
lists `%355 bwrap 2681946`, matching the `session_pane` row exactly. A dry run of the
whole waker chain against live state resolves the pane and reaches the poke.
Only the long-running `botmaster-proxy.service` disagrees.
Diagnostic landed in `1d63349dc` makes the log name every pane tmux returned — read it
first, then fix the real cause. Seam: `modules/botmaster/notify/waker.ts`,
`listPanes`/`paneRunsClaude` wiring in `packaging/botmaster-proxy.ts`.

### 2. Sessions announce themselves as "user" — CLOSED, see above
Owner sees `"user" sent you a message`. The session name shown in an outbound message
must be the real session label (e.g. `ci-cd-incremental-2`), never a placeholder.
Seam: `modules/botmaster/notify/identity.ts` + `format.ts`.

### 3. Ack ordering — still unproven
`Message #<id> received` now fires from the proxy on arrival (`9d43881c8`, deployed).
Verify it actually reaches Telegram once item 1's deploy lands — it has never been
observed working, because steering was off from 02:58.

### 4. `botmaster --attachment` — SHIPPED (43836e627 line); live-proven: document delivered, tg_message_id recorded
Send the owner files over Telegram. Claude writes this spec to
`docs/specs/2026-08-16-botmaster-attachments-design.md`; codex implements.
Must pin: flag contract vs `--text/--reply/--fyi/--needs-answer`; size and type limits;
`sendDocument` through the existing proxy/D1 seam; `store.ts` schema delta; hard refusal
for a missing, unreadable, credential or secret path; tests.

### 5. Per-request group announcement — SHIPPED (43836e627); live proof NOT run (a junk request would pollute the board); announced_at NULL rows are the honest signal
Every new request, at the moment it registers in the db, is announced to its project's
Telegram group via `botmaster --group <group> --text <request title>`, so each request
gets its own steering thread. Claude writes
`docs/specs/2026-08-16-botmaster-request-announce-design.md`; codex implements.

### 7. Idle delivery died again at 6h — CLOSED (9ad81152f, deployed 11:21)
The main claim was only stamped at SessionStart and went stale at 6h; a 9.6h-old live
session bounced owner messages with "nothing is listening". The claiming session now
refreshes claimed_at on every hook event, and the bounce names who went quiet and when.

### 8. Inbound attachments (owner → session) — SPEC WRITTEN, half-dispatched
Spec: `docs/specs/2026-08-16-botmaster-inbound-attachments-design.md`. Half A (bot-template
worker mirrors file metadata into D1) BLOCKED on the codex dispatch outage below and on
active foreign WIP in ~/Projects/Botmaster. Half B (proxy downloads via getFile) not
started — depends on Half A's schema.

### 9. cdx dispatch outage #3 — fix landed 912085fd4, awaiting image provision
Commit 884ab8dc8 (egress fail-closed, another lane) added a setpriv --reuid=agent that can
never work under --userns=keep-id; every cdx exec died at exit 127. Claimed as
fire-85e6ea5f82c3d0d0. Fix: egress init keeps nft + full cap-shed, drops the impossible
uid switch; sandbox-run drops the ineffective --user root. Also fixed: sandbox ids now
fold to the alphabet sandbox-run accepts (capital-letter repos like Botmaster killed
dispatch, bc0f40184).

### 6. Carried-in, not started
- Deploy notification naming what landed and its ticket (partially live — deploy
  messages already name the commit and subject; ticket binding is missing).
- botmaster slice 2 (ticket binding) re-scope; slice 6 (auto-naming) deferred.
- Remaining S2 slices and S3–S6 of `docs/plans/2026-08-12-ci-cd-incremental-delivery.md`.

## Known-unverified

- The waker has never successfully poked a real pane end to end.
- Intermittent `web-release` smoke flake under deploy load; rollback works.
- Workspace number is null under tmux (needs X11/xdotool).
