merge: integrate origin/main (v0.18.2.0) — context rot defense for /ship

Main added one commit (#1030, b3eaffce): "context rot defense for /ship —
subagent isolation + clean step numbering (v0.18.2.0)". This restructured
the ship template to:
- Renumber fractional steps (3.47, 8.5, 8.75) to clean integers (1-20)
- Move document-release from post-PR (Step 8.5) to pre-PR subagent
  dispatch (Step 18) so doc sync actually happens
- Wrap 4 heavy sub-workflows (coverage audit, plan completion audit,
  Greptile triage, doc sync) in subagent dispatches for context isolation

Conflicts and resolutions:
- VERSION: kept this branch's 0.19.0.0 (higher than main's 0.18.2.0).
- CHANGELOG.md: kept both entries — 0.19.0.0 on top, 0.18.2.0 below,
  contiguous version sequence preserved.
- ship/SKILL.md.tmpl: integrated this branch's WIP-squash sub-step with
  main's renumbered step structure. My old "Step 5.75: WIP Commit Squash"
  is now "Step 15.0: WIP Commit Squash" — a genuinely-nested sub-step
  inside main's "Step 15: Commit (bisectable chunks)". Per main's note:
  "Resolver sub-steps that are genuinely nested are preserved." Internal
  refs updated (Step 6 → Step 15.1, Step 7 → push step).
- package.json: version mismatch with VERSION caught by gen-skill-docs
  test. Bumped to 0.19.0.0 to match.
- ship/SKILL.md and golden ship fixtures: regenerated via
  `bun run gen:skill-docs --host all` and re-snapshotted for
  claude/codex/factory hosts.

Verification:
- bun test test/gen-skill-docs.test.ts: 348 pass / 0 fail
- bun test test/host-config.test.ts: passes
- bun run gen:skill-docs --host all: completes cleanly

