Commit Graph

220 Commits

Author SHA1 Message Date
Jordan Ritter af306b52c5 fix(showcase): slow D5 deep sweep cadence to 30min to stop staleness banner flap 2026-06-28 00:15:27 -07:00
Jordan Ritter edb8f8cbe8 fix(showcase): CR polish — soften family-silence comments, prune tautological tests, a11y label, grace-edge test 2026-06-26 13:55:38 -07:00
Jordan Ritter 6c5fc73cba fix(showcase): grace-window suppresses false family-silence on post-deploy worker bounce
A normal harness deploy rebuilds the shared showcase-harness image and
bounces the pool workers (PR #5715). Immediately after the bounce the
workers re-register, the producers re-arm, and every family is mid-sweep:
lastSuccessAt still points at the pre-bounce success, so it reads stale
against the silence thresholds (banner 2x period, Slack alert 3x period +
3 consecutive ticks). The result was a FALSE "worker family X has not
completed successfully" banner AND Slack family-silence alert during the
expected post-bounce drain window.

Fix: a bounce-keyed grace window. The freshest worker registered_at across
the /api/runs workers strip is the fleet's most-recent bounce instant
(independent of CP boot — a worker can bounce while the CP stays up). While
now - bounce < 2 x period, a family with no success yet is DRAINING, not
silent, so neither the §7.4 banner, the §7.3 cell glyph, nor the §9 Slack
alert flags it. Beyond the window with still-no-success, genuine silence
fires exactly as before.

The determination lives in two surfaces (server monitor for the Slack
alert; client isFamilySilent for the banner + glyph), so both now consume
the same new SSOT field (WorkerView.registeredAt) and the same 2x-period
grace constant, keeping them consistent.

- run-view.ts: project registered_at -> WorkerView.registeredAt (server)
- family-silence-monitor.ts: BOUNCE_GRACE_PERIOD_MULTIPLIER + freshest-bounce
  grace gate, keyed off body.workers
- worker-runs-context.tsx: freshestBounceMs + bounceAtMs grace arg on
  isFamilySilent; banner + cell glyph pass it
- ops-api.ts: WorkerView.registeredAt on the client DTO
2026-06-26 13:41:36 -07:00
Jordan Ritter 90d63c2dc3 fix(showcase): polish dashboard SWR chip — SR status, regression spinner-guard, chip-color ring, glyph size 2026-06-26 13:41:35 -07:00
Jordan Ritter 1c82f71928 fix(showcase): stale-while-revalidate for dashboard depth chip
A GREEN coverage cell flapped green -> grey -> green every time its probe
job's worker lease lapsed and the control-plane sweeper re-queued the job
(worker-reclaimed-pending). The data layer already preserves the
last-known-good colour in chipColor while surfaceState flips to "pending",
but depth-chip.tsx's `if (pending)` branch did a destructive grey
early-return that never read chipColor.

Split the pending branch:
- prior-good (chipColor is a real colour, or depth > 0): render the normal
  coloured chip via the default branch's exact ternary (threading regression
  through) PLUS a non-destructive refreshing affordance -- a corner ⟳ glyph
  and a subtle pulsing ring in the chip's own colour, with
  data-refreshing="true" / data-has-prior="true". Colour preserved.
- no-prior (never-run / first load: gray + depth 0): keep today's honest grey
  ⟳ chip, now tagged data-has-prior="false".

The unreachable red ⚡ overlay and the "failure never masked" gate are
untouched; red/regression cells pass through with no spinner. The refreshing
cue is conveyed by shape (⟳) + motion (ring), never by colour alone, and the
pulse/spin respect prefers-reduced-motion (motion-reduce:animate-none), so the
static ⟳ carries the meaning for colour-blind and reduced-motion operators.

