Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gaai/core/contexts/rules/orchestration.rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ A pre-push hook (`.githooks/pre-push`) enforces this rule at the git level.
Scope: **worktree-isolated delivery of code/content** — daemon-spawned story delivery and any manual session making an isolated change in a worktree. The merge path here is the same one the `production`-prohibition and auto-merge clauses above already govern; this subsection does not re-assert them, it adds the lifecycle clauses those clauses omit. The mechanism (idempotent creation, throttled reaping, retries, locks) lives in the daemon scripts; the procedure lives in `delivery-loop.workflow.md §Commit Phase`. This section is the normative authority both implement.

- **Governed merge path.** Worktree-originated code/content reaches `staging` only via `gh pr create --base staging --head story/{id}` then squash merge (auto-merge per the clause above). Manual Delivery repairs follow the same path with a dedicated branch name if no story branch is active. **Exempt:** Discovery's backlog/governance mutations push directly to `origin/staging` under the daemon staging lock per §Claim Protocol — that path has no story PR and is unaffected by this clause.
- **Post-merge cleanup.** After a story's PR merges, its remote branch (`gh pr merge --delete-branch`) and its worktree are removed; the daemon also drops the local branch ref. No worktree may persist past its story's terminal state.
- **Post-merge cleanup.** After a story's PR merges, its worktree is removed and its local branch ref is dropped through the landed-or-preserved guard below. No worktree may persist past its story's terminal state. The merge does **not** delete the remote branch — deleting it is a separate, optional step (`git push origin --delete <branch>`), never a flag on the merge.
- **The merge is an API-only operation (INVARIANT).** `gh pr merge` MUST target the PR by number with `--repo`, and MUST NOT be given `--delete-branch`. That flag deletes the *local* branch too, which forces `gh` to switch the current checkout onto the base branch first. Run from inside a worktree it makes that worktree squat the shared target-branch ref — which mechanically breaks the main-working-tree invariant above, since a branch can be checked out in only one tree — and it silently attempts a fast-forward of the local target branch. Every local teardown (`worktree remove`, `worktree prune`, `branch -D`) runs against the primary working tree with `git -C`, never from inside the worktree being removed. Pass `--match-head-commit <sha>` so a head that moved after review cannot be merged unseen.
- **Orphan reaping is eventually-consistent.** A worktree whose story PR is MERGED/CLOSED, or whose HEAD is an ancestor of `origin/staging`, is an orphan and MUST be reaped. Reaping is periodic/convergent, **not** synchronous — "no orphan subsists" is a convergence guarantee, not an instantaneous one. Do not assert or rely on synchronous orphan removal.
- **Data-safety refusal (INVARIANT).** A dirty or still-active worktree is NEVER force-removed. The reaper refuses removal and defers it (skip-and-retry next cycle); committed work is never lost because removal frees only the working dir, never a branch ref. Data safety dominates cleanup.
- **Landed-or-preserved branch deletion (INVARIANT).** A story branch is deletable ONLY IF its work is verifiably landed — its PR is MERGED, or the story is `status: done` on the remote backlog, or the branch's local tip matches a remote ref (pushed-but-not-yet-merged) — or it is preserved, never destroyed. Because squash-merges are never reachable from `origin/staging` by commit-SHA ancestry, ancestry-on-staging alone is NEVER a valid landed test. A verification failure (network, `gh`, or unreadable remote state) does not affirm landed and fails closed to preserve. Every story-branch deletion site (recovery, cleanup sweeps, reconcile, orphan reaping) routes through this single guard. When the guard refuses deletion, the branch is preserved by rename (`story/{id}-preserved-<timestamp>`) — never left in place under its original name, so the retry path still gets a fresh `story/{id}` — with an append-only audit entry recording the branch tip; the operator-facing log line is throttled per story id so periodic sweeps do not re-emit every cycle.
Expand Down
4 changes: 2 additions & 2 deletions .gaai/core/workflows/delivery-loop.workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ Deterministic bash only — no `claude -p` invocation. Implemented in `handle_co
2. Push story branch with retry-rebase pattern (3 attempts, backoff 2s / 4s / 6s)
3. `gh pr create --base staging --head story/{id}`
4. CI watch (advisory mode if no branch protection)
5. `gh pr merge --squash --delete-branch`
5. `gh pr merge <pr> --repo <owner/repo> --squash --match-head-commit <sha>` — by number, never `--delete-branch` (see the API-only merge invariant in the rules file)
6. Backlog status → `done` (flock-serialized push to staging)
7. Worktree removal (the *remote* branch is deleted by `--delete-branch` at step 5; the local worktree is removed here, and the reaper drops any surviving local branch ref)
7. Worktree removal via `git -C <primary working tree> worktree remove`, never from inside the worktree being removed; the local branch ref is dropped by the landed-or-preserved guard. The *remote* branch is left in place — no step here deletes it.

**Normative authority:** the worktree + PR + cleanup invariants are defined in `orchestration.rules.md §Branch Rules → Worktree lifecycle & cleanup`. This sequence is the procedure; the rules file is the authority. The procedure restates only hard safety boundaries (see **Safety boundary** below); it does not define invariants.

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Changed
- docs: the post-merge cleanup clause prescribed a flag that breaks an invariant
- fix: record run identity on the handle instead of inferring it
- fix: keep and poll the handle until a terminal receipt
- fix: make generated execution plans carry artefact frontmatter
Expand Down
Loading