The points that fit the existing model and need NetKingdom to decide:
1.**`target`/`action` are singular in the canonical field list but per-step in
BEA section 6.** Proposal: the receipt-level `target` is the admission's
target and the receipt-level `action` is `bounded-execution`. Each step's
target and action go in `steps[]`. Audit-core needs one answer in the schema.
It will not pick one.
2.**`decision_refs` must be typed.** The admission id, the admission digest and
the approval reference are three different things. An untyped list cannot
be checked against the carrier.
3.**`delegation` stays absent** when there is none. `time_interval.bound` stays
absent when no bound is established. Unknown attribution stays the explicit
`unknown`. This is unchanged from `docs/cross-repo-evidence-admission.md`.
4.**Check results carry an id and a result only.** They carry no response
bodies, tokens, password values or LLDAP/OpenBao payloads.
## Registration (proposal)
| Registry field | Proposed value | Reason |
| --- | --- | --- |
| `name` | `nk-bounded-executor` | one identity per executor deployment |
| `sources` | `["net-kingdom.bounded-executor"]` | exact, no wildcard |
| `tenants` | the exact admission tenant(s) | not `*`; the executor acts for named tenants only |
| `may_write` / `may_read` | `true` / `false` | the verifier reads with its own read identity |
| `secret_policy` | `reject` | a receipt is kept by hash. If audit-core redacted it silently, the stored body would no longer match the hash the executor computed, so a secret-shaped field must refuse the event (`400 secret_shaped_field`). The executor treats that as a defect |
| `evidence_kind` | `load-bearing`, if the `started` + receipt pair is adopted. Otherwise `attributive` with an explicit `completeness_trade` | the pair is what makes a missing receipt detectable |
Ingress: a new NetworkPolicy in `deploy/networkpolicies.yaml` admitting
namespace `sso` and the executor's exact pod labels, following
`audit-core-tenant-engine-ingress`. Do not admit the whole `sso` namespace,
because Authelia, LLDAP and KeyCape run there too. The bearer is
ESO-projected by railiance-platform, like the other in-cluster senders. No token
value appears in this repository.
## What audit-core needs back
- **NetKingdom (NK-WP-0040-T02 / NK-WP-0056):**
- the versioned receipt schema, validator, path and digest, with positive and
negative fixtures, covering `steps`, `reverted`, `budget` and the typed
`decision_refs`;
- an answer to point 1;
- the exact `source` and event types;
- the tenant binding;
- a decision on the `started` event and the emission guarantee.
- **The rapp-\* package owner:** the exact pod labels and ServiceAccount, and
the image revision that emits.
- **railiance-platform:** the ESO projection of the sender bearer
(catalog/route via `warden route`), and the attended seed of the registry
entry.
- **Founder:** the live registry entry and NetworkPolicy rollout are an approved
live change. Audit-core prepares them; the founder runs them.
3. It appends the `nk-bounded-executor` entry to the registry. The entry is the
declared scope plus the token, written with cas on the version read. Every
other sender stays byte-equal.
4. It force-syncs `audit-core-senders` and compares the token by SHA-256 only.
5. It restarts the receiver.
6. It proves the bearer without writing an event. Inside the receiver pod, with
the bearer on stdin:
- a read gets 403 (write-only);
- reconciliation for its own source and tenant `platform` gets 200;
- tenant `tenant:platform` gets 403;
- another source gets 403.
An unknown bearer gets 401.
7. It force-syncs `sso/nk-bind-executor-audit` and compares `audit-token` by
hash, but only if that ExternalSecret exists.
The script is silent. The receipt holds versions, booleans and a 12-hex
fingerprint. A rerun reuses its own custody and writes nothing new. It refuses
foreign or drifted custody, a sender registered without custody, a token
collision and a concurrent registry write. Tests:
`tests/test_seed_nk_bounded_executor_sender.py`.
The script refuses before any write unless all of the following hold:
- CCR-2026-0063 is `approved` or later, with all three owner reviews;
- the cluster is railiance01 (kube-system UID);
- the receiver runs the pinned image;
- the live scope ConfigMap matches;
- the ingress policy exists;
- the coding-agent boundary already denies the custody data and metadata paths.
It does not create the reader policy, the role or the boundary
(railiance-platform). It also does not create the `sso` ClusterSecretStore and
ExternalSecret, which belong to the rapp-bounded-executor package (CCR-2026-0063
`delivery.target`).
## Founder runbook — nk-bounded-executor sender
Run these in order. Steps 1 and 2 can run now. Step 3 depends on CCR-2026-0063:
railiance-platform must have it approved by platform-owner, audit-core-owner and
net-kingdom-owner, and must have applied its reader policy, role and
coding-agent boundary entries.
**1. Ingress (NK-WP-0056-T16).** This applies exactly one object. Run the server
dry-run first, then the apply:
```bash
cd /home/worsch/audit-core && python3 -c 'import sys,yaml; d=[x for x in yaml.safe_load_all(open("deploy/networkpolicies.yaml")) if x and x["metadata"]["name"]=="audit-core-nk-bounded-executor-ingress"]; assert len(d)==1; yaml.safe_dump(d[0],sys.stdout)' | KUBECONFIG=/home/worsch/.kube/config-railiance01 kubectl apply --dry-run=server -f -
cd /home/worsch/audit-core && python3 -c 'import sys,yaml; d=[x for x in yaml.safe_load_all(open("deploy/networkpolicies.yaml")) if x and x["metadata"]["name"]=="audit-core-nk-bounded-executor-ingress"]; assert len(d)==1; yaml.safe_dump(d[0],sys.stdout)' | KUBECONFIG=/home/worsch/.kube/config-railiance01 kubectl apply -f -
```
**2. Read-only preflight** (prints no secrets):
```bash
KUBECONFIG=/home/worsch/.kube/config-railiance01 kubectl -n audit-core get configmap audit-core-senders-scope -o jsonpath='{.data.senders-scope\.json}' | python3 -c 'import sys,json; print([e for e in json.load(sys.stdin) if e["name"]=="nk-bounded-executor"])'
KUBECONFIG=/home/worsch/.kube/config-railiance01 kubectl -n audit-core get deploy audit-core -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'