From eac779451f0a60feb8f5b3bd05b4f794fd7a96b0 Mon Sep 17 00:00:00 2001 From: Diego Andres Rabaioli Date: Sat, 20 Jun 2026 12:03:26 +0200 Subject: [PATCH 1/3] Fix Phase 10: dynamic default branch, /cdd-merge-base rename, CamelCase PROJECT_DIR, dynamic repo path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three Phase 10 defects closed: 1. cdd-merge-main.md → cdd-merge-base.md (both repo + template copies). The new command resolves the default branch at runtime via `git symbolic-ref --quiet --short refs/remotes/origin/HEAD` (fallback `main`), matching the worktree helper's existing approach. All `origin/main` git-command references replaced with `$DEFAULT_BRANCH`. cdd-pre-pr.md updated the same way. A scope note documents the gitflow case (platform default ≠ integration branch) as out of scope; tracked as a new Phase 10 item in the roadmap. 2. bootstrap-cdd-project.sh PROJECT_DIR regex loosened from ^[a-z][a-z0-9_-]*$ to ^[A-Za-z][A-Za-z0-9_-]*$ so CamelCase dirs like PyGroundControl are accepted. The rendered handoff path in cdd-next-step.md now matches what the worktree helper derives from the actual directory basename, closing the "No handoff file" divergence defect. CamelCase bootstrap case added to CI workflow and CLAUDE.md build/test section. 3. cdd-next-step.md §8 updated in both copies to resolve the repo root via `git rev-parse --show-toplevel` and embed the actual path in the printed source line, instead of hardcoding $HOME/Code/... Cross-cuts: all cdd-merge-main references swept across the full repo (process doc, demo, CLAUDE.md, template/CLAUDE.md, BOOTSTRAP.md, cdd-process-pr, cdd-retrofit, roadmap, ADR, feature/arch docs). Process doc §2.9 and template/BOOTSTRAP.md updated to note CamelCase is permitted for PROJECT_DIR. Roadmap Phase 10 items marked done; new gitflow item filed. Whitelist updated with three new <...> tokens introduced by the commands. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../{cdd-merge-main.md => cdd-merge-base.md} | 60 +++++++++++-------- .claude/commands/cdd-next-step.md | 10 +++- .claude/commands/cdd-pre-pr.md | 22 ++++--- .claude/commands/cdd-process-pr.md | 2 +- .claude/commands/cdd-retrofit.md | 2 +- .github/workflows/template-smoke.yml | 8 +++ CLAUDE.md | 7 ++- README.md | 2 +- demo/README.md | 4 +- demo/seed/CLAUDE.md | 2 +- demo/seed/doc/knowledge_base/roadmap.md | 4 +- ...0001-name-and-guard-founding-objectives.md | 2 +- doc/architecture/demo.md | 2 +- doc/features/demo.md | 2 +- .../claude-driven-development.md | 24 ++++---- doc/knowledge_base/roadmap.md | 9 +-- scripts/template-smoke-whitelist.txt | 3 + .../{cdd-merge-main.md => cdd-merge-base.md} | 60 +++++++++++-------- template/.claude/commands/cdd-next-step.md | 10 +++- template/.claude/commands/cdd-pre-pr.md | 22 ++++--- template/.claude/commands/cdd-process-pr.md | 2 +- template/BOOTSTRAP.md | 4 +- template/CLAUDE.md | 2 +- tools/bootstrap-cdd-project.sh | 6 +- 24 files changed, 168 insertions(+), 103 deletions(-) rename .claude/commands/{cdd-merge-main.md => cdd-merge-base.md} (57%) rename template/.claude/commands/{cdd-merge-main.md => cdd-merge-base.md} (57%) diff --git a/.claude/commands/cdd-merge-main.md b/.claude/commands/cdd-merge-base.md similarity index 57% rename from .claude/commands/cdd-merge-main.md rename to .claude/commands/cdd-merge-base.md index 4fc8fba..8996df8 100644 --- a/.claude/commands/cdd-merge-main.md +++ b/.claude/commands/cdd-merge-base.md @@ -1,13 +1,23 @@ -Integrate the current state of `main` into the feature branch. Two phases: a **dry-run conflict assessment** first, then on user approval the actual merge with conflict resolution. +Integrate the current state of the base branch into the feature branch. Two phases: a **dry-run conflict assessment** first, then on user approval the actual merge with conflict resolution. -Run this command on the feature branch (not on main). Use it when: +Run this command on the feature branch (not on the base branch). Use it when: -- `main` has advanced under your feature branch and you want to integrate before opening or merging the PR. -- Something useful has landed on main (a new utility, a refactor, an updated convention) that this branch should pick up without a separate roadmap task. +- The base branch has advanced under your feature branch and you want to integrate before opening or merging the PR. +- Something useful has landed on the base branch (a new utility, a refactor, an updated convention) that this branch should pick up without a separate roadmap task. + +## 0. Resolve the default branch + +```bash +DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null || echo main) +``` + +Use `$DEFAULT_BRANCH` everywhere `main`/`origin/main` appeared in earlier versions of this command. All git commands below use this variable. + +> **Scope note:** this detects the hosting platform's default branch. If the project uses a gitflow model where the platform default is a release branch and daily work targets a different integration branch (e.g. platform default is `main` but features branch off `devel`), this command targets the wrong branch. That case requires an explicit `BASE_BRANCH` config and is tracked as a separate roadmap item. ## 1. Sanity check -Confirm the current branch is not `main`: +Confirm the current branch is not the base branch: ```bash git rev-parse --abbrev-ref HEAD @@ -21,32 +31,32 @@ git status --porcelain If there are uncommitted changes, stop and ask the user whether to stash or commit before continuing. Do not merge over uncommitted work. -## 2. Update local main reference +## 2. Update local base branch reference ```bash -git fetch origin main +git fetch origin "$DEFAULT_BRANCH" ``` -Determine how far the branch has diverged from `origin/main`: +Determine how far the branch has diverged from `origin/$DEFAULT_BRANCH`: ```bash -git log --oneline HEAD..origin/main | head -50 -git log --oneline origin/main..HEAD | head -50 +git log --oneline "HEAD..origin/$DEFAULT_BRANCH" | head -50 +git log --oneline "origin/$DEFAULT_BRANCH..HEAD" | head -50 ``` Report: -- Number of commits on `origin/main` not in this branch. -- Number of commits on this branch not in `origin/main`. +- Number of commits on `origin/$DEFAULT_BRANCH` not in this branch. +- Number of commits on this branch not in `origin/$DEFAULT_BRANCH`. -If there is nothing on `origin/main` not in this branch, there is nothing to merge. Stop and report. +If there is nothing on `origin/$DEFAULT_BRANCH` not in this branch, there is nothing to merge. Stop and report. ## 3. Dry-run conflict assessment Perform a non-committing test merge to surface conflicts without mutating the working tree: ```bash -git merge-tree --write-tree --name-only origin/main HEAD +git merge-tree --write-tree --name-only "origin/$DEFAULT_BRANCH" HEAD ``` Capture the list of conflicting files. @@ -60,18 +70,18 @@ If there are conflicts, for each conflicting file: - Read both versions and the merge base. Use: ```bash - git show origin/main: + git show "origin/$DEFAULT_BRANCH:" git show HEAD: - git show $(git merge-base origin/main HEAD): + git show "$(git merge-base "origin/$DEFAULT_BRANCH" HEAD):" ``` - Classify the conflict: - **Mechanical**: textual collision in a region where the intent is obvious (e.g. both sides added an import, both sides added an entry to the same list, formatting drift). - **Logical**: the two sides changed the same logical concern in incompatible ways (e.g. one renamed a function the other modified the body of). - **Structural**: file moved/renamed/deleted on one side and modified on the other. -Also scan the non-conflicting changes on `origin/main` for items relevant to this branch: +Also scan the non-conflicting changes on `origin/$DEFAULT_BRANCH` for items relevant to this branch: -- New conventions established on main that this branch's code should adopt. +- New conventions established on the base branch that this branch's code should adopt. - New utilities or helpers that obviate code on this branch. - Refactored interfaces that this branch consumes. @@ -80,10 +90,10 @@ Also scan the non-conflicting changes on `origin/main` for items relevant to thi Present to the user: ``` -## Merge-main assessment +## Merge-base assessment -Commits to integrate from origin/main: -Commits unique to this branch: +Commits to integrate from origin/: +Commits unique to this branch: ### Conflicts - : , @@ -107,7 +117,7 @@ If conflicts are non-trivial, **stop and wait for explicit user approval**. Do n On user approval: ```bash -git merge origin/main +git merge "origin/$DEFAULT_BRANCH" ``` Resolve conflicts file by file: @@ -135,7 +145,7 @@ For each non-conflict item flagged in step 3 (new conventions, helpers, refactor If applied, commit separately from the merge commit with a message like: ``` -adopt: +adopt: ``` ## 7. Verify @@ -149,7 +159,7 @@ If anything fails, report the failure and stop. Do not push. Present a final summary: ``` -## Merge-main summary +## Merge-base summary - [ ] Merge completed - [ ] Conflicts resolved: (mechanical: M, logical: L, structural: S) - [ ] Improvements adopted: @@ -159,4 +169,4 @@ Present a final summary: Next: re-run /cdd-pre-pr before opening or updating the PR. ``` -The user should re-run `/cdd-pre-pr` in a fresh session after `/cdd-merge-main` to ensure the merged state passes all gates. +The user should re-run `/cdd-pre-pr` in a fresh session after `/cdd-merge-base` to ensure the merged state passes all gates. diff --git a/.claude/commands/cdd-next-step.md b/.claude/commands/cdd-next-step.md index eae72ad..0bb00e6 100644 --- a/.claude/commands/cdd-next-step.md +++ b/.claude/commands/cdd-next-step.md @@ -165,14 +165,20 @@ mkdir -p ~/.claude-handoffs/cdd ## 8. Print the next command -After writing, print exactly: +After writing, resolve the repo root: + +```bash +REPO_ROOT=$(git rev-parse --show-toplevel) +``` + +Then print exactly (substituting the actual `$REPO_ROOT` path, not a placeholder): ``` Handoff written: ~/.claude-handoffs/cdd/.md Next: cdd-worktree If `cdd-worktree` reports "command not found", the worktree helper isn't sourced. Add this to ~/.bashrc (or ~/.zshrc) and open a new shell: - [[ -f "$HOME/Code/cdd/tools/cdd-worktree.sh" ]] && source "$HOME/Code/cdd/tools/cdd-worktree.sh" + [[ -f "/tools/cdd-worktree.sh" ]] && source "/tools/cdd-worktree.sh" ``` The user will close this session, run `cdd-worktree ` from the main worktree, and a fresh Claude session will open in the new worktree with the first prompt already submitted. diff --git a/.claude/commands/cdd-pre-pr.md b/.claude/commands/cdd-pre-pr.md index 5eedcee..99dabcf 100644 --- a/.claude/commands/cdd-pre-pr.md +++ b/.claude/commands/cdd-pre-pr.md @@ -1,11 +1,19 @@ -Run a pre-PR checklist for the current branch. Compare against `main` to identify all changes. This is a verification session: it runs CI gates, code-reviews the diff, and reconciles documentation against the changes. +Run a pre-PR checklist for the current branch. Compare against the base branch to identify all changes. This is a verification session: it runs CI gates, code-reviews the diff, and reconciles documentation against the changes. This session is **fresh and separate** from the implementation session by design, so that the verification work is not biased by the context that produced the change. Any "propose to the user" step in this command is a proposal to the user running this session. +## 0. Resolve the default branch + +```bash +DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null || echo main) +``` + +Use `$DEFAULT_BRANCH` wherever `main`/`origin/main` appears in git commands below. + ## 1. Identify changes ```bash -git diff main...HEAD --name-only +git diff "$DEFAULT_BRANCH"...HEAD --name-only git status --porcelain ``` @@ -77,11 +85,11 @@ Do **not** propose generic CI improvements every run. The default is silence. If ## 7. Upstream drift check ```bash -git fetch origin main -git log --oneline HEAD..origin/main +git fetch origin "$DEFAULT_BRANCH" +git log --oneline "HEAD..origin/$DEFAULT_BRANCH" ``` -If `origin/main` has advanced beyond the branch point, mention it and recommend running `/cdd-merge-main` before opening the PR. Do not merge from this session. +If `origin/$DEFAULT_BRANCH` has advanced beyond the branch point, mention it and recommend running `/cdd-merge-base` before opening the PR. Do not merge from this session. ## Command-set drift (CDD repo only) @@ -117,7 +125,7 @@ Present a checklist summary: - [ ] Roadmap up to date - [ ] New behaviour tested (or untested-with-reason recorded) - [ ] CI gaps surfaced: none / proposed (list them) -- [ ] No upstream drift (or: /cdd-merge-main recommended) +- [ ] No upstream drift (or: /cdd-merge-base recommended) - [ ] Reconciliation edits committed ``` @@ -151,7 +159,7 @@ gh auth status && git remote get-url origin # origin should be a github.com UR If either is missing, say so in one line and skip this step (the checklist above still stands). -If §7 found upstream drift, restate the recommendation to run `/cdd-merge-main` before opening the PR, and let the user decide whether to proceed anyway. +If §7 found upstream drift, restate the recommendation to run `/cdd-merge-base` before opening the PR, and let the user decide whether to proceed anyway. Ask: **"Open a PR now?"** Do not pre-show a title or body, and do not print manual `gh` instructions — just ask whether to proceed. diff --git a/.claude/commands/cdd-process-pr.md b/.claude/commands/cdd-process-pr.md index 2b02f14..ac50102 100644 --- a/.claude/commands/cdd-process-pr.md +++ b/.claude/commands/cdd-process-pr.md @@ -1,6 +1,6 @@ Address the open PR's review feedback: read the review comments for the current branch, triage them, implement the change-requests (pushing back where warranted), then auto-post in-thread replies and auto-commit + push the result. -Run this command on the feature branch (not on main), after a PR has been opened and someone has reviewed it. It is a post-review side-loop, analogous in position to `/cdd-merge-main`. +Run this command on the feature branch (not on main), after a PR has been opened and someone has reviewed it. It is a post-review side-loop, analogous in position to `/cdd-merge-base`. **Note on automation:** this command has a single checkpoint, placed up front: the triage plan in step 4. Once the user approves that plan, the rest of the run — edits, in-thread replies, commit, push — executes without further confirmation gates (see the process doc, "The `/cdd-process-pr` exception"). Do not add per-action gates after the plan is approved. Review threads are never resolved by this command; the user resolves them. diff --git a/.claude/commands/cdd-retrofit.md b/.claude/commands/cdd-retrofit.md index 2776702..b3e735e 100644 --- a/.claude/commands/cdd-retrofit.md +++ b/.claude/commands/cdd-retrofit.md @@ -90,7 +90,7 @@ Walk every file in `$STAGE/render`. All writes go into `$WT` (the isolated workt - **Absent in `$WT`** → copy it directly (create parent dirs as needed). This covers the slash commands, doc skeletons, the worktree helper, `.claude/settings.json`, and the marker in the common case. - **Present in `$WT`** (collision — typically `CLAUDE.md`, sometimes `doc/` files or `.claude/settings.json`) → propose a merge interactively, one file at a time: - - `CLAUDE.md`: keep the project's existing content; propose adding the CDD pieces it lacks (the Key references table rows for `doc/`, and the Workflow section referencing `/cdd-next-step`, `/cdd-pre-pr`, `/cdd-merge-main`). Show the proposed result; apply only on approval. + - `CLAUDE.md`: keep the project's existing content; propose adding the CDD pieces it lacks (the Key references table rows for `doc/`, and the Workflow section referencing `/cdd-next-step`, `/cdd-pre-pr`, `/cdd-merge-base`). Show the proposed result; apply only on approval. - `.claude/settings.json`: merge the `permissions.allow` arrays (union); show the result before writing. - Anything else: show both versions and propose the merge; the user decides per file. - Never delete or move existing files. diff --git a/.github/workflows/template-smoke.yml b/.github/workflows/template-smoke.yml index 14b59ef..ff47dd8 100644 --- a/.github/workflows/template-smoke.yml +++ b/.github/workflows/template-smoke.yml @@ -46,6 +46,14 @@ jobs: - name: Show the scaffold commit run: git -C /tmp/smoke/demo-project log --oneline + - name: Bootstrap a CamelCase-dir project (Fix 2 coverage) + run: | + ./tools/bootstrap-cdd-project.sh \ + --name "My CamelCase Project" \ + --slug myproj \ + --path /tmp/smoke/MyProject + ./scripts/template-smoke-assert.sh /tmp/smoke/MyProject + - name: Stage a render-only tree and assert it is clean run: | ./tools/bootstrap-cdd-project.sh --stage \ diff --git a/CLAUDE.md b/CLAUDE.md index f626216..2a87cc9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -52,6 +52,11 @@ rm -rf /tmp/cdd-smoke && mkdir -p /tmp/cdd-smoke --path /tmp/cdd-smoke/demo-project ./scripts/template-smoke-assert.sh /tmp/cdd-smoke/demo-project +# CamelCase PROJECT_DIR smoke (Fix 2 coverage). +./tools/bootstrap-cdd-project.sh --name "My CamelCase Project" --slug myproj \ + --path /tmp/cdd-smoke/MyProject +./scripts/template-smoke-assert.sh /tmp/cdd-smoke/MyProject + # Demo subsystem smoke: bootstrap + seed overlay into a tmp base, no GitHub side effects. rm -rf /tmp/cdd-demo-smoke demo/setup.sh mdr_demo_99 --base /tmp/cdd-demo-smoke --local-only @@ -93,7 +98,7 @@ See `doc/knowledge_base/claude-driven-development.md` for the full picture. This project uses CDD on itself. Every CDD session is a fresh context doing exactly one job (see process doc section 3 for the session taxonomy). - **To start a new task** (handoff session): run `/cdd-next-step` from the main worktree to produce a handoff, then run `cdd-worktree ` to spin up the implementation worktree (implementation session, opens in plan mode). `/cdd-next-step` has three front-ends: no argument picks the next roadmap item; a task prompt starts off-roadmap work (intent-driven); and `#NN` / a bare integer / the `issue`/`issues` keyword sources the task from a GitHub issue (issue-driven), naming the branch `gh_issue_NN_`. -- **When main has advanced under a feature branch** (merge session): run `/cdd-merge-main` in a fresh context on the feature branch. +- **When main has advanced under a feature branch** (merge session): run `/cdd-merge-base` in a fresh context on the feature branch. - **Before opening a PR** (pre-PR session): run `/cdd-pre-pr` in a fresh context to verify the process doc and template are consistent and the roadmap reflects what landed; it auto-commits its own reconciliation edits (local, no push) and ends with an opt-in step to open the PR (adding `Closes #NN` when the branch carries the `gh_issue_NN` token). - **When a PR review leaves comments** (PR-review session): run `/cdd-process-pr` in a fresh context on the feature branch. - Keep the process doc, template, and roadmap consistent as part of every change. Process-first, then template. diff --git a/README.md b/README.md index 37139d1..f452514 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A task flows through up to five sessions, each driven by one slash command: flowchart TD NS("Handoff session
/cdd-next-step, on the main worktree"):::agent IMPL("Implementation session
opens in plan mode — ③ plan approved —
implement, update docs + roadmap, commit"):::agent - MM("Merge session
/cdd-merge-main: integrate main, dry-run first"):::opt + MM("Merge session
/cdd-merge-base: integrate main, dry-run first"):::opt PP("Pre-PR session
/cdd-pre-pr: CI gates, code review, doc reconciliation"):::agent REV("Human reviews the PR on GitHub"):::human PPR("PR-review session
/cdd-process-pr: triage + address review comments"):::opt diff --git a/demo/README.md b/demo/README.md index 59f685f..a603ec6 100644 --- a/demo/README.md +++ b/demo/README.md @@ -4,7 +4,7 @@ This directory is a **third artifact** of the CDD repo, alongside `template/` an The `demo/` subsystem serves two purposes from one shared seed: -- **Demo** — a reproducible, visual walkthrough of CDD's task cycle: one reviewable PR, two parallel branches that conflict, and a `/cdd-merge-main` that resolves the conflict *and* delivers a dependency. +- **Demo** — a reproducible, visual walkthrough of CDD's task cycle: one reviewable PR, two parallel branches that conflict, and a `/cdd-merge-base` that resolves the conflict *and* delivers a dependency. - **Dogfooding** — a real greenfield project (CDD roadmap Phase 2) so working past the demo is genuine work. The seed project is **Markdown Renderer**: a small local Flask app where you paste Markdown, see it rendered live, and copy the result as **rich text** so it pastes formatted into Gmail, Google Docs, or Word — not as raw `# Heading` source. The key technical spine: pasting into email clients needs `text/html` on the clipboard, and email strips `