Skip to content

CS-11658: boot assembly from trusted servers via _realm-auth#5285

Draft
lukemelia wants to merge 3 commits into
cs-11655-add-realm-servers-event-typefrom
cs-11658-boot-assembly-trusted-servers
Draft

CS-11658: boot assembly from trusted servers via _realm-auth#5285
lukemelia wants to merge 3 commits into
cs-11655-add-realm-servers-event-typefrom
cs-11658-boot-assembly-trusted-servers

Conversation

@lukemelia

Copy link
Copy Markdown
Contributor

Summary

Replaces the "account data is the realm list" boot path with "account data is the list of trusted servers; ask each server which realms the user has." Stacked on top of #5284 (CS-11655) which introduced the app.boxel.realm-servers event type — this PR's base is the CS-11655 branch, so review only the diff added on top.

  • realm-server.ts — new fetchUserRealmsFromTrustedServers(serverURLs). Iterates the trusted-server URLs, POSTs _realm-auth on each, returns the union of realm URLs. Calls assertOwnRealmServer() to preserve the single-server invariant; multi-realm-server federation stays out of scope.
  • matrix-service.ts start() — reads APP_BOXEL_REALM_SERVERS_EVENT_TYPE in parallel with favorites, hands the result to fetchUserRealmsFromTrustedServers, and pipes the URLs into setAvailableRealmIdentifiers and initSlidingSync. fetchCatalogRealms() is unchanged.
  • Transition fallback — when app.boxel.realm-servers is empty/absent, the boot falls back to reading app.boxel.realms so existing users aren't broken before CS-11659's lazy migration runs on their account. The fallback is clearly marked for removal once that migration ships.

Acceptance criteria (from CS-11658)

  • Boot assembles the realm list from trusted servers via _realm-auth when the new key is populated.
  • Catalog realms still appear (fetchCatalogRealms() is untouched).
  • Single-server assertion (assertOwnRealmServer()) is preserved.

Notes

  • Depends on CS-11655: add app.boxel.realm-servers event type + read/write helpers #5284 (CS-11655) — merge that first; this PR will retarget to main automatically.
  • Graceful degradation when a trusted server is unreachable is the next ticket (CS-11667).
  • Lazy migration that populates app.boxel.realm-servers from the legacy key is CS-11659.
  • The runtime account-data event listener at matrix-service.ts:393 still reads from app.boxel.realms — out of scope for this issue (boot only).

Test plan

  • Typecheck and lint clean on the host package; prettier clean on touched files.
  • CI: host integration tests in matrix-service-boot-assembly-test.ts — boot from trusted servers, fetchUserRealmsFromTrustedServers unit behaviour (round-trip, empty input, non-own server rejection), and the legacy fallback.

🤖 Generated with Claude Code

ylm and others added 2 commits June 18, 2026 17:14
Replace the "account data is the realm list" boot path with "account
data is the list of trusted servers; ask each server which realms the
user has." Builds on CS-11655 which introduced the new
`app.boxel.realm-servers` account-data event type.

- realm-server: new fetchUserRealmsFromTrustedServers() iterates the
  trusted-server URLs, POSTs _realm-auth on each, and returns the
  union of realm URLs. Preserves the single-server invariant by
  calling assertOwnRealmServer() — multi-realm-server federation is
  out of scope for v1.
- matrix-service start(): reads APP_BOXEL_REALM_SERVERS_EVENT_TYPE in
  parallel with favorites and assembles user realms via the new
  helper. Hands the result to setAvailableRealmIdentifiers and
  initSlidingSync (replacing the direct read of app.boxel.realms).
  fetchCatalogRealms() is unchanged.
- Transition fallback: when app.boxel.realm-servers is absent or
  empty, the boot falls back to reading the legacy
  app.boxel.realms key so existing users aren't broken before
  CS-11659's lazy migration has run on their account. The fallback
  is clearly marked for removal once that migration ships.
