Fix graphs list enumeration via a served-registry scope path#377
Open
ragnorc wants to merge 11 commits into
Open
Fix graphs list enumeration via a served-registry scope path#377ragnorc wants to merge 11 commits into
ragnorc wants to merge 11 commits into
Conversation
ragnorc
pushed a commit
that referenced
this pull request
Jul 20, 2026
Red half of the review-follow-up pair for PR #377: the capability-level matrix still admitted two per-verb silent drops. - init_with_store_flag_errors_instead_of_ignoring_it: `init` addresses its target positionally and never reads --store; today the guard admits the flag and init succeeds on the positional URI while silently ignoring the store address. - queries_list_with_as_flag_errors: only `cluster apply`/`approve` read the actor among control verbs; today `queries list --as` silently drops the identity and fails later asking for a cluster. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ef516c0. Configure here.
ragnorc
pushed a commit
that referenced
this pull request
Jul 20, 2026
Green half of the review-follow-up pair. The capability rows for --store and --as gain the same per-command refinement shape as accepts_cluster_addressing: - --store on `direct` excludes `init`, which addresses its target with a required positional URI and never reads the flag; the five maintenance verbs keep consuming it via resolve_maintenance_uri. - --as on `control` is limited to `cluster apply`/`cluster approve`, the only control verbs that attribute an actor; read-only control verbs (status/plan/validate, policy, queries) now reject it loudly. Closes both PR #377 review findings: the guard no longer admits the per-verb silent drops it exists to prevent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Extract GraphClient::registry_client(server) — the bare server base URL (never /graphs/<id>) plus the keyed bearer-token chain — and rewire the RFC-011 D7 multi-graph probe through it, so GET /graphs has exactly one addressing owner. Behavior-identical: the probe's None-base early return was unreachable (resolve_server_flag with a Some server never returns None), and unknown-server errors still propagate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Red half of the red-green pair for the declarative ScopeFlag x Capability addressing guard. Predicted failures against current code: - graphs_list_rejects_store_scope (rewrites the old remote-only-message test): today the flag flows through and fails late in the client with "requires a remote multi-graph server" instead of the guard rejection. - graphs_list_rejects_graph_selector: today --graph passes the guard and corrupts the URL to /graphs/<id>/graphs, failing with a connection error to the wrong route. - graphs_list_rejects_as_actor: today --as is silently ignored and the command fails with "no graph addressed". - optimize_with_as_flag_errors: today --as is silently ignored on the Direct maintenance verb. - queries_list_with_store_flag_errors: today --store is silently ignored and the command fails asking for a cluster. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Replace guard_addressing's three ad-hoc flag checks with one exhaustive
ScopeFlag enum and a flag_applies matrix keyed by capability (--cluster
keeps its per-command accepts_cluster_addressing refinement). Adding a
flag or capability now forces a matrix row at compile time, the same
can't-silently-drift construction as the exhaustive command_plane match.
Deliberate tightenings (previously silently ignored or failed late with
an unrelated message):
- served (graphs list) now rejects --graph (it used to corrupt the
registry URL to /graphs/<id>/graphs), --store, and --as at the guard;
- direct maintenance verbs reject --as (they record no actor);
- control/local verbs reject --store; local verbs reject --graph.
Load-bearing behavior preserved: --store/--as stay consumed on the data
(any) capability — embedded reads accept-and-ignore --as, and the
served-write --as rejection keeps its own downstream message. All
pinned guard message texts are byte-identical; served gains its own
remediation tail. command_label now descends into GraphsCommand
("graphs list"). accepts_server_addressing is folded into the matrix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Red half of the red-green pair for the served-registry resolution path. Predicted failures against current code: - graphs_list_without_scope_needs_server: today the graph-shaped "no graph addressed" advice points at flags graphs list cannot consume. - graphs_list_rejects_store_bound_profile: today the store scope flows through to the embedded arm and fails late with "requires a remote multi-graph server". - graphs_list_rejects_cluster_bound_profile: today the hardcoded Any capability yields the misleading "not valid for graph data commands" error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
The enumeration verb no longer routes through the graph-addressed GraphClient::resolve() preamble, whose RFC-011 D7 require-graph probe demanded --graph before list_graphs() could run — and whose URL builder then corrupted the target to /graphs/<id>/graphs when --graph was supplied. GraphClient::resolve_registry resolves a server scope (--server / --profile / defaults.server) straight to the bare base URL via the shared registry_client; it is synchronous by design, so the async D7 probe structurally cannot fire on this path, and a scope's default_graph is deliberately ignored (the registry is server-scoped; rejecting a config default would make graphs list unusable in any profile that sets one). scope_from_binding gains Served arms: a store-bound scope fails with scope-shaped advice and a cluster-bound scope points at `omnigraph cluster status` instead of the misleading graph-data error. The dead `--uri` option on `graphs list` (rejected at runtime by reject_positional_remote since RFC-011, contradicting its help text) is removed, and the unreachable embedded arm of list_graphs becomes a defensive internal-invariant bail. Turns the commit-4 red tests green; the ignored e2e graphs_list_against_multi_graph_server step 3 is the end-to-end owner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
resolve()/resolve_with_policy() take the verb's declared capability (planes::command_capability) instead of hardcoding Capability::Any, so scope resolution and the addressing guard share one classification. Behavior-neutral: every current caller is a data-plane (Any) verb — registry-scoped `graphs list` already resolves via resolve_registry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Red half of the review-follow-up pair for PR #377: the capability-level matrix still admitted two per-verb silent drops. - init_with_store_flag_errors_instead_of_ignoring_it: `init` addresses its target positionally and never reads --store; today the guard admits the flag and init succeeds on the positional URI while silently ignoring the store address. - queries_list_with_as_flag_errors: only `cluster apply`/`approve` read the actor among control verbs; today `queries list --as` silently drops the identity and fails later asking for a cluster. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Green half of the review-follow-up pair. The capability rows for --store and --as gain the same per-command refinement shape as accepts_cluster_addressing: - --store on `direct` excludes `init`, which addresses its target with a required positional URI and never reads the flag; the five maintenance verbs keep consuming it via resolve_maintenance_uri. - --as on `control` is limited to `cluster apply`/`cluster approve`, the only control verbs that attribute an actor; read-only control verbs (status/plan/validate, policy, queries) now reject it loudly. Closes both PR #377 review findings: the guard no longer admits the per-verb silent drops it exists to prevent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
ragnorc
force-pushed
the
claude/graphs-list-enumeration-a6h8l5
branch
from
July 20, 2026 23:12
f89bf7d to
663422c
Compare
Audience-neutrality pass over rendered surfaces (docs rule: prefer stable public identifiers over organization-specific labels): - CLI --help text (clap doc comments): drop RFC-011/MR-668/MR-981 parentheticals from flag and command help. - omnigraph-server boot error: "removed in RFC-011" -> "has been removed". - OpenAPI document: drop MR-668 from the graphs-list summary and RFC-011/RFC-022 from schema descriptions (openapi.json regenerated). - Engine duplicate-key error: drop the "see MR-957" tail; the in-source test now pins the precondition wording instead of the tracker id. IETF citations (RFC 9745/8288) and code comments are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
init never resolves a scope, so an explicit --profile (which may carry a store binding) is silently discarded today — the same two-address ambiguity the init --store rejection closed. Red half of the pair; predicted symptom: init succeeds on the positional URI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Green half of the pair. The Profile row joins the per-command refinement pattern: a profile is consumed wherever scope resolution runs (data/served resolvers, resolve_maintenance_uri, require_cluster_scope), so `init` (positional target only), the `cluster` family (--config), and local verbs now reject an explicit --profile instead of silently discarding it — including any store binding it carries. The ambient $OMNIGRAPH_PROFILE default remains ignored by those verbs (config default vs explicit intent, the same rule as default_graph on the registry path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What & why
omnigraph graphs list --server <name>was broken against any populated multi-graph server: the RFC-011 D7 require-graph guard ran inside the sharedGraphClient::resolve()preamble and bailed with "pass--graph" beforelist_graphs()could run — the enumeration command only "enumerated" via its error text, which also broke--jsonconsumers. Both remedies the error suggested made it worse:--graph/default_graphcorrupted the URL to/graphs/<id>/graphs(404), and the command's own--urioption was dead (rejected at runtime despite its help text).This fixes the class, not the instance:
graphs listnow resolves through a served-registry path (GraphClient::resolve_registry, synchronous by construction, so the async D7 probe structurally cannot run on it and no/graphs/<id>is ever appended); a declarativeScopeFlag×Capabilitymatrix inguard_addressingrejects nonsense flags loudly (graphs list --graph/--store/--as,optimize --as,queries --store, …) instead of silently dropping them or failing late; and the verb's declared capability is threaded intoGraphClientresolution, replacing the hardcodedCapability::Any. The dead--urioption is removed.Backing issue / RFC
None of the above: maintainer-internal process (bug reported and dispositioned in-session). The change preserves accepted RFC-011 behavior — Decision 7's candidate-listing error still fires on data verbs (pinned by
system_remote.rsstep 4), and Decision 2/9 addressing semantics are unchanged;graphs listis exempted because it is the enumeration D7 performs.Checklist
/graphs/<id>/graphsURL corruption captured verbatim), aScopeFlag × Capabilitymatrix unit test, scope/client unit tests, and the previously-red#[ignore]d e2egraphs_list_against_multi_graph_servernow passesdocs/user/cli/reference.md(newgraphs listcommand-table row, served/direct capability bullets, loud-rejection classes, D7 exemption note) and the CLIafter_helplegendNotes for reviewers
test(cli): pin scope-flag applicability matrix (red)→fix(cli): declarative ScopeFlag × Capability addressing guard, andtest(cli): pin graphs-list served-registry resolution (red)→fix(cli): graphs list resolves through the served registry path. The bracketing refactors (registry_clientextraction; capability threading) are behavior-neutral.--ason served/direct/local verbs,--storeon served/control/local verbs.--as/--storeremain consumed on data-plane (any) verbs — the parity harness and direct-write actor attribution depend on that. The served-write--asrejection keeps its own downstream message.default_graphis deliberately ignored on the registry path (an explicit--graphis rejected, a config default is skipped): rejecting the default would makegraphs listunusable in any profile that sets one. Commented atresolve_registry.--jsonon stdout, fast guard rejections, D7 intact onquery). The engine/cluster/server crates are byte-untouched by this diff; their suites hit the session's disk allowance locally, so CI is the canonical gate for them.#[ignore]d (loopback-dependent); the non-socket owners are the guard matrix unit test and the synchronousresolve_registryunit test, which run every PR.🤖 Generated with Claude Code
https://claude.ai/code/session_017fAXpLbhodrJMydMytJZEB
Generated by Claude Code
Note
Medium Risk
CLI addressing and scope resolution changed across many verbs; behavior is heavily tested but wrong flag acceptance could still confuse operators or break scripts.
Overview
Fixes
graphs listso it hits the server’s bareGET /graphsregistry URL instead of going throughGraphClient::resolve(), where the RFC-011 D7 “pick a graph” probe blocked listing and--graphcould turn the path into/graphs/<id>/graphs.graphs listnow uses synchronousresolve_registry(sharedregistry_clientwith the D7 probe). The dead--urisubcommand flag is removed; scope comes from global--server/--profileonly, withdefault_graphignored on this path.guard_addressingis generalized to aScopeFlag×Capabilitymatrix (server, cluster, graph, store,--as, profile), with per-command refinements forinit, cluster maintenance, and read-only control verbs. Misapplied flags fail up front instead of being dropped or failing later.Each verb’s capability is threaded from
mainintoGraphClient::resolve/resolve_with_policy.Capability::Servedscope resolution rejects store- and cluster-bound profiles for registry commands.Docs and OpenAPI comments are trimmed (internal RFC/MR refs); user CLI reference documents registry scope and the new rejection rules. Tests cover the matrix, registry URL shape, scope errors, and integration cases for
graphs list,init,optimize, andqueries list.Reviewed by Cursor Bugbot for commit 7d3a095. Bugbot is set up for automated code reviews on this repo. Configure here.
Greptile Summary
This PR fixes graph enumeration by resolving
graphs listat the server registry scope. The main changes are:Confidence Score: 5/5
This looks safe to merge.
Important Files Changed
Reviews (5): Last reviewed commit: "fix(cli): reject --profile on verbs that..." | Re-trigger Greptile
Context used: