Skip to content

feat(web): /snippets page — pipeline-ab Arm A (BASELINE)#9

Open
eksno wants to merge 7 commits into
alphafrom
feat/snippets-arm-a
Open

feat(web): /snippets page — pipeline-ab Arm A (BASELINE)#9
eksno wants to merge 7 commits into
alphafrom
feat/snippets-arm-a

Conversation

@eksno

@eksno eksno commented Jun 12, 2026

Copy link
Copy Markdown
Member

EXPERIMENT PR — DO NOT MERGE. pipeline-ab A/B experiment artifact (Arm A (BASELINE)).

Baseline feature layout: Opus hands + full mid-process prime<->linus review loop + George QA + review-reconcile.

Both arms build the IDENTICAL /snippets feature from ONE shared plan. This PR stays OPEN for the operator to evaluate by eye against its live Railway preview. Implementation commits land here next.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • New Features
    • Added a snippets gallery page featuring curated code examples in TypeScript, Svelte, and Shell with syntax highlighting
    • Implemented copy-to-clipboard functionality for each snippet with visual feedback
    • Added light and dark theme support for syntax highlighting with automatic color adaptation
    • New navigation link to snippets gallery in site header

@railway-app railway-app Bot temporarily deployed to testing / testing-pr-9 June 12, 2026 19:14 Destroyed
@railway-app

railway-app Bot commented Jun 12, 2026

Copy link
Copy Markdown

🚅 Deployed to the testing-pr-9 environment in testing

Service Status Web Updated (UTC)
testing ✅ Success (View Logs) Web Jun 12, 2026 at 7:44 pm

eksno added 5 commits June 12, 2026 19:27
Add shiki (dependency) for build-time syntax highlighting and vitest +
jsdom (devDependencies) for the unit-test floor. Wire up test/test:watch
scripts and a dedicated vitest.config.ts so pure-TS units run without the
SvelteKit plugin.

Station-Trailer-Version: 1
Add the pure snippet data model (typescript/svelte/shell samples) and a
browser-free highlightToHtml() that uses Shiki's css-variables theme so every
token color resolves through --shiki-* vars. Define those vars under :root and
.dark in app.css so syntax colors flip with the theme -- no hardcoded hex in the
rendered HTML. Unit tests assert the lang mapping and the hex-absence guarantee.

Station-Trailer-Version: 1
Add a dependency-free toast store with full timer ownership (every setTimeout
has a matching clearTimeout path; _clearAllTimers for viewport unmount) plus its
Toaster viewport, and an SSR-guarded copyToClipboard that no-ops when navigator
is unavailable. Tests cover auto-dismiss via fake timers, the cleanup path, and
the clipboard success/SSR/reject branches.

Station-Trailer-Version: 1
Add the SnippetCard (title, language badge, highlighted code, copy button with a
1.2s check-icon state and unmount timer cleanup) and the /snippets route. The
load() precomputes highlighted HTML on the server so the page prerenders to
static, already-highlighted output and ships zero highlighting JS to the client.
The page mounts the Toaster once near its root.

Station-Trailer-Version: 1
Add the Snippets link to the site-header nav array so it appears alongside Home
and Components and highlights as active on the route.

Station-Trailer-Version: 1
@railway-app railway-app Bot temporarily deployed to testing / testing-pr-9 June 12, 2026 19:31 Destroyed
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@eksno, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 54 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9638adf3-d515-4298-9284-108c910c4ec5

📥 Commits

Reviewing files that changed from the base of the PR and between b6a36c7 and 71b0d0f.

📒 Files selected for processing (1)
  • web/src/routes/snippets/+page.server.ts
📝 Walkthrough

Walkthrough

This PR introduces a complete code snippet gallery at /snippets with Shiki syntax highlighting, clipboard copying, and toast notifications. Changes span build configuration, theme CSS variables, core utilities, and new page components, all tested via Vitest.

Changes

Snippets Gallery Feature

