DSAMind

Changelog

Follow the latest changes, features, and fixes shipped to the platform.

Changelog

All notable changes to this project. Format: Keep a Changelog, trimmed. Append new entries to [Unreleased]. Never edit released sections.

[Unreleased]

[0.40.0] — 2026-07-16 — Account hub consolidation

Added

  • /account — a single hub replacing the separate Profile and Settings pages, with four tabs: Overview (profile card, stats, score trends, practice history — everything that used to live on /profile), Preferences (theme, coding language, email announcements), Billing (subscription status and a link to the billing portal), and Security (an embedded Clerk profile for credentials and sessions, plus account deletion).
  • Header — the separate "Profile" and "Settings" links are gone; clicking the avatar in the top-right corner now opens /account directly instead of Clerk's default popover. Sign out moved into the Security tab.

Changed

  • /profile and /settings now redirect to /account (Overview and Preferences respectively) instead of rendering their own pages.

[0.39.1] — 2026-07-15 — Database query performance pass

Fixed

  • Running code — each "Run" no longer fetches the same problem row from the database twice; the judge now reuses a single lookup.
  • Pattern Contract pages (/patterns/[patternId]) — removed a redundant lookup that queried the same pattern up to four times per page load.
  • Profile page — the practice-history query now pulls only the fields the page renders, instead of full attempt payloads (code, run output, AI coaching notes) for every completed attempt.
  • Dashboard "Topics" grid — solved-problem counts per topic are now computed by the database directly instead of loading every solved problem into the app to count them.

[0.39.0] — 2026-07-15 — Dashboard topics sorted by pattern complexity

Changed

  • Dashboard "Topics" grid — topic playlists now sort by curated pattern complexity (Two Pointers → Sliding Window → ... → Dynamic Programming → Matrices) instead of alphabetically. Previously "Backtracking" appeared first and "Two Pointers" last purely because of name sort order.

Added

  • Pattern.complexityScore — a curated complexity rank (1–16) for each of the 16 registered patterns.
  • Playlist.order — an explicit sort key for playlist listings, letting curated sets (e.g. "Top Picks") and topic playlists be ordered deliberately instead of by name or creation time.

[0.38.0] — 2026-07-15 — Playlist progress home

Added

  • Playlist page rebuilt as a progress home (/playlist/[slug]) — a hero with the playlist's pattern Elo (or a list-scoped rating for mixed lists), a rating trend graph replayed from your attempts on that list, and a five-axis skill radar (Coverage, Accuracy, Recognition, Edge cases, Speed). Single-pattern topic playlists link straight to their interactive pattern explainer.
  • Per-problem Elo signal + soft status — each problem row shows the rating change from your last rated attempt on it and a gentle status (In good shape / Keep going / Not started); ?list= deep links are preserved.
  • AI progress insight (Pro) — 1–3 short bullets on how you're doing and what to improve next, grounded only in your playlist metrics and the pattern's notes. Gated behind the playlist-ai-summary feature flag and Pro entitlement; free users see an honest locked card, and no AI call is made when locked or when the flag is off.

[0.37.2] — 2026-07-15 — Pattern Explainer chip merging + scroll containment

Fixed

  • Binary Search explainer — the mid marker sat on a permanently separate pointer row, floating detached below lo/hi even when nothing overlapped; lo/mid/hi now share one row and merge into a single labeled chip when they coincide (lo·mid, lo·mid·hi), matching the Greedy explainer's marker behavior.
  • All explainers (code panels) — long skeleton lines bled past the panel border (Heap's swap line, Linked List's sublist walk); code bodies now scroll horizontally with the active-line highlight spanning the full line.
  • All explainers (playground / mental model / mistakes) — panning a wide visualization horizontally dragged the step label, timeline controls, phase text and meters out of view; those now pin to the visible edge while only the visualization scrolls.

[0.37.1] — 2026-07-14 — Pattern Explainer visualization consistency pass

