mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-28 07:32:52 +00:00
/enso leads with three lines built from the enso.* runs: the router at 92.9% on GPQA Diamond, level with the pool's best single model, at $2.20, 5x less than Opus 4.8 (86.4%, $10.97); LiveCodeBench 93.7% at $3.06, 12.9x less than Opus 4.8 (72.0%, $39.43); and the pool's ceiling, 98.0% (194/198) with four arms, said only as the ceiling the router is trained toward. Under them a note says what that router was: enso-bench's at the tag its run names, and the arms its notes count, not today's presets. Every percentage and multiple is computed from the runs. A board is each system's frontier run, else its v1 run (the same prompts; v2 and max put others), over the whole set, none degraded. The GPQA and LiveCodeBench boards draw on /enso, /models/enso and /benchmarks, the GPQA one with the ceiling under it on /benchmarks/gpqa. /benchmarks' Enso title, figure, hero tile and frontier (now accuracy against what the run cost), the /models family card and the home tile read the same runs, and each says the API is unreachable rather than show an older number. lib/data/leaderboard.json and lib/leaderboard.ts are deleted: their Enso tiers (98.0, 96.0, 92.9) were no run's, 98.0 being the pool's oracle. With them go the vendor-reported field, the accuracy-at-cost scatter, the reported-versus-measured browser, the shelf's Enso entries and the two pages they generated, and the logo files only the scatter read. A preset card keeps its name and rate and states no score. The gates serve invented runs and hold every surface, the ceiling's figure and the unreachable state to lib/enso.
94 lines
3.8 KiB
JavaScript
Executable File
94 lines
3.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* How many models Hanzo serves is ONE fact, so it is stated in ONE place.
|
|
*
|
|
* This site quoted it eighteen times in three different numbers — "100+", "130+"
|
|
* and "400+" — and none was reached by editing the others. The estate was worse:
|
|
* 85+, 200+ and a bare 340 on other surfaces. A reader comparing two pages saw us
|
|
* disagree about our own catalog, and no build ever noticed.
|
|
*
|
|
* The count is read when a page opens, from the price list's own summary
|
|
* (components/api/count, GET /v1/pricing/summary). This gate fails the build
|
|
* on a new hand-typed one, the way audit-price-literals.mjs does for a rate.
|
|
*
|
|
* Sibling of that script by design — same ratchet, same shrink-only ALLOWED, same
|
|
* self-exemption. It states the rule, so its own prose is the specification.
|
|
*/
|
|
import { execFileSync } from "node:child_process";
|
|
import { readFileSync } from "node:fs";
|
|
import { resolve, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { code, isCode } from "./source.mjs";
|
|
|
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mdx"]);
|
|
const SELF = "scripts/audit-model-counts.mjs";
|
|
|
|
// A bare two-to-four digit count immediately followed by "model(s)". Deliberately
|
|
// narrow: "100+ capabilities" and "260+ MCP tools" are different facts with
|
|
// different owners, and widening this to every number would make the gate noise.
|
|
// "Model Context Protocol" is a proper noun, not a count of models — "260+ MCP
|
|
// tools" is a different fact with a different owner, and matching it would make
|
|
// this gate cry wolf on the one thing it must be trusted about.
|
|
const COUNT = /\b\d{2,4}\s*\+?\s*(?:AI |frontier |premium )?models?\b(?!\s+Context\s+Protocol)/i;
|
|
|
|
// The ratchet. Path → why it still holds a literal. SHRINK ONLY.
|
|
const ALLOWED = {
|
|
"app/(marketing)/press/page.tsx":
|
|
"Dated press-release titles and blurbs (Feb 27 2026, '100+ Models, Zero Markup'). A press release is a record of what was said on a day, not a live claim — rewriting the number would falsify the artifact. These must NOT be converted.",
|
|
};
|
|
|
|
function tracked() {
|
|
return execFileSync("git", ["ls-files", "-z"], { cwd: ROOT, maxBuffer: 64 << 20 })
|
|
.toString()
|
|
.split("\0")
|
|
.filter((p) => p && EXT.has(p.slice(p.lastIndexOf("."))));
|
|
}
|
|
|
|
/** The lines as a reader of the site sees them: comments are not copy. */
|
|
const copy = (rel) => {
|
|
const text = readFileSync(resolve(ROOT, rel), "utf8");
|
|
return (isCode(rel) ? code(text) : text).split("\n");
|
|
};
|
|
|
|
const offenders = [];
|
|
for (const rel of tracked()) {
|
|
if (rel === SELF || ALLOWED[rel]) continue;
|
|
copy(rel).forEach((line, i) => {
|
|
if (COUNT.test(line)) offenders.push(`${rel}:${i + 1}: ${line.trim().slice(0, 100)}`);
|
|
});
|
|
}
|
|
|
|
if (offenders.length) {
|
|
console.error(
|
|
`\nThe model count is typed into ${offenders.length} place(s) that should be reading it.\n\n` +
|
|
offenders.map((o) => ` ${o}`).join("\n") +
|
|
`\n\nDraw <Models /> (components/api/count: the price list's count, read when\n` +
|
|
`the page opens). It is not typed.\n` +
|
|
`Do not add a line to ALLOWED — that list only shrinks.\n`
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
// An entry that no longer holds a literal is a rule protecting nothing.
|
|
const stale = Object.keys(ALLOWED).filter((p) => {
|
|
try {
|
|
return !copy(p).some((l) => COUNT.test(l));
|
|
} catch {
|
|
return true;
|
|
}
|
|
});
|
|
if (stale.length) {
|
|
console.error(
|
|
`\n${stale.length} ALLOWED entr(y/ies) no longer hold a model count:\n\n` +
|
|
stale.map((p) => ` ${p}`).join("\n") +
|
|
`\n\nDelete them from ALLOWED — the list is meant to shrink, and an entry that\n` +
|
|
`protects nothing hides the next real copy.\n`
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(
|
|
`model counts: ${Object.keys(ALLOWED).length} known holder(s) remaining, no new copies.`
|
|
);
|