Skip to content

📝 docs(openspec): close 5 P2/P3 findings from the PR #45 re-review - #46

Merged
konih merged 6 commits into
mainfrom
spec-e10-e11-p2-fixes
Aug 10, 2026
Merged

📝 docs(openspec): close 5 P2/P3 findings from the PR #45 re-review#46
konih merged 6 commits into
mainfrom
spec-e10-e11-p2-fixes

Conversation

@konih

@konih konih commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #45, which merged with an independent APPROVE (zero P0, zero P1). The re-review also raised five P2/P3 findings that landed after the merge. Three of them sit on the exact guards that close #45's P1s, so they are worth fixing before an implementer picks up E10-S02 or E11-S00/S03.

The two that mattered

G2 — a verification that could not fail. REQ-E11-S03-04's Verify was go test ./internal/core/... -run TestPurity. TestPurity matches no test in the tree (the real names are TestCorePurity, TestCorePurityWalkReachesEveryGuardedDir, …), so it printed no tests to run and exited 0. That was the verification for the single requirement enforcing the (d1) rule-7 narrowing — it would have read as governed while checking nothing, which is the failure mode that requirement's own text warns about. Now -run TestCorePurity, confirmed to execute.

G3 — an incomplete FileAtRef enumeration. ADR-0021 and the E10 spec listed the retained ref-addressed policy loads as run.go:203, :211, :253. Verified against the tree, the actual call sites are :203 (MergePolicy), :211 (RulesetBinding), :230 (Config) and :249 (pack) — :253 is policy.LoadPack(packBytes), not a FileAtRef call. The omitted :230 is the most damaging one to get wrong: .assent/config.yaml declares the provider hosts, so migrating it to an MR-relative accessor would let a fork's head redefine its own fact semantics — precisely the trust-boundary regression #45's F1 fix exists to prevent. The enumeration read as exhaustive, so an implementer writing the "policy still ref-addressed" test over three call sites would have left that one unguarded.

One correction to the review

G1 was reported as "the Verify chain aborts, so task check never runs". That mechanism did not reproduce. In a default shell a pipeline's exit status is the last command's, so … | grep -c 'spikes/rego' | grep -qx 0 exited 0 when the spike was correctly isolated and 1 when it leaked — the correct polarity. It inverts to a false red only under set -o pipefail. Fixed anyway, to ! go list ./... | grep -q 'spikes/rego': a guard that flips meaning with a shell option is not a guard, and this one protects the "no OPA in go.mod while judgment call (d) is open" invariant. Both polarities verified under bash -o pipefail before and after.

Also

  • G4 — renamed the spike doc to spike-e-rego-budget.md; Spike D is already the Kubernetes CRD feasibility spike that E14 is gated on.
  • G5E11-S13's story dependencies corrected to S00–S12, matching the backlog row.

Gates

task check green locally at the branch tip (exit 0) — noted explicitly because release-exitgate skips on PRs in this repo, so CI never runs it.

Docs/spec only: no Go, no schemas/, no workflows.

Still open, unchanged by this PR

The (d1) vs (d2) mechanism half of E11's rule-7 judgment call still blocks E11-S03 and E11-S04. The operator's "accept and pin OPA" answer settled the supply-chain half only — (d2) also accepts and pins OPA; the two differ on where the evaluator lives and which gate enforces rule 7. Recorded in D-141 and in the INBOX.

konih added 6 commits August 10, 2026 16:40
G1 -- REQ-E11-S00-01's isolation guard rewritten to
'! go list ./... | grep -q spikes/rego'. NOTE the review's stated
mechanism did not reproduce: in a default shell a pipeline's exit status
is the LAST command's, so 'grep -c ... | grep -qx 0' actually exited 0
when isolated and 1 when leaked -- the correct polarity. It inverts to a
false red only under 'set -o pipefail'. Verified both polarities under
bash -o pipefail before and after. Conclusion right, reasoning wrong;
fixed because a guard that flips meaning with a shell option is not a
guard, and this one protects the 'no OPA in go.mod while (d) is open'
invariant.

