diff --git a/COMPREHENSION_QUESTIONS.md b/COMPREHENSION_QUESTIONS.md
new file mode 100644
index 0000000..ebec9ba
--- /dev/null
+++ b/COMPREHENSION_QUESTIONS.md
@@ -0,0 +1,415 @@
+# Module 01 — Linux & Command Line · Comprehension Questions
+
+Gating question bank for the LMS. Each question lists options, the correct
+answer, and a one-line rationale for the instructor/feedback panel. Mixed
+recall and applied ("predict the output") items. `[R]` = recall, `[A]` = applied.
+
+---
+
+## Workflow & mindset (gate before Lab 00)
+
+**Q0.1 [R]** In this workspace, what file is the authoritative definition of "done" for an exercise?
+- A. `README.md`
+- B. `solution.sh`
+- C. **`tests/*.bats`**
+- D. `scripts/grade.mjs`
+
+**Answer: C.** The bats test spec defines exactly what your solution must do; the README explains, the solution is your work, the grader just runs the spec.
+
+**Q0.2 [R]** The module's "golden rule" is:
+- A. Always use `sudo` so commands don't fail.
+- B. **Never run a command — or paste one from an AI — that you cannot explain.**
+- C. Prefer GUI tools over the command line when unsure.
+- D. Copy the hint verbatim; it is always correct.
+
+**Answer: B.** Understanding is the deliverable; the green check is only the evidence.
+
+**Q0.3 [A]** You push a commit. The Autograde check goes green only when:
+- A. At least one exercise passes.
+- B. The score is 70% or higher.
+- C. **Every exercise's tests pass AND every `solution.sh` parses cleanly (`bash -n`).**
+- D. You manually approve the run.
+
+**Answer: C.** The grader requires all tests green plus a passing shell-syntax gate.
+
+**Q0.4 [R]** In the "Draft → Verify → Log" AI workflow, why must you never run AI output on a real system unread?
+- A. It runs too slowly.
+- B. **AI is a fast but fallible pair; its output must be verified with the right tool before it touches a system.**
+- C. It always costs money.
+- D. The LMS blocks it.
+
+**Answer: B.** Verify with the matching tool (`shellcheck`, `sshd -t`, a dry-run `find`, `visudo -c`), then log what it got right/wrong.
+
+---
+
+## Lab 00 — Environment
+
+**Q00.1 [R]** Which file do Linux distributions ship so tools and humans can identify the running OS?
+- A. `/etc/hostname`
+- B. **`/etc/os-release`**
+- C. `/proc/version`
+- D. `/etc/motd`
+
+**Answer: B.** `/etc/os-release` is the standard key=value OS-identity file; `PRETTY_NAME` is the human-readable name.
+
+**Q00.2 [A]** Given the line `PRETTY_NAME="Ubuntu 24.04.1 LTS"`, the lab requires you to print exactly `Ubuntu 24.04.1 LTS`. What must your command do that a plain `grep` does not?
+- A. Sort the output.
+- B. **Split on `=` to take the value, then strip the surrounding double quotes.**
+- C. Convert to uppercase.
+- D. Add a trailing newline.
+
+**Answer: B.** e.g. `grep '^PRETTY_NAME=' | cut -d= -f2- | tr -d '"'`.
+
+---
+
+## Lab 01 — Filesystem survey
+
+**Q01.1 [A]** You must find the *largest* file in a tree. Which pipeline is the right shape?
+- A. `ls -l | head -1`
+- B. **`find
-type f -printf '%s %p\n' | sort -rn | head -1`** (or `du`-based equivalent)
+- C. `cat * | wc -c`
+- D. `grep -c . *`
+
+**Answer: B.** List each file with its size, sort numerically descending, take the top line. `ls -l | head` only looks at one directory and isn't sorted by size.
+
+**Q01.2 [R]** To count only regular files (not directories) under a tree, the key predicate is:
+- A. `-name '*'`
+- B. **`-type f`**
+- C. `-perm 644`
+- D. `-maxdepth 0`
+
+**Answer: B.** `-type f` matches regular files; `-type d` matches directories.
+
+---
+
+## Lab 02 — File recovery
+
+**Q02.1 [A]** You need to copy every `*.log` file under a tree into `recovered/`. Which approach is safest and most correct?
+- A. `mv *.log recovered/`
+- B. **`find -type f -name '*.log' -exec cp {} recovered/ \;`**
+- C. `cp *.log recovered/`
+- D. `rm *.log`
+
+**Answer: B.** `find … -name '*.log'` recurses into subdirectories; a bare `*.log` glob only matches the current directory, and `mv`/`rm` would destroy the originals.
+
+**Q02.2 [R]** Before running any destructive `find … -exec` command, the recommended verification step is to:
+- A. Run it as root.
+- B. **Run the `find` with no action first to see exactly which files match.**
+- C. Redirect output to `/dev/null`.
+- D. Add `-f` to force it.
+
+**Answer: B.** Dry-run the match before attaching an action — a core rule from the AI-workflow guide.
+
+---
+
+## Lab 03 — Permissions
+
+**Q03.1 [R]** The octal mode `640` grants which permissions?
+- A. Everyone read/write/execute.
+- B. **Owner read/write, group read, others nothing.**
+- C. Owner read only, group and others read.
+- D. Owner all, group all, others read.
+
+**Answer: B.** `6=rw-`, `4=r--`, `0=---` → `rw-r-----`. Appropriate for a secret readable only by owner and group.
+
+**Q03.2 [A]** "World-writable" means the *others* class has write permission. Which `find` predicate locates world-writable regular files?
+- A. `-perm 777`
+- B. `-perm -444`
+- C. **`-perm -002 -type f`**
+- D. `-writable`
+
+**Answer: C.** `-perm -002` matches any file whose "others" write bit is set, regardless of the other bits. Exact `-perm 777` would miss `666`, `662`, etc.
+
+**Q03.3 [R]** Why is `chmod 777` flagged as risky in this module?
+- A. It is slower than `chmod 755`.
+- B. **It makes a file readable, writable, and executable by *everyone*, including untrusted users — a common security mistake.**
+- C. It only works as root.
+- D. It removes the file.
+
+**Answer: B.** `777` is over-permissive; the AI guide explicitly lists suggesting `chmod 777` as a bad/risky AI habit.
+
+---
+
+## Lab 04 — Users & groups
+
+**Q04.1 [R]** In `/etc/group`, a line looks like `sudo:x:27:alice,bob`. Which field holds the member list?
+- A. Field 1 (group name)
+- B. Field 3 (GID)
+- C. **Field 4 (comma-separated members)**
+- D. Field 2 (password placeholder)
+
+**Answer: C.** Format is `name:passwd:GID:member,member` — members are the 4th colon-separated field.
+
+**Q04.2 [A]** To add user `bob` to the `docker` group *without removing his other groups*, which is correct?
+- A. `usermod -G docker bob`
+- B. **`usermod -aG docker bob`**
+- C. `usermod -g docker bob`
+- D. `groupadd bob docker`
+
+**Answer: B.** `-aG` *appends*; `-G` alone *replaces* all supplementary groups (a classic footgun the AI guide warns about). `-g` sets the primary group.
+
+---
+
+## Lab 05 — Log investigation
+
+**Q05.1 [A]** In a combined-format access log, field 1 is the client IP and field 9 is the HTTP status. Which pipeline finds the busiest client IP?
+- A. `sort access.log | head -1`
+- B. **`awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -1`**
+- C. `grep -c . access.log`
+- D. `awk '{print $9}' | uniq`
+
+**Answer: B.** Extract IPs, group-count with `sort | uniq -c`, then sort by count descending. `uniq -c` requires the input be sorted first.
+
+**Q05.2 [A]** Which condition counts exactly the 4xx and 5xx responses?
+- A. `$9 > 400`
+- B. **`$9 ~ /^[45][0-9][0-9]$/`**
+- C. `$9 == 4 || $9 == 5`
+- D. `$9 ~ /4|5/`
+
+**Answer: B.** Match a 3-digit status beginning with 4 or 5. `$9 ~ /4|5/` would wrongly match `204` or `500`-adjacent noise like `254`.
+
+**Q05.3 [R]** The AI-workflow guide warns that LLMs are unreliable at one specific task relevant to this lab. Which?
+- A. Explaining what a status code means.
+- B. **Counting from large files — they eyeball a sample instead of processing every line.**
+- C. Suggesting `awk`.
+- D. Naming the log format.
+
+**Answer: B.** Always compute counts with a tool; never trust an AI's "about N" tally.
+
+---
+
+## Lab 06 — Pipelines
+
+**Q06.1 [A]** You must both display a status-code tally *and* save every 5xx line to `errors.log`. Which command writes to the file while passing data through?
+- A. `> errors.log`
+- B. **`tee errors.log`**
+- C. `cat errors.log`
+- D. `cp errors.log`
+
+**Answer: B.** `tee` writes stdin to a file *and* forwards it down the pipe, so you can log and keep processing in one pass.
+
+**Q06.2 [A]** In `grep '^5' | tee errors.log | wc -l`, what does `wc -l` count?
+- A. Every line in the original log.
+- B. **Only the 5xx lines that passed through `tee`.**
+- C. The bytes in `errors.log`.
+- D. Nothing; `tee` consumes the stream.
+
+**Answer: B.** `tee` is transparent — the same 5xx lines continue to `wc -l`, which counts them.
+
+---
+
+## Lab 07 — Dotfiles
+
+**Q07.1 [R]** What does "idempotent" mean for the dotfile-symlink task?
+- A. It runs only once ever.
+- B. **Running it repeatedly produces the same end state without errors or duplicates.**
+- C. It requires root.
+- D. It deletes the target each time.
+
+**Answer: B.** A second run should be a safe no-op, not an error or a doubled link.
+
+**Q07.2 [A]** Which check makes `ln -s` idempotent so re-running doesn't error with "file exists"?
+- A. Always `rm -rf` the home directory first.
+- B. **Skip or `-f`/re-create only when the link is missing or points elsewhere (e.g. test with `[ -L "$dest" ]`).**
+- C. Run it inside `sudo`.
+- D. Redirect stderr to `/dev/null` and ignore it.
+
+**Answer: B.** Guard the link creation; silencing errors hides real problems and isn't true idempotency.
+
+---
+
+## Lab 08 — Onboarding script
+
+**Q08.1 [A]** The script must fail early if a required command (e.g. `git`) is missing. Which is the idiomatic check?
+- A. `if [ -f git ]`
+- B. **`if ! command -v git >/dev/null 2>&1; then fail ...; fi`**
+- C. `if git --version`
+- D. `which git || true`
+
+**Answer: B.** `command -v` is the portable "is this command available?" test; the others are fragile or swallow the failure.
+
+**Q08.2 [R]** The starter begins with `set -euo pipefail`. What does the `-e` do?
+- A. Echoes each command.
+- B. **Exits the script immediately if any command returns a non-zero status.**
+- C. Enables extended globbing.
+- D. Encrypts output.
+
+**Answer: B.** `-e` = exit on error, `-u` = error on unset variables, `pipefail` = a pipeline fails if any stage fails. Together they make scripts fail loudly instead of limping on.
+
+---
+
+## Lab 09 — Process management
+
+**Q09.1 [A]** From `ps aux` output, which pipeline finds the PID of the highest-`%CPU` process? (`%CPU` is column 3, PID is column 2.)
+- A. `sort ps.txt | head -1`
+- B. **`sort -rnk3 ps.txt | head -1 | awk '{print $2}'`** (skipping the header)
+- C. `awk '{print $2}' ps.txt | sort -rn`
+- D. `grep CPU ps.txt`
+
+**Answer: B.** Sort numerically-descending on the `%CPU` column, take the top data row, then print its PID field. You must exclude the header row.
+
+**Q09.2 [R]** Why sort with `-n` (numeric) rather than the default?
+- A. It is faster.
+- B. **A lexical sort would rank `9` above `80` because it compares character by character; numeric sort compares magnitudes.**
+- C. `-n` removes duplicates.
+- D. It is required by `ps`.
+
+**Answer: B.** Default `sort` is lexicographic, so `"9" > "80"` — wrong for numbers.
+
+---
+
+## Lab 10 — Networking
+
+**Q10.1 [R]** The `ss -ltn` flags mean, respectively:
+- A. list, tcp, numeric.
+- B. **listening sockets, TCP only, numeric ports (no name resolution).**
+- C. long, text, network.
+- D. loopback, transmit, new.
+
+**Answer: B.** `-l` listening, `-t` TCP, `-n` numeric (don't resolve service names to strings like `ssh`).
+
+**Q10.2 [A]** To list the *unique* listening TCP ports from `ss -ltn` output, you need to:
+- A. Print the whole file.
+- B. **Extract the port from the Local-Address:Port column, then de-duplicate (`sort -u`).**
+- C. Count total lines.
+- D. Reverse-resolve each IP.
+
+**Answer: B.** Parse the address column to isolate the port after the last `:`, then unique them.
+
+---
+
+## Lab 11 — SSH
+
+**Q11.1 [R]** A valid `~/.ssh/config` `Host` block groups connection settings under a host alias. Which is well-formed?
+- A. `Host prod HostName 10.0.0.5 User deploy` (all on one line)
+- B. **A `Host prod` line followed by indented `HostName`, `User`, and `Port` directives.**
+- C. `prod = 10.0.0.5`
+- D. `[prod] host=10.0.0.5`
+
+**Answer: B.** SSH config uses a `Host ` header with indented `Keyword value` lines beneath it; it is not INI or `key=value`.
+
+**Q11.2 [R]** What is the practical benefit of defining a `Host` alias?
+- A. It encrypts the connection more strongly.
+- B. **You can type `ssh prod` instead of the full user/host/port/key each time.**
+- C. It disables password auth automatically.
+- D. It is required for SSH to work.
+
+**Answer: B.** The alias captures HostName, User, Port, IdentityFile, etc., so connections become a single short command.
+
+---
+
+## Lab 12 — Packages
+
+**Q12.1 [A]** Given `wanted.txt` (required packages) and `installed.txt` (installed, one per line), which reports packages that are wanted but *not* installed?
+- A. `cat wanted.txt installed.txt | sort | uniq`
+- B. **`comm -23 <(sort -u wanted.txt) <(sort -u installed.txt)`** (or a `grep -vxf installed.txt wanted.txt`)
+- C. `diff wanted.txt installed.txt`
+- D. `grep -f wanted.txt installed.txt`
+
+**Answer: B.** You want set-difference (wanted minus installed). `comm -23` on sorted inputs, or `grep -vxf` (lines in wanted not matching a whole line in installed), both work. Option D finds the *present* ones — the opposite.
+
+**Q12.2 [R]** Why does a whole-line match (`grep -x`) matter when comparing package names?
+- A. It is faster.
+- B. **So a wanted package like `git` isn't falsely considered installed because `git-lfs` appears in the list.**
+- C. It sorts the output.
+- D. It is required by `apt`.
+
+**Answer: B.** Substring matching would give false "installed" positives; anchor to the full line.
+
+---
+
+## Lab 13 — Scheduling
+
+**Q13.1 [A]** Which crontab line runs a job at 09:00 on weekdays (Monday–Friday)?
+- A. `9 0 * * 1-5`
+- B. **`0 9 * * 1-5`**
+- C. `0 9 1-5 * *`
+- D. `* 9 * * 1-7`
+
+**Answer: B.** Fields are `minute hour day-of-month month day-of-week`. So `0 9 * * 1-5` = minute 0, hour 9, any date/month, weekdays 1–5.
+
+**Q13.2 [R]** The AI guide flags a specific cron mistake LLMs make. Which?
+- A. Using `*` too often.
+- B. **Swapping day-of-month and day-of-week (fields 3 and 5).**
+- C. Forgetting the command.
+- D. Using 24-hour time.
+
+**Answer: B.** Always reason through the five fields yourself or use a cron-expression checker before trusting AI output.
+
+---
+
+## Lab 14 — Resources / storage
+
+**Q14.1 [R]** In `df -P` output, which column is the use percentage you compare against the threshold?
+- A. Column 2 (1024-blocks)
+- B. Column 3 (Used)
+- C. **Column 5 (Use%)**
+- D. Column 6 (Mounted on)
+
+**Answer: C.** `df -P` (POSIX format) guarantees one line per filesystem; field 5 is `Use%` and field 6 is the mount point.
+
+**Q14.2 [A]** The `%` sign in the Use% field is a problem for a numeric comparison. What must you do before comparing to the threshold?
+- A. Multiply by 100.
+- B. **Strip the trailing `%` (e.g. `tr -d '%'` or `sub(/%/,"")`) so it is a plain integer.**
+- C. Convert to hexadecimal.
+- D. Nothing; `[ 85% -gt 80 ]` works.
+
+**Answer: B.** `85%` is a string; you must remove `%` to compare `85 > 80` numerically.
+
+**Q14.3 [R]** Why is `df -P` preferred over plain `df` for a script?
+- A. It shows more filesystems.
+- B. **The POSIX `-P` format keeps each filesystem on a single line with stable columns, so field parsing is reliable.**
+- C. It runs faster.
+- D. It requires root.
+
+**Answer: B.** Long device names can wrap onto two lines in plain `df`; `-P` prevents that, keeping `awk`/`cut` parsing correct.
+
+---
+
+## Capstone — CAP-9000 core (server health check)
+
+**Q15.1 [R]** The gradable capstone core integrates three earlier labs into one report. Which three?
+- A. Environment, SSH, scheduling.
+- B. **Permissions (world-writable), storage (disk over threshold), and packages (missing).**
+- C. Networking, processes, dotfiles.
+- D. File recovery, users, pipelines.
+
+**Answer: B.** It combines lab-03, lab-14, and lab-12 into a `WORLD-WRITABLE / DISK OVER THRESHOLD / MISSING PACKAGES` report.
+
+**Q15.2 [A]** The tests assert the three section headers appear *in a specific order*. What does this tell you about the spec?
+- A. Order never matters in Bash.
+- B. **Output format is part of correctness — you must print the exact headers in the required sequence, not just compute the right findings.**
+- C. You can print them in any order.
+- D. Headers are optional.
+
+**Answer: B.** A correct health check has a predictable, parseable format; the spec grades structure as well as content.
+
+**Q15.3 [R]** The README distinguishes the "gradable core" here from the "full CAP-9000" in the LMS box. Why isn't the full capstone (real `useradd`, hardened `sshd`, systemd timers) graded in this repo?
+- A. It is too easy.
+- B. **Those change real system state and can't be safely or deterministically auto-graded in a shared sandbox; they're verified in your LMS box + engineering notebook.**
+- C. Bats cannot run scripts.
+- D. It is not part of the module.
+
+**Answer: B.** The repo grades the deterministic, sandbox-safe core; system-state work is done and documented in the LMS environment.
+
+---
+
+### Answer key (compact)
+
+Q0.1 C · Q0.2 B · Q0.3 C · Q0.4 B ·
+Q00.1 B · Q00.2 B ·
+Q01.1 B · Q01.2 B ·
+Q02.1 B · Q02.2 B ·
+Q03.1 B · Q03.2 C · Q03.3 B ·
+Q04.1 C · Q04.2 B ·
+Q05.1 B · Q05.2 B · Q05.3 B ·
+Q06.1 B · Q06.2 B ·
+Q07.1 B · Q07.2 B ·
+Q08.1 B · Q08.2 B ·
+Q09.1 B · Q09.2 B ·
+Q10.1 B · Q10.2 B ·
+Q11.1 B · Q11.2 B ·
+Q12.1 B · Q12.2 B ·
+Q13.1 B · Q13.2 B ·
+Q14.1 C · Q14.2 B · Q14.3 B ·
+Q15.1 B · Q15.2 B · Q15.3 B