# Validate Migration Report (Post-Write) > **Read-only validation.** Run immediately after writing `migration-report.html` in `generate-artifacts-report.md` Step 4. Do NOT modify JSON artifacts. **Decision mode:** the same script validates `decision-report.html` (written at the post-Estimate Decision gate, choice A — see `report-decision-core.md`) with `--mode decision`: required sections become the exec set + `decision-cta`, and any `appendix-*` section fails (no Generate artifacts exist at decision time). All other checks (TOC integrity, readability, verdict, baseline rules) apply unchanged. Full mode's contract and `REPORT_OK` output format are unaffected. If validation fails: **rename** the incomplete HTML to `migration-report.incomplete.html` (default — preserves output for inspection), emit failures to the user, and retry report generation. Do **not** delete unless the user asks. The Generate phase still completes (report is optional), but the user MUST see `REPORT_FAIL` — never silently accept a stub report. --- ## How to run (deterministic script path) The validator script ships with the plugin at: `plugins/aws-startup-advisor/scripts/validate-migration-report.py` **Runtime dependency:** Python 3 only. Do not require or recommend Vale, Pa11y, axe, Lighthouse, or browser tooling for skill users. Accessibility and readability checks that matter for this report live inside this script. ```bash python3 "$PLUGIN_ROOT/scripts/validate-migration-report.py" \ "$MIGRATION_DIR/migration-report.html" \ --estimation-infra "$MIGRATION_DIR/estimation-infra.json" \ --estimation-ai "$MIGRATION_DIR/estimation-ai.json" \ --aws-design "$MIGRATION_DIR/aws-design.json" ``` Pass `--estimation-infra` / `--estimation-ai` / `--aws-design` only when those files exist. Flags: - `--migration-dir "$MIGRATION_DIR"` — enables **fixture-bleed detection** on real runs (the reference canary ID must not appear, and the report's migration ID must match the run folder). Omit it when validating the reference fixture itself. - `--no-require-toc` — skip the TOC requirement (for minimal test fixtures only). - `--no-readability` — skip the customer-facing readability checks (escape hatch; not for normal Generate runs). ### Check the exit code — do not pattern-match on stdout text alone The agent must branch on the shell **exit code** of the validator command, not just on whether `REPORT_OK` or `REPORT_FAIL` appears in the text. If `python3` is not on `$PATH` (or the script path is wrong), the shell returns exit code `127` ("command not found") with neither string in its output — parsing for `REPORT_OK`/`REPORT_FAIL` alone leaves that case undefined and produces unpredictable agent behavior. Handle exactly three outcomes: | Exit code | Meaning | Action | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `0` | `REPORT_OK` — validation passed | Proceed to Step 5 | | `1` | `REPORT_FAIL` — validation ran and found issues | Rename to `migration-report.incomplete.html`, surface failure lines to the user, retry report generation | | anything else (e.g. `127` command not found, `126` permission denied, `2` bad arguments) | **Validator did not run** — this is neither `REPORT_OK` nor `REPORT_FAIL` | Do **not** rename or delete the HTML file. Do **not** claim the report passed or failed validation. Tell the user: "Could not run the report validator (``) — install Python 3 (`python3 --version` to check) or verify `$PLUGIN_ROOT` is correct, then re-run validation manually." The Generate phase may still complete with the unvalidated report, but the user must be told validation did not occur — never silently treat a missing interpreter as a pass. | --- ## Scope This validator is a **structural + content + visual-readability completeness gate**. The visual contract is intentionally capability-based rather than pixel-perfect: reports must preserve the shared contrasting page shell, bordered section cards, responsive metric grid, mobile breakpoint, keyboard focus state, and print rules from `generate-artifacts-report.md`. Colors and small spacing refinements may evolve without changing the validator. The validator does **not** verify that every dollar figure in the HTML matches estimation JSON. Self-check item for numeric accuracy in `generate-artifacts-report.md` remains a manual step. `REPORT_OK | structure=complete` means the report is ready for human review, not financially audited. `--no-require-toc` also bypasses the visual-shell contract for deliberately minimal unit fixtures. It is not an escape hatch for normal generated full or decision reports. --- ## Required checks (REPORT_FAIL on any failure) | # | Check | PASS when | | -- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | Section IDs | Each required ID appears **exactly once** on a `
` element (not `
`) | | 2 | Table of contents | `