Skip to content

Answer the SPEC-v0.10 review round: eighteen findings, two more of my own - #173

Merged
rohanrkamath merged 2 commits into
spec/v0.10-review-answersfrom
spec/v0.10-review-round-1
Sep 13, 2026
Merged

rohanrkamath merged 2 commits into
spec/v0.10-review-answersfrom
spec/v0.10-review-round-1

Conversation

@arpanghoshal

Copy link
Copy Markdown
Member

Stacked on #172. Documentation only, no code changes. Item 0's required spec review round, and
its answers.

An adversarial round ran against SPEC-v0.10.md in a session that did not write it, under the
probe-before-you-assert rule. It returned eighteen findings. I checked every one against the
tree before answering it; all eighteen were real. Two more are mine, found while reading item
3's and item 4's targets.

The two that change the design

Control._suspend re-decides authority, and §2.3.2 never reached it

_suspend is the lease extension. control.py:2218 evaluates authority again and
control.py:2227 raises AuthorityDenied, and the comment above it says exactly why:

Without this, §5.7's "a chain of any depth is cut by one write" is false for exactly the actions
in flight when an operator hits the switch.

Under §2.3.2 the decision at execute's top is pinned to the hop; this one was not. So a receiver
holding any grant of its own keeps its reservation across the round trip after the hop is revoked
,
and revocation fails to cut the in-flight action that check exists to cut. That is §10's row "there
is no fallback", inverted.

New §3.4.3 carries it, with a table of where each path takes its hop from: execute from the
caller, _suspend from the context variable (same call, same stack), resume from the durable
event (a different call, whose ambient context is unrelated). T488a is the test, shaped so it cannot
pass for the wrong reason.

The same finding corrected §3.4.2's justification, which was inverted. resume records and does
not re-decide, which control.py:1847 says in a comment, so a hop there fixes which grant the
receipt names, not blast radius. I had borrowed an argument that does not apply.

Three of six hop refusals report no_authority with no id

matches_shape (authority.py:536) filters on subject, action, resource and environment before any
outcome is collected. P9, the only grant the principal holds being the hop:

case                       reason                   grant_id
inside the envelope        authority_grant          'dlg_30448e1d…'
action not covered         no_authority             None
resource not covered       no_authority             None
environment not covered    no_authority             None
constraint fails           authority_constraint     'dlg_30448e1d…'
subject is someone else    no_authority             None

That is the milestone's headline refusal, "this hop does not authorise this action", reported as
"you hold no authority at all"
with nothing to hand ctrlrun inspect --hop, while §6.3 promises
every refusal naming a delegation prints a command with its argument filled in. G24's own catalogue
comment set the precedent: it reports authority_task "rather than a bare no_authority so an
operator can tell this from having no grant at all".

authority_hop now covers a presented hop that does not match the action's shape, carrying
data.dimension. §2.3.3 has the probe and the argument.

The rest, in one table

# Finding Answer
1 -41013 was already taken by ctrlrun.not_a_human, shipped in SPEC-mcp-operator §9.3 and tested. One namespace, and I spent an allocated number Retaken as -41016, the first free code after -41015. §4.5 records that a new identifier in a shared namespace is searched for before it is spent
3 §2.3.2 rules 2 and 3 contradicted each other on a revoked hop, and covered no expired one Liveness struck from rule 2; the hop owns existence and shape, the chain owns everything else
4 §2.3.1's narrative was false of the probe it displays: the action is inside the envelope, not outside it Rewritten from what the probe printed, with both directions of the codepoint-order flip
5 CreatedVia's rollback denies every action in the deployment, not one delegation. authority.py:118-123 says so in the source New §9.3: the irreversible step is creating the first hop, not installing 0.10.0
7 A relay breaks rule 3 and G26, and DELEGATION_CREATED is action-less by construction (control.py:4316), so the created hop is linked to its action by a timestamp The event gains action_id when the hop was created inside an action; G26 becomes a hop is named on both sides and must be graded over a chain with a middle
8 The gateway reads no caller metadata and threads no task; §9 froze no surface item 1 could wire New §3.1.2 with the rows, and the argument that a lookup key is safe where an assertion is not, made once and cited twice
9 §4.4's "load error" is not implementable at load (one loader, no surface parameter) and would have stopped verify loading the example §7.3 requires Constructor-time refusal for the ACS hook; in-process falls to upstream_unverified at decision time
10 §7.1's G25 requirement had no implementable construction: verify cannot mint a root, and a sibling delegation makes the control a coin flip on secrets.token_hex Both orders asserted, so the coin flip is tested rather than hoped for; a second N/A reason added
12 needs_approval routes through evaluate with no hop, so the predicate disagrees with execute one frame up §9 row
13 §6.2's chain[] needed a helper that does not exist (contained_dimension computes the complement) and was singular where T470 is plural narrowed_dimensions, explicitly a reporting helper that decides nothing, so §2.2's one-relation rule holds
14 The resumed-leg discriminator must be key presence, not value: a 0.10 build writes {"hop": …, "task": None} Stated, with T487 asserting the key-presence reading
11 T504 and T505 contradicted: the id missing_parent_id carries is by construction unreadable, so the printed command must fail §6.3 prints the presented hop and names the unreachable ancestor in prose
15, 16, 17 Three citations line-accurate and semantically wrong: contained_dimension has seven callers and a hop adds none; max_delegation_depth is an authority: key, not a grant key; require_v7 gates grant entries while upstream: is an action-entry key All three corrected, each saying what the earlier draft claimed and why it was wrong
18 "plus its chain" read as "ancestors are candidates too" reopens the hole Rule 1 now says the named delegation is the only candidate and its chain is walked, not offered

