diff --git a/src/core/applicability.ts b/src/core/applicability.ts index d734504..4b72b0b 100644 --- a/src/core/applicability.ts +++ b/src/core/applicability.ts @@ -29,12 +29,10 @@ let runtimeModelBases: readonly string[] | null = null; * - 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. - * - 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 4.5 — packing + factsheet works for exact IDs, but pure-image is - * not Fable-level and the full quality suite is incomplete. Opt-in only - * until multi-seed + novel arithmetic clear a Fable-class bar. + * - GPT 5.6 Sol — 98/100 production arithmetic, but 79/93 completed gist, + * 4/15 completed guard confabulations, and 0/15 dense hex. + * - Grok 4.5 — 82/100 arithmetic, 83/98 gist, and 13/18 state tracking. + * Both profiles remain available for explicit opt-in. * Silently imaging weak or unvalidated readers is the wrong default. */ const DEFAULT_MODEL_BASES = ['claude-fable-5']; diff --git a/src/core/gpt-model-profiles.ts b/src/core/gpt-model-profiles.ts index 7743345..6ca6cd7 100644 --- a/src/core/gpt-model-profiles.ts +++ b/src/core/gpt-model-profiles.ts @@ -104,11 +104,11 @@ export const DEFAULT_GPT_PROFILE: GptModelProfile = { const GPT56_SOL_PROFILE: GptModelProfile = { vision: { regime: 'patch', multiplier: 1, patchCap: 10000 }, - stripCols: 126, + // Native 5×8 cells fit 152 columns at OpenAI's 768px short-side floor. + // Sol remains opt-in because broader recall is below the Fable bar. + stripCols: C, 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' }, + style: { ...BASE_STYLE, font: 'spleen-5x8' }, }; interface ProfileRule { @@ -176,14 +176,8 @@ const BUILTIN_RULES: ProfileRule[] = [ }, }, - // Grok (Responses path). Opt-in only (not Fable-level pure-image). Profile: - // Best stable pure-image recipe from brute force: stock Spleen 5×8, white AA, - // no grid, maxHeight 512, width 152 (768 short-side floor), plus an in-image - // IDS block is applied on every model path (appendIdsBlock); Grok still - // needs white AA + short pages. White+ids_block: 7/7 full 4/4 on grok-4.5 - // pure-image (no factsheet). - // paperGray 240 without grid confabulates ports; grid alone does not fix hex. - // Fact-sheet remains optional defense in depth. + // Grok remains opt-in. It shares the 5×8 production stack but uses shorter + // pages because its dense-image recall falls with taller strips. { test: (m) => /^grok-/.test(m), profile: { diff --git a/tests/design-behavior-e2e.test.ts b/tests/design-behavior-e2e.test.ts index 4d9ed6f..5f078be 100644 --- a/tests/design-behavior-e2e.test.ts +++ b/tests/design-behavior-e2e.test.ts @@ -21,9 +21,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { createProxy } from '../src/core/proxy.js'; -// These proxy-contract tests deliberately exercise the opt-in Sol transform. -// Snapshot the developer shell so the suite is deterministic now that Sol is -// intentionally absent from the built-in default scope. +// Pin the model scope so these proxy-contract tests stay independent of the developer shell. let ambientPxpipeModels: string | undefined; beforeAll(() => { ambientPxpipeModels = process.env.PXPIPE_MODELS; diff --git a/tests/openai-gpt5.test.ts b/tests/openai-gpt5.test.ts index 0ae4ee1..5a49f31 100644 --- a/tests/openai-gpt5.test.ts +++ b/tests/openai-gpt5.test.ts @@ -931,8 +931,8 @@ describe('resolveGptProfile (Claude on Responses)', () => { ]) { const sol = resolveGptProfile(model); expect(sol.maxHeightPx, model).toBe(1932); - expect(sol.stripCols, model).toBe(126); - expect(sol.style.font, model).toBe('jetbrains-mono-10'); + expect(sol.stripCols, model).toBe(152); + expect(sol.style.font, model).toBe('spleen-5x8'); } for (const model of ['gpt-5.6', 'gpt-5.6-terra', 'gpt-5.6-terra[1m]']) { const notSol = resolveGptProfile(model); diff --git a/tests/public-api.test.ts b/tests/public-api.test.ts index 87228a7..5602613 100644 --- a/tests/public-api.test.ts +++ b/tests/public-api.test.ts @@ -83,6 +83,7 @@ describe('public library API', () => { // null clears the override → back to the Fable-only default setAllowedModelBases(null); expect(isPxpipeSupportedModel('claude-fable-5')).toBe(true); + expect(isPxpipeSupportedGptModel('gpt-5.6-sol')).toBe(false); expect(isPxpipeSupportedGptModel('grok-4.5')).toBe(false); expect(isPxpipeSupportedModel('claude-opus-4-8')).toBe(false); } finally { @@ -90,7 +91,7 @@ describe('public library API', () => { } }); - it('keeps GPT 5.6 Sol off by default but preserves exact opt-in aliases', () => { + it('keeps GPT 5.6 Sol aliases opt-in by default', () => { expect(isPxpipeSupportedGptModel('gpt-5')).toBe(false); expect(isPxpipeSupportedGptModel('gpt-5.5')).toBe(false); expect(isPxpipeSupportedGptModel('gpt-5.5-codex')).toBe(false); @@ -110,9 +111,9 @@ describe('public library API', () => { expect(isPxpipeSupportedGptModel('gpt-5.6-terra')).toBe(false); }); - it('keeps Grok and Sol opt-in only (off by default, like Opus)', () => { - // Grok packing + factsheet helps exact IDs, but pure-image is not Fable- - // level and the full quality suite is incomplete — opt-in only. + it('keeps Grok and Sol opt-in by default', () => { + // Grok remains opt-in because its arithmetic, gist, and state results are + // below the Fable bar. const prev = process.env.PXPIPE_MODELS; try { delete process.env.PXPIPE_MODELS; diff --git a/tests/savings-math-e2e.test.ts b/tests/savings-math-e2e.test.ts index 2c0ae96..1d76373 100644 --- a/tests/savings-math-e2e.test.ts +++ b/tests/savings-math-e2e.test.ts @@ -23,8 +23,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { createProxy, type ProxyEvent } from '../src/core/proxy.js'; import { countTokens as o200k } from 'gpt-tokenizer/encoding/o200k_base'; -// The GPT tests below drive 'gpt-5.6-sol', which is intentionally absent from -// the built-in default scope (Fable 5 + Grok 4.5). Pin PXPIPE_MODELS so the suite is +// The GPT tests below drive exact Sol. Pin PXPIPE_MODELS so the suite is // deterministic regardless of the developer's shell (same convention as // proxy-usage.test.ts) — without this, the file passes or fails depending on // ambient env, which is exactly what broke CI. @@ -162,10 +161,10 @@ describe('savings math — GPT, cross-checked against the real o200k tokenizer', it('DECLINES A LOSER: refuses to image content where imaging would cost more than the real text', async () => { // Dense long-line slab: few o200k text tokens relative to vision pages. - // (The old 2k prose fixture is now profitable under Sol 6×11 packing — ~216 - // image vs ~500 text tokens — so it no longer exercises the decline path.) + // Use enough low-token-density alphabet runs to remain a loser under the denser + // Sol 5×8 packing; the gate must still reject it. const sys = Array.from({ length: 80 }, (_, i) => - `LINE${i} ` + 'abcdefghijklmnopqrstuvwxyz'.repeat(20), + `LINE${i} ` + 'abcdefghijklmnopqrstuvwxyz'.repeat(40), ).join('\n'); const realTok = o200k(sys); const body = JSON.stringify({