Back to Plate

slate v2 cva cn class sweep

docs/plans/2026-05-27-slate-v2-cva-cn-class-sweep.md

53.0.816.0 KB
Original Source

slate v2 cva cn class sweep

Objective: Sweep .tmp/slate-v2/site/examples/ts for manual class string builders and replace class composition with cva() / cn() where class names are involved.

Goal plan: docs/plans/2026-05-27-slate-v2-cva-cn-class-sweep.md

Template: docs/plans/templates/task.md

Primary template: docs/plans/templates/task.md

Applied packs:

  • browser (docs/plans/templates/packs/browser.md)

Task source:

  • type: user request
  • id / link: chat
  • title: avoid manual array/filter/join class builders in examples
  • acceptance criteria: migrate patterns like ['base', cond && 'is-x'].filter(Boolean).join(' ') to cva()/cn(); review all examples for misses.

Completion threshold:

  • No examples contain manual class array/filter/join builders.
  • Remaining .join(' ') hits are documented as non-class data strings.
  • Class composition uses cva() or cn() where applicable.
  • Emotion remains absent from source.
  • .tmp/slate-v2 source audits, lint/typecheck/check, and focused browser proof pass.
  • Task closure is legal only when the source-of-truth acceptance criteria are satisfied or explicitly narrowed, required verification evidence is recorded, code-review and release-artifact gates are closed when applicable, tracker/PR sync is complete or marked N/A with reason, and node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-slate-v2-cva-cn-class-sweep.md passes.

Verification surface:

  • Source audits over .tmp/slate-v2/site/examples/ts.
  • .tmp/slate-v2: bun lint:fix, bun typecheck:site, bun lint, bun check.
  • Focused browser smoke on changed routes.

Constraints:

  • Preserve existing user-facing behavior outside the task scope.
  • Prefer the durable ownership boundary over caller-by-caller patches.
  • Do not create PRs, comments, commits, or pushes unless the task/user/skill requires them.
  • Do not add broad ceremony when the task is trivial or docs-only.

Boundaries:

  • Source of truth: user correction in chat.
  • Allowed edit scope: .tmp/slate-v2/site/examples/ts, .tmp/slate-v2/site/public/index.css only if styles need pairing, and this plan.
  • Browser surface: changed example routes.
  • Tracker sync: N/A, chat-only task.
  • Non-goals: do not replace non-class data string joins or runtime arbitrary token class payloads with fake enumerated variants.

Blocked condition:

  • Blocked only if verification cannot run and source audits cannot establish the requested class-composition cleanup.

Task state:

  • task_type: implementation
  • task_complexity: normal
  • current_phase: closeout
  • current_phase_status: complete
  • next_phase: final response
  • goal_status: active

Current verdict:

  • verdict: complete
  • confidence: high
  • next owner: user
  • reason: manual class builders are removed or documented as non-class data; verification passed.

Completion rule:

  • Do not call update_goal(status: complete) while any required checklist item remains unchecked. If an item does not apply, check it and add N/A: <reason>.
  • Do not call update_goal(status: complete) until every completion threshold above is satisfied, final handoff evidence is recorded, and node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-slate-v2-cva-cn-class-sweep.md passes.
  • Do not create hook state for this goal. This file plus the active goal are the durable state.

Start Gates:

GateAppliesEvidence
Skill analysis before editsyesAutogoal used because the sweep has measurable audit gates.
Active goal checked or createdyesGoal created for class composition sweep.
Source of truth read before editsyesUser correction read.
Tracker comments and attachments readN/AChat-only task.
Video transcript evidence requiredN/ANo video source.
docs/solutions checked for non-trivial existing-code workN/ALocal style cleanup; no historical behavior claim.
TDD decision before behavior change or bug fixN/AStyling/class composition cleanup, not bug behavior.
Branch decision for code-changing taskN/ANo git/PR work requested.
Release artifact decisionN/AExample-only code; no package release artifact.
Browser tool decision for browser surfaceyesUse focused local Chromium smoke if repo browser tool remains unavailable.
PR expectation decisionN/ANo PR requested.
Tracker sync expectation decisionN/ANo tracker.
Browser pack selectedyes--with browser applied.
Browser route / app surface identifiedyesChanged routes: /examples/markdown-preview, /examples/code-highlighting, /examples/inlines.
Browser tool decision recordedyesLocal Chromium smoke acceptable if repo browser tool unavailable.
Console/network caveat policy recordedyesBrowser smoke checks app/page errors.

