refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

refactor(frontend): group components/ by responsibility (#293) - #494

Merged
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components
Jul 31, 2026
Merged

refactor(frontend): group components/ by responsibility (#293)#494
AndresL230 merged 2 commits into
mainfrom
feat/293-flatten-components

Conversation

@AndresL230

Copy link
Copy Markdown
Collaborator

The top level of components/ held 58 files with no organising principle. Grouped per the issue's own proposal — pure moves + import rewrites, zero behaviour change.

groupfiles
marketing/HowItWorks, SignInModal, HeroCard (+test)
graph/KnowledgeGraph, 2D, 3D (+3 tests)
chat/ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot, AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary

Top level: 58 → 38.ui/, flashcards/ and screens/ unchanged. Moves used git mv, so history follows the files.

Timing

The proposal flagged that the real risk here is timing, not correctness: "this touches ~50 files and will conflict with every open frontend branch. It should land when the frontend queue is empty." It is — 0 open PRs when this branched. That's why this went first.

Two deviations from the proposal, both deliberate

study/ and social/ were not created. Neither had any top-level members — those screens already live in screens/ — so the groups would have been empty directories.

Gradebook/ was not renamed to gradebook/. The proposal wanted "the two Gradebook levels merged", but they're already split cleanly by responsibility: components/Gradebook/ holds the parts, components/screens/Gradebook/ holds the routes. The only remaining delta is letter case, and a case-only directory rename is a real cross-platform hazard for the macOS contributors on this repo. Not worth it for a cosmetic gain — happy to do it if you disagree.

Four things that had to move with the files

Each of these would have failed silently or confusingly:

  • frontend/eslint.config.mjs — the testid-enforcement files array is path-keyed. Stale entries would have silently stopped enforcing the rule on the exact files it exists to cover. That's a quiet failure, which is the dangerous kind.
  • frontend/eslint-suppressions.json — also path-keyed. This one failed loudly: 22 lint errors, because the suppressions no longer matched any file.
  • docs/frontend-testids.md — the surface table names owning files; this is the other half of the testid convention.
  • HeroCard.test.tsx resolved src/ as __dirname/'..', which silently became components/ once the file moved a level deeper. Now '../..'.

Also refreshed live path references in SECURITY.md and the graph journey's header comment.

Historical records (docs/frontend-audit/, docs/decisions/, docs/superpowers/plans/) are deliberately left pointing at the old paths — they're dated snapshots of what was true when written, not live indexes. Rewriting them would falsify the record.

Gates

  • tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests
  • Full local e2e cycle — in a comment below

part of #293

The top level of components/ held 58 files with no organising principle.
Groups them per the issue's own proposal, as pure moves + import rewrites —
zero behaviour change.
marketing/ HowItWorks, SignInModal, HeroCard (+test)
graph/ KnowledgeGraph, 2D, 3D (+3 tests)
chat/ ChatPanel, MarkdownChat, MermaidBlock, FunctionPlot,
AIDisclaimerChip, ModelToggle, SharedContextToggle, SessionSummary
Top level: 58 -> 38 files. `ui/`, `flashcards/` and `screens/` are unchanged.
The proposal also listed study/ and social/ groups; neither had any top-level
members (those screens already live in screens/), so creating them would have
made empty directories.
Deliberately NOT done: renaming Gradebook/ to gradebook/. The proposal wanted
"the two Gradebook levels merged", but they are already split cleanly by
responsibility — components/Gradebook/ holds the parts, components/screens/
Gradebook/ holds the routes. The only remaining delta is letter case, and a
case-only directory rename is a genuine cross-platform hazard for the macOS
contributors on this repo. Not worth it for a cosmetic gain.
Moves were done with `git mv`, so history follows the files.
Four things had to move WITH the files, each of which would have failed
silently or confusingly otherwise:
- frontend/eslint.config.mjs — the testid-enforcement `files` array is keyed
by path; stale entries would have silently stopped enforcing the rule on
the exact files it was written to cover.
- frontend/eslint-suppressions.json — also path-keyed. Stale keys surfaced as
22 lint errors, since the suppressions no longer matched any file.
- docs/frontend-testids.md — the surface table names owning files. This is
the other half of the testid convention.
- HeroCard.test.tsx resolved src/ as `__dirname/..`, which silently became
components/ once the file moved a level deeper. Now `../..`.
Also refreshed the live path references in SECURITY.md and the graph journey's
header comment. Historical records (docs/frontend-audit/, docs/decisions/,
docs/superpowers/plans/) are deliberately left pointing at the old paths —
they are dated snapshots of what was true when written, not live indexes.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ybgqdonkoqftwrmweuyv because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 31, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingb72640fCommit Preview URL

Branch Preview URL
Jul 31 2026, 07:30 AM

…293)
Both passed green while silently mocking nothing — the exact failure mode a
move-only refactor hides, and the reason tsc/lint/vitest all being green did
not prove the move was complete.
Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"
vitest does not error on a mock specifier that resolves to nothing; it just
declines to intercept, so the real component rendered instead of the stub and
the tests stayed green either way. tsc cannot see these because a vi.mock path
is a string literal, not an import.
Swept every relative vi.mock specifier in src/ against the filesystem: these
two were the only unresolvable ones, and there are now zero.
part of #293
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

Review found two silent bugs the green gates could not

Multi-agent review over the move. tsc, lint, vitest and the full e2e lane were all green on the broken state — the exact hazard of a move-only refactor.

Two vi.mock() specifiers still pointed at pre-move paths:

Dashboard.test.tsx vi.mock("../KnowledgeGraph") -> "../graph/KnowledgeGraph"
chat/ChatPanel.test.tsx vi.mock("./Icon") -> "../Icon"

vitest doesn't error on a mock specifier that resolves to nothing — it just declines to intercept. So the real components rendered instead of the stubs and the tests stayed green either way. tsc can't see these because a vi.mock path is a string literal, not an import.

Fixed in b72640f, and I swept every relative vi.mock specifier in src/ against the filesystem: those two were the only unresolvable ones, and there are now zero.

Review also verified, all clean: every entry in eslint.config.mjs's testid files array and all 28 eslint-suppressions.json keys resolve to existing files (a stale entry there stops enforcing silently); docs/frontend-testids.md surface table updated; internal relative imports in all moved files correctly re-depthed; no other test resolves paths via __dirname; next.config.ts / tsconfig / vitest.config / playwright.config / CI workflows carry no old paths.

E2E

35 passed (1.3m)
0 finding(s), 1 suppressed (allowlisted)

Worth recording: the first run of this cycle failed with 34/35 — study-room.spec.ts read a different room's messages. My diff has zero overlap with the social/realtime path (verified: no social, realtime or room file appears in it), and the re-run at the same sha passed 35/35. That's a two-context realtime race, the same family as open issue #477. Flagging it there rather than papering over it here.

Gates: tsc --noEmit clean · npm run lint 0 errors · npx vitest run 58 files / 415 tests.

@AndresL230
AndresL230 merged commit abdde21 into mainJul 31, 2026
6 checks passed
@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndresL230, you've reached your PR review limit, so we couldn't start this review.

Next review available in:7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60acf317-35ee-4679-8970-90e248644219

📥 Commits

Reviewing files that changed from the base of the PR and between d10c5e0 and b72640f.

📒 Files selected for processing (34)
  • SECURITY.md
  • docs/frontend-testids.md
  • frontend/e2e/graph.spec.ts
  • frontend/eslint-suppressions.json
  • frontend/eslint.config.mjs
  • frontend/src/app/(public)/page.tsx
  • frontend/src/components/chat/AIDisclaimerChip.tsx
  • frontend/src/components/chat/ChatPanel.test.tsx
  • frontend/src/components/chat/ChatPanel.tsx
  • frontend/src/components/chat/FunctionPlot.tsx
  • frontend/src/components/chat/MarkdownChat.tsx
  • frontend/src/components/chat/MermaidBlock.tsx
  • frontend/src/components/chat/ModelToggle.tsx
  • frontend/src/components/chat/SessionSummary.tsx
  • frontend/src/components/chat/SharedContextToggle.test.tsx
  • frontend/src/components/chat/SharedContextToggle.tsx
  • frontend/src/components/graph/KnowledgeGraph.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph2D.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.testmode.test.tsx
  • frontend/src/components/graph/KnowledgeGraph3D.tsx
  • frontend/src/components/marketing/HeroCard.test.tsx
  • frontend/src/components/marketing/HeroCard.tsx
  • frontend/src/components/marketing/HowItWorks.tsx
  • frontend/src/components/marketing/SignInModal.tsx
  • frontend/src/components/screens/Dashboard.test.tsx
  • frontend/src/components/screens/Dashboard.tsx
  • frontend/src/components/screens/Learn.resume.test.ts
  • frontend/src/components/screens/Learn.tsx
  • frontend/src/components/screens/Library.tsx
  • frontend/src/components/screens/Quiz.tsx
  • frontend/src/components/screens/Study.tsx
  • frontend/src/components/screens/Tree.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for freeto 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

@AndresL230