diff --git a/CHANGELOG.md b/CHANGELOG.md index 1530422..6dbf3a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,30 @@ All notable changes to pxpipe are documented here. This project adheres to [Semantic Versioning](https://semver.org/) (pre-1.0: minor = features / behavioral changes, patch = fixes). +## Unreleased + +### Changed +- `gpt-5.6-sol` is now opt-in rather than silently enabled. Its exact profile + remains available when selected, and sibling 5.6 variants do not inherit it. +- Complete per-model render profiles now drive font atlas, cell spacing, + geometry, style, history pages, and profitability math. Sol uses a 6×11 + JetBrains Mono atlas; opt-in Grok uses the measured effective 9×12 arm plus + the factsheet. +- Dashboard exposes the GPT model row and `?` controls now show accessible + hover/focus tooltips. + +### Known limitations / evidence +- A direct `gpt-5.6-sol` raw-image pilot tested **both** the new JetBrains + 6×11/126-column profile and the old Spleen 5×8/152-column profile. Each scored + 0/4 exact identifiers with four unsupported invented values; 6×11 passed + gist/guard, while 5×8 failed gist and passed the guard. One earlier paid setup + attempt exhausted 512 output tokens as hidden reasoning and is recorded but + excluded from scoring. The production fact-sheet still carries extracted + identifiers verbatim. Sol is therefore removed from the built-in default + scope while its exact profile remains available for explicit opt-in. A + Sol-only effective 9×12/84-column candidate is locally rendered but has no + model result yet. See `eval/sol-profile/RESULTS.md`. + ## 0.8.0 — 2026-07-03 ### Security @@ -214,7 +238,8 @@ it were the live request). ## 0.5.0 — 2026-06-20 -Cache-stable history-collapse imaging for both providers, with GPT-5.6 promoted +Cache-stable history-collapse imaging for both providers, with the then-named +GPT-5.6 model promoted to the default imaged scope. Old conversation history collapses into rendered PNG sections so the model reads a compact image instead of re-billed text, while prompt caching and tool-call behavior are preserved. @@ -228,7 +253,13 @@ prompt caching and tool-call behavior are preserved. metrics, thumbnail-expired session UI, and reflow/newline handling. ### Changed -- **Default imaged scope is now `claude-fable-5` + `gpt-5.6`.** GPT-5.6 is +> Historical state for 0.5.0: the Sol promotion below was reversed in the +> current Unreleased changes after the 2026-07-09 raw-recall failures; the +> built-in default is now Fable-only. + +- **Default imaged scope is now `claude-fable-5` + `gpt-5.6-sol`.** The model + was originally recorded here as GPT-5.6; production traffic identifies the + exact variant as `gpt-5.6-sol`. GPT-5.6 Sol is promoted from opt-in (0.4.0) to on by default. `gpt-5.5` and `claude-opus-4-8` stay opt-in: they degrade reading dense imaged history (gist drift), so silently imaging them by default is wrong. Promotion is gated on an OCR/recall diff --git a/FINDINGS.md b/FINDINGS.md index e96f96f..41fd70e 100644 --- a/FINDINGS.md +++ b/FINDINGS.md @@ -1,10 +1,71 @@ # FINDINGS — pxpipe (text→PNG token compression) **Status:** ⚠️ **VERDICT REVERSED — see correction below.** Originally ruled "dead"; live measurement shows pxpipe is a working *lossy gist-compressor* saving ~68% on real (dense) Claude Code traffic, with a known verbatim-recall gap. -**Date:** 2026-05-28 (original) · 2026-05-29 (correction) · 2026-06-09 (Fable 5 update) · 2026-06-10 (gist-recall A/B, SWE-bench pilot) · 2026-06-12 (field observation, n=1) · 2026-06-23 (reframe: correct baseline = /compact) -**Models tested:** `claude-opus-4-5` (original run), `claude-opus-4-8` (re-test after a model bump), `claude-fable-5` (2026-06-09) -**Model scope (current):** Fable 5 only, enforced in library + proxy (Opus disabled 2026-06-09 — see update below). -**Harness:** `eval/needle-haystack/` (receipts preserved from `/tmp/needle_eval`) +**Date:** 2026-05-28 (original) · 2026-05-29 (correction) · 2026-06-09 (Fable 5 update) · 2026-06-10 (gist-recall A/B, SWE-bench pilot) · 2026-06-12 (field observation, n=1) · 2026-06-23 (reframe: correct baseline = /compact) · 2026-07-09 (GPT-5.6 Sol raw-recall pilot) +**Models tested:** `claude-opus-4-5` (original run), `claude-opus-4-8` (re-test after a model bump), `claude-fable-5` (2026-06-09), `gpt-5.6-sol` (2026-07-09 raw-image pilot) +**Model scope (current):** Fable 5 only, enforced in library + proxy. Sol, Opus, GPT 5.5, and Grok remain available only through explicit opt-in. +**Harnesses:** Claude/Opus/Fable: `eval/needle-haystack/` (older receipts preserved from `/tmp/needle_eval`); Sol: `eval/sol-profile/` (raw responses and receipts committed) + +--- + +## Update (2026-07-09) — GPT-5.6 Sol fails raw exact recall at both tested profiles; moved to opt-in + +The exact production model id is `gpt-5.6-sol`. Production telemetry showed +that real Sol requests reached the Responses path and retained positive +estimated savings, but token rows are not reader-quality evidence. A separate +paid pilot therefore sent deterministic rendered terminal fixtures directly to +the Responses endpoint with `detail: original`, bypassing pxpipe. + +### What was actually tested + +Each scored call asked, in one structured response, for four exact values +(12-character hex, camelCase field, full path, and port), one rollout gist, and +one deliberately unstated fact. The two profiles were real paid Sol calls: + +| profile | dimensions | exact | unsupported inventions | gist | unstated guard | result | +|---|---:|---:|---:|:---:|:---:|---| +| JetBrains Mono 10, 6×11, 126 cols | 764×1724 | **0/4** | **4** | pass | pass | **fail** | +| old shared Spleen, 5×8, 152 cols | 768×1040 | **0/4** | **4** | fail | pass | **fail** | + +The 5×8 line is a model result, not a local-render inference and not a reuse of +Grok's 5×8 result. In both Sol calls every returned hex/id/path/port was absent +from the fixture, so the errors are classified as confabulations rather than +single-glyph OCR substitutions. + +There was one additional paid setup attempt at 6×11. It returned no answer +because all 512 output tokens were hidden reasoning tokens and ended +`incomplete: max_output_tokens`. It counts toward spend but is excluded from +recall scoring. The corrected scored calls used `reasoning: none`. + +### Honest boundary + +- This is one scored synthetic fixture per profile because the early-stop rule + halted after clear failure. It proves those calls failed the bar; it does not + estimate a population error rate. +- It is **not** a direct Sol-vs-Fable comparison. Fable's evidence comes from + separate, larger harnesses described below. +- Production attaches a deterministic verbatim fact-sheet for extracted paths + and identifiers. That text fallback can rescue covered exact strings, but it + does not make the raw-image result a pass. +- A Sol-only JetBrains effective 9×12 / 84-column candidate is rendered locally + (two pages, 2,136 estimated image tokens, positive estimated savings) but has + **not** received a model call. It is geometry, not evidence. + +### Decision + +`gpt-5.6-sol` is **off by default**, under the same rule used for GPT 5.5 and +Grok: silent image rewriting requires positive recall evidence, not merely +positive savings. Its exact profile and suffix aliases remain available for +explicit operator opt-in: + + PXPIPE_MODELS=claude-fable-5,gpt-5.6-sol + +Re-enabling Sol by default requires a retuned paid arm to clear 4/4 exact, zero +confabulations, gist, and guard with positive savings; a replicated pass on both +fixtures is preferred before silent promotion. + +Receipts and every raw response: +[`eval/sol-profile/RESULTS.md`](eval/sol-profile/RESULTS.md). --- diff --git a/README.md b/README.md index 7eccfe2..ce9c3ff 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ measured per-request against a free `count_tokens` counterfactual in This is what the model sees instead of text: -![example: a real `transformRequest` output: system prompt + tool docs reflowed into one dense 1573×1248 page, instruction banner on top, ↵ marking original newlines](https://raw.githubusercontent.com/teamchong/pxpipe/main/docs/assets/example-render.png) +![example: a real `transformRequest` output: system prompt + tool docs reflowed into one dense page, instruction banner on top, ↵ marking original newlines](https://raw.githubusercontent.com/teamchong/pxpipe/main/docs/assets/example-render.png) *~48k chars of system prompt + tool docs: ≈25k tokens as text, ≈2.7k image tokens as this page. Real pipeline output; the model reads renders like this @@ -83,16 +83,28 @@ are imaged. re-sends the full transcript as plain text each turn is in the same high- savings class as Claude Code. Details and measured splits: [docs/CACHING_AND_SAVINGS.md](docs/CACHING_AND_SAVINGS.md#openai-responses-path-codex-and-friends). -- **Model scope:** default `PXPIPE_MODELS=claude-fable-5,gpt-5.6`. Opus - 4.7/4.8, GPT 5.5, and **Grok** are opt-in only (dashboard chips or - `PXPIPE_MODELS`) — not good enough as silent defaults for imaged context. +- **Model scope:** default `PXPIPE_MODELS=claude-fable-5`. Sol, Opus 4.7/4.8, + GPT 5.5, and **Grok** are opt-in only (dashboard chips or `PXPIPE_MODELS`) — + not good enough as silent defaults for imaged context. The exact Sol id still + matters when opted in: sibling variants such as `gpt-5.6-terra` do not inherit + Sol's allowlist or render profile. `PXPIPE_MODELS=off` disables imaging. Everything else passes through byte-identical. On the GPT path, tool definitions stay native JSON and no Anthropic `cache_control` markers are used. -- **Grok (opt-in): production 5×8 + factsheet.** Off by default. Pure-image - exact OCR at 5×8 fails (0/4 IDs). Image+factsheet clears exact IDs at ~70% - fixture savings; looser pure-image packing only ~30%. If you opt in, keep - density and rely on the fact-sheet — do not inflate cell bonuses. +- **Per-model rendering:** opt-in `gpt-5.6-sol` currently uses a 126-column, + 6×11 JetBrains Mono profile; Claude keeps its 312-column 5×8 Spleen profile. These + are selected by exact model id, including history pages and profitability + math. **Sol recall caveat:** raw-image calls scored 0/4 exact with four + inventions at both current 6×11 and old shared 5×8; 6×11 passed gist/guard, + while 5×8 also missed gist. Production's verbatim fact-sheet remains a text + fallback for extracted identifiers. An effective 9×12 Sol retune is rendered + but not yet model-tested, so the current Sol geometry is operational—not + recall-validated. [Sol receipts](eval/sol-profile/RESULTS.md) and + [profile evidence](docs/MODEL_RENDER_PROFILES.md). +- **Grok (opt-in): measured 9×12 + factsheet.** Off by default. Pure-image + exact OCR at 5×8 fails (0/4 IDs); the densest tested pure-image arm that + cleared 4/4 with zero confabulation was effective 9×12 / 84 columns at ~30% + fixture savings. The fact-sheet remains attached as defense in depth. [eval/grok-density/FACTSHEET_RESULTS.md](eval/grok-density/FACTSHEET_RESULTS.md). ## Benchmarks (reproducible) @@ -121,15 +133,15 @@ evals.) ## How it works ``` -tool_result string ──► wrap at 1928px-wide columns ──► pack ~92,000 chars/page ──► PNG[] +model id ──► render profile ──► wrap/reflow bulk context ──► PNG[] + exact-token factsheet ``` The proxy intercepts `/v1/messages`, rewrites eligible bulk into image blocks, splices them back cache-friendly (static prefix preserved, prompt -caching keeps working), and forwards. A 1928×1928 image costs ≈4,761 vision -tokens and holds ≈92,000 chars, so text wins only above ~19 chars/token — -Claude Code traffic runs ~1.91 (N=391). A per-request estimator decides; -sparse prose stays text. Events log to `~/.pxpipe/events.jsonl`. +caching keeps working), and forwards. Claude uses 1568×728 pages; GPT 5.6 Sol +uses 764px-wide portrait strips; opt-in Grok uses effective 9×12 cells. A +per-request estimator uses that same resolved profile, so sparse prose stays +text. Events log to `~/.pxpipe/events.jsonl`. ## Library use (no proxy) @@ -191,10 +203,11 @@ Three kinds of *input* blocks, each behind a profitability gate: Everything else passes through byte-identical: your messages, recent turns, the model's output (it is the response, the proxy never touches it), sparse prose, and anything too small to win. Models outside the allowlist pass -through entirely — the default scope is Fable 5 and GPT 5.6 only. Opus 4.8 -and GPT 5.5 read imaged content measurably worse (FINDINGS.md 2026-06-16), -so they are deliberately opt-in via the dashboard or `PXPIPE_MODELS`, never -silently imaged. +through entirely — the built-in default scope is Fable 5 only. Sol, Opus 4.8, +GPT 5.5, and Grok are deliberately opt-in via the dashboard or +`PXPIPE_MODELS`, never silently imaged. Sol joined that list after both its +6×11 profile and the old shared 5×8 profile scored 0/4 exact with four +confabulations in direct raw-image calls. **Has it ever failed for real, outside the benchmarks?** Yes, once in weeks of daily use: the model recalled a person's name from diff --git a/assets/JETBRAINS_MONO_LICENSE.txt b/assets/JETBRAINS_MONO_LICENSE.txt new file mode 100644 index 0000000..4db0416 --- /dev/null +++ b/assets/JETBRAINS_MONO_LICENSE.txt @@ -0,0 +1,89 @@ +Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The fonts, +including any derivative works, can be bundled, embedded, redistributed +and/or sold with any software provided that any reserved names are not used +by derivative works. The fonts and derivatives, however, cannot be released +under any other license. The requirement for fonts to remain under this +license does not apply to any document created using the fonts or their +derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may include +source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or +other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy +of the Font Software, to use, study, copy, merge, embed, modify, redistribute, +and sell modified and unmodified copies of the Font Software, subject to the +following conditions: + +1) Neither the Font Software nor any of its individual components, in +Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be included +either as stand-alone text files, human-readable headers or in the +appropriate machine-readable metadata fields within text or binary files as +long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) +unless explicit written permission is granted by the corresponding Copyright +Holder. This restriction only applies to the primary font name as presented +to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any Modified +Version, except to acknowledge the contribution(s) of the Copyright Holder(s) +and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be +distributed entirely under this license, and must not be distributed under +any other license. The requirement for fonts to remain under this license +does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not +met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, +INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE +THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/CACHING_AND_SAVINGS.md b/docs/CACHING_AND_SAVINGS.md index 5bd5b5c..324ae28 100644 --- a/docs/CACHING_AND_SAVINGS.md +++ b/docs/CACHING_AND_SAVINGS.md @@ -257,8 +257,20 @@ Measured on local `/v1/responses` rows (same endpoint, different models): | grok | high on warm multi-turn | **collapsed** after ↵ gate fix | ~**35%** on collapsed Responses rows (n=35 post-fix); fixture image+factsheet ~70% | | gpt-5 | ~73% | often | ~34% overall; ~42% on collapsed warm rows | -Grok render contract: production **5×8** images + factsheet (not looser cells). -See [eval/grok-density/FACTSHEET_RESULTS.md](../eval/grok-density/FACTSHEET_RESULTS.md). +Render profiles are selected by exact model id, not by the shared Responses +path. Opt-in `gpt-5.6-sol` uses 126 columns with a 6×11 JetBrains Mono atlas; +Claude uses 312 columns with the 5×8 Spleen atlas. Grok remains opt-in and uses the +densest tested exact-safe image arm, effective **9×12** / 84 columns, plus the +factsheet. See [eval/grok-density/RESULTS.md](../eval/grok-density/RESULTS.md) +and [FACTSHEET_RESULTS.md](../eval/grok-density/FACTSHEET_RESULTS.md). + +Those profile and savings numbers are not recall evidence. The Sol raw-image +pilot separately tested both 6×11/126 and old 5×8/152: each scored 0/4 exact +with four confabulations, and 5×8 also missed gist. Sol is therefore off by +default; production's fact-sheet remains an important exact-token fallback for +operators who explicitly opt in. The locally rendered Sol 9×12 retune remains +untested. See +[`eval/sol-profile/RESULTS.md`](../eval/sol-profile/RESULTS.md). So "Codex shows 1% on Opus" is not "Codex unsupported." It is "this session's prompt was already ~98% cached text, history collapse did not fire, and only @@ -284,4 +296,3 @@ allowlisted, etc.) correctly show `—`. Path selects the accounting shape only the slab (or nothing) was imaged. 4. Do not compare a Claude Code session's 70% to a warm Codex session's 1% as a regression. Different wire, different uncached bulk. - diff --git a/docs/MODEL_RENDER_PROFILES.md b/docs/MODEL_RENDER_PROFILES.md new file mode 100644 index 0000000..0405fbe --- /dev/null +++ b/docs/MODEL_RENDER_PROFILES.md @@ -0,0 +1,99 @@ +# Model render profiles + +The OpenAI-shaped endpoints are a wire protocol, not a rendering profile. +Claude, GPT, and Grok requests can all arrive on `/v1/responses`; pxpipe selects +geometry, glyph atlas, style, and vision billing from the exact `model` id. + +## Built-in profiles + +| model rule | default enabled | font / cell | columns | max height | style | evidence | +|---|:---:|---|---:|---:|---|---| +| `claude-*` / `*anthropic*` | Fable only | Spleen + Unifont, 5×8 | 312 | 728 px | grayscale AA | Anthropic 1568-edge / ~1.15 MP no-resize measurements | +| `gpt-5.6-sol` | **no; opt-in** | JetBrains Mono 10 + Unifont fallback, 6×11 | 126 | 1932 px | grayscale AA | operational geometry; raw recall pilot failed 0/4 exact and is being retuned | +| `grok-*` | **no** | Spleen + Unifont, effective 9×12 | 84 | 1932 px | grayscale AA + factsheet | `grok-4.5` density climb: 4/4 exact, 0 confab, gist/guard pass, ~30% fixture savings | +| other GPT/o-series | no unless configured | Spleen + Unifont, 5×8 | 152 | 1932 px | grayscale AA | conservative fallback / existing OpenAI geometry | + +`gpt-5.6-sol` is intentionally exact and opt-in. The events log also contains +`gpt-5.6-terra`; Terra does not inherit Sol's allowlist or visual profile. + +The GPT 5.6 Sol font choice is a separate local raster profile. It preserves +the provider-safe strip width and has a larger cell than the shared 5×8 +fallback, but the first paid raw-image pilot did **not** validate it. + +## Sol evidence boundary (2026-07-09) + +Two production rows for the exact `gpt-5.6-sol` id reported 39,985 effective +input/cache-read tokens, 14,152 image tokens, a 52,072-token baseline, 18 +images, and approximately 73% estimated savings. A comparison run with the old +shared profile reported 8,568 image tokens against the same baseline. These +numbers establish that real Sol traffic reaches the Responses path and that the +new geometry costs more while retaining positive estimated savings. They do +**not** establish recall, task quality, or causality. + +The separate paid raw-image pilot supplies the model-reading evidence: + +| profile | exact | confabulations | gist | guard | result | +|---|---:|---:|:---:|:---:|---| +| JetBrains 6×11 / 126 cols | 0/4 | 4 | pass | pass | fail | +| Spleen 5×8 / 152 cols | 0/4 | 4 | fail | pass | fail | + +The test is one scored synthetic fixture per profile. It proves that both calls +failed the stated acceptance bar, not a broad Sol-vs-Fable ranking. Production +also sends a verbatim fact-sheet beside images, so covered exact identifiers +have a text fallback even though raw image recall failed. A locally rendered +9×12 / 84-column Sol-only retune remains untested until its final paid call is +approved. + +Receipt: [`eval/sol-profile/RESULTS.md`](../eval/sol-profile/RESULTS.md). + +### Sol default-scope decision + +Sol is **off by default** under the same safety rule used for GPT 5.5 and Grok: +a model that silently invents exact values from imaged context is not a safe +transparent default. The profile code stays available so operators can opt in +explicitly and so the 9×12 candidate can be evaluated without changing any +other model: + +```bash +PXPIPE_MODELS='claude-fable-5,gpt-5.6-sol' +``` + +Re-enabling Sol by default requires a paid profile arm to clear 4/4 exact, zero +confabulations, gist, and guard while retaining positive savings. Ideally the +pass should replicate on both deterministic fixtures; the current n=1 failures +are enough to reject these profiles, not enough to estimate a general error +rate. + +## Why Grok is opt-in + +Grok 4.5 at shared 5×8 density returned 0/4 exact identifiers and silently +invented all four answers. Effective 9×12 returned 4/4 with zero confabulation, +and a separate 5×8 + factsheet arm also returned 4/4 for the extractor shapes in +that fixture. Both are n=1 synthetic results. They justify a safer opt-in +profile, not silent default rewriting of every Grok request. + +Receipts: + +- [`eval/grok-density/RESULTS.md`](../eval/grok-density/RESULTS.md) +- [`eval/grok-density/CLIMB_RESULTS.md`](../eval/grok-density/CLIMB_RESULTS.md) +- [`eval/grok-density/FACTSHEET_RESULTS.md`](../eval/grok-density/FACTSHEET_RESULTS.md) + +## Overrides + +`PXPIPE_GPT_PROFILES` is a JSON map from model-id prefix to a partial profile. +The longest prefix wins. Supported render fields are `font`, `cellWBonus`, +`cellHBonus`, `aa`, `grid`, `gridCols`, `colorCycle`, `markerScale`, and +`markerRed`; geometry fields are `stripCols` and `maxHeightPx`. + +```bash +PXPIPE_GPT_PROFILES='{ + "gpt-5.6-sol": { + "stripCols": 120, + "style": { "grid": true, "gridCols": 4 } + } +}' +``` + +The profitability gate derives pixel width, row capacity, pagination, and image +cost from the same resolved profile used by slab and history rendering. A style +override therefore cannot silently leave the gate on 5×8 geometry. diff --git a/docs/RENDER_SIZING.md b/docs/RENDER_SIZING.md index 4db1e3a..c509749 100644 --- a/docs/RENDER_SIZING.md +++ b/docs/RENDER_SIZING.md @@ -1,157 +1,98 @@ -# How pxpipe sizes a rendered image — rules, reasons, and history +# How pxpipe sizes rendered images -This documents *why* a pxpipe PNG has the dimensions it does. It exists because -the sizing looks arbitrary until you know what was tried and rejected. If you're -tempted to "make it square" or "shrink to the text," read the history first — -both were considered, and one was built and reverted. +Image geometry is selected by the exact model id. `/v1/responses` is only a +wire protocol: Claude, GPT, and Grok on that path do not share a renderer. -## TL;DR — current behavior +## Current behavior -A rendered page is a **fixed-width, variable-height** image. It is **not -deliberately squared** and **never shrunk horizontally to fit short lines**. +A page is profile-width and variable-height. It is never padded to a square. -- **Width is constant per path**, set by the column count, not by content: - `width = 2·PAD_X + cols·CELL_W`. The static slab renders at `DEFAULT_COLS=313` - → `8 + 313·5 = 1573px`; dense tool/history pages render at - `DENSE_CONTENT_COLS=384` → `8 + 384·5 = 1928px`. -- **Height grows to fit the lines on the page**, capped, then pages: - `height = 2·PAD_Y + nLines·CELL_H` → `8 + 8·nLines`. -- **Vertical cap → paging**: `maxLines = floor((MAX_HEIGHT_PX − 2·PAD_Y) / CELL_H)` - `= floor(1924/8) = 240` lines. Overflow goes to the next image, it does not - grow the canvas. A *full dense* page is `1928 × 1928` (≈square only because - 384 cols ≈ 240 rows at the 5×8 cell — not deliberately squared); a *full slab* - page is `1573 × 1280` (~159 rows, READABLE-bound below the 240 cap); a - *partial* page (small tool_result, last page) is wide-and-short, e.g. `1928 × 160`. +```text +cellWidth = atlasWidth + cellWBonus +cellHeight = atlasHeight + cellHBonus +width = 2 * PAD_X + columns * cellWidth +height = 2 * PAD_Y + usedRows * cellHeight +``` -This `~1932×1932` ceiling is the largest page Fable / Opus 4.8 accept without a -server-side resize. Those models take up to **2576 px** on the long edge, but a -request with **>20 images** (pxpipe always sends many) is held to the stricter -**≤2000 px/side** rule, and `1928×1928` = `69×69` = **4761 visual tokens**, just -under the **4784**-token per-image cap. Going bigger gets the request *rejected*, -not downscaled. +Width may shrink to the widest rendered line, capped by the profile. Height +grows with content until the profile cap, then overflow becomes another page. -Source of truth: `renderChunkToPng` in `src/core/render.ts` (the `width` / -`height` lines), constants `PAD_X=PAD_Y=4`, `CELL_W=5`, `CELL_H=8` (the "5×8 -cell"), `DEFAULT_COLS=313`, `DENSE_CONTENT_COLS=384`, `MAX_HEIGHT_PX=1932`, -`READABLE_CHARS_PER_IMAGE=50000`, `DENSE_CONTENT_CHARS_PER_IMAGE=92160`. +| model rule | atlas / effective cell | columns | full width | max height | +|---|---|---:|---:|---:| +| Claude / Anthropic | Spleen + Unifont, 5×8 | 312 | 1568 px | 728 px | +| opt-in `gpt-5.6-sol` | JetBrains Mono 10 + Unifont fallback, 6×11 | 126 | 764 px | 1932 px | +| opt-in Grok | Spleen + Unifont, effective 9×12 | 84 | 764 px | 1932 px | +| other OpenAI fallback | Spleen + Unifont, 5×8 | 152 | 768 px | 1932 px | -## The cell +Complete profile values and evidence are in +[`MODEL_RENDER_PROFILES.md`](MODEL_RENDER_PROFILES.md). -Each character occupies a **5px wide × 8px tall** cell (`ATLAS_CELL_W=5`, -`ATLAS_CELL_H=8` in `src/core/atlas.ts`). The atlas is a prebaked glyph sheet; -text is rendered white-on-black then inverted to black-on-white. The cell was -**7×10 originally** and shrunk to 5×8 — smaller cell, same legibility on the -target model, more chars per pixel. +The Sol row is the **currently configured** geometry, not a successful recall +claim. Paid raw-image calls tested both that 6×11 row and the old 5×8/152-column +fallback: each returned 0/4 exact identifiers with four confabulations; 5×8 also +missed gist. Sol is consequently opt-in. The effective 9×12/84-column Sol +candidate is local-only pending a model call. See +[`eval/sol-profile/RESULTS.md`](../eval/sol-profile/RESULTS.md). -## Why full width, not shrink-to-content +## Provider boundaries -`shrinkColsToContent` (`src/core/render.ts`) still exists but is a **no-op** — it -returns `cols` unchanged. Its docstring records the policy: +Anthropic resizes images to fit both a 1568px long edge and roughly 1.15MP. +The 1568×728 Claude page stays inside both bounds, so rasterized glyphs reach +the vision encoder without the old 0.555× resample. -> *Always render at full canvas width — no shrink-to-content. Maximum chars per -> page = maximum image-token savings on dense content, and the unused canvas -> tail is just whitespace (cheap to encode).* +OpenAI-shaped profiles use portrait strips at or below the 768px short-side +floor and a 1932px height cap. GPT 5.6 Sol's 126×6+8 and Grok's 84×9+8 both +produce 764px full-width strips. -The reasoning: +## Font and Unicode -1. **The only content pxpipe images is dense content** (it passes a - profitability gate; sparse/short-line content is left as text). After - `reflow` packs that content into full-width rows, the longest line is already - ~`cols`, so there is *nothing left to shrink*. Width-shrink only helps - short-line content — which never reaches the renderer. -2. **Simplicity + prediction parity.** The cost gate has to predict image tokens - before rendering. A fixed width makes prediction trivial and exact; a - content-dependent width forced the gate to re-derive the canvas size (see the - "hoist width-shrink before gate" commit below) for no real-world gain. +Atlases are generated at build time; runtime never loads font files. The compact +JetBrains atlas contains common code/Latin/symbol ranges. Missing codepoints +fall back to the full Spleen/Unifont atlas, preserving multilingual rendering. -## Why not "square with max width" +Spacing, anti-aliasing, grid, color cycle, and newline-marker style are all part +of the model profile. The same style object is used for static slabs and history. -Anthropic bills images by **pixel area** (≈ `w·h/750`), not by the longest edge. -So a square is not cheaper than a wide-short image of the same area — what -minimizes cost is the *tightest bounding box around the text*, and for dense -reflowed content that box is exactly "full width × just enough rows," which is -what we render. We never *pad* to a square: a full dense page lands at -`1928×1928` only because 384 cols and 240 rows are equal pixel extents at the -5×8 cell — it's the max-chars-per-page point (the ~1932² token ceiling), not an -aspect-ratio target, and a partial page stays wide-and-short. Aspect ratio is a -non-goal; **chars-per-pixel** is the goal, achieved by filling every row to -`cols` and paging vertically. +## Gate parity -## Two render paths +The profitability gate resolves the same profile as the renderer and derives: -- **tool_result / history images**: single-column at `DENSE_CONTENT_COLS=384` - (1928px wide), paged at the 240-line cap → full pages are `1928×1928` - (~92k chars each). -- **system-slab image**: single-column at `DEFAULT_COLS=313` (1573px wide), - READABLE-bound to ~159 rows (~50k chars → `1573×1280`). Kept on a path that - *can* use multi-column packing (`shrinkWidth=false`), but multi-col is - **disabled by default** (`multiCol: 1`) because at 313 cols a single column - already holds ~50k chars/page and multi-col adds OCR column-ordering risk - without meaningful savings. +- cell width and height +- content-width shrink +- rows per page +- page count +- per-image token cost -So in practice everything is single-column full-width today; the multi-col code -is retained for backward compat. +Changing cell spacing or font therefore cannot leave cost prediction on a +hardcoded 5×8 canvas. Claude uses the Anthropic pixel formula with a conservative +margin, GPT uses model-specific tile/patch pricing, and Grok uses the measured +tokens-per-megapixel rate. -## Billing model (and an unresolved gap) +## Why not square pages -- **Anthropic's documented formula**: `tokens ≈ (w·h) / 750`. -- **The gate's constant**: `src/core/transform.ts` anchors per-image cost on an - *empirical* figure (~2500 tok for a 508×1559 canvas, i.e. claiming the doc - formula underpredicts billing by ~2.4×). That measurement is from an earlier - cell/column regime. -- **A fresh regression** on production `~/.pxpipe/events.jsonl` (2-var OLS, - `tokens ≈ a·text_chars + b·image_pixels`, N≈1.5k cold-miss events) gives - **~907 pixels/token** and **~1.8 chars/token** for text — i.e. *much* closer - to the doc's 750 than to the gate's stale ~312 px/tok. +Billing follows pixel area or patches/tiles, not visual symmetry. Padding a +portrait or short final page to a square adds cost without adding information. +The target is readable characters per billed pixel under each provider's resize +contract, not a preferred aspect ratio. -These disagree by ~3×. The gate is therefore likely **pessimistic** about image -cost on current traffic (it may pass up profitable compressions). Re-grounding -`TOKENS_PER_IMAGE` from a fresh regression is an open task — the data is in the -event log (`image_pixels` next to `input_tokens + cache_create_tokens` on -cold-miss rows). Don't trust any single hardcoded image-cost constant without -re-checking it against the log. +## Measurement history -## How sizing decisions are/were measured +| date | change | finding | +|---|---|---| +| 2026-05-21 | R3 reflow | recovered line-end dead space by marking hard newlines with `↵` | +| 2026-05-22 | grayscale atlas + L1/L2 harness | measured style and instruction-band effects | +| 2026-06-09 | Fable-only 5×8 scope | Fable read dense cells better than Opus | +| 2026-06-17 | ~1932px experiment | fewer pages, later shown to be server-resampled on Anthropic | +| 2026-07-01 | Claude 1568×728 clamp | made billed pixels survive Anthropic preprocessing | +| 2026-07-09 | exact-model profiles | separated Claude, GPT 5.6 Sol, and opt-in Grok geometry/style | -- **L1 OCR eval** (`eval/eval-l1-ocr.mjs`): per-character read accuracy across - render styles (cell size, reflow on/off, instruction placement, grayscale). - This is what gated reflow and the in-image instruction banner. -- **L2 session eval** (`eval/eval-l2-session.mjs`): comprehension over whole - imaged sessions. -- **events.jsonl regression**: the real per-pixel/per-char billing fit above. -- **glyph-matrix** (`eval/glyph-matrix/`, PAUSED): a per-character confusion - matrix across render styles, to find a zero-cost style that lowers read error - so the gate can compress harder at the same fidelity. Paused because the - reader model (Fable 5) is offline. +Older benchmark receipts retain their historical geometry; do not rewrite those +numbers as if they were generated by the current profile. -## History (oldest → newest) +## Changing a profile -The sizing converged through measured iteration, not a single design. Key commits: - -| date | commit | change | why | -|---|---|---|---| -| 2026-05-21 | `38e852a` | add **R3 reflow** (recover line-end dead margin, ~29% glyph fill → dense) | rows were mostly empty; pack them | -| 2026-05-22 | `fbf32bb` | **pack reflow across newlines** + grayscale atlas + build **L1/L2 eval harness** | measure read fidelity of the packing | -| 2026-05-22 | `ea68340` | **in-image instruction banner** variant | L1 eval: **+1.04pp** char accuracy vs baseline | -| 2026-05-22 | `dca7807` | pack header prose to full row width, drop spurious ↵ markers | tidy reflow output | -| 2026-05-22 | `a9b0996` | docs: cell is now **5×8** (was 7×10) | denser cell | -| 2026-05-23 | `1afaa6c` | content-aware image cost + **width-shrinking** (WIP) | *tried* shrink-to-content | -| 2026-05-23 | `414f4bf` | hoist width-shrink before the cost gate so prediction matches render | make shrink predictable | -| 2026-05-25 | `3c8716c` | **full-canvas single-column rendering, 50k chars/page** — `shrinkColsToContent` becomes a **no-op** | shrink gave no gain on dense content; full width packs more | -| 2026-05-25 | `bb8e0d8` | **page** dense tool/history images | enforce the 195-line cap, split overflow | -| 2026-05-26 | `28bc65c` | reduce dense page size | tuning | -| 2026-06-09 | `cdfc99d` | drop Opus, **Fable-5 only**; dense render on bare 5×8 cell | Opus misread ~7% of renders | -| 2026-06-17 | (this change) | raise page ceiling to **~1932×1932**: `MAX_HEIGHT_PX=1932`, dense pages `DENSE_CONTENT_COLS=384` / `92160` chars; row cap follows each call's char budget | Fable/Opus 4.8 accept ≤2000px & ≤4784 tok/image (not the old 1568 limit); baseline left ~3× headroom unused → bigger pages = fewer image blocks at the same 5×8 legibility | - -The arc: **reflow** to stop wasting rows → **eval harness** to prove the packing -is still readable → **width-shrink** experiment → **reverted** to full-canvas -two days later because dense content already fills the width → **paging** for the -height cap → **model scope narrowed** to the reader that hits 100% on the cell. - -## If you want to change the sizing - -1. Add a style variant to the L1 OCR eval and measure char accuracy first. -2. Check the cost side against `events.jsonl` (don't trust the hardcoded - per-image constant — see the gap above). -3. Remember the gate must be able to *predict* the size cheaply; content-dependent - geometry is what got width-shrink reverted. +1. Add or re-run a reader-specific recall/style harness. +2. Measure the provider's real image-token accounting. +3. Keep the strip inside its no-resize boundary. +4. Test slab, history, gate, and cache determinism together. +5. Do not generalize one variant's result to sibling model ids. diff --git a/docs/TRANSFORM_INFO.md b/docs/TRANSFORM_INFO.md index 13f3667..fd66584 100644 --- a/docs/TRANSFORM_INFO.md +++ b/docs/TRANSFORM_INFO.md @@ -15,11 +15,11 @@ to re-read that text in token form — Anthropic prompt-caches it, and image blocks OCR cleanly at small font sizes. So pxpipe pulls the static prefix out of the JSON body, renders it as one or more grayscale PNG image blocks, and pins a single `cache_control` breakpoint on the last image. Anthropic -charges roughly `ceil(W*H/750)` tokens per image; a full static-slab page is -1573×1280, so each slab tile costs ~2684 tokens regardless of how much text it -carries. A 68K-token static slab collapses to ~3.5K image tokens on the first -turn and to a cache-read (billed at 0.10×) on every subsequent turn. The -trade is real text tokens for a few image tokens we cache once. +charges roughly `ceil(W*H/750)` tokens per image; the current Anthropic profile +caps pages at 1568×728 so rasterized pixels survive the provider's resize. A +large static slab becomes a small set of image pages on the first turn and a +cache-read (billed at 0.10×) on subsequent turns. The trade is real text tokens +for image tokens cached under the same stable prefix. ## 2. The static / dynamic split @@ -258,25 +258,21 @@ The `1.25` and `0.10` multipliers match Anthropic's published cache pricing for Opus: writing to the cache costs 1.25× the per-token input rate; reading from the cache costs 0.10×. -**Per-call baseline cost** — what the *same* call would have billed if we had -NOT compressed: +**Per-call baseline cost** — what the same call would have billed if it had not +been compressed. The implementation uses the actual baseline probe and observed +cache state; it does not multiply image count by a fixed historical canvas: ``` -text_tokens_we_removed = origChars / 4 # ~4 chars per token, rough -image_tokens_we_added = imageCount * 4761 # dense 1928×1928 ≈ 4761 tokens (slab ~2684) -extra_text_baseline = max(0, text_tokens_we_removed - image_tokens_we_added) - -# cache_create dominates the first turn; bias the baseline toward 1.25 in -# that regime. Otherwise assume a fully warm cache (0.10). -cache_total = cache_create + cache_read -baseline_rate = cache_create > 0 - ? (cache_create / cache_total) * 1.25 + (1 - cache_create / cache_total) * 0.10 - : 0.10 - -baseline = effective + extra_text_baseline * baseline_rate -saved = baseline - effective +baseline_raw = count_tokens(original_request) +baseline_eff = price(baseline_raw, observed_cache_state) +actual_eff = price(actual_usage, observed_cache_state) +saved = baseline_eff - actual_eff ``` +On OpenAI-shaped rows, response usage supplies `cached_tokens`; pxpipe records +actual image tokens from real dimensions and the o200k text value of the +replaced content. Rates and render geometry are selected by exact model id. + The dashboard's "tokens saved" and "$ saved" cards (and `pxpipe stats` for the offline aggregate) both surface these numbers. The $ figure in `src/dashboard.ts` uses a fixed per-Mtok input rate — note diff --git a/eval/grok-density/FACTSHEET_RESULTS.md b/eval/grok-density/FACTSHEET_RESULTS.md index 1a4b255..e1954cf 100644 --- a/eval/grok-density/FACTSHEET_RESULTS.md +++ b/eval/grok-density/FACTSHEET_RESULTS.md @@ -6,17 +6,16 @@ Fixture: same precision-critical synthetic session as the density harness ## Question -Production Grok keeps **5×8** packing because pure-image exact OCR fails at -that density. Does the shipping **image + factsheet** path clear the Opus -exact bar without giving up density? Is a denser pure-image packing still -worth considering? +One candidate kept **5×8** packing and relied on an image + factsheet contract. +Does that combination clear this fixture's exact bar? How does it compare with +the lower-density pure-image profile? ## Results | arm | exact | confab | gist | guard | save≈ | notes | |-----|------:|-------:|:----:|:-----:|------:|-------| | `5x8_image_only` | **0/4** | **4** | ok | ok | 76% | confabulates every ID | -| `5x8_image_plus_factsheet` | **4/4** | **0** | ok | ok | **70%** | **shipping contract** | +| `5x8_image_plus_factsheet` | **4/4** | **0** | ok | ok | **70%** | factsheet candidate | | `5x8_grid_plus_factsheet` | 4/4 | 0 | ok | ok | 70% | style no worse with sheet | | `5x8_color_plus_factsheet` | 4/4 | 0 | ok | ok | 70% | style no worse with sheet | | `d4_c84_image_only` | 4/4 | 0 | ok | ok | **30%** | pure-image Opus bar, half the density win | @@ -36,14 +35,13 @@ and history images (`src/core/openai.ts`). 1. **Grok stays opt-in only** (not in `DEFAULT_MODEL_BASES`). Same bar as Opus: not good enough as a silent pxpipe default. -2. **Do not change default Grok density when opted in.** 5×8 stays. -3. **Exact IDs are a factsheet problem, not a cell-size problem** at production - density. Image+factsheet passes 4/4 with ~70% fixture savings; pure-image d4 - also passes but only ~30% savings. -4. Style knobs (grid, colorCycle) at 5×8 do not replace the factsheet for exact - recall; with the sheet they are fine and optional. -5. Still open only if factsheet **coverage** misses a token class in the wild — - fix extractors, do not bloat cells. +2. The factsheet rescues the four token shapes in this fixture, but n=1 cannot + prove extractor coverage for real sessions. +3. The built-in opt-in profile therefore uses the independently measured + effective **9×12 / 84-column** arm (4/4, zero confab) and keeps the factsheet + as defense in depth. This is more conservative than 5×8 + factsheet. +4. Style knobs (grid, colorCycle) at 5×8 do not replace either larger cells or + the factsheet for exact recall. Enable with `PXPIPE_MODELS=...,grok-4.5` or the dashboard Grok chip. diff --git a/eval/grok-density/README.md b/eval/grok-density/README.md index 57801e7..ba2082d 100644 --- a/eval/grok-density/README.md +++ b/eval/grok-density/README.md @@ -1,9 +1,8 @@ # Grok density / image-recall sweep **Question:** prior pxpipe recall work covered Fable 5, Opus 4.8, and GPT notes. -Grok is imaging in production through the OpenAI Responses path, but it has no -measured profile. Does Grok read production-density images well enough, or does -it need a lower-density / different strip geometry profile? +If Grok is explicitly enabled on the OpenAI Responses path, does it read the +shared dense profile, or does it need lower-density geometry? This harness answers that with a measurement. It does **not** change production defaults. A Grok profile should only be added if the numbers clear the bar @@ -14,9 +13,7 @@ below. For each render **variant** (cell size) it: 1. Renders one synthetic session transcript to PNG(s) with the production - renderer, using the OpenAI-path page geometry Grok actually sees today - (strip capped at 768 px wide / 1932 px tall — the default GPT-profile - geometry that unmatched models, including Grok, currently inherit). + renderer, capped at 768 px wide / 1932 px tall. 2. Asks the model a fixed battery of questions against the image(s). 3. Scores exact recall, gist, confabulation guard, and refusal. @@ -79,16 +76,15 @@ Responses path with different page geometry and vision billing, so it needs its own client and cost accounting. Shared pieces (fixture, scoring rules) mirror the Opus harness on purpose so results are comparable. -## Production contract (image + factsheet) +## Factsheet arm -Density sweeps above measure **pure image** reading. Production Grok does not -rely on that for exact IDs: the Responses transform attaches a verbatim -fact-sheet next to the 5×8 images. Live proof that image-only fails and -image+factsheet clears the Opus exact bar: +Density sweeps above measure **pure image** reading. The Responses transform +also attaches a verbatim fact-sheet. The factsheet harness proves that it +rescues this fixture at 5×8, but not that every real token shape is covered. +The built-in opt-in profile therefore uses effective 9×12 and the factsheet: ```bash GROK_DENSITY_LIVE=1 node eval/grok-density/factsheet-vs-image.mjs ``` See [FACTSHEET_RESULTS.md](./FACTSHEET_RESULTS.md). - diff --git a/eval/grok-density/RESULTS.md b/eval/grok-density/RESULTS.md index 1d3deca..32a6a2d 100644 --- a/eval/grok-density/RESULTS.md +++ b/eval/grok-density/RESULTS.md @@ -1,14 +1,14 @@ # Grok density / image-recall sweep — results -Live run of `run.mjs`, 2026-07-09. Model: `grok-4.5`. Geometry: default -Responses-path profile (`stripCols=152`, `maxHeightPx=1932`, vision tile -`85/170`). `results.json` is this run. +Live run of `run.mjs`, 2026-07-09. Model: `grok-4.5`. The original receipt used +the then-shared Responses geometry (`stripCols=152`, `maxHeightPx=1932`) and +the GPT tile estimator. `results.json` is that historical run; later measured +Grok billing is ~1000 tokens/MPix (see `CLIMB_RESULTS.md`). ## Question -Prior recall work covered Fable 5 and Opus 4.8. Grok is already imaging on the -Responses path under the unmatched-model fallback profile. Does it read -production-density images well enough, or does it need a lower-density profile? +Prior recall work covered Fable 5 and Opus 4.8. If Grok is opted in, does it +read the shared dense profile well enough, or need a lower-density profile? ## Exact-string recall @@ -31,8 +31,8 @@ production-density images well enough, or does it need a lower-density profile? nibble). Gist + guard ok. **9x12** — clears the acceptance bar: 4/4 exact (byte-exact hex), 0 confab, -gist ok, guard ok. Savings collapse to ~5% under the current tile cost model -because the taller page bills more vision tokens. +gist ok, guard ok. This original table's 5% used the wrong GPT tile estimator; +measured Grok billing puts the same profile at ~30% fixture savings. ## Verdict @@ -42,11 +42,9 @@ because the taller page bills more vision tokens. strings. Candidate: an **opt-in lower-density Grok render profile at `9x12`** (or at least denser than production). **Not** a silent default change, and **not** a `DEFAULT_MODEL_BASES` change. -- Current unmatched-model vision profile (`tile 85/170`, 152 cols, 1932 px - height) is only a cost/geometry fallback. It does not measure Grok - readability. A real Grok profile should encode both: - 1. render density that clears exact recall (`9x12` candidate) - 2. vision billing numbers once Grok's real image-token formula is known +- The built-in opt-in Grok profile now encodes effective 9×12 / 84 columns and + measured ~1000 tokens/MPix billing. It still remains outside the default + allowlist because this is n=1 synthetic evidence. - n=1 per cell (harness design). Re-run before baking a production profile. ## How this was run diff --git a/eval/grok-density/brute-live-results.json b/eval/grok-density/brute-live-results.json new file mode 100644 index 0000000..6667986 --- /dev/null +++ b/eval/grok-density/brute-live-results.json @@ -0,0 +1,102 @@ +{ + "generatedAt": "2026-07-09T11:47:03.225Z", + "model": "grok-4.5", + "textTokens": 1168, + "rows": [ + { + "id": "w0h0_c152_H1932", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": { + "exactCorrect": 0, + "exactTotal": 4, + "confab": 3, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "NOT STATED", + "status": "completed", + "ok": false, + "abstained": true, + "confab": false, + "refused": false, + "ms": 13550 + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenedgeShard", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 861 + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "pro/core/anthropic-client.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2916 + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "97821", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2715 + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 918 + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 4625 + } + ] + } + } + ] +} \ No newline at end of file diff --git a/eval/grok-density/brute-live.mjs b/eval/grok-density/brute-live.mjs new file mode 100644 index 0000000..c5fa21f --- /dev/null +++ b/eval/grok-density/brute-live.mjs @@ -0,0 +1,213 @@ +// Focused live sweep: density ladder where dry-run still shows real savings. +// Full 225-combo dry-run is in brute.mjs; this only spends model calls on the +// candidates that can still win on cost. +import { writeFileSync, readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { renderTextToPngs } from '../../dist/core/render.js'; +import { openAIVisionTokens } from '../../dist/core/openai.js'; + +const here = dirname(fileURLToPath(import.meta.url)); +const MODEL = process.env.GROK_DENSITY_MODEL || 'grok-4.5'; +const TIMEOUT_MS = Number(process.env.GROK_DENSITY_TIMEOUT_MS || 180000); +const PAD_X = 4; +const CELL_BASE_W = 5; + +const TRUTH = { + hex: 'a3f9c1e0b7d2', + camel: 'tokenLedgerShard', + path: 'src/core/anthropic-vision.ts', + port: '47821', +}; +const SESSION = [ + 'Wire up the retry path. Use a retry budget of 3 attempts, backing off 250ms.', + `Done. The token cache key is ${TRUTH.hex}. I renamed the field to ${TRUTH.camel}`, + `and moved the tier math into ${TRUTH.path}. The CLI now takes --max-visual-tokens. Proxy stays on port ${TRUTH.port}.`, + 'Good. Keep the retry budget as decided; do not change the backoff.', + ...Array.from({ length: 40 }, (_, i) => + `step ${i}: processed shard ${i} of the ${TRUTH.camel}, ok, continuing the run.`), +].join('\n'); +const QUESTIONS = [ + { id: 'hex', kind: 'exact', q: 'What is the exact token cache key (12-char hex) mentioned in the transcript?', answer: TRUTH.hex }, + { id: 'camel', kind: 'exact', q: 'What is the exact field name the assistant renamed the field to?', answer: TRUTH.camel }, + { id: 'path', kind: 'exact', q: 'What exact file path did the tier math move into?', answer: TRUTH.path }, + { id: 'port', kind: 'exact', q: 'What port does the proxy stay on?', answer: TRUTH.port }, + { id: 'gist', kind: 'gist', q: 'What retry budget was decided (a number of attempts)?', answer: '3' }, + { id: 'guard', kind: 'guard', q: 'What database password was configured in this session? If it was not stated, say "NOT STATED".', answer: 'NOT STATED' }, +]; +const TEXT_TOKENS = Math.ceil(SESSION.length / 4); + +// Density ladder + geometry knobs that dry-run keeps save>=30% for most cells. +const CELLS = [ + [0, 0], // production baseline + [1, 1], + [2, 2], // prior 7x10-ish + [2, 3], + [3, 2], + [3, 3], + [3, 4], + [4, 2], + [4, 3], + [4, 4], // prior 9x12-ish +]; +const STRIP_COLS = [152, 128]; +const MAX_H = [1932, 1536]; + +function colsFor(stripCols, wBonus) { + const maxW = 2 * PAD_X + stripCols * CELL_BASE_W; + return Math.max(8, Math.floor((maxW - 2 * PAD_X) / (CELL_BASE_W + wBonus))); +} +function responsesBaseUrl() { + const base = (process.env.OPENAI_BASE_URL || '').replace(/\/$/, ''); + if (!base) throw new Error('OPENAI_BASE_URL required'); + return base.endsWith('/responses') ? base : `${base}/responses`; +} +async function callModel(dataUrls, question) { + const key = process.env.OPENAI_API_KEY; + if (!key) throw new Error('OPENAI_API_KEY required'); + const content = [ + ...dataUrls.map((u) => ({ type: 'input_image', image_url: u, detail: 'original' })), + { type: 'input_text', text: question + '\nAnswer with ONLY the exact value, or "NOT STATED" if it is not present. Do not guess.' }, + ]; + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), TIMEOUT_MS); + const t0 = Date.now(); + try { + const res = await fetch(responsesBaseUrl(), { + method: 'POST', + headers: { 'content-type': 'application/json', authorization: `Bearer ${key}` }, + body: JSON.stringify({ + model: MODEL, + stream: false, + max_output_tokens: 512, + input: [{ role: 'user', content }], + }), + signal: controller.signal, + }); + const raw = await res.text(); + const j = JSON.parse(raw); + if (!res.ok) throw new Error(`HTTP ${res.status}: ${j?.error?.message || raw.slice(0, 160)}`); + let text = typeof j.output_text === 'string' ? j.output_text : ''; + if (!text && Array.isArray(j.output)) { + for (const item of j.output) { + if (!item || item.type !== 'message' || !Array.isArray(item.content)) continue; + for (const part of item.content) { + if (part && (part.type === 'output_text' || part.type === 'text') && typeof part.text === 'string') text += part.text; + } + } + } + return { text: text.trim(), ms: Date.now() - t0, status: j.status || null }; + } finally { + clearTimeout(timer); + } +} +function score(kind, expected, got) { + if (!got) return { ok: false, abstained: false, confab: false, refused: true }; + const g = got.toLowerCase(); + const abstained = /not stated|unknown|not safe|can't|cannot|not present|i don't know|do not know/.test(g); + if (kind === 'guard') return { ok: abstained, abstained, confab: !abstained, refused: false }; + if (kind === 'gist') return { ok: g.includes(String(expected).toLowerCase()), abstained, confab: false, refused: false }; + return { ok: got.includes(expected), abstained, confab: !got.includes(expected) && !abstained, refused: false }; +} + +const combos = []; +for (const stripCols of STRIP_COLS) { + for (const maxHeightPx of MAX_H) { + for (const [cellWBonus, cellHBonus] of CELLS) { + combos.push({ + id: `w${cellWBonus}h${cellHBonus}_c${stripCols}_H${maxHeightPx}`, + cellWBonus, + cellHBonus, + stripCols, + maxHeightPx, + cols: colsFor(stripCols, cellWBonus), + style: { cellWBonus, cellHBonus, aa: true }, + }); + } + } +} + +console.log(`Grok focused live brute · model=${MODEL} · combos=${combos.length}`); +const rows = []; +for (const c of combos) { + const imgs = await renderTextToPngs(SESSION, c.cols, c.style, c.maxHeightPx); + const pages = imgs.map((im) => ({ png: im.png, width: im.width, height: im.height })); + const imageTokens = pages.reduce((n, p) => n + openAIVisionTokens(MODEL, p.width, p.height), 0); + const savingsPct = Math.round((1 - imageTokens / TEXT_TOKENS) * 100); + const row = { + id: c.id, + cellWBonus: c.cellWBonus, + cellHBonus: c.cellHBonus, + stripCols: c.stripCols, + maxHeightPx: c.maxHeightPx, + cols: c.cols, + pages: pages.length, + dims: pages.map((p) => `${p.width}x${p.height}`), + imageTokens, + savingsPct, + model: null, + }; + console.log(`\n[${c.id}] save=${savingsPct}% pages=${pages.length} dims=${row.dims.join(',')} imgTok=${imageTokens}`); + if (savingsPct < 15) { + console.log(' skip live: savings below 15%'); + rows.push(row); + continue; + } + const dataUrls = pages.map((p) => 'data:image/png;base64,' + Buffer.from(p.png).toString('base64')); + const m = { exactCorrect: 0, exactTotal: 0, confab: 0, gistOk: false, guardOk: false, answers: [] }; + for (const q of QUESTIONS) { + try { + const { text, ms, status } = await callModel(dataUrls, q.q); + const s = score(q.kind, q.answer, text); + m.answers.push({ id: q.id, kind: q.kind, expected: q.answer, got: text, status, ...s, ms }); + if (q.kind === 'exact') { + m.exactTotal++; + if (s.ok) m.exactCorrect++; + } + if (s.confab) m.confab++; + if (q.kind === 'gist' && !s.refused) m.gistOk = s.ok; + if (q.kind === 'guard' && !s.refused) m.guardOk = s.ok; + const mark = s.ok ? 'OK' : s.refused ? 'REFUSED' : s.abstained ? 'ABSTAIN' : s.confab ? 'CONFAB' : 'MISS'; + console.log(` ${q.id.padEnd(6)} ${mark.padEnd(8)} ${JSON.stringify(text).slice(0, 70)} (${ms}ms)`); + } catch (err) { + console.error(` ${q.id.padEnd(6)} ERROR ${err.message}`); + m.answers.push({ id: q.id, kind: q.kind, expected: q.answer, got: '', error: String(err.message || err), ok: false, confab: false, refused: true, ms: 0 }); + if (q.kind === 'exact') m.exactTotal++; + } + } + row.model = m; + console.log(` → exact ${m.exactCorrect}/${m.exactTotal} confab ${m.confab} gist ${m.gistOk ? 'ok' : 'FAIL'} guard ${m.guardOk ? 'ok' : 'FAIL'} save ${savingsPct}%`); + rows.push(row); + // checkpoint after each combo so a mid-run death is not total loss + writeFileSync(join(here, 'brute-live-results.json'), JSON.stringify({ + generatedAt: new Date().toISOString(), + model: MODEL, + textTokens: TEXT_TOKENS, + rows, + }, null, 2)); +} + +const liveRows = rows.filter((r) => r.model); +const perfect = liveRows + .filter((r) => r.model.exactCorrect === 4 && r.model.confab === 0 && r.model.gistOk && r.model.guardOk) + .sort((a, b) => b.savingsPct - a.savingsPct || a.imageTokens - b.imageTokens); +const good = liveRows + .filter((r) => r.model.exactCorrect >= 3 && r.model.confab <= 1 && r.model.gistOk && r.model.guardOk) + .sort((a, b) => b.savingsPct - a.savingsPct || a.imageTokens - b.imageTokens); + +const out = { + generatedAt: new Date().toISOString(), + model: MODEL, + textTokens: TEXT_TOKENS, + rows, + perfect, + good, + bestPerfect: perfect[0] || null, + bestGood: good[0] || null, +}; +writeFileSync(join(here, 'brute-live-results.json'), JSON.stringify(out, null, 2)); +console.log('\nBEST perfect:', perfect[0]?.id, perfect[0]?.savingsPct); +console.log('BEST good:', good[0]?.id, good[0]?.savingsPct, good[0]?.model && `${good[0].model.exactCorrect}/4`); +for (const r of perfect.slice(0, 8)) { + console.log(` perfect ${r.id} save=${r.savingsPct}% dims=${r.dims.join(',')}`); +} diff --git a/eval/grok-density/brute-results.json b/eval/grok-density/brute-results.json new file mode 100644 index 0000000..ce0dae4 --- /dev/null +++ b/eval/grok-density/brute-results.json @@ -0,0 +1,8153 @@ +{ + "generatedAt": "2026-07-09T11:47:44.516Z", + "model": "grok-4.5", + "live": false, + "textTokens": 1168, + "comboCount": 504, + "axes": { + "cells": [ + [ + 0, + 0 + ], + [ + 1, + 1 + ], + [ + 2, + 2 + ], + [ + 2, + 3 + ], + [ + 3, + 2 + ], + [ + 3, + 3 + ], + [ + 4, + 3 + ], + [ + 4, + 4 + ] + ], + "styles": [ + "aa", + "onebit", + "aa+grid", + "aa+color", + "aa+role", + "onebit+grid", + "onebit+color" + ], + "stripCols": [ + 152, + 128, + 100 + ], + "maxH": [ + 1932, + 1536, + 1024 + ] + }, + "rows": [ + { + "id": "w0h0_c152_H1932_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1932_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1932_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1932_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1932_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1932_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1932_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1932_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1932_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1932_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c152_H1932_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1932_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1932_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1932_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1932_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1932_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1932_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1932_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1932_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h4_c152_H1932_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1932_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1932_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1932_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1932_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1932_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1932_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w0h0_c152_H1536_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1536_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1536_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1536_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1536_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1536_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1536_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1536_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1536_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1536_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c152_H1536_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1536_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1536_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1536_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1536_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1536_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1536_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1536_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1536_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h4_c152_H1536_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1536_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1536_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1536_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1536_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1536_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c152_H1536_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w0h0_c152_H1024_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1024_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1024_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1024_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1024_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1024_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c152_H1024_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c152_H1024_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c152_H1024_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x458" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c152_H1024_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 108, + "pages": 1, + "dims": [ + "764x503" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c152_H1024_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1024_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1024_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1024_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1024_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1024_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c152_H1024_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x868" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c152_H1024_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 95, + "pages": 1, + "dims": [ + "768x954" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c152_H1024_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 84, + "pages": 1, + "dims": [ + "764x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h4_c152_H1024_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c152_H1024_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c152_H1024_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c152_H1024_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c152_H1024_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c152_H1024_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c152_H1024_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 152, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 84, + "pages": 2, + "dims": [ + "764x1016", + "764x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w0h0_c128_H1932_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1932_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1932_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1932_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1932_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1932_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1932_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1932_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c128_H1932_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1932_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1932_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1932_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1932_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1932_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1932_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1932_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1932_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1932_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1932_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h4_c128_H1932_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1932_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1932_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1932_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1932_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1932_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1932_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w0h0_c128_H1536_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1536_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1536_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1536_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1536_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1536_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1536_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1536_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c128_H1536_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1536_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1536_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1536_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1536_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1536_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1536_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1536_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1536_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1536_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1536_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h4_c128_H1536_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1536_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1536_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1536_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1536_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1536_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w4h4_c128_H1536_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x1064" + ], + "imageTokens": 1105, + "savingsPct": 5, + "model": null + }, + { + "id": "w0h0_c128_H1024_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1024_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1024_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1024_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1024_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1024_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c128_H1024_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 128, + "pages": 1, + "dims": [ + "648x368" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c128_H1024_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 106, + "pages": 1, + "dims": [ + "644x413" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c128_H1024_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1024_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1024_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1024_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1024_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1024_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h2_c128_H1024_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x878" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w2h3_c128_H1024_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 91, + "pages": 1, + "dims": [ + "645x965" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h2_c128_H1024_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x888" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w3h3_c128_H1024_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 80, + "pages": 1, + "dims": [ + "648x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h3_c128_H1024_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "647x976" + ], + "imageTokens": 765, + "savingsPct": 35, + "model": null + }, + { + "id": "w4h4_c128_H1024_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c128_H1024_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c128_H1024_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c128_H1024_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c128_H1024_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c128_H1024_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w4h4_c128_H1024_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 128, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 71, + "pages": 2, + "dims": [ + "647x1016", + "647x56" + ], + "imageTokens": 1190, + "savingsPct": -2, + "model": null + }, + { + "id": "w0h0_c100_H1932_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1932_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1932_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1932_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1932_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1932_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1932_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1932_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1932_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1932_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1932_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1932_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1932_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h4_c100_H1932_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1932_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1932_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1932_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1932_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "aa+role", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1932_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1932_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1932, + "styleName": "onebit+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w0h0_c100_H1536_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1536_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1536_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1536_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1536_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1536_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1536_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1536_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1536_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1536_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1536_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1536_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1536_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h4_c100_H1536_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1536_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1536_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1536_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1536_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "aa+role", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1536_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w4h4_c100_H1536_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1536, + "styleName": "onebit+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x1076" + ], + "imageTokens": 595, + "savingsPct": 49, + "model": null + }, + { + "id": "w0h0_c100_H1024_aa", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1024_onebit", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1024_aa+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1024_aa+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1024_aa+role", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1024_onebit+grid", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w0h0_c100_H1024_onebit+color", + "cellWBonus": 0, + "cellHBonus": 0, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 100, + "pages": 1, + "dims": [ + "508x688" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_aa", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_onebit", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_aa+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_aa+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_aa+role", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_onebit+grid", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w1h1_c100_H1024_onebit+color", + "cellWBonus": 1, + "cellHBonus": 1, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 83, + "pages": 1, + "dims": [ + "506x800" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_aa", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_onebit", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_aa+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_aa+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_aa+role", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h2_c100_H1024_onebit+color", + "cellWBonus": 2, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x888" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_aa", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_onebit", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_aa+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_aa+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_aa+role", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_onebit+grid", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w2h3_c100_H1024_onebit+color", + "cellWBonus": 2, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 71, + "pages": 1, + "dims": [ + "505x976" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_aa", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_onebit", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_aa+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_aa+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_aa+role", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h2_c100_H1024_onebit+color", + "cellWBonus": 3, + "cellHBonus": 2, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x898" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_aa", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_onebit", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_aa+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_aa+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_aa+role", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_onebit+grid", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w3h3_c100_H1024_onebit+color", + "cellWBonus": 3, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 62, + "pages": 1, + "dims": [ + "504x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_aa", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_onebit", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_aa+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_aa+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_aa+role", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h3_c100_H1024_onebit+color", + "cellWBonus": 4, + "cellHBonus": 3, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 55, + "pages": 1, + "dims": [ + "503x987" + ], + "imageTokens": 425, + "savingsPct": 64, + "model": null + }, + { + "id": "w4h4_c100_H1024_aa", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + }, + { + "id": "w4h4_c100_H1024_onebit", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + }, + { + "id": "w4h4_c100_H1024_aa+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+grid", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + }, + { + "id": "w4h4_c100_H1024_aa+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+color", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + }, + { + "id": "w4h4_c100_H1024_aa+role", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "aa+role", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + }, + { + "id": "w4h4_c100_H1024_onebit+grid", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+grid", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + }, + { + "id": "w4h4_c100_H1024_onebit+color", + "cellWBonus": 4, + "cellHBonus": 4, + "stripCols": 100, + "maxHeightPx": 1024, + "styleName": "onebit+color", + "cols": 55, + "pages": 2, + "dims": [ + "503x1016", + "503x68" + ], + "imageTokens": 680, + "savingsPct": 42, + "model": null + } + ], + "perfect": [], + "good": [], + "bestPerfect": null, + "bestGood": null +} \ No newline at end of file diff --git a/eval/grok-density/brute.mjs b/eval/grok-density/brute.mjs new file mode 100644 index 0000000..cead66a --- /dev/null +++ b/eval/grok-density/brute.mjs @@ -0,0 +1,259 @@ +// Brute-force Grok render profiles across density, strip geometry, AND style. +// Production is a fixed 5x8 atlas (not a TrueType face), so "font" here means +// the atlas/style arms the renderer actually exposes: AA vs 1-bit, grid, color. +// +// Dry-run default. GROK_BRUTE_LIVE=1 scores recall only for combos with save>=15%. +// +// pnpm run build +// node eval/grok-density/brute.mjs +// GROK_BRUTE_LIVE=1 node eval/grok-density/brute.mjs +import { writeFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { renderTextToPngs } from '../../dist/core/render.js'; +import { openAIVisionTokens } from '../../dist/core/openai.js'; + +const here = dirname(fileURLToPath(import.meta.url)); +const MODEL = process.env.GROK_DENSITY_MODEL || 'grok-4.5'; +const LIVE = process.env.GROK_BRUTE_LIVE === '1' || process.env.GROK_BRUTE_LIVE === 'true'; +const TIMEOUT_MS = Number(process.env.GROK_DENSITY_TIMEOUT_MS || 180000); +const MIN_SAVE = Number(process.env.GROK_BRUTE_MIN_SAVE || 15); +const PAD_X = 4; +const CELL_BASE_W = 5; + +const TRUTH = { + hex: 'a3f9c1e0b7d2', + camel: 'tokenLedgerShard', + path: 'src/core/anthropic-vision.ts', + port: '47821', +}; +const SESSION = [ + 'Wire up the retry path. Use a retry budget of 3 attempts, backing off 250ms.', + `Done. The token cache key is ${TRUTH.hex}. I renamed the field to ${TRUTH.camel}`, + `and moved the tier math into ${TRUTH.path}. The CLI now takes --max-visual-tokens. Proxy stays on port ${TRUTH.port}.`, + 'Good. Keep the retry budget as decided; do not change the backoff.', + ...Array.from({ length: 40 }, (_, i) => + `step ${i}: processed shard ${i} of the ${TRUTH.camel}, ok, continuing the run.`), +].join('\n'); +const QUESTIONS = [ + { id: 'hex', kind: 'exact', q: 'What is the exact token cache key (12-char hex) mentioned in the transcript?', answer: TRUTH.hex }, + { id: 'camel', kind: 'exact', q: 'What is the exact field name the assistant renamed the field to?', answer: TRUTH.camel }, + { id: 'path', kind: 'exact', q: 'What exact file path did the tier math move into?', answer: TRUTH.path }, + { id: 'port', kind: 'exact', q: 'What port does the proxy stay on?', answer: TRUTH.port }, + { id: 'gist', kind: 'gist', q: 'What retry budget was decided (a number of attempts)?', answer: '3' }, + { id: 'guard', kind: 'guard', q: 'What database password was configured in this session? If it was not stated, say "NOT STATED".', answer: 'NOT STATED' }, +]; +const TEXT_TOKENS = Math.ceil(SESSION.length / 4); + +// Style arms the renderer can actually change (atlas is fixed Unifont 5x8, not a face picker). +const STYLES = [ + { name: 'aa', style: { aa: true } }, + { name: 'onebit', style: { aa: false } }, + { name: 'aa+grid', style: { aa: true, grid: true } }, + { name: 'aa+color', style: { aa: true, colorCycle: true } }, + { name: 'aa+role', style: { aa: true, colorByRole: true } }, + { name: 'onebit+grid', style: { aa: false, grid: true } }, + { name: 'onebit+color', style: { aa: false, colorCycle: true } }, +]; + +// Density ladder: production through large cells. +const CELLS = [ + [0, 0], + [1, 1], + [2, 2], + [2, 3], + [3, 2], + [3, 3], + [4, 3], + [4, 4], +]; +const STRIP_COLS = [152, 128, 100]; +const MAX_H = [1932, 1536, 1024]; + +function colsFor(stripCols, wBonus) { + const maxW = 2 * PAD_X + stripCols * CELL_BASE_W; + return Math.max(8, Math.floor((maxW - 2 * PAD_X) / (CELL_BASE_W + wBonus))); +} +function responsesBaseUrl() { + const base = (process.env.OPENAI_BASE_URL || '').replace(/\/$/, ''); + if (!base) throw new Error('OPENAI_BASE_URL required for live'); + return base.endsWith('/responses') ? base : `${base}/responses`; +} +async function callModel(dataUrls, question) { + const key = process.env.OPENAI_API_KEY; + if (!key) throw new Error('OPENAI_API_KEY required for live'); + const content = [ + ...dataUrls.map((u) => ({ type: 'input_image', image_url: u, detail: 'original' })), + { type: 'input_text', text: question + '\nAnswer with ONLY the exact value, or "NOT STATED" if it is not present. Do not guess.' }, + ]; + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), TIMEOUT_MS); + const t0 = Date.now(); + try { + const res = await fetch(responsesBaseUrl(), { + method: 'POST', + headers: { 'content-type': 'application/json', authorization: `Bearer ${key}` }, + body: JSON.stringify({ + model: MODEL, + stream: false, + max_output_tokens: 512, + input: [{ role: 'user', content }], + }), + signal: controller.signal, + }); + const raw = await res.text(); + const j = JSON.parse(raw); + if (!res.ok) throw new Error(`HTTP ${res.status}: ${j?.error?.message || raw.slice(0, 160)}`); + let text = typeof j.output_text === 'string' ? j.output_text : ''; + if (!text && Array.isArray(j.output)) { + for (const item of j.output) { + if (!item || item.type !== 'message' || !Array.isArray(item.content)) continue; + for (const part of item.content) { + if (part && (part.type === 'output_text' || part.type === 'text') && typeof part.text === 'string') text += part.text; + } + } + } + return { text: text.trim(), ms: Date.now() - t0, status: j.status || null }; + } finally { + clearTimeout(timer); + } +} +function score(kind, expected, got) { + if (!got) return { ok: false, abstained: false, confab: false, refused: true }; + const g = got.toLowerCase(); + const abstained = /not stated|unknown|not safe|can't|cannot|not present|i don't know|do not know/.test(g); + if (kind === 'guard') return { ok: abstained, abstained, confab: !abstained, refused: false }; + if (kind === 'gist') return { ok: g.includes(String(expected).toLowerCase()), abstained, confab: false, refused: false }; + return { ok: got.includes(expected), abstained, confab: !got.includes(expected) && !abstained, refused: false }; +} + +const combos = []; +for (const stripCols of STRIP_COLS) { + for (const maxHeightPx of MAX_H) { + for (const [cellWBonus, cellHBonus] of CELLS) { + for (const st of STYLES) { + combos.push({ + id: `w${cellWBonus}h${cellHBonus}_c${stripCols}_H${maxHeightPx}_${st.name}`, + cellWBonus, + cellHBonus, + stripCols, + maxHeightPx, + styleName: st.name, + cols: colsFor(stripCols, cellWBonus), + style: { ...st.style, cellWBonus, cellHBonus }, + }); + } + } + } +} + +console.log(`Grok brute · model=${MODEL} · combos=${combos.length} · live=${LIVE} · minSave=${MIN_SAVE}`); +console.log(`axes: cells=${CELLS.length} styles=${STYLES.length} stripCols=${STRIP_COLS.length} maxH=${MAX_H.length}`); +console.log(`text baseline ≈ ${TEXT_TOKENS} tok`); + +const rows = []; +for (const c of combos) { + const imgs = await renderTextToPngs(SESSION, c.cols, c.style, c.maxHeightPx); + const pages = imgs.map((im) => ({ png: im.png, width: im.width, height: im.height })); + const imageTokens = pages.reduce((n, p) => n + openAIVisionTokens(MODEL, p.width, p.height), 0); + const savingsPct = Math.round((1 - imageTokens / TEXT_TOKENS) * 100); + const row = { + id: c.id, + cellWBonus: c.cellWBonus, + cellHBonus: c.cellHBonus, + stripCols: c.stripCols, + maxHeightPx: c.maxHeightPx, + styleName: c.styleName, + cols: c.cols, + pages: pages.length, + dims: pages.map((p) => `${p.width}x${p.height}`), + imageTokens, + savingsPct, + model: null, + }; + + const liveThis = LIVE && savingsPct >= MIN_SAVE; + if (!LIVE || liveThis) { + console.log(`[${c.id}] save=${savingsPct}% pages=${pages.length} dims=${row.dims.join(',')} imgTok=${imageTokens}`); + } else { + console.log(`[skip-live ${c.id}] save=${savingsPct}%`); + } + + if (liveThis) { + const dataUrls = pages.map((p) => 'data:image/png;base64,' + Buffer.from(p.png).toString('base64')); + const m = { exactCorrect: 0, exactTotal: 0, confab: 0, gistOk: false, guardOk: false, answers: [] }; + for (const q of QUESTIONS) { + try { + const { text, ms, status } = await callModel(dataUrls, q.q); + const s = score(q.kind, q.answer, text); + m.answers.push({ id: q.id, kind: q.kind, expected: q.answer, got: text, status, ...s, ms }); + if (q.kind === 'exact') { + m.exactTotal++; + if (s.ok) m.exactCorrect++; + } + if (s.confab) m.confab++; + if (q.kind === 'gist' && !s.refused) m.gistOk = s.ok; + if (q.kind === 'guard' && !s.refused) m.guardOk = s.ok; + const mark = s.ok ? 'OK' : s.refused ? 'REFUSED' : s.abstained ? 'ABSTAIN' : s.confab ? 'CONFAB' : 'MISS'; + console.log(` ${q.id.padEnd(6)} ${mark.padEnd(8)} ${JSON.stringify(text).slice(0, 70)} (${ms}ms)`); + } catch (err) { + console.error(` ${q.id.padEnd(6)} ERROR ${err.message}`); + m.answers.push({ id: q.id, kind: q.kind, expected: q.answer, got: '', error: String(err.message || err), ok: false, confab: false, refused: true, ms: 0 }); + if (q.kind === 'exact') m.exactTotal++; + } + } + row.model = m; + console.log(` → exact ${m.exactCorrect}/${m.exactTotal} confab ${m.confab} gist ${m.gistOk ? 'ok' : 'FAIL'} guard ${m.guardOk ? 'ok' : 'FAIL'} save ${savingsPct}%`); + // checkpoint + writeFileSync(join(here, 'brute-results.json'), JSON.stringify({ + generatedAt: new Date().toISOString(), + model: MODEL, + live: LIVE, + textTokens: TEXT_TOKENS, + rows: [...rows, row], + }, null, 2)); + } + rows.push(row); +} + +const liveRows = rows.filter((r) => r.model); +const perfect = liveRows + .filter((r) => r.model.exactCorrect === 4 && r.model.confab === 0 && r.model.gistOk && r.model.guardOk) + .sort((a, b) => b.savingsPct - a.savingsPct || a.imageTokens - b.imageTokens); +const good = liveRows + .filter((r) => r.model.exactCorrect >= 3 && r.model.confab <= 1 && r.model.gistOk && r.model.guardOk) + .sort((a, b) => b.savingsPct - a.savingsPct || a.imageTokens - b.imageTokens); + +const out = { + generatedAt: new Date().toISOString(), + model: MODEL, + live: LIVE, + textTokens: TEXT_TOKENS, + comboCount: combos.length, + axes: { cells: CELLS, styles: STYLES.map((s) => s.name), stripCols: STRIP_COLS, maxH: MAX_H }, + rows, + perfect, + good, + bestPerfect: perfect[0] || null, + bestGood: good[0] || null, +}; +writeFileSync(join(here, 'brute-results.json'), JSON.stringify(out, null, 2)); +console.log(`\nWrote ${join(here, 'brute-results.json')}`); +if (!LIVE) { + const profitable = rows.filter((r) => r.savingsPct >= MIN_SAVE); + console.log(`Dry-run: ${profitable.length}/${rows.length} combos save>=${MIN_SAVE}%`); + // best savings per style at fixed production geometry, and best savings overall + const byStyle = new Map(); + for (const r of profitable) { + const k = r.styleName; + if (!byStyle.has(k) || r.savingsPct > byStyle.get(k).savingsPct) byStyle.set(k, r); + } + console.log('Best savings per style (any density/geometry):'); + for (const [k, r] of [...byStyle.entries()].sort((a, b) => b[1].savingsPct - a[1].savingsPct)) { + console.log(` ${k}: ${r.id} save=${r.savingsPct}% dims=${r.dims.join(',')}`); + } +} else { + console.log('BEST perfect:', perfect[0]?.id, perfect[0]?.savingsPct); + console.log('BEST good:', good[0]?.id, good[0]?.savingsPct, good[0]?.model && `${good[0].model.exactCorrect}/4`); + for (const r of perfect.slice(0, 10)) console.log(` perfect ${r.id} save=${r.savingsPct}%`); +} diff --git a/eval/grok-density/live-all-results.json b/eval/grok-density/live-all-results.json new file mode 100644 index 0000000..cc0ea62 --- /dev/null +++ b/eval/grok-density/live-all-results.json @@ -0,0 +1,1658 @@ +{ + "generatedAt": "2026-07-09T11:56:45.434Z", + "model": "grok-4.5", + "textTokens": 1168, + "goal": "opus-bar: 4/4 exact, 0 confab, gist+guard ok, maximize savings", + "rows": [ + { + "id": "spleen5x8_aa_wide1932_c152", + "font": "spleen5x8", + "style": "aa", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 0, + "exactTotal": 4, + "confab": 4, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "5e5ce8d9a2", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 10480, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 1330, + "output_tokens_details": { + "reasoning_tokens": 1321 + }, + "total_tokens": 1869, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 82900000, + "context_details": { + "input_tokens": 539, + "output_tokens": 1330 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenedgeShard", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 822, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 3, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 537, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 3180000, + "context_details": { + "input_tokens": 534, + "output_tokens": 3 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "pro/core/anthropic-client.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2954, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 259, + "output_tokens_details": { + "reasoning_tokens": 250 + }, + "total_tokens": 791, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 18500000, + "context_details": { + "input_tokens": 532, + "output_tokens": 259 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "97821", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2257, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 187, + "output_tokens_details": { + "reasoning_tokens": 185 + }, + "total_tokens": 716, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 14120000, + "context_details": { + "input_tokens": 529, + "output_tokens": 187 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3477, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 268, + "output_tokens_details": { + "reasoning_tokens": 267 + }, + "total_tokens": 801, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 19060000, + "context_details": { + "input_tokens": 533, + "output_tokens": 268 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 2250, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 193, + "output_tokens_details": { + "reasoning_tokens": 190 + }, + "total_tokens": 736, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 14760000, + "context_details": { + "input_tokens": 543, + "output_tokens": 193 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_onebit_wide1932_c152", + "font": "spleen5x8", + "style": "onebit", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 1, + "exactTotal": 4, + "confab": 3, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "5c5e3e8b9d2", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 15111, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 1738, + "output_tokens_details": { + "reasoning_tokens": 1727 + }, + "total_tokens": 2277, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 107380000, + "context_details": { + "input_tokens": 539, + "output_tokens": 1738 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenLedgerShard", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 780, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 3, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 537, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 3180000, + "context_details": { + "input_tokens": 534, + "output_tokens": 3 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "pro/core/anthropic/pricing.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 3448, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 338, + "output_tokens_details": { + "reasoning_tokens": 329 + }, + "total_tokens": 870, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 23240000, + "context_details": { + "input_tokens": 532, + "output_tokens": 338 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "8787", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 3725, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 223, + "output_tokens_details": { + "reasoning_tokens": 221 + }, + "total_tokens": 752, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 16280000, + "context_details": { + "input_tokens": 529, + "output_tokens": 223 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3238, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 234, + "output_tokens_details": { + "reasoning_tokens": 233 + }, + "total_tokens": 767, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 17020000, + "context_details": { + "input_tokens": 533, + "output_tokens": 234 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 4605, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 342, + "output_tokens_details": { + "reasoning_tokens": 339 + }, + "total_tokens": 885, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 23700000, + "context_details": { + "input_tokens": 543, + "output_tokens": 342 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_aa+grid_wide1932_c152", + "font": "spleen5x8", + "style": "aa+grid", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 2, + "exactTotal": 4, + "confab": 2, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "5d5c4ed792", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 14901, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 1143, + "output_tokens_details": { + "reasoning_tokens": 1136 + }, + "total_tokens": 1682, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 77440000, + "context_details": { + "input_tokens": 539, + "output_tokens": 1143 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenLedgerShard", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3302, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 266, + "output_tokens_details": { + "reasoning_tokens": 263 + }, + "total_tokens": 800, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 24720000, + "context_details": { + "input_tokens": 534, + "output_tokens": 266 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "src/core/authropic/tier.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 3672, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 362, + "output_tokens_details": { + "reasoning_tokens": 353 + }, + "total_tokens": 894, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 30440000, + "context_details": { + "input_tokens": 532, + "output_tokens": 362 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "47821", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 2690, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 170, + "output_tokens_details": { + "reasoning_tokens": 168 + }, + "total_tokens": 699, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 18860000, + "context_details": { + "input_tokens": 529, + "output_tokens": 170 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 2497, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 183, + "output_tokens_details": { + "reasoning_tokens": 182 + }, + "total_tokens": 716, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 19720000, + "context_details": { + "input_tokens": 533, + "output_tokens": 183 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 3972, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 384 + }, + "output_tokens": 340, + "output_tokens_details": { + "reasoning_tokens": 337 + }, + "total_tokens": 883, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 25500000, + "context_details": { + "input_tokens": 543, + "output_tokens": 340 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_aa+color_wide1932_c152", + "font": "spleen5x8", + "style": "aa+color", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 2, + "exactTotal": 4, + "confab": 2, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "59c3c4e7d92", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 10755, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 1034, + "output_tokens_details": { + "reasoning_tokens": 1025 + }, + "total_tokens": 1573, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 70900000, + "context_details": { + "input_tokens": 539, + "output_tokens": 1034 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenLedgerShard", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3084, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 300, + "output_tokens_details": { + "reasoning_tokens": 297 + }, + "total_tokens": 834, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 26760000, + "context_details": { + "input_tokens": 534, + "output_tokens": 300 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "pro/core/anthropic/tokens.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2139, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 162, + "output_tokens_details": { + "reasoning_tokens": 153 + }, + "total_tokens": 694, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 18440000, + "context_details": { + "input_tokens": 532, + "output_tokens": 162 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "47821", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3536, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 246, + "output_tokens_details": { + "reasoning_tokens": 244 + }, + "total_tokens": 775, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 23420000, + "context_details": { + "input_tokens": 529, + "output_tokens": 246 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3486, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 274, + "output_tokens_details": { + "reasoning_tokens": 273 + }, + "total_tokens": 807, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 25180000, + "context_details": { + "input_tokens": 533, + "output_tokens": 274 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 3148, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 384 + }, + "output_tokens": 255, + "output_tokens_details": { + "reasoning_tokens": 252 + }, + "total_tokens": 798, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 20400000, + "context_details": { + "input_tokens": 543, + "output_tokens": 255 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_aa+role_wide1932_c152", + "font": "spleen5x8", + "style": "aa+role", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 1, + "exactTotal": 4, + "confab": 3, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "5e5e5e5e5e5e", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 5236, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 512, + "output_tokens_details": { + "reasoning_tokens": 500 + }, + "total_tokens": 1051, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 39580000, + "context_details": { + "input_tokens": 539, + "output_tokens": 512 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenLedgerShard", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 3865, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 360, + "output_tokens_details": { + "reasoning_tokens": 357 + }, + "total_tokens": 894, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 30360000, + "context_details": { + "input_tokens": 534, + "output_tokens": 360 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "pro/core/anthropic/client.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 3003, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 212, + "output_tokens_details": { + "reasoning_tokens": 203 + }, + "total_tokens": 744, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 21440000, + "context_details": { + "input_tokens": 532, + "output_tokens": 212 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "97821", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2553, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 189, + "output_tokens_details": { + "reasoning_tokens": 187 + }, + "total_tokens": 718, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 20000000, + "context_details": { + "input_tokens": 529, + "output_tokens": 189 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 2611, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 226, + "output_tokens_details": { + "reasoning_tokens": 225 + }, + "total_tokens": 759, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 22300000, + "context_details": { + "input_tokens": 533, + "output_tokens": 226 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 3873, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 384 + }, + "output_tokens": 307, + "output_tokens_details": { + "reasoning_tokens": 304 + }, + "total_tokens": 850, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 23520000, + "context_details": { + "input_tokens": 543, + "output_tokens": 307 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_onebit+grid_wide1932_c152", + "font": "spleen5x8", + "style": "onebit+grid", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 1, + "exactTotal": 4, + "confab": 3, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "sofacled7d2", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 21138, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 2411, + "output_tokens_details": { + "reasoning_tokens": 2405 + }, + "total_tokens": 2950, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 147760000, + "context_details": { + "input_tokens": 539, + "output_tokens": 2411 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "proxy/anthropic-proxy.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 993, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 7, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 541, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 3420000, + "context_details": { + "input_tokens": 534, + "output_tokens": 7 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "src/core/authropic/tier.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2526, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 219, + "output_tokens_details": { + "reasoning_tokens": 210 + }, + "total_tokens": 751, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 16100000, + "context_details": { + "input_tokens": 532, + "output_tokens": 219 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "47821", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 691, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 384 + }, + "output_tokens": 2, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 531, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 4940000, + "context_details": { + "input_tokens": 529, + "output_tokens": 2 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 699, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 1, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 534, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 3040000, + "context_details": { + "input_tokens": 533, + "output_tokens": 1 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 2485, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 198, + "output_tokens_details": { + "reasoning_tokens": 195 + }, + "total_tokens": 741, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 15060000, + "context_details": { + "input_tokens": 543, + "output_tokens": 198 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_onebit+color_wide1932_c152", + "font": "spleen5x8", + "style": "onebit+color", + "geo": "wide1932", + "cell": "5x8", + "cols": 152, + "pages": 1, + "dims": [ + "768x360" + ], + "pixels": 276480, + "imageTokensEst": 276, + "savingsPct": 76, + "model": { + "exactCorrect": 1, + "exactTotal": 4, + "confab": 3, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "69c3e4d7d2", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 7098, + "usage": { + "input_tokens": 539, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 711, + "output_tokens_details": { + "reasoning_tokens": 702 + }, + "total_tokens": 1250, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 45760000, + "context_details": { + "input_tokens": 539, + "output_tokens": 711 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenledger_shard", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 3669, + "usage": { + "input_tokens": 534, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 414, + "output_tokens_details": { + "reasoning_tokens": 410 + }, + "total_tokens": 948, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 27840000, + "context_details": { + "input_tokens": 534, + "output_tokens": 414 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "src/core/anthropic/client.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2760, + "usage": { + "input_tokens": 532, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 194, + "output_tokens_details": { + "reasoning_tokens": 185 + }, + "total_tokens": 726, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 14600000, + "context_details": { + "input_tokens": 532, + "output_tokens": 194 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "47821", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 2789, + "usage": { + "input_tokens": 529, + "input_tokens_details": { + "cached_tokens": 384 + }, + "output_tokens": 188, + "output_tokens_details": { + "reasoning_tokens": 186 + }, + "total_tokens": 717, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 16100000, + "context_details": { + "input_tokens": 529, + "output_tokens": 188 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 2484, + "usage": { + "input_tokens": 533, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 158, + "output_tokens_details": { + "reasoning_tokens": 157 + }, + "total_tokens": 691, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 12460000, + "context_details": { + "input_tokens": 533, + "output_tokens": 158 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 2127, + "usage": { + "input_tokens": 543, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 167, + "output_tokens_details": { + "reasoning_tokens": 164 + }, + "total_tokens": 710, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 13200000, + "context_details": { + "input_tokens": 543, + "output_tokens": 167 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 539 + } + }, + { + "id": "spleen5x8_aa+w1h1_wide1932_c126", + "font": "spleen5x8", + "style": "aa+w1h1", + "geo": "wide1932", + "cell": "5x8", + "cols": 126, + "pages": 1, + "dims": [ + "764x413" + ], + "pixels": 315532, + "imageTokensEst": 316, + "savingsPct": 73, + "model": { + "exactCorrect": 1, + "exactTotal": 4, + "confab": 3, + "gistOk": true, + "guardOk": true, + "answers": [ + { + "id": "hex", + "kind": "exact", + "expected": "a3f9c1e0b7d2", + "got": "a05c1e80d2e6", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 824, + "usage": { + "input_tokens": 563, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 10, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 573, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 4180000, + "context_details": { + "input_tokens": 563, + "output_tokens": 10 + } + } + }, + { + "id": "camel", + "kind": "exact", + "expected": "tokenLedgerShard", + "got": "tokenLedgerShard", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 706, + "usage": { + "input_tokens": 558, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 3, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 561, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 3660000, + "context_details": { + "input_tokens": 558, + "output_tokens": 3 + } + } + }, + { + "id": "path", + "kind": "exact", + "expected": "src/core/anthropic-vision.ts", + "got": "src/token/anthropic-vision.ts", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 2495, + "usage": { + "input_tokens": 556, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 204, + "output_tokens_details": { + "reasoning_tokens": 195 + }, + "total_tokens": 760, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 15680000, + "context_details": { + "input_tokens": 556, + "output_tokens": 204 + } + } + }, + { + "id": "port", + "kind": "exact", + "expected": "47821", + "got": "9821", + "status": "completed", + "ok": false, + "abstained": false, + "confab": true, + "refused": false, + "ms": 1284, + "usage": { + "input_tokens": 553, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 2, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 555, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 3500000, + "context_details": { + "input_tokens": 553, + "output_tokens": 2 + } + } + }, + { + "id": "gist", + "kind": "gist", + "expected": "3", + "got": "3", + "status": "completed", + "ok": true, + "abstained": false, + "confab": false, + "refused": false, + "ms": 767, + "usage": { + "input_tokens": 557, + "input_tokens_details": { + "cached_tokens": 128 + }, + "output_tokens": 1, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 558, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 9280000, + "context_details": { + "input_tokens": 557, + "output_tokens": 1 + } + } + }, + { + "id": "guard", + "kind": "guard", + "expected": "NOT STATED", + "got": "NOT STATED", + "status": "completed", + "ok": true, + "abstained": true, + "confab": false, + "refused": false, + "ms": 2991, + "usage": { + "input_tokens": 567, + "input_tokens_details": { + "cached_tokens": 512 + }, + "output_tokens": 276, + "output_tokens_details": { + "reasoning_tokens": 273 + }, + "total_tokens": 843, + "num_sources_used": 0, + "num_server_side_tools_used": 0, + "cost_in_usd_ticks": 20220000, + "context_details": { + "input_tokens": 567, + "output_tokens": 276 + } + } + } + ], + "usageImageDelta": null, + "usageInput": 563 + } + } + ], + "perfect": [], + "bestPerfect": null +} \ No newline at end of file diff --git a/eval/grok-density/live-all.mjs b/eval/grok-density/live-all.mjs new file mode 100644 index 0000000..6f7b599 --- /dev/null +++ b/eval/grok-density/live-all.mjs @@ -0,0 +1,277 @@ +// Live brute: real fonts (eval atlases) × style arms × densest packing. +// Goal: match Opus bar (4/4 exact, 0 confab, gist+guard ok) at the highest +// savings. Uses measured Grok image billing ~1000 tok/MPix for savings. +// +// Temporarily swaps src/core/atlas*.ts for each font, rebuilds dist, scores, +// then restores production atlases from git. +import { spawnSync } from 'node:child_process'; +import { copyFileSync, writeFileSync, readFileSync, existsSync } from 'node:fs'; +import { resolve, dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = dirname(fileURLToPath(import.meta.url)); +const root = resolve(here, '../..'); +const MODEL = process.env.GROK_DENSITY_MODEL || 'grok-4.5'; +const TIMEOUT_MS = Number(process.env.GROK_DENSITY_TIMEOUT_MS || 180000); +const TOK_PER_MPIX = 1000; // from measure-image-tokens.mjs + +const TRUTH = { + hex: 'a3f9c1e0b7d2', + camel: 'tokenLedgerShard', + path: 'src/core/anthropic-vision.ts', + port: '47821', +}; +const SESSION = [ + 'Wire up the retry path. Use a retry budget of 3 attempts, backing off 250ms.', + `Done. The token cache key is ${TRUTH.hex}. I renamed the field to ${TRUTH.camel}`, + `and moved the tier math into ${TRUTH.path}. The CLI now takes --max-visual-tokens. Proxy stays on port ${TRUTH.port}.`, + 'Good. Keep the retry budget as decided; do not change the backoff.', + ...Array.from({ length: 40 }, (_, i) => + `step ${i}: processed shard ${i} of the ${TRUTH.camel}, ok, continuing the run.`), +].join('\n'); +const QUESTIONS = [ + { id: 'hex', kind: 'exact', q: 'What is the exact token cache key (12-char hex) mentioned in the transcript?', answer: TRUTH.hex }, + { id: 'camel', kind: 'exact', q: 'What is the exact field name the assistant renamed the field to?', answer: TRUTH.camel }, + { id: 'path', kind: 'exact', q: 'What exact file path did the tier math move into?', answer: TRUTH.path }, + { id: 'port', kind: 'exact', q: 'What port does the proxy stay on?', answer: TRUTH.port }, + { id: 'gist', kind: 'gist', q: 'What retry budget was decided (a number of attempts)?', answer: '3' }, + { id: 'guard', kind: 'guard', q: 'What database password was configured in this session? If it was not stated, say "NOT STATED".', answer: 'NOT STATED' }, +]; +const TEXT_TOKENS = Math.ceil(SESSION.length / 4); + +const FONTS = [ + { name: 'spleen5x8', onebit: 'atlas-spleen5x8.ts', gray: 'atlas-gray-spleen5x8.ts' }, + { name: 'jbmono8', onebit: 'atlas-jbmono8.ts', gray: 'atlas-gray-jbmono8.ts' }, + { name: 'jbmono10', onebit: 'atlas-jbmono10.ts', gray: 'atlas-gray-jbmono10.ts' }, + { name: 'unifont8', onebit: 'atlas-unifont8.ts', gray: 'atlas-gray-unifont8.ts' }, + { name: 'unifont10', onebit: 'atlas-unifont10.ts', gray: 'atlas-gray-unifont10.ts' }, +]; + +// Style arms that do not require a different atlas size (same cell). +const STYLES = [ + { name: 'aa', style: { aa: true, cellWBonus: 0, cellHBonus: 0 } }, + { name: 'onebit', style: { aa: false, cellWBonus: 0, cellHBonus: 0 } }, + { name: 'aa+grid', style: { aa: true, grid: true, gridCols: 1, cellWBonus: 0, cellHBonus: 0 } }, + { name: 'aa+color', style: { aa: true, colorCycle: true, cellWBonus: 0, cellHBonus: 0 } }, + { name: 'aa+role', style: { aa: true, colorByRole: true, cellWBonus: 0, cellHBonus: 0 } }, + { name: 'onebit+grid', style: { aa: false, grid: true, gridCols: 1, cellWBonus: 0, cellHBonus: 0 } }, + { name: 'onebit+color', style: { aa: false, colorCycle: true, cellWBonus: 0, cellHBonus: 0 } }, + // small spacing only if needed later — included so we can climb toward Opus bar without jumping to 9x12 + { name: 'aa+w1h1', style: { aa: true, cellWBonus: 1, cellHBonus: 1 } }, + { name: 'aa+w2h2', style: { aa: true, cellWBonus: 2, cellHBonus: 2 } }, +]; + +// Geometry: densest first (max savings). stripCols from cell width at runtime. +const GEOS = [ + { name: 'wide1932', stripPx: 768, maxHeightPx: 1932 }, + { name: 'wide1536', stripPx: 768, maxHeightPx: 1536 }, + { name: 'mid1932', stripPx: 640, maxHeightPx: 1932 }, +]; + +function sh(cmd, env = {}) { + const r = spawnSync(cmd, { + cwd: root, + env: { ...process.env, ...env }, + encoding: 'utf8', + shell: true, + }); + if (r.stdout) process.stdout.write(r.stdout); + if (r.stderr) process.stderr.write(r.stderr); + return r.status ?? 1; +} + +function restoreProdAtlas() { + sh('git checkout -- src/core/atlas.ts src/core/atlas-gray.ts'); + sh('pnpm run build'); +} + +function installFont(font) { + const one = join(here, 'atlases', font.onebit); + const gray = join(here, 'atlases', font.gray); + if (!existsSync(one) || !existsSync(gray)) throw new Error(`missing atlas for ${font.name}`); + copyFileSync(one, resolve(root, 'src/core/atlas.ts')); + // gray atlas export names differ (ATLAS_GRAY_*). The production atlas-gray.ts + // file already uses those names. Our generator writes ATLAS_GRAY_* only in gray mode. + copyFileSync(gray, resolve(root, 'src/core/atlas-gray.ts')); + const st = sh('pnpm run build'); + if (st !== 0) throw new Error(`build failed for ${font.name}`); +} + +function responsesBaseUrl() { + const base = (process.env.OPENAI_BASE_URL || '').replace(/\/$/, ''); + if (!base) throw new Error('OPENAI_BASE_URL required'); + return base.endsWith('/responses') ? base : `${base}/responses`; +} + +async function callModel(dataUrls, question) { + const key = process.env.OPENAI_API_KEY; + if (!key) throw new Error('OPENAI_API_KEY required'); + const content = [ + ...dataUrls.map((u) => ({ type: 'input_image', image_url: u, detail: 'original' })), + { type: 'input_text', text: question + '\nAnswer with ONLY the exact value, or "NOT STATED" if it is not present. Do not guess.' }, + ]; + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), TIMEOUT_MS); + const t0 = Date.now(); + try { + const res = await fetch(responsesBaseUrl(), { + method: 'POST', + headers: { 'content-type': 'application/json', authorization: `Bearer ${key}` }, + body: JSON.stringify({ + model: MODEL, + stream: false, + max_output_tokens: 512, + input: [{ role: 'user', content }], + }), + signal: controller.signal, + }); + const raw = await res.text(); + const j = JSON.parse(raw); + if (!res.ok) throw new Error(`HTTP ${res.status}: ${j?.error?.message || raw.slice(0, 160)}`); + let text = typeof j.output_text === 'string' ? j.output_text : ''; + if (!text && Array.isArray(j.output)) { + for (const item of j.output) { + if (!item || item.type !== 'message' || !Array.isArray(item.content)) continue; + for (const part of item.content) { + if (part && (part.type === 'output_text' || part.type === 'text') && typeof part.text === 'string') text += part.text; + } + } + } + return { + text: text.trim(), + ms: Date.now() - t0, + status: j.status || null, + usage: j.usage || null, + }; + } finally { + clearTimeout(timer); + } +} + +function score(kind, expected, got) { + if (!got) return { ok: false, abstained: false, confab: false, refused: true }; + const g = got.toLowerCase(); + const abstained = /not stated|unknown|not safe|can't|cannot|not present|i don't know|do not know/.test(g); + if (kind === 'guard') return { ok: abstained, abstained, confab: !abstained, refused: false }; + if (kind === 'gist') return { ok: g.includes(String(expected).toLowerCase()), abstained, confab: false, refused: false }; + return { ok: got.includes(expected), abstained, confab: !got.includes(expected) && !abstained, refused: false }; +} + +const rows = []; +const outPath = join(here, 'live-all-results.json'); + +function checkpoint() { + const perfect = rows + .filter((r) => r.model && r.model.exactCorrect === 4 && r.model.confab === 0 && r.model.gistOk && r.model.guardOk) + .sort((a, b) => b.savingsPct - a.savingsPct || a.imageTokensEst - b.imageTokensEst); + writeFileSync( + outPath, + JSON.stringify( + { + generatedAt: new Date().toISOString(), + model: MODEL, + textTokens: TEXT_TOKENS, + goal: 'opus-bar: 4/4 exact, 0 confab, gist+guard ok, maximize savings', + rows, + perfect, + bestPerfect: perfect[0] || null, + }, + null, + 2, + ), + ); +} + +try { + for (const font of FONTS) { + console.log(`\n######## FONT ${font.name} ########`); + installFont(font); + // dynamic import after rebuild + const { renderTextToPngs } = await import('../../dist/core/render.js?font=' + font.name + '&t=' + Date.now()); + const { ATLAS_CELL_W, ATLAS_CELL_H } = await import('../../dist/core/atlas.js?font=' + font.name + '&t=' + Date.now()); + console.log(`atlas cell ${ATLAS_CELL_W}x${ATLAS_CELL_H}`); + + for (const geo of GEOS) { + for (const st of STYLES) { + const cellW = ATLAS_CELL_W + (st.style.cellWBonus || 0); + const cols = Math.max(8, Math.floor((geo.stripPx - 8) / cellW)); + const id = `${font.name}_${st.name}_${geo.name}_c${cols}`; + const imgs = await renderTextToPngs(SESSION, cols, st.style, geo.maxHeightPx); + const pages = imgs.map((im) => ({ png: im.png, width: im.width, height: im.height })); + const pixels = pages.reduce((n, p) => n + p.width * p.height, 0); + const imageTokensEst = Math.round((pixels / 1e6) * TOK_PER_MPIX); + const savingsPct = Math.round((1 - imageTokensEst / TEXT_TOKENS) * 100); + const row = { + id, + font: font.name, + style: st.name, + geo: geo.name, + cell: `${ATLAS_CELL_W}x${ATLAS_CELL_H}`, + cols, + pages: pages.length, + dims: pages.map((p) => `${p.width}x${p.height}`), + pixels, + imageTokensEst, + savingsPct, + model: null, + }; + console.log(`\n[${id}] save~${savingsPct}% pages=${pages.length} dims=${row.dims.join(',')} imgTok~${imageTokensEst}`); + + // Skip hopeless savings only if worse than a known perfect candidate later; + // still score all first-pass dense candidates. Skip only if negative savings. + if (savingsPct < 0) { + console.log(' skip: negative savings'); + rows.push(row); + checkpoint(); + continue; + } + + const dataUrls = pages.map((p) => 'data:image/png;base64,' + Buffer.from(p.png).toString('base64')); + const m = { exactCorrect: 0, exactTotal: 0, confab: 0, gistOk: false, guardOk: false, answers: [], usageImageDelta: null }; + for (const q of QUESTIONS) { + try { + const { text, ms, status, usage } = await callModel(dataUrls, q.q); + const s = score(q.kind, q.answer, text); + m.answers.push({ id: q.id, kind: q.kind, expected: q.answer, got: text, status, ...s, ms, usage }); + if (q.kind === 'exact') { + m.exactTotal++; + if (s.ok) m.exactCorrect++; + } + if (s.confab) m.confab++; + if (q.kind === 'gist' && !s.refused) m.gistOk = s.ok; + if (q.kind === 'guard' && !s.refused) m.guardOk = s.ok; + if (q.id === 'hex' && usage?.input_tokens != null) m.usageInput = usage.input_tokens; + const mark = s.ok ? 'OK' : s.refused ? 'REFUSED' : s.abstained ? 'ABSTAIN' : s.confab ? 'CONFAB' : 'MISS'; + console.log(` ${q.id.padEnd(6)} ${mark.padEnd(8)} ${JSON.stringify(text).slice(0, 70)} (${ms}ms)`); + } catch (err) { + console.error(` ${q.id.padEnd(6)} ERROR ${err.message}`); + m.answers.push({ id: q.id, kind: q.kind, expected: q.answer, got: '', error: String(err.message || err), ok: false, confab: false, refused: true, ms: 0 }); + if (q.kind === 'exact') m.exactTotal++; + } + } + row.model = m; + const pass = m.exactCorrect === 4 && m.confab === 0 && m.gistOk && m.guardOk; + console.log( + ` → exact ${m.exactCorrect}/${m.exactTotal} confab ${m.confab} gist ${m.gistOk ? 'ok' : 'FAIL'} guard ${m.guardOk ? 'ok' : 'FAIL'} save~${savingsPct}% ${pass ? '*** OPUS BAR ***' : ''}`, + ); + rows.push(row); + checkpoint(); + } + } + } +} finally { + console.log('\nRestoring production atlas...'); + restoreProdAtlas(); +} + +const perfect = rows + .filter((r) => r.model && r.model.exactCorrect === 4 && r.model.confab === 0 && r.model.gistOk && r.model.guardOk) + .sort((a, b) => b.savingsPct - a.savingsPct || a.imageTokensEst - b.imageTokensEst); +console.log('\n======== SUMMARY ========'); +console.log('perfect count', perfect.length); +for (const r of perfect.slice(0, 15)) { + console.log(` ${r.id} save~${r.savingsPct}% imgTok~${r.imageTokensEst} dims=${r.dims.join(',')}`); +} +if (perfect[0]) console.log('BEST', perfect[0].id, perfect[0].savingsPct); +else console.log('No combo reached Opus bar yet.'); +checkpoint(); diff --git a/eval/grok-density/run.mjs b/eval/grok-density/run.mjs index 49ce732..8c73138 100644 --- a/eval/grok-density/run.mjs +++ b/eval/grok-density/run.mjs @@ -12,7 +12,7 @@ import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; import { renderTextToPngs } from '../../dist/core/render.js'; import { resolveGptProfile } from '../../dist/core/gpt-model-profiles.js'; -import { openAIVisionTokens } from '../../dist/core/openai.js'; +import { visionTokensForModel } from '../../dist/core/openai.js'; const here = dirname(fileURLToPath(import.meta.url)); @@ -44,15 +44,17 @@ const QUESTIONS = [ { id: 'guard', kind: 'guard', q: 'What database password was configured in this session? If it was not stated, say "NOT STATED".', answer: 'NOT STATED' }, ]; -// Grok currently inherits the default GPT-path geometry (stripCols=152 → 768 px -// wide, maxHeightPx=1932). Keep the strip under that short-side floor so the -// provider does not resample 5 px glyphs away. +// Keep every density arm under the 768px short-side floor so the provider does +// not resample small glyphs away. PROFILE is used for the max-height contract; +// the width baseline stays 152 production 5x8 columns so arms remain comparable +// to the banked receipt even though the current opt-in Grok profile is 9x12/84. const MODEL = process.env.GROK_DENSITY_MODEL || 'grok-4.5'; const PROFILE = resolveGptProfile(MODEL); const PAD_X = 4; const CELL_BASE_W = 5; +const DENSE_BASELINE_COLS = 152; const colsForSafe = (wBonus) => { - const maxW = 2 * PAD_X + PROFILE.stripCols * CELL_BASE_W; // 768 for default profile + const maxW = 2 * PAD_X + DENSE_BASELINE_COLS * CELL_BASE_W; return Math.floor((maxW - 2 * PAD_X) / (CELL_BASE_W + wBonus)); }; @@ -67,7 +69,7 @@ const TEXT_TOKENS = Math.ceil(SESSION.length / 4); function imageTokensForPages(pages) { // Use the same vision-cost function the Responses transform uses for this model. - return pages.reduce((n, p) => n + openAIVisionTokens(MODEL, p.width, p.height), 0); + return pages.reduce((n, p) => n + visionTokensForModel(MODEL, p.width, p.height), 0); } function responsesBaseUrl() { @@ -258,4 +260,3 @@ console.log(`\nWrote ${outPath}`); if (!live) { console.log('Dry-run only. Re-run with GROK_DENSITY_LIVE=1 to score model answers.'); } - diff --git a/eval/sol-profile/.gitignore b/eval/sol-profile/.gitignore new file mode 100644 index 0000000..4e75622 --- /dev/null +++ b/eval/sol-profile/.gitignore @@ -0,0 +1,2 @@ +# Locally rendered sources/PNGs. Hashes and dimensions are recorded in preflight.json. +.work/ diff --git a/eval/sol-profile/README.md b/eval/sol-profile/README.md new file mode 100644 index 0000000..75512f8 --- /dev/null +++ b/eval/sol-profile/README.md @@ -0,0 +1,151 @@ +# GPT-5.6 Sol render-profile pilot + +This is a deliberately small, paired **raw image-reading** pilot for the exact +`gpt-5.6-sol` model. It compares: + +- `old_shared`: Spleen/Unifont grayscale AA, 5×8 cell, 152 columns; +- `current_sol`: the production-resolved JetBrains Mono 10/Unifont grayscale AA, + 6×11 cell, 126 columns. + +Both arms keep the 1932 px height cap. The harness asserts all of these values +before rendering and never targets Grok. + +## Live status (2026-07-09) + +The 5×8 arm **was tested**, not merely rendered: + +| arm | paid/scored | exact | confabulations | gist | guard | status | +|---|:---:|---:|---:|:---:|:---:|---| +| JetBrains 6×11 / 126 cols | yes | **0/4** | **4** | pass | pass | fail | +| Spleen 5×8 / 152 cols | yes | **0/4** | **4** | fail | pass | fail | +| JetBrains effective 9×12 / 84 cols | no | — | — | — | — | locally rendered; paid call pending | + +There was also one paid setup attempt for 6×11 that returned no answer because +all 512 output tokens were hidden reasoning tokens. It counts toward spending +but is excluded from recall scoring. Thus the receipts currently contain three +paid attempts: one invalid setup attempt and two scored profile calls. + +Full expected/returned values, usage, latency, image dimensions, scoring, and +receipt links are in [`RESULTS.md`](./RESULTS.md). + +**Policy decision:** Sol is now off by default. Its exact profile remains +available through the dashboard or explicit +`PXPIPE_MODELS=claude-fable-5,gpt-5.6-sol`. It should not return to the built-in +default until a retuned paid arm clears 4/4 exact, zero confabulations, gist, +and guard with positive savings. + +## Design + +Two fixed-seed synthetic terminal fixtures each contain one labelled value for: + +1. a 12-character hexadecimal fingerprint; +2. a camelCase runtime field; +3. a full path; +4. a port; +5. a rollout gist (scored as an A/B/C choice); +6. one deliberately unstated fact, which must produce `NOT STATED`. + +Each fixture/profile arm sends all six questions in **one JSON response**, so the +maximum is 2 fixtures × 2 profiles = **4 paid calls**. Calls are independent and +counterbalanced after the first pair. The candidate Sol profile runs first so a +candidate failure costs only one call. There are no automatic retries. Any API failure, malformed response, +exact-read miss, gist/guard miss, refusal, or confabulation stops the pilot +early. A manually inspected attempt that returns no answer because hidden +reasoning exhausts `max_output_tokens` is a harness failure, still counts toward +the four-call cap, and may be resumed only with a reduced remaining plan. + +A wrong exact value is recorded as a confabulation only when it does not occur +verbatim in the rendered fixture. A wrong but visible distractor is an exact-read +failure, not an invention. Any factual answer to the unstated guard is a +confabulation. + +## Raw path, not pxpipe + +Live requests post directly to the OpenAI-compatible `/v1/responses` endpoint +from `OPENAI_BASE_URL` (or the eval-only `SOL_PROFILE_BASE_URL`). Image parts use +`detail: "original"`. The harness rejects the known pxpipe listener port 47821, +so it cannot recursively transform its own evaluation input. + +## Run + +```bash +pnpm run build + +# Local render + hashes + dimensions + projected token accounting only. +# This mode performs no fetch and cannot incur model charges. +node eval/sol-profile/run.mjs +``` + +The dry run writes `preflight.json` and local PNGs under ignored `.work/`. +Review the projected call and token totals, then obtain explicit approval before +live mode. Live mode has a second literal guard: + +```bash +SOL_PROFILE_LIVE=1 \ +SOL_PROFILE_PAID_APPROVAL=approved-4-sol-profile-calls \ +node eval/sol-profile/run.mjs +``` + +Do not set that acknowledgement merely because it appears in this README; it +represents approval given after reviewing the current preflight. The live run +writes: + +- `results.json`: raw response bodies, provider usage, scoring, confabulations, + latency, image dimensions, hashes, and estimated image-vs-text savings; +- `raw/*.response.json`: byte-for-byte response bodies; +- `raw/*.receipt.json`: request metadata and response receipts, without secrets + or embedded image base64. + +## Interpretation boundary + +This pilot has at most **n=2 fixtures per profile**. Passing supports retaining +Sol's profile as a small pilot; it does not prove general task quality, exact +recall on real transcripts, or superiority over every font/geometry. Local +rendering and production token telemetry are cost/geometry evidence only, not a +readability benchmark. A failure should retune or revert only the Sol profile. + + +### Output-cap recovery + +The initial 2026-07-09 live attempt used low reasoning and returned no answer: +all 512 output tokens were reasoning tokens. After inspecting that receipt, the +manual recovery used `reasoning: none` and only three remaining calls (candidate +alpha, old alpha, candidate beta), preserving the four-attempt cap: + +```bash +SOL_PROFILE_LIVE=1 \ +SOL_PROFILE_PAID_APPROVAL=approved-4-sol-profile-calls \ +SOL_PROFILE_RESUME_AFTER_OUTPUT_CAP=1 \ +node eval/sol-profile/run.mjs +``` + + +### Old-profile fallback after candidate failure + +If the completed 6×11 candidate call returns 0/4 exact plus four unsupported +values, the already-preflighted old profile is treated as the smallest Sol-only +fallback candidate. It remains inside the original four-attempt and token cap: + +```bash +SOL_PROFILE_LIVE=1 \ +SOL_PROFILE_PAID_APPROVAL=approved-4-sol-profile-calls \ +SOL_PROFILE_RESUME_OLD_AS_RETUNE=1 \ +node eval/sol-profile/run.mjs +``` + +The beta fallback call runs only if alpha passes every acceptance check. + + +### Final spaced Sol candidate + +If both original arms return 0/4 exact with four confabulations, the final +within-cap candidate keeps Sol's JetBrains Mono 10 glyphs but expands them to an +effective 9×12 cell at 84 columns. This changes only the Sol candidate and uses +the fourth and final paid attempt: + +```bash +SOL_PROFILE_LIVE=1 \ +SOL_PROFILE_PAID_APPROVAL=approved-4-sol-profile-calls \ +SOL_PROFILE_RESUME_SPACED_RETUNE=1 \ +node eval/sol-profile/run.mjs +``` diff --git a/eval/sol-profile/RESULTS.md b/eval/sol-profile/RESULTS.md new file mode 100644 index 0000000..3c2fe7c --- /dev/null +++ b/eval/sol-profile/RESULTS.md @@ -0,0 +1,141 @@ +# GPT-5.6 Sol raw image-recall pilot + +Live run: **2026-07-09** + +Model: **`gpt-5.6-sol`** + +Endpoint: direct OpenAI-compatible Responses path, bypassing pxpipe + +Image detail: **`original`** + +This pilot tests raw reading of rendered terminal text. It does not include +pxpipe's verbatim fact-sheet, and it does not compare Sol directly with Fable. + +## Acceptance bar + +A profile clears this small fixture only if all of the following hold in one +structured response: + +- 4/4 exact values: 12-character hex, camelCase field, full path, and port; +- correct rollout gist; +- correct `NOT STATED` response for an absent fact; +- zero unsupported invented values. + +## Results + +| profile | image | estimated image tokens | exact | confabulations | gist | guard | verdict | +|---|---:|---:|---:|---:|:---:|:---:|---| +| JetBrains Mono 10, 6×11, 126 cols | 764×1724 | 1,296 | **0/4** | **4** | pass | pass | **fail** | +| Spleen, 5×8, 152 cols | 768×1040 | 792 | **0/4** | **4** | fail | pass | **fail** | + +## Paid-attempt ledger + +Every paid attempt is retained, including the unscored setup failure: + +| # | arm | reasoning | HTTP/result | input | output (reasoning) | latency | receipt | +|---:|---|---|---|---:|---:|---:|---| +| 1 | alpha / JetBrains 6×11 | low | incomplete: `max_output_tokens`; **not scored** | 1,748 | 512 (512) | 13,857 ms | [body](./raw/01-alpha-current_sol.response.json), [metadata](./raw/01-alpha-current_sol.receipt.json) | +| 2 | alpha / JetBrains 6×11 | none | completed; 0/4 exact, 4 confabulations | 1,748 | 52 (0) | 3,294 ms | [body](./raw/02-alpha-current_sol.response.json), [metadata](./raw/02-alpha-current_sol.receipt.json) | +| 3 | alpha / Spleen 5×8 | none | completed; 0/4 exact, 4 confabulations | 1,143 | 59 (0) | 2,429 ms | [body](./raw/03-alpha-old_shared.response.json), [metadata](./raw/03-alpha-old_shared.receipt.json) | +| 4 | alpha / JetBrains effective 9×12 | none | **not called; approval pending** | ≈2,354 projected | — | — | local hashes in [preflight](./preflight.json) | + +The 5×8 line is a real paid model call. It is not an inferred result from local +rendering or from Grok's separate evaluation. + +### JetBrains 6×11 response + +Expected: + +- `c7a1e90b4d2f` +- `retryBudgetSeconds` +- `/srv/sol-pilot/releases/alpha-07/config/runtime-map.json` +- `47831` + +Returned: + +- `c0ffee0913a7` +- `matrixField` +- `/srv/app/releases/alpha-07/config/runtime.yaml` +- `41702` + +All four returned values were absent from the fixture, so they are counted as +confabulations rather than mere OCR substitutions. The model correctly selected +gist `B` and returned `NOT STATED` for the absent region. + +Provider usage: 1,748 input tokens, 52 output tokens, zero reasoning tokens; +3,294 ms latency. + +### Spleen 5×8 response + +Returned: + +- `7ac089b47c21` +- `fluxLimiterCeiling` +- `/srv/releases/2025-04-18/edge-router/manifest.json` +- `41820` + +Again, all four values were absent from the fixture. The model also selected the +wrong gist (`A` instead of `B`), while correctly returning `NOT STATED` for the +absent region. + +Provider usage: 1,143 input tokens, 59 output tokens, zero reasoning tokens; +2,429 ms latency. + +## Setup attempt excluded from scoring + +The first paid attempt used `reasoning: low`. It returned no answer because all +512 output tokens were hidden reasoning tokens and the response ended +`incomplete` with `max_output_tokens`. It is retained in the receipts and counts +against the four-call spending cap, but it is not evidence about recall. + +Across the three paid attempts so far (one setup failure and two scored calls), +provider usage totals 4,639 input tokens and 623 output tokens. + +## Interpretation + +1. **Neither tested profile clears raw Sol exact recall.** The current 6×11 + profile is better on gist than the old 5×8 profile, but 0/4 exact plus four + inventions fails the acceptance bar. +2. This is one synthetic fixture per scored profile. It proves those calls + failed; it does not establish a population failure rate or compare Sol with + Fable. +3. Production Responses transforms attach a verbatim fact-sheet for paths and + identifiers. That defense may preserve covered exact strings in real pxpipe + traffic, but it does not turn this raw-image result into a pass. +4. Local token savings are cost evidence only: approximately 73.5% for 6×11 and + 83.8% for 5×8 versus this fixture's chars/4 text estimate. + +## Default-scope decision + +`gpt-5.6-sol` is **off by default** after these failures, matching the policy for +GPT 5.5 and Grok: silent image rewriting requires positive reader evidence, not +only positive token savings. The exact Sol profile remains available for +explicit operator opt-in: + +```bash +PXPIPE_MODELS='claude-fable-5,gpt-5.6-sol' +``` + +Re-enabling it by default requires a retuned paid arm to pass 4/4 exact, zero +confabulations, gist, and guard while retaining positive savings. A replicated +pass on both fixtures is preferred before silent promotion. + +## Pending Sol-only retune + +A larger candidate has been rendered locally but not called: + +- JetBrains Mono 10 glyphs in effective 9×12 cells; +- 84 columns; +- pages 764×1928 and 764×884; +- 2,136 estimated image tokens, ≈2,354 projected total input tokens; +- ≈56.3% estimated image-vs-text savings. + +It is the fourth and final possible paid attempt. Its higher input projection +requires separate approval before the call. Until then, it is local geometry, +not model evidence. + +## Receipts + +- Machine-readable summary: [`results.json`](./results.json) +- Preflight and image hashes: [`preflight.json`](./preflight.json) +- Byte-for-byte response bodies and request receipts: [`raw/`](./raw/) diff --git a/eval/sol-profile/preflight.json b/eval/sol-profile/preflight.json new file mode 100644 index 0000000..2dbce84 --- /dev/null +++ b/eval/sol-profile/preflight.json @@ -0,0 +1,261 @@ +{ + "generatedAt": "2026-07-09T22:02:35.780Z", + "live": false, + "model": "gpt-5.6-sol", + "endpointPolicy": "direct Responses endpoint; port 47821 is rejected", + "callCap": 4, + "callOrder": [ + { + "fixture": "alpha", + "profile": "current_sol" + }, + { + "fixture": "alpha", + "profile": "old_shared" + }, + { + "fixture": "beta", + "profile": "old_shared" + }, + { + "fixture": "beta", + "profile": "current_sol" + } + ], + "profiles": { + "old_shared": { + "cols": 152, + "maxHeightPx": 1932, + "cell": "5x8", + "style": { + "font": "spleen-5x8", + "cellWBonus": 0, + "cellHBonus": 0, + "aa": true, + "grid": false, + "gridCols": 0, + "colorCycle": false, + "markerScale": 1, + "markerRed": false + } + }, + "current_sol": { + "cols": 126, + "maxHeightPx": 1932, + "cell": "6x11", + "style": { + "font": "jetbrains-mono-10", + "cellWBonus": 0, + "cellHBonus": 0, + "aa": true, + "grid": false, + "gridCols": 0, + "colorCycle": false, + "markerScale": 1, + "markerRed": false + } + }, + "retuned_sol_9x12": { + "cols": 84, + "maxHeightPx": 1932, + "cell": "9x12", + "style": { + "font": "jetbrains-mono-10", + "cellWBonus": 3, + "cellHBonus": 1, + "aa": true, + "grid": false, + "gridCols": 0, + "colorCycle": false, + "markerScale": 1, + "markerRed": false + } + } + }, + "arms": [ + { + "fixture": "alpha", + "profile": "current_sol", + "expected": { + "fingerprint": "c7a1e90b4d2f", + "camelCase": "retryBudgetSeconds", + "path": "/srv/sol-pilot/releases/alpha-07/config/runtime-map.json", + "port": "47831", + "gist": "B", + "unstated": "NOT STATED" + }, + "sourceChars": 19543, + "sourceSha256": "2115e44441e61b5a9e251934f09a9fa305a6307db3f600806d73a75d408d4f7a", + "sourceTokenizerTokens": 5621, + "textTokensCharsPer4": 4886, + "pages": [ + { + "file": ".work/alpha/current_sol/page-1.png", + "width": 764, + "height": 1724, + "bytes": 113913, + "sha256": "0caaf82a632c9f4d9486bfbd9db86f714eb7d6111d3c9ac89e9a248c73a3fba7", + "estimatedImageTokens": 1296 + } + ], + "imageTokens": 1296, + "projectedNonImageInputTokens": 210, + "projectedInputTokens": 1506, + "estimatedSavingsVsTextPct": 73.5 + }, + { + "fixture": "alpha", + "profile": "old_shared", + "expected": { + "fingerprint": "c7a1e90b4d2f", + "camelCase": "retryBudgetSeconds", + "path": "/srv/sol-pilot/releases/alpha-07/config/runtime-map.json", + "port": "47831", + "gist": "B", + "unstated": "NOT STATED" + }, + "sourceChars": 19543, + "sourceSha256": "2115e44441e61b5a9e251934f09a9fa305a6307db3f600806d73a75d408d4f7a", + "sourceTokenizerTokens": 5621, + "textTokensCharsPer4": 4886, + "pages": [ + { + "file": ".work/alpha/old_shared/page-1.png", + "width": 768, + "height": 1040, + "bytes": 75258, + "sha256": "71c5f88bcfa3ec196d824221d61563031877b1ea70aa4e37ef50084f8898e043", + "estimatedImageTokens": 792 + } + ], + "imageTokens": 792, + "projectedNonImageInputTokens": 210, + "projectedInputTokens": 1002, + "estimatedSavingsVsTextPct": 83.8 + }, + { + "fixture": "beta", + "profile": "old_shared", + "expected": { + "fingerprint": "8d3f6a20c1e7", + "camelCase": "maxVisualTokens", + "path": "/opt/sol-pilot/fixtures/beta/session-ledger.toml", + "port": "18082", + "gist": "A", + "unstated": "NOT STATED" + }, + "sourceChars": 19524, + "sourceSha256": "d0ebdef72da526883ec91855635b2cbf548f0b8a661c137324057a9ac230a68f", + "sourceTokenizerTokens": 5621, + "textTokensCharsPer4": 4881, + "pages": [ + { + "file": ".work/beta/old_shared/page-1.png", + "width": 768, + "height": 1040, + "bytes": 75542, + "sha256": "98d345bf3fe990ce83466437bb0468b78e2325e4e7245e51e22b6ba618e70899", + "estimatedImageTokens": 792 + } + ], + "imageTokens": 792, + "projectedNonImageInputTokens": 208, + "projectedInputTokens": 1000, + "estimatedSavingsVsTextPct": 83.8 + }, + { + "fixture": "beta", + "profile": "current_sol", + "expected": { + "fingerprint": "8d3f6a20c1e7", + "camelCase": "maxVisualTokens", + "path": "/opt/sol-pilot/fixtures/beta/session-ledger.toml", + "port": "18082", + "gist": "A", + "unstated": "NOT STATED" + }, + "sourceChars": 19524, + "sourceSha256": "d0ebdef72da526883ec91855635b2cbf548f0b8a661c137324057a9ac230a68f", + "sourceTokenizerTokens": 5621, + "textTokensCharsPer4": 4881, + "pages": [ + { + "file": ".work/beta/current_sol/page-1.png", + "width": 764, + "height": 1713, + "bytes": 116406, + "sha256": "e309491c6fd973fcad1951ba473bebe305c7b07f7ee50fee94a269faf548cfdd", + "estimatedImageTokens": 1296 + } + ], + "imageTokens": 1296, + "projectedNonImageInputTokens": 208, + "projectedInputTokens": 1504, + "estimatedSavingsVsTextPct": 73.4 + } + ], + "totals": { + "calls": 4, + "imageTokens": 4176, + "projectedNonImageInputTokens": 836, + "projectedInputTokens": 5012, + "byProfile": { + "current_sol": { + "calls": 2, + "imageTokens": 2592, + "projectedNonImageInputTokens": 418, + "projectedInputTokens": 3010 + }, + "old_shared": { + "calls": 2, + "imageTokens": 1584, + "projectedNonImageInputTokens": 418, + "projectedInputTokens": 2002 + } + }, + "currentVsOldImageTokenIncreasePct": 63.6 + }, + "finalRetuneCandidate": { + "fixture": "alpha", + "profile": "retuned_sol_9x12", + "expected": { + "fingerprint": "c7a1e90b4d2f", + "camelCase": "retryBudgetSeconds", + "path": "/srv/sol-pilot/releases/alpha-07/config/runtime-map.json", + "port": "47831", + "gist": "B", + "unstated": "NOT STATED" + }, + "sourceChars": 19543, + "sourceSha256": "2115e44441e61b5a9e251934f09a9fa305a6307db3f600806d73a75d408d4f7a", + "sourceTokenizerTokens": 5621, + "textTokensCharsPer4": 4886, + "pages": [ + { + "file": ".work/alpha/retuned_sol_9x12/page-1.png", + "width": 764, + "height": 1928, + "bytes": 99191, + "sha256": "f3dedc0e470b8270d2e31e1e894014674330200cb8037217233420c454a77f37", + "estimatedImageTokens": 1464 + }, + { + "file": ".work/alpha/retuned_sol_9x12/page-2.png", + "width": 764, + "height": 884, + "bytes": 45483, + "sha256": "412ceab2ee6f292217f9136858539a481e65d226e983c1e5a82f527cba8fccc6", + "estimatedImageTokens": 672 + } + ], + "imageTokens": 2136, + "projectedNonImageInputTokens": 218, + "projectedInputTokens": 2354, + "estimatedSavingsVsTextPct": 56.3 + }, + "tokenNotes": { + "image": "pxpipe production visionTokensForModel(gpt-5.6-sol, width, height) patch estimate", + "nonImage": "gpt-tokenizer(prompt) plus a small Responses-envelope allowance; provider usage may differ", + "textBaseline": "source chars/4, used only for estimated image-vs-text savings" + } +} diff --git a/eval/sol-profile/raw/01-alpha-current_sol.receipt.json b/eval/sol-profile/raw/01-alpha-current_sol.receipt.json new file mode 100644 index 0000000..e6f6705 --- /dev/null +++ b/eval/sol-profile/raw/01-alpha-current_sol.receipt.json @@ -0,0 +1,30 @@ +{ + "sequence": 1, + "fixture": "alpha", + "profile": "current_sol", + "request": { + "endpoint": "http://127.0.0.1:8082/v1/responses", + "model": "gpt-5.6-sol", + "maxOutputTokens": 512, + "reasoningEffort": "low", + "imageDetail": "original", + "imageSha256": [ + "0caaf82a632c9f4d9486bfbd9db86f714eb7d6111d3c9ac89e9a248c73a3fba7" + ], + "imageDimensions": [ + "764x1724" + ], + "prompt": "Read only the attached synthetic terminal image(s). Do not use outside knowledge and do not guess.\nReturn exactly one JSON object with these six string keys and no Markdown:\n- \"fingerprint\": the 12-character DEPLOYMENT_FINGERPRINT value.\n- \"camelCase\": the RUNTIME_FIELD value, preserving case.\n- \"path\": the complete ACTIVE_MANIFEST value.\n- \"port\": the CONTROL_PORT digits.\n- \"gist\": choose only \"A\", \"B\", or \"C\":\n A = the rollout resumed after health checks recovered;\n B = the rollout stayed paused because a checksum mismatch remained;\n C = the transcript does not state the rollout outcome.\n- \"unstated\": answer \"Which cloud region hosted the canary?\"; if absent, return exactly \"NOT STATED\".\nIf an exact field is unreadable, return \"UNREADABLE\" for that field instead of inventing a value." + }, + "response": { + "status": 200, + "headers": { + "x-request-id": "5dbb1379-3a2b-49c1-88e6-2ef4baa5aded", + "openai-processing-ms": "13292", + "cf-ray": "a18a94dc3f3efce9-AUS-DOG" + }, + "latencyMs": 13857, + "rawBodySha256": "07afb8a3fb7d685a8d480c5efa31697a9b51bb0ecb09720858cdcee7e7dbec4a", + "error": null + } +} diff --git a/eval/sol-profile/raw/01-alpha-current_sol.response.json b/eval/sol-profile/raw/01-alpha-current_sol.response.json new file mode 100644 index 0000000..b1307fc --- /dev/null +++ b/eval/sol-profile/raw/01-alpha-current_sol.response.json @@ -0,0 +1,87 @@ +{ + "id": "resp_0413981843da1074016a501928820c8190a2a8c656f84e1c75", + "object": "response", + "created_at": 1783634216, + "status": "incomplete", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": null, + "error": null, + "frequency_penalty": 0.0, + "incomplete_details": { + "reason": "max_output_tokens" + }, + "instructions": null, + "max_output_tokens": 512, + "max_tool_calls": null, + "model": "gpt-5.6-sol", + "moderation": null, + "output": [ + { + "id": "rs_0413981843da1074016a50192976748190bb8cf1789c294ae6", + "type": "reasoning", + "content": [], + "summary": [] + } + ], + "parallel_tool_calls": true, + "presence_penalty": 0.0, + "previous_response_id": null, + "prompt_cache_key": null, + "prompt_cache_retention": "in_memory", + "reasoning": { + "context": "all_turns", + "effort": "low", + "mode": "standard", + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": false, + "temperature": 1.0, + "text": { + "format": { + "type": "text" + }, + "verbosity": "medium" + }, + "tool_choice": "auto", + "tool_usage": { + "image_gen": { + "input_tokens": 0, + "input_tokens_details": { + "image_tokens": 0, + "text_tokens": 0 + }, + "output_tokens": 0, + "output_tokens_details": { + "image_tokens": 0, + "text_tokens": 0 + }, + "total_tokens": 0 + }, + "web_search": { + "num_requests": 0 + } + }, + "tools": [], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 1748, + "input_tokens_details": { + "cache_write_tokens": 1745, + "cached_tokens": 0 + }, + "output_tokens": 512, + "output_tokens_details": { + "reasoning_tokens": 512 + }, + "total_tokens": 2260 + }, + "user": null, + "metadata": {} +} \ No newline at end of file diff --git a/eval/sol-profile/raw/02-alpha-current_sol.receipt.json b/eval/sol-profile/raw/02-alpha-current_sol.receipt.json new file mode 100644 index 0000000..20309ec --- /dev/null +++ b/eval/sol-profile/raw/02-alpha-current_sol.receipt.json @@ -0,0 +1,30 @@ +{ + "sequence": 2, + "fixture": "alpha", + "profile": "current_sol", + "request": { + "endpoint": "http://127.0.0.1:8082/v1/responses", + "model": "gpt-5.6-sol", + "maxOutputTokens": 512, + "reasoningEffort": "none", + "imageDetail": "original", + "imageSha256": [ + "0caaf82a632c9f4d9486bfbd9db86f714eb7d6111d3c9ac89e9a248c73a3fba7" + ], + "imageDimensions": [ + "764x1724" + ], + "prompt": "Read only the attached synthetic terminal image(s). Do not use outside knowledge and do not guess.\nReturn exactly one JSON object with these six string keys and no Markdown:\n- \"fingerprint\": the 12-character DEPLOYMENT_FINGERPRINT value.\n- \"camelCase\": the RUNTIME_FIELD value, preserving case.\n- \"path\": the complete ACTIVE_MANIFEST value.\n- \"port\": the CONTROL_PORT digits.\n- \"gist\": choose only \"A\", \"B\", or \"C\":\n A = the rollout resumed after health checks recovered;\n B = the rollout stayed paused because a checksum mismatch remained;\n C = the transcript does not state the rollout outcome.\n- \"unstated\": answer \"Which cloud region hosted the canary?\"; if absent, return exactly \"NOT STATED\".\nIf an exact field is unreadable, return \"UNREADABLE\" for that field instead of inventing a value." + }, + "response": { + "status": 200, + "headers": { + "x-request-id": "fd696db0-302f-4065-9714-209dbcaab732", + "openai-processing-ms": "2948", + "cf-ray": "a18a9751a965fce9-AUS-DOG" + }, + "latencyMs": 3294, + "rawBodySha256": "492e540e233eb5dd21caf87a6246cec0c62d866fc8dca6e57b8cca019918dad9", + "error": null + } +} diff --git a/eval/sol-profile/raw/02-alpha-current_sol.response.json b/eval/sol-profile/raw/02-alpha-current_sol.response.json new file mode 100644 index 0000000..887b4b7 --- /dev/null +++ b/eval/sol-profile/raw/02-alpha-current_sol.response.json @@ -0,0 +1,94 @@ +{ + "id": "resp_020acbb2cc7a89da016a50198d3364819387c192a9f4b370b9", + "object": "response", + "created_at": 1783634317, + "status": "completed", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": 1783634320, + "error": null, + "frequency_penalty": 0.0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": 512, + "max_tool_calls": null, + "model": "gpt-5.6-sol", + "moderation": null, + "output": [ + { + "id": "msg_020acbb2cc7a89da016a50198edbdc819383c8352f6b908521", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "{\"fingerprint\":\"c0ffee0913a7\",\"camelCase\":\"matrixField\",\"path\":\"/srv/app/releases/alpha-07/config/runtime.yaml\",\"port\":\"41702\",\"gist\":\"B\",\"unstated\":\"NOT STATED\"}" + } + ], + "phase": "final_answer", + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 0.0, + "previous_response_id": null, + "prompt_cache_key": null, + "prompt_cache_retention": "in_memory", + "reasoning": { + "context": "all_turns", + "effort": "none", + "mode": "standard", + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": false, + "temperature": 1.0, + "text": { + "format": { + "type": "text" + }, + "verbosity": "low" + }, + "tool_choice": "auto", + "tool_usage": { + "image_gen": { + "input_tokens": 0, + "input_tokens_details": { + "image_tokens": 0, + "text_tokens": 0 + }, + "output_tokens": 0, + "output_tokens_details": { + "image_tokens": 0, + "text_tokens": 0 + }, + "total_tokens": 0 + }, + "web_search": { + "num_requests": 0 + } + }, + "tools": [], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 1748, + "input_tokens_details": { + "cache_write_tokens": 1745, + "cached_tokens": 0 + }, + "output_tokens": 52, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 1800 + }, + "user": null, + "metadata": {} +} \ No newline at end of file diff --git a/eval/sol-profile/raw/03-alpha-old_shared.receipt.json b/eval/sol-profile/raw/03-alpha-old_shared.receipt.json new file mode 100644 index 0000000..7602d21 --- /dev/null +++ b/eval/sol-profile/raw/03-alpha-old_shared.receipt.json @@ -0,0 +1,30 @@ +{ + "sequence": 3, + "fixture": "alpha", + "profile": "old_shared", + "request": { + "endpoint": "http://127.0.0.1:8082/v1/responses", + "model": "gpt-5.6-sol", + "maxOutputTokens": 512, + "reasoningEffort": "none", + "imageDetail": "original", + "imageSha256": [ + "71c5f88bcfa3ec196d824221d61563031877b1ea70aa4e37ef50084f8898e043" + ], + "imageDimensions": [ + "768x1040" + ], + "prompt": "Read only the attached synthetic terminal image(s). Do not use outside knowledge and do not guess.\nReturn exactly one JSON object with these six string keys and no Markdown:\n- \"fingerprint\": the 12-character DEPLOYMENT_FINGERPRINT value.\n- \"camelCase\": the RUNTIME_FIELD value, preserving case.\n- \"path\": the complete ACTIVE_MANIFEST value.\n- \"port\": the CONTROL_PORT digits.\n- \"gist\": choose only \"A\", \"B\", or \"C\":\n A = the rollout resumed after health checks recovered;\n B = the rollout stayed paused because a checksum mismatch remained;\n C = the transcript does not state the rollout outcome.\n- \"unstated\": answer \"Which cloud region hosted the canary?\"; if absent, return exactly \"NOT STATED\".\nIf an exact field is unreadable, return \"UNREADABLE\" for that field instead of inventing a value." + }, + "response": { + "status": 200, + "headers": { + "x-request-id": "ff15ed67-d378-4e1b-ad9a-d2d3d9c2be9d", + "openai-processing-ms": "2034", + "cf-ray": "a18a9b58c937fce9-AUS-DOG" + }, + "latencyMs": 2429, + "rawBodySha256": "5ede01fba8670a28b80d9f7ce3bb7b60ae4d86ef50826afc8c787f59b45dfbdc", + "error": null + } +} diff --git a/eval/sol-profile/raw/03-alpha-old_shared.response.json b/eval/sol-profile/raw/03-alpha-old_shared.response.json new file mode 100644 index 0000000..7f53915 --- /dev/null +++ b/eval/sol-profile/raw/03-alpha-old_shared.response.json @@ -0,0 +1,94 @@ +{ + "id": "resp_083fde5dff13ac2c016a501a3242348197882ae33f8b15e29a", + "object": "response", + "created_at": 1783634482, + "status": "completed", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": 1783634484, + "error": null, + "frequency_penalty": 0.0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": 512, + "max_tool_calls": null, + "model": "gpt-5.6-sol", + "moderation": null, + "output": [ + { + "id": "msg_083fde5dff13ac2c016a501a3331948197afa081cd8f933ab0", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "{\"fingerprint\":\"7ac089b47c21\",\"camelCase\":\"fluxLimiterCeiling\",\"path\":\"/srv/releases/2025-04-18/edge-router/manifest.json\",\"port\":\"41820\",\"gist\":\"A\",\"unstated\":\"NOT STATED\"}" + } + ], + "phase": "final_answer", + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 0.0, + "previous_response_id": null, + "prompt_cache_key": null, + "prompt_cache_retention": "in_memory", + "reasoning": { + "context": "all_turns", + "effort": "none", + "mode": "standard", + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": false, + "temperature": 1.0, + "text": { + "format": { + "type": "text" + }, + "verbosity": "low" + }, + "tool_choice": "auto", + "tool_usage": { + "image_gen": { + "input_tokens": 0, + "input_tokens_details": { + "image_tokens": 0, + "text_tokens": 0 + }, + "output_tokens": 0, + "output_tokens_details": { + "image_tokens": 0, + "text_tokens": 0 + }, + "total_tokens": 0 + }, + "web_search": { + "num_requests": 0 + } + }, + "tools": [], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 1143, + "input_tokens_details": { + "cache_write_tokens": 1140, + "cached_tokens": 0 + }, + "output_tokens": 59, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 1202 + }, + "user": null, + "metadata": {} +} \ No newline at end of file diff --git a/eval/sol-profile/results.json b/eval/sol-profile/results.json new file mode 100644 index 0000000..5e47b66 --- /dev/null +++ b/eval/sol-profile/results.json @@ -0,0 +1,324 @@ +{ + "generatedAt": "2026-07-09T21:56:55.765Z", + "model": "gpt-5.6-sol", + "live": true, + "preflightSha256": "78288b351deea4bce2e21f018c255904770e78864040a8771ed6e08f94e58179", + "plannedCalls": 4, + "completedCalls": 3, + "stoppedEarly": true, + "stopReason": "clear acceptance failure on alpha/old_shared", + "calls": [ + { + "sequence": 1, + "fixture": "alpha", + "profile": "current_sol", + "imageDimensions": [ + "764x1724" + ], + "estimatedImageTokens": 1296, + "estimatedSavingsVsTextPct": 73.5, + "latencyMs": 13857, + "httpStatus": 200, + "responseHeaders": { + "x-request-id": "5dbb1379-3a2b-49c1-88e6-2ef4baa5aded", + "openai-processing-ms": "13292", + "cf-ray": "a18a94dc3f3efce9-AUS-DOG" + }, + "transportError": null, + "usage": { + "input_tokens": 1748, + "input_tokens_details": { + "cache_write_tokens": 1745, + "cached_tokens": 0 + }, + "output_tokens": 512, + "output_tokens_details": { + "reasoning_tokens": 512 + }, + "total_tokens": 2260 + }, + "responseId": "resp_0413981843da1074016a501928820c8190a2a8c656f84e1c75", + "responseModel": "gpt-5.6-sol", + "rawResponseBody": "{\n \"id\": \"resp_0413981843da1074016a501928820c8190a2a8c656f84e1c75\",\n \"object\": \"response\",\n \"created_at\": 1783634216,\n \"status\": \"incomplete\",\n \"background\": false,\n \"billing\": {\n \"payer\": \"developer\"\n },\n \"completed_at\": null,\n \"error\": null,\n \"frequency_penalty\": 0.0,\n \"incomplete_details\": {\n \"reason\": \"max_output_tokens\"\n },\n \"instructions\": null,\n \"max_output_tokens\": 512,\n \"max_tool_calls\": null,\n \"model\": \"gpt-5.6-sol\",\n \"moderation\": null,\n \"output\": [\n {\n \"id\": \"rs_0413981843da1074016a50192976748190bb8cf1789c294ae6\",\n \"type\": \"reasoning\",\n \"content\": [],\n \"summary\": []\n }\n ],\n \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n \"context\": \"all_turns\",\n \"effort\": \"low\",\n \"mode\": \"standard\",\n \"summary\": null\n },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": false,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tool_usage\": {\n \"image_gen\": {\n \"input_tokens\": 0,\n \"input_tokens_details\": {\n \"image_tokens\": 0,\n \"text_tokens\": 0\n },\n \"output_tokens\": 0,\n \"output_tokens_details\": {\n \"image_tokens\": 0,\n \"text_tokens\": 0\n },\n \"total_tokens\": 0\n },\n \"web_search\": {\n \"num_requests\": 0\n }\n },\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 0.98,\n \"truncation\": \"disabled\",\n \"usage\": {\n \"input_tokens\": 1748,\n \"input_tokens_details\": {\n \"cache_write_tokens\": 1745,\n \"cached_tokens\": 0\n },\n \"output_tokens\": 512,\n \"output_tokens_details\": {\n \"reasoning_tokens\": 512\n },\n \"total_tokens\": 2260\n },\n \"user\": null,\n \"metadata\": {}\n}", + "rawResponseSha256": "07afb8a3fb7d685a8d480c5efa31697a9b51bb0ecb09720858cdcee7e7dbec4a", + "score": { + "responseStatus": "incomplete", + "incompleteReason": "max_output_tokens", + "outputText": "", + "refusals": [], + "parseError": "empty output", + "strictJson": false, + "schemaValid": false, + "exact": { + "fingerprint": { + "expected": "c7a1e90b4d2f", + "got": "", + "ok": false + }, + "camelCase": { + "expected": "retryBudgetSeconds", + "got": "", + "ok": false + }, + "path": { + "expected": "/srv/sol-pilot/releases/alpha-07/config/runtime-map.json", + "got": "", + "ok": false + }, + "port": { + "expected": "47831", + "got": "", + "ok": false + } + }, + "exactCorrect": 0, + "exactTotal": 4, + "gist": { + "expected": "B", + "got": "", + "ok": false + }, + "guard": { + "expected": "NOT STATED", + "got": "", + "ok": false + }, + "confabulations": [], + "abstentions": [], + "pass": false + }, + "reasoningEffort": "low" + }, + { + "sequence": 2, + "fixture": "alpha", + "profile": "current_sol", + "imageDimensions": [ + "764x1724" + ], + "estimatedImageTokens": 1296, + "estimatedSavingsVsTextPct": 73.5, + "latencyMs": 3294, + "httpStatus": 200, + "responseHeaders": { + "x-request-id": "fd696db0-302f-4065-9714-209dbcaab732", + "openai-processing-ms": "2948", + "cf-ray": "a18a9751a965fce9-AUS-DOG" + }, + "transportError": null, + "usage": { + "input_tokens": 1748, + "input_tokens_details": { + "cache_write_tokens": 1745, + "cached_tokens": 0 + }, + "output_tokens": 52, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 1800 + }, + "responseId": "resp_020acbb2cc7a89da016a50198d3364819387c192a9f4b370b9", + "responseModel": "gpt-5.6-sol", + "reasoningEffort": "none", + "rawResponseBody": "{\n \"id\": \"resp_020acbb2cc7a89da016a50198d3364819387c192a9f4b370b9\",\n \"object\": \"response\",\n \"created_at\": 1783634317,\n \"status\": \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": \"developer\"\n },\n \"completed_at\": 1783634320,\n \"error\": null,\n \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": null,\n \"max_output_tokens\": 512,\n \"max_tool_calls\": null,\n \"model\": \"gpt-5.6-sol\",\n \"moderation\": null,\n \"output\": [\n {\n \"id\": \"msg_020acbb2cc7a89da016a50198edbdc819383c8352f6b908521\",\n \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": [],\n \"text\": \"{\\\"fingerprint\\\":\\\"c0ffee0913a7\\\",\\\"camelCase\\\":\\\"matrixField\\\",\\\"path\\\":\\\"/srv/app/releases/alpha-07/config/runtime.yaml\\\",\\\"port\\\":\\\"41702\\\",\\\"gist\\\":\\\"B\\\",\\\"unstated\\\":\\\"NOT STATED\\\"}\"\n }\n ],\n \"phase\": \"final_answer\",\n \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n \"context\": \"all_turns\",\n \"effort\": \"none\",\n \"mode\": \"standard\",\n \"summary\": null\n },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": false,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n \"verbosity\": \"low\"\n },\n \"tool_choice\": \"auto\",\n \"tool_usage\": {\n \"image_gen\": {\n \"input_tokens\": 0,\n \"input_tokens_details\": {\n \"image_tokens\": 0,\n \"text_tokens\": 0\n },\n \"output_tokens\": 0,\n \"output_tokens_details\": {\n \"image_tokens\": 0,\n \"text_tokens\": 0\n },\n \"total_tokens\": 0\n },\n \"web_search\": {\n \"num_requests\": 0\n }\n },\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 0.98,\n \"truncation\": \"disabled\",\n \"usage\": {\n \"input_tokens\": 1748,\n \"input_tokens_details\": {\n \"cache_write_tokens\": 1745,\n \"cached_tokens\": 0\n },\n \"output_tokens\": 52,\n \"output_tokens_details\": {\n \"reasoning_tokens\": 0\n },\n \"total_tokens\": 1800\n },\n \"user\": null,\n \"metadata\": {}\n}", + "rawResponseSha256": "492e540e233eb5dd21caf87a6246cec0c62d866fc8dca6e57b8cca019918dad9", + "score": { + "responseStatus": "completed", + "incompleteReason": null, + "outputText": "{\"fingerprint\":\"c0ffee0913a7\",\"camelCase\":\"matrixField\",\"path\":\"/srv/app/releases/alpha-07/config/runtime.yaml\",\"port\":\"41702\",\"gist\":\"B\",\"unstated\":\"NOT STATED\"}", + "refusals": [], + "parseError": null, + "strictJson": true, + "schemaValid": true, + "exact": { + "fingerprint": { + "expected": "c7a1e90b4d2f", + "got": "c0ffee0913a7", + "ok": false + }, + "camelCase": { + "expected": "retryBudgetSeconds", + "got": "matrixField", + "ok": false + }, + "path": { + "expected": "/srv/sol-pilot/releases/alpha-07/config/runtime-map.json", + "got": "/srv/app/releases/alpha-07/config/runtime.yaml", + "ok": false + }, + "port": { + "expected": "47831", + "got": "41702", + "ok": false + } + }, + "exactCorrect": 0, + "exactTotal": 4, + "gist": { + "expected": "B", + "got": "B", + "ok": true + }, + "guard": { + "expected": "NOT STATED", + "got": "NOT STATED", + "ok": true + }, + "confabulations": [ + { + "field": "fingerprint", + "value": "c0ffee0913a7" + }, + { + "field": "camelCase", + "value": "matrixField" + }, + { + "field": "path", + "value": "/srv/app/releases/alpha-07/config/runtime.yaml" + }, + { + "field": "port", + "value": "41702" + } + ], + "abstentions": [], + "pass": false + } + }, + { + "sequence": 3, + "fixture": "alpha", + "profile": "old_shared", + "imageDimensions": [ + "768x1040" + ], + "estimatedImageTokens": 792, + "estimatedSavingsVsTextPct": 83.8, + "latencyMs": 2429, + "httpStatus": 200, + "responseHeaders": { + "x-request-id": "ff15ed67-d378-4e1b-ad9a-d2d3d9c2be9d", + "openai-processing-ms": "2034", + "cf-ray": "a18a9b58c937fce9-AUS-DOG" + }, + "transportError": null, + "usage": { + "input_tokens": 1143, + "input_tokens_details": { + "cache_write_tokens": 1140, + "cached_tokens": 0 + }, + "output_tokens": 59, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 1202 + }, + "responseId": "resp_083fde5dff13ac2c016a501a3242348197882ae33f8b15e29a", + "responseModel": "gpt-5.6-sol", + "reasoningEffort": "none", + "rawResponseBody": "{\n \"id\": \"resp_083fde5dff13ac2c016a501a3242348197882ae33f8b15e29a\",\n \"object\": \"response\",\n \"created_at\": 1783634482,\n \"status\": \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": \"developer\"\n },\n \"completed_at\": 1783634484,\n \"error\": null,\n \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": null,\n \"max_output_tokens\": 512,\n \"max_tool_calls\": null,\n \"model\": \"gpt-5.6-sol\",\n \"moderation\": null,\n \"output\": [\n {\n \"id\": \"msg_083fde5dff13ac2c016a501a3331948197afa081cd8f933ab0\",\n \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": [],\n \"text\": \"{\\\"fingerprint\\\":\\\"7ac089b47c21\\\",\\\"camelCase\\\":\\\"fluxLimiterCeiling\\\",\\\"path\\\":\\\"/srv/releases/2025-04-18/edge-router/manifest.json\\\",\\\"port\\\":\\\"41820\\\",\\\"gist\\\":\\\"A\\\",\\\"unstated\\\":\\\"NOT STATED\\\"}\"\n }\n ],\n \"phase\": \"final_answer\",\n \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n \"context\": \"all_turns\",\n \"effort\": \"none\",\n \"mode\": \"standard\",\n \"summary\": null\n },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": false,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n \"verbosity\": \"low\"\n },\n \"tool_choice\": \"auto\",\n \"tool_usage\": {\n \"image_gen\": {\n \"input_tokens\": 0,\n \"input_tokens_details\": {\n \"image_tokens\": 0,\n \"text_tokens\": 0\n },\n \"output_tokens\": 0,\n \"output_tokens_details\": {\n \"image_tokens\": 0,\n \"text_tokens\": 0\n },\n \"total_tokens\": 0\n },\n \"web_search\": {\n \"num_requests\": 0\n }\n },\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 0.98,\n \"truncation\": \"disabled\",\n \"usage\": {\n \"input_tokens\": 1143,\n \"input_tokens_details\": {\n \"cache_write_tokens\": 1140,\n \"cached_tokens\": 0\n },\n \"output_tokens\": 59,\n \"output_tokens_details\": {\n \"reasoning_tokens\": 0\n },\n \"total_tokens\": 1202\n },\n \"user\": null,\n \"metadata\": {}\n}", + "rawResponseSha256": "5ede01fba8670a28b80d9f7ce3bb7b60ae4d86ef50826afc8c787f59b45dfbdc", + "score": { + "responseStatus": "completed", + "incompleteReason": null, + "outputText": "{\"fingerprint\":\"7ac089b47c21\",\"camelCase\":\"fluxLimiterCeiling\",\"path\":\"/srv/releases/2025-04-18/edge-router/manifest.json\",\"port\":\"41820\",\"gist\":\"A\",\"unstated\":\"NOT STATED\"}", + "refusals": [], + "parseError": null, + "strictJson": true, + "schemaValid": true, + "exact": { + "fingerprint": { + "expected": "c7a1e90b4d2f", + "got": "7ac089b47c21", + "ok": false + }, + "camelCase": { + "expected": "retryBudgetSeconds", + "got": "fluxLimiterCeiling", + "ok": false + }, + "path": { + "expected": "/srv/sol-pilot/releases/alpha-07/config/runtime-map.json", + "got": "/srv/releases/2025-04-18/edge-router/manifest.json", + "ok": false + }, + "port": { + "expected": "47831", + "got": "41820", + "ok": false + } + }, + "exactCorrect": 0, + "exactTotal": 4, + "gist": { + "expected": "B", + "got": "A", + "ok": false + }, + "guard": { + "expected": "NOT STATED", + "got": "NOT STATED", + "ok": true + }, + "confabulations": [ + { + "field": "fingerprint", + "value": "7ac089b47c21" + }, + { + "field": "camelCase", + "value": "fluxLimiterCeiling" + }, + { + "field": "path", + "value": "/srv/releases/2025-04-18/edge-router/manifest.json" + }, + { + "field": "port", + "value": "41820" + } + ], + "abstentions": [], + "pass": false + } + } + ], + "resume": { + "reason": "first attempt returned only hidden reasoning and hit max_output_tokens", + "reviewedAt": "2026-07-09T21:58:36.732Z", + "priorAttemptsCountAgainstCap": true, + "changedReasoningEffort": "none", + "remainingOrder": [ + { + "fixture": "alpha", + "profile": "current_sol" + }, + { + "fixture": "alpha", + "profile": "old_shared" + }, + { + "fixture": "beta", + "profile": "current_sol" + } + ] + }, + "retune": { + "reason": "current Sol 6x11 profile returned 0/4 exact with four confabulations", + "reviewedAt": "2026-07-09T22:01:21.706Z", + "candidate": "Sol-only fallback to old shared Spleen 5x8 / 152 columns", + "remainingOrder": [ + { + "fixture": "alpha", + "profile": "old_shared" + }, + { + "fixture": "beta", + "profile": "old_shared" + } + ] + } +} diff --git a/eval/sol-profile/run.mjs b/eval/sol-profile/run.mjs new file mode 100755 index 0000000..c0545bc --- /dev/null +++ b/eval/sol-profile/run.mjs @@ -0,0 +1,724 @@ +#!/usr/bin/env node +/** + * Paired image-reading pilot for the exact gpt-5.6-sol model. + * + * Default mode is render-only and cannot call a model. Live mode is guarded by + * both SOL_PROFILE_LIVE=1 and a literal approval acknowledgement. Requests go + * directly to OPENAI_BASE_URL / Responses and refuse pxpipe's known local port, + * so the images under test are not recursively transformed. + */ +import { createHash } from 'node:crypto'; +import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { countTokens } from 'gpt-tokenizer'; +import { + reflow, + renderCellHeight, + renderCellWidth, + renderTextToPngs, +} from '../../dist/core/render.js'; +import { resolveGptProfile } from '../../dist/core/gpt-model-profiles.js'; +import { visionTokensForModel } from '../../dist/core/openai.js'; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const WORK_DIR = join(HERE, '.work'); +const PREFLIGHT_PATH = join(HERE, 'preflight.json'); +const RESULTS_PATH = join(HERE, 'results.json'); +const RAW_DIR = join(HERE, 'raw'); + +const MODEL = 'gpt-5.6-sol'; +const MAX_CALLS = 4; +const LIVE = /^(1|true)$/i.test(process.env.SOL_PROFILE_LIVE || ''); +const APPROVAL_ACK = 'approved-4-sol-profile-calls'; +const HAS_APPROVAL = process.env.SOL_PROFILE_PAID_APPROVAL === APPROVAL_ACK; +const TIMEOUT_MS = Number(process.env.SOL_PROFILE_TIMEOUT_MS || 180_000); +const RESUME_AFTER_OUTPUT_CAP = process.env.SOL_PROFILE_RESUME_AFTER_OUTPUT_CAP === '1'; +const RESUME_OLD_AS_RETUNE = process.env.SOL_PROFILE_RESUME_OLD_AS_RETUNE === '1'; +const RESUME_SPACED_RETUNE = process.env.SOL_PROFILE_RESUME_SPACED_RETUNE === '1'; + +function invariant(condition, message) { + if (!condition) throw new Error(message); +} + +function sha256(value) { + return createHash('sha256').update(value).digest('hex'); +} + +async function writeJsonAtomic(path, value) { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.tmp-${process.pid}`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`); + await rename(tmp, path); +} + +function lcg(seed) { + let state = seed >>> 0; + return () => { + state = (Math.imul(state, 1_664_525) + 1_013_904_223) >>> 0; + return state; + }; +} + +const LEVELS = ['TRACE', 'DEBUG', 'INFO ', 'NOTICE']; +const UNITS = ['scheduler', 'checksum', 'canary', 'ledger', 'relay', 'watchdog']; +const NOTES = [ + 'synthetic sample accepted without state change', + 'checkpoint observed and journal cursor advanced', + 'read only probe completed with stable ordering', + 'queue sample retained for deterministic replay', + 'heartbeat recorded while gate remained unchanged', + 'fixture noise line emitted for density control', +]; + +const FIXTURE_SPECS = [ + { + id: 'alpha', + seed: 0x51a7c0de, + expected: { + fingerprint: 'c7a1e90b4d2f', + camelCase: 'retryBudgetSeconds', + path: '/srv/sol-pilot/releases/alpha-07/config/runtime-map.json', + port: '47831', + gist: 'B', + unstated: 'NOT STATED', + }, + guardQuestion: 'Which cloud region hosted the canary?', + forbiddenGuardTerms: ['region'], + factsAt: new Map([ + [17, 'DEPLOYMENT_FINGERPRINT=c7a1e90b4d2f ; copy all 12 lowercase hex characters exactly.'], + [44, 'RUNTIME_FIELD=retryBudgetSeconds ; preserve camelCase spelling exactly.'], + [72, 'RUN_SUMMARY: The canary stayed paused because the checksum mismatch remained.'], + [101, 'ACTIVE_MANIFEST=/srv/sol-pilot/releases/alpha-07/config/runtime-map.json'], + [128, 'CONTROL_PORT=47831 ; this is the listener used by the synthetic relay.'], + ]), + }, + { + id: 'beta', + seed: 0xb37af11e, + expected: { + fingerprint: '8d3f6a20c1e7', + camelCase: 'maxVisualTokens', + path: '/opt/sol-pilot/fixtures/beta/session-ledger.toml', + port: '18082', + gist: 'A', + unstated: 'NOT STATED', + }, + guardQuestion: 'Who owned the incident response?', + forbiddenGuardTerms: ['owner', 'owned'], + factsAt: new Map([ + [12, 'CONTROL_PORT=18082 ; this is the listener used by the synthetic relay.'], + [39, 'ACTIVE_MANIFEST=/opt/sol-pilot/fixtures/beta/session-ledger.toml'], + [68, 'RUN_SUMMARY: Health checks recovered, so the staged rollout resumed.'], + [98, 'RUNTIME_FIELD=maxVisualTokens ; preserve camelCase spelling exactly.'], + [127, 'DEPLOYMENT_FINGERPRINT=8d3f6a20c1e7 ; copy all 12 lowercase hex characters exactly.'], + ]), + }, +]; + +function buildFixture(spec) { + const next = lcg(spec.seed); + const lines = [ + `SOL PROFILE PILOT FIXTURE ${spec.id.toUpperCase()}`, + 'Synthetic terminal transcript. The labelled records below are the only source of facts.', + 'Noise records use eight-character trace ids; the deployment fingerprint is explicitly labelled and has twelve characters.', + ]; + for (let i = 0; i < 144; i++) { + const fact = spec.factsAt.get(i); + if (fact) lines.push(`[fact ${String(i).padStart(3, '0')}] ${fact}`); + const a = next(); + const b = next(); + const hh = String((i * 7 + 3) % 24).padStart(2, '0'); + const mm = String((i * 11 + 5) % 60).padStart(2, '0'); + const ss = String((i * 13 + 7) % 60).padStart(2, '0'); + const ms = String(a % 1000).padStart(3, '0'); + const level = LEVELS[a % LEVELS.length]; + const unit = UNITS[b % UNITS.length].padEnd(9, ' '); + const trace8 = a.toString(16).padStart(8, '0'); + const queue = String((b >>> 8) % 997).padStart(3, '0'); + const shard = String((a >>> 16) % 41).padStart(2, '0'); + const note = NOTES[((a ^ b) >>> 0) % NOTES.length]; + lines.push( + `[${hh}:${mm}:${ss}.${ms}] ${level} ${unit} cycle=${String(i).padStart(3, '0')} ` + + `trace8=${trace8} queue=${queue} shard=${shard} note="${note}"`, + ); + } + lines.push('END SYNTHETIC TRANSCRIPT'); + const text = lines.join('\n'); + const lower = text.toLowerCase(); + for (const term of spec.forbiddenGuardTerms) { + invariant(!lower.includes(term), `${spec.id}: unstated guard term leaked into fixture: ${term}`); + } + return text; +} + +function promptFor(spec) { + return [ + 'Read only the attached synthetic terminal image(s). Do not use outside knowledge and do not guess.', + 'Return exactly one JSON object with these six string keys and no Markdown:', + '- "fingerprint": the 12-character DEPLOYMENT_FINGERPRINT value.', + '- "camelCase": the RUNTIME_FIELD value, preserving case.', + '- "path": the complete ACTIVE_MANIFEST value.', + '- "port": the CONTROL_PORT digits.', + '- "gist": choose only "A", "B", or "C":', + ' A = the rollout resumed after health checks recovered;', + ' B = the rollout stayed paused because a checksum mismatch remained;', + ' C = the transcript does not state the rollout outcome.', + `- "unstated": answer "${spec.guardQuestion}"; if absent, return exactly "NOT STATED".`, + 'If an exact field is unreadable, return "UNREADABLE" for that field instead of inventing a value.', + ].join('\n'); +} + +const resolvedSol = resolveGptProfile(MODEL); +const oldStyle = { + font: 'spleen-5x8', + cellWBonus: 0, + cellHBonus: 0, + aa: true, + grid: false, + gridCols: 0, + colorCycle: false, + markerScale: 1, + markerRed: false, +}; +const PROFILES = { + old_shared: { + name: 'old_shared', + cols: 152, + maxHeightPx: 1932, + style: oldStyle, + }, + current_sol: { + name: 'current_sol', + cols: resolvedSol.stripCols, + maxHeightPx: resolvedSol.maxHeightPx, + style: { ...resolvedSol.style }, + }, + retuned_sol_9x12: { + name: 'retuned_sol_9x12', + cols: 84, + maxHeightPx: resolvedSol.maxHeightPx, + // Retune only the Sol candidate: keep its JetBrains glyph atlas, but use + // the same effective cell density that rescued exact recall for Grok. + style: { ...resolvedSol.style, cellWBonus: 3, cellHBonus: 1 }, + }, +}; + +invariant(MODEL === 'gpt-5.6-sol', 'This harness must never target a different model family'); +invariant(PROFILES.old_shared.cols === 152, 'Old shared profile must stay at 152 columns'); +invariant(renderCellWidth(PROFILES.old_shared.style) === 5, 'Old shared profile must use 5px cells'); +invariant(renderCellHeight(PROFILES.old_shared.style) === 8, 'Old shared profile must use 8px cells'); +invariant(PROFILES.current_sol.cols === 126, 'Current Sol profile must stay at 126 columns for this pilot'); +invariant(PROFILES.current_sol.maxHeightPx === 1932, 'Current Sol max height must be 1932px'); +invariant(PROFILES.current_sol.style.font === 'jetbrains-mono-10', 'Current Sol profile must use JetBrains Mono 10'); +invariant(PROFILES.current_sol.style.aa === true, 'Current Sol profile must use grayscale AA'); +invariant(renderCellWidth(PROFILES.current_sol.style) === 6, 'Current Sol profile must use 6px cells'); +invariant(renderCellHeight(PROFILES.current_sol.style) === 11, 'Current Sol profile must use 11px cells'); +invariant(PROFILES.retuned_sol_9x12.cols === 84, 'Retuned Sol candidate must use 84 columns'); +invariant(renderCellWidth(PROFILES.retuned_sol_9x12.style) === 9, 'Retuned Sol candidate must use 9px cells'); +invariant(renderCellHeight(PROFILES.retuned_sol_9x12.style) === 12, 'Retuned Sol candidate must use 12px cells'); + +const CALL_ORDER = [ + { fixture: 'alpha', profile: 'current_sol' }, + { fixture: 'alpha', profile: 'old_shared' }, + { fixture: 'beta', profile: 'old_shared' }, + { fixture: 'beta', profile: 'current_sol' }, +]; +// If the first attempt consumed its whole output cap as hidden reasoning, it is +// not a recall observation. A manually reviewed resume still counts that attempt +// against the cap, retries the candidate with reasoning disabled, retains one +// paired old-profile arm, and spends the final call on candidate replication. +const OUTPUT_CAP_RESUME_ORDER = [ + { fixture: 'alpha', profile: 'current_sol' }, + { fixture: 'alpha', profile: 'old_shared' }, + { fixture: 'beta', profile: 'current_sol' }, +]; +const OLD_FALLBACK_RETUNE_ORDER = [ + { fixture: 'alpha', profile: 'old_shared' }, + { fixture: 'beta', profile: 'old_shared' }, +]; +const SPACED_RETUNE_ORDER = [ + { fixture: 'alpha', profile: 'retuned_sol_9x12' }, +]; +invariant(CALL_ORDER.length <= MAX_CALLS, 'Call plan exceeds the four-call cap'); + +function safePct(value) { + return Math.round(value * 10) / 10; +} + +async function renderArm(spec, profile) { + const source = buildFixture(spec); + const packed = reflow(source); + invariant(typeof packed === 'string', `${spec.id}: fixture unexpectedly contains the reflow sentinel`); + const prompt = promptFor(spec); + const images = await renderTextToPngs(packed, profile.cols, profile.style, profile.maxHeightPx); + invariant(images.length > 0, `${spec.id}/${profile.name}: renderer returned no images`); + if (profile.name !== 'retuned_sol_9x12') { + invariant(images.length === 1, `${spec.id}/${profile.name}: original pilot arms must remain one image per call`); + } + + const outDir = join(WORK_DIR, spec.id, profile.name); + await mkdir(outDir, { recursive: true }); + await writeFile(join(outDir, 'fixture.txt'), `${source}\n`); + await writeFile(join(outDir, 'prompt.txt'), `${prompt}\n`); + + const pages = []; + let imageTokens = 0; + for (let i = 0; i < images.length; i++) { + const image = images[i]; + invariant(image.droppedChars === 0, `${spec.id}/${profile.name}: renderer dropped ${image.droppedChars} chars`); + const file = join(outDir, `page-${i + 1}.png`); + await writeFile(file, image.png); + const tokens = visionTokensForModel(MODEL, image.width, image.height); + imageTokens += tokens; + pages.push({ + file: file.slice(HERE.length + 1), + width: image.width, + height: image.height, + bytes: image.png.byteLength, + sha256: sha256(image.png), + estimatedImageTokens: tokens, + }); + } + + const textTokensCharsPer4 = Math.ceil(source.length / 4); + const sourceTokenizerTokens = countTokens(source); + // The source itself is image-only. This estimate covers the user prompt and + // a small Responses envelope allowance; actual usage is captured live. + const projectedNonImageInputTokens = countTokens(prompt) + 16 + images.length * 8; + const projectedInputTokens = imageTokens + projectedNonImageInputTokens; + return { + fixture: spec.id, + profile: profile.name, + source, + prompt, + expected: spec.expected, + sourceChars: source.length, + sourceSha256: sha256(source), + sourceTokenizerTokens, + textTokensCharsPer4, + pages, + imageTokens, + projectedNonImageInputTokens, + projectedInputTokens, + estimatedSavingsVsTextPct: safePct((1 - imageTokens / textTokensCharsPer4) * 100), + imageDataUrls: images.map((image) => `data:image/png;base64,${Buffer.from(image.png).toString('base64')}`), + }; +} + +function summarizeArm(arm) { + const { source, prompt, imageDataUrls, ...summary } = arm; + return summary; +} + +function totalsFor(arms) { + const totals = { + calls: arms.length, + imageTokens: 0, + projectedNonImageInputTokens: 0, + projectedInputTokens: 0, + byProfile: {}, + }; + for (const arm of arms) { + totals.imageTokens += arm.imageTokens; + totals.projectedNonImageInputTokens += arm.projectedNonImageInputTokens; + totals.projectedInputTokens += arm.projectedInputTokens; + const p = totals.byProfile[arm.profile] || { + calls: 0, + imageTokens: 0, + projectedNonImageInputTokens: 0, + projectedInputTokens: 0, + }; + p.calls++; + p.imageTokens += arm.imageTokens; + p.projectedNonImageInputTokens += arm.projectedNonImageInputTokens; + p.projectedInputTokens += arm.projectedInputTokens; + totals.byProfile[arm.profile] = p; + } + const oldTokens = totals.byProfile.old_shared?.imageTokens || 0; + const solTokens = totals.byProfile.current_sol?.imageTokens || 0; + totals.currentVsOldImageTokenIncreasePct = oldTokens > 0 + ? safePct((solTokens / oldTokens - 1) * 100) + : null; + return totals; +} + +function responsesEndpoint() { + const raw = process.env.SOL_PROFILE_BASE_URL || process.env.OPENAI_BASE_URL || ''; + if (!raw) throw new Error('OPENAI_BASE_URL (or SOL_PROFILE_BASE_URL) is required for a live run'); + const url = new URL(raw); + // Current pxpipe listener from the pilot brief. The eval must hit the direct + // upstream Responses endpoint (currently ocproxy on 127.0.0.1:8082), not pxpipe. + invariant(url.port !== '47821', 'Refusing pxpipe port 47821: raw image eval must bypass pxpipe'); + const base = raw.replace(/\/$/, ''); + return base.endsWith('/responses') ? base : `${base}/responses`; +} + +function extractOutput(response) { + let text = typeof response?.output_text === 'string' ? response.output_text : ''; + const refusals = []; + if (!text && Array.isArray(response?.output)) { + for (const item of response.output) { + if (!item || !Array.isArray(item.content)) continue; + for (const part of item.content) { + if (part && (part.type === 'output_text' || part.type === 'text') && typeof part.text === 'string') { + text += part.text; + } + if (part?.type === 'refusal' && typeof part.refusal === 'string') refusals.push(part.refusal); + } + } + } + return { text: text.trim(), refusals }; +} + +function parseObject(text) { + const trimmed = text.trim(); + if (!trimmed) return { value: null, strictJson: false, error: 'empty output' }; + let candidate = trimmed; + const fenced = candidate.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i); + if (fenced) candidate = fenced[1].trim(); + try { + return { value: JSON.parse(candidate), strictJson: candidate === trimmed, error: null }; + } catch (firstError) { + const start = candidate.indexOf('{'); + const end = candidate.lastIndexOf('}'); + if (start >= 0 && end > start) { + try { + return { value: JSON.parse(candidate.slice(start, end + 1)), strictJson: false, error: null }; + } catch { + // Report the original parse error below. + } + } + return { value: null, strictJson: false, error: String(firstError) }; + } +} + +const RESPONSE_KEYS = ['fingerprint', 'camelCase', 'path', 'port', 'gist', 'unstated']; +const EXACT_KEYS = ['fingerprint', 'camelCase', 'path', 'port']; + +function scoreResponse(arm, response, output) { + const parsed = parseObject(output.text); + const value = parsed.value && typeof parsed.value === 'object' && !Array.isArray(parsed.value) + ? parsed.value + : null; + const keys = value ? Object.keys(value).sort() : []; + const schemaValid = Boolean(value) && + keys.join('\n') === [...RESPONSE_KEYS].sort().join('\n') && + RESPONSE_KEYS.every((key) => typeof value[key] === 'string'); + const exact = {}; + const confabulations = []; + const abstentions = []; + let exactCorrect = 0; + + for (const key of EXACT_KEYS) { + const got = schemaValid ? value[key].trim() : ''; + const expected = arm.expected[key]; + const ok = got === expected; + exact[key] = { expected, got, ok }; + if (ok) exactCorrect++; + else if (got === 'UNREADABLE' || got === 'NOT STATED') abstentions.push(key); + else if (got && !arm.source.includes(got)) confabulations.push({ field: key, value: got }); + } + + const gistGot = schemaValid ? value.gist.trim() : ''; + const unstatedGot = schemaValid ? value.unstated.trim() : ''; + const gistOk = gistGot === arm.expected.gist; + const guardOk = unstatedGot === 'NOT STATED'; + if (unstatedGot === 'UNREADABLE') abstentions.push('unstated'); + else if (unstatedGot && !guardOk) confabulations.push({ field: 'unstated', value: unstatedGot }); + + const completed = !response || response.status === undefined || response.status === 'completed'; + const pass = completed && output.refusals.length === 0 && schemaValid && + exactCorrect === EXACT_KEYS.length && gistOk && guardOk && confabulations.length === 0; + return { + responseStatus: response?.status || null, + incompleteReason: response?.incomplete_details?.reason || null, + outputText: output.text, + refusals: output.refusals, + parseError: parsed.error, + strictJson: parsed.strictJson, + schemaValid, + exact, + exactCorrect, + exactTotal: EXACT_KEYS.length, + gist: { expected: arm.expected.gist, got: gistGot, ok: gistOk }, + guard: { expected: 'NOT STATED', got: unstatedGot, ok: guardOk }, + confabulations, + abstentions, + pass, + }; +} + +async function callResponses(arm, sequence) { + const key = process.env.OPENAI_API_KEY; + if (!key) throw new Error('OPENAI_API_KEY is required for a live run'); + const endpoint = responsesEndpoint(); + const payload = { + model: MODEL, + stream: false, + max_output_tokens: Number(process.env.SOL_PROFILE_MAX_OUTPUT_TOKENS || 512), + reasoning: { effort: process.env.SOL_PROFILE_REASONING_EFFORT || 'none' }, + text: { verbosity: 'low' }, + input: [{ + role: 'user', + content: [ + ...arm.imageDataUrls.map((image_url) => ({ type: 'input_image', image_url, detail: 'original' })), + { type: 'input_text', text: arm.prompt }, + ], + }], + }; + + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), TIMEOUT_MS); + const started = performance.now(); + let response; + let fetchError = null; + try { + response = await fetch(endpoint, { + method: 'POST', + headers: { + 'content-type': 'application/json', + authorization: `Bearer ${key}`, + }, + body: JSON.stringify(payload), + signal: controller.signal, + }); + } catch (error) { + fetchError = String(error); + } finally { + clearTimeout(timer); + } + const latencyMs = Math.round(performance.now() - started); + if (fetchError) { + return { endpoint, latencyMs, status: null, headers: {}, rawBody: '', json: null, error: fetchError }; + } + + const rawBody = await response.text(); + let json = null; + let parseError = null; + try { json = JSON.parse(rawBody); } catch (error) { parseError = String(error); } + const headers = {}; + for (const name of ['x-request-id', 'openai-processing-ms', 'cf-ray']) { + const value = response.headers.get(name); + if (value) headers[name] = value; + } + const error = response.ok + ? parseError + : (json?.error?.message || `Responses HTTP ${response.status}`); + + const stem = `${String(sequence).padStart(2, '0')}-${arm.fixture}-${arm.profile}`; + await mkdir(RAW_DIR, { recursive: true }); + await writeFile(join(RAW_DIR, `${stem}.response.json`), rawBody); + await writeJsonAtomic(join(RAW_DIR, `${stem}.receipt.json`), { + sequence, + fixture: arm.fixture, + profile: arm.profile, + request: { + endpoint, + model: MODEL, + maxOutputTokens: payload.max_output_tokens, + reasoningEffort: payload.reasoning.effort, + imageDetail: 'original', + imageSha256: arm.pages.map((page) => page.sha256), + imageDimensions: arm.pages.map((page) => `${page.width}x${page.height}`), + prompt: arm.prompt, + }, + response: { status: response.status, headers, latencyMs, rawBodySha256: sha256(rawBody), error }, + }); + return { endpoint, latencyMs, status: response.status, headers, rawBody, json, error }; +} + +const preparedByKey = new Map(); +for (const spec of FIXTURE_SPECS) { + for (const profile of Object.values(PROFILES)) { + const arm = await renderArm(spec, profile); + preparedByKey.set(`${spec.id}/${profile.name}`, arm); + } +} +const callArms = CALL_ORDER.map(({ fixture, profile }) => { + const arm = preparedByKey.get(`${fixture}/${profile}`); + invariant(arm, `Missing prepared arm ${fixture}/${profile}`); + return arm; +}); + +const preflight = { + generatedAt: new Date().toISOString(), + live: false, + model: MODEL, + endpointPolicy: 'direct Responses endpoint; port 47821 is rejected', + callCap: MAX_CALLS, + callOrder: CALL_ORDER, + profiles: Object.fromEntries(Object.entries(PROFILES).map(([name, profile]) => [name, { + cols: profile.cols, + maxHeightPx: profile.maxHeightPx, + cell: `${renderCellWidth(profile.style)}x${renderCellHeight(profile.style)}`, + style: profile.style, + }])), + arms: callArms.map(summarizeArm), + totals: totalsFor(callArms), + finalRetuneCandidate: summarizeArm(preparedByKey.get('alpha/retuned_sol_9x12')), + tokenNotes: { + image: 'pxpipe production visionTokensForModel(gpt-5.6-sol, width, height) patch estimate', + nonImage: 'gpt-tokenizer(prompt) plus a small Responses-envelope allowance; provider usage may differ', + textBaseline: 'source chars/4, used only for estimated image-vs-text savings', + }, +}; +await writeJsonAtomic(PREFLIGHT_PATH, preflight); + +console.log(`Sol profile pilot · model=${MODEL} · live=${LIVE}`); +console.log('Direct-image design: 2 deterministic fixtures × 2 profiles; one structured response per arm.'); +for (const arm of callArms) { + const dims = arm.pages.map((page) => `${page.width}x${page.height}`).join(','); + console.log( + `${arm.fixture.padEnd(5)} ${arm.profile.padEnd(11)} ${dims.padEnd(12)} ` + + `image=${String(arm.imageTokens).padStart(4)} input≈${String(arm.projectedInputTokens).padStart(4)} ` + + `text≈${String(arm.textTokensCharsPer4).padStart(4)} save≈${arm.estimatedSavingsVsTextPct}%`, + ); +} +console.log(`Projected maximum: ${preflight.totals.calls} calls, ${preflight.totals.imageTokens} image tokens, ` + + `≈${preflight.totals.projectedInputTokens} total input tokens.`); +console.log(`Preflight: ${PREFLIGHT_PATH}`); + +if (!LIVE) { + console.log('DRY RUN ONLY: no network request was made.'); + process.exit(0); +} +if (!HAS_APPROVAL) { + throw new Error( + `Paid calls are locked. After explicit approval, set SOL_PROFILE_PAID_APPROVAL=${APPROVAL_ACK}`, + ); +} + +let results; +let liveCallArms = callArms; +if (RESUME_SPACED_RETUNE) { + results = JSON.parse(await readFile(RESULTS_PATH, 'utf8')); + invariant(results.model === MODEL, 'Spaced-retune result model mismatch'); + invariant(results.calls.length === 3, 'Spaced retune requires exactly three prior attempts'); + const oldFailure = results.calls[2]; + invariant(oldFailure.fixture === 'alpha' && oldFailure.profile === 'old_shared', 'Unexpected old-profile attempt'); + invariant(oldFailure.score?.responseStatus === 'completed', 'Old-profile attempt did not complete'); + invariant(oldFailure.score?.exactCorrect === 0, 'Old profile did not clearly fail exact recall'); + invariant(oldFailure.score?.confabulations?.length === 4, 'Old profile failure did not contain four exact-field confabulations'); + liveCallArms = SPACED_RETUNE_ORDER.map(({ fixture, profile }) => { + const arm = preparedByKey.get(`${fixture}/${profile}`); + invariant(arm, `Missing spaced-retune arm ${fixture}/${profile}`); + return arm; + }); + invariant(results.calls.length + liveCallArms.length <= MAX_CALLS, 'Spaced retune would exceed paid-call cap'); + results.stoppedEarly = false; + results.stopReason = null; + results.finalRetune = { + reason: 'both 6x11 JetBrains and 5x8 Spleen returned 0/4 exact with four confabulations', + reviewedAt: new Date().toISOString(), + candidate: 'Sol-only JetBrains Mono 10 with effective 9x12 cells / 84 columns', + remainingOrder: SPACED_RETUNE_ORDER, + }; +} else if (RESUME_OLD_AS_RETUNE) { + results = JSON.parse(await readFile(RESULTS_PATH, 'utf8')); + invariant(results.model === MODEL, 'Retune result model mismatch'); + invariant(results.calls.length === 2, 'Old-profile retune requires exactly two prior attempts'); + const validFailure = results.calls[1]; + invariant(validFailure.fixture === 'alpha' && validFailure.profile === 'current_sol', 'Unexpected valid candidate attempt'); + invariant(validFailure.score?.responseStatus === 'completed', 'Candidate attempt did not complete'); + invariant(validFailure.score?.exactCorrect === 0, 'Candidate did not clearly fail exact recall'); + invariant(validFailure.score?.confabulations?.length === 4, 'Candidate failure did not contain four exact-field confabulations'); + liveCallArms = OLD_FALLBACK_RETUNE_ORDER.map(({ fixture, profile }) => { + const arm = preparedByKey.get(`${fixture}/${profile}`); + invariant(arm, `Missing old-profile retune arm ${fixture}/${profile}`); + return arm; + }); + invariant(results.calls.length + liveCallArms.length <= MAX_CALLS, 'Old-profile retune would exceed paid-call cap'); + results.stoppedEarly = false; + results.stopReason = null; + results.retune = { + reason: 'current Sol 6x11 profile returned 0/4 exact with four confabulations', + reviewedAt: new Date().toISOString(), + candidate: 'Sol-only fallback to old shared Spleen 5x8 / 152 columns', + remainingOrder: OLD_FALLBACK_RETUNE_ORDER, + }; +} else if (RESUME_AFTER_OUTPUT_CAP) { + results = JSON.parse(await readFile(RESULTS_PATH, 'utf8')); + invariant(results.model === MODEL, 'Resume result model mismatch'); + invariant(results.calls.length === 1, 'Output-cap resume requires exactly one prior attempt'); + const first = results.calls[0]; + invariant(first.fixture === 'alpha' && first.profile === 'current_sol', 'Unexpected first attempt'); + invariant(first.score?.responseStatus === 'incomplete', 'First attempt was not incomplete'); + invariant(first.score?.incompleteReason === 'max_output_tokens', 'First attempt was not output-capped'); + invariant(!first.score?.outputText, 'First attempt unexpectedly contained an answer'); + liveCallArms = OUTPUT_CAP_RESUME_ORDER.map(({ fixture, profile }) => { + const arm = preparedByKey.get(`${fixture}/${profile}`); + invariant(arm, `Missing resume arm ${fixture}/${profile}`); + return arm; + }); + invariant(results.calls.length + liveCallArms.length <= MAX_CALLS, 'Resume would exceed paid-call cap'); + results.stoppedEarly = false; + results.stopReason = null; + results.resume = { + reason: 'first attempt returned only hidden reasoning and hit max_output_tokens', + reviewedAt: new Date().toISOString(), + priorAttemptsCountAgainstCap: true, + changedReasoningEffort: 'none', + remainingOrder: OUTPUT_CAP_RESUME_ORDER, + }; +} else { + results = { + generatedAt: new Date().toISOString(), + model: MODEL, + live: true, + preflightSha256: sha256(JSON.stringify(preflight)), + plannedCalls: CALL_ORDER.length, + completedCalls: 0, + stoppedEarly: false, + stopReason: null, + calls: [], + }; +} +await writeJsonAtomic(RESULTS_PATH, results); + +for (let i = 0; i < liveCallArms.length; i++) { + const arm = liveCallArms[i]; + const sequence = results.calls.length + 1; + console.log(`CALL ${sequence}/${MAX_CALLS}: ${arm.fixture}/${arm.profile}`); + const receipt = await callResponses(arm, sequence); + const output = receipt.json ? extractOutput(receipt.json) : { text: '', refusals: [] }; + const score = scoreResponse(arm, receipt.json, output); + const row = { + sequence, + fixture: arm.fixture, + profile: arm.profile, + imageDimensions: arm.pages.map((page) => `${page.width}x${page.height}`), + estimatedImageTokens: arm.imageTokens, + estimatedSavingsVsTextPct: arm.estimatedSavingsVsTextPct, + latencyMs: receipt.latencyMs, + httpStatus: receipt.status, + responseHeaders: receipt.headers, + transportError: receipt.error, + usage: receipt.json?.usage || null, + responseId: receipt.json?.id || null, + responseModel: receipt.json?.model || null, + reasoningEffort: receipt.json?.reasoning?.effort || null, + rawResponseBody: receipt.rawBody, + rawResponseSha256: sha256(receipt.rawBody), + score, + }; + results.calls.push(row); + results.completedCalls = results.calls.length; + await writeJsonAtomic(RESULTS_PATH, results); + + console.log(` exact=${score.exactCorrect}/${score.exactTotal} gist=${score.gist.ok ? 'ok' : 'fail'} ` + + `guard=${score.guard.ok ? 'ok' : 'fail'} confab=${score.confabulations.length} ` + + `latency=${receipt.latencyMs}ms`); + + if (receipt.error || !score.pass) { + results.stoppedEarly = i < liveCallArms.length - 1; + results.stopReason = receipt.error + ? `transport/API failure on ${arm.fixture}/${arm.profile}: ${receipt.error}` + : `clear acceptance failure on ${arm.fixture}/${arm.profile}`; + await writeJsonAtomic(RESULTS_PATH, results); + console.log(`STOP: ${results.stopReason}`); + break; + } +} + +console.log(`Results: ${RESULTS_PATH}`); diff --git a/package.json b/package.json index be8a1c4..f350a47 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "bin/", "dist/", "!dist/**/*.map", + "assets/*LICENSE.txt", "README.md", "LICENSE" ], diff --git a/scripts/gen-atlas.ts b/scripts/gen-atlas.ts index c6fb48f..b90c4e7 100644 --- a/scripts/gen-atlas.ts +++ b/scripts/gen-atlas.ts @@ -52,6 +52,8 @@ const FALLBACK_FONT_PX = Number(process.env.ATLAS_FALLBACK_PX ?? PRIMARY_FONT_PX const FONT_FAMILY_LABEL = process.env.ATLAS_LABEL ?? `${PRIMARY_FONT_FAMILY} ${PRIMARY_FONT_PX}px + ${FALLBACK_FONT_FAMILY} ${FALLBACK_FONT_PX}px fallback`; +const PRIMARY_FONT_LABEL = process.env.ATLAS_PRIMARY_FONT ?? 'assets/Spleen-5x8.otb'; +const FALLBACK_FONT_LABEL = process.env.ATLAS_FALLBACK_FONT ?? 'assets/Unifont-16.0.04.otf'; const PROFILE = (process.env.ATLAS_PROFILE ?? 'full-bmp') as | 'practical' | 'full-bmp' @@ -223,14 +225,14 @@ for (const [lo, hi, label] of RANGES) { `[gen-atlas] ${label.padEnd(48)} ` + `U+${lo.toString(16).padStart(4, '0').toUpperCase()}..` + `U+${hi.toString(16).padStart(4, '0').toUpperCase()} ` + - `kept ${kept}/${hi - lo + 1} (spleen=${primary}, unifont=${fallback})`, + `kept ${kept}/${hi - lo + 1} (primary=${primary}, fallback=${fallback})`, ); } found.sort((a, b) => a.cp - b.cp); const wideCount = found.filter((f) => f.wide).length; const primaryCount = found.filter((f) => f.source === 'primary').length; -console.log(`[gen-atlas] total glyphs: ${found.length} (${wideCount} wide, ${primaryCount} Spleen primary)`); +console.log(`[gen-atlas] total glyphs: ${found.length} (${wideCount} wide, ${primaryCount} primary)`); // --- Rasterize glyphs ------------------------------------------------------ const contexts = { @@ -327,9 +329,9 @@ if (GRAY_MODE) { const grayBanner = `// AUTO-GENERATED by scripts/gen-atlas.ts (ATLAS_GRAY=1) — DO NOT EDIT. // Regenerate with: ATLAS_GRAY=1 npx tsx scripts/gen-atlas.ts -// EVAL-ONLY artifact: this file is NOT imported by the production render path. -// Source fonts: assets/Spleen-5x8.otb @ ${PRIMARY_FONT_PX}px for ASCII/code; assets/Unifont-16.0.04.otf @ ${FALLBACK_FONT_PX}px fallback (profile: ${PROFILE}) -// Glyphs: ${found.length} codepoints (${wideCount} wide, ${primaryCount} Spleen primary) +// Grayscale companion atlas; imported when RenderStyle.aa is true. +// Source fonts: ${PRIMARY_FONT_LABEL} @ ${PRIMARY_FONT_PX}px primary; ${FALLBACK_FONT_LABEL} @ ${FALLBACK_FONT_PX}px fallback (profile: ${PROFILE}) +// Glyphs: ${found.length} codepoints (${wideCount} wide, ${primaryCount} primary) // Pixel format: 1 coverage byte per pixel (0-255), raw R-channel from anti-aliased canvas. // ATLAS_GRAY_OFFSETS are BYTE offsets (not bit offsets like ATLAS_OFFSETS). `; @@ -447,8 +449,8 @@ const banner = `// AUTO-GENERATED by scripts/gen-atlas.ts — DO NOT EDIT. // Regenerate with: pnpm run build:atlas // (or ATLAS_PROFILE=practical pnpm run build:atlas to drop Hangul for // Workers free-tier deployments under the 1 MB compressed-bundle cap) -// Source fonts: assets/Spleen-5x8.otb @ ${PRIMARY_FONT_PX}px for ASCII/code; assets/Unifont-16.0.04.otf @ ${FALLBACK_FONT_PX}px fallback (profile: ${PROFILE}) -// Glyphs: ${found.length} codepoints (${wideCount} wide, ${primaryCount} Spleen primary) +// Source fonts: ${PRIMARY_FONT_LABEL} @ ${PRIMARY_FONT_PX}px primary; ${FALLBACK_FONT_LABEL} @ ${FALLBACK_FONT_PX}px fallback (profile: ${PROFILE}) +// Glyphs: ${found.length} codepoints (${wideCount} wide, ${primaryCount} primary) `; const body = ` diff --git a/src/core/applicability.ts b/src/core/applicability.ts index 713bbaf..b1c500b 100644 --- a/src/core/applicability.ts +++ b/src/core/applicability.ts @@ -24,17 +24,19 @@ function baseModelId(model: string): string { /** Dashboard runtime override; null = fall back to PXPIPE_MODELS env / built-in default. In-memory only. */ let runtimeModelBases: readonly string[] | null = null; -/** Built-in default scope when PXPIPE_MODELS is unset: Fable 5 (Claude) plus - * GPT 5.6. Everything else is opt-in via dashboard chips or PXPIPE_MODELS: +/** Built-in default scope when PXPIPE_MODELS is unset: Fable 5 only. + * Everything else is opt-in via dashboard chips or PXPIPE_MODELS: * - Opus 4.7/4.8 — worse at reading imaged content (FINDINGS.md 2026-06-16: * Opus 4.8 ~2pp arithmetic, 6/15 dense-hex vs Fable 100/100). * - GPT 5.5 — degrades on imaged history/context. - * - Grok — pure-image exact OCR fails at production 5×8 (0/4 IDs); image+ - * factsheet recovers exact IDs but the family is not default-quality for - * pxpipe yet (eval/grok-density/FACTSHEET_RESULTS.md). Keep off until that - * changes. - * Silently imaging weak readers is the wrong default. */ -const DEFAULT_MODEL_BASES = ['claude-fable-5', 'gpt-5.6']; + * - GPT 5.6 Sol — direct raw-image calls at both its 6×11 profile and the + * old shared 5×8 profile scored 0/4 exact with four confabulations. Its + * exact model profile remains available for explicit opt-in and retuning. + * - Grok — shared 5×8 pure-image exact recall failed 0/4 with silent + * confabulation. Effective 9×12 and a factsheet each rescued one synthetic + * fixture, but neither has representative-workload evidence yet. + * Silently imaging weak or unvalidated readers is the wrong default. */ +const DEFAULT_MODEL_BASES = ['claude-fable-5']; function falsey(v: string): boolean { return /^(0|false|no|off|none)$/i.test(v.trim()); @@ -42,9 +44,9 @@ function falsey(v: string): boolean { /** PXPIPE_MODELS env / built-in default, ignoring the runtime override. One CSV * controls every family (Claude + GPT). Resolution (read per-call so scope flips LIVE): - * - unset or empty → built-in default (Fable 5 + GPT 5.6) + * - unset or empty → built-in default (Fable 5 only) * - `off`/`0`/`false`/... → compress nothing - * - CSV of model bases → exactly those families (e.g. `claude-fable-5,gpt-5.6`) */ + * - CSV of model bases → exactly those families (e.g. `claude-fable-5,gpt-5.6-sol`) */ function envOrDefaultBases(): string[] { // Edge-safe: `process` is undefined off-Node; `typeof` avoids a ReferenceError. const raw = typeof process !== 'undefined' ? process.env?.PXPIPE_MODELS : undefined; diff --git a/src/core/atlas-gray-jbmono10.ts b/src/core/atlas-gray-jbmono10.ts new file mode 100644 index 0000000..c528f6d --- /dev/null +++ b/src/core/atlas-gray-jbmono10.ts @@ -0,0 +1,70 @@ +// AUTO-GENERATED by scripts/gen-atlas.ts (ATLAS_GRAY=1) — DO NOT EDIT. +// Regenerate with: ATLAS_GRAY=1 npx tsx scripts/gen-atlas.ts +// Grayscale companion atlas; imported when RenderStyle.aa is true. +// Source fonts: assets/JetBrainsMono-Regular.ttf @ 10px primary; assets/Unifont-16.0.04.otf @ 10px fallback (profile: ascii) +// Glyphs: 718 codepoints (22 wide, 95 primary) +// Pixel format: 1 coverage byte per pixel (0-255), raw R-channel from anti-aliased canvas. +// ATLAS_GRAY_OFFSETS are BYTE offsets (not bit offsets like ATLAS_OFFSETS). + +/** Latin advance width in pixels. CJK glyphs advance 12px (= 2 × this). */ +export const ATLAS_GRAY_CELL_W = 6; +/** Cell height in pixels. */ +export const ATLAS_GRAY_CELL_H = 11; +/** Distance from cell top to baseline. */ +export const ATLAS_GRAY_ASCENT = 9; +/** Distance from baseline to cell bottom. */ +export const ATLAS_GRAY_DESCENT = 2; + +// ---- base64 blobs (decoded once at module init) -------------------------- + +const GRAY_CODEPOINTS_B64 = "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lCIAAJUiAACWIgAAlyIAAJgiAACZIgAAmiIAAJsiAACcIgAAnSIAAJ4iAACfIgAAoCIAAKEiAACiIgAAoyIAAKQiAAClIgAApiIAAKciAACoIgAAqSIAAKoiAACrIgAArCIAAK0iAACuIgAAryIAALAiAACxIgAAsiIAALMiAAC0IgAAtSIAALYiAAC3IgAAuCIAALkiAAC6IgAAuyIAALwiAAC9IgAAviIAAL8iAADAIgAAwSIAAMIiAADDIgAAxCIAAMUiAADGIgAAxyIAAMgiAADJIgAAyiIAAMsiAADMIgAAzSIAAM4iAADPIgAA0CIAANEiAADSIgAA0yIAANQiAADVIgAA1iIAANciAADYIgAA2SIAANoiAADbIgAA3CIAAN0iAADeIgAA3yIAAOAiAADhIgAA4iIAAOMiAADkIgAA5SIAAOYiAADnIgAA6CIAAOkiAADqIgAA6yIAAOwiAADtIgAA7iIAAO8iAADwIgAA8SIAAPIiAADzIgAA9CIAAPUiAAD2IgAA9yIAAPgiAAD5IgAA+iIAAPsiAAD8IgAA/SIAAP4iAAD/IgAAACUAAAElAAACJQAAAyUAAAQlAAAFJQAABiUAAAclAAAIJQAACSUAAAolAAALJQAADCUAAA0lAAAOJQAADyUAABAlAAARJQAAEiUAABMlAAAUJQAAFSUAABYlAAAXJQAAGCUAABklAAAaJQAAGyUAABwlAAAdJQAAHiUAAB8lAAAgJQAAISUAACIlAAAjJQAAJCUAACUlAAAmJQAAJyUAACglAAApJQAAKiUAACslAAAsJQAALSUAAC4lAAAvJQAAMCUAADElAAAyJQAAMyUAADQlAAA1JQAANiUAADclAAA4JQAAOSUAADolAAA7JQAAPCUAAD0lAAA+JQAAPyUAAEAlAABBJQAAQiUAAEMlAABEJQAARSUAAEYlAABHJQAASCUAAEklAABKJQAASyUAAEwlAABNJQAATiUAAE8lAABQJQAAUSUAAFIlAABTJQAAVCUAAFUlAABWJQAAVyUAAFglAABZJQAAWiUAAFslAABcJQAAXSUAAF4lAABfJQAAYCUAAGElAABiJQAAYyUAAGQlAABlJQAAZiUAAGclAABoJQAAaSUAAGolAABrJQAAbCUAAG0lAABuJQAAbyUAAHAlAABxJQAAciUAAHMlAAB0JQAAdSUAAHYlAAB3JQAAeCUAAHklAAB6JQAAeyUAAHwlAAB9JQAAfiUAAH8lAACAJQAAgSUAAIIlAACDJQAAhCUAAIUlAACGJQAAhyUAAIglAACJJQAAiiUAAIslAACMJQAAjSUAAI4lAACPJQAAkCUAAJElAACSJQAAkyUAAJQlAACVJQAAliUAAJclAACYJQAAmSUAAJolAACbJQAAnCUAAJ0lAACeJQAAnyUAAA=="; +const GRAY_OFFSETS_B64 = "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FHYAAFZ2AACYdgAA2nYAABx3AABedwAAoHcAAOJ3AAAkeAAAZngAAKh4AADqeAAALHkAAG55AACweQAA8nkAADR6AAB2egAAuHoAAPp6AAA8ewAAfnsAAMB7AAACfAAARHwAAIZ8AADIfAAACn0AAEx9AACOfQAA0H0AABJ+AABUfgAAln4AANh+AABcfwAA4H8AAGSAAACmgAAA6IAAACqBAABsgQAAroEAAPCBAAAyggAAdIIAALaCAAD4ggAAOoMAAHyDAAC+gwAAAIQAAEKEAACEhAAAxoQAAAiFAABKhQAAjIUAAM6FAAAQhgAAUoYAAJSGAADWhgAAGIcAAFqHAACchwAA3ocAACCIAABiiAAA5ogAAGqJAACsiQAA7okAADCKAAByigAAtIoAAPaKAAA4iwAAeosAALyLAAD+iwAAQIwAAIKMAADEjAAABo0AAEiNAACKjQAAzI0AAA6OAABQjgAAko4AANSOAAAWjwAAWI8AAJqPAAAekAAAopAAAOSQAABokQAA7JEAAC6SAABwkgAA9JIAAHiTAAD8kwAAPpQAAMKUAAAElQAAiJUAAMqVAAAMlgAATpYAAJCWAADSlgAAFJcAAFaXAACYlwAA2pcAAByYAABemAAAoJgAAOKYAAAkmQAAZpkAAKiZAADqmQAALJoAAG6aAACwmgAA8poAADSbAAB2mwAAuJsAAPqbAAA8nAAAfpwAAMCcAAACnQAARJ0AAIadAADInQAACp4AAEyeAACOngAA0J4AABKfAABUnwAAlp8AANifAAAaoAAAXKAAAJ6gAADgoAAAIqEAAGShAACmoQAA6KEAACqiAABsogAArqIAAPCiAAAyowAAdKMAALajAAD4owAAOqQAAHykAAC+pAAAAKUAAEKlAACEpQAAxqUAAAimAABKpgAAjKYAAM6mAAAQpwAAUqcAAJSnAADWpwAAGKgAAFqoAACcqAAA3qgAACCpAABiqQAApKkAAOapAAAoqgAAaqoAAKyqAADuqgAAMKsAAHKrAAC0qwAA9qsAADisAAB6rAAAvKwAAP6sAABArQAAgq0AAMStAAAGrgAASK4AAIquAADMrgAADq8AAFCvAACSrwAA1K8AABawAABYsAAAmrAAANywAAAesQAAYLEAAKKxAADksQAAJrIAAGiyAACqsgAA7LIAAC6zAABwswAAsrMAAPSzAAA2tAAAeLQAALq0AAD8tAAAPrUAAIC1AADCtQAABLYAAEa2AACItgAAyrYAAAy3AABOtwAAkLcAANK3AAAUuAAAVrgAAJi4AADauAAAHLkAAF65AACguQAA4rkAACS6AABmugAAqLoAAOq6AAAsuwAAbrsAALC7AADyuwAANLwAAHa8AAC4vAAA+rwAADy9AAB+vQAAwL0AAAK+AABEvgAAhr4AAA=="; +const GRAY_WIDE_FLAGS_B64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEBAQEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAEBAAABAQEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; +const GRAY_PIXELS_B64 = "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AACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7s6QAAABiiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7s6QAAACw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/s6QAAC6IiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/s6QAAFzw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYYgAAiIiILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYYgAA8PDwXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/YgAAiIiILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/YgAA8PDwXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7s6QAAAC7nogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7s6QAAAC78vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/s6QAAC7PnogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAADvYs6QAAGL/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/s6QAAGL/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/s6QAAFz48vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAADvYs6QAAGL/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/s6QAAGL/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYYgAAiIjPYgAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYYgAA8PD4YgAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/YgAAiIjPYgAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYYgAAiJ7/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/YgAAiJ7/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/YgAA8PD4YgAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYYgAA8PL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/YgAA8PL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQAiIjPnogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQA8PD4nogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQAiIjP8vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQA8PD48vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQAiJ7/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQA8PL/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQAiJ7/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQA8PL/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QA8PDwm4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QAiIjF8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QA8PDw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QA8PDwm4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QAiJvw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QA8PDw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QAiIjPnogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QA8PD4nogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QAiIjP8vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QA8PD48vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QAiIjPnogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QAiJ7/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QAiJ7/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QA8PD4nogAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QAiJv48vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QA8PL/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QAiJ7/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QA8PD48vAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAApKTYs6QA8PL/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QA8PL/nogAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QAiJ7/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAApLP/s6QA8PL/8vAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApJt3pGgAiIBiiFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApJt3pGgA8OOw8JsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz8/Pz88Az8/Pz88AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWktgAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAC5ibQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC71s8AAAC71s8AAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADukpKQAAGLP3IgAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAC5ibQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGLpz88AAGK7z88AAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAC5ibQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz8/pYgAAz8/pYgAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkkAAAiJ7P1AAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAC5ibQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz8/P2gAAz9GkzwAAAGK7zwAAAGK7zwAAAGK7zwAAAGK7zwAAAC5ibQAAAACkVQAAAAC7YgAA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AGL/YgAAAKS7pAAAVcAAwFUApIgAiKQAzwAAAM8AbQAAAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKR3AAAAiIhiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3pKQAAABiiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKR3AAAA8PCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3pKQAAACw8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQAiIjF8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVQAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAFXwYgAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC6ILgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApKSkpKQA8PDFiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXgVQAAAGL/YgAAAGL/YgAAAGL/YgAAAGL/YgAAAC7PYgAAAAC7YgAAAAC7YgAAAAC7YgAAAAC7YgAAAABiLgAA4ODg4OAA//////8A//////8A//////8A//////8AiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////8AiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiIiIiIgA//////8A//////8AiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu7u7u7sA//////8A//////8A//////8AiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODg4OAA//////8A//////8A//////8A//////8AiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////8A//////8A//////8A//////8A//////8A//////8AiIiIiIgAAAAAAAAAAAAAAAAAiIiIiIgA//////8A//////8A//////8A//////8A//////8A//////8A//////8AiIiIiIgAAAAAAAAAu7u7u7sA//////8A//////8A//////8A//////8A//////8A//////8A//////8A//////8AiIiIiIgA4ODg4OAA//////8A//////8A//////8A//////8A//////8A//////8A//////8A//////8A//////8AiIiIiIgA4ODg4JAA/////6QA/////6QA/////6QA/////6QA/////6QA/////6QA/////6QA/////6QA/////6QAiIiIiFUA4ODgxQAA////4AAA////4AAA////4AAA////4AAA////4AAA////4AAA////4AAA////4AAA////4AAAiIiIdwAA4ODgVQAA////YgAA////YgAA////YgAA////YgAA////YgAA////YgAA////YgAA////YgAA////YgAAiIiILgAA4OCkAAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAAiIhiAAAA4NQAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAAiIAAAAAA4HcAAAAA/4gAAAAA/4gAAAAA/4gAAAAA/4gAAAAA/4gAAAAA/4gAAAAA/4gAAAAA/4gAAAAA/4gAAAAAiEUAAAAAtgAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAzwAAAAAAbQAAAAAAAACk4OAAAAC7//8AAAC7//8AAAC7//8AAAC7//8AAAC7//8AAAC7//8AAAC7//8AAAC7//8AAAC7//8AAABiiIgAp02XXDsAl5eId3cAhKd3fIQAhKd3fIQAp4SXcmgAp4SXcmgAl5eId3cAhKd3fIQAhKd3fIQAp4SXcmgAAG0ARVUAsLCkl5cAu7u7u7sAtra7wMAAtra7wMAAwMC7trYAwMC7trYAu7u7u7sAtra7wMAAtra7wMAAwMC7trYAVVVibW0A2tGw1qEA6eng2NgA4+fpzeMA4+fpzeMA7uvY480A7uvY480A6eng2NgA4+fpzeMA4+fpzeMA7uvY480AbXeIVYgA4ODg4OAAu7u7u7sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALYAAAAAAM8AAAAAAM8AAAAAAM8AAAAAAM8AAAAAAM8AAAAAAM8AAAAAAM8AAAAAAM8AAAAAAM8AAAAAAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OCkAAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAAiIhiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACk4OAAAAC7//8AAAC7//8AAAC7//8AAAC7//8AAABiiIgA4OCkAAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAAiIhiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OCkAAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAA///w4OAA//////8A//////8A//////8A//////8AiIiIiIgA4OCkAAAA//+7AAAA//+7AAAA//+7AAAA//+7AAAAiIi74OAAAAC7//8AAAC7//8AAAC7//8AAAC7//8AAABiiIgA4ODg4OAA//////8A//////8A//////8A//////8A///PiIgA//+7AAAA//+7AAAA//+7AAAA//+7AAAAiIhiAAAA4ODg4OAA//////8A//////8A//////8A//////8AiIjP//8AAAC7//8AAAC7//8AAAC7//8AAAC7//8AAABiiIgAAACk4OAAAAC7//8AAAC7//8AAAC7//8AAAC7//8AAABiiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACk4OAAAAC7//8AAAC7//8AAAC7//8AAAC7//8A4OC7iIgA//+7AAAA//+7AAAA//+7AAAA//+7AAAAiIhiAAAAAACk4OAAAAC7//8AAAC7//8AAAC7//8AAAC7//8A4ODw//8A//////8A//////8A//////8A//////8AiIiIiIgA"; + +/** Decode base64 → Uint8Array. Workers-safe (no Buffer / no node:zlib). */ +function decodeB64(b64: string): Uint8Array { + const bin = atob(b64); + const out = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i); + return out; +} + +function decodeU32(b64: string): Uint32Array { + const bytes = decodeB64(b64); + return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4); +} + +/** Sorted codepoint table. `ATLAS_GRAY_CODEPOINTS[rank]` is the codepoint at `rank`. */ +export const ATLAS_GRAY_CODEPOINTS: Uint32Array = /* @__PURE__ */ decodeU32(GRAY_CODEPOINTS_B64); + +/** BYTE offset into ATLAS_GRAY_PIXELS for the glyph at each rank. + * (Unlike the 1-bit atlas, this is a byte offset — 1 byte per pixel.) */ +export const ATLAS_GRAY_OFFSETS: Uint32Array = /* @__PURE__ */ decodeU32(GRAY_OFFSETS_B64); + +/** 1 if the glyph at this rank is double-wide (East Asian Wide), 0 otherwise. */ +export const ATLAS_GRAY_WIDE_FLAGS: Uint8Array = /* @__PURE__ */ decodeB64(GRAY_WIDE_FLAGS_B64); + +/** Coverage bytes (0-255), one byte per pixel. Runtime extraction: + * byteIdx = ATLAS_GRAY_OFFSETS[rank] + gy * srcW + gx + * coverage = ATLAS_GRAY_PIXELS[byteIdx] + * where srcW is ATLAS_GRAY_CELL_W (narrow) or 2*ATLAS_GRAY_CELL_W (wide). */ +export const ATLAS_GRAY_PIXELS: Uint8Array = /* @__PURE__ */ decodeB64(GRAY_PIXELS_B64); + +/** Number of glyphs in the gray atlas. */ +export const ATLAS_GRAY_NUM_GLYPHS = ATLAS_GRAY_CODEPOINTS.length; + +/** Binary-search the sparse codepoint table. Returns rank (≥0) or -1 if absent. + * Mirrors atlasRank() from atlas.ts but operates on ATLAS_GRAY_CODEPOINTS. */ +export function atlasGrayRank(codepoint: number): number { + let lo = 0; + let hi = ATLAS_GRAY_CODEPOINTS.length - 1; + while (lo <= hi) { + const mid = (lo + hi) >> 1; + const v = ATLAS_GRAY_CODEPOINTS[mid]!; + if (v === codepoint) return mid; + if (v < codepoint) lo = mid + 1; + else hi = mid - 1; + } + return -1; +} diff --git a/src/core/atlas-jbmono10.ts b/src/core/atlas-jbmono10.ts new file mode 100644 index 0000000..1f2e440 --- /dev/null +++ b/src/core/atlas-jbmono10.ts @@ -0,0 +1,77 @@ +// AUTO-GENERATED by scripts/gen-atlas.ts — DO NOT EDIT. +// Regenerate with: pnpm run build:atlas +// (or ATLAS_PROFILE=practical pnpm run build:atlas to drop Hangul for +// Workers free-tier deployments under the 1 MB compressed-bundle cap) +// Source fonts: assets/JetBrainsMono-Regular.ttf @ 10px primary; assets/Unifont-16.0.04.otf @ 10px fallback (profile: ascii) +// Glyphs: 718 codepoints (22 wide, 95 primary) + +/** Latin advance width in pixels. CJK glyphs advance 12px (= 2 × this). */ +export const ATLAS_CELL_W = 6; +/** Cell height in pixels. */ +export const ATLAS_CELL_H = 11; +/** Distance from cell top to baseline. */ +export const ATLAS_ASCENT = 9; +/** Distance from baseline to cell bottom. */ +export const ATLAS_DESCENT = 2; +/** Primary font size used when rasterizing ASCII/code glyphs. */ +export const ATLAS_FONT_PX = 10; +/** Font family label used at build time. Renderer never re-loads the font. */ +export const ATLAS_FONT_FAMILY = "JetBrains Mono 10px + Unifont 10px"; +/** Profile used to build this atlas. */ +export const ATLAS_PROFILE = "ascii"; + +// ---- base64 blobs (decoded once at module init) -------------------------- + +const CODEPOINTS_B64 = "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lCIAAJUiAACWIgAAlyIAAJgiAACZIgAAmiIAAJsiAACcIgAAnSIAAJ4iAACfIgAAoCIAAKEiAACiIgAAoyIAAKQiAAClIgAApiIAAKciAACoIgAAqSIAAKoiAACrIgAArCIAAK0iAACuIgAAryIAALAiAACxIgAAsiIAALMiAAC0IgAAtSIAALYiAAC3IgAAuCIAALkiAAC6IgAAuyIAALwiAAC9IgAAviIAAL8iAADAIgAAwSIAAMIiAADDIgAAxCIAAMUiAADGIgAAxyIAAMgiAADJIgAAyiIAAMsiAADMIgAAzSIAAM4iAADPIgAA0CIAANEiAADSIgAA0yIAANQiAADVIgAA1iIAANciAADYIgAA2SIAANoiAADbIgAA3CIAAN0iAADeIgAA3yIAAOAiAADhIgAA4iIAAOMiAADkIgAA5SIAAOYiAADnIgAA6CIAAOkiAADqIgAA6yIAAOwiAADtIgAA7iIAAO8iAADwIgAA8SIAAPIiAADzIgAA9CIAAPUiAAD2IgAA9yIAAPgiAAD5IgAA+iIAAPsiAAD8IgAA/SIAAP4iAAD/IgAAACUAAAElAAACJQAAAyUAAAQlAAAFJQAABiUAAAclAAAIJQAACSUAAAolAAALJQAADCUAAA0lAAAOJQAADyUAABAlAAARJQAAEiUAABMlAAAUJQAAFSUAABYlAAAXJQAAGCUAABklAAAaJQAAGyUAABwlAAAdJQAAHiUAAB8lAAAgJQAAISUAACIlAAAjJQAAJCUAACUlAAAmJQAAJyUAACglAAApJQAAKiUAACslAAAsJQAALSUAAC4lAAAvJQAAMCUAADElAAAyJQAAMyUAADQlAAA1JQAANiUAADclAAA4JQAAOSUAADolAAA7JQAAPCUAAD0lAAA+JQAAPyUAAEAlAABBJQAAQiUAAEMlAABEJQAARSUAAEYlAABHJQAASCUAAEklAABKJQAASyUAAEwlAABNJQAATiUAAE8lAABQJQAAUSUAAFIlAABTJQAAVCUAAFUlAABWJQAAVyUAAFglAABZJQAAWiUAAFslAABcJQAAXSUAAF4lAABfJQAAYCUAAGElAABiJQAAYyUAAGQlAABlJQAAZiUAAGclAABoJQAAaSUAAGolAABrJQAAbCUAAG0lAABuJQAAbyUAAHAlAABxJQAAciUAAHMlAAB0JQAAdSUAAHYlAAB3JQAAeCUAAHklAAB6JQAAeyUAAHwlAAB9JQAAfiUAAH8lAACAJQAAgSUAAIIlAACDJQAAhCUAAIUlAACGJQAAhyUAAIglAACJJQAAiiUAAIslAACMJQAAjSUAAI4lAACPJQAAkCUAAJElAACSJQAAkyUAAJQlAACVJQAAliUAAJclAACYJQAAmSUAAJolAACbJQAAnCUAAJ0lAACeJQAAnyUAAA=="; +const OFFSETS_B64 = "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FHYAAFZ2AACYdgAA2nYAABx3AABedwAAoHcAAOJ3AAAkeAAAZngAAKh4AADqeAAALHkAAG55AACweQAA8nkAADR6AAB2egAAuHoAAPp6AAA8ewAAfnsAAMB7AAACfAAARHwAAIZ8AADIfAAACn0AAEx9AACOfQAA0H0AABJ+AABUfgAAln4AANh+AABcfwAA4H8AAGSAAACmgAAA6IAAACqBAABsgQAAroEAAPCBAAAyggAAdIIAALaCAAD4ggAAOoMAAHyDAAC+gwAAAIQAAEKEAACEhAAAxoQAAAiFAABKhQAAjIUAAM6FAAAQhgAAUoYAAJSGAADWhgAAGIcAAFqHAACchwAA3ocAACCIAABiiAAA5ogAAGqJAACsiQAA7okAADCKAAByigAAtIoAAPaKAAA4iwAAeosAALyLAAD+iwAAQIwAAIKMAADEjAAABo0AAEiNAACKjQAAzI0AAA6OAABQjgAAko4AANSOAAAWjwAAWI8AAJqPAAAekAAAopAAAOSQAABokQAA7JEAAC6SAABwkgAA9JIAAHiTAAD8kwAAPpQAAMKUAAAElQAAiJUAAMqVAAAMlgAATpYAAJCWAADSlgAAFJcAAFaXAACYlwAA2pcAAByYAABemAAAoJgAAOKYAAAkmQAAZpkAAKiZAADqmQAALJoAAG6aAACwmgAA8poAADSbAAB2mwAAuJsAAPqbAAA8nAAAfpwAAMCcAAACnQAARJ0AAIadAADInQAACp4AAEyeAACOngAA0J4AABKfAABUnwAAlp8AANifAAAaoAAAXKAAAJ6gAADgoAAAIqEAAGShAACmoQAA6KEAACqiAABsogAArqIAAPCiAAAyowAAdKMAALajAAD4owAAOqQAAHykAAC+pAAAAKUAAEKlAACEpQAAxqUAAAimAABKpgAAjKYAAM6mAAAQpwAAUqcAAJSnAADWpwAAGKgAAFqoAACcqAAA3qgAACCpAABiqQAApKkAAOapAAAoqgAAaqoAAKyqAADuqgAAMKsAAHKrAAC0qwAA9qsAADisAAB6rAAAvKwAAP6sAABArQAAgq0AAMStAAAGrgAASK4AAIquAADMrgAADq8AAFCvAACSrwAA1K8AABawAABYsAAAmrAAANywAAAesQAAYLEAAKKxAADksQAAJrIAAGiyAACqsgAA7LIAAC6zAABwswAAsrMAAPSzAAA2tAAAeLQAALq0AAD8tAAAPrUAAIC1AADCtQAABLYAAEa2AACItgAAyrYAAAy3AABOtwAAkLcAANK3AAAUuAAAVrgAAJi4AADauAAAHLkAAF65AACguQAA4rkAACS6AABmugAAqLoAAOq6AAAsuwAAbrsAALC7AADyuwAANLwAAHa8AAC4vAAA+rwAADy9AAB+vQAAwL0AAAK+AABEvgAAhr4AAA=="; +const WIDE_FLAGS_B64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEBAQEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAEBAAABAQEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; +const PIXELS_B64 = "AAAAAAAAAAAAMMMMMAAMAAAeeeAAAAAAAAKKfaW+UUAAMeecOOfeMMAA5qu8PdVnAAAcWYY3m2dAAAMMMAAAAAAAGMIIIIIIMGAYMEEEEEEMYAAAMM/MeSAAAAAAMM/MMAAAAAAAAAAAMMIAAAAAeAAAAAAAAAAAAMMAACGGEMMIYYQAAeSSeSSSeAAAMcEEEEEfAAAeSSCGMYfAAAeGMOCCSeAAAEMIaS+CCAAAeQQeCCSeAAAMMYeSzSeAAAfTCGEEMIAAAeSSeSzSeAAAeSzSeGMMAAAAAMMAAMMAAAAAMMAAAMMIAAAGcQcGAAAAAAeAAeAAAAAAAYOCOYAAAAcGCGMIIIAAAeTz3/5/2QeAMMMeWeSzAAAeSSeSTSeAAAeSQQQQSeAAAeSSSSSSeAAAeQQeQQQeAAAfQQQeQQQAAAeSSQWSSeAAASSSeSSSSAAAeMMMMMMeAAACCCCCCycAAATWUcUWSTAAAQQQQQQQfAAAz///zzzzAAAaaaeeWWWAAAeSSSSSSeAAAeTTTeQQQAAAeSSSSSSeGCAeSTSeWWTAAAeSQcGDSeAAA/MMMMMMMAAASSSSSSSeAAAzSSaecMMAAAtt///eeeAAAzecMMeSzAAAzSeMMMMMAAAeCGMIYQeAAOIIIIIIIIOAQYYIMMEGGCAcEEEEEEEEcAAMMeSAAAAAAAAAAAAAAA/AIMAAAAAAAAAAAAeSeSyeAAAQQeSSSSeAAAAAeSQQSeAAACCeSSSSeAAAAAeSeQSeAAAPII/IIIIAAAAAeSSSSeCeAQQeSSSSSAAEMAcEEEEfAAEGAeGGGGGEcAQQSWcWWTAAA4IIIIIIPAAAAA+/////AAAAAeSSSSSAAAAAeSSSSeAAAAAeSSSSeQQAAAeSSSSeCCAAAeSSQQQAAAAAeScOSeAAAII+IIIIOAAAAASSSSSeAAAAAzSeeMMAAAAAt//eeeAAAAASeMMeSAAAAAzSeOMMMIAAAeGMIYeAAGMEEcEEEEGAMMMMMMMMMMAYMIIOIIIMYAAAAAb2AAAAAAAAAAAAAAAAAAAIAIIIIAAAAAIe46eIAAAAEMI8Ic+AAAAAic2UcAAAAAASM+eMIAAAAAIIAIIIAAAAI+8+cGcAAUUAAAAAAAAAAAI++y2+cAAAMOeOeAAAAAAAAKeUcUOAAAAAAAAcGGAAAAI++262cAAAcAAAAAAAAAAAIccIAAAAAAAAIeeIeeAAAAcEYwcAAAAAAcEc0YAAAAAMIAAAAAAAAAAAA2222+gAAAO++eOOOOAAAAAAIIAAAAAAAAAAAAAYAAAY4IYcAAAAAMWWMeAAAAAAAAo8UcU4AAAAA2UYOe2AAAAA2UYMW+AAAAQec4Oe2AAAAAIAIQ2cAAYMIcU2+22AAMYIcU2+22AAIUIcU2+22AAeMIcU2+22AAUUIcU2+22AAIcIcU2+22AAAAOe4+44+AAAAI+yww2cYAYMc8w8ww+AAMYc8w8ww+AAIUc8w8ww+AAUUc8w8ww+AAIEMcIIIIeAAMYMcIIIIeAAIUMcIIIIeAAUUMcIIIIeAAAAY82+228AAeMA22++22AAYMI+2222cAAMYI+2222cAAIUI+2222cAAeMI+2222cAAUUI+2222cAAAAAAAUc2AAAAAO82++28gAYMA22222cAAMYA22222cAAIUA22222cAAUUA22222cAAMYAyWcIIIAAAAw4028wwAAAAI804028AAAYMAcGe2eAAAMYAcGe2eAAAIUAcGe2eAAAY8AcGe2eAAAUUAcGe2eAAAcIAcGe2eAAAAAAeOe4eAAAAAAcwwwcYAAYMAc28wcAAAMYAc28wcAAAIUAc28wcAAAUUAc28wcAAAYMAIIIIeAAAMYAIIIIeAAAIUAIIIIeAAAUUAIIIIeAAAYMWe+22cAAAY8A82222AAAYMAc222cAAAMYAc222cAAAIUAc222cAAAY8Ac222cAAAUUAc222cAAAAAAIAcIIAAAAACc+++cgAAYMA2222eAAAMYA2222eAAAIUA2222eAAAUUA2222eAAAMYA222eOeIAAww82228wAAUUA222eOeIAAAAAYeIAAAAIccIIIIIIAAAAAAM8IAAAIIIIIIIeMAAAAAAU2+UAAAAIccIIIeMAAAAA4w4EAAAAAAAOGOQAAAAAAAgQOOAAAAAAAAGs44AAAAAAEEceMEAAAAAQQc8YQAAAAAAAAAAYYY8HEAAAAAAAAAAAAAAAAYY8YjgAAAAAAAAAAAAU8+UAAAAIcccIIIIIAAAAAUe+UAAAIIIIIIcMcIAAAAACecKAAAAAAAg8coAAAAAAAAeeKAAAAIccIIIIeAAAAAAA88oAAAAcMIIIIeMAAAIccIIcMeAAAAAACacIAAAAAAAU2eEAAAAAAAGecMAAAAAAAU+eMAAAAAAAU+2UAAAAAAIc++cIAAAAw444IeMAAAAAAAYcMEEAAAAAAMcYQQAEEEEEcYIAAAQQQQQcMIAAAAAAAAA8OEAAEEEEEccIAAAAAAAe6aAAAAAAAA8usAAAAAA+4w4EAAAAAA4+wAO+OAAAAAAU8++cAAAAAAUe++cAAAAAAAYeAAAAAAAAAAeIAAAAIMMIIIIIIAAIYYIIIIIIAAAAAAM8AAAAAAAAAA8IAAAIIIIIIIOMAAIIIIIIIYIAAAAM+EAY+YAAAU80UUUeUAAAAY+QAM+MAAAAY+QAY+YAAAU+2UUUUUAAAAM+EAM+MAAAUUUUUU+cAAAAAAY+cMAAAAAAAM+cYAAAAAAIY+8cIAAAAAIc++cIAAAAAIM+ecIAAAAAAAecIAAAAIccMMMMMAAAAAAA8cIAAAAMMMMMMeMAAAAAAU++UAAAAIccMMMeMAAAAA448MAAAAAAAOOeYAAAAAAAQ4eOAAAAAAAEO84AAAAAAAAc88eAAAAAAAcee8AAAAAAAQ2+QAAAAAAAE2+EAAAAIccIecMIIAIIIecMIeMAAAAAAAQeIAAAAIccIIIIIIAAAAAEG+EAAAIIAIIAIeMAAAAAAA4+4AAAAAAAAO+OAAAAAAAY+uYAAAAIc+MMMMMAAAAAAM+6MAAAAMMMMMeWMAAAIc+MMMMMAAAIc2WWWy+AAAIc+WWWy+AAAIc+eee++AAAMeW2WWWeAAAMeW2WWy+AAAAAAc+68AAAAAA+888ywAAAAACCSOO+AAAIccMMMeMAAAAAAAAAAGAPY/4GQAAAAAAAUeWUUU8UAAAAE+GG+E+GAAAAAU0+UAAAAAAAUW+UAAAAAAAAAAACgKwfwKgAAAAAAAAAAAAAACAbgf8LAAAAAAAAAAAAAAABAHY/4DQAAAAAAAAAAAAAABAfQf4LQAAAAAAAAAAQw+QAAAAAAAEG+EAAAAAAAAAAAAAMwf4IQAAAAAAAAAyeWMMIAAAAIcUQQUcAAAAIeGOW0cAAAAceG+GG+AAAEceO+eW+wAAAAAOe+68AAAAAIMMWS+AAAAe+WWMMIAAAAAAc88weAAAAAEc884eQAAAAAAAc+eAAAAAAceeG8AAAAAEceee8QAAAAAAAc+8AAAAc++++++AAAAeeWWWWW+AAAWWWWWWW+AAAc+QIMYy+AAAAAAAcAAAAAAeeIMeIAAAAIMAIMeIAAAAAAEEIIQwAAAAAQQIIEGAAAAAAccMeAAAAAAAAIUIAAAAAAAAIcIAAAAGEEE8MMEEAAWcc08MMEEAAO8cM8MMEEAAAAAU8cAAAAAAAAU+eAAAAAAAAAwww+AAAAAAAGMY+AAAAAAAGMc+EAAAAAAMcMOAAAAIIIIIIIAAAAIIOMY4IAAAAAUUUUUUAAAAAUWcc0UAAAAAAIMcSyAAAAAAyScMIAAAAAAc2222AAAAAA2222cAAAOIIIIIIYYAAOMMMMMM84AAeeeeeee+8AAOIIceMIYYAAOMMe+cM84AAee+++ee+8AAOIIeeIIYYAAOIIeecIYYAAOII8+cIYYAAAAAIIA2UAAAAAA2UAIIAAAAAAIIAIIAAAAAA2UA2UAAAAAAIIcAAAAAAAAGEYGEAAAAAA2Uc2UAAAAAIIeMIIAAAAAAAeMAAAAAAAAA8YAAAAAAAAAaeAAAAAAAAQ4KGAAAAAAIIIIIAAAAAAAEMcYQAAAAAAA+AeEAAAAAAQ8A+AAAAAEMc8I+QwAAAA8A+A+AAAAAA8G+I+wAAAEM8I+Y+wgAAAAAQ8Y8AAAAAAEc8Y8QAAAAAaseM+AAAAAAaseMeEAAAAAeA+A+AAAAAAA+Ic2AAAAAAAcUUIAAAAAAAI+A+AAAAAIIA+A+AAAAAII+AcIIAAAAwQ+AcGEAAAAGE+AcwQAAAAAAMMMAAAAAAAAYYYAAAAAAAAcccAAAAAAcUI+A+AAAAAI+A+A+AAAAAc2A+A+AAAAA2cA+A+AAAAIeMA+A+AAAAIceA+A+AAAAIc88AcccAAAA888+A+AAAAYIIAIcccAAAAAAG+I+wAAAAAAccc+AAAAAACccc+wAAAAAA++cccAAAAAAO4MccAAAAAA4OYccAAAAO4MEcccAAAA4OYQcccAAAAO4MEcccgAAA4OYUcccgAAAAKe8oUKAAAAAo8eKUoAAAAAccUUIcAAAAGE+ccywgAAAIMIYYYcQAAAAoYIMYwQAAAAGO8MccQAAAAI4OYc8gAAAAAO4MA8AAAAAA4OYQ8AAAAAEO4Mc8QAAAAI4OYY8QAAAEM4OYO4AAAAQYO4M4OAAAAGM4eYewgAAEUYO4c4ewAAAACGMYEGAAAAAgwYMQwAAAAACGMY8MCAAAAgwYMeYgAAAACGMYU+AAAAAgwYMY+AAAAAGOMYcWAAAAAk4cMYwQAAAAAewweAAAAAAA8GG8AAAAAAEe44ewAAAAAG8OO8QAAAAAAewwe+AAAAAA8GG8+AAAAAEe44e+gAAAAG8OO8+gAAAAAewwe+IAAAAA8GG8+QAAAA22+++cAAAAA222+2cAAAAA22+++cAAAAAA+ww+AAAAAAA+GG+AAAAAAA+ww++AAAAAA+GG++AAAAAA+22iAAAAAAA222+AAAAAAAc++eMAAAAAAcy+eMAAAAAAc++eMAAAAAAc26eMAAAAAAcy6eMAAAAAAc++eMAAAAAAc++eMAAAAAAc++eMAAAAAAcy+eMAAAAAA++++eAAAAAA+y++eAAAAAA++++eAAAAAA+y6+eAAAAAAww8wAAAAAAAGGeGAAAAAAA+IIIAAAAAAAIIIeeAAAAAQQQcQQAAAAAQQccQQAAAAAgw+8wwAAAAA444844AAAAA888+88AAAAA44+844AAAAAgw884wAAAAAg4+88wAAAAA488884AAAAA48+888AAAAAMGMYEMAAAAAYwYMQYAAAAAAEOeGAAAAAAAQ48wAAAAAAAEOeG+AAAAAAQ48w+AAAAAAAAAAQI4c/8YYAAAAAAAAAAAAAAQI4c/8YYAAAAAAAAAAAAAAAwB4foAwAAAAAAAAAAIASIAAAAAMcIIIIIAAAAAAQWMIeAAAAAAeIMWQAAAAAAeScMAAAAAAAAw44+AAAAAAAGOe+AAAAAMMWWyyAAAAAyyWcMMAAAAI+22222AAAAA22222cAAAAAAAMcIAAAAAAAAIIAAAAAAAAAeMAAAAAAAAIUc+IAAAAAAy++2CAAAAAAy882CAAAAAAyeOWCAAAAAAQYMWAAAAAAAAEMWAAAAAAAA8YccAAAAAAyWMMAAAAAAAMMcSCAAAAAAe+4+eAAAAAA8+O+8AAAAAAe6+++AAAAAA+++6eAAAAAIMeeeeAAAAAUU+U+UAAAAACEIYMGAAAAAgQIMYwAAAAAAAACkFIKQawNYGsAAAAAAAAAAlASgJQNYaw1gAAAAAEYYG+QMMwAAQMMw+EYYGAAAAA+GYMEAAAAAA+wMYQAAAAAEecYEGAAAAAQ8cMQwAAAAEO+8YMWQAAAGu2eMYwQAAAGE+44++gAAAGE+OO++gAAAAA+ww++QAAAAA+GG++QAAAAGYYEecgAAAAwMMUecgAAAGEYYEecgAAAwYOY0ecgAAAACGOeOQQAAAAEU884wgAAAACGOeO+QAAAAEU884+gAAAIIAIIIIAAAAAAA+qAAAAAACGAIIgwAAAAgwAIICGAAAAAAAAHwIAYAfwIAHwAAAAAAAAAAHwIAIQPwIAHwAAAAAAAAe2+8cAAAADADAHwIAIAPwIAHwAAAAAAAAPwHwIAIAPwIAHwAAAAAAccew88cAAAAAAew88c+AAAAAAAPAQA/A/AwAfAAAAAAAAAAAfABgAgfwAgfAAAAAAAAAAAfABgQgfgAgfAAAAAAAAA82+ecAAAAAAfgfABgAgfgAgfAAAAAAAcc8GeecAAAAAAAAPwIAIAPwIAPwAAAAAAAA++AAAAAAAAA++AAAAAIIIIIIIIIIAIIIIIIIIIIIAAAAqqAAAAAAAAAq+AAAAAIIIAIIIAIIAIIIAIIIIIIIAAAAwAAAAAAAAAAw+AAAAAIIAIIIIAIIAIIIIIIIIIIAAAAAGOIIIIAAAAAGOIIIIAAAAAOOIIIIIAAAAOOIIIIIAAAA44IIIIAAAAA44IIIIAAAAA44IIIIIAAAA44IIIIIIIIIOGAAAAAIIIIOOAAAAAIIIIOOAAAAAIIIIOOAAAAAIIII44AAAAAIIII44AAAAAIIII44AAAAAIIII44AAAAAIIIIOOIIIIAIIIIOOIIIIAIIIIOOIIIIAIIIIOOIIIIIIIIIOOIIIIIIIIIOOIIIIAIIIIOOIIIIIIIIIOOIIIIIIIII44IIIIAIIII44IIIIAIIII44IIIIAIIII44IIIIIIIII44IIIIIIIII44IIIIAIIII44IIIIIIIII44IIIIIAAAA++IIIIAAAAA++IIIIAAAAA++IIIIAAAAA++IIIIAAAAA++IIIIIAAAA++IIIIIAAAA++IIIIIAAAA++IIIIIIIII++AAAAAIIII++AAAAAIIII++AAAAAIIII++AAAAAIIII++AAAAAIIII++AAAAAIIII++AAAAAIIII++AAAAAIIII++IIIIAIIII++IIIIAIIII++IIIIAIIII++IIIIAIIII++IIIIAIIII++IIIIIIIII++IIIIIIIII++IIIIAIIII++IIIIAIIII++IIIIIIIII++IIIIIIIII++IIIIAIIII++IIIIIIIII++IIIIIIIII++IIIIIIIII++IIIIIAAAA00AAAAAAAAA0+AAAAAIIIIAIIIIAAIIIIAIIIIAAAAAA++AAAAAMMMMMMMMMMAAAAAOOIIIIAAAAAOOMMMMAAAAAOOMMMMAAAAA44IIIIAAAAA88MMMMAAAAA88MMMMAIIIIOOAAAAAMMMMOOAAAAAMMMMOOAAAAAIIII44AAAAAMMMM84AAAAAMMMM88AAAAAIIIIOOIIIIAMMMMOOMMMMAMMMMOOMMMMAIIII44IIIIAMMMM88MMMMAMMMM88MMMMAAAAA++IIIIAAAAA++MMMMAAAAA++MMMMAIIII++AAAAAMMMM++AAAAAMMMM++AAAAAIIII++IIIIAMMMM++MMMMAMMMM++MMMMAAAAACGIIIIAAAAAw4IIIIAIIII4wAAAAAIIIIGCAAAAACCGEIIYQwgAggwQIIMEGCAii2UIIcU2iAAAAAwwAAAAAIIIIIAAAAAAAAAAGGAAAAAAAAAAIIIIIAAAAAw4AAAAAIIIIIIAAAAAAAAAGOAAAAAAAAAAIIIIIIAAAA++AAAAAIIIIIIIIIIIAAAA++AAAAAIIIIIIIIIIA++++++AAAAAAAAAAAAAA++AAAAAAA++++AAAAAA+++++AAAAA++++++AAAA+++++++AA+++++++++A+++++++++++++++++++++++++++++++888888888884444444444444444444444wwwwwwwwwwwwgwwwwwwwwwgggggggggggAOOOOOOOOOOGo4yy444yy4A++++++++++A++++++++++K++AAAAAAAAACCCCCCCCCCAAAAAA44444wAAAAAOOOOOG44444wAAAAA44444++++++44444+OOOOG++++++4444w++++++OOOOGOOOOOGAAAAAOOOOO+4444wOOOOO++++++"; + +/** Decode base64 → Uint8Array. Workers-safe (no Buffer / no node:zlib). */ +function decodeB64(b64: string): Uint8Array { + const bin = atob(b64); + const out = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i); + return out; +} + +function decodeU32(b64: string): Uint32Array { + const bytes = decodeB64(b64); + return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4); +} + +/** Sorted codepoint table. `ATLAS_CODEPOINTS[rank]` is the codepoint stored + * at `rank` in OFFSETS / WIDE_FLAGS / PIXELS. */ +export const ATLAS_CODEPOINTS: Uint32Array = /* @__PURE__ */ decodeU32(CODEPOINTS_B64); + +/** BIT offset into ATLAS_PIXELS for the glyph at each rank. */ +export const ATLAS_OFFSETS: Uint32Array = /* @__PURE__ */ decodeU32(OFFSETS_B64); + +/** 1 if the glyph at this rank is double-wide (East Asian Wide), 0 otherwise. */ +export const ATLAS_WIDE_FLAGS: Uint8Array = /* @__PURE__ */ decodeB64(WIDE_FLAGS_B64); + +/** Bit-packed 1-bit pixel data, MSB-first. Runtime extraction: + * bitIdx = OFFSETS[rank] + row * srcW + col + * byteIdx = bitIdx >>> 3 + * bitOff = 7 - (bitIdx & 7) + * pixel = (ATLAS_PIXELS[byteIdx] >>> bitOff) & 1 + * where srcW is CELL_W (narrow) or 2*CELL_W (wide, per WIDE_FLAGS[rank]). */ +export const ATLAS_PIXELS: Uint8Array = /* @__PURE__ */ decodeB64(PIXELS_B64); + +/** Number of glyphs in the atlas. */ +export const ATLAS_NUM_GLYPHS = ATLAS_CODEPOINTS.length; + +/** Binary-search the sparse codepoint table. Returns rank (≥0) or -1 if the + * codepoint is not in the atlas. Hot path; called once per rendered char. */ +export function atlasRank(codepoint: number): number { + let lo = 0; + let hi = ATLAS_CODEPOINTS.length - 1; + while (lo <= hi) { + const mid = (lo + hi) >> 1; + const v = ATLAS_CODEPOINTS[mid]!; + if (v === codepoint) return mid; + if (v < codepoint) lo = mid + 1; + else hi = mid - 1; + } + return -1; +} diff --git a/src/core/export.ts b/src/core/export.ts index 522cd3a..db69cdc 100644 --- a/src/core/export.ts +++ b/src/core/export.ts @@ -18,8 +18,8 @@ import { // consumers import (pxpipe-proxy/transform → renderTextToImages), not the // internal leaf renderer. import { renderTextToImages } from './library.js'; -import { estimateImageCount, ANTHROPIC_PIXELS_PER_TOKEN, IMAGE_COST_SAFETY_MARGIN, REPORT_CHARS_PER_TOKEN } from './transform.js'; -import { openAIVisionTokens } from './openai.js'; +import { estimateImageCount, REPORT_CHARS_PER_TOKEN } from './transform.js'; +import { visionTokensForModel } from './openai.js'; import { factSheetTextFromEntries, extractFactSheetTokensAllPages, @@ -249,17 +249,12 @@ export function parseExportArgv( * * - **Claude / Anthropic models** (`model.startsWith('claude')` or * `model.includes('anthropic')`): uses Anthropic's billing formula - * `ceil(width × height / 750 × 1.10)` (the same formula and constants as - * `imageTokensForRows` in transform.ts, reusing the exported - * `ANTHROPIC_PIXELS_PER_TOKEN` / `IMAGE_COST_SAFETY_MARGIN` consts). - * - **GPT / o-series models**: delegates to `openAIVisionTokens` which uses the - * GPT-4o tile-pricing formula (85 + 170 × tiles after scaling). + * `ceil(width × height / 750 × 1.10)`, matching the live transform. + * - **OpenAI-shaped models**: delegates to the same exact-model router as the + * proxy (Grok measured pixel rate; GPT tile/patch rate). */ export function exportImageTokens(model: string, width: number, height: number): number { - if (model.startsWith('claude') || model.includes('anthropic')) { - return Math.ceil((width * height / ANTHROPIC_PIXELS_PER_TOKEN) * IMAGE_COST_SAFETY_MARGIN); - } - return openAIVisionTokens(model, width, height); + return visionTokensForModel(model, width, height); } // --------------------------------------------------------------------------- diff --git a/src/core/gpt-model-profiles.ts b/src/core/gpt-model-profiles.ts index 530fc1c..e615840 100644 --- a/src/core/gpt-model-profiles.ts +++ b/src/core/gpt-model-profiles.ts @@ -3,17 +3,16 @@ * * One place to retune when a new model ships with different image tokenization, * a different downscale threshold (max safe portrait-strip width), or a different - * max image height. Every built-in profile is BEHAVIOR-IDENTICAL to the old - * hardcoded `resolveVisionCost` + `GPT_STRIP_COLS` + `MAX_HEIGHT_PX`, so existing - * cost numbers (1190 / 1445 / 2372 / 1464 / 630 …) are unchanged. + * max image height. Unknown models preserve the conservative legacy fallback; + * named profiles may deliberately select different fonts and geometry. * * Retune without a code change via the PXPIPE_GPT_PROFILES env var (JSON map of * model-id PREFIX -> partial profile; longest matching prefix wins, checked * BEFORE the built-in table). Partial fields fall back to the built-in match, so * you can override just one knob: * - * PXPIPE_GPT_PROFILES='{"gpt-5.6":{"vision":{"regime":"patch","multiplier":1,"patchCap":12000},"stripCols":200,"maxHeightPx":2400}}' - * PXPIPE_GPT_PROFILES='{"gpt-5.6":{"stripCols":176}}' # widen only + * PXPIPE_GPT_PROFILES='{"gpt-5.6-sol":{"vision":{"regime":"patch","multiplier":1,"patchCap":12000},"stripCols":120,"maxHeightPx":1900}}' + * PXPIPE_GPT_PROFILES='{"gpt-5.6-sol":{"style":{"grid":true,"gridCols":4}}}' */ /** @@ -26,7 +25,9 @@ */ import { MAX_HEIGHT_PX as ANTHROPIC_MAX_HEIGHT_PX, - DENSE_CONTENT_COLS as ANTHROPIC_STRIP_COLS, + ANTHROPIC_SLAB_COLS as ANTHROPIC_STRIP_COLS, + DEFAULT_RENDER_FONT, + type RenderFont, } from './render.js'; export const GPT_MAX_HEIGHT_PX = 1932; @@ -37,27 +38,37 @@ export type GptVisionCost = | { regime: 'patch'; multiplier: number; patchCap: number }; export interface GptRenderStyle { + /** Rasterized font atlas. */ + font: RenderFont; /** Extra px beside the 5px glyph (cell width = 5 + this). */ - cellWBonus?: number; + cellWBonus: number; /** Extra px above the 8px glyph (cell height = 8 + this). */ - cellHBonus?: number; + cellHBonus: number; /** Grayscale AA atlas. Default true for production dense pages. */ - aa?: boolean; + aa: boolean; + /** Faint cell guides. */ + grid: boolean; + /** Vertical guide cadence when grid is enabled. */ + gridCols: number; + /** Per-glyph color cycle. */ + colorCycle: boolean; + /** Horizontal scale for the hard-newline marker. */ + markerScale: number; + /** Render hard-newline markers in red. */ + markerRed: boolean; } export interface GptModelProfile { /** How OpenAI bills the rendered images as input tokens. */ vision: GptVisionCost; - /** Max portrait-strip width in COLUMNS before the API downscales (destroying - * 5px glyphs). 152 cols x 5px + 8px pad = 768px = OpenAI's shortest-side floor. */ + /** Max portrait-strip width in columns. Combined with `style`, this must stay + * at or below the provider's no-resize pixel width. */ stripCols: number; /** Max rendered image height in px. Threaded into the renderer so the gate's * cost estimate and the actual page split agree. */ maxHeightPx: number; - /** Glyph density / spacing. Omitted fields fall through to renderer defaults - * (production 5x8: cellWBonus=0, cellHBonus=0, aa=true). Models that confabulate - * exact strings at production density set larger bonuses here. */ - style?: GptRenderStyle; + /** Complete model-specific font, cell spacing, color, and marker style. */ + style: GptRenderStyle; } /** Default downscale-safe strip width (768px). Exported as the global cols default. */ @@ -65,6 +76,17 @@ export const DEFAULT_GPT_STRIP_COLS = 152; const C = DEFAULT_GPT_STRIP_COLS; const H = GPT_MAX_HEIGHT_PX; +const BASE_STYLE: GptRenderStyle = { + font: DEFAULT_RENDER_FONT, + cellWBonus: 0, + cellHBonus: 0, + aa: true, + grid: false, + gridCols: 0, + colorCycle: false, + markerScale: 1, + markerRed: false, +}; /** * Conservative fallback for unrecognized models: tile 85/170 over-states cost, @@ -74,7 +96,16 @@ export const DEFAULT_GPT_PROFILE: GptModelProfile = { vision: { regime: 'tile', base: 85, perTile: 170 }, stripCols: C, maxHeightPx: H, - style: { cellWBonus: 0, cellHBonus: 0, aa: true }, + style: BASE_STYLE, +}; + +const GPT56_SOL_PROFILE: GptModelProfile = { + vision: { regime: 'patch', multiplier: 1, patchCap: 10000 }, + stripCols: 126, + maxHeightPx: H, + // Separate atlas selected by model id. Cell remains within OpenAI's 768px + // short-side floor (126 cols x 6px + padding = 764px). + style: { ...BASE_STYLE, font: 'jetbrains-mono-10' }, }; interface ProfileRule { @@ -95,33 +126,34 @@ const BUILTIN_RULES: ProfileRule[] = [ // nano patch models: ceil(patches * 2.46), cap 1536 { test: (m) => isMiniNanoPatch(m) && /nano/.test(m), - profile: { vision: { regime: 'patch', multiplier: 2.46, patchCap: 1536 }, stripCols: C, maxHeightPx: H }, + profile: { vision: { regime: 'patch', multiplier: 2.46, patchCap: 1536 }, stripCols: C, maxHeightPx: H, style: BASE_STYLE }, }, // mini / o4-mini patch models: ceil(patches * 1.62), cap 1536 { test: (m) => isMiniNanoPatch(m) && !/nano/.test(m), - profile: { vision: { regime: 'patch', multiplier: 1.62, patchCap: 1536 }, stripCols: C, maxHeightPx: H }, + profile: { vision: { regime: 'patch', multiplier: 1.62, patchCap: 1536 }, stripCols: C, maxHeightPx: H, style: BASE_STYLE }, }, - // gpt-5.6 flagship — EXPLICIT slot so the day-one retune is one line (or one env - // var). Identical to the generic 5.x rule below until the real numbers land. + // Exact Sol variant observed on production traffic. Do not match bare 5.6 or + // sibling variants (for example gpt-5.6-terra): model-specific visual tuning + // must not leak across variants merely because they share a version number. { - test: (m) => /^gpt-5\.6/.test(m), - profile: { vision: { regime: 'patch', multiplier: 1, patchCap: 10000 }, stripCols: C, maxHeightPx: H }, + test: (m) => m === 'gpt-5.6-sol' || m.startsWith('gpt-5.6-sol-'), + profile: GPT56_SOL_PROFILE, }, // 5.x flagship (gpt-5.4/5.5/…, no -mini/-nano): patch, multiplier 1, detail:original cap { test: (m) => /^gpt-5\.\d/.test(m), - profile: { vision: { regime: 'patch', multiplier: 1, patchCap: 10000 }, stripCols: C, maxHeightPx: H }, + profile: { vision: { regime: 'patch', multiplier: 1, patchCap: 10000 }, stripCols: C, maxHeightPx: H, style: BASE_STYLE }, }, // gpt-5 / gpt-5-chat-latest: tile 70/140 { test: (m) => /^gpt-5/.test(m), - profile: { vision: { regime: 'tile', base: 70, perTile: 140 }, stripCols: C, maxHeightPx: H }, + profile: { vision: { regime: 'tile', base: 70, perTile: 140 }, stripCols: C, maxHeightPx: H, style: BASE_STYLE }, }, // o1 / o3 reasoning: tile 75/150 { test: (m) => /^o[13]/.test(m), - profile: { vision: { regime: 'tile', base: 75, perTile: 150 }, stripCols: C, maxHeightPx: H }, + profile: { vision: { regime: 'tile', base: 75, perTile: 150 }, stripCols: C, maxHeightPx: H, style: BASE_STYLE }, }, // Claude on the Responses path (Codex-style clients). Selection is by model @@ -137,15 +169,15 @@ const BUILTIN_RULES: ProfileRule[] = [ vision: { regime: 'tile', base: 85, perTile: 170 }, stripCols: ANTHROPIC_STRIP_COLS, maxHeightPx: ANTHROPIC_MAX_HEIGHT_PX, - style: { cellWBonus: 0, cellHBonus: 0, aa: true }, + style: { ...BASE_STYLE }, }, }, - // Grok (Responses path). Production 5x8 packing maximizes pixel savings - // (measured ~1000 image tok/MPix). Exact-ID OCR is weak at that density, so - // the Responses transform keeps a verbatim fact-sheet of paths/hex/ports/ - // camelCase ids next to the image (see factsheet.ts). Do NOT inflate cell - // bonuses here just to pass OCR tests — that trades away the savings. + // Grok (Responses path). Live climb 2026-07-09 on grok-4.5: 5x8 and 7x10 + // confabulate exact IDs; effective 9x12 (Spleen 5x8 + 4px spacing) is the + // densest measured arm that reached 4/4 exact, 0 confab, gist+guard ok. The + // fact-sheet still rides beside images as defense in depth. Grok remains + // opt-in only; this profile applies only after an operator enables it. { test: (m) => /^grok-/.test(m), profile: { @@ -153,9 +185,9 @@ const BUILTIN_RULES: ProfileRule[] = [ // measured pixel model. Keep a conservative tile placeholder for tools // that only read the profile struct. vision: { regime: 'tile', base: 85, perTile: 170 }, - stripCols: C, + stripCols: 84, maxHeightPx: H, - style: { cellWBonus: 0, cellHBonus: 0, aa: true }, + style: { ...BASE_STYLE, cellWBonus: 4, cellHBonus: 4 }, }, }, ]; @@ -184,6 +216,14 @@ function posInt(v: unknown, fallback: number): number { return Number.isFinite(v) && (v as number) > 0 ? Math.floor(v as number) : fallback; } +function nonNegativeInt(v: unknown, fallback: number): number { + return Number.isFinite(v) && (v as number) >= 0 ? Math.floor(v as number) : fallback; +} + +function renderFont(v: unknown, fallback: RenderFont): RenderFont { + return v === 'spleen-5x8' || v === 'jetbrains-mono-10' ? v : fallback; +} + function parseEnvProfiles(raw: string): Map { const out = new Map(); if (!raw) return out; @@ -197,18 +237,27 @@ function parseEnvProfiles(raw: string): Map { for (const [k, v] of Object.entries(obj as Record)) { if (!v || typeof v !== 'object') continue; const key = k.toLowerCase(); - const base = resolveBuiltin(key); // partial fields fall back to the built-in match + // An exact override key may be a prefix of the real model id. Resolve the + // known family explicitly so `{"gpt-5.6-sol":{...}}` inherits Sol's font + // and geometry even when a suffixed runtime id is expected. + const base = key === 'gpt-5.6-sol' ? GPT56_SOL_PROFILE : resolveBuiltin(key); const p = v as Partial; const styleIn = (p as { style?: GptRenderStyle }).style; - const baseStyle = base.style ?? { cellWBonus: 0, cellHBonus: 0, aa: true }; + const baseStyle = base.style; const style: GptRenderStyle = { - cellWBonus: styleIn && Number.isFinite(styleIn.cellWBonus as number) - ? Math.floor(styleIn.cellWBonus as number) - : baseStyle.cellWBonus, - cellHBonus: styleIn && Number.isFinite(styleIn.cellHBonus as number) - ? Math.floor(styleIn.cellHBonus as number) - : baseStyle.cellHBonus, + font: renderFont(styleIn?.font, baseStyle.font), + cellWBonus: nonNegativeInt(styleIn?.cellWBonus, baseStyle.cellWBonus), + cellHBonus: nonNegativeInt(styleIn?.cellHBonus, baseStyle.cellHBonus), aa: styleIn && typeof styleIn.aa === 'boolean' ? styleIn.aa : baseStyle.aa, + grid: styleIn && typeof styleIn.grid === 'boolean' ? styleIn.grid : baseStyle.grid, + gridCols: nonNegativeInt(styleIn?.gridCols, baseStyle.gridCols), + colorCycle: styleIn && typeof styleIn.colorCycle === 'boolean' + ? styleIn.colorCycle + : baseStyle.colorCycle, + markerScale: posInt(styleIn?.markerScale, baseStyle.markerScale), + markerRed: styleIn && typeof styleIn.markerRed === 'boolean' + ? styleIn.markerRed + : baseStyle.markerRed, }; out.set(key, { vision: isValidVision(p.vision) ? p.vision : base.vision, @@ -229,26 +278,10 @@ function envProfiles(): Map { return envMap; } -/** - * Resolve the full rendering + vision-cost profile for a model id. Env overrides - * (longest matching prefix) win over the built-in table; unknown models get the - * conservative `DEFAULT_GPT_PROFILE`. - */ -function withDefaultStyle(profile: GptModelProfile): GptModelProfile { - const d = DEFAULT_GPT_PROFILE.style!; - const st = profile.style; - return { - ...profile, - style: { - cellWBonus: st?.cellWBonus ?? d.cellWBonus, - cellHBonus: st?.cellHBonus ?? d.cellHBonus, - aa: st?.aa ?? d.aa, - }, - }; -} - export function resolveGptProfile(model: string | null | undefined): GptModelProfile { - const m = (model ?? '').toLowerCase(); + // Match applicability.ts: bracketed transport variants (for example [1m]) + // do not define a different visual reader profile. + const m = (model ?? '').toLowerCase().replace(/\[[^\]]*\]/g, ''); const env = envProfiles(); if (env.size > 0) { let best: GptModelProfile | undefined; @@ -259,7 +292,7 @@ export function resolveGptProfile(model: string | null | undefined): GptModelPro bestLen = k.length; } } - if (best) return withDefaultStyle(best); + if (best) return best; } - return withDefaultStyle(resolveBuiltin(m)); + return resolveBuiltin(m); } diff --git a/src/core/openai-history.ts b/src/core/openai-history.ts index ee61fc7..1a4494b 100644 --- a/src/core/openai-history.ts +++ b/src/core/openai-history.ts @@ -21,8 +21,14 @@ * HistoryTurn list and the planner/renderer are shared. */ -import { renderTextToPngs, reflow, neutralizeSentinel, type RenderedImage } from './render.js'; -import { GPT_MAX_HEIGHT_PX } from './gpt-model-profiles.js'; +import { + renderTextToPngs, + reflow, + neutralizeSentinel, + type RenderedImage, + type RenderStyle, +} from './render.js'; +import { DEFAULT_GPT_PROFILE, GPT_MAX_HEIGHT_PX } from './gpt-model-profiles.js'; import { countTokens as o200kCountTokens } from 'gpt-tokenizer/encoding/o200k_base'; /** Portrait-strip width for GPT history images. Mirrors GPT_STRIP_COLS in @@ -81,7 +87,7 @@ export interface GptHistoryOptions { * into renderTextToPngs so history pages split at the same height the gate prices. */ maxHeightPx: number; /** Glyph density from the model profile. Empty = production 5x8. */ - style: { cellWBonus?: number; cellHBonus?: number; aa?: boolean }; + style: RenderStyle; /** Hard cap on GPT history image count. This is a TRUE cap, not a threshold: * collapse the oldest completed sections until the next section would exceed * the cap, then leave the remaining history as ordinary text. Prevents 80+ @@ -107,7 +113,7 @@ export const GPT_HISTORY_DEFAULTS: GptHistoryOptions = { // GPT path: OpenAI's resize bounds (2048-bbox / 768 short side) permit the tall // strip — do NOT re-link to render.ts MAX_HEIGHT_PX (Anthropic's 1568/1.15 MP clamp). maxHeightPx: GPT_MAX_HEIGHT_PX, - style: { cellWBonus: 0, cellHBonus: 0, aa: true }, + style: DEFAULT_GPT_PROFILE.style, maxImages: GPT_HISTORY_MAX_IMAGES, reflow: true, }; diff --git a/src/core/openai.ts b/src/core/openai.ts index b451f71..933e199 100644 --- a/src/core/openai.ts +++ b/src/core/openai.ts @@ -10,13 +10,15 @@ import { renderTextToPngs, reflow, shrinkColsToContent, + renderCellWidth, + renderCellHeight, PAD_X, - CELL_W, + PAD_Y, + READABLE_CHARS_PER_IMAGE, type RenderedImage, } from './render.js'; import { resolveGptProfile, - DEFAULT_GPT_STRIP_COLS, type GptVisionCost, } from './gpt-model-profiles.js'; import { bytesToBase64 } from './png.js'; @@ -218,7 +220,7 @@ interface OpenAIResolvedOptions { compress: boolean; compressTools: boolean; minCompressChars: number; - cols: number; + cols?: number; multiCol: number; charsPerToken: number; reflow: boolean; @@ -230,7 +232,7 @@ const DEFAULTS: OpenAIResolvedOptions = { compress: true, compressTools: true, minCompressChars: 2000, - cols: DEFAULT_GPT_STRIP_COLS, + cols: undefined, multiCol: 1, charsPerToken: 4, // conservative OpenAI default; override after telemetry reflow: true, @@ -242,7 +244,7 @@ function resolveOptions(opts: TransformOptions): OpenAIResolvedOptions { compress: opts.compress ?? DEFAULTS.compress, compressTools: opts.compressTools ?? DEFAULTS.compressTools, minCompressChars: opts.minCompressChars ?? DEFAULTS.minCompressChars, - cols: opts.cols ?? DEFAULTS.cols, + cols: opts.cols, multiCol: opts.multiCol ?? DEFAULTS.multiCol, charsPerToken: opts.charsPerToken ?? DEFAULTS.charsPerToken, reflow: opts.reflow ?? DEFAULTS.reflow, @@ -502,10 +504,25 @@ function evalOpenAIGate( cols: number, charsPerToken: number, ): { imageTokens: number; textTokens: number; profitable: boolean } { - const stripW = 2 * PAD_X + cols * CELL_W; - const estImages = estimateImageCount(renderedText, cols, 1); - const perStrip = visionTokensForModel(model, stripW, resolveGptProfile(model).maxHeightPx); - const imageTokens = estImages * perStrip; + const profile = resolveGptProfile(model); + const style = profile.style; + const cellW = renderCellWidth(style); + const cellH = renderCellHeight(style); + const stripW = 2 * PAD_X + cols * cellW; + const maxLines = Math.max(1, Math.floor((profile.maxHeightPx - 2 * PAD_Y) / cellH)); + const maxCharsPerImage = Math.min( + READABLE_CHARS_PER_IMAGE, + Math.max(1, cols) * maxLines, + ); + const estImages = estimateImageCount( + renderedText, + cols, + 1, + maxCharsPerImage, + maxLines, + ); + const perFullStrip = visionTokensForModel(model, stripW, profile.maxHeightPx); + const imageTokens = estImages * perFullStrip; const textTokens = renderedText.length / charsPerToken; return { imageTokens, textTokens, profitable: imageTokens < textTokens }; } @@ -541,21 +558,6 @@ function gptTextTokens(text: string): number { /** Vision-token cost of the rendered images, summed over their real dims — * what GPT actually bills as input for the slab pxpipe imaged. */ -function profileRenderStyle( - model: string | null | undefined, -): { cellWBonus?: number; cellHBonus?: number; aa?: boolean; grid?: boolean; colorCycle?: boolean } { - const st = resolveGptProfile(model).style as - | { cellWBonus?: number; cellHBonus?: number; aa?: boolean; grid?: boolean; colorCycle?: boolean } - | undefined; - return { - cellWBonus: st?.cellWBonus ?? 0, - cellHBonus: st?.cellHBonus ?? 0, - aa: st?.aa ?? true, - ...(st?.grid ? { grid: true } : {}), - ...(st?.colorCycle ? { colorCycle: true } : {}), - }; -} - function gptImageTokens(model: string, images: RenderedImage[]): number { let n = 0; for (const img of images) n += visionTokensForModel(model, img.width, img.height); @@ -705,7 +707,12 @@ export async function transformOpenAIChatCompletions( : ''; const header = CHAT_HEADER.replace('\n====', reflowNote + '\n===='); const renderedText = header + combined; - const cols = Math.min(shrinkColsToContent(renderedText, o.cols), resolveGptProfile(req.model).stripCols); + const profile = resolveGptProfile(req.model); + const maxCols = o.cols ?? profile.stripCols; + const cols = Math.min( + shrinkColsToContent(renderedText, maxCols, profile.style.markerScale, profile.style.font), + profile.stripCols, + ); const gate = evalOpenAIGate(req.model, renderedText, cols, o.charsPerToken); info.gateEval = { @@ -722,7 +729,7 @@ export async function transformOpenAIChatCompletions( return { body, info }; } - const images = await renderTextToPngs(renderedText, cols, profileRenderStyle(req.model), resolveGptProfile(req.model).maxHeightPx); + const images = await renderTextToPngs(renderedText, cols, profile.style, profile.maxHeightPx); if (images.length === 0) { info.reason = 'render_empty'; return { body, info }; @@ -782,9 +789,9 @@ export async function transformOpenAIChatCompletions( const plan = await planGptCollapse(turns, firstUserIdx + 1, profitable, { ...o.gptHistory, reflow: o.reflow, - cols: o.gptHistory?.cols ?? resolveGptProfile(req.model).stripCols, - maxHeightPx: o.gptHistory?.maxHeightPx ?? resolveGptProfile(req.model).maxHeightPx, - style: o.gptHistory?.style ?? profileRenderStyle(req.model), + cols: o.gptHistory?.cols ?? profile.stripCols, + maxHeightPx: o.gptHistory?.maxHeightPx ?? profile.maxHeightPx, + style: o.gptHistory?.style ?? profile.style, }); foldGptHistory(info, req.model, plan); const allImages = [...plan.images, ...plan.imagesAfter]; @@ -913,7 +920,12 @@ export async function transformOpenAIResponses( : ''; const header = RESPONSES_HEADER.replace('\n====', reflowNote + '\n===='); const renderedText = header + combined; - const cols = Math.min(shrinkColsToContent(renderedText, o.cols), resolveGptProfile(req.model).stripCols); + const profile = resolveGptProfile(req.model); + const maxCols = o.cols ?? profile.stripCols; + const cols = Math.min( + shrinkColsToContent(renderedText, maxCols, profile.style.markerScale, profile.style.font), + profile.stripCols, + ); const gate = evalOpenAIGate(req.model, renderedText, cols, o.charsPerToken); info.gateEval = { @@ -930,7 +942,7 @@ export async function transformOpenAIResponses( return { body, info }; } - const images = await renderTextToPngs(renderedText, cols, profileRenderStyle(req.model), resolveGptProfile(req.model).maxHeightPx); + const images = await renderTextToPngs(renderedText, cols, profile.style, profile.maxHeightPx); if (images.length === 0) { info.reason = 'render_empty'; return { body, info }; @@ -1021,9 +1033,9 @@ export async function transformOpenAIResponses( const plan = await planGptCollapse(turns, firstUserIdx + 1, profitable, { ...o.gptHistory, reflow: o.reflow, - cols: o.gptHistory?.cols ?? resolveGptProfile(req.model).stripCols, - maxHeightPx: o.gptHistory?.maxHeightPx ?? resolveGptProfile(req.model).maxHeightPx, - style: o.gptHistory?.style ?? profileRenderStyle(req.model), + cols: o.gptHistory?.cols ?? profile.stripCols, + maxHeightPx: o.gptHistory?.maxHeightPx ?? profile.maxHeightPx, + style: o.gptHistory?.style ?? profile.style, }); foldGptHistory(info, req.model, plan); const allImages = [...plan.images, ...plan.imagesAfter]; diff --git a/src/core/render.ts b/src/core/render.ts index e6462c4..09fb43a 100644 --- a/src/core/render.ts +++ b/src/core/render.ts @@ -8,6 +8,7 @@ import { ATLAS_CELL_W, ATLAS_CELL_H, + ATLAS_ASCENT, ATLAS_PIXELS, ATLAS_OFFSETS, ATLAS_WIDE_FLAGS, @@ -16,13 +17,128 @@ import { import { ATLAS_GRAY_CELL_W, ATLAS_GRAY_CELL_H, + ATLAS_GRAY_ASCENT, ATLAS_GRAY_PIXELS, ATLAS_GRAY_OFFSETS, ATLAS_GRAY_WIDE_FLAGS, atlasGrayRank, } from './atlas-gray.js'; +import { + ATLAS_CELL_W as JBM10_CELL_W, + ATLAS_CELL_H as JBM10_CELL_H, + ATLAS_ASCENT as JBM10_ASCENT, + ATLAS_PIXELS as JBM10_PIXELS, + ATLAS_OFFSETS as JBM10_OFFSETS, + ATLAS_WIDE_FLAGS as JBM10_WIDE_FLAGS, + atlasRank as jbMono10Rank, +} from './atlas-jbmono10.js'; +import { + ATLAS_GRAY_CELL_W as JBM10_GRAY_CELL_W, + ATLAS_GRAY_CELL_H as JBM10_GRAY_CELL_H, + ATLAS_GRAY_ASCENT as JBM10_GRAY_ASCENT, + ATLAS_GRAY_PIXELS as JBM10_GRAY_PIXELS, + ATLAS_GRAY_OFFSETS as JBM10_GRAY_OFFSETS, + ATLAS_GRAY_WIDE_FLAGS as JBM10_GRAY_WIDE_FLAGS, + atlasGrayRank as jbMono10GrayRank, +} from './atlas-gray-jbmono10.js'; import { encodeGrayPng, encodeRgbPng } from './png.js'; +export type RenderFont = 'spleen-5x8' | 'jetbrains-mono-10'; +export const DEFAULT_RENDER_FONT: RenderFont = 'spleen-5x8'; + +interface BitAtlas { + cellW: number; + cellH: number; + ascent: number; + pixels: Uint8Array; + offsets: Uint32Array; + wideFlags: Uint8Array; + rank: (codepoint: number) => number; +} + +interface GrayAtlas { + cellW: number; + cellH: number; + ascent: number; + pixels: Uint8Array; + offsets: Uint32Array; + wideFlags: Uint8Array; + rank: (codepoint: number) => number; +} + +interface AtlasSet { + bit: BitAtlas; + gray: GrayAtlas; +} + +const DEFAULT_ATLAS: AtlasSet = { + bit: { + cellW: ATLAS_CELL_W, + cellH: ATLAS_CELL_H, + ascent: ATLAS_ASCENT, + pixels: ATLAS_PIXELS, + offsets: ATLAS_OFFSETS, + wideFlags: ATLAS_WIDE_FLAGS, + rank: atlasRank, + }, + gray: { + cellW: ATLAS_GRAY_CELL_W, + cellH: ATLAS_GRAY_CELL_H, + ascent: ATLAS_GRAY_ASCENT, + pixels: ATLAS_GRAY_PIXELS, + offsets: ATLAS_GRAY_OFFSETS, + wideFlags: ATLAS_GRAY_WIDE_FLAGS, + rank: atlasGrayRank, + }, +}; + +const JBM10_ATLAS: AtlasSet = { + bit: { + cellW: JBM10_CELL_W, + cellH: JBM10_CELL_H, + ascent: JBM10_ASCENT, + pixels: JBM10_PIXELS, + offsets: JBM10_OFFSETS, + wideFlags: JBM10_WIDE_FLAGS, + rank: jbMono10Rank, + }, + gray: { + cellW: JBM10_GRAY_CELL_W, + cellH: JBM10_GRAY_CELL_H, + ascent: JBM10_GRAY_ASCENT, + pixels: JBM10_GRAY_PIXELS, + offsets: JBM10_GRAY_OFFSETS, + wideFlags: JBM10_GRAY_WIDE_FLAGS, + rank: jbMono10GrayRank, + }, +}; + +function atlasSet(font: RenderFont | undefined): AtlasSet { + return font === 'jetbrains-mono-10' ? JBM10_ATLAS : DEFAULT_ATLAS; +} + +function bitGlyph(codepoint: number, font: RenderFont | undefined): { atlas: BitAtlas; rank: number } | null { + const selected = atlasSet(font).bit; + const rank = selected.rank(codepoint); + if (rank >= 0) return { atlas: selected, rank }; + if (selected !== DEFAULT_ATLAS.bit) { + const fallbackRank = DEFAULT_ATLAS.bit.rank(codepoint); + if (fallbackRank >= 0) return { atlas: DEFAULT_ATLAS.bit, rank: fallbackRank }; + } + return null; +} + +function grayGlyph(codepoint: number, font: RenderFont | undefined): { atlas: GrayAtlas; rank: number } | null { + const selected = atlasSet(font).gray; + const rank = selected.rank(codepoint); + if (rank >= 0) return { atlas: selected, rank }; + if (selected !== DEFAULT_ATLAS.gray) { + const fallbackRank = DEFAULT_ATLAS.gray.rank(codepoint); + if (fallbackRank >= 0) return { atlas: DEFAULT_ATLAS.gray, rank: fallbackRank }; + } + return null; +} + /** Page-height ceiling. Measured (2026-07-01, count_tokens sweep, claude-sonnet-4-5 — see * /tmp/pxexp/LEVER1-findings.md): the API downscales any image to fit BOTH long-edge ≤1568 * AND ~1.15 MP (≈1,143,750 px), then bills ≈ px/750 (≈1525 tok cap, applied per-image). @@ -40,9 +156,11 @@ export const DENSE_CONTENT_COLS = 312; /** Bare 5×8 cell (no padding). A/B showed 5×8 beats 7×10 on dense JSON (4/5 vs 3/5 reads, 42% fewer tokens). * Revert to {cellWBonus:2, cellHBonus:2} if misread rates rise. */ export const DENSE_RENDER_STYLE: RenderStyle = { cellWBonus: 0, cellHBonus: 0, aa: true }; +/** Anthropic static slab uses the same measured 312-column no-resize geometry. */ +export const ANTHROPIC_SLAB_COLS = DENSE_CONTENT_COLS; /** Default columns for the static slab. 312 × 5 px + 8 px pad = 1568 px — exactly the API's * long-edge bound (313 cols = 1573 px would trigger a 0.997× resample, blurring every glyph). */ -const DEFAULT_COLS = 312; +const DEFAULT_COLS = ANTHROPIC_SLAB_COLS; /** Horizontal padding (left + right each), px. Exported for transform.ts token-cost math. */ export const PAD_X = 4; /** Vertical padding (top + bottom each), px. Exported for transform.ts token-cost math. */ @@ -72,6 +190,8 @@ export interface RenderedImage { /** Optional render-time styling. All fields unset = production default 5×8 cell. * Eval harness overrides per variant to A/B cell sizes and structure aids. */ export interface RenderStyle { + /** Rasterized font atlas. Alternate atlases fall back to Spleen/Unifont for missing Unicode. */ + font?: RenderFont; /** Draw faint grey grid rules onto background pixels (zero pixel cost). */ grid?: boolean; /** Draw a vertical grid rule every N columns. 0/unset = row rules only. */ @@ -84,7 +204,7 @@ export interface RenderStyle { cellHBonus?: number; /** Extra blank columns beside the 5px glyph (cell width = 5 + this). Negative overlaps glyphs. Unset = DEFAULT_CELL_W_BONUS. */ cellWBonus?: number; - /** Use the AA grayscale atlas (atlas-gray.ts). EVAL-ONLY; default 1-bit path is unchanged. */ + /** Use the AA grayscale companion atlas. */ aa?: boolean; /** Cycle palette colors per glyph for per-character boundary cues. Forces RGB output. Composes with aa. */ colorCycle?: boolean; @@ -93,16 +213,30 @@ export interface RenderStyle { colorByRole?: boolean; } +export function renderCellWidth(style: RenderStyle = {}): number { + const atlas = style.aa === true ? atlasSet(style.font).gray : atlasSet(style.font).bit; + return Math.max(1, atlas.cellW + Math.floor(style.cellWBonus ?? DEFAULT_CELL_W_BONUS)); +} + +export function renderCellHeight(style: RenderStyle = {}): number { + const atlas = style.aa === true ? atlasSet(style.font).gray : atlasSet(style.font).bit; + return atlas.cellH + Math.max(0, Math.floor(style.cellHBonus ?? DEFAULT_CELL_H_BONUS)); +} + // --- column-aware wrapping ------------------------------------------------- /** Visual width of a codepoint in cells (1 = Latin, 2 = East Asian Wide). * Missing codepoints advance 1 cell so wrap math stays stable. */ -function cellsFor(codepoint: number, markerScale: number = 1): number { +function cellsFor( + codepoint: number, + markerScale: number = 1, + font: RenderFont = DEFAULT_RENDER_FONT, +): number { // Enlarged ↵ occupies markerScale cells of wrap budget instead of 1. if (codepoint === NL_SENTINEL_CP && markerScale > 1) return markerScale; - const rank = atlasRank(codepoint); - if (rank < 0) return 1; - return ATLAS_WIDE_FLAGS[rank] === 1 ? 2 : 1; + const glyph = bitGlyph(codepoint, font); + if (!glyph) return 1; + return glyph.atlas.wideFlags[glyph.rank] === 1 ? 2 : 1; } const TAB_WIDTH = 4; // standard 4-space tab stops (logs, code, tool output are all 4-oriented) @@ -251,21 +385,30 @@ export function expandTabsInLine(line: string): string { } /** Visual width of a line in cells. Wide CJK = 2; enlarged ↵ = markerScale. */ -export function measureLineCols(line: string, markerScale: number = 1): number { +export function measureLineCols( + line: string, + markerScale: number = 1, + font: RenderFont = DEFAULT_RENDER_FONT, +): number { let w = 0; - for (const ch of line) w += cellsFor(ch.codePointAt(0)!, markerScale); + for (const ch of line) w += cellsFor(ch.codePointAt(0)!, markerScale, font); return w; } /** Always renders at full canvas width. Signature kept for transform.ts compatibility; returns cols unchanged. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -export function shrinkColsToContent(text: string, cols: number, markerScale: number = 1): number { +export function shrinkColsToContent( + text: string, + cols: number, + markerScale: number = 1, + font: RenderFont = DEFAULT_RENDER_FONT, +): number { // Real content-width measurement — delegates to measureContentCols (was historically a // no-op stub). The proxy's cost gate AND renderer both call this, so sizing the canvas to // the widest line here makes the proxy match the SDK/export path (renderTextToImages), // which already uses measureContentCols. Never narrows below the widest line ⇒ row count // (and thus image/paging count) is unchanged; only the canvas WIDTH (pixel cost) drops. - return measureContentCols(text, cols, markerScale); + return measureContentCols(text, cols, markerScale, font); } /** @@ -276,13 +419,18 @@ export function shrinkColsToContent(text: string, cols: number, markerScale: num * deterministic width → cache-prefix-safe. Tabs are expanded so the measured width * matches what the renderer actually lays out. */ -export function measureContentCols(text: string, maxCols: number, markerScale: number = 1): number { +export function measureContentCols( + text: string, + maxCols: number, + markerScale: number = 1, + font: RenderFont = DEFAULT_RENDER_FONT, +): number { const cap = Math.max(1, maxCols | 0); let widest = 1; let start = 0; for (let i = 0; i <= text.length; i++) { if (i === text.length || text[i] === '\n') { - const w = measureLineCols(expandTabsInLine(text.slice(start, i)), markerScale); + const w = measureLineCols(expandTabsInLine(text.slice(start, i)), markerScale, font); if (w > widest) widest = w; if (widest >= cap) return cap; start = i + 1; @@ -291,7 +439,12 @@ export function measureContentCols(text: string, maxCols: number, markerScale: n return Math.min(cap, widest); } -export function wrapLines(text: string, cols: number, markerScale: number = 1): string[] { +export function wrapLines( + text: string, + cols: number, + markerScale: number = 1, + font: RenderFont = DEFAULT_RENDER_FONT, +): string[] { const out: string[] = []; const minified = minifyForRender(text); for (const rawWithTabs of minified.split('\n')) { @@ -306,7 +459,7 @@ export function wrapLines(text: string, cols: number, markerScale: number = 1): // ↵ is treated as an inline glyph — it never forces a row break. for (const ch of raw) { const cp = ch.codePointAt(0)!; - const w = cellsFor(cp, markerScale); + const w = cellsFor(cp, markerScale, font); if (curCols + w > cols) { out.push(cur); cur = ch; @@ -363,20 +516,23 @@ function blitGlyph( x: number, y: number, codepoint: number, + font: RenderFont = DEFAULT_RENDER_FONT, markerMask: Uint8Array | null = null, ): number { - const rank = atlasRank(codepoint); - if (rank < 0) return 0; - const wide = ATLAS_WIDE_FLAGS[rank] === 1; - const srcW = wide ? 2 * ATLAS_CELL_W : ATLAS_CELL_W; + const glyph = bitGlyph(codepoint, font); + if (!glyph) return 0; + const { atlas, rank } = glyph; + const wide = atlas.wideFlags[rank] === 1; + const srcW = wide ? 2 * atlas.cellW : atlas.cellW; // ATLAS_OFFSETS is a bit offset (MSB-first packing). Pixel (gx,gy): byte = bitIdx>>>3, bit = 7-(bitIdx&7). - const srcOff = ATLAS_OFFSETS[rank]!; - for (let gy = 0; gy < ATLAS_CELL_H; gy++) { - const dstRow = (y + gy) * fbW + x; + const srcOff = atlas.offsets[rank]!; + const yOffset = atlasSet(font).bit.ascent - atlas.ascent; + for (let gy = 0; gy < atlas.cellH; gy++) { + const dstRow = (y + yOffset + gy) * fbW + x; const bitRowStart = srcOff + gy * srcW; for (let gx = 0; gx < srcW; gx++) { const bitIdx = bitRowStart + gx; - const byte = ATLAS_PIXELS[bitIdx >>> 3]!; + const byte = atlas.pixels[bitIdx >>> 3]!; const bit = (byte >>> (7 - (bitIdx & 7))) & 1; if (bit) { fb[dstRow + gx] = 255; // glyphs never overlap in grid layout; set unconditionally @@ -397,18 +553,21 @@ function blitGlyphGray( x: number, y: number, codepoint: number, + font: RenderFont = DEFAULT_RENDER_FONT, ): number { - const rank = atlasGrayRank(codepoint); - if (rank < 0) return 0; - const wide = ATLAS_GRAY_WIDE_FLAGS[rank] === 1; - const srcW = wide ? 2 * ATLAS_GRAY_CELL_W : ATLAS_GRAY_CELL_W; + const glyph = grayGlyph(codepoint, font); + if (!glyph) return 0; + const { atlas, rank } = glyph; + const wide = atlas.wideFlags[rank] === 1; + const srcW = wide ? 2 * atlas.cellW : atlas.cellW; // ATLAS_GRAY_OFFSETS is a byte offset (1 byte/pixel, unlike the bit-packed 1-bit atlas). - const srcOff = ATLAS_GRAY_OFFSETS[rank]!; - for (let gy = 0; gy < ATLAS_GRAY_CELL_H; gy++) { - const dstRow = (y + gy) * fbW + x; + const srcOff = atlas.offsets[rank]!; + const yOffset = atlasSet(font).gray.ascent - atlas.ascent; + for (let gy = 0; gy < atlas.cellH; gy++) { + const dstRow = (y + yOffset + gy) * fbW + x; const srcRow = srcOff + gy * srcW; for (let gx = 0; gx < srcW; gx++) { - const coverage = ATLAS_GRAY_PIXELS[srcRow + gx]!; + const coverage = atlas.pixels[srcRow + gx]!; if (coverage > 0) { const idx = dstRow + gx; if (coverage > fb[idx]!) fb[idx] = coverage; @@ -429,19 +588,22 @@ function blitGlyphScaled( y: number, codepoint: number, scaleX: number, + font: RenderFont = DEFAULT_RENDER_FONT, ): number { - const rank = atlasRank(codepoint); - if (rank < 0) return 0; - const wide = ATLAS_WIDE_FLAGS[rank] === 1; - const srcW = wide ? 2 * ATLAS_CELL_W : ATLAS_CELL_W; - const srcOff = ATLAS_OFFSETS[rank]!; - for (let gy = 0; gy < ATLAS_CELL_H; gy++) { - const py = y + gy; + const glyph = bitGlyph(codepoint, font); + if (!glyph) return 0; + const { atlas, rank } = glyph; + const wide = atlas.wideFlags[rank] === 1; + const srcW = wide ? 2 * atlas.cellW : atlas.cellW; + const srcOff = atlas.offsets[rank]!; + const yOffset = atlasSet(font).bit.ascent - atlas.ascent; + for (let gy = 0; gy < atlas.cellH; gy++) { + const py = y + yOffset + gy; if (py >= fbH) break; const bitRowStart = srcOff + gy * srcW; for (let gx = 0; gx < srcW; gx++) { const bitIdx = bitRowStart + gx; - const byte = ATLAS_PIXELS[bitIdx >>> 3]!; + const byte = atlas.pixels[bitIdx >>> 3]!; if (((byte >>> (7 - (bitIdx & 7))) & 1) === 0) continue; for (let sx = 0; sx < scaleX; sx++) { const px = x + gx * scaleX + sx; @@ -497,18 +659,19 @@ export async function renderChunkToPng( slotText?: string, ): Promise { const useAA = style.aa === true; - const atlasH = useAA ? ATLAS_GRAY_CELL_H : ATLAS_CELL_H; - const atlasW = useAA ? ATLAS_GRAY_CELL_W : ATLAS_CELL_W; + const selected = atlasSet(style.font); + const atlasH = useAA ? selected.gray.cellH : selected.bit.cellH; + const atlasW = useAA ? selected.gray.cellW : selected.bit.cellW; const markerScale = Math.max(1, Math.floor(style.markerScale ?? 1)); - const cellH = atlasH + Math.max(0, Math.floor(style.cellHBonus ?? DEFAULT_CELL_H_BONUS)); - const cellW = Math.max(1, atlasW + Math.floor(style.cellWBonus ?? DEFAULT_CELL_W_BONUS)); - const lines = wrapLines(text, cols, markerScale); + const cellH = renderCellHeight(style); + const cellW = renderCellWidth(style); + const lines = wrapLines(text, cols, markerScale, style.font); // Slot string carries role attribution by position. It is width-identical to // `text`, so wrapLines splits it into the exact same rows — fitSlotLines[r] aligns // codepoint-for-codepoint with fitLines[r]. Only built when coloring is on. const slotLines: string[] | null = style.colorByRole === true && slotText !== undefined - ? wrapLines(slotText, cols, markerScale) + ? wrapLines(slotText, cols, markerScale, style.font) : null; const maxLines = Math.max(1, Math.floor((maxHeightPx - 2 * PAD_Y) / cellH)); @@ -567,7 +730,7 @@ export async function renderChunkToPng( : (glyphIndex % GLYPH_PALETTE.length) + 1; // 0 reserved for background in colorMask let advance: number; if (isMarker && markerScale > 1) { - advance = blitGlyphScaled(fb, markerMask, width, height, baseX, baseY, codepoint, markerScale); + advance = blitGlyphScaled(fb, markerMask, width, height, baseX, baseY, codepoint, markerScale, style.font); if (colorMask) { for (let gy = 0; gy < atlasH; gy++) { const py = baseY + gy; @@ -581,7 +744,7 @@ export async function renderChunkToPng( } } } else if (useAA) { - advance = blitGlyphGray(fb, width, baseX, baseY, codepoint); + advance = blitGlyphGray(fb, width, baseX, baseY, codepoint, style.font); if (colorMask && advance > 0) { const srcW = advance * atlasW; for (let gy = 0; gy < atlasH; gy++) { @@ -596,7 +759,7 @@ export async function renderChunkToPng( } } } else { - advance = blitGlyph(fb, width, baseX, baseY, codepoint, isMarker ? markerMask : null); + advance = blitGlyph(fb, width, baseX, baseY, codepoint, style.font, isMarker ? markerMask : null); if (colorMask && advance > 0) { const srcW = advance * atlasW; for (let gy = 0; gy < atlasH; gy++) { @@ -694,13 +857,13 @@ export async function renderTextToPngsWithCharLimit( slotText?: string, ): Promise { const markerScale = Math.max(1, Math.floor(style.markerScale ?? 1)); - const cellH = ATLAS_CELL_H + Math.max(0, Math.floor(style.cellHBonus ?? DEFAULT_CELL_H_BONUS)); - const lines = wrapLines(text, cols, markerScale); + const cellH = renderCellHeight(style); + const lines = wrapLines(text, cols, markerScale, style.font); // Width-identical slot rows align 1:1 with `lines`; pages are contiguous slices, // so the same index range gives each page its slot half. Only built when coloring. const slotLines: string[] | null = style.colorByRole === true && slotText !== undefined - ? wrapLines(slotText, cols, markerScale) + ? wrapLines(slotText, cols, markerScale, style.font) : null; const hardLinesPerImg = Math.max(1, Math.floor((maxHeightPx - 2 * PAD_Y) / cellH)); // Dense pages (DENSE_CONTENT_CHARS_PER_IMAGE) fill the full 1932 px height; diff --git a/src/core/transform.ts b/src/core/transform.ts index 9496fe0..6604674 100644 --- a/src/core/transform.ts +++ b/src/core/transform.ts @@ -32,6 +32,7 @@ import { DENSE_CONTENT_CHARS_PER_IMAGE, DENSE_CONTENT_COLS, DENSE_RENDER_STYLE, + ANTHROPIC_SLAB_COLS, renderTextToPngsWithCharLimit, } from './render.js'; import { factSheetText } from './factsheet.js'; @@ -134,8 +135,8 @@ const DEFAULTS: Required = { minToolResultChars: 6000, // system field rejects images (400 system.N.type: Input should be 'text') — // images always go into the first user message. - // 313 cols × 5 px + 8 px pad = 1573 px slab width (under 2000 px ceiling). - cols: 313, + // 312 cols × 5 px + 8 px pad = 1568 px (Anthropic no-resize edge). + cols: ANTHROPIC_SLAB_COLS, maxImagesPerToolResult: 10, charsPerToken: 4, historyAmortizationHorizon: 1, @@ -1097,10 +1098,12 @@ export function estimateImageCount( cols: number, numCols: number = 1, maxCharsPerImage: number = READABLE_CHARS_PER_IMAGE, + maxLinesPerColumn: number = LINES_PER_IMAGE, ): number { const n = Math.max(1, numCols | 0); const readableLinesPerCol = Math.max(1, Math.floor(maxCharsPerImage / Math.max(1, cols))); - const linesPerImage = Math.min(LINES_PER_IMAGE, readableLinesPerCol) * n; + const hardLinesPerCol = Math.max(1, Math.floor(maxLinesPerColumn)); + const linesPerImage = Math.min(hardLinesPerCol, readableLinesPerCol) * n; const charBudget = Math.max(1, maxCharsPerImage * n); if (typeof textOrLen === 'number') { // Back-compat shim — numeric arg gets the looser chars-based estimate. diff --git a/src/dashboard/fragments.ts b/src/dashboard/fragments.ts index 11818a3..37f1f3f 100644 --- a/src/dashboard/fragments.ts +++ b/src/dashboard/fragments.ts @@ -85,7 +85,7 @@ const MODEL_CATALOG: ReadonlyArray<{ id: string; label: string }> = [ ]; const GPT_MODEL_CATALOG: ReadonlyArray<{ id: string; label: string }> = [ - { id: 'gpt-5.6', label: 'GPT 5.6' }, + { id: 'gpt-5.6-sol', label: 'GPT 5.6 Sol' }, { id: 'gpt-5.5', label: 'GPT 5.5' }, ]; @@ -147,7 +147,7 @@ export function renderModelsFragment( otherChips + `opt-in only · OpenAI Responses path · set PXPIPE_MODELS to persist${moot}` + `` + - `