Layer / File(s) Summary
Build Infrastructure & Test Configuration
web/package.json, web/vitest.config.ts
Added Vitest and Prettier scripts; configured Vitest environment to node with jsdom optional, test file discovery patterns, and $lib path alias.
Data Model & Theme System
web/src/lib/snippets.ts, web/src/lib/snippets.test.ts, web/src/app.css
Defined Lang type union and Snippet interface; exported four predefined code snippets (TypeScript, Svelte, Shell); added --shiki-* CSS variables for light and dark syntax highlighting themes.
Syntax Highlighting Engine
web/src/lib/highlight.ts, web/src/lib/highlight.test.ts
Mapped language names to Shiki grammar identifiers; created CSS variable–driven Shiki theme; cached highlighter singleton; exposed highlightToHtml() for pre-rendering highlighted code with color tokens via var(--shiki-*).
Notification & Clipboard Services
web/src/lib/toast.ts, web/src/lib/toast.test.ts, web/src/lib/components/toaster.svelte, web/src/lib/clipboard.ts, web/src/lib/clipboard.test.ts
Implemented Svelte toast store with auto-dismiss timers and cleanup; built UI component for toast notifications with transitions; added SSR-safe clipboard utility with error handling and fallback.
UI Components & Page Assembly
web/src/lib/components/snippet-card.svelte, web/src/lib/components/site-header.svelte, web/src/routes/snippets/+page.ts, web/src/routes/snippets/+page.svelte
Created snippet card component showing highlighted code, language badge, and copy-to-clipboard button with toast feedback; added snippets navigation link to site header; built page module with server-side highlighting via load() and gallery layout with responsive grid.

Sequence Diagram

sequenceDiagram
  participant Browser
  participant PageLoad as +page.ts Load
  participant Highlighter as highlightToHtml
  participant PageRender as +page.svelte
  participant SnippetCard as SnippetCard
  participant Clipboard as copyToClipboard
  Browser->>PageLoad: GET /snippets
  PageLoad->>Highlighter: for each snippet
  Highlighter-->>PageLoad: html (pre-rendered)
  PageLoad-->>PageRender: data.snippets with html
  PageRender->>SnippetCard: render snippet card keyed
  SnippetCard->>Browser: display code + copy button
  Browser->>SnippetCard: click copy button
  SnippetCard->>Clipboard: copyToClipboard(code)
  Clipboard-->>SnippetCard: true/false
  SnippetCard->>Browser: toast notification
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • startino/testing#7: Provides the initial SvelteKit scaffolding and design system that this PR builds upon with Shiki integration, theme CSS variables, and new page utilities.

Poem

A gallery of code, now beautifully lit,
With Shiki's bright colors and snippets that fit,
A toast pops up when you copy with care,
CSS variables dance in the light and the air. 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(web): /snippets page — pipeline-ab Arm A (BASELINE)' directly describes the main feature added: a /snippets page as part of an A/B test baseline. This accurately reflects the primary change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/snippets-arm-a

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 and usage tips.

…of the client bundle

A universal +page.ts load pulls its import graph ($lib/highlight -> shiki)
into the CLIENT bundle. The built snippets node chunk was 232KB and shipped
the Shiki runtime (createHighlighter/codeToHtml) plus the oniguruma WASM
engine to the browser, contradicting the design intent of build-time-only
highlighting. Renaming to +page.server.ts makes load server-only (still runs
at prerender), so the highlighter never enters the client graph. The route
chunk drops to 8KB and the browser receives only the precomputed static HTML.

Verified: npm run check / test (16) / build all green; shiki runtime absent
from .svelte-kit/output/client, present only in the server build.

