Skip to content

feat(learning): validator execution engine and learning API#58

Merged
Derssa merged 4 commits into
mainfrom
feat/learning-validation-engine
Jul 14, 2026
Merged

feat(learning): validator execution engine and learning API#58
Derssa merged 4 commits into
mainfrom
feat/learning-validation-engine

Conversation

@OthmaneZ05

@OthmaneZ05 OthmaneZ05 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Summary of Changes

The execution side of the roadmap format introduced in #54: a stateless engine that runs a step's declarative validators against the real state of a project's containers, so a learner's work can be auto-checked. Until now, roadmap files declared validators but nothing executed them.

New endpoints:

  • GET /api/learning/roadmaps — catalogue of the valid roadmap files in roadmaps/ (invalid files are logged server-side and never served)
  • GET /api/learning/roadmaps/:id — full roadmap
  • POST /api/learning/validate{projectId, roadmapId, stepId} → one structured result per validator (pass / fail / error + message + optional expected/observed) and an aggregated stepPassed

Design notes:

  • Pedagogical failure vs infrastructure error are distinct. fail means the learner hasn't completed the step yet; error means the check itself couldn't run (Docker daemon down, unknown validator type, bad params in the roadmap file) and carries an errorCode reusing the existing dockerErrors taxonomy. Infrastructure failures answer 200 with per-validator error results — 4xx/5xx are reserved for request problems.
  • A broken validator never blocks the others: each validator of a step is isolated, so an unknown type (e.g. a roadmap written for a newer Torollo) still lets the remaining checks report.
  • One extension point. Adding a validator type = one file under engine/validators/ + one line in engine/registry.ts (recipe in docs/learning-api.md). This PR ships the first one, container_running; the rest of the v1 palette comes next.
  • Nothing from a roadmap file is ever executedparams are inert JSON interpreted by code in this repo.
  • The container list is fetched lazily and memoized per run (one Docker call per step), and roadmap files are re-read per request, resolved from __dirname (the CLI spawns the server without a cwd). roadmaps/ is now shipped in the published npm package so the catalogue isn't empty in production.

Full contract, semantics and a curl walkthrough: docs/learning-api.md.

Types of Changes

  • New feature / node type addition
  • Bug fix (non-breaking change resolving an issue)
  • Refactoring / structural cleanup
  • Documentation update

Verification & Testing

Automated Checks

  • Run npm run lint successfully with no errors
  • Run npm run build successfully with no compilation errors
  • Run npm test successfully (all tests pass)

Manual Verification

Ran the full loop against real containers with the backend in dev mode and Docker running:

  1. Created a project, then POST /api/learning/validate on the example roadmap's first step before creating anything → status: "fail" with an actionable message ("No container named "web" exists in this project yet…").
  2. Created and started the web node via the containers API, re-validated → status: "pass", stepPassed: true.
  3. Stopped the container, re-validated → fail with observed: "exited".
  4. Validated a step mixing an implemented and a not-yet-implemented validator type → the unknown type reports error/UNKNOWN_VALIDATOR while the other validator still returns its verdict.
  5. Checked the request-error paths: unknown project/roadmap/step → typed 404s, missing body field → 400.
  6. GET /api/learning/roadmaps lists the example roadmap with stepCount: 4.

Checklist

  • My code follows the repository's code style and lint standards
  • I have updated the documentation or instructions if necessary
  • All unit and integration tests are passing

Runs the declarative validators of a roadmap step against the real state
of the project's containers. Dispatch by type through a single registry,
per-validator error isolation (an unknown type, invalid params or an
unreachable Docker daemon produce an 'error' result for that validator
and the others still run), infrastructure errors classified through the
existing dockerErrors taxonomy, and a lazy memoized container list (one
Docker call per step run). Ships the first validator, container_running.
- GET /api/learning/roadmaps — catalogue of the valid roadmap files
  found in roadmaps/ (invalid files are logged and never served)
- GET /api/learning/roadmaps/:id — full roadmap for the player
- POST /api/learning/validate — runs every validator of a step for a
  project and returns one structured result per validator
  ({status, message, errorCode?, expected?, observed?} + stepPassed)

Roadmap files are re-read on each request (hot reload for authors) and
resolved from __dirname, never process.cwd(): the CLI spawns the server
without a cwd. Infrastructure failures answer 200 with per-validator
'error' results — 4xx/5xx are reserved for request problems.
The learning engine loads roadmap files from roadmaps/ at the repo
root; without this entry the published CLI would start with an empty
catalogue.
Contract of the three /api/learning endpoints for the player (P-1/P-2):
pass/fail/error semantics and their intended UI mapping, errorCode
table, the 'Docker down answers 200 with error results' policy, a curl
walkthrough (pass and fail) against the example roadmap, and the recipe
for adding a validator type.
@OthmaneZ05
OthmaneZ05 requested a review from Derssa as a code owner July 14, 2026 17:31
@Derssa
Derssa merged commit ee0055a into main Jul 14, 2026
2 checks passed
@Derssa
Derssa deleted the feat/learning-validation-engine branch July 14, 2026 17:56
OthmaneZ05 added a commit that referenced this pull request Jul 18, 2026
* feat(learning): add the validator execution engine

Runs the declarative validators of a roadmap step against the real state
of the project's containers. Dispatch by type through a single registry,
per-validator error isolation (an unknown type, invalid params or an
unreachable Docker daemon produce an 'error' result for that validator
and the others still run), infrastructure errors classified through the
existing dockerErrors taxonomy, and a lazy memoized container list (one
Docker call per step run). Ships the first validator, container_running.

* feat(learning): expose roadmap loading and step validation over REST

- GET /api/learning/roadmaps — catalogue of the valid roadmap files
  found in roadmaps/ (invalid files are logged and never served)
- GET /api/learning/roadmaps/:id — full roadmap for the player
- POST /api/learning/validate — runs every validator of a step for a
  project and returns one structured result per validator
  ({status, message, errorCode?, expected?, observed?} + stepPassed)

Roadmap files are re-read on each request (hot reload for authors) and
resolved from __dirname, never process.cwd(): the CLI spawns the server
without a cwd. Infrastructure failures answer 200 with per-validator
'error' results — 4xx/5xx are reserved for request problems.

* chore: ship the roadmaps directory in the published npm package

The learning engine loads roadmap files from roadmaps/ at the repo
root; without this entry the published CLI would start with an empty
catalogue.

* docs: document the learning validation API

Contract of the three /api/learning endpoints for the player (P-1/P-2):
pass/fail/error semantics and their intended UI mapping, errorCode
table, the 'Docker down answers 200 with error results' policy, a curl
walkthrough (pass and fail) against the example roadmap, and the recipe
for adding a validator type.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants