Commit Graph

3254 Commits

Author SHA1 Message Date
Jordan Ritter d6b006dbab fix(showcase): forward x-aimock-context on all built-in-agent demo routes
The main /api/copilotkit route wraps its handlers in withForwardedHeaders
(ALS) and its factory builds openaiText(..., { fetch: forwardingFetch }),
so inbound x-aimock-context propagates to aimock on every outbound LLM
call. Every other demo route was missing one or both halves: the dedicated
runtimes were not ALS-wrapped and their factories built openaiText(...)
without the forwarding fetch, so those routes dropped x-aimock-context and
aimock returned 503 strict-mode misses (deterministic ctx-missing).

Apply the working main-route pattern everywhere:
- Add fetch: forwardingFetch to every openaiText(...) construction in the
  demo factories (a2ui main + secondary LLM, a2ui-fixed-schema, byoc-hashbrown,
  byoc-json-render, mcp-apps, ogui, reasoning, subagent-tools) and the inline
  agent-config route factory.
- Wrap every demo route handler in withForwardedHeaders (agent-config,
  byoc-hashbrown, byoc-json-render, mcp-apps, reasoning, ogui,
  a2ui-fixed-schema, declarative-gen-ui, multimodal, voice, auth).

Verified locally against strict aimock with d6 built-in-agent fixtures:
agent-config and declarative-gen-ui turns went from 503 ctx-missing
(x-aimock-context absent) to 200 fixture-matched (x-aimock-context present)
in the aimock journal.
2026-06-06 01:46:53 -07:00
Jordan Ritter 5812739b5e feat(showcase): drive bin/showcase test d5/d6 through the fleet control-plane + add dev hot-reload mode
Make the showcase dev tool faithful to staging by construction. Two changes:

1. `showcase test --d5/--d6` now drives the fleet CONTROL-PLANE (producer ->
   probe_jobs queue -> worker -> result-aggregator) instead of the legacy
   in-process runLevel() driver. The new cli/control-plane-run.ts replicates
   the deep/full producer tick exactly as runControlPlane wires it
   (createE2eDeepServiceEnumerator / createServiceEnumerator over
   createJobProducer + createFleetQueueClient), enqueues one operator-triggered
   tick, and polls local PocketBase for the run's terminal cells. The running
   worker fleet claims + runs the driver + the aggregator writes the d5/d6
   status cells, so the dev tool exercises the IDENTICAL wiring + concurrency
   as staging. The old in-process path stays available behind `--direct`.

2. `showcase up --dev` adds a docker-compose.dev.yml overlay that bind-mounts
   each integration's source and overrides the run command with a stack-aware
   hot-reload entrypoint (shared/dev/dev-entrypoint.sh: uvicorn --reload for
   FastAPI agents, langgraph dev for graphs, next dev for the frontend). Edit a
   source file and the component reloads in place with no image rebuild. The
   built-image mode remains the faithful/staging-equivalent default.
