mail-address-semantics/workplans/MAS-WP-0007-switchable-facility.md
tegwick f18eb0b8df Add an on/off switch for the MAS facility.
MAS-WP-0007 is finished. power.sh scales the MX and statute together
and records the power annotation. apply.sh keeps an off facility off.
The live facility was annotated power=on and was not restarted.

Assistant: grok
Assistant-Session: 01a198fa-fd27-7e41-a0a2-57355c3e4efd
2026-11-01 22:46:46 +01:00

154 lines
6.1 KiB
Markdown

---
id: MAS-WP-0007
type: workplan
title: "Operate MAS as a switchable facility"
domain: communication
repo: mail-address-semantics
status: finished
owner: claude
topic_slug: coulomb-social
created: "2026-10-18"
updated: "2026-11-01"
origin: residual
origin_ref: MAS-WP-0003
state_hub_workstream_id: "03751989-8ed1-5a3f-bcc3-71aef8b375a6"
---
# Operate MAS as a switchable facility
Residual of MAS-WP-0003. Namespace `mas` is the MAS facility for
`mas.coulomb.social`, with replies through Scaleway TEM capped at 300.
It stays. The 2026-10-19 retirement backlog is withdrawn.
**Founder decision (2026-11-01, `4d38ed47-8ab1-419e-839c-92921f7eeef1`): keep it, and make it switchable.** Do not
delete the namespace, revoke the TEM key, remove DNS, or tear down the
OpenBao role. Operate the existing facility so mail and the statute can
be turned off and back on without discarding evidence, credentials, or
the public address.
The 2026-10-19 redeploy record stays part of this workplan:
- 2026-10-19: redeployed `mas-mx` and `mas-statute` with image
`mas-live:v0.2-a95f848`, side-loaded into k3s containerd. The previous
image was `v0.2-a45f1a1`. The evidence (`events.jsonl`, 36 events, and
`tickets.sqlite3`) was backed up before the rollout and is intact on the
PVC. Checked: `mas discover` valid; the profile's relay control; TEM
relay with null-sender discard; OpenDKIM/OpenDMARC running; the ticket
service runs with `--max-sent 300 --require-dmarc-pass`; empty queue;
relaying to the public IP refused with 554 (`x@other`, `x!y@other`,
`a@mas...@other`).
- 2026-10-19: redeployed with image `mas-live:v0.2-480e69a`: MAS-WP-0012's
one outbound path, and v0.2 final. The evidence was backed up first. The
legacy outbox was imported once into `tickets-outbox.sqlite3`: 9 rows,
4 sent, so 4 of 300 count toward the cap. The ticket service runs with
`--max-sent 300 --require-dmarc-pass --email-held-duration-max 7d
--emails-held-storage-max 100MB`. Checked: statute valid, 36 evidence
events intact, TEM relay with null-sender discard, empty queue, relaying
refused with 554. The migration was first tested in the image against a
copy of the live volume.
## What the facility is
Durable parts stay when the facility is off. The power switch must not
delete or edit them:
- namespace `mas`
- PVC `mas-evidence` (`events.jsonl`, `tickets.sqlite3`, the outbox DB)
- Services `mas-smtp` (LoadBalancer) and `mas-statute`
- Ingress `mas-statute` and its TLS secret
- ExternalSecret `mas-relay`, its SecretStore, and ServiceAccount
- OpenBao role `external-secrets-mas-tem-relay`, policy
`workload-kv-read-mas-tem-relay`, and KV path
`platform/suppliers/scaleway/mas-tem-relay`
- DNS for `mas.coulomb.social`, the TEM domain, and the TEM API key
Switchable parts are the two Deployments, `mas-mx` and `mas-statute`.
Off means both `replicas: 0`. The LoadBalancer keeps its address and has
no ready pods, so port 25 takes no mail, and the statute ingress has no
backend. On means both `replicas: 1` and ready, on the same PVC and image.
Known limits, unchanged by this workplan: one replica, a side-loaded
image, snakeoil SMTP TLS, and the 300-reply cap. A later decision can
raise any of those. This workplan does not roll a new image and does not
turn the live facility off.
## Retire the teardown
```task
id: MAS-WP-0007-T01
status: cancel
priority: medium
state_hub_task_id: "e0a65837-1769-5129-b258-fbaeb3047f62"
```
Cancelled 2026-11-01. The founder withdrew retirement. Do not export for
teardown, delete namespace `mas`, ask ops-mason to remove the OpenBao
role, revoke the Scaleway TEM key, remove DNS, or delete the side-loaded
images.
## Record the facility contract
```task
id: MAS-WP-0007-T02
status: done
priority: high
state_hub_task_id: "18d8898e-52c9-572d-aa7c-014fb1f7751e"
```
Update the current-direction docs so they describe a kept, switchable
facility. `SCOPE.md` and INTENT.md phase-2 criterion 5 stop saying the
live environment is retired. `deploy/railiance/` states the durable and
switchable parts and the limits above. The release-unit note stops
calling this something other than the operated facility. Historical
workplans and `history/` stay as they were.
Done 2026-11-01. `SCOPE.md`, INTENT.md criterion 5, `deploy/railiance/README.md`,
the manifest header, and `registry/release-units/mas.yaml` describe the
switchable facility. The 300-reply cap, side-loaded image, and snakeoil
SMTP TLS are recorded as limits.
## Add the power switch
```task
id: MAS-WP-0007-T03
status: done
priority: high
state_hub_task_id: "78a11c89-7cda-5ff7-bd0a-b7958b6c9fe7"
```
Add an operator command, `on`, `off`, and `status`, that scales only
`deploy/mas-mx` and `deploy/mas-statute`. It records the desired power on
namespace `mas` as annotation `mas.coulomb.social/power`. The supported
apply path reads that annotation and renders `replicas: 0` when the
facility is off, so a later apply does not turn it back on. Missing
annotation means on, which matches the manifest and the live facility.
The command must not delete the namespace, volume, secrets, services, or
ingress.
On the cluster, record `power=on` to match the running facility. Do not
scale it to 0 and do not roll a new image.
Done 2026-11-01. `deploy/railiance/power.sh` and `apply.sh`, with
`facility.py` doing the render. Live: `power.sh on` with the railiance01
admin kubeconfig annotated namespace `mas` as `power=on`, scaled both
Deployments to 1, and both were already ready. Pod start times stayed
`mas-mx` 2026-10-21T22:18:00Z and `mas-statute` 2026-10-19T11:36:30Z.
`power.sh status` shows `power=on`, both Deployments 1/1, and endpoints
for `mas-smtp` and `mas-statute`. No new image.
## Test the switch offline
```task
id: MAS-WP-0007-T04
status: done
priority: high
state_hub_task_id: "3f458be1-a8c8-5b05-96e8-851294e36d60"
```
Test the render without a cluster. Power `off` sets both Deployment
replicas to 0 and leaves the Service, PVC, Ingress, and ExternalSecret
in place. Power `on` leaves `replicas: 1`. The image placeholder is
replaced. The operator command has no delete of those durable objects.
Done 2026-11-01. `tests/test_facility_power.py`: 4 passed.