FLEX-WP-0029: publish the second stance-register edition across five rows (a third scope axis, not a converging two — tenant-engine scopes on engine-reachability, not security-zone), record Finding 1 as resolved by gate-house doctrine rather than by either side, and note Finding 3 as still open in secrets-engine's file. First edition marked superseded, not amended. SCOPE.md's G3 gap closed accordingly. FLEX-WP-0031: correct cadence.yaml to declare one heartbeat per rare load-bearing class instead of a single combined class (tests pass unchanged). Acknowledged audit-core's AUDIT-IN-0006 reply on T02 and recorded its corrections; the remaining work (drain, reconciliation, PVC rollout, G2 closure) stays wait/blocked pending the founder's attended OpenBao mint and gate-house's atomicity ruling, so the workplan moves to blocked. FLEX-WP-0027: marked blocked — the sole remaining task needs the operator's own signed-in account, an irreducible human action. FLEX-WP-0020: recorded net-kingdom's T04 update (NK-WP-0039-T02 done, runtime.yaml digests current) and replied with no objection to their ADR-0015 values-pointer proposal for the drifted runtime.yaml reference. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 250108@bnt-lap001 Assistant-Session: bab3d5bd-b0bb-42d0-bf80-94ed6fc2b08a
206 lines
9.1 KiB
Markdown
206 lines
9.1 KiB
Markdown
---
|
|
id: FLEX-WP-0031
|
|
type: workplan
|
|
title: "The decision record has a declared emission guarantee and nothing that delivers it"
|
|
domain: infotech
|
|
repo: flex-auth
|
|
status: blocked
|
|
flavor: implementation
|
|
owner: claude
|
|
topic_slug: netkingdom
|
|
planning_priority: P1
|
|
planning_order: 310
|
|
related_workplans:
|
|
- FLEX-WP-0030
|
|
- FLEX-WP-0019
|
|
created: "2026-09-21"
|
|
updated: "2026-09-27"
|
|
state_hub_workstream_id: "84f5d9fe-b4c9-584a-b964-efe3e48af095"
|
|
---
|
|
|
|
# FLEX-WP-0031 — Deliver the decision-record emission guarantee
|
|
|
|
`GH-DEC-2026-018` ruled that flex-auth is the §4 source of evidence for the
|
|
decision record, and that it is not conforming on §11 until it declares and
|
|
delivers a per-event-class emission guarantee. The declaration is published
|
|
(`cadence.yaml`, `FLEX-WP-0030-T07`). Nothing emits: the decision record reaches
|
|
consumers only in the `/v1/check` response, no sender named flex-auth or
|
|
`access-engine` is registered with `audit-core`, and there is no outbox,
|
|
heartbeat or reconciliation count. This plan closes declared gap **G2**
|
|
(`docs/conformance/security-layer-conformance.md`, review 2026-10-19).
|
|
|
|
Bound, stated up front so no argument rests on more: heartbeat and
|
|
reconciliation detect loss, outage, drain failure and accident. Neither detects
|
|
a compromised flex-auth suppressing a record and its own count together.
|
|
|
|
## 1. Decide emission atomicity
|
|
|
|
```task
|
|
id: FLEX-WP-0031-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "2dbc225f-d762-537b-9a24-ab2b17fc2fa2"
|
|
```
|
|
|
|
`GH-DEC-2026-018` left open whether decision-record emission must be atomic with
|
|
the decision (§9.4), pending the class inventory. It exists now. Decide whether
|
|
a rare load-bearing decision (`deny`) may be returned before its record is
|
|
committed to the outbox, and record the answer as a `FLEX-DEC`. Gate: decided,
|
|
with the latency cost stated.
|
|
|
|
Done 2026-09-23: `FLEX-DEC-2026-018`. Every decision is released only after its
|
|
record commits to the local outbox. When the commit fails, restrictive effects
|
|
(`deny`, `redact`, `not_applicable`) are still released and counted as
|
|
`released_uncommitted`, while `allow` and `audit_only` are withheld (503).
|
|
Withholding a deny would turn it into an error that an open-stance consumer
|
|
treats as proceed. The measured cost is about 1.1 ms per durable append on
|
|
railiance01. The ruling puts two requirements on T03: the outbox needs a PVC,
|
|
and the node disk is at 84 %.
|
|
|
|
## 2. Register flex-auth as an audit-core sender
|
|
|
|
```task
|
|
id: FLEX-WP-0031-T02
|
|
status: wait
|
|
priority: high
|
|
state_hub_task_id: "89661908-ca9a-5e4a-a0a5-62d1a9e02568"
|
|
```
|
|
|
|
Open an intake with `audit-core` (worked examples `AUDIT-IN-0002`,
|
|
`AUDIT-IN-0003`): sender registration, `evidence_kind`, `heartbeat_classes` per
|
|
class exactly as `cadence.yaml` publishes them, and a token lane routed via
|
|
`warden route find`. audit-core has said it accepts the classification as
|
|
supplied and will not infer it. Gate: sender registered; no secret in any file.
|
|
|
|
Requested 2026-09-23 (hub message `6044ed35`). The request asks for six senders,
|
|
one per pin (`flex-auth.<pin>`), because each pin can only reconcile its own
|
|
count. It also asks for `tenants: ["*"]` with a justification,
|
|
`may_read: true` for `GET /v1/reconciliation`, and per-class `heartbeat_classes`
|
|
at 86400 s for the four rare classes. It asks audit-core to rule on whether
|
|
FLEX-DEC-2026-018's failure-path exception counts as a `completeness_trade`,
|
|
which `senders.py` forbids for a load-bearing source. warden route has no
|
|
catalog lane for audit-core sender tokens, and audit-core was asked to name one.
|
|
Waiting on audit-core.
|
|
|
|
2026-09-27: audit-core replied (`AUDIT-IN-0006`, thread `6044ed35`), accepted
|
|
with corrections: `may_read` must be `false`, not `true` (a writer already
|
|
counts its own sources without it); `tenants: ["*"]` accepted on the stated
|
|
justification; per-class heartbeats and the `cadence.yaml` correction accepted
|
|
(done, see T05); each registration must also carry an `emission_cadence`
|
|
declaration (info-tech-canon wire schema 0.1, contract digest
|
|
`b08b4d95fc4b0bd3`) with `allow` as expected-rate, or its rate is only
|
|
declared and not evaluated. Two envelope corrections land before submission:
|
|
the heartbeat event needs its own `correlation_id` (no decision id exists for
|
|
it), and `occurred_at` needs an explicit offset. The atomicity ruling
|
|
(whether the `FLEX-DEC-2026-018` failure-path release is a `completeness_trade`)
|
|
is referred to `gate-house` by audit-core, not decided here — flex-auth agreed
|
|
in reply to wait for that referral. The token lane is an attended OpenBao mint
|
|
in the founder's terminal (same path `tenant-engine` used,
|
|
`AUDIT-WP-0010-T02`); `ops-warden` has no catalog lane for it yet and will add
|
|
one when registration opens. flex-auth acknowledged all of this in reply.
|
|
Still `wait`: the mint needs the founder, and `ops-warden`'s catalog entry is
|
|
not yet in place.
|
|
|
|
## 3. Durable outbox and the release rule
|
|
|
|
```task
|
|
id: FLEX-WP-0031-T03
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "a59603d5-8954-5b05-b1a0-b143c82e439b"
|
|
```
|
|
|
|
Split on 2026-09-23 under the per-task budget. T05 and T06 carry the rest of
|
|
the original scope, and the original gate is divided between the three.
|
|
|
|
Done 2026-09-23:
|
|
|
|
- `internal/emission`: a durable outbox with one fsync per commit. A batch
|
|
commits once. Each event carries exactly the eight fields audit-core's
|
|
`normalize()` requires.
|
|
- Event ids are random and the decision id travels as `correlation_id`.
|
|
Decision ids are content digests, so two identical checks share one, and
|
|
idempotency would merge them.
|
|
- A torn tail is cut on open, and a failed commit is cut back to the last
|
|
committed size. Committed counts per class are rebuilt on restart.
|
|
- The engine applies `FLEX-DEC-2026-018` in `Check`, `BatchCheck` and
|
|
`ListAllowed`. A withheld decision answers 503.
|
|
- `serve --outbox-dir --emission-source` enables it, and `GET /v1/emission`
|
|
reports committed and `released_uncommitted` counts per class.
|
|
- `api.DecisionEffects()` lists the effect vocabulary. A source-parsing test
|
|
fails on any constant it misses, and a second test fails unless the
|
|
load-bearing classes in `cadence.yaml` equal that vocabulary.
|
|
- `make test` (race) passes, and a local serve smoke test committed and counted
|
|
one deny and one allow. Nothing is deployed and no chart changed.
|
|
|
|
## 5. Heartbeat and drain to audit-core
|
|
|
|
```task
|
|
id: FLEX-WP-0031-T05
|
|
status: wait
|
|
priority: high
|
|
state_hub_task_id: "14bd6648-11da-53d7-a512-027005bd4772"
|
|
```
|
|
|
|
2026-09-27: `cadence.yaml`'s heartbeat declaration corrected — it now names one
|
|
class per rare load-bearing event (`deny`, `redact`, `not_applicable`,
|
|
`audit_only`) instead of a single combined `flex-auth.decision.heartbeat`
|
|
class. `go build`/`go test ./...` pass unchanged. The remaining scope — the
|
|
actual per-class heartbeat sender and the drain to `POST /v1/events` — is
|
|
correctly blocked on T02's sender registration with `audit-core`; the task
|
|
stays `wait` rather than in progress here.
|
|
|
|
- Emit a daily `audit-core.heartbeat` event per rare class, with `data.class`
|
|
set to the class, following audit-core's `stream_findings` shape.
|
|
- Correct `cadence.yaml`, which still names a single
|
|
`flex-auth.decision.heartbeat` class.
|
|
- Drain committed events to `POST /v1/events` with `Idempotency-Key` set to the
|
|
event id, keep a drain cursor, and expose outbox depth and age against the
|
|
`lag_bound`.
|
|
- The drain stays disabled until T02 admits the senders.
|
|
|
|
## 6. Reconciliation, profile check, and storage
|
|
|
|
```task
|
|
id: FLEX-WP-0031-T06
|
|
status: wait
|
|
priority: high
|
|
state_hub_task_id: "bf92a951-3b69-59dd-8907-f6748c91a264"
|
|
```
|
|
|
|
2026-09-27: reconciliation compare needs `audit-core`'s `GET /v1/reconciliation`,
|
|
which does not exist until T02's sender is registered. The profile checker
|
|
(`net-kingdom/tools/emission-cadence-profile`) is runnable locally but needs a
|
|
`--contract-schema` for the decision-record cadence contract that is not yet
|
|
published in this repo or referenced by any sibling's invocation found —
|
|
inventing one here would be exactly the kind of schema flex-auth should
|
|
publish deliberately, not improvise for a validation run. The PVC chart change
|
|
is explicitly a production change needing the founder's go-ahead and was left
|
|
undone. Stays `wait`.
|
|
|
|
- Compare committed counts per class and window with audit-core's
|
|
`GET /v1/reconciliation`. Divergence is a finding, and undrained events count
|
|
as lag, not divergence.
|
|
- Validate `cadence.yaml` with the net-kingdom emission-cadence profile checker,
|
|
supplying the inventory as `--rare-load-bearing`/`--load-bearing`.
|
|
- Add an optional PVC to the chart for the outbox, sized against the node disk
|
|
(84 % on 2026-09-23). Rolling it out to any pin is a production change and
|
|
needs the founder's go-ahead.
|
|
|
|
## 4. Close G2
|
|
|
|
```task
|
|
id: FLEX-WP-0031-T04
|
|
status: wait
|
|
priority: medium
|
|
state_hub_task_id: "423b3090-1b72-58fd-9353-5c907c7683bb"
|
|
```
|
|
|
|
2026-09-27: closing G2 requires the silence-finding gate, which requires T05's
|
|
sender and T06's reconciliation to actually exist. Both are blocked on T02
|
|
(external, `audit-core`). Stays `wait`.
|
|
|
|
Change `cadence.yaml` `state` to emitting, move G2 out of the gap table with the
|
|
evidence, and tell `gate-house`, `audit-core` and `kings-guard`. Gate: a silence
|
|
finding is observed on a deliberately withheld heartbeat in a non-production
|
|
run.
|