refactor(office-hours): carve Phase 5+6 into on-demand section

Third Phase B carve (v2_PLAN.md:216, after ship and plan-ceo-review). Moves
Phase 5 (Design Doc templates) + Phase 6 (tiered relationship handoff) — the
session's output + closing tail, only reached after the conversation and
alternatives are done — into sections/design-and-handoff.md, behind a single
STOP-Read after Phase 4.5. The live conversation (Phases 1-4.5) and the
always-run Important Rules stay in the always-loaded skeleton.

Measured: always-loaded skeleton 118,280 -> 88,975 B (-24.8%). Union preserved.
The carved AUQ is identical to pre-carve (matrix: 7/7 format, substance 5),
and Layer 0 confirms the AUQ format spec stays in the skeleton — the AUQ
paranoid suite de-risked this carve end to end.

Atomic with tests + regen (skill-docs.yml gates gen:skill-docs freshness on
every push, so source + regen + tests land together; --host all regenerates
the inlined non-Claude variants):
- sections/manifest.json: passive registry, one entry.
- parity-harness: office-hours flipped to sectioned, maxSkeletonBytes 96_000
  (measured 88,975 + headroom); content/minBytes run against the union.
- skill-size-budget: office-hours added to SECTIONS_EXTRACTED.
- gen-skill-docs + skill-validation: read the skeleton+sections union for
  office-hours so relocated Phase 5/6 prose still counts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-06-01 22:25:07 -07:00
parent ed996caa61
commit be3ebbb58f
9 changed files with 1032 additions and 975 deletions
+6 -6
View File
@@ -1144,7 +1144,7 @@ describe('Retro plan completion section', () => {
describe('Plan status footer in preamble', () => {
test('preamble contains plan status footer as neutral forward reference to EXIT PLAN MODE GATE', () => {
// Read any skill that uses PREAMBLE
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
const content = readSkillUnion('office-hours'); // carved: Phase 5/6 prose moved to section
expect(content).toContain('Plan Status Footer');
expect(content).toContain('GSTACK REVIEW REPORT');
expect(content).toContain('ExitPlanMode');
@@ -1179,7 +1179,7 @@ describe('make-pdf setup ordering', () => {
describe('Skill invocation during plan mode in preamble', () => {
test('preamble contains skill invocation plan mode section', () => {
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
const content = readSkillUnion('office-hours'); // carved: Phase 5/6 prose moved to section
expect(content).toContain('Skill Invocation During Plan Mode');
expect(content).toContain('precedence over generic plan mode behavior');
expect(content).toContain('Do not continue the workflow');
@@ -1190,7 +1190,7 @@ describe('Skill invocation during plan mode in preamble', () => {
// --- {{SPEC_REVIEW_LOOP}} resolver tests ---
describe('SPEC_REVIEW_LOOP resolver', () => {
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
const content = readSkillUnion('office-hours'); // carved: Phase 5/6 prose moved to section
test('contains all 5 review dimensions', () => {
for (const dim of ['Completeness', 'Consistency', 'Clarity', 'Scope', 'Feasibility']) {
@@ -1226,7 +1226,7 @@ describe('SPEC_REVIEW_LOOP resolver', () => {
// --- {{DESIGN_SKETCH}} resolver tests ---
describe('DESIGN_SKETCH resolver', () => {
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
const content = readSkillUnion('office-hours'); // carved: Phase 5/6 prose moved to section
test('references DESIGN.md for design system constraints', () => {
expect(content).toContain('DESIGN.md');
@@ -1256,7 +1256,7 @@ describe('DESIGN_SKETCH resolver', () => {
// --- {{CODEX_SECOND_OPINION}} resolver tests ---
describe('CODEX_SECOND_OPINION resolver', () => {
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
const content = readSkillUnion('office-hours'); // carved: Phase 5/6 prose moved to section
const codexContent = fs.readFileSync(path.join(ROOT, '.agents', 'skills', 'gstack-office-hours', 'SKILL.md'), 'utf-8');
test('Phase 3.5 section appears in office-hours SKILL.md', () => {
@@ -1624,7 +1624,7 @@ describe('DESIGN_HARD_RULES resolver', () => {
// --- Extended DESIGN_SKETCH resolver tests ---
describe('DESIGN_SKETCH extended with outside voices', () => {
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
const content = readSkillUnion('office-hours'); // carved: Phase 5/6 prose moved to section
test('contains outside design voices step', () => {
expect(content).toContain('Outside design voices');
+8
View File
@@ -288,7 +288,15 @@ export const PARITY_INVARIANTS: ParityInvariant[] = [
minBytes: 30_000,
},
{
// Carved (v2 plan T9): skeleton SKILL.md + sections/design-and-handoff.md.
// Phase 5 (design doc) + Phase 6 (handoff) moved into the section, so
// 'design doc' / 'problem statement' now live there — content checks run
// against the union. maxSkeletonBytes asserts the always-loaded skeleton
// shrank from the ~118KB monolith to ~89KB (measured 88,975 B, -24.8%);
// headroom to 96KB so a small skeleton edit doesn't trip CI.
skill: 'office-hours',
sectioned: true,
maxSkeletonBytes: 96_000,
mustContain: ['design doc', 'problem statement'],
mustHaveHeadings: ['## Preamble', '## When to invoke'],
maxSizeRatio: 1.05,
+1 -1
View File
@@ -163,7 +163,7 @@ describe('SKILL.md size budget regression (gate, free)', () => {
// because prose moved into sections/*.md. The union size is guarded instead
// by the sectioned ship invariant in parity-harness.ts (minBytes on the
// skeleton+sections union), so exempt the skeleton from the body-strip floor.
const SECTIONS_EXTRACTED = new Set<string>(['ship', 'plan-ceo-review']);
const SECTIONS_EXTRACTED = new Set<string>(['ship', 'plan-ceo-review', 'office-hours']);
const undershoots: Array<{
skill: string; beforeBytes: number; afterBytes: number; ratio: number;
+4 -1
View File
@@ -623,7 +623,10 @@ describe('v0.4.1 preamble features', () => {
// --- Structural tests for new skills ---
describe('office-hours skill structure', () => {
const content = fs.readFileSync(path.join(ROOT, 'office-hours', 'SKILL.md'), 'utf-8');
// Carved (v2 plan T9): Phase 5 (Design Doc) + Phase 6 (handoff) moved into
// sections/design-and-handoff.md, so structural phrases now live there — read
// the skeleton+sections union.
const content = readSkillUnion('office-hours');
// Original structural assertions
for (const section of ['Phase 1', 'Phase 2', 'Phase 3', 'Phase 4', 'Phase 5', 'Phase 6',