Station-Trailer-Version: 1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/src/lib/components/toaster.svelte`:
- Around line 8-10: The effect cleanup currently only cancels timers via
toast._clearAllTimers(), leaving toast entries in the store; update the cleanup
returned from $effect to both cancel timers and clear toast state (e.g., call
toast._clearAllTimers(); then toast.clear() or the library's clearAll/clear
method) so toast entries are removed on unmount; modify the cleanup inside the
$effect that references toast._clearAllTimers() to also invoke the toast store's
clear method (toast.clear() / toast.clearAll()).

In `@web/src/lib/highlight.ts`:
- Around line 31-37: The cached promise _hp currently gets permanently set to a
rejected promise by getHighlighter(); change getHighlighter() so when assigning
(_hp = createHighlighter(...)) you attach a .catch handler that resets _hp to
null and rethrows the error (so transient init failures don't poison the cache);
ensure the handler references the same _hp variable and that highlightToHtml
callers still receive the original rejection when appropriate.

In `@web/src/routes/snippets/`+page.ts:
- Around line 1-15: The universal load() in +page.ts is using highlightToHtml
(which imports shiki at module scope) causing Shiki to be bundled to the client;
move the server-only highlighting to a server load: create +page.server.ts with
an exported load() that imports highlightToHtml (or move $lib/highlight.ts →
$lib/server/highlight.server.ts) and performs the Promise.all mapping (function
name: load, helper: highlightToHtml, data: snippets), then have +page.ts export
only a client-safe load or no load so the Shiki module is never imported in the
universal bundle.

In `@web/vitest.config.ts`:
- Line 14: Replace the Windows-unsafe new URL(...).pathname usage in the Vitest
alias by importing fileURLToPath from 'url' and using fileURLToPath(new
URL('./src/lib/', import.meta.url)) for the $lib alias; update the alias object
(alias: { $lib: ... }) to call fileURLToPath and add the fileURLToPath import at
the top of web/vitest.config.ts so path resolution is cross-platform-safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a1617ee-08d1-4e98-84fa-d73828d22ce5

📥 Commits

Reviewing files that changed from the base of the PR and between c20b967 and b6a36c7.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • web/package.json
  • web/src/app.css
  • web/src/lib/clipboard.test.ts
  • web/src/lib/clipboard.ts
  • web/src/lib/components/site-header.svelte
  • web/src/lib/components/snippet-card.svelte
  • web/src/lib/components/toaster.svelte
  • web/src/lib/highlight.test.ts
  • web/src/lib/highlight.ts
  • web/src/lib/snippets.test.ts
  • web/src/lib/snippets.ts
  • web/src/lib/toast.test.ts
  • web/src/lib/toast.ts
  • web/src/routes/snippets/+page.svelte
  • web/src/routes/snippets/+page.ts
  • web/vitest.config.ts

Comment on lines +8 to +10
$effect(() => {
return () => toast._clearAllTimers();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear toast state on unmount; timer-only cleanup can leave stale toasts.

Line 9 cancels timers but does not remove toast entries from the store. Because <Toaster /> is page-scoped (web/src/routes/snippets/+page.svelte), navigating away before TTL can leave old toasts persisted and re-rendered on remount.

💡 Suggested fix
 <script lang="ts">
 	import { toast } from '$lib/toast';
+	import { get } from 'svelte/store';
 	import { fly, fade } from 'svelte/transition';
@@
 	$effect(() => {
-		return () => toast._clearAllTimers();
+		return () => {
+			for (const t of get({ subscribe: toast.subscribe })) {
+				toast.dismiss(t.id);
+			}
+		};
 	});
 </script>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$effect(() => {
return () => toast._clearAllTimers();
});
$effect(() => {
return () => {
for (const t of get({ subscribe: toast.subscribe })) {
toast.dismiss(t.id);
}
};
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/lib/components/toaster.svelte` around lines 8 - 10, The effect
cleanup currently only cancels timers via toast._clearAllTimers(), leaving toast
entries in the store; update the cleanup returned from $effect to both cancel
timers and clear toast state (e.g., call toast._clearAllTimers(); then
toast.clear() or the library's clearAll/clear method) so toast entries are
removed on unmount; modify the cleanup inside the $effect that references
toast._clearAllTimers() to also invoke the toast store's clear method
(toast.clear() / toast.clearAll()).

Comment thread web/src/lib/highlight.ts
Comment on lines +31 to +37
let _hp: Promise<Highlighter> | null = null;

function getHighlighter(): Promise<Highlighter> {
return (_hp ??= createHighlighter({
themes: [cssVariablesTheme],
langs: ['typescript', 'svelte', 'shellscript'],
}));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset cached highlighter promise on initialization failure.

At Line 34, a single rejected createHighlighter(...) call permanently poisons _hp, so all future highlightToHtml calls fail even after transient startup errors.

Suggested fix
 let _hp: Promise<Highlighter> | null = null;

 function getHighlighter(): Promise<Highlighter> {
-	return (_hp ??= createHighlighter({
-		themes: [cssVariablesTheme],
-		langs: ['typescript', 'svelte', 'shellscript'],
-	}));
+	if (!_hp) {
+		_hp = createHighlighter({
+			themes: [cssVariablesTheme],
+			langs: ['typescript', 'svelte', 'shellscript'],
+		}).catch((err) => {
+			_hp = null;
+			throw err;
+		});
+	}
+	return _hp;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/lib/highlight.ts` around lines 31 - 37, The cached promise _hp
currently gets permanently set to a rejected promise by getHighlighter(); change
getHighlighter() so when assigning (_hp = createHighlighter(...)) you attach a
.catch handler that resets _hp to null and rethrows the error (so transient init
failures don't poison the cache); ensure the handler references the same _hp
variable and that highlightToHtml callers still receive the original rejection
when appropriate.

Comment thread web/src/routes/snippets/+page.server.ts
Comment thread web/vitest.config.ts
resolve: {
// Resolve `$lib/...` imports without pulling in the SvelteKit plugin, so pure-TS
// tests stay fast and avoid `$app/*` resolution issues.
alias: { $lib: new URL('./src/lib/', import.meta.url).pathname },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current alias-path pattern and whether Windows CI is in scope.

set -euo pipefail

echo "1) Find pathname-based URL alias conversions:"
rg -n --type ts "new URL\\(.*import\\.meta\\.url\\)\\.pathname"

echo
echo "2) Check for Windows runners in GitHub Actions workflows (if present):"
if [ -d ".github/workflows" ]; then
  rg -n --iglob '*.yml' --iglob '*.yaml' 'windows|win32|matrix' .github/workflows || true
else
  echo "No .github/workflows directory found."
fi

Repository: startino/testing

Length of output: 308


Fix $lib alias path conversion to be Windows-safe

web/vitest.config.ts:14 uses new URL(...).pathname for a filesystem path; this isn’t cross-platform safe on Windows. Switch to fileURLToPath() for reliable path resolution in Vitest.

Proposed fix
 import { defineConfig } from 'vitest/config';
+import { fileURLToPath } from 'node:url';

 export default defineConfig({
 	test: {
@@
 	resolve: {
@@
-		alias: { $lib: new URL('./src/lib/', import.meta.url).pathname },
+		alias: { $lib: fileURLToPath(new URL('./src/lib/', import.meta.url)) },
 	},
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
alias: { $lib: new URL('./src/lib/', import.meta.url).pathname },
import { defineConfig } from 'vitest/config';
import { fileURLToPath } from 'node:url';
export default defineConfig({
test: {
environment: 'node',
include: 'src/**/*.{test,spec}.ts',
},
resolve: {
alias: { $lib: fileURLToPath(new URL('./src/lib/', import.meta.url)) },
},
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/vitest.config.ts` at line 14, Replace the Windows-unsafe new
URL(...).pathname usage in the Vitest alias by importing fileURLToPath from
'url' and using fileURLToPath(new URL('./src/lib/', import.meta.url)) for the
$lib alias; update the alias object (alias: { $lib: ... }) to call fileURLToPath
and add the fileURLToPath import at the top of web/vitest.config.ts so path
resolution is cross-platform-safe.

@eksno

eksno commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Final review (advisory -- not a merge gate)

Arm A (BASELINE) -- review report: /snippets

Advisory red-team over every commit since origin/alpha. Reviewed the complete
change as one unit across three lenses. All files read in full. Tests/check/build
were green on entry; I re-ran them only to validate the one fix I applied.

Verdict

Strong, faithful implementation of the plan. One real quality finding
(client-bundle bloat) -- cheap, clearly-correct, behavior-preserving fix applied
and verified. Remaining items are minor judgment calls; none block the ship.


Lens 1 -- Spec gaps

No material gaps. The change satisfies the plan and the original ask end to end:

  • All 9 NEW files + 3 EDITED files from the manifest present; no DO-NOT-MODIFY file touched.
  • 4 snippets (>=3 required): 2x typescript, 1x svelte, 1x shell -- covers the >=1-each rule.
  • highlightToHtml/toShikiLang/copyToClipboard/toast exported as standalone, Node-testable units.
  • css-variables theme via createCssVariablesTheme (Shiki v4 dropped the bundled string theme) -- output still carries class="shiki css-variables" and var(--shiki-*), honoring the hard contract.
  • --shiki-* token vars added under BOTH :root and .dark, OKLCH, no hex. Background transparent so the block sits on bg-muted/50.
  • Copy writes RAW snippet.code; toast auto-dismisses (2500ms TTL); copy-icon reset timer (1200ms) cleared on unmount; Toaster _clearAllTimers() on unmount.
  • Nav wired with active-state logic; Toaster mounted once on the page.
  • 16 vitest tests across the 4 required/recommended files; the hex-absence assertion is present and passing.

Note (not a gap): the plan's §3a/§3b text prescribed a universal +page.ts load and asserted it "ships zero highlighting JS to the client." That assertion is FALSE for a universal load -- see Lens 3. The implementer followed the letter of the plan; the plan itself was wrong on that mechanism. I corrected the mechanism, preserving the plan's actual stated GOAL (build-time-only highlighting, zero client highlighter).

Lens 2 -- Standards violations

None blocking.

  • Svelte 5 runes only ($props, $state, $effect cleanup); no export let, no onMount.
  • Correct UI import paths (.../index.js), Badge/Button/Card.*, lucide icons.
  • ASCII throughout (--, straight quotes); prettier clean (tabs/single quotes/trailing commas) across all changed files; npm run check 0 errors/0 warnings.
  • package.json: shiki dependency, vitest+jsdom devDependencies, test/test:watch scripts -- correct placement. (@types/node reordered alphabetically -- harmless lockfile-adjacent churn.)
  • {@html} guarded with an eslint-disable plus a justifying comment (trusted server-rendered content).

Minor (judgment calls, left):

  • +page.svelte and snippet-card.svelte use untyped/hand-duplicated prop shapes rather than PageServerData / Snippet & { html: string }. check passes; cosmetic DRY only.
  • snippet-card.svelte places <style> before <script>. Valid + prettier-clean, just unconventional.

Lens 3 -- Quality problems

FINDING (acted-on): Shiki leaked into the CLIENT bundle.

Root cause: the route loaded via a UNIVERSAL src/routes/snippets/+page.ts. A
universal load's import graph ($lib/highlight -> shiki) is compiled into the
client bundle, even though under prerender the function only ever RUNS on the
server. Evidence from the on-entry client build:

  • nodes/4.*.js (the snippets route chunk) = 231,976 bytes and contained
    createHighlighter (x2) and codeToHtml (x7).
  • The oniguruma / vscode-textmate WASM regex engine appeared in multiple large
    shared client chunks (779KB / 626KB / 622KB) reachable from node 4.
    This directly contradicts the design intent ("no client-side highlighter, no
    WASM shipped to the browser").

Fix applied: renamed +page.ts -> +page.server.ts (server load still runs at
prerender; prerender/ssr exports remain valid). +page.svelte consumes only
data (serializable strings), so nothing else changed. Updated the leading
comment to document why server-side is required.

Post-fix verification (rebuilt):

  • snippets client node chunk: 231,976 -> 8,152 bytes (~28x smaller).
  • createHighlighter/codeToHtml/oniguruma/vscode-textmate/createCssVariablesTheme
    ALL absent from .svelte-kit/output/client/.
  • Shiki present only in the server build (entries/pages/snippets/_page.server.ts.js).
  • npm run check 0/0; npm run test 16/16; npm run build succeeded; prettier clean.

Other quality checks -- clean

  • Theme-correctness: every token color resolves through --shiki-* vars defined in both themes; hex-absence test passes; toast/card/badge/button use theme tokens only.
  • Timer/subscription leaks: every setTimeout has a matching clearTimeout path (per-toast dismiss, _clearAllTimers on Toaster unmount, copy-icon reset cleared on card unmount, $toast auto-unsubscribe). toast.test.ts proves the cleanup cancels pending timers.
  • SSR/prerender safety: copyToClipboard guards typeof navigator === 'undefined'; Toaster renders empty server-side (store starts []) -> no hydration mismatch; svelte/transition is client-only.
  • Test quality: pure, browser-free, deterministic; fake timers for TTL; clipboard navigator stub correctly saved/restored. Good coverage of the failure modes the card targets.
  • Dead deps/code: none. jsdom is a devDependency but no test currently switches to the jsdom environment (clipboard test injects a fake navigator under the node env instead). Harmless; the plan explicitly allowed including jsdom defensively. Left.

Gate after fix

PASS -- check (0/0), test (16/16), build all green; prettier clean.

Commit

  • 71b0d0f fix(web): move snippets highlight load server-side to keep Shiki out of the client bundle

@eksno

eksno commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Arm A (BASELINE) -- review disposition

Advisory only -- never blocks the ship.

findings-count: 4
acted-on: 1
left: 3
gate-after-fix: PASS

ACTED-ON (cheap, clearly-correct, behavior-preserving)

  1. [quality] Shiki shipped to the CLIENT bundle.
    • Universal +page.ts load pulled $lib/highlight -> shiki into the client
      graph: snippets route chunk = 232KB with createHighlighter/codeToHtml +
      oniguruma WASM engine in shared chunks.
    • Fix: git mv +page.ts -> +page.server.ts (server load still runs at
      prerender; page consumes only serializable data). Updated comment.
    • Verified: client node chunk 232KB -> 8KB; shiki absent from client output,
      present only in server build. check 0/0, test 16/16, build green, prettier clean.
    • Commit: 71b0d0f

LEFT (judgment calls -- one-line reason each)

  1. [standards] +page.svelte data and snippet-card.svelte props are untyped /
    hand-duplicated instead of PageServerData / Snippet & { html: string } --
    npm run check passes; cosmetic DRY/strictness only, not behavior.

  2. [standards] snippet-card.svelte orders <style> before <script> --
    valid Svelte and prettier-clean; purely conventional, not worth a rewrite.

  3. [quality] jsdom devDependency is declared but no test switches to the jsdom
    environment (clipboard test injects a fake navigator under node) -- harmless,
    the plan explicitly permitted including jsdom defensively; removing it is a
    taste call, not a correctness fix.

PASS-2 (report-only, post-fix)

Re-read the renamed +page.server.ts and rebuilt. No new findings; nothing
regressed. The three LEFT items are unchanged by the fix.

@eksno

eksno commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Known issues from QA (George -- baseline arm exploratory pass)

Surfaced by exploratory QA, triaged unblock-with-note (kept for the operator to eyeball; not auto-fixed so the two experiment arms stay comparable):

  1. Mobile nav overflow @375px -- header right-side controls (GitHub + theme toggle) exceed viewport ~31px; theme toggle ends up off-screen on phone width. (Pre-existing header behavior, surfaced by the new page.)
  2. Copy button icon never flips to check -- stays lucide-copy after a copy; no button-level success feedback (only the toast).
  3. Toasts dismiss very fast (~200ms visible) -- practically invisible at normal click speed.
  4. Unbounded toast stacking -- rapid repeated copy queues N simultaneous toasts; no cap/dedupe.
  5. Long code lines clipped -- a parent overflow:hidden cuts lines wider than the card with no horizontal scroll affordance.
  6. Card header wraps @narrow widths -- longer titles wrap, misaligning the language badge + copy button.
  7. <pre tabindex=0> focusable but not scrollable -- adds Tab-order noise with no scroll region.

These are the baseline arm's QA yield -- part of the experiment artifact, intentionally left visible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant