@plasius/learning 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,14 +6,22 @@ The package does **not** provide HTTP handlers, persistence, authentication, Tok
6
6
 
7
7
  ## Junior Coder catalog
8
8
 
9
- The initial catalog is exported as `JUNIOR_CODER_ROBOT_RESCUE_PATH_V1`. It contains 19 independently sellable, self-contained project modules:
9
+ The initial immutable catalog is exported as
10
+ `JUNIOR_CODER_ROBOT_RESCUE_PATH_V1`. The current uniformly priced pilot
11
+ catalog is exported as `JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1`, with
12
+ `JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT` available to adapters that
13
+ intentionally follow published successors. Each contains 19 independently
14
+ sellable, self-contained project modules:
10
15
 
11
16
  - 8 original arcade game modules;
12
17
  - 5 simulator-backed robotics modules;
13
18
  - 3 constrained Vibe Coding modules;
14
19
  - 3 web application modules.
15
20
 
16
- The catalog is in `pilot-grant-only` commercial state. Its prices are shadow prices for pilot measurement and are not authorization to enable public checkout.
21
+ Both catalogs remain in `pilot-grant-only` commercial state. The immutable
22
+ `1.1.0` modules each cost 50 Tokens (50,000 subunits), carrying a
23
+ non-redeemable £5 reference value. Price metadata is not authorization to
24
+ enable public checkout.
17
25
 
18
26
  ## Install
19
27
 
@@ -25,11 +33,11 @@ npm install @plasius/learning
25
33
 
26
34
  ```ts
27
35
  import {
28
- JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,
36
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT,
29
37
  assertValidLearningPath,
30
38
  } from "@plasius/learning";
31
39
 
32
- assertValidLearningPath(JUNIOR_CODER_ROBOT_RESCUE_PATH_V1);
40
+ assertValidLearningPath(JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT);
33
41
  ```
34
42
 
35
43
  ## Calculate an assessment
@@ -49,14 +57,21 @@ console.log(result.score, result.completed);
49
57
  ## Contract rules
50
58
 
51
59
  - Published IDs and versions are immutable.
60
+ - Reference prices are product-copy metadata and never create cash redemption
61
+ rights.
52
62
  - A module entitlement must bind to an exact module version.
63
+ - `admin-test-grant` is distinct from pilot, support and paid purchase sources;
64
+ consuming services must not attach an economy transaction to it.
53
65
  - Learner material never contains facilitator-only solutions or protected tests.
54
66
  - Rubric criteria total exactly 100 points.
55
67
  - Completion requires a score of at least 80 and every mandatory criterion.
56
68
  - Module agents may explain evidence and propose a bounded next step, but cannot assign scores or rewards.
57
69
  - Physical requirements are disclosed by a versioned manifest before purchase.
58
70
 
59
- See [the foundation design](docs/design/junior-coder-catalog-foundation.md) and [ADR 0001](docs/adrs/adr-0001-learning-domain-and-catalog-boundary.md).
71
+ See [the foundation design](docs/design/junior-coder-catalog-foundation.md),
72
+ [the uniform pricing design](docs/design/junior-coder-uniform-pricing.md),
73
+ [ADR 0001](docs/adrs/adr-0001-learning-domain-and-catalog-boundary.md), and
74
+ [ADR 0002](docs/adrs/adr-0002-immutable-module-repricing-and-admin-test-source.md).
60
75
 
61
76
  ## Development
62
77
 
@@ -70,7 +85,11 @@ npm run pack:check
70
85
  ```
71
86
 
72
87
  Node.js 24 is required. Releases are published only through the approved GitHub
73
- CD workflow on configurable trusted self-hosted runners. Release coverage and
88
+ CD workflow on configurable trusted self-hosted runners. Both release jobs
89
+ explicitly select the approved `Public CI - Quarantined` runner group by
90
+ default, with `CD_RUNNER_GROUP` and `CD_RUNNER_LABELS` reserved for governed
91
+ operator configuration. The organisation group remains restricted to
92
+ allowlisted workflows and selected repositories. Release coverage and
74
93
  the CycloneDX SBOM are retained even when an external coverage or provenance
75
94
  service is unavailable. Release tags and GitHub Releases use a current-repository
76
95
  GitHub App token with explicit Contents and Workflows write permissions; npm
package/dist/index.cjs CHANGED
@@ -20,7 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ JUNIOR_CODER_MODULE_PRICE_V1_1: () => JUNIOR_CODER_MODULE_PRICE_V1_1,
24
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT: () => JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT,
23
25
  JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: () => JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,
26
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1: () => JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1,
24
27
  assertValidLearningPath: () => assertValidLearningPath,
25
28
  calculateAssessment: () => calculateAssessment,
26
29
  validateLearningPath: () => validateLearningPath
@@ -561,6 +564,15 @@ var modules = [
561
564
  missionTitles: ["Build the Control Panel", "Simulate Telemetry", "Add Stop Confirmations", "Mission Control Challenge"]
562
565
  })
563
566
  ];
567
+ var JUNIOR_CODER_MODULE_PRICE_V1_1 = Object.freeze({
568
+ tokenSubunits: "50000",
569
+ referencePrice: Object.freeze({
570
+ currency: "GBP",
571
+ minorUnits: "500",
572
+ basis: "nominal-reference",
573
+ cashRedemptionAllowed: false
574
+ })
575
+ });
564
576
  var JUNIOR_CODER_ROBOT_RESCUE_PATH_V1 = {
565
577
  id: "junior-coder.robot-rescue-arcade",
566
578
  slug: "robot-rescue-arcade",
@@ -572,6 +584,21 @@ var JUNIOR_CODER_ROBOT_RESCUE_PATH_V1 = {
572
584
  featureFlag: "learning.junior-coder.catalog.enabled",
573
585
  modules
574
586
  };
587
+ var JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1 = {
588
+ ...JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,
589
+ version: "1.1.0",
590
+ modules: JUNIOR_CODER_ROBOT_RESCUE_PATH_V1.modules.map((entry) => ({
591
+ ...entry,
592
+ version: "1.1.0",
593
+ contentRevision: "2026-07-28.1",
594
+ pricing: {
595
+ ...entry.pricing,
596
+ tokenSubunits: JUNIOR_CODER_MODULE_PRICE_V1_1.tokenSubunits,
597
+ referencePrice: JUNIOR_CODER_MODULE_PRICE_V1_1.referencePrice
598
+ }
599
+ }))
600
+ };
601
+ var JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT = JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1;
575
602
 
576
603
  // src/validation.ts
577
604
  var DIMENSION_TOTALS = {
@@ -649,6 +676,17 @@ function validateModule(module3, moduleIndex) {
649
676
  )
650
677
  );
651
678
  }
679
+ const referencePrice = module3.pricing.referencePrice;
680
+ if (referencePrice && (referencePrice.currency !== "GBP" || !CANONICAL_TOKEN_SUBUNITS.test(referencePrice.minorUnits) || referencePrice.basis !== "nominal-reference" || referencePrice.cashRedemptionAllowed !== false)) {
681
+ issues.push(
682
+ issue(
683
+ "invalid-reference-price",
684
+ "Reference prices must use canonical GBP minor units, the nominal reference basis and prohibit cash redemption.",
685
+ `${base}.pricing.referencePrice`,
686
+ module3.id
687
+ )
688
+ );
689
+ }
652
690
  const criterionIds = /* @__PURE__ */ new Set();
653
691
  const dimensionTotals = {
654
692
  structure: 0,
@@ -780,7 +818,10 @@ ${summary}`);
780
818
  }
781
819
  // Annotate the CommonJS export names for ESM import in node:
