Free during the betaVersion 0.5.0macOS & Windowsproprietary licenceRead what to expect
All posts
18 min readCourtney Allen

Prompt to Page 0.5.0: a broken journey should look broken

Until this release, an exit that went nowhere was quietly rewritten onto the next page, so a broken journey still walked cleanly in the exported ZIP. The preview showed the unpatched exit all along. Only the thing you handed to someone else was smoothed over. 0.5.0 stops that, and applies the same rule to the assessment evidence document and to the quality claim the app makes about your model.

Version 0.5.0 of Prompt to Page is out. The Digital Agency Design System — デジタル庁デザインシステム, Japan — arrives as the eighth base pack, its component CSS and JavaScript pinned to the dated upstream release v20260825. Generated journeys now either resolve an exit to a real path or stamp it unresolved. Prototype quality is stated for your model on your design system. The assessment evidence export gains a Brief, a Components inventory and a Limitations section. The Bootstrap Italia furniture work, staged as 0.4.5 on 1 September and never built or published, is folded in. macOS went out on 2 September, the Windows MSI on the 3rd, both from the same v0.5.0 tag.

For a designer in a UK department, the new pack is the least consequential item on that list. The three that matter are the three places where the app was tidier than the evidence behind it: exit resolution, then the assessment evidence export, then the per-model quality line. After those come the preview and pages-rail fixes, the Bootstrap Italia furniture, and DADS. If a service assessment is next in your diary, take the first two first. They share a defect. The preview never smoothed an exit — it showed you the href the model wrote. The artefacts you handed to other people did not.

The ZIP used to lie

Four things could set where an exit goes, and they never formed a chain. The model invented paths. The class auto-fix could not see paths. The post-generation patch filled only empty or # primaries, and was hardcoded to GOV.UK. And export, last in the line, silently rewrote an unresolvable form action onto the next page — defensibly, since the ZIP is meant to be walkable. So a journey wired to nowhere walked in a straight line inside it.

In the packaged three-pack review of 23 August, a Bootstrap Italia export rewrote /application/submit to s2.html. A different page in that same export carries the whole asymmetry: its form action rewritten to l1.html, six Change links pointing at routes that do not exist left as dead absolute /application/… hrefs. One smoothed form, six broken links. NSW had the twin.

The root cause is worse than the failure. Two rules that would have caught the dead-route half of it already existed in the scorer: journey.no-self-loop and journey.valid-internal-path. Both were green in CI and dead in the shipped app at the same time, because the quality context's current path came only from a journey slug the app never sent. Rules that pass in the harness and never run in the product bought me confidence I had not earned.

The preview was deliberately never patched, precisely so a designer could see unwired exits on screen. Only the deliverable was smoothed. The person who could already see the problem was told about it. The person being handed the artefact was not.

That review's journey-wiring family came to 13 findings: 8 invented, self-linking or reversed forward targets, and 5 Change links with no provenance. Read it as pre-fix diagnosis and nothing else — one model, one seed, no repeats, the premium tier unscorable on a 24 GB host, the second-model pass never run. No post-fix battery has been run.

What an unresolved exit looks like now

On a freshly generated journey page the plan is authoritative. Every advancing exit that carries the pack's button class goes to the plan's next path, every recognised back link to the previous one, and on a check-answers page the advancing destination is the confirmation path, not simply the next page. It overwrites an href that already resolves, because the wrong real page is still wrong. The decision record carries both halves in its title: exit resolution overwrites planned destinations and refuses to guess.

Anything else internal that is not a path in the journey plan is stamped data-exit-unresolved, keeping the rejected target verbatim, titled "Unresolved: this does not go to a page", destination neutralised. Recognition is the limit at both ends: a plain Continue emitted without the pack's button class is not treated as an advancing exit, and a link to a real page outside this plan is stamped rather than kept. Fragments, mailto: and tel: are never stamped — they are not path navigation.

One rule paints it in both artefacts: a 3px dashed red outline, in public/preview.css and again in public/prototype.css. Clicks and submits on a stamped control are prevented in both. And because the last defect was a rule that only ran in the harness, the pass is now written twice on purpose — once in TypeScript for the browser path, once in Rust inside desktop finalize — so what the scorer sees is the HTML the app actually returns. The issue list is live: a red "N unresolved" badge in the pages rail, a page that cannot read as clean, and a validation-panel line naming the label and the rejected target. Export preflight warns per issue and does not block. You are told, and you decide. Retarget stays your fix, and clears the stamp in the same deterministic edit.

