docs: mark the unknown cell, measure the coverage we asked to publish
gate-house ruled the v0.8 assent round (GH-DEC-2026-011, net-kingdom@64394e9): ask 1 declined, ask 2 adopted. Ask 1's refusal is accepted without reservation and the reason is better than the ask -- a sanctioned transitional fail_open is indistinguishable at runtime from the stance the rule forbids, and would make the rule optional at the only moment it costs anything. Ask 2 gave §13.1 a Coverage column with this repo's figures as its first entries. Since we asked for the column, we owe it accuracy: scripts/report_coverage.py measures both populations from the artifacts the runtime uses (reusing the workload-join build rather than re-deriving it), and a test asserts pep-stance.yaml's published block equals what it measures. A hand-counted number in a register that explicitly does not recompute it decays silently, and a stale figure beside a marked cell is worse than the blank the other four rows carry. pep-stance.yaml marks the unknown cell inline as a declared gap -- assent, the measured reason for not flipping, the declined ask, WARDEN-WP-0040 as route -- and a second test keeps it marked while it is fail_open, failing when it is flipped. standard_version stays 0.7 because that is what binds; v0.8 is proposed, so it gains standard_version_reviewed rather than pre-adopting. Separately, gate-house corrected GH-DEC-2026-008: the claim/decision digest comparison it originally required is unimplementable and a fail-closed consumer obeying it would have denied permanently. We had never copied the wording, so nothing to unwind -- but everything they have sent about this lane was living in an inbox thread, a bad home for a correction that only matters when someone finally wires the consume. Now wiki/ApprovalConsumption.md, leading with "nothing is wired", carrying the corrected target and the attribution gap that digest matching does not discharge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013EPuTc18FjU5WFqoSEKH3C Assistant: claude-code Assistant-Model: opus Assistant-Process: 1276224@bnt-lap001 Assistant-Session: 426ec497-e1c4-4dd3-b417-dfce1ca1dbc3
This commit is contained in:
parent
a942ce805d
commit
5b1a508610
8 changed files with 388 additions and 2 deletions
|
|
@ -35,7 +35,7 @@
|
|||
| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| workplan | WARDEN-WP-0037 | active | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| workplan | WARDEN-WP-0038 | proposed | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md |
|
||||
| workplan | WARDEN-WP-0038 | finished | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md |
|
||||
| workplan | WARDEN-WP-0039 | blocked | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| workplan | WARDEN-WP-0040 | proposed | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
|
||||
|
|
|
|||
|
|
@ -117,3 +117,59 @@ catalog stage is an accurate statement about their control, and making them
|
|||
assert a zone they cannot know would trade a real fact for a conformant fiction.
|
||||
The unavailability of cross-axis aggregation is better recorded than papered
|
||||
over, and §13.1 now says so.
|
||||
|
||||
---
|
||||
|
||||
## Ruling — GH-DEC-2026-011, 2026-09-09
|
||||
|
||||
gate-house closed the assent round the same day: **ask 1 declined, ask 2
|
||||
adopted**, standard amended at `net-kingdom@64394e9`, dispositioned in
|
||||
`gate-house/docs/conformance/2026-09-06-v08-assent-round.md`.
|
||||
|
||||
**Ask 1 (a dated transitional `unknown: fail_open`) — declined**, and the reason
|
||||
is better than the ask. A sanctioned transitional `fail_open` is
|
||||
*indistinguishable at runtime* from the stance the rule forbids, and it would make
|
||||
the rule optional at the moment of adoption — the only moment it costs anything.
|
||||
Dating an intention to stop being permissive does not make `unknown` any more
|
||||
expensive for an attacker to induce while the transition runs. Accepted without
|
||||
reservation; the argument defeats the ask on its own terms.
|
||||
|
||||
**Ask 2 (coverage published beside stance) — adopted.** §13.1 now carries a
|
||||
Coverage column and this repo's figures are its first entries: *signing targets
|
||||
0/3 resolved; routing lanes 3/21 resolved (2026-09-09, self-measured)*. Three
|
||||
guards came with it, all of which we would have wanted: coverage does not soften
|
||||
the stance, does not gate it, and never makes a non-conformant cell conformant; a
|
||||
blank means "not reported" and never "complete"; and the decision carries an
|
||||
explicit reversal condition — if a row is ever argued to be conformant *because*
|
||||
its coverage is low, the column is doing harm and comes out.
|
||||
|
||||
That reversal condition is the right shape and it binds us first, since the column
|
||||
exists because we asked. Our row reads non-conformant **and** low-coverage; those
|
||||
are two facts, and the second is not a defence of the first.
|
||||
|
||||
**The deadlock was recorded rather than routed around.** §6.4 obligation 3 now
|
||||
states that a stricter stance is not a licence to manufacture the membership that
|
||||
makes it survivable — where a scope is unknown because another repository has
|
||||
published no workload-identity declaration, the consumer MUST NOT infer one. That
|
||||
is `ADR-0009` rule 3 promoted into the standard at exactly the point where the
|
||||
pressure lands, which is more than we asked for.
|
||||
|
||||
### What we did in response
|
||||
|
||||
- `pep-stance.yaml` marks the `unknown` cell as a **declared gap** inline, with
|
||||
the assent, the measured reason for not flipping, the declined ask, and
|
||||
`WARDEN-WP-0040` as its route. The stance value is unchanged — v0.8 is still
|
||||
`proposed` and v0.7 remains in force, so `standard_version` stays `0.7` with a
|
||||
new `standard_version_reviewed: 0.8`.
|
||||
- The coverage figures are published in `pep-stance.yaml` and, because we asked
|
||||
for the column, **measured rather than hand-counted**:
|
||||
`scripts/report_coverage.py` derives both populations from the artifacts the
|
||||
runtime uses, reusing `report_workload_join.build` rather than re-deriving the
|
||||
join. `tests/test_layer_conformance.py` asserts the published block equals the
|
||||
measured one, and asserts the cell stays marked while it is `fail_open`.
|
||||
|
||||
A hand-counted figure in a register that explicitly does not recompute it would
|
||||
decay silently, and a stale number beside a marked cell is worse than the blank
|
||||
the other four rows carry — a blank at least reads as "not reported".
|
||||
- `WARDEN-WP-0040` T04 is closed; T01–T03 stand unchanged. gate-house confirmed
|
||||
they are not asking for the cell to be flipped before coverage exists.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,13 @@
|
|||
|
||||
schema_version: "0.1"
|
||||
framework: netkingdom-security-layer-model
|
||||
# v0.7 is the accepted standard and the one in force. v0.8 is `proposed`: its
|
||||
# assent round closed 2026-09-09 (GH-DEC-2026-011) with nine corrections applied,
|
||||
# but the version is not yet accepted, so this declaration stays pinned to what
|
||||
# binds. The one cell v0.8 would change is marked inline below rather than
|
||||
# silently pre-adopted.
|
||||
standard_version: "0.7"
|
||||
standard_version_reviewed: "0.8" # reviewed and assented; see history/2026-09-09-layer-model-v08-review.md
|
||||
repository: ops-warden
|
||||
pep_shape: true
|
||||
declared_by: docs/adr/ADR-0009
|
||||
|
|
@ -36,7 +42,26 @@ stance:
|
|||
z2-protected: fail_open
|
||||
z2-continuity: fail_open
|
||||
z3-critical: fail_closed
|
||||
unknown: fail_open # versioned build profile (ADR-0009); explicit, never inferred
|
||||
# DECLARED GAP under security-layer-model v0.8 §6.4 obligation 3 (GH-DEC-2026-011,
|
||||
# net-kingdom@64394e9): unknown is not a zone and MUST resolve to fail_closed.
|
||||
# ops-warden ASSENTED to that rule — we went looking for the §5.1 read-only
|
||||
# diagnostic its reversal clause predicts and do not have one, because this map
|
||||
# governs `warden sign`, a credential-issuing side effect.
|
||||
#
|
||||
# The cell has not been flipped, and the reason is measured rather than argued:
|
||||
# 0 of 3 signing targets resolve to a zone, so converting today would fail closed
|
||||
# on essentially every certificate whenever the engine is unreachable — including
|
||||
# the certificate an operator needs to reach the host and repair it. That is
|
||||
# ADR-0006's rejected configuration reached from another direction.
|
||||
#
|
||||
# We asked for a coverage-gated transitional fail_open and were DECLINED: a
|
||||
# sanctioned transitional fail_open is indistinguishable at runtime from the
|
||||
# stance the rule forbids. Our second preference was adopted instead — §13.1 now
|
||||
# carries a Coverage column, and this repo's figures are its first entries.
|
||||
#
|
||||
# So this is tracked non-conformance with a route, not an exemption.
|
||||
# Route: WARDEN-WP-0040. Register row: §13.1, marked.
|
||||
unknown: fail_open # non-conformant at v0.8; see above
|
||||
not-applicable: fail_closed
|
||||
|
||||
# What happens when the stance is applied. §6.4 obligation 1 requires a decision
|
||||
|
|
@ -57,6 +82,23 @@ on_apply:
|
|||
# §6.4 obligation 2 — the verdict is never cached. Input claims (zone membership,
|
||||
# compiled from the flex-auth registry snapshot) are cached under their own
|
||||
# freshness rules; the answer is not.
|
||||
# Classification coverage, published beside the stance because v0.8 §6.4
|
||||
# obligation 3 now requires it and because ops-warden asked for the column.
|
||||
# Coverage is DISCLOSURE, never a transitional licence: it does not soften this
|
||||
# map's stance, does not gate it, and never makes the marked cell conformant.
|
||||
# Self-measured; regenerate with `python scripts/report_coverage.py`.
|
||||
classification_coverage:
|
||||
measured: "2026-09-09"
|
||||
attribution: self-measured
|
||||
signing_targets:
|
||||
resolved: 0
|
||||
unknown: 3
|
||||
not_applicable: 1
|
||||
routing_lanes:
|
||||
resolved: 3
|
||||
unknown: 18
|
||||
not_applicable: 12
|
||||
|
||||
verdict_caching: none
|
||||
input_claim_caching: "registry/flex-auth/production_registry_snapshot.json, rebuilt by scripts/build_flex_auth_registry.py"
|
||||
|
||||
|
|
|
|||
129
scripts/report_coverage.py
Normal file
129
scripts/report_coverage.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Measure the classification coverage published in `pep-stance.yaml`.
|
||||
|
||||
Read-only. No network, no OpenBao, no secret material.
|
||||
|
||||
Why this exists. security-layer-model v0.8 §6.4 obligation 3 requires a dated
|
||||
classification-coverage figure beside each stance, and §13.1 carries a Coverage
|
||||
column whose first entries are ops-warden's — because ops-warden asked for the
|
||||
column after measuring that 0 of 3 signing targets resolve to a zone.
|
||||
|
||||
Having asked for it, we own the figure's accuracy. A hand-counted number in a
|
||||
published register decays silently: the register explicitly does not compute
|
||||
anyone's coverage, and a stale figure beside a marked cell is worse than a blank,
|
||||
which at least reads as "not reported". So the figure is measured from the same
|
||||
two artifacts the runtime uses, and `tests/test_layer_conformance.py` asserts the
|
||||
published block equals what this reports — the same property that makes the stance
|
||||
map worth publishing (`pep-stance.yaml` equals `PolicyConfig.failure_modes` by
|
||||
test), applied one level up.
|
||||
|
||||
Two populations, deliberately not summed. They answer different questions and
|
||||
share no denominator:
|
||||
|
||||
signing targets — actor resources in the flex-auth registry snapshot. This is
|
||||
the population the stance map actually governs: `warden sign` resolves a zone
|
||||
per actor resource, and an unresolved one takes the `unknown` cell.
|
||||
routing lanes — catalog entries with an explicit workload reference. Wider than
|
||||
the stance map's reach, and the figure that shows *why* coverage is low: an
|
||||
unknown lane is almost always another repository's undeclared workload
|
||||
identity, which `ADR-0009` rule 3 forbids closing by inference here.
|
||||
|
||||
Usage:
|
||||
python scripts/report_coverage.py [--json]
|
||||
|
||||
Exit: 0 always. This reports; it does not gate. Coverage is disclosure, never a
|
||||
transitional licence, and a script that failed on low coverage would be arguing
|
||||
the case v0.8 declined.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
SNAPSHOT = REPO / "registry" / "flex-auth" / "production_registry_snapshot.json"
|
||||
NOT_APPLICABLE = "not-applicable"
|
||||
|
||||
|
||||
def signing_target_coverage(snapshot_path: Path = SNAPSHOT) -> dict[str, int]:
|
||||
"""Zone resolution across the actor resources `warden sign` can name."""
|
||||
registry = json.loads(snapshot_path.read_text())
|
||||
resolved = unknown = not_applicable = 0
|
||||
for manifest in registry.get("resource_manifests") or []:
|
||||
for resource in manifest.get("resources") or []:
|
||||
if str(resource.get("type")) != "ssh-certificate":
|
||||
continue
|
||||
attributes = resource.get("attributes") or {}
|
||||
admission = str(attributes.get("security_zone_admission") or "unknown")
|
||||
zone = str(attributes.get("security_zone") or "unknown")
|
||||
if admission == NOT_APPLICABLE:
|
||||
not_applicable += 1
|
||||
elif zone == "unknown":
|
||||
unknown += 1
|
||||
else:
|
||||
resolved += 1
|
||||
return {"resolved": resolved, "unknown": unknown, "not_applicable": not_applicable}
|
||||
|
||||
|
||||
def routing_lane_coverage(estate_root: Path | None = None) -> dict[str, int]:
|
||||
"""Workload resolution across catalog lanes.
|
||||
|
||||
Delegates to `report_workload_join.build` rather than re-deriving the join: two
|
||||
implementations of "is this lane resolved" would drift, and the published figure
|
||||
should be the one the join report shows.
|
||||
"""
|
||||
import importlib.util
|
||||
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"report_workload_join", Path(__file__).resolve().parent / "report_workload_join.py"
|
||||
)
|
||||
join = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(join)
|
||||
|
||||
report = join.build(
|
||||
REPO / "registry" / "routing" / "catalog.yaml",
|
||||
estate_root if estate_root is not None else Path.home(),
|
||||
)
|
||||
return {
|
||||
"resolved": len(report["resolved"]),
|
||||
"unknown": len(report["unknown"]),
|
||||
"not_applicable": len(report["not_applicable"]),
|
||||
}
|
||||
|
||||
|
||||
def measure(estate_root: Path | None = None) -> dict[str, Any]:
|
||||
return {
|
||||
"signing_targets": signing_target_coverage(),
|
||||
"routing_lanes": routing_lane_coverage(estate_root),
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--json", action="store_true", dest="as_json")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
report = measure()
|
||||
if args.as_json:
|
||||
print(json.dumps(report, indent=2))
|
||||
return 0
|
||||
|
||||
for name, counts in report.items():
|
||||
total = sum(counts.values())
|
||||
scoped = counts["resolved"] + counts["unknown"]
|
||||
print(f"{name.replace('_', ' ')}: {counts['resolved']}/{scoped} resolved "
|
||||
f"({counts['unknown']} unknown, {counts['not_applicable']} not-applicable, "
|
||||
f"{total} total)")
|
||||
print()
|
||||
print("Coverage is disclosure, not a transitional licence (v0.8 §6.4 obligation 3).")
|
||||
print("Publish in pep-stance.yaml; §13.1 does not compute it for you.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
|
@ -150,3 +150,52 @@ class TestPepStanceMap:
|
|||
assert cadence["observed_window"]["signature_records"] == 3
|
||||
assert cadence["observed_window"]["active_signature_days"] == 2
|
||||
assert cadence["reason"]
|
||||
|
||||
|
||||
# --- classification coverage (v0.8 §6.4 obligation 3) -------------------------
|
||||
|
||||
def test_published_coverage_equals_measured_coverage():
|
||||
"""The published figure must equal what the repo actually measures.
|
||||
|
||||
ops-warden asked gate-house for §13.1's Coverage column and its figures are
|
||||
that column's first entries, so their accuracy is ours to hold. The register
|
||||
explicitly does not compute anyone's coverage, and a stale number beside a
|
||||
marked cell is worse than a blank -- a blank at least reads as "not reported".
|
||||
|
||||
This is the same property that makes the stance map worth publishing (the map
|
||||
equals PolicyConfig.failure_modes by test), applied one level up.
|
||||
"""
|
||||
import importlib.util
|
||||
|
||||
repo = Path(__file__).resolve().parents[1]
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"report_coverage", repo / "scripts" / "report_coverage.py"
|
||||
)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
published = yaml.safe_load((repo / "pep-stance.yaml").read_text())[
|
||||
"classification_coverage"
|
||||
]
|
||||
measured = module.measure()
|
||||
|
||||
for population in ("signing_targets", "routing_lanes"):
|
||||
assert published[population] == measured[population], population
|
||||
|
||||
|
||||
def test_the_unknown_cell_is_marked_as_a_declared_gap():
|
||||
"""A non-conformant cell must say so where it is declared, not only in a review.
|
||||
|
||||
§11's marking obligation, which ops-warden argued for in the v0.6 round and
|
||||
then acquired a marked cell under. If the cell is ever flipped to fail_closed
|
||||
this test fails, which is the correct time to remove the marking.
|
||||
"""
|
||||
repo = Path(__file__).resolve().parents[1]
|
||||
text = (repo / "pep-stance.yaml").read_text()
|
||||
stance = yaml.safe_load(text)["stance"]
|
||||
|
||||
if stance["unknown"] == "fail_open":
|
||||
assert "DECLARED GAP" in text
|
||||
assert "WARDEN-WP-0040" in text
|
||||
else:
|
||||
assert stance["unknown"] == "fail_closed"
|
||||
|
|
|
|||
77
wiki/ApprovalConsumption.md
Normal file
77
wiki/ApprovalConsumption.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Approval consumption — notes for the signing lane's future consume
|
||||
|
||||
**Status:** notes only. **Nothing is wired.** ops-warden's pre-sign gate consults
|
||||
flex-auth (`wiki/PolicyGatedSigning.md`); it does not yet consume an approval
|
||||
artifact. This page exists so the corrections we have already been given survive
|
||||
until it does, rather than sitting in an inbox thread.
|
||||
|
||||
Owner of the contract: `gate-house`, `docs/contracts/approval-consumption.md`.
|
||||
ops-warden is one of two PEP-shaped consumers named there (the SSH signing lane).
|
||||
|
||||
## Validate across two artifacts, never one
|
||||
|
||||
`GH-DEC-2026-005` settles the step-1 artifact: `GET /v1/approvals/{id}/claim`
|
||||
serves the **approval-claim**. flex-auth's proposed `ActionAuthorization` is not
|
||||
required there and will not be served from that endpoint.
|
||||
|
||||
| Artifact | Carries |
|
||||
| --- | --- |
|
||||
| approval-claim (step 1) | the approval fact — binding digest, validity window, consumption state, freshness, issuer |
|
||||
| `DecisionEnvelope` (step 2) | exact `CheckRequest` match, policy pin |
|
||||
|
||||
v0.8 §6.4 obligation 5 hardened this: each artifact **must** be validated against
|
||||
the layer that owns its data, and a PIP **must not** republish the PDP's decision.
|
||||
Neither artifact may be taken from the other.
|
||||
|
||||
## Three things that are easy to get wrong
|
||||
|
||||
**1. Do not require `provenance.authority == 'state-hub'`.**
|
||||
|
||||
State Hub is a read model with no runtime approval authority. This is easy to get
|
||||
wrong precisely *because* the hub is where everything else about a workplan lives,
|
||||
so a consumer reaches for it as the authority on approval too.
|
||||
|
||||
Worth holding as a shape rather than an instance: a PEP requiring the hub to have
|
||||
asserted an approval is the same boundary violated from the **consuming** side
|
||||
that "never register workplans or tasks by hand" forbids from the **writing**
|
||||
side. Same rule, two directions.
|
||||
|
||||
**2. The digest comparison target was corrected. Use `binding.approval_binding_digest`.**
|
||||
|
||||
`GH-DEC-2026-008` as originally issued required the claim's `pdp_digest` to equal
|
||||
the decision's `request_digest`. That is unimplementable — a claim travelling
|
||||
inside a hashed request cannot name the digest of the request containing it — and
|
||||
a fail-closed consumer obeying it would have denied permanently. Corrected by
|
||||
`FLEX-DEC-2026-007` to the PDP's published **exclusion-scoped** digest,
|
||||
`binding.approval_binding_digest`.
|
||||
|
||||
ops-warden never copied the superseded wording anywhere (checked 2026-09-09), so
|
||||
there was nothing to unwind. Recorded here so it cannot be reintroduced from an
|
||||
older reading of the contract.
|
||||
|
||||
**3. Digest comparison does not discharge attribution, and attribution is not
|
||||
available today.**
|
||||
|
||||
`GH-DEC-2026-010` rules that a PEP must be able to **attribute** a decision to
|
||||
access-engine, and that matching digests does not achieve that. flex-auth's
|
||||
envelope is unsigned and its pins serve plain HTTP, so that half is a declared
|
||||
§13 gap owned by access-engine until `FLEX-WP-0024` lands.
|
||||
|
||||
Nothing for ops-warden to build. But when this lane is wired, its validation is
|
||||
**complete-minus-attribution** and must be described that way: fail-closed
|
||||
protects against a decision point that is absent, not against one that lies.
|
||||
|
||||
## Open dependency
|
||||
|
||||
`WARDEN-WP-0039-T03` — whether an admitted flex-auth contract exists for a
|
||||
delegated credential read where caller and resource owner differ. If the answer
|
||||
changes the caller shape it may reach how this lane's consume is built, and
|
||||
`gate-house` has asked to hear that before rather than after: a contract admitted
|
||||
for that shape would reach §6.4 obligation 5, and whether such a delegation
|
||||
attenuates or widens is doctrine they own.
|
||||
|
||||
## See also
|
||||
|
||||
- `wiki/PolicyGatedSigning.md` — the pre-sign gate as it actually is today
|
||||
- `pep-stance.yaml` — unreachable-engine stance, and the marked `unknown` cell
|
||||
- `history/2026-09-09-layer-model-v08-review.md` — the v0.8 assent round
|
||||
|
|
@ -192,6 +192,14 @@ Rollback is a versioned profile or registry rollback. Do not reintroduce
|
|||
`policy.enabled: false`: that would erase per-zone evidence and recreate the
|
||||
global control ADR-0009 supersedes.
|
||||
|
||||
## Approval consumption (not wired)
|
||||
|
||||
This lane does not yet consume an approval artifact. The corrections already
|
||||
received about how it must validate when it does — two artifacts never taken from
|
||||
each other, the corrected `binding.approval_binding_digest` comparison target, and
|
||||
the attribution gap that digest matching does not discharge — are held in
|
||||
`wiki/ApprovalConsumption.md` so they are not lost between now and then.
|
||||
|
||||
## See also
|
||||
|
||||
- `tenancy.yaml`
|
||||
|
|
|
|||
|
|
@ -125,3 +125,28 @@ records classification coverage alongside stance, so a register row cannot read
|
|||
If both are declined, that is an answer and this workplan proceeds unchanged —
|
||||
the cell stays a **declared gap** under §11 with this workplan as its route,
|
||||
which is what the `declared-gap` mark (our own v0.6 finding) exists to express.
|
||||
|
||||
**Answered 2026-09-09 — GH-DEC-2026-011.** Ask 1 declined, ask 2 adopted;
|
||||
standard amended at `net-kingdom@64394e9`.
|
||||
|
||||
Ask 1's refusal is correct and we are not appealing it: a sanctioned transitional
|
||||
`fail_open` is indistinguishable at runtime from the stance the rule forbids, and
|
||||
would make the rule optional at the only moment it costs anything. Ask 2 gave us
|
||||
what we actually needed — §13.1 carries a Coverage column with this repo's
|
||||
figures as its first entries, guarded so that coverage never softens a stance,
|
||||
never gates one, and never makes a non-conformant cell conformant.
|
||||
|
||||
The reversal condition on that column binds ops-warden first, since the column
|
||||
exists because we asked: if a row is ever argued conformant *because* its coverage
|
||||
is low, the column comes out. Our row reads non-conformant and low-coverage, and
|
||||
the second is not a defence of the first.
|
||||
|
||||
gate-house confirmed explicitly that they are **not** asking for the cell to be
|
||||
flipped before coverage exists, and that this workplan's order is right. The cell
|
||||
stays a declared gap under §11 with WP-0040 recorded as its route — the outcome
|
||||
this task named as acceptable if both asks were declined, reached with one of them
|
||||
adopted.
|
||||
|
||||
T01–T03 are unchanged and still gate the conversion. Coverage is now measured
|
||||
rather than asserted (`scripts/report_coverage.py`), so T02's reporting obligation
|
||||
has a tool behind it and the published figure cannot drift from the register's.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue