Compare commits

..

1 commit

Author SHA1 Message Date
45d6178b2e Prepare supervised Coulomb storage migration release and guarded node execution
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a17f16-d99c-7ea3-95f0-8212897fba6b
2026-10-29 23:35:58 +01:00
63 changed files with 341 additions and 4248 deletions

View file

@ -41,10 +41,6 @@
| task | RAPPS-WP-0015-T02 | done | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0015-T03 | done | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0015-T04 | wait | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0015-T05 | done | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0015-T06 | done | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0015-T07 | done | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0015-T08 | done | — | workplans/RAPPS-WP-0015-coulomb-personal-content-release.md |
| task | RAPPS-WP-0016-T01 | done | — | workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md |
| task | RAPPS-WP-0016-T02 | wait | — | workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md |
| task | RAPPS-WP-0016-T03 | wait | — | workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md |

View file

@ -1,39 +0,0 @@
# Completed Coulomb identity/export image release
The exact supervised proposal is
`sha256:9f1daf6c5fb56b2b4fc9817f28f5ad090c884b0295f7d6f4469e42d48fa8d59f`.
Resolved execution decision: `75b94bb6-4709-495f-91fe-43e53e2867ed`.
The full founder packet is
[coulomb-social release review](/home/worsch/coulomb-social/docs/release/identity-export-release-review-2026-10-31.md).
`tools/coulomb-image-release.py` prepares the capsule by default. `--preflight`
checks the live target without capture or deployment. `--execute --expect-digest`
requires the founder's own interactive terminal and the exact typed proposal.
The node controller freezes verified source bytes into its private durable
journal before execution. An existing attempt refuses blind replay.
This distinct controller adapts the previously reviewed storage controller
from owner source 45d6178. It requires migration 0003 and the global constraint
already present, adds exact migration-history equality, verifies installed
helpers during preflight, verifies the desired complete spec through an image-only
server-dry-run patch and verifies rollback readiness/specification. Unknown
helper changes refuse overwrite. Historical storage commands/capsules remain
unchanged and must not be replayed.
Candidate values live in `release/identity-export-values.yaml`; the current
`helm/coulomb-social-values.yaml` now matches verified revision 19/image522bcd7f.
The installed snapshot helper matches the reviewed bytes (dcc8dd2a).
No unit/timer, sender, grant, apex or data-restore operation is included.
Validation: 19 release safety cases pass; Ruff, Python compile and Helm lint pass.
The sealed native preflight is retained in
`docs/evidence/2026-10-31-coulomb-image-release-preflight.json`.
Four hash-bound candidate evidence files travel inside the capsule. The product
review names source 441 tests, actual packaged 25 tests, all 80 packaged source matches
and the retained isolated recovery/export/view checks with their limits.
Founder execution and independent postflight are verified at revision19. The
product independently retrieved/restored the fresh point and verified packaged
client export on the corrected data. T05 is complete. Native receipt, independent
postflight and live packaged-source proof are under docs/evidence/2026-10-31-coulomb-image-release-*.json.
The historical launcher/capsule is retained for audit and must not be replayed.

View file

@ -0,0 +1,85 @@
# Storage/content hardening release — exact supervised proposal
Prepared, not deployed. Decision 05c9b00f-e4e4-4593-bdeb-c63fe6a4fe15 is pending
founder disposition. Earlier backup/custody/schedule approvals remain in force.
This packet does not reopen them or approve Bubble/apex cutover.
Proposal digest:
`sha256:3389c506d86f1613c6567a2bba5c29ae22b812f19b011ebe454bb08af39a4132`.
It binds 12 capsule members including all node/launcher/probe code, exact chart and
values, dataset/schema expectations and the candidate snapshot-helper source.
Any changed reviewed byte produces another digest and refuses execution.
## Exact result
Target: `ADMINISTER @ realm:kubernetes/railiance01`, namespace/release
coulomb-social, current Helm revision 17. Candidate product source 17d0eb6 at
`sha256:512819463a1902b43a615beee14be7bf97e6a05e016385082b9380692ad1a8cd`.
The candidate contains global slug constraint 0003, tested content revision/recovery
hardening and strict original-date import guards. Renderer policy is unchanged.
The attended command rechecks cluster/node, exact live spec/PVC/Helm baseline,
headroom, no Argo adoption, data equality and server/client dry-runs. It then runs
the already admitted fresh paired backup and immutable primary readback, checks
the dataset again, and performs Helm --atomic/--wait with Recreate. The three
resource manifests change only the app image; the PVC, configuration, resources
and secret references are preserved. Startup applies the atomic SQL constraint;
it does not rename/merge/delete business rows or change grants.
Read-only postflight checks schema, all business/content aggregate hashes, actual
owner pages and unsaved-outsider denials, plus public health/landing/static bytes.
Only then refresh the root-owned snapshot helper's image pin to the new digest
and repeat its server dry-run. No private key/recovery pair is delivered to the
worker; no email, caller, issuer, DNS, apex, timer or production-data restore.
## Evidence and limits
- Packaged real recovered dataset: forward/refusal/reverse/reapply preserve all
12 business tables/91 rows and82 files; candidate renders 39 pages with owner/viewer/
ungranted checks. Old image also reads the migrated data and denies outsiders.
- Live data hashes match the independently protected recovered point. Current
image 9a646d8e, one Ready replica, revision 17, Recreate, Bound PVC, no pressure.
Requests:68% CPU / 76% memory. Helm lint passes; exact sealed live preflight passes.
- Product make check: 246 passed, including mandatory browser journeys. Ten
synthetic executor cases cover tampering, data drift, replay refusal, staging
immutability, unattended-launch refusal, rollback and capture cleanup timeout.
The fresh capture normally pauses/resumes in about 54 seconds; previous app
upgrades took about 20 seconds. Helm has a five-minute wait plus rollback handling.
Failure preserves post-capture writes and the fresh point. Automatic rollback
restores the prior image/revision, not database contents; the added uniqueness
constraint may remain. Its separate SQL inverse and old-image read compatibility
are rehearsed. A failed/uncertain attempt requires journal inspection, not replay.
No new node/PVC/service capacity is committed. One existing-size encrypted
generation/readback and normal API/storage usage are added. No EUR autopilot
budget or risk grant is claimed; execution remains supervised.
## Founder execution
Run in your own terminal from the prepared deployment checkout:
```sh
python3 /tmp/csoc-storage-release-owner-20261029/tools/coulomb-storage-release.py \
--execute \
--expect-digest sha256:3389c506d86f1613c6567a2bba5c29ae22b812f19b011ebe454bb08af39a4132 \
--output /tmp/csoc-storage-release-result-20261029.json
```
Review the digest and type DEPLOY followed by that full digest when prompted.
The command uses the founder's existing SSH/sudo path and returns metadata only.
No Scaleway login or credential pasted into chat is required. Reply done afterward;
the agent must inspect the node receipt and postflight before recording acceptance.
The durable node journal is
`/var/lib/coulomb-social-backup/releases/<proposal-hex>/receipt.json`.
This is an attended supervisor command, not a new credential/approval service.
The active gated-executor profile is Kubernetes-only and cannot perform the
root-owned node-helper refresh. Its configuration is left unchanged.
The exact-action requirement comes from the-custodian's
docs/agent-environment-orientation.md §4: “Every live change needs the founder's
go-ahead”, and docs/agent-autonomy-decision.md: supervised privileged actions use
an exact proposal; “The agent cannot approve itself.” This image/schema action
has no current exact founder approval. Preparation and all observed checks above
are complete; the app has not been changed by this packet.

View file

@ -1,49 +0,0 @@
{
"schema": "coulomb.independent-image-release-postflight.v1",
"status": "live_image_release_verified",
"observed_at": "2026-10-31T07:31:19.932895+00:00",
"proposal_digest": "sha256:9f1daf6c5fb56b2b4fc9817f28f5ad090c884b0295f7d6f4469e42d48fa8d59f",
"helm_revision": 19,
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"cluster_deployment_pvc_identity_verified": true,
"complete_deployment_spec_verified": true,
"sole_ready_pvc_writer": true,
"data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"installed_helper_sha256": {
"/opt/coulomb-social-backup/paired-backup.py": "43e119acb6a4933b4e144c349a091e074e1a91ab61dbe15a65c8264c1d47661a",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "dcc8dd2a3989f279597595f9260b31b24fcc9b6dc787f04c17ef0491c53d830d",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d"
},
"snapshot_server_dry_run": "passed",
"public_status": {
"/healthz": 200,
"/": 200,
"/static/spaces/copy-content.js": 200
},
"timers": {
"coulomb-social-paired-backup.timer": {
"LoadState": "not-found",
"ActiveState": "inactive"
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "not-found",
"ActiveState": "inactive"
}
},
"production_data_modified": false
}

View file

@ -1,25 +0,0 @@
{
"schema": "coulomb.guarded-image-release.v1",
"proposal_digest": "sha256:9f1daf6c5fb56b2b4fc9817f28f5ad090c884b0295f7d6f4469e42d48fa8d59f",
"started_at": "2026-10-31T03:41:35.362323+00:00",
"status": "live_release_preflight_verified",
"production_data_restored": false,
"timers_activated": false,
"node_request_percent": {
"cpu": 68,
"memory": 76
},
"preflight": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"live_changes": false
}

View file

@ -1,70 +0,0 @@
{
"completed_at": "2026-10-31T07:15:24.659887+00:00",
"elapsed_seconds": 99.14,
"existing_global_constraint_preserved": true,
"fresh_paired_point": {
"age_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"application": "coulomb-social",
"application_restore_verified": false,
"captured_at": "2026-10-31T07:13:52Z",
"ciphertext_bytes": 2181848,
"ciphertext_sha256": "840e633047fddd88c6e6a1a3d6909d9af1ad80eaba8c90f83d8e81188dfc17a4",
"completed_at": "2026-10-31T07:14:50.236959+00:00",
"content_sha256": "644db8f09684bd4a79c126a01a329904351c30bb340295b29c8bb0ca71092dfe",
"database_sha256": "498a11e221dcdef38075d23ef89a26f213316c6164addb70d47bfcb98a1999a7",
"destination": "s3://railiance-platform-pg-backup/platform-pg/application-archives/coulomb-social/2026/10/31/20261031T071352Z-abf5997f01a14d9cb05e4bba.tar.age",
"encrypted_bytes": 2181848,
"encrypted_sha256": "840e633047fddd88c6e6a1a3d6909d9af1ad80eaba8c90f83d8e81188dfc17a4",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:512819463a1902b43a615beee14be7bf97e6a05e016385082b9380692ad1a8cd",
"immutable_create": true,
"local_archive": "20261031T071352Z-abf5997f01a14d9cb05e4bba.tar.age",
"object_key": "platform-pg/application-archives/coulomb-social/2026/10/31/20261031T071352Z-abf5997f01a14d9cb05e4bba.tar.age",
"pause_and_capture_seconds": 56.34,
"remote_retrieval_verified": true,
"schema": "platform.application-primary-archive.v1",
"status": "offsite_fetched_verified",
"version_id": "1793430889823443"
},
"helm_revision": 19,
"node_request_percent": {
"cpu": 68,
"memory": 76
},
"pid": 3639216,
"postflight": {
"actual_owner_pages_rendered": 40,
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"business_tables": 12,
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"duplicate_slug_groups": 0,
"global_slug_constraint": true,
"migration_0003_applied": true,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"production_identity_or_grant_created": false,
"tenant_slug_constraint": true,
"unsaved_outsider_page_denials": 40
},
"preflight": {
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"business_tables": 12,
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"duplicate_slug_groups": 0,
"global_slug_constraint": true,
"migration_0003_applied": true,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"tenant_slug_constraint": true
},
"private_values_printed": false,
"production_data_restored": false,
"proposal_digest": "sha256:9f1daf6c5fb56b2b4fc9817f28f5ad090c884b0295f7d6f4469e42d48fa8d59f",
"public_health_landing_static_verified": true,
"schema": "coulomb.guarded-image-release.v1",
"snapshot_pin_refreshed": true,
"started_at": "2026-10-31T07:13:45.511369+00:00",
"status": "image_candidate_deployed_verified",
"timers_activated": false
}

View file

@ -1,10 +0,0 @@
{
"schema": "coulomb.live-source-provenance.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"packaged_files": 80,
"all_packaged_source_bytes_match": true,
"packaged_manifest_sha256": "6b5a7b339d88f3c5eafb70a33aa28a7d3972988645b246ae1a92a3f159d72528",
"live_read_only_probe": true,
"production_data_changed": false
}

View file

@ -1,68 +0,0 @@
{
"completed_at": "2026-10-31T00:29:28.113460+00:00",
"elapsed_seconds": 99.527,
"fresh_paired_point": {
"age_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"application": "coulomb-social",
"application_restore_verified": false,
"captured_at": "2026-10-31T00:27:56Z",
"ciphertext_bytes": 2181848,
"ciphertext_sha256": "f7be502c7e122283e70b10d2fd8a2cbf9550d2261192ba11f94d945a9f39af51",
"completed_at": "2026-10-31T00:28:53.504056+00:00",
"content_sha256": "22b694a56178a70274df55bdfc60f2cc0fe24ec66563c2e952058e5d8cf2154a",
"database_sha256": "99e704023d0832aa29dcfd7695dd436dea58038ae48e3ab142d0ec2b916eb574",
"destination": "s3://railiance-platform-pg-backup/platform-pg/application-archives/coulomb-social/2026/10/31/20261031T002756Z-c31b84b48b3874bdaa87cbf5.tar.age",
"encrypted_bytes": 2181848,
"encrypted_sha256": "f7be502c7e122283e70b10d2fd8a2cbf9550d2261192ba11f94d945a9f39af51",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:9a646d8e01a61ba5316d3c2eb0273064e17f2d0300ad07af766ccedda65ecb18",
"immutable_create": true,
"local_archive": "20261031T002756Z-c31b84b48b3874bdaa87cbf5.tar.age",
"object_key": "platform-pg/application-archives/coulomb-social/2026/10/31/20261031T002756Z-c31b84b48b3874bdaa87cbf5.tar.age",
"pause_and_capture_seconds": 56.63,
"remote_retrieval_verified": true,
"schema": "platform.application-primary-archive.v1",
"status": "offsite_fetched_verified",
"version_id": "1793406532815253"
},
"global_constraint_applied": true,
"helm_revision": 18,
"node_request_percent": {
"cpu": 68,
"memory": 76
},
"pid": 2724118,
"postflight": {
"actual_owner_pages_rendered": 40,
"business_rows": 92,
"business_rows_sha256": "b65c4a32d554d741569df5622c09f31423f6c18aa1c4edc5154c4a95e3511508",
"business_tables": 12,
"content_files": 86,
"content_files_sha256": "fd9ea2fa6890ad960e45dff308713ccd1aa303c502dd0ceb0cc26908326216a4",
"duplicate_slug_groups": 0,
"global_slug_constraint": true,
"migration_0003_applied": true,
"production_identity_or_grant_created": false,
"tenant_slug_constraint": true,
"unsaved_outsider_page_denials": 40
},
"preflight": {
"business_rows": 92,
"business_rows_sha256": "b65c4a32d554d741569df5622c09f31423f6c18aa1c4edc5154c4a95e3511508",
"business_tables": 12,
"content_files": 86,
"content_files_sha256": "fd9ea2fa6890ad960e45dff308713ccd1aa303c502dd0ceb0cc26908326216a4",
"duplicate_slug_groups": 0,
"global_slug_constraint": false,
"migration_0003_applied": false,
"tenant_slug_constraint": true
},
"private_values_printed": false,
"production_data_restored": false,
"proposal_digest": "sha256:5fd7ccd8f68057346367d81efb82b48280a16dd31d87683a5bd83e60e3d1837e",
"public_health_landing_static_verified": true,
"schema": "coulomb.guarded-storage-release.v1",
"snapshot_pin_refreshed": true,
"started_at": "2026-10-31T00:27:48.578472+00:00",
"status": "storage_candidate_deployed_verified",
"timers_activated": false
}

View file

@ -1,151 +0,0 @@
# rapp-bounded-executor intake (owner answer to NK-WP-0056-T02)
Status: owner answer from `railiance-apps`, 2026-10-31. Proposal only. Creating
the repository, its Forgejo remote and any live deploy remain founder decisions.
Request: `net-kingdom/docs/proposals/2026-10-31-nk56-t02-owner-requests.md`
(section "railiance-apps"), hub message `41dbcc41`. Founder decision hub
`6d1adce9`: NetKingdom writes a bounded executor runtime (standard
`net-kingdom/canon/standards/bounded-execution-admission_v0.1.md`); a new
`rapp-*` package deploys it in namespace `sso` with ServiceAccount
`nk-bind-executor`.
## Short answer
1. **`railiance-apps` does not create or own the repository.** Under ADR-0015
and the Railiance family contract, a `rapp-*` is its own repository. This
repository (S5) owns shared app-release lessons and the apps it still hosts
(Path C); it is not the factory for rapp repos.
2. **Who creates it:** the founder, by admitting the creation. The tool is
`repo-manager` (`rmgr rapp wrap`), run from a workstation checkout with
`--ownership-repo net-kingdom`. `wrap` writes local files only. Creating
the Forgejo remote (`coulomb/rapp-bounded-executor`) is a separate
founder-run step. Every existing NetKingdom rapp was bootstrapped this way
(for example `rapp-user-engine`, first commit 2026-08-18, "bootstrap managed
package from NetKingdom apply home"). NetKingdom's agent may run `rmgr rapp
wrap` locally once the founder says the repo should exist.
3. **The image is not built by the rapp.** Correction to the request wording
("rapp-bounded-executor builds the image"). The fleet rule is that the
**app repo** builds and publishes the image digest
(`.forgejo/workflows/image.yaml`), and the rapp **pins** that digest.
Here the app repo is `net-kingdom`, unless the executor gets its own source
repository (see founder item F2).
4. **Deploy path:** `kubectl` server-side apply of digest-pinned manifests
through the rapp's Makefile (`render`, `server-dry-run`, `deploy`,
`verify-live`, `rollback`). There is no ArgoCD or other GitOps controller
in this estate. Helm is optional; the default for a new first-party rapp is
`manifest-managed-platform-service`. Live apply is founder-run.
## Conventions that apply (with sources)
| Topic | Convention | Source |
| --- | --- | --- |
| What a rapp is | One Railiance-managed workload; packaging, not ownership | `railiance-master/docs/repository-axes.md`, ADR-0015 |
| Declaration | `declarations/rapp.yaml`, validated against the schema; there is no `register-rapp` command | `railiance-master/schemas/rapp.schema.json`, `railiance-master/docs/adr/ADR-0007-rapp-declaration-contract.md` |
| Repo baseline | `.repo-classification.yaml`, README, INTENT, SCOPE, AGENTS, CLAUDE, LICENSE, Makefile, `declarations/rapp.yaml`, `workplans/`, `workplans/archived/` | `railiance-master/docs/repo-family-bootstrap-contract.md`; `repo-manager/docs/RailianceAppDeploymentGuide.md` section 6 |
| Greenfield path | `rmgr rapp wrap` → human review → CI digest → `rmgr rapp pin-image` → `rmgr rapp place` → operator deploy | Deployment Guide section 0 |
| Ownership split | Code, tests, Containerfile, image build: app repo. Manifests, ServiceAccount, NetworkPolicy, Makefile, smoke, digest pin: rapp. Secret values: OpenBao via platform. | Deployment Guide section 5 |
| Image | Forge registry `forgejo.coulomb.social/coulomb/<image>@sha256:...`; never a tag; check pull with `railiance-apps/tools/check-oci-image.sh` | Deployment Guide sections 0, 9.4; `docs/s5-app-onboarding-checklist.md` |
| Reef binding | `bound_reefs: []` at `declared`; add `reef-railiance` binding in `reef-railiance/bindings/rapps.yaml` only with an explicit substrate decision | Deployment Guide 10.2; `reef-railiance/bindings/rapps.yaml` notes |
| Readiness | `draft` → `declared` → `deployed`/`verified` only with evidence | Deployment Guide section 6 table |
| Exposure | Omit (private). The executor has no Ingress. | Deployment Guide section 4 |
| Closest model | `rapp-user-engine` (manifest-managed, digest pin, `make verify-live`, `make rollback DIGEST=`) | `~/rapp-user-engine` |
## Proposed declaration values
| Field | Proposed value | Why |
| --- | --- | --- |
| `rapp_id` / `repo` | `rapp-bounded-executor` | working name from the request |
| `workload_identity.name` | `bounded-executor` (or `nk-bind-executor`) | must not carry `rapp-` |
| `ownership_repo` | `net-kingdom` | executor runtime is written there |
| `package_type` | `manifest-managed-platform-service` | no existing chart |
| `primary_rail` | `rail-kubernetes` | Job semantics; no scale-to-zero need |
| `bound_reefs` | `[]` until placement is admitted | |
| `data_classification` | `confidential` (consider `restricted`) | it handles directory credentials |
| `criticality` | `high` | it writes identity credentials |
| `runtime_dependencies` | `kubernetes-api`, `forgejo-oci-registry`, `openbao`, `approval-engine`, `lldap` | from the T02 request |
| `secret_references` | the OpenBao paths the secrets-engine answer grants (paths only) | |
| exposure | omitted | |
## Workload shape: Job, not Deployment
The standard says one admission is consumed once, before the first step. A
`Job` per admission (`backoffLimit: 0`, `activeDeadlineSeconds` equal to or
shorter than the admission window, `ttlSecondsAfterFinished`) matches that.
A long-running Deployment would hold OpenBao and directory reach with no
admission in hand. Proposed: the rapp ships a Job template and a founder-run
`make run ADMISSION_ID=<id>` that renders the Job with the pinned digest and the
admission id and applies it. No CronJob.
## Namespace `sso` implications
- The `sso` Namespace object, and its namespace-wide NetworkPolicy
(`net-kingdom/sso-mfa/k8s/network-policies/netpol-sso.yaml`), currently live
in `net-kingdom`'s migration apply home. The rapp must **not** redeclare the
Namespace. It applies only its own objects in `sso`.
- The rapp ships its own pod-scoped NetworkPolicy: egress to the OpenBao
service, LLDAP, approval-engine and DNS only; no ingress.
- `sso` already hosts KeyCape, LLDAP and Authelia. An executor pod there shares
their namespace. It needs its own Pod Security settings (non-root, read-only
root filesystem, no privilege escalation, dropped capabilities) and
`automountServiceAccountToken` only if the Kubernetes Role below needs it.
- A separate namespace would isolate it more. The founder chose `sso`; record
that choice in the rapp's runtime contract.
## ServiceAccount and RBAC ownership
| Object | Owner | Note |
| --- | --- | --- |
| `ServiceAccount nk-bind-executor` (in `sso`) | rapp | per the ownership split |
| `Role` / `RoleBinding` in `sso` (the Kubernetes part of the ceiling) | rapp applies it; **content is set by `net-kingdom`** | the ceiling is NetKingdom canon (BEA standard). The rapp must not widen it. Default: no Kubernetes permissions at all unless a pinned step needs them. |
| OpenBao Kubernetes-auth role bound to `sso/nk-bind-executor` (15-minute TTL) and its policy | `railiance-platform` / `secrets-engine` | answer pending from secrets-engine |
| LLDAP directory account for the executor | NetKingdom / secrets-engine lane | pending |
| Approval consume scope for `service:nk-bind-executor` | approval-engine | pending |
| PDP gate (later) | access-engine | pending |
## Proposed skeleton (not created)
```text
rapp-bounded-executor/
.repo-classification.yaml
README.md INTENT.md SCOPE.md AGENTS.md CLAUDE.md LICENSE
Makefile # check, render, server-dry-run, run ADMISSION_ID=, verify-live, rollback DIGEST=
declarations/rapp.yaml
manifests/
serviceaccount.yaml # nk-bind-executor
role.yaml # ceiling from net-kingdom; empty by default
networkpolicy.yaml # pod-scoped egress allowlist
job.template.yaml # digest placeholder, admission id parameter
docs/runtime-contract.md # identity table, namespace sso decision, smoke, rollback
docs/platform-handoffs.md # OpenBao role, LLDAP account, approval scope
tools/render.py tools/verify_live.sh
tests/ # render tests, no cluster
workplans/ workplans/archived/
```
And in `net-kingdom` (app repo): `Containerfile` for the executor and
`.forgejo/workflows/image.yaml` (fleet workflow) that publishes
`forgejo.coulomb.social/coulomb/bounded-executor@sha256:...`.
## Checklist
1. [ ] Founder: decide the repo should exist (F1) and where the executor source lives (F2).
2. [ ] Founder or NetKingdom agent: `rmgr rapp wrap --path ../rapp-bounded-executor --app bounded-executor --ownership-repo net-kingdom` (local files only).
3. [ ] Founder: create the Forgejo remote `coulomb/rapp-bounded-executor` and push.
4. [ ] NetKingdom: Containerfile and fleet `image.yaml` in the app repo; CI prints a digest.
5. [ ] `rmgr rapp pin-image --digest sha256:...`; `rmgr rapp validate --family-root ..`.
6. [ ] Rapp: ServiceAccount, Role (ceiling from NetKingdom), NetworkPolicy, Job template, Makefile, runtime contract.
7. [ ] Platform owners: OpenBao role and policy, LLDAP account, approval consume scope.
8. [ ] `make server-dry-run` against the cluster (read-only); `check-oci-image.sh` pull check.
9. [ ] Founder: `rmgr rapp place --reef reef-railiance` and a reef binding when the pilot is admitted.
10. [ ] Founder-run first `make run ADMISSION_ID=...` for the T06 pilot; evidence into the rapp.
## Items for the founder
- **F1** Admit creation of `rapp-bounded-executor` (local wrap plus Forgejo remote).
- **F2** Executor source home: inside `net-kingdom` (current decision) or a
separate app repo. If it stays in `net-kingdom`, that repo gains a
Containerfile and an image workflow. That is the fleet pattern, but it is new
for a canon repo.
- **F3** Job (recommended) or Deployment.
- **F4** Confirm `sso` over a dedicated namespace, accepting co-tenancy with KeyCape, LLDAP and Authelia.

View file

@ -3,8 +3,8 @@
image:
repository: forgejo.coulomb.social/coulomb/coulomb-social
tag: "31eaa581a65e"
digest: "sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e"
tag: "17d0eb6"
digest: "sha256:512819463a1902b43a615beee14be7bf97e6a05e016385082b9380692ad1a8cd"
# Public host: app.coulomb.social (parallel to Bubble on apex coulomb.social).
# Apex cutover is deferred until data + self-registration are ready.

View file

@ -1,32 +0,0 @@
{
"schema": "coulomb.attachment-menu-source-validation.v1",
"product_decision": "78175c34-58e1-4ad6-944d-0662c0462ae6",
"full_main_gate": {
"command": "TMPDIR=/var/tmp make check",
"passed": 670,
"failures": 0,
"errors": 0,
"skipped": 0,
"log_sha256": "357547d34f7d73f750721338cff3e07439e8c710d0f1cf838541c1b175268335"
},
"isolated_release_gate": {
"source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"command": "make check",
"passed": 568,
"failures": 0,
"errors": 0,
"skipped": 0,
"log_sha256": "d9a9c8883f0d4021918c8600f9b5055cac24ca6b9943ee89db067f55d65ccdb1"
},
"checks": [
"Author upload/remove; authorized reader download; foreign-tenant, outsider, revoked, archived and anonymous denial",
"Stale page and CSRF refusal; immutable file names; 16 MiB limit; traversal and symlink denial",
"Retained body/source dates and associations through edit/rename; removal keeps historical revision bytes",
"Independent copy/move associations and managed files through 14 abrupt process deaths",
"Upload recovery at partial bytes, complete bytes, stored revision and published page",
"Real loopback browser upload/download/copy/move/remove and permission checks; no external requests"
],
"synthetic_fixtures_only": true,
"production_deployed": false,
"productive_user_acceptance": false
}

View file

@ -1,371 +0,0 @@
{
"schema": "coulomb.backup-installation-independent-postflight.v1",
"verified_at": "2026-10-31T17:30:18.219708+00:00",
"status": "installed_files_and_inactive_units_verified",
"proposal_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"receipt_sha256": "96329afbd5662f71bf6d6b05c003f0810be12c10036f9cadb41cc373d3a1108b",
"receipt": {
"schema": "coulomb.backup-source-supervised-installation.v1",
"proposal_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"status": "sources_installed_units_inactive_verified",
"preflight": {
"units": {
"coulomb-social-paired-backup.service": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-paired-backup.timer": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-backup-freshness.service": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-backup-alert@coulomb-social-paired-backup.service.service": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
}
},
"capacity": {
"state_bytes": 11259904,
"state_reserve_bytes": 7532969984,
"disk_reserve_bytes": 8606711808,
"free_bytes": 115579949056,
"free_inodes": 24523113,
"filesystem_blocks_reserved": false
},
"sdk": {
"boto3": "1.40.18",
"botocore": "1.40.76"
},
"route": {
"helm_revision": 6,
"runtime_and_complete_resources_verified": true
}
},
"timers_activated": false,
"capture_executed": false,
"email_sent": false,
"retained_data_deleted": false,
"started_at": "2026-10-31T17:22:48.757530+00:00",
"capacity_profile": {
"maximum_new_file_bytes": 1073741824,
"state_budget_bytes": 8589934592,
"minimum_free_bytes": 8589934592,
"minimum_free_inodes": 1024,
"control_margin_bytes": 16777216
},
"founder_confirmed_profile_and_installation": true,
"route_postflight": {
"helm_revision": 6,
"runtime_and_complete_resources_verified": true
},
"verified_targets": 19,
"units": {
"coulomb-social-paired-backup.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.service",
"UnitFileState": "static"
},
"coulomb-social-paired-backup.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-freshness.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.service",
"UnitFileState": "static"
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-alert@coulomb-social-paired-backup.service.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-alert@.service",
"UnitFileState": "static"
}
},
"updated_at": "2026-10-31T17:22:54.560675+00:00"
},
"nested_receipt_sha256": "795d9eb672b24495c77ad636a210c5d2022c8c3124d276920db7eda02257e519",
"verified_targets": 19,
"installed_fingerprints": {
"/opt/coulomb-social-backup/paired-backup.py": {
"exists": true,
"sha256": "d161c742d1a6a182460a57d0a1719591ab58fc94006f55169ad3d74442a93630",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 534009,
"device": 2049,
"mtime_ns": 1793467368826077309
},
"/opt/coulomb-social-backup/snapshot-content-and-db.py": {
"exists": true,
"sha256": "dcc8dd2a3989f279597595f9260b31b24fcc9b6dc787f04c17ef0491c53d830d",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549255,
"device": 2049,
"mtime_ns": 1793430923413704430
},
"/opt/coulomb-social-backup/mirror-paired-backup.py": {
"exists": true,
"sha256": "9ceb26d9083af016c4b787907e4dce7bdf437c782fb2d15eb28d9e334e6e431c",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549201,
"device": 2049,
"mtime_ns": 1793467368831077393
},
"/opt/coulomb-social-backup/check-paired-backup-health.py": {
"exists": true,
"sha256": "2d40ec6e4c59ea7fe1d46065d197b9a87ca6811f023cc6f3e20e4184a3490566",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549309,
"device": 2049,
"mtime_ns": 1793467368836077477
},
"/opt/coulomb-social-backup/backup_capacity.py": {
"exists": true,
"sha256": "cb699a79e67b129239b5aa5d6f3b0d4ffaa9773a8b073227ad17fdecb5b9d893",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549354,
"device": 2049,
"mtime_ns": 1793467368843077594
},
"/opt/coulomb-social-backup/mirror-platform-runtime.json": {
"exists": true,
"sha256": "9253c5f6e956b67f499d3e12d2851be7fabd3bc56b00496b8810bbd0be8209f1",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549355,
"device": 2049,
"mtime_ns": 1793467368847077662
},
"/opt/coulomb-social-backup/backup_alerts.py": {
"exists": true,
"sha256": "07522437d4276b92f0a44149adc6c9e81bb18dbe59ce0f1f9e58a48347700d0e",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549359,
"device": 2049,
"mtime_ns": 1793467368887078332
},
"/opt/coulomb-social-backup/notify-backup-alert.py": {
"exists": true,
"sha256": "0bd53bc5ad22d8bcb0326fb18a17737744b06416fe785dad077308e45f051d5a",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549360,
"device": 2049,
"mtime_ns": 1793467368891078399
},
"/opt/coulomb-social-backup/observe-backup-alerts.py": {
"exists": true,
"sha256": "17caf4fa65283242f618b039ff1d018801c9890ea2a9178912cbdd4b50ee2664",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549361,
"device": 2049,
"mtime_ns": 1793467368895078466
},
"/opt/railiance-platform/scripts/application_recovery_identities.py": {
"exists": true,
"sha256": "20f56255ed6eeec4aafe33f142bc3ee03f623d4957a7b0cabb741d340f15f79d",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549356,
"device": 2049,
"mtime_ns": 1793467368852077745
},
"/opt/railiance-platform/scripts/application_recovery_mirror.py": {
"exists": true,
"sha256": "d48ab95e89b9eeae36269d853ebe4c44c22e1f57d4e14224f03d0b9aeeb34178",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549357,
"device": 2049,
"mtime_ns": 1793467368857077829
},
"/opt/railiance-platform/scripts/application_recovery_resources.py": {
"exists": true,
"sha256": "ab70ec341e738272730eb0daf76840d0bca807caeb3c4e4c2357f162fbed4498",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549358,
"device": 2049,
"mtime_ns": 1793467368862077913
},
"/opt/railiance-platform/scripts/primary_application_archive.py": {
"exists": true,
"sha256": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 540610,
"device": 2049,
"mtime_ns": 1791537447437616251
},
"/etc/systemd/system/coulomb-social-backup-freshness.service": {
"exists": true,
"sha256": "8d6278c2cbca7f48b659c239c1d1e181fa4b9cf023fe7429850e294c6cd84d0e",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19366,
"device": 2049,
"mtime_ns": 1793467368868078014
},
"/etc/systemd/system/coulomb-social-paired-backup.service": {
"exists": true,
"sha256": "8b01b788bb08f453fdd4807104185c89411e0b0b4dedee9240f14f110ceb5513",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 14867,
"device": 2049,
"mtime_ns": 1793467368873078098
},
"/etc/systemd/system/coulomb-social-backup-freshness.timer": {
"exists": true,
"sha256": "75d1d0721c07fdd0703910c06bb8a678396440e7d95411a37ee7de4938f3ac31",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19367,
"device": 2049,
"mtime_ns": 1793467368878078181
},
"/etc/systemd/system/coulomb-social-paired-backup.timer": {
"exists": true,
"sha256": "5e87235e66f89a64a972562d6f163f62420628fc44fb7fd8d603a96c347dfbb9",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19368,
"device": 2049,
"mtime_ns": 1793467368882078248
},
"/etc/systemd/system/coulomb-social-backup-alert@.service": {
"exists": true,
"sha256": "4bfa019d29b1d0de278f03553602a5e824de50ed99ebcf3b5035cf4d5b06fe98",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19370,
"device": 2049,
"mtime_ns": 1793467368899078533
},
"/etc/coulomb-social-backup/alerting.env": {
"exists": true,
"sha256": "509844b5c8ef618b812d52f32e19c3c559623636dca62f7b16f437aa90cc0458",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 19369,
"device": 2049,
"mtime_ns": 1793467368904078617
}
},
"units": {
"coulomb-social-paired-backup.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.service",
"UnitFileState": "static"
},
"coulomb-social-paired-backup.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-freshness.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.service",
"UnitFileState": "static"
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-alert@coulomb-social-paired-backup.service.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-alert@.service",
"UnitFileState": "static"
}
},
"route": {
"helm_revision": 6,
"runtime_and_complete_resources_verified": true
},
"capacity": {
"state_bytes": 11259904,
"state_reserve_bytes": 7532969984,
"disk_reserve_bytes": 8606711808,
"free_bytes": 115555618816,
"free_inodes": 24523041,
"filesystem_blocks_reserved": false
},
"sdk": {
"boto3": "1.40.18",
"botocore": "1.40.76"
},
"runtime_modified_by_verification": false
}

View file

@ -1,29 +0,0 @@
{
"schema": "coulomb.backup-route-independent-postflight.v1",
"verified_at": "2026-10-31T17:19:36.926769+00:00",
"status": "durable_receipt_and_live_route_verified",
"execution_digest": "sha256:4d8481061dc9ce6835169defc96887945052332a0db8d4234ae84032d63cc328",
"receipt": {
"schema": "rapp-telemetry.backup-route-execution.v1",
"execution_digest": "sha256:4d8481061dc9ce6835169defc96887945052332a0db8d4234ae84032d63cc328",
"proposal_digest": "sha256:4bcad54f7b8e1e77b94112e452cbb58eaf8e882dc10305129c5f9ca69f014a66",
"status": "backup_email_route_deployed_verified",
"timers_activated": false,
"notification_sent_by_helper": false,
"production_data_restored": false,
"started_at": "2026-10-31T17:17:13.743344+00:00",
"helm_revision": 6,
"verified_resource_count": 87,
"after_resources_sha256": "600c4998e54b8e11845849c7d8e4c6b6699556c21f5df6ca79bb86b2e8d1683f",
"live_desired_fields_verified": true,
"runtime_config_verified": true,
"existing_image_and_pvc_preserved": true,
"completed_at": "2026-10-31T17:17:31.488654+00:00"
},
"receipt_sha256": "c26d636f59109956f281ad46f4885c4db800a9553cf05cac324aa3155ef7ac40",
"original_execution_packet_matches": true,
"live_desired_fields_verified": true,
"runtime_config_verified": true,
"existing_image_and_pvc_preserved": true,
"runtime_modified_by_verification": false
}

View file

@ -1,45 +0,0 @@
{
"schema": "coulomb.content-acceptance-build.v1",
"completed_at": "2026-10-31T18:38:08.525103+00:00",
"source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"build_context": "clean restricted git archive",
"source_full_gate_tests": 568,
"runtime_packages_and_python_unchanged": true,
"runtime": {
"python": "3.12.16",
"distributions": {
"h11": "0.16.0",
"httpcore": "1.0.9",
"psycopg": "3.3.4",
"joserfc": "1.7.4",
"anyio": "4.14.2",
"cryptography": "50.0.0",
"idna": "3.18",
"certifi": "2026.7.22",
"packaging": "26.3",
"python-decouple": "3.8",
"psycopg-binary": "3.3.4",
"sqlparse": "0.5.5",
"whitenoise": "6.12.0",
"cffi": "2.1.1",
"markdown": "3.10.3",
"webencodings": "0.5.1",
"pycparser": "3.0",
"bleach": "6.4.0",
"authlib": "1.7.2",
"django": "6.1",
"typing_extensions": "4.16.0",
"gunicorn": "26.0.0",
"asgiref": "3.12.1",
"httpx": "0.28.1",
"dj-database-url": "3.1.2"
}
},
"django_checks": {
"check": "System check identified no issues (0 silenced).",
"makemigrations": "No changes detected"
},
"new_database_migrations": false,
"production_deployed": false
}

View file

@ -1,11 +0,0 @@
{
"schema": "coulomb.packaged-source-provenance.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"packaged_file_count": 79,
"all_packaged_source_bytes_match": true,
"source_revision_label_verified": true,
"registry_digest_resolves": true,
"application_source_overlay": false,
"manifest_sha256": "2eca0618df5bdf35928869c3b848be36190065a4cca8f855bba372df6c516556"
}

View file

@ -1,67 +0,0 @@
{
"schema": "coulomb.packaged-content-acceptance-recovery.v1",
"status": "packaged_recovered_export_and_views_verified",
"source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"restore_receipt_sha256": "3d6fe0b5d7426c9fb39ba22f18770319e0c89ba1981c61db171199d3b4e68524",
"retained_point_captured_at": "2026-10-31T07:13:52Z",
"candidate_application": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"previous_image_application": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"client_export": {
"status": "recovered_client_export_verified",
"schema": "coulomb.client-dataset-export.v1",
"content_files": 85,
"records": {
"members.user": 1,
"members.member": 1,
"spaces.space": 1,
"spaces.spacemembership": 1
},
"admin_events": 0,
"archive_sha256": "eb982edcdb94c976ab3d4e9797e4c34eb72a3ee3886a37e64508744ac172a8a8",
"offboarding_complete": false,
"all_source_tables_compared": 13,
"all_source_files_compared": 86,
"archive_member_hashes_verified": true,
"selected_client_content_complete_locally": true,
"source_sql_and_content_unchanged": true,
"external_bindings_require_review": 0,
"sessions_and_credentials_excluded": true
},
"source_content_files_unchanged": 86,
"all_tables_unchanged": true,
"application_source_overlay": false,
"network_internal": true,
"published_ports": 0,
"production_access": false,
"production_restore": false,
"driver_sha256": "da85e5f7d5cf68f599a897a932d51399340bdd026a7cddf9603bef4aeb40909a"
}

View file

@ -1,21 +0,0 @@
{
"baseline_revision": 19,
"baseline_helm_manifest_sha256": "93cb277abd1aea0657be482e458dcfb268fe0bfbd45d90aa1faedcc7f5bce499",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"baseline_spec_sha256": "42e091e52d5dae3c1f986e4898c62057fa80846adfce049a75d8fbd4681180ea",
"candidate_spec_sha256": "8d79c64cff4bd2c62f03494e80847dc99b965ddabf35645da67e8d1020220798",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"expected_data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"image_only_server_preview": true
}

View file

@ -1,13 +0,0 @@
{
"schema": "coulomb.packaged-content-acceptance-tests.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"tests": 110,
"failures": 0,
"errors": 0,
"skipped": 0,
"network": "none",
"read_only_root": true,
"application_source_overlay": false,
"synthetic_fixtures_only": true
}

View file

@ -1,25 +0,0 @@
{
"schema": "coulomb.packaged-content-lifecycle-tests.v1",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"image_id": "sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"tests": 29,
"failures": 4,
"expected_baseline_regressions": true,
"failed_nodes": [
"test_process_death_during_copy_or_move_is_recoverable[copy_page-during_first_asset]",
"test_process_death_during_copy_or_move_is_recoverable[copy_page-during_second_asset]",
"test_process_death_during_copy_or_move_is_recoverable[transfer_page-during_first_asset]",
"test_process_death_during_copy_or_move_is_recoverable[transfer_page-during_second_asset]"
],
"errors": 0,
"skipped": 0,
"network": "none",
"read_only_root": true,
"application_source_overlay": false,
"test_tooling_injected": true,
"application_modules_from_image_verified": true,
"production_access": false,
"junit_sha256": "edc52bd3a321d028d255b3d478020b3383d94747957ffe2985583b1f0741cb85",
"driver_sha256": "85b65114997c7e7c5323cb77a0043e495ec132506eef07dd394c6a6361380d36",
"test_source_sha256": "84a25a22a3cbda397e39c0508db8ea5aa90e6c467ccfa7da2b568d174d1ec449"
}

View file

@ -1,61 +0,0 @@
{
"changed_columns": {
"django_session": [
"session_key",
"session_data",
"expire_date"
],
"members_member": [
"updated_at",
"last_login_at"
],
"members_user": [
"last_login"
]
},
"file_changes": [],
"retained_fingerprint": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"schema": "coulomb.content-release-row-drift.v1",
"changed_tables": [
{
"table": "django_session",
"retained_rows": 42,
"current_rows": 43,
"retained_sha256": "c958e33ec782f9f2fd1b3cceba4a64da0038fde51050f25905ae42de91ca6dde",
"current_sha256": "594e246ef6297d9be9b6e8d9eda076a5b2ab36afb9263606b719f64f51293ba6"
},
{
"table": "members_member",
"retained_rows": 1,
"current_rows": 1,
"retained_sha256": "4d465d2b9d1e6311e505f861f2ed4b67763a545a965f9a7d0c586a3d07e3e9a3",
"current_sha256": "ab82b3f2c5e49f8634c598c9642894747f4b6fcff0f5230ac27f41939feb8640"
},
{
"table": "members_user",
"retained_rows": 1,
"current_rows": 1,
"retained_sha256": "81ccb3a40191e910a68c101896df518a588c00231728934c4c900577f8ae4f12",
"current_sha256": "0fc7a71b4b80a71fbedce527bbd2cae3858cf6a062e5714fc231be13ff987256"
}
],
"all_other_business_tables_equal": true,
"migration_history_equal": true,
"content_equal": true,
"retained_point": "2026-10-31T07:13:52Z",
"current_business_rows": 93,
"current_business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"private_row_values_printed": false,
"production_changes": false
}

View file

@ -1,58 +0,0 @@
{
"schema": "coulomb.content-lifecycle-validation.v1",
"recorded_at": "2026-10-31T11:54:24.215512+00:00",
"status": "source_fix_verified",
"workplan_task": "CSOC-WP-0013-T05",
"bug": "A process exit during attachment creation left bytes absent from the copy/move cleanup journal; the orphan blocked retry.",
"regression_observed_before_fix": {
"baseline": "f70708839cd5ca43310f6891c8d94aaff915139c",
"operations": [
"copy_page",
"transfer_page"
],
"interruption": "partial first attachment flushed, immediate os._exit(86)",
"result": "both failed because the partial destination survived recovery"
},
"fix": [
"Refuse existing attachment entries before recording cleanup authority.",
"Persist intended new attachment name before exclusive creation under the content writer lock.",
"Flush recovery and attachment directory entries before destination publication."
],
"focused_cases": {
"total": 29,
"abrupt_child_process_exit": 14,
"existing_destination_collision": 8,
"prior_retention_and_recovery": 7
},
"full_gate": {
"command": "make check",
"tests": 546,
"failures": 0,
"errors": 0,
"skipped": 0,
"warnings": 69,
"junit_sha256": "dd3d0433c8109f00f6dddd119cfdf8281915f94da2da1f5e6009c31cfe76c65b",
"log_sha256": "eb59a394c95c5307c17069874640d1655ef61c5aa7bb426ef6d21db4929f748e"
},
"files": [
{
"path": "coulomb_social/apps/spaces/pageops.py",
"sha256": "055ef25b5efc75798cf17ffa68739de4d4099d2cab4d041e7c7eacdfaf43803e"
},
{
"path": "tests/test_content_recovery.py",
"sha256": "84a25a22a3cbda397e39c0508db8ea5aa90e6c467ccfa7da2b568d174d1ec449"
}
],
"policy": "User accepted retain-all default and separately reviewed manual cutoff; keep live page and all history of deleted pages.",
"live_purge_authorized": false,
"live_purge_executed": false,
"production_deployed": false,
"productive_acceptance": false,
"limits": [
"Child process termination on synthetic local files is proved; physical power-loss durability is not experimentally proved.",
"Cooperating application/import writers must use the content writer lock.",
"Release delivery and productive copy/move review remain open."
],
"policy_decision_id": "c3a191f2-ce06-483f-82d7-ef8c54ea0d5e"
}

View file

@ -1,42 +0,0 @@
{
"schema": "coulomb.ordered-list-fidelity.v1",
"verified_at": "2026-10-31T17:20:32.943192+00:00",
"source_articles_sha256": "f33967c79c0f8a60a7d504f5d5e4082f8bc9e3c34f6a3160cb200fd380831d62",
"prior_audit_sha256": "3926e24a3b903f5e1d1c7133dc5f9df1e958183432c5131949ce838eb60acf1e",
"current_audit_sha256": "d8f382e24d7adfe3c43dc71f32f8f6e647bf68239cbcdc6769a6c8fb85d666b9",
"records": 245,
"rendered_cards_verified": 242,
"source_bodies_unchanged": true,
"missing_bodies_retained": 3,
"ordered_list_starts_restored": 15,
"affected_records": 4,
"markup_change_cases_before": 6,
"markup_change_cases_after": 3,
"remaining_removed_tags": {
"topic": 3
},
"remaining_removed_attributes": [
{
"tag": "topic",
"attribute": "name",
"count": 2
}
],
"private_review_directory": "~/.config/coulomb-social/auth/exports/rendering-review-20261031-numbering",
"source_hashes": {
"coulomb_social/apps/spaces/content.py": "5d6bb5c800b3e776fff385fa73284f4916403676dc2a8bc06b8fadc7d2387633",
"tests/test_rendering_audit.py": "ae092753f4d1d006bb88f1ce11581975c105c5231819f9409ddaaf2fc83d32f5"
},
"validation": {
"focused_passed": 14,
"full_gate_passed": 650,
"full_gate_warnings": 69,
"failures": 0,
"errors": 0,
"skipped": 0,
"full_gate_seconds": 91.85
},
"production_deployed": false,
"original_bubble_render_compared": false,
"productive_fidelity_accepted": false
}

View file

@ -1,175 +0,0 @@
#!/usr/bin/env python3
"""Node-side quiesced coulomb-social snapshot. Binary output stays private.
Run on railiance01 after reviewed live approval. Does not restore production.
Default is server dry-run; --execute briefly pauses the app and captures a
paired pg_dump/content archive. A separate isolated restore must validate it.
"""
from __future__ import annotations
import argparse
import fcntl
import hashlib
import json
import os
import signal
import stat
import subprocess
import sys
import time
from pathlib import Path
NS = 'coulomb-social'
IMAGE = ('forgejo.coulomb.social/coulomb/coulomb-social@sha256:'
'7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5')
CLUSTER_UID = 'a553c742-0115-43d4-99a4-a5ca56fe0786'
LOCK_PATH = Path('/var/lib/coulomb-social-backup/snapshot.lock')
class Refused(RuntimeError):
pass
def run(args: list[str], *, payload: bytes | None = None, timeout: int = 180) -> bytes:
p = subprocess.run(args, input=payload, capture_output=True, timeout=timeout)
if p.returncode:
raise Refused('command_failed')
return p.stdout
def k(*args: str, payload: bytes | None = None) -> bytes:
return run(['kubectl', *args], payload=payload)
def document(*args: str) -> dict:
return json.loads(k(*args, '-o', 'json'))
def private_write(path: Path, value: bytes) -> None:
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, 'wb') as f:
f.write(value)
def snapshot() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--execute', action='store_true')
parser.add_argument('--destination', type=Path, required=True)
args = parser.parse_args()
os.environ['KUBECONFIG'] = '/etc/rancher/k3s/k3s.yaml'
started = time.monotonic()
if document('get', 'namespace', 'kube-system')['metadata']['uid'] != CLUSTER_UID:
raise Refused('wrong_cluster')
dep = document('get', 'deployment', 'coulomb-social', '-n', NS)
spec = dep['spec']['template']['spec']
if dep['spec']['replicas'] != 1 or spec['containers'][0]['image'] != IMAGE:
raise Refused('unexpected_release')
if document('get', 'pvc', 'coulomb-social-content', '-n', NS)['status']['phase'] != 'Bound':
raise Refused('pvc_not_bound')
cluster = document('get', 'cluster', 'apps-pg', '-n', 'databases')
primary = cluster['status']['currentPrimary']
name = 'csoc-paired-snapshot-' + time.strftime('%Y%m%d%H%M%S', time.gmtime())
pod = {
'apiVersion': 'v1', 'kind': 'Pod',
'metadata': {'name': name, 'namespace': NS, 'labels': {'csoc-recovery': name}},
'spec': {
'restartPolicy': 'Never', 'automountServiceAccountToken': False,
'securityContext': {'runAsNonRoot': True, 'runAsUser': 10001,
'runAsGroup': 10001, 'fsGroup': 10001,
'fsGroupChangePolicy': 'OnRootMismatch'},
'containers': [{'name': 'snapshot', 'image': IMAGE,
'command': ['python', '-c', 'import time;time.sleep(1800)'],
'resources': {'requests': {'cpu': '10m', 'memory': '64Mi'},
'limits': {'cpu': '100m', 'memory': '256Mi'}},
'securityContext': {'allowPrivilegeEscalation': False,
'readOnlyRootFilesystem': True,
'capabilities': {'drop': ['ALL']}},
'volumeMounts': [{'name': 'content', 'mountPath': '/snapshot', 'readOnly': True}]}],
'volumes': [{'name': 'content', 'persistentVolumeClaim':
{'claimName': 'coulomb-social-content', 'readOnly': True}}],
},
}
body = json.dumps(pod).encode()
k('create', '--dry-run=server', '-f', '-', payload=body)
if not args.execute:
print(json.dumps({'status': 'reviewed', 'server_dry_run': True,
'image_pinned': True, 'pvc_read_only': True,
'db_scope': 'coulomb_social_db', 'replicas_restored_to': 1}))
return 0
dest = args.destination
if not dest.is_absolute() or dest.exists():
raise Refused('destination_must_be_new_absolute_directory')
dest.mkdir(mode=0o700)
paused = False
created = False
receipt = {'status': 'incomplete', 'app': 'coulomb-social',
'database': 'coulomb_social_db', 'image': IMAGE,
'started_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
try:
paused = True
k('scale', 'deployment/coulomb-social', '-n', NS, '--replicas=0')
k('wait', '--for=delete', 'pod', '-n', NS,
'-l', 'app.kubernetes.io/instance=coulomb-social', '--timeout=120s')
created = True
k('create', '-f', '-', payload=body)
k('wait', '--for=condition=Ready', 'pod/' + name, '-n', NS, '--timeout=120s')
dump = k('exec', '-n', 'databases', primary, '-c', 'postgres', '--',
'pg_dump', '-U', 'postgres', '-d', 'coulomb_social_db', '-Fc')
if not dump.startswith(b'PGDMP'):
raise Refused('invalid_pg_dump')
private_write(dest / 'database.dump', dump)
archive_code = ('import io,sys,tarfile; b=io.BytesIO(); '
't=tarfile.open(fileobj=b,mode="w:gz"); '
't.add("/snapshot",arcname="content"); '
't.close();sys.stdout.buffer.write(b.getvalue())')
content = k('exec', '-n', NS, name, '--', 'python', '-c', archive_code)
private_write(dest / 'content.tar.gz', content)
receipt.update(status='captured', writers_quiesced=True,
database_sha256=hashlib.sha256(dump).hexdigest(),
content_sha256=hashlib.sha256(content).hexdigest(),
database_bytes=len(dump), content_bytes=len(content))
finally:
try:
if created:
k('delete', 'pod', name, '-n', NS, '--wait=true', '--timeout=120s')
finally:
if paused:
k('scale', 'deployment/coulomb-social', '-n', NS, '--replicas=1')
k('rollout', 'status', 'deployment/coulomb-social', '-n', NS, '--timeout=180s')
receipt['app_resumed'] = True
receipt['elapsed_seconds'] = round(time.monotonic() - started, 2)
private_write(dest / 'receipt.json', json.dumps(receipt, indent=2).encode())
print(json.dumps(receipt))
return 0
def main() -> int:
if '--execute' not in sys.argv:
return snapshot()
LOCK_PATH.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
parent = LOCK_PATH.parent.lstat()
if (not stat.S_ISDIR(parent.st_mode) or parent.st_uid != os.geteuid()
or parent.st_mode & 0o077):
raise Refused('lock_directory_not_private')
fd = os.open(LOCK_PATH, os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600)
with os.fdopen(fd, 'w') as lock:
try:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
raise Refused('snapshot_already_running') from None
def terminate(signum, frame):
raise Refused('snapshot_interrupted')
previous = signal.signal(signal.SIGTERM, terminate)
try:
return snapshot()
finally:
signal.signal(signal.SIGTERM, previous)
if __name__ == '__main__':
try:
sys.exit(main())
except Exception as exc:
# Never expose child output, kubectl objects, credentials or raw exception messages.
print(json.dumps({'status': 'failed', 'failure_type': type(exc).__name__}))
sys.exit(1)

View file

@ -1,50 +0,0 @@
# Production overrides for coulomb-social.
# Non-secret values only. Secrets live in K8s Secret coulomb-social-env.
image:
repository: forgejo.coulomb.social/coulomb/coulomb-social
tag: "1139a6d30eee"
digest: "sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5"
# Public host: app.coulomb.social (parallel to Bubble on apex coulomb.social).
# Apex cutover is deferred until data + self-registration are ready.
env:
DJANGO_SETTINGS_MODULE: coulomb_social.settings.prod
ALLOWED_HOSTS: app.coulomb.social,localhost
CSRF_TRUSTED_ORIGINS: https://app.coulomb.social
CONTENT_ROOT: /app/var/content
DEFAULT_TENANT_ID: "tenant:coulomb"
OIDC_ENABLED: "true"
OIDC_ISSUER: https://kc.coulomb.social
OIDC_CLIENT_ID: coulomb-social
OIDC_REDIRECT_URI: https://app.coulomb.social/auth/callback/
OIDC_SCOPES: "openid profile email groups"
USER_ENGINE_BASE_URL: https://users.coulomb.social
USER_ENGINE_APPLICATION_ID: coulomb-social
USER_ENGINE_EXPECTED_AUDIENCE: user-engine-portal
NETKINGDOM_REGISTRATION_URL: https://users.92-205-62-239.nip.io/register
probes:
hostHeader: app.coulomb.social
path: /healthz
# One writable local-path volume; Recreate prevents concurrent old/new writers.
replicaCount: 1
deploymentStrategy: Recreate
persistence:
content:
enabled: true
storageClass: local-path
size: 2Gi
mountPath: /app/var/content
retain: true
# Wave-2 right-sizing (CSOC-WP-0017-T01, 2026-10-21 node budget): 7d p95
# 0.4m CPU / 146Mi. Limits stay at the chart defaults (1000m/1Gi).
resources:
requests:
cpu: 15m
memory: 176Mi
limits:
cpu: 1000m
memory: 1Gi

View file

@ -1,25 +0,0 @@
{
"schema": "coulomb.packaged-content-lifecycle-tests.v1",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"image_id": "sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"tests": 29,
"failures": 4,
"expected_baseline_regressions": true,
"failed_nodes": [
"test_process_death_during_copy_or_move_is_recoverable[copy_page-during_first_asset]",
"test_process_death_during_copy_or_move_is_recoverable[copy_page-during_second_asset]",
"test_process_death_during_copy_or_move_is_recoverable[transfer_page-during_first_asset]",
"test_process_death_during_copy_or_move_is_recoverable[transfer_page-during_second_asset]"
],
"errors": 0,
"skipped": 0,
"network": "none",
"read_only_root": true,
"application_source_overlay": false,
"test_tooling_injected": true,
"application_modules_from_image_verified": true,
"production_access": false,
"junit_sha256": "edc52bd3a321d028d255b3d478020b3383d94747957ffe2985583b1f0741cb85",
"driver_sha256": "85b65114997c7e7c5323cb77a0043e495ec132506eef07dd394c6a6361380d36",
"test_source_sha256": "84a25a22a3cbda397e39c0508db8ea5aa90e6c467ccfa7da2b568d174d1ec449"
}

View file

@ -1,119 +0,0 @@
{
"schema": "coulomb.content-lifecycle-candidate-build.v1",
"completed_at": "2026-10-31T11:58:26.697591+00:00",
"source": "f306dbfa2604e4815523667740be2925c333b84e",
"tag": "forgejo.coulomb.social/coulomb/coulomb-social:f306dbfa2604",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec",
"registry_digest_independently_verified": true,
"source_revision_label_verified": true,
"build_context": "Clean git archive restricted to Dockerfile, dockerignore, lock, project, manage.py, app and entrypoint.",
"build_inputs": [
{
"path": "Dockerfile",
"sha256": "d0e197a18db8980eb3e51cca842d693e10ab0b4208627bba28691d10719d4a00"
},
{
"path": ".dockerignore",
"sha256": "901c8b95d95549d0e78c1c3d6d0538bf0252c8a77e9409129e0cadfa55c7c56c"
},
{
"path": "pyproject.toml",
"sha256": "5758c56fd1be89b973861ccc5ecbadb495e742ee13ebd7e19a221a0f119c54ee"
},
{
"path": "uv.lock",
"sha256": "e8ebb6fc4b5abd1ac80f1c9012f1983642d0528a8a213cfcc394261606fad887"
},
{
"path": "scripts/docker-entrypoint.sh",
"sha256": "70100256ca41ae6afe77078c810a8b6012472f0a741919f403f32088f98ab463"
}
],
"runtime": {
"previous": {
"python": "3.12.16",
"distributions": {
"h11": "0.16.0",
"httpcore": "1.0.9",
"psycopg": "3.3.4",
"joserfc": "1.7.4",
"anyio": "4.14.2",
"cryptography": "50.0.0",
"idna": "3.18",
"certifi": "2026.7.22",
"packaging": "26.3",
"python-decouple": "3.8",
"psycopg-binary": "3.3.4",
"sqlparse": "0.5.5",
"whitenoise": "6.12.0",
"cffi": "2.1.1",
"markdown": "3.10.3",
"webencodings": "0.5.1",
"pycparser": "3.0",
"bleach": "6.4.0",
"authlib": "1.7.2",
"django": "6.1",
"typing_extensions": "4.16.0",
"gunicorn": "26.0.0",
"asgiref": "3.12.1",
"httpx": "0.28.1",
"dj-database-url": "3.1.2"
}
},
"candidate": {
"python": "3.12.16",
"distributions": {
"h11": "0.16.0",
"httpcore": "1.0.9",
"psycopg": "3.3.4",
"joserfc": "1.7.4",
"anyio": "4.14.2",
"cryptography": "50.0.0",
"idna": "3.18",
"certifi": "2026.7.22",
"packaging": "26.3",
"python-decouple": "3.8",
"psycopg-binary": "3.3.4",
"sqlparse": "0.5.5",
"whitenoise": "6.12.0",
"cffi": "2.1.1",
"markdown": "3.10.3",
"webencodings": "0.5.1",
"pycparser": "3.0",
"bleach": "6.4.0",
"authlib": "1.7.2",
"django": "6.1",
"typing_extensions": "4.16.0",
"gunicorn": "26.0.0",
"asgiref": "3.12.1",
"httpx": "0.28.1",
"dj-database-url": "3.1.2"
}
},
"runtime_packages_equal": true,
"python_versions_equal": true,
"django_check": {
"returncode": 0,
"output": "System check identified no issues (0 silenced)."
},
"migration_drift": {
"returncode": 0,
"output": "No changes detected"
}
},
"source_delta_from_revision_19": [
"coulomb_social/apps/spaces/pageops.py"
],
"new_database_migrations": false,
"production_deployed": false,
"live_release_pins_modified": false,
"source_full_gate_tests": 546,
"packaged_lifecycle_tests": 29,
"previous_image_expected_lifecycle_failures": 4,
"owner_release_task": "RAPPS-WP-0015-T07",
"remaining": [
"Exact current-target release packet, paired rollback evidence and candidate/previous-image restored-store checks.",
"Attended image release and independent native postflight.",
"Productive lifecycle verdict; retention policy already accepted under c3a191f2-ce06-483f-82d7-ef8c54ea0d5e."
]
}

View file

@ -1,20 +0,0 @@
{
"schema": "coulomb.packaged-source-provenance.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec",
"network": "none",
"read_only_root": true,
"entrypoint_bypassed": true,
"database_contact": false,
"production_changes": false,
"comparisons": [
{
"commit": "f306dbfa2604e4815523667740be2925c333b84e",
"packaged_file_count": 80,
"source_file_count": 80,
"different_files": 0,
"all_packaged_source_bytes_match": true
}
],
"actual_packaged_manifest_sha256": "b5c8a16b4b3d30cc9d8a7a9f3ed61bd8cb0e182589aceb5e4127fff27a8ae482",
"dependency_or_build_reproducibility_proved": false
}

View file

@ -1,65 +0,0 @@
{
"schema": "coulomb.packaged-content-lifecycle-recovery.v1",
"status": "packaged_recovered_client_export_and_views_verified",
"source": "f306dbfa2604e4815523667740be2925c333b84e",
"image_id": "sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec",
"restore_receipt_sha256": "966d6640e42e2f4940c66d1cd5c8a802cd950de0305572f3c8b720ee3d81ae2b",
"client_export": {
"status": "recovered_client_export_verified",
"schema": "coulomb.client-dataset-export.v1",
"content_files": 85,
"records": {
"members.user": 1,
"members.member": 1,
"spaces.space": 1,
"spaces.spacemembership": 1
},
"admin_events": 0,
"archive_sha256": "e364a61570e0083e729a3f314eb707c57347200438bd98170c77b8f7fcc2b337",
"offboarding_complete": false,
"all_source_tables_compared": 13,
"all_source_files_compared": 86,
"archive_member_hashes_verified": true,
"selected_client_content_complete_locally": true,
"source_sql_and_content_unchanged": true,
"external_bindings_require_review": 0,
"sessions_and_credentials_excluded": true
},
"candidate_application": {
"status": "isolated_application_recovery_verified",
"recovered_spaces_with_content": 1,
"actual_pages_rendered_through_view": 40,
"restored_owner_access_verified": true,
"synthetic_viewer_reads": 1,
"synthetic_viewer_mutation_denials": 1,
"same_tenant_ungranted_page_denials": 40,
"fixture_transaction_rolled_back": true,
"production_access": false,
"external_identity_provider_used": false,
"real_browser_journey_verified": false
},
"previous_image_application": {
"status": "isolated_application_recovery_verified",
"recovered_spaces_with_content": 1,
"actual_pages_rendered_through_view": 40,
"restored_owner_access_verified": true,
"synthetic_viewer_reads": 1,
"synthetic_viewer_mutation_denials": 1,
"same_tenant_ungranted_page_denials": 40,
"fixture_transaction_rolled_back": true,
"production_access": false,
"external_identity_provider_used": false,
"real_browser_journey_verified": false
},
"source_content_files_unchanged": 86,
"all_tables_unchanged_after_both_view_checks": true,
"application_source_overlay": false,
"export_archive_removed": true,
"network_internal": true,
"published_ports": 0,
"production_access": false,
"production_restore": false,
"post_date_correction_data_claimed": true,
"retained_point_captured_at": "2026-10-31T07:13:52Z",
"driver_sha256": "92b66225e5f9bdf03d0a0999b613370c42341a2ceef468f1743fb4301884cb25"
}

View file

@ -1,20 +0,0 @@
{
"schema": "coulomb.packaged-content-lifecycle-tests.v1",
"source": "f306dbfa2604e4815523667740be2925c333b84e",
"image_id": "sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec",
"tests": 29,
"failures": 0,
"expected_baseline_regressions": false,
"failed_nodes": [],
"errors": 0,
"skipped": 0,
"network": "none",
"read_only_root": true,
"application_source_overlay": false,
"test_tooling_injected": true,
"application_modules_from_image_verified": true,
"production_access": false,
"junit_sha256": "f2968ef1048ec9af68a187b967d558db0f6ee76e765a8106fb7fab284953511f",
"driver_sha256": "85b65114997c7e7c5323cb77a0043e495ec132506eef07dd394c6a6361380d36",
"test_source_sha256": "84a25a22a3cbda397e39c0508db8ea5aa90e6c467ccfa7da2b568d174d1ec449"
}

View file

@ -1,61 +0,0 @@
{
"changed_columns": {
"django_session": [
"session_key",
"session_data",
"expire_date"
],
"members_member": [
"updated_at",
"last_login_at"
],
"members_user": [
"last_login"
]
},
"file_changes": [],
"retained_fingerprint": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"schema": "coulomb.content-release-row-drift.v1",
"changed_tables": [
{
"table": "django_session",
"retained_rows": 42,
"current_rows": 43,
"retained_sha256": "c958e33ec782f9f2fd1b3cceba4a64da0038fde51050f25905ae42de91ca6dde",
"current_sha256": "594e246ef6297d9be9b6e8d9eda076a5b2ab36afb9263606b719f64f51293ba6"
},
{
"table": "members_member",
"retained_rows": 1,
"current_rows": 1,
"retained_sha256": "4d465d2b9d1e6311e505f861f2ed4b67763a545a965f9a7d0c586a3d07e3e9a3",
"current_sha256": "ab82b3f2c5e49f8634c598c9642894747f4b6fcff0f5230ac27f41939feb8640"
},
{
"table": "members_user",
"retained_rows": 1,
"current_rows": 1,
"retained_sha256": "81ccb3a40191e910a68c101896df518a588c00231728934c4c900577f8ae4f12",
"current_sha256": "0fc7a71b4b80a71fbedce527bbd2cae3858cf6a062e5714fc231be13ff987256"
}
],
"all_other_business_tables_equal": true,
"migration_history_equal": true,
"content_equal": true,
"retained_point": "2026-10-31T07:13:52Z",
"current_business_rows": 93,
"current_business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"private_row_values_printed": false,
"production_changes": false
}

View file

@ -1,62 +0,0 @@
{
"schema": "coulomb.content-release-target-observation.v1",
"observed_at": "2026-10-31T12:07:24.322343+00:00",
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"pvc_uid": "9888abeb-9d52-4c70-a23d-b5494780d9c3",
"baseline_revision": 19,
"baseline_helm_manifest_sha256": "93cb277abd1aea0657be482e458dcfb268fe0bfbd45d90aa1faedcc7f5bce499",
"baseline_spec_sha256": "42e091e52d5dae3c1f986e4898c62057fa80846adfce049a75d8fbd4681180ea",
"candidate_spec_sha256": "c65cb691bab7054ae25de58cdb75933d383621ec4e049d2daa1b1bf52dce0bba",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"candidate_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec",
"sole_ready_pvc_writer": true,
"existing_unmanaged_metadata_preserved": true,
"candidate_image_only_server_preview_verified": true,
"data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"matches_verified_revision19_data": false,
"installed_helper_sha256": {
"/opt/coulomb-social-backup/paired-backup.py": "43e119acb6a4933b4e144c349a091e074e1a91ab61dbe15a65c8264c1d47661a",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "dcc8dd2a3989f279597595f9260b31b24fcc9b6dc787f04c17ef0491c53d830d",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d"
},
"timers": {
"coulomb-social-paired-backup.timer": {
"LoadState": "not-found",
"ActiveState": "inactive",
"UnitFileState": ""
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "not-found",
"ActiveState": "inactive",
"UnitFileState": ""
}
},
"prerequisites": {
"custody": {
"exists": false
},
"installation": {
"exists": false
},
"route": {
"exists": false
}
},
"production_data_modified": false,
"release_executed": false
}

View file

@ -1,58 +0,0 @@
{
"schema": "coulomb.content-lifecycle-validation.v1",
"recorded_at": "2026-10-31T11:54:24.215512+00:00",
"status": "source_fix_verified",
"workplan_task": "CSOC-WP-0013-T05",
"bug": "A process exit during attachment creation left bytes absent from the copy/move cleanup journal; the orphan blocked retry.",
"regression_observed_before_fix": {
"baseline": "f70708839cd5ca43310f6891c8d94aaff915139c",
"operations": [
"copy_page",
"transfer_page"
],
"interruption": "partial first attachment flushed, immediate os._exit(86)",
"result": "both failed because the partial destination survived recovery"
},
"fix": [
"Refuse existing attachment entries before recording cleanup authority.",
"Persist intended new attachment name before exclusive creation under the content writer lock.",
"Flush recovery and attachment directory entries before destination publication."
],
"focused_cases": {
"total": 29,
"abrupt_child_process_exit": 14,
"existing_destination_collision": 8,
"prior_retention_and_recovery": 7
},
"full_gate": {
"command": "make check",
"tests": 546,
"failures": 0,
"errors": 0,
"skipped": 0,
"warnings": 69,
"junit_sha256": "dd3d0433c8109f00f6dddd119cfdf8281915f94da2da1f5e6009c31cfe76c65b",
"log_sha256": "eb59a394c95c5307c17069874640d1655ef61c5aa7bb426ef6d21db4929f748e"
},
"files": [
{
"path": "coulomb_social/apps/spaces/pageops.py",
"sha256": "055ef25b5efc75798cf17ffa68739de4d4099d2cab4d041e7c7eacdfaf43803e"
},
{
"path": "tests/test_content_recovery.py",
"sha256": "84a25a22a3cbda397e39c0508db8ea5aa90e6c467ccfa7da2b568d174d1ec449"
}
],
"policy": "User accepted retain-all default and separately reviewed manual cutoff; keep live page and all history of deleted pages.",
"live_purge_authorized": false,
"live_purge_executed": false,
"production_deployed": false,
"productive_acceptance": false,
"limits": [
"Child process termination on synthetic local files is proved; physical power-loss durability is not experimentally proved.",
"Cooperating application/import writers must use the content writer lock.",
"Release delivery and productive copy/move review remain open."
],
"policy_decision_id": "c3a191f2-ce06-483f-82d7-ef8c54ea0d5e"
}

View file

@ -1,175 +0,0 @@
#!/usr/bin/env python3
"""Node-side quiesced coulomb-social snapshot. Binary output stays private.
Run on railiance01 after reviewed live approval. Does not restore production.
Default is server dry-run; --execute briefly pauses the app and captures a
paired pg_dump/content archive. A separate isolated restore must validate it.
"""
from __future__ import annotations
import argparse
import fcntl
import hashlib
import json
import os
import signal
import stat
import subprocess
import sys
import time
from pathlib import Path
NS = 'coulomb-social'
IMAGE = ('forgejo.coulomb.social/coulomb/coulomb-social@sha256:'
'd3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec')
CLUSTER_UID = 'a553c742-0115-43d4-99a4-a5ca56fe0786'
LOCK_PATH = Path('/var/lib/coulomb-social-backup/snapshot.lock')
class Refused(RuntimeError):
pass
def run(args: list[str], *, payload: bytes | None = None, timeout: int = 180) -> bytes:
p = subprocess.run(args, input=payload, capture_output=True, timeout=timeout)
if p.returncode:
raise Refused('command_failed')
return p.stdout
def k(*args: str, payload: bytes | None = None) -> bytes:
return run(['kubectl', *args], payload=payload)
def document(*args: str) -> dict:
return json.loads(k(*args, '-o', 'json'))
def private_write(path: Path, value: bytes) -> None:
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, 'wb') as f:
f.write(value)
def snapshot() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--execute', action='store_true')
parser.add_argument('--destination', type=Path, required=True)
args = parser.parse_args()
os.environ['KUBECONFIG'] = '/etc/rancher/k3s/k3s.yaml'
started = time.monotonic()
if document('get', 'namespace', 'kube-system')['metadata']['uid'] != CLUSTER_UID:
raise Refused('wrong_cluster')
dep = document('get', 'deployment', 'coulomb-social', '-n', NS)
spec = dep['spec']['template']['spec']
if dep['spec']['replicas'] != 1 or spec['containers'][0]['image'] != IMAGE:
raise Refused('unexpected_release')
if document('get', 'pvc', 'coulomb-social-content', '-n', NS)['status']['phase'] != 'Bound':
raise Refused('pvc_not_bound')
cluster = document('get', 'cluster', 'apps-pg', '-n', 'databases')
primary = cluster['status']['currentPrimary']
name = 'csoc-paired-snapshot-' + time.strftime('%Y%m%d%H%M%S', time.gmtime())
pod = {
'apiVersion': 'v1', 'kind': 'Pod',
'metadata': {'name': name, 'namespace': NS, 'labels': {'csoc-recovery': name}},
'spec': {
'restartPolicy': 'Never', 'automountServiceAccountToken': False,
'securityContext': {'runAsNonRoot': True, 'runAsUser': 10001,
'runAsGroup': 10001, 'fsGroup': 10001,
'fsGroupChangePolicy': 'OnRootMismatch'},
'containers': [{'name': 'snapshot', 'image': IMAGE,
'command': ['python', '-c', 'import time;time.sleep(1800)'],
'resources': {'requests': {'cpu': '10m', 'memory': '64Mi'},
'limits': {'cpu': '100m', 'memory': '256Mi'}},
'securityContext': {'allowPrivilegeEscalation': False,
'readOnlyRootFilesystem': True,
'capabilities': {'drop': ['ALL']}},
'volumeMounts': [{'name': 'content', 'mountPath': '/snapshot', 'readOnly': True}]}],
'volumes': [{'name': 'content', 'persistentVolumeClaim':
{'claimName': 'coulomb-social-content', 'readOnly': True}}],
},
}
body = json.dumps(pod).encode()
k('create', '--dry-run=server', '-f', '-', payload=body)
if not args.execute:
print(json.dumps({'status': 'reviewed', 'server_dry_run': True,
'image_pinned': True, 'pvc_read_only': True,
'db_scope': 'coulomb_social_db', 'replicas_restored_to': 1}))
return 0
dest = args.destination
if not dest.is_absolute() or dest.exists():
raise Refused('destination_must_be_new_absolute_directory')
dest.mkdir(mode=0o700)
paused = False
created = False
receipt = {'status': 'incomplete', 'app': 'coulomb-social',
'database': 'coulomb_social_db', 'image': IMAGE,
'started_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
try:
paused = True
k('scale', 'deployment/coulomb-social', '-n', NS, '--replicas=0')
k('wait', '--for=delete', 'pod', '-n', NS,
'-l', 'app.kubernetes.io/instance=coulomb-social', '--timeout=120s')
created = True
k('create', '-f', '-', payload=body)
k('wait', '--for=condition=Ready', 'pod/' + name, '-n', NS, '--timeout=120s')
dump = k('exec', '-n', 'databases', primary, '-c', 'postgres', '--',
'pg_dump', '-U', 'postgres', '-d', 'coulomb_social_db', '-Fc')
if not dump.startswith(b'PGDMP'):
raise Refused('invalid_pg_dump')
private_write(dest / 'database.dump', dump)
archive_code = ('import io,sys,tarfile; b=io.BytesIO(); '
't=tarfile.open(fileobj=b,mode="w:gz"); '
't.add("/snapshot",arcname="content"); '
't.close();sys.stdout.buffer.write(b.getvalue())')
content = k('exec', '-n', NS, name, '--', 'python', '-c', archive_code)
private_write(dest / 'content.tar.gz', content)
receipt.update(status='captured', writers_quiesced=True,
database_sha256=hashlib.sha256(dump).hexdigest(),
content_sha256=hashlib.sha256(content).hexdigest(),
database_bytes=len(dump), content_bytes=len(content))
finally:
try:
if created:
k('delete', 'pod', name, '-n', NS, '--wait=true', '--timeout=120s')
finally:
if paused:
k('scale', 'deployment/coulomb-social', '-n', NS, '--replicas=1')
k('rollout', 'status', 'deployment/coulomb-social', '-n', NS, '--timeout=180s')
receipt['app_resumed'] = True
receipt['elapsed_seconds'] = round(time.monotonic() - started, 2)
private_write(dest / 'receipt.json', json.dumps(receipt, indent=2).encode())
print(json.dumps(receipt))
return 0
def main() -> int:
if '--execute' not in sys.argv:
return snapshot()
LOCK_PATH.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
parent = LOCK_PATH.parent.lstat()
if (not stat.S_ISDIR(parent.st_mode) or parent.st_uid != os.geteuid()
or parent.st_mode & 0o077):
raise Refused('lock_directory_not_private')
fd = os.open(LOCK_PATH, os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600)
with os.fdopen(fd, 'w') as lock:
try:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
raise Refused('snapshot_already_running') from None
def terminate(signum, frame):
raise Refused('snapshot_interrupted')
previous = signal.signal(signal.SIGTERM, terminate)
try:
return snapshot()
finally:
signal.signal(signal.SIGTERM, previous)
if __name__ == '__main__':
try:
sys.exit(main())
except Exception as exc:
# Never expose child output, kubectl objects, credentials or raw exception messages.
print(json.dumps({'status': 'failed', 'failure_type': type(exc).__name__}))
sys.exit(1)

View file

@ -1,50 +0,0 @@
# Production overrides for coulomb-social.
# Non-secret values only. Secrets live in K8s Secret coulomb-social-env.
image:
repository: forgejo.coulomb.social/coulomb/coulomb-social
tag: "f306dbfa2604"
digest: "sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec"
# Public host: app.coulomb.social (parallel to Bubble on apex coulomb.social).
# Apex cutover is deferred until data + self-registration are ready.
env:
DJANGO_SETTINGS_MODULE: coulomb_social.settings.prod
ALLOWED_HOSTS: app.coulomb.social,localhost
CSRF_TRUSTED_ORIGINS: https://app.coulomb.social
CONTENT_ROOT: /app/var/content
DEFAULT_TENANT_ID: "tenant:coulomb"
OIDC_ENABLED: "true"
OIDC_ISSUER: https://kc.coulomb.social
OIDC_CLIENT_ID: coulomb-social
OIDC_REDIRECT_URI: https://app.coulomb.social/auth/callback/
OIDC_SCOPES: "openid profile email groups"
USER_ENGINE_BASE_URL: https://users.coulomb.social
USER_ENGINE_APPLICATION_ID: coulomb-social
USER_ENGINE_EXPECTED_AUDIENCE: user-engine-portal
NETKINGDOM_REGISTRATION_URL: https://users.92-205-62-239.nip.io/register
probes:
hostHeader: app.coulomb.social
path: /healthz
# One writable local-path volume; Recreate prevents concurrent old/new writers.
replicaCount: 1
deploymentStrategy: Recreate
persistence:
content:
enabled: true
storageClass: local-path
size: 2Gi
mountPath: /app/var/content
retain: true
# Wave-2 right-sizing (CSOC-WP-0017-T01, 2026-10-21 node budget): 7d p95
# 0.4m CPU / 146Mi. Limits stay at the chart defaults (1000m/1Gi).
resources:
requests:
cpu: 15m
memory: 176Mi
limits:
cpu: 1000m
memory: 1Gi

View file

@ -1,79 +0,0 @@
{
"schema": "coulomb.reviewed-image-release.v1",
"proposal_id": "CSOC-CONTENT-ACCEPTANCE-20261031",
"scope": "ADMINISTER @ realm:kubernetes/railiance01; supervised founder execution only",
"operation": "image_only_existing_migration_0003",
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"baseline_revision": 19,
"baseline_helm_manifest_sha256": "93cb277abd1aea0657be482e458dcfb268fe0bfbd45d90aa1faedcc7f5bce499",
"candidate_render_sha256": "680debbf4f35d9571916e2016c83327d1212665be82164c40d2d0a49081fc4a8",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"pvc_uid": "9888abeb-9d52-4c70-a23d-b5494780d9c3",
"baseline_spec_sha256": "42e091e52d5dae3c1f986e4898c62057fa80846adfce049a75d8fbd4681180ea",
"candidate_spec_sha256": "8d79c64cff4bd2c62f03494e80847dc99b965ddabf35645da67e8d1020220798",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"candidate_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"product_source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"expected_data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"installed_helper_hashes": {
"/opt/coulomb-social-backup/paired-backup.py": "d161c742d1a6a182460a57d0a1719591ab58fc94006f55169ad3d74442a93630",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "dcc8dd2a3989f279597595f9260b31b24fcc9b6dc787f04c17ef0491c53d830d",
"/opt/coulomb-social-backup/mirror-paired-backup.py": "9ceb26d9083af016c4b787907e4dce7bdf437c782fb2d15eb28d9e334e6e431c",
"/opt/coulomb-social-backup/check-paired-backup-health.py": "2d40ec6e4c59ea7fe1d46065d197b9a87ca6811f023cc6f3e20e4184a3490566",
"/opt/coulomb-social-backup/backup_capacity.py": "cb699a79e67b129239b5aa5d6f3b0d4ffaa9773a8b073227ad17fdecb5b9d893",
"/opt/railiance-platform/scripts/application_recovery_identities.py": "20f56255ed6eeec4aafe33f142bc3ee03f623d4957a7b0cabb741d340f15f79d",
"/opt/railiance-platform/scripts/application_recovery_mirror.py": "d48ab95e89b9eeae36269d853ebe4c44c22e1f57d4e14224f03d0b9aeeb34178",
"/opt/railiance-platform/scripts/application_recovery_resources.py": "ab70ec341e738272730eb0daf76840d0bca807caeb3c4e4c2357f162fbed4498",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d",
"/opt/coulomb-social-backup/backup_alerts.py": "07522437d4276b92f0a44149adc6c9e81bb18dbe59ce0f1f9e58a48347700d0e",
"/opt/coulomb-social-backup/notify-backup-alert.py": "0bd53bc5ad22d8bcb0326fb18a17737744b06416fe785dad077308e45f051d5a",
"/opt/coulomb-social-backup/observe-backup-alerts.py": "17caf4fa65283242f618b039ff1d018801c9890ea2a9178912cbdd4b50ee2664"
},
"clipboard_static_sha256": "347eabe0c8d93bf439df02b5a08a7ea71004600e6ff4e8a42cecbee52a9f0413",
"fresh_backup_before_helm": true,
"requires_dataset_equality_before_and_after": true,
"node_request_percent_limit": 90,
"helm_atomic_timeout_seconds": 300,
"rollback": "Restore Helm revision19/image522bcd7f and verified snapshot pin; preserve all post-capture data. No production data restore or schema downgrade.",
"approval_status": "prepared_not_admitted",
"recovery_rehearsal_scope": "Candidate and previous image verified read-only against retained independently recovered 2026-10-31T07:13:52Z point: all13 tables/86 files unchanged,40 owner views/40 outsider denials,85 selected-client export files verified. Live baseline remains93 business rows versus92 at the retained point; previously verified session/login-only drift remains unchanged. Fresh paired capture/readback before Helm and independent recovery of that fresh point remain required.",
"rehearsal_evidence_sha256": {
"content-acceptance-build-2026-10-31.json": "39c5c78174e0dfc7fd93c4b718c2b15aa68cea8298be517e28ee2bd206912dd9",
"content-acceptance-provenance-2026-10-31.json": "7d24b3eecf0c2c9c923812a318d448233f5bfc9ae4242046dae1c4d20e7e664a",
"content-acceptance-tests-2026-10-31.json": "3da4d155d84553d7f2949d7e14e5c9cc6c819a6be6af04db5819b7f43ed18e47",
"content-acceptance-recovery-2026-10-31.json": "4ec1b46d8076c42ac0e5bc106b7ff7debf25a65e6c02d907d7148c200a811ede",
"content-acceptance-target-2026-10-31.json": "6651cbf0e2df889315464638158c3aaad885c3cb39fd5b51f06a5037434efebb",
"attachment-menu-validation-2026-10-31.json": "7e491219c701d2e67bb2c3bc849af1fb1a58f787fd17e0527eefcf6345c62f2d",
"ordered-list-fidelity-2026-10-31.json": "4dc3091876d355648d7482187d54f6a0501355274c263d0009d5d5ff6f42f64f",
"content-lifecycle-validation-2026-10-31.json": "cbb093af470588ca6e8eb3ec5bc1ccee0be537ab37a46625b6ac267c17343d99",
"content-lifecycle-baseline-tests-2026-10-31.json": "de14e4e10337990ccec1c483f7d943bdc7e11b03aa813aff47d00a9b38a07b65",
"content-lifecycle-release-row-drift-2026-10-31.json": "b10f65bf55e900199ae6037767f32e8901aaccb6f7f3a86461f13dd02ec8efce",
"backup-route-independent-return-2026-10-31.json": "3a3feb56c1af7e3db7b0f2380ec355bb465663073c0a0160034a35984ef23f6e",
"backup-installation-independent-return-2026-10-31.json": "2fe1972f4db0ba2468027f4926cd8111d6aa4b61d404592eda794b47733ce0df"
},
"new_resources_committed": 0,
"autopilot_or_eur_budget_claimed": false,
"values_file": "release/content-acceptance-values.yaml",
"snapshot_file": "release/content-acceptance-snapshot.py",
"evidence_directory": "release/content-acceptance-evidence",
"prerequisite_installation_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"requires_inactive_backup_units": true,
"product_changes": [
"Preserve ordered-list start numbers",
"Durable interrupted copy/move asset recovery",
"Plain attachment menu: author upload/remove and authenticated reader downloads; revisioned associations and independent copies/moves"
],
"product_decision": "78175c34-58e1-4ad6-944d-0662c0462ae6"
}

View file

@ -1,69 +0,0 @@
{
"schema": "coulomb.reviewed-image-release.v1",
"proposal_id": "CSOC-CONTENT-LIFECYCLE-20261031",
"scope": "ADMINISTER @ realm:kubernetes/railiance01; supervised founder execution only",
"operation": "image_only_existing_migration_0003",
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"baseline_revision": 19,
"baseline_helm_manifest_sha256": "93cb277abd1aea0657be482e458dcfb268fe0bfbd45d90aa1faedcc7f5bce499",
"candidate_render_sha256": "1606725273089b83689850ad1c25d1834faa15e00c8cf8aa24e1053273af71bc",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"pvc_uid": "9888abeb-9d52-4c70-a23d-b5494780d9c3",
"baseline_spec_sha256": "42e091e52d5dae3c1f986e4898c62057fa80846adfce049a75d8fbd4681180ea",
"candidate_spec_sha256": "c65cb691bab7054ae25de58cdb75933d383621ec4e049d2daa1b1bf52dce0bba",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"candidate_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec",
"product_source": "f306dbfa2604e4815523667740be2925c333b84e",
"expected_data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"installed_helper_hashes": {
"/opt/coulomb-social-backup/paired-backup.py": "d161c742d1a6a182460a57d0a1719591ab58fc94006f55169ad3d74442a93630",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "dcc8dd2a3989f279597595f9260b31b24fcc9b6dc787f04c17ef0491c53d830d",
"/opt/coulomb-social-backup/mirror-paired-backup.py": "9ceb26d9083af016c4b787907e4dce7bdf437c782fb2d15eb28d9e334e6e431c",
"/opt/coulomb-social-backup/check-paired-backup-health.py": "2d40ec6e4c59ea7fe1d46065d197b9a87ca6811f023cc6f3e20e4184a3490566",
"/opt/coulomb-social-backup/backup_capacity.py": "cb699a79e67b129239b5aa5d6f3b0d4ffaa9773a8b073227ad17fdecb5b9d893",
"/opt/railiance-platform/scripts/application_recovery_identities.py": "20f56255ed6eeec4aafe33f142bc3ee03f623d4957a7b0cabb741d340f15f79d",
"/opt/railiance-platform/scripts/application_recovery_mirror.py": "d48ab95e89b9eeae36269d853ebe4c44c22e1f57d4e14224f03d0b9aeeb34178",
"/opt/railiance-platform/scripts/application_recovery_resources.py": "ab70ec341e738272730eb0daf76840d0bca807caeb3c4e4c2357f162fbed4498",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d",
"/opt/coulomb-social-backup/backup_alerts.py": "07522437d4276b92f0a44149adc6c9e81bb18dbe59ce0f1f9e58a48347700d0e",
"/opt/coulomb-social-backup/notify-backup-alert.py": "0bd53bc5ad22d8bcb0326fb18a17737744b06416fe785dad077308e45f051d5a",
"/opt/coulomb-social-backup/observe-backup-alerts.py": "17caf4fa65283242f618b039ff1d018801c9890ea2a9178912cbdd4b50ee2664"
},
"clipboard_static_sha256": "347eabe0c8d93bf439df02b5a08a7ea71004600e6ff4e8a42cecbee52a9f0413",
"fresh_backup_before_helm": true,
"requires_dataset_equality_before_and_after": true,
"node_request_percent_limit": 90,
"helm_atomic_timeout_seconds": 300,
"rollback": "Restore Helm revision19/image522bcd7f and verified snapshot pin; preserve all post-capture data. No production data restore or schema downgrade.",
"approval_status": "prepared_not_admitted",
"recovery_rehearsal_scope": "Retained independently recovered 2026-10-31T07:13:52Z point; candidate and previous image preserve all 13 source tables and 86 files. Live observation now has93 business rows versus92 in that point; exact fresh paired backup/readback is required before Helm. Independent restore of the new point remains consumer follow-through. Read-only drift comparison confines differences to sessions and user/member login timestamps; all content and migration history match the retained point.",
"rehearsal_evidence_sha256": {
"content-lifecycle-candidate-build-2026-10-31.json": "83ad2ec41c85f8bb5087a250fdb91126ed92f12351cdc72b353c6f0e1a26452b",
"content-lifecycle-candidate-provenance-2026-10-31.json": "35ed909e0a2fa5c57cea1fcc4fbebb877eae559ca9dc753c3da00f84806d7b73",
"content-lifecycle-candidate-tests-2026-10-31.json": "27a75cfee6bbda41f377b73d6a6c7ecde0c54806c113f1be5223dd2f2cf39b3b",
"content-lifecycle-baseline-tests-2026-10-31.json": "de14e4e10337990ccec1c483f7d943bdc7e11b03aa813aff47d00a9b38a07b65",
"content-lifecycle-candidate-recovery-2026-10-31.json": "8d15172e5e330d01f153336e67f6bffb4363d571530c31ea05db872ca10807a9",
"content-lifecycle-validation-2026-10-31.json": "cbb093af470588ca6e8eb3ec5bc1ccee0be537ab37a46625b6ac267c17343d99",
"content-lifecycle-release-target-2026-10-31.json": "e9b50be3c8284c5a9ae96d75b800cbc4090580fa811c2ecd098d73ce8cbee74e",
"content-lifecycle-release-row-drift-2026-10-31.json": "b10f65bf55e900199ae6037767f32e8901aaccb6f7f3a86461f13dd02ec8efce"
},
"new_resources_committed": 0,
"autopilot_or_eur_budget_claimed": false,
"values_file": "release/content-lifecycle-values.yaml",
"snapshot_file": "release/content-lifecycle-snapshot.py",
"evidence_directory": "release/content-lifecycle-evidence",
"prerequisite_installation_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"requires_inactive_backup_units": true
}

View file

@ -1,77 +0,0 @@
{
"schema": "coulomb.reviewed-image-release.v1",
"proposal_id": "CSOC-EDITOR-ATTACHMENTS-20261031",
"scope": "ADMINISTER @ realm:kubernetes/railiance01; supervised founder execution only",
"operation": "image_only_existing_migration_0003",
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"baseline_revision": 20,
"baseline_helm_manifest_sha256": "e388f62c97e97d54d87671825bd0b05c854a70b0cca8a00faee452ae7841799e",
"candidate_render_sha256": "78ee8e0a73f87e1152b6f826029ed85385b6293c61a1cdab7171b6c6e40580bc",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"pvc_uid": "9888abeb-9d52-4c70-a23d-b5494780d9c3",
"baseline_spec_sha256": "8d79c64cff4bd2c62f03494e80847dc99b965ddabf35645da67e8d1020220798",
"candidate_spec_sha256": "4deab26fc15d63e09922259b3362cd4e5c6bfa10884de058f776c0de8b642b00",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"candidate_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e",
"product_source": "31eaa581a65e454b6ef9979326c5bdfe10e13806",
"expected_data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 97,
"business_rows_sha256": "35b0ae7d9dd1ff21c2ceaa04649162545ec36a2c68629548238352d9cd0fb303",
"content_files": 98,
"content_files_sha256": "b657c0e470399b6c7500da500cbbec061bea12ab9633bd74e2f142d797b2d26a",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"installed_helper_hashes": {
"/opt/coulomb-social-backup/paired-backup.py": "d161c742d1a6a182460a57d0a1719591ab58fc94006f55169ad3d74442a93630",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "23f92c96b840df61f92858004241e860e0ddb32ed6fd7448294d3c8278906e46",
"/opt/coulomb-social-backup/mirror-paired-backup.py": "9ceb26d9083af016c4b787907e4dce7bdf437c782fb2d15eb28d9e334e6e431c",
"/opt/coulomb-social-backup/check-paired-backup-health.py": "2d40ec6e4c59ea7fe1d46065d197b9a87ca6811f023cc6f3e20e4184a3490566",
"/opt/coulomb-social-backup/backup_capacity.py": "cb699a79e67b129239b5aa5d6f3b0d4ffaa9773a8b073227ad17fdecb5b9d893",
"/opt/railiance-platform/scripts/application_recovery_identities.py": "20f56255ed6eeec4aafe33f142bc3ee03f623d4957a7b0cabb741d340f15f79d",
"/opt/railiance-platform/scripts/application_recovery_mirror.py": "d48ab95e89b9eeae36269d853ebe4c44c22e1f57d4e14224f03d0b9aeeb34178",
"/opt/railiance-platform/scripts/application_recovery_resources.py": "ab70ec341e738272730eb0daf76840d0bca807caeb3c4e4c2357f162fbed4498",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d",
"/opt/coulomb-social-backup/backup_alerts.py": "07522437d4276b92f0a44149adc6c9e81bb18dbe59ce0f1f9e58a48347700d0e",
"/opt/coulomb-social-backup/notify-backup-alert.py": "0bd53bc5ad22d8bcb0326fb18a17737744b06416fe785dad077308e45f051d5a",
"/opt/coulomb-social-backup/observe-backup-alerts.py": "17caf4fa65283242f618b039ff1d018801c9890ea2a9178912cbdd4b50ee2664"
},
"clipboard_static_sha256": "347eabe0c8d93bf439df02b5a08a7ea71004600e6ff4e8a42cecbee52a9f0413",
"fresh_backup_before_helm": true,
"requires_dataset_equality_before_and_after": true,
"node_request_percent_limit": 90,
"helm_atomic_timeout_seconds": 300,
"rollback": "Restore Helm revision20/image7906f461 and verified snapshot pin, preserving all data; no production restore or schema downgrade.",
"approval_status": "prepared_not_admitted",
"recovery_rehearsal_scope": "Candidate and previous image verified against independently recovered 2026-10-31T20:21:01Z point:13tables/86files unchanged,40owner views/40outsider denials,85export files verified. Current97-row/98-file baseline adds2spaces/2memberships/12files from productive acceptance; all prior rows and86files are unchanged. Fresh paired capture/readback before Helm and independent recovery afterward remain required.",
"rehearsal_evidence_sha256": {
"editor-attachments-build-2026-10-31.json": "bb58b2fe23d101ab82ee0b210cc8f552f3667c785bd0207b1e1656b0577c106d",
"editor-attachments-provenance-2026-10-31.json": "3d4ec97702c5165af2198da4c4563cba204355480f5036fd22c48b9e3c300ba3",
"editor-attachments-tests-2026-10-31.json": "59d2d121befa7a8c3853fc89172bad5ce2abad1c1615cc2f2bea550f4d68a62d",
"editor-attachments-recovery-2026-10-31.json": "af68f6e86c0b3291d4ad880717c36eb95f1592f78d3c65596dd9cecd10755052",
"editor-attachments-target-2026-10-31.json": "b6d767ecb93b4638ca77a5052dcf3aab8a95dee922d3927956ad578290f9e58f",
"editor-attachments-baseline-change-2026-10-31.json": "db79f2838b88281c562b36996e74694c2a98e113c962b46eab0ef2cf69dd3b8c",
"editor-attachments-validation-2026-10-31.json": "427e228a9f2763cd583496d65e21b7599ef5e0df074dc507277ce2051169f562",
"backup-route-independent-return-2026-10-31.json": "3a3feb56c1af7e3db7b0f2380ec355bb465663073c0a0160034a35984ef23f6e",
"backup-installation-independent-return-2026-10-31.json": "2fe1972f4db0ba2468027f4926cd8111d6aa4b61d404592eda794b47733ce0df",
"content-acceptance-independent-postflight-2026-10-31.json": "6a8a4056b143011c50af24dd31d6338d00892bfe626666f85e607d86562dfe7c"
},
"new_resources_committed": 0,
"autopilot_or_eur_budget_claimed": false,
"values_file": "release/editor-attachments-values.yaml",
"snapshot_file": "release/editor-attachments-snapshot.py",
"evidence_directory": "release/editor-attachments-evidence",
"prerequisite_installation_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"requires_inactive_backup_units": true,
"product_changes": [
"Show saved attachments and downloads in editor tabs",
"Keep attachment list and submitted text after stale edit refusal",
"Open attachment management in a separate tab to preserve unsaved editor text"
],
"product_decision": "Productive review feedback: attachments present on original but absent from editing tabs."
}

View file

@ -1,51 +0,0 @@
{
"schema": "coulomb.reviewed-image-release.v1",
"proposal_id": "CSOC-IDENTITY-EXPORT-20261031",
"scope": "ADMINISTER @ realm:kubernetes/railiance01; supervised founder execution only",
"operation": "image_only_existing_migration_0003",
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"baseline_revision": 18,
"baseline_helm_manifest_sha256": "1f74302e7be7211b3ae8728f58ef6b8ec243ffa342306b25bbf42dd6f27b5ef7",
"candidate_render_sha256": "98ffff162a17a9ff4b3922364d002ddbc571f9c79af95191c84d7c0b47c9a16f",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"pvc_uid": "9888abeb-9d52-4c70-a23d-b5494780d9c3",
"baseline_spec_sha256": "013aca79ec910b52ed2c2df7a18050c436751005320d1dec616590962da30b8e",
"candidate_spec_sha256": "42e091e52d5dae3c1f986e4898c62057fa80846adfce049a75d8fbd4681180ea",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:512819463a1902b43a615beee14be7bf97e6a05e016385082b9380692ad1a8cd",
"candidate_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"product_source": "23ffe2cf4b214666754a2420558943438e54251a",
"expected_data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 92,
"business_rows_sha256": "6243955479f7861fcdcd79b62f7f1e9f9a27c05a17bd2c17b792ebc98b2fa7b6",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"installed_helper_hashes": {
"/opt/coulomb-social-backup/paired-backup.py": "43e119acb6a4933b4e144c349a091e074e1a91ab61dbe15a65c8264c1d47661a",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "4ff81b791daf6c8b976a4f89ef152e52f385fc1656986e2ea28bf555b9bd0d8a",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d"
},
"clipboard_static_sha256": "347eabe0c8d93bf439df02b5a08a7ea71004600e6ff4e8a42cecbee52a9f0413",
"fresh_backup_before_helm": true,
"requires_dataset_equality_before_and_after": true,
"node_request_percent_limit": 90,
"helm_atomic_timeout_seconds": 300,
"rollback": "Restore Helm revision18/image and verified snapshot pin; preserve all post-capture data. No production data restore or schema downgrade.",
"approval_status": "prepared_not_admitted",
"recovery_rehearsal_scope": "retained October30 point; fresh post-correction primary backup/readback occurs before Helm; independent retrieval/export of that new point remains subsequent consumer acceptance",
"rehearsal_evidence_sha256": {
"identity-export-candidate-build-2026-10-31.json": "12e8709529f27323274b40c68bd701c39e1cd2aa7428f42e061d8b5c2d410176",
"identity-export-candidate-provenance-2026-10-31.json": "71a8e1b2e60d0da6948fb74d9d1be8a8b892cef4be0d6dd0b98fa45d8983551c",
"identity-export-candidate-recovery-2026-10-31.json": "ccfe90ff68ecc80c02ef673a1d1efd21291e7c829c1dc17dc8bd0c902b9cb8b1",
"identity-export-candidate-tests-2026-10-31.json": "bd9d7535f42c7fe79752b46672f8da67492baf0dd06893b8a3288ac9eb3edaae"
},
"new_resources_committed": 0,
"autopilot_or_eur_budget_claimed": false
}

View file

@ -0,0 +1,70 @@
{
"schema": "coulomb.reviewed-storage-release.v1",
"proposal_id": "CSOC-STORAGE-20261029",
"scope": "ADMINISTER @ realm:kubernetes/railiance01; supervised founder execution only",
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"baseline_revision": 17,
"baseline_helm_manifest_sha256": "da80414e13e7c5fd254803a241f21ade223b4b84e68ed908535e36e854b523a2",
"candidate_render_sha256": "865b6a22b3c50c65a7417bb80de609b7e0290f54a99edebff497b2259bc067a2",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"pvc_uid": "9888abeb-9d52-4c70-a23d-b5494780d9c3",
"baseline_spec_sha256": "3185c30b966bc4a65d90e32dc8e0027bce957fc1fb66d10661e7e405ac215456",
"candidate_spec_sha256": "013aca79ec910b52ed2c2df7a18050c436751005320d1dec616590962da30b8e",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:9a646d8e01a61ba5316d3c2eb0273064e17f2d0300ad07af766ccedda65ecb18",
"candidate_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:512819463a1902b43a615beee14be7bf97e6a05e016385082b9380692ad1a8cd",
"product_source": "17d0eb67f397e3d1f5b9b63880df5054aa263c5a",
"expected_data": {
"business_tables": 12,
"business_rows": 91,
"business_rows_sha256": "1f404b7468011f8e006ed784628ade14bd03b53617282063f6d300df36f5090f",
"content_files": 82,
"content_files_sha256": "e3113909deccdab8135332c9e9fcacbed88f3216d9a1178f6b63da943aca3deb",
"global_slug_constraint": false,
"tenant_slug_constraint": true,
"migration_0003_applied": false,
"duplicate_slug_groups": 0
},
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"installed_helper_hashes": {
"/opt/coulomb-social-backup/paired-backup.py": "43e119acb6a4933b4e144c349a091e074e1a91ab61dbe15a65c8264c1d47661a",
"/opt/coulomb-social-backup/snapshot-content-and-db.py": "f98604294fdba5f1664529bd932592a641a22bb73ec4583bbabba8a9591cf8e3",
"/opt/railiance-platform/scripts/primary_application_archive.py": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d"
},
"clipboard_static_sha256": "347eabe0c8d93bf439df02b5a08a7ea71004600e6ff4e8a42cecbee52a9f0413",
"protected_recovered_point": {
"captured_at": "2026-10-29T21:22:46Z",
"object_key": "platform-pg/application-archives/coulomb-social/2026/10/29/20261029T212246Z-fd128164c7bb22a3a6c42acf.tar.age",
"version_id": "1793309020705518",
"ciphertext_sha256": "acbf92eda5074761bb6d00170e6e459e787359afcd377f2f18324ba17496510a",
"protected_kit": {
"automatic_expiry": false,
"bucket": "railiance-coulomb-social-recovery",
"bytes": 277585920,
"object_key": "kits/db05c8f3b5587dc1fc09a5352c317dd3357527dbe72366ab7ca1041db578c834/recovery-kit.tar",
"project_id": "06d107bc-9d84-4672-b2a0-95701cc0c07f",
"schema": "platform.coulomb-protected-recovery-kit.v1",
"sha256": "db05c8f3b5587dc1fc09a5352c317dd3357527dbe72366ab7ca1041db578c834",
"version_id": "1793309971213507"
},
"protected_recovery_proof": {
"project_id": "06d107bc-9d84-4672-b2a0-95701cc0c07f",
"bucket": "railiance-coulomb-social-recovery",
"object_key": "kits/receipts/a77477cac53086b83ad2cb512973ae0d1dfecba028a29a92e06a1bcfe5287f29/recovery-proof.json",
"version_id": "1793310476676486",
"sha256": "a77477cac53086b83ad2cb512973ae0d1dfecba028a29a92e06a1bcfe5287f29",
"bytes": 4237,
"independent_readback_verified": true,
"automatic_expiry": false
}
},
"fresh_backup_before_helm": true,
"requires_dataset_equality_before_and_after": true,
"node_request_percent_limit": 90,
"helm_atomic_timeout_seconds": 300,
"rollback": "Restore Helm revision17/image; preserve all post-capture data. Added uniqueness may remain. SQL inverse tested separately; no automatic production data restore.",
"new_resources_committed": 0,
"autopilot_or_eur_budget_claimed": false,
"approval_status": "awaiting_founder_execution",
"supervision_decision_id": "05c9b00f-e4e4-4593-bdeb-c63fe6a4fe15",
"current_preflight_is_read_only": true
}

View file

@ -1,371 +0,0 @@
{
"schema": "coulomb.backup-installation-independent-postflight.v1",
"verified_at": "2026-10-31T17:30:18.219708+00:00",
"status": "installed_files_and_inactive_units_verified",
"proposal_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"receipt_sha256": "96329afbd5662f71bf6d6b05c003f0810be12c10036f9cadb41cc373d3a1108b",
"receipt": {
"schema": "coulomb.backup-source-supervised-installation.v1",
"proposal_digest": "sha256:8f442bf0ebed8bbf3b7f227b52081df52613f3f5f6874c4a59511cfc2ba06d42",
"status": "sources_installed_units_inactive_verified",
"preflight": {
"units": {
"coulomb-social-paired-backup.service": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-paired-backup.timer": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-backup-freshness.service": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
},
"coulomb-social-backup-alert@coulomb-social-paired-backup.service.service": {
"LoadState": "not-found",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "",
"UnitFileState": ""
}
},
"capacity": {
"state_bytes": 11259904,
"state_reserve_bytes": 7532969984,
"disk_reserve_bytes": 8606711808,
"free_bytes": 115579949056,
"free_inodes": 24523113,
"filesystem_blocks_reserved": false
},
"sdk": {
"boto3": "1.40.18",
"botocore": "1.40.76"
},
"route": {
"helm_revision": 6,
"runtime_and_complete_resources_verified": true
}
},
"timers_activated": false,
"capture_executed": false,
"email_sent": false,
"retained_data_deleted": false,
"started_at": "2026-10-31T17:22:48.757530+00:00",
"capacity_profile": {
"maximum_new_file_bytes": 1073741824,
"state_budget_bytes": 8589934592,
"minimum_free_bytes": 8589934592,
"minimum_free_inodes": 1024,
"control_margin_bytes": 16777216
},
"founder_confirmed_profile_and_installation": true,
"route_postflight": {
"helm_revision": 6,
"runtime_and_complete_resources_verified": true
},
"verified_targets": 19,
"units": {
"coulomb-social-paired-backup.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.service",
"UnitFileState": "static"
},
"coulomb-social-paired-backup.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-freshness.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.service",
"UnitFileState": "static"
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-alert@coulomb-social-paired-backup.service.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-alert@.service",
"UnitFileState": "static"
}
},
"updated_at": "2026-10-31T17:22:54.560675+00:00"
},
"nested_receipt_sha256": "795d9eb672b24495c77ad636a210c5d2022c8c3124d276920db7eda02257e519",
"verified_targets": 19,
"installed_fingerprints": {
"/opt/coulomb-social-backup/paired-backup.py": {
"exists": true,
"sha256": "d161c742d1a6a182460a57d0a1719591ab58fc94006f55169ad3d74442a93630",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 534009,
"device": 2049,
"mtime_ns": 1793467368826077309
},
"/opt/coulomb-social-backup/snapshot-content-and-db.py": {
"exists": true,
"sha256": "dcc8dd2a3989f279597595f9260b31b24fcc9b6dc787f04c17ef0491c53d830d",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549255,
"device": 2049,
"mtime_ns": 1793430923413704430
},
"/opt/coulomb-social-backup/mirror-paired-backup.py": {
"exists": true,
"sha256": "9ceb26d9083af016c4b787907e4dce7bdf437c782fb2d15eb28d9e334e6e431c",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549201,
"device": 2049,
"mtime_ns": 1793467368831077393
},
"/opt/coulomb-social-backup/check-paired-backup-health.py": {
"exists": true,
"sha256": "2d40ec6e4c59ea7fe1d46065d197b9a87ca6811f023cc6f3e20e4184a3490566",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549309,
"device": 2049,
"mtime_ns": 1793467368836077477
},
"/opt/coulomb-social-backup/backup_capacity.py": {
"exists": true,
"sha256": "cb699a79e67b129239b5aa5d6f3b0d4ffaa9773a8b073227ad17fdecb5b9d893",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549354,
"device": 2049,
"mtime_ns": 1793467368843077594
},
"/opt/coulomb-social-backup/mirror-platform-runtime.json": {
"exists": true,
"sha256": "9253c5f6e956b67f499d3e12d2851be7fabd3bc56b00496b8810bbd0be8209f1",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549355,
"device": 2049,
"mtime_ns": 1793467368847077662
},
"/opt/coulomb-social-backup/backup_alerts.py": {
"exists": true,
"sha256": "07522437d4276b92f0a44149adc6c9e81bb18dbe59ce0f1f9e58a48347700d0e",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549359,
"device": 2049,
"mtime_ns": 1793467368887078332
},
"/opt/coulomb-social-backup/notify-backup-alert.py": {
"exists": true,
"sha256": "0bd53bc5ad22d8bcb0326fb18a17737744b06416fe785dad077308e45f051d5a",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549360,
"device": 2049,
"mtime_ns": 1793467368891078399
},
"/opt/coulomb-social-backup/observe-backup-alerts.py": {
"exists": true,
"sha256": "17caf4fa65283242f618b039ff1d018801c9890ea2a9178912cbdd4b50ee2664",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549361,
"device": 2049,
"mtime_ns": 1793467368895078466
},
"/opt/railiance-platform/scripts/application_recovery_identities.py": {
"exists": true,
"sha256": "20f56255ed6eeec4aafe33f142bc3ee03f623d4957a7b0cabb741d340f15f79d",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549356,
"device": 2049,
"mtime_ns": 1793467368852077745
},
"/opt/railiance-platform/scripts/application_recovery_mirror.py": {
"exists": true,
"sha256": "d48ab95e89b9eeae36269d853ebe4c44c22e1f57d4e14224f03d0b9aeeb34178",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549357,
"device": 2049,
"mtime_ns": 1793467368857077829
},
"/opt/railiance-platform/scripts/application_recovery_resources.py": {
"exists": true,
"sha256": "ab70ec341e738272730eb0daf76840d0bca807caeb3c4e4c2357f162fbed4498",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 549358,
"device": 2049,
"mtime_ns": 1793467368862077913
},
"/opt/railiance-platform/scripts/primary_application_archive.py": {
"exists": true,
"sha256": "a3f0a61e869a6012edb4b5288be14e3b0c4a9a1273b090320ab146d12e5aa94d",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 540610,
"device": 2049,
"mtime_ns": 1791537447437616251
},
"/etc/systemd/system/coulomb-social-backup-freshness.service": {
"exists": true,
"sha256": "8d6278c2cbca7f48b659c239c1d1e181fa4b9cf023fe7429850e294c6cd84d0e",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19366,
"device": 2049,
"mtime_ns": 1793467368868078014
},
"/etc/systemd/system/coulomb-social-paired-backup.service": {
"exists": true,
"sha256": "8b01b788bb08f453fdd4807104185c89411e0b0b4dedee9240f14f110ceb5513",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 14867,
"device": 2049,
"mtime_ns": 1793467368873078098
},
"/etc/systemd/system/coulomb-social-backup-freshness.timer": {
"exists": true,
"sha256": "75d1d0721c07fdd0703910c06bb8a678396440e7d95411a37ee7de4938f3ac31",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19367,
"device": 2049,
"mtime_ns": 1793467368878078181
},
"/etc/systemd/system/coulomb-social-paired-backup.timer": {
"exists": true,
"sha256": "5e87235e66f89a64a972562d6f163f62420628fc44fb7fd8d603a96c347dfbb9",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19368,
"device": 2049,
"mtime_ns": 1793467368882078248
},
"/etc/systemd/system/coulomb-social-backup-alert@.service": {
"exists": true,
"sha256": "4bfa019d29b1d0de278f03553602a5e824de50ed99ebcf3b5035cf4d5b06fe98",
"mode": 420,
"uid": 0,
"gid": 0,
"inode": 19370,
"device": 2049,
"mtime_ns": 1793467368899078533
},
"/etc/coulomb-social-backup/alerting.env": {
"exists": true,
"sha256": "509844b5c8ef618b812d52f32e19c3c559623636dca62f7b16f437aa90cc0458",
"mode": 384,
"uid": 0,
"gid": 0,
"inode": 19369,
"device": 2049,
"mtime_ns": 1793467368904078617
}
},
"units": {
"coulomb-social-paired-backup.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.service",
"UnitFileState": "static"
},
"coulomb-social-paired-backup.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-paired-backup.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-freshness.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.service",
"UnitFileState": "static"
},
"coulomb-social-backup-freshness.timer": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-freshness.timer",
"UnitFileState": "disabled"
},
"coulomb-social-backup-alert@coulomb-social-paired-backup.service.service": {
"LoadState": "loaded",
"ActiveState": "inactive",
"SubState": "dead",
"FragmentPath": "/etc/systemd/system/coulomb-social-backup-alert@.service",
"UnitFileState": "static"
}
},
"route": {
"helm_revision": 6,
"runtime_and_complete_resources_verified": true
},
"capacity": {
"state_bytes": 11259904,
"state_reserve_bytes": 7532969984,
"disk_reserve_bytes": 8606711808,
"free_bytes": 115555618816,
"free_inodes": 24523041,
"filesystem_blocks_reserved": false
},
"sdk": {
"boto3": "1.40.18",
"botocore": "1.40.76"
},
"runtime_modified_by_verification": false
}

View file

@ -1,29 +0,0 @@
{
"schema": "coulomb.backup-route-independent-postflight.v1",
"verified_at": "2026-10-31T17:19:36.926769+00:00",
"status": "durable_receipt_and_live_route_verified",
"execution_digest": "sha256:4d8481061dc9ce6835169defc96887945052332a0db8d4234ae84032d63cc328",
"receipt": {
"schema": "rapp-telemetry.backup-route-execution.v1",
"execution_digest": "sha256:4d8481061dc9ce6835169defc96887945052332a0db8d4234ae84032d63cc328",
"proposal_digest": "sha256:4bcad54f7b8e1e77b94112e452cbb58eaf8e882dc10305129c5f9ca69f014a66",
"status": "backup_email_route_deployed_verified",
"timers_activated": false,
"notification_sent_by_helper": false,
"production_data_restored": false,
"started_at": "2026-10-31T17:17:13.743344+00:00",
"helm_revision": 6,
"verified_resource_count": 87,
"after_resources_sha256": "600c4998e54b8e11845849c7d8e4c6b6699556c21f5df6ca79bb86b2e8d1683f",
"live_desired_fields_verified": true,
"runtime_config_verified": true,
"existing_image_and_pvc_preserved": true,
"completed_at": "2026-10-31T17:17:31.488654+00:00"
},
"receipt_sha256": "c26d636f59109956f281ad46f4885c4db800a9553cf05cac324aa3155ef7ac40",
"original_execution_packet_matches": true,
"live_desired_fields_verified": true,
"runtime_config_verified": true,
"existing_image_and_pvc_preserved": true,
"runtime_modified_by_verification": false
}

View file

@ -1,41 +0,0 @@
{
"schema": "coulomb.content-acceptance-independent-postflight.v1",
"status": "deployed_image_and_complete_native_state_verified",
"proposal_digest": "sha256:e96752ecfa7adef2fd1d9da48902c8e63de124ccfd272fe20ba79b758b3ca4a3",
"receipt_sha256": "074ec03d62d43f35bd6c276213a28de4a7b0161132379221bec0e402b5334233",
"helm_revision": 20,
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"source": "1139a6d30eee4f75317b46bd45120a15d818455f",
"packaged_source_files_verified": 79,
"sole_ready_content_writer": true,
"all_frozen_capsule_files_verified": 23,
"installed_helper_hashes_verified": true,
"snapshot_pin_refreshed": true,
"public_health_landing_static_verified": true,
"postflight": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"fresh_paired_point": {
"captured_at": "2026-10-31T20:21:01Z",
"destination": "s3://railiance-platform-pg-backup/platform-pg/application-archives/coulomb-social/2026/10/31/20261031T202101Z-2ad4faf215939d67e82f67a4.tar.age",
"version_id": "1793478121590106",
"encrypted_sha256": "91b4ffe4874a53e3422d604b7c3fa85f6551a481411ef82b2209993552486bfb",
"encrypted_bytes": 2181848,
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed"
},
"timers_activated": false,
"production_data_restored": false,
"productive_acceptance_inferred": false
}

View file

@ -1,39 +0,0 @@
{
"schema": "coulomb.acceptance-baseline-change.v1",
"retained_point": "2026-10-31T20:21:01Z",
"old_business_rows": 93,
"new_business_rows": 97,
"table_changes": {
"spaces_space": {
"old": 2,
"new": 4,
"removed": 0,
"added": 2
},
"spaces_spacemembership": {
"old": 1,
"new": 3,
"removed": 0,
"added": 2
}
},
"old_content_files": 86,
"new_content_files": 98,
"old_files_missing": 0,
"old_files_changed": 0,
"new_files_added": 12,
"old_rows_preserved": true,
"current_baseline": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 97,
"business_rows_sha256": "35b0ae7d9dd1ff21c2ceaa04649162545ec36a2c68629548238352d9cd0fb303",
"content_files": 98,
"content_files_sha256": "b657c0e470399b6c7500da500cbbec061bea12ab9633bd74e2f142d797b2d26a",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"interpretation": "Changes observed during the user-requested productive acceptance session; no user verdict inferred."
}

View file

@ -1,45 +0,0 @@
{
"schema": "coulomb.content-acceptance-build.v1",
"completed_at": "2026-10-31T21:13:04.039838+00:00",
"source": "31eaa581a65e454b6ef9979326c5bdfe10e13806",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e",
"build_context": "clean restricted git archive",
"source_full_gate_tests": 568,
"runtime_packages_and_python_unchanged": true,
"runtime": {
"python": "3.12.16",
"distributions": {
"h11": "0.16.0",
"httpcore": "1.0.9",
"psycopg": "3.3.4",
"joserfc": "1.7.4",
"anyio": "4.14.2",
"cryptography": "50.0.0",
"idna": "3.18",
"certifi": "2026.7.22",
"packaging": "26.3",
"python-decouple": "3.8",
"psycopg-binary": "3.3.4",
"sqlparse": "0.5.5",
"whitenoise": "6.12.0",
"cffi": "2.1.1",
"markdown": "3.10.3",
"webencodings": "0.5.1",
"pycparser": "3.0",
"bleach": "6.4.0",
"authlib": "1.7.2",
"django": "6.1",
"typing_extensions": "4.16.0",
"gunicorn": "26.0.0",
"asgiref": "3.12.1",
"httpx": "0.28.1",
"dj-database-url": "3.1.2"
}
},
"django_checks": {
"check": "System check identified no issues (0 silenced).",
"makemigrations": "No changes detected"
},
"new_database_migrations": false,
"production_deployed": false
}

View file

@ -1,11 +0,0 @@
{
"schema": "coulomb.packaged-source-provenance.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e",
"source": "31eaa581a65e454b6ef9979326c5bdfe10e13806",
"packaged_file_count": 79,
"all_packaged_source_bytes_match": true,
"source_revision_label_verified": true,
"registry_digest_resolves": true,
"application_source_overlay": false,
"manifest_sha256": "99401a60fdd9a95aff1168858e81fd7d8802cd7603f15c0ea35eb6917981f9fe"
}

View file

@ -1,67 +0,0 @@
{
"schema": "coulomb.packaged-content-acceptance-recovery.v1",
"status": "packaged_recovered_export_and_views_verified",
"source": "31eaa581a65e454b6ef9979326c5bdfe10e13806",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e",
"restore_receipt_sha256": "9dacbd44544f93abf99354158cf610b4fb1f4e59611b22056b3086e0033231ab",
"retained_point_captured_at": "2026-10-31T20:21:01Z",
"candidate_application": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"previous_image_application": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 93,
"business_rows_sha256": "7953b37b02b80d89ca6869dab6b2b0b996541de20ca0dd1b294a5f25572fb2ca",
"content_files": 86,
"content_files_sha256": "ed535246f4e8f46fcd7ce01f936127996aff873c6936b297f7272194b594aeda",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0,
"actual_owner_pages_rendered": 40,
"unsaved_outsider_page_denials": 40,
"production_identity_or_grant_created": false
},
"client_export": {
"status": "recovered_client_export_verified",
"schema": "coulomb.client-dataset-export.v1",
"content_files": 85,
"records": {
"members.user": 1,
"members.member": 1,
"spaces.space": 1,
"spaces.spacemembership": 1
},
"admin_events": 0,
"archive_sha256": "ecf5dba7ce891475cd5df15eb30205606f805850af7339ecd46e1479b45d6c5f",
"offboarding_complete": false,
"all_source_tables_compared": 13,
"all_source_files_compared": 86,
"archive_member_hashes_verified": true,
"selected_client_content_complete_locally": true,
"source_sql_and_content_unchanged": true,
"external_bindings_require_review": 0,
"sessions_and_credentials_excluded": true
},
"source_content_files_unchanged": 86,
"all_tables_unchanged": true,
"application_source_overlay": false,
"network_internal": true,
"published_ports": 0,
"production_access": false,
"production_restore": false,
"driver_sha256": "29c53d551eec2b4f4d60b047f123c727eef76ee7677c054bbfb0ab008355cff9"
}

View file

@ -1,21 +0,0 @@
{
"baseline_revision": 20,
"baseline_helm_manifest_sha256": "e388f62c97e97d54d87671825bd0b05c854a70b0cca8a00faee452ae7841799e",
"deployment_uid": "2dbe661a-d232-4477-bbd1-833813077fbe",
"baseline_spec_sha256": "8d79c64cff4bd2c62f03494e80847dc99b965ddabf35645da67e8d1020220798",
"candidate_spec_sha256": "4deab26fc15d63e09922259b3362cd4e5c6bfa10884de058f776c0de8b642b00",
"old_image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:7906f461bc8d2d5204fd4fde67a251850f725b914452a66172919d6853672ed5",
"expected_data": {
"business_tables": 12,
"migration_rows_sha256": "43471516387c0e2a3d35971033ed6af330e2963efe4da93293d97633825d04af",
"business_rows": 97,
"business_rows_sha256": "35b0ae7d9dd1ff21c2ceaa04649162545ec36a2c68629548238352d9cd0fb303",
"content_files": 98,
"content_files_sha256": "b657c0e470399b6c7500da500cbbec061bea12ab9633bd74e2f142d797b2d26a",
"global_slug_constraint": true,
"tenant_slug_constraint": true,
"migration_0003_applied": true,
"duplicate_slug_groups": 0
},
"image_only_server_preview": true
}

View file

@ -1,13 +0,0 @@
{
"schema": "coulomb.packaged-content-acceptance-tests.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e",
"source": "31eaa581a65e454b6ef9979326c5bdfe10e13806",
"tests": 110,
"failures": 0,
"errors": 0,
"skipped": 0,
"network": "none",
"read_only_root": true,
"application_source_overlay": false,
"synthetic_fixtures_only": true
}

View file

@ -1,34 +0,0 @@
{
"schema": "coulomb.editor-attachments-validation.v1",
"reported_gap": "Attachments visible on the original page were absent from editor tabs.",
"main_source": "8b38afddf3f3648f209c60b1bafe3dd25501d857",
"release_source": "31eaa581a65e454b6ef9979326c5bdfe10e13806",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e",
"main_full_gate": {
"tests": 670,
"failures": 0,
"errors": 0,
"skipped": 0
},
"release_full_gate": {
"tests": 568,
"failures": 0,
"errors": 0,
"skipped": 0
},
"packaged_tests": 110,
"browser_verifies": [
"saved file list and exact download bytes in both editor tabs",
"management opens separately and keeps unsaved text",
"stale refusal keeps submitted text and attachments",
"save keeps attachments and rejects stale overwrite",
"existing copy/move/download/detach permissions journey"
],
"runtime_changes": [
"coulomb_social/apps/spaces/views.py",
"coulomb_social/templates/spaces/page_form.html"
],
"storage_schema_or_authority_changed": false,
"productive_acceptance_inferred": false,
"test_environment": "Main uses /var/tmp; isolated branch native observer requires /tmp. Final complete gates pass without deselection."
}

View file

@ -1,175 +0,0 @@
#!/usr/bin/env python3
"""Node-side quiesced coulomb-social snapshot. Binary output stays private.
Run on railiance01 after reviewed live approval. Does not restore production.
Default is server dry-run; --execute briefly pauses the app and captures a
paired pg_dump/content archive. A separate isolated restore must validate it.
"""
from __future__ import annotations
import argparse
import fcntl
import hashlib
import json
import os
import signal
import stat
import subprocess
import sys
import time
from pathlib import Path
NS = 'coulomb-social'
IMAGE = ('forgejo.coulomb.social/coulomb/coulomb-social@sha256:'
'b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e')
CLUSTER_UID = 'a553c742-0115-43d4-99a4-a5ca56fe0786'
LOCK_PATH = Path('/var/lib/coulomb-social-backup/snapshot.lock')
class Refused(RuntimeError):
pass
def run(args: list[str], *, payload: bytes | None = None, timeout: int = 180) -> bytes:
p = subprocess.run(args, input=payload, capture_output=True, timeout=timeout)
if p.returncode:
raise Refused('command_failed')
return p.stdout
def k(*args: str, payload: bytes | None = None) -> bytes:
return run(['kubectl', *args], payload=payload)
def document(*args: str) -> dict:
return json.loads(k(*args, '-o', 'json'))
def private_write(path: Path, value: bytes) -> None:
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, 'wb') as f:
f.write(value)
def snapshot() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--execute', action='store_true')
parser.add_argument('--destination', type=Path, required=True)
args = parser.parse_args()
os.environ['KUBECONFIG'] = '/etc/rancher/k3s/k3s.yaml'
started = time.monotonic()
if document('get', 'namespace', 'kube-system')['metadata']['uid'] != CLUSTER_UID:
raise Refused('wrong_cluster')
dep = document('get', 'deployment', 'coulomb-social', '-n', NS)
spec = dep['spec']['template']['spec']
if dep['spec']['replicas'] != 1 or spec['containers'][0]['image'] != IMAGE:
raise Refused('unexpected_release')
if document('get', 'pvc', 'coulomb-social-content', '-n', NS)['status']['phase'] != 'Bound':
raise Refused('pvc_not_bound')
cluster = document('get', 'cluster', 'apps-pg', '-n', 'databases')
primary = cluster['status']['currentPrimary']
name = 'csoc-paired-snapshot-' + time.strftime('%Y%m%d%H%M%S', time.gmtime())
pod = {
'apiVersion': 'v1', 'kind': 'Pod',
'metadata': {'name': name, 'namespace': NS, 'labels': {'csoc-recovery': name}},
'spec': {
'restartPolicy': 'Never', 'automountServiceAccountToken': False,
'securityContext': {'runAsNonRoot': True, 'runAsUser': 10001,
'runAsGroup': 10001, 'fsGroup': 10001,
'fsGroupChangePolicy': 'OnRootMismatch'},
'containers': [{'name': 'snapshot', 'image': IMAGE,
'command': ['python', '-c', 'import time;time.sleep(1800)'],
'resources': {'requests': {'cpu': '10m', 'memory': '64Mi'},
'limits': {'cpu': '100m', 'memory': '256Mi'}},
'securityContext': {'allowPrivilegeEscalation': False,
'readOnlyRootFilesystem': True,
'capabilities': {'drop': ['ALL']}},
'volumeMounts': [{'name': 'content', 'mountPath': '/snapshot', 'readOnly': True}]}],
'volumes': [{'name': 'content', 'persistentVolumeClaim':
{'claimName': 'coulomb-social-content', 'readOnly': True}}],
},
}
body = json.dumps(pod).encode()
k('create', '--dry-run=server', '-f', '-', payload=body)
if not args.execute:
print(json.dumps({'status': 'reviewed', 'server_dry_run': True,
'image_pinned': True, 'pvc_read_only': True,
'db_scope': 'coulomb_social_db', 'replicas_restored_to': 1}))
return 0
dest = args.destination
if not dest.is_absolute() or dest.exists():
raise Refused('destination_must_be_new_absolute_directory')
dest.mkdir(mode=0o700)
paused = False
created = False
receipt = {'status': 'incomplete', 'app': 'coulomb-social',
'database': 'coulomb_social_db', 'image': IMAGE,
'started_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
try:
paused = True
k('scale', 'deployment/coulomb-social', '-n', NS, '--replicas=0')
k('wait', '--for=delete', 'pod', '-n', NS,
'-l', 'app.kubernetes.io/instance=coulomb-social', '--timeout=120s')
created = True
k('create', '-f', '-', payload=body)
k('wait', '--for=condition=Ready', 'pod/' + name, '-n', NS, '--timeout=120s')
dump = k('exec', '-n', 'databases', primary, '-c', 'postgres', '--',
'pg_dump', '-U', 'postgres', '-d', 'coulomb_social_db', '-Fc')
if not dump.startswith(b'PGDMP'):
raise Refused('invalid_pg_dump')
private_write(dest / 'database.dump', dump)
archive_code = ('import io,sys,tarfile; b=io.BytesIO(); '
't=tarfile.open(fileobj=b,mode="w:gz"); '
't.add("/snapshot",arcname="content"); '
't.close();sys.stdout.buffer.write(b.getvalue())')
content = k('exec', '-n', NS, name, '--', 'python', '-c', archive_code)
private_write(dest / 'content.tar.gz', content)
receipt.update(status='captured', writers_quiesced=True,
database_sha256=hashlib.sha256(dump).hexdigest(),
content_sha256=hashlib.sha256(content).hexdigest(),
database_bytes=len(dump), content_bytes=len(content))
finally:
try:
if created:
k('delete', 'pod', name, '-n', NS, '--wait=true', '--timeout=120s')
finally:
if paused:
k('scale', 'deployment/coulomb-social', '-n', NS, '--replicas=1')
k('rollout', 'status', 'deployment/coulomb-social', '-n', NS, '--timeout=180s')
receipt['app_resumed'] = True
receipt['elapsed_seconds'] = round(time.monotonic() - started, 2)
private_write(dest / 'receipt.json', json.dumps(receipt, indent=2).encode())
print(json.dumps(receipt))
return 0
def main() -> int:
if '--execute' not in sys.argv:
return snapshot()
LOCK_PATH.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
parent = LOCK_PATH.parent.lstat()
if (not stat.S_ISDIR(parent.st_mode) or parent.st_uid != os.geteuid()
or parent.st_mode & 0o077):
raise Refused('lock_directory_not_private')
fd = os.open(LOCK_PATH, os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600)
with os.fdopen(fd, 'w') as lock:
try:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
raise Refused('snapshot_already_running') from None
def terminate(signum, frame):
raise Refused('snapshot_interrupted')
previous = signal.signal(signal.SIGTERM, terminate)
try:
return snapshot()
finally:
signal.signal(signal.SIGTERM, previous)
if __name__ == '__main__':
try:
sys.exit(main())
except Exception as exc:
# Never expose child output, kubectl objects, credentials or raw exception messages.
print(json.dumps({'status': 'failed', 'failure_type': type(exc).__name__}))
sys.exit(1)

View file

@ -1,50 +0,0 @@
# Production overrides for coulomb-social.
# Non-secret values only. Secrets live in K8s Secret coulomb-social-env.
image:
repository: forgejo.coulomb.social/coulomb/coulomb-social
tag: "31eaa581a65e"
digest: "sha256:b58d858abd5b4acbd6b893c3f622f7a9fdb5e606164ab9866eb3cfaa04df1a0e"
# Public host: app.coulomb.social (parallel to Bubble on apex coulomb.social).
# Apex cutover is deferred until data + self-registration are ready.
env:
DJANGO_SETTINGS_MODULE: coulomb_social.settings.prod
ALLOWED_HOSTS: app.coulomb.social,localhost
CSRF_TRUSTED_ORIGINS: https://app.coulomb.social
CONTENT_ROOT: /app/var/content
DEFAULT_TENANT_ID: "tenant:coulomb"
OIDC_ENABLED: "true"
OIDC_ISSUER: https://kc.coulomb.social
OIDC_CLIENT_ID: coulomb-social
OIDC_REDIRECT_URI: https://app.coulomb.social/auth/callback/
OIDC_SCOPES: "openid profile email groups"
USER_ENGINE_BASE_URL: https://users.coulomb.social
USER_ENGINE_APPLICATION_ID: coulomb-social
USER_ENGINE_EXPECTED_AUDIENCE: user-engine-portal
NETKINGDOM_REGISTRATION_URL: https://users.92-205-62-239.nip.io/register
probes:
hostHeader: app.coulomb.social
path: /healthz
# One writable local-path volume; Recreate prevents concurrent old/new writers.
replicaCount: 1
deploymentStrategy: Recreate
persistence:
content:
enabled: true
storageClass: local-path
size: 2Gi
mountPath: /app/var/content
retain: true
# Wave-2 right-sizing (CSOC-WP-0017-T01, 2026-10-21 node budget): 7d p95
# 0.4m CPU / 146Mi. Limits stay at the chart defaults (1000m/1Gi).
resources:
requests:
cpu: 15m
memory: 176Mi
limits:
cpu: 1000m
memory: 1Gi

View file

@ -1,95 +0,0 @@
{
"schema": "coulomb.identity-export-candidate-build.v1",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"tag": "forgejo.coulomb.social/coulomb/coulomb-social:23ffe2cf4b21",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"registry_digest_independently_verified": true,
"source_revision_label_verified": true,
"build_context": "git archive of exact source; Dockerfile, dockerignore, lock, project, manage.py, app and entrypoint only",
"build_inputs": {
"Dockerfile": "d0e197a18db8980eb3e51cca842d693e10ab0b4208627bba28691d10719d4a00",
".dockerignore": "901c8b95d95549d0e78c1c3d6d0538bf0252c8a77e9409129e0cadfa55c7c56c",
"pyproject.toml": "5758c56fd1be89b973861ccc5ecbadb495e742ee13ebd7e19a221a0f119c54ee",
"uv.lock": "e8ebb6fc4b5abd1ac80f1c9012f1983642d0528a8a213cfcc394261606fad887",
"scripts/docker-entrypoint.sh": "70100256ca41ae6afe77078c810a8b6012472f0a741919f403f32088f98ab463"
},
"runtime": {
"live": {
"python": "3.12.16",
"distributions": {
"anyio": "4.14.2",
"asgiref": "3.12.1",
"authlib": "1.7.2",
"bleach": "6.4.0",
"certifi": "2026.7.22",
"cffi": "2.1.1",
"cryptography": "50.0.0",
"dj-database-url": "3.1.2",
"django": "6.1",
"gunicorn": "26.0.0",
"h11": "0.16.0",
"httpcore": "1.0.9",
"httpx": "0.28.1",
"idna": "3.18",
"joserfc": "1.7.4",
"markdown": "3.10.3",
"packaging": "26.3",
"psycopg": "3.3.4",
"psycopg-binary": "3.3.4",
"pycparser": "3.0",
"python-decouple": "3.8",
"sqlparse": "0.5.5",
"typing_extensions": "4.16.0",
"webencodings": "0.5.1",
"whitenoise": "6.12.0"
}
},
"candidate": {
"python": "3.12.16",
"distributions": {
"anyio": "4.14.2",
"asgiref": "3.12.1",
"authlib": "1.7.2",
"bleach": "6.4.0",
"certifi": "2026.7.22",
"cffi": "2.1.1",
"cryptography": "50.0.0",
"dj-database-url": "3.1.2",
"django": "6.1",
"gunicorn": "26.0.0",
"h11": "0.16.0",
"httpcore": "1.0.9",
"httpx": "0.28.1",
"idna": "3.18",
"joserfc": "1.7.4",
"markdown": "3.10.3",
"packaging": "26.3",
"psycopg": "3.3.4",
"psycopg-binary": "3.3.4",
"pycparser": "3.0",
"python-decouple": "3.8",
"sqlparse": "0.5.5",
"typing_extensions": "4.16.0",
"webencodings": "0.5.1",
"whitenoise": "6.12.0"
}
},
"runtime_packages_equal": true,
"python_versions_equal": true
},
"production_deployed": false,
"live_release_pins_modified": false,
"new_database_migrations": false,
"not_an_offboarding_or_transfer_acceptance": true,
"source_manifest_sha256": "a90b0217c6424a89e166a7df514fe4a86c9643b502ecdc9ebf0b64b76c06b739",
"packaged_django_check": "passed",
"packaged_migration_drift_check": "passed_no_changes_detected",
"source_gate": {
"command": "make check",
"tests": 441,
"failures": 0,
"errors": 0,
"skipped": 0,
"junit_sha256": "1e5b3c63d85a23f176420f2004831b59406d294c1528b3be80d49669edbb116f"
}
}

View file

@ -1,20 +0,0 @@
{
"schema": "coulomb.packaged-source-provenance.v1",
"image": "forgejo.coulomb.social/coulomb/coulomb-social@sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"network": "none",
"read_only_root": true,
"entrypoint_bypassed": true,
"database_contact": false,
"production_changes": false,
"comparisons": [
{
"commit": "23ffe2cf4b214666754a2420558943438e54251a",
"packaged_file_count": 80,
"source_file_count": 80,
"different_files": 0,
"all_packaged_source_bytes_match": true
}
],
"actual_packaged_manifest_sha256": "6b5a7b339d88f3c5eafb70a33aa28a7d3972988645b246ae1a92a3f159d72528",
"dependency_or_build_reproducibility_proved": false
}

View file

@ -1,63 +0,0 @@
{
"schema": "coulomb.packaged-identity-export-recovery.v1",
"status": "packaged_recovered_client_export_and_views_verified",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"image_id": "sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"restore_receipt_sha256": "b648348780f87f81094b40876a6b0ebabaefff7986cf20fb426c3d7456a0bc84",
"client_export": {
"status": "recovered_client_export_verified",
"schema": "coulomb.client-dataset-export.v1",
"content_files": 85,
"records": {
"members.user": 1,
"members.member": 1,
"spaces.space": 1,
"spaces.spacemembership": 1
},
"admin_events": 0,
"archive_sha256": "8efa82e7c29c95840d61d1290e20cac4b8acf5ae33d2c5b632382a7f6b779c37",
"offboarding_complete": false,
"all_source_tables_compared": 13,
"all_source_files_compared": 86,
"archive_member_hashes_verified": true,
"selected_client_content_complete_locally": true,
"source_sql_and_content_unchanged": true,
"external_bindings_require_review": 0,
"sessions_and_credentials_excluded": true
},
"candidate_application": {
"status": "isolated_application_recovery_verified",
"recovered_spaces_with_content": 1,
"actual_pages_rendered_through_view": 40,
"restored_owner_access_verified": true,
"synthetic_viewer_reads": 1,
"synthetic_viewer_mutation_denials": 1,
"same_tenant_ungranted_page_denials": 40,
"fixture_transaction_rolled_back": true,
"production_access": false,
"external_identity_provider_used": false,
"real_browser_journey_verified": false
},
"previous_image_application": {
"status": "isolated_application_recovery_verified",
"recovered_spaces_with_content": 1,
"actual_pages_rendered_through_view": 40,
"restored_owner_access_verified": true,
"synthetic_viewer_reads": 1,
"synthetic_viewer_mutation_denials": 1,
"same_tenant_ungranted_page_denials": 40,
"fixture_transaction_rolled_back": true,
"production_access": false,
"external_identity_provider_used": false,
"real_browser_journey_verified": false
},
"source_content_files_unchanged": 86,
"application_source_overlay": false,
"export_archive_removed": true,
"network_internal": true,
"published_ports": 0,
"production_access": false,
"production_restore": false,
"post_date_correction_data_claimed": false,
"driver_sha256": "9c370b6e7e1acb442cb660cc3709e3ffd3676c87419a217a7656174c8a347f95"
}

View file

@ -1,17 +0,0 @@
{
"schema": "coulomb.packaged-identity-export-tests.v1",
"source": "23ffe2cf4b214666754a2420558943438e54251a",
"image_id": "sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed",
"tests": 25,
"failures": 0,
"errors": 0,
"skipped": 0,
"network": "none",
"read_only_root": true,
"application_source_overlay": false,
"test_tooling_injected": true,
"application_modules_from_image_verified": true,
"production_access": false,
"junit_sha256": "85aac22d33a101d68e478f41f61bc3c7e7adb4f3d7f893a2810f7eb25fce5a39",
"driver_sha256": "a19f94f3dbc71dfd80a2d380f03e5f737c7453b64df022b6e5c2ede8141976b3"
}

View file

@ -1,50 +0,0 @@
# Production overrides for coulomb-social.
# Non-secret values only. Secrets live in K8s Secret coulomb-social-env.
image:
repository: forgejo.coulomb.social/coulomb/coulomb-social
tag: "23ffe2cf4b21"
digest: "sha256:522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed"
# Public host: app.coulomb.social (parallel to Bubble on apex coulomb.social).
# Apex cutover is deferred until data + self-registration are ready.
env:
DJANGO_SETTINGS_MODULE: coulomb_social.settings.prod
ALLOWED_HOSTS: app.coulomb.social,localhost
CSRF_TRUSTED_ORIGINS: https://app.coulomb.social
CONTENT_ROOT: /app/var/content
DEFAULT_TENANT_ID: "tenant:coulomb"
OIDC_ENABLED: "true"
OIDC_ISSUER: https://kc.coulomb.social
OIDC_CLIENT_ID: coulomb-social
OIDC_REDIRECT_URI: https://app.coulomb.social/auth/callback/
OIDC_SCOPES: "openid profile email groups"
USER_ENGINE_BASE_URL: https://users.coulomb.social
USER_ENGINE_APPLICATION_ID: coulomb-social
USER_ENGINE_EXPECTED_AUDIENCE: user-engine-portal
NETKINGDOM_REGISTRATION_URL: https://users.92-205-62-239.nip.io/register
probes:
hostHeader: app.coulomb.social
path: /healthz
# One writable local-path volume; Recreate prevents concurrent old/new writers.
replicaCount: 1
deploymentStrategy: Recreate
persistence:
content:
enabled: true
storageClass: local-path
size: 2Gi
mountPath: /app/var/content
retain: true
# Wave-2 right-sizing (CSOC-WP-0017-T01, 2026-10-21 node budget): 7d p95
# 0.4m CPU / 146Mi. Limits stay at the chart defaults (1000m/1Gi).
resources:
requests:
cpu: 15m
memory: 176Mi
limits:
cpu: 1000m
memory: 1Gi

View file

@ -21,7 +21,7 @@ from pathlib import Path
NS = 'coulomb-social'
IMAGE = ('forgejo.coulomb.social/coulomb/coulomb-social@sha256:'
'522bcd7fce92436765a60c1e4afa2598f3cc40913352153ff1c4319a99ca92ed')
'512819463a1902b43a615beee14be7bf97e6a05e016385082b9380692ad1a8cd')
CLUSTER_UID = 'a553c742-0115-43d4-99a4-a5ca56fe0786'
LOCK_PATH = Path('/var/lib/coulomb-social-backup/snapshot.lock')

View file

@ -1,364 +0,0 @@
"""Synthetic release safety cases; no cluster, credentials or real content."""
import copy
import importlib.util
import json
import os
import stat
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
SOURCE = Path(__file__).resolve().parents[1] / "tools/coulomb_image_release_node.py"
spec = importlib.util.spec_from_file_location("storage_release", SOURCE)
release = importlib.util.module_from_spec(spec)
spec.loader.exec_module(release)
launcher_spec = importlib.util.spec_from_file_location("storage_launcher", SOURCE.with_name("coulomb-image-release.py"))
launcher = importlib.util.module_from_spec(launcher_spec)
launcher_spec.loader.exec_module(launcher)
def capsule(tmp_path):
root = tmp_path / "capsule"
root.mkdir()
(root / "probe.py").write_bytes(b"synthetic read-only probe")
plan = {"files": {"probe.py": release.sha((root / "probe.py").read_bytes())}}
(root / "manifest.json").write_text(json.dumps(plan))
return root, "sha256:" + release.sha(release.canonical(plan))
def test_capsule_tampering_refuses_before_privileged_work(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
(root / "probe.py").write_bytes(b"changed")
with pytest.raises(release.Refused, match="capsule_file_differs"):
release.Release(root, digest)
assert not (tmp_path / "journal").exists()
def test_preflight_never_creates_an_execution_journal(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
instance = release.Release(root, digest, read_only=True)
instance.save()
assert not (tmp_path / "journal").exists()
def test_prior_attempt_is_not_blindly_replayed(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
journal = tmp_path / "journal"
(journal / digest.removeprefix("sha256:")).mkdir(parents=True)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", journal)
with pytest.raises(release.Refused, match="prior_execution_requires_review"):
release.Release(root, digest)
def test_mutable_staging_is_frozen_before_live_work(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
instance = release.Release(root, digest)
(root / "probe.py").write_bytes(b"changed after verification")
assert (instance.root / "probe.py").read_bytes() == b"synthetic read-only probe"
assert (instance.journal / "receipt.json").is_file()
def test_nested_capsule_and_release_root_stay_private_under_normal_umask(tmp_path, monkeypatch):
root, _ = capsule(tmp_path)
nested = root / "charts/coulomb/templates/deployment.yaml"
nested.parent.mkdir(parents=True)
nested.write_bytes(b"synthetic chart")
plan = {"files": {str(p.relative_to(root)): release.sha(p.read_bytes())
for p in root.rglob("*") if p.is_file() and p.name != "manifest.json"}}
(root / "manifest.json").write_text(json.dumps(plan))
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
previous = os.umask(0o022)
try:
instance = release.Release(root, "sha256:" + release.sha(release.canonical(plan)))
finally:
os.umask(previous)
for path in [tmp_path / "journal", *(tmp_path / "journal").rglob("*")]:
assert stat.S_IMODE(path.stat().st_mode) == (0o700 if path.is_dir() else 0o600)
assert (instance.root / nested.relative_to(root)).read_bytes() == b"synthetic chart"
@pytest.mark.parametrize("problem", ["broad", "link", "ancestor_link", "file"])
def test_unsafe_release_parent_is_refused_without_changing_it(tmp_path, monkeypatch, problem):
root, digest = capsule(tmp_path)
journal = tmp_path / "journal"
if problem == "broad":
journal.mkdir(mode=0o755)
elif problem == "file":
journal.write_text("untouched")
elif problem == "link":
journal.symlink_to(root, target_is_directory=True)
else:
alias = tmp_path / "alias"
alias.symlink_to(root, target_is_directory=True)
journal = alias / "journal"
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", journal)
before = {str(p): p.lstat() for p in tmp_path.rglob("*")}
with pytest.raises((release.Refused, OSError)):
release.Release(root, digest)
assert before == {str(p): p.lstat() for p in tmp_path.rglob("*")}
@pytest.mark.parametrize("field", ["business_rows_sha256", "content_files_sha256", "migration_rows_sha256"])
def test_dataset_drift_is_not_accepted(field):
instance = object.__new__(release.Release)
baseline = {"business_tables": 2, "business_rows": 3, "business_rows_sha256": "synthetic-a",
"content_files": 4, "content_files_sha256": "synthetic-b",
"migration_rows_sha256": "synthetic-migrations"}
instance.plan = {"expected_data": baseline}
changed = dict(baseline, duplicate_slug_groups=0, tenant_slug_constraint=True)
changed[field] = "different"
with pytest.raises(release.Refused, match="dataset_drifted"):
instance.same_data(changed)
def test_failed_preflight_never_captures_or_upgrades():
instance = object.__new__(release.Release)
instance.preflight = Mock(side_effect=release.Refused("guard stopped"))
instance.capture = Mock()
instance.command = Mock()
with pytest.raises(release.Refused):
instance.execute()
instance.capture.assert_not_called()
instance.command.assert_not_called()
@pytest.mark.parametrize("rollback_spec,rollback_ready,verified", [
({"synthetic": "old"}, 1, True),
({"synthetic": "candidate"}, 1, False),
({"synthetic": "old"}, 0, False),
])
def test_postflight_failure_rolls_back_image_without_restoring_data(
tmp_path, monkeypatch, rollback_spec, rollback_ready, verified):
pin = tmp_path / "snapshot.py"
pin.write_bytes(b"old pin")
monkeypatch.setattr(release, "SNAPSHOT", pin)
instance = object.__new__(release.Release)
instance.receipt = {}
instance.root = tmp_path
spec = {"synthetic": "candidate"}
baseline = {"business_tables": 2, "business_rows": 3, "business_rows_sha256": "synthetic-a",
"content_files": 4, "content_files_sha256": "synthetic-b",
"migration_rows_sha256": "synthetic-migrations"}
instance.plan = {"candidate_spec_sha256": release.sha(release.canonical(spec)), "baseline_revision": 18,
"baseline_spec_sha256": release.sha(release.canonical({"synthetic": "old"})),
"expected_data": baseline}
instance.preflight = Mock()
instance.capture = Mock()
instance.save = Mock()
instance.deployment = Mock(side_effect=[
{"spec": copy.deepcopy(spec), "status": {"readyReplicas": 1}},
{"spec": rollback_spec, "status": {"readyReplicas": rollback_ready}},
])
instance.probe = lambda mode: dict(baseline, business_rows_sha256="changed")
instance.command = Mock(return_value=SimpleNamespace(stdout=b"", returncode=0))
instance.restore_pin = Mock()
with pytest.raises(release.Refused, match="dataset_drifted"):
instance.execute()
commands = [call.args[0] for call in instance.command.call_args_list]
assert commands[0][:2] == ["helm", "upgrade"] and "--atomic" in commands[0]
assert commands[1][:4] == ["helm", "rollback", "coulomb-social", "18"]
assert not any("pg_restore" in command for command in commands)
instance.restore_pin.assert_called_once_with(b"old pin")
assert instance.receipt["image_rollback_completed"] is verified
def test_live_launcher_rejects_unattended_execution_before_ssh(monkeypatch):
_, digest, _ = launcher.prepare()
monkeypatch.setattr(launcher.sys, "argv", ["release", "--execute", "--expect-digest", digest])
monkeypatch.setattr(launcher.sys, "stdin", SimpleNamespace(isatty=lambda: False))
command = Mock()
monkeypatch.setattr(launcher.subprocess, "run", command)
with pytest.raises(SystemExit, match="own terminal"):
launcher.main()
command.assert_not_called()
def test_timeout_gives_the_existing_capture_resume_window(monkeypatch):
instance = object.__new__(release.Release)
instance.env = {}
process = Mock()
process.communicate.side_effect = release.subprocess.TimeoutExpired(["synthetic"], 1)
monkeypatch.setattr(release.subprocess, "Popen", Mock(return_value=process))
with pytest.raises(release.Refused, match="cleanup_window"):
instance.command(["synthetic"], timeout=1)
process.terminate.assert_called_once()
process.wait.assert_called_once_with(timeout=450)
process.kill.assert_not_called()
@pytest.mark.parametrize("field", ["global_slug_constraint", "migration_0003_applied"])
@pytest.mark.parametrize("value", [False, None])
def test_image_only_release_requires_existing_migration_and_constraint(field, value):
instance = object.__new__(release.Release)
baseline = {"business_tables": 2, "business_rows": 3,
"business_rows_sha256": "rows", "content_files": 4,
"content_files_sha256": "files", "migration_rows_sha256": "migrations"}
instance.plan = {"expected_data": baseline}
observed = dict(baseline, duplicate_slug_groups=0, tenant_slug_constraint=True,
global_slug_constraint=True, migration_0003_applied=True)
instance.same_data(observed)
observed[field] = value
with pytest.raises(release.Refused, match="already_migrated_baseline_required"):
instance.same_data(observed)
def test_rollback_does_not_overwrite_unrecognized_snapshot_helper(tmp_path, monkeypatch):
pin = tmp_path / "snapshot.py"
pin.write_bytes(b"concurrent owner change")
monkeypatch.setattr(release, "SNAPSHOT", pin)
instance = object.__new__(release.Release)
instance.plan = {"files": {"release/identity-export-snapshot.py": release.sha(b"new pin")}}
with pytest.raises(release.Refused, match="snapshot_pin_changed_during_rollback"):
instance.restore_pin(b"old pin")
assert pin.read_bytes() == b"concurrent owner change"
def test_known_candidate_helper_can_be_rolled_back(tmp_path, monkeypatch):
pin = tmp_path / "snapshot.py"
pin.write_bytes(b"new pin")
monkeypatch.setattr(release, "SNAPSHOT", pin)
instance = object.__new__(release.Release)
instance.plan = {"files": {"release/identity-export-snapshot.py": release.sha(b"new pin")}}
instance.restore_pin(b"old pin")
assert pin.read_bytes() == b"old pin"
# A completed inverse can be checked again without changing it.
instance.restore_pin(b"old pin")
assert pin.read_bytes() == b"old pin"
def test_missing_installation_refuses_before_execution_journal(tmp_path, monkeypatch):
root, _ = capsule(tmp_path)
plan = json.loads((root / 'manifest.json').read_text())
plan['prerequisite_installation_digest'] = 'sha256:' + 'a' * 64
(root / 'manifest.json').write_text(json.dumps(plan))
digest = 'sha256:' + release.sha(release.canonical(plan))
monkeypatch.setattr(release.os, 'geteuid', lambda: 0)
monkeypatch.setattr(release, 'JOURNAL_ROOT', tmp_path / 'journal')
monkeypatch.setattr(release, 'INSTALL_RECEIPT', tmp_path / 'missing.json')
with pytest.raises(release.Refused, match='installation_required_before_image'):
release.Release(root, digest)
assert not (tmp_path / 'journal').exists()
@pytest.fixture
def installed(monkeypatch):
instance = object.__new__(release.Release)
digest = 'sha256:' + 'a' * 64
instance.plan = {'prerequisite_installation_digest': digest}
receipt = {'schema': 'coulomb.backup-source-supervised-installation.v1',
'proposal_digest': digest, 'status': 'sources_installed_units_inactive_verified',
'verified_targets': 19, 'timers_activated': False}
path = SimpleNamespace(parents=[], lstat=lambda: SimpleNamespace(
st_mode=stat.S_IFREG | 0o600, st_uid=0, st_nlink=1),
read_bytes=lambda: json.dumps(receipt).encode())
monkeypatch.setattr(release, 'INSTALL_RECEIPT', path)
state = {'active': 'inactive', 'enabled': 'disabled', 'jobs': b''}
def command(arguments):
if arguments[1] == 'list-jobs':
return SimpleNamespace(stdout=state['jobs'])
return SimpleNamespace(stdout=(f"LoadState=loaded\nActiveState={state['active']}\n"
f"UnitFileState={state['enabled']}\n").encode())
instance.command = Mock(side_effect=command)
return instance, receipt, state
def test_completed_installer_and_inactive_units_admit_release_prerequisite(installed):
instance, _, _ = installed
instance.verify_installation_prerequisite()
assert instance.command.call_count == 5
@pytest.mark.parametrize('field,value', [
('status', 'installation_requires_inspection'), ('verified_targets', 18),
('proposal_digest', 'sha256:' + 'b' * 64), ('timers_activated', True),
])
def test_wrong_or_incomplete_installation_never_checks_or_changes_units(installed, field, value):
instance, receipt, _ = installed
receipt[field] = value
with pytest.raises(release.Refused, match='verified_inactive_backup_installation'):
instance.verify_installation_prerequisite()
instance.command.assert_not_called()
@pytest.mark.parametrize('field,value', [('active', 'active'), ('enabled', 'enabled'),
('jobs', b'17 coulomb-social-paired-backup.service start waiting\n'),
('jobs', b'unrecognized job format\n')])
def test_active_enabled_or_queued_backup_refuses_image_release(installed, field, value):
instance, _, state = installed
state[field] = value
with pytest.raises(release.Refused):
instance.verify_installation_prerequisite()
assert all(c.args[0][1] in {'show', 'list-jobs'} for c in instance.command.call_args_list)
def test_an_explicit_release_plan_seals_its_own_artifacts(tmp_path, monkeypatch):
monkeypatch.setattr(launcher, 'ROOT', tmp_path)
paths = ['tools/coulomb-image-release.py', 'tools/coulomb_image_release_node.py',
'tools/coulomb_image_probe.py', 'release/next-values.yaml',
'release/next-snapshot.py', 'charts/coulomb-social/Chart.yaml',
'release/next-evidence/proof.json']
for name in paths:
path = tmp_path / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(('synthetic ' + name).encode())
plan = {'values_file': paths[3], 'snapshot_file': paths[4],
'evidence_directory': 'release/next-evidence',
'rehearsal_evidence_sha256': {'proof.json': release.sha((tmp_path / paths[-1]).read_bytes())}}
path = tmp_path / 'release/next.json'
path.write_text(json.dumps(plan))
prepared, digest, content = launcher.prepare(path)
assert set(content) == set(paths) | {'manifest.json'}
assert digest == 'sha256:' + release.sha(release.canonical(prepared))
plan['values_file'] = '../outside.yaml'
path.write_text(json.dumps(plan))
with pytest.raises(RuntimeError, match='release_paths'):
launcher.prepare(path)
@pytest.mark.parametrize('name', ['release/missing.yaml', '../outside.yaml', '/outside.yaml'])
def test_node_refuses_unsealed_artifact_reference_before_journal(tmp_path, monkeypatch, name):
root, _ = capsule(tmp_path)
plan = json.loads((root / 'manifest.json').read_text())
plan['values_file'] = name
(root / 'manifest.json').write_text(json.dumps(plan))
monkeypatch.setattr(release.os, 'geteuid', lambda: 0)
monkeypatch.setattr(release, 'JOURNAL_ROOT', tmp_path / 'journal')
with pytest.raises(release.Refused, match='reviewed_release_artifact'):
release.Release(root, 'sha256:' + release.sha(release.canonical(plan)))
assert not (tmp_path / 'journal').exists()
def test_initializer_refusal_is_structured_and_never_calls_execute(monkeypatch, capsys):
monkeypatch.setattr(release, 'Release', Mock(side_effect=release.Refused(
'inactive_backup_installation_required_before_image_release')))
monkeypatch.setattr(release.argparse.ArgumentParser, 'parse_args', lambda _: SimpleNamespace(
capsule=Path('/synthetic'), expect_digest='sha256:' + 'a' * 64,
execute=False, preflight=True))
with pytest.raises(SystemExit):
release.main()
result = json.loads(capsys.readouterr().out)
assert result['execution_started'] is False
assert result['failure_reason'] == 'inactive_backup_installation_required_before_image_release'
def test_custom_snapshot_artifact_is_used_for_recognized_pin_rollback(tmp_path, monkeypatch):
path = tmp_path / 'snapshot.py'
path.write_bytes(b'new reviewed pin')
monkeypatch.setattr(release, 'SNAPSHOT', path)
instance = object.__new__(release.Release)
instance.plan = {'snapshot_file': 'release/next-snapshot.py',
'files': {'release/next-snapshot.py': release.sha(path.read_bytes())}}
instance.restore_pin(b'previous pin')
assert path.read_bytes() == b'previous pin'

View file

@ -0,0 +1,142 @@
"""Synthetic release safety cases; no cluster, credentials or real content."""
import copy
import importlib.util
import json
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
SOURCE = Path(__file__).resolve().parents[1] / "tools/coulomb_storage_release_node.py"
spec = importlib.util.spec_from_file_location("storage_release", SOURCE)
release = importlib.util.module_from_spec(spec)
spec.loader.exec_module(release)
launcher_spec = importlib.util.spec_from_file_location("storage_launcher", SOURCE.with_name("coulomb-storage-release.py"))
launcher = importlib.util.module_from_spec(launcher_spec)
launcher_spec.loader.exec_module(launcher)
def capsule(tmp_path):
root = tmp_path / "capsule"
root.mkdir()
(root / "probe.py").write_bytes(b"synthetic read-only probe")
plan = {"files": {"probe.py": release.sha((root / "probe.py").read_bytes())}}
(root / "manifest.json").write_text(json.dumps(plan))
return root, "sha256:" + release.sha(release.canonical(plan))
def test_capsule_tampering_refuses_before_privileged_work(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
(root / "probe.py").write_bytes(b"changed")
with pytest.raises(release.Refused, match="capsule_file_differs"):
release.Release(root, digest)
assert not (tmp_path / "journal").exists()
def test_preflight_never_creates_an_execution_journal(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
instance = release.Release(root, digest, read_only=True)
instance.save()
assert not (tmp_path / "journal").exists()
def test_prior_attempt_is_not_blindly_replayed(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
journal = tmp_path / "journal"
(journal / digest.removeprefix("sha256:")).mkdir(parents=True)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", journal)
with pytest.raises(release.Refused, match="prior_execution_requires_review"):
release.Release(root, digest)
def test_mutable_staging_is_frozen_before_live_work(tmp_path, monkeypatch):
root, digest = capsule(tmp_path)
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
instance = release.Release(root, digest)
(root / "probe.py").write_bytes(b"changed after verification")
assert (instance.root / "probe.py").read_bytes() == b"synthetic read-only probe"
assert (instance.journal / "receipt.json").is_file()
@pytest.mark.parametrize("field", ["business_rows_sha256", "content_files_sha256"])
def test_dataset_drift_is_not_accepted(field):
instance = object.__new__(release.Release)
baseline = {"business_tables": 2, "business_rows": 3, "business_rows_sha256": "synthetic-a",
"content_files": 4, "content_files_sha256": "synthetic-b"}
instance.plan = {"expected_data": baseline}
changed = dict(baseline, duplicate_slug_groups=0, tenant_slug_constraint=True)
changed[field] = "different"
with pytest.raises(release.Refused, match="dataset_drifted"):
instance.same_data(changed)
def test_failed_preflight_never_captures_or_upgrades():
instance = object.__new__(release.Release)
instance.preflight = Mock(side_effect=release.Refused("guard stopped"))
instance.capture = Mock()
instance.command = Mock()
with pytest.raises(release.Refused):
instance.execute()
instance.capture.assert_not_called()
instance.command.assert_not_called()
def test_postflight_failure_rolls_back_image_without_restoring_data(tmp_path, monkeypatch):
pin = tmp_path / "snapshot.py"
pin.write_bytes(b"old pin")
monkeypatch.setattr(release, "SNAPSHOT", pin)
instance = object.__new__(release.Release)
instance.receipt = {}
instance.root = tmp_path
spec = {"synthetic": "candidate"}
baseline = {"business_tables": 2, "business_rows": 3, "business_rows_sha256": "synthetic-a",
"content_files": 4, "content_files_sha256": "synthetic-b"}
instance.plan = {"candidate_spec_sha256": release.sha(release.canonical(spec)), "baseline_revision": 17,
"expected_data": baseline}
instance.preflight = Mock()
instance.capture = Mock()
instance.save = Mock()
instance.deployment = lambda: {"spec": copy.deepcopy(spec), "status": {"readyReplicas": 1}}
instance.probe = lambda mode: dict(baseline, business_rows_sha256="changed")
instance.command = Mock(return_value=SimpleNamespace(stdout=b"", returncode=0))
instance.restore_pin = Mock()
with pytest.raises(release.Refused, match="dataset_drifted"):
instance.execute()
commands = [call.args[0] for call in instance.command.call_args_list]
assert commands[0][:2] == ["helm", "upgrade"] and "--atomic" in commands[0]
assert commands[1][:4] == ["helm", "rollback", "coulomb-social", "17"]
assert not any("pg_restore" in command for command in commands)
instance.restore_pin.assert_called_once_with(b"old pin")
assert instance.receipt["image_rollback_completed"] is True
def test_live_launcher_rejects_unattended_execution_before_ssh(monkeypatch):
_, digest, _ = launcher.prepare()
monkeypatch.setattr(launcher.sys, "argv", ["release", "--execute", "--expect-digest", digest])
monkeypatch.setattr(launcher.sys, "stdin", SimpleNamespace(isatty=lambda: False))
command = Mock()
monkeypatch.setattr(launcher.subprocess, "run", command)
with pytest.raises(SystemExit, match="own terminal"):
launcher.main()
command.assert_not_called()
def test_timeout_gives_the_existing_capture_resume_window(monkeypatch):
instance = object.__new__(release.Release)
instance.env = {}
process = Mock()
process.communicate.side_effect = release.subprocess.TimeoutExpired(["synthetic"], 1)
monkeypatch.setattr(release.subprocess, "Popen", Mock(return_value=process))
with pytest.raises(release.Refused, match="cleanup_window"):
instance.command(["synthetic"], timeout=1)
process.terminate.assert_called_once()
process.wait.assert_called_once_with(timeout=450)
process.kill.assert_not_called()

View file

@ -19,39 +19,26 @@ import tarfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PLAN = ROOT / "release/coulomb-identity-export-23ffe2c.json"
PLAN = ROOT / "release/coulomb-storage-17d0eb6.json"
def canonical(value):
return json.dumps(value, sort_keys=True, separators=(",", ":")).encode()
def prepare(plan_path=None):
plan_path = plan_path or PLAN
if plan_path.is_symlink() or not plan_path.resolve().is_relative_to(ROOT.resolve()):
raise RuntimeError("reviewed_plan_inside_owner_repository_required")
plan = json.loads(plan_path.read_text())
values = plan.get("values_file", "release/identity-export-values.yaml")
snapshot = plan.get("snapshot_file", "release/identity-export-snapshot.py")
evidence = plan.get("evidence_directory", "release/identity-export-evidence")
for name in (values, snapshot, evidence):
if (not isinstance(name, str) or Path(name).is_absolute()
or ".." in Path(name).parts or not name.startswith("release/")):
raise RuntimeError("reviewed_release_paths_required")
if not all((ROOT / name).is_file() for name in (values, snapshot)):
raise RuntimeError("reviewed_release_artifacts_missing")
def prepare():
plan = json.loads(PLAN.read_text())
paths = [
ROOT / name
for name in (
"tools/coulomb-image-release.py",
"tools/coulomb_image_release_node.py",
"tools/coulomb_image_probe.py",
values,
snapshot,
"tools/coulomb-storage-release.py",
"tools/coulomb_storage_release_node.py",
"tools/coulomb_storage_probe.py",
"helm/coulomb-social-values.yaml",
"release/snapshot-content-and-db.py",
)
]
paths += sorted((ROOT / "charts/coulomb-social").rglob("*"))
paths += sorted((ROOT / evidence).glob("*.json"))
paths = [p for p in paths if p.is_file()]
if any(p.is_symlink() or not p.resolve().is_relative_to(ROOT) for p in paths):
raise RuntimeError("regular_reviewed_files_required")
@ -59,9 +46,6 @@ def prepare(plan_path=None):
plan["files"] = {
name: hashlib.sha256(data).hexdigest() for name, data in content.items()
}
for name, expected in plan["rehearsal_evidence_sha256"].items():
if plan["files"].get(evidence + "/" + name) != expected:
raise RuntimeError("reviewed_candidate_evidence_changed")
digest = "sha256:" + hashlib.sha256(canonical(plan)).hexdigest()
content["manifest.json"] = canonical(plan)
return plan, digest, content
@ -73,11 +57,10 @@ def main():
parser.add_argument("--execute", action="store_true")
parser.add_argument("--expect-digest")
parser.add_argument("--output", type=Path)
parser.add_argument("--plan", type=Path, default=PLAN)
args = parser.parse_args()
if args.preflight and args.execute:
raise SystemExit("choose read-only preflight or attended execution")
plan, digest, content = prepare(args.plan)
plan, digest, content = prepare()
if args.expect_digest and args.expect_digest != digest:
raise SystemExit("reviewed proposal changed; do not execute")
if not args.preflight and not args.execute:
@ -100,7 +83,7 @@ def main():
)
print("Reviewed proposal: " + digest)
print(
"Coulomb-only image update; existing database schema retained, fresh paired backup, postflight and backup image-pin refresh."
"Coulomb-only image/migration, fresh paired backup, postflight and backup image-pin refresh."
)
if (
input("Type DEPLOY followed by the full digest to proceed: ").strip()
@ -113,7 +96,7 @@ def main():
entry = tarfile.TarInfo(name)
entry.size, entry.mode = len(data), 0o600
archive.addfile(entry, io.BytesIO(data))
remote = "/tmp/csoc-reviewed-image-" + digest.removeprefix("sha256:")
remote = "/tmp/csoc-reviewed-storage-" + digest.removeprefix("sha256:")
receiver = r"""
import hashlib,io,json,os,pathlib,sys,tarfile
root=pathlib.Path(sys.argv[1]);expected=sys.argv[2]
@ -153,10 +136,10 @@ with tarfile.open(fileobj=io.BytesIO(raw),mode='r:') as archive:
)
if staged.returncode:
raise SystemExit("reviewed capsule staging refused; no live change")
node_hash = plan["files"]["tools/coulomb_image_release_node.py"]
node_hash = plan["files"]["tools/coulomb_storage_release_node.py"]
guard = (
"import hashlib,pathlib,sys;p=pathlib.Path("
+ repr(remote + "/tools/coulomb_image_release_node.py")
+ repr(remote + "/tools/coulomb_storage_release_node.py")
+ ");"
"b=p.read_bytes();assert hashlib.sha256(b).hexdigest()=="
+ repr(node_hash)

View file

@ -45,9 +45,6 @@ with connection.cursor() as cursor:
"SELECT COUNT(*) FROM django_migrations WHERE app='spaces' AND name='0003_space_slug_global_uniq'"
)
applied = cursor.fetchone()[0] == 1
cursor.execute("SELECT * FROM django_migrations")
migration_rows = sorted(json.dumps(row, default=str, separators=(",", ":"))
for row in cursor.fetchall())
root = Path(settings.CONTENT_ROOT)
files = {
str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest()
@ -56,7 +53,6 @@ files = {
}
result = {
"business_tables": len(tables),
"migration_rows_sha256": hashlib.sha256("\n".join(migration_rows).encode()).hexdigest(),
"business_rows": sum(t["rows"] for t in tables.values()),
"business_rows_sha256": hashlib.sha256(
json.dumps(tables, sort_keys=True, separators=(",", ":")).encode()

View file

@ -16,15 +16,11 @@ import subprocess
import tempfile
import time
import urllib.request
from contextlib import ExitStack
from datetime import UTC, datetime
from pathlib import Path
JOURNAL_ROOT = Path("/var/lib/coulomb-social-backup/releases")
SNAPSHOT = Path("/opt/coulomb-social-backup/snapshot-content-and-db.py")
INSTALL_RECEIPT = Path(
"/var/lib/coulomb-social-backup-installations/20261031bacc0001/receipt.json"
)
def canonical(value):
@ -39,33 +35,6 @@ class Refused(RuntimeError):
pass
def private_directories(root, relative):
"""Create every component privately; never repair existing unsafe state."""
if not root.is_absolute() or relative.is_absolute() or ".." in relative.parts:
raise Refused("private_directory_path_required")
with ExitStack() as stack:
def opened(name, parent=None):
fd = os.open(name, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW, dir_fd=parent)
stack.callback(os.close, fd)
return fd
fd = opened("/")
for component in root.parts[1:]:
fd = opened(component, fd)
for component in (*relative.parts, None):
info = os.fstat(fd)
if info.st_uid != os.getuid() or stat.S_IMODE(info.st_mode) != 0o700:
raise Refused("private_owned_directory_required")
if component is None:
break
try:
os.mkdir(component, mode=0o700, dir_fd=fd)
os.fsync(fd)
except FileExistsError:
pass
fd = opened(component, fd)
class Release:
def __init__(self, capsule, expected, read_only=False):
self.root = capsule
@ -91,14 +60,8 @@ class Release:
raise Refused("attended_founder_root_execution_required")
self.env = dict(os.environ, KUBECONFIG="/etc/rancher/k3s/k3s.yaml")
self.read_only = read_only
for field in ("values_file", "snapshot_file"):
if field in self.plan:
name = self.plan[field]
if (not isinstance(name, str) or not name.startswith("release/")
or ".." in Path(name).parts or name not in frozen):
raise Refused("reviewed_release_artifact_required")
self.receipt = {
"schema": "coulomb.guarded-image-release.v1",
"schema": "coulomb.guarded-storage-release.v1",
"proposal_digest": expected,
"started_at": datetime.now(UTC).isoformat(),
"status": "preflight",
@ -106,18 +69,16 @@ class Release:
"timers_activated": False,
}
self.journal = JOURNAL_ROOT / expected.removeprefix("sha256:")
self.verify_installation_prerequisite()
if read_only:
return
if self.journal.exists():
raise Refused("prior_execution_requires_review")
private_directories(JOURNAL_ROOT.parent, Path(JOURNAL_ROOT.name))
self.journal.mkdir(mode=0o700)
self.journal.mkdir(parents=True, mode=0o700)
self.root = self.journal / "capsule"
self.root.mkdir(mode=0o700)
for name, data in frozen.items():
target = self.root / name
private_directories(self.root, Path(name).parent)
target.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
fd = os.open(target, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, "wb") as stream:
stream.write(data)
@ -191,7 +152,7 @@ class Release:
return self.kdoc("get", "deployment", "coulomb-social", "-n", "coulomb-social")
def probe(self, mode="data"):
source = (self.root / "tools/coulomb_image_probe.py").read_text()
source = (self.root / "tools/coulomb_storage_probe.py").read_text()
result = self.command(
[
"kubectl",
@ -215,63 +176,13 @@ class Release:
"business_rows_sha256",
"content_files",
"content_files_sha256",
"migration_rows_sha256",
):
if actual[name] != self.plan["expected_data"][name]:
raise Refused("approved_recovered_dataset_drifted")
if actual["duplicate_slug_groups"] != 0 or actual["tenant_slug_constraint"] is not True:
if actual["duplicate_slug_groups"] != 0 or not actual["tenant_slug_constraint"]:
raise Refused("storage_invariant_refused")
if (actual.get("global_slug_constraint") is not True
or actual.get("migration_0003_applied") is not True):
raise Refused("already_migrated_baseline_required")
def artifact_name(self, field):
return self.plan.get(field, {
"values_file": "release/identity-export-values.yaml",
"snapshot_file": "release/identity-export-snapshot.py",
}[field])
def verify_installation_prerequisite(self):
expected = self.plan.get("prerequisite_installation_digest")
if expected is None:
return
if not re.fullmatch(r"sha256:[a-f0-9]{64}", expected):
raise Refused("reviewed_installation_digest_required")
try:
info = INSTALL_RECEIPT.lstat()
except FileNotFoundError:
raise Refused("inactive_backup_installation_required_before_image_release") from None
if (not stat.S_ISREG(info.st_mode) or info.st_uid != 0
or info.st_mode & 0o077 or info.st_nlink != 1
or any(p.is_symlink() for p in INSTALL_RECEIPT.parents)):
raise Refused("private_installation_receipt_required")
receipt = json.loads(INSTALL_RECEIPT.read_bytes())
if (receipt.get("schema") != "coulomb.backup-source-supervised-installation.v1"
or receipt.get("proposal_digest") != expected
or receipt.get("status") != "sources_installed_units_inactive_verified"
or receipt.get("verified_targets") != 19
or receipt.get("timers_activated") is not False):
raise Refused("verified_inactive_backup_installation_required")
for name in ("paired-backup", "backup-freshness"):
for suffix in ("service", "timer"):
unit = f"coulomb-social-{name}.{suffix}"
raw = self.command(["systemctl", "show", unit,
"--property=LoadState,ActiveState,UnitFileState"]).stdout
state = dict(line.split("=", 1) for line in raw.decode().splitlines())
if (state.get("LoadState") != "loaded" or state.get("ActiveState") != "inactive"
or state.get("UnitFileState") not in {"disabled", "static"}):
raise Refused("backup_units_must_remain_inactive_for_image_release")
jobs = self.command(["systemctl", "list-jobs", "--no-legend", "--no-pager",
"--plain"]).stdout.decode().splitlines()
for line in jobs:
fields = line.split()
if (len(fields) != 4 or not fields[0].isdecimal()
or fields[1].startswith("coulomb-social-")):
raise Refused("queued_backup_job_requires_review")
def preflight(self):
self.verify_installation_prerequisite()
self.verify_installed_helpers()
if (
self.kdoc("get", "namespace", "kube-system")["metadata"]["uid"]
!= self.plan["cluster_uid"]
@ -322,20 +233,6 @@ class Release:
or deployment["spec"]["strategy"]["type"] != "Recreate"
):
raise Refused("single_ready_writer_required")
# Helm's three-way merge preserves unmanaged pod metadata. Bind the
# complete desired live spec rather than treating kubectl apply's
# last-applied projection as Helm's result.
image_patch = [
{"op": "test", "path": "/spec", "value": deployment["spec"]},
{"op": "replace", "path": "/spec/template/spec/containers/0/image",
"value": self.plan["candidate_image"]},
]
preview = self.kdoc(
"patch", "deployment", "coulomb-social", "-n", "coulomb-social",
"--type=json", "--dry-run=server", "-p", json.dumps(image_patch),
)
if sha(canonical(preview["spec"])) != self.plan["candidate_spec_sha256"]:
raise Refused("image_only_server_preview_differs")
pvc = self.kdoc("get", "pvc", "coulomb-social-content", "-n", "coulomb-social")
if (
pvc["metadata"]["uid"] != self.plan["pvc_uid"]
@ -356,7 +253,7 @@ class Release:
"coulomb-social",
str(self.root / "charts/coulomb-social"),
"-f",
str(self.root / self.artifact_name("values_file")),
str(self.root / "helm/coulomb-social-values.yaml"),
"-n",
"coulomb-social",
]
@ -374,7 +271,7 @@ class Release:
"coulomb-social",
str(self.root / "charts/coulomb-social"),
"-f",
str(self.root / self.artifact_name("values_file")),
str(self.root / "helm/coulomb-social-values.yaml"),
"-n",
"coulomb-social",
"--dry-run=server",
@ -382,10 +279,12 @@ class Release:
)
before = self.probe()
self.same_data(before)
if before["global_slug_constraint"] or before["migration_0003_applied"]:
raise Refused("migration_baseline_changed")
self.receipt["preflight"] = before
self.save()
def verify_installed_helpers(self):
def capture(self):
for path, expected in self.plan["installed_helper_hashes"].items():
metadata = Path(path).lstat()
if (
@ -395,8 +294,6 @@ class Release:
or sha(Path(path).read_bytes()) != expected
):
raise Refused("installed_backup_helper_changed")
def capture(self):
self.verify_installed_helpers()
environment = dict(self.env)
for name in ("primary.env", "recipient.env"):
path = Path("/etc/coulomb-social-backup") / name
@ -441,11 +338,9 @@ class Release:
path = SNAPSHOT
if (
sha(path.read_bytes())
== self.plan["files"][self.artifact_name("snapshot_file")]
== self.plan["files"]["release/snapshot-content-and-db.py"]
):
self.replace_pin(path, old)
elif sha(path.read_bytes()) != sha(old):
raise Refused("snapshot_pin_changed_during_rollback")
def replace_pin(self, path, value):
fd, name = tempfile.mkstemp(prefix=".reviewed-snapshot-", dir=path.parent)
@ -479,7 +374,7 @@ class Release:
"coulomb-social",
str(self.root / "charts/coulomb-social"),
"-f",
str(self.root / self.artifact_name("values_file")),
str(self.root / "helm/coulomb-social-values.yaml"),
"-n",
"coulomb-social",
"--atomic",
@ -497,6 +392,11 @@ class Release:
raise Refused("candidate_spec_or_readiness_differs")
probe = self.probe("views")
self.same_data(probe)
if (
not probe["global_slug_constraint"]
or not probe["migration_0003_applied"]
):
raise Refused("production_migration_not_verified")
for suffix in ("/healthz", "/", "/static/spaces/copy-content.js"):
with urllib.request.urlopen(
"https://app.coulomb.social" + suffix, timeout=20
@ -516,23 +416,23 @@ class Release:
):
raise Refused("snapshot_pin_drifted")
self.replace_pin(
path, (self.root / self.artifact_name("snapshot_file")).read_bytes()
path, (self.root / "release/snapshot-content-and-db.py").read_bytes()
)
self.command(
[
"python3",
str(path),
"--destination",
"/tmp/csoc-post-image-server-review",
"/tmp/csoc-post-storage-server-review",
]
)
self.receipt.update(
status="image_candidate_deployed_verified",
status="storage_candidate_deployed_verified",
postflight=probe,
helm_revision=self.history()[-1]["revision"],
snapshot_pin_refreshed=True,
public_health_landing_static_verified=True,
existing_global_constraint_preserved=True,
global_constraint_applied=True,
)
except Exception:
self.receipt["rollback_requested"] = True
@ -552,10 +452,6 @@ class Release:
timeout=360,
)
self.restore_pin(old_pin)
restored = self.deployment()
if (sha(canonical(restored["spec"])) != self.plan["baseline_spec_sha256"]
or restored["status"].get("readyReplicas") != 1):
raise Refused("rollback_spec_or_readiness_differs")
self.receipt["image_rollback_completed"] = True
except Exception: # noqa: BLE001 -- retain explicit unconfirmed rollback outcome
self.receipt["image_rollback_completed"] = False
@ -581,9 +477,8 @@ def main():
return
if args.execute and args.preflight:
raise SystemExit("choose read-only preflight or attended execution")
release = None
release = Release(args.capsule, args.expect_digest, read_only=args.preflight)
try:
release = Release(args.capsule, args.expect_digest, read_only=args.preflight)
if args.preflight:
release.preflight()
print(
@ -598,15 +493,11 @@ def main():
return
print(json.dumps(release.execute()))
except Exception as error: # noqa: BLE001 -- private child diagnostics are suppressed
receipt = release.receipt if release is not None else {
"proposal_digest": args.expect_digest, "execution_started": False,
}
receipt.update(status="release_refused_or_failed", failure_type=type(error).__name__)
if isinstance(error, Refused):
receipt["failure_reason"] = str(error)
if release is not None:
release.save()
print(json.dumps(receipt))
release.receipt.update(
status="release_refused_or_failed", failure_type=type(error).__name__
)
release.save()
print(json.dumps(release.receipt))
raise SystemExit(1) from None

View file

@ -8,7 +8,7 @@ status: active
owner: codex
topic_slug: railiance-apps
created: "2026-10-06"
updated: "2026-11-01"
updated: "2026-10-08"
related:
- CSOC-WP-0008
state_hub_workstream_id: "79abacf8-361e-51ab-829d-40dec8e142d1"
@ -340,225 +340,3 @@ server dry-run pass. No Secret, issuer, mail, caller, PVC, offsite schedule or
Bubble/apex change. T04 remains wait for productive complete user acceptance;
product WP-0008/WP-0010 retain their broader open tasks. Product receipt:
docs/release/sharing-portability-review-2026-10-08.md.
## T05 — Deliver the identity-binding and operator-export image
```task
id: RAPPS-WP-0015-T05
status: done
priority: high
needs_human: false
decision_id: "75b94bb6-4709-495f-91fe-43e53e2867ed"
intervention_note: "Founder executed9f1daf6c; revision19 and complete independent postflight, source/helper/values reconciliation and current-point consumer recovery/export are verified. No rerun required."
state_hub_task_id: "9f657a95-ce0e-5805-b754-a64e38827c73"
```
Owner execution dependency for CSOC-WP-0012-T03 and CSOC-WP-0015-T04. This is
separate from completed storage release 5fd7ccd8 and date correction 47829c7a.
Candidate source 23ffe2c/image 522bcd7f is published and packaged-source verified;
441 source tests and 25 packaged identity/export tests pass. The retained isolated
recovery verifies 85 client files and 40 owner/40 outsider views without app overlays.
Current production remains revision 18/image 51281946; default live Helm values are
unchanged until the verified execution return.
Prepared separate image-only launcher/node/probe, candidate values and snapshot
pin. The controller requires both existing slug constraints and migration 0003,
compares complete business/migration-history/content fingerprints, makes a fresh
admitted primary backup/readback, then performs atomic Helm upgrade and postflight.
Rollback verifies the previous live specification, Ready replica and recognized
helper; no data restore/schema downgrade or automatic replay. The old storage
launcher is not reused. 19 synthetic safety tests, Ruff, compile and Helm lint pass.
Sealed read-only preflight 9f1daf6c passes at 2026-10-31T03:41:35Z: revision 18,
12 business tables/92 rows/86 files, exact migration history, unchanged helper pins,
CPU 68%/memory 76%, image-only chart/server-preview checks and no Argo adoption.
The expected live spec preserves the unmanaged restart annotation; raw kubectl
apply remains dry-run only. Receipt: docs/evidence/2026-10-31-coulomb-image-release-preflight.json.
Founder packet: coulomb-social/docs/release/identity-export-release-review-2026-10-31.md.
The new execution has not occurred. No node helper, Helm release, timer or data
changed. Existing recovery rehearsal predates the date correction; independent
retrieval/restore/export of the new execution point remains consumer follow-through.
Done when founder execution and independent postflight are verified, the native
receipt and actual image/helper pins are reconciled into owner/product source,
and the product records reference that exact release. This does not accept the
remaining productive journeys or service/offboarding obligations for the consumer.
2026-10-31 handoff: controller commit `84a5aa0` is published on owner main.
The canonical workstation launcher reproduces proposal `9f1daf6c` with
`live_changes: false`; the founder packet is ready for attended execution.
Consumer follow-through remains CSOC-WP-0012-T03 and CSOC-WP-0015-T04.
2026-10-31 founder image-release return: proposal9f1daf6c completed at07:15:24Z,
Helm revision19/image522bcd7f. Independent complete-spec/Ready/identity checks,
all80packaged source hashes, unchanged92business rows/86files/migration history,
40owner renders/40outsider denials, public endpoints and refreshed helperdcc8dd2a
all pass. Live owner values/product pins are reconciled. Fresh07:13 primary point
is mirrored, independently retrieved and restored (13tables/114rows/86files);
packaged client export verifies85files without source mutation. Full make check
441passes, zero skips. Release decision75b94bb6 is resolved only for that exact
execution; RAPPS-WP-0015-T05 is complete. Productive flow and service/offboarding
acceptance remain open. Return: docs/release/identity-export-release-return-2026-10-31.md.
## T06 — Preserve private custody when freezing future release evidence
```task
id: RAPPS-WP-0015-T06
status: done
priority: high
needs_human: false
state_hub_task_id: "5357f194-ae4d-599e-9a87-08e8d585a124"
```
Source correction for CSOC-WP-0012-T13 after backup installation preflight exposed
0755 intermediate capsule directories from completed releases. The current image
controller creates each component with mode0700 through no-follow directory
file descriptors, checks private ownership/mode and refuses unsafe existing state.
It does not chmod historical directories or replay the completed release. Files
remain0600. The old storage capsule remains frozen; it is not a current release path.
Validation: 24 focused release safety cases pass, including a nested chart under
umask022 and refusal of broad, symlinked, ancestor-symlinked and non-directory
parents without mutation. Ruff and git diff --check pass. Product receipt:
coulomb-social/docs/release/backup-producer-custody-validation-2026-10-31.json.
The historical eight-entry repair and recurring service acceptance remain product
T04/T09. No cluster operation occurred; future release proposals bind the new source.
## T07 — Deliver the combined content and author attachment release
```task
id: RAPPS-WP-0015-T07
status: done
priority: high
needs_human: false
decision_id: "d9b70cc5-e035-40ae-8d0d-020190581202"
intervention_note: "Founder executed e96752ec; independent verification confirms revision20/image7906f461 with unchanged data. No execution rerun required. Source pins and fresh-point mirror/recovery/export are verified; productive verdicts remain CSOC-WP-0013."
state_hub_task_id: "8f448934-bdfe-539f-8cab-a739ec752491"
```
Deployment-owner follow-through for CSOC-WP-0013-T05. Candidate source f306dbf is
published at `sha256:d3f2f5bb90f0ba79f4e1d8098d2eb06f8940b8789e5ecb851914bbab364597ec`.
Only packaged pageops.py differs from verified revision19/image522bcd7f. All80
packaged sources match the commit; Python/runtime distribution versions match;
no migration is added. Product full gate546 and packaged lifecycle29 pass. The
previous image reproduces exactly four partial-attachment recovery failures under
real child-process exits. Product evidence: docs/release/content-lifecycle-candidate-
{build,provenance,tests}-2026-10-31.json and the baseline-tests receipt.
Prepare an exact current-target image-only packet using the existing release
controller, including its private directory fix from T06. Verify current release,
full dataset/migration fingerprints and complete candidate/previous-image recovery
checks. Bind fresh paired rollback capture, postflight and snapshot image-pin
refresh. Keep historical capsules and existing pending backup repair/installation/
route packets intact. Then obtain the attended execution and independently verify
its durable return. Current verified revision19 remains authoritative until that
return; no image deploy is implied by publication. Productive review stays with
CSOC-WP-0013-T05/T03. Retention policy c3a191f2 is accepted; no cutoff or purge was
authorized. Do not replay the completed identity image release.
2026-10-31 preparation return: exact20-member proposal
`sha256:c9c3231620721ef3ea9b2bf22fc6c62fe3ed8efb91386cf7ec96acc6959dae08`
is prepared with a separate plan/values/snapshot/evidence set. The existing launcher
accepts an explicit reviewed plan; historical frozen capsules stay intact.40
controller tests, Ruff and Helm lint pass. Native image-only server preview preserves
the complete current specification and unmanaged metadata. Candidate/previous-image
checks on the independent07:13 recovery point render40owner pages, deny40outsiders,
verify85export files, and preserve all13tables/86files. Current target remains
revision19;93business rows reflect a new session plus login timestamp changes.
Content and migration history match the retained point; private values are not exposed.
Ordering is material: the pending installer8f442bf0 pins snapshotdcc8dd2a. Deploying
this image first would stale that reviewed packet. The new controller therefore
requires that exact completed installation receipt and currently inactive/disabled
backup units before creating its release journal, then pins all12 installed Python
helpers. Native full preflight correctly refuses the absent installation receipt;
it is not a pass and no image execution occurred. Historical custodyfa2763d1,
route4d848106 and installer8f442bf0 packets are unchanged. After their returns,
re-run the full image preflight before admitting execution; finish native service
proof/schedule activation afterward. Consumer review commands and exact scope:
coulomb-social/docs/usecases/sharing-portability-review.md, lifecycle release section.
Evidence: content-lifecycle-release-{target,row-drift,preflight,proposal,preparation}
JSON files in the consumer docs/release directory. T07 is now external wait for T08;
product policy is settled, and productive lifecycle acceptance remains open.
2026-10-31 combined candidate: the route and inactive installation now have
founder-executed independent returns. User requested plain attachment actions,
including author add/remove (product decision78175c34), and accepted the three
custom-topic rendering cases for now. The new source1139a6d combines the original
crash-recovery correction, ordered-list starts and revisioned attachment actions.
Image7906f461 has exact packaged provenance and unchanged runtime dependencies;
no schema migration. Main gate670, isolated source gate568 and packaged110 pass.
The retained independently recovered pair remains unchanged across candidate/old
40owner/40outsider views and85file selected-client export, all13tables/86files.
New immutable plan: release/coulomb-content-acceptance-1139a6d.json.
Exact proposal: sha256:e96752ecfa7adef2fd1d9da48902c8e63de124ccfd272fe20ba79b758b3ca4a3.
Full native read-only preflight passes at revision19 with unchanged93business
rows/86files, complete desired specification, Helm/server previews, installed
source prerequisite and inactive units. Historical c9c32316 remains unchanged;
use the new combined proposal only. Founder-terminal execution remains required.
The reviewed action captures a fresh pair before atomic Helm rollout and refreshes
the snapshot image pin after unchanged-data/view checks. No timer activation,
production restore, purge or mail. Productive acceptance remains with WP-0013.
Review/command: coulomb-social/docs/release/content-acceptance-review-2026-10-31.md.
2026-10-31 verified combined release: founder executed exact proposal e96752ec,
completed20:22:30Z at Helm revision20/image7906f461. Independent read-only proof
verifies complete desired spec, identities, sole Ready writer,79packaged source
files and23capsule members. All93business rows/86files are unchanged;40owner views
and40outsider denials pass. Snapshot/helper hashes match. Fresh20:21paired point
was fetched from primary; timers remain inactive. Deployment approval decision
d9b70cc5 is resolved. Consumer recovery/export follow-through and live source-pin
reconciliation are in progress; productive verdicts remain CSOC-WP-0013.
T07 complete: exact fresh20:21point independently mirrored/read back/decrypted
and restored (13tables/115rows,86files). Deployed and previous package views
pass40owner/40outsider checks; client export verifies85files with all source
SQL/files unchanged. Owner live values and consumer source/helper pins now match
revision20. Recovery remains isolated; timers are inactive/disabled. Remaining
user workflow verdicts are tracked by existing CSOC-WP-0013-T02/T03/T05/T06.
## T08 — Deliver the editor attachment visibility correction
```task
id: RAPPS-WP-0015-T08
status: done
priority: high
needs_human: false
decision_id: "0d538348-aadd-41a2-88f6-191defcf22b2"
intervention_note: "Founder executed2cddcf38; revision21/imageb58d858a independently verified, source pins reconciled, fresh-point recovery/export passed. No rerun required. User confirmed editor visibility; remaining productive checks stay CSOC-WP-0013."
state_hub_task_id: "e7b04735-e618-5551-9ecf-6d423c83d156"
```
Productive revision20 review identified that attachments are visible on the
original page but absent from editor tabs. CSOC-WP-0013-T06 owns the correction:
display saved attachments/downloads in the editor and preserve that list after
stale-edit refusal, with management opening separately to retain unsaved text.
Prepare the minimal follow-up image from the deployed source, preserve existing
schema/data/permissions, and reuse the exact attended image-release lane with a
fresh paired rollback point. Complete after founder execution and independent
postflight/recovery/source-pin reconciliation. Productive acceptance remains
CSOC-WP-0013-T03/T06; T07's verified revision20 delivery stays complete.
Prepared source31eaa58/imageb58d858a; exact proposal2cddcf38b7052287c10dce467a200a74cfa9699c666ae9ac538fc82917129e7a. Main670/isolated568/packaged110 pass.
Recovered views/export pass. Full native preflight at revision20/97rows/98files
passes; existing93rows/86files are unchanged by the productive review additions.
Plan: release/coulomb-editor-attachments-31eaa58.json. Review/command:
coulomb-social/docs/release/content-acceptance-review-2026-10-31.md.
2026-11-01 verified return: founder executed2cddcf38, completed at2026-10-31
23:32:38Z, Helm21/imageb58d858a/source31eaa58. Independent complete-spec/source/
helper checks agree with durable receipt:97business rows/98files unchanged,
43owner views/43outsider denials,79packaged files and21frozen capsule files.
Live GET-only check renders43editors and verifies42download links across41editors
with saved resources. Bernd confirms both reopened tabs show the attachment.
The fresh23:29:54point independently mirrors/reads back/decrypts/restores all13
SQL tables/119rows and98files. Deployed and previous packages read the recovered
store; exports verify its content tenant, with all source
SQL/files unchanged. Live values and consumer source/helper pins now match
revision21; snapshot server dry-run and9snapshot/restore regressions pass.
Recovery container is stopped and timers remain inactive/disabled. T08 is done;
remaining copy/move/sharing/portability outcomes stay CSOC-WP-0013-T03/T05/T06.
Evidence: coulomb-social/docs/release/editor-attachments-*-2026-11-01.json.