diff --git a/.claude/skills/ship-feature-lane/SKILL.md b/.claude/skills/ship-feature-lane/SKILL.md index fdb3e81..67865ec 100644 --- a/.claude/skills/ship-feature-lane/SKILL.md +++ b/.claude/skills/ship-feature-lane/SKILL.md @@ -83,8 +83,7 @@ Do NOT jump to code. Understand the requirement first. ### 2 — Pre-push CI gates + dev preflight (on the feature branch) - `ccam lanes hook ci-gate` — runs the profile's CI gate (lint / test / contract checks) against an isolated per-lane test DB. On failure: read the output, fix on the feature branch, commit, re-run. Loop until green. -- `ccam lanes sync-base --check feat/` — the dev preflight: fetches and checks the branch against the CURRENT `origin/development` without merging anything. **This command is a LATER task, not yet built as of this skill's authoring** — until it exists, skip this preflight check and rely on Stage 12's conflict handling to catch a divergence at merge time; note this gap explicitly in your Stage 2 evidence (`ccam stage gates --evidence "sync-base preflight unavailable, skipped"`). - - Once built, its contract is: exit 5 on a migration-number collision (print the exact rename, do it on the feature branch, re-run Stage 2); informational `DEV_DELTA:`/`DEV_OVERLAP:` output otherwise (you do NOT sync the branch for it — GitHub merges non-conflicting histories fine). +- `ccam lanes sync-base --check feat/` — the dev preflight: fetches and checks the branch against the CURRENT `origin/development` without merging anything. Exit 5 on a migration-number collision: rename the printed file to the suggested number on the feature branch (`git mv`, update any in-file references), then re-run Stage 2. Exit 0 with `DEV_DELTA:`/`DEV_OVERLAP:` output otherwise — informational, you do NOT sync the branch for it (GitHub merges non-conflicting histories fine); a large overlapping delta is a heads-up that post-merge behavior may differ from what you test locally. ### 3 — E2E on the feature branch The e2e hook doesn't run migrations itself — it tests the already-running stack. To exercise the feature's code and any new schema, boot the lane stack with the feature branch first: @@ -124,7 +123,7 @@ The e2e hook doesn't run migrations itself — it tests the already-running stac ### 8 — Publish: push branch + open/update PR *(GATED — only on GO)* - `ccam stage publishing --status running` -- Re-run the preflight if `ccam lanes sync-base` exists by the time you read this — development may have moved while you were in QC. If it doesn't exist yet, skip straight to the push (same gap noted in Stage 2). +- Re-run the preflight: `ccam lanes sync-base --check feat/` — development may have moved while you were in QC. A migration collision here (exit 5) sends you back to Stage 2 with the rename; a clean result (exit 0) proceeds to the push. - `git push -u origin feat/` — first push of the feature branch to remote. All gates have passed before this point; the PR is finalized before reviewers see it. - Open or update the PR **based on and targeting `development`**: `gh pr create --base development --fill` (or `gh pr edit` / the push itself if a prior run already created it). Capture the URL. - `ccam stage pr-open --evidence ""` — the dashboard shows the PR link from here (via `--evidence` in `ccam feature show`/`ccam lanes`). @@ -152,8 +151,8 @@ The e2e hook doesn't run migrations itself — it tests the already-running stac - `MERGED` → a human merged it: go to **Stage 13** (post-merge verification). - `CLOSED` (unmerged) → the human rejected/abandoned it: `ccam stage done --status passed --note "PR closed unmerged by human"` → STOP. - `CONFLICTING` → the feature branch conflicts with `development`. Resolve it as real work: - - If `ccam lanes sync-base` exists by now: `ccam lanes sync-base feat/` (merges the latest `origin/development` INTO the feature branch — the only sanctioned merge). Resolve every conflict thoughtfully — keep `development`'s behavior for code unrelated to this feature, preserve the feature's intent where they overlap; when genuinely ambiguous, STOP and escalate (`--status blocked`, note the files) rather than guess. `git add` ONLY the conflicted files, `git commit --no-edit`. - - If it doesn't exist yet: `git fetch origin && git merge origin/development` directly on the feature branch, resolve conflicts the same way, commit. + - `ccam lanes sync-base feat/` (merges the latest `origin/development` INTO the feature branch — the only sanctioned merge). A migration-number collision (exit 5) means nothing was merged — rename the printed file on the feature branch, re-run Stage 2, then retry this step. + - **Exit 4 — merge conflict, left in place on purpose.** Resolve every conflict thoughtfully on the feature branch — keep `development`'s behavior for code unrelated to this feature, preserve the feature's intent where they overlap; when genuinely ambiguous, STOP and escalate (`--status blocked`, note the files) rather than guess. Never hand-merge a generated contract/client file listed in the profile's `GENERATED_MERGE_PATHS` — the keep-ours driver + regen own them. `git add` ONLY the conflicted files, `git commit --no-edit`, then `ccam lanes sync-base --continue feat/` (folds any regenerated artifacts into a follow-up commit). - Re-enter the pipeline **from Stage 2 through Stage 8** (the push updates the PR), then return here and keep watching. - For each new PR comment (list with `gh pr view --json comments`, tracking which you've already handled by comment id in your own notes), triage AND **always reply on its thread** (every comment gets a response — no silent handling, so reviewers see it was considered): - **Worth fixing** (reviewer-requested change, real bug, test/doc gap): this is a NEW CHANGE — apply it on the feature branch and re-enter the pipeline **from Stage 2 through Stage 8** (+ Stage 10 CI watch). The full process applies; no shortcuts because "it's just review feedback". **After the fix is pushed, reply to the comment** confirming resolution — what changed + the commit/PR ref — by writing the reply to a file and posting `gh pr comment --body-file ` referencing the comment. **Never inline `--body "..."`** — bodies carry backticks/`file:line`/`$(...)` that bash reads as command substitution inside double quotes, which corrupts the comment and trips an approval prompt. Then come back here and keep watching. diff --git a/docs/LANES.md b/docs/LANES.md index e2684bb..3579b13 100644 --- a/docs/LANES.md +++ b/docs/LANES.md @@ -1013,6 +1013,28 @@ QC_BOOT_ENV="MOCK_PAYMENTS=1 STUB_EMAIL=1" These environment variables are passed to the profile's `boot` hook during `ccam lanes up --qc`, ensuring QC test runs are deterministic. +### Dev preflight and merge safety: sync-base + +`ccam lanes sync-base` is the ONE sanctioned merge in the pipeline — `origin/development` into a feature branch — used at Stages 2, 8, and 12. Three modes: + +```bash +ccam lanes sync-base --check feat/ # read-only preflight: fetch + collision check + DEV_DELTA/DEV_OVERLAP +ccam lanes sync-base feat/ # merge origin/development into the feature branch +ccam lanes sync-base --continue feat/ # finish after a manually resolved conflict +``` + +Exit codes: `0` clean, `4` merge conflict (left in place — resolve, commit, then `--continue`), `5` migration-number collision (nothing merged — rename the printed file, re-run). + +Two profile declarations control it, both empty (off) by default: + +```bash +# .ccam/profile/profile.env +MIGRATIONS_DIR="db/migrations" +GENERATED_MERGE_PATHS="api/openapi.json api/client.ts" +``` + +`MIGRATIONS_DIR` enables the collision preflight against a numbered-migrations directory. `GENERATED_MERGE_PATHS` gives the listed files a keep-ours merge driver (never hand-merged) and folds the profile's `regen` hook output into the sync commit — the single most common cross-lane conflict, for a repo that generates an API contract/client. + ### Pipeline template: ship-feature (16 node stages) The skill uses the `ship-feature` pipeline template, which defines the following 16 stages (node IDs): diff --git a/docs/superpowers/plans/2026-08-03-shipyard-parity-lanes.md b/docs/superpowers/plans/2026-08-03-shipyard-parity-lanes.md index 77ac583..bda47ec 100644 --- a/docs/superpowers/plans/2026-08-03-shipyard-parity-lanes.md +++ b/docs/superpowers/plans/2026-08-03-shipyard-parity-lanes.md @@ -279,7 +279,7 @@ with `LOCK_MAX_HOLD=1`; release from a non-holder is refused and leaves the lock **Goal:** port Shipyard's driving skill and its five agents. Needs A2·B·C·D. -**Progress:** pipeline template + skill text (E1) done 2026-08-04 — see `docs/superpowers/specs/2026-08-04-ship-feature-skill-design.md`. Agents, `sync-base`, and F's integrations remain. +**Progress:** pipeline template + skill text (E1) done 2026-08-04 — see `docs/superpowers/specs/2026-08-04-ship-feature-skill-design.md`. `sync-base` (E2) done 2026-08-05 — see `docs/superpowers/specs/2026-08-05-sync-base-design.md`. Agents and F's integrations remain. **This is where "CCAM does not orchestrate" is preserved by construction:** the skill runs in the session and calls `ccam` commands; the dashboard still only