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

6.1 KiB

id type title domain repo status owner topic_slug created updated origin origin_ref state_hub_workstream_id
MAS-WP-0007 workplan Operate MAS as a switchable facility communication mail-address-semantics finished claude coulomb-social 2026-10-18 2026-11-01 residual MAS-WP-0003 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

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

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

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

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.