Skip to content

Enhancement: wireframe-first approval loop for every change (propose → confirm → build → verify) #507

Open

Description

@MendixMau

Problem

The toolkit gets a user's approval of the wireframes once, at the Stage 3 gate. Every change after that goes from requirement to MDL with no visual check by the person who asked for it:

  • a new requirement in the middle of the build;
  • a greenfield page;
  • a change to a screen in a live .mpr.

The user first sees the change when they click through the built app. That is the pattern in #232: the LOOK was skipped and the user found UX defects by hand. In #291 the defects were designed in and then built faithfully.

The proposal: for every change that alters what a user sees, show a before/after wireframe first, ask "is this right?", stop, and build only after a yes. Then show the built page next to the approved design. That gives "a direct visualization of what's happening" without leaving the chat.

What exists today

Change kind Exists Gap
New screen, Stage 3 (migration/requirements) One annotated wireframe per screen, design/prototype.html, Steps 3b/3c (skills/design-artifacts.md); CAC-4 (skills/checkpoints/checkpoint-design.md); Stage 3 ✋ (skills/conversion-runbook.md) Mostly covered. Approval is per stage, and nothing records which wireframe version the user saw.
New screen, greenfield skills/ui-preflight-pages.md Step 1: no wireframe means STOP. bin/lib/artifact-manifest.tsv wireframes row excludes greenfield. Missing. The agent draws a wireframe to clear its own STOP, and nobody approves it.
Mid-build requirement Drift-sync "visually observable" re-render (conversion-runbook.md §3b, skills/iterative-build-loop.md); [sync: … UNSYNCED] gate Missing. The re-rendered wireframe is never shown to the user. The gate checks that the sync happened, not that anyone approved it.
Changed screen on a live .mpr skills/existing-app-change.md Stage 3 "wireframes only for screens that change"; ground rule 4 "as-is before to-be" (text); ui-preflight-pages.md Step 0 already runs DESCRIBE PAGE Partial. No as-is visual and no side-by-side.
Non-UI (entities, microflows, security) Stage 3 Mermaid in architecture/blueprint.md; BRD as-is/to-be text; role-to-access table Partial. Nothing per change shows a before/after.
Verify the build skills/ui-loop.md + project-bin/look-ledger.sh (screenshot), project-bin/page-fidelity.js (docs/PAGE-FIDELITY.tsv), skills/module-review.md stage 4, obligations look / fidelity Partial. These compare against the current wireframe, approved or not. No single artifact shows the approved design next to the built page.

Proposed loop

Run by the lead session, because subagents cannot ask the user:

  1. Classify. Is the change visually observable? Reuse the drift-sync filter.
    • If it is trivial (a label or one field), show an inline text diff and go to step 5.
    • If it is non-UI, render the equivalent instead: a Mermaid classDiagram before/after for entities, a behaviour table (input → outcome) for microflows, an access-matrix diff for security. Use the DESCRIBE/SHOW output the change already fetched.
  2. Propose. Write design/proposals/<date>-<slug>/.
    • before.*, taken from the cheapest existing source, in this order:
      1. the last LOOK screenshot;
      2. the current wireframe;
      3. a rough wireframe drawn from the DESCRIBE PAGE output that preflight Step 0 already fetched;
      4. a screenshot the user drops in.
    • after.html, built from ds.css with its binding table, as in design-artifacts Step 3.
    • proposal.html, showing before and after side by side, with changed regions outlined and a status strip (Proposed → Approved → Building → Built → Verified).
  3. Show it. Per-host options are in the next section.
  4. Ask, then stop. Offer Approve · Change (say what) · Drop, plus "something else". Render the question per skills/interview-protocol.md §3, then end the turn.
  5. Record. Add a PROJECT.md row: Wireframe approved: <Screen> (design/proposals/…) sha256:<8> | CONFIRMED, with the drift-sync marker. Copy after.html over design/wireframes/<Screen>.html. Every existing check then reads the approved version with no code change.
  6. Build. Run the normal loop unchanged. The status strip mirrors the Live Checklist.
  7. Verify. The existing ui-loop.md screenshot becomes built.png, and proposal.html gains an approved | built column. Answer the four LOOK questions against it. The page-fidelity.js row is unchanged.

Where it shows, per host

The loop needs three facts from the separate host-detection work: can the user render a local file, can the agent screenshot it, and is the session remote.

Host Show Agent sees it
Claude Code desktop (local) Click the path in chat to open it in the Browser pane Yes. Reload can serve stale HTML, so write a new revision filename each time.
Claude Code CLI (local) open / xdg-open / start, as bin/init-project.sh does for the guide, or a private Artifact Via Playwright
Claude Code web / cloud / remote-control Private Artifact, republished to the same URL Yes. The preview pane is unavailable in remote-control.
VS Code + Copilot Integrated Browser (local .html), Simple Browser (needs http.server), Live Preview ext. code -r opens the source only. Usually no
Cursor Built-in browser via "Open in Browser" on the HTML tab; Design Mode for annotating Agent browser tools
Windsurf (docs now Devin Desktop) Browser Previews of a local server; "Send element" to Cascade Partly
Codex App in-app browser (file-backed previews, comment mode); Browser plugin; CLI uses OS open App + plugin
Headless / CI / unattended Files plus a log path No. Record ASSUMED (opt-in unattended only), queue the proposal, and surface it at the next attended gate.

