Skip to content

Phase C: Split monolithic modules, consolidate duplicates - #709

Merged
lucaslyl merged 9 commits into
mainfrom
cs-12776-phase-c-split-monolithic-modules
Sep 6, 2026
Merged

Phase C: Split monolithic modules, consolidate duplicates#709
lucaslyl merged 9 commits into
mainfrom
cs-12776-phase-c-split-monolithic-modules

Conversation

@lucaslyl

@lucaslyl lucaslyl commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase C of the Master Catalog Refactor: audit catalog listings for monolithic files and duplicate code, split/consolidate at low risk.

Fixes: CS-12776
Part of: CS-12782 Master Catalog Refactor

Approach: these giant files are one Isolated/Fitted component class holding @tracked state, not naturally-separable pieces — so the low-risk extraction only pulls out standalone pure functions / FieldDef classes that already sit outside the component's instance state, leaving the component class bodies untouched.

Split (5 originally-identified monoliths):

  • Blog App — already had 4 separate top-level classes; extracted into components/admin-view.gts, admin-template.gts, site-view.gts, isolated-portal.gts
  • Homework Grader — GradeField/QuestionField/LetterGradeField/isGradeConsistentfields.gts; 3 Specs updated
  • Table Seating — 14 pure functions → utils/html-builders.gts, utils/geometry.gts, utils/async-helpers.gts
  • Virtual Piano — keyboard/notation/audio helpers → utils/keyboard-helpers.gts, utils/notation-helpers.gts, utils/audio-helpers.gts
  • Virtual Try-On — audited, nothing safely extractable (all logic reads component state)

Split (4 additional monoliths found during the full-catalog audit):

  • Blackjack — PlayingCardField/StatsField/normalizeStatisticsfields.gts
  • Beat Maker Studio — DrumKitField/DrumKitCard/BeatPatternField/BeatPatternCardfields.gts; fixed 12 card instances + 5 Specs whose module paths needed updating (one Spec set had a pre-existing, unrelated broken path from an old submission-folder rename)
  • AI Image Generator — versionLabel/friendlyErrorutils/generator-helpers.gts

Consolidated:

  • Removed boxel-surface + boxel-surface-demo — a framework package mistakenly committed into the catalog realm, not a listing, not imported anywhere (separate commit, already merged)
  • Removed a fully dead duplicate Popover copy in 19dee3-virtual-try-on-application/46f065-popover/ (nothing imported it — the listing already used the canonical @cardstack/catalog/46f065-popover/popover alias); ported one real feature the dead copy had gained (--bx-popover-* fallback tokens) into the canonical file first

Bugs caught and fixed during verification (none of these would have been caught by lint alone):

  • Blackjack: extraction dropped StringField/NumberField imports still needed by the Blackjack CardDef itself → runtime "X is not defined"
  • Beat Maker Studio: 12 pre-existing card instances still pointed adoptsFrom.module at ../beat-maker after the classes moved to ../fields

Audited, no action needed: the remaining 21 listings (Tier List, Wine Bottle, Wine Cellar, Stepper, Survey, Mortgage Calculator, 15 field listings) — no stale Specs, no broken imports, no orphaned files. Wine Bottle/Wine Cellar's byte-identical wine-bottle.gts is an intentional self-contained copy, confirmed in sync.

Follow-ups filed on CS-12776, not in this PR's scope:

  • image-source-editor.gts UI has drifted between the canonical fields/image-source and older embedded copies in Virtual Try-On + Tier List (both work, just an outdated design — needs a deliberate backport with browser QA)
  • 6a076d-ai-image-generator/Spec/generating-overlay.json is a pre-existing orphaned Spec pointing at a file that doesn't exist
  • 41e20f-wedding-table-seating-planner's ArrangeSeatsCommand Spec has a redundant .gts extension in its module path (harmless, resolves fine, just inconsistent)

Test plan

  • Prettier + ESLint clean on all touched files (21 .gts files)
  • All touched JSON Spec/instance files valid
  • Every split-off FieldDef/CardDef has a Spec with ref.module pointing at the new location
  • Server-side module + card-instance load check (200, no import errors) for all touched listings, run against a live local realm
  • Browser test (headless Chrome via chrome-devtools MCP) for all 8 touched apps: Blog App, Homework Grader, Table Seating, Virtual Piano, Blackjack (dealt real cards), Beat Maker Studio, AI Image Generator, Virtual Try-On (opened the Popover-driven "Add Garment" modal) — all render and interact correctly, no relevant console errors

🤖 Generated with Claude Code

Framework package mistakenly committed into the catalog realm. Not a
catalog listing, and not imported by any catalog file — the only
references elsewhere were an unrelated CSS var name coincidentally
containing "boxel-surface" and doc comments noting other components
were "ported from"/"styled after" it while staying self-contained.
blog-app.gts (2477 lines) was one giant class per section
(BlogAdminData, BlogAppTemplate, BlogSiteView, IsolatedPortal) plus the
BlogApp CardDef itself. Extracted the four component classes into
components/admin-view.gts, admin-template.gts, site-view.gts, and
isolated-portal.gts. blog-app.gts now only holds the CardDef.

No Spec update needed — BlogApp's own Spec still points at
./blog-app, and none of the internal components are Spec-referenced.
GradeField, QuestionField, LetterGradeField, and isGradeConsistent
were defined inline in homework-grader.gts (3032 lines) ahead of the
giant HomeworkIsolated/HomeworkFitted component classes, with zero
dependency on their instance state. Moved them to fields.gts; the two
big component classes are untouched.

Updated the 3 Specs (GradeField, QuestionField, LetterGradeField)
whose ref.module pointed at ../homework-grader to ../fields.
tsp.gts (11452 lines) had a block of ~14 standalone pure functions
sitting between the two giant Isolated/Fitted component classes:
HTML/string builders, geometry cloning + numeric clamping, and
generic async/loading helpers (including a PDF-to-PNG renderer).
Grouped into utils/html-builders.gts, utils/geometry.gts, and
utils/async-helpers.gts respectively. Neither component class body was
touched.
virtual-piano.gts (5414 lines) had keyboard-mapping, notation-parsing,
and audio-frequency helpers defined at module scope ahead of the
giant IsolatedVirtualPiano class, with no dependency on its instance
state. Split into utils/keyboard-helpers.gts, utils/notation-helpers.gts,
and utils/audio-helpers.gts. Also dropped a stale comment header left
orphaned by the earlier diffLabel/diffClass extraction.
PlayingCardField, StatsField, and normalizeStatistics were defined
inline in blackjack.gts (2552 lines) ahead of the giant
IsolatedTemplate/FittedTemplate/Blackjack classes, with no dependency
on their instance state. Moved to fields.gts.

Fixes a regression caught by Copilot-style verification: the move
initially dropped StringField/NumberField imports that Blackjack's
own CardDef fields still needed, which broke card rendering with
"X is not defined". Restored both imports.
DrumKitField, DrumKitCard, BeatPatternField, BeatPatternCard were
defined inline in beat-maker.gts (2984 lines) ahead of the giant
BeatMakerIsolated/BeatMakerCard classes, with no dependency on their
instance state. Moved to fields.gts.

Updated 12 pre-existing card instances (6 DrumKitCard + 6
BeatPatternCard) whose adoptsFrom.module still pointed at
../beat-maker post-move. Also fixed 5 Specs whose ref.module had a
stale, unrelated broken path left over from a prior submission-folder
rename (../beat-maker-studio-<hash>/beat-maker/beat-maker) — 4 now
point at ../fields, BeatMakerCard's own Spec at ../beat-maker.
components/generator.gts (2373 lines) had two pure template helpers
(versionLabel, friendlyError) defined at module scope alongside the
AiImageGeneratorIsolated/AiImageGeneratorEmbedded classes, with no
dependency on their instance state. Moved to utils/generator-helpers.gts.
…kens

19dee3-virtual-try-on-application/46f065-popover/ was a fully orphaned
copy of the Popover component/utils — virtual-try-on-app.gts already
imports the canonical @cardstack/catalog/46f065-popover/popover alias,
so nothing referenced the local copy.

Before deleting it, ported one real feature it had gained that the
canonical version lacked: --bx-popover-* custom-property names in the
portal's no-theme-scope fallback bridge, so popover-only knobs set
directly on an anchor with no linked theme (not just theme-scoped
knobs) still carry across the portal boundary.
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Staging Submissions Preview

This PR's content is pushed to the staging submissions realm: https://realms-staging.stack.cards/submissions/

Changed folders:

  • 150b3a-virtual-piano/
  • 25f2fc-homework-grader/
  • 41e20f-wedding-table-seating-planner/
  • 46f065-popover/
  • 673fb6-blackjack-cardgame-definition/
  • 6a076d-ai-image-generator/
  • 7af9aa-blog-app/
  • d8403b-beat-maker-studio-card/

Updated at 2026-09-06 07:45:18 UTC for commit ce12d3d. Shared realm: only this PR's changed files are pushed; files touched by multiple PRs reflect whichever pushed last, and deleted files are not removed.

@lucaslyl
lucaslyl merged commit 7a13657 into main Sep 6, 2026
3 checks passed
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