---
name: course-audit
description: "Audit or review my course — accessibility audit, full standards, or guided audit + fix. Quick Check (blockers), Deep Audit (accessibility, CRC readiness, pedagogy), or Guided Review."
---

# Course Audit Skill

> **Plugin**: ASU Canvas Course Builder
> **Scripts**: `scripts/criterion_evaluator.py`, `scripts/deterministic_checks.py`, `scripts/alignment_validator.py`, `scripts/link_validator.py`, `scripts/audit_report.py`
> **Standards**: `standards/asu-design-standards.yaml` (25 standards, 173 criteria), `standards/asu-design-standards-enrichment.yaml`
> **Related**: bulk-edit (remediation)

## Purpose

Scan a Canvas course for structural completeness, standards compliance, and content quality. Three modes serve different needs — from a quick pre-launch blocker scan to a full guided remediation session.

## When to Use — Mode Selection

| User says... | Mode |
|---|---|
| "Quick check" / "spot check" / "is this ready?" / "pre-launch check" | **Quick Check** — directly |
| "Full audit" / "deep audit" / "standards audit" / "run the full scan" | **Deep Audit** — directly |
| "Guided review" / "fix issues" / "walk me through" / "audit and fix" | **Guided Review** — directly |
| "Audit my course" / "check my course" (generic) | **Ask** — present 3 options |

**For generic requests**, present an `AskUserQuestion`:

**Question**: "What kind of audit would you like?"

| Label | Description |
|---|---|
| **Quick Check** | Fast blocker scan — navigation, assessments, accessibility, unfinished content (~30 seconds) |
| **Deep Audit** | Full 25-standard review with optional HTML report (~5 minutes) |
| **Guided Review** | Audit + fix issues interactively through staging |

---

## Mode 1: Quick Check

**Purpose**: Fast deterministic scan for launch blockers. No AI. ~25-35 high-signal checks only.

**When to use**: Before handoff, before publishing, or as a quick "did I forget anything?" pass.

### What Quick Check Covers

Quick Check answers exactly 4 questions:

#### 1. Can students navigate and use the course?
- Home page is configured (not default)
- Modules tab is visible in navigation
- Required nav tabs present (Syllabus, Modules, Resources, Accessibility, ASU Course Policies, Time in AZ)
- Module 0 / Getting Started exists with welcome page and syllabus
- No broken core module item links

#### 2. Are graded assessments actually configured?
- All assignments have points > 0
- All graded discussions have points > 0
- Rubrics attached where required (assignments, discussions)
- Assignment groups exist with weights summing to 100%
- Due dates present on graded items
- Quizzes have questions (not empty)

#### 3. Are there obvious accessibility failures?
- Images missing alt text
- H1 tags in page content (Canvas reserves H1)
- Heading level skips (H2 → H4)
- Generic link text ("click here", "read more", "here")
- Broken links / broken images (via `link_validator.py`)

#### 4. Is anything obviously unfinished?
- Empty pages (blank body or whitespace only)
- Placeholder text (TODO, TBD, PLACEHOLDER, Lorem ipsum, [INSERT...], [FACULTY:...])
- Missing required module items vs expected structure

### Quick Check Output

```
═══ Quick Check — [Course Name] ═══

✅ Navigation: 6/6 required tabs present, home page set
⚠️ Assessments: 2 items missing due dates, 1 discussion missing rubric
❌ Accessibility: 4 images missing alt text, 1 heading skip
⚠️ Completeness: 1 page has placeholder text

Blockers: 4 (must fix before launch)
Warnings: 3 (should fix)

Want me to fix these now, or run a full audit?
```

**No report file generated** — Quick Check results are shown in chat only.

### Quick Check Criterion Profile

Quick Check uses `criterion_evaluator.py` with a reduced profile — only the ~25-35 criterion IDs that map to the 4 questions above. This is NOT the full 173-criteria audit.

```bash
${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/criterion_evaluator.py --quick-check
```

---

## Mode 2: Deep Audit

**Purpose**: Full 25-standard review using the two-pass architecture. Deterministic base + AI judgment for qualitative criteria. Optional HTML report.

