feat(curriculum): Phase 6C module upgrades, security assessment bank, ROOT 11 orientation

Upgrades six PARTIAL modules to the gold-module standard (lesson/demonstration/
knowledge-check/guided-exercise/lab(s)/reflection), preserving every existing lab
activity_id and scenario_id: root-06-m03 (jobs/cronjobs/daemonsets), root-07-m04
(ingress/networkpolicy), root-07-m02 (configuration/secrets, converted in place
from a bare 5-lab bank), root-09-m02 (serviceaccounts/rbac), root-09-m03
(network/supply-chain security), root-10-m03 (troubleshooting framework).

root-05-m01 (20-task kubectl-fluency bank) gets a minimal bookending lesson +
reflection rather than a full redesign, since each task already carries its own
explanation. root-12-m01, root-capstone-m01, and root-09-m04 are promoted to
READY via documented exceptions (no new activities) where adding one would
misrepresent their intentional design.

Wires a new rootnode-security-assessment (exam, 60min, hint_policy disabled)
using the existing Phase 3B assessment engine: 3 required hands-on CORE
scenarios + 4 random-draw pools covering SecurityContext, RBAC, network
policy, and the 7 previously-unwired CKS MCQs. Wires the previously-unwired
readiness-probe-task scenario as an OPTIONAL practice lab in root-10-m01,
using the existing is_required model.

Adds root-11-m01-devops-platform-thinking — an honest, lesson-only ROOT 11
orientation module naming DevOps/platform engineering practices already
exercised in ROOT 05-10/12, explicit that GitOps/CI-CD/IaC/observability need
lab infrastructure this platform doesn't yet provide. No fake labs.

Adds infra/scripts/validate-course-content.js: cross-checks the DB against
scenario/content files for duplicate ids, orphans, invalid references, cycles,
sequence collisions, instructor-notes leakage, and (new) self-paced content
deferring explanation to a live instructor. 0 errors against the resulting
22 courses/modules, 163 activities, 98 scenario files.

