NEXT.JS SITEMAP LAB — REPRODUCTION
Synthetic fixture for local use only. Requires Node/npm and Python 3. Tested Node v25.2.1 and Python 3.9.6 on macOS. npm scripts use POSIX environment assignments; on Windows use WSL or an equivalent POSIX shell. Ports 8800/8801/8802 must be free. Do not expose these servers publicly.

1. Extract into an empty directory. The fixture includes a pinned package lock.
2. In terminal A at the extraction root: python3 feed.py
3. In terminal B: cd fixture; npm ci --ignore-scripts; npm run dev
4. In terminal C: cd fixture; npm run build; npm run start
5. Wait for both Next.js servers to report Ready. In terminal D at the extraction root: python3 collect.py
6. Inspect observations.json and evidence/. The collector checks frozen source hashes and refuses to overwrite an existing observations.json. For another run, use a fresh extraction. Stop all three servers with Ctrl+C when finished.

Expected rows: 28 sitemap responses + 36 listed responses + 2 source preflight responses. Fault responses are deliberate: dynamic-bad 500; /sitemaps/catalog.xml 404; /products/retired 404. The checked fetch throws for the missing feed. Corrected source/route variants return 200. stale-after contains one product because the unpublished record was removed.

The feed returns two fictional records. Sitemaps and loc requests are restricted to exact local origins; the collector does not follow redirects. No live websites are crawled. XML parsing is structural, not XSD validation. The fixture product pages are noindex/nofollow. This fixture tests availability only.

Install/build were performed cleanly for the primary experiment. The downloadable archive is checked against that frozen source. A subsequent archive replay reuses the same running servers; it is not an independent fresh server installation.
