---
id: RAILIANCE-WP-0025
type: workplan
title: "Version ephemeral custody projection and broker handoff"
domain: financials
repo: railiance-platform
status: finished
owner: codex
topic_slug: railiance
created: "2026-08-22"
updated: "2026-08-22"
related:
  - RAILIANCE-WP-0024
  - WHITEHAT-WP-0001
  - AUDIT-WP-0008
origin: run-review
origin_ref: "WH-ENG-20260822-AUDIT-E2-02 terminal clean admission abort"
state_hub_workstream_id: "2422d4e7-2125-591e-8e95-80ecc6e09da0"
---

# RAILIANCE-WP-0025 — Version ephemeral custody projection and broker handoff

## Goal

Replace engagement-specific credential scripts and prose handoffs with one
versioned, value-safe, fail-closed lifecycle. A consumer must prove it can
consume the projection receipt before platform custody mints anything. The
platform then exposes direct `preflight`, `project`, `status`, `cleanup`, and
expired-lease cleanup interfaces without transferring bearer values or
collapsing owner approvals.

The implementation is repository code and contracts only. It does not
authorize or schedule a live credential projection, workload, probe, or
unattended cleanup controller.

## T01 — Define projection, broker-readiness, and cleanup receipts

```task
id: RAILIANCE-WP-0025-T01
status: done
priority: high
state_hub_task_id: "b3a27c15-5717-5c9a-a530-b592dfa4b6f3"
```

Publish versioned JSON Schemas and canonical validation for the projection
contract, broker-readiness receipt, active projection receipt, and cleanup
receipt. Bind every receipt to the exact engagement, target revision and image,
runner and target contract digests, mounted identity handles, expiry, opaque
lease id, and cleanup authority. Values and value-derived fingerprints are
forbidden.

Done when malformed, stale, mismatched, expired, and value-bearing documents
fail closed and consumers can implement without interpreting prose.

Implemented in four JSON Schemas plus `scripts/custody_contract.py`. Canonical
projection ids cover all receipt content; validators bind target, contract,
roles, mount paths, resource names and UIDs, and reject value-bearing fields.
Broker approvals also pin the current hashes of all four interface schemas.

## T02 — Implement a data-driven custody lifecycle

```task
id: RAILIANCE-WP-0025-T02
status: done
priority: high
state_hub_task_id: "b549638b-cd39-57b1-a103-6ceea2a025e1"
```

Replace copied per-engagement code and static manifests with one lifecycle that
derives exact OpenBao and ESO resources from a validated engagement contract.
Expose value-safe `preflight`, `project`, `status`, and idempotent `cleanup`
commands. Preserve the existing two-identity sender overlay, application-level
expiry, exact-key mount, readiness reload, and exact-scope rollback behavior.

Done when a new engagement requires data only, not copied Python, HCL, or YAML,
and an old engagement identifier cannot leak into generated resources.

Implemented by `scripts/custody-projection.py` and the intentionally invalid
placeholder template `docs/custody-projection-contract.example.json`. Policy,
role, store, KV paths, ExternalSecret data mappings, sender overlays, expiry,
and cleanup scope derive from one validated contract. Resource names use an
engagement-id digest rather than a copied run suffix.

## T03 — Gate projection on a direct broker capability receipt

```task
id: RAILIANCE-WP-0025-T03
status: done
priority: high
state_hub_task_id: "dde2d93a-729d-50ba-88ce-fe0fb12f2c1e"
```

Provide a direct owner interface for `whitehat-security` to inspect, verify,
approve, or request changes to the contract. Approval must identify the tested
adapter revision and artifact digest and be posted directly to State Hub. The
platform lifecycle must find a current matching approval before generating a
credential.

Done when an unconnected, stale, wrong-engagement, or wrong-contract broker is
rejected before the first OpenBao or sender-registry mutation.

Implemented by `scripts/wp0025-broker-readiness.py`. Its closed verification
surface pins Whitehat's adapter and focused test paths, computes their commit
and digest, runs only the named focused test, and posts the canonical receipt
directly as `whitehat-security`. `project` checks State Hub before reading the
platform-admin token file, generating bearer values, or touching live state.
No adapter approval is fabricated by this implementation; a future Whitehat
adapter must pass the interface itself.

## T04 — Harden execution and transactional cleanup

```task
id: RAILIANCE-WP-0025-T04
status: done
priority: high
state_hub_task_id: "8b85184e-c5c1-56af-920b-b2bd3b6eb4ff"
```

Centralize remote argv quoting, test shell-hostile arguments, and inject
failures at each mutation boundary. Prove that partial projection invokes exact
cleanup and that status never infers absence after a connectivity failure.
Retire the copied `-01`/`-02` procedure from future-run instructions.

Done when the SSH expansion defect from the `-02` run and every modeled partial
failure have regression coverage.

Implemented by `scripts/remote_exec.py` and focused tests covering `$`, shell
substitution, semicolons, quotes, NUL refusal, and value-safe failure messages.
The lifecycle uses a transaction whose rollback is exercised after every
modeled mutation boundary. Connectivity failure cannot be interpreted as
absence, and cleanup refuses a recreated same-name Kubernetes resource whose
UID differs from the receipt.

## T05 — Add an approval-ready expired-lease cleanup entry point

```task
id: RAILIANCE-WP-0025-T05
status: done
priority: medium
state_hub_task_id: "af0a0de5-4753-52b9-aa2e-8e052c5254bf"
```

Add a fail-closed `cleanup-expired` interface that accepts only a valid
projection receipt after its expiry, removes only the receipt-bound resources,
and emits the normal cleanup receipt. Do not install a scheduler or controller;
deployment of unattended cleanup remains a separate owner decision.

Done when an approved future reaper can call a deterministic command without
receiving projected bearer values or reconstructing cleanup scope from chat.

Implemented as `cleanup-expired`. It refuses before expiry, requires the exact
canonical projection receipt and engagement confirmation, verifies live UIDs,
uses the ordinary exact cleanup transaction, and emits the versioned cleanup
receipt. No scheduler, controller, runtime identity, or unattended authority
was deployed; those remain a separate owner decision.

## Acceptance

- [x] No projection can begin without a current consumer broker receipt.
- [x] A new engagement is configuration, not copied executable code.
- [x] Projection and cleanup receipts are versioned, canonical, and value-safe.
- [x] Remote command arguments survive shell-hostile templates unchanged.
- [x] Every modeled partial mutation cleans only its receipt-bound scope.
- [x] Expired cleanup is executable but no unattended scheduler is deployed.

## T06 — Export the broker receipt consumed by admission

```task
id: RAILIANCE-WP-0025-T06
status: done
priority: high
```

The first fresh-run setup review found that `approve` posted the canonical
broker-readiness receipt to State Hub but exposed no safe way to persist the
raw receipt document required by Whitehat's `--broker-receipt` input. Redirecting
the command output would save a CLI wrapper rather than the canonical document.

`approve` and a ready `status` now accept `--receipt-out`, create parent
directories, write only the canonical value-safe receipt, and force mode
`0600`. Other commands fail closed when that option is supplied. Regression
coverage proves the wrapper is excluded and the file mode is private.
