Skip to content

Add GenUI Scorecard, stream robustness, and CI + contract-drift guard#6

Open
Vext-Labs wants to merge 4 commits into
thesysdev:mainfrom
Vext-Labs:agent/feat-genui-scorecard
Open

Add GenUI Scorecard, stream robustness, and CI + contract-drift guard#6
Vext-Labs wants to merge 4 commits into
thesysdev:mainfrom
Vext-Labs:agent/feat-genui-scorecard

Conversation

@Vext-Labs

Copy link
Copy Markdown

What

Three additive, test-backed quality improvements from a short engineering audit of the streaming + generation pipeline:

1. GenUI Scorecard (scorecard/) — a headless eval harness that scores openui-lang screens on contract validity (zod), render success through both the Cupertino and Material renderer sets, and unknown-component usage. Ships with a 12-screen corpus covering all 33 contract components, a npm run scorecard table reporter, and docs/scorecard.md. This is meant as a small, repo-local complement to the validation-playground discussion in thesysdev/openui#786 — a way to measure generation quality before changing prompts, contracts, or models.

2. Stream robustness (src/genos/stream.ts) — three fixes, all covered by the new __tests__/stream.test.ts (18 tests; this file previously had no direct coverage):

  • Residual-buffer flush: a trailing unterminated data: event at end-of-stream was silently discarded. Latent with Cerebras, a real risk for the advertised "any OpenAI-compatible endpoint".
  • Stall watchdog: if no bytes arrive for 20s mid-stream, the stream now aborts with a friendly error instead of spinning "materializing…" forever. Composes with the caller's AbortSignal; no dangling timers.
  • Error taxonomy: 429 → rate-limited, 5xx → provider-unavailable, network failure → connection message. Raw provider JSON bodies (up to 500 chars) are no longer surfaced to the UI; details are sanitized to ≤160 chars. The 401/403 key-rejection flow is unchanged.

3. CI + contract-drift guard — a GitHub Actions workflow (typecheck, jest, drift check) and scripts/check-contract-drift.mjs, which fails CI if ui/contract.tsx and the embedded system prompt drift apart (allowlist documents the intentional exceptions: Stack, CheckBoxGroup, RadioGroup).

Notes

  • All exports and signatures in stream.ts are unchanged; store.ts and the tool layer are unaffected.
  • No new dependencies.
  • Happy to split this into three PRs if you prefer smaller diffs.

Test plan

  • npm run typecheck
  • npm test — 54 passed (22 existing + 32 new) ✓
  • npm run check:drift ✓ (33 contract components, 3 documented exceptions)
  • npm run scorecard — 12/12 corpus screens pass both renderer sets ✓

Contributed by Vext Labs.

…dly error mapping

- Flush a trailing unterminated data: event after reader done (finish_reason
  could be lost when a proxy closes without a final newline)
- 20s byte-gap watchdog per read with caller-AbortSignal composition; timers
  cleared on every settle path, socket cancelled on stall
- Error taxonomy: keep 401/403 key rejection, add 429 rate-limit, 5xx
  provider-unavailable, network-failure messages; sanitize other HTTP error
  bodies to a 160-char JSON-free single line
- 18 new tests: chunk-boundary SSE, manual UTF-8 decoder, [DONE], truncated/
  dropped, tool-call index accumulation, MAX_TOOL_ROUNDS, NEEDS_LIVE_DATA,
  watchdog stall/reset, residual flush, every error branch
Exports and signatures unchanged (store.ts contract holds).
- scorecard/corpus: 12 exemplar openui-lang screens covering all 33 contract
  components (incl. TabItem/SelectItem/Series sub-components)
- scorecard/harness.ts: parses with the library JSON schema, validates each
  element's unwrapped props against its zod schema, lists unknown components,
  formats the score table
- __tests__/scorecard.test.tsx: renders every screen through both cupertino
  and material libraries, writes scorecard/SCORECARD.md, enforces coverage
- npm run scorecard + docs/scorecard.md (methodology, how to add entries)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant