# Custodian runtime binding proposal Update: user selected the existing worker. The concrete pinned image package, private state/fleet mount candidate and tunable policy now live in [`k8s/custodian-release/README.md`](../k8s/custodian-release/README.md). That packet supersedes the placement alternatives below. It remains outside active kustomization; schedules are disabled. Review artifact, 2026-10-19. Not a deployment or activation approval. Both native ActivityDefinitions remain `enabled: false`. No manifests, images or schedules were changed for this proposal. Read with `custodian-bounded-operations.md`. ## Verified source boundary The worker in `k8s/railiance/20-runtime.yaml` runs as UID/GID 1000 and already uses `actcore-ops-artefacts` for freshness and owner-return subdirectories. Its image does not contain the Custodian commands; its current mounts contain neither the accepted fleet workplans/decisions nor the new private state. `CUSTODIAN_REPO_ROOT=/var/custodian` only binds existing prompts/working memory; it does not satisfy any `ACTIVITY_CORE_CUSTODIAN_*` binding. The existing immutable ConfigMap plus read-only mount pattern documented in `k8s/backup-release/README.md` is sufficient for the small command bundle. No new packaging service is needed. Proposed source pin: `the-custodian@60d893af1bf77f457504b64ff1c9ffb5c6ae6579`. These four files total 30,169 bytes and use Python standard-library modules; the daily command imports/calls the two sibling helper scripts. | Path under owner root | SHA-256 | | --- | --- | | scripts/security_flow_daily.py | 4a4e84702b3fb38d086695bb6d601430d8914bd79286b4f683794206f110c353 | | scripts/security_flow_report.py | eac9fdcc56d7f3ff613e6848c7523fb9a421d82a3b564a51c36f8c2b842eef02 | | scripts/sync_resolved_decisions.py | 182433ca7cd31e2b2773246ec1be02569ba6f089ac009add6543e5e48777b5ec | | scripts/weekly_allocation_report.py | 93f546243331308d7e60f8db36e988d9847537a2fe46cce49ee2fffba1f7f247 | A reviewed immutable ConfigMap can map these four keys to `scripts/` below `/opt/custodian-commands`. Kubernetes ConfigMap volume projections use symlinks, which the executor deliberately rejects. Therefore copy the mounted immutable bundle into a dedicated emptyDir in an init container, verify all four hashes there, then mount that copy read-only in the worker. Do not bind the projected ConfigMap directly or weaken executor symlink checks. Alternatively, copy the same pinned files into the existing worker image during its reviewed build. The latter avoids the init-container copy and is the narrower runtime mount boundary, but requires an accepted source-delivery/build input. Neither alternative has been chosen or implemented here. ## Exact proposed bindings and outstanding choices | Binding | Proposed value / owner decision | | --- | --- | | ACTIVITY_CORE_CUSTODIAN_ROOT | `/opt/custodian-commands`, regular files, read-only, hashes above | | ACTIVITY_CORE_CUSTODIAN_FLEET_ROOT | `/var/lib/custodian-inputs/fleet`, read-only accepted snapshots | | ACTIVITY_CORE_CUSTODIAN_STATE_ROOT | `/var/lib/activity-core/custodian`, persistent, UID 1000, mode 0700 | | ACTIVITY_CORE_CUSTODIAN_REPOS | Explicit operator-approved subset of the daily report estate; each must have `workplans/` | | ACTIVITY_CORE_CUSTODIAN_HUB | `http://state-hub.state-hub.svc.cluster.local:8000`, subject to admitted network verification | | ACTIVITY_CORE_CUSTODIAN_ALLOCATION_REQUEST | `/var/lib/activity-core/custodian/requests/current.json`, regular file protected against concurrent writers | For daily input, preserve `/workplans/**/*.md` including dependency records and `/decisions/*.md` only for approved decision-sync scope. The decision helper scans every repo under the fleet root independently of the report list. Do not mount a whole workstation home, `.git`, credential directories or arbitrary mutable repositories. Fleet snapshots need per-repo revision, capture time, refresh owner and an explicit staleness policy. No existing publication contract for this combined input was found in the worker manifests. Choosing its publisher is a real prerequisite; a pinned old snapshot alone cannot support daily freshness. Weekly input remains the existing retained collector outputs plus request JSON, not a new collector. Its owner must bind actual input/report paths and evaluation time, freeze the request across retries, and publish a new request for the next week. The executor does not advance a static `current.json` automatically. Snapshot publication must be atomic relative to execution and preserve retained inputs needed to reproduce reports. Never substitute synthetic readings. Storage choice: reuse a new `custodian` subdirectory of existing `actcore-ops-artefacts` only after its owner accepts capacity, retention and backup coverage, or provision a dedicated claim with those properties. The existing rollout document describes a 1Gi local-path claim, and October 4 evidence reports it Bound; neither proves present capacity or backup coverage. Precreate state, `security-flow`, `requests` and output/input retention directories with correct ownership. Do not chown/chmod the whole shared claim. A PVC subPath is acceptable if actual mounted paths are regular directories and pass executor validation. The proposed direct Hub service matches the worker's existing `STATE_HUB_API_BASE`; the shared config also contains an edge-relay URL. Daily message delivery requires a central message ID. A relay queued receipt is pending evidence and is not interchangeable with that ID; do not select relay delivery without an explicit adapter/replay contract. Needed operations are GET open decisions, POST decision resolution, POST messages, and the existing progress sink. Runtime network authorization remains unverified. The shared worker already has secret env and kube mounts: this proposal does not establish credential isolation. Placement choices for owner review: 1. Existing production worker: choose image-baked scripts or verified copied immutable bundle, choose fleet publisher and state claim above, then review normal owner GitOps changes. This reuses the present Temporal task queue. 2. Workstation execution: requires an explicitly routed worker/task queue and a durable always-on ownership/connectivity contract. Merely starting another worker on `orchestrator-tq` is unsafe because either worker may receive these activities. No workstation routing or second scheduler is proposed. ## Verification and rollback before activation Prepare the accepted source bundle and manifest diff outside active kustomization until the choices above are recorded. Preserve both disabled definitions; native schedule synchronization creates disabled definitions paused. Verify their DB versions and Temporal paused state after any later deployment, without firing. Mount/env changes exceed image-only promotion authority; follow owner-reviewed GitOps promotion, not a widened image-only helper. Local source tests already cover parsing both disabled definitions, missing-binding refusal before subprocess, fixed commands, symlink rejection, bounded timeouts and sanitized receipts. At delivery review, independently verify pinned hashes, worker Python imports, UID/modes, mount read-only flags, free retained capacity, scoped fleet revision/age and actual request/output confinement. Use fixture inputs for initial process verification; daily dry-run still reads Hub and therefore is not an offline test. Obtain separate authorization for real Hub operations. After operator-approved runtime placement, retain exact worker image/bundle and input revisions, operation context, owner report hash, progress sink result and owner acknowledgment. Scheduled activation and first unattended run remain ACTIVITY-WP-0047-T02/T03 and CUST-WP-0071-T04/T05 gates. An exit-zero fixture or a paused schedule does not satisfy them. Rollback: keep both schedules paused, restore the previous reviewed worker image/config/bundle references through GitOps, and keep old bundle objects until no rollback ReplicaSet references them. Preserve private reports, checkpoints and requests; do not delete the state claim. Inspect partially delivered daily checkpoints before retrying, because rollback cannot undo Hub writes. Do not reuse or overwrite an immutable weekly output for revised inputs.