**When to use**: For thorough quality review, standards compliance verification, or generating a shareable report.

### Two-Pass Architecture

**Pass 1 — Deterministic (automated)**:
Run `criterion_evaluator.py` to evaluate all Col B criteria automatically:
```bash
${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/criterion_evaluator.py --full-audit
```

This produces a JSON result with:
- Every B-criterion evaluated with status (pass/fail/warn), confidence, evidence
- C-criteria flagged as "needs AI review" (not evaluated yet)

**Claude does NOT rebuild the deterministic layer.** The evaluator JSON is authoritative for all deterministic criteria. Claude reads it, does not re-check it.

**Pass 2 — AI Judgment (Claude)**:
For each C-criterion flagged by the evaluator, Claude reads the course content and makes a qualitative judgment:
- C-01.1: Do objectives avoid unmeasurable verbs?
- C-03.1: Are alignment explanations visible to learners?
- C-05.1: Is the tone welcoming and success-oriented?
- etc.

Claude adds its assessment to the result set alongside the deterministic findings.

### Deep Audit Output

After both passes complete, show a summary:

```
═══ Deep Audit — [Course Name] ═══

Standards Compliance:
  ✅ 18/25 standards fully satisfied
  ⚠️ 4 standards have warnings
  ❌ 3 standards have failures

By Category:
  Course Structure:    ★01 ✅  ★02 ✅  03 ⚠️  04 ❌
  Engagement:          05 ✅  ★06 ⚠️  07 N/A
  Assessment:          ★08 ✅  09 ❌  10 ✅  11 ✅
  Content:             ★12 ✅  13 ⚠️  14 ✅  15 ⚠️
  Media & Tech:        16 ✅  17 ✅  18 ⚠️  19 ✅  20 ✅
  Accessibility:       21 ✅  ★22 ❌  ★23 N/A  24 ✅  25 ✅

Findings: [N] failures, [N] warnings, [N] info
```

Then present the output choice:

| Label | Description |
|---|---|
| **Show results only** | Display detailed findings in chat — no file generated |
| **Generate HTML report** | Save a self-contained report to `courses/{id}/reports/` |
| **Fix issues now** | Switch to Guided Review mode for interactive remediation |

### HTML Report Generation

If the user chooses "Generate HTML report":

```bash
${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/audit_report.py --input {evaluator_json} --course-id {COURSE_ID}
```

Report saved to: `courses/{COURSE_ID}/reports/{CourseName}_{date}_AI-Audit.html`

(The `--course-id` flag directs output to the per-course reports directory. Without it, reports go to `reports/` at the plugin root.)

The report includes:
- Per-criterion results with severity badges, confidence, evidence, Canvas links
- Weighted overall score (design 40%, QA 30%, a11y 15%, readiness 15%)
- CLO alignment matrix
- External links audit

---

## Mode 3: Guided Review

**Purpose**: Same audit depth as Deep Audit, but interactive — fix issues as they're found, using ASUCB's staging/push workflow.

**When to use**: When the ID wants to clean up a course in one session.

### Guided Review Workflow

1. **Run the same audit as Deep Audit** (deterministic + AI passes)
2. **Group findings by severity**:
   - Group A: Blockers (FAIL) — must fix
   - Group B: Warnings (WARN) — should fix
   - Group C: Advisory (INFO) — optional
3. **Present Group A first**:
   ```
   ═══ Blockers (5 findings) ═══

   1. [FAIL] Standard 09: Assignment "Module 3 Artifact" missing rubric
      → Fix: Generate rubric via rubric-creator and attach

   2. [FAIL] Standard 22: Page m2-lesson has 3 images without alt text
      → Fix: Add descriptive alt text to each image

   3. [FAIL] Standard 04: No due dates on 4 assignments
      → Fix: Set due dates via course-config skill

   Fix these now?
   ```
4. **For each fix**:
   - Route to the appropriate skill or make the fix directly
   - Stage changes via `staging_manager.py`
   - Show staged preview
   - Push after user approval via `push_to_canvas.py`
   - Verify via `post_write_verify.py`
