---
name: verify-contract
description: Evolve scripts/verify.mjs across the Astro migration without losing coverage. Use whenever a verify assertion fails because of a refactor, or when adding checks for new architecture.
---

# The verification contract

Read [`../../context/verification.md`](../../context/verification.md) first.

`verify.mjs` has 42 assertions pinning real content and interactions. They are
the only thing preventing silent content loss during this migration, and they
will all break, because they assert against files that stop existing.

## The rule

**A failing assertion is a question, not a bug to delete.**

```
assertion fails
      ↓
does the user-visible fact it pins still exist?
      ├── yes → re-point the assertion at the new location
      └── no  → you deleted content. Put it back, or get sign-off.
```

`grep -c 'throw new Error' scripts/verify.mjs` must not decrease. If it must,
the `verification-engineer` writes a one-line reason per removal in the task
report. Nobody else may reduce coverage.

## Translating assertions

| Kind | Old | New |
| --- | --- | --- |
| Content presence | `html.includes('data-phase="plan"')` | same token, read from `dist/full-guide/index.html` |
| Implementation detail | `js.includes('renderTree')` | assert the rendered output has the tree UI, not that a function is named that |
| Asset version | `'app.js?v=20260904-vote-widget'` | assert the built HTML references a hashed asset |

Implementation-detail assertions are the dangerous ones: they *look* deletable.
They are pinning a feature. Replace with an output-level assertion of the same
feature; never drop.

## Add the stronger check

Token matching cannot catch a dropped paragraph. Add rendered-text snapshots:

```bash
# before migrating
node .agents/scripts/snapshot-route.mjs http://localhost:4173/models/ > .agents/snapshots/models.txt
# after
node .agents/scripts/snapshot-route.mjs dist/models/index.html | diff .agents/snapshots/models.txt -
```

Commit the snapshots. They are the migration's regression net.

## Extend audit-ui.mjs

It rejects external `<script>`/`<link>` but **misses external URLs inside CSS** —
which is exactly how the broken Google Fonts `@font-face` in `styles.css:1` got
into a "dependency-free" site. Add:

```js
if (/@import|src:\s*url\(['"]?https?:|url\(['"]?https?:/i.test(css))
  throw new Error(`${file} has an external CSS dependency`);
```
