-
Notifications
You must be signed in to change notification settings - Fork 0
primitives progression events
Progression events are the append-only event log that is the source of truth for learner state. ProgressionEvent is a Zod discriminated union in src/core/progression.ts with five members: quest_completed, unlock, xp_award, badge_award, and hint_opened. The extension and CLI append these to events.jsonl, and the progression engine's foldEvents is a pure function that replays the log into a ProgressionState. State is always reconstructable from the log alone.
| Type | File | Description |
|---|---|---|
ProgressionEvent |
src/core/progression.ts |
Discriminated union on type of the five event members below. |
QuestCompletedEvent |
src/core/progression.ts |
at, optional session_id, quest_id (QuestId), level_id (LevelId), required (boolean), xp (non-negative int). |
UnlockEvent |
src/core/progression.ts |
at, optional session_id, target (UnlockTarget), reason (enum), optional source_quest_id, optional source_level_id. |
XpAwardEvent |
src/core/progression.ts |
at, optional session_id, optional quest_id, amount (positive int), optional total (non-negative int). |
BadgeAwardEvent |
src/core/progression.ts |
at, optional session_id, badge (Badge), optional level_id, optional quest_id. |
HintOpenedEvent |
src/core/progression.ts |
at, optional session_id, quest_id (QuestId), level_id (LevelId), optional hint_id. |
UnlockTarget |
src/core/progression.ts |
Discriminated union on type: { type: "feature", id: FeatureId } or { type: "level", id: LevelId }. |
Badge |
src/core/progression.ts |
Enum: completionist, no_hint_clear, speedrunner. |
Every event shares eventBaseShape: an at timestamp and an optional session_id. The timestamp must match the ISO-8601 regex ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$. The session_id lets event checks constrain matches to the same session.
The UnlockEvent.reason enum records why a capability or level was unlocked:
-
quest_completed: a level's required quests completed andderiveUnlocksappended the event. -
speedrun: the learner chose speedrun at onboarding and skipped ahead without XP. -
cheat:garnish unlock --all(or/unlock --all) appended the event. -
system: a system-initiated unlock.
The progression fold sets usedSpeedrunPath when it sees a speedrun or cheat reason, which is what gates the speedrunner badge (see progression).
These event types flow through the system as the durable state layer:
-
Extension (
src/extension/index.ts): appendsquest_completedevents when quests pass, then re-folds and appendsunlockevents fromderiveUnlocks. -
CLI (
src/cli/):initappends speedrununlockevents;statusandquestfold the log to render state;unlockappendscheatunlock events. -
Progression (
src/progression/index.ts):foldEventsreplays the log intoProgressionState;deriveUnlockscomputes theunlockevents that follow level completions. -
Verifier (
src/verifier/index.ts): event checks with anafter: QuestIdboundary scan for the matchingquest_completedevent.
See quest verification for the flow that appends these events and progression for the fold that consumes them.
-
Discriminated union: each event is validated by its
typebranch. Unknown types are rejected. -
Strict objects: every event schema uses
z.strictObject, so unknown keys are rejected. -
Timestamp format:
atmust match the ISO-8601 regex above. -
Branded IDs:
quest_id,level_id, and feature targets use the branded slug types fromsrc/core/ids.ts(see domain IDs). -
Positive XP amounts:
XpAwardEvent.amountis a positive int;QuestCompletedEvent.xpis a non-negative int. -
Badge enum:
BadgeAwardEvent.badgemust be one of the three badge names.
events.jsonl is the log; foldEvents is the pure fold; ProgressionState is the derived snapshot. Because the fold is deterministic and the log is append-only, state is always reconstructable from the log. This is ADR-4. The progression engine's replayProgression self-check folds the same events twice and compares the JSON to verify determinism.
| File | Purpose |
|---|---|
src/core/progression.ts |
ProgressionEvent union, all five event schemas, UnlockTarget, Badge. |
src/progression/index.ts |
foldEvents, deriveUnlocks, replayProgression (see progression). |
src/extension/index.ts |
Appends quest_completed and unlock events during evaluation. |
Cross-link: progression, quest verification, domain IDs, domain model.