Deploy the project site
Build the allowlisted marketing site, docs, and observe-only console into site/dist/, then publish only that directory. This Pages project is not the v2 admission Worker.
Deploy
# From the private repository root
npm ci
npm run check
git status --short
git push origin main
COMMIT="$(git rev-parse HEAD)"
npm run site:deploy -- --origin https://x429.dev --confirm "$COMMIT"
site:deploy is the only production upload path. It requires a clean, governed commit already present at origin/main, rebuilds the allowlisted site, runs the release and vendor audits, uploads only site/dist/, and verifies the exact Pages deployment plus the custom-domain proof. Never call raw wrangler pages deploy, use drag-and-drop, or deploy the site/ source directory.
Verify
# From the private repository root
npm run site:verify -- https://x429.dev
The verifier uses non-following HEAD requests, validates the root security-header contract, and refuses a redirect that merely hides an exposed source file. Retain its JSON output with the deployment evidence.
Expected status codes:
| URL | Expected |
|---|---|
/ | 200 |
/docs/ | 200 |
/llms.txt | 200 text with explicit pre-release boundaries |
/wrangler.jsonc, /README.md, /SECURITY.md | 404; retain these negative checks with deployment evidence |
/429 offer nor public /.well-known/x429.json discovery. V2 discovery belongs on the separately deployed admission Worker, not the marketing hostname.Custom domain
Cloudflare Pages should have both custom domains attached:
x429.dev
www.x429.dev
DNS should be configured using the records or nameservers shown in the Cloudflare dashboard for this Pages project. Keep registrar-specific or account-specific values out of the public repository.
Production headers
The site includes a Pages _headers file. Keep public responses conservative: clear content types, restrictive security headers, and cache rules appropriate to each asset.
| Route | Header goal |
|---|---|
/llms.txt | Return concise text instructions for agent builders and crawlers. |
/docs/* | Return normal static HTML; cache immutable assets such as fonts and images where safe. |
/api/* | Return no-store authenticated telemetry responses; never grant admission or payment authority. |
Observe-console data boundary
- Ingest accepts at most 100 schema-validated events and 256 KiB per request. Query strings, arbitrary fields, raw address fields, secret fields, and legacy truncated client hashes are dropped.
- Accepted KV batches have a fixed 30-day expiry. The default schema still stores a bounded route path, truncated user-agent, status, latency, and protocol flags, so use route templates and complete legal/privacy and retention review before beta.
- Per-client bucketing is disabled by default. An approved deployment must change the non-secret Pages variable
X429_OBSERVE_CLIENT_HASHESfromdisabledto the exact valueenabled. The observed server must separately setcollectClient: true, an exactclientHashDomain, and a dedicatedX429_OBSERVE_CLIENT_HMAC_SECRETgenerated from at least 32 random bytes. Without both opt-ins, identifiers are dropped and hidden. - The dedicated HMAC secret belongs in the observed application's secret manager—not Pages, Wrangler variables, browser code, or the project credential. The middleware creates a full project/origin/UTC-day-scoped HMAC before sending telemetry. Missing or syntactically weak configuration emits no identifier; raw addresses and the secret never enter the telemetry payload.
Repo workflow
- Edit the public site files in
site/. - Run
npm run checkfrom the repo root; the guarded deploy rebuildssite/dist/. - Commit changes.
- Push to GitHub.
- Run
npm run site:deploy -- --origin https://x429.dev --confirm "$(git rev-parse HEAD)"; never bypass the gate or deploy the source directory.