782
820
  0 && (module.exports = {
821
+ JUNIOR_CODER_MODULE_PRICE_V1_1,
822
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT,
783
823
  JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,
824
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1,
784
825
  assertValidLearningPath,
785
826
  calculateAssessment,
786
827
  validateLearningPath
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/assessment.ts","../src/catalog.ts","../src/validation.ts"],"sourcesContent":["export * from \"./assessment.js\";\nexport * from \"./catalog.js\";\nexport * from \"./contracts.js\";\nexport * from \"./validation.js\";\n","import type {\n AssessmentCheckResultV1,\n AssessmentResultV1,\n AssessmentRubricV1,\n ScoreBandV1,\n} from \"./contracts.js\";\n\nfunction scoreBand(score: number): ScoreBandV1 {\n if (score >= 95) return \"mastered\";\n if (score >= 80) return \"mission-complete\";\n if (score >= 60) return \"nearly-there\";\n return \"keep-exploring\";\n}\n\n/**\n * Calculate a score solely from rubric criteria and objective check results.\n * Missing criteria fail closed; unknown and duplicate result IDs are rejected.\n */\nexport function calculateAssessment(\n rubric: AssessmentRubricV1,\n results: AssessmentCheckResultV1[],\n): AssessmentResultV1 {\n const knownIds = new Set(rubric.criteria.map((criterion) => criterion.id));\n const resultById = new Map<string, AssessmentCheckResultV1>();\n\n for (const result of results) {\n if (!knownIds.has(result.criterionId)) {\n throw new Error(`Unknown assessment criterion: ${result.criterionId}`);\n }\n if (resultById.has(result.criterionId)) {\n throw new Error(`Duplicate assessment result: ${result.criterionId}`);\n }\n resultById.set(result.criterionId, result);\n }\n\n let score = 0;\n const passedCriterionIds: string[] = [];\n const failedCriterionIds: string[] = [];\n const failedMandatoryCriterionIds: string[] = [];\n\n for (const criterion of rubric.criteria) {\n const passed = resultById.get(criterion.id)?.passed === true;\n if (passed) {\n score += criterion.points;\n passedCriterionIds.push(criterion.id);\n continue;\n }\n\n failedCriterionIds.push(criterion.id);\n if (criterion.mandatory) failedMandatoryCriterionIds.push(criterion.id);\n }\n\n return {\n score,\n band: scoreBand(score),\n completed:\n score >= rubric.completionScore && failedMandatoryCriterionIds.length === 0,\n passedCriterionIds,\n failedCriterionIds,\n failedMandatoryCriterionIds,\n };\n}\n","import type {\n AssessmentRubricV1,\n CourseMaterialsManifestV1,\n HardwareItemV1,\n HardwareRequirementManifestV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n MissionV1,\n ModuleAgentDefinitionV1,\n ModuleCategoryV1,\n} from \"./contracts.js\";\n\nconst SOFTWARE_HARDWARE: HardwareRequirementManifestV1 = {\n requirementsVersion: \"1.0.0\",\n mode: \"none\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"not-applicable\",\n publicSaleBlocked: false,\n preparationMinutes: 0,\n items: [],\n warnings: [\"No specialist physical equipment is required.\"],\n supportedPlatforms: [\"Current Chromium, Firefox or Safari browser\"],\n};\n\nconst CORE_ROBOT_ITEMS: HardwareItemV1[] = [\n {\n id: \"pico-2-w\",\n label: \"Raspberry Pi Pico 2 W\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Raspberry Pi Pico 2 W with soldered headers\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"breadboard\",\n label: \"Solderless breadboard\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"400-point or larger solderless breadboard\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"usb-data-cable\",\n label: \"USB data cable\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Data-capable USB cable compatible with the Pico 2 W\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"jumper-wires\",\n label: \"Jumper wires\",\n quantity: 12,\n requirement: \"required\",\n exactSpecification: \"Insulated male-to-male breadboard jumper wires\",\n adultOnly: false,\n stage: \"core\",\n },\n];\n\nconst ROBOT_WARNING =\n \"Physical publication is blocked until every listed actuator, driver, sensor and power configuration passes an adult bench test.\";\n\nfunction physicalHardware(\n requirementsVersion: string,\n preparationMinutes: number,\n items: HardwareItemV1[],\n platforms: string[],\n): HardwareRequirementManifestV1 {\n return {\n requirementsVersion,\n mode: \"physical-first\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"pending-bench-test\",\n publicSaleBlocked: true,\n preparationMinutes,\n items: [...CORE_ROBOT_ITEMS, ...items],\n warnings: [ROBOT_WARNING, \"An adult must disconnect actuator power before changing wiring.\"],\n supportedPlatforms: platforms,\n };\n}\n\nfunction materials(slug: string, robot = false): CourseMaterialsManifestV1 {\n return {\n version: \"1.0.0\",\n learner: [\n { id: `${slug}-child-guide`, kind: \"child-guide\", audience: \"learner\" },\n { id: `${slug}-mission-cards`, kind: \"mission-cards\", audience: \"learner\" },\n { id: `${slug}-starter`, kind: \"starter-project\", audience: \"learner\" },\n { id: `${slug}-assets`, kind: \"asset-pack\", audience: \"learner\" },\n { id: `${slug}-printable`, kind: \"printable\", audience: \"learner\" },\n ],\n facilitator: [\n { id: `${slug}-facilitator`, kind: \"facilitator-guide\", audience: \"facilitator\" },\n { id: `${slug}-answers`, kind: \"answer-key\", audience: \"facilitator\" },\n { id: `${slug}-tests`, kind: \"protected-tests\", audience: \"facilitator\" },\n ...(robot\n ? [\n {\n id: `${slug}-hardware`,\n kind: \"hardware-guide\" as const,\n audience: \"facilitator\" as const,\n },\n ]\n : []),\n ],\n };\n}\n\nfunction agents(slug: string): ModuleAgentDefinitionV1[] {\n return [\n {\n id: `${slug}-assessor`,\n role: \"assessor\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-debugger`,\n role: \"debugger\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-fix-guide`,\n role: \"fix-guide\",\n evidenceBound: true,\n maySuggestSingleFix: true,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-concept-explainer`,\n role: \"concept-explainer\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n ];\n}\n\nfunction rubric(slug: string): AssessmentRubricV1 {\n return {\n version: \"1.0.0\",\n completionScore: 80,\n criteria: [\n {\n id: `${slug}-build`,\n label: \"The project is structurally valid and starts successfully.\",\n dimension: \"structure\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-one`,\n label: \"The first published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-two`,\n label: \"The second published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-three`,\n label: \"The complete project challenge works.\",\n dimension: \"behaviour\",\n points: 10,\n mandatory: false,\n visibility: \"visible\",\n },\n {\n id: `${slug}-edge-one`,\n label: \"The project handles its first protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-edge-two`,\n label: \"The project handles its second protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-safety`,\n label: \"The project obeys its mandatory safety and privacy boundary.\",\n dimension: \"safety\",\n points: 10,\n mandatory: true,\n visibility: \"visible\",\n },\n ],\n };\n}\n\nfunction mission(\n slug: string,\n index: number,\n title: string,\n concepts: string[],\n statement: string,\n sideAdventure: string,\n): MissionV1 {\n return {\n id: `${slug}-mission-${index}`,\n title,\n estimatedMinutes: index === 4 ? 25 : 20,\n concepts,\n goals: [\n {\n id: `${slug}-goal-${index}`,\n statement,\n evidence: \"assessment\",\n },\n ],\n sideAdventure,\n };\n}\n\ninterface ModuleInput {\n slug: string;\n title: string;\n category: ModuleCategoryV1;\n summary: string;\n tools: string[];\n concepts: string[];\n tokenSubunits: string;\n hosting?: boolean;\n hardware?: HardwareRequirementManifestV1;\n missionTitles: [string, string, string, string];\n}\n\nfunction module(input: ModuleInput): LearningModuleVersionV1 {\n const isRobot = input.category === \"robot\";\n return {\n id: `junior-coder.${input.slug}`,\n slug: input.slug,\n version: \"1.0.0\",\n contentRevision: \"2026-07-21.1\",\n title: input.title,\n category: input.category,\n summary: input.summary,\n estimatedMinutes: 90,\n tools: input.tools,\n concepts: input.concepts,\n selfContained: true,\n prerequisiteModuleIds: [],\n pricing: {\n state: \"pilot-grant-only\",\n tokenSubunits: input.tokenSubunits,\n includesMaterials: true,\n includesAssessmentRetries: true,\n includesAgents: true,\n includesHostingAllowance: input.hosting ?? false,\n },\n materials: materials(input.slug, isRobot),\n hardware: input.hardware ?? SOFTWARE_HARDWARE,\n missions: input.missionTitles.map((title, index) =>\n mission(\n input.slug,\n index + 1,\n title,\n input.concepts.slice(0, 3),\n `Complete ${title.toLocaleLowerCase(\"en-GB\")} and explain the observed result.`,\n `Invent one safe remix for ${title.toLocaleLowerCase(\"en-GB\")}.`,\n ),\n ),\n assessment: rubric(input.slug),\n agents: agents(input.slug),\n badges: [\n {\n id: `${input.slug}-mission-complete`,\n title: `${input.title} Champion`,\n evidence: \"module-score\",\n tradeable: false,\n tokenConvertible: false,\n },\n ...(isRobot\n ? [\n {\n id: `${input.slug}-physical-builder`,\n title: `${input.title} Physical Builder`,\n evidence: \"adult-physical-signoff\" as const,\n tradeable: false as const,\n tokenConvertible: false as const,\n },\n ]\n : []),\n ],\n };\n}\n\nconst modules: LearningModuleVersionV1[] = [\n module({\n slug: \"robot-maze-dash\",\n title: \"Robot Maze Dash\",\n category: \"game\",\n summary: \"Guide rescue robots through original mazes with visual programs and side-by-side text code.\",\n tools: [\"Visual blocks\", \"JavaScript view\", \"Python view\", \"C++ view\"],\n concepts: [\"sequence\", \"variables\", \"loops\", \"conditions\", \"functions\"],\n tokenSubunits: \"8000\",\n missionTitles: [\"Meet Your Robot\", \"Repeat the Rescue\", \"Choose the Safe Path\", \"Lost Robot Challenge\"],\n }),\n module({\n slug: \"road-hopper-rally\",\n title: \"Road Hopper Rally\",\n category: \"game\",\n summary: \"Build an original road-crossing game with changing lanes and rescue targets.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"events\", \"coordinates\", \"animation\", \"collision\", \"scoring\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Draw the Rescue Road\", \"Move the Hopper\", \"Add Moving Traffic\", \"Rally Challenge\"],\n }),\n module({\n slug: \"skywing-sprint\",\n title: \"Skywing Sprint\",\n category: \"game\",\n summary: \"Fly a rescue craft through procedurally changing sky gates.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"velocity\", \"gravity\", \"timing\", \"randomness\", \"obstacles\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Give Skywing Lift\", \"Build a Gate\", \"Score a Safe Flight\", \"Sky Sprint Challenge\"],\n }),\n module({\n slug: \"paddle-pulse\",\n title: \"Paddle Pulse\",\n category: \"game\",\n summary: \"Create a paddle-and-energy-ball arcade game with levels and original power-ups.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"angles\", \"collision response\", \"levels\", \"power-ups\", \"state\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Move the Pulse Paddle\", \"Bounce the Energy Ball\", \"Build a Target Wall\", \"Power-Up Challenge\"],\n }),\n module({\n slug: \"meteor-shield\",\n title: \"Meteor Shield\",\n category: \"game\",\n summary: \"Protect rescue bases with careful targeting and limited shield energy.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"targeting\", \"projectiles\", \"timers\", \"waves\", \"resources\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Mark the Rescue Bases\", \"Launch a Shield\", \"Create Meteor Waves\", \"Last Base Challenge\"],\n }),\n module({\n slug: \"rescue-crew-commander\",\n title: \"Rescue Crew Commander\",\n category: \"game\",\n summary: \"Assign safe jobs, routes and priorities to a team of original helper creatures.\",\n tools: [\"Visual blocks\", \"JavaScript\"],\n concepts: [\"state machines\", \"routes\", \"priorities\", \"group behaviour\", \"debugging\"],\n tokenSubunits: \"14000\",\n missionTitles: [\"Meet the Rescue Crew\", \"Give a Crew Job\", \"Choose a Safe Route\", \"Commander Challenge\"],\n }),\n module({\n slug: \"pixel-trail-challenge\",\n title: \"Pixel Trail Challenge\",\n category: \"game\",\n summary: \"Use Python lists and grid movement to grow a safe energy trail.\",\n tools: [\"Python\", \"Pyodide\", \"Educational drawing API\"],\n concepts: [\"lists\", \"grid movement\", \"spawning\", \"collision\", \"score\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Move the Pixel\", \"Grow the Trail\", \"Place Energy Orbs\", \"Trail Challenge\"],\n }),\n module({\n slug: \"star-defender-squadron\",\n title: \"Star Defender Squadron\",\n category: \"game\",\n summary: \"Build a multi-level space-rescue finale with original entities and enemy patterns.\",\n tools: [\"Python\", \"JavaScript\", \"Educational drawing API\"],\n concepts: [\"entities\", \"projectiles\", \"patterns\", \"health\", \"levels\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Launch the Squadron\", \"Build a Rescue Wave\", \"Add Shields and Health\", \"Star Defender Finale\"],\n }),\n module({\n slug: \"beacon-bot\",\n title: \"Beacon Bot\",\n category: \"robot\",\n summary: \"Program visible and infrared rescue signals with C++ and a Pico 2 W.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"digital output\", \"timing\", \"functions\", \"signals\", \"sensor input\"],\n tokenSubunits: \"8000\",\n hardware: physicalHardware(\"1.0.0\", 30, [\n { id: \"led-pack\", label: \"Visible LEDs\", quantity: 3, requirement: \"required\", exactSpecification: \"5 mm low-current red, amber and green LEDs\", adultOnly: false, stage: \"core\" },\n { id: \"led-resistors\", label: \"LED current-limiting resistors\", quantity: 3, requirement: \"required\", exactSpecification: \"330 ohm, 0.25 W resistors\", adultOnly: false, stage: \"core\" },\n { id: \"ir-pair\", label: \"Infrared emitter and receiver\", quantity: 1, requirement: \"required\", exactSpecification: \"Matched 940 nm IR LED and 3.3 V-compatible digital receiver pair; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Blink a Rescue Signal\", \"Build a Signal Function\", \"Send an IR Message\", \"Beacon Challenge\"],\n }),\n module({\n slug: \"servo-creature\",\n title: \"Servo Creature\",\n category: \"robot\",\n summary: \"Give a servo creature safe movements, moods and sensor reactions.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"PWM\", \"angles\", \"sequences\", \"limits\", \"interaction\"],\n tokenSubunits: \"10000\",\n hardware: physicalHardware(\"1.0.0\", 40, [\n { id: \"micro-servo\", label: \"Micro servo\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V signal-compatible micro servo; exact reference model and external power arrangement pending bench verification\", adultOnly: true, stage: \"servo\" },\n { id: \"servo-power\", label: \"Servo power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Switched regulated supply sized for the verified servo, with common signal ground\", adultOnly: true, stage: \"servo\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Wake the Creature\", \"Make a Movement Sequence\", \"Choose a Mood\", \"Creature Show Challenge\"],\n }),\n module({\n slug: \"dance-rover\",\n title: \"Dance Rover\",\n category: \"robot\",\n summary: \"Build reusable movement functions and a fail-safe rover dance.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"motor direction\", \"PWM speed\", \"functions\", \"sequences\", \"emergency stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 90, [\n { id: \"dual-motor-driver\", label: \"Dual motor driver\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V logic-compatible dual H-bridge; exact reference model pending bench verification\", adultOnly: true, stage: \"rover\" },\n { id: \"geared-motors\", label: \"Matching geared motors\", quantity: 2, requirement: \"required\", exactSpecification: \"Matching low-voltage geared DC motors compatible with the verified driver and supply\", adultOnly: true, stage: \"rover\" },\n { id: \"rover-chassis\", label: \"Rover chassis set\", quantity: 1, requirement: \"required\", exactSpecification: \"Two-wheel chassis with matching wheels and caster or skid\", adultOnly: true, stage: \"rover\" },\n { id: \"motor-power\", label: \"Switched motor power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Fused or protected switched supply within verified driver and motor ratings\", adultOnly: true, stage: \"rover\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Lifted-Wheel Safety Test\", \"Drive and Turn\", \"Build Movement Functions\", \"Rover Dance Challenge\"],\n }),\n module({\n slug: \"obstacle-explorer\",\n title: \"Obstacle Explorer\",\n category: \"robot\",\n summary: \"Use IR sensing, state and watchdogs to navigate and stop safely.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"booleans\", \"state\", \"navigation\", \"watchdogs\", \"fail-safe stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 60, [\n { id: \"verified-rover\", label: \"Verified Dance Rover build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Dance Rover reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"obstacle-sensors\", label: \"Digital IR obstacle sensors\", quantity: 2, requirement: \"required\", exactSpecification: \"3.3 V-compatible digital IR obstacle sensors; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Read an Obstacle\", \"Choose a Safe Response\", \"Add a Watchdog\", \"Explorer Maze Challenge\"],\n }),\n module({\n slug: \"rainbow-rescue-rover\",\n title: \"Rainbow Rescue Rover\",\n category: \"robot\",\n summary: \"Recognise local colour targets and send bounded serial commands to a safe rover.\",\n tools: [\"Python\", \"C++\", \"Pico 2 W\", \"Pi Zero 2 W\", \"Camera Module 3\", \"Simulator\"],\n concepts: [\"colour recognition\", \"coordinates\", \"serial protocol\", \"heartbeats\", \"integration\"],\n tokenSubunits: \"18000\",\n hardware: physicalHardware(\"1.0.0\", 120, [\n { id: \"verified-explorer\", label: \"Verified Obstacle Explorer build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Obstacle Explorer reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"pi-zero-2-w\", label: \"Raspberry Pi Zero 2 W\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Zero 2 W with supported Raspberry Pi OS image\", adultOnly: true, stage: \"camera\" },\n { id: \"camera-3\", label: \"Raspberry Pi Camera Module 3\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Camera Module 3 with the correct Zero-series camera ribbon\", adultOnly: true, stage: \"camera\" },\n { id: \"pi-storage-power\", label: \"Pi storage and power\", quantity: 1, requirement: \"required\", exactSpecification: \"Supported microSD card and regulated Raspberry Pi power supply\", adultOnly: true, stage: \"camera\" },\n ], [\"Current Raspberry Pi OS\", \"Pico SDK\"]),\n missionTitles: [\"Find a Colour Target\", \"Report Left Centre or Right\", \"Send Safe Serial Commands\", \"Rainbow Rescue Challenge\"],\n }),\n module({\n slug: \"vibe-game-remix-lab\",\n title: \"Vibe Game Remix Lab\",\n category: \"vibe\",\n summary: \"Transform a supplied mini-game through structured, evidence-bound AI suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"JavaScript sandbox\"],\n concepts: [\"intent\", \"constraints\", \"diffs\", \"testing\", \"explanation\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Describe the Remix\", \"Constrain the Change\", \"Review One Diff\", \"Remix Challenge\"],\n }),\n module({\n slug: \"vibe-bug-detective\",\n title: \"Vibe Bug Detective\",\n category: \"vibe\",\n summary: \"Repair an intentionally broken project using assessment evidence and focused suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"Assessment runner\"],\n concepts: [\"diagnostics\", \"hypotheses\", \"minimal fixes\", \"regression tests\", \"reflection\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Read the Evidence\", \"Ask a Focused Question\", \"Inspect a Suggested Fix\", \"Regression Challenge\"],\n }),\n module({\n slug: \"vibe-idea-studio\",\n title: \"Vibe Idea Studio\",\n category: \"vibe\",\n summary: \"Turn a bounded original idea into goals, acceptance tests and a working prototype.\",\n tools: [\"Intent cards\", \"Structured prompt builder\", \"Diff review\", \"Sandbox\"],\n concepts: [\"goals\", \"acceptance tests\", \"iteration\", \"trade-offs\", \"explanation\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Shape the Idea\", \"Write Success Tests\", \"Build One Step\", \"Prototype Showcase\"],\n }),\n module({\n slug: \"adventure-mission-planner\",\n title: \"Adventure Mission Planner\",\n category: \"web-app\",\n summary: \"Build an accessible planner for fictional quests and activities.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"semantic HTML\", \"forms\", \"validation\", \"arrays\", \"local persistence\"],\n tokenSubunits: \"10000\",\n hosting: true,\n missionTitles: [\"Make a Semantic Page\", \"Add a Mission Form\", \"Save Fictional Missions\", \"Accessible Planner Challenge\"],\n }),\n module({\n slug: \"creature-care-dashboard\",\n title: \"Creature Care Dashboard\",\n category: \"web-app\",\n summary: \"Create a responsive dashboard for a fictional digital creature.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"components\", \"events\", \"timers\", \"status displays\", \"reduced motion\"],\n tokenSubunits: \"12000\",\n hosting: true,\n missionTitles: [\"Design the Creature Card\", \"Update Creature State\", \"Add a Safe Timer\", \"Care Dashboard Challenge\"],\n }),\n module({\n slug: \"robot-mission-control\",\n title: \"Robot Mission Control\",\n category: \"web-app\",\n summary: \"Build a simulated control and telemetry interface with safety confirmations.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Serial simulator\", \"Private preview\"],\n concepts: [\"commands\", \"state machines\", \"confirmations\", \"charts\", \"responsive controls\"],\n tokenSubunits: \"14000\",\n hosting: true,\n missionTitles: [\"Build the Control Panel\", \"Simulate Telemetry\", \"Add Stop Confirmations\", \"Mission Control Challenge\"],\n }),\n];\n\n/** Initial immutable Junior Coder path manifest for pilot grants and shadow pricing. */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: LearningPathVersionV1 = {\n id: \"junior-coder.robot-rescue-arcade\",\n slug: \"robot-rescue-arcade\",\n version: \"1.0.0\",\n title: \"Junior Coder: Robot Rescue Arcade\",\n description: \"Nineteen self-contained game, robotics, Vibe Coding and web-app projects for young programmers.\",\n catalogState: \"pilot\",\n publicLaunchAtomic: true,\n featureFlag: \"learning.junior-coder.catalog.enabled\",\n modules,\n};\n","import type {\n AssessmentDimensionV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n LearningValidationIssueV1,\n} from \"./contracts.js\";\n\nconst DIMENSION_TOTALS: Record<AssessmentDimensionV1, number> = {\n structure: 20,\n behaviour: 50,\n resilience: 20,\n safety: 10,\n};\n\nconst CANONICAL_TOKEN_SUBUNITS = /^(0|[1-9][0-9]*)$/u;\n\nfunction issue(\n code: LearningValidationIssueV1[\"code\"],\n message: string,\n path: string,\n moduleId?: string,\n): LearningValidationIssueV1 {\n return { code, message, path, ...(moduleId ? { moduleId } : {}) };\n}\n\nfunction validateModule(\n module: LearningModuleVersionV1,\n moduleIndex: number,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const base = `modules[${moduleIndex}]`;\n\n if (!module.selfContained) {\n issues.push(\n issue(\n \"module-not-self-contained\",\n \"Every sellable module must be self-contained.\",\n `${base}.selfContained`,\n module.id,\n ),\n );\n }\n\n if (module.prerequisiteModuleIds.length > 0) {\n issues.push(\n issue(\n \"paid-prerequisite\",\n \"A sellable module cannot require another paid module.\",\n `${base}.prerequisiteModuleIds`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.learner.length === 0 ||\n module.materials.facilitator.length === 0\n ) {\n issues.push(\n issue(\n \"missing-materials\",\n \"Learner and facilitator material manifests are both required.\",\n `${base}.materials`,\n module.id,\n ),\n );\n }\n\n if (module.materials.learner.some((material) => material.audience !== \"learner\")) {\n issues.push(\n issue(\n \"facilitator-material-leak\",\n \"Learner material contains a facilitator-only record.\",\n `${base}.materials.learner`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.facilitator.some(\n (material) => material.audience !== \"facilitator\",\n )\n ) {\n issues.push(\n issue(\n \"learner-material-leak\",\n \"Facilitator material contains a learner record.\",\n `${base}.materials.facilitator`,\n module.id,\n ),\n );\n }\n\n if (!CANONICAL_TOKEN_SUBUNITS.test(module.pricing.tokenSubunits)) {\n issues.push(\n issue(\n \"invalid-token-subunits\",\n \"Token subunits must be a canonical non-negative base-10 integer string.\",\n `${base}.pricing.tokenSubunits`,\n module.id,\n ),\n );\n }\n\n const criterionIds = new Set<string>();\n const dimensionTotals: Record<AssessmentDimensionV1, number> = {\n structure: 0,\n behaviour: 0,\n resilience: 0,\n safety: 0,\n };\n let rubricTotal = 0;\n\n for (const criterion of module.assessment.criteria) {\n rubricTotal += criterion.points;\n dimensionTotals[criterion.dimension] += criterion.points;\n if (criterionIds.has(criterion.id)) {\n issues.push(\n issue(\n \"duplicate-criterion-id\",\n `Duplicate assessment criterion ${criterion.id}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n criterionIds.add(criterion.id);\n }\n\n if (rubricTotal !== 100) {\n issues.push(\n issue(\n \"rubric-total\",\n `Assessment rubric totals ${rubricTotal}; expected 100.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n for (const [dimension, expected] of Object.entries(DIMENSION_TOTALS) as Array<\n [AssessmentDimensionV1, number]\n >) {\n if (dimensionTotals[dimension] !== expected) {\n issues.push(\n issue(\n \"rubric-dimension-total\",\n `${dimension} criteria total ${dimensionTotals[dimension]}; expected ${expected}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n }\n\n if (\n !module.assessment.criteria.some(\n (criterion) => criterion.dimension === \"safety\" && criterion.mandatory,\n )\n ) {\n issues.push(\n issue(\n \"missing-mandatory-safety\",\n \"Every module requires a mandatory safety criterion.\",\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n if (module.hardware.mode === \"physical-first\" && module.hardware.items.length === 0) {\n issues.push(\n issue(\n \"missing-hardware-items\",\n \"Physical-first modules require an exact hardware item list.\",\n `${base}.hardware.items`,\n module.id,\n ),\n );\n }\n\n if (\n module.agents.some(\n (agent) =>\n agent.mayAssignScore !== false ||\n agent.mayAwardReward !== false ||\n agent.mayPublish !== false ||\n agent.mayControlHardware !== false,\n )\n ) {\n issues.push(\n issue(\n \"invalid-agent-authority\",\n \"Module agents cannot own scores, rewards, publishing or hardware control.\",\n `${base}.agents`,\n module.id,\n ),\n );\n }\n\n if (module.missions.length === 0) {\n issues.push(\n issue(\n \"missing-missions\",\n \"A module requires at least one mission.\",\n `${base}.missions`,\n module.id,\n ),\n );\n }\n\n return issues;\n}\n\n/** Return every catalog issue without throwing, suitable for authoring tools. */\nexport function validateLearningPath(\n path: LearningPathVersionV1,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const moduleIds = new Set<string>();\n const moduleSlugs = new Set<string>();\n\n for (const [index, module] of path.modules.entries()) {\n if (moduleIds.has(module.id)) {\n issues.push(\n issue(\n \"duplicate-module-id\",\n `Duplicate module id ${module.id}.`,\n `modules[${index}].id`,\n module.id,\n ),\n );\n }\n moduleIds.add(module.id);\n\n if (moduleSlugs.has(module.slug)) {\n issues.push(\n issue(\n \"duplicate-module-slug\",\n `Duplicate module slug ${module.slug}.`,\n `modules[${index}].slug`,\n module.id,\n ),\n );\n }\n moduleSlugs.add(module.slug);\n issues.push(...validateModule(module, index));\n }\n\n return issues;\n}\n\n/** Fail fast when a path is not safe to publish or consume. */\nexport function assertValidLearningPath(path: LearningPathVersionV1): void {\n const issues = validateLearningPath(path);\n if (issues.length === 0) return;\n\n const summary = issues\n .map((entry) => `${entry.code} at ${entry.path}: ${entry.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid learning path:\\n${summary}`);\n}\n"],"mappings":"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","names":["rubric","module","module"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/assessment.ts","../src/catalog.ts","../src/validation.ts"],"sourcesContent":["export * from \"./assessment.js\";\nexport * from \"./catalog.js\";\nexport * from \"./contracts.js\";\nexport * from \"./validation.js\";\n","import type {\n AssessmentCheckResultV1,\n AssessmentResultV1,\n AssessmentRubricV1,\n ScoreBandV1,\n} from \"./contracts.js\";\n\nfunction scoreBand(score: number): ScoreBandV1 {\n if (score >= 95) return \"mastered\";\n if (score >= 80) return \"mission-complete\";\n if (score >= 60) return \"nearly-there\";\n return \"keep-exploring\";\n}\n\n/**\n * Calculate a score solely from rubric criteria and objective check results.\n * Missing criteria fail closed; unknown and duplicate result IDs are rejected.\n */\nexport function calculateAssessment(\n rubric: AssessmentRubricV1,\n results: AssessmentCheckResultV1[],\n): AssessmentResultV1 {\n const knownIds = new Set(rubric.criteria.map((criterion) => criterion.id));\n const resultById = new Map<string, AssessmentCheckResultV1>();\n\n for (const result of results) {\n if (!knownIds.has(result.criterionId)) {\n throw new Error(`Unknown assessment criterion: ${result.criterionId}`);\n }\n if (resultById.has(result.criterionId)) {\n throw new Error(`Duplicate assessment result: ${result.criterionId}`);\n }\n resultById.set(result.criterionId, result);\n }\n\n let score = 0;\n const passedCriterionIds: string[] = [];\n const failedCriterionIds: string[] = [];\n const failedMandatoryCriterionIds: string[] = [];\n\n for (const criterion of rubric.criteria) {\n const passed = resultById.get(criterion.id)?.passed === true;\n if (passed) {\n score += criterion.points;\n passedCriterionIds.push(criterion.id);\n continue;\n }\n\n failedCriterionIds.push(criterion.id);\n if (criterion.mandatory) failedMandatoryCriterionIds.push(criterion.id);\n }\n\n return {\n score,\n band: scoreBand(score),\n completed:\n score >= rubric.completionScore && failedMandatoryCriterionIds.length === 0,\n passedCriterionIds,\n failedCriterionIds,\n failedMandatoryCriterionIds,\n };\n}\n","import type {\n AssessmentRubricV1,\n CourseMaterialsManifestV1,\n HardwareItemV1,\n HardwareRequirementManifestV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n MissionV1,\n ModuleAgentDefinitionV1,\n ModuleCategoryV1,\n} from \"./contracts.js\";\n\nconst SOFTWARE_HARDWARE: HardwareRequirementManifestV1 = {\n requirementsVersion: \"1.0.0\",\n mode: \"none\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"not-applicable\",\n publicSaleBlocked: false,\n preparationMinutes: 0,\n items: [],\n warnings: [\"No specialist physical equipment is required.\"],\n supportedPlatforms: [\"Current Chromium, Firefox or Safari browser\"],\n};\n\nconst CORE_ROBOT_ITEMS: HardwareItemV1[] = [\n {\n id: \"pico-2-w\",\n label: \"Raspberry Pi Pico 2 W\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Raspberry Pi Pico 2 W with soldered headers\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"breadboard\",\n label: \"Solderless breadboard\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"400-point or larger solderless breadboard\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"usb-data-cable\",\n label: \"USB data cable\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Data-capable USB cable compatible with the Pico 2 W\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"jumper-wires\",\n label: \"Jumper wires\",\n quantity: 12,\n requirement: \"required\",\n exactSpecification: \"Insulated male-to-male breadboard jumper wires\",\n adultOnly: false,\n stage: \"core\",\n },\n];\n\nconst ROBOT_WARNING =\n \"Physical publication is blocked until every listed actuator, driver, sensor and power configuration passes an adult bench test.\";\n\nfunction physicalHardware(\n requirementsVersion: string,\n preparationMinutes: number,\n items: HardwareItemV1[],\n platforms: string[],\n): HardwareRequirementManifestV1 {\n return {\n requirementsVersion,\n mode: \"physical-first\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"pending-bench-test\",\n publicSaleBlocked: true,\n preparationMinutes,\n items: [...CORE_ROBOT_ITEMS, ...items],\n warnings: [ROBOT_WARNING, \"An adult must disconnect actuator power before changing wiring.\"],\n supportedPlatforms: platforms,\n };\n}\n\nfunction materials(slug: string, robot = false): CourseMaterialsManifestV1 {\n return {\n version: \"1.0.0\",\n learner: [\n { id: `${slug}-child-guide`, kind: \"child-guide\", audience: \"learner\" },\n { id: `${slug}-mission-cards`, kind: \"mission-cards\", audience: \"learner\" },\n { id: `${slug}-starter`, kind: \"starter-project\", audience: \"learner\" },\n { id: `${slug}-assets`, kind: \"asset-pack\", audience: \"learner\" },\n { id: `${slug}-printable`, kind: \"printable\", audience: \"learner\" },\n ],\n facilitator: [\n { id: `${slug}-facilitator`, kind: \"facilitator-guide\", audience: \"facilitator\" },\n { id: `${slug}-answers`, kind: \"answer-key\", audience: \"facilitator\" },\n { id: `${slug}-tests`, kind: \"protected-tests\", audience: \"facilitator\" },\n ...(robot\n ? [\n {\n id: `${slug}-hardware`,\n kind: \"hardware-guide\" as const,\n audience: \"facilitator\" as const,\n },\n ]\n : []),\n ],\n };\n}\n\nfunction agents(slug: string): ModuleAgentDefinitionV1[] {\n return [\n {\n id: `${slug}-assessor`,\n role: \"assessor\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-debugger`,\n role: \"debugger\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-fix-guide`,\n role: \"fix-guide\",\n evidenceBound: true,\n maySuggestSingleFix: true,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-concept-explainer`,\n role: \"concept-explainer\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n ];\n}\n\nfunction rubric(slug: string): AssessmentRubricV1 {\n return {\n version: \"1.0.0\",\n completionScore: 80,\n criteria: [\n {\n id: `${slug}-build`,\n label: \"The project is structurally valid and starts successfully.\",\n dimension: \"structure\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-one`,\n label: \"The first published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-two`,\n label: \"The second published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-three`,\n label: \"The complete project challenge works.\",\n dimension: \"behaviour\",\n points: 10,\n mandatory: false,\n visibility: \"visible\",\n },\n {\n id: `${slug}-edge-one`,\n label: \"The project handles its first protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-edge-two`,\n label: \"The project handles its second protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-safety`,\n label: \"The project obeys its mandatory safety and privacy boundary.\",\n dimension: \"safety\",\n points: 10,\n mandatory: true,\n visibility: \"visible\",\n },\n ],\n };\n}\n\nfunction mission(\n slug: string,\n index: number,\n title: string,\n concepts: string[],\n statement: string,\n sideAdventure: string,\n): MissionV1 {\n return {\n id: `${slug}-mission-${index}`,\n title,\n estimatedMinutes: index === 4 ? 25 : 20,\n concepts,\n goals: [\n {\n id: `${slug}-goal-${index}`,\n statement,\n evidence: \"assessment\",\n },\n ],\n sideAdventure,\n };\n}\n\ninterface ModuleInput {\n slug: string;\n title: string;\n category: ModuleCategoryV1;\n summary: string;\n tools: string[];\n concepts: string[];\n tokenSubunits: string;\n hosting?: boolean;\n hardware?: HardwareRequirementManifestV1;\n missionTitles: [string, string, string, string];\n}\n\nfunction module(input: ModuleInput): LearningModuleVersionV1 {\n const isRobot = input.category === \"robot\";\n return {\n id: `junior-coder.${input.slug}`,\n slug: input.slug,\n version: \"1.0.0\",\n contentRevision: \"2026-07-21.1\",\n title: input.title,\n category: input.category,\n summary: input.summary,\n estimatedMinutes: 90,\n tools: input.tools,\n concepts: input.concepts,\n selfContained: true,\n prerequisiteModuleIds: [],\n pricing: {\n state: \"pilot-grant-only\",\n tokenSubunits: input.tokenSubunits,\n includesMaterials: true,\n includesAssessmentRetries: true,\n includesAgents: true,\n includesHostingAllowance: input.hosting ?? false,\n },\n materials: materials(input.slug, isRobot),\n hardware: input.hardware ?? SOFTWARE_HARDWARE,\n missions: input.missionTitles.map((title, index) =>\n mission(\n input.slug,\n index + 1,\n title,\n input.concepts.slice(0, 3),\n `Complete ${title.toLocaleLowerCase(\"en-GB\")} and explain the observed result.`,\n `Invent one safe remix for ${title.toLocaleLowerCase(\"en-GB\")}.`,\n ),\n ),\n assessment: rubric(input.slug),\n agents: agents(input.slug),\n badges: [\n {\n id: `${input.slug}-mission-complete`,\n title: `${input.title} Champion`,\n evidence: \"module-score\",\n tradeable: false,\n tokenConvertible: false,\n },\n ...(isRobot\n ? [\n {\n id: `${input.slug}-physical-builder`,\n title: `${input.title} Physical Builder`,\n evidence: \"adult-physical-signoff\" as const,\n tradeable: false as const,\n tokenConvertible: false as const,\n },\n ]\n : []),\n ],\n };\n}\n\nconst modules: LearningModuleVersionV1[] = [\n module({\n slug: \"robot-maze-dash\",\n title: \"Robot Maze Dash\",\n category: \"game\",\n summary: \"Guide rescue robots through original mazes with visual programs and side-by-side text code.\",\n tools: [\"Visual blocks\", \"JavaScript view\", \"Python view\", \"C++ view\"],\n concepts: [\"sequence\", \"variables\", \"loops\", \"conditions\", \"functions\"],\n tokenSubunits: \"8000\",\n missionTitles: [\"Meet Your Robot\", \"Repeat the Rescue\", \"Choose the Safe Path\", \"Lost Robot Challenge\"],\n }),\n module({\n slug: \"road-hopper-rally\",\n title: \"Road Hopper Rally\",\n category: \"game\",\n summary: \"Build an original road-crossing game with changing lanes and rescue targets.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"events\", \"coordinates\", \"animation\", \"collision\", \"scoring\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Draw the Rescue Road\", \"Move the Hopper\", \"Add Moving Traffic\", \"Rally Challenge\"],\n }),\n module({\n slug: \"skywing-sprint\",\n title: \"Skywing Sprint\",\n category: \"game\",\n summary: \"Fly a rescue craft through procedurally changing sky gates.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"velocity\", \"gravity\", \"timing\", \"randomness\", \"obstacles\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Give Skywing Lift\", \"Build a Gate\", \"Score a Safe Flight\", \"Sky Sprint Challenge\"],\n }),\n module({\n slug: \"paddle-pulse\",\n title: \"Paddle Pulse\",\n category: \"game\",\n summary: \"Create a paddle-and-energy-ball arcade game with levels and original power-ups.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"angles\", \"collision response\", \"levels\", \"power-ups\", \"state\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Move the Pulse Paddle\", \"Bounce the Energy Ball\", \"Build a Target Wall\", \"Power-Up Challenge\"],\n }),\n module({\n slug: \"meteor-shield\",\n title: \"Meteor Shield\",\n category: \"game\",\n summary: \"Protect rescue bases with careful targeting and limited shield energy.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"targeting\", \"projectiles\", \"timers\", \"waves\", \"resources\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Mark the Rescue Bases\", \"Launch a Shield\", \"Create Meteor Waves\", \"Last Base Challenge\"],\n }),\n module({\n slug: \"rescue-crew-commander\",\n title: \"Rescue Crew Commander\",\n category: \"game\",\n summary: \"Assign safe jobs, routes and priorities to a team of original helper creatures.\",\n tools: [\"Visual blocks\", \"JavaScript\"],\n concepts: [\"state machines\", \"routes\", \"priorities\", \"group behaviour\", \"debugging\"],\n tokenSubunits: \"14000\",\n missionTitles: [\"Meet the Rescue Crew\", \"Give a Crew Job\", \"Choose a Safe Route\", \"Commander Challenge\"],\n }),\n module({\n slug: \"pixel-trail-challenge\",\n title: \"Pixel Trail Challenge\",\n category: \"game\",\n summary: \"Use Python lists and grid movement to grow a safe energy trail.\",\n tools: [\"Python\", \"Pyodide\", \"Educational drawing API\"],\n concepts: [\"lists\", \"grid movement\", \"spawning\", \"collision\", \"score\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Move the Pixel\", \"Grow the Trail\", \"Place Energy Orbs\", \"Trail Challenge\"],\n }),\n module({\n slug: \"star-defender-squadron\",\n title: \"Star Defender Squadron\",\n category: \"game\",\n summary: \"Build a multi-level space-rescue finale with original entities and enemy patterns.\",\n tools: [\"Python\", \"JavaScript\", \"Educational drawing API\"],\n concepts: [\"entities\", \"projectiles\", \"patterns\", \"health\", \"levels\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Launch the Squadron\", \"Build a Rescue Wave\", \"Add Shields and Health\", \"Star Defender Finale\"],\n }),\n module({\n slug: \"beacon-bot\",\n title: \"Beacon Bot\",\n category: \"robot\",\n summary: \"Program visible and infrared rescue signals with C++ and a Pico 2 W.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"digital output\", \"timing\", \"functions\", \"signals\", \"sensor input\"],\n tokenSubunits: \"8000\",\n hardware: physicalHardware(\"1.0.0\", 30, [\n { id: \"led-pack\", label: \"Visible LEDs\", quantity: 3, requirement: \"required\", exactSpecification: \"5 mm low-current red, amber and green LEDs\", adultOnly: false, stage: \"core\" },\n { id: \"led-resistors\", label: \"LED current-limiting resistors\", quantity: 3, requirement: \"required\", exactSpecification: \"330 ohm, 0.25 W resistors\", adultOnly: false, stage: \"core\" },\n { id: \"ir-pair\", label: \"Infrared emitter and receiver\", quantity: 1, requirement: \"required\", exactSpecification: \"Matched 940 nm IR LED and 3.3 V-compatible digital receiver pair; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Blink a Rescue Signal\", \"Build a Signal Function\", \"Send an IR Message\", \"Beacon Challenge\"],\n }),\n module({\n slug: \"servo-creature\",\n title: \"Servo Creature\",\n category: \"robot\",\n summary: \"Give a servo creature safe movements, moods and sensor reactions.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"PWM\", \"angles\", \"sequences\", \"limits\", \"interaction\"],\n tokenSubunits: \"10000\",\n hardware: physicalHardware(\"1.0.0\", 40, [\n { id: \"micro-servo\", label: \"Micro servo\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V signal-compatible micro servo; exact reference model and external power arrangement pending bench verification\", adultOnly: true, stage: \"servo\" },\n { id: \"servo-power\", label: \"Servo power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Switched regulated supply sized for the verified servo, with common signal ground\", adultOnly: true, stage: \"servo\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Wake the Creature\", \"Make a Movement Sequence\", \"Choose a Mood\", \"Creature Show Challenge\"],\n }),\n module({\n slug: \"dance-rover\",\n title: \"Dance Rover\",\n category: \"robot\",\n summary: \"Build reusable movement functions and a fail-safe rover dance.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"motor direction\", \"PWM speed\", \"functions\", \"sequences\", \"emergency stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 90, [\n { id: \"dual-motor-driver\", label: \"Dual motor driver\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V logic-compatible dual H-bridge; exact reference model pending bench verification\", adultOnly: true, stage: \"rover\" },\n { id: \"geared-motors\", label: \"Matching geared motors\", quantity: 2, requirement: \"required\", exactSpecification: \"Matching low-voltage geared DC motors compatible with the verified driver and supply\", adultOnly: true, stage: \"rover\" },\n { id: \"rover-chassis\", label: \"Rover chassis set\", quantity: 1, requirement: \"required\", exactSpecification: \"Two-wheel chassis with matching wheels and caster or skid\", adultOnly: true, stage: \"rover\" },\n { id: \"motor-power\", label: \"Switched motor power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Fused or protected switched supply within verified driver and motor ratings\", adultOnly: true, stage: \"rover\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Lifted-Wheel Safety Test\", \"Drive and Turn\", \"Build Movement Functions\", \"Rover Dance Challenge\"],\n }),\n module({\n slug: \"obstacle-explorer\",\n title: \"Obstacle Explorer\",\n category: \"robot\",\n summary: \"Use IR sensing, state and watchdogs to navigate and stop safely.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"booleans\", \"state\", \"navigation\", \"watchdogs\", \"fail-safe stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 60, [\n { id: \"verified-rover\", label: \"Verified Dance Rover build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Dance Rover reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"obstacle-sensors\", label: \"Digital IR obstacle sensors\", quantity: 2, requirement: \"required\", exactSpecification: \"3.3 V-compatible digital IR obstacle sensors; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Read an Obstacle\", \"Choose a Safe Response\", \"Add a Watchdog\", \"Explorer Maze Challenge\"],\n }),\n module({\n slug: \"rainbow-rescue-rover\",\n title: \"Rainbow Rescue Rover\",\n category: \"robot\",\n summary: \"Recognise local colour targets and send bounded serial commands to a safe rover.\",\n tools: [\"Python\", \"C++\", \"Pico 2 W\", \"Pi Zero 2 W\", \"Camera Module 3\", \"Simulator\"],\n concepts: [\"colour recognition\", \"coordinates\", \"serial protocol\", \"heartbeats\", \"integration\"],\n tokenSubunits: \"18000\",\n hardware: physicalHardware(\"1.0.0\", 120, [\n { id: \"verified-explorer\", label: \"Verified Obstacle Explorer build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Obstacle Explorer reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"pi-zero-2-w\", label: \"Raspberry Pi Zero 2 W\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Zero 2 W with supported Raspberry Pi OS image\", adultOnly: true, stage: \"camera\" },\n { id: \"camera-3\", label: \"Raspberry Pi Camera Module 3\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Camera Module 3 with the correct Zero-series camera ribbon\", adultOnly: true, stage: \"camera\" },\n { id: \"pi-storage-power\", label: \"Pi storage and power\", quantity: 1, requirement: \"required\", exactSpecification: \"Supported microSD card and regulated Raspberry Pi power supply\", adultOnly: true, stage: \"camera\" },\n ], [\"Current Raspberry Pi OS\", \"Pico SDK\"]),\n missionTitles: [\"Find a Colour Target\", \"Report Left Centre or Right\", \"Send Safe Serial Commands\", \"Rainbow Rescue Challenge\"],\n }),\n module({\n slug: \"vibe-game-remix-lab\",\n title: \"Vibe Game Remix Lab\",\n category: \"vibe\",\n summary: \"Transform a supplied mini-game through structured, evidence-bound AI suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"JavaScript sandbox\"],\n concepts: [\"intent\", \"constraints\", \"diffs\", \"testing\", \"explanation\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Describe the Remix\", \"Constrain the Change\", \"Review One Diff\", \"Remix Challenge\"],\n }),\n module({\n slug: \"vibe-bug-detective\",\n title: \"Vibe Bug Detective\",\n category: \"vibe\",\n summary: \"Repair an intentionally broken project using assessment evidence and focused suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"Assessment runner\"],\n concepts: [\"diagnostics\", \"hypotheses\", \"minimal fixes\", \"regression tests\", \"reflection\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Read the Evidence\", \"Ask a Focused Question\", \"Inspect a Suggested Fix\", \"Regression Challenge\"],\n }),\n module({\n slug: \"vibe-idea-studio\",\n title: \"Vibe Idea Studio\",\n category: \"vibe\",\n summary: \"Turn a bounded original idea into goals, acceptance tests and a working prototype.\",\n tools: [\"Intent cards\", \"Structured prompt builder\", \"Diff review\", \"Sandbox\"],\n concepts: [\"goals\", \"acceptance tests\", \"iteration\", \"trade-offs\", \"explanation\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Shape the Idea\", \"Write Success Tests\", \"Build One Step\", \"Prototype Showcase\"],\n }),\n module({\n slug: \"adventure-mission-planner\",\n title: \"Adventure Mission Planner\",\n category: \"web-app\",\n summary: \"Build an accessible planner for fictional quests and activities.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"semantic HTML\", \"forms\", \"validation\", \"arrays\", \"local persistence\"],\n tokenSubunits: \"10000\",\n hosting: true,\n missionTitles: [\"Make a Semantic Page\", \"Add a Mission Form\", \"Save Fictional Missions\", \"Accessible Planner Challenge\"],\n }),\n module({\n slug: \"creature-care-dashboard\",\n title: \"Creature Care Dashboard\",\n category: \"web-app\",\n summary: \"Create a responsive dashboard for a fictional digital creature.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"components\", \"events\", \"timers\", \"status displays\", \"reduced motion\"],\n tokenSubunits: \"12000\",\n hosting: true,\n missionTitles: [\"Design the Creature Card\", \"Update Creature State\", \"Add a Safe Timer\", \"Care Dashboard Challenge\"],\n }),\n module({\n slug: \"robot-mission-control\",\n title: \"Robot Mission Control\",\n category: \"web-app\",\n summary: \"Build a simulated control and telemetry interface with safety confirmations.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Serial simulator\", \"Private preview\"],\n concepts: [\"commands\", \"state machines\", \"confirmations\", \"charts\", \"responsive controls\"],\n tokenSubunits: \"14000\",\n hosting: true,\n missionTitles: [\"Build the Control Panel\", \"Simulate Telemetry\", \"Add Stop Confirmations\", \"Mission Control Challenge\"],\n }),\n];\n\n/**\n * Uniform price for the immutable 1.1.0 pilot catalog.\n *\n * The GBP value is product-copy reference metadata under the published\n * 10p-per-Token economy reference rate. It does not create redemption rights.\n */\nexport const JUNIOR_CODER_MODULE_PRICE_V1_1 = Object.freeze({\n tokenSubunits: \"50000\",\n referencePrice: Object.freeze({\n currency: \"GBP\" as const,\n minorUnits: \"500\",\n basis: \"nominal-reference\" as const,\n cashRedemptionAllowed: false as const,\n }),\n});\n\n/** Initial immutable Junior Coder path manifest for pilot grants and shadow pricing. */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: LearningPathVersionV1 = {\n id: \"junior-coder.robot-rescue-arcade\",\n slug: \"robot-rescue-arcade\",\n version: \"1.0.0\",\n title: \"Junior Coder: Robot Rescue Arcade\",\n description: \"Nineteen self-contained game, robotics, Vibe Coding and web-app projects for young programmers.\",\n catalogState: \"pilot\",\n publicLaunchAtomic: true,\n featureFlag: \"learning.junior-coder.catalog.enabled\",\n modules,\n};\n\n/**\n * Uniformly priced successor to the immutable 1.0.0 pilot catalog.\n *\n * All modules remain independently sellable and retain their existing content,\n * manifests and safeguards. The new module and path versions bind the new price\n * without altering previously published records.\n */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1: LearningPathVersionV1 = {\n ...JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,\n version: \"1.1.0\",\n modules: JUNIOR_CODER_ROBOT_RESCUE_PATH_V1.modules.map((entry) => ({\n ...entry,\n version: \"1.1.0\",\n contentRevision: \"2026-07-28.1\",\n pricing: {\n ...entry.pricing,\n tokenSubunits: JUNIOR_CODER_MODULE_PRICE_V1_1.tokenSubunits,\n referencePrice: JUNIOR_CODER_MODULE_PRICE_V1_1.referencePrice,\n },\n })),\n};\n\n/** Current pilot catalog for server adapters that intentionally follow releases. */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT =\n JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1;\n","import type {\n AssessmentDimensionV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n LearningValidationIssueV1,\n} from \"./contracts.js\";\n\nconst DIMENSION_TOTALS: Record<AssessmentDimensionV1, number> = {\n structure: 20,\n behaviour: 50,\n resilience: 20,\n safety: 10,\n};\n\nconst CANONICAL_TOKEN_SUBUNITS = /^(0|[1-9][0-9]*)$/u;\n\nfunction issue(\n code: LearningValidationIssueV1[\"code\"],\n message: string,\n path: string,\n moduleId?: string,\n): LearningValidationIssueV1 {\n return { code, message, path, ...(moduleId ? { moduleId } : {}) };\n}\n\nfunction validateModule(\n module: LearningModuleVersionV1,\n moduleIndex: number,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const base = `modules[${moduleIndex}]`;\n\n if (!module.selfContained) {\n issues.push(\n issue(\n \"module-not-self-contained\",\n \"Every sellable module must be self-contained.\",\n `${base}.selfContained`,\n module.id,\n ),\n );\n }\n\n if (module.prerequisiteModuleIds.length > 0) {\n issues.push(\n issue(\n \"paid-prerequisite\",\n \"A sellable module cannot require another paid module.\",\n `${base}.prerequisiteModuleIds`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.learner.length === 0 ||\n module.materials.facilitator.length === 0\n ) {\n issues.push(\n issue(\n \"missing-materials\",\n \"Learner and facilitator material manifests are both required.\",\n `${base}.materials`,\n module.id,\n ),\n );\n }\n\n if (module.materials.learner.some((material) => material.audience !== \"learner\")) {\n issues.push(\n issue(\n \"facilitator-material-leak\",\n \"Learner material contains a facilitator-only record.\",\n `${base}.materials.learner`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.facilitator.some(\n (material) => material.audience !== \"facilitator\",\n )\n ) {\n issues.push(\n issue(\n \"learner-material-leak\",\n \"Facilitator material contains a learner record.\",\n `${base}.materials.facilitator`,\n module.id,\n ),\n );\n }\n\n if (!CANONICAL_TOKEN_SUBUNITS.test(module.pricing.tokenSubunits)) {\n issues.push(\n issue(\n \"invalid-token-subunits\",\n \"Token subunits must be a canonical non-negative base-10 integer string.\",\n `${base}.pricing.tokenSubunits`,\n module.id,\n ),\n );\n }\n\n const referencePrice = module.pricing.referencePrice;\n if (\n referencePrice\n && (\n referencePrice.currency !== \"GBP\"\n || !CANONICAL_TOKEN_SUBUNITS.test(referencePrice.minorUnits)\n || referencePrice.basis !== \"nominal-reference\"\n || referencePrice.cashRedemptionAllowed !== false\n )\n ) {\n issues.push(\n issue(\n \"invalid-reference-price\",\n \"Reference prices must use canonical GBP minor units, the nominal reference basis and prohibit cash redemption.\",\n `${base}.pricing.referencePrice`,\n module.id,\n ),\n );\n }\n\n const criterionIds = new Set<string>();\n const dimensionTotals: Record<AssessmentDimensionV1, number> = {\n structure: 0,\n behaviour: 0,\n resilience: 0,\n safety: 0,\n };\n let rubricTotal = 0;\n\n for (const criterion of module.assessment.criteria) {\n rubricTotal += criterion.points;\n dimensionTotals[criterion.dimension] += criterion.points;\n if (criterionIds.has(criterion.id)) {\n issues.push(\n issue(\n \"duplicate-criterion-id\",\n `Duplicate assessment criterion ${criterion.id}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n criterionIds.add(criterion.id);\n }\n\n if (rubricTotal !== 100) {\n issues.push(\n issue(\n \"rubric-total\",\n `Assessment rubric totals ${rubricTotal}; expected 100.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n for (const [dimension, expected] of Object.entries(DIMENSION_TOTALS) as Array<\n [AssessmentDimensionV1, number]\n >) {\n if (dimensionTotals[dimension] !== expected) {\n issues.push(\n issue(\n \"rubric-dimension-total\",\n `${dimension} criteria total ${dimensionTotals[dimension]}; expected ${expected}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n }\n\n if (\n !module.assessment.criteria.some(\n (criterion) => criterion.dimension === \"safety\" && criterion.mandatory,\n )\n ) {\n issues.push(\n issue(\n \"missing-mandatory-safety\",\n \"Every module requires a mandatory safety criterion.\",\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n if (module.hardware.mode === \"physical-first\" && module.hardware.items.length === 0) {\n issues.push(\n issue(\n \"missing-hardware-items\",\n \"Physical-first modules require an exact hardware item list.\",\n `${base}.hardware.items`,\n module.id,\n ),\n );\n }\n\n if (\n module.agents.some(\n (agent) =>\n agent.mayAssignScore !== false ||\n agent.mayAwardReward !== false ||\n agent.mayPublish !== false ||\n agent.mayControlHardware !== false,\n )\n ) {\n issues.push(\n issue(\n \"invalid-agent-authority\",\n \"Module agents cannot own scores, rewards, publishing or hardware control.\",\n `${base}.agents`,\n module.id,\n ),\n );\n }\n\n if (module.missions.length === 0) {\n issues.push(\n issue(\n \"missing-missions\",\n \"A module requires at least one mission.\",\n `${base}.missions`,\n module.id,\n ),\n );\n }\n\n return issues;\n}\n\n/** Return every catalog issue without throwing, suitable for authoring tools. */\nexport function validateLearningPath(\n path: LearningPathVersionV1,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const moduleIds = new Set<string>();\n const moduleSlugs = new Set<string>();\n\n for (const [index, module] of path.modules.entries()) {\n if (moduleIds.has(module.id)) {\n issues.push(\n issue(\n \"duplicate-module-id\",\n `Duplicate module id ${module.id}.`,\n `modules[${index}].id`,\n module.id,\n ),\n );\n }\n moduleIds.add(module.id);\n\n if (moduleSlugs.has(module.slug)) {\n issues.push(\n issue(\n \"duplicate-module-slug\",\n `Duplicate module slug ${module.slug}.`,\n `modules[${index}].slug`,\n module.id,\n ),\n );\n }\n moduleSlugs.add(module.slug);\n issues.push(...validateModule(module, index));\n }\n\n return issues;\n}\n\n/** Fail fast when a path is not safe to publish or consume. */\nexport function assertValidLearningPath(path: LearningPathVersionV1): void {\n const issues = validateLearningPath(path);\n if (issues.length === 0) return;\n\n const summary = issues\n .map((entry) => `${entry.code} at ${entry.path}: ${entry.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid learning path:\\n${summary}`);\n}\n"],"mappings":"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","names":["rubric","module","module"]}
package/dist/index.d.cts CHANGED
@@ -118,9 +118,18 @@ interface ModuleAgentFeedbackV1 {
118
118
  scoreAuthority: "deterministic-assessment";
119
119
  }
