|
1 | 1 | # The `prod` branch — public AMA deployment |
2 | 2 |
|
3 | | -**Status:** temporary. Exists only for the window between the M4 AMA cutover and the moment one |
4 | | -remaining client finishes the AMA they are currently running on the canary bot. |
| 3 | +**Status:** temporary, with a target end date. Exists only for the window between the M4 AMA cutover |
| 4 | +and **2026-08-13**, when the one remaining client finishes the AMA they are running on the canary |
| 5 | +bot. On that date this deployment folds _into_ the canary one (see [Convergence](#convergence)) — |
| 6 | +that direction is decided, not open. |
5 | 7 |
|
6 | 8 | ## Why there are two deployments |
7 | 9 |
|
@@ -90,14 +92,75 @@ out of `canary.automoderator.app`. |
90 | 92 |
|
91 | 93 | ## Convergence |
92 | 94 |
|
93 | | -When the client finishes their AMA: |
| 95 | +**Direction: this deployment folds into the canary one on 2026-08-13.** The canary deployment |
| 96 | +(`chatsift-v3`, `/home/deploys/repos/canary`, branch `main`) survives and takes over the public AMA |
| 97 | +token; `chatsift-prod` is deleted. |
94 | 98 |
|
95 | | -1. Migrate their now-historical AMA rows from the canary database to this one. Historical rows are |
96 | | - far safer to move than in-flight ones — that timing is the entire point of this arrangement. |
97 | | -2. Shut down the canary deployment's `ama-bot` and retire `canary.automoderator.app` / |
98 | | - `api-canary.automoderator.app`, or keep them as a genuine canary. |
99 | | -3. Decide whether ModMail and the monitoring stack move into this deployment, or this deployment's |
100 | | - AMA folds back into the canary one. Whichever database you keep sets the migration direction. |
101 | | - That decision does not have to be made now. |
| 99 | +That direction is chosen because it moves the least, and moves the safest things: |
102 | 100 |
|
103 | | -Once converged, delete this branch rather than merging it. |
| 101 | +- **The client's rows never move at all.** They are already in the surviving database. The |
| 102 | + alternative direction would mean migrating them a second time. |
| 103 | +- The surviving deployment keeps the awkward, stateful pieces in place — the #216 partner ModMail |
| 104 | + instances and their per-partner tokens, Prometheus history, Grafana dashboards, Dozzle's bcrypt |
| 105 | + users volume. Re-homing those is strictly more work than moving a few days of AMA rows. |
| 106 | +- Only public-AMA data created between the cutover and 2026-08-13 has to move, and AMA sessions are |
| 107 | + short-lived events, so that is a small set. This deployment runs no `modmail-bot`, so every ModMail |
| 108 | + table in its database is empty — nothing to reconcile there. |
| 109 | + |
| 110 | +### The one real cost: identity-column collisions |
| 111 | + |
| 112 | +Every AMA table keys on `INTEGER GENERATED BY DEFAULT AS IDENTITY`, so both databases have rows |
| 113 | +numbered from 1 and the merge needs an id remap across the whole FK graph: |
| 114 | + |
| 115 | +``` |
| 116 | +ama_sessions (id) |
| 117 | +├── ama_prompt_data .ama_id → sessions.id (UNIQUE; own identity id) |
| 118 | +├── ama_question_tags .ama_id → sessions.id (own identity id; UNIQUE (id, ama_id)) |
| 119 | +└── ama_questions .ama_id → sessions.id (own identity id; UNIQUE (id, ama_id)) |
| 120 | + ├── ama_question_askers .question_id → questions.id (own identity id) |
| 121 | + └── ama_question_tag_assignments (question_id, ama_id) → ama_questions (id, ama_id) |
| 122 | + (tag_id, ama_id) → ama_question_tags (id, ama_id) |
| 123 | +``` |
| 124 | + |
| 125 | +`GENERATED BY DEFAULT` rather than `ALWAYS` is what makes this tractable: explicit ids can be |
| 126 | +inserted without disabling anything. Pick a per-table offset above the surviving database's current |
| 127 | +`max(id)`, shift every prod id and every referencing FK by that same offset, insert parent-first in |
| 128 | +the order above, then `ALTER TABLE … ALTER COLUMN id RESTART WITH …` on each sequence. |
| 129 | + |
| 130 | +`scripts/import-legacy-ama.mjs` is the precedent to follow: it emits a single `BEGIN`/`COMMIT` around |
| 131 | +a plpgsql `DO` block to stdout for review rather than connecting to a database, and is applied with |
| 132 | +`psql -v ON_ERROR_STOP=1`. Do the same here. |
| 133 | + |
| 134 | +Unique constraints to be aware of while merging: |
| 135 | + |
| 136 | +- `ama_sessions.share_token` and `ama_prompt_data.prompt_message_id` — random tokens and Discord |
| 137 | + snowflakes respectively, so collisions are not a practical concern. |
| 138 | +- `dashboard_grants (guild_id, user_id)` — the one genuine risk if any guild ended up with both bots. |
| 139 | + Insert with `ON CONFLICT DO NOTHING`. |
| 140 | + |
| 141 | +### Steps |
| 142 | + |
| 143 | +1. Confirm the client's AMA is `ended`, then stop **both** `ama-bot` containers so nothing writes |
| 144 | + mid-merge. |
| 145 | +2. Dump this deployment's AMA tables plus `dashboard_grants`, remap ids as above, apply to the canary |
| 146 | + database inside one transaction. |
| 147 | +3. In the canary checkout, set `AMA_BOT_TOKEN` to the **public** `@AMA#5595` token and merge this |
| 148 | + branch's `.env.public` changes into `main` — `API_URL_PROD`, `FRONTEND_URL_PROD`, and `CORS`, but |
| 149 | + **keep `API_PORT=7004`**, since the surviving deployment is already on that port. |
| 150 | +4. In `chatsift/caddy`, repoint `api.automoderator.app` from `:7005` to `:7004` and delete the |
| 151 | + `api-canary.automoderator.app` block. |
| 152 | +5. `./compose up -d` in the canary checkout; `./compose down -v` in the prod one; delete |
| 153 | + `/home/deploys/repos/prod`. |
| 154 | +6. Delete this branch. Its `docker-compose.yml` trim is throwaway, but note that step 3 means the |
| 155 | + `.env.public` half of it **does** belong on `main` — don't discard the branch before that lands. |
| 156 | + |
| 157 | +### After the fold |
| 158 | + |
| 159 | +- **The client's historical AMA messages become uneditable.** They were authored by the canary |
| 160 | + application, and the surviving API holds only the public token, so `updateQuestion`, `mergeShared`, |
| 161 | + and `updateAMA`'s prompt edit will get a 403 on those specific old rows. The session is over, so |
| 162 | + this is cosmetic — but it is permanent, and worth saying out loud rather than discovering later. |
| 163 | +- **The client needs `@AMA#5595` invited** to their guild for any future AMA; the canary application |
| 164 | + will no longer be running anywhere. |
| 165 | +- Their dashboard session survives the move to `automoderator.app` without a re-login, because the |
| 166 | + cookie is scoped to the bare `ROOT_DOMAIN` and both deployments share an `ENCRYPTION_KEY`. |
0 commit comments