Files
Claude-Code-Monitor/docs/superpowers/specs/2026-08-04-ship-feature-skill-design.md
nntrivi2001 b08504858c docs(lanes): design E1 — ship-feature pipeline template + skill port
Scopes the first of E's four independent pieces: --qc boot flag +
QC_BOOT_ENV, the pipeline template, and the ported skill text. Agents,
sync-base, and F's integrations are named but deliberately out of scope,
per the roadmap's own subsystem split.
2026-08-04 17:37:33 +07:00

76 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# E1 — Ship-feature pipeline template + skill port
**Status:** approved 2026-08-04. Roadmap it belongs to:
`docs/superpowers/plans/2026-08-03-shipyard-parity-lanes.md` (subsystem **E**).
## Problem
Shipyard's `ship-feature/SKILL.md` (`~/MyDrive/Projects/ResearchAndDevelopment/AgentWorkflow/claude/skills/ship-feature/SKILL.md`, 208 lines, 16 stages) is the driving skill that runs a lane end-to-end: intake → TDD implement → gates → e2e → review → QC → senior gate → publish PR → watch → post-merge verify → done. CCAM has no equivalent yet. E (per the roadmap) is four independent pieces — this spec covers only the first: the pipeline template + the skill text itself. Agents (qc-local, senior-gate-reviewer, ticketer, dev-qc, pr-reviewer) and `ccam lanes sync-base` are separate, later tasks; F's integrations (tracker, dev-QC, CI-wait) are later still.
## Scope
**In scope:**
1. A backend gap the skill text requires to be truthful: `ccam lanes up --qc`, backed by a new `QC_BOOT_ENV` profile declaration.
2. `server/data/pipelines/ship-feature.json` — the node/stage definitions the dashboard renders against.
3. `.claude/skills/ship-feature-lane/SKILL.md` — the ported skill, every Shipyard `bin/…` call rewritten to its CCAM equivalent.
**Out of scope (later tasks, referenced by name in the ported skill but not built here):**
- `ccam lanes sync-base` (the migration-collision + merge-driver command Stage 2/8/12 call).
- `ccam lanes mcp sync` (F) — Stage 0's MCP preflight becomes a manual check + a message to the human, not an auto-sync call.
- `ccam lanes integration <name>` / `.ccam/profile/integrations.env` (F) — tracker/dev_qc/ci_wait are **hardcoded off** in this port; Stage 9 (ticket) and the dev-QC half of Stage 13 unconditionally skip; Stage 10's CI watch unconditionally uses the `gh pr checks` fallback the original skill already documents for "helper not configured" (no conditional branch needed — there is nothing to branch on yet).
- `ccam ci` (F, `ci-job.sh` port) — same reasoning; Stage 10/13's CI-triage logic that depends on it is dropped to the fallback path.
- The five agents — the skill references them by `subagent_type` at Stages 6/7/9/13/12(pr-reviewer callout), but none exist yet. This spec's own verification stops where an agent invocation would occur.
## Decisions
| | Choice | Rationale |
|---|---|---|
| `--qc` boot flag | New `QC_BOOT_ENV` profile declaration (space-separated `KEY=value` pairs, same shape as Shipyard's), injected into the boot hook's environment only when `up` is called with `qc: true` | The skill calls `lane-up.sh "$N" --qc` in Stage 3 to get a deterministic (mocked/stubbed) stack for QC. Without a real flag this line in the ported skill would be false documentation — violates this repo's docs rule (executable, aligned with actual scripts). A profile that never declares `QC_BOOT_ENV` gets no extra env (dead code doesn't run), same pattern every other A2 declaration in `DEFAULTS` already follows. |
| `state.sh "$N" init` (open a clean feature slot before Stage 0's Q&A) | Dropped — replaced by a plain `ccam feature activate <slug>` at Stage 1 | Task B's `activateFeature` already archives the outgoing active feature automatically on switch; Shipyard needed a separate `init` step because it had no DB-backed archive. Porting `init` as a distinct call would be redundant with what `activate` already does. |
| Integration toggles (tracker/dev_qc/ci_wait) | Hardcoded off, not a runtime check | F doesn't exist yet. The alternative (a stub `ccam lanes integration` that always returns off) adds surface area for no behavioral difference today; the skill's own text already documents the "toggle off" behavior for each stage, so hardcoding is truthful, not a shortcut. When F ships, this becomes a follow-up edit to swap hardcoded skips for real checks — an explicit, later, reviewable diff. |
| Hook names for `lane-ci-gate.sh` / `lane-e2e.sh` | `ccam lanes hook ci-gate` / `ccam lanes hook e2e` | Both names are **already** in `server/lib/lane-profile.js`'s `HOOKS` allowlist, added during A1 specifically "because... the driving skill needs that surface stable" — this spec is that driving skill. No backend change needed for these two. |
| `.harness-lane` marker / `lane-assign.sh` | Dropped entirely | CCAM already resolves a lane from `cwd` (path-boundary prefix match, documented in this repo's CLAUDE.md) — the marker file and the assign step exist in Shipyard only because it has no such resolution. |
| `@@HARNESS_ROOT@@` / `@@DEV_QC_MCP@@` / `@@TRACKER_MCP@@` placeholders | Dropped | Install-time templating that doesn't exist in CCAM; every reference becomes the literal CCAM command or, for the two MCP placeholders, is deleted along with the (out-of-scope) integrations that used them. |
## Command mapping
| Shipyard | CCAM | Status |
|---|---|---|
| `state.sh "$N" set stage=X status=Y` | `ccam stage X --status Y` | exists |
| `state.sh "$N" activate feat/<slug>` | `ccam feature activate <slug>` | exists (Task B) |
| `state.sh "$N" init` | (dropped — see Decisions) | n/a |
| `lane-ci-gate.sh "$N"` | `ccam lanes hook ci-gate` | exists (hook allowlisted) |
| `lane-up.sh "$N" --qc` | `ccam lanes up --qc` | **new in this task** |
| `lane-e2e.sh "$N" [-- specs]` | `ccam lanes hook e2e [-- specs]` | exists (hook allowlisted) |
| `lane-sync-dev.sh …` | `ccam lanes sync-base …` | later task (referenced, not built) |
| `lane-mcp-sync.sh "$N"` | `ccam lanes mcp sync` | F (referenced as manual fallback) |
| `lane-env.sh "$N" --check X` | (hardcoded off) | F (deferred) |
| `ci-job.sh status\|failures\|rerun\|cancel` | `ccam ci …` | F (deferred; skill uses its own `gh`-only fallback) |
## Design
### `--qc` boot flag
- `QC_BOOT_ENV` added to `server/lib/lane-profile.js`'s `DEFAULTS` (empty string default — off).
- `POST /:id/up` accepts `{build, qc}` in its body (currently only reads `build`); `qc: true` is threaded through to whatever assembles the boot hook's environment (read the actual `upLane`/hook-invocation code path in `server/lib/lane-runtime.js` before implementing — this spec names the profile declaration and the route contract, not the exact internal plumbing function).
- `ccam lanes up [--no-build] [--qc]` in `bin/ccam.js``--qc` sets `{qc: true}` in the POST body alongside the existing `--no-build``{build: false}` handling.
- `QC_BOOT_ENV` format: space-separated `KEY=value` pairs, parsed the same way this file already parses `PORTS`/`LANE_DIRS` (space-separated lists) — not a new parsing convention.
### Pipeline template
`server/data/pipelines/ship-feature.json` — one node per skill stage (0 through 15, using the skill's own stage names: `intake`, `plan`, `implementing`, `gates`, `e2e-feature`, `e2e-feature-passed`, `review`, `qc-plan`, `qc`, `gate`, `publishing`, `pr-open`, `reported`, `watching-pr`, `merged`, `done`), same node-definition shape `default.json` already uses (label, `detect` rules matching the `stage=` values `ccam stage` sets). `default.json` untouched. A lane opts into this template via its `pipeline` field, same mechanism every other custom template already uses.
### Skill
`.claude/skills/ship-feature-lane/SKILL.md` — the full port. Frontmatter, hard rules, and all 16 stages carried over with the Command mapping table's substitutions applied line-by-line. Every hard-won rule (turn-liveness, no-retry-cap/phase-clock, one-driver-per-MCP, never-push-base, the fix-loop's two fast-path exceptions, cross-lane etiquette) is kept verbatim in spirit, with `lane-lock.sh` etiquette re-pointed at D's `ccam lock` CLI and named locks.
## Invariants
1. **CCAM still does not orchestrate.** The skill runs in the session and calls `ccam` commands one at a time; nothing in this task adds chaining, gate evaluation, or retry logic to the dashboard itself.
2. **Every command the skill text names must actually exist and behave as documented** — the docs-markdown rule (executable examples, aligned with actual scripts) applies to a skill file exactly as it applies to `docs/*.md`.
3. **A profile that never declares `QC_BOOT_ENV` sees no behavior change**`--qc` degrades to a plain boot when the declaration is absent, same as every other optional A2 declaration.
## Verify
A real dry run on a scratch repo with a profile, walking Stage 0 through Stage 2 (intake → plan → `ccam lanes hook ci-gate`) — the furthest the pipeline can go without the not-yet-built agents. Confirms every `ccam` command named in stages 02 exists and behaves as documented. `ccam lanes up --qc` gets its own unit/integration test verifying `QC_BOOT_ENV` reaches the boot hook's environment when declared, and is a no-op when absent. Full Stage 0→14 verification is the agents-port task's responsibility, once qc-local/senior-gate-reviewer exist.