Skip to content

fix: address lazy loading followups#1068

Merged
stack72 merged 1 commit intomainfrom
worktree-followups
Apr 2, 2026
Merged

fix: address lazy loading followups#1068
stack72 merged 1 commit intomainfrom
worktree-followups

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented Apr 2, 2026

Summary

Fixes three issues identified in post-merge review of #1063 (lazy per-bundle loading):

  • skipAlreadyRegistered missing on bootstrap pathbuildIndex() full-import fallback now passes skipAlreadyRegistered: true, preventing failures when user extensions shadow built-in type names during first-run catalog bootstrap.
  • typeLoadPromises never pruned on success — Resolved promises are now deleted from the map in the .then() handler. Removes the dead lazyTypes.delete(key) call that duplicated promoteFromLazy() cleanup.
  • Classification comment in populateCatalogFromDir — Added clarifying comment explaining that extension-takes-priority matches the loader's own if/else if semantics and that the exports are mutually exclusive by design.

Test Plan

  • All 4047 existing tests pass (including 51 model registry + 45 user model loader tests)
  • deno check, deno lint, deno fmt all clean

🤖 Generated with Claude Code

…pruning, comments

- Pass skipAlreadyRegistered: true in buildIndex full-import fallback so
  user extensions that shadow built-in type names don't fail on first-run
  bootstrap.
- Prune resolved promises from typeLoadPromises in the success handler
  instead of keeping them forever; remove dead lazyTypes.delete call
  that duplicated promoteFromLazy cleanup.
- Add clarifying comment on extension-takes-priority classification in
  populateCatalogFromDir explaining it matches the loader's if/else if
  semantics.
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Code Review

Blocking Issues

None.

Suggestions

None.

Clean, well-scoped bugfix. All three changes are correct:

  1. Promise pruning (model.ts) — The old .then() handler called this.lazyTypes.delete(key) (duplicating promoteFromLazy()) while never pruning typeLoadPromises, causing unbounded map growth. The fix correctly deletes the resolved promise, matching the existing .catch() cleanup pattern.

  2. skipAlreadyRegistered on bootstrap path (user_model_loader.ts) — The buildIndex() full-import fallback now passes skipAlreadyRegistered: true, preventing failures when user extensions shadow built-in type names during first-run bootstrap. This brings the fallback path in line with the lazy-load path.

  3. Clarifying comment in populateCatalogFromDir — Explains the extension-takes-priority classification and mutual exclusivity of exports. Appropriate context for a best-effort regex.

No DDD concerns — changes are internal to the ModelRegistry aggregate and UserModelLoader domain service. No libswamp import boundary violations. No new public behavior requiring additional tests.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Adversarial Review

Critical / High

None.

Medium

None.

Low

  1. model.ts:779-784.then() handler deletes from typeLoadPromises before the outer await resumes: Between the .then() microtask and the resumption of the await at line 791, a concurrent caller could call ensureTypeLoaded for the same key, see this.models.has(key) as true (because promoteFromLazy already ran during the loader), and return early — which is correct. However, if the loader ever resolved without calling promoteFromLazy, the promise would be pruned and lazyTypes would still have the entry, causing an infinite retry loop. This is actually better than the old behavior (which deleted from lazyTypes and silently lost the type), and the production type loader always calls promoteFromLazy via loadSingleType, so this is purely theoretical.

Verdict

PASS — All three changes are correct. The typeLoadPromises leak fix is the substantive change; the old code deleted from lazyTypes (already handled by promoteFromLazy) instead of cleaning up the resolved promise. The skipAlreadyRegistered addition on the bootstrap path correctly prevents collisions when user extensions shadow built-in types during first-run catalog bootstrap. The comment addition is accurate.

@stack72 stack72 merged commit 4e29cd6 into main Apr 2, 2026
10 checks passed
@stack72 stack72 deleted the worktree-followups branch April 2, 2026 19:52
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