Files
learning-platform/docs/generation-spec.md
RaymondVerhoef 07af2783dc
All checks were successful
On Push to Main / test (push) Successful in 1m33s
On Push to Main / publish (push) Successful in 1m31s
On Push to Main / deploy-dev (push) Successful in 2m3s
Add comprehensive documentation for key organizational aspects
- Introduced "Pension Scheme & Benefits" detailing secondary employment benefits and pension specifics.
- Created "Roles & Accountabilities" outlining the Holacracy role structure and responsibilities within Respellion.
- Added "Security" section covering GDPR compliance and workplace safety protocols.
- Established "Spending and Contracting" policy detailing expense categories and submission processes.
- Documented "Who We Are" to define Respellion's identity, services, and operational model under Holacracy and ISO 9001.
2026-05-27 08:24:56 +02:00

88 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Generation spec: learning content & micro-learnings
Two generators turn a topic into learner-facing material. Both go through
`callLLM` with forced tool use and Zod-validated output. All content is cached in
PocketBase so it is generated once per topic/type.
---
## A. Long-form content — `src/lib/learningService.js`
Stored in the `content` collection (one record per topic, `data` is a merged
object). Three types, generated **on demand**:
| Type | Tool | Min requirements |
|---|---|---|
| `article` | `emit_learning_article` | ≥3 sections, ≥2 takeaways |
| `slides` | `emit_learning_slides` | ≥4 slides |
| `infographic` | `emit_learning_infographic` | ≥3 stats, ≥3 steps |
`generateLearningContent(topic, force, selectedType)`:
- tier `standard`, `maxTokens: 8192`
- `selectedType` is one of the three, or `'all'` (`emit_learning_all`) for admin regeneration
- cache check looks at `content[selectedType]`; on generation the new payload is
**shallow-merged** into the cached object so other types survive
- there is **no podcast type**
**Article refinement** (`refineLearningContent`): the admin describes a change and
the model edits via targeted patch tools — `set_intro`, `set_section`,
`add_section`, `remove_section`, `replace_takeaways` — so only the affected parts
change. Patches are applied and re-validated in `src/lib/articlePatches.js`.
---
## B. Micro-learnings — `src/lib/microLearningService.js`
Stored in the `micro_learnings` collection (one record per topic per type,
`status='published'`). Three types:
| Type | Tool | Tier | Shape |
|---|---|---|---|
| `concept_explainer` | `emit_concept_explainer` | standard | `{ sections: [{ title, content (HTML) }] }`, ≥3 sections |
| `scenario_quiz` | `emit_scenario_quiz` | standard | `{ scenario, options: [{ text, isCorrect, explanation }] }`, 34 options, exactly 1 correct |
| `flashcard_set` | `emit_flashcard_set` | fast (Haiku) | `{ cards: [{ front, back }] }`, 510 cards |
`getOrGenerateMicroLearning(topicId, type)`:
- returns the cached published record if one exists (`findExisting`)
- otherwise loads the topic, calls `callLLM` with forced tool choice, and creates a
`micro_learnings` record with the validated `content`
> A former `reflection_prompt` type was dropped. Do not re-add it.
Completion is recorded (append-only) by `useMicroLearningCompletions` into
`micro_learning_completions` with `{ team_member_id, micro_learning_id, topic_id,
type, session_week }`.
---
## C. Weekly quiz — `src/lib/testService.js`
Generates a 5-question multiple-choice test for the user's current week.
- **Topic selection** (`selectTestTopics`): primary topic from the active
curriculum week (else hash fallback) + a few review topics for breadth.
- **Batch generation** (`callQuizBatchModel`): a single `fast`-tier call
(`emit_quiz_questions`, `maxTokens: 4096`, 25s timeout) returns all 5 questions.
- **Quality gates** (`validateBatchQuality`): no duplicate options; no banned
fillers ("all/none of the above", "both A and B"); explanations ≥20 chars; reject
if `correctIndex` is dominated by one position (>80%) and re-roll.
- **Scoring** (`saveTestResult`): `pointsEarned = score * 2`, written to
`leaderboard` via `db.upsertLeaderboardEntry`.
Question shape: `{ id, question, topicLabel, options[4], correctIndex (03),
explanation, difficulty }`.
---
## Shared infrastructure (`src/lib/llm.js`)
- **Tiers:** `fast` (Haiku 4.5), `standard` (Sonnet 4.6), `reasoning` (Opus 4.7);
per-tier admin overrides via `admin:model:{tier}`.
- **Structured output:** prefer tool use with forced `toolChoice`; inputs validated
by `toolSchemaRegistry`. Text responses go through `parseStructuredText`.
- **Caching:** wrap stable system text with `cachedSystem(...)`.
- **Retry/limits:** `src/lib/llmRetry.js` — backoff + jitter on 408/425/429/5xx/529,
honors `Retry-After`, rate limiters for bulk work.
- **Telemetry:** every call logged to `llm_calls`.
- **Simulation:** with `admin:use_simulation`, calls return stub output (no API hit).