Skip to content

feat(site): real multi-page site for nesy-prover.dev - #329

Merged
hyperpolymath merged 3 commits into
mainfrom
feat/nesy-prover-site
Jul 28, 2026
Merged

feat(site): real multi-page site for nesy-prover.dev#329
hyperpolymath merged 3 commits into
mainfrom
feat/nesy-prover-site

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Turns the Pages output at nesy-prover.dev from a README dump into an actual site: landing page, platform docs, an accurate API reference, and a working in-browser Coq playground.

Why the build changed

pages.yml built from src/ — the Rust source tree — with a README shim. That published five stray src/**/README.html pages to the live site and set the Ddraig base URL to hyperpolymath.github.io/echidna, so every canonical URL, sitemap entry and feed link pointed at the wrong host. It now builds from a dedicated site/ tree with the custom domain as base, and copies the playground in with cp (Ddraig's copyTree is text-only and corrupts binaries).

No CNAME file is needed: build_type is workflow, so the custom domain lives in the Pages settings, where it is already verified.

The API reference was wrong in every example

An adversarial review confirmed the pages inherited from docs-site/content documented an API that does not exist:

  • GraphQL documented at /graphql and /playground — both 404; the service serves POST and the playground at /
  • suggestTactics shown as a Query; it is a Mutation taking (prover, context, goalState). The query is suggestTacticsByProofId
  • argument names wrong throughout (proofState(sessionId:)id, submitProof(proverKind:)prover+goal, applyTactic(sessionId:)proofId+tactic+required args)
  • REST documented timeout_ms; the field is timeout_seconds (serde silently drops the unknown key, so an operator's timeout vanishes — and 30000 s vs ms is a 1000× trap if they only fix the name). Tactic body is {name, args}, not {tactic}
  • gRPC showed a SubmitProofResponse and a ProofUpdate shape that are not in the proto
  • every quick-start curl used https:// against services that bind plain HTTP on loopback

All three interface references are rewritten from source, and a new core server reference documents what is actually deployed at api.nesy-prover.dev, taken from the route table and types in src/rust/server.rs. The stale 30-row prover table claiming every backend is tier "core" is gone; the canonical tier table is linked instead.

Playground

echidna-playground/index.html never loaded jsCoq at all — the init block was commented out behind an npm install note. It now loads jsCoq 0.17.1 from jsdelivr as an ES module. The bundled demo was Mathematical Components, which the CDN package does not ship, so the example is a stdlib-only induction proof (n + 0 = n) that actually runs.

The load-failure banner uses a dynamic import() inside try/catch: with a static import, a failed CDN fetch aborts module instantiation, so the handler that reveals the banner would never run — in exactly the case the banner exists for.

Verification

  • ddraig build locally: 6/6 pages [a11y ok] (the SSG hard-fails on multiple h1s, skipped heading levels, or missing alt text)
  • every absolute internal link resolves in the assembled artifact, including /playground/
  • the playground references no asset beyond the styles.css shipped alongside it
  • sitemap.xml entries use https://nesy-prover.dev
  • hypatia governance gate re-run on this branch merged with fix(governance): reconcile hypatia baseline with current scanner ruleset #328: 136 findings, 0 kept, exit 0 — this branch introduces no new findings

Note on DNS (separate from this PR)

nesy-prover.dev currently resolves to Cloudflare proxy IPs and does not answer (curl hangs), while hyperpolymath.github.io/echidna 301s to it. The apex records need reconciling to GitHub Pages before this site is reachable.

hyperpolymath and others added 3 commits July 28, 2026 15:28
Build the Pages artifact from a dedicated site/ content tree instead of
the Rust src/ tree (which leaked five src/**/README.html pages onto the
live site) and set the Ddraig base URL to the custom domain so canonical
URLs, sitemap, and feed stop pointing at github.io.

- site/index.md: landing page with live-API examples
- site/docs/: platform docs + REST/GraphQL/gRPC references adapted from
  docs-site/content (prover counts stripped per R5a count-drift policy;
  licence corrected to AGPL-3.0-or-later)
- pages.yml: build from site/, copy the playground in binary-safe with
  cp (ddraig copyTree is text-only)
- playground: wire jsCoq 0.17.1 via jsdelivr ES module with a visible
  fallback banner; replace the mathcomp demo with a stdlib-only proof
  (the CDN package ships no mathcomp); drop dead scratchpad/favicon
  references; repoint deno dev/serve tasks at jsr:@std/http/file-server
  (server.ts never existed)

Verified locally: ddraig build exits 0 with [a11y ok] on all five pages;
sitemap URLs use https://nesy-prover.dev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The @std/yaml lockfile entry was an accidental side effect of a local
validation run, not a dependency of this change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An adversarial review of this branch confirmed that the API pages
carried over from docs-site/content described an API that does not
exist: GraphQL was documented at /graphql and /playground (both 404 —
the service serves POST and the playground at /), suggestTactics was
shown as a Query when it is a Mutation with different arguments, REST
documented timeout_ms instead of timeout_seconds and a tactic body of
{tactic} instead of the required {name, args}, gRPC showed a
SubmitProofResponse and a ProofUpdate shape neither of which is in the
proto, and every quick-start curl used https:// against services that
bind plain HTTP on loopback. Every copy-pasted example failed.

Rewrite all three interface references from source
(src/interfaces/{rest,graphql,grpc}), and add a core server reference
documenting what is actually deployed at api.nesy-prover.dev, taken
from the route table and request/response types in src/rust/server.rs.
Drop the stale 30-row prover table that claimed every backend is tier
'core' and point at the canonical tier table instead.

Also fix the playground fallback banner: the jsCoq import was static,
so a CDN fetch failure aborted module instantiation and the .catch
that reveals the banner never ran — precisely the case the banner
advertises. Use a dynamic import inside try/catch.

Verified: ddraig builds 6/6 pages [a11y ok]; every absolute internal
link resolves in the assembled artifact (including /playground/); the
playground references no asset beyond the styles.css that ships with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hyperpolymath

Copy link
Copy Markdown
Owner Author

The site was dead for a reason outside this diff

While verifying, I found the actual reason nesy-prover.dev serves nothing — and it is not the build config this PR fixes:

pages.yml was disabled_manually. The workflow had exactly one run in its entire history (2026-07-19, startup_failure) and was then switched off in the Actions UI, so no commit to it could ever build. gh api .../pages reports status: null and https_enforced: false, consistent with a site that has never deployed.

I have re-enabled that one workflow (PUT .../workflows/316167448/enable, now active).

An audit of both repos found three workflows silently off:

repo workflow state action
echidna pages.yml disabled_manually re-enabled — required for the site
echidna instant-sync.yml disabled_manually left off (dispatches to the private farm)
echidna push-email-notify.yml disabled_manually left off (sends mail)
echidnabot instant-sync.yml, push-email-notify.yml disabled_manually left off

The two I left alone look deliberately disabled, so I have not touched them — worth confirming that is still the intent.

Remaining blocker for the live site: apex DNS

With Pages building again, the apex still needs fixing. nesy-prover.dev currently resolves to Cloudflare proxy IPs (104.21.34.184, 172.67.163.185); the TLS handshake to Cloudflare succeeds but the request then hangs, i.e. Cloudflare is proxying to an origin that is not answering. GitHub Pages also cannot provision its certificate while the record is proxied, which matches https_enforced: false.

Cure: point the apex at the GitHub Pages addresses DNS-only (grey cloud) — A to 185.199.108–111.153, AAAA to 2606:50c0:800{0,1,2,3}::153 — let GitHub issue the certificate, turn on Enforce HTTPS, and only then consider re-proxying with Full (strict). That needs a Cloudflare token with Zone:DNS:Edit, which I do not have.

Comment thread echidna-playground/index.html
@gitar-bot

gitar-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

Note

Automatic reviews are paused because your trial's included automatic processing has been used for this period. Upgrade now, or comment "Gitar review" to run a review anytime.
Learn more

Code Review ✅ Approved 1 resolved / 1 findings

Adds a multi-page site for nesy-prover.dev with landing, docs, and playground pages, but the jsCoq 0.17.1 initialization API entry point may not match usage in the playground script.

✅ 1 resolved
Bug: jsCoq 0.17.1 init API/entry point may not match usage

📄 echidna-playground/index.html:144-158
The playground loads jsCoq via import('https://cdn.jsdelivr.net/npm/jscoq@0.17.1/jscoq.js') and calls JsCoq.start(jscoq_ids, jscoq_opts) with a (ids, options) signature and no base path. jsCoq's documented embedding API historically loads through jscoq-loader.js and uses JsCoq.start(base_path, base_url, element_ids, options); if 0.17.1 has not switched to an ESM jscoq.js with this two-arg signature, start() will throw or fail to resolve its wasm/package assets, and the playground never initializes (falling into the load-error banner in every case). Verify the exact 0.17.1 ESM entry point and start() signature against the published package before relying on this, and adjust the import path/arguments (including a base_path/base_url if required) accordingly.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@hyperpolymath
hyperpolymath merged commit 21a219e into main Jul 28, 2026
1 check passed
@hyperpolymath
hyperpolymath deleted the feat/nesy-prover-site branch July 28, 2026 17:32
hyperpolymath added a commit that referenced this pull request Jul 29, 2026
Documents where ECHIDNA actually runs — the map that was missing after
the site and deploy work landed in #329/#330.

## What's here

**`docs/HOSTING.md`** (humans) — the three public surfaces and how each
is built:

| Surface | Host |
|---|---|
| `nesy-prover.dev` — website | Cloudflare Pages, built by `pages.yml`
(Ddraig SSG) |
| `api.nesy-prover.dev` — HTTP API | Hetzner, rootless podman quadlets
behind Caddy |
| `sudo@nesy-prover.dev` — contact | Cloudflare Email Routing forwarder
|

It also captures the two site constraints that bite when editing: the
SSG **hard-fails the build** on any a11y violation (more than one `h1`,
a skipped heading level, a missing `alt`), and its `copyTree` is
**text-only and corrupts binaries** — which is why the playground has a
separate `cp` step.

**`.machine_readable/deployment.a2ml`** (machines) — the same topology
as structured data, including the API's limits (`30/min/ip`, 1 MB body,
`--memory=1500m --pids-limit=512`, no published host port) and an
explicit risk block: the API has no authentication and spawns prover
binaries on user input, rate limiting bounds request *count* rather than
the cost of one request, and a per-request prover timeout is
outstanding.

## Honest about what is broken

Both files record the two live blockers rather than describing an
aspirational happy path:

1. **Repository-wide Actions `startup_failure`** — every workflow,
including `pages.yml`. A minimal probe workflow containing one
SHA-pinned `actions/checkout` fails identically, so this is *not* a
workflow-file fault.
2. **The apex has no origin** — `nesy-prover.dev` resolves to
Cloudflare, the TLS handshake completes, and the request then hangs. The
DNS records are likely already right; the Pages project behind them is
what is missing.

Both also carry the diagnostic that keeps costing time here: **a
workflow that fails at startup registers no check run**, so `gh pr
checks` reports success while every real gate is dead — and a workflow
listed by *path* instead of *name* has never been parsed.

## Stale doc neutralised

`docs/deployment/DEPLOYMENT_GUIDE.md` becomes a superseded stub. It
described a 2025-11 v0.1.0 deployment whose next step was "deploy to
GitLab", referenced an unrelated `zotero-voyant-export` migration, and
quoted a fixed prover count that the canonical-reference policy forbids
in prose. Kept as a stub so existing links don't dead-end.

## Verification

`.githooks/validate-a2ml.sh` passes (exit 0) with the new manifest
present — the same validator the dogfood gate runs.

Note that CI cannot verify this PR: see blocker 1 above.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant