fix(windows): stop a PowerShell BOM breaking hook rebuilds - #3086
fix(windows): stop a PowerShell BOM breaking hook rebuilds#3086rohit-jsfreaky wants to merge 1 commit 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. No changes could be formally verified in this run.
Graphify review — findings
Fixes WinError 123 rebuild failures on Windows PowerShell 5.1 (#3028) by decoding the .graphify_root marker with utf-8-sig everywhere it's read — _infer_merge_root, both hook rebuild bodies, _resolve_source_path, and watch's _StoredSourcePaths — so a stray UTF-8 BOM no longer rides into a path and gets silently treated as relative. Switches the Windows skill/powershell bootstrap to write .graphify_python and .graphify_root via WriteAllText with a BOM-less UTF8Encoding, since 5.1's Out-File -Encoding utf8 always emits a BOM; the reader change heals existing broken checkouts in place.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1687 functions depend on the 613 functions this change touches.
Health — this change adds coupling hotspots:
- new:
_rebuild_code()— 98 callers, 50 callees - new:
build_from_json()— 187 callers, 18 callees - new:
build_merge()— 46 callers, 14 callees - new:
to_obsidian()— 36 callers, 13 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
to_wiki()— 41 callers, 7 callees - new:
extract_corpus_parallel()— 26 callers, 11 callees - new:
_call_claude_cli()— 31 callers, 9 callees - …and 50 more — each is listed as a finding
Verification — 1687 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: 1308 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_infer\_merge\_root.
The verifier did not have enough to check \_infer\_merge\_root, 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: parameter `graph_path` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_resolve\_source\_path.
The verifier did not have enough to check \_resolve\_source\_path, 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: parameter `graph_path` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_\_init\_\_.
The verifier did not have enough to check \_\_init\_\_, 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: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
· 58 more finding(s) on lines outside this diff (see the check run).
|
Shipped in v0.9.50 via authorship-preserving cherry-pick so you keep contributor-graph credit. Thanks @rohit-jsfreaky! Release: https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.50 |
Fixes #3028.
Summary
The Windows bootstrap writes the two sidecar markers with
Out-File -Encoding utf8. On Windows PowerShell 5.1 that always prepends a UTF-8 BOM —utf8NoBOMonly exists from PowerShell 6, and-NoNewlinedoes nothing about it. Sographify-out/.graphify_pythonand.graphify_rootstart withEF BB BF.Every reader then decodes them with
utf-8, which keeps the BOM asU+FEFF, andstr.strip()does not remove it —U+FEFFis not whitespace. The character rides into path handling and the post-commit rebuild dies withWinError 123, whilehook installandhook statusboth keep reporting success. The graph silently goes stale unless someone opens~/.cache/graphify-rebuild.log.WinError 123is the loud failure. There is a quiet one too: in_infer_merge_rootthe BOM makes an absolute path stop being drive-qualified, soPath(recorded).resolve()treats it as relative and silently joins it onto the cwd — no exception, just a wrong scan root:Changes
Read side — the half that repairs installs already broken. Five call sites now decode with
utf-8-sig, which strips an optional BOM and is a no-op on a clean file:hooks.py(both rebuild bodies),watch.py,reflect.py,build.py. Rewriting the markers alone would only help fresh runs; anyone already in this state stays broken until they re-run the bootstrap. Withutf-8-sigthey recover on the next commit.Write side — stop producing the BOM.
fragments/shell/powershell.mdwrites both markers through[System.IO.File]::WriteAllTextwith an explicitNew-Object System.Text.UTF8Encoding $false, which emits no BOM and appends no newline — the same bytes the POSIX fragment already writes withecho >. Regenerated withpython -m tools.skillgen+--bless; only the windows platform uses this fragment, soskill-windows.mdand itsexpected/snapshot are the only rendered artifacts that change.Verification on the actual shell
Both forms run on Windows PowerShell 5.1.26100.9168, writing the same interpreter path:
Out-File -Encoding utf8 -NoNewline(today)EF BB BFWriteAllText+UTF8Encoding $false(this PR)43 3A 5C(C:\)Exactly the three BOM bytes apart, and no trailing newline either way.
Tests
Four added, each confirmed to fail with the source changes reverted and the tests kept:
test_graphify_root_marker_with_a_utf8_bom_still_resolves— the repro: a marker written with a realEF BB BFprefix must still resolve to the true root through_infer_merge_root.test_rebuild_bodies_tolerate_a_bom_in_graphify_root(both hook bodies) — the generated rebuild must read the marker BOM-tolerantly, since that is the site that producedWinError 123.test_windows_skill_writes_marker_files_without_a_bom— the rendered Windows skill must not write either marker through a BOM-emittingOut-File.One existing test needed updating rather than working around:
test_rebuild_bodies_read_graphify_rootasserted the literalread_text(encoding='utf-8'). Its stated intent is shell-quote safety inside the double-quoted launcher ("single quotes only"), whichutf-8-sigstill satisfies, so the literal moved with a comment explaining why the codec changed.hooks 95 passed (2 pre-existing platform failures), skillgen 65 passed, build-merge 10 passed.
All five skillgen guards pass:
--check(134 artifacts),--audit-coverage,--schema-singleton,--monolith-roundtrip,--always-on-roundtrip.uv run --no-sync ruff checkon every touched file — passed.Full suite: 14 failed, 4985 passed, 41 skipped — the same 14 as a clean
v8checkout of this commit on this Windows machine (12 platform tests: fifo / unix-socket / hermes / gemini paths / watch; plus 2 FalkorDB integration tests failing against the local port with a redisResponseError). Verified by running them in a detached worktree at282976band diffing the failure lists.I have not run an end-to-end
git commitagainst a BOM'd install; the evidence here is the byte-level PowerShell comparison above plus the reproduced path corruption.Note: this touches
graphify/skill-windows.md, which #2677 also touches — at line 645 there versus 120/122 here, so they should merge cleanly in either order.