Fixed

  • Binary Search explainer — the mid marker rendered underneath the array cells (a dead .bsviz height override never matched), so the probe pointer was invisible whenever it sat near lo/hi. mid now has its own pointer row, lo/hi merge into a single lo·hi chip when the range collapses to one element, and the inspector shows instead of a misleading 0 when no probe is active.
  • Graphs (topological sort) explainer — the state inspector rendered as unstyled inline text instead of the shared inspector cells; the node currently being processed was faded green like a finished node instead of highlighted blue; and the live-highlighted code skeleton panel was missing from the playground (every other explainer has it).
  • Greedy Algorithms explainer — the jump visualization's i/end/far markers stacked on top of each other whenever they landed on the same index (always true at the start); markers that coincide now merge into a single labeled chip (i·end, end·far) on the shared pointer row. Its CSS classes also collided with the shared graph-visualization namespace (gviz) and could bleed styles across pages after client-side navigation; renamed to a local jviz namespace.
  • Sliding Window & Two Pointers explainersleft/right pointer chips stacked when both pointers sat on the same index (single-element window, converged pointers); they now merge into one labeled chip.
  • DFS / BFS / Graphs shared graph language — resting edges, arrowheads, and node outlines were nearly invisible in both themes; raised their contrast and un-faded processed nodes so graph structure stays legible while state is signalled by color.
  • Intervals explainer — un-swept interval bars were rendered at 35% opacity and read as an empty panel; they now stay clearly legible with a dashed "not yet swept" border.
  • Heap explainer — node index labels collided with the root/current node's highlight ring in the tree view; labels now clear the ring.
  • Prefix Sum explainer — the checkpoint pointer chip was labeled l, indistinguishable from the digit 1 beside numeric checkpoints; renamed to left.
  • All explainers (Variations section) — cards with long one-line code snippets forced their grid column wider than the page, overflowing the viewport (grid items' implicit min-width); snippets now scroll inside their card.
  • Console noise: React "Invalid DOM property" warnings from kebab-case SVG attributes in the feedback dialog icon.

[0.37.0] — 2026-07-13 — Dynamic Programming Pattern Explainer

Added

  • Dynamic Programming interactive explainer (/patterns/dynamic-programming) — hand-built pattern page with House Robber as the reference instance: an animated street-and-ledger visualization of tabulation, a recognition quiz, a hover-annotated code skeleton (TypeScript / Python / Java), an editable playground with a scrubbable execution timeline, a naive-recursion vs. tabulation complexity race with real call counts, a mistake simulator that executes three genuinely wrong implementations (forgotten skip branch, adjacent lookback, botched base case), variations with LeetCode anchors, and a pattern-matching quiz. Follows Sliding Window's ten-section format; linked from the pattern notes wherever Dynamic Programming appears.

[0.36.1] — 2026-07-13 — Pattern Explainer viz UX (Heap, DFS, BFS, Graphs, Trie)

Fixed

  • Heap, DFS, BFS, Graphs, Trie Pattern Explainers — graph/tree visualizations used dark-only chrome (invisible edges and panel borders on light theme), stacked stack/queue/order badges on top of nodes, and Graphs was missing base graph styles entirely so the topo viz had no canvas frame. Rebuilt with a shared theme-aware node-link language (_shared/graph-viz.css), HUD chips below the canvas, dual labeled tree/array panels for Heap, and path/word-end highlighting for Trie.

[0.36.0] — 2026-07-13 — Greedy Algorithms Pattern Explainer

Added

  • Interactive Greedy Algorithms Pattern Explainer at /patterns/greedy-algorithms — a recognition quiz, a range-scout visualization for Jump Game II, an editable playground, a brute-force-vs-greedy complexity race, and a mistake simulator for three real bugs (local-only jumps, counting every farthest growth, looping past the last index) — built with the dsa-pattern-explainer skill.

[0.35.0] — 2026-07-13 — Matrices Pattern Explainer

Added

  • Interactive Matrices Pattern Explainer at /patterns/matrices — a recognition quiz, a grid visualization that walks spiral-order layer bounds (top/right/bottom/left), an editable playground for multiple grid shapes, a brute-rescan-vs-bound-spiral complexity race, and a mistake simulator for three real bugs (skipping reverse-wall guards, forgetting to shrink a bound, exclusive loop ends) — built with the dsa-pattern-explainer skill.

[0.34.1] — 2026-07-13 — Trie Pattern Explainer fixes

Fixed

  • Trie Pattern Explainer (/patterns/trie) — the prefix-tree visualization rendered as solid black circles with invisible connecting lines and invisible letters (broken CSS theming), the code skeleton highlighted the wrong line while stepping through the playground, the Variations cards had no styling and no LeetCode references, the complexity race was unreadable in light mode, and the playground's tree visualization changed height and reflowed on every step. All fixed — the tree now renders correctly in both themes, node positions stay fixed as the tree is built, and the code highlight tracks the active line correctly.
  • Pattern Explainer pages, all patterns (/patterns/*) — the blue and violet accent colors used for emphasized text, kickers, and labels across every pattern explainer page were tuned for dark mode only, making them nearly unreadable in light mode. Now theme-aware, like every other color in the design system.
  • Pattern Explainer pages, all patterns (/patterns/*) — panel borders, dividers, and subtle background tints (the glass card border, the variable inspector, code-panel dividers, quiz score card, summary tags, and more) were hardcoded to a white tint meant only for dark backgrounds, so they were invisible on the light theme. Now theme-aware.
  • Trie Pattern Explainer (/patterns/trie) — the Summary section referenced a CSS class that didn't exist, so it rendered as a plain, borderless box instead of the styled card every other pattern explainer uses, and was missing its closing tag chips entirely. Fixed to match the standard structure.

[0.34.0] — 2026-07-13 — Backtracking Pattern Explainer

Added

  • Interactive Backtracking Pattern Explainer at /patterns/backtracking — a recognition quiz, a decision-tree visualization with choose / prune / backtrack states for Generate Parentheses, an editable playground for n = 1..3, a brute-force-vs-pruned complexity race, and a mistake simulator for three real bugs (forgetting to undo, missing the close guard, recording partials) — built with the dsa-pattern-explainer skill.

[0.33.0] — 2026-07-12 — Prefix Sum Pattern Explainer

Added

  • A new interactive "Pattern Explainer" page for Prefix Sum (/patterns/prefix-sum), reachable from the pattern notes wherever Prefix Sum appears. Follows Sliding Window's ten-section format: an odometer-style decision-rule contract, an animated build-then-query mental model, a three-question recognition quiz, a hover-to-explain code skeleton (TypeScript, Python, or Java), an editable playground with multi-query support, a brute-force-vs-prefix-sum race, a "break it on purpose" bug simulator covering three real Prefix Sum mistakes, the pattern's common variations (range sum, prefix + hashmap, 2D, XOR), a final recognition quiz, and a one-line summary.

[0.32.0] — 2026-07-12 — Graphs Pattern Explainer

Added

  • Interactive Graphs Pattern Explainer at /patterns/graphs — a recognition quiz, a node-link graph visualization with live indegree badges and the ready queue for Kahn's algorithm, an editable playground, a complexity race (naive rescans vs single O(V+E) pass), a mistake simulator for three real bugs (forgetting to decrement, ignoring incomplete results), and a three-question quiz — built with the dsa-pattern-explainer skill.

[0.31.0] — 2026-07-12 — Trie Pattern Explainer

Added

  • Interactive Trie Pattern Explainer at /patterns/trie — a recognition quiz, an auto-animating prefix tree visualization, an editable playground inserting and searching for prefixes, a complexity race (naïve array prefix search vs optimal trie), and a mistake simulator covering common bugs (forgetting isWord = true, confusing search and startsWith) — built with the dsa-pattern-explainer skill.

[0.30.0] — 2026-07-12 — Breadth-First Search Pattern Explainer

Added

  • Interactive Breadth-First Search Pattern Explainer at /patterns/breadth-first-search — a recognition quiz, a node-and-link graph visualization showing the current node, FIFO queue frontier, visited set, level, and discovery order, an editable playground with multiple starting nodes, a complexity race (DFS-for-shortest-path vs BFS level-by-level), and a mistake simulator exercising the classic queue bugs (no visited guard, mark on dequeue, pop instead of shift) — built with the dsa-pattern-explainer skill.

[0.29.0] — 2026-07-12 — Depth-First Search Pattern Explainer

Added

  • Interactive Depth-First Search Pattern Explainer at /patterns/depth-first-search — a recognition quiz, a node-and-link graph visualization showing the current node, recursion stack path, visited set and discovery order, an editable playground with multiple starting nodes, a complexity race (naïve restarts vs single traversal with visited), and a mistake simulator exercising the classic guard bugs (no visited check, mark too late, reversed child consideration) — built with the dsa-pattern-explainer skill. Introduces the reusable GraphViz component for future DFS/BFS/Graph explainers.

[0.28.0] — 2026-07-12 — Intervals Pattern Explainer

Added

  • An interactive Intervals Pattern Explainer at /patterns/intervals — a recognition quiz, a number-line mechanics visualization (sort, then sweep, extending or closing a merged reach), an editable playground, a complexity race, and a mistake simulator covering three real bugs (forgetting to sort, an off-by-one on touching endpoints, and overwriting instead of extending the merged reach) — built with the dsa-pattern-explainer skill.

[0.27.0] — 2026-07-12 — Linked-List Pattern Explainer

Added

  • Interactive Linked List Pattern Explainer (/patterns/linked-list): a recognition quiz, a node-and-arrow mechanics visualization built around iterative in-place reversal, a variable playground, an animated re-scan-vs-single-walk complexity race, and a mistake simulator covering the three classic reversal bugs (flipping before saving, forgetting to advance the walker, returning the wrong pointer).

[0.26.0] — 2026-07-12 — Stack Pattern Explainer

Added

  • A new interactive "Pattern Explainer" page for Stack, reachable from the pattern notes you already see (both the standalone pattern page and the in-workspace Notes tab link to it). Ten focused sections built around a single running example — Next Greater Element — including a "waiting room" mental model, a three-question recognition quiz, a hover-to-explain code skeleton (TypeScript, Python, or Java), an editable step-through playground, a brute-force-vs- stack race, a "break it on purpose" bug simulator with three real monotonic-stack mistakes, the pattern's common variations (next-greater, distance-based, bracket matching, augmented stacks), a final recognition quiz, and a one-line summary. Introduces a new vertical LIFO visualization for the stack itself, alongside the existing array-cell visualization reused by the array/window family of patterns.

[0.25.0] — 2026-07-12 — Heap Pattern Explainer

Added

  • A new interactive "Pattern Explainer" page for Heap, the second in the series after Sliding Window. Ten sections walk through a size-k min-heap keeping the largest values seen in a stream: a bubble-buoyancy mental model, a three-question recognition quiz, a hover-to-explain code skeleton (TypeScript, Python, or Java), an editable step-through playground, a heap-vs- brute-force race, a "break it on purpose" bug simulator with four real broken implementations, the pattern's common variations, a final recognition quiz, and a one-line summary. Introduces a new array-as-tree visualization, reused across every section on the page.

[0.24.0] — 2026-07-12 — Binary Search pattern explainer

Added

  • An interactive Binary Search Pattern Explainer at /patterns/binary-search: a recognition quiz, an auto-animating "higher, lower, gone" mechanics walkthrough, a hoverable reference skeleton in TypeScript/Python/Java, a scrubbable playground over your own sorted array and target, a linear-vs-binary complexity race, a mistake simulator covering three real bugs (wrong loop bound, eliminating the wrong half, forgetting to advance the pointer), variations with real LeetCode anchors, and a closing quiz.

[0.23.0] — 2026-07-12 — Two Pointers Pattern Explainer

Added

  • Interactive Two Pointers pattern explainer at /patterns/two-pointers: a recognition quiz, a mechanics visualization of pointers converging from both ends of a sorted sequence, an editable playground with a step-by-step trace, a complexity race against brute-force all-pairs, three simulated wrong implementations (wrong direction, blind advance, an off-by-one boundary bug), real LeetCode variations, and a closing quiz.

[0.22.0] — 2026-07-12 — Pattern Explainer authoring skill

Added

  • A repo skill (dsa-pattern-explainer) codifying how to build the remaining 15 interactive Pattern Explainer pages consistently with Sliding Window's: the section structure, shared components, and copy voice, so each new pattern is a scaffolding pass instead of a from-scratch design.

Changed

  • Internal only, no user-facing change. Extracted the pattern-agnostic pieces of the Sliding Window explainer (reveal/number/section-header components, the page nav, motion and timeline hooks, and the shared stylesheet) into app/patterns/_shared/, so future pattern pages import them instead of duplicating them.

[0.21.1] — 2026-07-08 — Governance audit reconciliation

Fixed

  • Internal only, no user-facing change. Reconciled findings from a structural audit of the project's governance documents: a stale cross-reference in prisma/patterns/CLAUDE.md to a retired data structure, an undeclared vendored-docs path in the governance map, and two architecture decision records whose status hadn't been updated after their changes shipped.
  • Bumped the constitution-cli dev dependency (governance tooling, not part of the app).

[0.21.0] — 2026-07-06 — Sliding Window Pattern Explainer

Added

  • A new interactive "Pattern Explainer" page for Sliding Window, reachable from the pattern notes you already see (both the standalone pattern page and the in-workspace Notes tab now link to it when available). It replaces a plain scrolled block of text with ten focused sections: the decision-rule contract, an animated mental model, a three-question recognition quiz, a hover-to-explain code skeleton (TypeScript, Python, or Java), an editable step-through playground, a brute-force-vs-sliding-window race, a "break it on purpose" bug simulator, the pattern's common variations, a final recognition quiz, and a one-line summary.
  • This is a pilot for one pattern; the rest of the pattern notes are unaffected and continue to work as before.

Changed

  • app/globals.css gained a handful of new design tokens (--text-body, --text-tiny, --code-bg/--code-dark-bg, --hit-target-mobile/--hit-target-desktop, --ease-out) used by the new page — no visual change to existing pages.

[0.20.0] — 2026-07-05 — Problem source attribution

Added

  • Problems can now credit the question bank they were adapted from. When a catalog entry has both a source platform and problem number set, the problem page shows a small "Inspired by LeetCode #42"-style line linking back to the original. Existing problems are unaffected — nothing is shown until a problem is explicitly attributed.

[0.19.0] — 2026-07-05 — Upgrade to Prisma ORM v7

Changed

  • Prisma upgraded from v6 to v7. The client now connects through an explicit @prisma/adapter-pg driver adapter instead of Prisma's engine reading the schema's connection URL directly. No change in database behavior or query semantics for end users.

[0.18.1] — 2026-07-05 — Catalog patternName reconciled against the pattern registry

Fixed

  • npm run problems:lint no longer fails on every catalog problem. Every patternName in prisma/problems/*.ts referenced the old 25-slug taxonomy (e.g. two_pointer, dp_linear, graph_dfs) instead of Article A7's 16 canonical pattern names, so every problem's patternName failed to resolve to prisma/patterns/:PATTERNS (introduced when the registry was populated in 0.18.0). Updated all 103 catalog entries across all 16 topic files to reference the canonical names (e.g. stack_count/stack_monotonicStack; union_find/topological_sort/ shortest_pathGraphs; tree_dfs_bottom_up/tree_dfs_top_down/graph_dfsDepth-First Search).

[0.18.0] — 2026-07-06 — Pattern registry populated; obsolete category mapping retired (Article A7)

Added

  • The pattern registry now has real content — all 16 patterns from Article A7 (Two Pointers, Sliding Window, Linked List, Prefix Sum, Intervals, Stack, Binary Search, Heap, Depth-First Search, Breadth-First Search, Graphs, Trie, Backtracking, Dynamic Programming, Greedy Algorithms, Matrices), each with a description written for the AI reviewer's alignment grading.
  • Governance conventions for the pattern registry — documented the closed 16-pattern set, its coverage floor, and note-completeness expectations across lib/features/CLAUDE.md, prisma/problems/CLAUDE.md, prisma/CLAUDE.md, and a new prisma/patterns/CLAUDE.md.

Changed

  • Topic playlists are now sourced directly from the pattern registry, not a separate hand-maintained category list — one source of truth instead of two lists kept in sync by convention.
  • Playlist documentation now correctly reflects the already-live TOPIC kind, alongside CURATED and USER.

Removed

  • The obsolete CATEGORIES list (and its unused icon/color fields) is gone from the database seed script.

[0.17.0] — 2026-07-06 — Pattern is a first-class database entity (Article A6)

Changed

  • Pattern is now a real database table, not a hardcoded 25-slug map. Problem.patternId, PatternNote.patternId, and Playlist.patternId (nullable) are schema-level foreign keys to Pattern.id — an unknown pattern now fails at the database, not silently. Extending the pattern set is a data change (prisma/patterns.ts), not a code change.
  • This is a hard cutover, not a preserving migration (ADR-0012): existing problems, attempts, ratings, and pattern notes are wiped and rebuilt from scratch. Every user's practice history and rating resets to zero. A brand-new pattern set and problem catalog are authored separately, after this lands.
  • Dashboard topic cards' "Owned" badge now resolves via a direct Playlist → Pattern link instead of a hardcoded slug map.

[0.16.2] — 2026-07-01 — Conformance re-audit: practice-loop ordering unguarded

Fixed

  • Article C1's enforcement was overstated as GATED. A conformance re-audit found the Approach-before-Code ordering has no server-side guard — only the lock's one-way-ness is repo-guarded; a direct API call can persist code with no approach ever locked. Downgraded to UNGUARDED and added to the mechanization backlog in CONSTITUTION.md. No behavior change; this corrects the governance record to match what the code actually guarantees.

[0.16.1] — 2026-07-01 — Governance document reorganization

Changed

  • Relocated the project constitution from decisions/CONSTITUTION.md to CONSTITUTION.md at the repo root, and moved the governance-map entry point from CLAUDE.md to AGENTS.md, aligning with the current governance framework's structural conventions. All cross-references across CLAUDE.md, AGENTS.md, lib/features/CLAUDE.md, and decisions/INDEX.md updated to match.
  • Fixed an ADR (0008) whose serves field pointed at a non-existent id.

[0.16.0] — 2026-06-29 — Pattern taxonomy completion (A1/A2)

Fixed

  • 5 catalog patterns were unregistered in the canonical taxonomy. greedy, merge_intervals, matrix, prefix_sum, and shortest_path were assigned to problems in 0.15.0 but missing from PATTERN_DISPLAY, the patternId→display map that also gates pattern-note generation. Effect: pattern notes returned unknown_pattern for any problem in those patterns, and the AI review's expectedPattern fell back to the raw slug (e.g. shortest_path) instead of a display label, weakening alignment grading. Added all five — the taxonomy is now 25 patterns and every catalog patternId resolves.

Changed

  • Pattern display labels now cover the full catalog: mastery views, the /patterns/[patternId] page, and OpenGraph images render proper names (e.g. "Shortest Path") for the five previously-unregistered patterns.

[0.15.0] — 2026-06-28 — Constitution Conformance: A1, A5 & A3

Fixed

  • Problem.patternId is now non-null (A1) — every catalog problem carries an explicit canonical patternId from the 20-pattern taxonomy; the schema column is tightened to NOT NULL.
  • Pattern-ownership floor raised to 5 attempts (A5)OWNED_THRESHOLD.minAttempts corrected from 3 to the constitution-ratified value of 5.
  • RawAttemptRow.patternNormalized renamed to pattern (A3) — aligns the type name with its actual content (the pattern display name derived from Problem.patternId) following the removal of Attempt.patternNormalized.

Removed

  • Dead patternIdForSeed() fallback — removed from seed.ts; every SeedProblem now carries an explicit patternId, making the runtime fallback unreachable.

[0.14.0] — 2026-06-28 — Expected Pattern AI Review Reinforcement & Schema Cleanup

Changed

  • AI coaching pattern payload & prompt — updated the coaching payload to retrieve the problem's static patternId and pass it as expectedPattern to the LLM reviewer. Configured the system prompt to explicitly verify this pattern, marking detours or sub-optimal patterns as a failure mode (mismatch/stall), even if test cases pass.
  • Rating replay engine — updated the Elo calculator to replay and group attempts directly using the problem's static patternId instead of the dynamic attempt field.
  • UI page pattern displays — updated the workspace review pane, attempts history page, and profile page to resolve pattern names from problem.patternId.

Removed

  • Attempt.patternNormalized database column — dropped the redundant dynamic post-coaching classification column from the Attempt table and generated the database schema migration.

[0.13.0] — 2026-06-28 — Concrete Problem to Pattern Mapping

Added

  • Problem patternId field — added a database-backed patternId field to the Problem model to establish a concrete static link between a problem and its canonical algorithmic pattern (e.g. two_pointer, sliding_window).
  • Seed patternId resolver — updated the database seed script to compute and seed patternId for all 103 catalog problems, utilizing default rules and custom overrides for complex tree/graph/stack/DP problems.

Changed

  • Workspace pattern note loading — modified app/problem/[slug]/page.tsx to read the canonical patternId directly from the Problem database record, eliminating the previous weak/imprecise playlist-slug mapping fallback.
  • Curated lists unification — transitioned curated lists to use the unified Playlist primitive (specifically kind="CURATED" playlists).
  • Dashboard back navigation — redirected back links on the playlist view to /dashboard instead of the redundant /lists page.

Removed

  • Obsolete /lists page & routes — deleted app/lists/ directory and all /lists and /lists/[slug] frontend routes. Added 308 permanent redirects in next.config.ts to forward old paths.
  • Redundant List module — deleted the entire duplicate lib/features/list/ backend directory (repository, service, types, and tests).

[0.12.0] — 2026-06-28 — Destructive Migration & Category Cleanup

Changed

  • Dashboard page & topic grid — transitioned the dashboard to render topic list cards using Playlist (specifically kind="TOPIC" playlists) instead of the obsolete Category model. Solved counts are tracked by playlist ID.
  • Problem slug page — updated page metadata, breadcrumbs, and pattern note mappings to read from the problem's first topic playlist rather than the defunct Category model.

Removed

  • Category database model — dropped the Category table and all category relations/references from Problem model.
  • Mode enum — dropped the database level Mode enum, Attempt.mode, and UserPreference.defaultMode.
  • Category service & repository — deleted the entire category feature folder (lib/features/category/).

[0.11.0] — 2026-06-28 — Single Approach->Code->Review loop

Changed

  • Practice modes collapsed — simplified the dual practice modes (LEARNING/INTERVIEW) to a single default flow. All attempts now use INTERVIEW mode (one-shot) by default, eliminating the toggles and branching logic.
  • Practice loop flow — now routes uniformly: Approach → Code → Review → Next/Retry.

Removed

  • Mode preferences and toggles — removed the mode toggle UI from Settings, user preference persistence for defaultMode, and mode column display in profile history.
  • Learning mode branching — removed branching logic from workspace and attempt creation, along with associated test assertions.

[0.10.0] — 2026-06-28 — Unified playlist routes + problems index

Added

  • /playlist/[slug] — a unified playlist view (topics, curated, any kind) showing problems in order with per-user solved/attempted status; opening a problem from here threads the playlist (?list=). Fires a playlist_opened event.
  • /problems — an index of every problem with all the playlists it belongs to (the many-to-many payoff), each tag linking to its playlist.
  • Playlist-aware practice loop — when a problem is opened with ?list=<slug>, the post-review CTA splits into Retry (same problem) and Next problem → (advances by playlist position); the last item routes to the playlist page instead of dead-ending. Without ?list, the loop is unchanged.

Changed

  • /topic/[slug]/playlist/[slug] — old topic URLs now 308-redirect to the unified playlist route, and the dashboard links straight to /playlist.

[0.9.0] — 2026-06-28 — Playlist data layer; Elo by difficulty score

Added

  • Playlist read layer (lib/features/playlist/*) — playlistService.getTopicPlaylists(), getPlaylistBySlug() (with per-user solved/attempted status), and getAllProblemsWithTags() (every problem with all the playlists it belongs to). Membership reads from PlaylistItem. Groundwork for the unified /playlist and /problems surfaces; not yet wired into a page.

Changed

  • Per-pattern rating scores against Problem.difficultyScore — the Elo "opponent" each attempt is rated against is now the numeric difficultyScore, falling back to the difficulty bucket when absent. Because difficultyScore is seeded from the same buckets, ratings and the pattern_owned signal are unchanged at cutover.

[0.8.1] — 2026-06-28 — Type-check fix for playlist repo tests

Fixed

  • lib/features/list/list.repo.test.ts mocks are now typed against the real Prisma findMany/findUnique signatures, so npx tsc --noEmit is clean again. No behavior change — the tests already passed at runtime.

[0.8.0] — 2026-06-28 — Playlist primitive groundwork (ADR 0010)

Added

  • Problem.difficultyScore — an additive numeric difficulty (migration 20260628120000_add_difficulty_score), seeded from the EASY/MEDIUM/HARD bucket (1000/1500/2000). It becomes the Elo opponent rating and the within-playlist sort key as the playlist unification lands; seeding it from the existing buckets keeps every rating unchanged at cutover.
  • Topic playlists — every topic is now also seeded as a kind="TOPIC" playlist whose membership mirrors that topic's problems, ordered by difficulty. This is the first step of making Playlist the single grouping primitive (ADR 0010). Non-destructive — Problem.categoryId is untouched in this release; the two-mode system and the Category model are removed in later Phase 2 steps.

[0.7.0] — 2026-06-23 — Dashboard as the navigation hub

Changed

  • Curated sets on the dashboard — curated lists now render in a "Curated sets" section on the dashboard (alongside Topics), instead of only at /lists.
  • Compact progress hero — the "Your progress" hero no longer fills the screen: the longitudinal trend chart and the in-progress patterns now sit side by side, so Topics and Curated sets are reachable without scrolling past a full-height hero. The company-specific placeholder moved into Curated sets.
  • Decluttered header — removed the Topics and Lists links from the global header; both are reached from the dashboard hub (the logo links home to the dashboard for signed-in users).

[0.6.0] — 2026-06-23 — Curated lists (playlists)

Added

  • Playlists — additive Playlist + PlaylistItem schema (migration 20260622140000_add_playlists). A playlist is an ordered set of problems; kind is "CURATED" or "USER". Problem.categoryId is untouched — membership is additive and many-to-many. (Phase 2 widens this into the canonical grouping primitive.)
  • "Top Picks" curated list — seeded (idempotent) with 16 foundational problems spanning the core patterns, ordered for a top-to-bottom warm-up.
  • /lists + /lists/[slug] — browse curated lists and work through a list's problems in order, with per-problem solved/attempted status. "Lists" added to the header nav.
  • List feature (lib/features/list/*) — listService.getCuratedLists() and getListBySlug().
  • lists_viewed + list_opened events — fire on the lists browse page (curated_count) and a list detail view (list_slug, problem_count, solved_count), making list-open rate measurable.

[0.5.0] — 2026-06-22 — Dashboard analytics hero

Added

  • Dashboard hero — the authenticated home now opens with a personalized hero: the global interview rating + tier, patterns owned (chips), problems solved, an in-progress patterns list (each with its rating and a progress bar toward the ownership bar), the longitudinal score-trend chart, and a company-specific placeholder (Phase 2).
  • PatternService.getRatingSummary — one pass over a user's attempts → global rating + per-pattern ratings, pre-split into owned vs in-progress.
  • ratingTier (lib/features/pattern/rating.ts) — maps a rating to a tier label (Novice → Mastery); the "Owned" band starts exactly at the ownership bar.
  • AttemptService.getScoreTrend — recent scored attempts shaped as chronological chart points.

Changed

  • Dashboard is server-rendered — the per-user hero and topic grid render on the server, removing the client-side /api/progress fetch waterfall. The page is now dynamic (category summaries stay cached). The topic-card "Owned" badge is mapped via the canonical pattern slug (patternIdForCategory) instead of a fragile category-name match.
  • ScoreTrendsChart moved to app/_components/ and shared by the dashboard and profile.

Removed

  • GET /api/progress and the client DashboardClient — superseded by server-side rendering of the dashboard.

[0.4.0] — 2026-06-22 — Per-pattern Elo rating; "owned" redefined

Added

  • Per-pattern Elo rating (lib/features/pattern/rating.ts) — computePatternRatings replays a user's finalized attempts on-read (no migration, no stored rating). Each attempt is an Elo "match" vs the problem's difficulty bucket (EASY 1000 / MEDIUM 1500 / HARD 2000); the outcome blends correctness, passing, time efficiency, and confidence calibration. Emits a per-attempt rating series for trend charts. computeGlobalRating is a capped attempts-weighted mean across patterns.

Changed

  • "Owned" is now Elo-basedOWNED_THRESHOLD changed from the rigid average-correctness/time/confidence gates over the last 5 attempts to { minAttempts: 3, minRating: 1600 }. computeOwnedPatterns is reimplemented on top of the rating, so ownership and the dashboard rating share one source of truth. This fixes the prior definition that left most users' north star reading 0 indefinitely.
  • OwnedPattern shape — now { pattern, rating, attempts } (was { pattern, attempts, avgCorrectness, avgTimeRatio, avgConfidence }). The pattern_owned analytics event now carries rating instead of the three avg_* properties.

[0.3.9] — 2026-06-22 — Signed-in users land on the dashboard

Changed

  • Authenticated home redirect — signed-in users hitting / are now redirected to /dashboard instead of seeing the marketing landing page. The landing copy and its sign-in CTAs only apply to logged-out visitors.

[0.3.8] — 2026-06-22 — DB and UX Performance Optimizations

Added

  • HTML5 Speculation Rules — added prefetching for /topic/* links and pre-rendering for /problem/* workspaces on hover.
  • Monaco Editor Preloading — preloads Monaco editor resources on approach lock to eliminate typing workspace transition latency.
  • Client-side dynamic progress API — added /api/progress dynamic endpoint to support client-side hydration of category progress.

Fixed

  • User Authentication DB Cache — cached user queries using react.cache() to prevent redundant Clerk API requests and DB writes on render cycles.
  • Page-level dynamic caching — wrapped problem slug lookups in request-scoped caching.
  • Aggregated Attempt Counting — rewrote attempt count checks using a single consolidated raw SQL query.
  • Static Topic Dashboard — refactored the topics dashboard to be statically pre-rendered instead of dynamically generated on every hit.
  • Decoupled Quota Chip — moved expensive entitlement DB checks out of root layout SSR to post-hydration client fetches.
  • Lazy Entitlement Grants — introduced eligible check guards to prevent unnecessary DB writes on campaign entitlement check cycles.
  • New Relic Dev Guard — prevented console noise and loading crashes in developer environments when license keys are missing.
  • Turbopack Scope Correction — pinned Turbopack watcher root to __dirname to restrict the watcher from reading the whole user home directory.

[0.3.7] — 2026-06-22 — Product analytics: funnel-granularity events (P1)

Added

  • dashboard_viewed event — fires when the Topics dashboard loads (with patterns_owned), the top of the activation funnel.
  • topic_selected event — fires on a topic page view (topic_slug, topic_name).
  • problem_opened event — fires on a problem page view (problem_slug, problem_id, category_slug, difficulty, is_preview), the step just before approach_committed.
  • credit_consumed event — fires server-side when a finite AI-review credit is actually spent (paywall on, not exhausted), with remaining. Closes the gap between ai_review_received and quota_exhausted for credit-burn-rate analysis.
  • TrackEvent client component (app/_components/TrackEvent.tsx) — fires a one-shot PostHog event on mount so server components can emit page-view-style funnel events.

Fixed

  • package-lock.json version sync — bumped to match package.json (the lockfile had drifted to 0.3.5 while package.json was 0.3.6).

[0.3.6] — 2026-06-22 — Preferred coding language persistence in UserPreference

Added

  • preferredCodingLanguage preference column — Added database-backed storage of the user's preferred coding language in the UserPreference table to avoid ambiguity with future localized spoken language (locale) preferences.
  • updatePreferredCodingLanguage server action — A lightweight server action to update the user's preferred coding language from the workspace environment dynamically.
  • Coding workspace and settings page synchronization — The settings page form now includes a select dropdown to view and update the preferred programming language. The coding workspace initializes Monaco's language from this DB preference if set (falling back to localStorage) and automatically updates it in the database when the user changes it in the coding pane.

[0.3.5] — 2026-06-22 — Product analytics: value-moment & paywall instrumentation (P0)

Added

  • ai_review_received event — the activation "aha" moment. Captured server-side on every run with success (coaching actually generated), failure_mode, passed, attempt_num, pattern guess vs normalized, and quota_remaining. Previously only attempt_run_completed fired, which couldn't tell whether the user got real coaching.
  • quota_exhausted event — fired when a free user hits the credit wall, the highest-intent monetization trigger (was previously unmeasured).
  • upsell_shown event — the in-workspace quota-wall UpsellCard impression (the in-product paywall surface had zero tracking).
  • pattern_owned event — the North-Star crossing. New PatternService.detectNewlyOwnedPattern detects, statelessly, when an attempt first tips a pattern into "owned" and emits the event once per crossing.
  • checkout_initiated surface property — now distinguishes workspace_quota_wall vs pricing_page (added to both the UpsellCard and pricing-page paths), enabling per-surface conversion analysis.

[0.3.4] — 2026-06-22 — Onboarding credit eligibility & webhook idempotency fixes

Added

  • Release-discipline CI gate — a Version & Changelog workflow (.github/workflows/version-changelog.yml) + scripts/ci/check-version-changelog.sh fail any PR into main unless package.json is bumped (valid, greater SemVer) and CHANGELOG.md has a matching ## [<version>] section. Make it a required status check in branch protection to enforce it. An emergency skip-release PR label bypasses the gate for hotfix rollouts.

Removed

  • Stale VERSION file — a vestige of the old gstack /ship 4-part versioning, frozen at 0.3.1 and read by nothing since the project adopted standard SemVer in package.json (commit 1ce3de2). package.json is now the single source of truth.

Fixed

  • Free-tier credit eligibilityfindEligibleGrants no longer excludes finite credit grants. A malformed NOT: { AND: [...] } clause collapsed to amount IS NULL, so the 5 signup credits (and any finite grant) were never returned when the paywall was enabled. Removed the clause; exhausted grants are still filtered by callers and by atomicReserve's WHERE used < amount guard.
  • Duplicate signup side effects — the Clerk user.created webhook now sends the welcome email and emits the user_signed_up analytics event only on first provisioning, guarding against duplicate webhook deliveries (svix retries).
  • API routes no longer throw across the boundaryPOST /api/attempts/[id]/run and POST /api/attempts now map unexpected errors (including AttemptConflict) to the standard JSON error envelope instead of surfacing a raw 500.
  • Attempt-creation rate limiting — added a STANDARD_ROUTE_LIMITS preset and applied it to POST /api/attempts, which was previously unthrottled.
  • Entitlement observabilityensureSignupGrant now logs when the signup_v1 grant cannot be provisioned (inactive/expired campaign) or throws, instead of failing silently.

[0.3.3] — 2026-06-20 — Workspace state, language parity & historical attempt fixes

Added

  • Monaco Editor model isolation — Bound the editor's key and path props to a unique string containing the problem slug and attempt identifier, preventing Monaco's global model cache from retaining and leaking past attempt code into the active workspace.
  • Stopwatch static duration for past attempts — Passed the calculated elapsed duration (completedAt - startedAt) to the stopwatch to render static time taken for past attempts instead of displaying 00:00.
  • Selected language persistence — Synchronized selected languages to localStorage under default_language, ensuring that the preferred language defaults correctly for new attempts and page reloads.
  • Dynamic template loading on language change — Added dynamic starter code template loading for non-seeded languages. Implemented GET /api/judge API endpoint to translate and cache missing starter codes on demand, complete with a visual progress overlay while loading.

Fixed

  • Missing AI reviews and test results in historical attempts — Fixed a bug where test results, console outputs, and AI reviews were not displayed when viewing past attempts in the workspace (fixed by reconstructing RunResult from Prisma JSON cases, and setting a dynamic key on the workspace based on the attempt identifier to force React to unmount and reset all states).
  • Results layout rearrangement — Swapped the order of the AI score graph (radar chart) and the before/after retry delta component in the results pane to show the score graph above the delta.

[0.3.2] — 2026-06-20 — Server-Side Execution Judge & GTM Launch Features

Added

  • Managed Judge0 CE API Integration — Migrated the server-side code execution engine from self-hosted Piston to a managed Judge0 CE API (via RapidAPI) with base64-encoded request/response sandboxing, supporting isolated code execution for 9 programming languages: Python, JavaScript, TypeScript, C, C++, Java, Kotlin, Rust, and Swift.
  • Judge Metadata & Harness Schemas — Added database migrations to record execution metrics (memoryKb, judgeVersion) on Attempt and seed language-specific wrapper testing code (harnesses) on Problem.
  • Judge Route Rate Limiting — Configured JUDGE_ROUTE_LIMITS sliding-window limits (10/min per user, 30/min per IP) to prevent denial-of-service abuse on the code execution endpoint.
  • Anonymous Pattern Cached Views & Preview Mode — Workspace pages at /problem/[slug] support preview mode for unauthenticated visitors, disabling editing and code runs and displaying sign-up CTAs. /patterns/[patternId] pages display cached-only views.
  • Dynamic sitemap & robots.txt — Dynamic /sitemap.xml and /robots.txt routes to allow public crawling of static and DB paths while disallowing private routes.
  • Dynamic Open Graph Images — Next.js metadata routes at /patterns/[patternId]/opengraph-image.tsx and /problem/[slug]/opengraph-image.tsx render custom dynamic OG cards.
  • Landing Page Refinement — Sleek landing page additions at app/page.tsx including structured pricing cards, testimonials, and footer links.
  • Campaign & Promo Route — Seeding of launch_week_2026 promotional campaign, and a dynamic /promo/[slug] route enforcing authentication/claims.
  • Welcome Email Webhook — Integrates Resend in the Clerk user.created webhook to automate welcome emails.
  • Product Hunt Launch Draft — Copwriting draft added at marketing/product_hunt_launch.md.
  • Per-Attempt History View — Users can now view past completed attempts in read-only mode by visiting /problem/[slug]?attempt=<attemptId>. This mode blocks Monaco editor inputs, disables language changes, stops the stopwatch, shows a custom past-attempt banner, and changes the ResultsPane CTA to "Resume active attempt".
  • In-Progress Workspace Resume — Auto-saves code drafts debounced (500ms) during the CODING phase to PATCH /api/attempts/[id]/code-draft. If a user reloads the workspace on an uncompleted attempt where the approach is locked, the workspace resumes straight to the CODING phase with Monaco populated with the draft code.

Fixed

  • Public Routes Access — Exposed /sitemap.xml and /robots.txt as public routes in middleware proxy.ts to prevent unauthenticated crawler redirects to Clerk login.
  • Typecheck Circular Reference — Resolved a pre-existing TypeScript circularity reference error in lib/rate-limit/postgres.provider.test.ts where typing mock variables with typeof tx inside callback parameters caused compiler type loops.
  • CSP Whitelisting & Prefetch CORS Redirects — Added permissions for accounts.dsamind.com and *.vercel.live inside next.config.ts, exempted static assets and /ingest routes in proxy.ts, and implemented dynamic client-side Link routing to /sign-in when logged out to avoid CORS prefetch redirects.
  • Custom Auth Routes — Added local app/sign-in and app/sign-up catch-all pages to prevent 404s when prefetching or visiting these paths.
  • Typecheck Compilation — Declared user outside the try/catch block in app/layout.tsx and passed isAuthenticated to <FinalCTA> and <Footer> in app/page.tsx to fix compiler type errors.
  • New Relic browser RUM injection moved from a hand-written <script dangerouslySetInnerHTML> in <head> to next/script's <Script strategy="beforeInteractive" dangerouslySetInnerHTML>, matching the existing theme-init script pattern. See ADR 0009 for the residual dangerouslySetInnerHTML trade-off (server-generated content, not user input).
  • Judge Service Tests Out of Sync with Judge0 Migrationlib/features/judge/judge.service.test.ts's execute suite mocked global.fetch with stale Piston-shaped responses, left over from before the Judge0 migration. Since judgeService.execute calls Judge0Client.submit directly, the mock was never intercepted and the suite failed in CI. Updated the suite to mock Judge0Client.submit with Judge0-shaped (base64-encoded, status: {id, description}) responses.

[0.3.1] — 2026-06-13 — M3 Observability + Rate-limit refactor

Added

  • PostHog analytics — 12 events instrumented across the user journey: user_signed_up, attempt_created, attempt_run_completed, approach_committed, code_run, self_score_saved, coaching_retry_clicked, pro_plan_activated, checkout_initiated, checkout_session_completed, subscription_upserted, subscription_canceled. Client-side via instrumentation-client.ts, server-side via lib/posthog-server.ts singleton. All server events use Clerk user ID as distinctId for consistent identity across client and server.
  • New Relic APMinstrumentation.ts loads the New Relic agent on server startup (Node.js runtime only). newrelic.js configures EU datacenter (collector.eu01.nr-data.net).
  • New Relic Browser RUMlib/newrelic-browser.ts injects browser timing header via dangerouslySetInnerHTML in root layout. Guarded by NEXT_RUNTIME === 'nodejs'.
  • Pluggable rate-limit architecturelib/rate-limit/ replaces the old single-file rate-limit stub. RateLimitProvider interface with PostgresRateLimitProvider (default, always active) and UpstashRateLimitProvider (activated when UPSTASH_REDIS_REST_URL + UPSTASH_REDIS_REST_TOKEN are set). RateLimitEntry Prisma model for the Postgres sliding window.
  • Rate-limit advisory lock — Postgres provider uses pg_advisory_xact_lock inside the transaction to prevent concurrent burst bypass under READ COMMITTED isolation.

Fixed

  • Rate-limit 429 response body now matches API contract ({ ok: false, error: { code: 'TOO_MANY_REQUESTS', message: '...' } }).
  • Retry-After header is always included in 429 responses (falls back to windowSeconds).
  • IP extraction prioritises x-real-ip (platform-set, not user-spoofable) over x-forwarded-for.
  • PostHog NEXT_PUBLIC_POSTHOG_HOST default changed from EU to US to match /ingest rewrite target.
  • subscription_created PostHog event renamed to subscription_upserted (fires on both create and update).
  • Upstash provider no longer adds a redundant rl: key prefix (aligned with Postgres provider).

[0.2.2] — 2026-06-13 — v0.3 perception layer + workspace QA

Added

  • post-merge git hook (scripts/git-hooks/post-merge). Runs npx prisma generate automatically when a merge brings in changes to prisma/schema.prisma, and prints a warning pointing to npm run db:migrate / npx prisma migrate deploy when prisma/migrations/ changes. Self-installs via a postinstall npm script (scripts/install-git-hooks.mjs) that sets core.hooksPath — zero manual setup per clone. Motivation: after PR #9 landed schema changes on main, developers who pulled were left with a stale lib/generated/prisma/ (missing Attempt / PatternNote delegates), causing a runtime "Cannot read properties of undefined (reading 'findMany')" on /dashboard.

  • Repository governance system: layered CLAUDE.md + AGENTS.md, decisions/ ADRs, CHANGELOG.md, scoped CLAUDE.md for prisma/, prisma/problems/, app/api/. See ADR-0001.

  • .claude/skills/ project skills: dsa-implement-feature, dsa-add-api-route, dsa-migrate-schema, dsa-audit-governance, dsa-verify-ship, dsa-capture-work.

  • gstack skill suite — added the routing section + skills list to root CLAUDE.md.

  • Workspace QA sprint — PR2 (UX/state): Signals pill moved to position: fixed at the viewport level in ProblemWorkspace (gated on attemptId !== null), escaping all pane flex/scroll/overflow constraints permanently. "Start next attempt" now resets the editor to starterCode so each attempt begins from a clean slate.

  • v0.3 perception layer — PR1 (data + AI infra):

    • Mode enum (LEARNING | INTERVIEW) on Attempt, default INTERVIEW (preserves v0.2 single-shot semantics for existing rows).
    • AttemptScore.scoreConfidence JSON column — AI-emitted per-metric confidence (1-5) for the subjective metrics (patternRecognition, skeletonFluency, edgeCases, confidenceAfter).
    • PatternNote model — globally cached AI-generated pattern teaching notes, one canonical row per pattern slug, lazy-generated on first LEARNING-mode access.
    • lib/features/pattern/pattern-note.{repo,service}.tsgetOrGenerate (cache-first, AI-fallback) + findCached. Canonical-slug ↔ display-name map covers all 20 patterns from v0.2 PRD §11 taxonomy.
    • lib/ai/{agents,prompts}/pattern-note.{agent,prompt}.ts — Anthropic-backed agent; default model claude-sonnet-4-6, configurable via DSA_PATTERN_NOTE_MODEL.
    • GET /api/pattern-notes/[patternId] — auth-gated route, zod-validated snake_case patternId, returns { content, generatedAt, model, cached }.
    • prisma/scripts/pregen-pattern-notes.ts + npm run db:pregen-notes — one-off pre-generation script for the 5 priority patterns (two_pointer, sliding_window, binary_search, dp_linear, tree_dfs_bottom_up).
    • AI scoring fills all 8 metrics + scoreConfidence (T6 + T24). Coaching prompt rubric expanded to score patternRecognition, skeletonFluency, edgeCases, confidenceAfter from signals + code + approach text + timing, alongside the existing observable metrics (correctness, timeRatio, complexityAchievement, planCodeAlignment). The agent also emits a scoreConfidence map — its own 1-5 confidence in each of the four subjective scores. Persisted to AttemptScore on finalize and on RetryCoachingButton re-run. SelfScoreForm stays in the UI for now (deletion lands in PR2 with the page restructure).
  • v0.3 perception layer — PR2 (in progress):

    • Signal toolbar simplification (T3). Deleted the SignalContextInput sub-component. Signals are now pure one-tap — no "what's blocking you?" affordance. (Server discarded the value anyway, and a text input at the moment of cognitive breakdown contradicts the product principle of zero friction during breakdown.)
    • Structured 4-section coach output (T4 + T17). Coaching agent now emits three discrete text sections (gotRightdivergencenextStep) via the existing tool call, plus the failureMode enum as the fourth visible section. CoachingNote renders all four with the first ("What you got right") getting heavier visual weight via emerald-500 left-accent — coach, not critic, per design D4. Structured sections persist to attempt.metadata.coachingSections; the flattened concatenated string still writes to attempt.coachingNote for backward compat with v0.2 rows.
    • Single-page progressive disclosure (T2 + T5 + T16 + Eng-D2). The problem page (/problem/[slug]) is now the single home for the entire attempt lifecycle: Approach → Code → Tests → AI Review → Start Next Attempt. The dedicated review route (/attempt/[id]/review/page.tsx) is deleted; old bookmarks 404 (Eng-D2 = C). Each section reveals progressively as the previous CTA fires; locked sections (Approach after Write Code, Code after Run) render at full contrast with a small 🔒 + timestamp badge (T16 — settled, not disabled, per design D3). The Review section renders inline using the same reusable components from _components/ (CoachingNote, SignalTimeline, EdgeCaseComparison, RetryDelta) plus a new submitted-code panel (T5) and an AI-score chip row showing all 8 metrics as 1-5 dots (timeRatio shown as 0.92× float). "Start Next Attempt" resets the page in-place for a fresh attempt on the same problem. The /run API now returns the full review + previous-attempt summary inline so no follow-up fetch is needed.
    • Mode selector (T2 partial / A2 deferred). A segmented [ Learning | Interview ] control sits at the top of the problem page; the chosen mode is persisted on Attempt.mode (default INTERVIEW). The mode-divergent iterative behavior from A2 (LEARNING allows multiple Runs before user-triggered finalize) is deferred to PR2.1 — for now both modes behave identically (one-shot lock on Run per D9). The selector locks in place once the attempt starts so the captured mode is stable. Mode visual distinction (D2): active section gets a subtle warm tint in LEARNING and stays cool zinc in INTERVIEW. A one-line descriptor under the selector explains what each mode means.
    • Approach panel — whiteboard restyle (D3 = A literal). All six measurement fields stay (pattern, steps, time, space, confidence, edge cases — load-bearing per CrackingInterviews/CLAUDE.md). Presentation reshaped: conversational question headings per block ("Which pattern is this?", "Sketch the algorithm in 2-3 lines."), generous block spacing, edge cases demoted to a collapsible + Edge cases (optional) link, redundant "Show problem description" toggle removed (the description stays visible in the left pane on desktop), CTA renamed Write Code → to match the page state machine.
    • P2002 race fix. Multi-keystroke onAttemptInteract was firing parallel POST /api/attempts calls before React state could mark one in-flight. The unique constraint (userId, problemId, attemptNum) would then fail. Switched the in-flight guard from React state to a synchronous useRef, with an await-loop fallback for parallel callers waiting on the first call's completion. Server-side: createAttemptRecord is now idempotent (returns the existing in-progress attempt instead of destroying it via deleteMany).
  • Pattern Notes — AI-Nudged Pattern System. /patterns/[patternId] pages surface AI-generated contract-first teaching notes (Mental Model → Templates → Rules → When to Use → Edge Cases → Drill). Nudge card (PatternNudgeCard) fires post-attempt in both the desktop (ReviewPane) and mobile (MobileReviewSection) render paths when failureMode is pattern_mismatch or approach_void and the pattern maps to a known slug. Reuses the existing patternNoteService.getOrGenerate() and CoachingResult.normalizedPattern — no second LLM call. taxonomyNameToPatternId added to pattern-note.service.ts to bridge the Title Case Attempt.patternNormalized values to snake_case slugs. Routes are public by default (no Clerk middleware change). Visualizer and DB-backed personalization deferred to Phase 2.

  • v0.3 perception layer — PR3 (in progress, hygiene + polish):

    • Light/dark theme toggle (T8). Class-based dark mode (Tailwind 4 @custom-variant), cookie-persisted (theme=light|dark, SameSite=Lax, 1yr). Layout reads the cookie server-side and sets .dark on <html> before render; head-script fallback honors prefers-color-scheme for first-visit users without the cookie. ThemeToggle button in the header (sun/moon glyph, accessible label) flips both the class and the cookie. prefers-reduced-motion CSS hook added to globals.css.
    • Clickable problem rows (T9 part 1). ProblemList rows now navigate as a whole — typing useRouter().push() on row click, with a guard that skips when the user clicks the inner title <Link> (preserving keyboard nav + right-click + screen-reader path).
    • Back-link contrast (T9 part 2). text-zinc-500text-zinc-700 dark:text-zinc-400 across all top-of-page back-links (topic, problem, attempts pages). WCAG AA contrast on resting state; the previous styling was failing on light mode.
    • Uniform dashboard cards (T10 part 1). min-h-[170px] on topic cards; Link wrapper now block so the article fills the link's full height. Descriptions still use line-clamp-2 so taller content doesn't expand a single card past its neighbors.
    • Regression fix. app/problem/[slug]/attempts/page.tsx was linking each historical attempt to /attempt/[id]/review, which 404s after PR2's Eng-D2 deletion. List rows are now static (no link); per-attempt deep-linking will return via a ?attempt=<id> query param in a follow-up.
  • Workspace QA sprint — radar chart (issue 7):

    • ScoreRadar replaces AIScoreChips in ResultsPane. Scores are now visualized as a radar chart (recharts@^2.15.4, dynamic import with ssr: false). Eight axes: correctness, time ratio, complexity, plan↔code alignment, pattern recognition, skeleton fluency, edge cases, confidence after. timeRatio (a float) is normalized to 1–5 via clamp(5 / v, 1, 5); v = 0 maps to 5 (no target set). Null score (coaching failed) renders an "AI analysis not available" placeholder instead of the chart.
    • edgeCases added to METRIC_LABEL. The array had 7 entries; edgeCases was missing. Now all 8 AttemptScore dimensions are covered.
  • Workspace QA sprint — AI behavior (issues 1, 2, 3, 6):

    • AI gate on syntax errors (issue 1). finalizeRun now skips the coaching API call when run.status === "ERROR" — syntax/runtime crashes are not coaching opportunities. coachingError is set to "skipped:error" instead. runStatus is persisted to attempt.metadata (JSON column, no migration needed) so retryCoaching can also gate on it without re-reading run results.
    • AI loading indicator split (issue 2). running in ProblemWorkspace is now two phases: testRunning (browser test execution) and reviewLoading (AI POST). ResultsPane shows Tests/Console tabs immediately after tests finish and renders an animated skeleton in the Review tab while the AI call is in flight. reviewLoading is skipped for ERROR runs.
    • approach_error failure mode (issue 3). New mode added to FAILURE_MODES in lib/dsa-taxonomy.ts for algorithmically-wrong approaches (wrong search direction, incorrect loop invariant, etc.). Coaching prompt divergence section now checks both implementation drift and algorithmic correctness of the approach. CoachingNote label added; TypeScript exhaustiveness check on FAILURE_MODE_LABEL enforces completeness.
    • Clean-pass brevity (issue 6). Coaching prompt updated with a 2-sentence budget exception for clean passes and a CLEAN PASS SHORT-CIRCUIT instruction — prevents verbose output when the attempt passed cleanly with no drift.
  • Fix: ERROR run no longer locks the code editor. setCodeLocked(true) is now deferred until after the browser test completes and the status is confirmed non-ERROR. For status === "ERROR" the editor stays unlocked, the Run button stays visible, and the server POST is skipped — the attempt remains in-progress so the next successful run finalises it normally. Fixes the regression introduced by PR #51's AI-gate (issue 1), where skipping coaching on ERROR still left the user unable to edit their code.

  • Fix: AI coach now runs for case-level runtime errors. The "ERROR" status is overloaded in the browser runner: it covers both true syntax/compile errors (worker fails to parse, results = []) and case-level runtime exceptions (function ran but threw inside a test case, results.length > 0). The coach gate — in both useAttemptLifecycle.ts (client) and attempt.service.ts (server) — now discriminates on results.length === 0 rather than status === "ERROR". Result: all tests throwing a runtime error (e.g. null.length, wrong return type) now correctly lock the editor and trigger AI coaching. retryCoaching gate also updated: now checks cases.length === 0 instead of the stale runStatus === "ERROR" metadata field, which is more robust and backward-compatible.

Changed

  • Migration history note: shadow-DB validation is broken because 20260511223558_add-attempt-signal-score-replace-submissions-userproblem predates the 20260512000000_baseline it depends on. The v0.3 migration was authored via prisma migrate diff + applied with prisma migrate deploy to bypass shadow validation. Future schema changes will need the same workaround until the migration history is repaired.
  • ProblemSolver lint fixes. Removed useEffect that called setMidTab synchronously (violated react-hooks/set-state-in-effect); setMidTab("CODE") is now called at each phase-transition callsite (approach→coding, run→reviewing, review received). Removed headingRef prop from TestsBody and ReviewPane (was declared but never passed a value — dead prop). Pane tab labels shortened to "Approach" / "Code" (numbers dropped).
  • Vitest type fix in attempt.service.test.ts. Replaced jest.Mocked<AttemptRepository> (Jest global namespace) with Mocked<AttemptRepository> from "vitest" — the project uses Vitest; the Jest shim was hiding a real type boundary.
  • Landing page copy. Removed "Phase 1 / 2 / 3 / The north star" kicker labels from feature sections; trimmed the "Twelve owned patterns" subtitle pending a content rewrite.
  • dsa-audit-governance skill. Added explicit 5-phase execution order (gather → static → semantic → historical → synthesis), tool/fallback policy for shell vs. file-read vs. Unable-to-Verify, expanded local CLAUDE.md budget rules with explicit glob patterns, monorepo workspace package.json handling notes, and clarified CHANGELOG entry format (multi-line bullets allowed; standalone prose paragraphs are not).
  • Governance dead-pointer sweep (round 1). Fixed 8 stale references found by /dsa-audit-governance: lib/auth.tsuserService from lib/features/user/user.service.ts (CLAUDE.md, AGENTS.md, app/api/CLAUDE.md); removed deleted lib/submissions.ts and lib/problem-json.ts from lib description (→ lib/features/problem/problem.types.ts); updated app/api/ project map to attempts/ + pattern-notes/; replaced submissions/route.ts guidance in app/api/CLAUDE.md with the live attempts/[id]/run path; removed duplicated "No DB in client" rule from prisma/CLAUDE.md; added missing dsa-capture-work to the CLAUDE.md skills list. Filed #49 to track legacy ProblemSolver.tsx deletion.
  • Governance dead-pointer sweep (round 2). Fixed 5 remaining gaps found by post-workspace-QA /dsa-audit-governance re-run: prisma/CLAUDE.md still referenced lib/auth.ts:getCurrentUser (→ userService.getCurrentUser() in lib/features/user/user.service.ts) and the deleted UserProblem composite key example (→ Attempt @@unique with ADR-0002 note); CLAUDE.md project map missing app/attempt/, app/patterns/, lib/ai/, and lib/dsa-taxonomy.ts; app/api/CLAUDE.md route list updated to enumerate v0.3 sub-routes ([id]/approach, [id]/score, [id]/signals); prisma/CLAUDE.md query-patterns rule rephrased to be an elaboration (not a restatement) of the root singleton rule.

[0.3.0] — 2026-06-11 — v0.4 Market Readiness (M0+M1+M2)

Added

  • Stripe Checkout integration: POST /api/checkout creates a Stripe Checkout Session (redirect-to-Stripe). Supports two plans: Pro ($9/mo, recurring) and Interview Pass ($29, one-time 90-day unlimited grant). client_reference_id and metadata.userId wire the session back to the local user record.
  • Stripe webhook handler (POST /api/webhooks/stripe): raw-body signature verification via stripe.webhooks.constructEvent. Handles checkout.session.completed (Interview Pass → 90-day CreditGrant; subscription → Subscription row upsert), customer.subscription.created/updated (re-fetches authoritative state from Stripe — order-agnostic), and customer.subscription.deleted (marks canceled). 200 returned even on handler errors to prevent Stripe retries causing double-grants.
  • Billing portal redirect (GET /api/billing-portal): redirects authenticated Pro subscribers to the Stripe Customer Portal. Falls back to /pricing if no active subscription.
  • /pricing page: single Pro card (copy leads with loop value, not feature list), Interview Pass card, quiet free-tier text ledger, FAQ (6 questions). Anti-slop constraints: zinc surfaces, Geist Mono price, text ledger under 11px uppercase headers. Signed-in visitors see their remaining credits. Already-Pro visitors see billing management link.
  • /checkout/success page: polls /api/quota at 1.5s intervals until remaining === null (Pro active) or 15s timeout elapses. Shows activation spinner → Pro confirmation → fallback message with support email if webhook is delayed.
  • UpsellCard component: shown when quota is exhausted. Achievement recap ("5 free reviews used") → honest review skeleton (section labels as empty outlines, no blur) → "Upgrade to Pro" checkout CTA → "Keep practicing" pattern-note link. Per design findings 9, 11, 14.
  • Pre-spend quota surfacing in the code pane: amber "Last free review" label under the Run button at 1 remaining; grey "Tests run free · no AI review" note when quota is already exhausted.
  • Quiet "N reviews left" line after each rendered review for free users (amber at 1).
  • lib/stripe.ts — lazy Stripe client singleton. Throws a descriptive error if STRIPE_SECRET_KEY is missing at call time (not at module load, so next build is safe).
  • STRIPE_PRICE_PRO_MONTHLY and STRIPE_PRICE_INTERVIEW_PASS env vars documented in .env.example.
  • CONFIGURATION_ERROR and STRIPE_ERROR error codes added to lib/api-response.ts.
  • 7 new Prisma models (one migration: 20260611000000_v0.4_entitlement_billing_prefs): CreditGrant, UsageEvent (with UsageStatus enum: RESERVED | COMMITTED | REFUNDED), Campaign, Subscription, UserPreference, Feedback, AiCallLog.
  • lib/features/entitlement/: entitlement.types.ts (typed EntitlementFeature, QuotaSnapshot, ConsumeResult); entitlement.repo.ts (atomic reserve via raw UPDATE WHERE used<amount, commitOrRefund, upsertCampaignGrant); entitlement.service.ts (check, reserveCredit, settleCredit, grantForCampaign, lazy ensureSignupGrant fallback).
  • Three-transaction pattern in attempt.service.finalizeRun and retryCoaching: txn1 = atomic credit reserve, LLM call outside any transaction (avoids pgbouncer pool exhaustion), txn2 = commit on success / refund on LLM failure. Credits are never lost to our errors.
  • Clerk webhook (POST /api/webhooks/clerk): raw-body svix signature verification. user.createdprisma.user.upsert + entitlementService.grantForCampaign(userId, "signup_v1"). user.deleted → cascading deletion of all user data.
  • GET /api/quota: returns current user's quota snapshot for MeterChip.
  • MeterChip component in the header: shows "N reviews left" (amber at 1), "0 reviews left", or "Pro". Refreshes on window focus.
  • scripts/backfill-signup-grants.ts: idempotent --dry-run capable script to provision signup_v1 grants for all existing users.
  • signup_v1 Campaign seeded in prisma/seed.ts (feature: ai_review, grantAmount: 5, endsAt: null — evergreen).
  • 14 unit tests for EntitlementService (check, reserveCredit, settleCredit, grantForCampaign). Vitest alias @/lib/generated/prisma → lib/__mocks__/prisma-stub.ts so tests run without prisma generate.
  • DSA_PAYWALL_ENABLED env flag: instant rollback to v0.3 behavior (no quota checks) with zero redeploy.
  • CI workflow (.github/workflows/ci.yml): build + lint + problems:lint + vitest on every PR and main push. Postgres service container for integration tests using prisma migrate deploy on a fresh DB.
  • lib/env.ts — zod-validated environment contract. Server vars validated lazily (safe for next build in CI without runtime secrets); public vars validated at boot. Fail-fast error messages name the missing variable.
  • lib/logger.ts — level-aware structured logger. JSON output in production (parseable by Sentry/CloudWatch), coloured human-readable output in development. Replaces bare console.* in app code.
  • lib/rate-limit.ts — per-user + per-IP rate limiter on AI spend routes. Uses Upstash Ratelimit when UPSTASH_REDIS_REST_URL is configured; skips gracefully in dev/test. Applied to POST /api/attempts/[id]/run and GET /api/pattern-notes/[patternId].
  • Security headers (next.config.ts): X-Frame-Options: SAMEORIGIN, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy (no camera/mic/geo), and Content-Security-Policy-Report-Only (Report-Only in M0; becomes enforced in M1 after tuning against reports).
  • scripts/repair-migration-history.ts — one-time script to rename the baseline migration entry in _prisma_migrations on existing production databases after the timestamp reorder.
  • ADR-0003 (Sentry + PostHog observability stack), ADR-0004 (Stripe Checkout payments provider), ADR-0005 (campaign-based credit grant entitlement architecture).

Changed

  • proxy.ts: added /api/checkout/*, /api/billing-portal/*, /api/quota/*, and /checkout/* to the protected routes list.

Fixed

  • proxy.ts dead route matchers: removed references to /api/submissions and /api/problems (routes removed in v0.2). Replaced with the live protected route list (/api/attempts/*, /api/pattern-notes/*, /attempt/*, /settings/*, /profile/*) and an explicit public route list (/, /pricing, /terms, /privacy, /changelog, /help, /patterns/*, /api/webhooks/*).
  • Migration history ordering: renamed 20260512000000_baseline20260510000000_baseline so prisma migrate deploy on a fresh database applies the baseline schema before the add-attempt migration. Unblocks CI integration tests and green production deploys from scratch.
  • .env.example: rewrote from stale SQLite/mock-auth Phase A config to the live Postgres + Clerk + Anthropic stack. Added env var slots for Stripe, PostHog, Sentry, Upstash, and Resend (M1–M4 surfaces).

[0.2.1] - 2026-06-09

Added

  • Pattern and complexity dropdowns in the approach gate. Before opening the editor, you can now explicitly select the pattern you intend to use (e.g. Sliding Window, Two Pointers) and your target time and space complexity from fixed dropdowns. Leaving any blank is fine — blank = coached miss, surfaced in the post-run completeness card.
  • Complexity shown while coding. The "Your approach" strip visible above the editor now shows the time and space complexity you committed to, with an italic "not set" placeholder if left blank.

Changed

  • Approach gate is now the only entry point. ProblemWorkspace is promoted to the single renderer for the problem page — the ?ws=1 flag and the legacy ProblemSolver component are gone.

Fixed

  • Autosave reset bug on "Start next attempt". The autosave snapshot now correctly includes all five approach fields, preventing a spurious re-save of an empty draft on the new attempt.

Removed

  • Free-text extraction pipeline deleted. The regex + planned LLM approach-extraction infrastructure has been removed. Pattern and complexity are now captured deterministically via dropdowns, eliminating latency, cost, and non-determinism.
  • ProblemSolver.tsx deleted (1,901 lines). The legacy single-pane component is no longer used.

[0.2.0] - 2026-05-25

Added

  • DSA Mind Design System — triptych problem solver. Three-pane split layout (problem description / solver / AI review) with horizontal drag-to-resize handles. Replaces the single-column mobile-only layout with a proper desktop IDE-style workspace.
  • Tests dock with vertical drag. After running code, a resizable tests panel docks at 50% of the middle pane. Drag the handle up/down to resize. Hidden while coding so the code editor fills the full pane — appears only once Run is clicked.
  • Landing page redesign. Full new marketing page with Hero, three-phase feature sections (Approach / Code / Review), social proof strip, and a closing CTA. Removed Clerk auth component dependencies from the landing route.
  • RetryDelta metric cards. Four-card grid showing delta values (signals fired, plan↔code alignment, confidence after, time ratio) between the current and previous attempt. Replaced the earlier dumbbell chart.

Changed

  • body height: min-h-fullh-full. Root fix for the triptych: the body is now viewport-bounded, so flex-1 min-h-0 chains propagate correctly through all pane descendants. Previously the body could grow past the viewport, making flex-1 on <main> unbounded.
  • CoachingNote sections. Four structured sections (What you got right / Where it diverged / Next step) with 2px colored left rails (emerald/amber). Failure mode pill moves inline into the "Where it diverged" heading row.
  • Section header tokens. All review page headings standardized to text-[11px] font-semibold uppercase tracking-[0.08em] text-zinc-500.
  • SignalTimeline & EdgeCaseComparison. Section headings updated to design system tokens; track background and legend text refined.
  • Deleted CollapsibleDescription.tsx. Component was no longer imported anywhere; description is now passed as a React node prop into ProblemSolver.
  • attempt.service.test.ts — updated assertion to match finalizeRun's current return shape ({ reviewUrl, review, previous }).