Skip to content

Recognize Workspace as a default realm index card#5585

Open
lukemelia wants to merge 2 commits into
cs-12277-extract-workspace-carddeffrom
cs-12279-recognize-workspace-adoption
Open

Recognize Workspace as a default realm index card#5585
lukemelia wants to merge 2 commits into
cs-12277-extract-workspace-carddeffrom
cs-12279-recognize-workspace-adoption

Conversation

@lukemelia

Copy link
Copy Markdown
Contributor

What

Both the publish handler and the prerender fast-path only recognized CardsGrid as a realm's default index card. This teaches them to recognize Workspace too, so Workspace-indexed realms get the same default-index handling.

Changes

  • handle-publish-realm.ts — the CardsGrid-specific CARDS_GRID_MODULE_FORMS + name check becomes a list of recognized default-index adoptions (CardsGrid + Workspace). Publishing a realm whose index.json adopts either now writes includePrerenderedDefaultRealmIndex: true so the published homepage gets real prerendered content.
  • routes/render/html.ts#isDefaultRealmCardsGridIndex#isDefaultRealmIndexCard, comparing the index card's top type against a list of recognized default-index refs via internalKeyFor. A realm indexed by CardsGrid or Workspace (and not opted in) short-circuits the isolated render to the boilerplate placeholder.
  • realm-index-boilerplate.ts — the placeholder serves both index cards now, so its cards-grid-specific class/data attributes are generalized to realm-index-neutral names (no other consumers reference them).

A realm with a bespoke (non-default) index card is still left alone in both paths.

Why this matters for the project

Making Workspace the actual default for new realms (create-realm.ts) depends on this — otherwise a newly created Workspace-indexed realm would lose the prerendered-default-index fast-path on publish.

Tests

  • Realm-server (publish-unpublish-realm-test.ts) — publishing a realm whose index adopts Workspace writes includePrerenderedDefaultRealmIndex, mirroring the existing CardsGrid case.
  • Host (realm-indexing-test.gts) — a Workspace-indexed realm that has not opted in gets the boilerplate placeholder as its isolated HTML, mirroring the existing CardsGrid case.

Stacking

Based on the Workspace port branch — the recognition is meaningless without the card, and the tests set up Workspace-indexed realms. Retargets to main once the port merges. Draft until then.

Test plan

realm-server ember-tsc + host glint clean; eslint + prettier clean. Host boilerplate test run locally against a full dev stack — 1 passed. The realm-server publish test is static-verified and mirrors an existing passing test; it runs in CI (the realm-server publish harness needs test-pg + its own prerender, not wired up in this local session).

🤖 Generated with Claude Code

Both the publish handler and the prerender fast-path only recognized
CardsGrid as a realm's default index card. Generalize each to a list of
recognized default index cards (CardsGrid + Workspace):

- publish handler: opt a realm into includePrerenderedDefaultRealmIndex
  when its index.json adopts any recognized default index card.
- render/html.ts: short-circuit the isolated render to the boilerplate
  when the index card's top type is any recognized default index card and
  the realm has not opted in.
- the boilerplate placeholder is generalized (it serves both), dropping
  cards-grid-specific class names.

Covers the publish-handler recognition (realm-server) and the
useRealmIndexBoilerplate recognition (host realm-indexing) with tests
mirroring the existing CardsGrid cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files  ±0      1 suites  ±0   3h 3m 8s ⏱️ + 3m 14s
3 602 tests ±0  3 587 ✅ ±0  15 💤 ±0  0 ❌ ±0 
3 621 runs  ±0  3 606 ✅ ±0  15 💤 ±0  0 ❌ ±0 

Results for commit 632a1b9. ± Comparison against earlier commit 6cd5b90.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   11m 43s ⏱️ - 1m 13s
1 920 tests ±0  1 920 ✅ ±0  0 💤 ±0  0 ❌ ±0 
1 999 runs  ±0  1 999 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 632a1b9. ± Comparison against earlier commit 6cd5b90.

@lukemelia
lukemelia marked this pull request as ready for review July 22, 2026 21:42
@lukemelia
lukemelia requested review from a team and backspace July 22, 2026 21:43

@habdelra habdelra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Claude Code 🤖] Reviewed with a focus on completeness of the generalization — the risk in a "recognize one more card type" change is a missed twin recognizer or a downstream consumer still hard-coded to the old type, so I traced every place that decides "is this the realm's default index card" and every reference to the renamed CSS hooks.

Bottom line: this is a clean, correctly-scoped change with no blocking issues. Both recognizers were updated symmetrically, the rename is safe, and the tests pin the new behavior. Only two minor comment/doc drifts to tidy (both non-blocking).