My two

§5.2's ordered list cannot live inside the two _secure methods. policy_unapproved is decided
by _require_approved at control.py:1293, above authority at :1298, and returns early when
observing; _observe_secure is not called until :1526. P7, one action, one document:

enforce: RAISED ActionDenied  reason='policy_unapproved'
observe: ran, receipt result=observed  would_have.blocked_reason='no_authority'

An item unifying only the two methods leaves that case exactly as broken and its generated pair
test passes
, because the pair set is built from a list that never covered it. The order to declare
is already a comment at control.py:1296. T499a is the test.

§4.2 pinned by digest while §4.3 made the pinned certificates trust anchors. A digest cannot be
a trust anchor; load_verify_locations takes PEM. P8, against a CA-signed leaf:

ssl.VERIFY_X509_PARTIAL_CHAIN available: True
the pinned server   HANDSHAKE OK
a swapped server    REFUSED  SSLCertVerificationError: CERTIFICATE_VERIFY_FAILED

The mechanism works, so §4.2 gains a certificate-valued key for check 3, the digest serves checks 1
and 2, and pinning by digest alone is stated as getting two checks rather than three. §9 gains the
ssl_context= row gateway/transport.py:155 needs.

What the review confirmed as correct

Worth recording, because most of the document held. It reproduced P1, P5 and P5(b) byte for byte;
stress-tested transitivity far harder than I did (1,043 grants, 2,910 contained pairs, 5,058
triples, 0 violations
, plus 13,024 pairs checked for soundness over 10,800 situations); confirmed
the title widths, the schema arithmetic, §5.1's ordering line numbers, §3.4.2's event claims, the
no-migration analysis, and all 33 citations, independently, 0 unresolved.

Checks

  • 48 line citations, 0 unverified, each spot-checked against the token it is cited for. Three
    off-by-one errors introduced during this edit were caught by that check and fixed.
  • 0 em dashes. Tests T470 to T507, contiguous, plus T488a and T499a (the T91d/T223b
    suffix convention).
  • Guarantee titles 30 / 28 / 28 against the 32 limit.
  • No dangling internal section references across 61 headings.

What a second round should look at

The reviewer's own list, carried forward rather than closed: the remaining _authority_result call
sites (Control.evaluate at control.py:865, and the observe path); contextvar hygiene now that
_HOP joins _TASK, _AUTHORITY_GRANT_ID, _AUTHORITY_RESULT and _BUDGET_CHARGES, with a
nested suspend-and-resume case; §5 as a whole, which got the least attention; §4 against a real TLS
listener; and whether adding hop to the receipt moves the hashed shape in a way G11 notices.

Not merging and not tagging.

An adversarial round against SPEC-v0.10 returned eighteen defects. All were
checked against the tree before being answered; every one below was real.
Two more are mine, found while reading item 3's and item 4's targets.

The two that change the design.

