Skip to content

feat: UX clarity — project ownership, Examples separation, honest fallback, always-available Export - #70

Merged
ryandmonk merged 8 commits into
mainfrom
feat/composer-ux-clarity
Aug 10, 2026
Merged

feat: UX clarity — project ownership, Examples separation, honest fallback, always-available Export#70
ryandmonk merged 8 commits into
mainfrom
feat/composer-ux-clarity

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

The UX-clarity milestone: no new technology — the existing capabilities made understandable, and every screen made to reflect the active project. Every screen now answers What project am I looking at? What is this page for? What should I do next? Root causes from the approved audit; design forks implemented per the owner's decisions.

The one authorized behavior change — user-built surfaces are first-class project content (D2)

The architecture's own promise (projects.ts: reference-backed projects "may persist a small authored delta") — implemented:

  • Reference contract/profile + project-authored delta = working project. The delta (composer.project.examples.<id>) holds accepted builds and authored scenarios; it merges over the base on open. The canonical shadcn/Astryx reference is never mutated.
  • Accept works in the browser ("Add to project"): the same deterministic gate the agent applies, run client-side — S1–S3 lint, authored intent, collision-free ex.chat-N, never overwrite. The agent remains for writing to a real repository — not a prerequisite for owning browser-authored work.
  • Preview opens on the user's latest surface, with "Your surfaces" vs "Reference examples · " never mixed into one anonymous list; a fresh project says "none yet — build something in Build, then Add to project" instead of showing the reference gallery as the user's work; an inspected reference example states it is teaching material.
  • Scenarios: "Project scenarios" primary; the reference corpus is a labeled secondary section with copy-to-project (reference rows are never edited in place).
  • Export/duplicate/remove carry/clear the delta; a reload and an export/import round-trip preserve accepted work.

Examples separated from Your projects (D1)

A new hub Examples section (after Your projects): each packaged reference as a read-only example — Open example / Create copy. Opening is an ephemeral workspace: no StoredProject, no lastOpened (a reload lands where you actually work), pristine every open, labeled by an EXAMPLE chip + banner ("explore and edit freely; changes are not kept") with Duplicate into your projects — which carries session-accepted work via the delta. Reference examples remain inside user projects as internal context (few-shot, scripted replay, governance evidence) but never masquerade as authored content.

Honest wireframe fallback (D3)

registryFor now composes the universal wireframe visual under each native registry, per component (native wins name-by-name; identity-cached because the canvas memoizes on registry identity). Raw [unimplemented: X] text never appears in the product canvas; Preview's caption reads "N of M components render as wireframe (no native shadcn visual yet) — hover for the list". No renderer campaign; nothing silently approximated.

Export from the working experience (D4)

A quiet Export beside the project chip — Build → Preview → Export without returning to Projects. Hub card Export kept; examples don't export (duplicate first).

Clarity fixes (F1–F7)

  • Demo purge: a user's browser project is never called a demo. "You're in the hosted demo" → "This project runs in your browser — no install"; every "Demo: … edits stay in memory" note replaced with precise persistence language (Scenarios now truthfully persists); stale "build-time emit" claims corrected.
  • Stale references: no more "Validate view", "load the demo", "connect from Project", "Inventory", "Ownership panel"; Checks stops rendering a permanently-disabled Emit button for browser projects.
  • Page identity: title "Composer · Aesthetic Function"; honest description.
  • Ratified framings: Catalog = "the governed component vocabulary available to this project" + summary (34 components from shadcn/ui · 30 mapped · 4 declared casualties, explained); Governance = "the design-system rules and intent context governing this project" + summary, intent names first; Scenarios framed via ViewHeader.
  • Shell: every working route without a project falls back to the hub (five views previously rendered blank); the chip states the true source (shadcn/ui / Astryx / Imported / Local repository / Example — imported no longer reads HOSTED).
  • Dead code: DEMO_* consts, loadDemo, Reference.emit (−~760 KB of never-read JSON out of the client bundle). demo-project/ untouched (Acme migration golden).
  • Landed the stray lifecycle e2e test from the adoption closeout.

Verification

  • Composer units 19/19 (5 new registry invariants, fail-first proven: 5/5 fail on old registryFor).
  • Smoke (agent-free) 11/11, incl. 3 new milestone proofs — fail-first proven against a build of pre-milestone main (all 3 fail there exactly at the feature boundaries).
  • Agent suite: green across runs (43 specs; a11y spec updated for the intended accept-control rename; one intermittent in fix(composer): keep Hosted AI selectable when the local agent is up #69's provider test — 4/4 alone, filed separately).
  • Repo typecheck clean.

Test plan

  • CI green
  • Merge → Cloudflare deploy
  • Live acceptance on production: Hotel Reservation (shadcn, hosted-ai) — Build → honest wireframe fallback → Add to project → Preview default → Scenarios split → Catalog/Governance framing → top-bar Export → refresh + export/import preserve it; smaller Astryx equivalent; first-time-user audit.

🤖 Generated with Claude Code

ryandmonk and others added 7 commits August 10, 2026 11:16
…itch/remove)

Ran in the adoption-milestone closeout (8/8 incl. production) but was never
committed — the working tree held it since. Landing it verbatim.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A catalog name with no native visual now renders as its universal wireframe
representation inside the otherwise-native surface — never the raw red
"[unimplemented: X]" placeholder in the product canvas. Native renderer when
available → wireframe when not; the gap stays visible, not alarming.

- registries.ts: registryFor merges wireframe impls under the native custom
  map (native wins name-by-name), with a per-(catalog,id) identity cache —
  A2uiCanvas memoizes ingestion on registry identity and the Build canvas
  calls registryFor in its render body, so identity stability is required,
  not an optimization. New nativeRegistryFor + wireframeFallbackNames expose
  the honest PRE-merge gap.
- Preview: the coverage caption now reads "N of M components render as
  wireframe (no native shadcn visual yet) — hover for the list" instead of
  "unimplemented in this registry"; wireframe mode says what it is.
- app/registries.test.ts: 5 invariants (full post-merge coverage, honest
  pre-merge gap incl. Separator/Checkbox/Textarea, no fallback for
  full-coverage/wireframe, object identity, native-wins) — fail-first proven
  against the old registryFor (5/5 fail), green on the new (19/19).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build → Preview → Export without returning to Projects: a quiet Export
control sits beside the project context whenever a project is open (same
portable file as the hub card; no dropdown machinery). The context chip now
states the project's SOURCE in the hub's own words — shadcn/ui / Astryx /
Imported / Local repository — instead of conflating source with the HOSTED
execution mode (imported projects previously read HOSTED). Every working
route without a project now falls back to the hub; scenarios/checks/
component/mapper/repository previously rendered a blank page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The authored delta the project model always promised (projects.ts:12-15),
implemented: a browser project OWNS its accepted surfaces, persisted per
project id and merged over its base vocabulary on open. The canonical
reference is never mutated. Reference contract/profile + project-authored
delta = working project.

- projects.ts: composer.project.examples.<id> delta store (quota-honest),
  mergeExamples (replace-by-id else append — authored work lands LAST, which
  is what scripted replay and few-shot want), examplesDelta (recomputed
  live-vs-base each save; no incremental bookkeeping), nextChatExampleId
  (agent's rule, kept in sync); duplicate copies the delta, remove clears it.
- state: loadReference(id, projectId?) merges the delta and records
  referenceExampleIds (provenance by BASE MEMBERSHIP, never id prefix);
  loadImported merges its delta (an imported bundle is all project-owned);
  saveContract's browser branch persists the delta — scenario-view saves get
  persistence for free; exportProject merges the delta for closed projects
  so "take it with me" includes accepted work.
- Accept works in the browser: acceptBuildTurn's browser branch runs the
  SAME deterministic gate client-side (S1–S3 via lintOneSurface, authored
  intent, collision-free ex.chat-N against the merged set, never overwrite)
  then saves through the one funnel. The agent remains for writing to a real
  repository — not a prerequisite for owning browser-authored work. The
  Build control reads "Add to project" in both modes with an honest hint.
- Preview: "Your surfaces" (opens on the LATEST project surface) vs
  "Reference examples · <DS>" — never one anonymous list; an inspected
  reference example says what it is; honest empty state ("none yet — build
  something, then Add to project").
- Scenarios: ViewHeader + ratified framing; "Project scenarios" primary with
  its own empty state; "Reference examples · <DS>" secondary with
  copy-to-project (the canonical row is never edited in place; agent
  projects are unaffected — their contract is wholly their own).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mple workspaces

The hub now draws the line the mental model needs: "Your projects" holds only
what the user created or imported; a new "Examples" section holds the
packaged references as teaching material — "Open example" / "Create copy",
never mixed with the user's work.

- Opening an example is EPHEMERAL: no StoredProject, no lastOpened (a reload
  lands where you actually work), pristine on every open. The shell labels it
  unmistakably — EXAMPLE chip + a banner ("a read-only reference; explore and
  edit freely; changes are not kept") with "Duplicate into your projects".
  Play is allowed because demo-mode edits were always session-only; honesty
  is the label, not a lock.
- duplicateExample carries the session's accepted work into the new project
  via the authored delta — "duplicate to keep what you build" is real.
- Example workspaces flip the ownership framing: Preview shows "Example
  surfaces" (the reference gallery IS the content), Scenarios "Example
  scenarios", Build's accept hint says session-only + duplicate to keep. No
  Export in an example (an example is not the user's portable work).
- Examples section renders AFTER Your projects with example-* testids — the
  smoke suite's project-export-* prefix locator and grid-scoped selectors are
  unaffected; the first-run empty state points to the examples.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tities

A user-created browser project is not a demo. "Hosted/in-browser" is an
execution mode; "example/reference" is teaching material; "my project" is
ownership — the copy now keeps those apart everywhere.

- Demo purge: Build's "You're in the hosted demo — no install" → "This
  project runs in your browser — no install"; every per-view "Demo: … edits
  stay in memory" note replaced with precise session/persistence language
  (Scenarios now truthfully says saves persist to the project); the
  factually-stale runEmit/mapper claims of "build-time emit" corrected (emit
  recomputes live in-browser).
- Stale references: Preview's empty state no longer points at a "Validate
  view" or a "load the demo" that doesn't exist; Checks stops rendering a
  permanently-disabled "Emit catalog" button for browser projects and states
  what actually happens; component-view says Catalog (not Inventory); Build
  says "Projects → Connect a repository" (not "connect from Project");
  notices say Checks (not Validate) and Repository view (not "Ownership
  panel").
- Page identity: title "Composer · Aesthetic Function" (was "Catalog
  Composer · Aesthetic Function Studio") + a description that matches the
  actual product story.
- Ratified framings: Catalog = "the governed component vocabulary available
  to this project" with a summary line (N components from <DS> · M mapped ·
  K declared casualties, casualties explained); Governance = "the
  design-system rules and intent context governing this project" with a
  summary line and intent NAMES first (ids secondary) instead of a wall of
  id+prose; Scenarios' ViewHeader landed with the ownership split.
- Dead code: DEMO_* consts, loadDemo, and Reference.emit removed — the two
  never-read ~380 KB emit JSONs leave the client bundle; stale comments
  corrected (modes doc no longer claims an "Acme UI demo project").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three new smoke specs prove the UX-clarity milestone end to end, fail-first
verified against a build of pre-milestone main (all three fail there: no
browser Accept, no Preview ownership groups, no Examples section):

- a built surface becomes first-class project content: scripted build →
  "Add to project" → ex.chat-1 is Preview's DEFAULT surface with the
  reference corpus in its own labeled group → Scenarios lists it under
  Project scenarios → survives reload (persisted delta) → top-bar Export's
  file carries it. Also asserts the honest wireframe fallback: a reference
  surface using Switch/Separator renders [data-wireframe] stand-ins under
  the shadcn registry, the caption says "render as wireframe", and raw
  "[unimplemented:" text never appears.
- a fresh project's Preview is honest: "none yet — build something", the
  reference gallery labeled as references, and an inspected reference
  example states it is teaching material.
- Examples are teaching material: separate hub section, ephemeral read-only
  workspace (EXAMPLE chip + banner; never in Your projects; a reload lands
  the hub, not a resurrected example), and Duplicate creates a normal
  project.

Also: composer-build-a11y updated for the accept control's new accessible
name ("Accept turn N into the project" — the intended rename).

Local gates: smoke 11/11 · composer units 19/19 · repo typecheck clean ·
agent suite green across runs (one intermittent in #69's provider test,
4/4 alone — filed separately, not chased here).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 10, 2026 15:59
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
dspack-studio-composer f20bde4 Aug 10 2026, 04:04 PM

… does

registries.test.ts asserts against the real generated emit catalogs; CI's
unit step ran before anything generated them (locally they existed from
typecheck). Mirror the typecheck script's own idiom. Verified by deleting
app/demo/generated and running the test script: regenerates, 19/19.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

This PR delivers the “UX clarity” milestone for Composer by making project ownership explicit across views, separating packaged Examples from user projects, persisting browser-authored worked surfaces as first-class project content, and ensuring Preview never shows raw unimplemented placeholders (wireframe fallback is always used).

Changes:

  • Add a persisted “authored examples delta” for browser projects (accepted Build surfaces + authored Scenarios), merged over reference/imported bases on open/export.
  • Introduce an Examples hub section with an ephemeral read-only “example workspace” plus “Duplicate into your projects” to keep session-accepted work.
  • Make Preview’s native registries compose a per-component wireframe fallback, add honest coverage messaging, and add always-available in-context Export.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated no comments.

Show a summary per file
File Description
e2e/composer-prod-smoke.spec.ts Adds prod smoke coverage for browser accept→persist→preview/scenarios separation, examples hub behavior, and in-context export.
e2e/composer-build-a11y.spec.ts Updates accessible-name assertion for the renamed Accept/Add-to-project control.
apps/composer/app/views/validate-view.tsx Makes Emit control honest/conditional and updates explanatory copy for browser vs agent mode.
apps/composer/app/views/scenario-view.tsx Splits project scenarios vs reference examples; adds “copy to project” for references; updates framing/header.
apps/composer/app/views/projects-view.tsx Adds Examples section (open ephemeral example / create copy) and updates empty-state guidance.
apps/composer/app/views/preview-view.tsx Separates “Your surfaces” vs reference surfaces; defaults to latest project surface; replaces coverage logic with wireframe-fallback reporting; adds reference labeling and empty-state.
apps/composer/app/views/mapper-view.tsx Updates persistence language to reflect browser-session vs agent-backed saves.
apps/composer/app/views/inventory-view.tsx Reframes Catalog copy and adds a concise catalog summary line.
apps/composer/app/views/governance-view.tsx Reframes Governance copy, adds summary counts, and changes intent list presentation.
apps/composer/app/views/component-view.tsx Updates terminology (“Catalog”) and save-status message for browser session behavior.
apps/composer/app/views/build-view.tsx Makes “Add to project” available in-browser (and in example sessions with correct messaging); updates hosted/browser copy.
apps/composer/app/state.tsx Implements examples-delta persistence/merge, example workspace + duplication, browser-side accept gating, updated notices, and removes demo-loading path.
apps/composer/app/registries.ts Adds merged registry composition (native + wireframe fallback), identity caching, and fallback-name reporting.
apps/composer/app/registries.test.ts Adds unit tests for merged registry coverage, honest gap reporting, identity caching, and precedence rules.
apps/composer/app/projects.ts Adds localStorage-backed examples-delta storage/merge/diff utilities and ensures duplicate/remove carry/clear the delta.
apps/composer/app/layout.tsx Updates product title/description metadata to match new framing.
apps/composer/app/hosted-build.ts Updates error copy to reflect “browser project” terminology.
apps/composer/app/demo-data.ts Reframes packaged references as design systems/examples material; removes pre-emitted JSON from reference shape.
apps/composer/app/composer.tsx Updates project-context chip semantics, adds top-bar Export (non-example), adds example banner + duplicate action, and makes hub fallback cover all working routes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ryandmonk
ryandmonk merged commit 757aca4 into main Aug 10, 2026
2 checks passed
@ryandmonk
ryandmonk deleted the feat/composer-ux-clarity branch August 10, 2026 16:09
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