Adds a /topic-test route where learners can take a 5-question test on any
eligible topic at any time. Questions come from a shared, admin-curated
question_bank — no LLM calls on the user path. Points feed the existing
leaderboard with a 10pt/topic/week cap (per ISO week) so the bank can't be
farmed, and repeats from a thin bank yield 0 points.
- New PB collections: question_bank, on_demand_attempts (+ migrations and
setup-pb-collections.mjs entries).
- db.js: un-deprecates getQuizBank/setQuizBank against question_bank so the
existing admin TestManager panel becomes functional again; adds
saveOnDemandAttempt, getOnDemandPointsThisWeek, getUserSeenQuestionIds,
getAllOnDemandAttempts, isoWeekKey.
- testService.js: getEligibleTopicsForOnDemand, startOnDemandTest (unseen-
first draw), finishOnDemandTest (cap enforcement + leaderboard upsert).
- New TopicTest page, route, and nav entry; weekly test flow untouched.
- Leaderboard folds on-demand 100%s into perfect-score count and merges
on-demand attempts into the recent activity feed.
- Spec: docs/on-demand-tests-spec.md with ADRs and extension points.
- Tests: 5 new vitest cases covering eligibility, draw fallback, scoring,
partial cap, and exhausted cap (85/85 total).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a HelpCircle toggle button in the Dashboard header so users can
re-open the platform explainer after dismissing it. The per-user
dismissed state is preserved as the initial-open default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New theme_sessions + theme_session_completions PocketBase collections
- Generate a detailed per-week theme summary covering every topic in the
week's curriculum slot via EMIT_THEME_SESSION_TOOL; cache per
(curriculum_version, week_number)
- Replace Leren.jsx "This Week's Topic" card with "This Week's Theme
Session" that opens the new ThemeSessionView; per-topic micro-learnings
remain reachable as optional practice from inside the session
- Group the Knowledge Library by topic.theme, pin the current week's
theme on top, and badge topics already covered by the active session
- Mark week complete when the user finishes reading the theme session
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces a per-user, dismissible "How Respellion works" card on the
Dashboard so new users understand the learn/test/leaderboard loop and
where to find R42 and the main navigation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every micro-learning format used to call onComplete implicitly — scroll
to the bottom of the explainer, flip the last flashcard, or pick any
scenario option — which yanked users out of the content before they
were done with it.
Replace the implicit triggers with a Finish session button on each
format. The scenario quiz exposes the button only after an option is
chosen so explanations still get read; the flashcard set exposes a
viewed-cards counter next to it.
The topic-reviewed landing screen now offers Back to Station, Try
another format, and Go to test, so finishing a session leads somewhere
useful instead of dead-ending. Drop the unreachable completion box that
the container was rendering underneath the parent's success screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Truncates sources, curriculum, content, quiz banks/results/cache, topics
and relations in dependency order so AI-generated state can be wiped
between smoke runs without leaving dangling references. Handbook sync
state is cleared by default (otherwise re-sync is a no-op); user
progress and leaderboard are opt-in. Team members, settings, and LLM
telemetry are preserved.
UI lives in Admin → Settings → Danger Zone and requires typing RESET
before the button enables. Per-collection deletion counts are reported.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add dependency-free TF-IDF retrieval (src/lib/retrieval.js) with NL+EN
stopwords and a WeakMap-cached index.
- Rewrite buildKbContext to ship the top-K relevant topics + verbatim-
mentioned ids only, filter relations to the included set, and append a
[kb_hash: <8 hex>] suffix so the ephemeral prompt cache busts when the
graph changes. Returns { context, retrievedTopics, allTopics }.
- Add LOOKUP_TOPIC_TOOL and drive useChat through callLLM directly with a
multi-hop tool_result loop capped at 3 hops; preserve Anthropic-provided
tool_use ids through callLLM so the loop can echo correct tool_use_id.
- Truncate R42 history to the last 12 turns and prepend a single
"(earlier conversation truncated)" assistant message.
- Set R42 chat defaults: temperature 0.3, maxTokens 2048.
- Add pb_migrations/1780500002_created_llm_calls.js (the best-effort
logger in callLLM was already wired) and a new Admin → Diagnostics
view showing the last 100 calls with token usage, cache-hit rate, and
USD cost from a local Anthropic price table.
- Finalize AI_PIPELINE_HARDENING_PLAN.md: mark Phases 1–5 shipped and
Phase 6 (eval harness) explicitly out of scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements phase 1 of AI_PIPELINE_HARDENING_PLAN.md. Every Anthropic call
now goes through one module that owns retry, timeout, abort, structured-
output parsing, schema validation, and best-effort call telemetry.
* src/lib/llm.js — single callLLM entry point. Resolves model per tier
(fast / standard / reasoning) with admin:model legacy fallback for the
standard tier; 60s default timeout via AbortController; balanced-brace
JSON extraction; LLMHttpError, LLMTruncatedError, LLMOutputError, and
LLMValidationError surface clearly distinct failure modes.
* src/lib/llmRetry.js — exponential backoff with full jitter, retries
only on transient HTTP statuses, honours Retry-After up to 60s, never
retries on AbortError.
* src/lib/llmSchemas.js — Zod schemas for every structured task plus
normalizeHandbookResult (collapses legacy "executes" relations into
the canonical "executed_by" vocabulary).
* src/lib/api.js — thin shim over callLLM so existing callers (extraction
pipeline, learning, quiz, R42, knowledge graph) keep working unchanged.
* src/lib/__tests__/ — 32 Vitest cases covering parse paths, error
surfaces, simulation mode, model resolution, and schema validation.
* src/pages/Admin/index.jsx — three model inputs (fast / standard /
reasoning) replacing the single legacy field; legacy value falls back
for the standard tier so existing overrides survive.
Adds Zod and Vitest, plus an "npm run test" script.
Also cleans up the pre-existing repo-wide ESLint failures so phase 1's
"npm run lint passes" acceptance criterion can be checked: drops unused
React imports across the JSX tree (React 19 JSX runtime auto-imports),
attaches cause to rethrown errors in the service modules, ignores
pb_migrations in the ESLint config (PocketBase JSVM globals), and
removes one dead handleCreateCustom function in Leren.jsx. A real
behaviour bug surfaced in Testen.jsx — the quiz timer captured a stale
finishQuiz via setInterval closure; now updated via finishQuizRef so the
timer always invokes the latest callback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>