Files
platform/deploy/2026.08.23.05.report.md
2026-08-23 18:48:57 +00:00

11 KiB

2026.08.23.05 — deploy report

5 of 5 target hosts succeeded. Two hosts skipped by design: officer-dev (the host running the rollout) and edge-pertento-bridge (in the Deliberately skipped section of docs/servers.md).

Every target ended at e15ab2303a17ed0e1d1cf59b35f34aec68875907 = deploy/2026.08.23.05, merged --ff-only onto the tag itself. No host was left on the branch, and no host is a commit past the tag.

Schema evidence is per host, by query, below. --force was never used and was never needed.


Per host

alpha — succeeded

Checkout (from PM2 pm_cwd) /home/pastilhas/officerdev/platform
HEAD before ff647fba (deploy/2026.08.23.04)
HEAD after e15ab230 (deploy/2026.08.23.05)
Tracked changes before none
Untracked files none

Pre-check: roles = 4, orphan users 0, orphan grants 0.

SQL applied, exit 0. Verification query:

            conname            |                    pg_get_constraintdef
-------------------------------+-------------------------------------------------------------
 ck_role_permissions_not_owner | CHECK ((role <> 'Super Admin'::text))
 fk_role_permissions_role      | FOREIGN KEY (role) REFERENCES roles(name) ON UPDATE CASCADE
 fk_users_role                 | FOREIGN KEY (role) REFERENCES roles(name) ON UPDATE CASCADE

Both fk_ present, ON UPDATE CASCADE, no ON DELETE. ck_role_permissions_role absent. ck_role_permissions_not_owner present. Re-queried after db:push — unchanged.

bun db:push ran clean. It is not a no-op on this host — see "The one thing that is not clean" below.

bun run plugins:update: 12/12 updated in 47s, exit 0. That step restarted twelve plugin sidecars — atelier, bitcoin-wallet, email, gitea, invoices, jellyfin, music, offscale, photos, soulseek, transmission, vault.

pm2 restart officer: restart_time 70 → 71, online. All 19 officer* processes online afterwards.

fofos — succeeded

Checkout /home/pastilhas/officerdev/platform
HEAD before ff647fba (deploy/2026.08.23.04)
HEAD after e15ab230 (deploy/2026.08.23.05)
Tracked changes before none
Untracked files scripts/chk.ts — left alone, not a reason to skip

Pre-check: roles = 4, orphans 0 / 0. SQL applied, exit 0. Verification query returned the same three rows as alpha: both fk_ present with ON UPDATE CASCADE, ck_role_permissions_role absent, ck_role_permissions_not_owner present.

bun db:push clean; a second push --verbose said No changes detected — a genuine no-op.

bun run plugins:update: 1/1 updated in 7s, exit 0. Restarted officer-gitea.

pm2 restart officer: 24 → 25, online. All 8 processes online.

production-pertento-bridge — succeeded

Checkout /home/pastilhas/officerdev/platform
HEAD before ff647fba (deploy/2026.08.23.04)
HEAD after e15ab230 (deploy/2026.08.23.05)
Tracked changes before none
Untracked files none

Pre-check: roles = 4, orphans 0 / 0. SQL applied, exit 0. Verification query: same three rows, same verdict.

bun db:push clean; second push --verbose → No changes detected.

bun run plugins:update: 1/1 updated in 5s, exit 0. Restarted officer-gitea.

pm2 restart officer: 3 → 4, online. All 15 processes online (this host also runs eight non-Officer PM2 entries — Crons/Dashboard/Tracking/Uptime — untouched and still online).

Cosmetic, pre-existing, not caused by this release: every $SHELL -ic command on this host prints an nvm warning about a globalconfig/prefix in ~/.npmrc. Nothing failed because of it.

deadpool-rezio-bridge — succeeded

Login br, per docs/servers.md.

Checkout /home/br/officerdev/platform
HEAD before ff647fba (deploy/2026.08.23.04)
HEAD after e15ab230 (deploy/2026.08.23.05)
Tracked changes before none
Untracked files none

Pre-check: roles = 4, orphans 0 / 0. SQL applied, exit 0. Verification query: same three rows, same verdict.

bun db:push clean; second push --verbose → No changes detected.

bun run plugins:update: 2/2 updated in 7s, exit 0. Restarted officer-email and officer-offscale.

pm2 restart officer: 9 → 10, online. All 9 processes online.

macbookpro — succeeded, and the host the plan flagged is now verified

Awake and reachable. macOS, so the PATH and psql notes in docs/servers.md all applied.

Checkout /Users/pastilhas/projects/officer-suite/platform
HEAD before 6e092c32 (deploy/2026.08.23.04-48-g6e092c32)
HEAD after e15ab230 (deploy/2026.08.23.05)
Tracked changes before none
Untracked files none

It started 48 commits past the previous tag rather than on it — the tag was still an ancestor, so the fast-forward was legitimate and no reset was needed.

