Didact integration in SkillNet
Status: full inventory integrated; functional adoption by families
Didact: https://github.com/JoseEstevez520/Didact (MIT)
Revision examined: 06c80e8
Related: openui-adoption.md, personalization-architecture.md,
learning-experience-architecture.md, v2-dynamic-courses.md
Scope of this document: describes the current inventory and executable integration of Didact. The target neutral architecture —where Didact is a replaceable provider,
LearningExperiencereplaces the specific boundary, and legacy pedagogical blocks leave new courses— is defined inlearning-experience-architecture.md. When a historical incremental-adoption decision on this page contradicts that target, the neutral document wins; this page still wins on which types and ports work today.
Decision
SkillNet keeps pedagogical authoring, personalization, RAG, evaluation security, and on-the-fly generated OpenUI composition. Didact contributes accessible educational contracts and components. It is not integrated as a second course engine nor as a list of widgets the LLM must fully know.
objective + knowledge pack + closed profile
│
▼
SkillNet experience plan
│
▼
Didact capability resolver
│ 2–5 compatible candidates
▼
on-the-fly OpenUI generation
│
▼
validation → adapted Didact render → events
Didact offers the facets needed to select without inferring from names: purpose,
representation, learner action, context, accessibility, maturity, authoring schema,
capabilities, and optional dependencies. SkillNet adapts them to ComponentDescriptor;
the catalog doesn’t decide by itself what the person should learn.
Direct OpenUI base
Integration started with two experiences from the real skillnet-ui/1 catalog:
| Component | Why it’s included | State it keeps |
|---|---|---|
Flashcard(front, back) |
Recall attempt before reveal; useful for recognizing or reconstructing | reveal and local self-assessment |
HintReveal(title, hints, solution) |
Progressive hints and solution on request; especially useful with more scaffolding | hint count and visible solution |
Both comply with the static dialect: literal properties, local React state, no
Query, Mutation, executable code, or identity. Glossary, Timeline, and WorkedExample
were later added as direct blocks, and DidactActivity as an opaque reference to
server-owned definitions. Their schemas exist in frontend and backend; the drift test
checks names, property order, and the prompt artifact. The prompt version invalidates
renders produced with earlier catalogs.
In the first adoption, StepSequence wasn’t replaced by Timeline: they represented the
same capability and duplicating them in the catalog was avoided. This was an incremental
decision, not the target state. For new courses, the approved migration removes
StepSequence and the other legacy pedagogical components from the authoring catalog;
Didact enters through the neutral LearningExperience boundary. Legacy renderers remain
only to play back published courses. Spaced repetition also wasn’t added; Didact
correctly separates the card from repeat scheduling, and SkillNet doesn’t need that
scheduler yet.
Selection as the catalog grows
Current executable boundary
Full availability and model exposure are two distinct sets:
didact_snapshot.jsonandexport_didact_descriptors()project the 34 types to the resolver. They keep identity, facets, actions, representations, accessibility, producer, and port requirements; a blocked type remains discoverable for experiments and to explain what capability is missing.openui_names_for_shortlist()is the fail-closed gate. It only translates a type to its schema name when the renderer, emission permission, and ports are ready.build_didact_prompt_slice()serializes only those accepted schemas along with the safe screen shell. An installed but blocked type produces an explicit error; it never silently disappears or reaches the LLM without a contract.
Today all 34 types are inventoried and lazy-loaded in the frontend. Twenty-nine have an honest emission path: five direct OpenUI blocks, eleven server-side evaluations, three activities with reviewed assets, two host progress reads, and eight activities with definition, state, and ports. The other five remain available to the resolver but blocked until a scheduler, adapted simulation, or sandbox exist. The runtime table at the end of this document is the authority on each family.
The boundary is already wired to the generator: the runtime forms a shortlist of
3-5 types, applies renderer, port, and data gates, and hands the model only the
allowed slice. For rich activities, an authoring phase creates a server-owned
ActivityDefinition and validates it before persisting. If it can’t build one with
backed data, it Declines and falls back to a safe representation.
The model must not receive all of Didact’s components. Deterministic filters are applied before each generation:
- availability and allowed maturity;
- cognitive mission and source function;
- requirements present in the knowledge pack;
- mandatory accessibility capabilities;
- available producer (
content,assessment,media,simulation, ordeterministic); - declared presentation preferences, as a bias rather than an obligation;
- screen complexity budget.
The result is a small, versioned collection, not a rigid final choice. The LLM can
compose among those candidates and Decline if none honestly represents the
mission. component_id@version, capabilities, and selection version will enter
trace and cache once the filter moves from shadow to production.
Adoption levels
Level A — static and safe
Flat props or lists, ephemeral state, no external services. Can go directly into OpenUI: Flashcard, HintReveal, Glossary, and some visual representations.
Level B — response and host evaluation
The component collects a serializable response, but SkillNet keeps the correct answer and evaluates it via API. Matching, evidence-based rubrics, annotation, and advanced questions need mapping to the endpoint and event envelope before entering.
Level C — engine or injected medium
CodeExercise, InteractiveMedia, BranchingScenario, and SimulationLab need an explicit execution, playback, or state-transition port. A simulation is data + state + deterministic transitions + renderer; never LLM-invented code inside the OpenUI program.
Invariants
- More components add richness when they add actions, states, feedback, or useful representations.
- Critical facts and safety rules come from the knowledge pack, not the component.
- A visual preference doesn’t force a valueless image nor allow inventing an asset.
- The answer key never reaches props in the browser.
- Dragging is never the only way to interact.
- A missing capability produces an explicit fallback or
Decline, not a faked simulation. - The copy of a Didact component lives in SkillNet and is updated deliberately; a
mutable
mainis not consumed in production.
Frontend runtime matrix (2026-08-13)
All 34 types are installed, have a lazy loader, and can be referenced via
DidactActivity(activity_id, component_id). OpenUI never receives the public
definition, correct answers, or evaluation configuration. The didact.progress
and didact.mastery-badge percentage is injected by the host from
LearnerNodeState; the client can’t write it.
| State | Types | Reason |
|---|---|---|
| Usable local/static | flashcard, glossary-term, hint-reveal, rubric, timeline-steps, worked-example, data-explorer | Doesn’t claim correctness; absent optional ports degrade |
| Host persistence | self-explanation-prompt, concept-map, drawing-response, evidence-annotation | State via /activities/{id}/state; drawing and annotation accept async evaluation |
| Compatible host evaluation | equation-workbench, measurement-lab | Async callback with result from /activities/{id}/evaluate |
| Server-side evaluation | matching, sort, categorize, five quiz types, completion-problem, numeric-question, word-bank | SecureEvaluatedActivity adapter; the key never reaches props, DOM, or events |
| Reviewed assets | hotspot, label-diagram, interactive-media | Opaque skasset_ refs; geometry/transcript verified server-side |
| Read-only progress | progress, mastery-badge | GET /activities/{id}/progress projects node mastery; progress.write is forbidden |
| Blocked: composition/scheduling | practice-set, retrieval-practice-session | Composes evaluable children or requires a scheduler; not faked |
| Blocked: runtime | branching-scenario, simulation-lab | Missing adaptation of remote transitions to the component’s concrete state |
| Blocked: execution | code-exercise | The generic response still doesn’t satisfy ArtifactExecutionResponse |
Definition, state, evaluation, transition, execution, assets, and progress
endpoints are wired as generic ports. A port is only exposed when the concrete
contract is compatible. The mere existence of /evaluate doesn’t unlock a quiz
that self-corrects in the browser, nor does /progress enable practice-set.
Proposed next wave
- real scheduler before emitting
retrieval-practice-session; - composition of evaluable children before emitting
practice-set; - deterministic transitions for
branching-scenarioandsimulation-labover the component’s concrete state; code-exercisesandbox that satisfiesArtifactExecutionResponse;- measure the 7 selection strategies with the offline bench and, if a key is available, a small LLM pilot.
Each wave is measured with the same node and knowledge pack: critical-fact coverage, obtainable evidence, action variety, accessibility, repair rate, tokens, latency, and stability. A component isn’t promoted just because its isolated story is appealing.
Closing status as of August 13, 2026
- All 34 Didact types are pinned by commit, inventoried, and available via lazy loaders; the full catalog doesn’t increase the initial bundle.
- 29 types are emittable. Five remain honestly blocked:
practice-set,retrieval-practice-session,branching-scenario,simulation-lab, andcode-exercise. - The runtime defaults to
top5over a shortlist of 3-5 candidates. Dual-agent and specialist remain in shadow. The full catalog remains queryable by the resolver. - The optional authoring call logs tokens, model, and duration; if it fails, the
lesson continues with a safe representation. An
unsupportedtype declines before reaching the LLM. - The fixture experiment favors intent + shortlist + specific schema: 89.8 points and 100% gate pass, versus 27.8 for the legacy arm. This is architecture evidence, not definitive proof of LLM quality.
- Causal personalization remains weak (15.4% in the fixture). The next round must isolate scaffolding, presentation, and depth with real models and blind evaluation.