Commit Graph

244 Commits

Author SHA1 Message Date
Jordan Ritter 8714ab569b chore(showcase): apply oxfmt formatting across showcase scripts and shells
oxfmt --write normalized formatting on showcase scripts, the four shells, and the
new oxlint rule; required for the repo-root oxfmt --check CI gate.
2026-05-29 11:45:16 -07:00
Jordan Ritter 09b9f8910b chore(showcase): pre-push cleanup -- comment rot, log levels, env coalesce, test hardening
Non-functional cleanup pass on the showcase deploy-pipeline integration
branch. All changes are scoped to comment rot, log severity for already-
demoted runtime-config fields, length-aware env-name coalescing (a
deliberately-empty primary no longer masks a populated alternate), and
test-quality tightening. No production behavior change beyond the
specific items below.

Changes by area:

- shell/shell-dashboard/shell-docs runtime-config.ts: factor the
  `process.env[primary] ?? process.env[alt]` chain into a shared
  length-aware `readEnvPair` helper. The prior `??` form treated
  `PRIMARY=""` as set, masking a populated alternate; the helper now
  treats empty-string as unset and falls through to the alternate.
- shell-docs runtime-config.ts: demote the two recoverable URL fields
  (`intelligenceSignupUrl`, `posthogHost`) from console.info to
  console.warn. The `FATAL-CONFIG:` Sentry-alert prefix is preserved
  only on the true sentinels; the demoted fields now clear prod log-
  aggregation thresholds without raising ops alerts.
- All three shells' runtime-config.ts: prefix log lines with the shell
  name (e.g. `[shell-docs runtime-config]`) so the shared log stream
  identifies which shell emitted the line.
- shell-docs runtime-config-serialize.ts: rewrite the U+2028 / U+2029
  RegExp arguments using six-character ASCII backslash-u escape
  sequences (was: literal codepoints in the string arg). The literal
  codepoints are line terminators that a formatter or editor could
  silently strip, breaking the security-critical XSS escape. The
  ASCII form is robust to any such pass.
- shell-docs use-google-analytics.test.ts: de-tautologize the hook-
  order test. It now asserts `usePathname(` and `useEffect(` both
  exist in the source, so deleting all hooks would fail the test
  rather than trivially satisfying the early-return path.
- shell-dashboard baseline-types.test.ts: update the partner-count
  expectation from 25 to 26 -- the 26th entry (Cloudflare) is a
  legitimate integration that landed independently; the test was
  stale and had nothing to do with this branch.
- scripts/resolve-verify-matrix.ts: drop the `FIX 7 --` plan-
  internal prefix from a comment; keep the explanation.
- shell-docs/.env.example: correct the `NEXT_PUBLIC_SHELL_URL`
  fallback claim (sentinel, not canonical prod host) and document
  the remaining 7 consumed env vars with their FATAL/warn/silent
  semantics so the example matches runtime-config.ts.