The roles table the plan could not verify before the tag is now verified: roles = 4, orphan users 0, orphan grants 0. The plan was right that there is no psql here — there is also no Homebrew postgres and no postgres container. The query went through Bun's own SQL client (bun 1.3.14) against the same OFFICERDEV_POSTGRES_URL the platform's drizzle.config.ts reads, so it is that host's own database and not an inference from another one.

SQL applied through the same client, no exception raised. Verification query:

[
  { "conname": "ck_role_permissions_not_owner",
    "pg_get_constraintdef": "CHECK ((role <> 'Super Admin'::text))" },
  { "conname": "fk_role_permissions_role",
    "pg_get_constraintdef": "FOREIGN KEY (role) REFERENCES roles(name) ON UPDATE CASCADE" },
  { "conname": "fk_users_role",
    "pg_get_constraintdef": "FOREIGN KEY (role) REFERENCES roles(name) ON UPDATE CASCADE" }
]

Both fk_ present with ON UPDATE CASCADE and no ON DELETE; ck_role_permissions_role absent; ck_role_permissions_not_owner present. Same verdict as the other four.

bun db:push ran clean. It is not a no-op here either — see below.

bun run plugins:update: exit 0, and its whole output was no plugins installed — nothing to update. No sidecar restarted. That is worth a second look and is covered below.

pm2 restart officer: 11 → 12, online. All 6 processes online.


The one thing that is not clean

The plan says bun db:push should be a no-op after the SQL, and that anything it still wants to alter means the SQL was incomplete. On two hosts it still wants to alter something. It is not the release's schema change, and the SQL was not incomplete — the verification query above proves the constraints this release introduced are exactly right on all five hosts, and re-querying after push on alpha showed them unchanged.

What push --verbose still wants, after the SQL:

  • alpha — drops and immediately re-adds pk_music_now_playing on music_now_playing, with an identical definition.
  • macbookpro — the same music_now_playing churn, plus two atelier_collection_items foreign keys dropped and re-added under names one character longer (…_id_f → …_id_fk).

Both are plugin tables, both are the documented drizzle-kit mis-diff on named composite constraints and on foreign keys whose generated name Postgres truncates at 63 characters. The atelier case is precisely the churn this release's notes claim to end "across the fleet's plugins" — and on alpha, where the plugins did update, the atelier churn is indeed gone and only the music one remains. On macbookpro the plugins did not update at all, so it still carries both.

fofos, production-pertento-bridge and deadpool-rezio-bridge all reported No changes detected — a true no-op, which is the outcome the plan expected.

I judged this not to be a stop condition and continued. The reasoning, so it can be overruled: the plan's "stop and report" is aimed at the roles/FK change being half-applied, that change is provably whole on every host, and the residue is a pre-existing self-cancelling churn on plugin tables that this release does not touch. If that call was wrong, the thing to re-examine is music_now_playing's composite primary key — it is the one still churning on the host where plugins are current.


What I did not do, and could not verify

  • officer-dev — skipped entirely. Not pulled, nothing restarted. It is at 6cd99ddb, one commit past the tag; that commit landed on master after the tag was cut and is a docs commit. Its schema change was already applied and verified before this rollout, per the plan. It is the only host not at the tag exactly, and restarting it is the owner's deliberate last step.
  • edge-pertento-bridge — skipped, not a failure. Listed in Deliberately skipped since 2026-08-23. Nothing was spent on it: no SSH attempt, no retry.
  • The five-language picker was NOT checked in a browser. The plan's "what to check" asks for the profile settings picker to offer five languages and for a panel to be inspected in a non-English locale. That is a UI check and I did not perform it. What I can say is narrower: every host serves the tag's bundle and every host restarted officer afterwards, so the fix is present in the code each host is running. Whether it renders is unconfirmed.
  • Minesweeper's absence was not checked. /minesweeper was not requested on any host, and the dock was not inspected.
  • macbookpro reports no plugins installed while gen-plugin-schemas finds three schema files on disk (atelier, kiosk, music). So that host has plugin schemas without registered plugins. This predates the release and nothing in the plan covers it, so I left it alone — but it explains why the atelier constraint churn cleared on alpha and not here, and it means macbookpro's plugins are not being updated by the deploy at all.
  • plugins:update restarted sidecars on four hosts before the plan's own restart step, as docs/servers.md warns. Counted per host above rather than left as "restarted: officer".

One note for docs/servers.md

The database URL key is not the same on every host. alpha has only POSTGRES_URL; fofos, production-pertento-bridge, deadpool-rezio-bridge and macbookpro have only OFFICERDEV_POSTGRES_URL. drizzle.config.ts reads OFFICERDEV_POSTGRES_URL ?? POSTGRES_URL, so both work for the app — but a rollout that queries the database directly must follow the same precedence or it verifies the wrong database and says "schema ✓" about it. This cost one failed step on fofos before being caught, and I re-checked alpha afterwards to confirm it holds only the one key and that its verification was therefore sound.

macbookpro also has no timeout(1). A remote command wrapping anything in timeout fails there with command not found — and it fails silently in the sense that what you see is the next command's error, not the missing binary's.