Work Checklist:

  • Objective includes outcome, completion threshold, verification surface, constraints, boundaries, and blocked condition.
  • Task source classified with source type, id/link, title, task type, acceptance criteria, caveats, likely files/routes/packages, browser surface, and root-cause layer.
  • Required video or screen-recording evidence marked N/A: no video source.
  • Nearby repo instructions and implementation patterns read before edits.
  • Implementation fixes the right ownership boundary, or the narrower choice is recorded with reason.
  • Release artifact requirement recorded as N/A: examples/script declaration cleanup only, no published behavior.
  • Final handoff shape decided: concise summary with audits, commands, and browser proof.
  • Branch handling recorded as N/A: no git/PR work requested.
  • Local-env-rot retry policy recorded as N/A: no corruption-shaped failure.
  • Workspace authority recorded: every proof command names the cwd/tool that owns the changed behavior.
  • High-risk note marked N/A: no public API/runtime/package boundary changed.
  • Review/autoreview target marked N/A: small follow-up to style-only sweep; prior helper hung on the same local diff class, manual audit plus full bun check and browser proof used.
  • Agent-native review marked N/A: no agent/tooling files changed.
  • Browser pack: route, interaction path, and expected visible outcome are recorded before proof.
  • Browser pack: local Chromium smoke used against dev server on port 3210.
  • Browser pack: console and network errors checked; no app errors.
  • Browser pack: screenshot saved for markdown preview proof.

Completion Gates:

GateAppliesRequired actionEvidence
Named verification thresholdyesRun the command, proof, source audit, or artifact check named in this planSource audits, bun typecheck:site, bun lint, bun check, and browser smoke passed.
Bug reproduced before fixnoRecord failing test/repro or N/A with reasonN/A: style cleanup request.
Targeted behavior verificationyesRun focused test/proof for changed behavior or record N/ABrowser smoke passed /examples/markdown-preview, /examples/code-highlighting, and /examples/inlines.
TypeScript or typed config changedyesRun relevant typecheckbun typecheck:site and bun check passed.
Package exports or file layout changednoRun pnpm brl before final verification and keep generated barrel updatesN/A: no package exports or file layout changed.
Package manifests, lockfile, or install graph changednoRun pnpm install and relevant package checksN/A: no manifests or lockfile changed.
Agent rules or skills changednoRun pnpm install and verify generated skill syncN/A: no agent rules or skills changed.
Workspace authority proofyesRun verification in the owning repo/package/app/route/tool and record cwd; do not count the wrong workspace as proofAll checks ran in .tmp/slate-v2; plan checker runs from plate-2.
Browser surface changedyesCapture Browser Use proof or record explicit waiver/blockerLocal Chromium smoke used; repo browser tool unavailable in this turn.
Browser final proofyesAttach screenshot or exact browser verification caveat when browser proof applies/tmp/slate-v2-cva-cn-class-sweep-markdown-preview.png; JSON smoke result recorded.
CI-controlled template output changednoRestore generated template output or record why it is intentionally keptN/A: no template output touched.
Package behavior or public API changednoAdd a changeset or record why no changeset appliesN/A: examples/declaration cleanup only.
Registry-only component work changednoUpdate docs/components/changelog.mdx or record N/AN/A: no registry-only component work.
Docs or content changedyesFor docs-heavy work, use --template docs; for incidental docs, verify source-backed claims, links, examples, and rendered output or record N/AThis plan only; claims are command-backed.
High-risk mini gatenoFor public API/runtime/package-boundary/browser/agent-action/command-contract changes, record realistic failure mode, proof plan, and why the chosen boundary is right; otherwise N/AN/A: no high-risk surface.
Agent-native review for agent/tooling changesnoFor .agents/**, .claude/**, .codex/**, skills, hooks, commands, prompts, or user-action tooling, load .agents/skills/agent-native-reviewer/SKILL.md and close accepted/actionable findings, or record N/AN/A: no agent/tooling changes.
Local install corruption suspectednoRun pnpm run reinstall once, rerun the exact failing command, or record N/AN/A: no local-env-rot shape.
Autoreview for non-trivial implementation changesnoLoad .agents/skills/autoreview/SKILL.md; use dirty local target until clean, or record N/AN/A: small style-followup; prior helper was unavailable/hung, manual audit plus full check/browser proof used.
PR create or updatenoRun check before PR work and sync PR body to final handoffN/A: no PR requested.
PR proof image hostingnoIf PR body needs browser proof, replace local image paths with hosted GitHub URLs or record N/AN/A: no PR body.
Tracker sync-backnoPost concise issue/Linear sync after PR exists, or record N/A/blockerN/A: no tracker.
Final handoff contractyesFill the final handoff fields below with exact PR/issue/confidence/tests/browser/outcome/caveats/design/verification content or N/A reasonFilled below.
Final lintyesRun pnpm lint:fix or scoped equivalentbun lint:fix, bun lint, and bun check passed.
Goal plan completeyesRun node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-27-slate-v2-cva-cn-class-sweep.mdTo run after this update.
Browser interaction proofyesExercise the target route/interaction with the approved browser tool or record blockerLocal Chromium smoke passed on changed routes.
Browser console/network checkyesRecord console/network state or why it is not applicableBrowser smoke reported appErrors: [].
Browser final proof artifactyesRecord screenshot/trace/route proof or exact caveatScreenshot saved under /tmp; JSON counts recorded below.

Phase / pass table:

PhaseStatusEvidenceNext
Intake and source readdoneaudited class composition patterns in examplesimplementation
Implementationdonemigrated markdown-preview, code-highlighting, and inlines class compositionverification
Verificationdonesource audits, lint/typecheck/check, and browser smoke passedcloseout
PR / tracker syncN/Ano PR/tracker requestedfinal response
Closeoutdoneplan updated; checker is final commandfinal response

Findings:

  • markdown-preview.tsx used the exact bad array.filter(Boolean).join(' ') class builder.
  • code-highlighting.tsx used filter/map before cn() for arbitrary Prism token class payloads; this can stay runtime-token driven but should not build classes manually.
  • inlines.tsx had one ternary className that should be cn(...).
  • multi-root-document.tsx has .join(' '), but it joins document text for a status label, not class names.

Decisions and tradeoffs:

  • Use cva() for markdown preview’s known static token variants.
  • Use cn() for arbitrary Prism token class payloads because those token names are runtime data, not a closed variant list.
  • Leave non-class text joins alone.

Implementation notes:

  • markdown-preview.tsx now uses markdownSegmentVariants = cva(...) and cn(markdownSegmentVariants(...)).
  • code-highlighting.tsx now passes runtime token classes directly through cn(...) without manual filter/join.
  • inlines.tsx now uses cn(text.text === '' && ...).

Review fixes:

  • None yet.

Error attempts:

Error / failed attemptCountNext different moveResolution
None yet0

Verification evidence:

  • .tmp/slate-v2: rg -n 'filter\\(Boolean\\)|\\.join\\('\\'' '\\''\\)|const\\s+className\\s*=\\s*\\[|className=\\{[^}]*\\?[^}]*:' site/examples/ts returned only site/examples/ts/multi-root-document.tsx:38, where .join(' ') builds document text for a status label, not class names.
  • .tmp/slate-v2: rg -n '@emotion|emotion|css\\(|cx\\(' . --glob '!site/.next/**' --glob '!site/out/**' returned no matches.
  • .tmp/slate-v2: bun lint:fix passed.
  • .tmp/slate-v2: bun typecheck:site passed.
  • .tmp/slate-v2: bun lint passed.
  • .tmp/slate-v2: bun check passed: lint, package/site/root typecheck, Bun tests, and Slate React Vitest suite.
  • .tmp/slate-v2: focused Chromium smoke against localhost:3210 passed: /examples/markdown-preview, /examples/code-highlighting, /examples/inlines; markdown segments 5, code blocks 2, positioned code elements 33, inline badges 1, editor visible true, appErrors: [].
  • Browser proof screenshot: /tmp/slate-v2-cva-cn-class-sweep-markdown-preview.png.

Final handoff contract:

  • PR line: N/A, no PR requested.
  • Issue / tracker line: N/A, no tracker item.
  • Confidence line: high.
  • Flow table:
    • Reproduced: N/A, style-composition sweep.
    • Verified: source audits, lint/typecheck/check, and browser smoke passed.
  • Browser check: local Chromium smoke passed on changed routes with zero app errors.
  • Outcome: manual class builder pattern is gone from examples; markdown preview uses cva(), runtime arbitrary token classes use cn(), and ternary className miss uses cn().
  • Caveat: remaining .join(' ') is not class composition.
  • Design:
    • Chosen boundary: static variants use cva(); dynamic class payloads use cn().
    • Why not quick patch: swapping only the shown snippet would miss adjacent manual composition.
    • Why not broader change: non-class text joins and arbitrary Prism token names are runtime data, not a closed styling variant API.
  • Verified: commands and browser proof above.

Final handoff / sync:

  • PR: N/A, no PR requested.
  • Issue / tracker: N/A, no tracker item.
  • Browser proof: focused Chromium smoke and screenshot listed above.
  • Caveats: none beyond the documented non-class .join(' ').

Timeline:

  • 2026-05-27T08:44:06.946Z Task goal plan created.
  • 2026-05-27T08:45:30Z Migrated markdown-preview manual class builder to cva()/cn(); tightened code-highlighting and inlines.
  • 2026-05-27T08:47:00Z bun lint:fix, bun typecheck:site, and bun lint passed.
  • 2026-05-27T08:48:30Z bun check found script declaration drift; added commandKeyFor, getRunReuseDecision, and runId typings.
  • 2026-05-27T08:49:00Z bun check passed.
  • 2026-05-27T08:51:00Z Focused Chromium smoke passed on changed routes.

Reboot status:

QuestionAnswer
Where am I?Closeout complete.
Where am I going?Run checker, close goal, final response.
What is the goal?Sweep Slate v2 examples for manual class builders and migrate to cva()/cn().
What have I learned?See Findings.
What have I done?See Timeline.

Open risks:

  • None known.