2026-06-06 00:06:29 -07:00
Jordan Ritter 3948629576 docs(showcase): remove stale e2e_deep/d5-single-pill references after D5=D6-take-one 2026-06-05 21:54:42 -07:00
Jordan Ritter a6a28f276e fix(showcase): keep D5 CLI error-path key consistent with success path 2026-06-05 21:42:50 -07:00
Jordan Ritter f723bc27da docs(showcase): correct payload-mapper to three browser driver families
The e2e_deep kind was removed (D5 now runs the D6 driver), leaving three
browser driver families: e2e_d6, e2e_demos, e2e_smoke. Update the stale
"four browser driver families" docstring and its test comment.
2026-06-05 21:36:16 -07:00
Jordan Ritter db2bf3e2ce test(showcase): cover composed representativeOnly+rowPrefix:d5 D5 invocation
Asserts the real D5 invocation shape buildDeepInputs stamps (both knobs
together): only D5_REPRESENTATIVES featureTypes run AND every emitted key
(per-cell d5:<slug>/<ft> + aggregate d5:<slug>) uses the d5: prefix. The
existing tests cover the knobs in isolation only.
2026-06-05 21:36:09 -07:00
Jordan Ritter 27c5217d1c fix(showcase): forward notSupportedFeatures + use d5: error key in D5 CLI path
buildDeepInputs now forwards manifest.not_supported_features (matching D6's
buildFullInputs) so local CLI D5 runs don't false-red architecturally-
unsupported features. The D5 thrown-error terminal key changes from
d5-single-pill-e2e:<slug> to d5:<slug> (the driver's own emitAggregate key
shape) so a hard driver throw surfaces as a RED D5 cell, not a blank row.
Also corrects D5-scope docs: representativeOnly keeps the representative
featureTypes per D5_REPRESENTATIVES, not "one pill per category".
2026-06-05 21:36:02 -07:00
Jordan Ritter 04a7ee703a fix(showcase): repoint d6-capture-references import off deleted d5-single-pill 2026-06-05 21:35:47 -07:00
Jordan Ritter 703985ec39 refactor(showcase): drop the e2e_deep kind constant + stale D5-driver references
Removes E2E_DEEP_DRIVER_KIND and "e2e_deep" from the worker-internal
closed driver-kind set (D5 runs the e2e_d6 driver now), updates the
x-test-id-headers guard to assert on the surviving d6-all-pills driver
(d5-single-pill.ts was deleted), and repoints a stale doc comment.
2026-06-05 21:23:21 -07:00
Jordan Ritter 1829c3f580 feat(showcase): run D5 as "D6 take-one" via driver inputs, not a separate kind
Repoints the D5 probe at the unified D6 driver. The fleet D5
enumerator now stamps driverKind=e2e_d6 with representativeOnly + a
"d5" rowPrefix; the CLI's buildDeepInputs carries the same inputs;
config/probes/e2e-deep.yml declares kind=e2e_d6. Drops the e2e_deep
driver registration (orchestrator + worker registry + BROWSER_KINDS +
the worker-internal kind set), keeping the D5 producer schedule/cadence
intact. The worker now honors driverInputs.rowPrefix when filtering the
aggregate side-row out of captured cells so a "d5:<slug>" aggregate
doesn't leak into the D6 entry's "d6:<slug>" cell capture. This
eliminates the separate D5 launcher path whose own launcher instance +
cadence systematically dropped x-aimock-context against the shared fleet
pool (aimock strict 503 -> red).
2026-06-05 21:22:45 -07:00
Jordan Ritter 8db67ca064 feat(showcase): add representativeOnly + rowPrefix knobs to the D6 driver
Adds two input knobs to the d6-all-pills driver so it can run as "D5
take-one": `representativeOnly` filters the feature matrix to the
D5_REPRESENTATIVES set, and `rowPrefix` ("d5" | "d6", default "d6")
threads the dashboard key prefix through every emitted per-cell and
aggregate PB row. The representatives map is injectable for testing.
Everything else (route, headers, conversation, pooled launcher) is
unchanged. Red-green unit tests cover both knobs.
2026-06-05 21:21:03 -07:00
Jordan Ritter 723090e24e feat(showcase): mount /api/probes trigger endpoint on the fleet control-plane
The control-plane runs the 8 in-process HTTP probe families but the
on-demand trigger endpoint (POST /api/probes/:id/trigger) was only mounted
on the legacy boot() path, so operators had no way to fire a family
immediately and had to wait on the slow cron. Wire the same
registerProbesRoutes onto the control-plane's buildServer using its own
httpProbeRegistry/httpProbeConfigs/scheduler/httpRunWriter and
OPS_TRIGGER_TOKEN. Only the prefixed in-process probe ids (probe:<id>) are
triggerable; browser-only and unknown ids 404. Token handling mirrors
boot() (unset -> router omitted; set-but-empty -> fail-loud).
2026-06-05 16:44:43 -07:00
Jordan Ritter 3d940a3c74 feat(showcase): run e2e_smoke/e2e_demos/e2e_deep browser families on the fleet
Phase 2 of the harness pool-fleet migration — wire the three remaining BROWSER
probe families into the control-plane PRODUCER side so they actually run on the
fleet (the worker DriverRegistry for all four kinds already landed in #5283).

Unit A — three catalog-enumerator factories mirroring createD6ServiceEnumerator,
each delegating to the generic createServiceEnumerator with its own driverKind +
dashboard probeKey prefix and the shared D6_DISCOVERY_FILTER:
  - createE2eSmokeServiceEnumerator → e2e_smoke / d4:<slug>
  - createE2eDemosServiceEnumerator → e2e_demos / e2e-demos:<slug>
  - createE2eDeepServiceEnumerator  → e2e_deep  / d5-single-pill-e2e:<slug>

R-timeout (demos): the demos driver's 20-min outer cap is threaded in-process via
the legacy E2E_DEMOS_TIMEOUT_MS env, which the fleet worker never sets. The demos
enumerator now conveys the YAML timeout_ms per-job in driverInputs.timeout_ms
(new E2E_DEMOS_TIMEOUT_MS SSOT const mirroring e2e-demos.yml), and the demos
driver reads input.timeout_ms as a resolution source (env > input > deps >
default) so the 38-demo service no longer blows the 5-min default to all-red.

Unit B — runControlPlane now builds four producers and passes a multi-schedule
manifest (buildProducerSchedules) to createControlPlane, each family on its own
cron read literally from the config YAMLs (the deliberate offsets stagger the
families' Playwright fan-outs on the shared BrowserPool):
  - fleet-job-producer       40 * * * *          (d6, unchanged; honors FLEET_PRODUCER_CRON)
  - fleet-producer-e2e-smoke  */15 * * * *
  - fleet-producer-e2e-demos  10 * * * *
  - fleet-producer-e2e-deep   5,20,35,50 * * * *
The in-process HTTP probe runner and the d6 producer's REQ-B sweep leg are left
intact (additive). The worker registry is untouched.

R1 (verified, no change): both createPooledE2eSmokeLauncher and
createPooledE2eDeepLauncher thread contextOpts.extraHTTPHeaders, so smoke + deep
set their per-slug X-AIMock-Context themselves.
2026-06-05 16:11:08 -07:00
github-actions[bot] 12a6c18049 style: auto-fix formatting 2026-06-05 22:49:28 +00:00
github-actions[bot] a3ec4f5875 style: auto-fix formatting 2026-06-05 15:48:34 -07:00
Jordan Ritter eed8d8316f fix(showcase): control-plane probe sweep parity, kind drift-guard, and CR gap-fills
Address the CR gaps on the in-process HTTP-probe control-plane:

- Sweep orphaned `running` probe_runs at control-plane boot (boot()'s
  sweepStaleRuns never ran in fleet mode → leaked rows forever). Best-effort;
  a sweep failure does not abort boot.
- Add a fail-loud BROWSER_KINDS / HTTP-driver disjointness assert at boot plus
  a drift-lock test mirroring registerAllProbeDrivers, so a mis-added kind
  can't silently go dark.
- Assert the PR's headline guarantees that were unasserted: cron-from-YAML
  (exact values), /health loader-failure boot-survival + probes.reload.failed
  emit + rules=0 observability, hot-reload add/remove + watcher teardown, a
  discovery-backed family (qa) in the in-process schedule, and tightened
  /health rule/job counts to exact equality.
- Bump the includeKind skip log to info; make diffHttpProbeSchedules'
  unregister-failure post-state explicit (keep config observable); correct the
  /health "no longer masks" comment, the discovery-source comment
  (image_drift uses railway-services; version_drift uses pnpm-packages), the
  reload-failed surface comment (no bus subscriber on the control-plane), and
  drop transitional-rot tags.
2026-06-05 15:46:15 -07:00
Jordan Ritter 8caff3f704 feat(showcase): run HTTP-only probe families in-process on the fleet control-plane
The fleet control-plane previously ran only the d6 producer, leaving the 8
HTTP-only probe families (smoke, starter_smoke, image_drift, qa, aimock_wiring,
version_drift, pin_drift, redirect_decommission) dark on the fleet. Lift the
legacy boot() probe-loader machinery into runControlPlane so those families run
in-process:

- Add BROWSER_KINDS = {e2e_d6, e2e_smoke, e2e_demos, e2e_deep}; HTTP = every
  other kind. Add registerHttpProbeDrivers (HTTP-only driver set, no BrowserPool
  drivers).
- In runControlPlane, build an HTTP-only probeRegistry + discovery registry
  (railway-services cached + pnpm-packages, mirroring boot()), a probe-loader
  scoped to HTTP kinds, and the same diffProbeSchedules/buildProbeInvoker loop
  boot() uses — registering one probe:<id> scheduler entry per YAML config.
  Crons are driven from the YAML schedule. Browser e2e_* YAMLs route to the
  worker producer path and are NOT scheduled in-process.
- Add an includeKind predicate to createProbeLoader so a browser YAML on disk is
  SKIPPED (not rejected) against the HTTP-only registry — no spurious
  probes.reload.failed.
- /health: ruleCount now reflects the in-process HTTP probe count (was a
  hardcoded 0). The control-plane role still drops the rules>0 gate, but the
  real count means a silent probe-loader failure is visible on /health rather
  than masked. schedulerJobCount already counts the new probe entries.
- Tear down the HTTP-probe file watcher on stop() and on bind failure.
2026-06-05 15:46:15 -07:00
Jordan Ritter ca96837025 feat(harness/fleet): generalize enumerator + control-plane for N producer schedules (#5285)
## Summary

Producer-side foundation for fleet framework item 3b. Two
**behavior-preserving** generalizations that make the seam capable of
multiple browser families and multiple producer cadences, while keeping
the d6 case **byte-identical**. No wiring is flipped on yet (see Out of
Scope).

### 1. Parameterized service enumerator
`showcase/harness/src/fleet/control-plane/catalog-enumerator.ts`
- New generic `createServiceEnumerator(params)`
(catalog-enumerator.ts:215) takes the service-set `filter`, the
`driverKind`, and a `probeKeyPrefix` (string prefix → `<prefix>:<slug>`,
or a builder fn).
- `createD6ServiceEnumerator` (catalog-enumerator.ts:280) is
re-expressed as a thin call passing the d6 params: `D6_DRIVER_KIND`
(`e2e_d6`), prefix `"d6"` (→ `d6:<slug>`), and `D6_DISCOVERY_FILTER`. d6
output is unchanged — same services, same filter, same kind, same keys.

### 2. Control-plane accepts an array of producer schedules
`showcase/harness/src/fleet/control-plane/control-plane.ts`
- New `ProducerSchedule` type (`{ scheduleId, cron, producer }`) + a
`schedules?` dep on `ControlPlaneDeps`.
- `createControlPlane` normalizes to an array (control-plane.ts:~232);
omitting `schedules` degenerates to the single d6 schedule on
`FLEET_PRODUCER_SCHEDULE_ID` (`fleet-job-producer`) @ `40 * * * *` —
current behavior preserved exactly.
- `start()` / `stop()` iterate the array, registering/unregistering each
scheduler entry and starting/stopping each producer.

## Out of scope (deferred — gated on other in-flight PRs)
- **No `runControlPlane` wiring** to actually PASS multiple schedules —
that edit conflicts with in-flight **#5284** (which edits
`runControlPlane`) and is deferred. This PR only makes
`control-plane.ts` *capable* of N schedules + generalizes the enumerator
seam; the wiring lands later.
- No `e2e_smoke` / `e2e_demos` / `e2e_deep` enumerators or producers
(Phase 2).
- No changes to `worker-loop.ts` / `payload-mapper.ts` /
`probe-loader.ts` (other PRs own those).
- No driverKind constant / contract changes.

## Test plan
- [x] Red→green TDD: 3 new enumerator tests (generic
kind/keys/filter/fn-prefix) + 2 new control-plane tests (N entries
registered with distinct crons; stop tears all down) failed before impl,
pass after.
- [x] Equivalence: all pre-existing d6-enumerator + single-schedule
control-plane tests pass unchanged.
- [x] Full harness suite green: **2078 passed** (119 files).
- [x] `tsc -p tsconfig.build.json` clean (exit 0).
- [x] Only the 4 intended files changed; no lockfile drift.

Do not merge — producer-side foundation only; wiring follows after #5284
lands.
2026-06-05 15:44:07 -07:00
Jordan Ritter fcf1a33d73 fix(showcase): track interim harness-legacy service in railway-envs SSOT (unblock harness builds)
The showcase_build verify-image-refs gate (SSOT = showcase/scripts/railway-envs.ts)
was failing with "1 untracked Railway services" because the interim
harness-legacy staging service (the legacy all-probe harness kept live during
the pool-fleet migration) exists on Railway but had no SSOT entry. That
Railway->SSOT drift check skips the build, so nothing deploys.

Adds a harness-legacy SERVICES entry mirroring the showcase-harness-worker
precedent (PR #5280): ciBuilt:false (not built by showcase_build, runs a pinned
out-of-band digest) and gateIgnore:true (deliberately-untracked for the image-ref
gate). findUntrackedServices treats any SSOT entry as known, so this clears the
untracked failure; gateValidated:false keeps findMissingServices from flagging
it. Real serviceInstance IDs for both envs recorded from Railway GraphQL.
Regenerates railway-envs.generated.json and updates the service-count /
gate-ignored carve-out assertions (28->29 services).

Verified: live verify-railway-image-refs.ts now exits 0 ("54 env-scoped
instances verified, 2 skipped"); without the entry it exits 1 with the
harness-legacy untracked failure. Full scripts test suite green (1771 passed).
2026-06-05 15:37:26 -07:00
Jordan Ritter ef4413035d fix(harness/fleet): harden multi-schedule seam to fail-loud bar
The multi-schedule seam (createServiceEnumerator + the schedules[] capability
in control-plane) didn't meet the file's own best-effort/fail-loud bar. Harden
it now since Phase 2 builds on it (no production caller yet):

- stop(): guard each producer.stop() per-entry so one rejection no longer aborts
  teardown of later schedules (leaked cron handlers + running producers).
- start(): pre-validate every schedule's cron up-front before starting any
  producer, throwing an aggregated error naming the offending scheduleId — no
  more half-started plane with `started` latched true.
- normalization: throw on duplicate scheduleId (replace-semantics would silently
  collapse two producers onto one entry) and on an explicitly-empty schedules:[]
  (distinct from omitted, which keeps the d6 default).
- createServiceEnumerator: require a non-empty filter.namePrefix (an absent
  prefix would enumerate ALL services) and reject an empty probeKey from a
  function-form prefix, naming the slug.

Also: narrow the d6 "byte-identical" docstring (specs identical; the
catalog-enumerated log adds driverKind), pluralize the start()/stop() +
module-header producer comments, drop the Phase 2 marker, and extract the shared
ServiceSetFilter type.
2026-06-05 15:24:55 -07:00
github-actions[bot] ab4bb1cc65 style: auto-fix formatting 2026-06-05 22:16:41 +00:00
github-actions[bot] 97d9c0cfe8 style: auto-fix formatting 2026-06-05 22:11:51 +00:00
Jordan Ritter 4c3610c8c8 feat(harness/fleet): generalize enumerator + control-plane for multi-schedule producers
Producer-side foundation for fleet item 3b — two behavior-preserving
generalizations, byte-identical for the d6 case:

1. Generalize the d6 service enumerator into a parameterized
   `createServiceEnumerator(params)` carrying the service-set filter, the
   driverKind, and the probeKey prefix builder. `createD6ServiceEnumerator`
   is now a thin wrapper passing the d6 params (e2e_d6 kind, d6:<slug> keys,
   D6_DISCOVERY_FILTER), so d6 behavior is unchanged.

2. Generalize createControlPlane to accept an array of
   { scheduleId, cron, producer } entries and register each on the scheduler.
   The single-d6 case degenerates to a one-element array on
   fleet-job-producer @ 40 * * * *, preserving current behavior.

Out of scope (gated on in-flight PRs): orchestrator runControlPlane wiring
to pass multiple schedules (conflicts with #5284), the e2e_smoke/demos/deep
families (Phase 2), and worker-loop/payload-mapper/probe-loader.
2026-06-05 15:10:29 -07:00
Jordan Ritter 2a9b38bbfe fix(showcase): repair self-contained worker boot + generalize driver registry seams
CR fixes for the fleet worker driverKind→driver registry (PR #5283):

- Fix default (self-contained) worker boot: build the default d6 as a
  registry entry { driver, payloadToInput, aggregateSlugKey } instead of a
  bare driver with no mapper, so startWorkerLoop's construction guard no
  longer throws "Fleet worker has no drivers".
- Thread aggregate-key derivation through DriverRegistryEntry
  (aggregateSlugKey?), defaulting to d6:<slug> so the d6 cell-capture filter
  stays byte-identical while non-d6 kinds can supply their own scheme.
- Add construction-time fail-loud assert that each registry entry's factory
  kind matches its key; raise unknown-driver-kind log to error to match the
  sibling protocol-violation logs.
- Extract shared buildPooledBrowserDrivers consumed by both
  registerAllProbeDrivers and the worker registry; collapse no-op per-kind
  payload-mapper aliases to the single createPayloadToInput.
- Introduce typed DriverKind union (contained to worker/payload-mapper);
  keep contracts.driverKind a string wire boundary.
- Tests: new fleet/orchestrator.test.ts (default-boot equivalence), driver
  construction-guard + custom aggregateSlugKey coverage, and lock-step +
  registry-wiring pins (factory kind == constant).
2026-06-05 15:10:18 -07:00
github-actions[bot] bb46436d1c style: auto-fix formatting 2026-06-05 21:45:50 +00:00
Jordan Ritter 36b1404d52 feat(showcase): worker driver registry (driverKind→driver) for fleet
Generalize the fleet worker from a single hardwired d6 driver into a
driver REGISTRY keyed by payload.driverKind, so one worker can host all
four browser driver families (e2e_d6, e2e_deep, e2e_demos, e2e_smoke).

- worker-loop: accept a `drivers: Map<kind, { driver, payloadToInput }>`
  and dispatch each claimed job by `payload.driverKind`. Unknown kind →
  terminal `worker-protocol-violation` (same shape as an unmappable
  payload), never a worker crash. Legacy single `driver`+`payloadToInput`
  pair retained as a fallback for back-compat. Fail-loud at construction
  when neither a registry nor the legacy pair is supplied.
- payload-mapper: generalize createD6PayloadToInput into a shared
  createPayloadToInput plus per-kind aliases and the four driver-kind
  constants (the input re-hydration is identical across families; each
  driver's own zod schema is the validation gate).
- orchestrator runWorker: build all four pooled drivers on the shared
  BrowserPool and register them by kind, lifted from the legacy
  registerAllProbeDrivers pooled construction.

d6 routing is unchanged (equivalence gate). Red-green tests cover
routing e2e_smoke/e2e_deep/e2e_d6 to their drivers and unknown-kind →
protocol-violation. Full harness suite green (2085 tests); tsc clean
except the known pre-existing toReversed error.
2026-06-05 14:44:57 -07:00
github-actions[bot] 3a56ecab00 style: auto-fix formatting 2026-06-05 20:00:49 +00:00
Jordan Ritter 959d42b585 fix(showcase): add showcase-harness-worker to Railway SSOT (railway-envs.ts)
The pool-fleet cutover manually created the staging-only
`showcase-harness-worker` Railway service (HARNESS_ROLE=worker, 2
replicas) and flipped the existing `harness` service to
HARNESS_ROLE=control-plane. The new service was untracked in the SSOT,
so verify-railway-image-refs.ts failed the "Showcase: Build & Push"
workflow on every push to main (1 untracked Railway service), which
skipped the harness `build` job and blocked harness image rebuilds.

Add the worker to SERVICES as a staging-only, domain-less queue worker:
- ciBuilt:false — it runs the SAME `showcase-harness` image the existing
  harness build slot produces; there is no separate worker build.
- gateIgnore:true / gateValidated:false — no prod instance and no public
  domain, so it does not fit the symmetric dual-env shape the image-ref
  gate validates. gateIgnore clears the "untracked Railway service"
  failure (any SSOT entry counts as known) without tripping a false
  "missing from prod" failure.
- repoNameOverride → showcase-harness so the image-ref shape resolves.
- probe disabled in both envs (no externally-reachable health endpoint).

Regenerate railway-envs.generated.json and update the SSOT-count and
gate-coverage test invariants (27→28 services; worker is the sole
intentional gateIgnore/gateValidated:false entry).
2026-06-05 12:59:51 -07:00
Jordan Ritter ec85e17b14 fix(showcase): send X-AIMock-Context from starter-smoke chat probe (match scoped fixtures)
The harness starter-smoke CHAT rung 503'd on staging because its raw fetch()
POST sent only Content-Type — omitting X-AIMock-Context. The scoped
per-integration "Hello" fixtures in showcase/aimock/d4/<integration>/chat.json
only match (under aimock strict mode) when the request carries
X-AIMock-Context:<context>, and that context token IS the dashboard column
slug (verified against each integration's
showcase/integrations/<col>/playwright.config.ts extraHTTPHeaders and the
fixture's match.context). The local browser e2e passes only because Playwright
injects the header, forwarded by HeaderForwardingMiddleware to aimock.

Send X-AIMock-Context: <columnSlug> on the chat POST only (matching the
browser; the GET rungs hit the runtime /info route, not aimock). columnSlug is
already resolved via starterToColumnSlug before the chat rung runs, so the skew
cases (langgraph-js->langgraph-typescript, adk->google-adk,
strands-python->strands, ms-agent-framework-*->ms-agent-*) get the correct
context for free.

Proven RED->GREEN against live staging aimock
(https://aimock-staging.up.railway.app): without the header -> 503
no_fixture_match; with the mapped column-slug context -> 200 matching the
scoped fixture.
2026-06-05 12:39:54 -07:00
Jordan Ritter 6d318afa12 fix(showcase): path-based content-level starter-smoke probe (#5262)
## Summary

Rewrites the `starter-smoke` probe to the **v2 path-based multi-route**
runtime protocol the deployed starters actually speak — proven via a
local build+curl gate against `examples/integrations/crewai-crews` at
1.59.5 (the runtime mounts `createCopilotEndpoint` in default
`mode:"multi-route"`, identical at 1.59.3 and 1.59.5).

- **agent** → `GET /api/copilotkit/info` requiring 200 + `version` (was:
"any non-404", which a health-JSON/HTML error page wrongly passed)
- **chat** → `POST /api/copilotkit/agent/<id>/run` (`Accept:
text/event-stream`), asserting ≥1 `TEXT_MESSAGE_CONTENT` delta **+**
terminal `RUN_FINISHED` **+** no `RUN_ERROR` (was: "non-empty body")
- **health** → repointed to `GET /api/copilotkit/info` (the starters
serve no `/api/health` route)
- **interaction** → `GET /` (unchanged)
- **drop the trailing slash** on runtime POSTs — `POST /api/copilotkit/`
308-redirects and drops the POST → 404, the core cause of the red rungs

Plus a **unified abort/body-read error classification** (one
`abortOutcome()` helper keyed on the local `externallyAborted` flag): a
self-timeout or a non-abort error → `transport-error` (soft), only a
genuine external abort → `aborted`; a cut-short body read softens to
`transport-error` instead of hard `smoke-failed`; the level loop
short-circuits on external abort. Reviewed across 3 CR rounds
(path-based rewrite + 2 abort-classification fix rounds + confirmation).

> **NOTE:** the content-level chat rung will correctly read **RED**
against the deployed starters until the Python-side `ag-ui-crewai`
`RUN_ERROR` (a real-LLM, in-process agent failure — *not* a probe bug)
is fixed. That is the truthful signal.

## Deferred follow-ups (tracked, not in scope)
- **Verify the alert/staleness consumer branches on `errorClass`, not
`state`** — else the soft/hard (`transport-error` vs `smoke-failed`)
split is cosmetic at the dashboard layer
- `res.text()` resolve-partial (truncated-but-resolved body) precision
edge → could mis-class as `smoke-failed`
- `redirect:"follow"` POST→GET edge; health/interaction success-path
body drain; health/agent share `/info` (correlated signals)
- `CLASS_RANK` ranks `aborted` lowest (design call); unmapped-starter
`columnSlug` invariant + prototype-key collision
- test-coverage gaps: `resolveTimeoutMs` env parsing,
`deriveStarterSlug` fallback, real-timer abort path

## Test plan
- [x] Harness unit suite — 1829 tests pass (105 files); starter-smoke
35/35; red-green verified for protocol + all abort/body-read fixes
- [x] Typecheck (no new errors), oxlint (0 errors), oxfmt, harness build
- [ ] Post-merge: redeploy harness, re-probe; chat rung greens once the
Python-side RUN_ERROR is fixed (separate workstream)
2026-06-05 11:13:09 -07:00
github-actions[bot] a5b474eedd style: auto-fix formatting 2026-06-05 18:11:11 +00:00
Jordan Ritter 680d4284c0 fix(showcase): harden starter-smoke agentId resolution + chat-rung failure handling (CR round) 2026-06-05 11:04:46 -07:00
Jordan Ritter 4654e747d3 fix(showcase): resolve starter-smoke chat agentId from /info agents map
The chat rung hardcoded `/api/copilotkit/agent/default/run`, which 404s for
mastra — it registers dynamic non-`default` agent keys via
`MastraAgent.getLocalAgents` rather than `agents:{default}`. Resolve the
agent id per-starter from the first key of the `/info` `agents` map (the same
info response the health + agent rungs already fetch), falling back to
`default` only when that map is empty/unreadable, and surface the resolved id
on the chat row signal for drilldown.
2026-06-05 10:50:36 -07:00
Jordan Ritter 0fbf0e9140 fix(showcase): path-based content-level starter-smoke probe
Rewrite the starter-smoke probe to the v2 path-based multi-route runtime
protocol the deployed starters actually speak (proven via a local
build+curl gate against examples/integrations/crewai-crews at 1.59.5):

- agent rung: GET /api/copilotkit/info -> 200 + version (was: any non-404)
- chat rung: POST /api/copilotkit/agent/<id>/run (Accept: text/event-stream)
  asserting >=1 TEXT_MESSAGE_CONTENT delta + terminal RUN_FINISHED + no
  RUN_ERROR (was: non-empty body)
- health rung: repointed to GET /api/copilotkit/info (the starters serve
  no /api/health route)
- interaction rung: GET / (unchanged)
- drop trailing slash on all runtime POSTs (the old /api/copilotkit/ 308s
  and drops the POST -> 404, the core cause of the red rung)

Plus a unified abort/body-read error classification (one abortOutcome()
helper keyed on the local externallyAborted flag): a self-timeout or a
non-abort error is transport-error (soft), only a genuine external abort
is 'aborted'; a cut-short body read softens to transport-error instead of
hard smoke-failed; the level loop short-circuits on external abort.

NOTE: the content-level chat rung will correctly read RED against the
deployed starters until the Python-side ag-ui-crewai RUN_ERROR (a
real-LLM, in-process agent failure, NOT a probe bug) is fixed.

Deferred follow-ups: verify the alert/staleness consumer branches on
errorClass (not state) so the soft/hard split is actually consumed;
res.text() resolve-partial precision edge; redirect:follow POST edge;
health/interaction body-drain; health/agent shared /info; CLASS_RANK
aborted-lowest; unmapped-starter columnSlug/prototype-key; test-coverage
gaps (resolveTimeoutMs, deriveStarterSlug, real-timer abort).
2026-06-05 10:50:36 -07:00
Jordan Ritter 84b0035d1d feat(showcase): wire fleet roles into the showcase CLI and local compose 2026-06-05 10:38:41 -07:00
Jordan Ritter ffc60ff1ca feat(showcase): surface fleet pool comm-errors (unreachable overlay) on the dashboard 2026-06-05 10:38:41 -07:00
Jordan Ritter ef76c6d0ff feat(showcase): add fleet worker loop, registration, and health 2026-06-05 10:38:40 -07:00
Jordan Ritter 554e824a8f feat(showcase): add fleet control-plane (producer/consumer/aggregator/fleet-health) + role dispatch 2026-06-05 10:38:40 -07:00
Jordan Ritter f8aee59b62 feat(showcase): add fleet queue client, CAS claim, and role-config 2026-06-05 10:38:40 -07:00
Jordan Ritter 57122abe83 feat(showcase): add PocketBase pull-queue collections + CAS claim hook for harness fleet 2026-06-05 10:38:40 -07:00
Jordan Ritter 1d29464df2 Showcase dashboard: robustness + signal-projection follow-up to #5256 (#5263)
## Summary

Follow-up to #5256 (the concurrent-paged initial-fetch perf fix). Trims
the live-status payload and hardens the realtime/SSE path of the
showcase Coverage dashboard.

- **Trim initial projection** — drop the heavy `signal` field from the
initial PocketBase fetch via a compiler-guarded `STATUS_LIST_FIELDS`
projection + `skipTotal` + length-based bounded-concurrency pagination.
Consumers adapted: `CellDrilldown` lazy-loads `signal` on demand
(genuine failures only), `DiscoveryAuthBanner` self-fetches detail
(identity-tagged cache), legacy `LiveBadge` degrades gracefully when
`signal` is absent.
- **Harden the realtime path** — `flushPending` teardown guards,
keyless-delete `id→key` buffer collapse (per-row last-write-wins, pure
ref+effect mirror), SSE-delta signal-presence upsert, and a `degraded`
flapping flag (clears on heartbeat success, resets on terminal error).
- **Grid/UX** — a `stale` (muted, non-authoritative) tally state
distinct from the no-rows loading state, an amber-chip/green-D5
dimension-classification fix, and `degraded` surfaced in the header
`LiveIndicator` (offline outranks degraded).

## Test plan

- [x] `tsc --noEmit` clean
- [x] `vitest run` — 879 passed / 1 skipped (56 files); +63 new
behavioral tests across the changed areas (real-SDK socket tests for
fetch/autocancel/lazy-signal, fake-timer tests for the flapping detector
and reconnect chain, exhaustive resolveCell truth-tables)
- [x] `next build` — compiled successfully, 5/5 static pages
- [x] oxfmt + oxlint clean
- [ ] CI green
- [ ] Visual verification on staging after deploy

## Known follow-ups (deferred — pre-existing / out-of-subject, not
introduced by this PR)

These were surfaced during review, verified pre-existing on `main` (or
unreachable in the shipping config), and intentionally not fixed here to
keep the PR scoped:

- Column-header tally counts deprecated features hidden from the grid
body (`computeColumnTally` iterates the full `features` list while the
body renders `visibleFeatures`) — pre-existing, header/body over-count
identical before and after. Strong candidate for a dedicated follow-up.
- `resolveCell` rollup does not suppress amber/degraded cells when
`connection === "error"` (only green is suppressed) — pre-existing
precedence.
- `formatTooltip` offline branch renders "degraded since
<transitioned_at>" for a staleness-downgraded green row.
- `LiveBadge` arms the `useLastTransition` fetch for
staleness-downgraded amber badges (no `isGenuineFailure` filter, unlike
the drilldown).
- `CellStatus` passes the raw `featureId` as the CV-badge transition
key, so mapped D5 families query a non-existent history row.
- Cosmetic: `extractSignalFields` renders `{}` for an empty-object error
field; `degraded` lacks an effect-cleanup reset on the
(production-unused) `dimension` param path; minor comment-accuracy nits
(reconnect backoff tiers, rollup-precedence JSDoc).
2026-06-05 10:09:54 -07:00
Benjamin Taylor 1c92a69f58 fix(links): point cloud.copilotkit.ai web links at the Intelligence dashboard
New users were still discovering cloud.copilotkit.ai through docs pages,
the README, example READMEs, and in-app banners/console messages. Replace
all user-facing web links with dashboard.operations.copilotkit.ai (the
destination the marketing-site CTAs already use). Functional API endpoints
(api.cloud.copilotkit.ai) are deliberately untouched since existing cloud
customers depend on them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 11:20:44 -05:00
Ran Shemtov a5037cafd4 Merge branch 'main' into chore/upgrade-showcase-a2ui-deps 2026-06-05 17:55:27 +02:00
github-actions[bot] 83404f8ca5 style: auto-fix formatting 2026-06-05 15:54:58 +00:00
Ran Shem Tov efd35f0f8d chore: align all a2ui instances with the latest implementations 2026-06-05 17:54:16 +02:00
Tyler Slaton ca6115850b docs: unify theme (#5269)
Our previous doc site had a fumadocs/shadcn theme that was a bit
hodge-podge. This brings all of it into one clean and visually appealing
design. The border radii are standardized, colors are standardized and
bunch of passes for mobile/tablet have been done. An added bonus is that
the header nav has been redone to feel more natural to the eyes.

<img width="1850" height="1256" alt="Screenshot 2026-06-05 at 7 48
00 AM"
src="https://github.com/user-attachments/assets/0c6032f2-e406-4e51-9c31-d69a9d258d61"
/>
2026-06-05 08:19:55 -07:00
Tyler Slaton 563d8a7986 docs(shell-docs): align docs page rendering
Updates the shell-docs route wrappers, MDX component chrome, page actions, snippets, and registry rendering so content pages inherit the refreshed theme and responsive sizing consistently.

Call-site enumeration:

- DocsPageView and mdx-components remain the route-level rendering path for docs, framework, AG-UI, and reference pages.

- CopyButton/Snippet/PropertyReference changes stay within MDX-rendered content surfaces.
2026-06-05 07:38:53 -07:00
Tyler Slaton f5d7a7617b docs(shell-docs): refresh landing surfaces
Applies the updated shell-docs theme treatment to the overview cards, sample tabs, framework selectors, hero command controls, and Copilot Cloud CTAs.

Call-site enumeration:

- FrameworkSelector/FrameworkTabs/IntegrationGrid changes stay on the docs landing and framework overview surfaces that already own those controls.

- OpsPlatformCTA and LinkToCopilotCloud keep their existing call sites while switching to shared chrome variables.
2026-06-05 07:35:42 -07:00
Tyler Slaton 7510d9d6b4 docs(shell-docs): unify docs chrome
Refreshes the shell docs chrome around the shared theme tokens, announcement banner, desktop and mobile navigation, search trigger, theme toggle, and sidebar footer actions.

Call-site enumeration:

- PrimaryDocsTabs: rendered by MobileTopNav for tablet header tabs and ShellDocsLayout for mobile sidebar tabs.

- MobileSidebarFooterTalk: rendered by ShellDocsLayout sidebar.footer and hidden outside mobile/tablet sidebar usage via responsive classes.

- INTELLIGENCE_CTA_HREF and TALK_TO_ENGINEER_HREF: exported from BrandNav and reused by BrandNav/MobileSidebarFooterTalk so CTA destinations stay centralized.
2026-06-05 07:34:22 -07:00
Ran Shem Tov 20aa327a8c fix(showcase): enable injectA2UITool for langgraph-python declarative-gen-ui
It was left at false while fastapi/typescript are true. Under the opt-in
A2UI model false means no tool is injected, so the python demo rendered
no surfaces (and the docs code-tab showed no injectA2UITool). Set true to
match the other langgraph integrations.
2026-06-05 11:25:23 +02:00