feat: add boxel realm archive / restore + archived state in realm list (CS-11671)#5365
feat: add boxel realm archive / restore + archived state in realm list (CS-11671)#5365lukemelia wants to merge 2 commits into
boxel realm archive / restore + archived state in realm list (CS-11671)#5365Conversation
…m list` - `archive <realm-url>` posts to `/_archive-realm` (owner-only, with a TTY confirmation step and a `-y` skip flag), `restore <realm-url>` posts to `/_unarchive-realm` (the server-side handler also enqueues a full reindex). - `list` calls `_archived-realms` only when `--include-archived` is set; `RealmSummary` gains an `archived` flag so JSON consumers and the TTY output can both surface the marker. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The branch was cut before the sibling archive PRs (#5353 _archived-realms, #5358 _realm-auth archived exclusion / CS-11665) merged, so it carried an older realm-server that did not omit archived realms from fetchUserPermissions. With that exclusion absent, _realm-auth still enumerated archived realms as archived:false, and `boxel realm list` deduped the _archived-realms entries against them — leaving the archived marker off and breaking the three realm-list-archived integration tests. Merging main restores the exclusion (and the rest of main's archive-server work this branch had reverted).
There was a problem hiding this comment.
Pull request overview
This PR adds CLI support for realm archive/restore and improves how archived realms are surfaced (and enforced) across the stack, alongside a larger set of related platform changes: archived-realm request sealing in runtime-common, RRI/canonical-id handling improvements, searchable-annotation validation + tooling, and tightening “data-test selector” usage in production code and templates.
Changes:
- Add
boxel realm archive/boxel realm restoreand extendboxel realm listwith--include-archived, includingRealmSummary.archived. - Enforce “archived realm sealing” at the runtime-common realm boundary and expose an explicit archived marker (header + JSON:API error code) to clients.
- Add canonical-RRI resolution utilities and broaden tests + linting/templating guardrails (including banning
data-test-*selectors for production behavior/styling).
Reviewed changes
Copilot reviewed 151 out of 153 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/template-lint/plugin.mjs | Adds test-file overrides to disable the no-data-test-selector template-lint rule for tests. |
| packages/template-lint/lib/no-data-test-selector.mjs | Expands the rule messaging and adds detection for [data-test-*] usage inside <style> text nodes. |
| packages/software-factory/tests/issue-loop.test.ts | Adds unit coverage for a new onBootstrapComplete hook behavior. |
| packages/software-factory/tests/index.ts | Registers new software-factory test modules. |
| packages/software-factory/tests/factory-seed.test.ts | Adds unit tests for post-bootstrap linking of seed issue → Project relationship. |
| packages/software-factory/src/issue-scheduler.ts | Refactors issue-tracker module URL inference into a shared helper. |
| packages/software-factory/src/issue-loop.ts | Introduces onBootstrapComplete hook and fires it after successful bootstrap completion. |
| packages/software-factory/src/factory-seed.ts | Adds linkProjectToSeedIssue to patch the seed issue once Project exists in the index. |
| packages/software-factory/src/factory-realm-index.ts | New module to write a RealmDashboard index and link the board relationship after bootstrap. |
| packages/software-factory/src/factory-issue-loop-wiring.ts | Threads onBootstrapComplete through factory wiring config. |
| packages/software-factory/src/factory-entrypoint.ts | Wires bootstrap artifacts early (hook) + backstop retry; writes dashboard index for newly created realms. |
| packages/software-factory/realm/test-results.gts | Fixes template arg usage (@model) for skipped count rendering. |
| packages/software-factory/realm/empty-state.gts | Adds a shared EmptyState hero component for bootstrapping/empty dashboards. |
| packages/software-factory/realm/document.gts | Fixes a malformed template-lint disable directive. |
| packages/software-factory/README.md | Updates docs to include dashboard/index artifacts and module responsibilities. |
| packages/software-factory/package.json | Adds ember-template-lint dependency and new lint scripts for realm templates. |
| packages/software-factory/docs/architecture.md | Updates architecture diagram to include dashboard write + bootstrap artifact linking. |
| packages/software-factory/.template-lintrc.cjs | Enables template linting with the shared template-lint plugin. |
| packages/runtime-common/url.ts | Adds resolveRRIReference() for mapping-free resolution in RRI space. |
| packages/runtime-common/router.ts | Introduces ArchivedRealmError for archived realm request boundary failures. |
| packages/runtime-common/realm.ts | Seals archived realms at the request boundary (403 + archived marker), with exempt operational endpoints. |
| packages/runtime-common/index.ts | Adds searchable-path diagnostics types and simplifies isLocalId() semantics for canonical RRI. |
| packages/runtime-common/index-query-engine.ts | Expands reference-filter in values to equivalent URL forms when given prefix-form RRIs. |
| packages/runtime-common/definitions.ts | Persists raw searchable annotations in field definitions and adds validation helper for annotation paths. |
| packages/runtime-common/db-queries/realm-permission-queries.ts | Adds includeArchived option and excludes archived realms by default. |
| packages/runtime-common/create-response.ts | Exposes the X-Boxel-Realm-Archived header for browser clients. |
| packages/realm-server/tests/server-endpoints/archive-realm-test.ts | Adds coverage that archiving cancels pending indexing jobs for the realm. |
| packages/realm-server/tests/searchable-parity-diff-test.ts | Adds unit tests for searchable parity diff logic (pure comparison utilities). |
| packages/realm-server/tests/search-entries-engine-test.ts | Adds coverage for canonical-RRI id filtering + an overmatch guard for non-reference url fields. |
| packages/realm-server/tests/realm-auth-test.ts | Ensures _realm-auth omits archived realms and includes them again after restore. |
| packages/realm-server/tests/queries-test.ts | Adds tests for excluding archived realms by default and for includeArchived. |
| packages/realm-server/tests/prerender-diagnostics-persistence-test.ts | Ensures prerender timing decoration merges diagnostics rather than replacing them. |
| packages/realm-server/tests/index.ts | Registers new tests including archived sealing coverage and parity diff tests. |
| packages/realm-server/tests/full-reindex-test.ts | Adds coverage that full-reindex sweep excludes archived realms via new helper. |
| packages/realm-server/tests/definition-lookup-test.ts | Adds coverage that searchable diagnostics/annotations persist into modules.* rows. |
| packages/realm-server/scripts/codemod/searchable/republish.mjs | Adds a codemod helper to republish pairs and assert searchable annotations land. |
| packages/realm-server/scripts/codemod/searchable/realm-list.mjs | Adds helper to list deployed realms with annotated defs (excluding repo-handled realms). |
| packages/realm-server/scripts/codemod/searchable/README.md | Documents searchable migration codemod pipeline and usage. |
| packages/realm-server/scripts/codemod/searchable/derive-stream.ts | Adds NDJSON stdin derivation entrypoint for searchable inference from stored docs. |
| packages/realm-server/prerender/render-settlement.ts | Fixes diagnostics merge semantics when stamping prerender timing metadata. |
| packages/realm-server/package.json | Adds deps and scripts for searchable codemod and stable stringify. |
| packages/realm-server/lib/full-reindex-realm-urls.ts | New helper to return only active (non-archived) realms for sweep indexing. |
| packages/realm-server/handlers/handle-archive-realm.ts | Cancels realm indexing jobs when archiving a realm. |
| packages/matrix/tests/registration-with-token.spec.ts | Adds UI assertions for validation indicators before registering. |
| packages/matrix/helpers/index.ts | Updates expected registration copy to match punctuation changes. |
| packages/host/tests/unit/url-test.ts | Adds unit coverage for resolveRRIReference(). |
| packages/host/tests/unit/code-ref-test.ts | Adds coverage for resolving CodeRefs against prefix-form RRI bases. |
| packages/host/tests/integration/components/card-info-thumbnail-picker-test.gts | Updates expectations for new “Theme & Thumbnail” label behavior. |
| packages/host/tests/helpers/indexer.ts | Updates test helper serialization calls to new serializeCard signature. |
| packages/host/tests/helpers/index.gts | Updates saved-card helper serialization calls to new serializeCard signature. |
| packages/host/tests/helpers/base-realm.ts | Exposes searchable generator + updates serialize wrappers to no longer require VN injection. |
| packages/host/tests/helpers/adapter.ts | Updates TestRealmAdapter serialization to match new API. |
| packages/host/tests/acceptance/prerender-module-test.gts | Adds acceptance coverage for searchable-path diagnostics in module prerender meta. |
| packages/host/tests/acceptance/interact-submode-creation-and-permissions-test.gts | Updates to new isLocalId() signature in assertions. |
| packages/host/scripts/check-memory-baseline.mjs | Adjusts baseline logic to use a “ceiling” for hard failure gating. |
| packages/host/app/templates/loading.gts | Switches to a Glimmer component template to conditionally apply a dark auth palette at boot. |
| packages/host/app/services/store.ts | Updates isLocalId() call sites and serialization opts; keeps URL-form keying decisions. |
| packages/host/app/services/spec-panel-service.ts | Updates isLocalId() call sites for selection behavior. |
| packages/host/app/services/render-service.ts | Updates id normalization to match new isLocalId() behavior and serialization options. |
| packages/host/app/services/recent-cards-service.ts | Updates isLocalId() call sites. |
| packages/host/app/services/playground-panel-service.ts | Updates isLocalId() call sites. |
| packages/host/app/services/operator-mode-state-service.ts | Updates isLocalId() call sites and serialization behavior. |
| packages/host/app/services/card-service.ts | Updates serializeCard opts type threading (no VN required). |
| packages/host/app/routes/render/meta.ts | Removes VN from serialize options and keeps explicit reference normalization. |
| packages/host/app/routes/module.ts | Adds searchable annotation validation and persists findings via module render meta diagnostics. |
| packages/host/app/lib/gc-card-store.ts | Updates isLocalId() call sites for local/remote id handling. |
| packages/host/app/components/operator-mode/code-submode/spec-preview.gts | Updates isLocalId() checks for spec navigation. |
| packages/host/app/components/matrix/auth-form-field.gts | Adds a shared auth form field wrapper component with scoped styling. |
| packages/host/app/components/matrix/auth-container.gts | Restyles auth container to a dark theme and introduces shared auth CSS variables. |
| packages/host/app/components/matrix/auth-button.gts | Adds a shared auth button component with variants and scoped styling. |
| packages/host/app/commands/copy-and-edit.ts | Updates serialization to no longer depend on VN injection. |
| packages/host/.eslintrc.js | Re-declares the data-test selector ban for app code in a root-scoped eslint config. |
| packages/experiments-realm/trip-info.gts | Adds searchable annotations to relationships/contains fields. |
| packages/experiments-realm/transaction.gts | Adds searchable annotations to relationship fields. |
| packages/experiments-realm/task.gts | Adds searchable annotations to relationship fields. |
| packages/experiments-realm/sprint-task.gts | Adds searchable annotations to relationships and preserves isUsed where needed. |
| packages/experiments-realm/sprint-planner.gts | Adds searchable annotation to the project relationship. |
| packages/experiments-realm/shopping-cart.gts | Adds searchable annotations to relationship fields. |
| packages/experiments-realm/product.gts | Removes production CSS reliance on data-test selectors and adds searchable annotations. |
| packages/experiments-realm/post.gts | Adds searchable annotations for relationship traversal. |
| packages/experiments-realm/polymorphic-field.gts | Adds searchable annotation to a linksToMany relationship. |
| packages/experiments-realm/pickup-games-scheduler.gts | Adds searchable annotation to linksToMany relationship. |
| packages/experiments-realm/pet-person.gts | Adds searchable annotations to relationship fields. |
| packages/experiments-realm/person.gts | Adds searchable annotations to relationship/contains fields. |
| packages/experiments-realm/markdown-skill.gts | Adds searchable annotation to instructionsSource link. |
| packages/experiments-realm/llm-model-environment/environment.gts | Adds extensive searchable annotations for deeply-nested relationships. |
| packages/experiments-realm/image-def-playground.gts | Adds searchable annotations to image relationships. |
| packages/experiments-realm/friends.gts | Adds searchable annotation to friends relationship. |
| packages/experiments-realm/friend.gts | Adds searchable annotation to self-referential link. |
| packages/experiments-realm/file-links-example.gts | Adds searchable annotations to file relationships. |
| packages/experiments-realm/exchange-rate.gts | Fixes import to type-only and adds searchable annotations to links. |
| packages/experiments-realm/dnd.gts | Adds searchable annotations to relationships and nested relationship routes. |
| packages/experiments-realm/crm/task.gts | Adds searchable annotations to CRM relationships. |
| packages/experiments-realm/crm/deal.gts | Adds searchable annotations to CRM relationships and reformats a computed getter. |
| packages/experiments-realm/crm/deal-event.gts | Adds searchable annotation to assignee relationship. |
| packages/experiments-realm/crm/contact.gts | Adds searchable annotations to CRM relationships. |
| packages/experiments-realm/crm/company.gts | Adds searchable annotation to crmApp relationship. |
| packages/experiments-realm/crm/account.gts | Adds searchable annotations to CRM relationships and reformats a computed getter. |
| packages/experiments-realm/booking.gts | Adds searchable annotation to hosts linksToMany. |
| packages/experiments-realm/blog-post.gts | Adds searchable annotations to blog relationships and related links. |
| packages/experiments-realm/blog-category.gts | Adds searchable annotation while preserving isUsed. |
| packages/experiments-realm/author.gts | Adds searchable annotation while preserving isUsed. |
| packages/experiments-realm/atom-examples.gts | Adds searchable annotations to example relationships. |
| packages/experiments-realm/adorn-overflow-demo.gts | Adds searchable annotations to linksToMany fields. |
| packages/catalog/.eslintrc.cjs | Adds shared data-test selector ban for content code and an override to allow it in tests. |
| packages/boxel-ui/test-app/.eslintrc.js | Re-declares data-test selector ban for app code in a root-scoped eslint config. |
| packages/boxel-ui/addon/src/icons/google-color.gts | Adds generated Google brand icon component. |
| packages/boxel-ui/addon/src/icons.gts | Registers and exports the new GoogleColor icon. |
| packages/boxel-ui/addon/src/components/tabbed-header/index.gts | Avoids functional reliance on data-test attributes; improves header theming vars and optional title rendering. |
| packages/boxel-ui/addon/raw-icons/google-color.svg | Adds raw SVG source for Google brand icon. |
| packages/boxel-ui/addon/.eslintrc.cjs | Re-declares data-test selector ban for addon source in a root-scoped eslint config. |
| packages/boxel-cli/tests/integration/realm-list.test.ts | Updates list integration assertions for archived: false default. |
| packages/boxel-cli/tests/integration/realm-list-archived.test.ts | Adds integration coverage for hiding archived realms by default and showing them with --include-archived. |
| packages/boxel-cli/tests/integration/realm-archive.test.ts | Adds integration coverage for archive/restore happy path and non-owner 403 behavior. |
| packages/boxel-cli/src/commands/realm/restore.ts | Adds realm restore command implementation (POST /_unarchive-realm). |
| packages/boxel-cli/src/commands/realm/list.ts | Adds archived to realm summaries and --include-archived flag behavior. |
| packages/boxel-cli/src/commands/realm/index.ts | Registers new archive and restore subcommands. |
| packages/boxel-cli/src/commands/realm/archive.ts | Adds realm archive command with TTY confirmation and --yes. |
| packages/base/system-card.gts | Adds searchable annotations for model configuration links. |
| packages/base/skill-set.gts | Adds searchable annotations to nested skill references. |
| packages/base/skill-plus.gts | Adds searchable annotation for markdown instruction source link. |
| packages/base/default-templates/card-info.gts | Avoids production styling relying on data-test attrs; updates copy to “Theme & Thumbnail” when applicable. |
| packages/base/card-serialization.ts | Removes VN requirement from serialization and resolves references in RRI space via resolveRRIReference. |
| eslint/data-test-selectors.cjs | Centralizes shared no-restricted-syntax selectors for banning [data-test-*] selectors. |
| .eslintrc.js | Switches to the centralized DATA_TEST_SELECTORS definition. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| summaries = summaries.filter((r) => !r.hidden); | ||
| } | ||
|
|
||
| if (options.includeArchived) { |
There was a problem hiding this comment.
--include-archived failure replaces entire realm. When the archived-realms lookup fails (e.g. 403 for non-owner), the response is { realms: [], error: "..." }. this wipes out the normal realm list entirely. A non-owner running boxel realm list --include-archived gets no realms back at all, just an error.
Summary
CLI parity for the archive/restore feature, plus surfacing archived state in
boxel realm list. Resolves CS-11671.boxel realm archive <realm-url>→POST /_archive-realm. Owner-only (server returns 403 for non-owners with a clear surfaced message). TTY confirmation step,-y / --yesto skip. Same programmatic shape asremoveRealm— returns a result object on every path, never callsprocess.exit.boxel realm restore <realm-url>→POST /_unarchive-realm. The server-side handler enqueues a full reindex on restore; the CLI just hits the endpoint and reports the outcome.boxel realm listgains--include-archived. By default archived realms are hidden (matching the workspace chooser). With the flag set, the owner-onlyGET /_archived-realmsendpoint is consulted and the caller's archived realms are appended to the output with a(archived)marker.RealmSummarygains anarchived: booleanfield so JSON consumers and the TTY output can both surface the marker.Test plan
pnpm lint:types+pnpm lint:jsclean.pnpm test:unit-exclude-smoke— 327/327 pass.boxel realm --helplistsarchiveandrestore;boxel realm list --helpshows--include-archived.tests/integration/realm-archive.test.ts,tests/integration/realm-list-archived.test.ts, updatedrealm-list.test.ts) — require Docker for the test Postgres; will be exercised in CI.Depends on
GET /_archived-realmsendpoint. This PR stacks on top.🤖 Generated with Claude Code