Skip to content

The browser page becomes a playground: one refund you can break six ways, on the released wheel - #107

Merged
arpanghoshal merged 2 commits into
mainfrom
docs/playground
Sep 6, 2026
Merged

arpanghoshal merged 2 commits into
mainfrom
docs/playground

Conversation

@arpanghoshal

Copy link
Copy Markdown
Member

What changes

/try-it was a button and a canned transcript. It is now a playground: one protected refund under one policy, with amount, payment id, lose the reply, Refund, and an Approve button that is the human. Every line printed is ctrlrun's own output on the released wheel, in the tab.

  • The page's Python is a module over the public API (Control, InMemoryStateStore, LocalApprovalProvider, Policy.from_yaml, @protect, context, with_approval) defining step(request_json) -> result_json. JS owns the DOM and nothing else. An approval is grant_approval on the store — the write ctrlrun approve makes. No auto-approve, no dry run; test_the_playground_has_no_way_to_grant_but_the_human_button asserts one grant path.
  • The native check that was missing. tests/test_docs_travelling.py extracts the module with the same regex the Node harness uses and runs it through the six steps the page suggests, asserting each outcome and remote_calls — no Node, no network, every commit. Mutation: reporting a refused retry as executed fails two tests.
  • Harnesses. verify-browser-demo.mjs drives the same sequence under real Pyodide 314.0.6 (ctrlrun 0.5.0 from PyPI), then the five scenarios, and writes docs/assets/browser-demo.verified.json; test_the_page_quotes_the_run_the_harness_recorded holds the page's date and versions to it. verify-browser-wiring.mjs clicks every control under jsdom with Pyodide stubbed (21 checks). Both run today, all green.
  • Page prose: policy → panel → "Try this, in order" (six steps) → the demo button → transcript and verification prose in <Accordion>s. 830 words, under budget. mint validate passes.
  • Home and README CTAs updated; CLAIMS.md gains The browser playground; CHANGELOG entry.

Checks

  • Full suite under .venv: 4120 passed, 45 skipped.
  • lint.py 0, links.py 0 broken, snippets.py 0 failed, ruff, mypy --strict src/ clean.
  • No src/ changes.

…ays, on the released wheel

`/try-it` was a button and a transcript: real Python, the real wheel, and nothing for the
reader to do but watch. Now it is one protected refund under one policy, with an amount, a
payment id, a *lose the reply* switch, a *Refund* button and an *Approve* button that is the
human. Every line in the box is `ctrlrun`'s own: the page's Python is a module over the public
API — `Control`, `InMemoryStateStore`, `LocalApprovalProvider`, `Policy.from_yaml`, `@protect`,
`context`, `with_approval` — defining one `step(request_json) -> result_json`, and the
JavaScript owns the DOM and nothing else. An approval is `grant_approval` on the store, the
write `ctrlrun approve` makes; there is no auto-approve and no dry run, and a test asserts the
module has one way to grant.

The module is a JSON array in `try-it.js`, beside the demo's, read out by the same regex the
Node harness uses. That shape is the point: `tests/test_docs_travelling.py` now runs the page's
Python natively through the six steps the page tells the reader to try — allowed;
`ApprovalRequired` then `ApprovalMismatch` then executed on the same approval; `consumed`;
`ActionDenied` with no request; `AMBIGUOUS` then a refused retry with one remote call;
`DuplicateEffect` — and asserts each outcome on every commit, with no Node and no network. That
is the check this page lacked when a syntax error shipped past two green harnesses. Mutation:
reporting the refused retry as `executed` fails the sequence test and the outcome-vocabulary
test.

`verify-browser-demo.mjs` drives the same sequence under Pyodide 314.0.6 on the released
0.5.0 wheel, then the five scenarios, and writes `browser-demo.verified.json`; the page's
quoted date and versions are held to that record rather than typed. `verify-browser-wiring.mjs`
clicks every control under jsdom with Pyodide stubbed and checks which request each builds,
when *Approve* appears, and that letters in the amount field are refused on the page rather
than sent as €0. Both ran today, every check true.

The page: the policy, the panel, "Try this, in order", the demo button under it, and the
transcript and verification prose folded into accordions. Home and README CTAs say what the
page now lets you do. CLAIMS.md gains the section; CHANGELOG the entry.

Full suite 4120 passed; lint, links, snippets, `mint validate` green.
@mintlify

mintlify Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
ctrlrun 🟢 Ready View Preview Sep 6, 2026, 10:40 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@arpanghoshal
arpanghoshal merged commit 30dcdd0 into main Sep 6, 2026
11 checks passed
@arpanghoshal
arpanghoshal deleted the docs/playground branch September 6, 2026 22:54
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