Skip to content

fix(local-inference): store container-relative model paths + self-heal legacy absolute registry entries (#11669) - #11700

Merged
lalalune merged 2 commits into
developfrom
fix/11669-registry-relative-paths
Jul 3, 2026
Merged

fix(local-inference): store container-relative model paths + self-heal legacy absolute registry entries (#11669)#11700
lalalune merged 2 commits into
developfrom
fix/11669-registry-relative-paths

Conversation

@lalalune

@lalalune lalalune commented Jul 2, 2026

Copy link
Copy Markdown
Member

Closes #11669

Root cause

local-inference/registry.json persisted 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:

  1. No existence verification / no persisted heal (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 in registry.json forever.
  2. The on-device full-Bun loader path was still broken (plugin-capacitor-bridge/src/mobile-device-bridge-bootstrap.ts): resolveFromRegistry / resolveAssignedRegistryModel did a verbatim existsSync(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.
  3. Android had the mirror-image gap (plugin-aosp-local-inference): mapExistingModelPath handled legacy absolute rows via the /local-inference/models/ suffix but not the new container-relative rows.

Fix (platform-neutral)

  • plugin-local-inference registry: 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-heals registry.json once — legacy absolute rows are rewritten in canonical container-relative form via the existing atomic tmp+rename writer. Also fixed hydration leaking the raw stored bundleRoot/manifestPath string when resolution fails.
  • New shared resolver 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/var alias); 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.
  • AOSP bootstrap (Android): mapExistingModelPath maps container-relative rows against the current device root.

Tests (container migration simulated by moving the root between write and read)

Suite Coverage
plugin-local-inference/src/services/registry.test.ts (8) moved-root reanchor + on-disk self-heal to relative form; dangling legacy absolute row → dropped from listing and file; deleted-artifact relative row → dropped; mixed registry keeps healthy row while healing
plugin-capacitor-bridge/src/shared/local-inference-stored-path.test.ts (10, new) relative resolve, dead-container re-anchor with the exact path shape from the issue, /private/var alias, traversal rejection, round-trip, absent → null
plugin-capacitor-bridge/src/mobile-device-bridge-bootstrap.registry-paths.test.ts (3, new) mobileDeviceBridge.status().modelPath resolves relative rows, re-anchors dead-container rows, reports null when genuinely absent
plugin-aosp-local-inference bootstrap tests (+2) readAssignedBundledModels resolves relative rows; absent artifact → null

Anti-larp negative check: temporarily reverted the three source files to origin/develop and 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

Evidence rows (PR_EVIDENCE.md)

  • Backend logs: structured [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.
  • Real-LLM trajectories: N/A — no agent/action/provider/prompt/model behavior change; server-side path resolution only.
  • Screenshots / video / frontend logs: N/A — no UI change; the user-visible effect (model loads instead of wedging) is exercised by the moved-root regression tests.
  • On-device iOS leg: honestly stated as gated on this branch — a live reinstall capture needs the full device bundle + 6.5 GB model download (capture:ios-sim lane). 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-sed of the UUID un-wedges the load with no other change, which is precisely the transformation the resolver now performs (exists-verified).
  • Domain artifacts: healed registry.json contents asserted in-tests (canonical relative rows on disk after list; dangling rows removed).

🤖 Generated with Claude Code

Shaw and others added 2 commits July 2, 2026 19:57
…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>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bc29b8b5-2534-47fd-a9f8-6861f7ff6757

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/11669-registry-relative-paths

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(local-inference): registry.json stores absolute app-container paths — model never loads after iOS container migration

1 participant