fix: sourceLocalPath handles wrapped {sources:[...]} shape from gbrain v0.18.0+#1610
fix: sourceLocalPath handles wrapped {sources:[...]} shape from gbrain v0.18.0+#1610pennyultima wants to merge 1 commit into
Conversation
…n v0.18.0+
`gbrain sources list --json` has returned `{sources: [...]}` since v0.18.0
(commit 90c5d93, "multi-source brains"). `sourceLocalPath()` typed the
response as a raw `Array<...>` and called `.find()` directly, crashing
`/sync-gbrain --full` with: `list.find is not a function`.
The bug only surfaces on full reindex (`runCodeImport` is the only caller)
so the cheap incremental path didn't hit it.
Patch is defensive against both shapes so the helper works on any gbrain
version: wrapped (v0.18.0+) or raw array (older).
Test fixture audit: the existing 3 tests for sourceLocalPath all used the
raw-array shape, which is why CI didn't catch the bug. Added matching
tests for the live wrapped shape and kept the raw-array tests for
back-compat coverage. 5 tests pass; pre-fix code would have failed the
two new wrapped-shape tests.
Closes garrytan#1609
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for pinning this. This appears to be the same I think #1594 is the canonical landing path now. If anything from this PR is still missing after that wave, the useful follow-up would be a targeted regression against current |
|
Your fix was independently shipped via another route before this PR could land — verified in current main. Closing. Thanks for the contribution, @pennyultima! |
Closes #1609
What
gbrain sources list --jsonhas returned{sources: [...]}since gbrain v0.18.0 (commit90c5d93, "multi-source brains," 2026-04-22).sourceLocalPath()inbin/gstack-gbrain-sync.ts:291typed the response as a rawArray<...>and called.find()directly, crashing/sync-gbrain --full:The bug only surfaces on full reindex (
runCodeImportis the only caller ofsourceLocalPath), so the cheap incremental path users hit via the hourly LaunchAgent didn't trigger it. That's why it's been latent.How
Defensive against both shapes — works on any gbrain version, wrapped (v0.18.0+) or raw array (older):
Why CI didn't catch it
The existing 3 unit tests for
sourceLocalPathall use the raw-array shape in their fixtures:The function passes them because the mock matches the function's (wrong) type assumption. The real gbrain CLI returns the wrapped shape, and the function crashes there.
This PR updates the fixtures to use the live wrapped shape and keeps the raw-array tests for back-compat. Net: 5 tests cover both shapes.
Pre-fix code fails 2 of these (the new wrapped-shape tests). Post-fix passes all 5.
Audit of other call sites
I grepped for every consumer of
gbrain sources list --jsonacrossbin/andlib/:bin/gstack-gbrain-sync.ts:292(this PR)lib/gbrain-sources.ts:54(probeSource).sourceslib/gbrain-sources.ts:165(sourcePageCount).sourcesbin/gstack-gbrain-source-wireup:215,298(shell)jq '.sources[]'lib/gbrain-local-status.ts:224So this is the only broken call site. The lib code does it right; the orchestrator should ideally use
lib/gbrain-sources.tsdirectly (a future refactor — not in this PR to keep the diff minimal).Suggested follow-up: contract test
Worth adding
test/contract/gbrain-cli.test.tsthat runs against a realgbrainbinary in CI (probably gated on aGSTACK_CONTRACT_TEST=1env var so unit tests stay fast). That would catch any future JSON shape drift between gstack and gbrain at PR time instead of in users' terminals. Happy to write this in a follow-up if the maintainer wants it.Test plan
bun test test/gstack-gbrain-sync.test.ts -t "sourceLocalPath"— 5/5 pass🤖 Generated with Claude Code