Skip to content

fix(rcfile): read .graphifyrc with utf-8-sig so a BOM doesn't drop the first key - #4538

Open
rudycelekli wants to merge 1 commit into
Graphify-Labs:v8from
rudycelekli:fix/rcfile-utf8-bom
Open

rudycelekli wants to merge 1 commit into
Graphify-Labs:v8from
rudycelekli:fix/rcfile-utf8-bom

Conversation

@rudycelekli

Copy link
Copy Markdown

What does this PR do?

load_graphifyrc read .graphifyrc as plain utf-8. Windows PowerShell 5.1 (Set-Content -Encoding UTF8) and older Notepad save UTF-8 with a BOM, which then became part of the first key (language.inc). Unknown keys are ignored by design, so the user's first setting was dropped without any warning:

with BOM:    {'viz_node_limit': 500}
without BOM: {'viz_node_limit': 500, 'languages': {'.inc': '.php'}}

It now reads with utf-8-sig, which strips a leading BOM and is identical to utf-8 otherwise. That matches how build.py, cli.py, hooks.py, install.py and watch.py already read Windows-edited files.

Type of change

  • Bug fix

Verification & Invariants

  • Read CONTRIBUTING.md (cross-platform section)
  • Smallest fix
  • Regression test test_a_utf8_bom_does_not_swallow_the_first_key in tests/test_language_overrides.py

How was this tested?

# with the fix stashed
uv run --frozen pytest tests/test_language_overrides.py -k bom -q   # 1 failed
# with the fix
uv run --frozen pytest tests/test_language_overrides.py -q          # 56 passed, 1 skipped
uv run --frozen ruff check graphify/rcfile.py tests/test_language_overrides.py   # clean

Graphify-specific checklist

  • Cross-platform behavior considered (Windows editors)
  • No unsafe interpolation
  • AI authorship disclosed in the commit

I used Claude Code for this change and reviewed and ran it myself.

🤖 Generated with Claude Code

…e first key

Windows PowerShell 5.1 (Set-Content -Encoding UTF8) and older Notepad save
UTF-8 with a BOM. load_graphifyrc read the file as plain utf-8, so the BOM
became part of the first key; unknown keys are ignored by design, so that
setting (say language.inc=php) vanished without a warning. Read with
utf-8-sig, as the other Windows-edited files in the repo already are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Thanks for the pull request, @rudycelekli. A maintainer will review it soon.

Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions.

A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic.

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

No issues found by static checks — no coupling regressions or blocking issues in the code graph. That is not the same as safe to merge: see what was not checked.

Not checked: tests were not run; formal verification proved 0 of 1 changed function(s) (1 sampled, not proven).

Formal verification. PR-changed functions: 1/1 verified (0 proven, 1 may-equivalent, 0 distinguished) · 0 not verified.


Graphify review — findings

Fixes load_graphifyrc silently dropping the first line of a .graphifyrc saved with a UTF-8 BOM, which is what Windows PowerShell 5.1 and older Notepad produce. The file is now read as utf-8-sig, so the BOM is stripped instead of being glued onto the first key, where it matched nothing and was ignored with no warning. A new test writes a BOM-prefixed file and checks that both the language.inc mapping and the following option are parsed.

No blocking issues surfaced.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 3303 functions depend on the 76 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: load_graphifyrc() — 11 callers, 3 callees

Verification — 3303 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: 1323 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

55 of 432 test file(s) selected (13%) via static blast radius.

  • tests/test_astro_extraction.py — impact
  • tests/test_atomic_writes.py — impact
  • tests/test_build.py — impact
  • tests/test_cjs_module_extension.py — impact
  • tests/test_csharp_interface_dispatch.py — impact
  • tests/test_csharp_partial_classes.py — impact
  • tests/test_detect.py — impact
  • tests/test_dotnet.py — impact
  • tests/test_ejs_extractor.py — impact
  • tests/test_ext_tagged_id_clash.py — impact
  • tests/test_extract.py — impact
  • tests/test_extract_cli.py — impact
  • tests/test_forwarding_review_findings.py — impact
  • tests/test_hook_chain_survives_skip.py — impact
  • tests/test_hooks.py — impact
  • tests/test_hooks_rewrite.py — impact
  • tests/test_ignore_file_encoding.py — impact
  • tests/test_import_extension_resolution.py — impact
  • tests/test_incremental_mtime_collision.py — impact
  • tests/test_indirect_call_block_scoped_shadow.py — impact
  • tests/test_js_exported_scalar_bindings.py — impact
  • tests/test_js_member_collisions.py — impact
  • tests/test_js_walk_order.py — impact
  • tests/test_language_override_imports.py — impact
  • tests/test_language_override_lifecycle.py — impact
  • tests/test_language_overrides.py — impact, changed-test
  • tests/test_language_resolvers.py — impact
  • tests/test_languages.py — impact
  • tests/test_loose_sibling_import_resolution.py — impact
  • tests/test_manifest_ingest.py — impact
  • tests/test_markdown_code_spans.py — impact
  • tests/test_mcp_ingest.py — impact
  • tests/test_multilang.py — impact
  • tests/test_ocaml.py — impact
  • tests/test_out_dir_evidence.py — impact
  • tests/test_package_json_subpath_imports.py — impact
  • tests/test_phantom_external_import.py — impact
  • tests/test_pipeline.py — impact
  • tests/test_pr10_csharp_overrides.py — impact
  • tests/test_pr10_resolution_overrides.py — impact
  • tests/test_pr10_watch_overrides.py — impact
  • tests/test_python_import_resolution.py — impact
  • tests/test_rationale.py — impact
  • tests/test_skill_persisted_scan_options.py — impact
  • tests/test_src_layout_import_resolution.py — impact
  • tests/test_stale_prune.py — impact
  • tests/test_svelte_extraction.py — impact
  • tests/test_swift_protocol_dispatch.py — impact
  • tests/test_symbol_resolution.py — impact
  • tests/test_ts_new_expression_calls.py — impact
  • … and 5 more

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

No difference found (not proven): No behavior difference found in load\_graphifyrc (not a proof).

The verifier ran both versions of load\_graphifyrc 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.

· 1 more finding(s) on lines outside this diff (see the check run).

This branch has not been deployed

No deployments
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.

1 participant