docs(phase6b): document curriculum expansion
PHASE6B_ROOT_CURRICULUM_EXPANSION.md — the phase summary: what was authored per course, the is_required extension, the capstone unlock fix, verified scenario coverage before/after (44 -> 88 of 98, 89.8%, by direct query not estimate), and honest known limitations/Phase 6C recommendations. ROOT_CAPSTONE_READINESS.md — the readiness module and the server-side unlock fix in full detail, including why the module's completion and the real assessment's unlock gate are deliberately independent systems. Updated ROOT_CURRICULUM_INVENTORY.md (Phase 6B coverage numbers), ROOT_PROGRAM_ARCHITECTURE.md (ROOT 08/09 PARTIAL, new module lists per course), COURSE_CONTENT_MODEL.md (is_required completion rule, a new content-versioning section per this phase's own requirement), COURSE_AUTHORING_STANDARD.md (classifying near-duplicate/advanced scenarios), ENGINEERING_SOP.md (new Phase 6B section), REMOTE_AND_SELF_PACED_ARCHITECTURE.md (cross-reference), and platform/README.md (e2e-phase6b.js, the Phase 6B rehearsal, isolation- per-suite regression guidance). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -64,6 +64,17 @@ connects what was just taught to the incident the student is about to solve, wit
|
||||
the scenario's own hints/solution — the Lab's own progressive hints stay the only place the
|
||||
actual answer path lives.
|
||||
|
||||
### Classifying near-duplicate or advanced scenarios (Phase 6B)
|
||||
|
||||
When two scenarios teach essentially the same concept (e.g. `pod-security-context` and
|
||||
`cks-pod-security-context`), don't wire both as required core labs — pick the better-fitting one
|
||||
as CORE and mark the other `is_required = false` as INDEPENDENT PRACTICE (see
|
||||
`docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md`'s "duplicate concepts identified" for worked examples).
|
||||
Likewise, a genuinely harder or more niche scenario (CKS-exam-style, a less commonly needed
|
||||
skill) belongs as `is_required = false` GUIDED/ADVANCED practice, not force-fit into the
|
||||
required core path just because it exists — see `docs/COURSE_CONTENT_MODEL.md`'s optional-vs-
|
||||
required section for how this affects module completion.
|
||||
|
||||
## 9. Knowledge check
|
||||
|
||||
A handful of self-check questions with answers shown inline (not a graded exam — that's what the
|
||||
|
||||
@@ -84,6 +84,16 @@ decided, and it never invents new state for anything that's independently verifi
|
||||
Course and module completion are pure aggregates over their activities' completion (`total`/
|
||||
`completed`/`pct`/`complete` — see `totals()`), never separately stored.
|
||||
|
||||
### Optional vs. required activities (Phase 6B)
|
||||
|
||||
`module_activities.is_required` (defaults `true`) lets a module distinguish CORE teaching from
|
||||
GUIDED/INDEPENDENT-practice duplicates and ADVANCED/optional extras — see
|
||||
`docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md`'s classification scheme, used throughout ROOT 09. A
|
||||
module's `complete` flag is true once every REQUIRED activity is done; an incomplete optional
|
||||
activity never blocks it, though `total`/`pct` still count every activity, required or not.
|
||||
Every Phase 6A activity has `is_required = true` (the column's default) — this is purely
|
||||
additive, nothing that was complete before Phase 6B becomes incomplete now.
|
||||
|
||||
## 5. Prerequisite/locking rule
|
||||
|
||||
A course or module lists `prerequisites` (an array of other course/module ids). It's locked if
|
||||
@@ -109,6 +119,40 @@ stop, regardless of its `status`. Use `draft` for genuinely unfinished authoring
|
||||
want a student to see at all yet; use `status = planned` for an honest "not built yet" that's
|
||||
fine to be visible.
|
||||
|
||||
## 6b. Content versioning (Phase 6B §21)
|
||||
|
||||
Follows the exact same convention `assessment_definitions`/`programs` already established — a
|
||||
plain incrementing `version` integer, bumped by hand, informational rather than enforced:
|
||||
|
||||
- **A typo-only edit** (fixing a spelling mistake, a broken link, rewording a sentence without
|
||||
changing its meaning) does NOT require a version bump — nothing about what a student is being
|
||||
taught or held to changed.
|
||||
- **A semantic edit** (changing a learning objective, swapping a lab's `scenario_id`, changing
|
||||
`completion_behavior`, adding/removing/reordering activities in a way that changes what
|
||||
"complete" means) SHOULD bump `version` on the affected row(s) — see
|
||||
`023_phase6b_curriculum.sql`'s own `version = version + 1` on every row it semantically
|
||||
changes (resequencing, prerequisite changes, `is_required` changes).
|
||||
- **What happens to existing completions**: nothing, automatically. Unlike an assessment
|
||||
session (which snapshots the definition version it was drawn against, because a session is a
|
||||
point-in-time timed attempt), a course/module/activity's completion is derived LIVE every time
|
||||
it's read (`course-progress.js`) from the CURRENT row plus the student's progress/achievements/
|
||||
activity_completions — there is no snapshot to invalidate. A `manual_marker` completion
|
||||
(`activity_completions`) is keyed by `activity_id`, which is stable across a version bump
|
||||
(the id doesn't change, only its content/metadata does) — so a student's prior "I did this"
|
||||
record stays valid even after a semantic edit, exactly like editing a scenario's own
|
||||
Markdown description doesn't retroactively un-complete it in `progress`.
|
||||
- **Scenario references across versions**: a `lab` activity's `scenario_id` is just a string
|
||||
reference into `scenarios/data/*.json` — if that scenario file itself changes, the activity
|
||||
automatically reflects the new content next time it's loaded (same as every other consumer of
|
||||
`curriculum.js`'s cache). If an activity's `scenario_id` itself is changed to point at a
|
||||
DIFFERENT scenario, that's a semantic edit (bump the version) and — depending on intent — may
|
||||
warrant a new `activity_id` instead of mutating the existing one, so a student's prior
|
||||
completion of the OLD scenario isn't silently reinterpreted as completion of the new one.
|
||||
- **What this deliberately does NOT build**: no content-revision history table, no diffing, no
|
||||
"students who saw v1 vs v2" cohort tracking. If a future phase needs that level of rigor
|
||||
(e.g. for compliance/audit reasons), it's a real, separate feature — not something to bolt
|
||||
onto a plain integer column.
|
||||
|
||||
## 7. Why this doesn't touch Phase 1-5 systems
|
||||
|
||||
No column was added to `scenarios/*.json`, `assessment_definitions`, `achievements`,
|
||||
|
||||
@@ -461,3 +461,34 @@ Full design: `docs/PHASE6A_ROOT_COURSE_FOUNDATION.md`, plus `docs/ROOT_CURRICULU
|
||||
the gold module's real lesson content, launches a real Lab, the Lab's own `setup_commands`
|
||||
stand up the broken deployment, a real `kubectl patch` fixes it, and the module completes and
|
||||
unlocks the next one) — both against a live stack.
|
||||
|
||||
## 18. ROOT_ Curriculum Authoring & Coverage Expansion (Phase 6B)
|
||||
|
||||
Full design: `docs/PHASE6B_ROOT_CURRICULUM_EXPANSION.md`, plus
|
||||
`docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md` and `docs/ROOT_CAPSTONE_READINESS.md`.
|
||||
|
||||
- **What it is:** 13 new teaching modules across ROOT 05-10/12/Capstone
|
||||
(`023_phase6b_curriculum.sql`), built entirely from the 98-scenario inventory Phase 6A already
|
||||
catalogued — no new scenarios needed. ROOT 08/09 moved from PLANNED to PARTIAL; scenario
|
||||
coverage in structured curriculum went from 44/98 to 88/98 (89.8%), verified by direct query,
|
||||
not estimated. 3 modules (plus the pre-existing gold standard) reach the full READY bar; every
|
||||
other new module is honestly PARTIAL, missing a demonstration or guided exercise, documented
|
||||
per-module rather than glossed over.
|
||||
- **`is_required`** (new `module_activities` column, defaults `true`): distinguishes CORE
|
||||
teaching from GUIDED/INDEPENDENT-practice duplicates and ADVANCED/optional extras — a module
|
||||
is complete once every REQUIRED activity is done; an incomplete optional one never blocks it.
|
||||
Every Phase 6A activity is unaffected (defaults to required).
|
||||
- **The capstone server-side unlock fix:** `POST /api/assessments/:id/start` never checked
|
||||
`unlock_rule` before this phase — a direct API call could start the capstone before its
|
||||
prerequisite stages were complete, even though the UI never exposed that path. Fixed by
|
||||
binding to the same `computeCurriculumState()` gate `GET /api/capstone` already used. See
|
||||
`docs/ROOT_CAPSTONE_READINESS.md` §4 for the full story, including a pre-existing gap this
|
||||
fix exposed in `e2e-phase5b.js`'s own capstone test (fixed alongside).
|
||||
- **Tested, not just designed:** `platform/test/e2e-phase6b.js` (24 checks: new-module
|
||||
hierarchy, prerequisite chains through the newly-inserted front-door modules, the
|
||||
optional-vs-required completion rule, the capstone bypass fix in both directions, persistence/
|
||||
isolation/RBAC/draft-hiding proven against the new content) and
|
||||
`infra/scripts/drills/test-phase6b-root-course-rehearsal.js` (11 checks, real k3s: a student
|
||||
walks a brand-new module — ROOT 07 Services & Service Discovery — end to end including a real
|
||||
`kubectl expose` against a live cluster, plus an instructor narrative proving Curriculum view,
|
||||
Prepare Labs, and classroom tooling all still work against the expanded curriculum).
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# Phase 6B — ROOT_ Curriculum Authoring & Coverage Expansion
|
||||
|
||||
**Status: PHASE 6B COMPLETE. 13 NEW TEACHING MODULES AUTHORED ACROSS ROOT 05-10/12/CAPSTONE.
|
||||
CAPSTONE SERVER-SIDE UNLOCK ENFORCEMENT FIXED. VALIDATED AGAINST A REAL LAB.**
|
||||
|
||||
Phase 6A built the course/module/activity content model and one gold-standard module. Phase 6B
|
||||
is the primary content-authoring phase: real, substantial teaching content across the
|
||||
Kubernetes/operations portion of `root_`, built strictly from the existing 98-scenario
|
||||
inventory — no new scenarios were needed or created (see §7).
|
||||
|
||||
## 1. What was authored
|
||||
|
||||
13 new modules across 7 courses, all evidence-mapped in `docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md`:
|
||||
|
||||
| Course | New module(s) | Depth |
|
||||
|---|---|---|
|
||||
| ROOT 05 | Kubernetes Mental Model & Core Objects | **READY** — full gold-standard pattern |
|
||||
| ROOT 06 | Deployments, Scaling & Updates | **READY** — full gold-standard pattern |
|
||||
| ROOT 06 | Jobs, CronJobs & DaemonSets | PARTIAL — lesson + knowledge check + labs |
|
||||
| ROOT 07 | Services & Service Discovery | **READY** — full gold-standard pattern |
|
||||
| ROOT 07 | Ingress & NetworkPolicy Foundations | PARTIAL — lesson + knowledge check + labs |
|
||||
| ROOT 08 | Storage Fundamentals | PARTIAL — lesson + knowledge check + labs |
|
||||
| ROOT 08 | Scheduling & Resource Governance | PARTIAL — lesson + knowledge check + labs |
|
||||
| ROOT 09 | Security Model & SecurityContext | **READY** — full gold-standard pattern + guided/independent/advanced practice |
|
||||
| ROOT 09 | ServiceAccounts & RBAC | PARTIAL — lesson + knowledge check + labs |
|
||||
| ROOT 09 | Network & Supply Chain Security | PARTIAL — lesson + knowledge check + labs |
|
||||
| ROOT 09 | Cluster Hardening & Runtime Security | PARTIAL — survey-depth lesson + labs |
|
||||
| ROOT 10 | The RootNode Troubleshooting Framework | PARTIAL — lesson + demonstration + knowledge check + labs |
|
||||
| ROOT 12 | Incident-response framing added to the existing Real Ops module | PARTIAL — framework lesson + reflection wrapping the existing incidents |
|
||||
| ROOT Capstone | Capstone Readiness | **READY** — orientation module, see `docs/ROOT_CAPSTONE_READINESS.md` |
|
||||
|
||||
3 modules reach **READY** by the honest bar in `docs/COURSE_AUTHORING_STANDARD.md` (introduction,
|
||||
objectives, concept lesson, demonstration, knowledge check, guided practice, lab, reflection,
|
||||
instructor notes, estimated duration, all present) — plus the pre-existing gold-standard Health
|
||||
Probes module, unchanged. Every other new module is honestly **PARTIAL**: real lesson content
|
||||
and real labs, missing one or more of demonstration/guided-exercise (documented per-module in the
|
||||
coverage matrix, not glossed over).
|
||||
|
||||
ROOT 08 and ROOT 09 moved from **PLANNED** to **PARTIAL** at the course level — real content now
|
||||
exists where Phase 6A left them structurally empty.
|
||||
|
||||
## 2. The is_required extension (Phase 6B, not Phase 6A)
|
||||
|
||||
`module_activities.is_required` (new column, defaults `true` — every Phase 6A activity is
|
||||
unaffected) lets a module distinguish CORE activities from GUIDED/INDEPENDENT-practice
|
||||
duplicates and ADVANCED/optional extras (ROOT 09's CKS-style content, mostly). A module is
|
||||
"complete" once every REQUIRED activity is done — an incomplete optional activity never blocks
|
||||
it, though it still counts toward the displayed percent. See `docs/COURSE_CONTENT_MODEL.md`'s
|
||||
updated completion-rules section.
|
||||
|
||||
## 3. The capstone server-side unlock fix
|
||||
|
||||
Full detail in `docs/ROOT_CAPSTONE_READINESS.md` §4. Summary: `POST /api/assessments/
|
||||
:definitionId/start` previously never checked `unlock_rule` — a direct API call could start the
|
||||
capstone before its prerequisite stages were genuinely complete, even though the UI never
|
||||
exposed a way to trigger this. Fixed by binding to the same `computeCurriculumState()` gate
|
||||
`GET /api/capstone` already used. Found while fixing this: `e2e-phase5b.js`'s own capstone test
|
||||
had been passing only because of this exact gap (it never completed the `real-ops` stage before
|
||||
attempting to start) — fixed alongside the platform code, not routed around.
|
||||
|
||||
## 4. Content quality bar applied honestly
|
||||
|
||||
No module was marked READY merely for having activity rows, headings, or scenario references.
|
||||
The ROOT 08/09 storage/scheduling/security modules are real, substantive lessons with real
|
||||
knowledge checks — but without a demonstration or guided exercise, they're PARTIAL, not READY,
|
||||
by this project's own stated standard. See the coverage matrix for the specific gap in each.
|
||||
|
||||
## 5. Scenario coverage before/after
|
||||
|
||||
Verified by direct query against `module_activities.scenario_id`, not estimated.
|
||||
|
||||
Before Phase 6B: 44 of 98 scenarios wired into structured curriculum (all via Phase 6A's
|
||||
mechanical mapping of `rootnode-path.json`'s existing stages).
|
||||
|
||||
After Phase 6B: **88 of 98 scenarios (89.8%) now in structured curriculum** — 44 newly wired
|
||||
this phase: `deployment-rollback` (added to ROOT 06 m02 as hands-on rollback practice
|
||||
alongside its lesson), `job-task`, `cronjob-task` (ROOT 06 m03); `nodeport-task`,
|
||||
`dns-resolution-mcq` (ROOT 07 m01), `ingress-task`, `network-policy` (ROOT 07 m04);
|
||||
`emptydir-pod`, `pv-pvc-mount`, `pvc-dynamic-task`, `storageclass-mcq` (ROOT 08 m01),
|
||||
`node-label-selector`, `node-taint-toleration`, `pod-affinity-mcq`, `priority-class-task`,
|
||||
`pod-disruption-budget-task`, `resource-quota-ns`, `limitrange-task` (ROOT 08 m02);
|
||||
`cks-non-root-enforce`, `cks-drop-capabilities`, `cks-readonly-filesystem`,
|
||||
`cks-pod-security-context`, `cks-seccomp-profile`, `cks-apparmor-profile`,
|
||||
`pod-security-context` (ROOT 09 m01); `serviceaccount-pod`, `cks-automount-token`, `rbac-role`,
|
||||
`cks-rbac-clusterrole`, `cks-rbac-least-privilege`, `rbac-clusterrole` (ROOT 09 m02);
|
||||
`cks-network-policy`, `cks-egress-namespace`, `cks-tls-ingress`, `cks-image-pull-secret`,
|
||||
`networkpolicy-egress`, `cks-network-policy-metadata` (ROOT 09 m03); `cks-psa-namespace`,
|
||||
`cks-immutable-secret`, `cks-runtime-class`, `cks-audit-policy` (ROOT 09 m04); `crashloop-fix`,
|
||||
`endpoint-fix-task` (ROOT 10 m03), `container-logging-mcq` (ROOT 10 m02, existing bank).
|
||||
|
||||
**10 scenarios remain unwired**, each with a specific, documented reason rather than an
|
||||
oversight: `cluster-upgrade-mcq`, `etcd-backup-mcq` (ROOT 11/DevOps territory, explicitly out of
|
||||
Phase 6B's authoring scope); 7 CKS-style MCQs classified as ASSESSMENT BANK material
|
||||
(`cks-mcq-api-server`, `cks-mcq-audit-policy`, `cks-mcq-kubelet-auth`, `cks-mcq-psp-replacement`,
|
||||
`cks-mcq-runtime-security`, `cks-mcq-sandboxing`, `cks-mcq-image-footprint`) — recall-style
|
||||
questions better suited to a future structured exam pool than hands-on core teaching, flagged
|
||||
for that future use rather than silently dropped; and `readiness-probe-task` — a real, unused
|
||||
candidate for independent practice in ROOT 06 or ROOT 10 that this phase simply didn't get to,
|
||||
honestly left for Phase 6C rather than force-mapped at the last minute. Quality of mapping, not
|
||||
percentage, drove every placement decision — see the coverage matrix's "duplicate concepts
|
||||
identified" section for how near-duplicate scenarios were handled deliberately rather than both
|
||||
force-fit into "core."
|
||||
|
||||
## 6. Knowledge-check and guided-exercise approach
|
||||
|
||||
Every new knowledge check uses scenario-interpretation and reasoning questions ("A Deployment
|
||||
has three replicas but the Service has zero endpoints — which part of the system should you
|
||||
inspect first, and why?"), never "what command was shown two paragraphs ago." Every guided
|
||||
exercise bridges lesson to lab without revealing the lab's answer — modeled directly on the
|
||||
existing gold module's own guided exercise. No new knowledge-check engine capability was needed;
|
||||
the existing Markdown + manual-marker model was sufficient throughout.
|
||||
|
||||
## 7. Why no new scenarios were created
|
||||
|
||||
Every learning objective this phase authored had a suitable existing scenario — the 54-scenario
|
||||
unused bank Phase 6A inventoried was exactly the content Phase 6B needed. No objective was found
|
||||
that genuinely required new hands-on lab content with no existing scenario able to serve it, so
|
||||
no new `rootnode-*` scenario was created this phase (see the authorization's explicit
|
||||
justification bar in its §17 — none of the three required conditions were met for any specific
|
||||
gap identified during authoring).
|
||||
|
||||
## 8. What Phase 6B deliberately did not build
|
||||
|
||||
Per the authorization's explicit scope line: `init_`/`compile_` curriculum, deep authoring of
|
||||
ROOT 01-04 or ROOT 11 (both remain structurally PLANNED, as Phase 6A left them — genuinely no
|
||||
scenario content exists for either), a Parent Portal, payments, public registration, an AI
|
||||
tutor, chat/video/voice, proctoring, a mobile app, certificates, a multi-host scheduler,
|
||||
production deployment changes, an LMS/CMS, a WYSIWYG authoring system, or complex drip
|
||||
scheduling. The Provisioner, Gateway, Lab Router, student/instructor authentication, enrollment
|
||||
architecture, and notification architecture were not redesigned — the one fix made
|
||||
(capstone unlock) was the smallest correct change to the assessment engine's existing route,
|
||||
not a redesign of the engine itself.
|
||||
|
||||
## 9. Test results
|
||||
|
||||
- `e2e-phase6b.js`: **24 passed, 0 failed.**
|
||||
- `test-phase6b-root-course-rehearsal.js` (real k3s Lab, real `kubectl expose`, real classroom
|
||||
tooling): **11 passed, 0 failed.**
|
||||
- Full regression (2A/2B/3A/3B/5A/5B/5C/6A), each run in isolation per the convention Phase 6A
|
||||
established — see the final report for the run-by-run result and the two pre-existing test
|
||||
gaps found and fixed along the way (in `e2e-phase5b.js` and `e2e-phase6a.js`, both caused by
|
||||
this phase's own intentional, documented behavior changes, not by a defect).
|
||||
|
||||
## 10. Known limitations / recommended Phase 6C scope
|
||||
|
||||
- ROOT 06/07/08/09/10's PARTIAL modules are missing a demonstration and/or guided exercise —
|
||||
the natural next authoring pass, module by module, using the 3 READY modules as templates.
|
||||
- ROOT 09's 7 ASSESSMENT-BANK-classified MCQs are inventoried but not yet wired into an actual
|
||||
assessment definition.
|
||||
- ROOT 11 (DevOps & Platform Engineering) remains entirely PLANNED — no scenario content exists
|
||||
anywhere in this repository for CI/CD, IaC, or GitOps concepts; a future phase would need to
|
||||
either author new `rootnode-*` scenarios for it or explicitly scope it out of `root_`.
|
||||
- The Capstone Readiness module's completion is intentionally independent of the real capstone's
|
||||
unlock gate (see `docs/ROOT_CAPSTONE_READINESS.md` §3) — worth revisiting only if a future
|
||||
phase has a concrete reason to couple them, not as a default assumption.
|
||||
@@ -91,7 +91,10 @@ this flow specifically — see the Phase 4.1 report for the full run results.
|
||||
activity tree (lessons, demonstrations, knowledge checks, guided exercises, labs,
|
||||
reflections, assessments/capstone) instead of just a bare scenario id list — the same tree an
|
||||
instructor-led classroom student sees, consumed through the identical `buildCourseTree()`.
|
||||
See `docs/COURSE_CONTENT_MODEL.md` and `docs/PHASE6A_ROOT_COURSE_FOUNDATION.md`.
|
||||
See `docs/COURSE_CONTENT_MODEL.md` and `docs/PHASE6A_ROOT_COURSE_FOUNDATION.md`. **Populated
|
||||
with real teaching content across most of the Kubernetes/operations courses in Phase 6B** —
|
||||
see `docs/PHASE6B_ROOT_CURRICULUM_EXPANSION.md`. The architecture itself (this closed gap)
|
||||
didn't change; what a self-paced student actually finds inside it did.
|
||||
|
||||
## What Phase 4.1 deliberately did NOT do here
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# ROOT Capstone Readiness
|
||||
|
||||
Phase 6B §9/§10 — the instructional runway that prepares a student for the existing
|
||||
`rootnode-capstone` assessment, and the server-side fix that makes its unlock rule actually
|
||||
enforced. This document does not redesign the capstone engine itself (`assessments.js`,
|
||||
`013_assessments.sql`) — see `docs/PHASE3B_LEARNING_AND_ASSESSMENT.md` for that.
|
||||
|
||||
## 1. The Capstone Readiness module
|
||||
|
||||
`root-capstone-m02-capstone-readiness` (sequenced BEFORE the real capstone module,
|
||||
`root-capstone-m01-operate-and-recover`, within the `root-capstone` course) — 4 activities:
|
||||
|
||||
1. **Lesson — What the Capstone Measures & How the Draw Works.** Explains the required-vs-random
|
||||
scenario draw, what "unlocked" means, and what completion records. Never publishes the exact
|
||||
scenario IDs in the current pool or any answer.
|
||||
2. **Lesson — Time Management & Troubleshooting Strategy Under a Clock.** Budgeting the 90
|
||||
minutes, reusing the ROOT 10/ROOT 12 frameworks under pressure, and when to move on from a
|
||||
stuck scenario.
|
||||
3. **Knowledge check — Readiness Check: Are You Actually Ready?** A genuine self-assessment
|
||||
(not a graded quiz) against concrete criteria, pointing back to specific ROOT_ modules for
|
||||
any "no" answer.
|
||||
4. **Reflection — What Completion Means.** Connects passing the Capstone to a durable,
|
||||
demonstrated skill rather than a completion checkbox.
|
||||
|
||||
This module derives its own completion the same way every other lesson-only module does
|
||||
(`activity_completions`, `manual_marker`) — it is intentionally NOT a prerequisite the real
|
||||
capstone assessment engine checks before allowing a start (see §3 below for why these two gates
|
||||
are deliberately independent).
|
||||
|
||||
## 2. What was NOT built
|
||||
|
||||
No answers, no exact scenario IDs from the current pool, no capstone-specific hint content
|
||||
beyond what the Lab's own progressive hints already provide. No new assessment engine, no
|
||||
second capstone, no readiness "score." This is orientation content, not a shadow exam.
|
||||
|
||||
## 3. Why readiness-module completion and the real unlock gate are independent
|
||||
|
||||
The real capstone start (`POST /api/assessments/rootnode-capstone/start`) is gated by the
|
||||
curriculum path's own `unlock_rule` — all 6 content stages of `rootnode-path.json` complete
|
||||
(Foundation, Workloads, Networking, Configuration, Troubleshooting, Real Ops) — computed by
|
||||
`computeCurriculumState()` (`curriculum-rules.js`), the exact same function `GET /api/capstone`
|
||||
already used to display lock state. Whether a student has viewed or completed the Capstone
|
||||
Readiness module has NO bearing on this gate.
|
||||
|
||||
This is deliberate, not an oversight: hard-locking the real assessment behind a CONTENT-MODEL
|
||||
module (course_modules/module_activities) would mean the security-critical enforcement boundary
|
||||
lives in two different systems that could drift out of sync — the curriculum-path unlock_rule
|
||||
(Postgres-backed, achievement-derived, already proven) and the course-content prerequisite chain
|
||||
(newer, additive, built for teaching sequencing rather than security enforcement). Keeping them
|
||||
independent means: the readiness module is free to be completed early, late, or skipped by a
|
||||
student who's already prepared some other way, while the real gate remains exactly as strict as
|
||||
`docs/PHASE3B_LEARNING_AND_ASSESSMENT.md` originally specified.
|
||||
|
||||
## 4. The server-side unlock enforcement fix (Phase 6B §10)
|
||||
|
||||
**The gap** (documented in `docs/PHASE6A_ROOT_COURSE_FOUNDATION.md` §10): `POST /api/assessments/
|
||||
:definitionId/start` (`learning-routes.js`) checked only that the assessment definition existed
|
||||
and was `status = 'active'` — it never checked `unlock_rule` at all. `GET /api/capstone`
|
||||
correctly computed and displayed lock state, and the student UI never exposed a "start" action
|
||||
while locked, but a direct POST to the start route bypassed the check entirely. Student UI state
|
||||
was the only thing standing between a student and an early capstone attempt.
|
||||
|
||||
**The fix**: the start route now resolves whether the requested definition is the curriculum
|
||||
path's OWN configured capstone (`path.stages.find(s => s.type === 'capstone' && s
|
||||
.capstone_assessment_id === definition.assessment_definition_id)`), and if so, computes the
|
||||
exact same `computeCurriculumState()` gate `/api/capstone` already relies on. A `locked` gate
|
||||
now returns a clean `403 { error: 'locked', message, blocking_stage_ids }` — the same
|
||||
`blocking_stage_ids` shape `/api/capstone` already exposes, so a client integrating against this
|
||||
route gets consistent, already-documented error shape rather than a new one. No internal state
|
||||
beyond the stage ids that are actually incomplete is ever returned.
|
||||
|
||||
**What is NOT gated**: any assessment definition the curriculum path does NOT name as its
|
||||
capstone (e.g. `rootnode-quick-assessment`) is completely unaffected — the check only ever
|
||||
triggers for the one definition the path itself points at via `capstone_assessment_id`.
|
||||
|
||||
**What remains valid**: no existing `assessment_sessions` row, no achievement, no enrollment
|
||||
completion record was touched by this fix — it only affects a NEW start attempt going forward.
|
||||
A student who already legitimately completed the capstone before this fix keeps that record
|
||||
exactly as it was.
|
||||
|
||||
**Regression coverage**: `platform/test/e2e-phase6b.js` proves both directions — a direct start
|
||||
attempt before prerequisites are met is rejected (`403 locked`), and a legitimately unlocked
|
||||
attempt (all 6 stages genuinely complete) still succeeds and completes normally. A pre-existing
|
||||
gap was also found and fixed in `e2e-phase5b.js`'s own capstone-completion test, which had never
|
||||
included the `real-ops` stage in its completion loop — it was passing only because the very
|
||||
bug this phase fixes let an incomplete curriculum still start the capstone. See that test file's
|
||||
own comment for detail.
|
||||
@@ -207,3 +207,15 @@ ROOT 07/08/09/10 can draw on in Phase 6B, not content that needs to be invented:
|
||||
- No DevOps/CI/CD/IaC/GitOps scenario content exists (ROOT 11 is necessarily 100% PLANNED).
|
||||
- No Linux-fundamentals, Git, or Docker-specific scenario content exists (ROOT 01-04 are
|
||||
necessarily 100% PLANNED) — everything in `scenarios/data/` is Kubernetes/CKS content.
|
||||
|
||||
## 8. Phase 6B update — scenario coverage after curriculum authoring
|
||||
|
||||
Phase 6B wired 44 more of the scenarios above into structured curriculum (verified by direct
|
||||
query against `module_activities.scenario_id`, not estimated): **88 of 98 scenarios (89.8%)**
|
||||
are now in structured curriculum, up from 44 at the end of Phase 6A. The remaining 10 —
|
||||
`cluster-upgrade-mcq`, `etcd-backup-mcq` (ROOT 11 territory), 7 CKS-style MCQs classified as
|
||||
future ASSESSMENT BANK material, and `readiness-probe-task` (a genuine, documented gap for
|
||||
Phase 6C) — are listed with their specific reasons in
|
||||
`docs/PHASE6B_ROOT_CURRICULUM_EXPANSION.md` §5. The full course-by-course mapping, including
|
||||
which scenarios were classified CORE/GUIDED/INDEPENDENT/ADVANCED/ASSESSMENT-BANK and why, lives
|
||||
in `docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md` — this file is intentionally not duplicated there.
|
||||
|
||||
@@ -9,6 +9,11 @@ All 13 rows below are `courses` under the ONE existing program, `root-kubernetes
|
||||
(`programs` table, unchanged — see §"why one program, not thirteen" below). Every status claim
|
||||
here is grounded in `docs/ROOT_CURRICULUM_INVENTORY.md`, not aspirational.
|
||||
|
||||
**Updated for Phase 6B** (`platform/api/migrations/023_phase6b_curriculum.sql`,
|
||||
`docs/PHASE6B_ROOT_CURRICULUM_EXPANSION.md`): ROOT 08 and 09 moved from PLANNED to PARTIAL, and
|
||||
6 courses gained new teaching modules — the module-level detail and evidence for every new
|
||||
placement lives in `docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md`, not duplicated here.
|
||||
|
||||
## Course sequence
|
||||
|
||||
| # | Course | Status | Why |
|
||||
@@ -17,15 +22,15 @@ here is grounded in `docs/ROOT_CURRICULUM_INVENTORY.md`, not aspirational.
|
||||
| 2 | Linux Administration & Networking | **PLANNED** | Same — no Linux-admin scenario content exists. |
|
||||
| 3 | Git & Collaborative Development | **PLANNED** | No Git scenario content exists. |
|
||||
| 4 | Containers & Docker | **PLANNED** | No Docker-specific scenario content exists (the Lab itself runs k3s, but no student-facing "learn Docker" scenarios exist). |
|
||||
| 5 | Kubernetes Foundations | **PARTIAL** | Real content: the existing "Foundation" stage's 20 scenarios, wrapped as one module (`root-05-m01-pods-and-kubectl-basics`). No teaching lesson content authored yet — bare labs only. |
|
||||
| 6 | Kubernetes Application Workloads | **PARTIAL** | The existing "Workloads" stage's 8 scenarios, one module. Bare labs only. |
|
||||
| 7 | Kubernetes Networking & Configuration | **PARTIAL** | The existing "Networking" (2) and "Configuration" (5) stages, two modules. Bare labs only. |
|
||||
| 8 | Kubernetes Storage & Scheduling | **PLANNED** | Real scenario content exists (PV/PVC, StorageClass, taints/tolerations, PDB — see inventory §5) but is not yet wired into a module. Deliberately left PLANNED rather than fabricating a module shell with no honest content behind it — Phase 6B. |
|
||||
| 9 | Kubernetes Security | **PLANNED** | A substantial 22-scenario CKS-style bank exists (RBAC, PSA, network policy, supply chain, runtime hardening) but is not yet wired into a module — Phase 6B. |
|
||||
| 10 | Kubernetes Troubleshooting & Observability | **PARTIAL** | Contains the Phase 6A gold-standard module (READY) plus the existing "Troubleshooting" stage's remaining 5 scenarios as a second, bare-lab module. |
|
||||
| 11 | DevOps & Platform Engineering Foundations | **PLANNED** | No CI/CD/IaC/GitOps scenario content exists anywhere in this repository. |
|
||||
| 12 | RootNode Real Ops | **PARTIAL** | The existing "RootNode: Real Ops" stage's 4 scenarios (3 RootNode-authored + 1 generic), one module. Bare labs, no teaching content — the gold module already gives one of these four (`rootnode-probe-port-mismatch`) a full teaching treatment elsewhere; this module exercises it again alongside the other three, deliberately (see module notes below). |
|
||||
| 13 | ROOT Capstone — Operate and Recover a Production-Like Environment | **PARTIAL** | The existing, fully working `rootnode-capstone` assessment (90 min, mixed required/random pool). No capstone orientation/briefing lesson authored yet. |
|
||||
| 5 | Kubernetes Foundations | **PARTIAL** | Phase 6B added a READY front-door module (`root-05-m00-kubernetes-mental-model` — full lesson/demo/knowledge-check/guided-exercise/lab/reflection) sequenced before the existing 20-scenario bare-lab bank (`root-05-m01`), which now sits behind it. |
|
||||
| 6 | Kubernetes Application Workloads | **PARTIAL** | Phase 6B added a READY `root-06-m02-deployments-scaling-updates` and a PARTIAL `root-06-m03-jobs-cronjobs-daemonsets`, both in front of the existing bare-lab bank. |
|
||||
| 7 | Kubernetes Networking & Configuration | **PARTIAL** | Phase 6B added a READY `root-07-m03-services-and-service-discovery` and a PARTIAL `root-07-m04-ingress-networkpolicy-foundations`. The existing configuration bank (`root-07-m02`) still has no authored teaching content — an honest, documented gap. |
|
||||
| 8 | Kubernetes Storage & Scheduling | **PARTIAL** | Phase 6B wired the real scenario content the inventory identified (PV/PVC, StorageClass, taints/tolerations, PDB, quotas/limits) into two new PARTIAL modules — moved off PLANNED for the first time. |
|
||||
| 9 | Kubernetes Security | **PARTIAL** | Phase 6B built the 22-scenario CKS-style bank into four modules (Security Model & SecurityContext — READY; ServiceAccounts & RBAC, Network & Supply Chain Security, Cluster Hardening & Runtime — all PARTIAL), classifying scenarios CORE/GUIDED/INDEPENDENT/ADVANCED/ASSESSMENT-BANK rather than exposing them as 22 disconnected tasks — moved off PLANNED. |
|
||||
| 10 | Kubernetes Troubleshooting & Observability | **PARTIAL** | The Phase 6A gold-standard module (READY, unmodified) plus a new PARTIAL `root-10-m03-troubleshooting-framework` (the generalized Observe/Evidence/Hypothesis/Test/Repair/Validate/Prevent framework) and the existing bare-lab bank, now sequenced last. |
|
||||
| 11 | DevOps & Platform Engineering Foundations | **PLANNED** | No CI/CD/IaC/GitOps scenario content exists anywhere in this repository — unchanged, out of Phase 6B's authoring scope. |
|
||||
| 12 | RootNode Real Ops | **PARTIAL** | Phase 6B added an incident-response framing lesson and a post-incident reflection wrapping the existing 4-scenario module — the incidents themselves are unchanged, still deliberately un-guided. |
|
||||
| 13 | ROOT Capstone — Operate and Recover a Production-Like Environment | **PARTIAL** | Phase 6B added a READY Capstone Readiness module (orientation, no answers) sequenced before the existing capstone assessment module — see `docs/ROOT_CAPSTONE_READINESS.md`. |
|
||||
|
||||
No course is marked READY at the course level in Phase 6A — that's honest: a course only earns
|
||||
READY once every module in it has real teaching content, and Phase 6A deliberately built exactly
|
||||
|
||||
+19
-6
@@ -14,7 +14,9 @@ entrypoint/Dockerfile unmodified; frontend bundle gained Phase 3B learning UX, s
|
||||
(Phase 5A), self-paced programs/enrollment + the website integration boundary (Phase 5B), and
|
||||
a provider-neutral enrollment-communications pipeline (activation/enrollment-confirmation/
|
||||
password-reset email, Phase 5C), the ROOT_ course/module/activity content model layered over
|
||||
curriculum/assessments (Phase 6A), and the instructor/admin control plane. No k3s, no
|
||||
curriculum/assessments (Phase 6A) with real teaching content across most of the Kubernetes
|
||||
courses and a server-side capstone unlock enforcement fix (Phase 6B), and the instructor/admin
|
||||
control plane. No k3s, no
|
||||
`--privileged` — this replaced Phase 2A's "identity" instance, which was a full Lab image
|
||||
booting an unused k3s cluster just to serve these APIs. Design:
|
||||
`docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md` (split + Postgres migration),
|
||||
@@ -24,7 +26,8 @@ entrypoint/Dockerfile unmodified; frontend bundle gained Phase 3B learning UX, s
|
||||
`docs/PHASE5B_SELF_PACED_ENROLLMENT.md` (programs, enrollment, website integration boundary),
|
||||
`docs/PHASE5C_ENROLLMENT_COMMUNICATIONS.md` (notifications, email delivery),
|
||||
`docs/PHASE6A_ROOT_COURSE_FOUNDATION.md` (course/module/activity content model, gold-standard
|
||||
module). Operational reference: `api/README.md`.
|
||||
module), `docs/PHASE6B_ROOT_CURRICULUM_EXPANSION.md` (curriculum authoring across ROOT
|
||||
05-10/12/Capstone, the capstone unlock fix). Operational reference: `api/README.md`.
|
||||
- `gateway/` — the only student-facing path to a Lab (HTTP + WebSocket proxy, environment-aware
|
||||
routing derived from a server-controlled session — not a client-suppliable header/param — and,
|
||||
as of Phase 3B, server-side gating of progressive hint reveal). Design:
|
||||
@@ -88,15 +91,25 @@ further instructor accounts from the Instructors tab).
|
||||
- `test/e2e-phase6a.js` — course/module/activity hierarchy and ordering, prerequisite-based
|
||||
locking, all three completion behaviors (manual marker/scenario/assessment-derived), resume,
|
||||
cross-student isolation, RBAC for self-paced (no-cohort) students, and draft-content hiding.
|
||||
- `test/e2e-phase6b.js` — hierarchy for the 13 new modules across ROOT 05-10/12/Capstone,
|
||||
prerequisite chains through the newly-inserted front-door modules, the optional-vs-required
|
||||
(`is_required`) completion rule, and the capstone server-side unlock fix in both directions
|
||||
(a direct bypass attempt rejected, a legitimately unlocked attempt still accepted).
|
||||
|
||||
All e2e suites need `OWNER_EMAIL` / `OWNER_PASSWORD` set to a real bootstrapped instructor
|
||||
account (see "Running the full stack locally" above) — the old `ADMIN_PASSWORD` mechanism is
|
||||
gone. They're slow (real k3s boots, `e2e-phase3b.js` also runs a real API restart) and need the
|
||||
full stack up. None of them substitute for the manual real-Lab-image checks (node-pty, terminal
|
||||
full stack up. Run each suite against its own freshly-reset stack, not chained one after another
|
||||
against the same Postgres — several routes (the admin dashboard's running-lab count, a course's
|
||||
percent-complete) read GLOBAL state on purpose, and chaining suites produces false failures from
|
||||
shared state, not real regressions (found and documented during Phase 6A's own regression pass).
|
||||
None of them substitute for the manual real-Lab-image checks (node-pty, terminal
|
||||
WebSocket, `kubectl`, scenario validation) in `docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md` §8 —
|
||||
those need a browser-equivalent client and aren't automated here. The one exception is Phase
|
||||
6A's gold-standard module, which DOES get a real-Lab dress rehearsal —
|
||||
`infra/scripts/drills/run-phase6a-course-rehearsal.sh`.
|
||||
those need a browser-equivalent client and aren't automated here. Two exceptions get a real-Lab
|
||||
dress rehearsal instead: Phase 6A's gold-standard module
|
||||
(`infra/scripts/drills/run-phase6a-course-rehearsal.sh`) and Phase 6B's curriculum expansion,
|
||||
including a real `kubectl expose` and a real instructor/classroom narrative
|
||||
(`infra/scripts/drills/run-phase6b-root-course-rehearsal.sh`).
|
||||
|
||||
## Known limitations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user