test(phase6d): acceptance suite, real-Lab rehearsal, and 6A/6B resume-point fixes

Adds platform/test/e2e-phase6d.js (20 checks): ROOT 01 hierarchy, ROOT 02-04 honestly empty
(not padded), activity ordering, lab-cannot-be-manually-completed, full course completion via
lesson/lab/assessment, the prerequisite chain proven on two students (one who completed ROOT 01,
one fresh), existing ROOT 05+/Capstone state unaffected, is_required unaffected, self-paced
no-instructor-deferral check, instructor-notes exclusion, RBAC, logout/login persistence,
cross-student isolation, version-bump stability, and content validation. 20/20 pass against both
a warm and a freshly-reset dev stack.

Adds infra/scripts/drills/{run,test}-phase6d-foundations-rehearsal — the real disposable-Lab
dress rehearsal: login -> enroll -> lesson/guided-exercise -> real Lab launch -> real bash
hardware inspection (nproc/free/df, written to a real file) -> real validation -> a genuine
permission denial (a second Linux user actually denied via `su -`) then a real chmod fix ->
remaining modules -> assessment -> course completion -> ROOT 02 unlock -> logout/login
persistence -> instructor visibility of the resulting learning state. 11/11 pass against a real
Lab container, no mocking. (First run caught a real triple-escaping bug in the hardware-report
step's inline heredoc — fixed by writing the script to a file and docker-cp-ing it in instead.)

Fixes two stale hardcoded assumptions in e2e-phase6a.js and e2e-phase6b.js that this phase's own
ROOT 01 addition broke: both suites asserted `resume` landed on ROOT 05's gold module as "the
first real content," which was true before this phase and is now ROOT 01. Both suites' original
intent (resume must never land on a bare-lab bank) is preserved, just against the current front
door. Both suites re-verified green (21/21 and 24/24) against a fresh stack.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-26 13:00:17 -05:00
co-authored by Claude Sonnet 5
parent 15b616274b
commit f5379afd5c
5 changed files with 496 additions and 8 deletions
+6 -2
View File
@@ -126,9 +126,13 @@ async function main() {
assert.equal(moduleById(body.courses, 'root-10-m03-troubleshooting-framework').locked, true, 'must stay locked behind the gold module even though it is a different course-level dependency chain');
});
await test('resume points at ROOT 05\'s new mental-model module, not the old bare-lab bank', async () => {
await test('resume points at ROOT 01 (Phase 6D\'s new front door), not ROOT 05\'s old bare-lab bank', async () => {
// Phase 6D authored ROOT 01 as real, non-PLANNED content sequenced before ROOT 05 — it is
// now genuinely the program's front door (docs/PHASE6D_ROOT_FOUNDATIONS.md). This test's
// original intent — resume must never land on a bare-lab bank when real front-door content
// exists — is unchanged, just against the current front door.
const { body } = await casey.request('GET', `/api/student/programs/${enrollmentId}/courses`);
assert.equal(body.resume.module_id, 'root-05-m00-kubernetes-mental-model');
assert.equal(body.resume.module_id, 'root-01-m01-how-computers-run-software');
});
await test('lesson/knowledge_check completion works identically in a brand-new module (root-05-m00)', async () => {