diff --git a/SCOPE.md b/SCOPE.md index ee9516f..5c5d39d 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -4,39 +4,31 @@ > direction belongs in `INTENT.md`; the current stage belongs in `GOAL.md`; > current work and gates belong in `workplans/`. -## Lifecycle expansion — 2026-10-04 (source implementation) +## Lifecycle production boundary — 2026-10-05 -INFD-WP-0007 adds a headless service and an optional browser workspace. The shared -foundation supports registration with packet custody, immutable revisions, -attributed sources/evaluations/comments, explicit revision-specific publication, -authorized search, retrieval and history. Every operation consumes fresh Access -Engine policy observations; audience facts do not implement a local ACL. +The headless lifecycle service and browser workspace are deployed at +`decisions.coulomb.social` under the founder-approved initial audience: +net-kingdom-admins humans and system:serviceaccount:state-hub:state-hub. +Service image 804d89fb runs schema 5; Access Engine owns lifecycle v1 and +compact-sitting v12 policy decisions. Approval Engine remains the approval-state +owner. The UI uses the shared service foundation; the private bearer API listens +on 8081 through informed-decision-workload and is absent from public ingress. -The workspace reuses verified KeyCape sessions and CSRF/origin checks for draft -creation, research, discussion, publication, refinement, revision comparison and -packet downloads. Runtime configuration requires a separate lifecycle policy -package. The bearer API adapter remains unmounted pending workload identity and -listener admission. Lifecycle records remain outside the legacy approver overview; -a durable revision-specific request now connects supported records to intake -and the existing human-only review path. Outcomes retain exact source revision -and distinguish prepared/unresolved submissions from confirmed entries. See -`docs/specs/LifecycleReviewHandoff.md`; production forwarding is still outstanding. +Native proof registered two records, retained sources/evaluation/comment, revised +and published one, and sent its exact review envelope through the private State +Hub dispatcher to native approval 22b30fe7-c565-46f2-8193-d8875975ad9e. No image, +configuration or policy change was required for these decisions. Service and +dispatcher pod recreation retained revision 2, custody and the same receipt. +Missing/crossed-audience/unregistered callers are refused. Independent Audit +Core counts match; prior 24 confirmed submissions were preserved. -Opt-in delivery commits lifecycle evidence through the existing Audit Core -outbox, with receipt-based settlement, retries and reconciliation. Current delivery -is platform-tenant-only. Pending evidence closes runtime readiness. The deployment -renderer supports separately pinned lifecycle policy and exact network proposals; -no live configuration was changed. Cross-repository validation: 634 passed, -5 skipped, including two agent-created decisions and human collaboration with -unchanged runtime configuration, actual Approval Engine acceptance of a linked -source revision, and Audit Core delivery. Schema 5 prevents older code without -source-revision guards from opening the database. Identity and PDP -responses in that scenario are synthetic; this is not live acceptance evidence. +Human acceptance of the new lifecycle review is still pending. Broader binding +profiles and browser acceptance remain live tasks in INFD-WP-0007; intake +continuation is INFD-WP-0005. Issuer rotation is separately governed under Platform +RPF-IN-0004. Automatic Hub resolution write-back remains disabled. -Contracts: `docs/specs/DecisionLifecycleService.md`, `LifecycleFoundationContract.md`, -`LifecycleServiceContract.md`, `LifecycleHTTPContract.md` and -`LifecycleWorkspaceDelivery.md` under `docs/specs/`. INFD-WP-0005 retains intake -runtime/admission work. The deployment snapshot below is historical. +Release/cutover procedure: `deploy/lifecycle/README.md`. Native receipts: +`docs/evidence/2026-10-05-lifecycle-cutover/`. Earlier statuses below are historical. ## Status — 2026-09-27 diff --git a/deploy/lifecycle/README.md b/deploy/lifecycle/README.md index bc26a4b..36ef4af 100644 --- a/deploy/lifecycle/README.md +++ b/deploy/lifecycle/README.md @@ -1,7 +1,7 @@ # INFD-WP-0007 production candidate Prepared 2026-10-04 for the founder-selected initial audience: net-kingdom-admins -humans and system:serviceaccount:state-hub:state-hub. **Not deployed.** +humans and system:serviceaccount:state-hub:state-hub. **Deployed under founder approval on 2026-10-05 (Europe/Berlin).** | Artifact | Immutable reference | | --- | --- | @@ -20,7 +20,7 @@ server dry-run against railiance01. No Secret is included. Dry-run does not test reachability, credential delivery, policy caller identity, backup restoration or a human disposition. -## Proposed live changes +## Approved live changes - Replace the service's image and immutable runtime ConfigMap, retaining its public Service/Ingress, single writer, Recreate strategy and existing PVC. @@ -139,6 +139,31 @@ the live PVC's private directory. Refresh the snapshot after closing writes for cutover; this online drill is not the final maintenance-window backup. The requester proof's eight temporary resources were removed. No native approval -was created, consumed or human-bound by these tests. The actual review service -and State Hub dispatcher have not been rolled out. Concrete cutover approval is -the remaining gate for the initial audience and artifacts in this packet. +was created, consumed or human-bound by these tests. The actual review service and State Hub dispatcher were subsequently rolled out +under explicit founder approval; see the native cutover record below. + +## Native cutover — 2026-10-05 + +Approval: State Hub decision d2eaa2e9-6d11-4676-a07f-e3b7e59a88e3. +Service: manual Argo application informed-decision, path deploy/lifecycle, +source b5b5a5a. Dispatcher: manual Argo application state-hub-memo-dispatch, +State Hub source 1321361. Both retain the image digests above. The dispatcher +source adds non-root private-directory initialization for Kubernetes inherited +setgid, with nine passing regression tests. Only empty owned 2700 custody is +normalized; existing nonempty or unsafe custody fails closed. + +The final quiesced backup matches the previously restored snapshot digest. +Schema 5 preserves 24 confirmed submissions. Actual receiving-pod credential +exchange and 0440/read-only mount pass. Public /healthz and /readyz return 200; +private /v1/decisions and /v1/memos return 404 on the public origin. + +The selected workload created two records and a revision with unchanged +deployment templates/generations and policy pins. Native audience/caller negatives, +private dispatch, notification and independent audit reconciliation pass. Pod +recreation retains the same version and single approval receipt; explicit +re-enqueue is replay. Temporary negative-verification resources were deleted. + +Human review remains at /review?memo_id=review-0d55a416-178c-46f5-b74b-b9b668390448. +No native human disposition is claimed yet. Evidence and exact pins are retained +in docs/evidence/2026-10-05-lifecycle-cutover/. Issuer rotation is a separate +Platform residual, RPF-IN-0004; it was neither performed nor authorized here. diff --git a/deploy/lifecycle/dispatcher.candidate.json b/deploy/lifecycle/dispatcher.candidate.json index cd7197b..0e7e046 100644 --- a/deploy/lifecycle/dispatcher.candidate.json +++ b/deploy/lifecycle/dispatcher.candidate.json @@ -9,7 +9,7 @@ "name": "state-hub-memo-dispatch", "namespace": "state-hub", "annotations": { - "state-hub.coulomb.social/admission": "proposal; STATE-WP-0096 / INFD-WP-0007 approved rollout required" + "state-hub.coulomb.social/admission": "approved; INFD-WP-0007 cutover" } }, "spec": { @@ -31,7 +31,7 @@ "name": "state-hub-memo-dispatch", "namespace": "state-hub", "annotations": { - "state-hub.coulomb.social/admission": "proposal; STATE-WP-0096 / INFD-WP-0007 approved rollout required" + "state-hub.coulomb.social/admission": "approved; INFD-WP-0007 cutover" } }, "spec": { @@ -131,6 +131,42 @@ ] } } + ], + "initContainers": [ + { + "name": "prepare-private-queue", + "image": "forgejo.coulomb.social/coulomb/state-hub-memo-dispatch@sha256:410fb6b6c9fd7a7ee0b63d727fd3249fb3ae13943421d6a5ce88b7ad2520bd2f", + "command": [ + "python", + "-c", + "import os, stat\np='/data/private'\ntry:\n os.mkdir(p, 0o700)\nexcept FileExistsError:\n pass\nfd=os.open(p, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)\ntry:\n info=os.fstat(fd)\n if info.st_uid != os.getuid():\n raise SystemExit('queue owner refused')\n mode=stat.S_IMODE(info.st_mode)\n if mode == 0o2700 and not os.listdir(fd):\n os.fchmod(fd, 0o700)\n elif mode != 0o700:\n raise SystemExit('queue mode refused')\nfinally:\n os.close(fd)\n" + ], + "securityContext": { + "allowPrivilegeEscalation": false, + "readOnlyRootFilesystem": true, + "capabilities": { + "drop": [ + "ALL" + ] + } + }, + "resources": { + "requests": { + "cpu": "5m", + "memory": "24Mi" + }, + "limits": { + "cpu": "100m", + "memory": "96Mi" + } + }, + "volumeMounts": [ + { + "name": "queue", + "mountPath": "/data" + } + ] + } ] } } @@ -143,7 +179,7 @@ "name": "state-hub-memo-dispatch", "namespace": "state-hub", "annotations": { - "state-hub.coulomb.social/admission": "proposal; STATE-WP-0096 / INFD-WP-0007 approved rollout required" + "state-hub.coulomb.social/admission": "approved; INFD-WP-0007 cutover" } }, "spec": { diff --git a/docs/evidence/2026-10-05-lifecycle-cutover/deployment-pins-before-restart.json b/docs/evidence/2026-10-05-lifecycle-cutover/deployment-pins-before-restart.json new file mode 100644 index 0000000..4da308a --- /dev/null +++ b/docs/evidence/2026-10-05-lifecycle-cutover/deployment-pins-before-restart.json @@ -0,0 +1,687 @@ +[ + { + "namespace": "informed-decision", + "name": "informed-decision", + "generation": 21, + "template": { + "metadata": { + "annotations": { + "informed-decision.coulomb.social/admission": "approved; INFD-WP-0007 cutover" + }, + "labels": { + "app.kubernetes.io/component": "review", + "app.kubernetes.io/name": "informed-decision" + } + }, + "spec": { + "automountServiceAccountToken": false, + "containers": [ + { + "env": [ + { + "name": "INFD_KEYCAPE_ISSUER", + "value": "https://kc.coulomb.social" + }, + { + "name": "INFD_CONTAINER_CONFIG", + "value": "/configuration/runtime.json" + } + ], + "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:804d89fb0bb3d691720380eedde4f361133bada717d1773c2eb349004346ebf1", + "imagePullPolicy": "IfNotPresent", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 2 + }, + "name": "informed-decision", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + }, + { + "containerPort": 8081, + "name": "workload", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 2 + }, + "resources": { + "limits": { + "cpu": "500m", + "memory": "256Mi" + }, + "requests": { + "cpu": "5m", + "memory": "64Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "startupProbe": { + "failureThreshold": 12, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 10, + "successThreshold": 1, + "timeoutSeconds": 2 + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "data" + }, + { + "mountPath": "/run/informed-decision", + "name": "runtime" + }, + { + "mountPath": "/tmp", + "name": "tmp" + }, + { + "mountPath": "/configuration", + "name": "configuration", + "readOnly": true + }, + { + "mountPath": "/var/run/secrets/informed-decision/policy", + "name": "caller", + "readOnly": true + }, + { + "mountPath": "/var/run/secrets/informed-decision/audit", + "name": "audit", + "readOnly": true + }, + { + "mountPath": "/var/run/secrets/informed-decision/kubernetes", + "name": "kubernetes-api", + "readOnly": true + }, + { + "mountPath": "/workload-registry", + "name": "workload-registry", + "readOnly": true + }, + { + "mountPath": "/var/run/secrets/informed-decision/requester", + "name": "sitting-requester", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 10001, + "fsGroupChangePolicy": "OnRootMismatch", + "runAsGroup": 10001, + "runAsNonRoot": true, + "runAsUser": 10001, + "seccompProfile": { + "type": "RuntimeDefault" + } + }, + "serviceAccount": "review", + "serviceAccountName": "review", + "terminationGracePeriodSeconds": 45, + "volumes": [ + { + "name": "data", + "persistentVolumeClaim": { + "claimName": "informed-decision-data" + } + }, + { + "emptyDir": { + "medium": "Memory", + "sizeLimit": "16Mi" + }, + "name": "runtime" + }, + { + "emptyDir": { + "medium": "Memory", + "sizeLimit": "16Mi" + }, + "name": "tmp" + }, + { + "configMap": { + "defaultMode": 292, + "name": "informed-decision-runtime-92d01402eb05" + }, + "name": "configuration" + }, + { + "name": "caller", + "projected": { + "defaultMode": 288, + "sources": [ + { + "serviceAccountToken": { + "audience": "flex-auth", + "expirationSeconds": 3600, + "path": "token" + } + } + ] + } + }, + { + "name": "audit", + "secret": { + "defaultMode": 288, + "items": [ + { + "key": "token", + "path": "token" + } + ], + "secretName": "informed-decision-audit" + } + }, + { + "name": "kubernetes-api", + "projected": { + "defaultMode": 288, + "sources": [ + { + "serviceAccountToken": { + "expirationSeconds": 600, + "path": "token" + } + }, + { + "configMap": { + "items": [ + { + "key": "ca.crt", + "path": "ca.crt" + } + ], + "name": "kube-root-ca.crt" + } + } + ] + } + }, + { + "configMap": { + "defaultMode": 292, + "name": "informed-decision-workload-registry" + }, + "name": "workload-registry" + }, + { + "name": "sitting-requester", + "secret": { + "defaultMode": 288, + "items": [ + { + "key": "client-secret", + "path": "client-secret" + } + ], + "optional": false, + "secretName": "informed-decision-sitting-requester" + } + } + ] + } + }, + "ready": 1 + }, + { + "namespace": "state-hub", + "name": "state-hub-memo-dispatch", + "generation": 2, + "template": { + "metadata": { + "labels": { + "app.kubernetes.io/component": "memo-dispatch", + "app.kubernetes.io/name": "state-hub" + } + }, + "spec": { + "automountServiceAccountToken": false, + "containers": [ + { + "image": "forgejo.coulomb.social/coulomb/state-hub-memo-dispatch@sha256:410fb6b6c9fd7a7ee0b63d727fd3249fb3ae13943421d6a5ce88b7ad2520bd2f", + "imagePullPolicy": "IfNotPresent", + "name": "dispatcher", + "resources": { + "limits": { + "cpu": "100m", + "memory": "96Mi" + }, + "requests": { + "cpu": "5m", + "memory": "24Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "queue" + }, + { + "mountPath": "/var/run/secrets/state-hub/informed-decision", + "name": "intake-caller", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "initContainers": [ + { + "command": [ + "python", + "-c", + "import os, stat\np='/data/private'\ntry:\n os.mkdir(p, 0o700)\nexcept FileExistsError:\n pass\nfd=os.open(p, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)\ntry:\n info=os.fstat(fd)\n if info.st_uid != os.getuid():\n raise SystemExit('queue owner refused')\n mode=stat.S_IMODE(info.st_mode)\n if mode == 0o2700 and not os.listdir(fd):\n os.fchmod(fd, 0o700)\n elif mode != 0o700:\n raise SystemExit('queue mode refused')\nfinally:\n os.close(fd)\n" + ], + "image": "forgejo.coulomb.social/coulomb/state-hub-memo-dispatch@sha256:410fb6b6c9fd7a7ee0b63d727fd3249fb3ae13943421d6a5ce88b7ad2520bd2f", + "imagePullPolicy": "IfNotPresent", + "name": "prepare-private-queue", + "resources": { + "limits": { + "cpu": "100m", + "memory": "96Mi" + }, + "requests": { + "cpu": "5m", + "memory": "24Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/data", + "name": "queue" + } + ] + } + ], + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 10001, + "fsGroupChangePolicy": "OnRootMismatch", + "runAsGroup": 10001, + "runAsNonRoot": true, + "runAsUser": 10001, + "seccompProfile": { + "type": "RuntimeDefault" + } + }, + "serviceAccount": "state-hub", + "serviceAccountName": "state-hub", + "terminationGracePeriodSeconds": 15, + "volumes": [ + { + "name": "queue", + "persistentVolumeClaim": { + "claimName": "state-hub-memo-dispatch" + } + }, + { + "name": "intake-caller", + "projected": { + "defaultMode": 288, + "sources": [ + { + "serviceAccountToken": { + "audience": "informed-decision-intake", + "expirationSeconds": 600, + "path": "intake-token" + } + }, + { + "serviceAccountToken": { + "audience": "informed-decision-lifecycle", + "expirationSeconds": 600, + "path": "lifecycle-token" + } + } + ] + } + } + ] + } + }, + "ready": 1 + }, + { + "namespace": "flex-auth", + "name": "flex-auth-informed-decision-sitting", + "generation": 12, + "template": { + "metadata": { + "labels": { + "app.kubernetes.io/instance": "flex-auth-informed-decision-sitting", + "app.kubernetes.io/name": "flex-auth-informed-decision-sitting", + "app.kubernetes.io/part-of": "flex-auth" + } + }, + "spec": { + "automountServiceAccountToken": false, + "containers": [ + { + "args": [ + "serve", + "--addr", + "0.0.0.0:8080", + "--registry", + "/opt/flex-auth/examples/informed-decision-lifecycle-review/registry.json", + "--policy", + "/opt/flex-auth/examples/informed-decision-lifecycle-review/policy.md", + "--caller-auth-mode", + "enforce", + "--caller-kubernetes-url", + "https://10.43.0.1", + "--caller-binding", + "informed-decision=system:serviceaccount:informed-decision:review" + ], + "image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99", + "imagePullPolicy": "IfNotPresent", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 20, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "flex-auth", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 5, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "300m", + "memory": "192Mi" + }, + "requests": { + "cpu": "5m", + "memory": "32Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/flex-auth-reviewer", + "name": "flex-auth-reviewer", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 65532, + "runAsGroup": 65532, + "runAsNonRoot": true, + "runAsUser": 65532, + "seccompProfile": { + "type": "RuntimeDefault" + } + }, + "serviceAccount": "flex-auth-informed-decision-sitting", + "serviceAccountName": "flex-auth-informed-decision-sitting", + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "flex-auth-reviewer", + "projected": { + "defaultMode": 288, + "sources": [ + { + "serviceAccountToken": { + "expirationSeconds": 3600, + "path": "token" + } + }, + { + "configMap": { + "items": [ + { + "key": "ca.crt", + "path": "ca.crt" + } + ], + "name": "kube-root-ca.crt" + } + } + ] + } + } + ] + } + }, + "ready": 1 + }, + { + "namespace": "flex-auth", + "name": "flex-auth-informed-decision-lifecycle", + "generation": 1, + "template": { + "metadata": { + "labels": { + "app.kubernetes.io/instance": "flex-auth-informed-decision-lifecycle", + "app.kubernetes.io/name": "flex-auth-informed-decision-lifecycle", + "app.kubernetes.io/part-of": "flex-auth" + } + }, + "spec": { + "automountServiceAccountToken": false, + "containers": [ + { + "args": [ + "serve", + "--addr", + "0.0.0.0:8080", + "--registry", + "/opt/flex-auth/examples/informed-decision-lifecycle/registry.json", + "--policy", + "/opt/flex-auth/examples/informed-decision-lifecycle/policy.md", + "--caller-auth-mode", + "enforce", + "--caller-kubernetes-url", + "https://10.43.0.1", + "--caller-binding", + "informed-decision=system:serviceaccount:informed-decision:review" + ], + "image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99", + "imagePullPolicy": "IfNotPresent", + "livenessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 20, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "name": "flex-auth", + "ports": [ + { + "containerPort": 8080, + "name": "http", + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 3, + "httpGet": { + "path": "/healthz", + "port": "http", + "scheme": "HTTP" + }, + "periodSeconds": 5, + "successThreshold": 1, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "cpu": "300m", + "memory": "192Mi" + }, + "requests": { + "cpu": "5m", + "memory": "32Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/flex-auth-reviewer", + "name": "flex-auth-reviewer", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": { + "fsGroup": 65532, + "runAsGroup": 65532, + "runAsNonRoot": true, + "runAsUser": 65532, + "seccompProfile": { + "type": "RuntimeDefault" + } + }, + "serviceAccount": "flex-auth-informed-decision-lifecycle", + "serviceAccountName": "flex-auth-informed-decision-lifecycle", + "terminationGracePeriodSeconds": 30, + "volumes": [ + { + "name": "flex-auth-reviewer", + "projected": { + "defaultMode": 288, + "sources": [ + { + "serviceAccountToken": { + "expirationSeconds": 3600, + "path": "token" + } + }, + { + "configMap": { + "items": [ + { + "key": "ca.crt", + "path": "ca.crt" + } + ], + "name": "kube-root-ca.crt" + } + } + ] + } + } + ] + } + }, + "ready": 1 + } +] diff --git a/docs/evidence/2026-10-05-lifecycle-cutover/lifecycle-flow.json b/docs/evidence/2026-10-05-lifecycle-cutover/lifecycle-flow.json new file mode 100644 index 0000000..8287161 --- /dev/null +++ b/docs/evidence/2026-10-05-lifecycle-cutover/lifecycle-flow.json @@ -0,0 +1,48 @@ +{ + "register": { + "event_id": "8bc87458-c042-4e45-883d-d7c189a089f7", + "memo_id": "infd-20261005-lifecycle-production-proof", + "resource": "/v1/decisions/infd-20261005-lifecycle-production-proof?version=1", + "version": 1, + "workspace_url": "https://decisions.coulomb.social/decisions/infd-20261005-lifecycle-production-proof?version=1" + }, + "second_register": { + "event_id": "ef7c9698-8466-45c8-872e-d6375b11bfa7", + "memo_id": "infd-20261005-lifecycle-recovery-notes", + "resource": "/v1/decisions/infd-20261005-lifecycle-recovery-notes?version=1", + "version": 1, + "workspace_url": "https://decisions.coulomb.social/decisions/infd-20261005-lifecycle-recovery-notes?version=1" + }, + "source": { + "event_id": "db6229d0-ed8e-460a-8c56-778f2477244c", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1 + }, + "evaluation": { + "event_id": "15249473-4736-4f1c-bb6c-d130aeb473c8", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1 + }, + "comment": { + "event_id": "9b51d039-4ded-41b4-b083-178644d25eb4", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1 + }, + "revise": { + "event_id": "85c3b0aa-46f9-4e96-b8eb-e7c48f70e732", + "memo_id": "infd-20261005-lifecycle-production-proof", + "resource": "/v1/decisions/infd-20261005-lifecycle-production-proof?version=2", + "version": 2, + "workspace_url": "https://decisions.coulomb.social/decisions/infd-20261005-lifecycle-production-proof?version=2" + }, + "publish": { + "event_id": "9a363333-5891-462a-af39-54e3161b7f6b", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 2 + }, + "retrieve_version": 2, + "search_count": 2, + "review_memo_id": "review-0d55a416-178c-46f5-b74b-b9b668390448", + "envelope_sha256": "3eac156d92e74674e8f516e5eb489e2b052621e7ce207c471db67df18c0806fb", + "enqueue_status": "pending" +} diff --git a/docs/evidence/2026-10-05-lifecycle-cutover/native-audit-before-restart.json b/docs/evidence/2026-10-05-lifecycle-cutover/native-audit-before-restart.json new file mode 100644 index 0000000..56079fa --- /dev/null +++ b/docs/evidence/2026-10-05-lifecycle-cutover/native-audit-before-restart.json @@ -0,0 +1,154 @@ +{ + "events": [ + { + "id": "8bc87458-c042-4e45-883d-d7c189a089f7", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1, + "kind": "registered", + "at": "2026-10-04T22:07:33.060609+00:00" + }, + { + "id": "ef7c9698-8466-45c8-872e-d6375b11bfa7", + "memo_id": "infd-20261005-lifecycle-recovery-notes", + "version": 1, + "kind": "registered", + "at": "2026-10-04T22:07:33.131538+00:00" + }, + { + "id": "db6229d0-ed8e-460a-8c56-778f2477244c", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1, + "kind": "source", + "at": "2026-10-04T22:07:33.201167+00:00" + }, + { + "id": "15249473-4736-4f1c-bb6c-d130aeb473c8", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1, + "kind": "evaluation", + "at": "2026-10-04T22:07:33.254457+00:00" + }, + { + "id": "9b51d039-4ded-41b4-b083-178644d25eb4", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 1, + "kind": "comment", + "at": "2026-10-04T22:07:33.300510+00:00" + }, + { + "id": "85c3b0aa-46f9-4e96-b8eb-e7c48f70e732", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 2, + "kind": "revised", + "at": "2026-10-04T22:07:33.355967+00:00" + }, + { + "id": "9a363333-5891-462a-af39-54e3161b7f6b", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 2, + "kind": "published", + "at": "2026-10-04T22:07:33.401132+00:00" + }, + { + "id": "5a2e81e3-70fd-4ad4-8be4-140c5d88a8b8", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 2, + "kind": "review_requested", + "at": "2026-10-04T22:07:33.595603+00:00" + }, + { + "id": "240451dc-4ef6-43d6-a5cd-99c098ae0d14", + "memo_id": "infd-20261005-lifecycle-production-proof", + "version": 2, + "kind": "source", + "at": "2026-10-04T22:09:20.847454+00:00" + } + ], + "receipts": [ + { + "id": "8bc87458-c042-4e45-883d-d7c189a089f7", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.060609+00:00", + "state": "delivered", + "receiver_reference": "audit:8bc87458-c042-4e45-883d-d7c189a089f7" + }, + { + "id": "ef7c9698-8466-45c8-872e-d6375b11bfa7", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.131538+00:00", + "state": "delivered", + "receiver_reference": "audit:ef7c9698-8466-45c8-872e-d6375b11bfa7" + }, + { + "id": "db6229d0-ed8e-460a-8c56-778f2477244c", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.201167+00:00", + "state": "delivered", + "receiver_reference": "audit:db6229d0-ed8e-460a-8c56-778f2477244c" + }, + { + "id": "15249473-4736-4f1c-bb6c-d130aeb473c8", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.254457+00:00", + "state": "delivered", + "receiver_reference": "audit:15249473-4736-4f1c-bb6c-d130aeb473c8" + }, + { + "id": "9b51d039-4ded-41b4-b083-178644d25eb4", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.300510+00:00", + "state": "delivered", + "receiver_reference": "audit:9b51d039-4ded-41b4-b083-178644d25eb4" + }, + { + "id": "85c3b0aa-46f9-4e96-b8eb-e7c48f70e732", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.355967+00:00", + "state": "delivered", + "receiver_reference": "audit:85c3b0aa-46f9-4e96-b8eb-e7c48f70e732" + }, + { + "id": "9a363333-5891-462a-af39-54e3161b7f6b", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.401132+00:00", + "state": "delivered", + "receiver_reference": "audit:9a363333-5891-462a-af39-54e3161b7f6b" + }, + { + "id": "5a2e81e3-70fd-4ad4-8be4-140c5d88a8b8", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:07:33.595603+00:00", + "state": "delivered", + "receiver_reference": "audit:5a2e81e3-70fd-4ad4-8be4-140c5d88a8b8" + }, + { + "id": "d94d567c-f7e0-48f1-980e-9609d69c5eec", + "class": "informed-decision.memo.posed", + "at": "2026-10-04T22:07:34.878488+00:00", + "state": "delivered", + "receiver_reference": "audit:d94d567c-f7e0-48f1-980e-9609d69c5eec" + }, + { + "id": "240451dc-4ef6-43d6-a5cd-99c098ae0d14", + "class": "informed-decision.lifecycle", + "at": "2026-10-04T22:09:20.847454+00:00", + "state": "delivered", + "receiver_reference": "audit:240451dc-4ef6-43d6-a5cd-99c098ae0d14" + } + ], + "receiver_counts": { + "audit-core.heartbeat": 2, + "informed-decision.lifecycle": 9, + "informed-decision.memo.posed": 1 + }, + "local_counts": { + "audit-core.heartbeat": 2, + "informed-decision.lifecycle": 9, + "informed-decision.memo.posed": 1 + }, + "counts_match": true, + "submissions": { + "confirmed": 24 + }, + "pending": 0 +} diff --git a/docs/evidence/2026-10-05-lifecycle-cutover/restart-retrieval.json b/docs/evidence/2026-10-05-lifecycle-cutover/restart-retrieval.json new file mode 100644 index 0000000..aa5502d --- /dev/null +++ b/docs/evidence/2026-10-05-lifecycle-cutover/restart-retrieval.json @@ -0,0 +1,22 @@ +{ + "version": 2, + "outcomes": { + "dispositions": [], + "review": { + "intake_state": "ready", + "memo_id": "review-0d55a416-178c-46f5-b74b-b9b668390448", + "path": "/review?memo_id=review-0d55a416-178c-46f5-b74b-b9b668390448", + "stale": false + } + }, + "queue": { + "delivered": 1 + }, + "same_envelope_reenqueue": "replay", + "receipt": { + "approval_binding_digest": "sha256:c3b1d474aa00316a9bc2bc3e1635b4a84d7108f3817c1e2e19a1bf0fecfbcaa4", + "approval_id": "22b30fe7-c565-46f2-8193-d8875975ad9e", + "memo_id": "review-0d55a416-178c-46f5-b74b-b9b668390448" + }, + "deployment_pins_unchanged": true +} diff --git a/docs/evidence/2026-10-05-lifecycle-cutover/restore-source-correction.json b/docs/evidence/2026-10-05-lifecycle-cutover/restore-source-correction.json new file mode 100644 index 0000000..a09c2e9 --- /dev/null +++ b/docs/evidence/2026-10-05-lifecycle-cutover/restore-source-correction.json @@ -0,0 +1 @@ +{"event_id": "240451dc-4ef6-43d6-a5cd-99c098ae0d14", "memo_id": "infd-20261005-lifecycle-production-proof", "version": 2} diff --git a/docs/evidence/2026-10-05-lifecycle-cutover/wrong-caller.json b/docs/evidence/2026-10-05-lifecycle-cutover/wrong-caller.json new file mode 100644 index 0000000..7e81c12 --- /dev/null +++ b/docs/evidence/2026-10-05-lifecycle-cutover/wrong-caller.json @@ -0,0 +1,4 @@ +{ + "check": "unregistered-service-account-correct-audience", + "status": 401 +} diff --git a/workplans/INFD-WP-0005-frictionless-decision-intake.md b/workplans/INFD-WP-0005-frictionless-decision-intake.md index 3778243..fe338ca 100644 --- a/workplans/INFD-WP-0005-frictionless-decision-intake.md +++ b/workplans/INFD-WP-0005-frictionless-decision-intake.md @@ -4,12 +4,12 @@ type: workplan title: "Frictionless decision intake — agents pose memos, only answering is human" domain: infotech repo: informed-decision -status: blocked +status: active flavor: implementation owner: claude topic_slug: netkingdom created: "2026-10-03" -updated: "2026-10-04" +updated: "2026-10-05" related: - INFD-WP-0002 - INFD-WP-0003 @@ -109,11 +109,8 @@ Offline-testable with a fake TokenReview and fake approval client. ```task id: INFD-WP-0005-T05 -status: wait +status: done priority: high -blocked_on: message-from:railiance-platform -needs_human: true -blocking_reason: "Native requester custody/identity/path/scope/projection and revocation proofs passed against candidate 804d89fb; actual receiving service mount and separate rollout go remain" state_hub_task_id: "3b0f536c-e8ee-5493-b663-2f60f5f429ad" decision_id: "0d6792b6-59e4-4fa0-887a-c4e51ea8e131" ``` @@ -127,10 +124,8 @@ memo, and records the receipt. Replaces OPERATOR step A3. ```task id: INFD-WP-0005-T06 -status: wait +status: progress priority: high -blocked_on: message-from:access-engine -blocking_reason: "Consumer implemented; FLEX-WP-0033 prepares v12 State Hub / decision-record admission; native verification and concrete rollout approval remain" state_hub_task_id: "c03016da-a795-5c5c-b86e-0ce9afc67be6" ``` @@ -164,10 +159,8 @@ evidence, notification and gated resolution delivery. Live acceptance remains T1 ```task id: INFD-WP-0005-T08 -status: wait +status: progress priority: medium -blocked_on: message-from:state-hub -blocking_reason: "STATE-WP-0096 implements private queue/runtime and projected audience proposals; native forwarding acceptance waits on approved service/worker rollout; requester custody proofs now pass" state_hub_task_id: "ce2b36b4-ef82-53b7-aee7-e0063855370b" ``` @@ -195,11 +188,9 @@ Record gate-house's answer in the spec; adjust §5 if doctrine requires it. ```task id: INFD-WP-0005-T10 -status: wait +status: progress priority: low depends_on: [INFD-WP-0005-T05, INFD-WP-0005-T06] -needs_human: true -blocking_reason: "Live rollout of intake, admission branch and write-back flag needs the founder's go" state_hub_task_id: "e7d98fc0-0e56-50e6-955d-c70209ad4712" decision_id: "24b0c846-a58e-43bc-ab80-988180ddd2f9" ``` @@ -288,3 +279,15 @@ Native requester verification passed after KeyCape Basic-auth alignment at zero HIGH/CRITICAL scan. T05 waits only on actual receiving-pod/cutover acceptance; no further requester metadata approval is pending. Production snapshot migration was proven offline without changing live schema or approval state. + +## Native intake cutover — 2026-10-05 + +Founder-approved lifecycle cutover completed actual requester mount/exchange, +private listener and selected State Hub registration, v12 attribute admission, +private dispatch and native Approval Engine creation. The retained review is +review-0d55a416-178c-46f5-b74b-b9b668390448, approval +22b30fe7-c565-46f2-8193-d8875975ad9e. Notification/memo-posed receipts are delivered; +restart and same-envelope replay preserve that one native receipt. T05 is done. +T06/T08/T10 remain in progress for the human browser/acceptance return and final +fallback documentation. Resolution write-back stays disabled. Platform RPF-IN-0004 +tracks separately governed issuer rotation proof. No renewed cutover go is needed. diff --git a/workplans/INFD-WP-0007-decision-lifecycle-service.md b/workplans/INFD-WP-0007-decision-lifecycle-service.md index 44f1b5a..4747815 100644 --- a/workplans/INFD-WP-0007-decision-lifecycle-service.md +++ b/workplans/INFD-WP-0007-decision-lifecycle-service.md @@ -8,7 +8,7 @@ status: active owner: codex topic_slug: netkingdom created: "2026-10-04" -updated: "2026-10-04" +updated: "2026-10-05" origin: demand origin_ref: "Founder 2026-10-04: full decision lifecycle for agents and humans, no per-decision infrastructure rollout, headless foundation and UI at decisions.coulomb.social" related: @@ -22,7 +22,7 @@ state_hub_workstream_id: "2b3e04ed-2137-584f-a6c2-f1abb29636fa" Contract: `docs/specs/DecisionLifecycleService.md`. This extends the existing memo and intake implementation. `INFD-WP-0005` continues to own intake runtime, attribute admission, forwarding and live acceptance. Implementation started on -2026-10-04 at the founder's request. Production identity/policy admission and broader human binding profiles remain +2026-10-04 at the founder's request. The initial production identity/policy audience is live; broader human binding profiles remain open. The shared service now has a bearer API adapter and optional browser workspace. ## Record product direction and architecture @@ -121,7 +121,7 @@ packet before requesting the separately required live rollout approval. ```task id: INFD-WP-0007-T07 -status: todo +status: progress priority: high depends_on: [INFD-WP-0007-T06] state_hub_task_id: "25fa4743-5c7e-5609-9872-7c5971ff62bc" @@ -321,3 +321,35 @@ Requester metadata approval is complete. T07 still awaits exact service/PDP/ worker cutover approval and subsequent native agent-human-agent acceptance. Issuer rotation is separately governed under Platform's lane contract and was not performed or claimed by the initial delivery proof. + +## Approved production cutover — 2026-10-05 + +Founder approved packet 70dc3b9 (decision d2eaa2e9-6d11-4676-a07f-e3b7e59a88e3). +Public traffic was briefly closed, a final consistent schema-2 snapshot retained +off-cluster (SHA-256 b0346c42434cdc375eaa591f4bffeb62b9b2e19bf589a92501c96626142670e6), +and owner Helm releases deployed before the schema-5 service. Public health and +readiness pass after reopening. All 24 confirmed prior submissions survive. +The actual receiving requester projection is read-only 0440 and signed +create-only exchange passes. Platform delivery is accepted; separate issuer +rotation evidence is tracked as RPF-IN-0004, not authorized by this cutover. + +Manual, pinned Argo applications own the service and private State Hub dispatcher. +The worker's native startup exposed Kubernetes inherited setgid; State Hub +1321361 adds a same-image non-root queue initializer, with nine regression tests. +It normalizes only an empty owned 2700 directory; existing unsafe/nonempty custody +is refused. Public ingress still targets only the browser listener. + +Native selected-workload operations registered two records, recorded research, +evaluation and comment, revised and published one record, then queued its retained +review envelope. Missing credentials, crossed audiences and an unregistered +service account with the correct audience return 401; public API routes return +404. All four deployment templates/generations remain unchanged across the +decision operations and controlled service/dispatcher pod recreation. Retrieval +returns revision 2 and the same receipt; re-enqueue is replay with one delivered +queue row, not a second approval. Independent Audit Core counts match, pending 0. + +Review memo: review-0d55a416-178c-46f5-b74b-b9b668390448; Approval Engine id: +22b30fe7-c565-46f2-8193-d8875975ad9e. Native notification and memo-posed delivery +are settled. Human disposition remains pending; no agent acceptance is claimed. +Evidence: docs/evidence/2026-10-05-lifecycle-cutover/. T07 stays in progress; +broader browser profiles and unresolved spec items remain in T02/T05/T06.