tenant-engine/workplans/TEN-WP-0007-guardrail-production-rollout.md
tegwick 9f1e58a797 Plan guardrail production rollout (TEN-WP-0007)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 02:52:05 +02:00

5.3 KiB

id type title domain repo status owner topic_slug created updated depends_on unblocks
TEN-WP-0007 workplan Production rollout of the guardrail surface infotech tenant-engine ready claude tenant-guardrails 2026-08-16 2026-08-16
TEN-WP-0006

TEN-WP-0007 - Guardrail production rollout

TEN-WP-0006 deliberately left production rollout out of scope. The operator has now authorized proceeding, so this workplan carries the deploy that TEN-WP-0006 would not.

Sequencing (agreed with flex-auth, FLEX-WP-0014)

  1. flex-auth first — CI image from the nine-action commit, pin flex-auth-tenant-engine.
  2. tenant-engine second — pin the guardrail image.
  3. Joint live verification against a disposable tenant.

flex-auth goes first on purpose. If we pin first, the guardrail surface is live but every call denies with write_denied — a state indistinguishable from a broken deployment to anyone reading logs. Their step landing first makes each step independently observable.

What is already true

  • Source revision e5c1061 on main, TEN-WP-0006 finished, 231 tests passing.
  • flex-auth's nine-action package is verified in source (17/17 Rego tests, 23/23 fixtures, end-to-end against our unmodified FlexAuthWriteAuthorizer).
  • Production flex-auth serves the seven-action image @sha256:9320df39… — the four-action regression is resolved, but the guardrail actions are not in that image.
  • Production tenant-engine still runs the TEN-WP-0005 lifecycle image.

T01 - Confirm the CI image and its digest

id: TEN-WP-0007-T01
status: todo
priority: high

src/** is a trigger path in .forgejo/workflows/image.yaml and the guardrail commits are pushed, so CI should have built an image for main-e5c1061. Confirm it exists and record the immutable digest.

Blocked from this workstation: no registry credentials. Needs a shell with forge access, or the digest relayed by whoever has one.

Done when the digest is recorded here and the image is confirmed to contain the guardrail routes (GET /openapi.json on the built image lists /tenants/{tenant_id}/guardrails).

T02 - Wait for the flex-auth nine-action pin

id: TEN-WP-0007-T02
status: wait
priority: high

Waiting on FLEX-WP-0014 step 1. Two things to collect when it lands:

  • the new flex-auth image digest;
  • confirmation that the seven pre-existing actions still allow after the pin. The last regression surfaced as a silent rollback, and lifecycle authority is what user-engine is already shipping against — a second silent rollback would break a live consumer, not just this workplan.

Done when guardrail checks return allow instead of deny unknown_action against the live decision surface.

T03 - Apply the migration and pin the tenant-engine image

id: TEN-WP-0007-T03
status: wait
priority: high

The guardrail schema change is two new tables created by the same CREATE TABLE IF NOT EXISTS script fresh and existing databases both take, so the migration is forward-only and idempotent and needs no separate step. What it does need is evidence that the existing SQLite database on the PVC survives it with tenants, grants, and plans untouched.

Rollback is kubectl -n tenant-engine rollout undo; last-known-good is the TEN-WP-0005 lifecycle digest @sha256:08be0b1dcdc65575592b7be665c28e09a82316ea3d4c9b551ccb753f25360612. Rolling back is safe in one direction only: the new tables are additive and the old image ignores them, but any override written while the new image is live stops being enforced on rollback. Nothing reads guardrails yet, so today that is inert — record it before that stops being true.

Blocked from this workstation: kubectl returns Unauthorized. This is an operator step.

Done when the deployment is pinned to the T01 digest and the pre-existing tenants are intact.

T04 - Live verification and consumer confirmation

id: TEN-WP-0007-T04
status: wait
priority: high

Against a disposable tenant, in the TEN-WP-0005-T05 evidence style:

  • guardrail read returns the grouping default with provenance grouping;
  • a trial tenant reads a zero spend ceiling — the ADR-0013 mandate, and the one thing here that is enforceable with no meter;
  • override set → read reflects it with provenance override;
  • override cleared → falls back to the grouping default;
  • actor=ops denied on both read and write;
  • flex-auth allowed on read, denied on write (action_not_granted);
  • retired tenant still reads, clamps to floor, loosening refused;
  • idempotent replay returns the original result unchanged.

Then confirm to flex-auth from our side — they verified the decision surface, not our endpoints in production, and TEN-WP-0005 established that those are different claims.

Done when live evidence is recorded here and the confirmation is sent.

Out of scope

  • Metering. Still unowned by any repo. The guardrail read stays ceiling-only until canon names a meter.
  • The plan-derived layer. adaptive-pricing exposes no plan-derived ceilings; the precedence layer exists and is tested but has no feed.
  • Grouping ceiling values. The non-trial defaults are conservative opening numbers pending product sign-off. Rolling out does not ratify them — they are config, changeable without a deploy.