No application code changed — every gap was satisfiable with existing tables
(course_modules, module_activities, assessment_definitions) and the existing
content-delivery pipeline.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-26 11:20:17 -05:00
co-authored by Claude Sonnet 5
parent 2db136875f
commit 7f6e1857c0
26 changed files with 1716 additions and 0 deletions
@@ -0,0 +1,225 @@
-- Phase 6C — curriculum completion, assessment bank, ROOT 11 scope. Additive on top of Phase
-- 6B's 023_phase6b_curriculum.sql. No schema change was needed — is_required (Phase 6B) and
-- the existing assessment_definitions table already cover every genuine Phase 6C requirement.
-- See docs/ROOT_PILOT_READINESS_STANDARD.md for the bar these upgrades were checked against
-- and docs/PHASE6C_CURRICULUM_COMPLETION.md for which modules were upgraded and why.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 1: root-06-m03-jobs-cronjobs-daemonsets — lesson+KC+2labs -> full gold pattern.
-- Existing activities resequenced to make room; scenario_id/activity_type/completion_behavior
-- of every existing row is untouched, so no student's derived completion changes meaning.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = 3, version = version + 1, updated_at = now() WHERE activity_id = 'root-06-m03-a02-knowledge-check';
UPDATE module_activities SET sequence = 5, version = version + 1, updated_at = now() WHERE activity_id = 'root-06-m03-a03-lab-job-task';
UPDATE module_activities SET sequence = 6, version = version + 1, updated_at = now() WHERE activity_id = 'root-06-m03-a04-lab-cronjob-task';
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-06-m03-a01b-demonstration-job-lifecycle', 'root-06-m03-jobs-cronjobs-daemonsets', 2, 'demonstration', 'Demonstration: Watching a Job Actually Complete',
'content/root/root-06-kubernetes-application-workloads/m03-jobs-cronjobs-daemonsets/03-demonstration-job-lifecycle.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-06-m03-a02b-guided-exercise-choosing-primitive', 'root-06-m03-jobs-cronjobs-daemonsets', 4, 'guided_exercise', 'Guided Exercise: Choosing the Right Workload Primitive',
'content/root/root-06-kubernetes-application-workloads/m03-jobs-cronjobs-daemonsets/04-guided-exercise-choosing-primitive.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-06-m03-a05-reflection', 'root-06-m03-jobs-cronjobs-daemonsets', 7, 'reflection', 'Reflection: The Right Primitive Is a Correctness Decision, Not a Style Choice',
'content/root/root-06-kubernetes-application-workloads/m03-jobs-cronjobs-daemonsets/05-reflection.md', NULL, NULL, 'manual_marker', 10, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-06-m03-jobs-cronjobs-daemonsets';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 2: root-07-m04-ingress-networkpolicy-foundations — lesson+KC+2labs -> full gold pattern.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = 3, version = version + 1, updated_at = now() WHERE activity_id = 'root-07-m04-a02-knowledge-check';
UPDATE module_activities SET sequence = 5, version = version + 1, updated_at = now() WHERE activity_id = 'root-07-m04-a03-lab-ingress-task';
UPDATE module_activities SET sequence = 6, version = version + 1, updated_at = now() WHERE activity_id = 'root-07-m04-a04-lab-network-policy';
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-07-m04-a01b-demonstration-ingress-routing', 'root-07-m04-ingress-networkpolicy-foundations', 2, 'demonstration', 'Demonstration: Tracing a Request Through Ingress',
'content/root/root-07-kubernetes-networking-config/m04-ingress-networkpolicy-foundations/03-demonstration-ingress-routing.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-07-m04-a02b-guided-exercise-network-isolation', 'root-07-m04-ingress-networkpolicy-foundations', 4, 'guided_exercise', 'Guided Exercise: Planning Network Isolation',
'content/root/root-07-kubernetes-networking-config/m04-ingress-networkpolicy-foundations/04-guided-exercise-network-isolation-plan.md', NULL, NULL, 'manual_marker', 12, 'ready'),
('root-07-m04-a05-reflection', 'root-07-m04-ingress-networkpolicy-foundations', 7, 'reflection', 'Reflection: Reachability Should Be a Decision, Not a Default',
'content/root/root-07-kubernetes-networking-config/m04-ingress-networkpolicy-foundations/05-reflection.md', NULL, NULL, 'manual_marker', 10, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-07-m04-ingress-networkpolicy-foundations';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 3: root-07-m02-configuration-and-secrets — converted IN PLACE from a bare 5-lab bank
-- into a full teaching module (no new module created; this is the last networking/config
-- module with no front-door teaching, an honest gap Phase 6B's own doc flagged). The 5
-- existing lab activities are untouched (id/scenario_id/type/completion_behavior) other than
-- their sequence number shifting to make room.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = sequence + 4, version = version + 1, updated_at = now() WHERE module_id = 'root-07-m02-configuration-and-secrets';
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-07-m02-a00-lesson-configuration', 'root-07-m02-configuration-and-secrets', 1, 'lesson', 'Externalizing Configuration: ConfigMaps & Secrets',
'content/root/root-07-kubernetes-networking-config/m02-configuration-and-secrets/00-lesson-configuration.md', NULL, NULL, 'manual_marker', 15, 'ready'),
('root-07-m02-a00b-demonstration-secret-not-encrypted', 'root-07-m02-configuration-and-secrets', 2, 'demonstration', 'Demonstration: A Secret Is Encoded, Not Encrypted',
'content/root/root-07-kubernetes-networking-config/m02-configuration-and-secrets/01-demonstration-secret-not-encrypted.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-07-m02-a00c-knowledge-check', 'root-07-m02-configuration-and-secrets', 3, 'knowledge_check', 'Knowledge Check: Configuration & Secrets',
'content/root/root-07-kubernetes-networking-config/m02-configuration-and-secrets/02-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-07-m02-a00d-guided-exercise-choosing-mechanism', 'root-07-m02-configuration-and-secrets', 4, 'guided_exercise', 'Guided Exercise: ConfigMap, Secret, Env Var, or Volume?',
'content/root/root-07-kubernetes-networking-config/m02-configuration-and-secrets/03-guided-exercise-choosing-mechanism.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-07-m02-a99-reflection', 'root-07-m02-configuration-and-secrets', 10, 'reflection', 'Reflection: Configuration Is Infrastructure, Secrets Are a Trust Boundary',
'content/root/root-07-kubernetes-networking-config/m02-configuration-and-secrets/06-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-07-m02-configuration-and-secrets';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 4: root-09-m02-serviceaccounts-and-rbac — lesson+KC+6labs -> full gold pattern.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = 3, version = version + 1, updated_at = now() WHERE activity_id = 'root-09-m02-a02-knowledge-check';
UPDATE module_activities SET sequence = sequence + 2, version = version + 1, updated_at = now() WHERE module_id = 'root-09-m02-serviceaccounts-and-rbac' AND activity_id IN
('root-09-m02-a03-lab-serviceaccount-pod','root-09-m02-a04-lab-automount-token','root-09-m02-a05-lab-rbac-role','root-09-m02-a06-lab-rbac-clusterrole','root-09-m02-a07-lab-rbac-least-privilege','root-09-m02-a08-lab-rbac-clusterrole-independent');
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-09-m02-a01b-demonstration-rbac-denial', 'root-09-m02-serviceaccounts-and-rbac', 2, 'demonstration', 'Demonstration: Watching RBAC Actually Deny Something',
'content/root/root-09-kubernetes-security/m02-serviceaccounts-and-rbac/03-demonstration-rbac-denial.md', NULL, NULL, 'manual_marker', 8, 'ready'),
('root-09-m02-a02b-guided-exercise-least-privilege-role', 'root-09-m02-serviceaccounts-and-rbac', 4, 'guided_exercise', 'Guided Exercise: Writing a Least-Privilege Role',
'content/root/root-09-kubernetes-security/m02-serviceaccounts-and-rbac/04-guided-exercise-least-privilege-role.md', NULL, NULL, 'manual_marker', 12, 'ready'),
('root-09-m02-a09-reflection', 'root-09-m02-serviceaccounts-and-rbac', 11, 'reflection', 'Reflection: Permissions Should Reflect What a Workload Actually Needs',
'content/root/root-09-kubernetes-security/m02-serviceaccounts-and-rbac/07-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-09-m02-serviceaccounts-and-rbac';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 5: root-09-m03-network-and-supplychain-security — lesson+KC+6labs -> full gold pattern.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = 3, version = version + 1, updated_at = now() WHERE activity_id = 'root-09-m03-a02-knowledge-check';
UPDATE module_activities SET sequence = sequence + 2, version = version + 1, updated_at = now() WHERE module_id = 'root-09-m03-network-and-supplychain-security' AND activity_id IN
('root-09-m03-a03-lab-default-deny','root-09-m03-a04-lab-egress-namespace','root-09-m03-a05-lab-egress-networkpolicy-guided','root-09-m03-a06-lab-tls-ingress','root-09-m03-a07-lab-image-pull-secret','root-09-m03-a08-lab-network-policy-metadata-advanced');
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-09-m03-a01b-demonstration-default-deny', 'root-09-m03-network-and-supplychain-security', 2, 'demonstration', 'Demonstration: Default-Deny, Before and After',
'content/root/root-09-kubernetes-security/m03-network-and-supplychain-security/03-demonstration-default-deny.md', NULL, NULL, 'manual_marker', 10, 'ready'),
('root-09-m03-a02b-guided-exercise-egress-plan', 'root-09-m03-network-and-supplychain-security', 4, 'guided_exercise', 'Guided Exercise: Planning Egress Restriction',
'content/root/root-09-kubernetes-security/m03-network-and-supplychain-security/04-guided-exercise-egress-plan.md', NULL, NULL, 'manual_marker', 12, 'ready'),
('root-09-m03-a09-reflection', 'root-09-m03-network-and-supplychain-security', 11, 'reflection', 'Reflection: Reachability and Trust Are Decisions You Make on Purpose',
'content/root/root-09-kubernetes-security/m03-network-and-supplychain-security/09-reflection.md', NULL, NULL, 'manual_marker', 10, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-09-m03-network-and-supplychain-security';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 6: root-10-m03-troubleshooting-framework — lesson+demo+KC+2labs -> full gold pattern
-- (only guided_exercise + reflection were missing).
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = 5, version = version + 1, updated_at = now() WHERE activity_id = 'root-10-m03-a04-lab-crashloop-fix';
UPDATE module_activities SET sequence = 6, version = version + 1, updated_at = now() WHERE activity_id = 'root-10-m03-a05-lab-endpoint-fix';
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-10-m03-a03b-guided-exercise-endpoint-mismatch', 'root-10-m03-troubleshooting-framework', 4, 'guided_exercise', 'Guided Exercise: Applying the Framework to a Broken Service, on Paper First',
'content/root/root-10-kubernetes-troubleshooting-observability/m03-troubleshooting-framework/04-guided-exercise-endpoint-mismatch.md', NULL, NULL, 'manual_marker', 12, 'ready'),
('root-10-m03-a06-reflection', 'root-10-m03-troubleshooting-framework', 7, 'reflection', 'Reflection: A Framework You''ve Actually Used Is One You''ll Trust Under Pressure',
'content/root/root-10-kubernetes-troubleshooting-observability/m03-troubleshooting-framework/06-reflection.md', NULL, NULL, 'manual_marker', 10, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-10-m03-troubleshooting-framework';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Upgrade 7: root-05-m01-pods-and-kubectl-basics — a 20-task kubectl-fluency drill bank with no
-- bookending at all. Each individual task already carries its own explanation (per-scenario
-- description/hints), so the real gap was framing, not per-command teaching: a short lesson
-- explaining WHY this module is 20 independent tasks rather than one narrative, plus a
-- reflection that makes students name their own remaining gaps. All 20 existing lab/MCQ
-- activities are untouched.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-05-m01-a00-lesson-kubectl-fluency', 'root-05-m01-pods-and-kubectl-basics', 0, 'lesson', 'Building kubectl Fluency: Why Twenty Small Reps Beat One Big Lecture',
'content/root/root-05-kubernetes-foundations/m01-pods-and-kubectl-basics/00-lesson-kubectl-fluency.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-05-m01-a21-reflection', 'root-05-m01-pods-and-kubectl-basics', 21, 'reflection', 'Reflection: Naming Your Gaps While They''re Still Cheap to Close',
'content/root/root-05-kubernetes-foundations/m01-pods-and-kubectl-basics/21-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-05-m01-pods-and-kubectl-basics';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- root-09-m04-cluster-hardening-and-runtime — READY via documented exception. Phase 6B already
-- documented this module as deliberately survey-depth ("not core, not daily-driver"). It now
-- has a lesson, two required hands-on labs, two optional deeper labs, and a real timed
-- assessment checkpoint (this migration's security-assessment wiring above) — sufficient for
-- its intentionally lighter scope without forcing a demonstration/guided-exercise pattern that
-- would misrepresent it as core daily-driver content.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-09-m04-cluster-hardening-and-runtime';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- root-capstone-m01-operate-and-recover — READY via documented exception, not new content. Its
-- single 'capstone' activity IS the terminal exam this module exists to deliver; the readiness
-- teaching/prep work already lives in the preceding root-capstone-m02-capstone-readiness module
-- (already READY). Adding a lesson/reflection here would duplicate that module's job.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-capstone-m01-operate-and-recover';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- root-12-m01-real-ops-incidents — READY via documented exception, not new content. Its
-- lesson + 4 deliberately-unguided incidents + reflection IS the intentional shape for this
-- module (see docs/ROOT_PILOT_READINESS_STANDARD.md's flexibility principle and
-- docs/PHASE6C_CURRICULUM_COMPLETION.md for the full reasoning) — a knowledge check or guided
-- exercise here would undermine its explicit "you are responsible for this environment, not
-- handed a hint system" design. No activities added; status promoted to reflect the review.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE course_modules SET status = 'ready', version = version + 1, updated_at = now() WHERE module_id = 'root-12-m01-real-ops-incidents';
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Section 9 — Kubernetes security assessment bank. Wires the 7 previously-unwired CKS MCQs
-- (docs/PHASE6B_ROOT_CURRICULUM_EXPANSION.md's ASSESSMENT-BANK classification) into a real
-- assessment_definition using the EXISTING Phase 3B assessment engine — no new mechanism, no
-- duplicated scenario content. Required scenarios are hands-on CORE labs already in ROOT 09;
-- random pools mix additional hands-on practice with the recall-style MCQs.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
INSERT INTO assessment_definitions (assessment_definition_id, type, title, description, duration_minutes, hint_policy, pool_spec, completion_rule)
VALUES (
'rootnode-security-assessment', 'exam', 'RootNode Kubernetes Security Assessment',
'A timed skills check across Kubernetes security fundamentals: SecurityContext hardening, least-privilege RBAC, NetworkPolicy as a security control, and secrets handling — combining hands-on tasks with conceptual reasoning questions. Example exam definition, following the same pattern as rootnode-quick-assessment.',
60, 'disabled',
'{"required": ["cks-pod-security-context","cks-rbac-least-privilege","cks-network-policy"],
"random": [
{"count":2,"from":["cks-non-root-enforce","cks-drop-capabilities","cks-readonly-filesystem","cks-seccomp-profile"]},
{"count":1,"from":["serviceaccount-pod","cks-automount-token","rbac-role","cks-rbac-clusterrole"]},
{"count":1,"from":["cks-egress-namespace","networkpolicy-egress","cks-tls-ingress","cks-image-pull-secret"]},
{"count":2,"from":["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"]}
]}',
'{"type":"all_scenarios_passed"}'
) ON CONFLICT (assessment_definition_id) DO NOTHING;
-- Given real curriculum visibility as an 'assessment' activity at the end of ROOT 09's
-- advanced/survey module — the natural home for a security checkpoint, not a new module.
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-09-m04-a06-assessment-security', 'root-09-m04-cluster-hardening-and-runtime', 6, 'assessment', 'RootNode Kubernetes Security Assessment', NULL, NULL, 'rootnode-security-assessment', 'auto_assessment', 60, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Section 11/12 — ROOT 11 gets an honest, lesson-only orientation module. No fake labs: the
-- current Lab platform provides Kubernetes/k3s only, not a Git+CI runner, ArgoCD, Terraform, or
-- Prometheus/Grafana environment (docs/ROOT11_DEVOPS_PLATFORM_SCOPE.md documents exactly what
-- would be needed for those). ROOT 11 moves from PLANNED to PARTIAL — real content exists, no
-- longer an unexplained empty placeholder — while staying honest that no hands-on lab exists
-- for this course yet.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE courses SET status = 'partial', updated_at = now() WHERE course_id = 'root-11-devops-platform-engineering';
-- prerequisites is left empty at the MODULE level (course_modules.prerequisites references
-- other MODULE ids, not course ids) — the course-level gate (courses.prerequisites, already
-- 'root-10-kubernetes-troubleshooting-observability' since Phase 6A's 022_course_content.sql)
-- already requires ROOT 10 complete before a student can enter ROOT 11 at all. Found by
-- infra/scripts/validate-course-content.js — an earlier draft of this migration incorrectly
-- put a course id in a module-prerequisites array.
INSERT INTO course_modules (module_id, course_id, title, description, sequence, objectives, prerequisites, estimated_duration_minutes, status) VALUES
('root-11-m01-devops-platform-thinking', 'root-11-devops-platform-engineering', 'From Sysadmin to Platform Thinking',
'DevOps as an operating model, platform engineering, and where Kubernetes fits in the larger platform ecosystem — lesson-only orientation; no hands-on Lab exists for this course yet (see docs/ROOT11_DEVOPS_PLATFORM_SCOPE.md).',
1, '{"Explain DevOps as an operating model rather than a job title","Explain what platform engineering adds on top of DevOps practice","Describe how declarative infrastructure, automation, and feedback loops reduce cognitive load for engineers"}',
'{}', 30, 'partial')
ON CONFLICT (module_id) DO NOTHING;
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES
('root-11-m01-a01-lesson-devops-platform-thinking', 'root-11-m01-devops-platform-thinking', 1, 'lesson', 'DevOps as an Operating Model, Not a Job Title',
'content/root/root-11-devops-platform-engineering/m01-devops-platform-thinking/01-lesson-devops-platform-thinking.md', NULL, NULL, 'manual_marker', 20, 'ready'),
('root-11-m01-a02-knowledge-check', 'root-11-m01-devops-platform-thinking', 2, 'knowledge_check', 'Knowledge Check: DevOps & Platform Thinking',
'content/root/root-11-devops-platform-engineering/m01-devops-platform-thinking/02-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'),
('root-11-m01-a03-reflection', 'root-11-m01-devops-platform-thinking', 3, 'reflection', 'Reflection: Where You Already Practiced This',
'content/root/root-11-devops-platform-engineering/m01-devops-platform-thinking/03-reflection.md', NULL, NULL, 'manual_marker', 10, 'ready')
ON CONFLICT (activity_id) DO NOTHING;
-- ═══════════════════════════════════════════════════════════════════════════════════════════
-- Section 13/14 — readiness-probe-task was an unwired scenario (a constructive "author a
-- readiness probe" Lab) that doesn't duplicate root-10-m01's existing
-- rootnode-probe-port-mismatch Lab (a diagnostic "find the misconfigured probe" task). Wired in
-- as OPTIONAL practice using the existing is_required model (Phase 6B) rather than a second
-- practice system — students who want more probe-authoring reps can do it without it blocking
-- required progression.
-- ═══════════════════════════════════════════════════════════════════════════════════════════
UPDATE module_activities SET sequence = 7, version = version + 1, updated_at = now() WHERE activity_id = 'root-10-m01-a06-reflection-real-ops-takeaway';
INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, is_required, estimated_duration_minutes, status) VALUES
('root-10-m01-a05b-lab-readiness-probe-optional', 'root-10-m01-health-probes-and-troubleshooting', 6, 'lab', 'Optional Practice: Configure a Readiness Probe',
NULL, 'readiness-probe-task', NULL, 'auto_scenario', false, 10, 'ready')
ON CONFLICT (activity_id) DO NOTHING;