Resource / agent-built page verification

Browser/Render Smoke Tests for Agent-Built Pages

A practical verification ladder for catching blank renders, broken links, localhost-only assumptions, and missing evidence before anyone says a generated page is ready.

Seven tiersChecklist includedNo formsPublic resource

Public safety status

This staged page follows a completed risk review with a PASS verdict. It intentionally excludes source maps, raw verification internals, private environment paths, credentials, account details, client data, pricing, lead capture, tracking scripts, and deployment actions.

The resource distinguishes local checks, staged review, and public URL smoke. Passing these smoke tests is verification hygiene; it is not a security audit, compliance certification, penetration test, or guarantee.

Who this is for

Audience: builders shipping pages or dashboards from agent workflows.

Use: apply the minimum tiers before review, then add link, private-path, and public URL checks when those conditions apply.

Audience: Builders shipping pages or dashboards from agent workflows.

Promise: Explain why "HTML exists" is not enough, and what minimum verification tiers catch before anyone says ready.

Last updated: 2026-06-27


The problem

Agents can generate HTML files that look complete in source but fail in practice:

None of these are caught by "I wrote the file."

The validation tiers

Smoke testing for agent-built pages moves through seven tiers. Each tier catches failures the previous one misses.

Tier 1: File exists and is non-empty

What it catches: Agent claimed success but wrote nothing, crashed mid-write, or wrote to the wrong path.

Check:

test -s /path/to/output/page.html && echo "OK: file exists and non-empty"

Example:

$ test -s /tmp/agent-output/dashboard.html && echo "OK"
OK
$ wc -c /tmp/agent-output/dashboard.html
8472 /tmp/agent-output/dashboard.html

Why it matters: Agents sometimes report success before the write completes, or write to a scratch workspace and claim a durable path. File existence is the minimum proof the artifact landed.


Tier 2: HTML validates (well-formed)

What it catches: Unclosed tags, broken nesting, missing DOCTYPE, encoding errors that browsers tolerate but tools reject.

Check:

python3 -c "from html.parser import HTMLParser; HTMLParser().feed(open('/path/to/page.html').read())"

Or with xmllint:

xmllint --html --noout /path/to/page.html

Example:

$ xmllint --html --noout /tmp/agent-output/page.html
/tmp/agent-output/page.html:23: parser error : Opening and ending tag mismatch: div line 15 and body

Why it matters: Invalid HTML can render in one browser but break in another, or fail accessibility tools and crawlers. Validation is cheap; cross-browser testing is expensive.


Tier 3: Local HTTP 200 (server smoke)

What it catches: File exists but the server returns 404, 500, or redirect loops. Static file paths are wrong, permissions block access, or the server is not running.

Check:

python3 -m http.server 8888 &
curl -I http://localhost:8888/page.html | head -1

Example:

$ cd /tmp/agent-output && python3 -m http.server 8888 &
$ curl -I http://localhost:8888/dashboard.html | head -1
HTTP/1.0 200 OK

Why it matters: A file on disk is not a page until something serves it. Local HTTP smoke proves the file is reachable through a web server, not just the filesystem. This catches permission errors, wrong document roots, and missing index files.

Caveat: Local HTTP 200 does not prove the page is useful. It only proves the server can deliver bytes.


Tier 4: Screenshot non-blank and legible

What it catches: Page loads but renders blank (JS error, missing assets, CORS block), shows only "Loading..." spinners, or displays console errors that block rendering.

Check:

chromium-browser --headless --screenshot=/tmp/smoke.png http://localhost:8888/page.html
file /tmp/smoke.png
identify /tmp/smoke.png  # ImageMagick

Example:

$ chromium-browser --headless --screenshot=/tmp/dashboard.png http://localhost:8888/dashboard.html
$ file /tmp/dashboard.png
/tmp/dashboard.png: PNG image data, 1920 x 1080, 8-bit/color RGBA
$ identify /tmp/dashboard.png | awk '{print $3, $7}'
1920x1080 245K

Manual check: Open the screenshot. Does it show real content, or a blank white page? Are there visible error messages, broken image icons, or layout collapse?

Why it matters: Headless browsers execute JavaScript, load CSS, and render the DOM. A screenshot proves the page is visually complete, not just syntactically valid. This catches:

Automated non-blank check:

# Count unique colors; blank pages have very few
convert /tmp/smoke.png -format %k info:
# > 100 colors usually means real content

What it catches: Broken internal links, external links that 404, or links pointing to private/localhost paths that will not work in production.

Check:

# Extract all href values
grep -oP 'href="\K[^"]+' /path/to/page.html | sort -u

# Check internal links
for link in $(grep -oP 'href="\K[^"]+' page.html | grep -v '^http'); do
  test -f "/path/to/site/$link" && echo "OK: $link" || echo "BROKEN: $link"
done

# Check external links (slow, rate-limit friendly)
for link in $(grep -oP 'href="\K[^"]+' page.html | grep '^http'); do
  curl -sI "$link" | head -1
done

Example:

$ grep -oP 'href="\K[^"]+' /tmp/agent-output/index.html | sort -u
about.html
contact.html
https://example.com/docs
resources/style.css

$ test -f /tmp/agent-output/resources/style.css && echo "OK" || echo "BROKEN"
BROKEN

Why it matters: Agents often generate links based on assumed directory structures. If the agent writes href="/assets/style.css" but the actual path is href="style.css", the page renders without styling. Link scans catch structural assumptions before deployment.

Private-path scan:

# Flag links that should not be public
grep -E 'href=".*(localhost|127\.0\.0\.1|\.local|/home/|/Users/|file://)' page.html

Tier 6: Private-path and secret scan

What it catches: Agent accidentally included local filesystem paths, API keys, tokens, or internal URLs in the public output.

Check:

# Scan for common secret patterns
grep -E '(api[_-]?key|token|secret|password|AWS_|OPENAI_|sk-)' /path/to/page.html

# Scan for private paths
grep -E '(/home/[a-z]+|/Users/[a-z]+|C:\\Users|file:///)' /path/to/page.html

# Scan for internal URLs
grep -E '(localhost|127\.0\.0\.1|\.local|\.internal)' /path/to/page.html

Example:

$ grep -E '(api[_-]?key|token|secret)' /tmp/agent-output/config.html
Found: <script>const API_KEY = "sk-abc123...";</script>

Why it matters: Agents sometimes copy environment variables, config files, or debug output into generated pages. These leaks are invisible in source review but obvious in a grep scan. Public deployment with embedded secrets is a security incident.

Safe placeholders:

If the page needs example values, use obvious placeholders:

<script>const API_KEY = "YOUR_API_KEY_HERE";</script>

Not:

<script>const API_KEY = "sk-proj-abc123xyz789";</script>

Tier 7: Public URL smoke (when applicable)

What it catches: Page works locally but fails in production due to CDN caching, HTTPS mixed-content blocks, CORS policy changes, or DNS/routing errors.

Check:

# After deployment, verify public URL
curl -I https://example.com/page.html | head -1
curl -s https://example.com/page.html | grep -c '<title>'

Example:

$ curl -I https://www.example.com/resources/guide/ | head -1
HTTP/2 200

$ curl -s https://www.example.com/resources/guide/ | grep -c '<title>'
1

Why it matters: Local verification does not catch production-only failures:

Public URL smoke is the final gate. If the page is not yet deployed, skip this tier and note "public URL unverified" in the completion metadata.


The minimum smoke test

For most agent-built pages, tiers 1-4 are the minimum:

  1. File exists and is non-empty
  2. HTML validates
  3. Local HTTP returns 200
  4. Screenshot shows real content

Tiers 5-7 are required when:

See minimum-smoke-checklist.md for a copy-paste checklist.


Why agents skip these (and why that is wrong)

Agents skip smoke tests because:

  1. The file exists, so it must work. (Tier 1 is necessary but not sufficient.)
  2. I generated valid HTML, so it renders. (Tier 2 does not catch runtime errors.)
  3. I can read the source, so I know it is correct. (Source review does not catch CSS/JS failures.)
  4. The user will test it. (The user hired an agent to avoid manual testing.)

Smoke tests are cheap. A 30-second screenshot check catches blank pages, broken layouts, and console errors. Skipping it means shipping invisible failures and waiting for the user to notice.


What "ready" means

A page is ready for review when:

A page is not ready when:


Tools and commands reference

TierToolCommand
1test, wctest -s file.html && wc -c file.html
2xmllint, Pythonxmllint --html --noout file.html
3curl, http.servercurl -I http://localhost:8888/page.html
4chromium-browser, identifychromium-browser --headless --screenshot=out.png URL
5grep, curlgrep -oP 'href="\K[^"]+' file.html
6grep`grep -E '(api_key\token\secret)' file.html`
7curlcurl -I https://example.com/page.html

Source and context

This resource is based on patterns from agent-built static site deployments, verification reports, and smoke-test workflows. It generalizes local verification discipline into a reusable public checklist.

Related resources:

No private paths, credentials, or live host details are included in this resource.

Minimum smoke checklist

Copy this checklist into the task or completion note before anyone says a generated page is ready.

Use this before anyone says "ready."

Copy this checklist into your task or completion note. Check each tier that applies.


Pre-flight


Tier 1: File exists and is non-empty

Command:

test -s <path-to-file> && wc -c <path-to-file>

Record:


Tier 2: HTML validates (well-formed)

Command:

xmllint --html --noout <path-to-file>

Result: PASS / FAIL

Notes: _______________


Tier 3: Local HTTP 200

Commands:

cd <output-dir> && python3 -m http.server 8888 &
curl -I http://localhost:8888/<filename> | head -1

Result: PASS / FAIL

Status line: _______________


Tier 4: Screenshot non-blank and legible

Commands:

chromium-browser --headless --screenshot=/tmp/smoke.png http://localhost:8888/<filename>
file /tmp/smoke.png

Result: PASS / FAIL

Image dimensions: _______________

Visual check: _______________

Optional automated non-blank check:

convert /tmp/smoke.png -format %k info:
# > 100 unique colours usually means real content

Required when the page has navigation, references, or asset links.

Commands:

# Extract all hrefs
grep -oP 'href="\K[^"]+' <path-to-file> | sort -u

# Flag private/localhost links
grep -E 'href=".*(localhost|127\.0\.0\.1|\.local|file://)' <path-to-file>

Result: PASS / FAIL / SKIPPED

Broken links found: _______________


Tier 6: Private-path and secret scan

Required when the page was generated from config files, environment data, or code repos.

Commands:

grep -E '(api[_-]?key|token|secret|password|AWS_|OPENAI_|sk-)' <path-to-file>
grep -E '(/home/[a-z]+|/Users/[a-z]+|C:\\Users|file:///)' <path-to-file>
grep -E '(localhost|127\.0\.0\.1|\.local|\.internal)' <path-to-file>

Result: PASS / FAIL / SKIPPED

Hits found: _______________


Tier 7: Public URL smoke

Required when the page is deployed or will be deployed without further review.

Commands:

curl -I https://<public-domain>/<path>/ | head -1
curl -s https://<public-domain>/<path>/ | grep -c '<title>'

Result: PASS / FAIL / SKIPPED (not yet deployed)

Status line: _______________


Completion record

TierCheckResult
1File exists, non-empty
2HTML validates
3Local HTTP 200
4Screenshot non-blank
5Link scan
6Secret/private scan
7Public URL smoke

Overall verdict: PASS / FAIL / PARTIAL (list skipped tiers)

Durable path: _______________

File bytes: _______________

SHA-256: _______________

Checked by: _______________

Date: _______________


When to escalate

Stop and ask before proceeding if:

Do not mark "ready" with open failures. Fix or escalate.

Boundary note

This static staged page performs no account, credential, payment, outreach, deployment, provider, gateway, DNS, service, upload, tracking-script, lead-capture, or spend actions. Public URL smoke remains a downstream gate after an approved deploy.

Back to resource index Read the build journal

Last updated: 2026-06-27. Public resource on the Ana & The Goblins resource shelf. Spend: $0.00.