Skip to content

feat: pre-1.0 first impression — native preview, real wireframes, human labels, Flows in nav - #82

Merged
ryandmonk merged 2 commits into
mainfrom
feat/pre1-first-impression
Aug 12, 2026
Merged

feat: pre-1.0 first impression — native preview, real wireframes, human labels, Flows in nav#82
ryandmonk merged 2 commits into
mainfrom
feat/pre1-first-impression

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

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 labelled EX.CHAT-1; three red refused rows 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.

  • B5 native-registry default via two pure functions, with a stale cross-project selection clamping to this project's default.
  • B6 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.
  • B7 surface-identity.tsname → prompt → description → id, empty-safe and truncated; applied in Preview, flow pickers, the Surfaces listing, and accept messaging. Ids remain visible for audit.
  • B8 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.
  • C9 nav becomes Build · Preview · Surfaces · Flows · Catalog · Governance · Checks; Flows renders the Preview view focused on flows — no duplicated canvas logic.
  • C10 hub leads with the three beats (describe · built from approved components · composed into a workflow) and states the boundary as a position: representations now; live data, running workflows, and state between steps next.
  • C11 "Scenarios" retired from the UI; "reference examples" → "reference surfaces" so example only ever means a reference project. One testid renamed (nav-scenariosnav-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 test 11 packages green, typecheck green, composer smoke 14/14, composer-agent 44/44.

🤖 Generated with Claude Code

ryandmonk and others added 2 commits August 12, 2026 11:32
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=[&quot;Invoice&quot;,&quot;Status&quot;,&quot;Amount&quot;]</span>
    <span …>rows=[{&quot;cells&quot;:[&quot;INV-001&quot;,&quot;Paid&quot;,&quot;$120.00&quot;]},…]</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>
Copilot AI lite review requested due to automatic review settings August 12, 2026 15:56
@cloudflare-workers-and-pages

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 7565496 Aug 12 2026, 03:58 PM

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

Comment thread README.md
@@ -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,
);
@ryandmonk
ryandmonk merged commit 9148876 into main Aug 12, 2026
3 checks passed
@ryandmonk
ryandmonk deleted the feat/pre1-first-impression branch August 12, 2026 16:03
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