Files
hanzo.ai/components/home/Research.tsx
zeekay bc62b4a3eb Sign in with the password on the first screen; the beta strip's edges are bevels; Zen's speed and Kai's flash each their own section; the trolley problem on both pages
The sign-in: /login and /signup draw the password beside the address (login: the account's, autocomplete current-password;
signup: one to choose, at least 8 characters), a code one press away. IAM is asked about the address on the press: on
/login a new one goes to /signup before anything is sent; on /signup a known one logs in with its password at once (the
'You already have an account / Log in / Use a different email' bounce is gone), one that signs in by code alone is sent
one and told so, and a new one proves itself with the code, agrees to the terms, and is made with the password it chose
(iam.signup); a login page's password never makes an account (createAccountWithCode). lib/auth/first: login → password,
signup → create, no-password apps → code. The login, sale and first gates follow it.

The beta strip (app/layout.tsx): each diagonal edge is a honed bevel, a lit facet rising to a bright edge, the ground
side in shadow and a second facet's thin line behind it, over a brushed grain along the blade; both layers painted once
and only moved, as before.

The home: #speed is Zen 6's alone, prefill beside decode on the three desks, each figure to its own scale; #flash
('Decisions in a flash.', components/home/Flash) is Kai's: the clock's three lanes, cached, runtime and served over
HTTP, drawn to scale with no hosted call beside them and no 'cached decision' or 'in process' talk, and the Decision
Suite's won tasks; the other side is named on /kai (Flash named) and 'the baseline' on the landing, which names no rival
decision model. Order: Products, Models, Speed, Race, Flash, Pareto, Benchmarks. The research card says one decision's
served p50. components/home/lane.tsx is the shared bar.

The trolley problem (lib/data/benchmarks-trolley.json → lib/trolley → INDEX.trolley): kai-1.8 through nio/harm@1 at
floor .9 on Zach Landes's benchmark beside Jev's and GPT-6 Luna's recorded answers, only the checks Kai leads Jev on
drawn (dominated choices, stranger-not-server pairs, the switch onto one person), and the sealed ground-8 families, five
of them (8,300 scenes) decided right every time with no wrong course: /benchmarks#trolley (Showcase Trolley, blocks
kai-trolley and kai-trolley-sealed) and a landing card. The benchmarks and reads gates hold the rows to the file.

