FLEX-WP-0031-T01: decide emission atomicity (FLEX-DEC-2026-018)
Commit before release for every class; on commit failure restrictive effects are released and counted released_uncommitted, allow/audit_only are withheld. Withholding a deny would be fail-open at open-stance consumers. Measured cost ~1.1 ms per durable append on railiance01. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 307130@bnt-lap001 Assistant-Session: 270c79f7-0823-4b0d-990d-aad5af9935ce
This commit is contained in:
parent
68b3d74df3
commit
da520615e5
2 changed files with 74 additions and 3 deletions
|
|
@ -2010,3 +2010,65 @@ the act scope. T03's own 57 checks pass.
|
||||||
**Rollout.** Deploying v3 changes the pin serving a live human-review surface,
|
**Rollout.** Deploying v3 changes the pin serving a live human-review surface,
|
||||||
and is confirmed with the operator before it runs. informed-decision updates its
|
and is confirmed with the operator before it runs. informed-decision updates its
|
||||||
admission input to the version and digest above once the pin serves v3.
|
admission input to the version and digest above once the pin serves v3.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FLEX-DEC-2026-018 — A decision is released after its record commits, except that a restriction is never withheld
|
||||||
|
|
||||||
|
**Date:** 2026-09-23
|
||||||
|
**Status:** accepted
|
||||||
|
**Workplan:** `FLEX-WP-0031-T01`
|
||||||
|
**Authority:** `GH-DEC-2026-018` (left atomicity open pending the class
|
||||||
|
inventory, §9.4); inventory: `cadence.yaml` `classes`
|
||||||
|
|
||||||
|
**Question.** May a decision, and in particular a rare load-bearing `deny`, be
|
||||||
|
returned to the caller before its record is committed to the emission outbox?
|
||||||
|
|
||||||
|
**Today.** `Engine.Check` already appends the record before it returns, and
|
||||||
|
fails the check if the append fails. But no production pin passes
|
||||||
|
`--decision-log`, so the record lands only in process memory: every class is
|
||||||
|
released today without a durable record. Nothing below is a regression on
|
||||||
|
anything live.
|
||||||
|
|
||||||
|
**Ruling.**
|
||||||
|
|
||||||
|
1. **Commit before release, for every class.** A decision envelope leaves
|
||||||
|
flex-auth only after its record is durably committed to the local outbox.
|
||||||
|
Draining to `audit-core` stays asynchronous. Atomicity is with the local
|
||||||
|
commit, not with delivery.
|
||||||
|
2. **On a failed commit the rule splits by direction:**
|
||||||
|
|
||||||
|
| Effect | On commit failure | Why |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `deny`, `redact`, `not_applicable` | Released anyway, and counted as `released_uncommitted` per class | Withholding turns the decision into an error, and a consumer whose stance is open for that scope treats an error as proceed. That is `ops-warden` for `z0`-`z2` and `unknown`. Withholding a restriction would therefore manufacture a permission. |
|
||||||
|
| `allow`, `audit_only` | Withheld. The check answers 503 and the consumer's declared stance applies | Authority must never be granted without its evidence. `audit_only` exists only for its record. |
|
||||||
|
|
||||||
|
The asymmetry is the finding of this ruling. Strict atomicity applied to a
|
||||||
|
`deny` would be a fail-open path at open-stance consumers. A missing record
|
||||||
|
is a missed detection, which fails closed. A withheld deny can become a
|
||||||
|
permission, which fails open. The estate's fail-closed direction wins.
|
||||||
|
3. **The failure is visible, not silent.** `released_uncommitted` is exposed
|
||||||
|
next to the committed counts that reconciliation compares. A released but
|
||||||
|
unrecorded restriction shows up as divergence rather than disappearing.
|
||||||
|
Every non-zero value is a finding.
|
||||||
|
|
||||||
|
**Latency cost.** One durable local append per decision. Measured on
|
||||||
|
railiance01 on 2026-09-23: about **1.1 ms** per synchronous 1 KB write (`dd
|
||||||
|
oflag=dsync`, 2,000 writes in 2.26 s). The current check path is in-memory, so
|
||||||
|
a single caller pays up to about +1.1 ms per check. Group commit amortises the
|
||||||
|
cost under concurrency. `BatchCheck` commits the whole batch in one sync,
|
||||||
|
not one per resource.
|
||||||
|
|
||||||
|
**Consequences for `FLEX-WP-0031-T03`.**
|
||||||
|
|
||||||
|
- The outbox needs storage that survives pod deletion (a PVC). An `emptyDir`
|
||||||
|
loses the records and their counts together on reschedule. Reconciliation
|
||||||
|
cannot see that loss; only the heartbeat gap can.
|
||||||
|
- The node's root filesystem is at 84 % (2026-09-23). Size the volume and the
|
||||||
|
retention after drain before requesting it.
|
||||||
|
- `released_uncommitted` counters are in memory until the outbox is healthy
|
||||||
|
again, so a restart during an outbox outage loses them. This is the same
|
||||||
|
residual as the stated bound, not a new one.
|
||||||
|
|
||||||
|
**Bound.** Unchanged from `cadence.yaml`: none of this detects a compromised
|
||||||
|
flex-auth suppressing a record together with its own count.
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ type: workplan
|
||||||
title: "The decision record has a declared emission guarantee and nothing that delivers it"
|
title: "The decision record has a declared emission guarantee and nothing that delivers it"
|
||||||
domain: infotech
|
domain: infotech
|
||||||
repo: flex-auth
|
repo: flex-auth
|
||||||
status: ready
|
status: active
|
||||||
flavor: implementation
|
flavor: implementation
|
||||||
owner: claude
|
owner: claude
|
||||||
topic_slug: netkingdom
|
topic_slug: netkingdom
|
||||||
|
|
@ -14,7 +14,7 @@ related_workplans:
|
||||||
- FLEX-WP-0030
|
- FLEX-WP-0030
|
||||||
- FLEX-WP-0019
|
- FLEX-WP-0019
|
||||||
created: "2026-09-21"
|
created: "2026-09-21"
|
||||||
updated: "2026-09-21"
|
updated: "2026-09-23"
|
||||||
state_hub_workstream_id: "84f5d9fe-b4c9-584a-b964-efe3e48af095"
|
state_hub_workstream_id: "84f5d9fe-b4c9-584a-b964-efe3e48af095"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ a compromised flex-auth suppressing a record and its own count together.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: FLEX-WP-0031-T01
|
id: FLEX-WP-0031-T01
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "2dbc225f-d762-537b-9a24-ab2b17fc2fa2"
|
state_hub_task_id: "2dbc225f-d762-537b-9a24-ab2b17fc2fa2"
|
||||||
```
|
```
|
||||||
|
|
@ -48,6 +48,15 @@ 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,
|
committed to the outbox, and record the answer as a `FLEX-DEC`. Gate: decided,
|
||||||
with the latency cost stated.
|
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
|
## 2. Register flex-auth as an audit-core sender
|
||||||
|
|
||||||
```task
|
```task
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue