fix(local-inference): store container-relative model paths + self-heal legacy absolute registry entries (#11669) - #11700
Conversation
…l legacy absolute registry entries iOS rotates the app data-container UUID on every reinstall/update, so any absolute path persisted in local-inference/registry.json dangles after a migration even though the model bytes migrated fine — the loader never finds the model and the app wedges on 'Loading Eliza-1 2B…' (#11669). Registry rows are persisted container-relative (since #11371); this closes the remaining gaps: - plugin-local-inference registry: listInstalledModels() now verifies the model artifact actually exists at the hydrated path, drops rows whose file is genuinely absent (surfacing the real not-downloaded state), and self-heals registry.json once — legacy absolute rows are rewritten in canonical container-relative form. Hydration no longer leaks a raw stored bundleRoot/manifestPath string when resolution fails. - plugin-capacitor-bridge mobile-device-bridge-bootstrap: registry-backed model resolution (resolveFromRegistry / resolveAssignedRegistryModel) resolved stored rows verbatim with existsSync, so BOTH the new relative rows and legacy dead-container absolute rows failed and the bootstrap fell through to re-downloading a model already on disk. Rows now resolve through a shared stored-path resolver (relative → current root; legacy absolute → re-anchored by /local-inference/ suffix; exists-verified). - plugin-capacitor-bridge ios/bridge: dedupe its local stored-path logic into the shared resolver (behavior preserved, fs-sandbox probe injected). - plugin-aosp-local-inference (Android): mapExistingModelPath only handled legacy absolute rows; container-relative rows now map against the current device root, keeping the fix platform-neutral. Closes #11669 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Closes #11669
Root cause
local-inference/registry.jsonpersisted absolute app-container paths. iOS rotates the data-container UUID on every reinstall/update, so the persisted prefix dies while the model bytes migrate fine — the loader never finds the 6.5 GB bundle and the app wedges on "Loading Eliza-1 2B…".#11371 (67c2b7b, landed earlier today) made the canonical registry store container-relative rows and re-anchor legacy absolute rows at hydrate time — but left three gaps that this PR closes:
plugin-local-inference/src/services/registry.ts): hydration re-anchored blindly, returning "installed" rows whose file may not exist, and the legacy absolute strings stayed inregistry.jsonforever.plugin-capacitor-bridge/src/mobile-device-bridge-bootstrap.ts):resolveFromRegistry/resolveAssignedRegistryModeldid a verbatimexistsSync(matched.path)on the stored string — so both the new relative rows (models/…probed against cwd) and legacy dead-container absolute rows failed, and the bootstrap fell through to re-downloading a model already fully on disk.plugin-aosp-local-inference):mapExistingModelPathhandled legacy absolute rows via the/local-inference/models/suffix but not the new container-relative rows.Fix (platform-neutral)
plugin-local-inferenceregistry:listInstalledModels()verifies the model artifact exists at the hydrated path, drops rows whose file is genuinely absent (structured[LocalInferenceRegistry]warn → readiness/UI surface the real not-downloaded state; no silent fallback), and self-healsregistry.jsononce — legacy absolute rows are rewritten in canonical container-relative form via the existing atomic tmp+rename writer. Also fixed hydration leaking the raw storedbundleRoot/manifestPathstring when resolution fails.plugin-capacitor-bridge/src/shared/local-inference-stored-path.ts: relative rows join the CURRENT root; legacy absolute rows re-anchor by their/local-inference/suffix (plus the simulator/private/var↔/varalias); every candidate is exists-verified; traversal rejected. Exists-probe injectable so the iOS stdio bridge keeps probing through the mobile fs sandbox proxy.ios/bridge.ts: deduped its local copy of the same logic into the shared resolver (behavior preserved).mobile-device-bridge-bootstrap.ts: registry-backed model resolution goes through the shared resolver.mapExistingModelPathmaps container-relative rows against the current device root.Tests (container migration simulated by moving the root between write and read)
plugin-local-inference/src/services/registry.test.ts(8)plugin-capacitor-bridge/src/shared/local-inference-stored-path.test.ts(10, new)/private/varalias, traversal rejection, round-trip, absent → nullplugin-capacitor-bridge/src/mobile-device-bridge-bootstrap.registry-paths.test.ts(3, new)mobileDeviceBridge.status().modelPathresolves relative rows, re-anchors dead-container rows, reports null when genuinely absentplugin-aosp-local-inferencebootstrap tests (+2)readAssignedBundledModelsresolves relative rows; absent artifact → nullAnti-larp negative check: temporarily reverted the three source files to
origin/developand re-ran the new tests — bootstrap 2/3 failed, registry 4/8 failed, AOSP relative-row failed (exactly the fixed bugs). Restored; all green.Verification
bunx vitest run --root plugins/plugin-local-inference→ 2272 passed / 13 skipped; 1 failure is pre-existing on pristineorigin/developon this host (imagegen CUDA-proof env test, unrelated).bunx vitest run --root plugins/plugin-capacitor-bridge→ 48 passed; 2 failures pre-existing on macOS (abstract\0sockets are Linux-only; identical on pristine develop).bun run --cwd plugins/plugin-aosp-local-inference test→ 75 pass / 0 fail.typecheck+buildpass for all three plugins; biome clean on all touched files.downloader.test.ts,local-inference-routes.test.ts,ensure-local-artifacts.test.tsall pass (40/40); the sidecars are path-adjacent files and unaffected.Evidence rows (PR_EVIDENCE.md)
[LocalInferenceRegistry]warn/info fire on drop/heal (asserted paths exercised by the tests above); evidence doc.github/issue-evidence/11669-registry-relative-self-heal.md.capture:ios-simlane). The container-UUID rotation state transition (same bytes, new root) is exercised directly by the moved-root tests; the original issue also confirmed a hand-sedof the UUID un-wedges the load with no other change, which is precisely the transformation the resolver now performs (exists-verified).registry.jsoncontents asserted in-tests (canonical relative rows on disk after list; dangling rows removed).🤖 Generated with Claude Code