Token-ceiling warnings on plan-ceo-review (29K), office-hours (26K),
ship (35K — grew slightly from main's 34K with the WIP squash addition).
Pre-existing concern, flagged as follow-up, not blocking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-17 14:24:35 +08:00
18 changed files with 954 additions and 606 deletions
+6 -6
View File
@@ -13,8 +13,8 @@ import type { TemplateContext } from './types';
function generateSpecialistSelection(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepSel = isShip ? '3.55' : '4.5';
const stepMerge = isShip ? '3.56' : '4.6';
const stepSel = isShip ? '9.1' : '4.5';
const stepMerge = isShip ? '9.2' : '4.6';
const nextStep = isShip ? 'the Fix-First flow (item 4)' : 'Step 5';
return `## Step ${stepSel}: Review Army — Specialist Dispatch
@@ -134,10 +134,10 @@ CHECKLIST:
function generateFindingsMerge(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepMerge = isShip ? '3.56' : '4.6';
const stepSel = isShip ? '3.55' : '4.5';
const stepMerge = isShip ? '9.2' : '4.6';
const stepSel = isShip ? '9.1' : '4.5';
const fixFirstRef = isShip ? 'the Fix-First flow (item 4)' : 'Step 5 Fix-First';
const critPassRef = isShip ? 'the checklist pass (Step 3.5)' : 'the CRITICAL pass findings from Step 4';
const critPassRef = isShip ? 'the checklist pass (Step 9)' : 'the CRITICAL pass findings from Step 4';
const persistRef = isShip ? 'the review-log persist' : 'the review-log entry in Step 5.8';
return `### Step ${stepMerge}: Collect and merge findings
@@ -202,7 +202,7 @@ Remember these stats — you will need them for the review-log entry in Step 5.8
function generateRedTeam(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepMerge = isShip ? '3.56' : '4.6';
const stepMerge = isShip ? '9.2' : '4.6';
const fixFirstRef = isShip ? 'the Fix-First flow (item 4)' : 'Step 5 Fix-First';
return `### Red Team dispatch (conditional)
+9 -9
View File
@@ -368,7 +368,7 @@ If A: revise the premise and note the revision. If B: proceed (and note that the
export function generateScopeDrift(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepNum = isShip ? '3.48' : '1.5';
const stepNum = isShip ? '8.2' : '1.5';
return `## Step ${stepNum}: Scope Drift Detection
@@ -413,7 +413,7 @@ export function generateAdversarialStep(ctx: TemplateContext): string {
if (ctx.host === 'codex') return '';
const isShip = ctx.skillName === 'ship';
const stepNum = isShip ? '3.8' : '5.7';
const stepNum = isShip ? '11' : '5.7';
return `## Step ${stepNum}: Adversarial review (always-on)
@@ -501,7 +501,7 @@ A) Investigate and fix now (recommended)
B) Continue — review will still complete
\`\`\`
If A: address the findings${isShip ? '. After fixing, re-run tests (Step 3) since code has changed' : ''}. Re-run \`codex review\` to verify.
If A: address the findings${isShip ? '. After fixing, re-run tests (Step 5) since code has changed' : ''}. Re-run \`codex review\` to verify.
Read stderr for errors (same error handling as Codex adversarial above).
@@ -917,16 +917,16 @@ export function generatePlanCompletionAuditReview(_ctx: TemplateContext): string
// ─── Plan Verification Execution ──────────────────────────────────────
export function generatePlanVerificationExec(_ctx: TemplateContext): string {
return `## Step 3.47: Plan Verification
return `## Step 8.1: Plan Verification
Automatically verify the plan's testing/verification steps using the \`/qa-only\` skill.
### 1. Check for verification section
Using the plan file already discovered in Step 3.45, look for a verification section. Match any of these headings: \`## Verification\`, \`## Test plan\`, \`## Testing\`, \`## How to test\`, \`## Manual testing\`, or any section with verification-flavored items (URLs to visit, things to check visually, interactions to test).
Using the plan file already discovered in Step 8, look for a verification section. Match any of these headings: \`## Verification\`, \`## Test plan\`, \`## Testing\`, \`## How to test\`, \`## Manual testing\`, or any section with verification-flavored items (URLs to visit, things to check visually, interactions to test).
**If no verification section found:** Skip with "No verification steps found in plan — skipping auto-verification."
**If no plan file was found in Step 3.45:** Skip (already handled).
**If no plan file was found in Step 8:** Skip (already handled).
### 2. Check for running dev server
@@ -971,7 +971,7 @@ Follow the /qa-only workflow with these modifications:
### 5. Include in PR body
Add a \`## Verification Results\` section to the PR body (Step 8):
Add a \`## Verification Results\` section to the PR body (Step 19):
- If verification ran: summary of results (N PASS, M FAIL, K SKIPPED)
- If skipped: reason for skipping (no plan, no server, no verification section)`;
}
@@ -980,9 +980,9 @@ Add a \`## Verification Results\` section to the PR body (Step 8):
export function generateCrossReviewDedup(ctx: TemplateContext): string {
const isShip = ctx.skillName === 'ship';
const stepNum = isShip ? '3.57' : '5.0';
const stepNum = isShip ? '9.3' : '5.0';
const findingsRef = isShip
? 'the checklist pass (Step 3.5) and specialist review (Step 3.55-3.56)'
? 'the checklist pass (Step 9) and specialist review (Step 9.1-9.2)'
: 'Step 4 critical pass and Step 4.5-4.6 specialists';
return `### Step ${stepNum}: Cross-review finding dedup
+5 -5
View File
@@ -28,7 +28,7 @@ ls -d test/ tests/ spec/ __tests__/ cypress/ e2e/ 2>/dev/null
**If test framework detected** (config files or test directories found):
Print "Test framework detected: {name} ({N} existing tests). Skipping bootstrap."
Read 2-3 existing test files to learn conventions (naming, imports, assertion style, setup patterns).
Store conventions as prose context for use in Phase 8e.5 or Step 3.4. **Skip the rest of bootstrap.**
Store conventions as prose context for use in Phase 8e.5 or Step 7. **Skip the rest of bootstrap.**
**If BOOTSTRAP_DECLINED** appears: Print "Test bootstrap previously declined — skipping." **Skip the rest of bootstrap.**
@@ -213,7 +213,7 @@ ls jest.config.* vitest.config.* playwright.config.* cypress.config.* .rspec pyt
ls -d test/ tests/ spec/ __tests__/ cypress/ e2e/ 2>/dev/null
\`\`\`
3. **If no framework detected:**${mode === 'ship' ? ' falls through to the Test Framework Bootstrap step (Step 2.5) which handles full setup.' : ' still produce the coverage diagram, but skip test generation.'}`);
3. **If no framework detected:**${mode === 'ship' ? ' falls through to the Test Framework Bootstrap step (Step 4) which handles full setup.' : ' still produce the coverage diagram, but skip test generation.'}`);
// ── Before/after count (ship only) ──
if (mode === 'ship') {
@@ -379,7 +379,7 @@ GAPS: 8 paths need tests (2 need E2E, 1 needs eval)
─────────────────────────────────
\`\`\`
**Fast path:** All paths covered → "${mode === 'ship' ? 'Step 3.4' : mode === 'review' ? 'Step 4.75' : 'Test review'}: All new code paths have test coverage ✓" Continue.`);
**Fast path:** All paths covered → "${mode === 'ship' ? 'Step 7' : mode === 'review' ? 'Step 4.75' : 'Test review'}: All new code paths have test coverage ✓" Continue.`);
// ── Mode-specific action section ──
if (mode === 'plan') {
@@ -432,7 +432,7 @@ This file is consumed by \`/qa\` and \`/qa-only\` as primary test input. Include
sections.push(`
**5. Generate tests for uncovered paths:**
If test framework detected (or bootstrapped in Step 2.5):
If test framework detected (or bootstrapped in Step 4):
- Prioritize error handlers and edge cases first (happy paths are more likely already tested)
- Read 2-3 existing test files to match conventions exactly
- Generate unit tests. Mock all external dependencies (DB, API, Redis).
@@ -446,7 +446,7 @@ Caps: 30 code paths max, 20 tests generated max (code + user flow combined), 2-m
If no test framework AND user declined bootstrap → diagram only, no generation. Note: "Test generation skipped — no test framework configured."
**Diff is test-only changes:** Skip Step 3.4 entirely: "No new application code paths to audit."
**Diff is test-only changes:** Skip Step 7 entirely: "No new application code paths to audit."
**6. After-count and coverage summary:**
+1 -1
View File
@@ -373,7 +373,7 @@ export function generateCoAuthorTrailer(ctx: TemplateContext): string {
}
export function generateChangelogWorkflow(_ctx: TemplateContext): string {
return `## CHANGELOG (auto-generate)
return `## Step 13: CHANGELOG (auto-generate)
1. Read \`CHANGELOG.md\` header to know the format.