Control._suspend re-decides authority and takes no hop. It is the lease
extension: control.py:2218 evaluates again and control.py:2227 raises
AuthorityDenied, and the comment above it says why, that without it v0.3
section 5.7's "a chain of any depth is cut by one write" is false for
exactly the actions in flight. Under section 2.3.2 the decision at
execute's top is pinned to the hop and this one was not, so a receiver
holding any grant of its own keeps its reservation across a round trip
after the hop is cut. New section 3.4.3, with a table of where each path
takes its hop from and why the context variable is right at _suspend and
wrong at resume. Section 3.4.2's justification was also inverted: resume
records and does not re-decide, which control.py:1847 says in a comment,
so a hop there fixes which grant the receipt names, not blast radius.

Three of six hop refusals report no_authority with no id. matches_shape
filters on subject, action, resource and environment before any outcome is
collected, so a hop that does not cover them falls out of the loop and
evaluate returns no_authority with grant_id None. That is the milestone's
headline refusal reported as "you hold no authority at all", with nothing
to hand inspect --hop, and section 6.3 promised a command with its argument
filled in. authority_hop now covers a presented hop that does not match the
action's shape, carrying data.dimension. Section 2.3.3 has the probe.

Also: -41013 was already ctrlrun.not_a_human, shipped in SPEC-mcp-operator
and tested; retaken as -41016, the first free code. Rules 2 and 3 of
section 2.3.2 contradicted each other on a revoked hop and covered no
expired one; liveness is struck from rule 2. Section 2.3.1's narrative was
false of the probe it displays, which shows an action inside the envelope,
not outside it. A relay breaks rule 3 and G26: DELEGATION_CREATED is
action-less by construction, so the created hop is linked to the action
that created it by nothing but a timestamp; the event gains action_id and
G26 becomes "a hop is named on both sides", graded over a chain with a
middle. CreatedVia's rollback denies every action in the deployment, not
one delegation, which makes the first hop the irreversible step; new
section 9.3. The gateway reads no caller metadata and threads no task, and
needs_approval routes through evaluate with neither, so section 9 froze no
surface item 1 could wire. Section 4.4's load error is not implementable at
load and would have stopped verify loading the example section 7.3
requires. Section 7.1's G25 requirement had no implementable construction.
Section 6.2's chain[] needed a helper that does not exist and was singular
where T470 is plural. The resumed-leg discriminator must be key presence,
not value. Three citations were semantically wrong while line-accurate:
contained_dimension has seven callers and a hop adds none,
max_delegation_depth is a section key not a grant key, and require_v7 gates
grant entries while upstream: is an action-entry key.

Mine. The ordered list of section 5.2 cannot live inside the two _secure
methods: policy_unapproved is decided at control.py:1293 above authority,
while _observe_secure is not called until :1526, so a _secure-only refactor
leaves v0.9 section 4.2.1b's second case broken and its generated pair test
green. Measured, one action, one document: enforce raises policy_unapproved
and observe reports no_authority. And section 4.2 pinned by digest while
section 4.3 made the pinned certificates trust anchors, which a digest
cannot be; a certificate-valued key is added, and a probe shows a CA-signed
leaf with VERIFY_X509_PARTIAL_CHAIN admits the pinned server and refuses a
swapped one.

48 line citations, all resolving. Tests T470-T507 plus T488a and T499a.
Documentation only. No code changes.

Signed-off-by: arpan <contact@arpanghoshal.com>
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 4dda4392-7d1f-40ba-914a-8570f84203c1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Round one's answer said a presented hop that does not match the action's
shape reports authority_hop with data.dimension naming which of subject,
actions, resources or environments failed. Grant.matches_shape
(authority.py:534) returns a bool and returns False at the first failure,
so that value exists on the stack and is discarded, and section 9 named
nothing that could supply it.

unmatched_shape(grant, action) -> str | None returns the first failing row,
and matches_shape becomes a call to it so the two cannot drift. That is
contained_dimension's shape applied to the other half of v0.3 section 4.3's
iff, which is also why it is not a second walk inside evaluate.

Found while reading the answer before writing code against it.

Signed-off-by: arpan <contact@arpanghoshal.com>
@rohanrkamath
rohanrkamath merged commit 143c7db into spec/v0.10-review-answers Sep 13, 2026
16 checks passed
@rohanrkamath
rohanrkamath deleted the spec/v0.10-review-round-1 branch September 13, 2026 14:14
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.

2 participants