Skip to content

Add Quantus Captcha widget/demo and Debate Tree plan#558

Open
illuzen wants to merge 3 commits into
mainfrom
illuzen/debate-tree
Open

Add Quantus Captcha widget/demo and Debate Tree plan#558
illuzen wants to merge 3 commits into
mainfrom
illuzen/debate-tree

Conversation

@illuzen

@illuzen illuzen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

captcha/: drop-in proof-of-work captcha widget (checkbox UI, Web Worker WASM solver, hidden token input, quan-captcha-solved event), demo form page, integration README with threat model. Consumes the pool-service API from Quantus-Network/quantus-miner (companion PR).
debate-tree/PLAN.md: full plan for the AI-moderated debate platform (components, gating model, djb hybrid-vs-pure-PQ seed strategy, risks).
Test plan

  • Manual e2e via the demo page against a dev node (5 solves, verified server-side)

  • Not wired into melos/Flutter tooling (plain JS/static assets; dist/ is gitignored)


Note

Low Risk
Greenfield static JS, demo HTML, docs, and a plan file; no changes to existing app runtime or auth paths in this repo.

Overview
Introduces captcha/, a new embeddable Quantus proof-of-work captcha that treats each solve as a real mining share against pool-service (companion PR in quantus-miner). The widget (quan-captcha.js) is a checkbox UI that only starts work on user click: it calls POST /api/session, runs Poseidon2 hashing in a Web Worker with WASM from build-solver.sh, submits the nonce via POST /api/share, injects a hidden quan-captcha-token, and fires quan-captcha-solved. A demo form illustrates end-to-end flow (including demo-only siteverify). README documents integration, API surface, and an explicit rate-limiter threat model; dist/ is gitignored.

Also adds debate-tree/PLAN.md, a product/architecture plan for a future AI-moderated debate app that would consume this captcha plus QUAN balance gates—no application code in this PR.

Reviewed by Cursor Bugbot for commit cd6fccd. Configure here.

captcha/ is the embeddable proof-of-work captcha: drop-in widget, Web Worker
WASM solver glue, demo form page, and integration docs; it consumes the
pool-service API from quantus-miner. debate-tree/PLAN.md is the full plan
for the AI-moderated debate platform the captcha gates.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit cd6fccd. Configure here.

Comment thread captcha/widget/quan-captcha.js
illuzen and others added 2 commits July 6, 2026 16:56
setState now owns the checkmark in both directions, and the solved state is
applied after the hidden-token injection so a throw in the tail lands in
fail() without leaving solved visuals behind.

Co-authored-by: Cursor <cursoragent@cursor.com>
@n13

n13 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Review

Checked out illuzen/debate-tree (7389dfb) in a clean worktree, alongside the companion pool PR (Quantus-Network/quantus-miner#74) whose API this widget consumes. Note the PR description still says "no application code" for debate-tree, but 7389dfb added the steelman spike (debate-tree/spike/ — server, prompts, UI); the description could use a refresh.

What's solid

  • The widget is genuinely drop-in: zero dependencies, style injection with an id guard, double-init guard, ARIA checkbox semantics with keyboard handling, and work only starts on explicit user action — consistent with the Coinhive-lessons guardrail the README states.
  • The solved-state ordering (17ba15e) is right: all fallible tail work (share POST, token input injection) happens before setState("solved"), and setState owns the checkmark in both directions, so error/retry never shows stale solved visuals.
  • The worker protocol is clean: chunked solve(2048) with progress messages, io_len() layout check against the wasm module, and hexToBytes pads to the fixed widths the C-ABI buffer expects, matching the unpadded {:x} hex the pool emits.
  • README threat model is honest ("rate limiter, not sybil resistance") — this framing should survive into any marketing copy.
  • The steelman prompts (debate-tree/spike/prompts.mjs) are thoughtfully constrained (never flip stance, no invented facts, author feedback is authoritative), and the spike UI escapes all model output before rendering. Prompts-as-the-artifact is the right framing.

Findings

  1. Cross-origin embedding is broken by default (the advertised use case). The README integration example puts the widget on example.com with data-endpoint="https://pool.example.com", and quan-captcha.js then does new Worker("https://pool.example.com/widget/solver-worker.js"). Dedicated workers are same-origin-only — this throws a SecurityError and every third-party embed lands in fail("solver failed to load") (or the constructor throw). It works today only because the demo is same-origin via --serve-dir. Fix options: fetch the worker script (CORS is already open on the pool) and instantiate via a Blob URL, or document that integrators must self-host solver-worker.js and set data-worker-url. The wasm fetch inside the worker is fine as-is since it's a plain CORS fetch.

  2. No solve timeout vs. the 120 s session TTL (minor). The worker grinds forever; on a slow device an unlucky session expires mid-solve and the user gets session_expired after a long spinner. A widget-side deadline derived from expires_in_secs (fail early → "click to retry" gets a fresh session) would make the failure mode much less confusing. Related UX: token TTL is 300 s, so a user who solves and then writes a long comment submits a dead token with no re-arm path — worth at least a note in the README's integration section.

  3. Spike server trusts the client-held transcript (fine for a spike, flagging for the real thing). POST /api/steelman rebuilds the conversation from client-supplied rounds with no server-side cap — MAX_ROUNDS lives only in the browser, so anyone hitting the endpoint directly gets unbounded LLM calls on your key. PLAN.md already lists round caps + spend caps for the production write path; just don't expose this spike beyond localhost meanwhile.

  4. Two products in one PR. Captcha widget and debate-tree plan/spike are independent deliverables on one branch (illuzen/debate-tree, title says captcha). Not blocking since it's all additive greenfield, but they'll want to evolve on separate branches after this lands.

Verdict

Opinion only — not a formal approve/request-changes: I'd merge this as-is if the README's cross-origin integration example (finding 1) is corrected or caveated first — shipping docs that direct integrators into a guaranteed SecurityError is the one thing I'd hold the PR for, and it's either a small widget change (Blob-URL worker) or a two-line doc fix. Everything else is minor or explicitly spike-quality by design. The captcha slice is coherent, honest about what it is, and verified against the companion pool PR; the plan doc is unusually clear about risks and build order.

@n13 n13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, should update documentation

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.

2 participants