{
  "schemaVersion": "1.0.0",
  "title": "Learn & build",
  "subtitle": "Start small. Make something. Understand why it works.",
  "lastChecked": "2026-10-20",
  "totalEffortEstimate": "About 60–95 hours for selected core lessons and builds, self-paced. Estimates exclude full optional courses, physical fabrication, and advanced on-device ML.",
  "audience": "New builders and Harness Labs community members, including Mukunth Rajendran.",
  "editorialNote": "A curated starting path, not an exhaustive archive. Resources stay on their original publishers’ sites; descriptions and learning tasks are original.",
  "stages": [
    {
      "id": "foundations",
      "order": 1,
      "title": "Start with code and a clear idea",
      "display_title": "Code the basics",
      "one_line_summary": "Turn a small idea into a working decision rule.",
      "first_action": "Run a tiny Python example in your browser.",
      "goal": "Learn enough Python and version control to make a small, explainable program.",
      "level": "beginner",
      "estimatedHours": {
        "min": 12,
        "max": 18,
        "label": "Estimated 12–18 hours"
      },
      "prerequisites": [],
      "outcomes": [
        "Use variables, functions, conditions, and loops.",
        "Keep sample data separate from decisions.",
        "Save a recoverable revision and explain a change."
      ],
      "milestoneId": "m1",
      "buildTitle": "A tiny decision engine",
      "productFlowStep": "Idea → requirements",
      "resourceIds": [
        "pyodide-console",
        "cs50p-week0",
        "github-intro",
        "progit",
        "python-tutorial"
      ],
      "primaryResourceId": "cs50p-week0",
      "milestone": "Write a text-only program that maps a sample input to idle, active, or unknown.",
      "selectedStudyScope": "CS50P Week 0 plus selected conditionals/loops lessons as needed; basic Git exercise. Full CS50P and reference books are optional.",
      "aiAssist": {
        "use": "Ask AI to explain one error and propose a smaller example.",
        "verify": "Run the example and explain the fix yourself."
      }
    },
    {
      "id": "circuits",
      "order": 2,
      "title": "Understand circuits and sensor inputs",
      "display_title": "Simulate a circuit",
      "one_line_summary": "Make an input change an indicator.",
      "first_action": "Build a virtual LED circuit, then add a button.",
      "goal": "Build a virtual circuit and explain the voltage, current, and signal path before touching hardware.",
      "level": "beginner",
      "estimatedHours": {
        "min": 6,
        "max": 10,
        "label": "Estimated 6–10 hours"
      },
      "prerequisites": [
        "foundations"
      ],
      "outcomes": [
        "Identify power, ground, signal, and current limiting.",
        "Read a simulated analog input.",
        "Distinguish a raw sensor value from a measured physical quantity."
      ],
      "milestoneId": "m2",
      "buildTitle": "A virtual sensor light",
      "productFlowStep": "Requirements → circuit sketch",
      "resourceIds": [
        "sparkfun-ohms",
        "sparkfun-breadboard",
        "tinkercad-circuits",
        "adafruit-calibration"
      ],
      "primaryResourceId": "tinkercad-circuits",
      "milestone": "Use a button or simulated analog input to change an LED indicator.",
      "selectedStudyScope": "Voltage/current basics and three small virtual circuits. No physical calibration required.",
      "aiAssist": {
        "use": "Ask AI to review your labeled circuit and list assumptions.",
        "verify": "Check every pin, voltage, and resistor calculation against the source documentation."
      }
    },
    {
      "id": "embedded",
      "order": 3,
      "title": "Give the device explicit behavior",
      "display_title": "Write the firmware",
      "one_line_summary": "Make your virtual gadget respond predictably.",
      "first_action": "Run an ESP32 MicroPython example in Wokwi.",
      "goal": "Move decision logic into an ESP32 simulation and define its behavior over time.",
      "level": "beginner",
      "estimatedHours": {
        "min": 8,
        "max": 12,
        "label": "Estimated 8–12 hours"
      },
      "prerequisites": [
        "circuits"
      ],
      "outcomes": [
        "Read inputs and drive an indicator with MicroPython.",
        "Use named states and a non-blocking loop.",
        "Handle reset and missing input deliberately."
      ],
      "milestoneId": "m3",
      "buildTitle": "A three-state gadget",
      "productFlowStep": "Circuit sketch → firmware",
      "resourceIds": [
        "wokwi-esp32",
        "arduino-examples",
        "wokwi-dht22",
        "micropython-esp32",
        "micropython-time"
      ],
      "primaryResourceId": "wokwi-esp32",
      "milestone": "Make an ESP32 simulation behave consistently through idle, active, and unknown states.",
      "selectedStudyScope": "Wokwi ESP32 MicroPython template, Pin/ADC, and ticks-based scheduling. Arduino/C++ and DHT22 are optional alternatives/extensions.",
      "aiAssist": {
        "use": "Ask AI to suggest missing state transitions and failure cases.",
        "verify": "Compile/run the code and replay those cases; generated behavior is not evidence."
      }
    },
    {
      "id": "cad",
      "order": 4,
      "title": "Design an enclosure around real constraints",
      "display_title": "Shape the enclosure",
      "one_line_summary": "Create a box that fits the parts and can be opened.",
      "first_action": "Sketch the board, connector, and lid before opening CAD.",
      "goal": "Model a simple enclosure using dimensions, clearances, and an editable design.",
      "level": "beginner",
      "estimatedHours": {
        "min": 6,
        "max": 10,
        "label": "Estimated 6–10 hours"
      },
      "prerequisites": [
        "embedded"
      ],
      "outcomes": [
        "Create a dimensioned sketch and a solid model.",
        "Leave access for connectors, wires, and a removable lid.",
        "Record assumed dimensions and what still needs a real fit check."
      ],
      "milestoneId": "m4",
      "buildTitle": "An editable enclosure",
      "productFlowStep": "Sketch → CAD → preliminary BOM",
      "resourceIds": [
        "tinkercad-3d",
        "onshape-cad-basics",
        "onshape-shell",
        "prusa-print-design"
      ],
      "primaryResourceId": "tinkercad-3d",
      "milestone": "Model a removable-lid enclosure around the board, indicator, button, and cable.",
      "selectedStudyScope": "Tinkercad basics and a simple enclosure. Onshape is an optional public, non-commercial parametric route.",
      "aiAssist": {
        "use": "Ask AI to turn your dimensions into a design checklist.",
        "verify": "Check dimensions in CAD and mark physical fit as unverified until tested."
      }
    },
    {
      "id": "ai",
      "order": 5,
      "title": "Add a small model and an honest fallback",
      "display_title": "Add useful AI",
      "one_line_summary": "Train a simple classifier and test where it fails.",
      "first_action": "Train a two-object classifier in your browser.",
      "goal": "Learn classification and evaluation with non-sensitive images before considering a microcontroller model.",
      "level": "intermediate",
      "estimatedHours": {
        "min": 8,
        "max": 14,
        "label": "Estimated 8–14 hours"
      },
      "prerequisites": [
        "foundations",
        "embedded"
      ],
      "outcomes": [
        "Separate training examples from held-out tests.",
        "Measure per-class mistakes and test unfamiliar inputs.",
        "Use an unknown state and record model limitations."
      ],
      "milestoneId": "m5",
      "buildTitle": "A classifier with an unknown state",
      "productFlowStep": "Inputs → model → decision contract",
      "resourceIds": [
        "ai_teachable_machine",
        "ai_mlcc",
        "ai_litert_micro",
        "ai_mobilenets_paper",
        "ai_model_cards_paper"
      ],
      "primaryResourceId": "ai_teachable_machine",
      "milestone": "Recognize two harmless personal objects in the browser, then show when the model is unsure.",
      "selectedStudyScope": "A Teachable Machine image experiment and selected ML Crash Course evaluation concepts. Papers and device deployment are optional.",
      "aiAssist": {
        "use": "Ask AI to challenge your dataset split and model-card claims.",
        "verify": "Preserve actual test counts and inspect errors; never invent performance results."
      }
    },
    {
      "id": "interactions",
      "order": 6,
      "title": "Make the parts talk clearly",
      "display_title": "Connect the behaviors",
      "one_line_summary": "Define what every event means before networking.",
      "first_action": "Write down the three events your indicator understands.",
      "goal": "Connect input, model, and output through a small event contract and replayable state transitions.",
      "level": "intermediate",
      "estimatedHours": {
        "min": 5,
        "max": 8,
        "label": "Estimated 5–8 hours"
      },
      "prerequisites": [
        "embedded",
        "ai"
      ],
      "outcomes": [
        "Define event names, fields, units, and versions.",
        "Replay lost, stale, duplicated, and invalid messages.",
        "Explain MQTT publish/subscribe without depending on a public broker."
      ],
      "milestoneId": "m6",
      "buildTitle": "A replayable interaction",
      "productFlowStep": "Modules → event contract → integration",
      "resourceIds": [
        "interaction_mqtt_video",
        "interaction_state_machines",
        "interaction_mqtt_browser",
        "interaction_asyncapi"
      ],
      "primaryResourceId": "interaction_state_machines",
      "milestone": "Connect classification results to the indicator through a small, versioned event format.",
      "selectedStudyScope": "State-machine sketch, MQTT introduction, and event replay. Live networking and formal schemas are optional.",
      "aiAssist": {
        "use": "Ask AI to identify ambiguities in your event contract.",
        "verify": "Replay malformed, stale, and duplicate messages to check the fixes."
      }
    },
    {
      "id": "verification",
      "order": 7,
      "title": "Test the claim, not just the happy path",
      "display_title": "Prove what works",
      "one_line_summary": "Keep evidence for successes, failures, and unknowns.",
      "first_action": "Choose one requirement and define its pass/fail test.",
      "goal": "Create a small verification matrix and separate simulated evidence from physical evidence.",
      "level": "intermediate",
      "estimatedHours": {
        "min": 6,
        "max": 10,
        "label": "Estimated 6–10 hours"
      },
      "prerequisites": [
        "cad",
        "interactions"
      ],
      "outcomes": [
        "Map every requirement to a reproducible test.",
        "Automate decision-rule checks.",
        "Record model errors, simulator limits, and physical checks still required."
      ],
      "milestoneId": "m7",
      "buildTitle": "A compact test report",
      "productFlowStep": "Prototype → test → revision",
      "resourceIds": [
        "verification-python",
        "verification-nasa",
        "verification-wokwi",
        "verification-arm"
      ],
      "primaryResourceId": "verification-python",
      "milestone": "Build a repeatable evidence pack for the requirements and the model’s limits.",
      "selectedStudyScope": "A small Python test suite and NASA Appendices C–E scaled to five requirements. Signal tracing and the white paper are optional.",
      "aiAssist": {
        "use": "Ask AI to propose tests that could disprove your claim.",
        "verify": "Run the tests and keep the observed outputs, including failures."
      }
    },
    {
      "id": "release",
      "order": 8,
      "title": "Package a build another person can repeat",
      "display_title": "Make it reproducible",
      "one_line_summary": "Finish a learning release with files, instructions, and limits.",
      "first_action": "Follow your own README from a clean folder.",
      "goal": "Assemble the Desk Signals capstone into a traceable release candidate for review.",
      "level": "intermediate",
      "estimatedHours": {
        "min": 8,
        "max": 12,
        "label": "Estimated 8–12 hours"
      },
      "prerequisites": [
        "verification"
      ],
      "outcomes": [
        "Package source, editable CAD, BOM, and assembly instructions.",
        "Version the model, firmware, event contract, and test evidence.",
        "Explain reuse permissions and scope before publishing."
      ],
      "milestoneId": "m8",
      "buildTitle": "Desk Signals release candidate",
      "productFlowStep": "Tested prototype → documented release candidate",
      "resourceIds": [
        "release-readme",
        "release-oshwa",
        "release-github",
        "release-license"
      ],
      "primaryResourceId": "release-readme",
      "milestone": "Package the previous builds so another learner can reproduce the same scoped demonstration.",
      "selectedStudyScope": "README, editable files, BOM, assembly plan, model notes, and evidence. Publication is a separate choice.",
      "aiAssist": {
        "use": "Ask AI to review your README for missing steps.",
        "verify": "Follow it from a clean folder and verify every part number and third-party license."
      }
    }
  ],
  "resources": [
    {
      "id": "pyodide-console",
      "stageId": "foundations",
      "title": "Pyodide browser Python console",
      "source": "Pyodide project",
      "url": "https://pyodide.org/en/stable/console.html",
      "type": "tool",
      "formatDetail": "interactive playground",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Immediate Python practice without installation or login. Pair it with the first lecture rather than spending the first session on setup.",
      "estimatedEffort": "Estimated 20–45 minutes for arithmetic, strings, variables, and one small function.",
      "prerequisites": [
        "A modern browser; no programming experience required for the first arithmetic and variable exercises."
      ],
      "access": {
        "cost": "Free public demo.",
        "account": "No account or login was requested in the live browser check.",
        "hardware": "Computer/browser only; no electronics.",
        "notes": "Treat this as a scratch console, not durable project storage. Browser Python has compatibility limits; it is not a full replacement for desktop Python or a hardware-programming IDE."
      },
      "lastChecked": "2026-10-20",
      "verification": "Opened in the cloud browser without login and evaluated 2 + 2, which returned 4.",
      "supportingUrls": [
        "https://pyodide.org/en/stable/",
        "https://pyodide.org/en/stable/console.html"
      ],
      "display_title": "Try Python in your browser",
      "one_line_summary": "Run your first lines of Python without installing anything.",
      "first_action": "Type 2 + 2, then try a variable and print its value.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account",
        "hardware": "Browser only"
      }
    },
    {
      "id": "cs50p-week0",
      "stageId": "foundations",
      "title": "CS50P: Week 0, Functions and Variables",
      "source": "Harvard CS50",
      "url": "https://cs50.harvard.edu/python/weeks/0/",
      "type": "video",
      "formatDetail": "video",
      "level": "beginner",
      "role": "core",
      "whyUseful": "A structured first lesson with video, notes, transcript, and examples. Continue to conditionals, loops, exceptions, tests, and file I/O as needed for sensor-data work.",
      "estimatedEffort": "Estimated 3–5 hours for Week 0 and practice; 40–80 hours for the full course and projects is a separate optional commitment.",
      "prerequisites": [
        "None; the course explicitly welcomes learners without prior programming experience."
      ],
      "access": {
        "cost": "OpenCourseWare learning materials are free; a paid verified certificate is optional.",
        "account": "No login needed to watch/read. Official submission and cs50.dev workflow uses a GitHub account and authorization; course feedback instructions also call for an edX account. First-session practice can stay in Pyodide.",
        "hardware": "Computer/browser only.",
        "notes": "The entire ten-week course is not a prerequisite for the first circuit. Follow course academic-honesty rules for submitted assignments."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official lecture page and its linked YouTube destination opened; account requirements checked in official problem-set instructions.",
      "supportingUrls": [
        "https://cs50.harvard.edu/python/",
        "https://cs50.harvard.edu/python/weeks/0/",
        "https://cs50.harvard.edu/python/psets/0/",
        "https://cs50.readthedocs.io/cs50.dev/",
        "https://cs50.harvard.edu/python/weeks/1/",
        "https://cs50.harvard.edu/python/weeks/2/"
      ],
      "display_title": "Your first Python lesson",
      "one_line_summary": "Learn functions and variables with Harvard’s video and notes.",
      "first_action": "Watch the opening lesson and run each small example yourself.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      },
      "selectedScope": "Start with Week 0, then selected Week 1 conditionals and Week 2 loops sections for the decision-engine milestone."
    },
    {
      "id": "github-intro",
      "stageId": "foundations",
      "title": "GitHub Skills: Introduction to GitHub",
      "source": "GitHub Skills",
      "url": "https://github.com/skills/introduction-to-github",
      "type": "course",
      "formatDetail": "interactive course",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Practice repositories, branches, commits, and pull requests through a tiny README exercise; useful for keeping experiments reproducible.",
      "estimatedEffort": "Estimated 45–90 minutes including writing a useful project README. Provider states its basic exercise takes less than one hour.",
      "prerequisites": [
        "None beyond basic browser use."
      ],
      "access": {
        "cost": "Free exercise; the provider recommends a public practice repository because private repositories consume Actions minutes.",
        "account": "GitHub account required to copy and run the exercise; reading instructions is public.",
        "hardware": "Computer/browser only.",
        "notes": "Use harmless practice content in a public repository. Never commit Wi-Fi passwords, API keys, personal recordings, or private lab data."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official GitHub Skills repository opened and prerequisite, duration, and public/private warning checked.",
      "supportingUrls": [
        "https://github.com/skills/introduction-to-github"
      ],
      "display_title": "Save a version with GitHub",
      "one_line_summary": "Practice commits and branches on harmless sample files.",
      "first_action": "Read the exercise, then decide whether to use a free practice account.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "Account for exercise",
        "hardware": "Browser only"
      }
    },
    {
      "id": "progit",
      "stageId": "foundations",
      "title": "Pro Git: Getting Started and Git Basics",
      "source": "Git project / Scott Chacon and Ben Straub",
      "url": "https://git-scm.com/book/en/v2",
      "type": "guide",
      "formatDetail": "book",
      "level": "beginner",
      "role": "optional",
      "whyUseful": "A durable explanation of Git itself, complementing the GitHub website workflow. Use chapters 1–2 and basic branching before reading advanced chapters.",
      "estimatedEffort": "Estimated 3–5 hours for selected early chapters with practice.",
      "prerequisites": [
        "Basic files/folders; terminal basics helpful for doing the command-line exercises."
      ],
      "access": {
        "cost": "Entire online book is free; optional print copies cost money.",
        "account": "None to read or use Git locally.",
        "hardware": "Browser for reading; Git-capable local or existing cloud terminal for hands-on command-line practice later.",
        "notes": "Do not make Git installation or a cloud account a day-one blocker."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official Git website opened and book contents checked.",
      "supportingUrls": [
        "https://git-scm.com/book/en/v2"
      ],
      "display_title": "Understand Git",
      "one_line_summary": "Learn what a commit, branch, and repository actually mean.",
      "first_action": "Read Getting Started and the first Git Basics sections.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "Terminal for practice"
      }
    },
    {
      "id": "python-tutorial",
      "stageId": "foundations",
      "title": "The Python Tutorial",
      "source": "Python Software Foundation",
      "url": "https://docs.python.org/3/tutorial/",
      "type": "documentation",
      "formatDetail": "reference tutorial",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Authoritative reference for lists, functions, modules, files, and exceptions when a lab needs a specific concept.",
      "estimatedEffort": "Estimated 2–4 hours of selected sections; use as-needed rather than cover-to-cover.",
      "prerequisites": [
        "Basic programming concepts, gained from the introductory lessons."
      ],
      "access": {
        "cost": "Free official documentation.",
        "account": "None.",
        "hardware": "Browser only for reading; Pyodide can run many elementary examples.",
        "notes": "The tutorial explicitly assumes general programming knowledge. It should not be the only first resource for a complete beginner."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official Python documentation opened and audience warning checked.",
      "supportingUrls": [
        "https://docs.python.org/3/tutorial/"
      ],
      "display_title": "Look up a Python concept",
      "one_line_summary": "Use the official reference after the first lessons.",
      "first_action": "Find the section for a concept your program needs.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "sparkfun-ohms",
      "stageId": "circuits",
      "title": "SparkFun: Voltage, Current, Resistance, and Ohm's Law",
      "source": "SparkFun",
      "url": "https://learn.sparkfun.com/tutorials/voltage-current-resistance-and-ohms-law",
      "type": "guide",
      "formatDetail": "tutorial with video",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Connects voltage, current, resistance, and LED current limiting before wiring a circuit.",
      "estimatedEffort": "Estimated 60–90 minutes including a few resistor/current calculations.",
      "prerequisites": [
        "Basic arithmetic and rearranging a simple equation."
      ],
      "access": {
        "cost": "Free public learning article.",
        "account": "None for reading.",
        "hardware": "No hardware for reading/calculations; reproduce the example in simulation instead of buying its listed parts.",
        "notes": "The article's physical experiment uses a battery and meter. Keep this curriculum simulator-first, then manufacturer-supported USB low-voltage hardware only."
      },
      "lastChecked": "2026-10-20",
      "verification": "Title and full article text verified in the web index of SparkFun's official page; direct fetch returned HTTP 403. Official SparkFun video was independently found. Not a live UI access test.",
      "supportingUrls": [
        "https://learn.sparkfun.com/tutorials/voltage-current-resistance-and-ohms-law",
        "https://www.youtube.com/watch?v=8jB6hDUqN0Y"
      ],
      "display_title": "Voltage, current, resistance",
      "one_line_summary": "Understand the relationships before wiring a circuit.",
      "first_action": "Read the LED example and calculate a suitable current-limiting resistance.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "sparkfun-breadboard",
      "stageId": "circuits",
      "title": "SparkFun: How to Use a Breadboard",
      "source": "SparkFun",
      "url": "https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all",
      "type": "guide",
      "formatDetail": "illustrated tutorial",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Explains connected rows, the central gap, and power rails, preventing common wiring mistakes even in a simulator.",
      "estimatedEffort": "Estimated 45–75 minutes including tracing a simple virtual circuit.",
      "prerequisites": [
        "Understand a closed circuit and power/ground."
      ],
      "access": {
        "cost": "Free public learning article.",
        "account": "None for reading.",
        "hardware": "No purchase required; use a virtual breadboard.",
        "notes": "Check rail connectivity on the actual breadboard later; do not assume rail labels or both sides imply electrical connections."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official article and anatomy section verified through indexed text; direct web fetch returned HTTP 403. Not a live UI access test.",
      "supportingUrls": [
        "https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all",
        "https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/anatomy-of-a-breadboard"
      ],
      "display_title": "Read a breadboard",
      "one_line_summary": "See which holes connect and trace the current path.",
      "first_action": "Trace one complete circuit through the virtual breadboard rows.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "tinkercad-circuits",
      "stageId": "circuits",
      "title": "Tinkercad: Learn Circuits",
      "source": "Autodesk Tinkercad",
      "url": "https://www.tinkercad.com/learn/circuits?collectionId=OSZ5W2BL1",
      "type": "tool",
      "formatDetail": "interactive simulator lessons",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Build and simulate circuit basics and Arduino examples before buying components. Move from blocks to text once the logic is understandable.",
      "estimatedEffort": "Estimated 3–5 hours for an LED, resistor, pushbutton, and sensor-input lesson.",
      "prerequisites": [
        "Basic voltage/current and breadboard ideas; coding can start with blocks."
      ],
      "access": {
        "cost": "Free browser app; see Tinkercad platform conditions.",
        "account": "Sign-in required to create and save work; private-by-default designs according to Autodesk's guide.",
        "hardware": "Browser/internet only; no board or components needed.",
        "notes": "Simulation covers supported parts and libraries, not every Arduino shield or real-world electrical behavior."
      },
      "lastChecked": "2026-10-20",
      "verification": "Lesson landing page indexed by web; official 28-page guide opened and checked. Interactive editor was not signed into or tested.",
      "supportingUrls": [
        "https://www.tinkercad.com/learn/circuits?collectionId=OSZ5W2BL1",
        "https://images.tinkercad.com/jl5ii4oqrdmc/4sMFqe3rDlbUymJt0I4yh/85a4487f7fe274e74c19870ae4679fc1/tinkercad-guides_circuits-Printable.pdf"
      ],
      "display_title": "Build a virtual circuit",
      "one_line_summary": "Try an LED, button, and sensor input without buying parts.",
      "first_action": "Open an introductory LED circuit lesson.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "Account to create",
        "hardware": "Browser only"
      }
    },
    {
      "id": "adafruit-calibration",
      "stageId": "circuits",
      "title": "Adafruit: Calibrating Sensors",
      "source": "Adafruit",
      "url": "https://learn.adafruit.com/calibrating-sensors",
      "type": "guide",
      "formatDetail": "skill guide",
      "level": "beginner",
      "role": "optional",
      "whyUseful": "Explains why readings vary and introduces calibration, precision, resolution, noise, and one-/two-point correction. Essential context before training a model on sensor data.",
      "estimatedEffort": "Estimated 1–2 hours with a synthetic offset/scale correction exercise.",
      "prerequisites": [
        "Know what a sensor reading represents; basic arithmetic."
      ],
      "access": {
        "cost": "Free public guide; product links are optional.",
        "account": "None to read; account only for optional favorites.",
        "hardware": "No hardware to learn the concepts or use synthetic readings. Real calibration later needs an appropriate reference.",
        "notes": "Simulation and synthetic data do not prove real sensor accuracy. Skip hot/cold or hazardous physical experiments in this beginner path."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official Adafruit guide opened; sections and beginner level checked.",
      "supportingUrls": [
        "https://learn.adafruit.com/calibrating-sensors"
      ],
      "display_title": "Understand sensor errors",
      "one_line_summary": "Learn why raw readings and accurate measurements differ.",
      "first_action": "Compare an offset error with a scale error using invented readings.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "wokwi-esp32",
      "stageId": "embedded",
      "title": "Wokwi: ESP32 Simulation",
      "source": "Wokwi",
      "url": "https://docs.wokwi.com/guides/esp32",
      "type": "documentation",
      "formatDetail": "simulator guide",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Start with the linked ESP32 MicroPython template and Blink example, preserving the Python learning path; then add a button, potentiometer, serial output, and state transitions.",
      "estimatedEffort": "Estimated 2–4 hours for Blink, a button, serial output, and one modification.",
      "prerequisites": [
        "Basic variables, loops, functions, and circuit connections."
      ],
      "access": {
        "cost": "Browser-based personal learning is available free; see Wokwi platform conditions.",
        "account": "Documentation/examples are public. An account is useful for keeping a continuing project; exact anonymous-save limits were not live-tested.",
        "hardware": "No physical ESP32 required.",
        "notes": "Bluetooth is not simulated. Timing/peripherals are incomplete approximations; successful simulation is not a hardware pass."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official guide opened; templates, supported features, and Bluetooth limitation checked.",
      "supportingUrls": [
        "https://docs.wokwi.com/guides/esp32",
        "https://wokwi.com/pricing"
      ],
      "display_title": "Simulate an ESP32",
      "one_line_summary": "Run MicroPython on a virtual microcontroller.",
      "first_action": "Open the linked MicroPython template and change Blink.",
      "accessShort": {
        "cost": "Free personal projects",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "arduino-examples",
      "stageId": "embedded",
      "title": "Arduino: Built-in Examples",
      "source": "Arduino",
      "url": "https://docs.arduino.cc/built-in-examples/",
      "type": "documentation",
      "formatDetail": "example collection",
      "level": "beginner",
      "role": "optional",
      "whyUseful": "An optional Arduino/C++ route. Blink Without Delay and Debounce illustrate responsive timing and button handling, but the core curriculum can remain in MicroPython.",
      "estimatedEffort": "Estimated 3–5 hours for the selected examples and one combined sensor monitor.",
      "prerequisites": [
        "Basic programming and simple circuits; Arduino examples use C++ syntax."
      ],
      "access": {
        "cost": "Free official documentation and example code.",
        "account": "None to read. Use the simulator's own account rules if saving a virtual build.",
        "hardware": "Use a simulated Arduino Uno for these beginner examples; no purchase needed.",
        "notes": "Board pins and voltage assumptions differ from ESP32. Do not copy Arduino Uno wiring onto ESP32 without checking the board documentation."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official Arduino collection opened and named examples checked.",
      "supportingUrls": [
        "https://docs.arduino.cc/built-in-examples/"
      ],
      "display_title": "Try Arduino later",
      "one_line_summary": "Explore the optional C++ route for timing and buttons.",
      "first_action": "Read Blink Without Delay; keep its board assumptions separate.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "wokwi-dht22",
      "stageId": "embedded",
      "title": "Wokwi: DHT22 Temperature and Humidity Sensor",
      "source": "Wokwi",
      "url": "https://docs.wokwi.com/parts/wokwi-dht22",
      "type": "documentation",
      "formatDetail": "sensor reference and runnable example",
      "level": "beginner",
      "role": "optional",
      "whyUseful": "A later virtual-sensor extension after the potentiometer lab. Change simulated temperature/humidity and use MicroPython’s dht.DHT22 driver from its official ESP32 quick reference.",
      "estimatedEffort": "Estimated 1–2 hours to read values and add a threshold indicator.",
      "prerequisites": [
        "Basic digital input/output and serial printing."
      ],
      "access": {
        "cost": "Free documentation; the linked simulator follows Wokwi Community conditions.",
        "account": "Public read access; account useful for ongoing saved projects.",
        "hardware": "No hardware required.",
        "notes": "For the Arduino-on-ESP32 example, Wokwi specifically recommends the DHT sensor library for ESPx. Its SDA label denotes this sensor's data pin; do not assume the device uses I2C."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pin reference, interactive-value controls, and library warning opened and checked.",
      "supportingUrls": [
        "https://docs.wokwi.com/parts/wokwi-dht22",
        "https://docs.micropython.org/en/latest/esp32/quickref.html"
      ],
      "display_title": "Add a virtual sensor",
      "one_line_summary": "Extend your gadget with simulated temperature and humidity.",
      "first_action": "Change one simulated reading and inspect the logged value.",
      "accessShort": {
        "cost": "Free personal projects",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "micropython-esp32",
      "stageId": "embedded",
      "title": "MicroPython: Quick Reference for ESP32",
      "source": "MicroPython",
      "url": "https://docs.micropython.org/en/latest/esp32/quickref.html",
      "type": "documentation",
      "formatDetail": "official API reference",
      "level": "intermediate",
      "role": "core",
      "whyUseful": "The main Python-to-hardware reference: use Pin for LED/button, ADC for the potentiometer, and time.ticks_ms/ticks_diff for responsive scheduling; DHT is an optional later sensor.",
      "estimatedEffort": "Estimated 2–4 hours for selected GPIO, timing, and ADC examples.",
      "prerequisites": [
        "Python functions/loops and the Wokwi ESP32 MicroPython template."
      ],
      "access": {
        "cost": "Free official documentation.",
        "account": "None to read.",
        "hardware": "Use Wokwi for supported virtual peripherals first; physical flashing requires a compatible board later.",
        "notes": "The latest URL is the development branch. Match docs to stable firmware/runtime; not all peripherals are simulated. ESP32 uses 3.3 V logic: do not feed GPIO with Uno 5 V wiring; physical hardware must follow the exact board’s pin/voltage limits."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official reference opened; version warning and input-voltage caution checked.",
      "supportingUrls": [
        "https://docs.micropython.org/en/latest/esp32/quickref.html",
        "https://docs.wokwi.com/guides/esp32"
      ],
      "display_title": "Control pins with Python",
      "one_line_summary": "Use digital inputs, outputs, and analog readings.",
      "first_action": "Read the Pin and ADC examples that match your runtime.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "micropython-time",
      "stageId": "embedded",
      "title": "MicroPython: time, ticks_ms and ticks_diff",
      "source": "MicroPython",
      "url": "https://docs.micropython.org/en/latest/library/time.html",
      "type": "documentation",
      "formatDetail": "official API reference",
      "level": "intermediate",
      "role": "core",
      "whyUseful": "Use elapsed-time checks to sample sensors while continuing to poll the reset button. ticks_diff handles the millisecond counter’s wraparound.",
      "estimatedEffort": "Estimated 1–2 hours to replace a long blocking delay with a responsive scheduling loop.",
      "prerequisites": [
        "Python loops, conditionals, and variables; a running Wokwi MicroPython example."
      ],
      "access": {
        "cost": "Free official documentation.",
        "account": "None to read.",
        "hardware": "Wokwi simulation only; no board needed.",
        "notes": "Use ticks_diff rather than plain subtraction on tick counters. Keep each loop iteration short; a long sensor call can still block. Select docs matching the runtime version."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official time-module reference opened; counter wraparound and ticks_diff usage checked.",
      "supportingUrls": [
        "https://docs.micropython.org/en/latest/library/time.html"
      ],
      "display_title": "Keep the loop responsive",
      "one_line_summary": "Measure elapsed time without freezing the button input.",
      "first_action": "Replace one long sleep with ticks_ms and ticks_diff.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "tinkercad-3d",
      "stageId": "cad",
      "title": "Tinkercad: Learn 3D Design",
      "source": "Autodesk Tinkercad",
      "url": "https://www.tinkercad.com/learn/3d-design",
      "type": "course",
      "formatDetail": "interactive CAD lessons",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Learn moving, resizing, aligning, and combining solids/holes before modeling a simple enclosure.",
      "estimatedEffort": "Estimated 2–4 hours for basics and a rough two-part box.",
      "prerequisites": [
        "Basic mouse/trackpad navigation; no CAD experience."
      ],
      "access": {
        "cost": "Free browser app; see Tinkercad platform conditions.",
        "account": "Account/sign-in for creating and saving designs; private by default according to official guide.",
        "hardware": "Browser only; no 3D printer required for the design milestone.",
        "notes": "Simple geometry is a good first step, but more complex dimension-driven revisions are easier in parametric CAD. Commercial licensing is not asserted here."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official lesson URL resolves; it is JavaScript-rendered. Official getting-started PDF opened to corroborate product and learning features. Editor not tested.",
      "supportingUrls": [
        "https://www.tinkercad.com/learn/3d-design",
        "https://images.tinkercad.com/jl5ii4oqrdmc/4nMtGEJi53o3n7V2KJKG7a/0b1818fdecff4868bebc74ebeaf925cf/Tinkercad_Getting_Started_Guide_printable.pdf"
      ],
      "display_title": "Make your first enclosure",
      "one_line_summary": "Combine simple shapes into a removable-lid box.",
      "first_action": "Practice aligning a solid box and a hole.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "Account to create",
        "hardware": "Browser only"
      }
    },
    {
      "id": "onshape-cad-basics",
      "stageId": "cad",
      "title": "Onshape: CAD Basics Learning Pathway",
      "source": "Onshape",
      "url": "https://learn.onshape.com/learning-paths/introduction-to-cad",
      "type": "course",
      "formatDetail": "video course with exercises",
      "level": "beginner",
      "role": "optional",
      "whyUseful": "Builds the parametric sketch/feature/part concepts needed for editable enclosures. Choose this route if changing dimensions and repeated iterations matter.",
      "estimatedEffort": "Estimated 5–8 hours with practice; work through the beginning rather than rushing every lesson.",
      "prerequisites": [
        "None; intended for new CAD learners."
      ],
      "access": {
        "cost": "CAD Basics is among official free self-paced resources. Free CAD plan is non-commercial and public-only; see platform conditions.",
        "account": "Onshape sign-in required for hands-on documents and Learning Center access/progress.",
        "hardware": "Browser/internet only; no printer required.",
        "notes": "Warning: Free-plan models are PUBLIC and can be viewed and copied. Do not upload confidential, client, employer, or commercially sensitive designs. Education eligibility must be checked separately."
      },
      "lastChecked": "2026-10-20",
      "verification": "Followed exact CAD Basics link from official student-resources page; destination resolves as a JavaScript app. Full logged-in course was not tested.",
      "supportingUrls": [
        "https://learn.onshape.com/learning-paths/introduction-to-cad",
        "https://www.onshape.com/en/education/student-resources",
        "https://www.onshape.com/en/products/free"
      ],
      "display_title": "Explore parametric CAD",
      "one_line_summary": "Make dimension-driven designs that are easier to revise.",
      "first_action": "Read the public-design warning before choosing this optional route.",
      "accessShort": {
        "cost": "Free non-commercial plan",
        "account": "Account; public designs",
        "hardware": "Browser only"
      }
    },
    {
      "id": "onshape-shell",
      "stageId": "cad",
      "title": "Onshape Help: Shell",
      "source": "Onshape",
      "url": "https://cad.onshape.com/help/Content/PartStudio/shell.htm",
      "type": "documentation",
      "formatDetail": "reference with video",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Shows how to turn a solid into a constant-wall-thickness cavity, a useful enclosure operation. Practice with a plain box before adding cutouts and mounting features.",
      "estimatedEffort": "Estimated 45–90 minutes including making and inspecting a box cavity.",
      "prerequisites": [
        "Can sketch and extrude a solid part in Onshape."
      ],
      "access": {
        "cost": "Free public help page. Modeling follows Onshape plan restrictions.",
        "account": "None to read; an Onshape account to practice.",
        "hardware": "Browser only.",
        "notes": "Shell is one modeling operation, not a complete enclosure engineering course. Free-plan practice models are public; wall and fit choices still need physical validation."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official help page and video transcript opened; page updated October 15, 2026.",
      "supportingUrls": [
        "https://cad.onshape.com/help/Content/PartStudio/shell.htm"
      ],
      "display_title": "Hollow out a solid",
      "one_line_summary": "Create an enclosure cavity with the Shell feature.",
      "first_action": "Try Shell on a simple box before adding cutouts.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "Public-design practice account",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "prusa-print-design",
      "stageId": "cad",
      "title": "Prusa: Modeling with 3D Printing in Mind",
      "source": "Prusa Research",
      "url": "https://help.prusa3d.com/article/modeling-with-3d-printing-in-mind_164135",
      "type": "guide",
      "formatDetail": "design guide",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Explains overhangs, wall thickness, tolerances, print orientation, and iteration so a virtual enclosure is designed with manufacturing in mind.",
      "estimatedEffort": "Estimated 1–2 hours to read and annotate an enclosure design checklist.",
      "prerequisites": [
        "Can make a basic 3D shape; no printer ownership needed."
      ],
      "access": {
        "cost": "Free public knowledge-base article.",
        "account": "None to read.",
        "hardware": "No hardware required for reading/design review; later fit testing requires a real print or dimensional mock-up.",
        "notes": "There is no universal fit tolerance. Treat printer/material-specific values as examples, then verify the actual process. Buying a printer is unnecessary for this stage."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official article URL opened; substantive content verified via indexed official text.",
      "supportingUrls": [
        "https://help.prusa3d.com/article/modeling-with-3d-printing-in-mind_164135"
      ],
      "display_title": "Design for a real print",
      "one_line_summary": "Consider walls, clearances, overhangs, and orientation.",
      "first_action": "Annotate your enclosure with the fit assumptions that need testing.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "ai_teachable_machine",
      "stageId": "ai",
      "title": "Teachable Machine",
      "source": "Google Creative Lab",
      "url": "https://teachablemachine.withgoogle.com/",
      "type": "tool",
      "formatDetail": "Browser tool with short tutorial videos",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Train and preview an image classifier using your own examples. Makes the difference between collecting examples, training, and making predictions tangible.",
      "estimatedEffort": "Estimated 60–90 minutes for the first classifier",
      "prerequisites": [
        "Use a desktop browser and organize a few image files; no coding or ML background required."
      ],
      "access": {
        "cost": "Free basic browser tool; no purchase required.",
        "account": "Basic local train/test is presented without a required sign-in. Optional Google Drive saving uses a Google account. No account was created or tested during verification.",
        "hardware": "Existing computer and modern desktop browser. Use your own non-sensitive image files; a webcam is optional, not necessary. No development board.",
        "notes": "Google says examples and training stay on-device unless the learner chooses Google Drive saving. Local processing does not by itself mean the site and exported project will load without internet; test that separately. Browser training is not microcontroller deployment."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Image project; collect two object classes plus an other/background class, train, test unseen images, and record a few predictions. Keep the model and samples local rather than choosing cloud save or hosting.",
      "supportingUrls": [
        "https://blog.google/innovation-and-ai/products/teachable-machine/"
      ],
      "display_title": "Train a tiny classifier",
      "one_line_summary": "Teach the browser to recognize your own everyday objects.",
      "first_action": "Use two harmless object classes and a separate other/background class.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account for basics",
        "hardware": "Browser; own image files"
      }
    },
    {
      "id": "ai_mlcc",
      "stageId": "ai",
      "title": "Machine Learning Crash Course",
      "source": "Google for Developers",
      "url": "https://developers.google.com/machine-learning/crash-course",
      "type": "course",
      "formatDetail": "Self-paced course with animated videos, visualizations, and exercises",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Explains thresholds, confusion matrices, precision/recall, train/test separation and overfitting, so a successful-looking demo is not mistaken for strong evidence.",
      "estimatedEffort": "Estimated 3–4 hours for the selected concepts and exercises; not the entire course",
      "prerequisites": [
        "For the full course: variables, graphs, algebra, basic statistics and programming, ideally Python. NumPy/pandas prework is recommended for coding exercises. A new coder can start with the selected visual lessons and defer notebooks."
      ],
      "access": {
        "cost": "Public course content is free to read.",
        "account": "No account needed for public lessons. Optional Colab notebook work may require Google sign-in; no paid Colab plan is needed for the conceptual path.",
        "hardware": "Existing computer and browser; no board or separate GPU. The course uses browser-based Colab for optional programming exercises.",
        "notes": "Do not require the complete course or calculus before building the first toy classifier."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Read/watch Classification and Datasets, Generalization, and Overfitting. Use the embedded visual explanations first; Python notebook exercises are optional. If vocabulary is unfamiliar, begin with the linked Introduction to Machine Learning.",
      "supportingUrls": [
        "https://developers.google.com/machine-learning/crash-course/prereqs-and-prework",
        "https://developers.google.com/machine-learning/intro-to-ml"
      ],
      "display_title": "Understand model mistakes",
      "one_line_summary": "Learn train/test separation, thresholds, and confusion matrices.",
      "first_action": "Start with Classification and the visual examples.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "ai_litert_micro",
      "stageId": "ai",
      "title": "LiteRT for Microcontrollers",
      "source": "Google AI Edge",
      "url": "https://developers.google.com/edge/litert/microcontrollers/overview",
      "type": "documentation",
      "formatDetail": "Official technical overview",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Introduces what changes when inference moves to a tiny device: constrained memory, supported operators, conversion, and target-specific integration.",
      "estimatedEffort": "Estimated 30–45 minutes",
      "prerequisites": [
        "Know what a model, training and inference are. C++ and embedded basics are needed only if implementing the examples later."
      ],
      "access": {
        "cost": "Free public documentation.",
        "account": "None for reading.",
        "hardware": "None for this reading. The hardware examples are deferred; executing them requires an appropriate target and toolchain.",
        "notes": "The official overview says the runtime targets 32-bit platforms, uses a low-level C++ API and does not support on-device training. It is not a turnkey Teachable Machine-to-board tutorial."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Read Workflow and Limitations. Draw training computer → converted model → device inference. Explain why a browser model cannot simply be assumed to fit a microcontroller.",
      "supportingUrls": [],
      "display_title": "What changes on a tiny device?",
      "one_line_summary": "Learn why a browser model may not fit a microcontroller.",
      "first_action": "Read Workflow and Limitations; do not start by buying a board.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "ai_mobilenets_paper",
      "stageId": "ai",
      "title": "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications",
      "source": "Howard et al., author paper on arXiv (2017)",
      "url": "https://arxiv.org/abs/1704.04861",
      "type": "paper",
      "formatDetail": "Research paper",
      "level": "deep-dive",
      "role": "optional",
      "whyUseful": "A concrete example of model design trading accuracy against computation for mobile and embedded applications.",
      "estimatedEffort": "Estimated 20–30 minutes for a guided skim",
      "prerequisites": [
        "Basic idea of a neural network and tradeoffs between model size, latency and accuracy. Convolution math is optional for this skim."
      ],
      "access": {
        "cost": "Free author manuscript and PDF on arXiv.",
        "account": "None.",
        "hardware": "None; no paper reproduction required.",
        "notes": "Historical foundational paper, not a claim that this architecture is the best current choice or that it fits any given microcontroller."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Read the abstract, introduction and conclusion. Inspect one accuracy-versus-compute comparison. Skip derivations. Answer: which tradeoff might matter for a battery-powered product?",
      "supportingUrls": [],
      "display_title": "Paper: smaller vision models",
      "one_line_summary": "Explore an early accuracy-versus-compute design tradeoff.",
      "first_action": "Read the abstract and inspect one accuracy-versus-compute figure.",
      "subtype": "research-paper",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "ai_model_cards_paper",
      "stageId": "ai",
      "title": "Model Cards for Model Reporting",
      "source": "Mitchell et al., FAT* 2019; author paper on arXiv",
      "url": "https://arxiv.org/abs/1810.03993",
      "type": "paper",
      "formatDetail": "Research paper",
      "level": "deep-dive",
      "role": "optional",
      "whyUseful": "Shows how intended uses, evaluation conditions and limitations belong alongside model scores. Provides a useful reporting habit before moving toward physical products.",
      "estimatedEffort": "Estimated 20–30 minutes for reading, plus 30–45 minutes for your card",
      "prerequisites": [
        "Have trained or inspected one classifier. No advanced mathematics needed for the reporting idea."
      ],
      "access": {
        "cost": "Free author manuscript and PDF on arXiv.",
        "account": "None.",
        "hardware": "None.",
        "notes": "The curriculum adds offline behavior and manual fallback fields for the physical-product context; these are exercise design choices, not a claim that the paper prescribes those exact fields."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Read the abstract and model-card framework. Borrow the headings for a one-page card for Desk Signals; do not reproduce the paper's face or toxicity datasets.",
      "supportingUrls": [],
      "display_title": "Paper: report model limits",
      "one_line_summary": "Document what your model is for and where it fails.",
      "first_action": "Borrow a few model-card headings for your own experiment.",
      "subtype": "research-paper",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "interaction_mqtt_video",
      "stageId": "interactions",
      "title": "MQTT Essentials Video Series",
      "source": "HiveMQ",
      "url": "https://www.hivemq.com/blog/mqtt-essentials-video-series/",
      "type": "video",
      "formatDetail": "Official video lesson with text companion",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Introduces MQTT and the roles of clients, brokers and publish/subscribe messaging without starting with the full protocol specification.",
      "estimatedEffort": "Estimated 20–30 minutes for video and a diagram",
      "prerequisites": [
        "Understand a device can send and receive a message; no networking setup required."
      ],
      "access": {
        "cost": "Public lesson and written companion are free.",
        "account": "No account for the public article. Embedded video availability can depend on browser/region; use the written companion if it does not play.",
        "hardware": "Existing browser only.",
        "notes": "The official HiveMQ page links to its YouTube video; search metadata identified the uploader as HiveMQ. Direct YouTube retrieval failed, so playback was not verified. No broker or paid cloud plan is required to learn the concepts."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Watch the embedded Part 1 introduction. Then use the written MQTT introduction to sketch classifier → topic → subscriber. Skim the linked QoS and retained-message explanations only when designing the test cases.",
      "supportingUrls": [
        "https://www.youtube.com/watch?v=jTeJxQFD8Ak",
        "https://www.hivemq.com/blog/mqtt-essentials-part-1-introducing-mqtt/",
        "https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/",
        "https://www.hivemq.com/blog/mqtt-essentials-part-8-retained-messages/"
      ],
      "display_title": "Watch: how MQTT works",
      "one_line_summary": "Understand publishers, subscribers, topics, and brokers.",
      "first_action": "Watch Part 1, or use the written companion.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "interaction_state_machines",
      "stageId": "interactions",
      "title": "What are state machines and statecharts?",
      "source": "Stately",
      "url": "https://stately.ai/docs/state-machines-and-statecharts",
      "type": "documentation",
      "formatDetail": "Concept documentation with interactive examples; browser simulator companion",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Turns vague product behavior into explicit states, events and transitions. Helps identify what should happen on unknown input, timeout, disconnect and reset.",
      "estimatedEffort": "Estimated 45–60 minutes",
      "prerequisites": [
        "Basic if/else logic helps; no library installation is required for reading or sketching states."
      ],
      "access": {
        "cost": "Free public docs. Stately Sketch is open source and offers the described no-login visualizing/simulating flow.",
        "account": "None for docs or the basic Sketch flow described by Stately. Saving/sharing a permanent Sketch URL requires sign-in; do not use it for this exercise.",
        "hardware": "Existing computer or browser; paper tracing is a fully acceptable fallback. No physical device.",
        "notes": "Use the language-independent concepts and a simple diagram; the docs currently expose evolving XState versions. No dependency installation or commitment to a particular XState version is required. Simulation checks the modeled behavior only."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Read states, initial states, events and transitions. Draw Idle, Recognized, Unknown, Offline and Error, then simulate a few event sequences in Stately Sketch or trace them on paper.",
      "supportingUrls": [
        "https://sketch.stately.ai/",
        "https://stately.ai/blog/2026-03-26-introducing-stately-sketch"
      ],
      "display_title": "Draw the device behavior",
      "one_line_summary": "Define states and transitions before connecting modules.",
      "first_action": "Draw idle, active, and unknown, then add reset and timeout events.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "interaction_mqtt_browser",
      "stageId": "interactions",
      "title": "Free MQTT broker",
      "source": "HiveMQ",
      "url": "https://www.hivemq.com/mqtt/public-mqtt-broker/",
      "type": "tool",
      "formatDetail": "Browser lab entry point and public test broker",
      "level": "beginner",
      "role": "optional",
      "whyUseful": "Lets two browser tabs act as publisher and subscriber, making message routing concrete without buying or configuring a board.",
      "estimatedEffort": "Estimated 30–45 minutes",
      "prerequisites": [
        "Know broker, client, topic and message. Read the public-data warning first."
      ],
      "access": {
        "cost": "Free shared public test broker and browser client.",
        "account": "HiveMQ explicitly says its shared public broker needs no account or broker setup. Its separate private/cloud broker signup is not required.",
        "hardware": "Existing modern browser and internet connection; two tabs. No board or software installation.",
        "notes": "The broker is public and shared. Use only invented labels and numbers, never samples, images, personal identifiers, secrets, private model data or real control commands. Random topics reduce accidental collisions, not provide privacy. Availability and message delivery are not guaranteed. Leave Retain off for this introductory test."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Use the linked public broker and browser client for a small temporary test with invented messages. Give both clients different client IDs and use a fresh random topic suffix. Subscribe one tab, publish from the other, then disconnect and reconnect.",
      "supportingUrls": [
        "https://www.hivemq.com/demos/websocket-client/"
      ],
      "display_title": "Try messages in two tabs",
      "one_line_summary": "Explore a shared public broker with invented test data only.",
      "first_action": "Read the public-data warning before opening the browser client.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account; public broker",
        "hardware": "Browser and internet"
      }
    },
    {
      "id": "interaction_asyncapi",
      "stageId": "interactions",
      "title": "Hello world",
      "source": "AsyncAPI Initiative",
      "url": "https://www.asyncapi.com/docs/tutorials/getting-started/hello-world",
      "type": "documentation",
      "formatDetail": "Official event-contract tutorial",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Shows that a message interface needs an agreed channel, payload shape and send/receive behavior. Useful for separating the classifier from the device controller.",
      "estimatedEffort": "Estimated 30–45 minutes reading and contract design; add 30 minutes for optional Studio validation",
      "prerequisites": [
        "Know an event/message and a channel/topic; reading simple JSON or YAML helps."
      ],
      "access": {
        "cost": "Free public documentation and open browser Studio.",
        "account": "No account needed for reading. Studio is publicly accessible; save files locally rather than enabling cloud collaboration. Interactive runtime was not tested.",
        "hardware": "Existing browser only; no broker required for writing or validating the description.",
        "notes": "The current Hello world page uses AsyncAPI 3.1.0. Schema validation describes/checks the interface; it does not establish delivery, ordering, electrical safety or application-level correctness."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official pages and author paper records were checked through web retrieval on the stated date. Dynamic apps, video playback, broker connectivity, accounts and model export were not functionally tested. Source-check notes record the distinction.",
      "selectedScope": "Read the tiny Hello world contract and write a plain-language contract for Desk Signals. Optional: adapt a toy document in AsyncAPI Studio and intentionally break a required property to inspect validation feedback.",
      "supportingUrls": [
        "https://www.asyncapi.com/docs/tutorials/studio-document-validation",
        "https://studio.asyncapi.com/"
      ],
      "display_title": "Describe an event contract",
      "one_line_summary": "Agree on message fields and allowed values.",
      "first_action": "Write a plain-language contract before trying YAML.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "verification-python",
      "stageId": "verification",
      "title": "Python: your first automated tests",
      "display_title": "Test your decision rule",
      "source": "Python Software Foundation",
      "url": "https://docs.python.org/3/library/unittest.html#basic-example",
      "type": "documentation",
      "level": "intermediate",
      "role": "core",
      "whyUseful": "Turn expected outputs into repeatable checks for your decision rules.",
      "one_line_summary": "Make checks repeatable instead of testing by memory.",
      "first_action": "Write valid, missing, and out-of-range input tests.",
      "estimatedEffort": "Estimated 1–2 hours for the basic example and your own tests.",
      "prerequisites": [
        "Python functions; basic familiarity with classes."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read.",
        "hardware": "None; Python is needed to run examples, in a browser runtime or locally.",
        "notes": "Read the Basic example first; skip the long API reference. In a browser, use an explicit test suite and TextTestRunner rather than relying on command-line discovery."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official Python documentation opened; the linked Basic example and test runner usage were checked. No claim that this validates firmware on hardware.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "verification-nasa",
      "stageId": "verification",
      "title": "NASA: write a testable requirement",
      "display_title": "Turn a goal into a test",
      "source": "NASA",
      "url": "https://www.nasa.gov/reference/system-engineering-handbook-appendix/",
      "type": "guide",
      "level": "intermediate",
      "role": "core",
      "whyUseful": "Use a small requirements-to-test table to show what your prototype actually proves.",
      "one_line_summary": "Link each requirement to an observable result.",
      "first_action": "Read Appendix C, then write one pass/fail requirement.",
      "estimatedEffort": "Estimated 45–90 minutes for Appendices C–E.",
      "prerequisites": [
        "A written user need and a prototype."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read.",
        "hardware": "None.",
        "notes": "Selected appendices of a professional systems-engineering handbook. Scale the method down to five requirements; the full handbook is optional."
      },
      "lastChecked": "2026-10-20",
      "subtype": "technical-handbook",
      "verification": "Official page opened and content checked on 2026-10-20; interactive workflow was not executed.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "verification-wokwi",
      "stageId": "verification",
      "title": "See your simulated digital signals",
      "display_title": "Inspect digital timing",
      "source": "Wokwi",
      "url": "https://docs.wokwi.com/guides/logic-analyzer",
      "type": "documentation",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Capture digital transitions when a log alone cannot explain a timing problem.",
      "one_line_summary": "Capture a virtual signal when logs are not enough.",
      "first_action": "Record one button-to-indicator transition.",
      "estimatedEffort": "Estimated 1–2 hours for one capture.",
      "prerequisites": [
        "A working Wokwi circuit; digital pin basics."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read; saving simulator projects may require a Wokwi account.",
        "hardware": "No physical analyzer needed; Wokwi simulates it.",
        "notes": "The browser simulator can export a VCD trace. Viewing detailed waveforms may require a separate local viewer such as PulseView or GTKWave. Virtual signals do not establish physical voltage or timing margins."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official page opened and content checked on 2026-10-20; interactive workflow was not executed.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "Optional local waveform viewer"
      }
    },
    {
      "id": "verification-arm",
      "stageId": "verification",
      "title": "How to read an embedded-AI white paper",
      "display_title": "White paper: check the claims",
      "source": "Arm / Tanuj Arora",
      "url": "https://www.arm.com/-/media/Files/pdf/ethos/Arm_Accelerating_ML_Compute_for_Embedded_Market_white_paper.pdf",
      "type": "paper",
      "level": "deep-dive",
      "role": "optional",
      "whyUseful": "Practice separating hardware performance claims from the workload and measurements behind them.",
      "one_line_summary": "Read an embedded-AI performance claim critically.",
      "first_action": "List the workload and hardware behind one claimed speedup.",
      "estimatedEffort": "Estimated 45–90 minutes for a guided skim.",
      "prerequisites": [
        "Inference, memory, latency, and microcontroller basics."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read.",
        "hardware": "None.",
        "notes": "Vendor white paper: Accelerating Machine Learning Compute for the IoT and Embedded Market. It discusses particular Arm technologies; it is not a neutral benchmark or a required shopping list. PDF downloads directly and currently redirects to Arm’s document storage."
      },
      "lastChecked": "2026-10-20",
      "subtype": "whitepaper",
      "verification": "Official Arm PDF indexed text checked. A direct HTTP request returned 200 and a PDF file signature, redirecting to armkeil.blob.core.windows.net. No benchmark was reproduced.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "release-readme",
      "stageId": "release",
      "title": "Write a README someone can follow",
      "display_title": "Write the quick start",
      "source": "GitHub Docs",
      "url": "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes",
      "type": "documentation",
      "level": "beginner",
      "role": "core",
      "whyUseful": "Give another builder a clear starting point, setup steps, and known limitations.",
      "one_line_summary": "Help a second builder reproduce your scoped demo.",
      "first_action": "Write purpose, setup, replay steps, and known limits.",
      "estimatedEffort": "Estimated 30–60 minutes to read and draft your README.",
      "prerequisites": [
        "A working or clearly scoped prototype."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read or draft locally; GitHub account needed to publish on GitHub.",
        "hardware": "None.",
        "notes": "Publishing is optional. A local folder or ZIP is enough for the learning milestone."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official page opened and content checked on 2026-10-20; interactive workflow was not executed.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "release-oshwa",
      "stageId": "release",
      "title": "Package an open hardware project",
      "display_title": "Package the design files",
      "source": "Open Source Hardware Association",
      "url": "https://oshwa.org/resources/sharing-best-practices/",
      "type": "guide",
      "level": "intermediate",
      "role": "core",
      "whyUseful": "Keep editable design files, a parts list, firmware, and assembly notes together.",
      "one_line_summary": "Keep source, parts, and assembly notes together.",
      "first_action": "List what another builder would need to modify your project.",
      "estimatedEffort": "Estimated 1–2 hours for the selected documentation sections.",
      "prerequisites": [
        "CAD, firmware, and a preliminary bill of materials."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read.",
        "hardware": "None.",
        "notes": "Read Original Design Files, Bill of Materials, Software and Firmware, and Instructions. Decide licensing separately; this curriculum does not publish or license your work for you."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official page opened and content checked on 2026-10-20; interactive workflow was not executed.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "release-github",
      "stageId": "release",
      "title": "Create a versioned release",
      "display_title": "Version the release",
      "source": "GitHub Docs",
      "url": "https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases",
      "type": "documentation",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Learn how tags and release notes connect a reproducible package to a specific revision.",
      "one_line_summary": "Connect the package to a specific revision.",
      "first_action": "Draft a version name and release notes locally.",
      "estimatedEffort": "Estimated 30–60 minutes for a draft release.",
      "prerequisites": [
        "Basic Git history and a complete project folder."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read; a GitHub account and repository write permission are needed to publish.",
        "hardware": "None.",
        "notes": "Draft the release notes locally first. No repository, upload, or public release is required by the course."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official page opened and content checked on 2026-10-20; interactive workflow was not executed.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    },
    {
      "id": "release-license",
      "stageId": "release",
      "title": "Understand repository licensing",
      "display_title": "Check reuse permissions",
      "source": "GitHub Docs",
      "url": "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository",
      "type": "documentation",
      "level": "intermediate",
      "role": "optional",
      "whyUseful": "Check permissions before you reuse third-party work or invite others to reuse yours.",
      "one_line_summary": "Record asset origins before sharing your work.",
      "first_action": "List the license for each third-party file or dependency.",
      "estimatedEffort": "Estimated 30–60 minutes for a first pass.",
      "prerequisites": [
        "A list of your own files and third-party dependencies."
      ],
      "access": {
        "cost": "Free to read.",
        "account": "None to read.",
        "hardware": "None.",
        "notes": "Software, hardware designs, data, and documentation may need different licenses. This is orientation, not legal advice. Do not assume that public source code is automatically reusable."
      },
      "lastChecked": "2026-10-20",
      "verification": "Official page opened and content checked on 2026-10-20; interactive workflow was not executed.",
      "accessShort": {
        "cost": "Free learning access",
        "account": "No account to read",
        "hardware": "No hardware purchase"
      }
    }
  ],
  "milestones": [
    {
      "id": "m1",
      "stageId": "foundations",
      "title": "A tiny decision engine",
      "brief": "Write a text-only program that maps a sample input to idle, active, or unknown.",
      "buildSteps": [
        "Describe one harmless desk-indicator use case in one sentence.",
        "Write three observable requirements and three example inputs.",
        "Implement the decision rule in Python; print the chosen state and its reason.",
        "Save a named revision and a short change note."
      ],
      "deliverables": [
        "One-page brief",
        "Python decision function",
        "Example inputs and expected outputs",
        "One recoverable revision"
      ],
      "acceptanceChecks": [
        "Valid input produces the expected state.",
        "Missing or invalid input produces unknown.",
        "You can explain each line and restore the previous version."
      ],
      "hardwareOption": "None. Use the browser Python console or local Python.",
      "estimatedEffort": "Estimated 2–3 hours, included in the stage estimate."
    },
    {
      "id": "m2",
      "stageId": "circuits",
      "title": "A virtual sensor light",
      "brief": "Use a button or simulated analog input to change an LED indicator.",
      "buildSteps": [
        "Build the LED circuit in a simulator with appropriate current limiting.",
        "Add a button, then a potentiometer as a controllable analog input.",
        "Record the input range and the threshold used by your rule.",
        "Draw the signal path and mark assumed voltage levels."
      ],
      "deliverables": [
        "Circuit diagram",
        "Input-to-output table",
        "Voltage and component assumptions"
      ],
      "acceptanceChecks": [
        "The input changes the output repeatably in the simulator.",
        "The LED has an appropriate current-limiting arrangement.",
        "Raw values are not presented as calibrated physical measurements."
      ],
      "hardwareOption": "No components needed. Optional later build: compatible low-voltage development board, resistor, LED, button, breadboard, and jumpers; confirm the exact board and ratings first.",
      "estimatedEffort": "Estimated 2–3 hours, included in the stage estimate."
    },
    {
      "id": "m3",
      "stageId": "embedded",
      "title": "A three-state gadget",
      "brief": "Make an ESP32 simulation behave consistently through idle, active, and unknown states.",
      "buildSteps": [
        "Use MicroPython in Wokwi to read inputs and drive an indicator.",
        "Define all allowed state transitions before coding them.",
        "Add a manual reset and time-based behavior without a long blocking sleep.",
        "Log input, state, and transition reason.",
        "Inject invalid or stale data with a test flag; a disconnected analog input may float and is not reliable fault detection."
      ],
      "deliverables": [
        "Firmware source",
        "State-transition table",
        "Normal, reset, and invalid-input traces"
      ],
      "acceptanceChecks": [
        "Each input sequence produces the documented state.",
        "Reset works while a timed behavior is running.",
        "Input failures move to a harmless fallback."
      ],
      "hardwareOption": "Simulator only by default. Optional USB-powered ESP32 hardware must use board-correct 3.3 V logic and current limits; Arduino Uno wiring is not automatically compatible.",
      "estimatedEffort": "Estimated 3–4 hours, included in the stage estimate."
    },
    {
      "id": "m4",
      "stageId": "cad",
      "title": "An editable enclosure",
      "brief": "Model a removable-lid enclosure around the board, indicator, button, and cable.",
      "buildSteps": [
        "Create a component envelope from official dimensions or clearly labeled assumptions.",
        "Make a dimensioned sketch and extrude the enclosure.",
        "Add openings for the cable, indicator, and button; keep the lid removable.",
        "Export a viewable model and retain the editable original."
      ],
      "deliverables": [
        "Editable CAD source",
        "Dimensioned drawing",
        "Exported model",
        "Preliminary BOM with assumed dimensions marked"
      ],
      "acceptanceChecks": [
        "The modeled board and cable have clearance in CAD.",
        "A changed board width updates the design sensibly.",
        "The record separates modeled fit from a physical fit check."
      ],
      "hardwareOption": "No printer required. Optional paper/cardboard mock-up or physical print only after dimensions and safe tool use are reviewed.",
      "estimatedEffort": "Estimated 3–4 hours, included in the stage estimate."
    },
    {
      "id": "m5",
      "stageId": "ai",
      "title": "A classifier with an unknown state",
      "brief": "Recognize two harmless personal objects in the browser, then show when the model is unsure.",
      "buildSteps": [
        "Use objects or drawings you own; avoid people, faces, voices, screens, and private surroundings.",
        "Collect separate training, development, and final-test examples from different sessions, angles, or lighting.",
        "Train the model; choose the initial confidence rule using only development examples.",
        "Lock the rule, run the untouched final test, record per-class errors, and emit unknown for unsupported cases. After tuning again, use a new final test set.",
        "Write a short model card and keep a versioned local export where supported."
      ],
      "deliverables": [
        "Model or reproducible project export",
        "Dataset description",
        "Held-out results by class",
        "Model card",
        "Example classification events"
      ],
      "acceptanceChecks": [
        "Reported test examples were not used to train or tune the model.",
        "The report includes at least one failure or a clearly documented limitation.",
        "Low confidence and out-of-scope inputs are handled deliberately; confidence is not claimed to be calibrated probability."
      ],
      "hardwareOption": "None beyond a suitable browser and your own image files. Webcam use is optional and requires your permission. The initial model runs in the browser, not on the microcontroller.",
      "estimatedEffort": "Estimated 3–5 hours, included in the stage estimate."
    },
    {
      "id": "m6",
      "stageId": "interactions",
      "title": "A replayable interaction",
      "brief": "Connect classification results to the indicator through a small, versioned event format.",
      "buildSteps": [
        "Define fields for version, event type, label, score, sequence number, and sample age.",
        "Manually save a short trace from model observations, or label it synthetic if fabricated for testing.",
        "Replay the same trace through the Python rule and the simulated firmware.",
        "Add tests for unknown, duplicate, stale, missing, and malformed events.",
        "Optionally explore MQTT with harmless invented messages after understanding the event contract."
      ],
      "deliverables": [
        "Event contract",
        "Recorded or labeled-synthetic event trace",
        "State timeline",
        "Failure-case examples"
      ],
      "acceptanceChecks": [
        "The same trace produces the same output states.",
        "A stale or malformed event cannot trigger an active state.",
        "The record says whether messages were manually replayed or sent live."
      ],
      "hardwareOption": "No network or hardware is required for trace replay. An optional public MQTT lab uses only invented messages; never send credentials, personal data, or private project details.",
      "estimatedEffort": "Estimated 2–4 hours, included in the stage estimate."
    },
    {
      "id": "m7",
      "stageId": "verification",
      "title": "A compact test report",
      "brief": "Build a repeatable evidence pack for the requirements and the model’s limits.",
      "buildSteps": [
        "Create a five-row requirement-to-test matrix.",
        "Automate the pure decision rule with Python unittest or simple assertions.",
        "Run normal, reset, duplicate, stale, invalid, and unknown-input cases.",
        "Record the simulator and code versions and preserve actual outputs.",
        "Add a separate checklist for unperformed physical tests."
      ],
      "deliverables": [
        "Requirements/test matrix",
        "Automated tests",
        "Observed test log",
        "Model evaluation summary",
        "Open-issues list"
      ],
      "acceptanceChecks": [
        "Every requirement has a test and a recorded outcome.",
        "A failing check remains visible until corrected and rerun.",
        "Simulated timing, fit, and signals are not described as physical reliability or certification."
      ],
      "hardwareOption": "No hardware required for the simulation report. Optional physical checks include pin levels, current, reset behavior, connector strain, and fit, performed safely with appropriate tools.",
      "estimatedEffort": "Estimated 3–4 hours, included in the stage estimate."
    },
    {
      "id": "m8",
      "stageId": "release",
      "title": "Desk Signals release candidate",
      "brief": "Package the previous builds so another learner can reproduce the same scoped demonstration.",
      "buildSteps": [
        "Collect the brief, requirements, CAD, BOM, firmware, model notes, event trace, and tests in one folder.",
        "Write setup and replay instructions plus an illustrated assembly plan.",
        "Record versions, dependencies, asset origins, and known limits.",
        "Follow the README from a clean folder; invite review only if you choose to share.",
        "Keep publishing and any hardware purchasing as separate decisions."
      ],
      "deliverables": [
        "Versioned learning-release folder or ZIP",
        "README and assembly guide",
        "Editable source and CAD",
        "BOM and model card",
        "Test evidence and known limits"
      ],
      "acceptanceChecks": [
        "A fresh replay matches the documented expected results.",
        "Every claimed result links to evidence.",
        "All untested or simulation-only parts are labeled.",
        "The package includes reuse/attribution notes without assuming third-party permission."
      ],
      "hardwareOption": "Optional physical USB-powered indicator only after a separate wiring review. The browser model and simulation remain a valid learning capstone.",
      "estimatedEffort": "Estimated 4–6 hours, included in the stage estimate."
    }
  ],
  "capstone": {
    "id": "desk-signals",
    "title": "Desk Signals: a modular AI-enabled indicator",
    "summary": "A harmless desk prototype that classifies your own object images and maps results to a clear indicator state.",
    "defaultRoute": "Browser model → saved event trace → replayed ESP32 simulator → CAD enclosure → documented release candidate.",
    "physicalOption": "Optionally reproduce the indicator on a compatible USB-powered development board after reviewing its exact wiring, logic levels, and current limits. Keep the model in the browser unless a separate on-device conversion and evaluation step succeeds.",
    "modules": [
      {
        "name": "Input",
        "purpose": "Personal object images, button input, and clearly labeled synthetic test events."
      },
      {
        "name": "Model",
        "purpose": "Browser inference, held-out evaluation, and a documented unknown state."
      },
      {
        "name": "Decision",
        "purpose": "A deterministic state machine with stale-event rejection and manual reset."
      },
      {
        "name": "Output",
        "purpose": "A virtual indicator first; an optional low-voltage LED later."
      },
      {
        "name": "Enclosure",
        "purpose": "Editable CAD with connector access and explicit fit assumptions."
      },
      {
        "name": "Evidence",
        "purpose": "Versioned requirements, event traces, tests, and limitations."
      }
    ],
    "workflow": [
      {
        "step": "Idea",
        "artifact": "One-sentence need, intended learner, and exclusions."
      },
      {
        "step": "Requirements",
        "artifact": "Five numbered, observable acceptance criteria."
      },
      {
        "step": "Sketch / CAD",
        "artifact": "Block diagram, circuit sketch, editable enclosure, and dimension assumptions."
      },
      {
        "step": "BOM",
        "artifact": "Part identifiers, quantities, ratings, datasheet links, alternatives, and unverified prices left blank."
      },
      {
        "step": "Assembly",
        "artifact": "Simulator diagram and an optional physical assembly plan with power-off wiring checks."
      },
      {
        "step": "Test",
        "artifact": "Requirement-to-test matrix, model results, traces, failures, and unperformed physical checks."
      },
      {
        "step": "Release",
        "artifact": "Versioned source package, README, model card, licenses/attributions, and known limits."
      }
    ],
    "definitionOfDone": [
      "The learner can explain the input, model, decision, and output modules.",
      "The same saved event trace reproduces the same indicator states.",
      "Unknown, malformed, stale, and duplicate events have defined behavior.",
      "A new learner can follow the README without guessing missing steps.",
      "Every result is labeled as observed in software, observed in simulation, or tested on hardware."
    ],
    "limits": [
      "Educational prototype only; no safety, medical, security, or production-readiness claims.",
      "No claim that a browser model automatically deploys to a microcontroller. Model size, supported operations, memory, latency, and accuracy must be checked separately.",
      "No built-in live bridge between the browser model and Wokwi is assumed; manual event replay is the baseline.",
      "No mains wiring, battery construction or charging circuits, heaters, motors, or other hazardous actuation.",
      "A model score is not a calibrated probability; an unknown threshold reduces some errors but does not guarantee detection of unfamiliar inputs."
    ]
  },
  "accessNotes": [
    "The default route uses a desktop-class browser and no purchased hardware. An internet connection is needed to load tools and learning material.",
    "All selected reading and videos are free to access at the checked links. Some authoring, saving, grading, or publishing features require accounts; paid certificates and upgrades are not part of this path.",
    "Public/free authoring tools may expose project files. Use non-sensitive practice data and check visibility before saving.",
    "Onshape Free is for non-commercial work and makes documents public. Use an appropriate private/local CAD workflow for confidential or commercial designs.",
    "A local folder is an acceptable release artifact. Nothing in this curriculum requires you to publish, upload, or buy anything."
  ],
  "safetyNotes": [
    "Start in a simulator. For optional physical work, use compatible USB-powered low-voltage development boards and verify the exact pinout, logic voltage, and component ratings.",
    "Disconnect power before changing wiring. A simulator cannot prove real electrical safety, current limits, thermal behavior, radio reliability, or mechanical fit.",
    "Avoid mains electricity, battery fabrication or charging circuits, high-current loads, motors, heaters, and safety-critical or medical use cases.",
    "Use your own non-sensitive object images. Camera use is optional; avoid recording people or private surroundings.",
    "Public MQTT brokers are shared and untrusted. Use invented data only and do not connect them to consequential actuators."
  ],
  "firstSession": {
    "title": "Your first 90 minutes",
    "description": "No hardware purchase or account needed for this first session.",
    "steps": [
      "Open the Pyodide browser console and run a small expression.",
      "Watch the opening portion of the CS50P functions-and-variables lesson at your own pace.",
      "Make a tiny rule that prints idle, active, or unknown for three sample values.",
      "Save the code and one sentence about what it does."
    ]
  },
  "readingStrategy": [
    "Start with the single highlighted resource and the build for each stage.",
    "Open the remaining resources only when you need a concept or want more depth.",
    "For a paper: read the abstract and conclusion, inspect one figure, and write down the claim, evidence, and limitation before tackling the mathematics.",
    "Use AI to explain an error, suggest a test, or review a draft. Verify generated wiring, pins, dimensions, part numbers, citations, and claims against primary sources. Never treat generated text as test evidence."
  ],
  "platformConditions": [
    {
      "platform": "Wokwi",
      "summary": "Free Community tier supports unlimited simulations and public projects. Documentation calls it free for personal use; commercial/professional work has paid plans. Free projects are visible to everyone. Unlisted projects, custom-library uploads and the private IoT gateway are paid features. Do not put credentials or confidential code in public projects; avoid networking in the first labs.",
      "source_urls": [
        "https://docs.wokwi.com/",
        "https://wokwi.com/pricing"
      ],
      "last_checked": "2026-10-20"
    },
    {
      "platform": "Tinkercad",
      "summary": "Free browser app; sign-in is used to create and keep designs. Autodesk's official guide says designs are private by default. Its current free-CAD FAQ describes Tinkercad as intended for educational and personal projects; this research does not establish a blanket commercial-use license. Review applicable terms before business use. Do not confuse Tinkercad with Fusion's separate personal-use or education licenses.",
      "source_urls": [
        "https://www.tinkercad.com/learn/circuits?collectionId=OSZ5W2BL1",
        "https://images.tinkercad.com/jl5ii4oqrdmc/4sMFqe3rDlbUymJt0I4yh/85a4487f7fe274e74c19870ae4679fc1/tinkercad-guides_circuits-Printable.pdf",
        "https://www.autodesk.com/solutions/free-cad-software"
      ],
      "last_checked": "2026-10-20"
    },
    {
      "platform": "Onshape",
      "summary": "Free plan is for non-commercial work and public, open-source designs. Other users can view and copy those documents. It cannot create private documents. Use only throwaway learning models or designs you intentionally want public. Education plans have separate eligibility and restrictions; do not assume eligibility. Free learning resources exist, but not all Learning Center content is free.",
      "source_urls": [
        "https://www.onshape.com/en/products/free",
        "https://cad.onshape.com/help/Content/Plans/managing_your_onshape_account_and_subscription.htm",
        "https://www.onshape.com/en/education/student-resources"
      ],
      "last_checked": "2026-10-20"
    }
  ],
  "practiceDetails": [
    {
      "stageId": "ai",
      "title": "Desk Signals: a browser image classifier with an honest test report",
      "estimated_effort": "2–3 hours beyond the selected lessons, estimated",
      "steps": [
        "Choose two ordinary objects you own, such as a mug and a notebook, plus an other/background class. Keep faces, names, screens, labels with personal data, and private surroundings out of the images.",
        "Make a small balanced learning set, for example 30–50 varied images per class. Collect a separate development set for trying decision thresholds and a separate final test set from a later session with different backgrounds and lighting. Do not mix adjacent near-identical frames between these sets. These are exercise-scale counts, not evidence that the dataset is sufficient for a real product.",
        "Train in Teachable Machine using only the learning set. Use the development set to choose a tentative score threshold and a stability rule. Treat the displayed score as a model score, not a calibrated probability of being correct.",
        "Lock the choices and run the untouched final test set once. Record class-by-class correct, wrong and abstained outcomes, plus confusing examples. Report counts as well as percentages. If you revise the model or threshold after seeing those results, collect a new final test set before making a fresh performance claim.",
        "Include deliberately unfamiliar objects, a dark or partly occluded image, and a missing-input case. Low scores and an other class can help route to uncertainty, but neither reliably detects every out-of-distribution input.",
        "Record a short event trace from the browser preview by hand. Include sequence, elapsed time, model version, predicted label, score and decision such as mug, notebook, unknown or input_missing. Replay those recorded decisions in the later indicator-state-machine exercise. No live browser-to-Wokwi bridge is required.",
        "Write the model card below. Keep the raw images, model export and trace private/local unless you deliberately choose another destination. Do not host the model or save to Drive just to finish the exercise."
      ],
      "model_card_fields": [
        "Purpose: toy desk-object indicator; intended user and environment; no health, safety or identity decision",
        "Model and dataset version; class definitions; number of independent collection sessions and samples; what was excluded",
        "How learning, development and final-test data were separated; known background or lighting shortcuts",
        "Chosen threshold and stability rule; class-by-class results; false activations, abstentions and example failures",
        "Uncertainty behavior: return unknown rather than force a confident-looking state; scores are not guaranteed probabilities",
        "Offline behavior: distinguish locally running inference from network-dependent app/model loading; record what was actually tested and mark untested offline claims",
        "Fallback: manual selection or neutral indicator if input/model is missing, stale or uncertain; a clear way to reset",
        "Limits: synthetic/small dataset, changing environment, browser latency only; no evidence of physical electrical, mechanical, thermal, battery or radio reliability"
      ],
      "completion_check": "Explain training versus inference, show a held-out result table, demonstrate unknown/input-missing states, and provide a recorded event trace plus model card. A high accuracy number is not the passing criterion."
    },
    {
      "stageId": "interactions",
      "title": "Desk Signals: event contract and replayable indicator behavior",
      "estimated_effort": "90–150 minutes beyond the selected lessons, estimated",
      "steps": [
        "Write a small event contract with schema version, event ID, elapsed/observed time, source/model version, event type, label and optional score. Define allowed labels and a validity duration. Invent identifiers rather than including personal data.",
        "Specify how the indicator handles an ordinary recognized label, unknown label, missing input, malformed event, stale event, duplicated event, disconnect, reconnect and reset. Keep confidence interpretation in the classifier/decision step; the indicator consumes an explicit decision.",
        "Draw a state machine and make a transition table. An unknown, stale or missing decision should show the neutral/unknown indicator. An explicit disconnected event should show offline. A malformed event should be rejected or enter a defined error state. Manual reset must always have a defined behavior.",
        "Replay the recorded classifier trace manually into the later Wokwi indicator simulation, using the simulator exercise's chosen input mechanism. Do not assume a live network or direct model connection. Add synthetic duplicate, delayed and disconnected cases.",
        "If trying MQTT separately, publish only synthetic test data on the public broker. Understand that QoS 1 can deliver duplicates and that retained messages can replay old state; neither is permission to treat an old command as fresh. Use event IDs and validity checks in the design. An MQTT acknowledgment does not prove a physical action occurred.",
        "Keep a small test log containing initial state, event, expected next state, observed next state and result. Include a reset/recovery path after each failure."
      ],
      "completion_check": "Another person can read the contract and replay at least ten normal/failure events to the same expected states. Include at least one unknown, malformed, stale, duplicate and offline case. State plainly that these checks validate modeled software behavior, not physical reliability or safety.",
      "physical_limit": "Browser and Wokwi work does not measure real sensor noise, actuator power, battery life, thermal behavior, mechanical tolerances, RF coverage or electromagnetic compatibility. Those require later target-specific design and physical testing."
    }
  ],
  "alternatives": [
    {
      "title": "Getting started for beginners",
      "url": "https://docs.edgeimpulse.com/knowledge/guides/getting-started-for-beginners",
      "notes": "Verified official Edge Impulse guide. It says creating an account is free to start, supports importing existing data, and can export inference to a browser. Use only if a learner deliberately chooses an account-based alternative; datasets are handled by a cloud service, so this is not equivalent to local-only Teachable Machine processing. Do not require extra hardware or create an account automatically.",
      "last_checked": "2026-10-20"
    }
  ],
  "verificationNote": "Links and source content were checked on 2026-10-20. Pyodide arithmetic was live-tested. Course accounts, most interactive tools, video playback, networking, CAD exports, model training, and physical builds were not end-to-end tested. Source-specific checks appear with each resource. Access and pricing can change."
}