What lands right

  • Both recognizers updated, and they agree. The publish handler (isDefaultRealmIndexAdoption, reading index.json's adoptsFrom) and the host render route (#isDefaultRealmIndexCard, comparing types[0] via internalKeyFor) are the only two places that classify the default index card. Both were generalized the same way, and they resolve to the same answer for a directly-adopting index.json. Details in the inline note on handle-publish-realm.ts.
  • The CSS-hook rename is safe. boxel-cards-grid-shell / data-boxel-cards-grid-indexboxel-realm-index-shell / data-boxel-realm-index. I grepped the tree: the old names have zero remaining references, and the new names appear only in realm-index-boilerplate.ts. Nothing selects on these (they exist for hydration-replaceable markup), so the rename is inert beyond readability.
  • No third recognizer downstream. The published-realm SSR injection path keys off the includePrerenderedDefaultRealmIndex flag (read from RealmConfig on disk into RealmInfo), not the card type — so writing the flag from the publish handler is the whole story; nothing else needed generalizing.
  • Tests mirror the CardsGrid cases faithfully. The host test asserts a not-opted-in Workspace realm gets REALM_INDEX_BOILERPLATE_HTML, and the realm-server test asserts publishing a Workspace-indexed realm writes the opt-in flag — each a line-for-line analogue of the existing CardsGrid test. Both are green on the head commit in CI.

On the one red check (Host Memory Baseline) — not caused by this diff. It fails on "modules not in baseline," and the modules it names are all the Workspace card's own test suites, which come from the base branch this PR stacks on, not from this PR (which adds no new test module and no new retained state). It should re-baseline once the stack retargets to main. Worth a glance to confirm, but not a regression here.

Recommendations (all non-blocking)

  1. html.ts — update the stale Model.useRealmIndexBoilerplate docstring ("the type chain is base CardsGrid") to match the generalized sibling comments. See the file comment.
  2. handle-publish-realm.ts — optionally generalize the opening of the "The CardsGrid CardDef can be referenced two equivalent ways…" comment so the shared rationale reads as card-agnostic. See the inline note.

Adjacent, out of scopeRealmInfo.includePrerenderedDefaultRealmIndex in packages/runtime-common/realm.ts is documented as opt-in "for the realm's default CardsGrid index card." This PR widens that field's meaning to Workspace-indexed realms too, so the field doc is now narrower than the behavior. That file isn't in this diff; a one-word tweak there (or in a follow-up) would keep the doc honest.


Generated by Claude Code

Comment on lines +62 to +89
const DEFAULT_REALM_INDEX_ADOPTIONS: { name: string; modules: Set<string> }[] =
[
{
name: 'CardsGrid',
modules: new Set([
'https://cardstack.com/base/cards-grid',
'@cardstack/base/cards-grid',
]),
},
{
name: 'Workspace',
modules: new Set([
'https://cardstack.com/base/workspace',
'@cardstack/base/workspace',
]),
},
];

function isDefaultRealmIndexAdoption(adoptsFrom: {
module: string;
name: string;
}): boolean {
return DEFAULT_REALM_INDEX_ADOPTIONS.some(
(adoption) =>
adoption.modules.has(adoptsFrom.module) &&
adoption.name === adoptsFrom.name,
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Claude Code 🤖] Confirmation — the recognizer is correct and matches its twin. Non-blocking.

isDefaultRealmIndexAdoption AND-checks module membership against name equality, so it won't misfire on a card named Workspace living in a different module, nor on a CardsGrid-named card in the workspace module. Both module spellings per card mirror the existing CardsGrid pair, and the base-realm URL for the new entry (https://cardstack.com/base/workspace) is the correct absolute form for packages/base/workspace.gts.

This is one of the two places that recognize a realm's default index card. I checked the other — #isDefaultRealmIndexCard in packages/host/app/routes/render/html.ts — and it was generalized the same way (comparing types[0] against DEFAULT_REALM_INDEX_REFS via internalKeyFor). The two agree in the common case that matters here: an index.json that directly adopts the base def produces an instance whose own type (types[0]) is that base def, so the disk-adoptsFrom read and the resolved-type read land on the same answer. I also confirmed there's no third recognizer downstream — the published-realm SSR path keys off the includePrerenderedDefaultRealmIndex flag this handler writes, not the card type — so generalizing these two is complete.

Minor, optional: the comment block just above (beginning "The CardsGrid CardDef can be referenced two equivalent ways…") still frames the two-module-forms rationale as CardsGrid-specific, even though it now applies to every entry in this list. Consider opening it with "A base CardDef can be referenced two equivalent ways…" so the note reads as general, since the generalized comment below points back to it with "see the note above."


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[Claude Code 🤖] Done in 632a1b9 — opened the comment with "A base CardDef can be referenced two equivalent ways…" so the shared two-module-forms rationale reads as card-agnostic, matching the "see the note above" pointer below it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Claude Code 🤖] Stale comment left behind by the generalization. Non-blocking (doc drift).

The Model.useRealmIndexBoilerplate docstring near the top of this file still reads:

Set only when format === 'isolated', the card is the realm's default index, the type chain is base CardsGrid, and the realm has not opted in…

That sentence describes the pre-PR behavior. The change generalized the check to CardsGrid or Workspace and updated the sibling comments — the method's own docstring on #isDefaultRealmIndexCard, the comment in packages/host/app/components/card-prerender.gts, and the boilerplate constant's header all now say "CardsGrid or Workspace" — but this interface docstring was missed. Suggest matching it, e.g. "the type chain begins with a recognized default index card (CardsGrid or Workspace)", so the two comments in this file don't contradict each other.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[Claude Code 🤖] Fixed in 632a1b9 — the useRealmIndexBoilerplate docstring now reads "the type chain begins with a recognized default index card (CardsGrid or Workspace)", consistent with the sibling comments. Also generalized the RealmInfo.includePrerenderedDefaultRealmIndex field doc in packages/runtime-common/realm.ts (the adjacent out-of-scope item) in the same commit.

Three doc comments still described the default-index recognition as
CardsGrid-specific after the recognizers were generalized to accept
Workspace too. Align them with the generalized behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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