release 2026.08.29.02 — a plugin can ship a commander

THIS ONE CHANGES THE DATABASE, and the plan says so with the command that proves
what the change is rather than the claim alone:

  command_hq_sessions
    + plugin         text   null
    + plugin_config  jsonb  null

both nullable, no default, no constraint — so every existing row is valid the
moment they exist and there is nothing to backfill. no rename, nothing dropped, no
create-then-constrain, and therefore no --force needed or permitted.

THE PLAN DEMANDS A QUERY, NOT AN EXIT CODE. drizzle-kit push can fail and still
exit 0, so step 3 is a verification that must print exactly `plugin plugin_config`
and whose OUTPUT goes in the report per host — not "schema ✓". I ran that exact
command here before asking seven hosts to run it.

NO bun install step: package.json and bun.lock are untouched since .01. that also
sidesteps the step-order bug the last rollout found, where the standard
plugins:update runs before a plan's install and imports a package that is not there
yet.

the backup step reads the env variable name rather than assuming it. several hosts
use OFFICERDEV_POSTGRES_URL and not POSTGRES_URL, which is the kind of detail that
turns a backup step into a file containing an error message.

av-club's commander template reaches each host through the standard plugins:update
step rather than through this plan — worth saying, because av-club moving is
expected here rather than a surprise.

gate before tagging: typecheck clean, docs:check green, locale parity green. the
ModelSelector test still fails and is still not mine — same chat code, untouched by
this range.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-29 03:12:45 +01:00
co-authored by Claude Opus 5
parent 347acf0171
commit 78bf63c209
2 changed files with 120 additions and 1 deletions
+119
View File
@@ -0,0 +1,119 @@
# 2026.08.29.02 — a plugin can ship a commander
**This one changes the database.** Two columns, both nullable additions, on a table that already exists.
There is no rename in it, nothing is dropped, and no existing row changes — but `db:push` is still not
to be trusted on its exit code, so there is a per-host query below and the report must carry its answer
for each host.
No dependency change: `package.json` and `bun.lock` are untouched since `2026.08.29.01`. **There is no
`bun install` step in this plan** — which also sidesteps the step-order problem the last rollout found,
where the standard `plugins:update` ran before the plan's install.
## What is in it
- **Plugins can ship commanders.** A plugin with `commanders/<name>/COMMANDER.md` offers one; it appears
in Command HQ under a new **From plugins** section, arrives **not running**, and must be configured
before it can arm.
- **av-club ships the first one** — *Convert on arrival*: watches a folder, converts what lands in it.
It reaches each host through the standard `bun run plugins:update` step, not through this plan.
- Marketplace, file browser and Convert Image work from earlier today rides along.
## Schema — CHANGED. `db:push` is required.
```
command_hq_sessions
+ plugin text null which plugin's template made this commander
+ plugin_config jsonb null the owner's answers to that template's inputs
```
Verified as the whole of it:
```bash
git diff --name-only deploy/2026.08.29.01..deploy/2026.08.29.02 | grep -iE 'schema|/db/|databases'
# → src/databases/officer_db/src/command-hq/queries.ts
# src/databases/officer_db/src/command-hq/schema.ts
```
`queries.ts` is code, not schema. The only structural change is the two columns above.
**Both are nullable with no default and no constraint**, so every existing row is valid the moment they
exist and there is nothing to backfill. This is the shape `db:push` handles cleanly — there is no
create-then-constrain here, and no `--force` is needed or permitted.
## Every host — the commands
After the standard steps in `prompts/deploy-commander.md` (dirty check, `git fetch origin --tags`,
`git merge --ff-only deploy/2026.08.29.02`, `bun run plugins:update`), in the checkout from PM2's
`pm_cwd`:
### 1. Back the database up first
```bash
pg_dump "$(grep -m1 -E '^(OFFICERDEV_)?POSTGRES_URL=' .env | cut -d= -f2-)" > ~/db-backups/officer-$(date +%Y%m%d-%H%M).sql
```
Read the variable name rather than assuming it: **several hosts use `OFFICERDEV_POSTGRES_URL`**, not
`POSTGRES_URL`. `mkdir -p ~/db-backups` first if it is not there.
### 2. Push the schema
```bash
bun db:push < /dev/null
```
**stdin closed**, so it can never sit waiting on a prompt in an unattended run — it fails instead, which
is the outcome you want. Expect `[✓] Changes applied` and then the two post-push scripts.
### 3. VERIFY BY QUERY. The exit code is not the answer.
```bash
bun -e "
const { db } = await import('officerdb/db'); const { sql } = await import('drizzle-orm');
const r = await db.execute(sql\`select column_name from information_schema.columns
where table_name='command_hq_sessions' and column_name in ('plugin','plugin_config') order by column_name\`);
console.log([...((r as any).rows ?? r)].map((x:any)=>x.column_name).join(' '));
process.exit(0)"
```
Must print exactly:
```
plugin plugin_config
```
**Put that line in the report, per host.** Not "schema ✓" — the output. A host printing one column, or
none, is a **failed host**: report it, move on, and do not attempt a repair you invented.
### 4. Restart
```bash
pm2 restart officer
```
`officer` only. `plugins:update` has already restarted the plugin sidecars itself.
### 5. Check it came back
`pm2 jlist`: `officer` online and `restart_time` moved, then `/api/health` on the host's own port
(9010 on `macbookpro` and `production-pertento-bridge`, 9000 elsewhere). `200` or `401` are both healthy.
## Per host
| Host | Note |
| --- | --- |
| `officer-dev` | **SKIP ENTIRELY.** The rollout runs here. Its schema is already pushed; nothing else is needed. Name it as skipped. |
| `alpha` | Nothing special. |
| `fofos` | The one that matters this time — `av-club` is installed there and the commander template is the point of the release. |
| `macbookpro` | macOS, port **9010**, a laptop. Unreachable is a SKIP with a note. |
| `macbruno` | macOS, login `brunoalcadapadezmonteirodaconceicao`. |
| `production-pertento-bridge` | Port **9010**. |
| `edge-pertento-bridge` | Nothing special. |
| `deadpool-rezio-bridge` | Login **`br`**, checkout `/home/br/officerdev/platform`. |
## What "done" looks like
Per host: HEAD before and after, whether the backup was written, `db:push` result, **the exact output of
the verification query**, and `officer` back online with a moved `restart_time`.
The line that matters in the summary: **which hosts print `plugin plugin_config`**. That is the only
thing this release actually changes about a machine.