deploy: pin and record the schema v9 sole-pod rollout

The live StatefulSet now runs
sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2.
A verified pre-v9 backup was migrated in isolation with unchanged counts
before the sole pod was replaced. Readiness, integrity and a single writer
were checked after the restart.

Assistant: grok
Assistant-Session: 01a1b5fd-0c33-7ba1-b383-53937d525595
This commit is contained in:
tegwick 2026-11-07 14:21:04 +01:00
parent 2745cd7fdd
commit d39da805fe
7 changed files with 113 additions and 29 deletions

View file

@ -5,33 +5,36 @@ The StatefulSet is deployed as of 2026-09-14. The metadata receipt is
storage, and an `OnDelete` update: never start two writers against a copied
database.
**Current image: pinned, published and deployed (2026-10-15).** Both `image:`
**Current image: pinned, published and deployed (2026-11-07).** Both `image:`
references carry
`sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d`
(source `a786b061da4d7730c0827cf4919ab9206aed6d3e`). Migration and server
`sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2`
(source `2745cd7fdd3c6e17af38650c4a3eff1f1e003373`). Migration and server
use identical immutable pins. The scanned image has zero HIGH/CRITICAL findings.
Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`.
The founder-approved NK-WP-0035 release moved schema v5 to v6 and retained the
hourly heartbeat setting. A fresh verified online backup and independent 0600
copy preceded the controlled sole-pod replacement. The new image also opened
and migrated an isolated production backup with unchanged record counts.
Native readiness and v6 integrity pass; 54 approvals and 47 entries were
preserved with zero pending outbox rows. Source defaults and interval settings
alone do not establish elapsed-hour or independent receiver acceptance.
Receipts: `net-kingdom/docs/evidence/2026-10-15-cadence-adoption/` files
`approval-engine-pre-schema6-backup.json`, `approval-engine-v6-isolated-restore.json`
and `approval-engine-schema6-rollout.json`.
This release moves the live store from schema v6 to v9. v7 adds
`approvals.required_assurance`, v8 adds `approvals.actor_consumes`, and v9 adds
`revoked_by_*` plus `revocation_reason`. A verified online backup and an
independent 0600 copy preceded the sole-pod replacement. The new image opened
that copy, migrated it, and left the record counts unchanged. Live readiness
and v9 integrity pass; 59 approvals, 50 entries and 2279 outbox rows were
preserved with zero pending outbox rows. The pre-migration backup remains on
the volume at `/data/pre-schema9-20261107.sqlite`.
Schema v6 records verified `entries.tenant_source`; it does not infer legacy
provenance. The prior v5 image was
The previous v6 image was
`sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d`
(source `a786b061da4d7730c0827cf4919ab9206aed6d3e`). It refuses a v9 store:
rollback requires the matching verified pre-v9 backup and the
stopped-single-writer restore procedure in `docs/storage-operations.md`.
The founder-approved NK-WP-0035 release had moved schema v5 to v6 on 2026-10-15
and retained the hourly heartbeat setting. That rollout preserved 54 approvals
and 47 entries. Receipts: `net-kingdom/docs/evidence/2026-10-15-cadence-adoption/`
files `approval-engine-pre-schema6-backup.json`,
`approval-engine-v6-isolated-restore.json` and
`approval-engine-schema6-rollout.json`. The v5 image was
`sha256:251941a5cb2724b57cc32cff6b693b1ab0be695bee4f56f02d51961189c0fa49`.
It refuses a v6 store: rollback requires the matching verified pre-v6 backup
and the stopped-single-writer restore procedure in `docs/storage-operations.md`.
Source has since moved to schema v9 (v7 `approvals.required_assurance`,
APPROVAL-WP-0007-T01; v8 `approvals.actor_consumes`, APPROVAL-WP-0007-T02;
v9 `revoked_by_*`, APPROVAL-WP-0007-T03); the pinned image predates schema v9
(and v7). Deploying needs a new release, a verified pre-v7 backup and a
founder-run rollout like the v6 one.
It refuses a v6 store.
The earlier September v5 release evidence remains historical at
[the image evidence](../docs/evidence/2026-09-10-human-control-image.json).

View file

@ -45,7 +45,7 @@ spec:
seccompProfile: {type: RuntimeDefault}
initContainers:
- name: migrate
image: forgejo.coulomb.social/coulomb/approval-engine@sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d
image: forgejo.coulomb.social/coulomb/approval-engine@sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2
args: ["migrate", "--db", "/data/approvals.sqlite"]
securityContext:
allowPrivilegeEscalation: false
@ -56,7 +56,7 @@ spec:
- {name: tmp, mountPath: /tmp}
containers:
- name: approval-engine
image: forgejo.coulomb.social/coulomb/approval-engine@sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d
image: forgejo.coulomb.social/coulomb/approval-engine@sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2
args:
- serve
- --production

View file

@ -0,0 +1,78 @@
{
"status": "deployed",
"observed_at": "2026-11-07T13:17:00Z",
"source_commit": "2745cd7fdd3c6e17af38650c4a3eff1f1e003373",
"image": {
"repository": "forgejo.coulomb.social/coulomb/approval-engine",
"tag": "0.1.0",
"digest": "sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2",
"linux_amd64_manifest": "sha256:0ff0974535848412cd649f578796ffec6fad2c0a3b2079b80cf4162ab2a55c23",
"schema_version": 9
},
"previous_image": {
"digest": "sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d",
"schema_version": 6,
"source_commit": "a786b061da4d7730c0827cf4919ab9206aed6d3e"
},
"scan": {
"scanner_image": "aquasec/trivy:latest",
"gate": "CRITICAL,HIGH; exit-code 1",
"exit_code": 0,
"high": 0,
"critical": 0,
"os": "Alpine 3.24.1",
"package_floors": [
"libuuid>=2.42.3-r1",
"musl>=1.2.6-r3",
"musl-utils>=1.2.6-r3",
"zlib>=1.3.2-r1"
]
},
"container_verification": {
"status": "passed",
"schema_version": 9,
"checks": [
"registry digest present",
"previous digest still present",
"isolated v6 backup migrated to v9",
"live sole-pod replacement",
"readiness",
"integrity",
"restart persistence",
"zero pending outbox"
]
},
"backup": {
"live_schema_before": 6,
"persistent_path": "/data/pre-schema9-20261107.sqlite",
"local_copy": "/tmp/ae-pre-schema9-20261107/pre-schema9.sqlite",
"local_mode": "0600",
"sha256": "8501d223bd16032946e55b3b71b9a4b1155be31e4fdac07831222fd3f2bc3a3f",
"integrity": "ok",
"live_database_overwritten_by_backup": false
},
"isolated_restore": {
"pre_schema": 6,
"post_schema": 9,
"counts_unchanged": true,
"live_database_overwritten": false,
"nonroot_uid": 10001,
"counts": {"approvals": 59, "entries": 50, "outbox": 2279},
"pending_outbox": 0
},
"rollout": {
"namespace": "approval-engine",
"pod": "approval-engine-0",
"pod_uid": "fd89dab8-b587-4443-8200-288d94272145",
"replicas": 1,
"readiness": 200,
"schema_version": 9,
"integrity": "ok",
"foreign_key_violations": 0,
"counts": {"approvals": 59, "entries": 50, "outbox": 2279},
"pending_outbox": 0,
"latest_heartbeat_created_at": "2026-11-07T13:07:32+00:00",
"latest_heartbeat_drained_at": "2026-11-07T13:07:32+00:00",
"heartbeat_interval_seconds": 3600
}
}

View file

@ -106,4 +106,5 @@ Nothing is inferred for old approvals, entries, or revocations.
A v6 server refuses a v9 store. Rollback uses the verified pre-v9 backup with
the matching v6 release and the stopped single-writer restore procedure above.
Take and verify that backup, and open an isolated copy with the new image,
before the sole pod is replaced.
before the sole pod is replaced. That rollout completed on 2026-11-07.
Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`.