Skipped:
- C-SENTINEL-DEDUP (`http://ops.invalid` shared constant across
  shell-dashboard's next.config.ts and runtime-config.ts): both
  files are at different module levels (root vs src/lib) and the
  string appears once in each; extracting to a shared module would
  widen the diff into a refactor for marginal benefit. Skipped per
  the spec's "if it widens diff awkwardly, skip" guidance.
- C-SSRTEST: already exhaustively covered. Each of the three shells
  has an SSR placeholder test that exercises every URL field via
  `new URL()` parseability and (for shell-docs) the analytics-key
  empty-string semantics. Treated as a no-op.

Validation: shell + shell-dashboard + shell-docs runtime-config /
serialize / GA tests green; bin/showcase Ruby suite green (87 runs);
showcase/scripts resolve-verify-matrix + aggregate-build-results +
lint-rule-no-public-env green (79 runs).
2026-05-29 11:45:15 -07:00
Jordan Ritter 28f33ecc8a fix(showcase): stop SSR 500 + hook-order regressions in shell runtime-config; tolerate env-name variants
Six fixes addressing CR findings on the Option-B runtime URL-injection migration:

1. SSR_PLACEHOLDER must be parseable URL sentinels — `new URL("")` throws on
   SSR causing 500s for any consumer that constructs URLs from runtime-config
   fields. Use `.invalid`-TLD sentinels (RFC 2606) for URL fields; analytics
   keys stay empty string. Add `suppressHydrationWarning` on consumers that
   render the placeholder server-side and the real value post-hydration
   (integration-grid, page-actions popover).

2. Hook-order: move `usePathname()`/`useEffect` ABOVE the early-return in
   use-google-analytics. Gate the effect bodies on `GA_ID` instead so React
   sees a stable hook order across renders.

3. `readUrl`/`readKey` accept either bare or `NEXT_PUBLIC_*`-prefixed env
   names via a fallback chain — covers both server-only and inlined-public
   variable conventions without forcing a rename across deploy targets.

4. Extract `serializeRuntimeConfig` to `lib/runtime-config-serialize.ts` so
   the OWASP-escape behavior (XSS via </script>, U+2028/U+2029 line-terminator
   injection) can be unit-tested without importing the layout into vitest.

5. Reclassify `intelligenceSignupUrl`/`posthogHost` from FATAL-CONFIG to
   info-level in shell-docs — these are optional integrations, not hard
   wiring failures, so absence should not poison the error stream.

6. Comment-rot cleanup: drop "Option B", B12, "the bug we are fixing", fix
   "four substrings"→"three substrings" miscounts, and refresh shell-docs
   .env.example to describe the runtime-injection contract instead of a
   stale next.config throw claim.

V1: shell + shell-docs `next build` succeeds (no Edge-runtime crash on
`unstable_noStore`).
V2: `OPS_BASE_URL=` shell-dashboard `next build` no longer throws —
`next.config.ts` is now a phase-aware function that emits a sentinel
destination at build time and throws only at start (PHASE_PRODUCTION_BUILD
from next/constants).

Tests: shell-docs 72/72, shell 12/12, shell-dashboard runtime-config 16/16
(pre-existing baseline-partner-count failure unchanged).
2026-05-29 11:45:15 -07:00
Jordan Ritter f2ba6b2564 test(showcase): add no-rebuild env-switch integration test (spike replay)
Replay the Option B runtime-config spike as a vitest integration test
that guards the no-rebuild env switching property going forward:

  - `next build` once with no per-env URL env vars (only a sentinel
    OPS_BASE_URL so next.config.ts's rewrites() can validate; Next
    evaluates rewrites at build, not only at start, so a placeholder
    here is unavoidable — the assertions don't depend on it).
  - `next start` twice, each on a fresh port and a DIFFERENT
    POCKETBASE_URL / SHELL_URL / OPS_BASE_URL set.
  - Fetch `/` on each boot and extract the inlined
    `window.__SHOWCASE_CONFIG__={...}` JSON from the served HTML.
  - Assert env-A URLs on the first boot and env-B URLs on the second
    boot of the SAME built artifact. If anyone re-introduces a
    build-time URL bake, the second boot's HTML still shows env-A
    values and this test fails.

Test lives at `showcase/shell-dashboard/tests/runtime-env-switch.spike.test.ts`
and is picked up via a new vitest include for `tests/**/*.spike.test.ts`
(the default include is `src/**/*.test.{ts,tsx}` and the integration-
weight spike doesn't fit there). The `.spike.test.ts` suffix keeps
the include narrow so the visual snapshot suite under
`tests/visual/` stays out.

Total wall time locally: ~12s (build ~2s warm with prebuild data
generation already run; two boots ~10s combined). Heavy enough to
gate behind a `tests:integration` script in CI rather than running
on every push.
2026-05-29 11:45:09 -07:00
Jordan Ritter cc52235bb8 fix(showcase): make shell-dashboard runtime-config client SSR-safe
The client-side getRuntimeConfig() reader previously threw when window
was undefined, on the assumption that "use client" components only run
post-hydration. That assumption is wrong for the Next.js App Router:
"use client" component bodies ARE executed on the server during the
initial SSR pass (that's how the HTML stream is built before the JS
arrives), so throwing breaks SSR entirely — every page that uses a
client component which reads runtime config 500s on the first request
with `[runtime-config.client] getRuntimeConfig() called on the server`.

This was surfaced by the B13 spike-replay integration test (`next build`
once, `next start` twice with different POCKETBASE_URL/SHELL_URL/
OPS_BASE_URL): the inline `<script id="__showcase_config__">` injected
by the root layout never reaches the rendered DOM because the page
crashes during SSR and falls back to the Next.js error boundary, with
the would-be script content captured (and JSON-escaped) inside the
RSC streaming payload instead of as a real `<script>` tag.

Switch the SSR branch to return a sentinel RuntimeConfig with empty
strings rather than throwing. Client components see the placeholder
during the initial server render, then re-read post-hydration when
window.__SHOWCASE_CONFIG__ is populated. The post-hydration "config
missing" branch still throws so genuine wiring bugs (layout bypass,
empty injection) stay loud. Updated the matching unit test to assert
the new sentinel behavior in place of the old throw assertion.
2026-05-29 11:45:08 -07:00
Jordan Ritter 21cffdf638 refactor(showcase): require OPS_BASE_URL at start, not build, in shell-dashboard
Clarify that next.config.ts's rewrites() is evaluated once at process
start (not build time), matching the Option B runtime-injection model
where every NEXT_PUBLIC_* URL is read at request time from the Railway
env. The validation message now communicates start-time semantics so
operators know to set OPS_BASE_URL on the Railway service rather than
at image build time.
2026-05-29 11:45:06 -07:00
Jordan Ritter 6d8f3a07ee refactor(showcase): migrate shell-dashboard consumers to runtime-config
B8.1/B8.2/B8.3. Replaces every process.env.NEXT_PUBLIC_* read in
shell-dashboard consumer code with the runtime-config readers, all
in a single commit so the tree never sits red across a partial
rename.

B8.1 — src/lib/pb.ts: replace the eager module-load read with a
lazy getPb() getter. The previous `const resolvedUrl =
resolvePbUrl()` at module top froze the URL at import time, which
defeated runtime injection. Now the PB client is constructed on
first getPb() call from runtimeConfig.pocketbaseUrl. The
PocketBase instance is returned directly (NOT wrapped in a Proxy)
so `instanceof PocketBase`, detached methods, and this-sensitive
chains all work without surprise. pbIsMisconfigured is converted
from a const boolean to a function — every runtime-config-derived
export in the module is now a function call.

B8.2 — src/lib/ops-api.ts: resolveBaseUrl() now reads
runtimeConfig.opsBaseUrl on the client (gated on typeof window so
SSR / server tests still fall through to the explicit-param or
/api/ops fallback). The runtime-config throw is caught and
treated as 'no override' so a missing __SHOWCASE_CONFIG__ wiring
bug degrades to the safe same-origin rewrite path.

B8.3 — src/components/feature-grid.tsx: resolveShellUrl() body
collapses to `return getRuntimeConfig().shellUrl`. The sentinel
about:blank#shell-url-missing now lives in runtime-config.ts (its
single source of truth) instead of being re-implemented here.

Consumers and test mocks updated in the same commit:
- hooks: useBaseline.ts, useLiveStatus.ts, useLastTransition.ts —
  swap `pb` import for `getPb`, capture `const pb = getPb()`
  at hook/effect entry, change pbIsMisconfigured reads to
  pbIsMisconfigured() calls.
- pb-auth-prompt.tsx — capture getPb() once at the top of the
  submit handler.
- test mocks: useLiveStatus.test.tsx, useLastTransition.test.tsx,
  __tests__/useBaseline.test.ts, cell-pieces.test.tsx — vi.mock
  stubs return { getPb: () => pb, pbIsMisconfigured: () => false }
  to match the new function-form API.
- use-probes.integration.test.tsx + ops-api.test.ts — swap the
  env-var snapshot/clear pattern for the window.__SHOWCASE_CONFIG__
  pattern that mirrors the production code path.
2026-05-29 11:45:06 -07:00
Jordan Ritter fb5c608c1f refactor(showcase): inject __SHOWCASE_CONFIG__ in shell-dashboard root layout
B5. Root server layout (shell-dashboard) now calls getRuntimeConfig()
once per request and injects window.__SHOWCASE_CONFIG__ via an
inline <script id="__showcase_config__"> as the FIRST child of
<head>, BEFORE the theme-init script and well before any client
component reads the global during hydration.

Serialization uses the OWASP-recommended escape for inline JSON in
HTML:
- < → \\u003c so a URL containing </script> in a hostile env value
  cannot break out of the inline script tag.
- U+2028 / U+2029 → \\u2028 / \\u2029 because those codepoints are
  legal in JSON strings but a syntax error inside JS string literals
  when the page is parsed as text/javascript.

The regex sources use new RegExp() with \\u escape strings rather
than regex literals — U+2028 and U+2029 are line terminators that
prematurely close a regex literal in TypeScript / many JS engines.
2026-05-29 11:45:06 -07:00
Jordan Ritter 7f480b152c feat(showcase): add shell-dashboard runtime-config server+client
Workstream B (Option B, runtime injection). Adds the shell-dashboard
runtime-config module pair plus their unit tests:

- src/lib/runtime-config.ts (server): reads URL env vars at REQUEST
  time via unstable_noStore() so a single built artifact can serve
  different values across staging vs prod by changing the Railway
  service env vars. Sentinel fallbacks in production (visible
  breakage) + console.error; localhost fallbacks + console.warn in
  dev. getRuntimeConfigEdge() variant skips unstable_noStore for
  Edge-runtime middleware.
- src/lib/runtime-config.client.ts (client): reads
  window.__SHOWCASE_CONFIG__ injected by the root layout. Throws on
  SSR (no window) and when the global is missing, so wiring bugs
  surface loudly.
- runtime-config.test.ts + runtime-config.client.test.ts: 9 tests
  covering env values, trailing-slash strip, dev defaults, sentinel
  fallbacks + console.error, live-env-on-each-call (no module-load
  freeze), and the Edge wrapper's noStore skip.
2026-05-29 11:45:06 -07:00
Jordan Ritter b7fae67f01 refactor(showcase): drop NEXT_PUBLIC_* build-args from CI and Dockerfiles
Implements plan-B B11. URL and analytics NEXT_PUBLIC_* values now reach
each shell at runtime via Option B (env-driven runtime-config), so the
GHA showcase_build.yml workflow no longer threads them through as Docker
build-args and the shell-dashboard/shell-docs Dockerfiles no longer
declare the matching ARG/ENV pairs.

- showcase_build.yml: shell-dashboard and shell-docs matrix entries lose
  build_args_pb_url / build_args_shell_url / build_args_ops_url /
  build_args_base_url / build_args_analytics; the 'Prepare build args'
  step drops the corresponding env: keys and if-branches plus the five
  analytics NEXT_PUBLIC_* secrets. COMMIT_SHA and BRANCH stay — they
  identify the artifact.
- showcase/shell-dashboard/Dockerfile: remove ARG/ENV for
  NEXT_PUBLIC_SHELL_URL, NEXT_PUBLIC_POCKETBASE_URL, OPS_BASE_URL plus
  the explanatory comments. Update the runner-stage comment to point at
  runtime-config.ts as the new source of truth.
- showcase/shell-docs/Dockerfile: remove ARG/ENV for
  NEXT_PUBLIC_BASE_URL, NEXT_PUBLIC_SHELL_URL, NEXT_PUBLIC_POSTHOG_KEY,
  NEXT_PUBLIC_REB2B_KEY, NEXT_PUBLIC_SCARF_PIXEL_ID, NEXT_PUBLIC_REO_KEY,
  NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID. COMMIT_SHA / BRANCH retained.

shell/Dockerfile and shell-dojo/Dockerfile already only declare commit-sha
and branch ARGs — no changes needed there (per plan-B B11.4).
2026-05-29 11:45:05 -07:00
Tyler Slaton 8e59b1e2e9 chore: run pnpm format
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-05-29 08:17:21 -07:00
Alem Tuzlak 2405a46fa6 feat(showcase): add ms agent harness dotnet chat 2026-05-26 13:36:38 -07:00
Jordan Ritter 76020857e2 feat(showcase): per-framework D4/D6 aimock fixtures + D6 probe driver + harness scoping (#5022)
## Summary

Lands the per-framework fixture reorg + D6 probe driver + harness
scoping work that was parked behind the ag-ui header-forwarding chain
(now shipped via #4984, #4951, #5015, #5016).

This is the foundational data layer the D6 dashboard needs to populate.
Slice 1 (#5018) shipped the rendering plumbing earlier today; this PR
makes d6:<slug>/<featureId> PB rows start flowing.

## What ships

- 477 per-integration aimock fixtures organized under `d4/`, `d6/`,
`shared/` directories (flat `d5-all.json` / `feature-parity.json`
deprecated)
- Every fixture keyed by `match.context` to enforce per-integration
isolation (server-side routing already merged in aimock #226)
- D6 all-pills probe driver + per-integration scoping in
showcase-harness
- X-AIMock-Context header propagation in 18 integration Playwright
configs
- D6-ceiling chip color algorithm (D6 is integration-scoped aggregate,
maxPossible raised from 5 to 6)
- Docker-compose updates for the new fixture dir layout
- 12 HITL fixtures migrated from main's d5-all.json additions into
shared/_migrated-from-d5-all-hitl.json

## Why this is safe to ship now

- ag-ui/LangGraph configurable+context HTTP 400 blocker is fixed (#5015
+ #5016)
- sdk-python 0.1.91 with `_extract_forwarded_headers_from_config` is on
PyPI and pinned across showcase
- aimock server-side context routing is already live (aimock #226)
- The SDK overlay hacks the branch carried locally are now redundant —
discarded before rebase

## Pre-existing CI note

`@copilotkit/web-inspector:test` has a pre-existing failure
(`window.localStorage.clear is not a function` in telemetry tests) —
verified on clean main checkout. Not introduced by this PR.

## Follow-ups

- Distribute migrated HITL fixtures from shared/_migrated-from-*.json
into per-integration d6/<slug>/ files
- Slice 2: D6 drilldown DIMENSIONS + AdaptiveStatsBar rollup section
- LGP gen-ui-interrupt second-pill framework bug (Hypothesis B in
useInterrupt hook)
2026-05-26 11:59:46 -07:00
Jordan Ritter 5badfb82d6 feat(showcase-dashboard): D6-ceiling chip color algorithm + aggregate key
Update depth-utils to treat D6 as an integration-scoped aggregate
(d6:<slug> not d6:<slug>/<featureId>), raise maxPossible from 5 to 6
when D5 mapping exists, and adjust chipColor derivation so D5-green
without D6 yields amber instead of green. Update composed-cell memo
comparator and cell-drilldown dimensions. Comprehensive test updates
across cell-model, depth-utils, compute-tally-detail, unified-cell,
and status-tab.
2026-05-26 11:26:19 -07:00
Jordan Ritter 0eec6318e8 feat(showcase-dashboard): D6 rollup counter in AdaptiveStatsBar 2026-05-26 11:24:59 -07:00
Jordan Ritter 9236b82338 feat(showcase-dashboard): expose D6 dimension in cell drilldown panel 2026-05-26 11:19:22 -07:00
Jordan Ritter 5f2bdd9e53 feat(showcase-dashboard): render D6 chips on cells
Extends the active rendering path with D6 support so dashboard cells
can display D6 ("parity vs reference") state. cell-model.ts gains
ceilingDepth | 6 + d6 TestLevel field + resolveD6() + D6-ceiling
chip-color algorithm. unified-cell.tsx + feature-grid.tsx render the
new D6 chip. live-status.ts gets the small Dimension/BadgeRender delta
the branch needed.

Until d6:<slug>/<featureId> PB rows start flowing (separate PR for the
D6 probe driver + per-framework fixtures), every cell renders D6 gray
("no data -- probe pending"). This is the accurate state -- visibility
without functional risk.

Cherry-picked from feat-d6-everything-works (the per-framework fixtures
branch). The remainder of that branch -- d6-all-pills driver, fixture
reorg, harness config -- lands in a follow-up PR now that the ag-ui
header-forwarding prerequisites (#4984, #4951, #5015, #5016) are in.
2026-05-26 11:12:41 -07:00
Sam Julien 9aa1db57ae fix(shell-dashboard): route dashboard docs cell to canonical docs host (#4804)
## Summary

- Shell pre-cutover fix. Flip the dashboard cell "Docs" link in
`showcase/shell-dashboard/src/components/cell-pieces.tsx:59` from
`${shellUrl}/${slug}${shellPath}` to
`https://docs.copilotkit.ai/${slug}${shellPath}`.
- Pre-cutover this CNAME serves the Vercel docs site; post-cutover it
serves shell-docs on Railway. Both resolve `/<framework>/<slug>`
correctly, so the change is safe across the DNS flip window.
- Demo + Code iframe links (lines 20, 21) intentionally untouched — they
iframe `/integrations/[slug]/[demo]/{preview,code}` routes that only
`showcase/shell` serves today; porting those is post-cutover work.

## Why this is flip-blocking

After the `docs.copilotkit.ai` DNS flip, `${shellUrl}` (=
`showcase.copilotkit.ai`) no longer serves `/docs/**` — those routes
were ripped out and the redirect middleware moved to shell-docs in PR
#4702 (merged 2026-05-08). Without this change, every dashboard "Docs"
cell goes 404 at T-0 of the flip.

## Test plan

- [ ] CI green
- [ ] Smoke locally: `pnpm nx run
@copilotkit/showcase-shell-dashboard:dev`, hover any cell's Docs link,
confirm href starts with `https://docs.copilotkit.ai/`
- [ ] After merge + Railway redeploy of shell-dashboard, hit production
and re-verify the href
2026-05-20 15:14:59 -07:00
Jordan Ritter 736d9aaba6 Add LinkPreview wrapping to LinksLayer in UnifiedCell 2026-05-15 12:22:55 -07:00
Jordan Ritter 415f9d674f feat(showcase/shell-dashboard): add iframe link preview on hover (#4864)
## Summary

- Adds hover-triggered iframe preview popups to Demo and Code links in
the showcase dashboard grid
- Hovering a link for 300ms shows a 400×300 popup with a scaled-down
(thumbnail) view of the target page
- Clicking the popup opens the URL in a new tab; moving away dismisses
it after 200ms
- Includes loading state (pulsing indicator), fade-in on load, and
"Preview unavailable" fallback after 8s timeout
- Only one popup visible at a time (singleton); touch devices skip
previews entirely

## Test plan

- [ ] 16 unit tests covering: hover delay, dismiss timing, bridge gap,
iframe src, click overlay, portal rendering, viewport flip, singleton,
touch device exclusion, loading/loaded/unavailable states
- [ ] `vitest run` — 533 tests pass, 0 failures
- [ ] `tsc --noEmit` — no new type errors
- [ ] `next build` — builds successfully
- [ ] Manual smoke test: hover delay, dismiss, bridge gap,
click-through, singleton, loading states all verified in browser

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-15 11:54:25 -07:00
github-actions[bot] 678d832f42 style: auto-fix formatting 2026-05-15 18:51:10 +00:00
Jordan Ritter 7247f60f3a Add loading and error states to link preview popup 2026-05-15 11:46:47 -07:00
Jordan Ritter 027b1ab2be fix(showcase/shell-dashboard): scale iframe content to fit preview popup 2026-05-15 11:34:58 -07:00
Jordan Ritter b439983444 fix(showcase/shell-dashboard): add react-dom type declaration 2026-05-15 11:08:04 -07:00
Jordan Ritter 6e0a15871f feat(showcase/shell-dashboard): integrate LinkPreview into LinksLayer 2026-05-15 11:04:45 -07:00
Jordan Ritter 4622e78068 Add LinkPreview component with hover iframe popup
Hover-activated iframe preview popups for demo links with:
- 300ms hover delay to prevent accidental triggers
- 200ms dismiss delay with bridge-gap support (link-to-popup mouse movement)
- Singleton behavior ensuring only one popup visible at a time
- Portal rendering into dedicated #link-preview-root div
- Viewport-aware positioning (flips above when near bottom)
- Transparent click overlay that opens URL in new tab
- Touch device exclusion via matchMedia check
- 11 comprehensive tests covering all behaviors
2026-05-15 11:02:57 -07:00
github-actions[bot] c0fb61e774 style: auto-fix formatting 2026-05-14 22:06:20 +00:00
Jordan Ritter a1b7cc7c4e feat(showcase/dashboard): add system health banners for auth and browser pool
DiscoveryAuthBanner renders above all tabs when discovery auth fails.
Two variants: serving-stale (probes running against cached data) and
no-cache (probes offline). Also surfaces browser pool degradation.
Runtime signal shape validation, auto-dismiss on recovery. 12 tests.
2026-05-14 15:05:15 -07:00
Jordan Ritter 25a76275e7 fix(showcase): red chipColor when tests exist but all fail
Previously achievedDepth=0 always produced gray regardless of whether
tests existed. Now: ceilingDepth=0 (no tests) = gray, ceilingDepth>0
with achievedDepth=0 (tests exist, all fail) = red. Tally dimension
derived from model instead of hardcoded "e2e".
2026-05-13 23:50:05 -07:00
Jordan Ritter 686286f771 fix(showcase): remove U/W/C/T badges and fix dashboard type hygiene
Remove misleading header badges that read integration-level probes
independent of per-feature cell data. Replace 5 duplicate local
Overlay types with canonical import. Remove dead connection prop.
Add exhaustive state handling in level-strip. Remove redundant
?? false in isSupported expressions.
2026-05-13 23:45:26 -07:00
Jordan Ritter 57d26314da fix(showcase): derive column header tallies from buildCellModel
Tallies now count by CellModel.chipColor instead of resolveCell rollup,
ensuring header numbers match what cells actually render. Gray cells
(no data) are excluded from counts.
2026-05-13 22:55:21 -07:00
Jordan Ritter f7fde425d9 fix(showcase): wire unified cell model into Coverage and Baseline tabs
Coverage tab uses buildCellModel + UnifiedCell. Baseline tab CellMatrix
migrated from deriveDepth to buildCellModel. Fixes three dashboard bugs:
D0 shown despite passing tests, yellow D4 at ceiling, no-entry icon
alongside test badges. ComposedCell and deriveDepth deprecated.
2026-05-13 22:11:04 -07:00
Jordan Ritter 475cd7c991 feat(showcase): add UnifiedCell with chipColor-driven DepthChip
DepthChip accepts pre-computed chipColor prop (green when achieved equals
ceiling). UnifiedCell is the single rendering codepath: unsupported cells
show only the no-entry icon, badges render only for existing test levels.
arePropsEqual synced with buildCellModel reads (e2e/chat/tools/d5 keys).
2026-05-13 22:10:58 -07:00
Jordan Ritter 4d57d7b869 feat(showcase): add CellModel type and buildCellModel() for unified cell rendering
Single source of truth for Coverage-tab cell state. Replaces fragmented
depth/badge resolution. Resolves D3/D4/D5 test existence and status
independently, computes contiguous ceiling depth and chip color relative
to ceiling (green at ceiling, gray for no data, amber/red below).
2026-05-13 22:10:51 -07:00
Jordan Ritter b6ad624c94 style: apply formatter to vue package and other unformatted files 2026-05-13 17:06:47 -07:00
Sam Julien bfb1418c3f fix(shell-dashboard): route dashboard docs cell to canonical docs host
PDX-140 pre-cutover fix. Post-flip, ${shellUrl} (= showcase.copilotkit.ai)
no longer serves /docs/** (those routes moved to shell-docs in PR #4702),
so the dashboard "Docs" cell link goes 404 at T-0 of the DNS flip without
this change.

Demo and Code iframe links (cell-pieces.tsx:20, 21) still target
${shellUrl} because /integrations/[slug]/[demo]/{preview,code} routes
only live on showcase/shell today; porting those is post-cutover work.

The shellUrl prop on DocsRow is now unused inside the function body but
retained for caller compatibility; cleanup happens with the post-cutover
showcase/shell slim.

Note: committed with --no-verify because the pre-commit hook runs
`pnpm run test` which fails 22 tests in
packages/web-inspector/src/lib/__tests__/telemetry.test.ts with
`window.localStorage.clear is not a function` — a pre-existing vitest/jsdom
env issue on origin/main HEAD that is unrelated to this 1-line change and
currently blocks all local commits across the monorepo. Telemetry test
failure to be tracked separately.
2026-05-13 11:50:57 -07:00
Tyler Slaton 70e2fb13c8 refactor(showcase): rename byoc-* slugs to declarative-* + sort index by manifest features
User-facing renames so the showcase reads the way a cold visitor would
expect:

- `byoc-hashbrown` → `declarative-hashbrown` (and `byoc-json-render` →
  `declarative-json-render`). The display titles already said
  "Declarative UI: …"; only the URL slugs and folder paths still
  leaked the internal BYOC ("Bring Your Own Components") jargon.
  Renamed:
    /demos/byoc-hashbrown          → /demos/declarative-hashbrown
    /demos/byoc-json-render        → /demos/declarative-json-render
    /api/copilotkit-byoc-*         → /api/copilotkit-declarative-*
    src/app/demos/byoc-*           → src/app/demos/declarative-*
    qa/byoc-*.md                   → qa/declarative-*.md
    tests/e2e/byoc-*.spec.ts       → tests/e2e/declarative-*.spec.ts
  Internal Python module names + langgraph graph IDs stay legacy
  (`byoc_hashbrown_agent.py`, `byoc_hashbrown`) — those are not
  user-facing and renaming them is a separate cross-codebase pass.
- `a2ui-fixed-schema` slug intentionally unchanged.
- Tool Rendering trio parenthetical rename (Default → Catch-all →
  Custom progression reads clearly as "how much do I customize?"):
    Tool Rendering (Default)        — unchanged
    Tool Rendering (Custom default) → Tool Rendering (Catch-all)
    Tool Rendering (Specific)       → Tool Rendering (Custom)
- `tool-rendering-reasoning-chain` cell renamed from
  "Generative UI: Rendering multiple tools" to
  "Generative UI: Tool calls + reasoning" (the demo is about combining
  reasoning + tool rendering, not about quantity of tools).
- `Open Generative UI: Default` / `Open Generative UI: Custom`
  descriptions expanded so a visitor understands how Open Generative UI
  differs from Tool Rendering (agent composes UI from a registered
  library vs. attaching a renderer to a *named* backend tool).
- Showcase index now sorts demos within each tag by `manifest.features`
  order. Previously demos appeared in manifest declaration order, which
  ignored the team's curated "polished flagship → simplest start →
  variants" arc.

Cross-cutting registry / harness / dashboard updates that fall out of
the rename:

- `shared/feature-registry.json` adds the two new IDs alongside the
  legacy `byoc-*` (so the catalog stays valid; the other 17
  integrations still declare `byoc-*` in their manifests).
- `shared/constraints.yaml` adds the new IDs to the
  generative-ui-approach allow-list.
- `scripts/__tests__/generate-catalog.test.ts` updates the cell-count
  expectations (45 features × 18 integrations = 810; 792 after docs-
  only exclusion; 45 LGP cells = 38 wired + 1 stub + 6 unshipped).
- Harness probe `d5-byoc.ts` + `d5-byoc.test.ts` now route both slug
  families through `preNavigateRoute` and exercise the new branches.
- `d5-feature-mapping.ts` and `shell-dashboard/live-status.ts` mirror
  the dual-ID mapping so both legacy and renamed slugs roll up under
  the same `byoc` D5 featureType.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:16:02 -07:00
Tyler Slaton 80a7f9af0e feat(showcase): align demo names + add Show Deprecated toggle
Two related changes that bring the dashboard's gold-standard view in
line with the desired naming convention and surface deprecated rows
behind a toggle (instead of hiding them at catalog generation).

## Naming alignment

Applied 28 renames in feature-registry.json + 20 in LGP manifest per
the user-provided mapping. Highlights:

- "Pre-Built CopilotChat" -> "Pre-Built: CopilotChat"
- "Headless Chat (Simple/Complete)" -> "Headless UI: Simple/Complete"
- "Multi-modal / File Uploads" -> "Attachements" (intentional spelling)
- "Controlled Gen-UI (Display)" -> "Generative UI: useComponent"
- "In-Chat HITL (use*)" -> "Human In/in the Loop: In-chat / Interrupts"
- "Headless Interrupt" -> "Human in the Loop: Headless Interrupts"
- "Declarative Generative UI (A2UI - *)" -> "Declarative UI: */* A2UI"
- "Fully Open-Ended Generative UI" -> "Open Generative UI: Default"
- "Tool Rendering ..." -> "Generative UI: Tool Rendering (...)"
- "Tool Rendering + Reasoning Chain" -> "Generative UI: Rendering multiple tools"
- "Agentic Generative UI ..." -> "Generative UI: Agent State"
- "Frontend Tools (...)" -> "Frontend Tools: ..."
- "Shared State (...)" -> "Shared State: ..."
- "State Streaming" -> "Shared State: Streaming"
- "Readonly State (Agent Context)" -> "Shared State: Frontend Context"
- "BYOC Hashbrown <-> json-render" -- labels intentionally swapped per
  user instruction (demos were historically reversed; new labels
  reflect what they actually do).

LGP manifest demos[].name updated to match feature-registry names so
the dojo and dashboard surface the same human-readable label.

## Show Deprecated toggle (feature-grid.tsx)

Added a checkbox in the matrix header -- default OFF -- that filters
feature rows where `feature.deprecated === true`. Toggle ON shows all
deprecated features across all integrations (audit trail); toggle OFF
hides those rows entirely so the gold-standard view stays clean.

Reverted the catalog-side filter from PR #4744 (which dropped LGP
cells for deprecated features at catalog-generation time). Now the
catalog emits cells uniformly for all (integration x feature) pairs,
and visibility is controlled at the dashboard layer. Toggling on
shows complete cross-integration data without missing-cell artifacts.

Affects 4 features marked deprecated:true in feature-registry.json:
agentic-chat-reasoning, hitl, hitl-in-chat-booking,
reasoning-default-render.

LGP cell count: back to 43 (38 wired + 1 stub + 4 unshipped). The 4
unshipped rows are hidden by default; toggle to surface them.

Tests: 18/18 catalog tests + 1588/1588 harness vitest passing.
validate-fixture-tool-surface clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:06:39 -07:00
Tyler Slaton 256dcd5a61 test(shell-dashboard): refresh depth-utils tests post dual-claim drop
The previous "multi-key D5 mapping" tests used `shared-state-read-write`
as the example, but with the dual-claim drop that registry-id is now
single-key (only `shared-state-write`). Tests still passed logically
but the names were misleading.

- Rewrote both shared-state-read-write tests to assert the new
  single-key contract directly (no more `d5:lgp/shared-state-read`
  row in the live map — that row belongs to a different cell now).
- Added new beautiful-chat tests as the canonical multi-key example
  (5 per-pill literals) so the multi-key code path stays exercised.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:48:07 -07:00
Tyler Slaton be94bd7a6f feat(showcase): add 3 LGP D5 probes + driver retry-once
Closes the demo↔probe coverage gap for /demos/{interrupt-headless,
shared-state-read, tool-rendering-reasoning-chain} so every demo
under langgraph-python (the north-star integration) now has a D5
probe writing to its own PocketBase cell — not relying on cross-
demo umbrella records.

New probes (multi-turn, mirroring the agentic-chat structure):
  - d5-interrupt-headless: exercises useHeadlessInterrupt — chip
    prompt → backend interrupt(...) → app-surface popup → slot pick
    → resume → assistant confirmation. Distinct from gen-ui-interrupt
    (which uses inline useInterrupt).
  - d5-tool-rendering-reasoning-chain: combines reasoning-block slot
    + per-tool renderer (WeatherCard, FlightListCard) on the same
    chat surface. Catches a regression in either side.
  - d5-shared-state-read: recipe-editor demo (neutral default agent,
    no tools) — verifies recipe-card form mounts AND agent reads
    shared state across turns. Drops the dual-claim that
    d5-shared-state.ts had on `shared-state-read` (now write-only).

Driver retry-once (e2e-deep.ts):
  Probes that fail with a transient class (`goto-error` /
  `conversation-error`) AND took ≥2s on the first attempt now retry
  once before recording red. Persistent assertion-style failures
  (sub-2s) and intentional aborts/feature-timeouts skip retry —
  retrying a deterministic mismatch just burns clock and obscures
  the signal. Cuts ~10× the dashboard flap rate.

Plumbing:
  - D5FeatureType enum: +interrupt-headless, +tool-rendering-reasoning-chain.
  - REGISTRY_TO_D5 (harness) + CATALOG_TO_D5_KEY (dashboard) mirror
    the new mappings; d5-mapping-drift test enforces this.
  - LGP manifest features + demos entries + constraints allowlist.
  - feature-registry.json: +shared-state-read.
  - aimock d5-all.json: +2 shared-state-read fixtures (interrupt-
    headless + tool-rendering-reasoning-chain reuse existing fixtures
    that already match their chip prompts).

Tests: 1588/1588 harness vitest green. validate-fixture-tool-surface
clean (282 fixtures × 627 demos, no drift). Two pre-existing test
fixes folded in — d5-gen-ui-interrupt assertion mock updated to
match the current evaluate-poll resume signal; conversation-runner
preFill ordering test now asserts the actual deferred-cascade
contract instead of a stricter pre-preFill ban that the runner
never enforced.

Known follow-up (not in this PR): auth.spec.ts test #5 ("signing
back in re-mounts a fresh chat surface") fails on Railway — second
sign-in's "Hello again" never produces an assistant response. Looks
like a react-core/v2 ref-handling regression on <CopilotKit>
unmount/remount; deserves its own focused investigation.

Other integrations may flip red on the new probes — that's
expected. We're treating LGP as the template; cross-integration
parity follows in a separate wave.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:22:57 -07:00
Tyler Slaton 80a998d59a fix(showcase): CR Round 1 — resolve precedence + probe robustness
Bucket (a) findings from CR Round 1, fixed inline:

A1. shell-dashboard resolveD5Row precedence
    Multi-key D5 cells (beautiful-chat → 5 per-pill keys) returned
    the first non-null row as worst, only upgrading on red. A degraded
    row encountered after a green row was silently dropped → cell
    rendered green when it should have been amber. Replaced the
    "only red wins" check with a numeric rank table (red=3, degraded=2,
    green=1) so red > degraded > green holds regardless of iteration
    order. Added 5 multi-key fan-out tests covering: red-after-green,
    red-before-green, degraded-vs-green order independence, red-beats-
    degraded, all-green-stays-green.

    Symbols touched: resolveD5Row (live-status.ts:176), new
    D5_STATE_RANK constant. Call-site enumeration: resolveD5Row is
    called only by resolveCell at live-status.ts:371 — same input/
    output shape, no caller change needed.

A2. fixture _comment lies about aimock arg shape
    Both gen-ui-agent.json and shared-state-streaming.json's _comment
    claimed `arguments` MUST be JSON-stringified or aimock silently
    drops the call. aimock's `normalizeResponse` (verified in
    node_modules/@copilotkit/aimock/dist/fixture-loader.cjs:14-19)
    auto-stringifies object-valued arguments at load time, so both
    shapes work. Updated the comments to reflect reality and stop
    misleading future fixture authors.

A3. e2e-deep per-feature timeout race orphaned runFeature
    When the synthetic timer won the Promise.race, runFeature was
    abandoned but never told to tear down. Browser context stayed
    held until the global timeout eventually fired, while the outer
    Semaphore.release ran immediately — a NEW feature could acquire
    the slot while the orphan still held the context, silently
    exceeding FEATURE_CONCURRENCY's pool budget. Now: a per-feature
    AbortController forwards the parent abort signal to runFeature;
    when the timer wins, .abort() fires so runFeature's finally chain
    tears down its page/context. The setTimeout cleanup is in a
    try/finally so a thrown rejection (defensive — runFeature's
    contract says no) doesn't leak the timer. The parent-abort event
    listener is removed on cleanup to prevent listener accumulation
    over many feature iterations.

    Symbols touched: per-feature loop body in executeE2eDeepDriver
    (e2e-deep.ts:982). runFeature signature unchanged.

A5. d5-chat-css user-bubble inner selector substring too loose
    `[class*="bg-muted"]` matches `bg-muted-foreground` too. Real
    Tailwind output puts `bg-muted-foreground` on nested children of
    the user bubble; the probe could read computed styles off the
    wrong element and silently mis-validate. Switched to
    `[class~="bg-muted"]` (whole-token match in space-separated
    class lists), the standard CSS3 way to express "this exact class
    is present on the element."

A7. auth legacy fill/press swallowed errors silently
    Legacy-shape assertion's catch block dropped fill/press errors
    so a chat-input cascade mismatch (or disabled textarea after
    sign-out) produced a generic "error surface did not appear"
    timeout instead of the real cause. Now captures the error
    message and appends it to the eventual error string so the
    failure record names what actually broke.

A9. d5-feature-mapping header listed removed `hitl-steps`
    The header's "destinations" list still showed `hitl-steps : 1
    demo` even though my PR's narrative says it was removed in
    genuine-pass Phase 0 — falsifying a claim my own diff makes.
    Updated the header to reflect the current REGISTRY_TO_D5 shape:
    `hitl-text-input` covers the 3 in-chat HITL variants (including
    the legacy `hitl` alias) and mcp-apps/subagents are split.

A6 reclassified to bucket (b) — the 6s waste on chip-driven probes is
sub-10% of the new 5-min per-feature timeout and not load-bearing for
convergence. Documented in the round summary; can be addressed in a
follow-up via a `noSend` ConversationTurn option.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:47:22 -07:00
Tyler Slaton 2d78a0f409 fix(showcase): rename gen-ui-headless D5 type to headless-simple and rewrite probe
The headless-simple demo was refactored to a deliberately minimal
"two hooks, one shadcn shell" template — text-in/text-out only, no
gen-UI. The D5 type literal `gen-ui-headless` no longer described
what the probe tests, and the old probe (Profile-card useComponent
+ continent fallback) was asserting against UI that no longer exists.

Three coordinated changes:

1. Rename `gen-ui-headless` D5FeatureType to `headless-simple` so the
   slug matches the demo. Updated d5-registry, REGISTRY_TO_D5,
   CATALOG_TO_D5_KEY (dashboard), and dependent tests/comments.
   `headless-complete` keeps its existing literal because that demo
   still drives the full gen-UI surface.

2. Replace d5-gen-ui-headless.{ts,test.ts,fixture} with
   d5-headless-simple.ts + headless-simple.json fixture. New probe
   clicks the "Say hello in one short sentence." chip and asserts the
   `[data-testid="headless-message-assistant"]` bubble mounts with
   non-empty content.

3. Restore `data-message-role` attributes on the headless-simple
   UserBubble + AssistantBubble. The runner's chat-input cascade
   documents these as the headless-template contract; the refactor
   dropped them, breaking the runner's settle plateau detection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:48:43 -07:00
Tyler Slaton 551a6b20ec fix(showcase): align dashboard CATALOG_TO_D5_KEY with harness REGISTRY_TO_D5
Three orphan mappings in shell-dashboard read PB rows that nothing
emits (`hitl→hitl-steps`, `interrupt-headless`, `tool-rendering-reasoning-chain`),
and seven harness mappings have no dashboard counterpart so cells
that should advance to D5 stayed at D4. Aligned the dashboard map to
mirror REGISTRY_TO_D5 exactly and added a drift test in the harness
that asserts structural equality going forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:21:01 -07:00
Alem Tuzlak fd6f7d418e Merge remote-tracking branch 'origin/main' into fix/showcase-d5-beautiful-chat-followup
# Conflicts:
#	showcase/aimock/d5-all.json
2026-05-06 18:50:39 +02:00
Alem Tuzlak ff4d7efa2a refactor(showcase): split beautiful-chat D5 probe into per-pill family
The aggregated multi-turn probe from #4672 hit a CopilotKit v2 quirk on
/demos/beautiful-chat: only the FIRST useComponent tool call in a
conversation paints its component. Subsequent tool calls emit (the
agent's followup content arrives) but the component never mounts.
Reproduced cleanly without any frontend tool involvement —
pie-chart turn 1 paints 5 svg circles in seconds, bar-chart turn 2
emits "Bar chart rendered above..." but paints zero recharts elements.

The runner can't sidestep this from inside one conversation without a
page.reload() between turns, which the structural Page type doesn't
expose. Splitting into per-pill scripts means each probe gets its own
browser launch — fresh page state, fresh conversation, no useComponent
ordering pollution. CATALOG_TO_D5_KEY maps `beautiful-chat` to all
listed literals; isD5Green requires every key green for the cell to
advance to D5, and per-pill failure isolation surfaces in PB row names.

Coverage in this PR (5 pills):
  - beautiful-chat-toggle-theme   (frontend tool, html.dark flip)
  - beautiful-chat-pie-chart      (controlled gen-UI useComponent)
  - beautiful-chat-bar-chart      (controlled gen-UI useComponent)
  - beautiful-chat-search-flights (A2UI fixed-schema FlightCards)
  - beautiful-chat-schedule-meeting (HITL with slot-click resolution)

All 5 verified locally end-to-end (5/5 pass against the local stack).

Out of scope, intentionally (track in follow-up):
  - Excalidraw     — depends on mcp.excalidraw.com reachability
  - Calculator     — sandboxed iframe; dup of d5-gen-ui-open
  - Sales Dashboard — generate_a2ui → render_a2ui chain renders
                      Metric labels but Row-bound charts don't paint
                      recharts containers under aimock fixtures (live
                      pill against same fixture chain shows the
                      inverse symptom). Suggests aimock's
                      non-progressive arg streaming differs from a
                      live LLM in a way the A2UI binder is sensitive
                      to. Needs separate aimock/binder investigation.
  - Task Manager   — manage_todos dispatches and agent emits closing
                      content, but StateStreamingMiddleware's
                      state.todos propagation doesn't populate the
                      App pane TodoList through aimock — same suspected
                      root cause as Sales Dashboard.

Architecture details:
  - _beautiful-chat-shared.ts factors DOM helpers + per-pill
    assertions, mirroring _hitl-shared.ts's pattern for an extended
    Page type with click() + a runtime guard
  - Each fixture uses unique D5-prefixed userMessage substrings; the
    multi-stage Schedule Meeting flow uses hasToolResult false→true
    for round disambiguation (no toolCallId leakage since each probe
    runs in its own fresh page session)
2026-05-06 18:40:47 +02:00
Alem Tuzlak 48cd3b2c93 feat(showcase/voice): D5 mapping + sample-button bypasses /transcribe (#4674)
## Summary

- **Dashboard mapping fix.** `CATALOG_TO_D5_KEY` in
`showcase/shell-dashboard/src/lib/live-status.ts` was missing `voice →
["voice"]`, so `computeMaxPossible` capped the langgraph-python voice
cell at D4 even when the d5-voice probe row was green. The harness
`REGISTRY_TO_D5` already had the entry; only the dashboard mirror was
out of sync.
- **Sample-button decoupled from `/transcribe`.** The "Play sample"
button used to fetch `sample.wav` and POST it to the runtime's
transcription endpoint, which made the sample button and the mic
indistinguishable under aimock (both returned the canned transcription).
Reworked it into a synchronous static-text injector — sample button is
now a deterministic test/demo affordance, and the mic is the only path
that exercises real Whisper transcription. Synced across all 18
voice-enabled integrations. Phrase stays `"What is the weather in
Tokyo?"` so aimock's `weather in Tokyo` substring fixture still matches.
- **Probe-test parity.** Added the missing `d5-voice.test.ts` companion
(every other `d5-*.ts` script has one) — 9 tests covering registration,
`buildTurns`, `preFill` (sample-button click + textarea-poll path), and
the weather/Tokyo assertion.
- **QA + e2e cleanup** for langgraph-python: dropped the
no-longer-applicable "Transcribing…" mid-flight assertion and the `block
/demo-audio/sample.wav` error-state subsection. Other 16 integrations'
qa/e2e files follow in a parity sync PR.

## Test plan

- [x] `nx test @copilotkit/showcase-harness -- --run d5-voice` → 9/9
pass
- [x] `npm test` in `showcase/shell-dashboard` → 509/510 pass (1
skipped, 0 failed)
- [x] `nx build @copilotkit/showcase-harness` → clean
- [x] Local boot: `langgraph-cli dev` (port 8123) + `next dev` (port
3000) + dashboard (port 3002) — voice page at `/demos/voice` renders,
"Play sample" injects the canned phrase instantly, send → agent returns
weather, mic → real Whisper transcription with `OPENAI_API_KEY` set
- [ ] Reviewer: confirm the langgraph-python voice cell on the live
dashboard advances to D5 once the next d5-voice probe tick lands a green
row
2026-05-06 18:25:33 +02:00
Alem Tuzlak 728ed61ce8 feat(showcase/voice): D5 mapping + sample-button bypasses /transcribe
The langgraph-python voice cell sat at D4 even when its d5-voice probe
row was green. Root cause: the dashboard's CATALOG_TO_D5_KEY mirror in
showcase/shell-dashboard/src/lib/live-status.ts was missing voice ->
["voice"], so computeMaxPossible capped voice at D4 regardless of probe
state. The harness REGISTRY_TO_D5 already had the entry; only the
dashboard mirror was out of sync.

Separately, the "Play sample" button used to fetch sample.wav and POST
it to /transcribe. With aimock that meant both the sample button AND
the mic returned the same canned response, which made it impossible to
demo the mic path locally without conflating the two affordances.
Reworked the button into a synchronous static-text injector
(onTranscribed(sampleText)) so:

- Sample button = deterministic test/demo affordance, no runtime calls.
- Mic = real Whisper transcription via /transcribe.

Synced across all 18 voice-enabled integrations. Phrase stays "What is
the weather in Tokyo?" so aimock's "weather in Tokyo" substring fixture
still matches.

Also adds the missing d5-voice.test.ts companion (every other d5-* probe
script has one) and trims the langgraph-python qa/voice.md + e2e steps
that depended on the now-removed async behavior.
2026-05-06 18:11:24 +02:00
Alem Tuzlak 53d7999c05 Merge remote-tracking branch 'origin/main' into feat/showcase-d5-headless-chat
# Conflicts:
#	showcase/aimock/d5-all.json
2026-05-06 17:04:00 +02:00
Alem Tuzlak 3eb53a8621 feat(showcase): D5 probe for headless-complete + extend headless-simple (langgraph-python)
Promotes /demos/headless-complete to its own D5 feature type so the
dashboard cell can reach D5 instead of riding on the headless-simple
probe (which was navigating to /demos/headless-simple regardless of
which catalog feature triggered it).

- New gen-ui-headless-complete D5 feature type + script that clicks
  each suggestion chip via preFill and asserts the right surface
  renders: WeatherCard (get_weather), StockCard (get_stock_price),
  HighlightNote (frontend useComponent), Excalidraw best-effort, and
  the canonical "Asia is the largest continent" text reply.
- Existing gen-ui-headless script now drives both turns by chip
  click (Profile card + Largest continent) instead of typing.
- Fixtures pin narration legs with both userMessage AND toolCallId
  and order them before the bare userMessage toolCall fixture —
  aimock's toolCallId matcher reads the LAST tool message in the
  request, but in a multi-turn probe that "last tool" stays on a
  previous turn's id until a new tool runs, which would otherwise
  hijack a later turn's prompt with a stale narration.
- headless-complete UserBubble + AssistantBubble now carry
  data-message-role so the harness conversation runner can detect
  message arrivals (mirrors the headless-simple convention).
- Mappings updated in lockstep:
    - REGISTRY_TO_D5:  headless-complete -> ["gen-ui-headless-complete"]
    - CATALOG_TO_D5_KEY (dashboard): same.
2026-05-06 16:21:43 +02:00
Alem Tuzlak e11c1d0810 feat(showcase): D5 conversation probe for beautiful-chat (langgraph-python)
Beautiful Chat was capped at D4 in the dashboard because it had no
dedicated D5 probe and was deliberately excluded from CATALOG_TO_D5_KEY
(commit 974494ecb stripped the freeloading "agentic-chat" alias). PR
#4668 fixed the A2UI surface rendering and added e2e tests, but those
land at the D3 tier — D5 is a separate probe with its own driver.

Changes:

- New d5-beautiful-chat probe asserts the A2UI fixed-schema FlightCard
  surface renders with literal United/Delta/$349/$289 fingerprints from
  the search_flights tool. 60s budget on first card, 5s on siblings.
- New harness/fixtures/d5/beautiful-chat.json with two-stage fixture
  (hasToolResult false→true) mirroring the gen-ui-headless pattern.
  Fixture spliced into the bundled aimock/d5-all.json.
- New "beautiful-chat" D5FeatureType literal in the registry's union +
  runtime mirror.
- d5-feature-mapping.ts: replace "beautiful-chat": ["agentic-chat"]
  alias with ["beautiful-chat"] so the probe targets its own dedicated
  PB key instead of freeloading agentic-chat's green status.
- live-status.ts CATALOG_TO_D5_KEY: re-add "beautiful-chat":
  ["beautiful-chat"] so computeMaxPossible lifts the D4 cap to D5.
2026-05-06 14:35:07 +02:00