feat: add governed gateway routing and production graph queries - #2735
feat: add governed gateway routing and production graph queries#2735Alter-Igor wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. 2 change(s) alter behavior, breaking input(s) attached.
Behavior changes: format\_affected changes behavior, here is the input that shows it.
The verifier found a concrete input on which format\_affected behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"'\(\)'"\}, the old code produced 'No unique node match for \(\)' but the new code produces raises KeyError. Paste that input straight into a regression test.
Behavior changes: resolve\_seed changes behavior, here is the input that shows it.
The verifier found a concrete input on which resolve\_seed behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"'\(\)'"\}, the old code produced None but the new code produces raises KeyError. Paste that input straight into a regression test.
Graphify review — findings
This pull request adds an optional "production-only" mode to the affected command's reverse dependency traversal, which excludes test, eval, and docs nodes. It introduces a new --production-only CLI flag, path classification helpers (e.g. _is_production_source, _is_production_node), and refactors seed resolution and edge-traversal logic in affected.py into smaller helper functions. Separately, it adds support for a GRAPHIFY_OPENAI_HEADERS_JSON environment variable that lets users supply extra non-credential headers for OpenAI-compatible gateways, with credential/transport headers rejected. The README documents both changes and affected is added to the free-text command set so its arguments bypass the generic help handler. The touched surface spans README.md, __main__.py, affected.py, LLM/OpenAI header handling, and associated test files.
No blocking issues surfaced. 3 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1013 functions depend on the 373 functions this change touches.
Health — this change adds coupling hotspots:
- worse:
dispatch_command()— 2 callers, 118 callees - worse:
_call_llm()— 12 callers, 18 callees - worse:
_call_openai_compat()— 24 callers, 9 callees - worse:
affected_nodes()— 28 callers, 6 callees - worse:
resolve_seed()— 18 callers, 4 callees - worse:
triage_with_opus()— 3 callers, 6 callees - worse:
format_affected()— 4 callers, 4 callees - worse:
_resolve_triage_backend()— 4 callers, 3 callees
Verification — 1013 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 933 function(s) in the blast radius were not formally verified this run
Formal verification
Behavior changes: format\_affected changes behavior, here is the input that shows it.
The verifier found a concrete input on which format\_affected behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"'\(\)'"\}, the old code produced 'No unique node match for \(\)' but the new code produces raises KeyError. Paste that input straight into a regression test.
Behavior changes: resolve\_seed changes behavior, here is the input that shows it.
The verifier found a concrete input on which resolve\_seed behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"'\(\)'"\}, the old code produced None but the new code produces raises KeyError. Paste that input straight into a regression test.
Verification did not run: Verification did not run for affected\_nodes.
The verification could not execute (an environment/toolchain issue, not a statement about the code).
Guarantee: No guarantee, the check itself did not complete.
Note: Detail: exec: NameError
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
Could not verify: Could not verify \_call\_llm.
The verifier did not have enough to check \_call\_llm, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly TypeError — names the real obstacle, not a sampling gap)
Verification did not run: Verification did not run for \_call\_openai\_compat.
The verification could not execute (an environment/toolchain issue, not a statement about the code).
Guarantee: No guarantee, the check itself did not complete.
Note: Detail: harness produced no verdict (rc=124): timeout after 30s
No difference found (not proven): No behavior difference found in \_run\_cli (not a proof).
The verifier ran both versions of \_run\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_resolve\_triage\_backend (not a proof).
The verifier ran both versions of \_resolve\_triage\_backend on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in triage\_with\_opus (not a proof).
The verifier ran both versions of triage\_with\_opus on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).
| ] | ||
| if len(matches) == 1: | ||
| return str(matches[0]) | ||
| return _prefer_file_node(graph, matches, repo_relative_query) if matches else None |
There was a problem hiding this comment.
resolve_seed()
18 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| if production_only and not _is_production_node(graph, member_id): | ||
| continue | ||
| seen.add(member_id) | ||
| queue.append((member_id, 0)) |
There was a problem hiding this comment.
affected_nodes()
fans out to 6 callees (efferent coupling); 28 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return _TRIAGE_MODEL_DEFAULTS.get(backend) or _default_model_for_backend(backend) | ||
|
|
||
|
|
||
| def _resolve_triage_backend() -> tuple[str, str]: |
There was a problem hiding this comment.
_resolve_triage_backend()
high coupling complexity (Ca·Ce = 12).
Grounded coupling-delta finding (deterministic), not an LLM guess.
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. 3 change(s) alter behavior, breaking input(s) attached.
Behavior changes: format\_affected changes behavior, here is the input that shows it.
The verifier found a concrete input on which format\_affected behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"''"\}, the old code produced raises KeyError but the new code produces 'No unique node match for '. Paste that input straight into a regression test.
Behavior changes: \_prefer\_file\_node changes behavior, here is the input that shows it.
The verifier found a concrete input on which \_prefer\_file\_node behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(0, \{\}\), \(1, \{\}\), \(2, \{\}\)\]\), \_g\.add\_edges\_from\(\[\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","node\_ids":"\[1\]","query":"'/'"\}, the old code produced 1 but the new code produces '1'. Paste that input straight into a regression test.
Behavior changes: resolve\_seed changes behavior, here is the input that shows it.
The verifier found a concrete input on which resolve\_seed behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"''"\}, the old code produced raises KeyError but the new code produces None. Paste that input straight into a regression test.
Graphify review — findings
This PR adds a --production-only option to the affected command, which excludes test, eval, and docs nodes during reverse dependency traversal. It introduces path-classification helpers (_is_production_source, _is_production_node) and refactors the resolve_seed logic into smaller helpers (_unique_or_production_match, _label_matches, _resolve_source_match, _seed_members), while also adding affected to the free-text command exemption list in the CLI help handling. The changes also touch OpenAI backend header handling (documented via a new GRAPHIFY_OPENAI_HEADERS_JSON env var in the README) and adjust several LLM-related symbols and tests around synapse routing, triage models, and path/source evidence.
No blocking issues surfaced. 4 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1014 functions depend on the 374 functions this change touches.
Health — this change adds coupling hotspots:
- worse:
dispatch_command()— 2 callers, 118 callees - worse:
_call_llm()— 12 callers, 18 callees - worse:
_call_openai_compat()— 24 callers, 9 callees - worse:
affected_nodes()— 28 callers, 6 callees - worse:
resolve_seed()— 19 callers, 4 callees - worse:
format_affected()— 5 callers, 4 callees - worse:
triage_with_opus()— 3 callers, 6 callees - worse:
_resolve_triage_backend()— 4 callers, 3 callees
Verification — 1014 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 934 function(s) in the blast radius were not formally verified this run
Formal verification
Behavior changes: format\_affected changes behavior, here is the input that shows it.
The verifier found a concrete input on which format\_affected behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"''"\}, the old code produced raises KeyError but the new code produces 'No unique node match for '. Paste that input straight into a regression test.
Behavior changes: \_prefer\_file\_node changes behavior, here is the input that shows it.
The verifier found a concrete input on which \_prefer\_file\_node behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(0, \{\}\), \(1, \{\}\), \(2, \{\}\)\]\), \_g\.add\_edges\_from\(\[\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","node\_ids":"\[1\]","query":"'/'"\}, the old code produced 1 but the new code produces '1'. Paste that input straight into a regression test.
Behavior changes: resolve\_seed changes behavior, here is the input that shows it.
The verifier found a concrete input on which resolve\_seed behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"graph":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","query":"''"\}, the old code produced raises KeyError but the new code produces None. Paste that input straight into a regression test.
Verification did not run: Verification did not run for affected\_nodes.
The verification could not execute (an environment/toolchain issue, not a statement about the code).
Guarantee: No guarantee, the check itself did not complete.
Note: Detail: exec: NameError
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
Could not verify: Could not verify \_call\_llm.
The verifier did not have enough to check \_call\_llm, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly TypeError — names the real obstacle, not a sampling gap)
Verification did not run: Verification did not run for \_call\_openai\_compat.
The verification could not execute (an environment/toolchain issue, not a statement about the code).
Guarantee: No guarantee, the check itself did not complete.
Note: Detail: harness produced no verdict (rc=124): timeout after 30s
No difference found (not proven): No behavior difference found in \_run\_cli (not a proof).
The verifier ran both versions of \_run\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_resolve\_triage\_backend (not a proof).
The verifier ran both versions of \_resolve\_triage\_backend on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in triage\_with\_opus (not a proof).
The verifier ran both versions of triage\_with\_opus on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).
| return _prefer_file_node(graph, matches, repo_relative_query) if matches else None | ||
|
|
||
|
|
||
| def resolve_seed(graph: nx.Graph, query: str) -> str | None: |
There was a problem hiding this comment.
resolve_seed()
19 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| queue.append((member_id, 0)) | ||
|
|
||
|
|
||
| def affected_nodes( |
There was a problem hiding this comment.
affected_nodes()
fans out to 6 callees (efferent coupling); 28 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return _TRIAGE_MODEL_DEFAULTS.get(backend) or _default_model_for_backend(backend) | ||
|
|
||
|
|
||
| def _resolve_triage_backend() -> tuple[str, str]: |
There was a problem hiding this comment.
_resolve_triage_backend()
high coupling complexity (Ca·Ce = 12).
Grounded coupling-delta finding (deterministic), not an LLM guess.
Outcome
Adds governed OpenAI-compatible gateway metadata and improves Graphify's structural CLI evidence without changing its default model selection.
Changes
GRAPHIFY_OPENAI_HEADERS_JSONautothrough unchangedaffected --production-onlywith fail-closed path and edge filteringpathoutputaffectedflags and supports command help plus option-first orderingThe default behavior remains compatible when the new environment variable and flag are absent.
Validation
graphify update .: completedNo lockfile change is included.