G2 -- REQ-E11-S03-04's Verify used '-run TestPurity', which matches NO
test (the real names are TestCorePurity*). Confirmed vacuous: it printed
'no tests to run' and exited 0. That was the verification for the single
REQ enforcing the (d1) hard-rule narrowing -- exactly the
tests-that-cannot-fail class this repo keeps re-finding, and it would
have read as governed while checking nothing. Now -run TestCorePurity,
confirmed to execute.

G3 -- the retained-FileAtRef enumeration was incomplete and one line
number was wrong: actual ref-addressed policy loads are run.go:203
(MergePolicy), :211 (RulesetBinding), :230 (Config) and :249 (pack);
:253 is LoadPack, not a FileAtRef call. The omitted :230 is the most
damaging to get wrong -- .assent/config.yaml declares the provider
hosts, so migrating it to an MR-relative accessor would let a fork's
head redefine its own fact semantics, the precise trust-boundary
regression the F1 fix exists to prevent.

G4 -- renamed the spike doc to spike-e-rego-budget.md; 'Spike D' is
already the Kubernetes CRD feasibility spike that E14 is gated on.

G5 -- E11-S13's story dependencies corrected to S00-S12 to match the
backlog row.
…austive

H1 -- the enumeration added in the previous commit covered run.go only,
while newly asserting it was exhaustive. Two further ref-addressed
decision-input reads live in cmd/assent/provider_host.go: the provider
host declaration (:82) and the resource-owner registry (:275). Six call
sites, not four.

provider_host.go:275 is the most dangerous read in the repo to migrate.
That registry decides WHO MAY APPROVE, and its own comment records that
it once preferred the checkout -- which under --checkout is the merge
request's own head tree -- letting an MR ship a registry naming its
author as owner of the resource it is changing. That escalation was
found and fixed as D-130. An implementer writing REQ-E10-S02-05(ii)'s
guard test from a four-site list would leave it uncovered, and a later
'consistency' refactor onto FileAtHead would reintroduce D-130 with a
green suite.

H2 -- cmd/assent declares TWO port interfaces, not one: run.go:64
forgePort (the anonymous literal) and provider_host.go:246 refFilePort,
a hand-rolled FileAtRef-only interface. E10-S02's DoD said 'anonymous
port literal deleted' (singular), so replacing forgePort alone would
leave refFilePort standing with the DoD reading satisfied and both
go build and task lint green. The DoD now names both, and notes that
refFilePort is a named interface -- which is why the original wording
did not describe it and so did not cover it.

Both found by the independent reviewer after the P2 pass; both verified
against the tree before acting.
…iant (I1-I3)

I1 -- H2 fixed the DoD by naming the two ports that exist today, but an
allowlist goes stale the moment a third is added, and cmd/assent already
declares three interfaces (forgePort, refFilePort, and the benign
checkout.go:27 localCheckout). New REQ-E10-S02-07 states the invariant
instead: no interface declared in cmd/assent may carry a forge read or
write method except forge.RunPort, enforced in depguard_test.sh -- which
already walks cmd/assent source and already carries the mutation-control
pattern REQ-E10-S02-04 rebuilds. localCheckout must stay green, so the
guard has to distinguish a local-tree seam from a forge port rather than
banning interfaces outright. Same upgrade this chain applied to
REQ-E11-S03-04: enforced, not merely stated. The enumeration has been
wrong three times; a human re-reading the tree at S02 time is what kept
failing.

I2 -- S02-05(i) said 'no FileAtRef call remains on the governed-subject
path', which an implementer could read as 'all governed-subject sourcing
is now MR-relative'. It is not: under --checkout, run.go:283 overrides
base/head from the local tree via dirCheckout.FileContents, which carries
no FileAtRef call and is invisible to the source-level guard. That is
intended existing behaviour (EFE-S03 / ADR-0008 s4 -- the local head tree
is the presence authority) and S02 does not change it. Now stated.

I3 -- the two provider_host.go reads take a targetRef parameter, not
info.TargetBranch; REQ-E10-S02-05(ii) still said targetBranch after
ADR item 5 had already been corrected.
@konih
konih merged commit ad8853a into main Aug 10, 2026
7 checks passed
@konih
konih deleted the spec-e10-e11-p2-fixes branch August 10, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant