Skip to content

feat(loader): resolve interface facades per consumer - #104

Closed
Upd4ting wants to merge 10 commits into
fix/require-interface-core-0.0.12from
fix/require-interface-core-0.0.13
Closed

feat(loader): resolve interface facades per consumer#104
Upd4ting wants to merge 10 commits into
fix/require-interface-core-0.0.12from
fix/require-interface-core-0.0.13

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Aug 21, 2026

Copy link
Copy Markdown
Member

Summary

  • preserve the declaration-only entry and CommonJS cache contract already validated on this branch
  • create and cache an interface facade for each consumer lifecycle generation
  • resolve both standalone interface roots and embedded interface subpaths through that facade
  • leave implementing provider modules on canonical declarations for singleton identity and hot-path performance
  • evict only the destroyed consumer's synthetic facades during unload/HMR
  • run interface package tests in the configured module context

Resolver behavior

The resolver already owns the mapping from a consumer to its selected providers. It now applies that mapping when Node resolves the consumer's interface import.

consumer require(interface)
  -> canonical declaration singleton
  -> consumer/generation facade
  -> bound InterfaceFunction
  -> selected provider

Application syntax stays unchanged. Providers still receive canonical declarations for ImplementInterface; classes, symbols, metadata, proxies, and callbacks preserve strict identity.

Bug reproduced

With two Auth providers, the old resolver returned the same canonical Auth module to both consumers. Direct calls could work while a lifecycle context was active, but Authentication() stored a parameter provider that ran later under API's provider context. That later ValidateRaw() call had no consumer provider route and failed with AmbiguousProviderError.

The integration regression builds two real consumer modules with different Auth importOverrides, registers real Auth and API decorators, waits across an async boundary, invokes both deferred parameter providers outside the consumers' lifecycle contexts, and proves results route to auth-provider-a and auth-provider-b. The registered HTTP callbacks remain strict-equal to the controller methods.

The self-implemented interface regression also imports ./interface-declarations through a consumer facade and proves delayed nested calls, reconstruction, HMR, and declaration identity.

Validation

  • pnpm lint (exit 0; two pre-existing warnings and one informational finding outside this diff)
  • pnpm build
  • Core unit/integration command exit 0
  • focused resolver, standalone Auth/API, embedded subpath, declaration lifecycle, and HMR tests: 6 passing
  • interface-core full tests: 81 passing
  • real API module suite through this Core: 94 passing
  • interface-auth facade regression passing
  • git diff --check

Performance

The resolver performs facade construction only during module resolution. Implementing provider modules stay canonical, request callbacks are not wrapped, and the historical AsyncProxy.call() attached-provider path is unchanged.

An isolated A/B HTTP gate (Node 24.19.0, pinned server CPU, 8 repetitions, 8-second samples) measured +1.15% JSON c100, +2.46% dynamic routes, +1.68% POST echo, and -0.36% on the last of 1,000 routes. This shows no attributable steady-state regression; the rejected callback-wrapper branch measured roughly -8% to -14%.

CI and release ordering

The stock Ubuntu install remains expected to fail until unpublished @antelopejs/interface-core@0.0.13 (or its final next release version) exists in the registry. Do not work around that provenance gate in the lockfile.

Merge/release order starts with interface-core #12, then this Core PR, then interface-api #17 and interface-auth. No package is published by this PR.

Copy link
Copy Markdown
Member Author

@greptileai review current HEAD 90cc407. Verify runtime optional RegisteringProxy stubs remain providerless, explicit TestModule stubs attach route-aware no-op handlers only for stubbed interfaces, provider-consumer registrations replay and unload cleanly, and AsyncProxy behavior remains unchanged.

Copy link
Copy Markdown
Member Author

@greptileai review current HEAD 3edd84a. Verify TestModule explicit RegisteringProxy stub leases remain route-aware through owned-entry unregister, are detached during manager teardown, cannot accept a same-route registration in a later manager/process phase, and report no teardown errors. Also verify runtime optional RegisteringProxy remains providerless, replay/ownership/unload semantics remain intact, unrelated RegisteringProxy still fails, and AsyncProxy stubs still reject.

Upd4ting added 2 commits August 21, 2026 22:24
Resolve self-implemented interface proxies through a dedicated declaration-only package entry so graph preparation cannot evaluate application lifecycle side effects outside module ownership.

Copy link
Copy Markdown
Member Author

@greptileai review current HEAD 4ef985b. Verify self-implemented interface graph discovery resolves only the canonical ./interface-declarations subpath and never evaluates the application main during addModules; external declaration-only interface packages retain root fallback; the declaration path cannot escape its canonical package; provider-route identities cover canonical public subpath proxies; side-effectful registrations load under lifecycle generation ownership, nested callbacks retain provider context, generation destroy leaves zero stale replay; early RegisteringProxy registrations replay and unregister on the exact future provider without consumer-route fallback; no DEFAULT_PROVIDER fallback, selectProvider weakening, or unregisterModule cleanup was introduced. Review the declaration-closure documentation and the deterministic RED/GREEN regressions. Ignore the expected CI install 404 for unpublished @antelopejs/interface-core@0.0.13.

Copy link
Copy Markdown
Member Author

@greptile review

Co-authored-by: Upd4ting <upd4ting@gmail.com>
@Upd4ting Upd4ting changed the title fix(runtime): require context binding interface feat(loader): resolve interface facades per consumer Aug 25, 2026

Copy link
Copy Markdown
Member Author

Closed at Upd4ting's request: the Core 1.5 / multi-provider train is deferred and will be restarted manually later. This PR contains only work for that train; no independent fix is being retained. Do not merge or publish artifacts from this branch. Any future implementation should start from the then-current main branches and released package graph.

@Upd4ting Upd4ting closed this Aug 27, 2026
@Upd4ting
Upd4ting deleted the fix/require-interface-core-0.0.13 branch August 27, 2026 21:14
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.

2 participants