View file

@ -35,7 +35,7 @@ pins:
digest:
hashAlgorithm: SHA-256
normalisationAlgorithm: ociArtifactDigest/v1
value: sha256:16e5d222d58e179f4836f649e8f8128321a8b644d29dc426b4d21a65ff97845d
value: sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2
sources:
- name: approval-engine
type: git
@ -43,4 +43,4 @@ pins:
digest:
hashAlgorithm: SHA-1
normalisationAlgorithm: gitCommit/v1
value: 01abbe192816fa10a50eb13796480ae1de47db92
value: 2745cd7fdd3c6e17af38650c4a3eff1f1e003373

View file

@ -16,7 +16,7 @@ from approval_engine.store import LATEST_SCHEMA_VERSION
ROOT = Path(__file__).resolve().parents[1]
MANIFEST = ROOT / "deploy" / "approval-engine.yaml"
RELEASE_RECORD = ROOT / "docs" / "evidence" / "2026-09-10-human-control-image.json"
RELEASE_RECORD = ROOT / "docs" / "evidence" / "2026-11-07-schema-v9-rollout.json"
DEPLOY_README = ROOT / "deploy" / "README.md"
IMAGE_LINE = re.compile(r"^\s*image:\s*(\S+)\s*$", re.MULTILINE)

View file

@ -121,7 +121,9 @@ Done 2026-11-07 in source (schema v9, `tests/test_revoker.py`, contract in
reason of at most 200 characters. The token supplies the revoker. GET and
`details.revoked_by` serve it. The claim omits it. An internal revoke with no
verified identity still revokes and omits the member, as do migrated rows.
Not released or deployed: a v9 image and a founder-run rollout are still needed.
Released and deployed 2026-11-07 as
`sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2`.
Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`.
## Synthetic bounded-execution carrier proof