Renderer-only change; unified-cell.tsx is the sole caller passing `pending`.
2026-06-26 13:41:35 -07:00
Jordan Ritter 4ef08bb112 refactor(showcase): revert label-derived var names to mirror Status enum
The internal counter vars pctBeAgent and totalBeAgent were introduced in
PR #5498 when the display label happened to be "BE (Agent)". The label
has since changed (#5505 made it "API (HTTP)"). Coupling internal variable
identifiers to display labels is fragile — labels move; the underlying
Status enum string "wired" is a persisted contract that does not.

Revert the var identifiers to mirror the enum:

  pctBeAgent   -> pctWired   (coverage-bar.tsx)
  totalBeAgent -> totalWired (cells-view.tsx, parity-view.tsx)

Display labels ("API (HTTP)", etc.) are unchanged — this is internal
identifiers only.
2026-06-16 15:05:46 -07:00
Jordan Ritter 14451d5c3d refactor(showcase): normalize API/BE long-form labels — API (HTTP) for transport, BE (Agent) for chat round-trip
PR #5498 renamed the L1 row "Wired" → "BE (Agent)" for the D2 agent-liveness
dimension (transport/Railway up). PR #5503 renamed the per-cell D4 badge
"RT" → "BE", whose long form was already "BE (Round Trip)". The result was a
same-label-different-concept collision: "BE (Agent)" referred to D2 in some
places while the D4 per-cell badge used "BE (Round Trip)", and the per-cell
D2 badge separately used "API (Agent)" — three names for two concepts.

Normalize the long-form labels so each user-facing layer has exactly one name:

  D2 (transport / Railway up, HTTP-reachable) = "API (HTTP)"
  D4 (agent chat round-trip, end-to-end)      = "BE (Agent)"

That cleanly distinguishes by layer: HTTP transport vs Agent message handling.

Sites touched (visible labels + matching legend prose / test assertions only):
  - stats-bar.tsx, adaptive-stats-bar.tsx — wired count label
  - filter-chips.tsx                       — chip label (id "wired" preserved)
  - packages-section.tsx + .test.tsx       — UWCT legend mnemonic B → A
  - level-strip.tsx + .test.tsx            — agent-dimension badge label (and
                                             derived first letter B → A)
  - cell-drilldown.tsx + .test.tsx +
    cell-drilldown.lazy-signal.test.tsx    — D4 label and D2 label, plus
                                             testid-derivation drift
  - adaptive-legend.tsx                    — D2 / D4 prose

Stable contracts preserved (NOT changed):
  - keyFor("agent" | "d2" | "d4", …) and the "agent" LiveDimension value
  - Filter-chip id "wired"
  - Variable names (`wired`, etc.) — internal; pure label rename is in scope
  - Status enum values "wired" | "stub" | "unshipped" | "unsupported"
  - Driver names, probe registry keys, harness API contracts

Verified: typecheck clean, 1089 pass / 1 skip / 0 fail, build clean.
2026-06-16 14:19:17 -07:00
Jordan Ritter 1d6d063c76 refactor(showcase): rename cell-badge CV → 1P (clearer scope framing vs D6 all-pills)
The per-cell health badge previously labelled "CV" (for "Conversation") is
renamed to "1P" — Single Pill. The new label tells operators what the badge
covers in scope terms (one pill out of N), which is the actual contrast the
D5/D6 ladder draws: D5 driver is `d5-single-pill.ts` (one canonical scripted
conversation), D6 driver is `d6-all-pills.ts` (the full suite). "CV" was
opaque — operators had to remember what "Conversation" meant and how it
differed from D6's full run. "1P vs D6 all-pills" is self-describing.

Mirrors PR #5503's RT → BE pass: only the badge LABEL changes; every stable
contract is preserved.

Stable contracts preserved:
  - Dimension level identifier  `model.d5` / `cell.d5` / `level={model.d5}`
  - Drilldown dimension key     `keyFor("d5", ...)` / `key: "d5"`
  - Probe registry key          `d5:<slug>/<featureId>`
  - PocketBase row keys         unchanged
  - LiveDimension union / Status enum strings  unchanged
  - Driver file names           `d5-single-pill.ts`, `d6-all-pills.ts`
  - `e2e-deep` producer name    unchanged (separate from CV → 1P label)

Updates:
  - Source: badge label in `unified-cell.tsx`, `cell-pieces.tsx`, drilldown
    label in `cell-drilldown.tsx` ("CV (Conversation)" → "1P (Single Pill)"),
    legend text in `adaptive-legend.tsx`, comment refs in `composed-cell.tsx`,
    `cell-model.ts`, `page-stats.ts`, `depth-utils.ts`, `live-status.ts`.
  - Tests: testid strings (`mock-badge-CV` → `mock-badge-1P`), label-text
    assertions, type unions, and comment refs in the affected component +
    drilldown + integration + lib tests.

Verification: typecheck clean, `npm test` = 1089 pass / 1 skip / 0 fail
(same shape as #5503), `npm run build` clean, no remaining `\bCV\b` in
`showcase/shell-dashboard/src/`.
2026-06-16 14:13:24 -07:00
Jordan Ritter 601e45f0d8 refactor(showcase): rename cell-badge RT → BE (parallel to E2E → UI in #5473)
PR #5498 was mis-scoped — it renamed the L1 row label and catalog status
display from "Wired" to "BE (Agent)", but the dashboard's per-cell badge
code rendered in the grid was still "RT". This commit lands the parallel
flip that mirrors PR #5473's E2E → UI rename for the D4 chat/tools
round-trip badge.

Visible-label flips (RT → BE):
  - unified-cell.tsx: <TestBadge name="RT" level={model.d4} /> → name="BE"
  - cell-drilldown.tsx: { key: "d4", label: "RT (Round Trip)" } → "BE (Round Trip)"
  - adaptive-legend.tsx: legend entry "Round Trip (RT)" → "Round Trip (BE)"
  - Doc-comment taxonomy notes in cell-pieces.test.tsx, composed-cell.tsx,
    cell-model.ts, page-stats.ts, unified-cell.tsx, cell-drilldown.tsx,
    overlay-selector-integration.test.tsx, dashboard-color-matrix.test.tsx
  - Test assertions in dashboard-color-matrix.test.tsx, cell-drilldown.test.tsx,
    unified-cell.test.tsx (mock-badge-RT → mock-badge-BE, drilldown-badge-rt-
    → drilldown-badge-be-, "RT (Round Trip)" → "BE (Round Trip)")

Stable contract identifiers are PRESERVED — only the visible name flips:
  - level={model.d4} unchanged (D4 is still D4)
  - dimensionKey={keyFor("e2e", ...)} unchanged
  - probe registry-key "d4"/"chat"/"tools" unchanged
  - persisted dimension codes unchanged

Two intentional residual "RT" mentions remain in
cell-pieces.signal-degrade.test.tsx as historical commentary documenting
the rename lineage (RT → UI on the e2e badge in #5473, then RT → BE on the
D4 badge here).

Verification (in showcase/shell-dashboard):
  - npm run typecheck: clean
  - npm test: 1089 tests passed
  - npm run build: clean (next build OK)
  - LC_ALL=C grep -rlP '\x00' showcase/shell-dashboard/src: empty
2026-06-16 11:40:50 -07:00
Jordan Ritter 80b526d68b refactor(showcase): slugify stats-bar testids to handle multi-word labels
The testid generator in stats-bar.tsx used `label.toLowerCase()` directly,
producing fragile selectors with spaces and parens for compound labels.
After this PR's rename of "Wired" to "BE (Agent)", the testid became
`stat-be (agent)` — a CSS-hostile selector. A pre-existing
`stat-max depth` (from "Max Depth") had the same problem but predated
this PR.

Fix: replace with a proper slugifier:
  label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "")

Resulting testids:
  "BE (Agent)"   -> stat-be-agent   (was stat-be (agent), broken)
  "Max Depth"    -> stat-max-depth  (was stat-max depth, pre-existing fix)
  "Stub"         -> stat-stub       (unchanged)
  "Unshipped"    -> stat-unshipped  (unchanged)
  "Unsupported"  -> stat-unsupported (unchanged)
  "Regressions"  -> stat-regressions (unchanged)
  "Failures"     -> stat-failures   (unchanged)

Call-site enumeration receipt (mandatory):
  rg 'stat-wired|stat-be|stat-max|stat-stub|stat-unshipped|stat-unsupported|stat-regressions|stat-failures' showcase/shell-dashboard/
    -> no matches (zero hardcoded references anywhere)
  rg 'data-testid=.stat-|"stat-|`stat-' showcase/shell-dashboard/
    -> only one hit: stats-bar.tsx:29 (the generator itself)
  rg 'stat-' showcase/shell-dashboard/tests/
    -> no matches (no Playwright/visual tests depend on these testids)

No test updates required.

Verification:
  npm run typecheck   -> clean
  npm test            -> 1088 pass / 1 pre-existing unrelated failure
                         (useLiveStatus.test.tsx R5 F5.2 — does not
                         reference stats-bar, exists on PR HEAD)
  npm run build       -> clean (Next.js lint inline; no lint script)
  NUL byte sweep      -> empty
2026-06-16 09:40:49 -07:00
Jordan Ritter f316d055fb refactor(showcase): rename internal Wired counters to BeAgent
Renames the internal display-counter variables that fed the
stats-bar / coverage-bar "Wired" labels to match the new "BE (Agent)"
taxonomy: totalWired → totalBeAgent in cells-view.tsx and
parity-view.tsx, pctWired → pctBeAgent in coverage-bar.tsx. These
are local render-time aggregates, not part of any persisted
contract.

The status enum literal "wired" (the .filter((c) => c.status ===
"wired") guard, the coverage-segment-wired test ID, and the
wiredByCategory Map's local name) is intentionally preserved — those
all key directly off the persisted catalog Status enum and changing
them would expand scope into the catalog contract.
2026-06-16 09:23:00 -07:00
Jordan Ritter bfebac6565 refactor(showcase): relabel catalog status Wired display → BE (Agent)
Unifies the catalog integration status display label with the same
"BE (Agent)" taxonomy as the live-probe agent dimension. The
underlying Status enum literal ("wired"), the catalog.metadata.wired
data field, and the filter chip id ("wired" → cell-matrix.tsx:311
status === "wired" filter key) are all PRESERVED — they are
persisted catalog data + filter state contracts that must not move.
Only the user-facing display label on stats-bar, adaptive-stats-bar,
and the filter chip flips.

This collapses the two distinct dashboard "Wired" surfaces (the L1
live-probe dimension and the per-cell build-state count) under one
unified label, matching the user-confirmed Path B.
2026-06-16 09:22:41 -07:00
Jordan Ritter ef40bd7cfb refactor(showcase): relabel live-probe agent dimension Wired → BE (Agent)
Unifies the L1 "agent" live-probe display label with the taxonomy
convention established by #5473 (UI (Frontend), E2E, CV, D6 — layer
descriptor in parentheses). The dimension name stays "agent" in code
(PocketBase row keys agent:<slug>, LiveDimension union, keyFor
lookups are all unchanged stable contracts) — only the visible label
changes.

Updates the level-strip L1 badge label and the packages-section
L1-L4 header legend (W → B, "Wired" → "BE (Agent)") so the
level-strip's ToneChip first-letter abbreviation matches the legend
key. Test assertions covering the rendered letter, the legend text,
and the degraded-tone test's local variable follow suit.
2026-06-16 09:22:31 -07:00
Jordan Ritter 53f021afe8 refactor(showcase): probe taxonomy cleanup — drop Smoke, E2E (Demo) → UI (Frontend)
The smoke probe was the same HTTP contract as /health on the same
service (200-OK JSON body), so every tick paid two HTTP calls for the
same liveness signal. Drop the /smoke GET + the smoke:<slug> primary
ProbeResult; the driver now emits health:<slug> as the primary and
agent:<slug> via writer side-emit (half the per-tick cost).

The driver's registry kind stays "smoke" so existing YAML configs and
orchestrator family wiring keep routing to this driver — the
emission key (health:<slug>) is the taxonomy contract that matters.

Dashboard:
- Drilldown: D3/e2e row labelled "UI (Frontend)" (was "E2E (Demo)");
  Smoke row dropped (CellState.smoke field retained for back-compat).
- Cell badges: short label "UI" (was "E2E") in cell-pieces + unified-cell.
- Legend: D3 = "UI (Frontend): demo page renders in browser (Playwright)"
  plus an explicit Health row at the top.

Tests updated to assert new labels:
- cell-drilldown.test.tsx: 6 dimensions (no Smoke); UI (Frontend) label.
- cell-drilldown.lazy-signal.test.tsx: drilldown-badge-ui--frontend- testid.
- cell-pieces.test.tsx + .signal-degrade.test.tsx: badge name "UI".
- unified-cell.test.tsx: mock-badge-UI.
- overlay-selector-integration.test.tsx: "UI" in place of "E2E".
- dashboard-color-matrix.test.tsx: badge: "UI" case names.
- liveness.test.ts: two-call contract (health + agent), regression guard
  asserting no smoke:<slug> ever emitted.

Underlying probe key (e2e:<slug>/<feature>) preserved on PocketBase so
historical rows render correctly during the rename window.
2026-06-16 01:48:41 -07:00
Jordan Ritter 06f6f2cd6d fix(dashboard): worker-run-detail-panel abort fetches on cleanup + move side-effects out of setState updater 2026-06-11 21:16:38 -07:00
Jordan Ritter 1223bb9fc1 feat(showcase): dashboard worker-runs UI + data layer
Adds the dashboard Ops worker-runs section — family table, worker strip,
run-history drill-down, D0-from-staleness vs D0-from-failure family
annotation with clock glyph, and the per-family silence banner on the
coverage tab. Wires the data layer: DTOs, /api/runs fetchers, polling
hook, and a worker-runs context provider. cell-drilldown / cell-pieces
gain family-aware rendering.
2026-06-11 21:13:34 -07:00
Jordan Ritter 9554abf78f fix(showcase): unify dimension naming on the legend taxonomy across grid, legacy cells, and legend
Grid d3 badge API->E2E, legacy e2e badge RT->E2E, legend D6 "Parity
(PR)"->"Parity (Reference)", legend D4 chip copy 6h->1h (real window);
d4 grid "RT" and d2 "API" unchanged.
2026-06-11 20:42:49 -07:00
Jordan Ritter 553b64495a fix(showcase): drilldown shows the D4 row, de-crosses the e2e label, and scopes the rollup line honestly
D4 row inserted with worst-state strictness; e2e relabeled "E2E (Demo)"
atomically (label-derived testids); rollup line relabeled "Service
(health + e2e)"; headline regression pins pill-red <-> visible red popup
row via buildCellModel.chipColor cross-assert; green-badge tests
FRESH-pinned.
2026-06-11 20:42:48 -07:00
Jordan Ritter 042e79e259 fix(showcase): dashboard pending-surface never masks a real red — severity-first comm-error decode, stale-observedAt guard, pending chip 2026-06-07 22:40:13 -07:00
Jordan Ritter 5387e4de38 fix(showcase): add D6 entry to coverage dashboard legend 2026-06-06 02:30:36 -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 6161047933 fix(showcase-dashboard): degrade LiveBadge gracefully when row lacks signal
Treat `signal` as optional on legacy LiveBadge rows (neutral 'unknown' marker
when absent), so the trimmed initial projection cannot misrender or throw.
2026-06-05 01:46:12 -07:00
Jordan Ritter 264f88f2b1 feat(showcase-dashboard): lazy-load signal in CellDrilldown
Fetch `signal` on demand for genuinely-failing badges (excluding staleness-
downgraded greens via fail_count), with per-badge loading/error resolution that
distinguishes in-flight, partial-failure (requested-but-absent), and resolved
states. Injection-safe pb.filter OR query; object-valued fields render as JSON.
2026-06-05 01:46:11 -07:00
Jordan Ritter c5a6db9991 fix(showcase-dashboard): self-fetch signal in DiscoveryAuthBanner
Banner visibility still derives from projection-safe key+state on the live rows;
detail copy self-fetches `signal` (via pb.filter placeholders, page size = key
count) only when omitted by the trimmed projection, with an identity-tagged cache
(id + transitioned_at) that won't serve a stale signal across content changes.
2026-06-05 01:46:11 -07:00
Jordan Ritter e76129ca55 feat(showcase-dashboard): add stale tally, fix amber/D5 dimension, surface degraded
Thread a `stale` flag (muted, non-authoritative counts during reconnect-with-rows,
distinct from the no-rows loading state), fix the amber-chip/green-D5 cell to
classify into the health dimension, and surface the hook's `degraded` flag in the
header LiveIndicator (offline outranks degraded). Wire `degraded` from
useLiveStatus through to FeatureGrid in dashboard-page.
2026-06-05 01:46:11 -07:00
Jordan Ritter cd45c873a9 fix(showcase-dashboard): show loading state instead of authoritative zeros during initial fetch
A connecting status with an empty status map now renders a loading
affordance instead of authoritative checkmark-0 / D0 cells and
zeroed column tallies. Make loading required on the tally type so the
contract is explicit, and default the fail-safe undefined-tally
fallback to loading rather than fake zeros. Adds coverage for the
loading-state quadrants across computeColumnTally /
computeColumnTallyDetail and the OverlayColumnHeader affordance.
2026-06-04 23:03:40 -07:00
Jordan Ritter dc76bb4220 fix(showcase): render absent-starter columns as 🚫 unsupported, not grey/red ✗
A STARTER-row column for an integration that has NO starter (the 7 columns
absent from STARTER_TO_COLUMN) was rendering a grey "✗" with a "no starter
for this integration" tooltip. That mis-communicates the truth: a grey/red
✗ reads as "we expected data and got none" or "a probe ran and failed",
when the reality is "this integration is architecturally unsupported in the
starter row".

buildStarterBadge's mapping-derived !isSupported branch now returns the same
🚫 "Not supported by this framework" treatment depth-chip/unified-cell
already use for unsupported cells. Columns that DO have a starter keep
surfacing their real probe status — a genuinely-red starter still renders
red ✗ and is never masked as 🚫.
2026-06-04 22:26:36 -07:00
Jordan Ritter be8a5c04ea fix(showcase/dashboard): render Starter row-group in the live FeatureGrid (was in dead CellMatrix)
PR #5226 added the "Starter" pseudo-category row-group (StarterSection,
using resolveStarterRow/buildStarterBadge) only to CellMatrix in
cell-matrix.tsx. But the live DashboardPage renders the matrix tab via
FeatureGrid (feature-grid.tsx); CellMatrix is reached only through
cells-view.tsx, which no live route imports — it is dead/legacy. So the
Starter row shipped in code but could never render (the served prod bundle
had zero StarterSection/starter-row-/"no starter" strings).

Port the StarterSection into FeatureGrid: render the four fixed sub-rows
(health/agent/chat/interaction) after the feature categories, resolving
each cell via the existing S3 helpers (resolveStarterRow + buildStarterBadge,
5-state vocab) and structurally excluded from the feature rollup/column tally
(never calls renderCell/buildCellModel). Aligned to FeatureGrid's table
structure (Feature col + optional parity ref-depth spacer + categoryColSpan).
Remove the duplicate from the dead CellMatrix and move its dedicated tests
to feature-grid.test.tsx, which exercises the live registry-backed grid.

Render proof: production next build now bakes starter-row-/starter-cell-/
"no starter for this integration" into the served page.js (client + server)
bundles. Full dashboard suite green (815 passed, 1 skipped).
2026-06-04 01:17:59 -07:00
Jordan Ritter 92c2f3d06c fix(showcase/dashboard): correct starter staleness window to hourly cadence
The starter_smoke probe runs hourly (`schedule: "40 * * * *"`), but
STARTER_STALE_AFTER_MS was set to 13h with a comment claiming a 6h cadence
— ~13 missed hourly ticks before amber, defeating the intended two-miss
flip. Re-derive the window from the 1h probe period to 2.5h: strictly
> 2 periods (so two consecutive misses, last row ~3h old, flip amber) yet
< 3h (so a single missed/slow-wake tick, last row ~2h old, stays green,
absorbing a scale-to-zero cold-start). Reconcile both the staleness.ts and
starter_smoke.yml comments to the same hourly basis + 2.5h window in
lockstep (no more "6h" in the starter context). Extend the staleness tests
with explicit hourly-tick boundaries (1 miss → green, 2 misses → amber).

Also drop the inaccurate "hollow" from the not-supported ✗ comments — there
is no hollow render variant; the state renders as grey ✗ text.
2026-06-04 00:24:11 -07:00
Jordan Ritter 71de409884 feat(showcase/dashboard): add Starter row-group with 5-state smoke-health vocabulary
Builds the dashboard UI for the starter-smoke dimension: resolveStarterRow
(flat starter:<col>/<level> lookup) + buildStarterBadge implementing the full
5-state cell vocabulary (green ✓, red ✗ smoke-failed, amber ~ stale, gray ?
not-yet-run, grey ✗ not-supported keyed off the S1 mapping), the StarterSection
row-group, rollup-exclusion so starter rows don't skew column aggregates, and a
13h staleness window (> 2× the probe cadence).

UI slot (S3) of the starter-row-group spec (model B).
2026-06-04 00:24:11 -07:00
github-actions[bot] 33d7eef4e4 style: auto-fix formatting 2026-06-03 00:58:59 +00:00
Jordan Ritter 9125ec5b81 fix(showcase): gate Coverage D6 badge + stats by depth ladder; gated indicator only on genuine lower-rung failure 2026-06-02 17:57:48 -07:00
Jordan Ritter 7d097feabc fix(showcase): resolve dashboard links to real shell host via server-threaded shellUrl 2026-06-02 17:57:47 -07:00
github-actions[bot] a8f1544286 style: auto-fix formatting 2026-06-02 20:51:16 +00:00
Jordan Ritter 7b0e663b22 fix(showcase): render reachable depth buckets (D0..D6) in stats bar, drop dead D1/D2
The depth-distribution row showed permanent-zero D2/D1 rows while the computed
D0 bucket (wired-but-unverified cells) was never rendered, so wired cells
vanished from the row and it never summed to the "Wired" count.
buildCellModel().achievedDepth is typed 0|3|4|5|6 and can never be 1 or 2.

- Remove unreachable d1/d2 from the DepthDistribution type, from
  computeDepthDistribution's init, and from the rendered levels array.
- Add a D0 row to the rendered levels so wired-unverified cells are visible
  and the distribution sums to the wired-cell count (D6,D5,D4,D3,D0).
- Reconcile section wrapper keys: use each section's stable key instead of the
  array index so overlay-toggle reconciliation is correct.
- Document that health/depth/d6 rollups need no dedup: catalogData.cells is
  one row per (integration, feature) grid cell (verified: 0 duplicate pairs),
  so these per-cell signals are counted exactly once.
2026-06-02 13:30:35 -07:00
Jordan Ritter 13d7fa5ee5 fix(showcase): correct aggregate-stats divergence from per-cell model
Extract the AdaptiveStatsBar aggregate computations out of page.tsx into a
unit-testable pure module (src/lib/page-stats.ts), mirroring the
computeColumnTally pattern, and fix a cluster of correctness bugs:

1. D6 cells were dropped from the depth distribution: DepthDistribution
   lacked a `d6` key and the `\`d${depth}\` as keyof` cast produced
   `dist["d6"]++ === NaN`. Add `d6` to the type, render a D6 row in
   DepthDistributionSection, and replace the cast with an exhaustive
   Record<0|3|4|5|6, keyof DepthDistribution> map the compiler checks.
2. d6Stats folded amber (stale/degraded D6) into gray. Count degraded
   distinctly and surface it in D6Section.
3. healthStats counted gray (no-data) cells as green, contradicting the
   "stats bar matches the matrix" invariant. Track no-data separately and
   render it in HealthSection.
4. isSupported is correctly hardcoded true for wired-cell stats: a wired
   catalog cell can never be in not_supported_features (generate-registry
   resolves those to status "unsupported" before "wired"), so stats and
   renderCell cannot diverge. Comment updated to state the invariant.
5. parity_tier was indexed via an unchecked cast (unknown tier →
   `undefined++ === NaN`). Validate against the known tier set and skip +
   log loud on unknown.

The matrix render path (renderCell/buildCellModel) is untouched.
2026-06-02 13:19:43 -07:00
Jordan Ritter 377b56cb19 test(showcase): harden D6 rollup tests — order-independent worst-state, comment precision
Add a D5 any-fail fan-out case where the red sub-key is NOT first (greens
then a trailing red) and assert the rollup still resolves red, proving the
worst-state fold is order-independent. Also tighten three imprecise/misleading
comments: clarify the absent-tools D4 worst-state skip, annotate the d6:lgp
aggregate as a distractor not consulted by per-cell resolveD6, and drop the
inapplicable amber-path clause from the aggregate-only gray case.
2026-06-02 13:06:01 -07:00
Jordan Ritter e6da6ba3ed refactor(showcase): re-export overlay/preset definitions from overlay-types
OverlayToggleBar redefined ALL_OVERLAYS, PRESETS, and OverlayPreset as local
literals duplicating src/lib/overlay-types.ts (drift hazard if an overlay or
preset is added to one but not the other). Replace the local definitions with
re-exports from overlay-types so there is a single source of truth. Behavior
identical; existing component-level imports keep working via the re-export.
2026-06-02 13:05:58 -07:00
Jordan Ritter e408489313 fix(showcase): correct cell renderer memo keys and d6 overlay blank matrix
ComposedCell.arePropsEqual watched the wrong liveStatus keys: it omitted
agent/chat/tools (which its only consumer, deriveDepth, reads for D2/D4) and
watched an unused smoke key. Watch exactly deriveDepth's reads and fix the
stale "keep in sync with resolveCell" comment.

UnifiedCell rendered a blank cell for a {d6}-only overlay set because d6 is
consumed only by AdaptiveStatsBar and produced no per-cell content. Treat d6
as content-bearing: surface the depth chip + health row (which renders the
per-cell D6 badge). Default overlay set (links/health/depth) is unchanged.
2026-06-02 13:05:56 -07:00
Jordan Ritter 7f5c3ac16e fix(showcase): correct live-status/depth-utils CR findings
- Rename module-private D5_STATE_RANK to WORST_STATE_RANK (used by both
  resolveD5Row and resolveD6Row) and move the misplaced resolveD5Row doc
  block onto resolveD5Row.
- Add a test asserting every CATALOG_TO_D5_KEY mapping value is free of the
  ':' / '/' key delimiters (keyFor's guard did not cover mapping values).
- mergeRowsToMap: fire the collision warning only on genuine state
  divergence (rowsAreNoop content compare) instead of reference inequality,
  eliminating noisy false warnings.
- isD6Green JSDoc: note the caller only invokes it after D5 is green
  (contiguous ladder), so D6 can never be credited over a broken D5.
- computeMaxPossible: treat stub like unshipped (maxPossible=0) so a
  not-yet-wired stub cell no longer false-positives isRegression.
2026-06-02 13:05:55 -07:00
Jordan Ritter c32a877a91 test(showcase): add dashboard cell color/rollup matrix 2026-06-02 12:37:55 -07:00
Jordan Ritter 377b7e8163 test(showcase): complete D6 per-cell test migration
Rewrite the two stale live-status keyFor tests that still asserted the old
integration-scoped D6 model (and the wrong e2e-full driver) to assert the
per-cell d6:<slug>/<featureId> shape; expand the two beautiful-chat D5 fan-out
tests to emit all 5 sub-keys so the worst-state fold (not the missing-row path)
is what's exercised; drop the dead unmapped-feature else branch in unified-cell
arePropsEqual (resolvers never read a direct key for unmapped features).
2026-06-02 11:35:51 -07:00
Jordan Ritter c64aebc422 fix(showcase): resolve D6 per-cell instead of integration aggregate
The Feature Matrix rendered every D6 cell in an integration's column from
the aggregate PocketBase row `d6:<slug>` (red whenever ANY cell fails),
so genuinely-green cells (e.g. langgraph-python/voice) rendered red. The
harness already emits per-cell `d6:<slug>/<featureType>` rows over the same
featureType keyspace as D5.

Resolve D6 per-cell through the same CATALOG_TO_D5_KEY bridge D5 uses,
mirroring resolveD5/resolveD5Row exactly: per-sub-row stale-green→degraded
fold before the worst-state fold, and strict handling of a missing mapped
sub-row (no-data unless a present sub-row is red). The aggregate `d6:<slug>`
row no longer drives per-cell rendering. Updated the two memo comparators
(composed-cell, unified-cell) to diff per-cell D6 sub-keys, and the stale
doc-comments that described D6 as an integration-level aggregate.
2026-06-02 09:47:34 -07:00
Jordan Ritter f7203f3368 fix(showcase): thread shared now through cell-matrix render path
Hoist a single now (memoized on liveStatus) and thread it into the
render-path buildCellModel so the chip, the regressions/gaps filter, and
the badges all judge staleness against one instant. Previously the render
path defaulted to a fresh Date.now() per cell, so a cell the filter
included could render a different staleness state across a window boundary.
2026-05-30 21:34:48 -07:00
Jordan Ritter 36f316b24d fix(showcase): resolveD5Row returns null for unmapped features
Drop the direct-key d5 fallback in resolveD5Row so the coverage badge
agrees with the chip (cell-model resolveD5) and depth (depth-utils
isD5Green), which both treat an unmapped feature as no-D5. Previously an
unmapped feature with a stray d5:<slug>/<featureId> row rendered a green
badge while the chip showed gray. Also guards the empty-map case.
2026-05-30 21:34:39 -07:00
Jordan Ritter 79a22fb18d test(showcase): cover computeColumnTallyDetail health-dimension branch
Add cases for green-D3+D4+red-D5 and green-D3+red-D4, both landing in the
red bucket with dimension 'health'. No production change.
2026-05-30 20:52:07 -07:00
Jordan Ritter c506d8badf fix(showcase): deriveDepth D4 uses worst-state-wins instead of OR
A present red chat/tools row now pulls D4 down even if its sibling is green,
matching cell-model resolveD4. Single-side present-green cases still achieve
D4 (absent sibling is skipped).
2026-05-30 20:50:45 -07:00
Jordan Ritter afd3bdba36 fix(showcase): require emitted data above achievedDepth for isRegression
A cell is a regression only when the next rung above achievedDepth has
emitted data (exists && status !== null). Drops the no-data-D5 false
positive (mapped but unemitted D5) while keeping red-below-ceiling and
D3-red regressions.
2026-05-30 20:49:11 -07:00
Jordan Ritter 8c61713d66 fix(showcase): downgrade stale-green rows in resolveCell + resolveD5Row
Fold each contributing row's stale-green to degraded before tone/rollup
derivation so a frozen-green driver no longer reads as healthy. Per-badge
windows: e2e/d5/d6 6h, health/d2/smoke 45m. Thread co-render now from
cell-matrix gaps filter and cells-view stats.
2026-05-30 20:46:32 -07:00
Jordan Ritter d0da6e357d refactor(showcase): extract shared staleness helper into lib/staleness.ts
Move the three staleness windows and the byte-identical isStale/isRowStale
duplicate out of cell-model.ts and depth-utils.ts into one lib/staleness.ts.
Type-only import of StatusRow avoids a runtime cycle so live-status can also
consume it. No behavior change.
2026-05-30 20:41:25 -07:00