NK-WP-0055-T11: plan audit sender payloads, chain correlation id, core PDP readiness
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

FLEX-WP-0031 gains T10 (final per-pin payloads for AUDIT-WP-0013-T02) and
T11 (cross-stream correlation id, FLEX-WP-0024 relation); T02 no longer waits
on the settled failure-path ruling. New proposed FLEX-WP-0039 covers ADR-0018
readiness surface, per-consumer fail-closed receipts and policy import options.
SCOPE.md: secrets-engine pin enforces caller auth since 6e3dfae.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4515@bnt-lap001
Assistant-Session: 0bf96127-6e04-41be-bfda-d11717c3f354
This commit is contained in:
tegwick 2026-10-27 22:35:31 +01:00
parent b2ddb4b3eb
commit 7cbd4e5328
4 changed files with 204 additions and 3 deletions

View file

@ -122,7 +122,8 @@ secret-catalog-lane`, twelve actions delivered by secrets-engine rather than
inferred, `destroy` gated on a dual-control approval claim, and a dedicated
`flex-auth-secrets-engine` pin at
`http://flex-auth-secrets-engine.flex-auth.svc.cluster.local.:8080` —
trailing dot required, in-cluster only — with `callerAuth.mode: warn`. Adoption is not complete: secrets-engine is a CLI
trailing dot required, in-cluster only — with `callerAuth.mode: enforce` (since
2026-09-06, `6e3dfae`, verified operator caller identity). Adoption is not complete: secrets-engine is a CLI
rather than a workload, and the pin's default-deny ingress admits a pod, so an
operator-run access path is still undecided.

View file

@ -48,6 +48,7 @@
| workplan | FLEX-WP-0036 | active | — | workplans/FLEX-WP-0036-runtime-rename-access-engine.md |
| workplan | FLEX-WP-0037 | finished | — | workplans/FLEX-WP-0037-ops-warden-agt-custodian-actor.md |
| workplan | FLEX-WP-0038 | active | — | workplans/FLEX-WP-0038-wave2-resource-right-sizing.md |
| workplan | FLEX-WP-0039 | proposed | — | workplans/FLEX-WP-0039-core-pdp-production-readiness.md |
| task | FLEX-WP-ADHOC-2026-10-03-T01 | done | — | workplans/ADHOC-2026-10-03.md |
| task | FLEX-WP-ADHOC-2026-10-03-T02 | wait | — | workplans/ADHOC-2026-10-03.md |
| task | FLEX-WP-ADHOC-2026-10-11-T01 | done | — | workplans/ADHOC-2026-10-11.md |
@ -204,6 +205,8 @@
| task | FLEX-WP-0031-T07 | done | — | workplans/FLEX-WP-0031-decision-record-emission.md |
| task | FLEX-WP-0031-T08 | wait | — | workplans/FLEX-WP-0031-decision-record-emission.md |
| task | FLEX-WP-0031-T09 | done | — | workplans/FLEX-WP-0031-decision-record-emission.md |
| task | FLEX-WP-0031-T10 | todo | — | workplans/FLEX-WP-0031-decision-record-emission.md |
| task | FLEX-WP-0031-T11 | wait | — | workplans/FLEX-WP-0031-decision-record-emission.md |
| task | FLEX-WP-0032-T01 | done | — | workplans/FLEX-WP-0032-informed-decision-list-action.md |
| task | FLEX-WP-0032-T02 | done | — | workplans/FLEX-WP-0032-informed-decision-list-action.md |
| task | FLEX-WP-0032-T03 | done | — | workplans/FLEX-WP-0032-informed-decision-list-action.md |
@ -231,6 +234,10 @@
| task | FLEX-WP-0037-T02 | done | — | workplans/FLEX-WP-0037-ops-warden-agt-custodian-actor.md |
| task | FLEX-WP-0037-T03 | done | — | workplans/FLEX-WP-0037-ops-warden-agt-custodian-actor.md |
| task | FLEX-WP-0038-T01 | wait | — | workplans/FLEX-WP-0038-wave2-resource-right-sizing.md |
| task | FLEX-WP-0039-T01 | todo | — | workplans/FLEX-WP-0039-core-pdp-production-readiness.md |
| task | FLEX-WP-0039-T02 | todo | — | workplans/FLEX-WP-0039-core-pdp-production-readiness.md |
| task | FLEX-WP-0039-T03 | todo | — | workplans/FLEX-WP-0039-core-pdp-production-readiness.md |
| task | FLEX-WP-0039-T04 | todo | — | workplans/FLEX-WP-0039-core-pdp-production-readiness.md |
| intake | FLEX-IN-0001 | closed | — | intakes/intakes.md |
| intake | FLEX-IN-0002 | closed | — | intakes/intakes.md |
| intake | FLEX-IN-0003 | open | — | intakes/intakes.md |

View file

@ -62,8 +62,8 @@ and the node disk is at 84 %.
```task
id: FLEX-WP-0031-T02
status: wait
blocked_on: message-from:audit-core
blocking_reason: "GH-WP-0004-T12 refused the load-bearing failure-path exception (GH-DEC-2026-024). AUDIT-IN-0006 sender rows and governed token delivery remain pending."
blocked_on: task:FLEX-WP-0031-T10
blocking_reason: "Failure-path ruling settled (GH-DEC-2026-024, implemented in T09). AUDIT-WP-0013-T02 now waits on our final per-pin payloads (T10); ops-warden mint lane and railiance-platform attended custody remain external."
priority: high
state_hub_task_id: "89661908-ca9a-5e4a-a0a5-62d1a9e02568"
```
@ -343,3 +343,84 @@ and integer boundary rendering passed. Original stage retained; no native change
> critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged;
> promote back when demand or risk appears. See the-custodian
> `history/20261011-netkingdom-security-progress-assessment.md`.
## 10. Return final per-pin registration payloads to AUDIT-WP-0013-T02
```task
id: FLEX-WP-0031-T10
status: todo
priority: high
depends_on: [FLEX-WP-0031-T09]
```
Added 2026-10-27 for NetKingdom NK-WP-0055-T11. audit-core's
`AUDIT-WP-0013-T02` is `blocked_on: message-from:flex-auth`: it needs our
non-secret, final registration payloads, not another intake. The failure-path
question that held T02 is settled (`GH-DEC-2026-024`, source enforced in T09),
so nothing on our side waits on a ruling any more.
Per release unit, one file under `docs/contracts/audit-senders/<pin>.json`:
- `source: flex-auth.<pin>` (exact, no wildcard), write true, `may_read: false`,
`tenants: ["*"]` with the deny-before-tenant-creation justification,
`secret_policy: redact`, load-bearing;
- `heartbeat_classes`: `flex-auth.decision.deny`, `.redact`, `.not_applicable`,
`.audit_only` at 86400 s (the stored `ClassPrefix` names, not shorthand);
- a canonical `emission_cadence` (wire schema 0.1) naming that exact source,
with **our** chosen `allow` expected rate, window and threshold, derived from
each pin's observed decision volume, not invented;
- the pin's namespace/pod ingress selector as rendered by `charts/flex-auth`.
Open scope question to settle first: audit-core lists six pins
(ops-warden, tenant-engine, user-engine, secrets-engine, informed-decision-t03,
informed-decision-sitting). `registry/release-units/` now declares nine; the
newer `ops-warden-fetch`, `application-readback` and
`informed-decision-lifecycle` units also answer load-bearing decisions. Either
register all nine or record why a unit emits nothing. Source names keep the
`flex-auth.` prefix: release units were not renamed by `FLEX-DEC-2026-020`.
Gate: payloads committed, validated against the cadence profile checker, and
sent to audit-core on thread `6044ed35`. Token mint stays founder-attended
(ops-warden lane, railiance-platform custody) under T08.
## 11. Carry the cross-stream correlation id in the decision envelope
```task
id: FLEX-WP-0031-T11
status: wait
priority: high
blocked_on: message-from:net-kingdom
blocking_reason: "NetKingdom owns the onboarding-chain correlation-id contract (NK-WP-0055-T11); field name, format and propagation rule are not yet defined."
```
Added 2026-10-27. Today the emitted event's `correlation_id` is the decision
id, a content digest that two identical checks share. That joins a record to
its decision, but not to the identity, OpenBao, Kubernetes and workload records
of the same onboarding chain that NK-WP-0055-T11 needs.
Plan, once NetKingdom publishes the contract:
1. Accept the chain id from the caller in the check request (beside the
request `id`, and like it excluded from `request_digest`, so the id never
changes a decision or its replay).
2. Echo it in `flex-auth.decision-record.v1` as a named field and, when present,
use it as the audit event's `correlation_id`; the decision id stays in
`data`. Absent: keep today's behaviour. Heartbeats keep their own ids.
3. FLEX-WP-0024 relation: the signed envelope must cover the chain id, or a
relaying responder could re-attribute a decision to another chain. Until
0024 signs, the id is caller-asserted correlation, never evidence of who
asked; record it as such in `docs/decision-record-contract.md`.
4. Tests: digest invariance with and without the id; outbox and drain carry it;
explain returns it.
Gate: contract field merged, tests pass, and an NK onboarding-chain test shows
one id across at least the identity and authorization records.
## What remains for durable decision records (2026-10-27)
Source is complete: durable outbox, mandatory commit (T09), heartbeat and
drain (T05), chart PVC and delivery wiring (T07, T08 prep). Open: T10 payloads
(ours, now), T11 correlation (waits on NetKingdom), T02 sender rows and
attended token mint (audit-core, ops-warden, railiance-platform, founder), T08
approved rollout and native 202/silence proof, T06 reconciliation (audit-core
time basis), T04 G2 closure.

View file

@ -0,0 +1,112 @@
---
id: FLEX-WP-0039
type: workplan
title: "Core PDP production readiness: per-pin readiness surface and policy import path"
domain: infotech
repo: access-engine
status: proposed
flavor: implementation
owner: access-engine
created: "2026-10-27"
updated: "2026-10-27"
related: [NK-ADR-0018, NK-WP-0055, FLEX-WP-0031, FLEX-WP-0024, FLEX-WP-0011]
---
# FLEX-WP-0039 — Core PDP production readiness
NetKingdom ADR-0018 (accepted 2026-10-27) makes the access-engine Go core the
production PDP and runs the PDP readiness checks against it: health, data
freshness, policy load status, and per-consumer fail-closed behaviour
(NK-WP-0055-T12). It moves the policy import gap to NK-WP-0055-T14.
Current state, from source: `/healthz` returns a static `{"status":"ok"}` and
says nothing about what was loaded. Each pin loads its policy package and
registry snapshot from a path baked into the image
(`/opt/flex-auth/examples/<consumer>/...`), so every policy change is an image
rebuild and rollout. `/v1/emission` already reports outbox state.
## 1. Readiness surface per pin
```task
id: FLEX-WP-0039-T01
status: todo
priority: medium
```
Add `GET /v1/readiness` (and make `/readyz` fail when it fails), no secrets,
caller-auth exempt like `/healthz`:
- `policy`: package id, version, `policy_package_digest`, source path,
`loaded_at`, load result (`ok` or the refusal reason);
- `registry`: `registry_snapshot_digest`, snapshot `generated_at`, age in
seconds against a per-pin `maxSnapshotAge` (data freshness);
- `caller_auth`: mode (`enforce`/`warn`/`off`) and audience;
- `emission`: recorder attached, pending depth, lag-bound exceeded (from
`/v1/emission`);
- `release_unit` and image digest.
A pin is not ready when the policy failed to load, the snapshot is older than
its bound, or caller auth is not `enforce` on a production unit. Gate: tests
for each not-ready cause; chart wires `readinessProbe` to `/readyz`.
## 2. Per-consumer fail-closed receipt
```task
id: FLEX-WP-0039-T02
status: todo
priority: medium
depends_on: [FLEX-WP-0039-T01]
```
A read-only script `tools/readiness-receipt` that, for each release unit in
`registry/release-units/`, reads `/v1/readiness` through the operator access
path and joins it with the consumer's `pep-stance.yaml` (ops-warden,
tenant-engine, user-engine, secrets-engine, informed-decision). Output is a
dated, non-secret receipt per consumer: readiness fields, declared stance on
PDP unavailable / 503 / malformed envelope, and whether that stance is closed
for the scope. An open-for-scope stance is reported as a finding, not
corrected here (FLEX-WP-0031-T09: a 503 only denies if the consumer closes).
Live runs are founder-run; the script is tested on fixtures. Gate: receipt for
all nine units feeds NK-WP-0055-T12.
## 3. Decide the policy import path
```task
id: FLEX-WP-0039-T03
status: todo
priority: medium
needs_human: true
```
NK-WP-0055-T14 accepts either option; the founder picks one:
- **A. Rebuild-and-deploy is the import path.** Keep policies in the image;
require digest-pinned images, a recorded `policy_package_digest` per release,
and `explain` receipt after rollout. No new runtime surface. Cost: a release
per policy change.
- **B. Mounted policy bundle.** Chart mounts a ConfigMap (or OCI artifact
pulled by an init container) holding the policy package and registry
snapshot; the pin loads it at start (restart on change, no hot reload in
v1). Requires a digest pin in values so the loaded package is the reviewed
one, and the readiness surface (T01) to prove which digest is live.
- **C. Signed bundle pull.** As B, but the bundle is signed and verified
before load. Pairs with FLEX-WP-0024's signer custody; heavier, and blocked
where 0024 is.
Recommendation: B now with digest pinning, C when FLEX-WP-0024 custody exists.
Gate: founder decision recorded as a `FLEX-DEC`.
## 4. Split tenant:coulomb platform and tenant packages
```task
id: FLEX-WP-0039-T04
status: todo
priority: medium
depends_on: [FLEX-WP-0039-T03]
```
Separate the platform-owned package (guardrails, protected-system actions)
from a `tenant:coulomb` package so tenant policy changes do not touch platform
rules, per NK-WP-0055-T14. Produce one production `explain` receipt
(founder-run) against the split. Gate: both packages validate, tenant-scope
tests pass, receipt recorded.