fix(providers): don't warn about project-local providers.json when it is the global file - #3256
fix(providers): don't warn about project-local providers.json when it is the global file#3256curtisgray wants to merge 1 commit into
Conversation
… when cwd is $HOME Running graphify from the home directory makes the relative ./.graphify/providers.json resolve to ~/.graphify/providers.json itself, so the gate warned about 'ignoring' the user's own trusted global file — which it then loaded via the global path anyway. A false positive here trains users to export GRAPHIFY_ALLOW_LOCAL_PROVIDERS=1 and disarm the gate for real. Treat a local path that is the same file as the global one as not-local: no warning, no double read. Stat errors resolve to 'distinct' so the gate never silently relaxes. Claude-Session: https://claude.ai/code/session_0115RXPvhNCHAnc7AFn1ud3H
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. 1 change(s) tested, no difference found (not proven).
Graphify review — findings
Stops _load_custom_providers from warning about and skipping the project-local providers file when it resolves to the same inode as the trusted global ~/.graphify/providers.json (e.g. when run from $HOME), so the user's own config loads without a false-positive warning that pushes people toward the GRAPHIFY_ALLOW_LOCAL_PROVIDERS bypass. Any stat error during the samefile check treats the path as distinct, keeping the gate closed rather than silently relaxing it.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 807 functions depend on the 190 functions this change touches.
Health — this change adds coupling hotspots:
- new:
deduplicate_entities()— 63 callers, 21 callees - new:
build_merge()— 62 callers, 13 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
extract_corpus_parallel()— 26 callers, 11 callees - new:
_call_claude_cli()— 31 callers, 9 callees - new:
dispatch_command()— 2 callers, 123 callees - new:
_extract_with_adaptive_retry()— 22 callers, 10 callees - new:
_call_llm()— 11 callers, 18 callees - …and 16 more — each is listed as a finding
Verification — 807 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: 511 function(s) in the blast radius were not formally verified this run
Formal verification
No difference found (not proven): No behavior difference found in \_load\_custom\_providers (not a proof).
The verifier ran both versions of \_load\_custom\_providers 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.
· 24 more finding(s) on lines outside this diff (see the check run).
Running graphify with the working directory at $HOME makes the relative project-local path
./.graphify/providers.jsonresolve to~/.graphify/providers.jsonitself._load_custom_providers()then warns it is ignoring the user's own trusted global file — which it immediately loads via the global path anyway. The warning is a false positive with an unfortunate failure mode: the remedy it suggests,GRAPHIFY_ALLOW_LOCAL_PROVIDERS=1, is exactly the thing a user (or an agent tidying up warnings) would export globally, permanently disarming the injected-config gate the warning exists to enforce.Fix: a local path that is the same file as the global one (
Path.samefile) is treated as not-local — no warning, no double read. A stat error resolves to "distinct", so the gate never silently relaxes; behavior for a genuinely distinct project-local file is unchanged. One test added mirroring the existing F1 tests.pytest tests/test_provider_registry.py: all pass including the new test;ruff checkclean. Noticed while verifying, unrelated to this diff:test_detect_backend_custom_provider_after_builtinsfails on a dev machine that has a real~/.graphify/providers.jsonprovider whose env key is set (the #1084 dogfood setup) whentest_llm_backends.pyis collected in the same run — it fails identically on an unmodified checkout and can't affect CI, so I left it alone; happy to file it separately.https://claude.ai/code/session_0115RXPvhNCHAnc7AFn1ud3H