Updated by fix-consistency on 2026-10-11: - workplan status: backlog → active Assistant: claude-code Assistant-Model: opus Assistant-Process: 1370019@bnt-lap001 Assistant-Session: d462dd63-16de-4189-ae70-b9cd6566bf87
17 KiB
| id | type | title | domain | repo | status | flavor | owner | topic_slug | planning_priority | planning_order | related_workplans | created | updated | state_hub_workstream_id | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FLEX-WP-0031 | workplan | The decision record has a declared emission guarantee and nothing that delivers it | infotech | flex-auth | active | residual | claude | netkingdom | P1 | 310 |
|
2026-09-21 | 2026-10-10 | 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
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
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."
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
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'snormalize()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-018inCheck,BatchCheckandListAllowed. A withheld decision answers 503. serve --outbox-dir --emission-sourceenables it, andGET /v1/emissionreports committed andreleased_uncommittedcounts 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 incadence.yamlequal 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. Implement heartbeat and drain to audit-core
id: FLEX-WP-0031-T05
status: done
priority: high
state_hub_task_id: "14bd6648-11da-53d7-a512-027005bd4772"
2026-10-04: split implementation from native delivery acceptance (new T08).
internal/emission/delivery.go implements daily per-class audit-core.heartbeat
events with independent correlation IDs and offset timestamps, persisted in
our durable outbox. Restart rebuilds each class's last heartbeat from the log.
Heartbeats expose committed and released-uncommitted counts; a known failure
changes the assertion to released-uncommitted-finding.
The asynchronous drain sends the eight-field envelope with event-ID
idempotency, reads a mounted token file per event for rotation, refuses
redirects, and advances a fsynced/renamed cursor only on 200 or 202. Every other
response, transport failure or cursor-write failure retains the event. A
bounded drain runs each minute, without holding the decision lock during HTTP.
GET /v1/emission exposes pending depth, oldest pending timestamp and lag-bound
exceedance (100 events / 1h). No response body or token is logged.
serve --audit-url <explicit /v1/events endpoint> --audit-token-file <mount>
enables the worker only with an outbox. Both default empty, and no pin enables
it. Local tests cover per-class cadence, restart, rejection, stable replay,
ambiguous acceptance, token rotation and cursor durability. The current outbox
retains acknowledged log entries; retention/compaction is not implemented, so
capacity planning must include cumulative log growth.
6. Reconciliation, profile check, and storage
id: FLEX-WP-0031-T06
status: wait
depends_on: [FLEX-WP-0031-T02]
blocked_on: message-from:audit-core
blocking_reason: "Receiver counts use accepted_at, while local counts use commit time; audit-core must supply compatible window semantics or durable acceptance timestamps before a valid comparator can be implemented."
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.yamlwith 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.
2026-10-04: storage/profile preparation is now complete as T07. The remaining comparator is independently blocked by receiver time semantics, not just a missing registration: audit-core counts accepted_at in half-open windows, while our log timestamps local commits. Ingest returns status/reference only. A receiver-approved matching basis or stable acceptance-time receipts (also on duplicates) is required before implementing a comparison. Do not widen may_read to fetch archive payloads as a workaround. T02 and T08 still gate native custody/rollout evidence; see the dependency record for exact returns.
4. Close G2
id: FLEX-WP-0031-T04
status: wait
depends_on: [FLEX-WP-0031-T08, FLEX-WP-0031-T06]
blocking_reason: "G2 needs T08 native heartbeat/drain and silence-finding evidence plus T06 reconciliation; local tests cannot close the delivery gap."
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.
7. Prepare persistent storage and validate the cadence contract
id: FLEX-WP-0031-T07
status: done
priority: high
state_hub_task_id: "151fe609-ba68-506b-9c2c-9fdb0b149eef"
Split from T06 on 2026-10-04; its historical schema/storage blockers above are
superseded by this implementation. charts/flex-auth has optional outbox PVC,
mount, source and flags, defaults disabled, a one-replica constraint and
Recreate strategy to avoid two writers during rollout. It supports an existing
claim. Rendering is tested with caller auth enabled and disabled. No values pin
or live deployment is changed; 1Gi is a configurable preparation value, not an
assertion of available node space.
Published docs/contracts/decision-emission-cadence.json against the actual
InfoTechCanon wire schema and NetKingdom profile. All five decision classes
are explicitly supplied; contract/profile assessment passes. The generic
expected-rate schema forbids reconciliation on that entry and the profile
forbids duplicate classes, so allow's additional reconciliation guarantee is
in the extensions.flex-auth namespace. Receiver acceptance of that mapping
remains part of T02; a profile pass does not establish observer delivery.
8. Admit and exercise native heartbeat/drain delivery
id: FLEX-WP-0031-T08
status: wait
priority: high
depends_on: [FLEX-WP-0031-T02]
needs_human: true
blocking_reason: "Needs admitted sender/token mounts, founder approval of exact image/PVC/network rollout, and audit-core observer evidence; no production delivery is enabled."
state_hub_task_id: "b3b52b30-c73d-5a90-9935-d98afe5a9eaf"
Remaining acceptance split from T05: audit-core's owner must return admitted
exact per-pin sources, scope, heartbeat classes and cadence mapping under
AUDIT-IN-0006. Platform must provide governed attended token custody and
mount references, never values. The founder must approve exact immutable image,
PVC capacity and rollout; network owners must admit the decision pins to the
receiver. Record native 202 and idempotent 200 delivery, restart cursor/lag
behaviour, and an audit-core silence finding from a separately authorized
non-production withheld-heartbeat exercise. No test engagement/window is
created by this workplan. T06 still owns the compatible-time reconciliation
implementation and its native acceptance. See
docs/blocked-task-dependencies-2026-10-04.md for the concrete dependency gates.
2026-10-04 review: workplan stays blocked. Local heartbeat/drain and storage
preparation no longer wait on another repository, but admission, statutory
ruling, valid reconciliation time basis and approved native acceptance do.
cadence.yaml remains declared-not-yet-emitting and G2 remains open.
9. Enforce the accepted mandatory-emission ruling in source
id: FLEX-WP-0031-T09
status: done
priority: high
state_hub_task_id: "02a8d006-cc70-5a0e-b773-6924f05540ed"
2026-10-10: implemented GH-DEC-2026-024 §3, the accepted refusal of
load-bearing failure-path release. This corrects the source release behavior
described under T01/T03; those dated entries remain historical evidence of
FLEX-DEC-2026-018, not the current implementation. No new human decision is
needed to implement the accepted doctrine in source.
With a required recorder attached, a failed durable append now withholds every
effect, including deny/redact/not_applicable. Single checks, restriction-only
batches, list-allowed and application readback retain the existing
ErrRecordNotCommitted / HTTP 503 availability representation. No replacement
allow or deny is manufactured. Uncommitted results are not inserted into
Explain's history, and no released-uncommitted counter is incremented. Existing
historical outbox counters and their reporting remain readable. Standalone
operation without an attached recorder remains unchanged; no source change
enables production emission or claims that an unconfigured pin is conformant.
Tests inject commit failure across the complete five-effect vocabulary, check
that Explain cannot expose uncommitted results and can expose committed ones,
exercise actual restrictive single/batch/list policy paths, and verify
restrictive enforcement and readback HTTP 503. Affected package suites pass:
go test ./internal/decision ./internal/emission ./internal/readback ./cmd/access-engine ./pkg/api.
This source fix is not deployed. Consumer outage behavior remains governed by
each declared PEP stance: a consumer with an open-for-scope stance can treat
unavailable evaluation as proceed, so the exact rollout must review those
stances rather than claim that a 503 enforces denial. T02 native sender/custody,
T06 compatible reconciliation windows, T08 exact approved rollout and silence
proof, and T04 G2 closure remain unfinished. cadence.yaml remains declared,
and the emission completeness gap remains open until native acceptance.
T08 independent chart delivery preparation — 2026-10-11
Prepared inert chart auditDelivery configuration for existing admitted per-pin
Secret/key directory mount, explicit /v1/events endpoint and narrow receiver/DNS
egress. Supports existing serve pins only; unsupported readback flags refuse.
No pin defaults, native rollout, credential or sender registration changes.
Renderer tests pass for auth on/off, safe mounts/scoped peers, disabled defaults
and invalid/partial configurations. Mandatory-commit/emission/readback/HTTP/API
Go suites pass. Exact remaining image/PVC/custody/network/receiver and same-trial
native receipts are in docs/audit-delivery-rollout-preparation.md.
T08 remains wait; T06 receiver time basis and T04 native G2 acceptance remain open.
T08 preparation revision 2: independent Platform review found fractional YAML/ JSON receiver ports could survive integer truncation and render invalid Kubernetes NetworkPolicy. Corrected integer-shape guard plus 22 YAML/JSON rejection cases and integer boundary rendering passed. Original stage retained; no native change.
2026-10-11: demoted to
flavor: residual/backlogby founder-authorized triage — off the critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged; promote back when demand or risk appears. See the-custodianhistory/20261011-netkingdom-security-progress-assessment.md.