The refusals matter as much as the rewrites. A Change link resolves only by a 1:1 lookup of the row's field name against the unique earlier plan page that collected it; ambiguous, missing or empty, it is stamped rather than guessed. Missing controls are never invented — wrapping a standalone submit that already exists is in scope, inserting a Start button the model never emitted is not. And the pass does not run on code edits, retargets or imports, because those are your hands on the HTML.

The document you take to the assessment

This is a different download from the walkable prototype, and deliberately slower, because it runs an accessibility scan on every page before it writes anything. The ZIP holds EVIDENCE.html and a README.md generated from the same data, plus ACCESSIBILITY.md, one real rendered page per page, and the design-system assets. Its section order is fixed and test-locked: Cover, Brief, Journey overview, Pages, Components, Accessibility position, Limitations.

Brief is quoted, never written: the journey plan's description; failing that the start page's original generation prompt — the first one, not a later refinement; failing that the earliest page that has one. With none of those it prints "No brief was written for this prototype." A persisted service-description field and a model-written summary were both considered and rejected, because either puts a brief in front of an assessor that you did not write.

Components inventories the design-system blocks present in your authored HTML, rolled up to the BEM block — govuk-button--start and govuk-button__icon both report as Button. Blocks found in your pages, not the pack catalogue; and they are not checked against that catalogue, so an invented class carrying the pack's prefix would be listed as a component.

Limitations replaces Known gaps outright rather than sitting beside it: a reviewer hunting for what this cannot claim should not have two places to look. Three standing limits print in every ZIP whatever the project, and the third is a refusal, in the document's own words: automated accessibility results are a floor, not WCAG conformance and not an assistive-technology assessment. That is enforced, not merely intended — a unit test forbids "meets WCAG", "WCAG 2.2 AA compliant" and "tested with a screen reader" from ever appearing there.

The scan is axe-core in the same WCAG 2.2 AA configuration as the in-app panel, which maps to roughly 20 of the 55 Level A and AA criteria. EVIDENCE.html names the four core manual checks that still need a person; ACCESSIBILITY.md ships all thirteen. A page that failed to render or scan prints "Not scanned" with the reason, then the line that stops an absence reading as a pass: its result is missing, not clean. Each embedded page is the real rendered page, not a screenshot, scripts stripped so the document stays inert; the app makes no PDF, you print it yourself. An unresolved exit surfaces here too, as an export warning inside Limitations — the same fact in both artefacts rather than in neither. One fact does not make that trip: a page records its pack and its version but not the model that generated it, so the evidence document cannot tell an assessor which model wrote the pages.

One sentence about your model, on your design system

Two real cases forced this. A Mac running an MLX model in a Scottish Government project saw no caveat and no score at all. A Windows machine with 8 GB, running the one lite model actually measured on USWDS, saw a caveat telling it USWDS had not been evaluated. I would rather make one statement than two that can contradict each other. It is the export defect turned inward: where the ZIP smoothed a break in the prototype, the picker smoothed a gap in what I had actually measured.

Both are gone. One line replaces them, naming the model, the design system and the level: "Prototype quality with Qwen2.5-Coder 7B on GOV.UK Design System: Good, measured." Or "Not measured." The words are exactly Basic, Fair, Good, Very good and Excellent, with a plain-English gloss beneath: measured means we generated test pages with this model on this design system and checked them against the system's rules.

What that gloss hides, and I would rather say here: measured is not one quantity of evidence. A GGUF level is the median of five seeded runs. An MLX level is a single run, because the MLX server ignores the requested seed and cannot be seeded at all. Both print the same word.

Levels are never compared across design systems, and the reason is mechanical. Component cases score near 100 for every model while journey cases score 55 to 85, and the batteries have different case mixes: GOV.UK's is one component case plus six page and journey cases, the Scottish Government's is fourteen plus six. That alone turns a GOV.UK 1 into a Scottish 4. They also ran under different scorer versions. And some GOV.UK levels are themselves stale — the Qwen3 1s predate the thinking-suppression fix, and my own rung record puts Qwen3-8B at a mean of 82.3 on the full prompt, which buckets to a 3. One disclosure keeps the rest honest: "Best for this Mac" is still ranked on GOV.UK results, and the card says so when another pack is in context.

Nineteen of the 20 catalog entries carry a GOV.UK level, 29 further model-on-pack levels sit across 10 entries, and DADS, Abstract and the MOJ overlay carry none. The NSW and Bootstrap Italia levels written this release come from the batteries of 24 August: seven GGUF models at five seeds each, all run on one 24 GB Mac even though four are Windows-only catalog entries. 1,260 generated pages, no seed failing, no foreign design-system class token in any of them. A case passes only at 80 or above with no error-severity issue, so medians and pass counts tell different stories. NSW, 20 cases:

ModelMedian (5 seeds)Cases passedLevel
Qwen3 8B8511–12Good
Gemma 4 12B Coder8410–12Good
Qwen2.5-Coder 7B8310–11Good
Gemma 4 E4B8210–11Good
Gemma 3 12B8111–12Good
Gemma 4 E2B7510–11Fair
Qwen2.5-Coder 1.5B727–8Fair

Bootstrap Italia, 16 cases, a different ruler — read it on its own and against nothing above:

ModelMedian (5 seeds)Cases passedLevel
Qwen2.5-Coder 7B886–7Very good
Gemma 4 12B Coder874–7Good
Qwen3 8B867Good
Gemma 4 E4B867Good
Gemma 3 12B857–8Good
Qwen2.5-Coder 1.5B845–6Good
Gemma 4 E2B834Good

Both ceilings are partly mine, not the models'. All 35 Bootstrap Italia confirmation pages failed identically, because the shipped guidance still pointed at a JavaScript toast that never fires in a static prototype. And these are pre-fix numbers, taken the day before 0.4.4's prompt and corpus fixes shipped. A post-fix re-run is owed, and neither pack is blessed, validated or quality-evaluated on the strength of them.

Which brings me to this release's own new pack. Zero-shot — five patterns, one run per model per condition — the DADS probe's four runnable models scored 2.5, 2.5, 27.17 and 2.5 for structural fidelity on English content, and invented up to 97.14% of their class occurrences. Mostly GOV.UK's form idiom wearing a dads- prefix: dads-form-group--error, dads-form-label--required, modifiers the real design system does not have. Grounded on the pack's own reference markup — which carries canonical fragments for all five probed patterns, so read this as fidelity of copying — the same four scored 96.67, 96.67, 100 and 87, with no invented classes. Four of six gated models; the other two were hardware-blocked at 32 GB on a 24 GB host.

The shipped app is the third data point and the least flattering. On this release's own packaged smoke, a generated Japanese question page carried 18 dads- class occurrences: 8 valid, 10 invalid, including an invented dads-form wrapper. The Windows attempt recorded 31 classes, 23 valid, 8 invalid. A capability probe never writes a quality level; only a battery does, and that battery has not run. So the item this release sounds biggest on — and the one I have just told you matters least to your week — ships stamped Not measured, with the Japanese copy in its guidance still awaiting native review. That is the rule applied to the thing it would have been most tempting to exempt.

Where this does not hold yet

Hardest first. At the release commit, exit resolution had no DADS arm in either the TypeScript or the Rust pack-role table. DADS journey pages fell through to the GOV.UK classes, so their advancing exits, back links and Change rows were unrecognisable to the pass. The release's headline pack was excluded from the release's headline fix. The correction landed on 5 September, after the build. It is not in the shipped 0.5.0.

Building that table turned up an older mistake that shipped alongside it. The Scottish Government pack declared its check-answers row as ds_summary-list__row — a class its own corpus does not define, since the rows are ds_summary-list__item. And the same table declares an empty summary-row class for USWDS, NSW and Bootstrap Italia. So the Change-link paragraph above, the refusal I am proudest of, only actually runs on GOV.UK, NHS.UK and Abstract in the shipped build. On three packs it does nothing; on Scotland it matched nothing.

Back-link rewriting has the same shape: it applies only to packs that declare a back-link class, and USWDS, NSW and Bootstrap Italia declare an empty one.

Export still rewrites an external form action onto the next page, with a warning, because an exported form must never submit off-prototype — so "no longer rewrites" is exact only for internal unresolvable actions. It also still wraps and stamps a standalone submit control it finds at export time.

The semantically wrong but resolvable Change link is deferred entirely. On the Scottish Government check-answers page in the August battery, four of five Change links went to the wrong question — "Change name" and "Change address" both landing on an eligibility radio. A route-existence pass cannot judge that.

