diff --git a/Cargo.lock b/Cargo.lock index 4abba1e..bd89712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,7 +451,7 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cli-sub-agent" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -610,7 +610,7 @@ dependencies = [ [[package]] name = "csa-acp" -version = "0.1.104" +version = "0.1.105" dependencies = [ "agent-client-protocol", "anyhow", @@ -629,7 +629,7 @@ dependencies = [ [[package]] name = "csa-config" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -645,7 +645,7 @@ dependencies = [ [[package]] name = "csa-core" -version = "0.1.104" +version = "0.1.105" dependencies = [ "agent-teams", "chrono", @@ -659,7 +659,7 @@ dependencies = [ [[package]] name = "csa-executor" -version = "0.1.104" +version = "0.1.105" dependencies = [ "agent-teams", "anyhow", @@ -683,7 +683,7 @@ dependencies = [ [[package]] name = "csa-hooks" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -698,7 +698,7 @@ dependencies = [ [[package]] name = "csa-lock" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -710,7 +710,7 @@ dependencies = [ [[package]] name = "csa-mcp-hub" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "axum", @@ -732,7 +732,7 @@ dependencies = [ [[package]] name = "csa-memory" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "async-trait", @@ -750,7 +750,7 @@ dependencies = [ [[package]] name = "csa-process" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "csa-core", @@ -767,7 +767,7 @@ dependencies = [ [[package]] name = "csa-resource" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "csa-core", @@ -782,7 +782,7 @@ dependencies = [ [[package]] name = "csa-scheduler" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -800,7 +800,7 @@ dependencies = [ [[package]] name = "csa-session" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -821,7 +821,7 @@ dependencies = [ [[package]] name = "csa-todo" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "chrono", @@ -4089,7 +4089,7 @@ dependencies = [ [[package]] name = "weave" -version = "0.1.104" +version = "0.1.105" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index fb0ebe1..224a55a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/*"] resolver = "2" [workspace.package] -version = "0.1.104" +version = "0.1.105" edition = "2024" rust-version = "1.85" license = "Apache-2.0" diff --git a/patterns/dev2merge/PATTERN.md b/patterns/dev2merge/PATTERN.md index 0af4101..1d4193e 100644 --- a/patterns/dev2merge/PATTERN.md +++ b/patterns/dev2merge/PATTERN.md @@ -578,3 +578,38 @@ set -euo pipefail csa run --sa-mode false --skill pr-codex-bot --no-stream-stdout \ "Operate on the current branch and active PR. Execute the full cloud review lifecycle end-to-end, including trigger, polling, timeout fallback, iterative fixes, and merge." ``` + +## Step 21: Post-Merge Local Sync + +Tool: bash +OnFail: abort + +After the delegated pr-codex-bot workflow completes (which includes +`gh pr merge`), sync the local main branch to match remote and clean up +the feature branch. This ensures local state is consistent with remote +after the remote-side squash-merge. + +```bash +set -euo pipefail +FEATURE_BRANCH="$(git branch --show-current 2>/dev/null || true)" + +# Sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only + +# Verify local main matches remote +LOCAL_SHA="$(git rev-parse HEAD)" +REMOTE_SHA="$(git rev-parse origin/main)" +if [ "${LOCAL_SHA}" != "${REMOTE_SHA}" ]; then + echo "ERROR: Local main (${LOCAL_SHA}) does not match origin/main (${REMOTE_SHA}) after sync." >&2 + exit 1 +fi +echo "Local main synced to ${LOCAL_SHA}." + +# Clean up feature branch (local and remote) +if [ -n "${FEATURE_BRANCH}" ] && [ "${FEATURE_BRANCH}" != "main" ] && [ "${FEATURE_BRANCH}" != "dev" ]; then + git branch -d "${FEATURE_BRANCH}" 2>/dev/null || echo "INFO: Local branch ${FEATURE_BRANCH} already deleted." + git push origin --delete "${FEATURE_BRANCH}" 2>/dev/null || echo "INFO: Remote branch ${FEATURE_BRANCH} already deleted." +fi +``` diff --git a/patterns/dev2merge/skills/dev2merge/SKILL.md b/patterns/dev2merge/skills/dev2merge/SKILL.md index 5b86702..666b82a 100644 --- a/patterns/dev2merge/skills/dev2merge/SKILL.md +++ b/patterns/dev2merge/skills/dev2merge/SKILL.md @@ -79,7 +79,7 @@ breaks prompt-guard propagation. 14. **Create PR**: `gh pr create --base main`. 15. **Delegate PR review loop**: invoke `csa run --skill pr-codex-bot --no-stream-stdout ...`. 16. **Do not poll in caller**: all trigger/poll/timeout/fix/review/merge waiting is handled inside delegated CSA workflow. -17. **Post-merge sync**: ensure local `main` is updated after delegated workflow completes. +17. **Post-merge sync**: `git fetch origin && git checkout main && git merge origin/main --ff-only`. Delete feature branch locally and remotely. ## Example Usage @@ -109,5 +109,5 @@ breaks prompt-guard propagation. 10. `pr-codex-bot` delegated workflow completed successfully. 11. Cloud review polling and fix loops stayed inside delegated CSA session (no caller-side polling loop). 12. PR merged via squash-merge. -13. Local main updated: `git checkout main && git pull origin main`. +13. Local main updated: `git fetch origin && git checkout main && git merge origin/main --ff-only`. 14. Feature branch deleted (remote and local). diff --git a/patterns/dev2merge/workflow.toml b/patterns/dev2merge/workflow.toml index a2a8301..49e2652 100644 --- a/patterns/dev2merge/workflow.toml +++ b/patterns/dev2merge/workflow.toml @@ -80,6 +80,9 @@ name = "VERSION" [[workflow.variables]] name = "dir" +[[workflow.variables]] +name = "FEATURE_BRANCH" + [[workflow.variables]] name = "file" @@ -679,3 +682,35 @@ csa run --sa-mode false --skill pr-codex-bot --no-stream-stdout \ "Operate on the current branch and active PR. Execute the full cloud review lifecycle end-to-end, including trigger, polling, timeout fallback, iterative fixes, and merge." ```''' on_fail = "abort" + +[[workflow.steps]] +id = 21 +title = "Post-Merge Local Sync" +tool = "bash" +prompt = ''' +After the delegated pr-codex-bot workflow completes (which includes +`gh pr merge`), sync the local main branch to match remote and clean up +the feature branch. + +```bash +set -euo pipefail +FEATURE_BRANCH="$(git branch --show-current 2>/dev/null || true)" + +git fetch origin +git checkout main +git merge origin/main --ff-only + +LOCAL_SHA="$(git rev-parse HEAD)" +REMOTE_SHA="$(git rev-parse origin/main)" +if [ "${LOCAL_SHA}" != "${REMOTE_SHA}" ]; then + echo "ERROR: Local main (${LOCAL_SHA}) does not match origin/main (${REMOTE_SHA}) after sync." >&2 + exit 1 +fi +echo "Local main synced to ${LOCAL_SHA}." + +if [ -n "${FEATURE_BRANCH}" ] && [ "${FEATURE_BRANCH}" != "main" ] && [ "${FEATURE_BRANCH}" != "dev" ]; then + git branch -d "${FEATURE_BRANCH}" 2>/dev/null || echo "INFO: Local branch ${FEATURE_BRANCH} already deleted." + git push origin --delete "${FEATURE_BRANCH}" 2>/dev/null || echo "INFO: Remote branch ${FEATURE_BRANCH} already deleted." +fi +```''' +on_fail = "abort" diff --git a/patterns/pr-codex-bot/PATTERN.md b/patterns/pr-codex-bot/PATTERN.md index 8e9ca5c..5c6f5ff 100644 --- a/patterns/pr-codex-bot/PATTERN.md +++ b/patterns/pr-codex-bot/PATTERN.md @@ -549,7 +549,17 @@ gh pr comment "${PR_NUM}" --repo "${REPO}" --body \ "**Merge rationale**: Cloud bot (@codex) is disabled or unavailable. Local \`csa review --branch main\` passed CLEAN (or issues were fixed in fallback cycle). Proceeding to merge with local review as the review layer." gh pr merge "${PR_NUM}" --repo "${REPO}" --squash --delete-branch -git checkout main && git pull origin main + +# Post-merge: sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only +git log --oneline -1 # verify local matches remote + +# Clean up feature branch locally (remote already deleted by --delete-branch) +if [ -n "${WORKFLOW_BRANCH}" ] && [ "${WORKFLOW_BRANCH}" != "main" ]; then + git branch -d "${WORKFLOW_BRANCH}" 2>/dev/null || true +fi ``` ## ELSE @@ -1155,7 +1165,17 @@ fi git push origin "${WORKFLOW_BRANCH}" gh pr merge "${WORKFLOW_BRANCH}-clean" --repo "${REPO}" --squash --delete-branch -git checkout main && git pull origin main + +# Post-merge: sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only +git log --oneline -1 # verify local matches remote + +# Clean up feature branch locally (remote already deleted by --delete-branch) +if [ -n "${WORKFLOW_BRANCH}" ] && [ "${WORKFLOW_BRANCH}" != "main" ]; then + git branch -d "${WORKFLOW_BRANCH}" 2>/dev/null || true +fi ``` ## ELSE @@ -1184,7 +1204,17 @@ fi git push origin "${WORKFLOW_BRANCH}" gh pr merge "${PR_NUM}" --repo "${REPO}" --squash --delete-branch -git checkout main && git pull origin main + +# Post-merge: sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only +git log --oneline -1 # verify local matches remote + +# Clean up feature branch locally (remote already deleted by --delete-branch) +if [ -n "${WORKFLOW_BRANCH}" ] && [ "${WORKFLOW_BRANCH}" != "main" ]; then + git branch -d "${WORKFLOW_BRANCH}" 2>/dev/null || true +fi ``` ## ENDIF diff --git a/patterns/pr-codex-bot/skills/pr-codex-bot/SKILL.md b/patterns/pr-codex-bot/skills/pr-codex-bot/SKILL.md index b0c7653..06eadf8 100644 --- a/patterns/pr-codex-bot/skills/pr-codex-bot/SKILL.md +++ b/patterns/pr-codex-bot/skills/pr-codex-bot/SKILL.md @@ -177,7 +177,7 @@ breaks prompt-guard propagation. 9. **Continue loop**: Push fixes and loop back (next trigger is issued in Step 4). Track iteration count via `REVIEW_ROUND`. When `REVIEW_ROUND` reaches `MAX_REVIEW_ROUNDS` (default: 10), STOP and present options to the user: (A) Merge now, (B) Continue for more rounds, (C) Abort and investigate manually. The workflow MUST NOT auto-merge or auto-abort at the round limit. 10. **Clean resubmission** (if fixes accumulated): Create clean branch for final review. 10.5. **Rebase for clean history**: If branch has > 3 commits, create backup branch, soft reset to `$(git merge-base main HEAD)` (not local main tip, which may have advanced), create logical commits by selectively staging, force push with lease, then trigger one final `@codex review`. **MUST block**: delegate post-rebase wait/fix/review handling to one CSA-managed gate step and proceed only when it returns pass. The delegated gate is hard-time-bounded and must return an explicit pass marker; non-zero/timeout/invalid-marker is hard fail. If issues remain after bounded retries, abort. If bot times out, delegated gate must execute fallback `csa review --range main...HEAD` plus bounded fix cycle. FORBIDDEN: proceeding to merge while post-rebase review has unresolved issues. Skip rebase entirely if <= 3 commits or already logically grouped. -11. **Merge**: Leave audit trail comment if bot was unavailable (explaining merge rationale: bot timeout + local review CLEAN). Then `gh pr merge --squash --delete-branch`, then `git checkout main && git pull`. +11. **Merge**: Leave audit trail comment if bot was unavailable (explaining merge rationale: bot timeout + local review CLEAN). Then `gh pr merge --squash --delete-branch`, then `git fetch origin && git checkout main && git merge origin/main --ff-only`. Delete feature branch locally (`git branch -d`). ## Example Usage @@ -213,4 +213,4 @@ breaks prompt-guard propagation. 10b. **Rebase for clean history** (Step 10.5): If branch had > 3 accumulated commits, commits were rebased into logical groups, force-pushed, and delegated post-rebase CSA gate passed before merge (including timeout fallback handling). Backup branch created at `backup--pre-rebase`. 11. **Audit trail**: Every dismissed PR-page finding (for example, a bot finding) has a corresponding explanatory PR comment posted by an explicit workflow step BEFORE proceeding or merging. 12. PR merged via squash-merge with branch cleanup. -13. Local main updated: `git checkout main && git pull origin main`. +13. Local main updated: `git fetch origin && git checkout main && git merge origin/main --ff-only`. Feature branch deleted locally and remotely. diff --git a/patterns/pr-codex-bot/workflow.toml b/patterns/pr-codex-bot/workflow.toml index 8233a4f..66e96ea 100644 --- a/patterns/pr-codex-bot/workflow.toml +++ b/patterns/pr-codex-bot/workflow.toml @@ -548,7 +548,17 @@ gh pr comment "${PR_NUM}" --repo "${REPO}" --body \ "**Merge rationale**: Cloud bot (@codex) is disabled or unavailable. Local csa review --branch main passed CLEAN (or issues were fixed in fallback cycle). Proceeding to merge with local review as the review layer." gh pr merge "${PR_NUM}" --repo "${REPO}" --squash --delete-branch -git checkout main && git pull origin main + +# Post-merge: sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only +git log --oneline -1 # verify local matches remote + +# Clean up feature branch locally (remote already deleted by --delete-branch) +if [ -n "${WORKFLOW_BRANCH}" ] && [ "${WORKFLOW_BRANCH}" != "main" ]; then + git branch -d "${WORKFLOW_BRANCH}" 2>/dev/null || true +fi ```""" on_fail = "abort" condition = "(${BOT_UNAVAILABLE}) && (!(${FALLBACK_REVIEW_HAS_ISSUES})) && (!(${ROUND_LIMIT_REACHED}))" @@ -1164,7 +1174,17 @@ fi git push origin "${WORKFLOW_BRANCH}" gh pr merge "${WORKFLOW_BRANCH}-clean" --repo "${REPO}" --squash --delete-branch -git checkout main && git pull origin main + +# Post-merge: sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only +git log --oneline -1 # verify local matches remote + +# Clean up feature branch locally (remote already deleted by --delete-branch) +if [ -n "${WORKFLOW_BRANCH}" ] && [ "${WORKFLOW_BRANCH}" != "main" ]; then + git branch -d "${WORKFLOW_BRANCH}" 2>/dev/null || true +fi ```""" on_fail = "abort" condition = "(!(${BOT_UNAVAILABLE})) && (${FIXES_ACCUMULATED}) && (!(${ROUND_LIMIT_REACHED}))" @@ -1190,7 +1210,17 @@ fi git push origin "${WORKFLOW_BRANCH}" gh pr merge "${PR_NUM}" --repo "${REPO}" --squash --delete-branch -git checkout main && git pull origin main + +# Post-merge: sync local main with remote +git fetch origin +git checkout main +git merge origin/main --ff-only +git log --oneline -1 # verify local matches remote + +# Clean up feature branch locally (remote already deleted by --delete-branch) +if [ -n "${WORKFLOW_BRANCH}" ] && [ "${WORKFLOW_BRANCH}" != "main" ]; then + git branch -d "${WORKFLOW_BRANCH}" 2>/dev/null || true +fi ```""" on_fail = "abort" condition = "(!(${BOT_UNAVAILABLE})) && (!(${FIXES_ACCUMULATED})) && (!(${ROUND_LIMIT_REACHED}))" diff --git a/weave.lock b/weave.lock index 97e7320..41ae7d0 100644 --- a/weave.lock +++ b/weave.lock @@ -1,9 +1,9 @@ package = [] [versions] -csa = "0.1.104" +csa = "0.1.105" last_migrated_at = "2026-03-08T12:08:01.820964091Z" -weave = "0.1.104" +weave = "0.1.105" [migrations] applied = [