Skip to content

Item 5: the operator surfaces for a hop - #179

Merged
rohanrkamath merged 1 commit into
v0.10/4-one-ordered-listfrom
v0.10/5-operator-surfaces
Sep 13, 2026
Merged

rohanrkamath merged 1 commit into
v0.10/4-one-ordered-listfrom
v0.10/5-operator-surfaces

Conversation

@arpanghoshal

Copy link
Copy Markdown
Member

Item 5 of v0.10, SPEC-v0.10 §6. Stacked on #178.

No new command. v0.9 §7.1's reasoning applies unchanged, and a hop is one more thing inspect
answers about.

What lands

ctrlrun inspect --hop <id> emits ctrlrun.hop/v1 — its own document rather than a key inside
ctrlrun.inspection/v2, on v0.9 §10.1's argument: that one answers about an action, this
answers about an authority record, and a reader handed one would have to know which shape it
got before it could read either. It answers about a hop and an ordinary delegation alike, because
an operator paged about a refusal does not yet know which they have.

narrowed_dimensions is the helper §6.2 needs and the tree did not have.
contained_dimension computes the complement: the first row a child violates, or None
where it is contained. What an operator reading a refused chain needs is which link took the
resource away
, and nothing answered it. It is a reporting helper that decides nothing, which is
the line that keeps §2.2's one-relation rule intact.

§6.3: the refusal prints its own command, with the argument filled in — and the argument is
always the presented hop. An earlier draft printed the id missing_parent_id names; that id is
by construction the record the store could not read, so the suggestion is T504's unknown-id path
and exits non-zero. A refusal whose one suggestion is guaranteed to fail is worse than none. The
unreadable id goes in the prose beside it.

Mutation table

Mutation Result
P1 depth read from the stored column instead of walked SURVIVED, then caught
P2 the refusal suggests the unreadable ancestor instead of the presented hop SURVIVED, then caught

Both survived the first pass, for the same reason: every test covered the healthy chain.
Reading depth from the column agrees with the walk on any chain Control.hop built, and printing
the missing ancestor agrees with printing the presented hop when nothing is missing.

The two cases that discriminate both require editing the store the way a text editor would
which is precisely the threat v0.3 §5.5 ("a row edited directly in the database cannot assert its
way to a shorter chain") and v0.3 §5.6 rule 1 exist for. So T503b updates the depth column
behind the store's back and asserts the view still walks; T505c deletes a parent row and asserts the
printed command names the leaf, not the hole. Both caught on the re-run.

That is the third time in this milestone a guard looked tested and was not, and each time the
missing case was the adversarial one rather than the ordinary one.

Gate

4426 passed, 0 skipped with Postgres. ruff, mypy --strict clean.

Still outstanding for the release item

  • §6.4 (ctrlrun scan naming principals who hold a root grant) is not in this PR. It is the
    operator's half of §2.3.2's deployment rule, and it belongs with scan's own surface rather than
    with inspect's; the release item owns the exit criteria that reference it. Flagged rather than
    silently dropped.
  • §5.2's text still describes moving observe mode's policy_unapproved, which is not what item
    4 shipped or needed. The spec owes that correction and I will carry it in the release pass.
  • §7.3's shipped example that pins an upstream (from Item 3: upstream identity pinning #177), still unmet for the reason given
    there.

Not merging and not tagging.

SPEC-v0.10 section 6. No new command: v0.9 section 7.1's reasoning applies
unchanged, and a hop is one more thing inspect answers about.

ctrlrun inspect --hop emits ctrlrun.hop/v1, its own document rather than a
key inside ctrlrun.inspection/v2 on v0.9 section 10.1's argument: that one
answers about an action and this answers about an authority record, and a
reader handed one would have to know which shape it got before it could
read either. It answers about a hop and an ordinary delegation alike,
because an operator paged about a refusal does not yet know which they
have.

narrowed_dimensions is the helper section 6.2 needs and the tree did not
have. contained_dimension computes the complement: the first row a child
VIOLATES, or None where it is contained. What an operator reading a refused
chain needs is which link took the resource away, and nothing answered it.
It is a reporting helper that decides nothing, which is the line that keeps
section 2.2's one-relation rule intact.

Every refusal that has an id prints ctrlrun inspect --hop with it filled
in, and the argument is always the PRESENTED hop. An earlier draft of
section 6.3 printed the id missing_parent_id names; that id is by
construction the record the store could not read, so the suggested command
is the unknown-id path and exits non-zero. A refusal whose one suggestion
is guaranteed to fail is worse than none, because it teaches an operator
the line is noise. The unreadable id goes in the prose beside it.

Mutation table in the PR body. Both mutations SURVIVED the first pass, and
for the same reason: every test covered the healthy chain. Reading depth
from the stored column agrees with the walk on any chain Control.hop built,
and printing the missing ancestor agrees with printing the presented hop
when nothing is missing. The two cases that discriminate both require
editing the store the way a text editor would, which is the threat v0.3
section 5.5 and section 5.6 rule 1 exist for, so the tests now do the
editing. Both caught on the re-run.

Gate with Postgres: 4426 passed, 0 skipped.

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: b3da729e-128d-4ecc-a233-08cb419721f8

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.

@rohanrkamath
rohanrkamath merged commit 170d45e into v0.10/4-one-ordered-list Sep 13, 2026
15 of 16 checks passed
@rohanrkamath
rohanrkamath deleted the v0.10/5-operator-surfaces branch September 13, 2026 18:42
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