120
120
  /** Ordinary Token subunits used as a pilot shadow or fixed price. */
121
+ interface ModuleReferencePriceV1 {
122
+ /** Reference copy only; this is never a cash balance or redemption promise. */
123
+ currency: "GBP";
124
+ /** Canonical GBP minor units. */
125
+ minorUnits: string;
126
+ basis: "nominal-reference";
127
+ cashRedemptionAllowed: false;
128
+ }
121
129
  interface ModulePricingV1 {
122
130
  state: CommercialStateV1;
123
131
  tokenSubunits: string;
132
+ referencePrice?: ModuleReferencePriceV1;
124
133
  includesMaterials: true;
125
134
  includesAssessmentRetries: true;
126
135
  includesAgents: true;
@@ -173,7 +182,7 @@ interface ModuleEntitlementV1 {
173
182
  subjectAccountId: string;
174
183
  moduleId: string;
175
184
  moduleVersion: string;
176
- source: "pilot-grant" | "module-allowance-purchase" | "support-grant";
185
+ source: "pilot-grant" | "module-allowance-purchase" | "support-grant" | "admin-test-grant";
177
186
  state: "pending" | "active" | "revoked";
178
187
  economyTransactionId?: string;
179
188
  grantedAt: string;
@@ -210,7 +219,7 @@ interface PublishedStaticProjectSnapshotV1 {
210
219
  expiresAt: string;
211
220
  }
212
221
  interface LearningValidationIssueV1 {
213
- code: "duplicate-module-id" | "duplicate-module-slug" | "module-not-self-contained" | "paid-prerequisite" | "missing-materials" | "facilitator-material-leak" | "learner-material-leak" | "invalid-token-subunits" | "rubric-total" | "rubric-dimension-total" | "duplicate-criterion-id" | "missing-mandatory-safety" | "missing-hardware-items" | "invalid-agent-authority" | "missing-missions";
222
+ code: "duplicate-module-id" | "duplicate-module-slug" | "module-not-self-contained" | "paid-prerequisite" | "missing-materials" | "facilitator-material-leak" | "learner-material-leak" | "invalid-token-subunits" | "invalid-reference-price" | "rubric-total" | "rubric-dimension-total" | "duplicate-criterion-id" | "missing-mandatory-safety" | "missing-hardware-items" | "invalid-agent-authority" | "missing-missions";
214
223
  message: string;
215
224
  moduleId?: string;
216
225
  path: string;
@@ -222,12 +231,37 @@ interface LearningValidationIssueV1 {
222
231
  */
223
232
  declare function calculateAssessment(rubric: AssessmentRubricV1, results: AssessmentCheckResultV1[]): AssessmentResultV1;
224
233
 
234
+ /**
235
+ * Uniform price for the immutable 1.1.0 pilot catalog.
236
+ *
237
+ * The GBP value is product-copy reference metadata under the published
238
+ * 10p-per-Token economy reference rate. It does not create redemption rights.
239
+ */
240
+ declare const JUNIOR_CODER_MODULE_PRICE_V1_1: Readonly<{
241
+ tokenSubunits: "50000";
242
+ referencePrice: Readonly<{
243
+ currency: "GBP";
244
+ minorUnits: "500";
245
+ basis: "nominal-reference";
246
+ cashRedemptionAllowed: false;
247
+ }>;
248
+ }>;
225
249
  /** Initial immutable Junior Coder path manifest for pilot grants and shadow pricing. */
226
250
  declare const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: LearningPathVersionV1;
251
+ /**
252
+ * Uniformly priced successor to the immutable 1.0.0 pilot catalog.
253
+ *
254
+ * All modules remain independently sellable and retain their existing content,
255
+ * manifests and safeguards. The new module and path versions bind the new price
256
+ * without altering previously published records.
257
+ */
258
+ declare const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1: LearningPathVersionV1;
259
+ /** Current pilot catalog for server adapters that intentionally follow releases. */
260
+ declare const JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT: LearningPathVersionV1;
227
261
 
228
262
  /** Return every catalog issue without throwing, suitable for authoring tools. */
229
263
  declare function validateLearningPath(path: LearningPathVersionV1): LearningValidationIssueV1[];
230
264
  /** Fail fast when a path is not safe to publish or consume. */
231
265
  declare function assertValidLearningPath(path: LearningPathVersionV1): void;
232
266
 
233
- export { type AssessmentCheckResultV1, type AssessmentCriterionV1, type AssessmentDimensionV1, type AssessmentResultV1, type AssessmentRubricV1, type AttemptEvidenceV1, type BadgeDefinitionV1, type CommercialStateV1, type CourseMaterialAudienceV1, type CourseMaterialKindV1, type CourseMaterialV1, type CourseMaterialsManifestV1, type GuardianAiConsentV1, type HardwareItemV1, type HardwareModeV1, type HardwareRequirementManifestV1, type HardwareVerificationStatusV1, JUNIOR_CODER_ROBOT_RESCUE_PATH_V1, type LearningGoalV1, type LearningModuleVersionV1, type LearningPathVersionV1, type LearningValidationIssueV1, type MissionV1, type ModuleAgentDefinitionV1, type ModuleAgentFeedbackV1, type ModuleAgentRoleV1, type ModuleCategoryV1, type ModuleEntitlementV1, type ModulePricingV1, type PublishedStaticProjectSnapshotV1, type ScoreBandV1, assertValidLearningPath, calculateAssessment, validateLearningPath };
267
+ export { type AssessmentCheckResultV1, type AssessmentCriterionV1, type AssessmentDimensionV1, type AssessmentResultV1, type AssessmentRubricV1, type AttemptEvidenceV1, type BadgeDefinitionV1, type CommercialStateV1, type CourseMaterialAudienceV1, type CourseMaterialKindV1, type CourseMaterialV1, type CourseMaterialsManifestV1, type GuardianAiConsentV1, type HardwareItemV1, type HardwareModeV1, type HardwareRequirementManifestV1, type HardwareVerificationStatusV1, JUNIOR_CODER_MODULE_PRICE_V1_1, JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT, JUNIOR_CODER_ROBOT_RESCUE_PATH_V1, JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1, type LearningGoalV1, type LearningModuleVersionV1, type LearningPathVersionV1, type LearningValidationIssueV1, type MissionV1, type ModuleAgentDefinitionV1, type ModuleAgentFeedbackV1, type ModuleAgentRoleV1, type ModuleCategoryV1, type ModuleEntitlementV1, type ModulePricingV1, type ModuleReferencePriceV1, type PublishedStaticProjectSnapshotV1, type ScoreBandV1, assertValidLearningPath, calculateAssessment, validateLearningPath };
package/dist/index.d.ts CHANGED
@@ -118,9 +118,18 @@ interface ModuleAgentFeedbackV1 {
118
118
  scoreAuthority: "deterministic-assessment";
119
119
  }
120
120
  /** Ordinary Token subunits used as a pilot shadow or fixed price. */
121
+ interface ModuleReferencePriceV1 {
122
+ /** Reference copy only; this is never a cash balance or redemption promise. */
123
+ currency: "GBP";
124
+ /** Canonical GBP minor units. */
125
+ minorUnits: string;
126
+ basis: "nominal-reference";
127
+ cashRedemptionAllowed: false;
128
+ }
121
129
  interface ModulePricingV1 {
122
130
  state: CommercialStateV1;
123
131
  tokenSubunits: string;
132
+ referencePrice?: ModuleReferencePriceV1;
124
133
  includesMaterials: true;
125
134
  includesAssessmentRetries: true;
126
135
  includesAgents: true;
@@ -173,7 +182,7 @@ interface ModuleEntitlementV1 {
173
182
  subjectAccountId: string;
174
183
  moduleId: string;
175
184
  moduleVersion: string;
176
- source: "pilot-grant" | "module-allowance-purchase" | "support-grant";
185
+ source: "pilot-grant" | "module-allowance-purchase" | "support-grant" | "admin-test-grant";
177
186
  state: "pending" | "active" | "revoked";
178
187
  economyTransactionId?: string;
179
188
  grantedAt: string;
@@ -210,7 +219,7 @@ interface PublishedStaticProjectSnapshotV1 {
210
219
  expiresAt: string;
211
220
  }
212
221
  interface LearningValidationIssueV1 {
213
- code: "duplicate-module-id" | "duplicate-module-slug" | "module-not-self-contained" | "paid-prerequisite" | "missing-materials" | "facilitator-material-leak" | "learner-material-leak" | "invalid-token-subunits" | "rubric-total" | "rubric-dimension-total" | "duplicate-criterion-id" | "missing-mandatory-safety" | "missing-hardware-items" | "invalid-agent-authority" | "missing-missions";
222
+ code: "duplicate-module-id" | "duplicate-module-slug" | "module-not-self-contained" | "paid-prerequisite" | "missing-materials" | "facilitator-material-leak" | "learner-material-leak" | "invalid-token-subunits" | "invalid-reference-price" | "rubric-total" | "rubric-dimension-total" | "duplicate-criterion-id" | "missing-mandatory-safety" | "missing-hardware-items" | "invalid-agent-authority" | "missing-missions";
214
223
  message: string;
215
224
  moduleId?: string;
216
225
  path: string;
@@ -222,12 +231,37 @@ interface LearningValidationIssueV1 {
222
231
  */
223
232
  declare function calculateAssessment(rubric: AssessmentRubricV1, results: AssessmentCheckResultV1[]): AssessmentResultV1;
224
233
 
234
+ /**
235
+ * Uniform price for the immutable 1.1.0 pilot catalog.
236
+ *
237
+ * The GBP value is product-copy reference metadata under the published
238
+ * 10p-per-Token economy reference rate. It does not create redemption rights.
239
+ */
240
+ declare const JUNIOR_CODER_MODULE_PRICE_V1_1: Readonly<{
241
+ tokenSubunits: "50000";
242
+ referencePrice: Readonly<{
243
+ currency: "GBP";
244
+ minorUnits: "500";
245
+ basis: "nominal-reference";
246
+ cashRedemptionAllowed: false;
247
+ }>;
248
+ }>;
225
249
  /** Initial immutable Junior Coder path manifest for pilot grants and shadow pricing. */
226
250
  declare const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: LearningPathVersionV1;
251
+ /**
252
+ * Uniformly priced successor to the immutable 1.0.0 pilot catalog.
253
+ *
254
+ * All modules remain independently sellable and retain their existing content,
255
+ * manifests and safeguards. The new module and path versions bind the new price
256
+ * without altering previously published records.
257
+ */
258
+ declare const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1: LearningPathVersionV1;
259
+ /** Current pilot catalog for server adapters that intentionally follow releases. */
260
+ declare const JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT: LearningPathVersionV1;
227
261
 
228
262
  /** Return every catalog issue without throwing, suitable for authoring tools. */
229
263
  declare function validateLearningPath(path: LearningPathVersionV1): LearningValidationIssueV1[];
230
264
  /** Fail fast when a path is not safe to publish or consume. */
231
265
  declare function assertValidLearningPath(path: LearningPathVersionV1): void;
232
266
 
233
- export { type AssessmentCheckResultV1, type AssessmentCriterionV1, type AssessmentDimensionV1, type AssessmentResultV1, type AssessmentRubricV1, type AttemptEvidenceV1, type BadgeDefinitionV1, type CommercialStateV1, type CourseMaterialAudienceV1, type CourseMaterialKindV1, type CourseMaterialV1, type CourseMaterialsManifestV1, type GuardianAiConsentV1, type HardwareItemV1, type HardwareModeV1, type HardwareRequirementManifestV1, type HardwareVerificationStatusV1, JUNIOR_CODER_ROBOT_RESCUE_PATH_V1, type LearningGoalV1, type LearningModuleVersionV1, type LearningPathVersionV1, type LearningValidationIssueV1, type MissionV1, type ModuleAgentDefinitionV1, type ModuleAgentFeedbackV1, type ModuleAgentRoleV1, type ModuleCategoryV1, type ModuleEntitlementV1, type ModulePricingV1, type PublishedStaticProjectSnapshotV1, type ScoreBandV1, assertValidLearningPath, calculateAssessment, validateLearningPath };
267
+ export { type AssessmentCheckResultV1, type AssessmentCriterionV1, type AssessmentDimensionV1, type AssessmentResultV1, type AssessmentRubricV1, type AttemptEvidenceV1, type BadgeDefinitionV1, type CommercialStateV1, type CourseMaterialAudienceV1, type CourseMaterialKindV1, type CourseMaterialV1, type CourseMaterialsManifestV1, type GuardianAiConsentV1, type HardwareItemV1, type HardwareModeV1, type HardwareRequirementManifestV1, type HardwareVerificationStatusV1, JUNIOR_CODER_MODULE_PRICE_V1_1, JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT, JUNIOR_CODER_ROBOT_RESCUE_PATH_V1, JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1, type LearningGoalV1, type LearningModuleVersionV1, type LearningPathVersionV1, type LearningValidationIssueV1, type MissionV1, type ModuleAgentDefinitionV1, type ModuleAgentFeedbackV1, type ModuleAgentRoleV1, type ModuleCategoryV1, type ModuleEntitlementV1, type ModulePricingV1, type ModuleReferencePriceV1, type PublishedStaticProjectSnapshotV1, type ScoreBandV1, assertValidLearningPath, calculateAssessment, validateLearningPath };
package/dist/index.js CHANGED
@@ -532,6 +532,15 @@ var modules = [
532
532
  missionTitles: ["Build the Control Panel", "Simulate Telemetry", "Add Stop Confirmations", "Mission Control Challenge"]
533
533
  })
534
534
  ];
535
+ var JUNIOR_CODER_MODULE_PRICE_V1_1 = Object.freeze({
536
+ tokenSubunits: "50000",
537
+ referencePrice: Object.freeze({
538
+ currency: "GBP",
539
+ minorUnits: "500",
540
+ basis: "nominal-reference",
541
+ cashRedemptionAllowed: false
542
+ })
543
+ });
535
544
  var JUNIOR_CODER_ROBOT_RESCUE_PATH_V1 = {
536
545
  id: "junior-coder.robot-rescue-arcade",
537
546
  slug: "robot-rescue-arcade",
@@ -543,6 +552,21 @@ var JUNIOR_CODER_ROBOT_RESCUE_PATH_V1 = {
543
552
  featureFlag: "learning.junior-coder.catalog.enabled",
544
553
  modules
545
554
  };
555
+ var JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1 = {
556
+ ...JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,
557
+ version: "1.1.0",
558
+ modules: JUNIOR_CODER_ROBOT_RESCUE_PATH_V1.modules.map((entry) => ({
559
+ ...entry,
560
+ version: "1.1.0",
561
+ contentRevision: "2026-07-28.1",
562
+ pricing: {
563
+ ...entry.pricing,
564
+ tokenSubunits: JUNIOR_CODER_MODULE_PRICE_V1_1.tokenSubunits,
565
+ referencePrice: JUNIOR_CODER_MODULE_PRICE_V1_1.referencePrice
566
+ }
567
+ }))
568
+ };
569
+ var JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT = JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1;
546
570
 
547
571
  // src/validation.ts
548
572
  var DIMENSION_TOTALS = {
@@ -620,6 +644,17 @@ function validateModule(module2, moduleIndex) {
620
644
  )
621
645
  );
622
646
  }
647
+ const referencePrice = module2.pricing.referencePrice;
648
+ if (referencePrice && (referencePrice.currency !== "GBP" || !CANONICAL_TOKEN_SUBUNITS.test(referencePrice.minorUnits) || referencePrice.basis !== "nominal-reference" || referencePrice.cashRedemptionAllowed !== false)) {
649
+ issues.push(
650
+ issue(
651
+ "invalid-reference-price",
652
+ "Reference prices must use canonical GBP minor units, the nominal reference basis and prohibit cash redemption.",
653
+ `${base}.pricing.referencePrice`,
654
+ module2.id
655
+ )
656
+ );
657
+ }
623
658
  const criterionIds = /* @__PURE__ */ new Set();
624
659
  const dimensionTotals = {
625
660
  structure: 0,
@@ -750,7 +785,10 @@ function assertValidLearningPath(path) {
750
785
  ${summary}`);
751
786
  }
752
787
  export {
788
+ JUNIOR_CODER_MODULE_PRICE_V1_1,
789
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT,
753
790
  JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,
791
+ JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1,
754
792
  assertValidLearningPath,
755
793
  calculateAssessment,
756
794
  validateLearningPath
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/assessment.ts","../src/catalog.ts","../src/validation.ts"],"sourcesContent":["import type {\n AssessmentCheckResultV1,\n AssessmentResultV1,\n AssessmentRubricV1,\n ScoreBandV1,\n} from \"./contracts.js\";\n\nfunction scoreBand(score: number): ScoreBandV1 {\n if (score >= 95) return \"mastered\";\n if (score >= 80) return \"mission-complete\";\n if (score >= 60) return \"nearly-there\";\n return \"keep-exploring\";\n}\n\n/**\n * Calculate a score solely from rubric criteria and objective check results.\n * Missing criteria fail closed; unknown and duplicate result IDs are rejected.\n */\nexport function calculateAssessment(\n rubric: AssessmentRubricV1,\n results: AssessmentCheckResultV1[],\n): AssessmentResultV1 {\n const knownIds = new Set(rubric.criteria.map((criterion) => criterion.id));\n const resultById = new Map<string, AssessmentCheckResultV1>();\n\n for (const result of results) {\n if (!knownIds.has(result.criterionId)) {\n throw new Error(`Unknown assessment criterion: ${result.criterionId}`);\n }\n if (resultById.has(result.criterionId)) {\n throw new Error(`Duplicate assessment result: ${result.criterionId}`);\n }\n resultById.set(result.criterionId, result);\n }\n\n let score = 0;\n const passedCriterionIds: string[] = [];\n const failedCriterionIds: string[] = [];\n const failedMandatoryCriterionIds: string[] = [];\n\n for (const criterion of rubric.criteria) {\n const passed = resultById.get(criterion.id)?.passed === true;\n if (passed) {\n score += criterion.points;\n passedCriterionIds.push(criterion.id);\n continue;\n }\n\n failedCriterionIds.push(criterion.id);\n if (criterion.mandatory) failedMandatoryCriterionIds.push(criterion.id);\n }\n\n return {\n score,\n band: scoreBand(score),\n completed:\n score >= rubric.completionScore && failedMandatoryCriterionIds.length === 0,\n passedCriterionIds,\n failedCriterionIds,\n failedMandatoryCriterionIds,\n };\n}\n","import type {\n AssessmentRubricV1,\n CourseMaterialsManifestV1,\n HardwareItemV1,\n HardwareRequirementManifestV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n MissionV1,\n ModuleAgentDefinitionV1,\n ModuleCategoryV1,\n} from \"./contracts.js\";\n\nconst SOFTWARE_HARDWARE: HardwareRequirementManifestV1 = {\n requirementsVersion: \"1.0.0\",\n mode: \"none\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"not-applicable\",\n publicSaleBlocked: false,\n preparationMinutes: 0,\n items: [],\n warnings: [\"No specialist physical equipment is required.\"],\n supportedPlatforms: [\"Current Chromium, Firefox or Safari browser\"],\n};\n\nconst CORE_ROBOT_ITEMS: HardwareItemV1[] = [\n {\n id: \"pico-2-w\",\n label: \"Raspberry Pi Pico 2 W\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Raspberry Pi Pico 2 W with soldered headers\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"breadboard\",\n label: \"Solderless breadboard\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"400-point or larger solderless breadboard\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"usb-data-cable\",\n label: \"USB data cable\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Data-capable USB cable compatible with the Pico 2 W\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"jumper-wires\",\n label: \"Jumper wires\",\n quantity: 12,\n requirement: \"required\",\n exactSpecification: \"Insulated male-to-male breadboard jumper wires\",\n adultOnly: false,\n stage: \"core\",\n },\n];\n\nconst ROBOT_WARNING =\n \"Physical publication is blocked until every listed actuator, driver, sensor and power configuration passes an adult bench test.\";\n\nfunction physicalHardware(\n requirementsVersion: string,\n preparationMinutes: number,\n items: HardwareItemV1[],\n platforms: string[],\n): HardwareRequirementManifestV1 {\n return {\n requirementsVersion,\n mode: \"physical-first\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"pending-bench-test\",\n publicSaleBlocked: true,\n preparationMinutes,\n items: [...CORE_ROBOT_ITEMS, ...items],\n warnings: [ROBOT_WARNING, \"An adult must disconnect actuator power before changing wiring.\"],\n supportedPlatforms: platforms,\n };\n}\n\nfunction materials(slug: string, robot = false): CourseMaterialsManifestV1 {\n return {\n version: \"1.0.0\",\n learner: [\n { id: `${slug}-child-guide`, kind: \"child-guide\", audience: \"learner\" },\n { id: `${slug}-mission-cards`, kind: \"mission-cards\", audience: \"learner\" },\n { id: `${slug}-starter`, kind: \"starter-project\", audience: \"learner\" },\n { id: `${slug}-assets`, kind: \"asset-pack\", audience: \"learner\" },\n { id: `${slug}-printable`, kind: \"printable\", audience: \"learner\" },\n ],\n facilitator: [\n { id: `${slug}-facilitator`, kind: \"facilitator-guide\", audience: \"facilitator\" },\n { id: `${slug}-answers`, kind: \"answer-key\", audience: \"facilitator\" },\n { id: `${slug}-tests`, kind: \"protected-tests\", audience: \"facilitator\" },\n ...(robot\n ? [\n {\n id: `${slug}-hardware`,\n kind: \"hardware-guide\" as const,\n audience: \"facilitator\" as const,\n },\n ]\n : []),\n ],\n };\n}\n\nfunction agents(slug: string): ModuleAgentDefinitionV1[] {\n return [\n {\n id: `${slug}-assessor`,\n role: \"assessor\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-debugger`,\n role: \"debugger\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-fix-guide`,\n role: \"fix-guide\",\n evidenceBound: true,\n maySuggestSingleFix: true,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-concept-explainer`,\n role: \"concept-explainer\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n ];\n}\n\nfunction rubric(slug: string): AssessmentRubricV1 {\n return {\n version: \"1.0.0\",\n completionScore: 80,\n criteria: [\n {\n id: `${slug}-build`,\n label: \"The project is structurally valid and starts successfully.\",\n dimension: \"structure\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-one`,\n label: \"The first published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-two`,\n label: \"The second published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-three`,\n label: \"The complete project challenge works.\",\n dimension: \"behaviour\",\n points: 10,\n mandatory: false,\n visibility: \"visible\",\n },\n {\n id: `${slug}-edge-one`,\n label: \"The project handles its first protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-edge-two`,\n label: \"The project handles its second protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-safety`,\n label: \"The project obeys its mandatory safety and privacy boundary.\",\n dimension: \"safety\",\n points: 10,\n mandatory: true,\n visibility: \"visible\",\n },\n ],\n };\n}\n\nfunction mission(\n slug: string,\n index: number,\n title: string,\n concepts: string[],\n statement: string,\n sideAdventure: string,\n): MissionV1 {\n return {\n id: `${slug}-mission-${index}`,\n title,\n estimatedMinutes: index === 4 ? 25 : 20,\n concepts,\n goals: [\n {\n id: `${slug}-goal-${index}`,\n statement,\n evidence: \"assessment\",\n },\n ],\n sideAdventure,\n };\n}\n\ninterface ModuleInput {\n slug: string;\n title: string;\n category: ModuleCategoryV1;\n summary: string;\n tools: string[];\n concepts: string[];\n tokenSubunits: string;\n hosting?: boolean;\n hardware?: HardwareRequirementManifestV1;\n missionTitles: [string, string, string, string];\n}\n\nfunction module(input: ModuleInput): LearningModuleVersionV1 {\n const isRobot = input.category === \"robot\";\n return {\n id: `junior-coder.${input.slug}`,\n slug: input.slug,\n version: \"1.0.0\",\n contentRevision: \"2026-07-21.1\",\n title: input.title,\n category: input.category,\n summary: input.summary,\n estimatedMinutes: 90,\n tools: input.tools,\n concepts: input.concepts,\n selfContained: true,\n prerequisiteModuleIds: [],\n pricing: {\n state: \"pilot-grant-only\",\n tokenSubunits: input.tokenSubunits,\n includesMaterials: true,\n includesAssessmentRetries: true,\n includesAgents: true,\n includesHostingAllowance: input.hosting ?? false,\n },\n materials: materials(input.slug, isRobot),\n hardware: input.hardware ?? SOFTWARE_HARDWARE,\n missions: input.missionTitles.map((title, index) =>\n mission(\n input.slug,\n index + 1,\n title,\n input.concepts.slice(0, 3),\n `Complete ${title.toLocaleLowerCase(\"en-GB\")} and explain the observed result.`,\n `Invent one safe remix for ${title.toLocaleLowerCase(\"en-GB\")}.`,\n ),\n ),\n assessment: rubric(input.slug),\n agents: agents(input.slug),\n badges: [\n {\n id: `${input.slug}-mission-complete`,\n title: `${input.title} Champion`,\n evidence: \"module-score\",\n tradeable: false,\n tokenConvertible: false,\n },\n ...(isRobot\n ? [\n {\n id: `${input.slug}-physical-builder`,\n title: `${input.title} Physical Builder`,\n evidence: \"adult-physical-signoff\" as const,\n tradeable: false as const,\n tokenConvertible: false as const,\n },\n ]\n : []),\n ],\n };\n}\n\nconst modules: LearningModuleVersionV1[] = [\n module({\n slug: \"robot-maze-dash\",\n title: \"Robot Maze Dash\",\n category: \"game\",\n summary: \"Guide rescue robots through original mazes with visual programs and side-by-side text code.\",\n tools: [\"Visual blocks\", \"JavaScript view\", \"Python view\", \"C++ view\"],\n concepts: [\"sequence\", \"variables\", \"loops\", \"conditions\", \"functions\"],\n tokenSubunits: \"8000\",\n missionTitles: [\"Meet Your Robot\", \"Repeat the Rescue\", \"Choose the Safe Path\", \"Lost Robot Challenge\"],\n }),\n module({\n slug: \"road-hopper-rally\",\n title: \"Road Hopper Rally\",\n category: \"game\",\n summary: \"Build an original road-crossing game with changing lanes and rescue targets.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"events\", \"coordinates\", \"animation\", \"collision\", \"scoring\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Draw the Rescue Road\", \"Move the Hopper\", \"Add Moving Traffic\", \"Rally Challenge\"],\n }),\n module({\n slug: \"skywing-sprint\",\n title: \"Skywing Sprint\",\n category: \"game\",\n summary: \"Fly a rescue craft through procedurally changing sky gates.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"velocity\", \"gravity\", \"timing\", \"randomness\", \"obstacles\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Give Skywing Lift\", \"Build a Gate\", \"Score a Safe Flight\", \"Sky Sprint Challenge\"],\n }),\n module({\n slug: \"paddle-pulse\",\n title: \"Paddle Pulse\",\n category: \"game\",\n summary: \"Create a paddle-and-energy-ball arcade game with levels and original power-ups.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"angles\", \"collision response\", \"levels\", \"power-ups\", \"state\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Move the Pulse Paddle\", \"Bounce the Energy Ball\", \"Build a Target Wall\", \"Power-Up Challenge\"],\n }),\n module({\n slug: \"meteor-shield\",\n title: \"Meteor Shield\",\n category: \"game\",\n summary: \"Protect rescue bases with careful targeting and limited shield energy.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"targeting\", \"projectiles\", \"timers\", \"waves\", \"resources\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Mark the Rescue Bases\", \"Launch a Shield\", \"Create Meteor Waves\", \"Last Base Challenge\"],\n }),\n module({\n slug: \"rescue-crew-commander\",\n title: \"Rescue Crew Commander\",\n category: \"game\",\n summary: \"Assign safe jobs, routes and priorities to a team of original helper creatures.\",\n tools: [\"Visual blocks\", \"JavaScript\"],\n concepts: [\"state machines\", \"routes\", \"priorities\", \"group behaviour\", \"debugging\"],\n tokenSubunits: \"14000\",\n missionTitles: [\"Meet the Rescue Crew\", \"Give a Crew Job\", \"Choose a Safe Route\", \"Commander Challenge\"],\n }),\n module({\n slug: \"pixel-trail-challenge\",\n title: \"Pixel Trail Challenge\",\n category: \"game\",\n summary: \"Use Python lists and grid movement to grow a safe energy trail.\",\n tools: [\"Python\", \"Pyodide\", \"Educational drawing API\"],\n concepts: [\"lists\", \"grid movement\", \"spawning\", \"collision\", \"score\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Move the Pixel\", \"Grow the Trail\", \"Place Energy Orbs\", \"Trail Challenge\"],\n }),\n module({\n slug: \"star-defender-squadron\",\n title: \"Star Defender Squadron\",\n category: \"game\",\n summary: \"Build a multi-level space-rescue finale with original entities and enemy patterns.\",\n tools: [\"Python\", \"JavaScript\", \"Educational drawing API\"],\n concepts: [\"entities\", \"projectiles\", \"patterns\", \"health\", \"levels\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Launch the Squadron\", \"Build a Rescue Wave\", \"Add Shields and Health\", \"Star Defender Finale\"],\n }),\n module({\n slug: \"beacon-bot\",\n title: \"Beacon Bot\",\n category: \"robot\",\n summary: \"Program visible and infrared rescue signals with C++ and a Pico 2 W.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"digital output\", \"timing\", \"functions\", \"signals\", \"sensor input\"],\n tokenSubunits: \"8000\",\n hardware: physicalHardware(\"1.0.0\", 30, [\n { id: \"led-pack\", label: \"Visible LEDs\", quantity: 3, requirement: \"required\", exactSpecification: \"5 mm low-current red, amber and green LEDs\", adultOnly: false, stage: \"core\" },\n { id: \"led-resistors\", label: \"LED current-limiting resistors\", quantity: 3, requirement: \"required\", exactSpecification: \"330 ohm, 0.25 W resistors\", adultOnly: false, stage: \"core\" },\n { id: \"ir-pair\", label: \"Infrared emitter and receiver\", quantity: 1, requirement: \"required\", exactSpecification: \"Matched 940 nm IR LED and 3.3 V-compatible digital receiver pair; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Blink a Rescue Signal\", \"Build a Signal Function\", \"Send an IR Message\", \"Beacon Challenge\"],\n }),\n module({\n slug: \"servo-creature\",\n title: \"Servo Creature\",\n category: \"robot\",\n summary: \"Give a servo creature safe movements, moods and sensor reactions.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"PWM\", \"angles\", \"sequences\", \"limits\", \"interaction\"],\n tokenSubunits: \"10000\",\n hardware: physicalHardware(\"1.0.0\", 40, [\n { id: \"micro-servo\", label: \"Micro servo\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V signal-compatible micro servo; exact reference model and external power arrangement pending bench verification\", adultOnly: true, stage: \"servo\" },\n { id: \"servo-power\", label: \"Servo power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Switched regulated supply sized for the verified servo, with common signal ground\", adultOnly: true, stage: \"servo\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Wake the Creature\", \"Make a Movement Sequence\", \"Choose a Mood\", \"Creature Show Challenge\"],\n }),\n module({\n slug: \"dance-rover\",\n title: \"Dance Rover\",\n category: \"robot\",\n summary: \"Build reusable movement functions and a fail-safe rover dance.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"motor direction\", \"PWM speed\", \"functions\", \"sequences\", \"emergency stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 90, [\n { id: \"dual-motor-driver\", label: \"Dual motor driver\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V logic-compatible dual H-bridge; exact reference model pending bench verification\", adultOnly: true, stage: \"rover\" },\n { id: \"geared-motors\", label: \"Matching geared motors\", quantity: 2, requirement: \"required\", exactSpecification: \"Matching low-voltage geared DC motors compatible with the verified driver and supply\", adultOnly: true, stage: \"rover\" },\n { id: \"rover-chassis\", label: \"Rover chassis set\", quantity: 1, requirement: \"required\", exactSpecification: \"Two-wheel chassis with matching wheels and caster or skid\", adultOnly: true, stage: \"rover\" },\n { id: \"motor-power\", label: \"Switched motor power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Fused or protected switched supply within verified driver and motor ratings\", adultOnly: true, stage: \"rover\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Lifted-Wheel Safety Test\", \"Drive and Turn\", \"Build Movement Functions\", \"Rover Dance Challenge\"],\n }),\n module({\n slug: \"obstacle-explorer\",\n title: \"Obstacle Explorer\",\n category: \"robot\",\n summary: \"Use IR sensing, state and watchdogs to navigate and stop safely.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"booleans\", \"state\", \"navigation\", \"watchdogs\", \"fail-safe stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 60, [\n { id: \"verified-rover\", label: \"Verified Dance Rover build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Dance Rover reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"obstacle-sensors\", label: \"Digital IR obstacle sensors\", quantity: 2, requirement: \"required\", exactSpecification: \"3.3 V-compatible digital IR obstacle sensors; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Read an Obstacle\", \"Choose a Safe Response\", \"Add a Watchdog\", \"Explorer Maze Challenge\"],\n }),\n module({\n slug: \"rainbow-rescue-rover\",\n title: \"Rainbow Rescue Rover\",\n category: \"robot\",\n summary: \"Recognise local colour targets and send bounded serial commands to a safe rover.\",\n tools: [\"Python\", \"C++\", \"Pico 2 W\", \"Pi Zero 2 W\", \"Camera Module 3\", \"Simulator\"],\n concepts: [\"colour recognition\", \"coordinates\", \"serial protocol\", \"heartbeats\", \"integration\"],\n tokenSubunits: \"18000\",\n hardware: physicalHardware(\"1.0.0\", 120, [\n { id: \"verified-explorer\", label: \"Verified Obstacle Explorer build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Obstacle Explorer reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"pi-zero-2-w\", label: \"Raspberry Pi Zero 2 W\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Zero 2 W with supported Raspberry Pi OS image\", adultOnly: true, stage: \"camera\" },\n { id: \"camera-3\", label: \"Raspberry Pi Camera Module 3\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Camera Module 3 with the correct Zero-series camera ribbon\", adultOnly: true, stage: \"camera\" },\n { id: \"pi-storage-power\", label: \"Pi storage and power\", quantity: 1, requirement: \"required\", exactSpecification: \"Supported microSD card and regulated Raspberry Pi power supply\", adultOnly: true, stage: \"camera\" },\n ], [\"Current Raspberry Pi OS\", \"Pico SDK\"]),\n missionTitles: [\"Find a Colour Target\", \"Report Left Centre or Right\", \"Send Safe Serial Commands\", \"Rainbow Rescue Challenge\"],\n }),\n module({\n slug: \"vibe-game-remix-lab\",\n title: \"Vibe Game Remix Lab\",\n category: \"vibe\",\n summary: \"Transform a supplied mini-game through structured, evidence-bound AI suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"JavaScript sandbox\"],\n concepts: [\"intent\", \"constraints\", \"diffs\", \"testing\", \"explanation\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Describe the Remix\", \"Constrain the Change\", \"Review One Diff\", \"Remix Challenge\"],\n }),\n module({\n slug: \"vibe-bug-detective\",\n title: \"Vibe Bug Detective\",\n category: \"vibe\",\n summary: \"Repair an intentionally broken project using assessment evidence and focused suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"Assessment runner\"],\n concepts: [\"diagnostics\", \"hypotheses\", \"minimal fixes\", \"regression tests\", \"reflection\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Read the Evidence\", \"Ask a Focused Question\", \"Inspect a Suggested Fix\", \"Regression Challenge\"],\n }),\n module({\n slug: \"vibe-idea-studio\",\n title: \"Vibe Idea Studio\",\n category: \"vibe\",\n summary: \"Turn a bounded original idea into goals, acceptance tests and a working prototype.\",\n tools: [\"Intent cards\", \"Structured prompt builder\", \"Diff review\", \"Sandbox\"],\n concepts: [\"goals\", \"acceptance tests\", \"iteration\", \"trade-offs\", \"explanation\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Shape the Idea\", \"Write Success Tests\", \"Build One Step\", \"Prototype Showcase\"],\n }),\n module({\n slug: \"adventure-mission-planner\",\n title: \"Adventure Mission Planner\",\n category: \"web-app\",\n summary: \"Build an accessible planner for fictional quests and activities.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"semantic HTML\", \"forms\", \"validation\", \"arrays\", \"local persistence\"],\n tokenSubunits: \"10000\",\n hosting: true,\n missionTitles: [\"Make a Semantic Page\", \"Add a Mission Form\", \"Save Fictional Missions\", \"Accessible Planner Challenge\"],\n }),\n module({\n slug: \"creature-care-dashboard\",\n title: \"Creature Care Dashboard\",\n category: \"web-app\",\n summary: \"Create a responsive dashboard for a fictional digital creature.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"components\", \"events\", \"timers\", \"status displays\", \"reduced motion\"],\n tokenSubunits: \"12000\",\n hosting: true,\n missionTitles: [\"Design the Creature Card\", \"Update Creature State\", \"Add a Safe Timer\", \"Care Dashboard Challenge\"],\n }),\n module({\n slug: \"robot-mission-control\",\n title: \"Robot Mission Control\",\n category: \"web-app\",\n summary: \"Build a simulated control and telemetry interface with safety confirmations.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Serial simulator\", \"Private preview\"],\n concepts: [\"commands\", \"state machines\", \"confirmations\", \"charts\", \"responsive controls\"],\n tokenSubunits: \"14000\",\n hosting: true,\n missionTitles: [\"Build the Control Panel\", \"Simulate Telemetry\", \"Add Stop Confirmations\", \"Mission Control Challenge\"],\n }),\n];\n\n/** Initial immutable Junior Coder path manifest for pilot grants and shadow pricing. */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: LearningPathVersionV1 = {\n id: \"junior-coder.robot-rescue-arcade\",\n slug: \"robot-rescue-arcade\",\n version: \"1.0.0\",\n title: \"Junior Coder: Robot Rescue Arcade\",\n description: \"Nineteen self-contained game, robotics, Vibe Coding and web-app projects for young programmers.\",\n catalogState: \"pilot\",\n publicLaunchAtomic: true,\n featureFlag: \"learning.junior-coder.catalog.enabled\",\n modules,\n};\n","import type {\n AssessmentDimensionV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n LearningValidationIssueV1,\n} from \"./contracts.js\";\n\nconst DIMENSION_TOTALS: Record<AssessmentDimensionV1, number> = {\n structure: 20,\n behaviour: 50,\n resilience: 20,\n safety: 10,\n};\n\nconst CANONICAL_TOKEN_SUBUNITS = /^(0|[1-9][0-9]*)$/u;\n\nfunction issue(\n code: LearningValidationIssueV1[\"code\"],\n message: string,\n path: string,\n moduleId?: string,\n): LearningValidationIssueV1 {\n return { code, message, path, ...(moduleId ? { moduleId } : {}) };\n}\n\nfunction validateModule(\n module: LearningModuleVersionV1,\n moduleIndex: number,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const base = `modules[${moduleIndex}]`;\n\n if (!module.selfContained) {\n issues.push(\n issue(\n \"module-not-self-contained\",\n \"Every sellable module must be self-contained.\",\n `${base}.selfContained`,\n module.id,\n ),\n );\n }\n\n if (module.prerequisiteModuleIds.length > 0) {\n issues.push(\n issue(\n \"paid-prerequisite\",\n \"A sellable module cannot require another paid module.\",\n `${base}.prerequisiteModuleIds`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.learner.length === 0 ||\n module.materials.facilitator.length === 0\n ) {\n issues.push(\n issue(\n \"missing-materials\",\n \"Learner and facilitator material manifests are both required.\",\n `${base}.materials`,\n module.id,\n ),\n );\n }\n\n if (module.materials.learner.some((material) => material.audience !== \"learner\")) {\n issues.push(\n issue(\n \"facilitator-material-leak\",\n \"Learner material contains a facilitator-only record.\",\n `${base}.materials.learner`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.facilitator.some(\n (material) => material.audience !== \"facilitator\",\n )\n ) {\n issues.push(\n issue(\n \"learner-material-leak\",\n \"Facilitator material contains a learner record.\",\n `${base}.materials.facilitator`,\n module.id,\n ),\n );\n }\n\n if (!CANONICAL_TOKEN_SUBUNITS.test(module.pricing.tokenSubunits)) {\n issues.push(\n issue(\n \"invalid-token-subunits\",\n \"Token subunits must be a canonical non-negative base-10 integer string.\",\n `${base}.pricing.tokenSubunits`,\n module.id,\n ),\n );\n }\n\n const criterionIds = new Set<string>();\n const dimensionTotals: Record<AssessmentDimensionV1, number> = {\n structure: 0,\n behaviour: 0,\n resilience: 0,\n safety: 0,\n };\n let rubricTotal = 0;\n\n for (const criterion of module.assessment.criteria) {\n rubricTotal += criterion.points;\n dimensionTotals[criterion.dimension] += criterion.points;\n if (criterionIds.has(criterion.id)) {\n issues.push(\n issue(\n \"duplicate-criterion-id\",\n `Duplicate assessment criterion ${criterion.id}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n criterionIds.add(criterion.id);\n }\n\n if (rubricTotal !== 100) {\n issues.push(\n issue(\n \"rubric-total\",\n `Assessment rubric totals ${rubricTotal}; expected 100.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n for (const [dimension, expected] of Object.entries(DIMENSION_TOTALS) as Array<\n [AssessmentDimensionV1, number]\n >) {\n if (dimensionTotals[dimension] !== expected) {\n issues.push(\n issue(\n \"rubric-dimension-total\",\n `${dimension} criteria total ${dimensionTotals[dimension]}; expected ${expected}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n }\n\n if (\n !module.assessment.criteria.some(\n (criterion) => criterion.dimension === \"safety\" && criterion.mandatory,\n )\n ) {\n issues.push(\n issue(\n \"missing-mandatory-safety\",\n \"Every module requires a mandatory safety criterion.\",\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n if (module.hardware.mode === \"physical-first\" && module.hardware.items.length === 0) {\n issues.push(\n issue(\n \"missing-hardware-items\",\n \"Physical-first modules require an exact hardware item list.\",\n `${base}.hardware.items`,\n module.id,\n ),\n );\n }\n\n if (\n module.agents.some(\n (agent) =>\n agent.mayAssignScore !== false ||\n agent.mayAwardReward !== false ||\n agent.mayPublish !== false ||\n agent.mayControlHardware !== false,\n )\n ) {\n issues.push(\n issue(\n \"invalid-agent-authority\",\n \"Module agents cannot own scores, rewards, publishing or hardware control.\",\n `${base}.agents`,\n module.id,\n ),\n );\n }\n\n if (module.missions.length === 0) {\n issues.push(\n issue(\n \"missing-missions\",\n \"A module requires at least one mission.\",\n `${base}.missions`,\n module.id,\n ),\n );\n }\n\n return issues;\n}\n\n/** Return every catalog issue without throwing, suitable for authoring tools. */\nexport function validateLearningPath(\n path: LearningPathVersionV1,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const moduleIds = new Set<string>();\n const moduleSlugs = new Set<string>();\n\n for (const [index, module] of path.modules.entries()) {\n if (moduleIds.has(module.id)) {\n issues.push(\n issue(\n \"duplicate-module-id\",\n `Duplicate module id ${module.id}.`,\n `modules[${index}].id`,\n module.id,\n ),\n );\n }\n moduleIds.add(module.id);\n\n if (moduleSlugs.has(module.slug)) {\n issues.push(\n issue(\n \"duplicate-module-slug\",\n `Duplicate module slug ${module.slug}.`,\n `modules[${index}].slug`,\n module.id,\n ),\n );\n }\n moduleSlugs.add(module.slug);\n issues.push(...validateModule(module, index));\n }\n\n return issues;\n}\n\n/** Fail fast when a path is not safe to publish or consume. */\nexport function assertValidLearningPath(path: LearningPathVersionV1): void {\n const issues = validateLearningPath(path);\n if (issues.length === 0) return;\n\n const summary = issues\n .map((entry) => `${entry.code} at ${entry.path}: ${entry.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid learning path:\\n${summary}`);\n}\n"],"mappings":"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","names":["rubric","module"]}
1
+ {"version":3,"sources":["../src/assessment.ts","../src/catalog.ts","../src/validation.ts"],"sourcesContent":["import type {\n AssessmentCheckResultV1,\n AssessmentResultV1,\n AssessmentRubricV1,\n ScoreBandV1,\n} from \"./contracts.js\";\n\nfunction scoreBand(score: number): ScoreBandV1 {\n if (score >= 95) return \"mastered\";\n if (score >= 80) return \"mission-complete\";\n if (score >= 60) return \"nearly-there\";\n return \"keep-exploring\";\n}\n\n/**\n * Calculate a score solely from rubric criteria and objective check results.\n * Missing criteria fail closed; unknown and duplicate result IDs are rejected.\n */\nexport function calculateAssessment(\n rubric: AssessmentRubricV1,\n results: AssessmentCheckResultV1[],\n): AssessmentResultV1 {\n const knownIds = new Set(rubric.criteria.map((criterion) => criterion.id));\n const resultById = new Map<string, AssessmentCheckResultV1>();\n\n for (const result of results) {\n if (!knownIds.has(result.criterionId)) {\n throw new Error(`Unknown assessment criterion: ${result.criterionId}`);\n }\n if (resultById.has(result.criterionId)) {\n throw new Error(`Duplicate assessment result: ${result.criterionId}`);\n }\n resultById.set(result.criterionId, result);\n }\n\n let score = 0;\n const passedCriterionIds: string[] = [];\n const failedCriterionIds: string[] = [];\n const failedMandatoryCriterionIds: string[] = [];\n\n for (const criterion of rubric.criteria) {\n const passed = resultById.get(criterion.id)?.passed === true;\n if (passed) {\n score += criterion.points;\n passedCriterionIds.push(criterion.id);\n continue;\n }\n\n failedCriterionIds.push(criterion.id);\n if (criterion.mandatory) failedMandatoryCriterionIds.push(criterion.id);\n }\n\n return {\n score,\n band: scoreBand(score),\n completed:\n score >= rubric.completionScore && failedMandatoryCriterionIds.length === 0,\n passedCriterionIds,\n failedCriterionIds,\n failedMandatoryCriterionIds,\n };\n}\n","import type {\n AssessmentRubricV1,\n CourseMaterialsManifestV1,\n HardwareItemV1,\n HardwareRequirementManifestV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n MissionV1,\n ModuleAgentDefinitionV1,\n ModuleCategoryV1,\n} from \"./contracts.js\";\n\nconst SOFTWARE_HARDWARE: HardwareRequirementManifestV1 = {\n requirementsVersion: \"1.0.0\",\n mode: \"none\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"not-applicable\",\n publicSaleBlocked: false,\n preparationMinutes: 0,\n items: [],\n warnings: [\"No specialist physical equipment is required.\"],\n supportedPlatforms: [\"Current Chromium, Firefox or Safari browser\"],\n};\n\nconst CORE_ROBOT_ITEMS: HardwareItemV1[] = [\n {\n id: \"pico-2-w\",\n label: \"Raspberry Pi Pico 2 W\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Raspberry Pi Pico 2 W with soldered headers\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"breadboard\",\n label: \"Solderless breadboard\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"400-point or larger solderless breadboard\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"usb-data-cable\",\n label: \"USB data cable\",\n quantity: 1,\n requirement: \"required\",\n exactSpecification: \"Data-capable USB cable compatible with the Pico 2 W\",\n adultOnly: false,\n stage: \"core\",\n },\n {\n id: \"jumper-wires\",\n label: \"Jumper wires\",\n quantity: 12,\n requirement: \"required\",\n exactSpecification: \"Insulated male-to-male breadboard jumper wires\",\n adultOnly: false,\n stage: \"core\",\n },\n];\n\nconst ROBOT_WARNING =\n \"Physical publication is blocked until every listed actuator, driver, sensor and power configuration passes an adult bench test.\";\n\nfunction physicalHardware(\n requirementsVersion: string,\n preparationMinutes: number,\n items: HardwareItemV1[],\n platforms: string[],\n): HardwareRequirementManifestV1 {\n return {\n requirementsVersion,\n mode: \"physical-first\",\n hardwareIncluded: false,\n simulatorAvailable: true,\n verificationStatus: \"pending-bench-test\",\n publicSaleBlocked: true,\n preparationMinutes,\n items: [...CORE_ROBOT_ITEMS, ...items],\n warnings: [ROBOT_WARNING, \"An adult must disconnect actuator power before changing wiring.\"],\n supportedPlatforms: platforms,\n };\n}\n\nfunction materials(slug: string, robot = false): CourseMaterialsManifestV1 {\n return {\n version: \"1.0.0\",\n learner: [\n { id: `${slug}-child-guide`, kind: \"child-guide\", audience: \"learner\" },\n { id: `${slug}-mission-cards`, kind: \"mission-cards\", audience: \"learner\" },\n { id: `${slug}-starter`, kind: \"starter-project\", audience: \"learner\" },\n { id: `${slug}-assets`, kind: \"asset-pack\", audience: \"learner\" },\n { id: `${slug}-printable`, kind: \"printable\", audience: \"learner\" },\n ],\n facilitator: [\n { id: `${slug}-facilitator`, kind: \"facilitator-guide\", audience: \"facilitator\" },\n { id: `${slug}-answers`, kind: \"answer-key\", audience: \"facilitator\" },\n { id: `${slug}-tests`, kind: \"protected-tests\", audience: \"facilitator\" },\n ...(robot\n ? [\n {\n id: `${slug}-hardware`,\n kind: \"hardware-guide\" as const,\n audience: \"facilitator\" as const,\n },\n ]\n : []),\n ],\n };\n}\n\nfunction agents(slug: string): ModuleAgentDefinitionV1[] {\n return [\n {\n id: `${slug}-assessor`,\n role: \"assessor\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-debugger`,\n role: \"debugger\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-fix-guide`,\n role: \"fix-guide\",\n evidenceBound: true,\n maySuggestSingleFix: true,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n {\n id: `${slug}-concept-explainer`,\n role: \"concept-explainer\",\n evidenceBound: true,\n maySuggestSingleFix: false,\n mayAssignScore: false,\n mayAwardReward: false,\n mayPublish: false,\n mayControlHardware: false,\n },\n ];\n}\n\nfunction rubric(slug: string): AssessmentRubricV1 {\n return {\n version: \"1.0.0\",\n completionScore: 80,\n criteria: [\n {\n id: `${slug}-build`,\n label: \"The project is structurally valid and starts successfully.\",\n dimension: \"structure\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-one`,\n label: \"The first published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-two`,\n label: \"The second published project behaviour works.\",\n dimension: \"behaviour\",\n points: 20,\n mandatory: true,\n visibility: \"visible\",\n },\n {\n id: `${slug}-goal-three`,\n label: \"The complete project challenge works.\",\n dimension: \"behaviour\",\n points: 10,\n mandatory: false,\n visibility: \"visible\",\n },\n {\n id: `${slug}-edge-one`,\n label: \"The project handles its first protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-edge-two`,\n label: \"The project handles its second protected edge case.\",\n dimension: \"resilience\",\n points: 10,\n mandatory: false,\n visibility: \"protected\",\n },\n {\n id: `${slug}-safety`,\n label: \"The project obeys its mandatory safety and privacy boundary.\",\n dimension: \"safety\",\n points: 10,\n mandatory: true,\n visibility: \"visible\",\n },\n ],\n };\n}\n\nfunction mission(\n slug: string,\n index: number,\n title: string,\n concepts: string[],\n statement: string,\n sideAdventure: string,\n): MissionV1 {\n return {\n id: `${slug}-mission-${index}`,\n title,\n estimatedMinutes: index === 4 ? 25 : 20,\n concepts,\n goals: [\n {\n id: `${slug}-goal-${index}`,\n statement,\n evidence: \"assessment\",\n },\n ],\n sideAdventure,\n };\n}\n\ninterface ModuleInput {\n slug: string;\n title: string;\n category: ModuleCategoryV1;\n summary: string;\n tools: string[];\n concepts: string[];\n tokenSubunits: string;\n hosting?: boolean;\n hardware?: HardwareRequirementManifestV1;\n missionTitles: [string, string, string, string];\n}\n\nfunction module(input: ModuleInput): LearningModuleVersionV1 {\n const isRobot = input.category === \"robot\";\n return {\n id: `junior-coder.${input.slug}`,\n slug: input.slug,\n version: \"1.0.0\",\n contentRevision: \"2026-07-21.1\",\n title: input.title,\n category: input.category,\n summary: input.summary,\n estimatedMinutes: 90,\n tools: input.tools,\n concepts: input.concepts,\n selfContained: true,\n prerequisiteModuleIds: [],\n pricing: {\n state: \"pilot-grant-only\",\n tokenSubunits: input.tokenSubunits,\n includesMaterials: true,\n includesAssessmentRetries: true,\n includesAgents: true,\n includesHostingAllowance: input.hosting ?? false,\n },\n materials: materials(input.slug, isRobot),\n hardware: input.hardware ?? SOFTWARE_HARDWARE,\n missions: input.missionTitles.map((title, index) =>\n mission(\n input.slug,\n index + 1,\n title,\n input.concepts.slice(0, 3),\n `Complete ${title.toLocaleLowerCase(\"en-GB\")} and explain the observed result.`,\n `Invent one safe remix for ${title.toLocaleLowerCase(\"en-GB\")}.`,\n ),\n ),\n assessment: rubric(input.slug),\n agents: agents(input.slug),\n badges: [\n {\n id: `${input.slug}-mission-complete`,\n title: `${input.title} Champion`,\n evidence: \"module-score\",\n tradeable: false,\n tokenConvertible: false,\n },\n ...(isRobot\n ? [\n {\n id: `${input.slug}-physical-builder`,\n title: `${input.title} Physical Builder`,\n evidence: \"adult-physical-signoff\" as const,\n tradeable: false as const,\n tokenConvertible: false as const,\n },\n ]\n : []),\n ],\n };\n}\n\nconst modules: LearningModuleVersionV1[] = [\n module({\n slug: \"robot-maze-dash\",\n title: \"Robot Maze Dash\",\n category: \"game\",\n summary: \"Guide rescue robots through original mazes with visual programs and side-by-side text code.\",\n tools: [\"Visual blocks\", \"JavaScript view\", \"Python view\", \"C++ view\"],\n concepts: [\"sequence\", \"variables\", \"loops\", \"conditions\", \"functions\"],\n tokenSubunits: \"8000\",\n missionTitles: [\"Meet Your Robot\", \"Repeat the Rescue\", \"Choose the Safe Path\", \"Lost Robot Challenge\"],\n }),\n module({\n slug: \"road-hopper-rally\",\n title: \"Road Hopper Rally\",\n category: \"game\",\n summary: \"Build an original road-crossing game with changing lanes and rescue targets.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"events\", \"coordinates\", \"animation\", \"collision\", \"scoring\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Draw the Rescue Road\", \"Move the Hopper\", \"Add Moving Traffic\", \"Rally Challenge\"],\n }),\n module({\n slug: \"skywing-sprint\",\n title: \"Skywing Sprint\",\n category: \"game\",\n summary: \"Fly a rescue craft through procedurally changing sky gates.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"velocity\", \"gravity\", \"timing\", \"randomness\", \"obstacles\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Give Skywing Lift\", \"Build a Gate\", \"Score a Safe Flight\", \"Sky Sprint Challenge\"],\n }),\n module({\n slug: \"paddle-pulse\",\n title: \"Paddle Pulse\",\n category: \"game\",\n summary: \"Create a paddle-and-energy-ball arcade game with levels and original power-ups.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"angles\", \"collision response\", \"levels\", \"power-ups\", \"state\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Move the Pulse Paddle\", \"Bounce the Energy Ball\", \"Build a Target Wall\", \"Power-Up Challenge\"],\n }),\n module({\n slug: \"meteor-shield\",\n title: \"Meteor Shield\",\n category: \"game\",\n summary: \"Protect rescue bases with careful targeting and limited shield energy.\",\n tools: [\"JavaScript\", \"Educational canvas API\"],\n concepts: [\"targeting\", \"projectiles\", \"timers\", \"waves\", \"resources\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Mark the Rescue Bases\", \"Launch a Shield\", \"Create Meteor Waves\", \"Last Base Challenge\"],\n }),\n module({\n slug: \"rescue-crew-commander\",\n title: \"Rescue Crew Commander\",\n category: \"game\",\n summary: \"Assign safe jobs, routes and priorities to a team of original helper creatures.\",\n tools: [\"Visual blocks\", \"JavaScript\"],\n concepts: [\"state machines\", \"routes\", \"priorities\", \"group behaviour\", \"debugging\"],\n tokenSubunits: \"14000\",\n missionTitles: [\"Meet the Rescue Crew\", \"Give a Crew Job\", \"Choose a Safe Route\", \"Commander Challenge\"],\n }),\n module({\n slug: \"pixel-trail-challenge\",\n title: \"Pixel Trail Challenge\",\n category: \"game\",\n summary: \"Use Python lists and grid movement to grow a safe energy trail.\",\n tools: [\"Python\", \"Pyodide\", \"Educational drawing API\"],\n concepts: [\"lists\", \"grid movement\", \"spawning\", \"collision\", \"score\"],\n tokenSubunits: \"10000\",\n missionTitles: [\"Move the Pixel\", \"Grow the Trail\", \"Place Energy Orbs\", \"Trail Challenge\"],\n }),\n module({\n slug: \"star-defender-squadron\",\n title: \"Star Defender Squadron\",\n category: \"game\",\n summary: \"Build a multi-level space-rescue finale with original entities and enemy patterns.\",\n tools: [\"Python\", \"JavaScript\", \"Educational drawing API\"],\n concepts: [\"entities\", \"projectiles\", \"patterns\", \"health\", \"levels\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Launch the Squadron\", \"Build a Rescue Wave\", \"Add Shields and Health\", \"Star Defender Finale\"],\n }),\n module({\n slug: \"beacon-bot\",\n title: \"Beacon Bot\",\n category: \"robot\",\n summary: \"Program visible and infrared rescue signals with C++ and a Pico 2 W.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"digital output\", \"timing\", \"functions\", \"signals\", \"sensor input\"],\n tokenSubunits: \"8000\",\n hardware: physicalHardware(\"1.0.0\", 30, [\n { id: \"led-pack\", label: \"Visible LEDs\", quantity: 3, requirement: \"required\", exactSpecification: \"5 mm low-current red, amber and green LEDs\", adultOnly: false, stage: \"core\" },\n { id: \"led-resistors\", label: \"LED current-limiting resistors\", quantity: 3, requirement: \"required\", exactSpecification: \"330 ohm, 0.25 W resistors\", adultOnly: false, stage: \"core\" },\n { id: \"ir-pair\", label: \"Infrared emitter and receiver\", quantity: 1, requirement: \"required\", exactSpecification: \"Matched 940 nm IR LED and 3.3 V-compatible digital receiver pair; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Blink a Rescue Signal\", \"Build a Signal Function\", \"Send an IR Message\", \"Beacon Challenge\"],\n }),\n module({\n slug: \"servo-creature\",\n title: \"Servo Creature\",\n category: \"robot\",\n summary: \"Give a servo creature safe movements, moods and sensor reactions.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"PWM\", \"angles\", \"sequences\", \"limits\", \"interaction\"],\n tokenSubunits: \"10000\",\n hardware: physicalHardware(\"1.0.0\", 40, [\n { id: \"micro-servo\", label: \"Micro servo\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V signal-compatible micro servo; exact reference model and external power arrangement pending bench verification\", adultOnly: true, stage: \"servo\" },\n { id: \"servo-power\", label: \"Servo power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Switched regulated supply sized for the verified servo, with common signal ground\", adultOnly: true, stage: \"servo\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Wake the Creature\", \"Make a Movement Sequence\", \"Choose a Mood\", \"Creature Show Challenge\"],\n }),\n module({\n slug: \"dance-rover\",\n title: \"Dance Rover\",\n category: \"robot\",\n summary: \"Build reusable movement functions and a fail-safe rover dance.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"motor direction\", \"PWM speed\", \"functions\", \"sequences\", \"emergency stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 90, [\n { id: \"dual-motor-driver\", label: \"Dual motor driver\", quantity: 1, requirement: \"required\", exactSpecification: \"3.3 V logic-compatible dual H-bridge; exact reference model pending bench verification\", adultOnly: true, stage: \"rover\" },\n { id: \"geared-motors\", label: \"Matching geared motors\", quantity: 2, requirement: \"required\", exactSpecification: \"Matching low-voltage geared DC motors compatible with the verified driver and supply\", adultOnly: true, stage: \"rover\" },\n { id: \"rover-chassis\", label: \"Rover chassis set\", quantity: 1, requirement: \"required\", exactSpecification: \"Two-wheel chassis with matching wheels and caster or skid\", adultOnly: true, stage: \"rover\" },\n { id: \"motor-power\", label: \"Switched motor power supply\", quantity: 1, requirement: \"required\", exactSpecification: \"Fused or protected switched supply within verified driver and motor ratings\", adultOnly: true, stage: \"rover\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Lifted-Wheel Safety Test\", \"Drive and Turn\", \"Build Movement Functions\", \"Rover Dance Challenge\"],\n }),\n module({\n slug: \"obstacle-explorer\",\n title: \"Obstacle Explorer\",\n category: \"robot\",\n summary: \"Use IR sensing, state and watchdogs to navigate and stop safely.\",\n tools: [\"C++\", \"Pico 2 W\", \"Simulator\"],\n concepts: [\"booleans\", \"state\", \"navigation\", \"watchdogs\", \"fail-safe stop\"],\n tokenSubunits: \"14000\",\n hardware: physicalHardware(\"1.0.0\", 60, [\n { id: \"verified-rover\", label: \"Verified Dance Rover build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Dance Rover reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"obstacle-sensors\", label: \"Digital IR obstacle sensors\", quantity: 2, requirement: \"required\", exactSpecification: \"3.3 V-compatible digital IR obstacle sensors; exact reference model pending bench verification\", adultOnly: true, stage: \"sensor\" },\n ], [\"Pico SDK on Raspberry Pi OS or supported desktop toolchain\"]),\n missionTitles: [\"Read an Obstacle\", \"Choose a Safe Response\", \"Add a Watchdog\", \"Explorer Maze Challenge\"],\n }),\n module({\n slug: \"rainbow-rescue-rover\",\n title: \"Rainbow Rescue Rover\",\n category: \"robot\",\n summary: \"Recognise local colour targets and send bounded serial commands to a safe rover.\",\n tools: [\"Python\", \"C++\", \"Pico 2 W\", \"Pi Zero 2 W\", \"Camera Module 3\", \"Simulator\"],\n concepts: [\"colour recognition\", \"coordinates\", \"serial protocol\", \"heartbeats\", \"integration\"],\n tokenSubunits: \"18000\",\n hardware: physicalHardware(\"1.0.0\", 120, [\n { id: \"verified-explorer\", label: \"Verified Obstacle Explorer build\", quantity: 1, requirement: \"required\", exactSpecification: \"Bench-signed rover matching the published Obstacle Explorer reference build\", adultOnly: true, stage: \"rover\" },\n { id: \"pi-zero-2-w\", label: \"Raspberry Pi Zero 2 W\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Zero 2 W with supported Raspberry Pi OS image\", adultOnly: true, stage: \"camera\" },\n { id: \"camera-3\", label: \"Raspberry Pi Camera Module 3\", quantity: 1, requirement: \"required\", exactSpecification: \"Raspberry Pi Camera Module 3 with the correct Zero-series camera ribbon\", adultOnly: true, stage: \"camera\" },\n { id: \"pi-storage-power\", label: \"Pi storage and power\", quantity: 1, requirement: \"required\", exactSpecification: \"Supported microSD card and regulated Raspberry Pi power supply\", adultOnly: true, stage: \"camera\" },\n ], [\"Current Raspberry Pi OS\", \"Pico SDK\"]),\n missionTitles: [\"Find a Colour Target\", \"Report Left Centre or Right\", \"Send Safe Serial Commands\", \"Rainbow Rescue Challenge\"],\n }),\n module({\n slug: \"vibe-game-remix-lab\",\n title: \"Vibe Game Remix Lab\",\n category: \"vibe\",\n summary: \"Transform a supplied mini-game through structured, evidence-bound AI suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"JavaScript sandbox\"],\n concepts: [\"intent\", \"constraints\", \"diffs\", \"testing\", \"explanation\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Describe the Remix\", \"Constrain the Change\", \"Review One Diff\", \"Remix Challenge\"],\n }),\n module({\n slug: \"vibe-bug-detective\",\n title: \"Vibe Bug Detective\",\n category: \"vibe\",\n summary: \"Repair an intentionally broken project using assessment evidence and focused suggestions.\",\n tools: [\"Structured prompt builder\", \"Diff review\", \"Assessment runner\"],\n concepts: [\"diagnostics\", \"hypotheses\", \"minimal fixes\", \"regression tests\", \"reflection\"],\n tokenSubunits: \"12000\",\n missionTitles: [\"Read the Evidence\", \"Ask a Focused Question\", \"Inspect a Suggested Fix\", \"Regression Challenge\"],\n }),\n module({\n slug: \"vibe-idea-studio\",\n title: \"Vibe Idea Studio\",\n category: \"vibe\",\n summary: \"Turn a bounded original idea into goals, acceptance tests and a working prototype.\",\n tools: [\"Intent cards\", \"Structured prompt builder\", \"Diff review\", \"Sandbox\"],\n concepts: [\"goals\", \"acceptance tests\", \"iteration\", \"trade-offs\", \"explanation\"],\n tokenSubunits: \"16000\",\n missionTitles: [\"Shape the Idea\", \"Write Success Tests\", \"Build One Step\", \"Prototype Showcase\"],\n }),\n module({\n slug: \"adventure-mission-planner\",\n title: \"Adventure Mission Planner\",\n category: \"web-app\",\n summary: \"Build an accessible planner for fictional quests and activities.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"semantic HTML\", \"forms\", \"validation\", \"arrays\", \"local persistence\"],\n tokenSubunits: \"10000\",\n hosting: true,\n missionTitles: [\"Make a Semantic Page\", \"Add a Mission Form\", \"Save Fictional Missions\", \"Accessible Planner Challenge\"],\n }),\n module({\n slug: \"creature-care-dashboard\",\n title: \"Creature Care Dashboard\",\n category: \"web-app\",\n summary: \"Create a responsive dashboard for a fictional digital creature.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Private preview\"],\n concepts: [\"components\", \"events\", \"timers\", \"status displays\", \"reduced motion\"],\n tokenSubunits: \"12000\",\n hosting: true,\n missionTitles: [\"Design the Creature Card\", \"Update Creature State\", \"Add a Safe Timer\", \"Care Dashboard Challenge\"],\n }),\n module({\n slug: \"robot-mission-control\",\n title: \"Robot Mission Control\",\n category: \"web-app\",\n summary: \"Build a simulated control and telemetry interface with safety confirmations.\",\n tools: [\"HTML\", \"CSS\", \"JavaScript\", \"Serial simulator\", \"Private preview\"],\n concepts: [\"commands\", \"state machines\", \"confirmations\", \"charts\", \"responsive controls\"],\n tokenSubunits: \"14000\",\n hosting: true,\n missionTitles: [\"Build the Control Panel\", \"Simulate Telemetry\", \"Add Stop Confirmations\", \"Mission Control Challenge\"],\n }),\n];\n\n/**\n * Uniform price for the immutable 1.1.0 pilot catalog.\n *\n * The GBP value is product-copy reference metadata under the published\n * 10p-per-Token economy reference rate. It does not create redemption rights.\n */\nexport const JUNIOR_CODER_MODULE_PRICE_V1_1 = Object.freeze({\n tokenSubunits: \"50000\",\n referencePrice: Object.freeze({\n currency: \"GBP\" as const,\n minorUnits: \"500\",\n basis: \"nominal-reference\" as const,\n cashRedemptionAllowed: false as const,\n }),\n});\n\n/** Initial immutable Junior Coder path manifest for pilot grants and shadow pricing. */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1: LearningPathVersionV1 = {\n id: \"junior-coder.robot-rescue-arcade\",\n slug: \"robot-rescue-arcade\",\n version: \"1.0.0\",\n title: \"Junior Coder: Robot Rescue Arcade\",\n description: \"Nineteen self-contained game, robotics, Vibe Coding and web-app projects for young programmers.\",\n catalogState: \"pilot\",\n publicLaunchAtomic: true,\n featureFlag: \"learning.junior-coder.catalog.enabled\",\n modules,\n};\n\n/**\n * Uniformly priced successor to the immutable 1.0.0 pilot catalog.\n *\n * All modules remain independently sellable and retain their existing content,\n * manifests and safeguards. The new module and path versions bind the new price\n * without altering previously published records.\n */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1: LearningPathVersionV1 = {\n ...JUNIOR_CODER_ROBOT_RESCUE_PATH_V1,\n version: \"1.1.0\",\n modules: JUNIOR_CODER_ROBOT_RESCUE_PATH_V1.modules.map((entry) => ({\n ...entry,\n version: \"1.1.0\",\n contentRevision: \"2026-07-28.1\",\n pricing: {\n ...entry.pricing,\n tokenSubunits: JUNIOR_CODER_MODULE_PRICE_V1_1.tokenSubunits,\n referencePrice: JUNIOR_CODER_MODULE_PRICE_V1_1.referencePrice,\n },\n })),\n};\n\n/** Current pilot catalog for server adapters that intentionally follow releases. */\nexport const JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT =\n JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1;\n","import type {\n AssessmentDimensionV1,\n LearningModuleVersionV1,\n LearningPathVersionV1,\n LearningValidationIssueV1,\n} from \"./contracts.js\";\n\nconst DIMENSION_TOTALS: Record<AssessmentDimensionV1, number> = {\n structure: 20,\n behaviour: 50,\n resilience: 20,\n safety: 10,\n};\n\nconst CANONICAL_TOKEN_SUBUNITS = /^(0|[1-9][0-9]*)$/u;\n\nfunction issue(\n code: LearningValidationIssueV1[\"code\"],\n message: string,\n path: string,\n moduleId?: string,\n): LearningValidationIssueV1 {\n return { code, message, path, ...(moduleId ? { moduleId } : {}) };\n}\n\nfunction validateModule(\n module: LearningModuleVersionV1,\n moduleIndex: number,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const base = `modules[${moduleIndex}]`;\n\n if (!module.selfContained) {\n issues.push(\n issue(\n \"module-not-self-contained\",\n \"Every sellable module must be self-contained.\",\n `${base}.selfContained`,\n module.id,\n ),\n );\n }\n\n if (module.prerequisiteModuleIds.length > 0) {\n issues.push(\n issue(\n \"paid-prerequisite\",\n \"A sellable module cannot require another paid module.\",\n `${base}.prerequisiteModuleIds`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.learner.length === 0 ||\n module.materials.facilitator.length === 0\n ) {\n issues.push(\n issue(\n \"missing-materials\",\n \"Learner and facilitator material manifests are both required.\",\n `${base}.materials`,\n module.id,\n ),\n );\n }\n\n if (module.materials.learner.some((material) => material.audience !== \"learner\")) {\n issues.push(\n issue(\n \"facilitator-material-leak\",\n \"Learner material contains a facilitator-only record.\",\n `${base}.materials.learner`,\n module.id,\n ),\n );\n }\n\n if (\n module.materials.facilitator.some(\n (material) => material.audience !== \"facilitator\",\n )\n ) {\n issues.push(\n issue(\n \"learner-material-leak\",\n \"Facilitator material contains a learner record.\",\n `${base}.materials.facilitator`,\n module.id,\n ),\n );\n }\n\n if (!CANONICAL_TOKEN_SUBUNITS.test(module.pricing.tokenSubunits)) {\n issues.push(\n issue(\n \"invalid-token-subunits\",\n \"Token subunits must be a canonical non-negative base-10 integer string.\",\n `${base}.pricing.tokenSubunits`,\n module.id,\n ),\n );\n }\n\n const referencePrice = module.pricing.referencePrice;\n if (\n referencePrice\n && (\n referencePrice.currency !== \"GBP\"\n || !CANONICAL_TOKEN_SUBUNITS.test(referencePrice.minorUnits)\n || referencePrice.basis !== \"nominal-reference\"\n || referencePrice.cashRedemptionAllowed !== false\n )\n ) {\n issues.push(\n issue(\n \"invalid-reference-price\",\n \"Reference prices must use canonical GBP minor units, the nominal reference basis and prohibit cash redemption.\",\n `${base}.pricing.referencePrice`,\n module.id,\n ),\n );\n }\n\n const criterionIds = new Set<string>();\n const dimensionTotals: Record<AssessmentDimensionV1, number> = {\n structure: 0,\n behaviour: 0,\n resilience: 0,\n safety: 0,\n };\n let rubricTotal = 0;\n\n for (const criterion of module.assessment.criteria) {\n rubricTotal += criterion.points;\n dimensionTotals[criterion.dimension] += criterion.points;\n if (criterionIds.has(criterion.id)) {\n issues.push(\n issue(\n \"duplicate-criterion-id\",\n `Duplicate assessment criterion ${criterion.id}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n criterionIds.add(criterion.id);\n }\n\n if (rubricTotal !== 100) {\n issues.push(\n issue(\n \"rubric-total\",\n `Assessment rubric totals ${rubricTotal}; expected 100.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n for (const [dimension, expected] of Object.entries(DIMENSION_TOTALS) as Array<\n [AssessmentDimensionV1, number]\n >) {\n if (dimensionTotals[dimension] !== expected) {\n issues.push(\n issue(\n \"rubric-dimension-total\",\n `${dimension} criteria total ${dimensionTotals[dimension]}; expected ${expected}.`,\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n }\n\n if (\n !module.assessment.criteria.some(\n (criterion) => criterion.dimension === \"safety\" && criterion.mandatory,\n )\n ) {\n issues.push(\n issue(\n \"missing-mandatory-safety\",\n \"Every module requires a mandatory safety criterion.\",\n `${base}.assessment.criteria`,\n module.id,\n ),\n );\n }\n\n if (module.hardware.mode === \"physical-first\" && module.hardware.items.length === 0) {\n issues.push(\n issue(\n \"missing-hardware-items\",\n \"Physical-first modules require an exact hardware item list.\",\n `${base}.hardware.items`,\n module.id,\n ),\n );\n }\n\n if (\n module.agents.some(\n (agent) =>\n agent.mayAssignScore !== false ||\n agent.mayAwardReward !== false ||\n agent.mayPublish !== false ||\n agent.mayControlHardware !== false,\n )\n ) {\n issues.push(\n issue(\n \"invalid-agent-authority\",\n \"Module agents cannot own scores, rewards, publishing or hardware control.\",\n `${base}.agents`,\n module.id,\n ),\n );\n }\n\n if (module.missions.length === 0) {\n issues.push(\n issue(\n \"missing-missions\",\n \"A module requires at least one mission.\",\n `${base}.missions`,\n module.id,\n ),\n );\n }\n\n return issues;\n}\n\n/** Return every catalog issue without throwing, suitable for authoring tools. */\nexport function validateLearningPath(\n path: LearningPathVersionV1,\n): LearningValidationIssueV1[] {\n const issues: LearningValidationIssueV1[] = [];\n const moduleIds = new Set<string>();\n const moduleSlugs = new Set<string>();\n\n for (const [index, module] of path.modules.entries()) {\n if (moduleIds.has(module.id)) {\n issues.push(\n issue(\n \"duplicate-module-id\",\n `Duplicate module id ${module.id}.`,\n `modules[${index}].id`,\n module.id,\n ),\n );\n }\n moduleIds.add(module.id);\n\n if (moduleSlugs.has(module.slug)) {\n issues.push(\n issue(\n \"duplicate-module-slug\",\n `Duplicate module slug ${module.slug}.`,\n `modules[${index}].slug`,\n module.id,\n ),\n );\n }\n moduleSlugs.add(module.slug);\n issues.push(...validateModule(module, index));\n }\n\n return issues;\n}\n\n/** Fail fast when a path is not safe to publish or consume. */\nexport function assertValidLearningPath(path: LearningPathVersionV1): void {\n const issues = validateLearningPath(path);\n if (issues.length === 0) return;\n\n const summary = issues\n .map((entry) => `${entry.code} at ${entry.path}: ${entry.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid learning path:\\n${summary}`);\n}\n"],"mappings":"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","names":["rubric","module"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasius/learning",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Versioned learning module, assessment, entitlement, and reward contracts for the Plasius ecosystem",
5
5
  "type": "module",
6
6
  "sideEffects": false,