5. **After Group A**: "Blockers resolved. Continue to warnings, or stop here?"
6. **Present Group B** (same flow)
7. **Present Group C** (same flow)
8. **Summary after completion**:
   ```
   ═══ Guided Review Complete ═══
   Fixed: 5 blockers, 3 warnings
   Remaining: 2 advisory items (skipped)
   All fixes pushed and verified.
   ```

If Guided Review surfaces failed alignment criteria, `/alignment` is the next read-only review step before remediation so CLO/MLO/assessment evidence stays traceable.

### Remediation Safety

All fixes in Guided Review follow ASUCB's standard safety flow:
- Content staged before push (`staging_manager.py`)
- Backup created before overwrite (`backup_manager.py`)
- Push via `push_to_canvas.py` (atomic: backup → push → verify → clear)
- Verification via `post_write_verify.py`

Guided Review does NOT bypass any safety checks. Every fix is a standard staged push.

---

## Accessibility Audit Mode

Use this mode when the user asks whether a course, module, or page is accessible, WCAG compliant, or ready for screen-reader/keyboard users. This mode keeps its WCAG 2.1 AA focus inside `course-audit`.

### WCAG 2.1 AA Check Categories

Run or reproduce the `scripts/audit_pages.py` checks first, then add manual or AI-assisted review where the script cannot decide.

| Category | Required checks |
|---|---|
| Images / WCAG 1.1.1 | Missing `alt`, empty `alt` on non-decorative images, filename alt text, raw LaTeX source as alt text, relevant images incorrectly marked decorative (`alt=""` / `role="presentation"` / `aria-hidden`), decorative images lacking proper marking. For full semantic classification (content-relevant vs decorative), run the `audit_image_alt.py` vision workflow (see Accessibility Scan Procedure step 4). |
| Headings / WCAG 1.3.1, 2.4.6 | H1 in Canvas body content, skipped heading levels, bold/large text used as fake headings, missing or non-descriptive headings |
| Links / WCAG 2.4.4 | Generic link text, bare URLs as link text, identical labels pointing to different URLs, new-window links without a warning |
| Color and contrast / WCAG 1.4.3, 1.4.11 | Inline colors below 4.5:1 for normal text or 3:1 for large text, color used as the only indicator, known low-contrast colors such as `#999`, `#aaa`, and light gray on white |
| Tables / WCAG 1.3.1 | Missing `<th>`, missing `scope`, layout tables, complex tables without captions |
| Media / WCAG 1.2.1-1.2.3 | Video without captions, audio without transcript, auto captions not reviewed, missing expandable transcript block below media |
| Interactive content / WCAG 2.1.1, 4.1.2 | Missing ARIA role or labels, missing keyboard handlers, invisible focus, missing live regions, touch targets below 44x44 px |
| Forms / WCAG 1.3.1, 3.3.2 | Inputs without labels, required fields not indicated, error messages not associated with inputs, submissions without confirmation |
| Document structure / WCAG 1.3.1, 2.4.1 | Meaning conveyed only by formatting, lists not using list markup, broken reading order, missing language markers for foreign text |
| Document and FRAME compliance | Flag PDFs, DOCX, PPTX, and image files for Microsoft Accessibility Checker, Equidox, Canvas Ally, MediaPlus, captions, transcripts, and Canvas Accessibility Checker follow-up |
| External link security and accessibility | `target="_blank"` without `rel="noopener noreferrer"`, missing screen-reader hint, external links that should open in a new tab |

### Accessibility Scan Procedure

1. Fetch the target course/page content from Canvas.
2. Run the fast HTML scanner:
   ```bash
   ${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/audit_pages.py --output audit_report.txt
   ```
3. For media, files, forms, and interactive content, inspect source HTML and file metadata manually.
4. For semantic alt-text quality — classifying each image as content-relevant vs decorative — run the `audit_image_alt.py` manifest-for-agent workflow (Option A). This is a two-step loop:

   **Step 4a — build manifest** (fetches all course images, applies deterministic heuristics, downloads images, writes manifest):
   ```bash
   ${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/audit_image_alt.py --course-id {COURSE_ID} --build-manifest
   ```
   Output: `courses/{COURSE_ID}/reports/vision/alt-manifest.json`

   **Step 4b — Claude vision classification**: Read `alt-manifest.json`. For each image entry where `heuristic_classification` is absent and `cached_classification` is absent, Claude opens the local image file listed in `local_path` and classifies it as `relevant` or `decorative`, plus proposes a descriptive alt if relevant. Write the results to `courses/{COURSE_ID}/reports/vision/alt-classifications.json` — an array of `{image_id, classification, proposed_alt, rationale}` objects.

   **Step 4c — apply verdicts** (applies the deterministic verdict matrix, emits findings to backlog under `a11y.wcag:1.1.1`):
   ```bash
   ${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/audit_image_alt.py --course-id {COURSE_ID} --apply --json
   ```

   **IMPORTANT — proposed alt discipline**: The script proposes alt text as a placeholder string for human review; Claude's proposed alts are flagged for validation. Never auto-apply proposed alt text to Canvas without ID review. The fix classification for relevant images missing/incorrect alt is `guided`, not `auto`.

   Heuristic cases (equation images → relevant; aria-hidden / tiny/spacer / role="presentation" → decorative) are resolved by the script without a vision pass. Cached classifications (sha256-keyed) are reused across runs so only new/changed images require a vision pass.
5. Summarize findings by category, severity, affected pages, and remediation path.

### Accessibility Report Requirements

When generating an interactive HTML report, issue rows must include machine-readable `data-*` attributes: issue id, issue type, severity, affected pages, affected page titles, fix description, fix type (`auto`, `guided`, or `manual`), report type, and course id. Auto/guided issues should include an "Ask Claude to Fix" control and hidden fix panel. Manual issues should include an explicit manual-action note.

### Accessibility Fix Classification

| Issue | Fix type |
|---|---|
| H1 in body, skipped headings, low-contrast known inline colors, table scope, missing `rel="noopener"`, missing new-tab screen-reader hint | `auto` |
| Generic link text | `guided` |
| Relevant image: missing alt, filename alt, raw LaTeX alt, or marked decorative — proposed alt from `audit_image_alt.py` vision workflow, **flagged for ID validation before push** | `guided` |
| Decorative image: missing `alt=""` + `role="presentation"` marking | `guided` |
| Relevant image incorrectly marked decorative (content hidden from AT) | `guided` |
| Video captions, audio transcripts, Ally/SCOUT/document checker results | `manual` |

Auto-fix candidates route to `bulk-edit`, but never bypass staging. **Never auto-apply descriptive alt text to content images** — `audit_image_alt.py` proposes alt text for each relevant image, but proposed alts are placeholders for human review. The ID approves or edits each one before staging. Mark confirmed-decorative images with `alt="" role="presentation"` automatically.

## CRC Mode

Use this mode when the user asks for a Course Readiness Check, pre-launch readiness, or the ID Assistant checklist. This mode presents readiness in the CRC format.

### CRC Categories

| Category | Key checks |
|---|---|
| 1. Navigation Menu | Home, Syllabus, Modules, Resources, Accessibility, ASU Course Policies, Time in AZ; front page targets Welcome/Getting Started; course image/banner set |
| 2. Syllabus Completeness | Course description, credits, instructor contact, communication, CLOs, module objectives, General Studies Gold when applicable, technology requirements, access statement, submission/late/turnaround policies, grade breakdown and scale, academic integrity, generative AI policy, office hours, disclaimer, no outdated tools or dates |
| 3. Canvas Template and Structure | ASU template conventions, module/page naming, Links & Tools or equivalent, Getting Started module, community forum, schedule/important dates, final evaluation reminder |
| 4. Accessibility | Summarize Accessibility Audit Mode results; note Ally and SCOUT as manual verification when applicable |
| 5. Course Component Settings | Due dates, date/syllabus consistency, assignment group weights, correct assignment groups, group naming, no empty groups, assessment settings matching instructions |
| 6. Assessments | Formative practice, variety of graded assessment types, clear instructions, settings/instructions consistency, rubrics attached and populated, quiz shuffle risks, same-type assessment consistency |
| 7. Content, Media, and Page Elements | Videos playable, external URLs valid, documents display, images sized appropriately, external links open as expected, Drive links flagged, media citations, downloadable slide decks, typo/formatting consistency |
| 8. Proctoring | Conditional on config or detected indicators; verify syllabus information, settings/windows, and student instructions |
| 9. Launch Readiness | Course complete, pages/assignments/quizzes/discussions published, module prerequisites appropriate, overall learner-ready judgment |

### CRC Data Fetch

Fetch course metadata, tabs, modules with items, all pages with bodies, syllabus body, assignments with rubric data, quizzes, discussion topics, assignment groups, and `course-config.json` when available. Cross-reference syllabus, dates, grading, and settings against config when possible. Mark unsupported checks as `SKIP` with a note rather than inventing evidence.

### CRC Status Rules

- **READY**: zero FAIL items.
- **NEEDS ATTENTION**: 1-3 FAIL items that can be fixed before launch.
- **NOT READY**: 4+ FAIL items or critical structural gaps.

Report PASS/WARN/FAIL/SKIP/INFO counts by category, manual verification items, FAIL remediation priorities first, WARN priorities second, and a `[FACULTY:` placeholder count. Offer `bulk-edit` only for auto-fixable content issues; structural fixes should name the relevant Canvas API action or skill path.

## Pedagogical Review Mode

Use this mode when the user asks for pedagogy review, instructional design review, a design audit, an expert-eye review, or Quality Matters-style feedback. This mode evaluates quality beyond structural compliance.

**HPI/ID lens — applied automatically** (per CLAUDE.md §Operating Standard: HPI/ID Practitioner). A design audit is an HPI diagnosis, not a rubric tick. Before and during the 8-dimension scoring below, apply `standards/instructional-design.md` **Section 13 (HPI Performance Diagnosis)** — its BEM cell model, the Mager & Pipe skill-vs-will test, and the four-part recommendation contract. Section 13 is the source of truth for the diagnostic procedure; follow it rather than re-deriving it here. The user does not have to ask for this lens; it is the default for this mode.

### Review Dimensions

Score each dimension 1-4 and compute the weighted overall score.

| Dimension | Weight | Evidence |
|---|---:|---|
| Learning Objective Alignment | 15% | `course-config.json`, syllabus, assessment instructions, rubrics |
| Assessment Quality | 20% | Quiz questions, assignment instructions, rubric cells, discussion prompts |
| Content Quality and Accuracy | 15% | Lesson pages, resource links, media descriptions, source attribution |
| Student Experience and Navigation | 10% | Module walkthrough, overview/lesson/conclusion arc, clarity, workload, tone, inclusive framing |
| Engagement and Active Learning | 15% | Interactive activities, discussions, guided practice, self-assessment, variety |
| Accessibility and Inclusion | 10% | Accessibility Audit Mode results, UDL, captions, transcripts, alt text, headings, links |
| Scaffolding and Progression | 10% | Cross-module sequencing, prerequisite concepts, Bloom's progression, bridges between modules |
| Professional/Applied Connections | 5% | Discipline scenarios, career relevance, applied examples, professional task authenticity |

### Tier-Aware Calibration

Before scoring, read `course.tier` from `course-config.json` when available and calibrate the same 1-4 scale against `standards/assessment-best-practices.md`.

- Introductory: a 4 requires thorough, accurate application with examples and complete task coverage.
- Advanced: a 4 requires evidence-based analysis, multiple perspectives, defensible connections, and independent reasoning.
- Graduate: a 4 requires scholarly synthesis across competing frameworks or evidence sources, not polished description alone.

### Pedagogical Review Procedure

1. Prefer live Canvas data: pages, assignments, quizzes, discussions, and modules with items.
2. If live fetch fails, use local artifacts in priority order: `courses/{id}/staging/.course-tree.json`, most recent audit JSON under `courses/{id}/reports/`, then `courses/{id}/content_cache/`.
3. Record the data source in the report header: live Canvas or local cache with inferred date.
4. Review every content module, including pages, assessment content, rubrics, interactives, and media.
5. Run cross-module analysis for Bloom's progression, assessment variety, discussion variety, quality consistency, and CLO coverage.
6. Produce a scored report with strengths, Critical/Important/Enhancement recommendations, module notes, and a CLO-to-assessment alignment matrix.

When a recommendation cites an ASU standard, include the evidence tier from `standards/asu-design-standards-enrichment.yaml` and preserve the standard id/title so the tag is traceable. In standalone mode without `course-config.json`, infer objectives from Canvas content and state that alignment analysis is based on page content only.

## Prerequisites

- Canvas API credentials configured (CANVAS_TOKEN, CANVAS_DOMAIN)
- Course ID (from URL, registry, or user input)
- `standards/asu-design-standards.yaml` present (for criterion definitions)
- `course-config.json` (optional — enables alignment checks and syllabus cross-reference)

## Error Handling

| Error | Resolution |
|---|---|
| Canvas API 401 | Token expired — guide through regeneration |
| Canvas API 403 | Permission denied — check course role |
| No course-config.json | Run without alignment checks; note reduced scope |
| Evaluator script fails | Fall back to chat-native category checks |
| Link validator timeout | Skip link check, note in results |

## Conversion-Readiness Mode

Use this mode when the user asks whether a course is ready to convert from in-person to online, or when they say "conversion audit", "is this course online-ready?", "intake audit for conversion", or "how ready is this for online delivery?".

**Batch-eligible**: returns the `--json` summary for multi-course aggregation.

### What It Detects

7 deterministic detectors — no AI judgment required. Each runs as a pure function against fetched Canvas data:

| # | Detector | Signal | Severity |
|---|---|---|---|
| 1 | Bare media-embed pages (≤40 non-ws chars + iframe/video) | Lecture-capture file cabinet | HIGH |
| 2 | Off-host / fragile video embeds (Drive, Dropbox, personal hosts) | Fragile embeds that break at conversion | HIGH / MEDIUM |
| 3 | Caption/transcript gap (video embed with no transcript/caption link) | Accessibility blocker | MEDIUM |
| 4 | Missing objectives (no Overview page, or Overview lacks `/objectives?/i` heading) | No measurable terminal performance | HIGH |
| 5 | Empty syllabus body | Course not described for students | MEDIUM |
| 6 | No discussion topics | No async interaction layer | MEDIUM |
| 7 | Gradebook junk (0-pt `none` assignments or 0-question quizzes) | Placeholder rows with no learning value | LOW |

### Readiness Signal

| Signal | Meaning |
|---|---|
| **Build, not port** | Any HIGH finding present — structural rebuild required before this course can go online |
| **Conversion-ready with cleanup** | Only MEDIUM / LOW findings — targeted fixes before launch |
| **Online-ready** | Zero findings — course structure is suitable for online delivery |

### Script

```bash
${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 \
  scripts/audit_conversion_readiness.py --course-id {COURSE_ID}
```

Flags:
- `--json` — machine-readable summary `{course_id, score, signal, detectors:{...}}` for batch aggregation
- `--report` — write HTML report to `courses/{id}/reports/{YYYYMMDD-HHmmss}-conversion-readiness.html`
- `--emit-backlog` — persist findings to `backlog_manager.add` (off by default; pass it when user wants findings tracked)

### Procedure

1. Run the script with `--json` to get the structured summary.
2. Show the user the readiness signal, score, and per-detector breakdown in chat.
3. If the user wants findings tracked: rerun with `--emit-backlog`.
4. If the user wants an HTML report: rerun with `--report` and share the path.
5. For batch (multiple courses): pass `--json` per course via the batch subagent pattern; aggregate results into a batch summary.

### Security

All URL/host handling uses exact-host matching — reuses the same guard as `canvas_api._is_canvas_response_url`. Substring tricks (`evil-drive.google.com.attacker.com`) fail closed and are tested. The Canvas token is never attached to off-domain URLs.

---

## Output

The skill produces (depending on mode):
1. **Quick Check**: Chat summary of blockers + warnings
2. **Deep Audit**: Full findings + optional HTML report at `courses/{id}/reports/`
3. **Guided Review**: Interactive remediation with staged fixes + completion summary
4. **Conversion-Readiness**: Readiness signal + score + per-detector findings; optional HTML report and backlog emission
