Files
hanzo.ai/e2e/gates/glyphs.spec.ts
zeekayandHanzo Dev d58d99ae86 benchmarks: five products, wins only, monochrome, one icon set
/benchmarks now reads as one story in five products: Enso (intelligence
per dollar), Kai (decisions), Zen 6 (speed on Hanzo hardware), the agent
harness and the agent platform. Each section opens with one headline and
one number, then its chart. Methods and the searchable shelf follow.

It publishes wins and the product's own measurements, each a recorded run:
- Kai leads Jev on 11 suites, listed by name. The Jailbreak suite and the
  typed HarmBench constants are gone, and so is "Decision Index v2", whose
  12th row was not a HarmBench run.
- No jailbreak-board figure is published. The Jev run on its unseen rows
  (hanzo-inc/kai 1671eca) has Jev ahead.
- Enso shows the frontiers it holds: GPQA-Diamond and LiveCodeBench v6.
- Zen 6 shows its 2026-09-23 readings.
- The platform section reads the cloud bench (lib/data/bench.json) and the
  runtime passes.
- The ledger keeps wins and standalone measurements; the leaderboard lists
  the suites Kai leads on the metric drawn.

Monochrome: Hanzo is in the brightest ink and the field in the mid grey;
standing is a glyph and a word. Icons come from gui's lucide set, and
e2e/gates/glyphs.spec.ts fails on an icon at 0×0, an <svg> with no shapes,
an icon outside 12–24 px, or an arrow typed as a character. Both schemes
are covered at 375 and 1440 px, as is the contrast gate.

Co-authored-by: Hanzo Dev <[email protected]>
2026-10-09 10:50:29 -07:00

83 lines
4.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Every icon the benchmark pages draw is a real one, drawn.
//
// An icon that renders at 0×0, or as an <svg> with nothing in it, is a gap the
// reader sees as a broken page and no other gate notices. An arrow typed as a
// character is not an icon either: its shape is whatever the visitor's fonts
// make of it, so the board uses one set (gui's lucide) and types none. Checked on
// the index, a benchmark's own page and the open palette, in both schemes, on a
// phone and a laptop: every visible <svg> has a size and a shape, every icon
// (an <svg> that is not a chart) sits between 12 and 24 px, and no arrow glyph
// stands in for one.
import { test, expect, type Page } from '@playwright/test'
import { serveExport } from './export'
import { api } from './revision'
import snapshot from '../../lib/data/benchmarks-kai.json' with { type: 'json' }
let site: Awaited<ReturnType<typeof serveExport>>
test.beforeAll(async () => {
site = await serveExport()
})
test.afterAll(async () => {
await site.close()
})
/** Every visible <svg>: where it is, its box, how many shapes it holds, and whether it is a chart. */
const svgs = (page: Page) =>
page.evaluate(() =>
[...document.querySelectorAll('svg')]
.filter((el) => el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }))
.map((el) => {
const r = el.getBoundingClientRect()
const chart = el.getAttribute('role') === 'img' && Boolean(el.getAttribute('aria-label'))
const where = el.closest('header') ? 'header' : el.closest('footer') ? 'footer' : el.closest('[role="dialog"]') ? 'palette' : 'page'
const name = el.closest('[aria-label]')?.getAttribute('aria-label') ?? el.parentElement?.textContent?.trim().slice(0, 32) ?? ''
return { where, name, w: Math.round(r.width), h: Math.round(r.height), shapes: el.querySelectorAll('path, circle, rect, line, polyline, polygon, ellipse, use').length, chart }
}),
)
/** Arrow characters used as icons inside the page's own content. */
const ARROWS = /[←→↑↓↗↘⟶➜➔]/
const check = (all: Awaited<ReturnType<typeof svgs>>, at: string) => {
expect(all.length, `${at}: no icon drawn at all`).toBeGreaterThan(0)
for (const s of all) {
expect(s.w * s.h, `${at} ${s.where} "${s.name}": renders at ${s.w}×${s.h}`).toBeGreaterThan(0)
expect(s.shapes, `${at} ${s.where} "${s.name}": an <svg> with no shapes`).toBeGreaterThan(0)
if (!s.chart) {
expect(s.w, `${at} ${s.where} "${s.name}": icon width ${s.w}`).toBeGreaterThanOrEqual(12)
expect(s.w, `${at} ${s.where} "${s.name}": icon width ${s.w}`).toBeLessThanOrEqual(24)
}
}
}
for (const scheme of ['light', 'dark'] as const) {
for (const width of [375, 1440]) {
test(`/benchmarks draws every icon, in one set, under a ${scheme} scheme at ${width}px`, async ({ page }) => {
await page.emulateMedia({ colorScheme: scheme, reducedMotion: 'reduce' })
await page.setViewportSize({ width, height: 900 })
await page.route(api, (r) => r.fulfill({ json: { data: snapshot.data, total: snapshot.data.length } }))
const hydrated = page.waitForRequest((r) => api(new URL(r.url())))
await page.goto(`${site.url}/benchmarks`)
await hydrated
check(await svgs(page), `${scheme} ${width}px index`)
const text = await page.locator('main').last().innerText()
expect(text.match(ARROWS)?.[0] ?? null, `${scheme} ${width}px: an arrow typed as a character`).toBeNull()
await expect(async () => {
await page.keyboard.press('/')
await expect(page.getByRole('dialog', { name: 'Jump to a benchmark' })).toBeVisible({ timeout: 500 })
}).toPass()
check((await svgs(page)).filter((s) => s.where === 'palette'), `${scheme} ${width}px palette`)
})
test(`a benchmark's own page draws every icon under a ${scheme} scheme at ${width}px`, async ({ page }) => {
await page.emulateMedia({ colorScheme: scheme, reducedMotion: 'reduce' })
await page.setViewportSize({ width, height: 900 })
await page.goto(`${site.url}/benchmarks/kai-banking77`)
check(await svgs(page), `${scheme} ${width}px detail`)
expect((await page.locator('main').last().innerText()).match(ARROWS)?.[0] ?? null).toBeNull()
})
}
}