Gates aligned with what ships: the rail's places (Library, Templates, Scheduled tasks…) and Dev's mark for Customize;
the sidebar's Search opens the palette; the build's own suggestions call (@hanzo/build lib/suggest.js) is counted apart
from the chat's; /kai's hero as its copy now reads; the lane's opening as @hanzo/build 0.2.69 draws it; the home's suite
figure in the Flash section. Still failing, not of this change: app 'every kind of address' (the account menu's 'Usage
remaining' under @hanzo/rooms 0.1.84), the Recents view menu staying open after a pick, and e2e/unit/refusal.spec.ts
against @hanzo/rooms 0.1.84's planRequired.
2026-10-20 17:50:48 -07:00

203 lines
9.3 KiB
TypeScript

'use client'
import Link from 'next/link'
import { FlaskConical } from 'lucide-react'
import { Text, View, XStack, YStack } from '@hanzo/ui'
import { More } from '@hanzo/ui/marketing'
import { Loading } from '@/components/api/state'
import { DESKS, MEASURED } from '@/components/zen/desks'
import { useCoding } from '@/hooks/useCoding'
import { useEnso } from '@/hooks/useEnso'
import { useClaim, useSuite } from '@/hooks/useSuite'
import { runs } from '@/lib/api/research'
import { useReading } from '@/lib/api/use'
import { LEVEL, range, times } from '@/lib/coding'
import { clock, gpqa, livecode, ms, race, tasks } from '@/lib/home'
import { DECISION } from '@/lib/kai'
import { day } from '@/lib/tally'
import { Board } from './Board'
import { Hold, Section, Win, useGrow, useSeen, useStill } from './chrome'
/**
* The latest results, both read from the research API when the page opens.
*
* THE DECISION SUITE: the tasks Kai wins as a grid, one cell a task, lit in
* turn, and their count as "tasks won by Kai", the suite's own claim ("16 of
* 16" while Kai wins every task, else the bare count) — drawn only once every
* task's figures are in. The same tasks, each with its runs, are on /benchmarks,
* linked below; no task Kai does not win is drawn, counted or named.
*
* LIVECODEBENCH: the board's rows as bars (lib/home `bars`), while the router
* tops every single model on it.
*
* Under them, one tile a result, each a figure and what it measured, opening
* the page that shows it in full: Enso on GPQA Diamond (lib/home `gpqa`), a
* Kai decision's clock (`clock`), Hanzo Dev's coding race (`race`, read when
* the page opens, never from the build's snapshot), and Zen 6's prefill on
* Hanzo's own machine (components/zen/desks). Each tile stands only while its
* read holds what its page would draw.
*
* The section is drawn while any read result holds; Zen's measured figure
* alone does not hold it up.
*/
/** One result: whose it is, the figure, what was measured, the sentence that says it, and the page that shows it in full. */
function Result({ who, figure, what, note, href, slot }: { who: string; figure: string; what: string; note: string; href: string; slot: string }) {
return (
<YStack
render={<Link href={href} />}
data-figure={slot}
gap={8}
p={20}
rounded={16}
borderWidth={1}
borderColor="var(--border)"
bg="$panel"
hoverStyle={{ borderColor: 'var(--border-strong)' }}
$platform-web={{ borderRadius: '16px', textDecoration: 'none' }}
>
<Text fontFamily="$mono" fontSize="$1" color="var(--muted-foreground)">
{who}
</Text>
<Text fontSize="2.5rem" lineHeight="2.5rem" fontWeight="500" color="var(--foreground)" $platform-web={{ letterSpacing: '-0.03em', fontVariantNumeric: 'tabular-nums' }}>
{figure}
</Text>
<Text fontSize="$3" lineHeight="$4" fontWeight="600" color="var(--foreground)">
{what}
</Text>
<Text fontSize="$2" lineHeight="$3" color="var(--muted-foreground)">
{note}
</Text>
</YStack>
)
}
function Cell({ label, i, play, still }: { label: string; i: number; play: boolean; still: boolean }) {
const ref = useGrow(play, still, { delay: i * 85, duration: 360, from: 'scale(0)', to: 'scale(1)' })
return (
<View
role="img"
aria-label={label}
borderWidth={1}
borderColor="var(--foreground)"
p={3}
rounded={9999}
overflow="hidden"
$platform-web={{ aspectRatio: '1', borderRadius: '9999px' }}
>
<View ref={ref} width="100%" height="100%" rounded={9999} bg="var(--foreground)" $platform-web={{ borderRadius: '9999px' }} />
</View>
)
}
export default function Research() {
const [ref, seen] = useSeen(0.2)
const still = useStill()
const said = useClaim()
const suite = useSuite()
const enso = useEnso()
// The tasks Kai wins, and no other: the same rows /benchmarks draws.
const list = suite.state === 'ready' ? tasks(suite.data, DECISION.fixed) : null
const days = list ? [...new Set(list.map((t) => t.set))].sort().map(day) : []
const claim = said?.claim ?? null
const lcb = enso.state === 'ready' ? livecode(enso.data) : null
const all = useReading(runs)
const coding = race(useCoding(null))
const g = enso.state === 'ready' ? gpqa(enso.data) : null
const time = suite.state === 'ready' && all.state === 'ready' ? clock(suite.data, all.data) : null
const zen = DESKS[0]
const hasSuite = Boolean(claim && list?.length)
const suiteDone = suite.state === 'unreachable' || (said !== null && !hasSuite)
const lcbDone = enso.state === 'unreachable' || (enso.state === 'ready' && !lcb)
const read = Boolean(g || time || coding)
if (suiteDone && lcbDone && !read) return null
return (
<Section id="research" label="Research.Log" title="The latest results, with every task." lede="Each result is read from research runs on public questions, the same for every model.">
<View ref={ref}>
<Hold height={360}>
<View display="grid" gridTemplateColumns="minmax(0, 1fr)" gap={16} $lg={{ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 20 }}>
{suiteDone ? null : (
<Win title="Research.DecisionSuite" icon={<FlaskConical size={14} color="var(--background)" strokeWidth={2.2} />} aside="Kai" slot="suite">
<YStack p={20} gap={16}>
{claim && list?.length ? (
<>
<XStack gap={20} items="center" flexWrap="wrap">
<View display="grid" gridTemplateColumns={`repeat(${Math.ceil(Math.sqrt(list.length))}, 28px)`} gap={4} role="list" aria-label="Decision Suite tasks">
{list.map((t, i) => (
<View key={t.label} role="listitem">
<Cell label={`${t.label}: Kai leads`} i={i} play={seen} still={still} />
</View>
))}
</View>
<YStack gap={4} minW={180} flex={1}>
<Text fontSize="3.5rem" lineHeight="3.5rem" $md={{ fontSize: '4rem', lineHeight: '4rem' }} fontWeight="500" color="var(--foreground)" data-figure="suite" $platform-web={{ letterSpacing: '-0.03em' }}>
{claim.figure}
</Text>
<Text fontSize="$4" lineHeight="$4" fontWeight="600" color="var(--foreground)">
Decision Suite tasks won by Kai
</Text>
</YStack>
</XStack>
<Text fontSize="$3" lineHeight="$4" color="var(--muted-foreground)" data-figure="suite-note">
Each set on {days.join(' or ')}, with its public data and the runs of both models.
</Text>
<More href="/benchmarks#decision-suite">Each task and its runs →</More>
</>
) : (
<Loading what="the Decision Suite's runs" />
)}
</YStack>
</Win>
)}
{lcbDone ? null : lcb ? (
<YStack gap={12} data-figure="livecode">
<Board b={lcb} title="Research.LiveCodeBench" play={seen} still={still} slot="livecode" limit={6} />
<Text fontSize="$3" lineHeight="$4" color="var(--muted-foreground)">
LiveCodeBench&apos;s recent problems: Enso {lcb.lead.figure}, {lcb.lead.note}
</Text>
</YStack>
) : (
<Loading what="Enso's research runs" />
)}
</View>
</Hold>
{read ? (
<View display="grid" gridTemplateColumns="minmax(0, 1fr)" gap={16} mt={16} $sm={{ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))' }} $lg={{ gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 20, mt: 20 }}>
{g ? <Result slot="gpqa" who={g.lead.who} figure={g.lead.figure} what="GPQA Diamond" note={g.lead.note} href="/enso" /> : null}
{time ? (
<Result
slot="decision"
who="Kai"
figure={`${ms(time.fresh ?? time.same ?? time.cached)} ms`}
what="One decision, served"
note={`Kai on GPU, each a p50: ${ms(time.cached)} ms cached${time.same != null ? `, ${ms(time.same)} ms through the runtime` : ''}${time.fresh != null ? `, ${ms(time.fresh)} ms served over HTTP` : ''}.`}
href="/kai"
/>
) : null}
{coding ? (
<Result
slot="race"
who="Hanzo Dev"
figure={times(coding.speed)}
what="Faster on the same coding tasks"
note={`Over the ${coding.speed.n} tasks both agents solved, ${LEVEL} interval ${range(coding.speed)}.`}
href="/dev"
/>
) : null}
{zen ? (
<Result
slot="prefill"
who="Zen 6"
figure={zen.prefill}
what="Prompt tokens a second"
note={`On ${zen.machine}, ${zen.build}. Measured by Hanzo, ${day(MEASURED)}.`}
href="/zen#desks"
/>
) : null}
</View>
) : null}
</View>
</Section>
)
}