Verification, honestly. No packaged smoke row exercised a freshly generated journey for exit resolution, there is no end-to-end browser coverage of stamping, and the evidence export got no packaged smoke row this sitting. Six of fourteen UI-review rows ran on the installed app and eight did not. VoiceOver was never run, so the aria-current="page" now on the active page card rests on an attribute and a unit test rather than on anything heard. Most Windows rows ran against the release-tree executable rather than a driven MSI install, and the Windows in-app update path has not been driven since 0.2.5 to 0.3.0.

DADS carries its own list: no battery; a native-review packet of 64 rows with a blank sign-off block, which gates the pack's final system prompt; and an owed row for its custom elements — switch, tabs and accordion enhancing inside the app's own preview and export — attempted on Windows, blocked by a degenerate generation, and confirmed only outside the app. Capability evidence is not demand evidence, and none exists for Japan. My own release handoff advised holding the DADS story until the battery and the review land, which is why this post uses the pack as evidence rather than as a launch.

Last, in my own voice, because a post about handover artefacts telling the truth cannot quietly ship a false statement about its own privacy behaviour. The Beta terms bullet under Settings › Help & feedback in the shipped 0.5.0 build says usage statistics are on by default. They are off. The sentence described an earlier design and was never updated when lifecycle statistics became opt-in. No behaviour was affected — the code was right and the copy was wrong. I found it during the release sitting and it went out anyway. It is fixed on main. It is not fixed in the build you can download today.

The smaller print

Bootstrap Italia prototypes now use the pack's own furniture — a three-band header, a two-band footer — with Titillium Web, Lora and Roboto Mono inlined as data-URI faces, so preview and the offline ZIP match and no font files ship at all. It is de-branded by design and by test: no public-administration emblem, no flag, no SPID chrome, no official-service claim. Export no longer wraps the page in a second container. Existing Italia projects pick up the furniture and fonts on update without regenerating anything, because the furniture is deterministic code rather than model output; the exception is start pages, whose stored HTML keeps the old shape until you regenerate them.

The preview, pages-rail and Settings fixes came from an external, AI-authored usability review of 0.4.4, triaged claim by claim against the code: four findings confirmed, one with its mechanism corrected, one reframed, two invalid, and two of its three proposed fixes for its own highest-impact items rejected as harmful. It also called a Tauri app Electron.

What shipped, one line each. The Screen-reader tree and Version history panels no longer land on the toolbar buttons when the toolbar wraps. Distraction-free mode zooms to fit instead of leaving a 1280×900 frame to scroll inside the stage. The active page card carries an accent rail and an aria-current="page" attribute the collapsed rail already had. Settings names the chosen .gguf file beneath a path field that used to clip it, and Settings › Help finally lists the two command-palette shortcuts, which live in the keyboard handler rather than the registry that list is generated from. The code view gains an always-present bar with a per-page Copy HTML whose result is announced. And the Tools tabs, measured at 29.1875 px, are now 40 px — the defect was a control that shrank when you expanded it; both heights clear WCAG 2.5.8's 24 px minimum and neither reaches 2.5.5 AAA's 44 px.

What's next

The DADS blessing battery and the native-speaker review of the Japanese guidance, which together gate that pack's final system prompt and any level it will ever carry. The post-fix re-run of the NSW and Bootstrap Italia batteries, which will say it is post-fix when it lands. The MLX and 32 GB legs those batteries never ran — both read Not measured on the Scottish Government pack today, and that comes off the day the leg runs, never by borrowing a number from another runtime. And before anyone can ask a cross-pack question at all, every battery re-derived on the seven common-core cases every pack shares, under one scorer version. No dates. Conditions.

The app can tell you that a destination does not exist. It cannot tell you that the destination that does exist is the right one. What changed in 0.5.0 is that it stopped pretending otherwise in the artefacts you hand to other people.

Prompt to Page 0.5.0 is live for macOS (Apple Silicon) and Windows; installed copies update in place. Free closed beta. If you want in, you know where to find me.

Prompt to Page is an independent project by Courtney Allen. It is not affiliated with, endorsed by, or connected to the Government Digital Service, the Scottish Government, the NSW Government, the NHS, the U.S. General Services Administration, the Developers Italia community, the Digital Agency (デジタル庁) of Japan, the Crown, or any UK, Australian, Italian, Japanese or US government body. The design systems named are referenced descriptively, and none of their logos, logotypes, crests or restricted fonts are bundled.

Try Prompt to Page.

Free during the closed beta. Generation runs on your machine.