Skip to content

Change dependency tracker to use canonical RRI form - #5776

Open
backspace wants to merge 7 commits into
mainfrom
cs-12212-tracker-rri-native-v2
Open

Change dependency tracker to use canonical RRI form#5776
backspace wants to merge 7 commits into
mainfrom
cs-12212-tracker-rri-native-v2

Conversation

@backspace

Copy link
Copy Markdown
Contributor

Previously it was converting everything to a URL first, now it can handle prefix RRIs.

Claude’s explanationThe dependency tracker's `canonicalURL` guard dropped any identifier without an `http(s)` scheme, so prefix-form identifiers could not be tracked at all. Every caller therefore converted to a URL first: `card-api` through `Loader.dependencyTrackingKey`, and the loader internally through `canonicalizeTrackingKey`, which folded each module onto its virtual-alias URL. The forms were then converted back — three of the four snapshot consumers run the deps through `unresolveURLs`, and the index writer folds them again before persisting. The tracker was a URL-form island inside an RRI-form pipeline.

Accept both canonical remote forms in the guard instead. A URL starts with http:///https:// and a prefix-form RRI starts with @, which distinguishes them without a VirtualNetwork — the same syntactic test isLocalId uses — so the tracker stays free of realm mappings. Bare specifiers, relative references and other schemes are still dropped.

That lets the conversions go:

  • card-api records identity.module and the loader's consumed-module list as they are, both already canonical RRI.
  • The loader's two internal tracking calls use moduleCacheKey, the same fold its module cache uses, so a module's dependency identity and its class identity are one key and cannot diverge.
  • dependencyTrackingKey and canonicalizeTrackingKey are removed.

Deps on disk are unchanged: they were already normalized to prefix form by the index writer, which now finds them in that form to begin with. The unresolveURLs calls at the snapshot consumers are left in place — they also normalize deps from other sources merged into the same arrays.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Host Test Results

    1 files      1 suites   2h 25m 8s ⏱️
4 309 tests 4 295 ✅ 14 💤 0 ❌
4 328 runs  4 314 ✅ 14 💤 0 ❌

Results for commit 2f89811.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   16m 30s ⏱️ +8s
2 192 tests ±0  2 192 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 275 runs  ±0  2 275 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 2f89811. ± Comparison against earlier commit a6314e6.

@backspace
backspace force-pushed the cs-12212-tracker-rri-native-v2 branch from 3aa3933 to 7ce848a Compare August 17, 2026 13:41
@backspace
backspace changed the base branch from main to matrix-realm-server-start-cap August 17, 2026 13:46
backspace and others added 3 commits August 17, 2026 16:14
The dependency tracker's `canonicalURL` guard dropped any identifier without an
`http(s)` scheme, so prefix-form identifiers could not be tracked at all. Every
caller therefore converted to a URL first: `card-api` through
`Loader.dependencyTrackingKey`, and the loader internally through
`canonicalizeTrackingKey`, which folded each module onto its virtual-alias URL.
The forms were then converted back — three of the four snapshot consumers run
the deps through `unresolveURLs`, and the index writer folds them again before
persisting. The tracker was a URL-form island inside an RRI-form pipeline.

Accept both canonical remote forms in the guard instead. A URL starts with
`http://`/`https://` and a prefix-form RRI starts with `@`, which distinguishes
them without a VirtualNetwork — the same syntactic test `isLocalId` uses — so
the tracker stays free of realm mappings. Bare specifiers, relative references
and other schemes are still dropped.

That lets the conversions go:

- `card-api` records `identity.module` and the loader's consumed-module list as
  they are, both already canonical RRI.
- The loader's two internal tracking calls use `moduleCacheKey`, the same fold
  its module cache uses, so a module's dependency identity and its class
  identity are one key and cannot diverge.
- `dependencyTrackingKey` and `canonicalizeTrackingKey` are removed.

Deps on disk are unchanged: they were already normalized to prefix form by the
index writer, which now finds them in that form to begin with. The
`unresolveURLs` calls at the snapshot consumers are left in place — they also
normalize deps from other sources merged into the same arrays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`moduleCacheKey` folds a module onto its canonical RRI, which is right for a
realm reached through a registered prefix but wrong for one that has only a URL
mapping: `unresolveURL` maps an alias *to* the real URL and never back, so a
module in such a realm was recorded under the host actually serving it rather
than the alias the index names it by. In CI that meant a dep on
`https://realm-test.ci.localhost/test/person` where every index row says
`https://localhost:4202/test/person` — a dep no invalidation scan can match.

Give tracking its own fold: canonical RRI when a prefix mapping claims the
module, the virtual alias when only a URL mapping does. The module cache keeps
`moduleCacheKey`, which needs internal consistency rather than agreement with
the index, and the two requirements are not the same.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dependency walk re-derives a tracking key for every module in a root's
transitive set on every import of that root, so a realm's modules are folded
repeatedly during a from-scratch index — and the url-mapped branch allocates a
URL each time. Cache the result per module identifier.

Cleared alongside the other mapping-derived caches when a realm mapping is
added or removed, since the key is only stable between those changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@backspace
backspace force-pushed the cs-12212-tracker-rri-native-v2 branch from 7ce848a to 359b9a1 Compare August 17, 2026 20:21
@backspace
backspace changed the base branch from matrix-realm-server-start-cap to main August 17, 2026 20:21
@backspace
backspace marked this pull request as ready for review August 20, 2026 01:23

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f89811e59

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

!url ||
(!url.startsWith('http://') &&
!url.startsWith('https://') &&
!url.startsWith('@'))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exclude RRI spellings of the session root

When a prefix-mapped card is prerendered, packages/host/app/routes/render.ts starts the tracking session with the URL-form route id, while deserialization and field contexts in card-api.gts use the canonical RRI-form resource.id or instance.id as their consumer. Admitting @... here causes #normalizeConsumer to record that same root under its RRI spelling, but #rootCandidates only excludes string-equivalent URL/.json variants, so the rendered row is emitted as its own dependency. Normalize roots and consumers to the same form, or make root exclusion recognize both spellings.

Useful? React with 👍 / 👎.

Comment on lines +923 to +925
let cached = this.trackingKeyCache.get(moduleIdentifier);
if (cached !== undefined) {
return cached;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Invalidate cached tracking keys for URL mappings

If VirtualNetwork.addURLMapping() is called after this loader has already derived a key, this cache continues returning the pre-mapping real URL instead of the newly available virtual alias. addURLMapping() clears the VirtualNetwork's own mapping caches but does not call notifyMappingChange(), so the loader's onMappingChange subscription never clears trackingKeyCache; subsequent cache-hit imports can therefore persist a dependency spelling that invalidation will not find. Either notify loaders about URL-mapping changes or avoid retaining alias-derived keys across them.

Useful? React with 👍 / 👎.

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