Adds PHASE6D_ROOT_FOUNDATIONS.md (the phase's own record: the generic-scenario-engine finding, the tested container-runtime decision, what was authored, the bugs found and fixed, and honest test/regression/rehearsal results) and ROOT_FOUNDATIONS_PILOT_READINESS.md (module-by-module READY/DEFERRED classification for ROOT 01-04 against the unchanged Phase 6C readiness standard — ROOT 01 READY, ROOT 02-04 DEFERRED by design). Adds ROOT_PROGRAM_DURATION_MODEL.md — real per-course instructional-hour totals computed from actual estimated_duration_minutes values (2,931 minutes / 48.9 hours across all authored content), not invented, with an explicit note on why instructor-led timing isn't a separate summable field yet. Updates ROOT_PROGRAM_ARCHITECTURE.md (ROOT 01's new READY status and the real 01-04 prerequisite chain), ROOT_PILOT_CURRICULUM.md (ROOT 01 added to the pilot, module-level detail), and ROOT_CURRICULUM_COVERAGE_MATRIX.md (updated module/scenario totals) to reflect what Phase 6D actually built, without restating Phase 6C's own Kubernetes-scenario tables. Co-Authored-By: Claude Sonnet 5 <[email protected]>
142 lines
8.3 KiB
Markdown
142 lines
8.3 KiB
Markdown
# Phase 6D — ROOT_ Systems Foundations
|
|
|
|
Phase 6D's mission: build the foundational half of ROOT_ (ROOT 01-04) so a student reaches
|
|
ROOT 05 already fluent in Linux/networking/Git and understanding why Kubernetes exists, using
|
|
the existing course/module/activity model throughout.
|
|
|
|
## Baseline verification
|
|
|
|
Confirmed at start: branch `main`, clean tree, HEAD = `origin/main` =
|
|
`bd0a10fbfb31b05a6264d083f27d85a6f7d5d50c` (the Phase 6C milestone).
|
|
|
|
## The central architectural finding (Section 6/7)
|
|
|
|
`backend/server.js`'s scenario engine (`runCommand()`) executes an arbitrary shell command
|
|
string from a scenario's `setup_commands`/`validation.commands` and checks its output — nothing
|
|
about it is Kubernetes-specific. This means the existing `lab` activity type and
|
|
`scenarios/data/*.json` format already fully support Linux and Git exercises with real,
|
|
deterministic validation. **No `shell_lab`/`git_lab`/`container_lab` activity type was built —
|
|
the speculative multi-type model the authorization raised as a possibility was unnecessary.**
|
|
See `docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md`.
|
|
|
|
## Container runtime decision, tested not assumed (Section 10)
|
|
|
|
Installed Docker Engine (`docker.io` + a static `docker-compose` v2 binary) inside the same
|
|
already-`Privileged: true` Lab container, alongside k3s. This does not weaken the security
|
|
boundary — the Lab Host's own Docker socket is never touched; the nested daemon has its own
|
|
socket inside the guest. Verified empirically against the real production resource caps (2
|
|
vCPU, 4096MB, 512 PIDs): k3s + dockerd + a running `nginx:alpine` container + a real image
|
|
build together used 884MB/4096MB and 160/512 PIDs, comfortable headroom in all dimensions.
|
|
`Dockerfile` and `scripts/entrypoint.sh` updated accordingly (dockerd starts non-blockingly
|
|
alongside k3s; a Docker daemon failure never breaks Kubernetes-only Labs).
|
|
|
|
## ROOT 01 — Computing & Linux Foundations: fully authored, READY
|
|
|
|
6 modules, 35 activities, 29 new content files, 6 new hands-on scenario files
|
|
(`linux-inspect-hardware`, `linux-shell-basics`, `linux-filesystem-navigation`,
|
|
`linux-files-and-text`, `linux-process-management`, `linux-permissions-foundations`) plus 2 MCQ
|
|
scenarios, all using the existing generic scenario/validation engine — no new mechanism. Every
|
|
lab was tested end-to-end via the real scenario API (setup → solve → validate), including
|
|
negative tests confirming they correctly FAIL when not actually solved. A new
|
|
`rootnode-linux-foundations-assessment` (2 required + 4 random-draw scenarios) uses the existing
|
|
Phase 3B engine.
|
|
|
|
## ROOT 02-04: architecture designed, content deferred
|
|
|
|
`docs/ROOT_FOUNDATIONS_ARCHITECTURE.md` designs all remaining 20 modules (6+6+8) in full —
|
|
outcomes, activities, and Real Ops connections for each. Given realistic effort constraints,
|
|
authoring, testing, and verifying ROOT 01 to genuine READY depth was prioritized over shallow
|
|
architecture-only coverage across all four courses (see
|
|
`docs/ROOT_FOUNDATIONS_PILOT_READINESS.md` for the full reasoning). ROOT 02-04 remain honestly
|
|
`status = 'planned'` with zero modules — not padded to look further along than they are.
|
|
|
|
## Course prerequisite chain (Section 19)
|
|
|
|
`courses.prerequisites` now encodes ROOT 01→02→03→04→05 server-side, verified live: a fresh
|
|
student sees ROOT 02 correctly LOCKED (ROOT 01 is real, non-empty content) while ROOT 03/04/05
|
|
stay unlocked (vacuously satisfied — their own prerequisite courses are still empty). Completing
|
|
ROOT 01 unlocks ROOT 02 for that student. ROOT 06+ and the Capstone are completely unaffected
|
|
(re-confirmed via regression). No UI-only hiding — this is a real `courses` table constraint the
|
|
existing `prerequisitesSatisfied()` engine already enforced correctly before this phase; Phase
|
|
6D only populated real data into it.
|
|
|
|
## Extension point for placement/override (Section 20)
|
|
|
|
Documented, not built: `courses.prerequisites` is a plain array a future placement assessment or
|
|
instructor override could satisfy without a schema change. No bypass button implemented.
|
|
|
|
## Frontend (Sections 21-23)
|
|
|
|
No frontend change was needed or made. `CourseView.jsx` and `CurriculumView.jsx` already
|
|
generalized correctly to ROOT 01's activity/status shapes (lesson/demonstration/knowledge_check/
|
|
guided_exercise/lab/reflection/assessment, `ready`/`planned` status, `is_required`,
|
|
`instructor_notes`) — the same generic rendering already proven for ROOT 05-12 in Phase 6C.
|
|
Verified by inspection and by the real API responses `e2e-phase6d.js` and the rehearsal exercise.
|
|
|
|
## New application/platform code and why necessary
|
|
|
|
- `Dockerfile` + `scripts/entrypoint.sh`: the nested Docker Engine described above — a genuine
|
|
platform gap (ROOT 04's course design needs it) that the existing content model couldn't
|
|
satisfy on its own, tested and justified in `docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md`.
|
|
- No other application code. Every ROOT 01 requirement was satisfiable with the existing
|
|
`course_modules`/`module_activities`/`assessment_definitions`/scenario-engine model.
|
|
|
|
## Bugs found and fixed
|
|
|
|
- An early draft of the real-Lab rehearsal's hardware-report step used a triple-nested
|
|
JS-template/shell/heredoc string that silently produced a malformed file. Caught by actually
|
|
running the rehearsal against a real Lab (not assumed to work); fixed by writing the script to
|
|
a file and `docker cp`-ing it in rather than an inline heredoc.
|
|
- Phase 6D's own content changes made two hardcoded assumptions in `e2e-phase6a.js`/
|
|
`e2e-phase6b.js` stale: both suites asserted `resume` pointed at ROOT 05's gold module as "the
|
|
first real content," which was true before this phase and is now ROOT 01. Both suites fixed
|
|
and re-verified green against a fresh stack.
|
|
|
|
## Testing (Section 26)
|
|
|
|
`platform/test/e2e-phase6d.js` — 20/20 passing (fresh stack): ROOT 01 hierarchy, ROOT 02-04
|
|
honestly empty, activity ordering, lab-cannot-be-manually-completed, full course completion via
|
|
lesson/lab/assessment, prerequisite chain (both the locked and unlocked directions, on two
|
|
separate students), existing ROOT 05+ and Capstone state unaffected, is_required rule
|
|
unaffected, self-paced no-instructor-deferral check, instructor-notes exclusion, RBAC, logout/
|
|
login persistence, cross-student isolation, version-bump stability, and content validation.
|
|
|
|
## Real-Lab rehearsal (Section 27)
|
|
|
|
`infra/scripts/drills/test-phase6d-foundations-rehearsal.js` — 11/11 passing against a real
|
|
disposable Lab container (no mocking): login → enroll → resume → lesson/guided-exercise →
|
|
real Lab launch → real bash hardware inspection (`nproc`/`free`/`df`, written to a real file) →
|
|
real validation → real permission-denial-then-fix (`su - labuser`, genuinely denied, then
|
|
genuinely allowed after `chmod 644`) → remaining modules → assessment → course completion →
|
|
ROOT 02 unlock → logout/login persistence → instructor visibility of the resulting state.
|
|
|
|
## Regression (Section 30)
|
|
|
|
Re-ran 6A (21/21), 6B (24/24), 6C (17/17) fresh, each against its own freshly-reset stack per
|
|
the established isolation convention — all green after the two resume-point staleness fixes
|
|
above. 2A/2B/3A/3B/5A/5B/5C were not re-run: `git diff` for this phase shows no changes to
|
|
`platform/api/src/`, gateway, or provisioner code (only the Lab image/entrypoint, migrations,
|
|
content, scenarios, tests, and docs), so their surface area was untouched. Frontend build: clean
|
|
(`vite build`, unchanged this phase). Lab image: rebuilt and standalone-smoke-tested directly
|
|
(see the container runtime section above) in addition to the full-stack rehearsal.
|
|
|
|
## Content validation
|
|
|
|
`infra/scripts/validate-course-content.js` — 0 errors against 17 courses/modules with real
|
|
content, 201 activities, 106 scenario files (98 + 8 new this phase).
|
|
|
|
## Known limitations / intentionally deferred
|
|
|
|
- ROOT 02, 03, 04 course content — architecture designed, not authored.
|
|
- ROOT 04's Docker/Compose hands-on labs specifically — platform extension done and verified,
|
|
course content not yet written against it.
|
|
- Instructor-led vs. self-paced timing is not a separate database field (see
|
|
`docs/ROOT_PROGRAM_DURATION_MODEL.md`).
|
|
- No placement testing or instructor-override UI (explicitly out of scope this phase).
|
|
|
|
## Recommended Phase 6E scope
|
|
|
|
Author ROOT 02 (prioritize the "critical" Networking Mental Model module), then ROOT 03 (Git,
|
|
using the already-verified local-repo strategy), then ROOT 04 (content only — the runtime is
|
|
already built and tested).
|