From b7f16261e8a2f31be0e952f7bf4ffc40c59192cb Mon Sep 17 00:00:00 2001 From: garrytan Date: Tue, 6 Oct 2026 20:56:03 +0000 Subject: [PATCH] fix: carve office-hours on every host to stay under the 160,000-byte ceiling With its brief, feedback and research prompts moved into files, the inlined office-hours render is 161,329 bytes on Codex and 160,302 on Factory, over SKILL_BYTE_CEILING, so gen-skill-docs --host all fails. Per the C4 policy (carve every skill whose external render exceeds the ceiling), office-hours joins ship and plan-ceo-review in CARVED_ON_EVERY_HOST. The Claude render is unchanged; external hosts read its sections relative to the installed skill. external-host-carve and qa-lazy-sections now include office-hours in their carved-skill lists. Co-authored-by: dgrant --- scripts/resolvers/sections.ts | 2 +- test/external-host-carve.test.ts | 6 +++--- test/qa-lazy-sections.test.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/resolvers/sections.ts b/scripts/resolvers/sections.ts index df3eb7077..d17d959df 100644 --- a/scripts/resolvers/sections.ts +++ b/scripts/resolvers/sections.ts @@ -27,7 +27,7 @@ export const QA_ASSET_BLOCKER = 'If missing or unreadable, report a QA setup blo /** Skills carved on every host: QA (portable assets) and those whose external * render would exceed SKILL_BYTE_CEILING inlined (C4, #2777). */ -const CARVED_ON_EVERY_HOST = ['qa', 'qa-only', 'ship', 'plan-ceo-review']; +const CARVED_ON_EVERY_HOST = ['qa', 'qa-only', 'ship', 'plan-ceo-review', 'office-hours']; /** Hosts read at most this many UTF-8 bytes of one SKILL.md (~40K tokens). */ export const SKILL_BYTE_CEILING = 160_000; diff --git a/test/external-host-carve.test.ts b/test/external-host-carve.test.ts index dedf269e1..3051785b0 100644 --- a/test/external-host-carve.test.ts +++ b/test/external-host-carve.test.ts @@ -1,5 +1,5 @@ /** - * C4 (#2777): ship and plan-ceo-review are carved on every host, and no + * C4 (#2777): ship, plan-ceo-review and office-hours are carved on every host, and no * generated SKILL.md exceeds 160,000 UTF-8 bytes on any host or model overlay * setup can select. Carved sections on external hosts are pointed at relative * to the installed skill directory: `$GSTACK_ROOT//sections/...` does @@ -65,10 +65,10 @@ describe('C4: external section pointers', () => { }); }); -describe('C4: ship and plan-ceo-review are carved on every external host', () => { +describe('C4: ship, plan-ceo-review and office-hours are carved on every external host', () => { for (const config of EXTERNAL) { test(`${config.name}: every pointer in the carved skill resolves to a generated section file`, () => { - for (const skill of ['ship', 'plan-ceo-review']) { + for (const skill of ['ship', 'plan-ceo-review', 'office-hours']) { expect(usesLazySections(config.name, skill)).toBe(true); const dir = skillDir(config, renders.all, skill); const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, skill, 'sections', 'manifest.json'), 'utf8')) as { sections: Array<{ file: string }> }; diff --git a/test/qa-lazy-sections.test.ts b/test/qa-lazy-sections.test.ts index 699cf32d4..8ba03d20b 100644 --- a/test/qa-lazy-sections.test.ts +++ b/test/qa-lazy-sections.test.ts @@ -161,8 +161,8 @@ describe('QA-only cross-host lazy rendering', () => { expect(fs.readFileSync(path.join(rendered, dir, 'SKILL.md'), 'utf8')).not.toContain(body.split('\n').slice(2).join('\n').trim()); } const outside = generated.artifacts.filter(artifact => artifact.host === host.name && artifact.kind === 'section' - && !/^(?:qa|qa-only|ship|plan-ceo-review)\//.test(artifact.relativePath) - && !/\/gstack-(?:qa(?:-only)?|ship|plan-ceo-review)\//.test(artifact.relativePath)); + && !/^(?:qa|qa-only|ship|plan-ceo-review|office-hours)\//.test(artifact.relativePath) + && !/\/gstack-(?:qa(?:-only)?|ship|plan-ceo-review|office-hours)\//.test(artifact.relativePath)); expect(outside.length > 0).toBe(host.name === 'claude'); // C4: ship is carved on every host; external pointers are relative to the installed skill. const ctx = context(host.name, 'ship');