Minimal design

  • New skill skills/propose-before-build.md. It holds the 7 steps, skip rules, the before-source ladder, a compare-page HTML template, and a host table that defers to host detection. It ends on a denominator: "N of N changed screens have a proposal folder and a CONFIRMED/ASSUMED row".
  • Routing row in bin/lib/skill-routing.tsv. Agents lead, stages 3,5, tier experimental, group design. A lead-only row renders into no agent stub, and the experimental tier is never the reason a gate fails.
  • One-line hooks in on-demand skills only:
    • design-artifacts.md, for wireframes edited after Stage 3 approval;
    • the existing-app-change.md Stage 3 row, for the as-is visual;
    • the iterative-build-loop.md drift-sync rule, so a visual re-render is approved before the marker flips.
  • No new obligation in v1. The existing look and fidelity obligations already verify against design/wireframes/<Screen>.html, which is now the approved version.
  • No script in v1, per skills/skills-over-scripts.md row 4 and its "Adding a new capability" rule: use the skill by hand twice first. A small compare-page helper can come later if that proves tedious.
  • v2, after field use:
    • a gate-check join with no mxcli: a design/wireframes/*.html committed after Stage 3 approval with no Wireframe approved: row (or waiver) reports;
    • add greenfield to the wireframes manifest row.
  • Behaviour A/B. Not needed for v1, because no baseline text and no stub is touched. Still run render-routing.sh --check and a retrieval check on real phrasings (CLAUDE.md rule 8). An A/B is needed before promotion to baseline, before any line goes into conversion-runbook.md or ui-preflight-pages.md, or before a stub changes. The behaviour suite is on the unmerged tests/behaviour-suite branch.

Cost / performance

  • Zero added mxcli or mxbuild calls. The "before" image reuses an existing screenshot, the wireframe, or the DESCRIBE PAGE that preflight Step 0 already runs. The "built" image reuses the ui-loop.md screenshot. The build still runs one exec.sh and mxbuild per script ([field 2026-10-17] Gate cost: full deploy mxbuild per small script, no check-only or batch mode, no global lock #444 is about that cost and must not grow).
  • Tokens: about 3–8k per changed screen (edit the wireframe and fill the compare template), plus one ask-and-wait turn. That is an estimate, not a measurement. Human latency dominates.
  • Skip when:
    • the change is not visually observable;
    • the lightweight carve-out applies (use an inline diff);
    • the user said "no visual": Proposal mode: off | inline in PROJECT.md, in the same style as Interview mode;
    • the screen was already approved in the Stage 3 prototype and this is its first build.

Risks

  • Approval fatigue. Batch per slice or phase: one page, one question, "approve all / one by one". When more than about 5 screens change at once, route back to Stage 3 instead.
  • Wireframe vs real Atlas rendering. Prefer a real screenshot as "before" and label "after" as intent, not pixels. The approved | built column is where drift shows, and the LOOK judges it. B0 check-design-reaches-app.sh covers the token gap. Do not move wireframes to Atlas classes (skills/existing-app-assurance.md).
  • A "before" drawn from describe output is lossy. Label it so and prefer a screenshot.
  • Rubber-stamp. Approval proves the user saw the design, not that it suits several roles and objects. That is Usability/flow defects pass every gate: proposal for a Stage-3 interaction-model deliverable and gate #291's job.
  • Renderer creep. Keep it as a skill; see skills-over-scripts.

Open questions

  1. Approval granularity: per screen, per change, or per phase with batching? I recommend per change, batched.
  2. v2 join verdict for an edited wireframe with no approval row: FAIL or MANUAL?
  3. For an existing app with no screenshot on disk: accept a describe-derived "before", or start the app once for a real screenshot? A real screenshot costs an app start, not mxbuild.
  4. Should non-UI proposals share the proposal folder, or ride on the drift-sync decision row only?
  5. Unattended runs: queue the proposal as ASSUMED, or block page scripts for that screen until an attended session approves?
  6. Should the proposal page carry Usability/flow defects pass every gate: proposal for a Stage-3 interaction-model deliverable and gate #291's "two objects, two roles" walk for the changed screen?
  7. Which host-detection output will this consume?

Next steps

  1. Draft skills/propose-before-build.md (experimental, lead-only) plus its routing row; run bin/render-routing.sh --check.
  2. Use it by hand on two real changes: one mid-build requirement on a greenfield or requirements-driven app, and one change to an existing .mpr. Record per change:
    • tokens spent;
    • wall time to approval;
    • whether the user changed the proposal;
    • whether the built page diverged.
  3. Decide from that evidence whether to add the v2 join, a compare-page helper, and promotion (with a behaviour A/B).

Sources

Caveat: the VS Code, Codex and Windsurf pages were read through search summaries, not fetched directly. The Cursor claims come from its forum.


Generated by Claude Code

Activity

  1. MendixMau commented on Oct 21, 2026

    @MendixMau
    OwnerAuthor

    Linked: #508 is narrowed to a model change view (before/after of the documents a script touches, or between two commits), to serve as this loop's picture for non-UI changes. It is parked until the hand trial of this loop on two real changes shows the picture is wanted.


    Generated by Claude Code

  2. MendixMau commented on Nov 3, 2026

    @MendixMau
    OwnerAuthor

    Parked (maintainer decision, 2026-11-03). Good direction, but it changes the process path in every entry mode. Revisit after the Stage 3 interaction-model gate (#291 / #333) lands, since that gives the wireframe a mechanical contract to approve against.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions