feat: pre-1.0 first impression — native preview, real wireframes, human labels, Flows in nav - #82
Merged
Merged
Conversation
The assertions for Phases B and C, written against the CURRENT product and
run red before a line of implementation exists.
- registries.test.ts: defaultRegistryId / resolveRegistryId — a project
previews as ITSELF (native when it has one, wireframe only as fallback),
and a selection carried over from another project clamps to this one's
default instead of silently rendering the wrong system.
- surface-identity.test.ts (new): the human title (name -> prompt ->
description -> id), empty-safety, truncation, and the ownership
partition every picker orders by — the user's work first, refusals
demoted by OWNER rather than hidden.
- wireframe.test.tsx: the registry must draw low-fidelity STRUCTURE, not a
props dump. Asserted on an inline collection catalog the package has
never seen, so the rule stays generic and data-driven.
- composer-prod-smoke.spec.ts: a first-run journey — one scripted build,
one accept, then Preview through the NATIVE registry, the user's surface
FIRST with a human label, refused reference surfaces behind one honest
disclosure, and Flows one click from the nav.
Existing specs updated deliberately in this commit (old copy pinned by
them is being retired): nav-scenarios -> nav-surfaces (composer-build.spec,
composer-prod-smoke.spec), "Reference examples" -> "Reference surfaces",
and the wireframe test's `label=Acknowledge` / `variant=primary` props-dump
assertions, which pinned exactly the debugger view B6 removes.
--- pnpm --filter composer test ---------------------------------------
❯ app/registries.test.ts (10 tests | 5 failed) 5ms
× defaultRegistryId — a project previews as itself > defaults to the project's native registry when it has one
→ (0 , defaultRegistryId) is not a function
× defaultRegistryId — a project previews as itself > falls back to wireframe only when there is no native registry
→ (0 , defaultRegistryId) is not a function
× resolveRegistryId — a stale selection clamps safely > honours an explicit choice this project can render
→ (0 , resolveRegistryId) is not a function
× resolveRegistryId — a stale selection clamps safely > clamps a selection carried over from ANOTHER project back to this one's default
→ (0 , resolveRegistryId) is not a function
× resolveRegistryId — a stale selection clamps safely > no selection, or an unknown one, is the project's default
→ (0 , resolveRegistryId) is not a function
⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯
FAIL app/surface-identity.test.ts [ app/surface-identity.test.ts ]
Error: Cannot find module './surface-identity' imported from
'/Users/ryandombrowski/Desktop/dspack-studio/apps/composer/app/surface-identity.test.ts'
Test Files 2 failed | 8 passed (10)
Tests 5 failed | 76 passed (81)
--- pnpm --filter @dspack-studio/wireframe-renderers test --------------
❯ src/wireframe.test.tsx (11 tests | 9 failed) 15ms
× classifies a value prop's SHAPE from the catalog (enum, boolean, text, structure)
→ expected undefined to be 'text' // Object.is equality
× renders a labeled wireframe with real text, a state chip, and an inert action
→ expected '<span style="display:contents" data-a…' not to contain 'label=Acknowledge'
× renders child references through buildChild without executing user code
→ expected '<span style="display:contents" data-a…' to contain 'data-wire="block"'
× the wireframe is a structural sketch… > never serializes props into the visual
→ expected '<span style="display:contents" data-a…' not to contain 'rows=[{'
× the wireframe is a structural sketch… > draws the component name and a structural sketch
→ expected '<span style="display:contents" data-a…' to contain 'data-wire-sketch'
× the wireframe is a structural sketch… > a header band uses the REAL column labels and count
→ expected '<span style="display:contents" data-a…' to contain 'data-wire-band="header"'
× the wireframe is a structural sketch… > row bands use the REAL row count and show the row's own text
→ expected [] to have a length of 3 but got +0
× the wireframe is a structural sketch… > a long collection stays a sketch: bands are capped and the remainder is stated
→ expected 0 to be greater than 0
× the wireframe is a structural sketch… > textual props read as text lines — the honest 'no native visual here', never an error
→ expected '<span style="display:contents" data-a…' to contain 'data-wire="text"'
The received markup, verbatim — the debugger view B6 exists to remove:
<div data-wireframe="Table"><div …>Table</div><div …>
<span …>caption=Recent invoices</span>
<span …>columns=["Invoice","Status","Amount"]</span>
<span …>rows=[{"cells":["INV-001","Paid","$120.00"]},…]</span>
</div></div>
--- playwright --config playwright.composer-smoke.config.ts ------------
-g "first run: the project previews as ITSELF"
1) first run: the project previews as ITSELF, the user's work leads with
a human label, and Flows is one click away
Error: expect(locator).toHaveClass(expected) failed
Locator: getByTestId('registry-shadcn')
Expected pattern: /st-btn--active/
Received string: "st-btn"
14 × locator resolved to <button class="st-btn" data-testid="registry-shadcn">shadcn</button>
1 failed
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A newcomer picked shadcn, typed a goal, watched four gates go green, and then
met a debugger: a greybox printing `rows=[{"cells":…}]`, their own work
labelled `ex.chat-1`, fourteen reference chips and three red refusals in front
of it, and no way to reach Flows. Every one of those is fixed here; nothing
about contracts, emit, generation, A2UI, intents, or governance moved.
B5 — Preview opens on the project's own design system.
`defaultRegistryId` / `resolveRegistryId` (registries.ts) own the rule:
native when the project has one, wireframe only as fallback, and a
selection carried over from another project clamps to THIS project's
default instead of drawing the wrong catalog. Wireframe stays a first-class
inspection mode with its honest coverage caption; it is now the mode you
switch INTO, not the one every project meets first. Identical for
single-surface and flow mode, because both read one resolved id.
B6 — a wireframe looks like a wireframe.
New `sketch.tsx` draws low-fidelity structure from the data's own shape:
text lines for genuinely textual values, state chips for enums and flags, a
header band sized by the real column count, one row band per real record
with the record's own cell text, bordered blocks for nesting, and a stated
remainder past the cap. `classifyProps` now also reports a prop's declared
SHAPE (DynamicString/enum/boolean/number/array/object), so every decision
comes from the catalog plus the value — no component names, no design
system, no hand-written visuals. A catalog the package has never seen
sketches as well as the ones it ships with; nothing is ever serialized.
B7 — surfaces have human titles.
New `surface-identity.ts` resolves name → prompt → description → id, empty
safe, whitespace-collapsed, word-boundary truncated. Applied in Preview's
surface picker, the flow step picker, the flow editor's step rows, the flow
navigator tooltips, the Surfaces listing, and Build's accept confirmation
and notices. The canonical id is never dropped — it sits beside the title,
small, so an audit is one glance away. Accepted builds now mint the goal
itself as the title (the `ex.chat-N` id still carries the provenance).
B8 — the user's work is visually primary.
`partitionSurfaces` groups by OWNER first, then by whether the surface
renders: yours, yours-refused, reference, reference-refused. Every picker
orders by it. The three reference surfaces the emitter refuses now sit
behind one honest disclosure ("3 reference surfaces can't be emitted —
why?") that opens to the verbatim reasons; the project's OWN refusals stay
in front of the person whose work they are. The flow editor's step dropdown
is optgrouped the same way instead of a flat list with the user's surface
last.
C9 — Flows in the primary navigation.
`Build · Preview · Surfaces · Flows · Catalog · Governance · Checks`.
Flows renders `<PreviewView focus="flows" />`: the same canvas, the same
flow code, opened on flow mode with a flows-specific header and a real
empty state. No duplicated preview logic.
C10 / C10b — the hub tells the workflow story, and states the boundary.
The hub leads with what you get — describe a screen, build it from your
design system's approved components, compose those screens into a walkable
workflow — and follows with the honest position: Composer composes and
governs interface REPRESENTATIONS; live data, running workflows, and state
between steps are where it goes next. Preview carries the same sentence
where a person is actually walking one.
C11 — the ratified vocabulary, everywhere a person reads.
Surface / Flow / Step / Example. "Scenarios" is gone from the UI; inside a
project "reference examples" are "reference surfaces", so "example" only
ever means a reference PROJECT on the hub. Internal names are untouched by
design: `contract.examples`, `ex.*` ids, `packages/scenarios`,
`scenario-view.tsx`, the `scenario-*` data-testids, AG-UI STEP_* events.
Specs updated deliberately (they pinned copy this retires):
- e2e/composer-prod-smoke.spec.ts, e2e/composer-build.spec.ts —
`nav-scenarios` -> `nav-surfaces` (the only data-testid renamed);
"Reference examples" -> "Reference surfaces"; the agent-side scripted
refusal now says "own surface".
- packages/composer-core/src/composer-core.test.ts — the readiness reason
no longer says "worked example ... save one scenario first".
- apps/agent/src/project.test.ts — same message, agent side.
- packages/wireframe-renderers/src/wireframe.test.tsx — the
`label=Acknowledge` / `variant=primary` assertions pinned the props dump
itself.
Green: pnpm test (11 packages), pnpm -r typecheck (12 projects),
composer smoke 14/14, composer-agent 44/44.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
dspack-studio-composer | 7565496 | Aug 12 2026, 03:58 PM |
There was a problem hiding this comment.
Pull request overview
This PR updates Composer’s first-run/product presentation so Preview defaults to the project’s native design system, wireframes become structural sketches (not serialized prop dumps), “Scenarios” is renamed/positioned as “Surfaces”, and “Flows” becomes a first-class nav entry by reusing Preview in flow-focus mode.
Changes:
- Replace wireframe prop-dump rendering with a catalog-driven structural sketch (bands/cells/chips/blocks) and expand tests to forbid serialized-props output.
- Introduce surface identity + ownership partitioning (human titles, yours-first ordering, collapsed reference refusals) and apply it across Preview/Surfaces/Build messaging.
- Update navigation + docs/tests to reflect Surfaces/Flows and the revised first-run journey.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates product terminology in docs (Preview/Surfaces/Flows wording). |
| packages/wireframe-renderers/src/wireframe.test.tsx | Adds coverage for shape classification + “never props dump” invariants. |
| packages/wireframe-renderers/src/sketch.tsx | New structural sketch renderer for low-fidelity wireframes. |
| packages/wireframe-renderers/src/registry.tsx | Switches wireframe registry rendering from prop chips to structural sketch + improved slots/actions. |
| packages/wireframe-renderers/src/index.ts | Exposes WireShape type. |
| packages/wireframe-renderers/src/classify-props.ts | Adds WireShape and catalog-driven shape classification for value props. |
| packages/composer-core/src/composer-core.test.ts | Updates readiness messaging expectations to “no surfaces yet”. |
| packages/composer-core/src/build.ts | Updates build readiness failure reason to “no surfaces yet”. |
| e2e/composer-prod-smoke.spec.ts | Aligns e2e expectations with Surfaces/Flows + validates no serialized props dump in wireframe fallback. |
| e2e/composer-build.spec.ts | Updates navigation/test assertions from Scenarios → Surfaces and copy updates. |
| docs/COMPOSER.md | Updates documentation language to Surfaces while preserving storage details. |
| apps/composer/app/views/settings-view.tsx | Adjusts scripted-mode labeling/copy to “replays a surface”. |
| apps/composer/app/views/scenario-view.tsx | Repositions Scenario authoring UI as Surfaces; adds human surface titles and copy changes. |
| apps/composer/app/views/repository-view.tsx | Updates progress language from worked examples → surfaces. |
| apps/composer/app/views/projects-view.tsx | Updates hub copy and clarifies “Example = reference project” vocabulary. |
| apps/composer/app/views/preview-view.tsx | Implements native-registry defaulting, surface title/partitioning, collapsed reference refusals, and flow-focused mode. |
| apps/composer/app/views/governance-view.tsx | Updates governance copy from worked examples → surfaces. |
| apps/composer/app/views/build-view.tsx | Updates accept/refusal messaging and surfaces terminology in Build. |
| apps/composer/app/surface-identity.ts | New utilities for surface titles + ownership partitioning logic. |
| apps/composer/app/surface-identity.test.ts | Tests title resolution/truncation and ownership partition behavior. |
| apps/composer/app/state.tsx | Updates accepted-surface metadata/title and notice copy to match new vocabulary. |
| apps/composer/app/registries.ts | Adds default/resolve helpers so Preview opens on the project’s native registry. |
| apps/composer/app/registries.test.ts | Tests default/resolve registry selection behavior. |
| apps/composer/app/hosted-build.ts | Updates scripted-mode error copy to surfaces terminology. |
| apps/composer/app/composer.tsx | Adds Surfaces + Flows views to nav; Flows routes to Preview in flow-focus mode. |
| apps/agent/src/project.ts | Updates scripted-mode error message to Surfaces terminology. |
| apps/agent/src/project.test.ts | Updates assertions for the new scripted-mode error phrasing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @@ -82,7 +82,7 @@ Both can be reachable at once. When the local agent is connected, Hosted AI stay | |||
| ## Projects | |||
|
|
|||
| - **Your projects** holds only what you created or imported. **Examples** (on the same hub) are read-only reference projects — the design systems' own worked examples, scenarios, and governance — for learning: *Open example* to explore (changes are not kept), *Create copy* to start your own. | |||
Comment on lines
371
to
+375
| {mode === "agent" | ||
| ? "Saves into your repository's contract on disk as a worked example." | ||
| ? "Saves this surface into your repository's contract on disk." | ||
| : isExample | ||
| ? "Kept for this session only — duplicate this example into your projects to keep what you build." | ||
| : "Saves to this project in your browser as a worked example — it appears in Preview and Scenarios, and seeds future generation."} | ||
| : "Saves this surface to your project in your browser — it appears in Preview, Surfaces, and any flow you compose, and it becomes context the next build learns from."} |
Comment on lines
1299
to
1303
| setNotice( | ||
| (activeProjectId | ||
| ? `Accepted as '${id}' — saved to this project in your browser; it now seeds generation for '${turn.intent}'.` | ||
| : `Accepted as '${id}' for this session — duplicate this example into your projects to keep it.`) + bound.note, | ||
| ? `Saved “${entry.name}” (${id}) to this project — it is one of your surfaces now, and context the next '${turn.intent}' build learns from.` | ||
| : `Saved “${entry.name}” (${id}) for this session — duplicate this example into your projects to keep it.`) + bound.note, | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phases B and C of the pre-1.0 product-readiness milestone: make the payoff moment demonstrate the product instead of exposing debugging machinery. Product-language and presentation only — no contract, governance, intent, A2UI, or pipeline change.
The first-run journey, before → after. Before: create a project, type a goal, watch four gates go green — and Preview opens on wireframe, showing a debug greybox of serialized props (
columns=["Invoice",…] rows=[{"cells":…}]); the picker leads with eleven reference chips while your work is one chip labelledEX.CHAT-1; three redrefusedrows sit underneath; the nav says Scenarios and Flows is nowhere. After: Preview opens in shadcn with the real dialog rendered; "Your surfaces" leads with "let people permanently delete their account" and its id beside it; reference surfaces are a dimmer second row; refusals collapse behind one honest line; wireframe is a click away and now draws structure (header band, row bands from the real records, state chips); Flows is in the nav.wireframe-renderers/sketch.tsx— structural sketches driven by the catalog's declared prop shapes plus runtime values. Generic across catalogs; no per-design-system visuals.surface-identity.ts—name → prompt → description → id, empty-safe and truncated; applied in Preview, flow pickers, the Surfaces listing, and accept messaging. Ids remain visible for audit.partitionSurfaces— yours / yours-refused / reference / reference-refused, applied to rows, the (now optgrouped) step dropdown, and default selection. Your own refusals stay inline; reference refusals collapse.Build · Preview · Surfaces · Flows · Catalog · Governance · Checks; Flows renders the Preview view focused on flows — no duplicated canvas logic.nav-scenarios→nav-surfaces), every spec updated in the same commit.Fail-first evidence in
de85b56(including the received markup showing the props dump the wireframe test now forbids).pnpm test11 packages green, typecheck green, composer smoke 14/14, composer-agent 44/44.🤖 Generated with Claude Code