- Tests: boot populates the realm list from the trusted-servers
  path; direct unit coverage of the new method (round-trip, empty
  input short-circuit, non-own server rejection); fallback module
  verifies the legacy path still works when realm-servers is empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Issue per-server _realm-auth requests concurrently via Promise.all,
then union the returned realm URLs. Failure semantics unchanged: the
first rejection still surfaces (graceful degradation is CS-11667).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lukemelia

Copy link
Copy Markdown
Contributor Author

[Codex] Finding: app.boxel.realms account-data events can still overwrite the new trusted-server boot result.

start() now derives userRealmURLs from app.boxel.realm-servers and _realm-auth (packages/host/app/services/matrix-service.ts:856-884), but the existing account-data listener still handles APP_BOXEL_REALMS_EVENT_TYPE by calling setAvailableRealmIdentifiers((e.event.content.realms as string[]).map(ri)) (same file:397-400). Since the listener is bound before startClient(), the initial Matrix sync can emit the existing legacy app.boxel.realms event after the new boot path has populated available realms. If that legacy event is stale or differs from _realm-auth, it will remove realms discovered from trusted servers or re-add stale legacy realms.

The new test does not catch this because its mock legacy activeRealms matches the _realm-auth result. Please either ignore/migrate legacy app.boxel.realms events when app.boxel.realm-servers is present, add handling for APP_BOXEL_REALM_SERVERS_EVENT_TYPE that recomputes via _realm-auth, or add a regression test where legacy realms differ from _realm-auth and verify the trusted-server result survives startClient().

Addresses the Codex review on PR #5285. The matrix sync triggered
by `startClient()` re-emits the existing `app.boxel.realms`
AccountData event, and the listener bound during `bindEventListeners`
was overwriting the trusted-servers boot result with the legacy
key's content.

- matrix-service: track `trustedRealmServersAuthoritative`. Boot
  sets it true when `app.boxel.realm-servers` has entries; the new
  realm-servers listener flips it on at runtime if the key gains
  content.
- Legacy `app.boxel.realms` listener: skip
  `setAvailableRealmIdentifiers` while the flag is true. Login side
  effects (loginToRealms, loadMoreAuthRooms) still run so
  authentication for new realms isn't dropped.
- New `app.boxel.realm-servers` listener: re-fetch via _realm-auth,
  call setAvailableRealmIdentifiers, then loginToRealms /
  loadMoreAuthRooms post-login. Natural runtime counterpart to the
  new boot path.
- Regression test: a setup where mock activeRealms = [] but
  realmPermissions advertises two realms via _realm-auth verifies
  both _realm-auth realms survive `startClient`'s synthetic event.
  Without the listener gating the test fails.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lukemelia

Copy link
Copy Markdown
Contributor Author

Good catch — fixed in 4bb2b12. The legacy app.boxel.realms listener was indeed clobbering the trusted-servers boot result via startClient()'s synthetic AccountData re-emit.

Changes:

  • New trustedRealmServersAuthoritative flag set during boot (true when app.boxel.realm-servers has entries) and at runtime by the new realm-servers listener.
  • Legacy app.boxel.realms listener now skips setAvailableRealmIdentifiers while the flag is true. loginToRealms / loadMoreAuthRooms still run so authentication for new realms isn't dropped.
  • New APP_BOXEL_REALM_SERVERS_EVENT_TYPE listener re-fetches via _realm-auth and updates the available-realms list — runtime counterpart to the new boot path.
  • Regression test where mock activeRealms = [] but realmPermissions advertises two realms via _realm-auth; both must survive startClient(). Without the gating it fails.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files      1 suites   1h 40m 57s ⏱️
3 108 tests 3 089 ✅ 15 💤 0 ❌ 4 🔥
3 127 runs  3 104 ✅ 15 💤 4 ❌ 4 🔥

Results for commit 4bb2b12.

For more details on these errors, see this check.

Realm Server Test Results

    1 files      1 suites   11m 55s ⏱️
1 425 tests 1 425 ✅ 0 💤 0 ❌
1 484 runs  1 484 ✅ 0 💤 0 ❌

Results for commit 4bb2b12.

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