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 <dgrant@users.noreply.github.com>
This commit is contained in:
garrytananddgrant committed 2026-10-06 20:57:02 +00:00
1 parent 7637f604a4
commit b7f16261e8
3 files changed
+6 -6

No files matched your search

+1 -1
View File
@@ -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;
+3 -3
View File
@@ -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/<skill>/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 }> };
+2 -2
View File
@@ -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');