@caddis/cli 0.4.55 → 0.4.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/antigravity-plugin/caddis_statusline.py +7 -3
- package/bundles/antigravity-plugin/guard_agy.py +1056 -83
- package/bundles/antigravity-plugin/hooks.json +2 -1
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/repo_freshness.py +182 -4
- package/bundles/antigravity-plugin/scripts/caddis_adhoc.py +20 -12
- package/bundles/antigravity-plugin/scripts/caddis_checkout_guard.py +63 -12
- package/bundles/antigravity-plugin/scripts/caddis_docs_pr.py +14 -5
- package/bundles/antigravity-plugin/scripts/caddis_gate.py +27 -1
- package/bundles/antigravity-plugin/scripts/caddis_lanes.py +93 -6
- package/bundles/antigravity-plugin/scripts/caddis_merge_chain.py +67 -22
- package/bundles/antigravity-plugin/scripts/caddis_relay_git.py +8 -2
- package/bundles/antigravity-plugin/scripts/caddis_review.py +290 -176
- package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +346 -50
- package/bundles/antigravity-plugin/scripts/caddis_roadmap_page.py +82 -8
- package/bundles/antigravity-plugin/scripts/caddis_roadmap_run.py +89 -24
- package/bundles/antigravity-plugin/scripts/caddis_statusline.py +7 -3
- package/bundles/antigravity-plugin/scripts/caddis_tidy.py +10 -6
- package/bundles/antigravity-plugin/scripts/caddis_todo.py +7 -1
- package/bundles/antigravity-plugin/scripts/caddis_worktree_close.py +12 -5
- package/bundles/antigravity-plugin/scripts/caddis_worktree_safety.py +182 -0
- package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +2 -0
- package/bundles/antigravity-plugin/scripts/claudster_doctor.py +6 -2
- package/bundles/antigravity-plugin/scripts/no_window.py +49 -0
- package/bundles/antigravity-plugin/scripts/oss_review.py +303 -79
- package/bundles/antigravity-plugin/scripts/secret_filter.py +190 -22
- package/bundles/antigravity-plugin/scripts/setup_project_ai.py +6 -1
- package/bundles/antigravity-plugin/session_end_agy.py +27 -11
- package/bundles/antigravity-plugin/skills/cloud-phases/SKILL.md +55 -9
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +11 -8
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +10 -6
- package/bundles/antigravity-plugin/skills/git-commit/SKILL.md +2 -3
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +31 -17
- package/bundles/antigravity-plugin/skills/mmr/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/pr-merge/SKILL.md +45 -5
- package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +4 -2
- package/bundles/antigravity-plugin/skills/review-pr/SKILL.md +13 -4
- package/bundles/antigravity-plugin/skills/roadmap/SKILL.md +28 -6
- package/bundles/antigravity-plugin/skills/roadmap/assets/review-protocol.md +16 -13
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +32 -10
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +32 -1
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +44 -6
- package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +1 -1
- package/bundles/antigravity-plugin/warm_start_agy.py +40 -16
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +5 -5
- package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +1 -1
- package/bundles/antigravity-plugin-extras/skills/deploy-local/SKILL.md +2 -1
- package/bundles/antigravity-plugin-extras/skills/update-readme/SKILL.md +1 -1
- package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +4 -2
- package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +10 -6
- package/bundles/codex/.codex/skills/devops/git-commit/SKILL.md +2 -3
- package/bundles/codex/.codex/skills/docs/writing-plans/SKILL.md +1 -1
- package/bundles/codex/.codex/skills/workflow/roadmap/SKILL.md +28 -6
- package/bundles/codex/.codex/skills/workflow/roadmap/assets/review-protocol.md +16 -13
- package/bundles/manifest.json +3 -3
- package/package.json +1 -1
|
@@ -32,8 +32,8 @@ These override everything below. They exist because branch isolation and the run
|
|
|
32
32
|
depend on them:
|
|
33
33
|
|
|
34
34
|
- **Work ONLY on the current branch.** You are already on the feature branch (the current branch,
|
|
35
|
-
`git branch --show-current`; that read is the only `git branch` form allowed).
|
|
36
|
-
`git checkout`, `git switch`, `git branch <name>`, `git switch -c`, or any command that changes,
|
|
35
|
+
`git branch --show-current`; that read is the only `git branch` form allowed).
|
|
36
|
+
**NEVER** run `git checkout`, `git switch`, `git branch <name>`, `git switch -c`, or any command that changes,
|
|
37
37
|
creates, or leaves the current branch. Read the default branch with
|
|
38
38
|
`git symbolic-ref --short refs/remotes/origin/HEAD`, which prints `origin/<default>`: remove the
|
|
39
39
|
`origin/` prefix before you compare. If that command fails (origin/HEAD is not set), the default
|
|
@@ -46,7 +46,9 @@ depend on them:
|
|
|
46
46
|
the project's test command anywhere (config, CI, package scripts). The runner treats any such edit as
|
|
47
47
|
tampering and fails the run. If the plan asks you to touch these, skip that step and note it in the
|
|
48
48
|
review file instead.
|
|
49
|
-
- **Commit per phase, on this branch, with a normal commit.** Use `git add <paths
|
|
49
|
+
- **Commit per phase, on this branch, with a normal commit.** Use `git add <paths>`, then check `git diff --cached --name-only` lists only those paths (refuse on any
|
|
50
|
+
other staged path: a peer staged it; note it in the review file), then `git commit -m "…" -- <paths>`.
|
|
51
|
+
Never `git add -A`, `.`, `-u` or a folder, and never `git commit -a` (the guard denies them).
|
|
50
52
|
Do not use `--no-verify` (a pre-commit hook guards the branch — let it run). Do not amend or rebase
|
|
51
53
|
prior commits. One phase → one (or more) commit(s); never one giant end-of-run commit.
|
|
52
54
|
- **Never ask a question, never pause, never wait for input.** No human will answer. Never use
|
|
@@ -55,7 +57,7 @@ depend on them:
|
|
|
55
57
|
|
|
56
58
|
## Three rules: one attempt, one review
|
|
57
59
|
1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
|
|
58
|
-
2. **Run it before review.** The coder runs the
|
|
60
|
+
2. **Run it before review.** The coder runs only the tests of the files it touched, in the foreground, each command under 10 minutes (split into parts if needed). Name the exact commands in the task. Never start the full suite in the background and never wait on a monitor for it: CI runs the full suite on every PR. Then run the change once on real data.
|
|
59
61
|
3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
|
|
60
62
|
Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
|
|
61
63
|
the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
|
|
@@ -164,8 +166,11 @@ row, visible to any later reader without anyone having to catch it live.
|
|
|
164
166
|
so it proves timing by design.
|
|
165
167
|
3. **ACCEPT** means run `caddis_lanes.py accept --plan <plan> --phase N --attempt K --message
|
|
166
168
|
"<the phase's commit message>"`. It runs only on the programme branch, never on `main`. It
|
|
167
|
-
refuses a `BLOCKING` review
|
|
168
|
-
|
|
169
|
+
refuses a `BLOCKING` review and a `MISSING` review (no verdict: provider down, 429, filter
|
|
170
|
+
refusal). If you checked the finding and it is false, add
|
|
171
|
+
`--override-review "<why the finding is false>"`. For a `MISSING` review, re-run the review
|
|
172
|
+
first; add the override only if the owner accepts a phase with no vendor verdict. The reason
|
|
173
|
+
must not be empty. The script records it in the packet.
|
|
169
174
|
4. Allow at most **2 attempts** per phase on a non-Claude lane. An out-of-budget switch is not an
|
|
170
175
|
attempt. The owner can request TAKEOVER at any time.
|
|
171
176
|
5. A UI phase needs a `ui-design-reviewer` screenshot review before ACCEPT. This rule applies
|
|
@@ -180,12 +185,17 @@ row, visible to any later reader without anyone having to catch it live.
|
|
|
180
185
|
this wording without `--allow-load`. Only the owner gives that flag.
|
|
181
186
|
7b. **Write test economy into every agent brief, not only the lane prompt.** The script already adds it
|
|
182
187
|
to its lane prompts. A brief you write yourself (an Agent-tool subagent, a peer session) needs the same
|
|
183
|
-
five lines: after each step run only the tests for the file or module you changed
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
five lines: after each step run only the tests for the file or module you changed, in the foreground, each
|
|
189
|
+
command under 10 minutes; never start the full suite, and never wait on a monitor for it (CI runs it on every PR);
|
|
190
|
+
run no review loop inside the agent (you review); report progress
|
|
191
|
+
every 20 minutes; never start a second heavy test run while one is still running. **Agents never run
|
|
192
|
+
the full suite.** Measured 2026-10-02 on one shared box: a 2,063-test suite took 2.7 min
|
|
187
193
|
alone and 6.7 min beside a second test-heavy agent, and one agent's brief (baseline, tests after each of 9
|
|
188
194
|
module switches, full gates, in-agent review) cost 30-40 of its 59 minutes.
|
|
195
|
+
On 18-19 Oct 2026 agents started the full suite (about 40 min) in the background and waited through
|
|
196
|
+
monitors with their own timeouts. One missed the finish and sat "Waiting" for over 1 h. Four parallel
|
|
197
|
+
suites also slowed the box. The orchestrator checks a stalled agent by process (pytest alive, CPU moving),
|
|
198
|
+
not by its monitor.
|
|
189
199
|
8. Record these Tracker values:
|
|
190
200
|
- `Model` = the packet's `model`.
|
|
191
201
|
- `Lane` = the lanes tried, joined with ` -> ` and followed by the reason. For example,
|
|
@@ -234,7 +244,8 @@ report — do not redo completed work.
|
|
|
234
244
|
- **REFACTOR** — clean names/structure/duplication while keeping green.
|
|
235
245
|
- **VERIFY** — run the phase's exit-gate check (the literal command the plan names) and the relevant
|
|
236
246
|
suite so you didn't regress. Do not claim a state you did not run.
|
|
237
|
-
- **COMMIT** — `git add` the phase's files
|
|
247
|
+
- **COMMIT** — `git add` the phase's files by name, check `git diff --cached --name-only` shows only
|
|
248
|
+
them, and `git commit -m "…" -- <files>` with the phase's conventional-commit message
|
|
238
249
|
(from the plan, or a faithful equivalent). Stay on the current branch.
|
|
239
250
|
- **UPDATE THE TRACKER** — edit the plan's `## Tracker` row for this phase: set Status to `done`, fill
|
|
240
251
|
the short commit hash (`git rev-parse --short HEAD`), set the `Lane` column to the lane this phase
|
|
@@ -282,10 +293,12 @@ You: /clear, then paste ↓
|
|
|
282
293
|
**In headless/runner mode, never ask — halt, write the block, and exit.** The block is how a
|
|
283
294
|
non-interactive run tells a human what it needs; asking is still forbidden.
|
|
284
295
|
|
|
285
|
-
**4. Run the tests yourself.** After the last phase you complete, run the
|
|
286
|
-
more
|
|
287
|
-
|
|
288
|
-
suite
|
|
296
|
+
**4. Run the tests yourself.** After the last phase you complete, run the tests of the files you touched
|
|
297
|
+
once more, in the foreground, each command under 10 minutes (split into parts if needed), and record the
|
|
298
|
+
real result. Never start the full suite in the background and never wait on a monitor for it. CI runs the
|
|
299
|
+
full suite on every PR and is the gate before merge. The runner re-runs its own gate independently and
|
|
300
|
+
that decides success — but you run your tests too so your reported `"tests"` value is truthful, not
|
|
301
|
+
assumed. Never report `"passed"` on tests you did not see go green.
|
|
289
302
|
|
|
290
303
|
**4b. If every phase is now done, tidy the plan into `done/` IN THE SAME COMMIT.** Only when the
|
|
291
304
|
whole plan is finished (every `## Tracker` row is `done`, no halt, no blocker) — a mid-plan halt is
|
|
@@ -303,8 +316,9 @@ for a later session to clean up, and nothing is left uncommitted. Order matters:
|
|
|
303
316
|
no other file. **Refuse** if it would touch anything else, or prints `ERROR` or `NOT MOVED`:
|
|
304
317
|
stop, do not commit the move, and report the output in the review file.
|
|
305
318
|
3. `git add` the moved plan by name (`.caddis/plans/done/<plan>.md`, so the status and Tracker edits
|
|
306
|
-
are staged with the rename), then make the final commit
|
|
307
|
-
|
|
319
|
+
are staged with the rename), then make the final commit with
|
|
320
|
+
`git commit -m "…" -- .caddis/plans/<plan>.md .caddis/plans/done/<plan>.md` (both sides of the
|
|
321
|
+
rename). The move, the status and the last Tracker row land in one commit.
|
|
308
322
|
|
|
309
323
|
(Falls back to `scripts/caddis_tidy.py` from a source checkout; **skip this step if the script is
|
|
310
324
|
missing** — degrades open, same as the gates in Step 1.) A **collision** (`done/<name>` already
|
|
@@ -22,7 +22,7 @@ The exit codes follow `caddis_exit.py`: 0 clean, 1 blocked, 2 advisory, 3 could
|
|
|
22
22
|
|
|
23
23
|
## Three rules: one attempt, one review
|
|
24
24
|
1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
|
|
25
|
-
2. **Run it before review.** The coder runs the
|
|
25
|
+
2. **Run it before review.** The coder runs only the tests of the files it touched, in the foreground, each command under 10 minutes (split into parts if needed). Name the exact commands in the task. Never start the full suite in the background and never wait on a monitor for it: CI runs the full suite on every PR. Then run the change once on real data.
|
|
26
26
|
3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
|
|
27
27
|
Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
|
|
28
28
|
the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
|
|
@@ -9,7 +9,7 @@ End-to-end delivery of feature-branch work through the reviewed lane in one shot
|
|
|
9
9
|
push safely, create or update the Pull Request, monitor CI checks to green, merge into the default
|
|
10
10
|
branch, validate the deployment, and clean up the feature branch.
|
|
11
11
|
|
|
12
|
-
For a
|
|
12
|
+
For a quick commit and push of a feature branch, use `/ship` (the express lane). It never pushes the default branch.
|
|
13
13
|
To open a PR and stop at green for human review without merging, use `/ship-pr`.
|
|
14
14
|
To merge an already-opened PR, use `/ship-merge`.
|
|
15
15
|
|
|
@@ -29,11 +29,47 @@ can be provided.
|
|
|
29
29
|
Read `AGENTS.md` + the detected workflow file(s) first for the repo's real gate names, default
|
|
30
30
|
branch, and merge conventions — never assume `main`, never assume job names.
|
|
31
31
|
|
|
32
|
+
## Step 0b — Is this checkout safe to move?
|
|
33
|
+
|
|
34
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
35
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
36
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
37
|
+
```
|
|
38
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
39
|
+
```
|
|
40
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
41
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
42
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
43
|
+
|
|
44
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
45
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
46
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
47
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
48
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
49
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
50
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
51
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
52
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
53
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
54
|
+
checkout has it out.
|
|
55
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
56
|
+
|
|
57
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
58
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
59
|
+
<!-- /checkout-safety -->
|
|
60
|
+
|
|
32
61
|
## Step 1 — Refuse on the default branch
|
|
33
62
|
|
|
34
|
-
A PR is *branch → default*.
|
|
35
|
-
|
|
36
|
-
|
|
63
|
+
A PR is *branch → default*. Read the default branch as a bare name: `git rev-parse --abbrev-ref
|
|
64
|
+
origin/HEAD` prints `origin/<default>`, so strip the `origin/` prefix before you compare.
|
|
65
|
+
```bash
|
|
66
|
+
d=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) && d=${d#origin/} # prints origin/<default>: strip origin/
|
|
67
|
+
[ -n "$d" ] || d=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name) # origin/HEAD not set
|
|
68
|
+
git branch --show-current # compare with "$d"
|
|
69
|
+
```
|
|
70
|
+
If HEAD **is** the default branch, stop: there is nothing to open a PR from. Offer to move the
|
|
71
|
+
uncommitted work to a feature branch (`git switch -c <branch>`), or run `/ship`, which does that and
|
|
72
|
+
hands back here.
|
|
37
73
|
|
|
38
74
|
## Step 2 — Preflight (local gates mirroring CI)
|
|
39
75
|
|
|
@@ -69,6 +105,8 @@ Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <
|
|
|
69
105
|
git rebase <default-branch>
|
|
70
106
|
git push --force-with-lease origin <branch> # never bare --force
|
|
71
107
|
```
|
|
108
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), never rebase here: rebase in a detached worktree, as
|
|
109
|
+
Step 0b says.
|
|
72
110
|
|
|
73
111
|
## Step 5 — Push + create or update the PR
|
|
74
112
|
|
|
@@ -141,6 +179,8 @@ If the default branch triggers an automated deployment pipeline:
|
|
|
141
179
|
**Only after** the merge is complete and deployment (if any) is validated green:
|
|
142
180
|
- Run `git status --short`. If it shows changes you did not make, do not switch, stash, reset or commit:
|
|
143
181
|
leave them, report them, and stop cleanup here (a shared checkout often holds a peer's edits).
|
|
182
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), skip the switch and the pull below. Clean up as Step 0b
|
|
183
|
+
says: `git fetch --prune`, `git fetch origin <default-branch>:<default-branch>`, then delete the branches.
|
|
144
184
|
- Fetch and prune: `git fetch --prune`.
|
|
145
185
|
- Switch to the default branch: `git switch <default-branch>`.
|
|
146
186
|
- Fast-forward to the merge commit: `git pull --ff-only origin <default-branch>`.
|
|
@@ -168,7 +208,7 @@ Cleanup: remote branch deleted / local branch deleted / backup ref dropped
|
|
|
168
208
|
|
|
169
209
|
- Never merge a PR whose required checks are red or absent.
|
|
170
210
|
- Never delete a feature branch before its merge is confirmed and any deploy validated.
|
|
171
|
-
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies
|
|
211
|
+
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies all three, and `git add -u` and `git commit -a`). Commit with `git commit -m "..." -- <files>`, after `git diff --cached --name-only` shows only those files.
|
|
172
212
|
- Never force-push without a `backup/*-preship` recovery ref; force pushes are `--force-with-lease` only.
|
|
173
213
|
- Never edit a workflow file (`.gitea/workflows/`, `.github/workflows/`) to make a gate pass — fix the source.
|
|
174
214
|
- Local-only lane: refuse + point at `/ship`. On the default branch: stop + point at `/ship`.
|
|
@@ -128,7 +128,8 @@ Activate when:
|
|
|
128
128
|
```bash
|
|
129
129
|
git status --short # stage the files you changed, by name
|
|
130
130
|
git add tests/test_<module>.py
|
|
131
|
-
git
|
|
131
|
+
git diff --cached --name-only # only the files you named
|
|
132
|
+
git commit -m "chore: add tests before refactoring" -- tests/test_<module>.py
|
|
132
133
|
```
|
|
133
134
|
|
|
134
135
|
---
|
|
@@ -387,7 +388,8 @@ DEPRECATED_VALUE = 5 # Not referenced
|
|
|
387
388
|
|
|
388
389
|
2. **If tests pass, commit**
|
|
389
390
|
```bash
|
|
390
|
-
git
|
|
391
|
+
git add <files you changed>
|
|
392
|
+
git commit -m "refactor: extract validation to separate method" -- <files you changed>
|
|
391
393
|
```
|
|
392
394
|
|
|
393
395
|
3. **If tests fail, revert**
|
|
@@ -34,8 +34,11 @@ gh pr view <n> --repo <owner/repo> --json number,title,author,state,isDraft,merg
|
|
|
34
34
|
- the PR is **merged or closed** — there is nothing to decide;
|
|
35
35
|
- it is a **draft** — say so and ask whether to continue;
|
|
36
36
|
- **the operator is the author.** GitHub does not allow approving your own PR. Say it plainly, and
|
|
37
|
-
say the alternatives: have someone else approve it, or merge with an admin bypass
|
|
38
|
-
|
|
37
|
+
say the alternatives: have someone else approve it, or merge with an admin bypass. An admin
|
|
38
|
+
bypass skips the approval only, never the CI rule: merge only after `caddis_lanes.py ci-watch
|
|
39
|
+
--pr <n>` prints `RESULT: pass`, with no default-branch run in progress (section 4)
|
|
40
|
+
(`gh pr merge <n> --squash --admin --match-head-commit <watched head>`). Do not silently produce a
|
|
41
|
+
review they cannot submit.
|
|
39
42
|
|
|
40
43
|
## 2. Gather what the decision needs
|
|
41
44
|
|
|
@@ -85,12 +88,18 @@ Lead with the verdict. Keep it short enough to read before deciding:
|
|
|
85
88
|
- **CI** — green, red, or still running. Name the failing check.
|
|
86
89
|
- **Merge state** — and what would clear it.
|
|
87
90
|
|
|
88
|
-
Then print the exact commands, and stop:
|
|
91
|
+
Then print the exact commands, and stop. The merge follows the CI rule: wait with ci-watch, and
|
|
92
|
+
merge only on `RESULT: pass`, only the head it watched (`HEAD:`), and never while a CI run on the
|
|
93
|
+
default branch is in progress.
|
|
89
94
|
|
|
90
95
|
```bash
|
|
91
96
|
# approve
|
|
92
97
|
gh pr review <n> --repo <owner/repo> --approve
|
|
93
|
-
|
|
98
|
+
# wait for CI; merge only on RESULT: pass. HEAD: is the watched head
|
|
99
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_lanes.py" ci-watch --pr <n> --repo <owner/repo>
|
|
100
|
+
# no in_progress or queued run may be listed
|
|
101
|
+
gh run list --repo <owner/repo> --branch <default branch> --json status
|
|
102
|
+
gh pr merge <n> --repo <owner/repo> --squash --delete-branch --match-head-commit <watched head>
|
|
94
103
|
|
|
95
104
|
# or ask for changes
|
|
96
105
|
gh pr review <n> --repo <owner/repo> --request-changes --body "..."
|
|
@@ -89,8 +89,26 @@ python scripts/caddis_roadmap.py recheck --roadmap <slug>
|
|
|
89
89
|
`Depends on` milestone `done` or `not-needed`, and no open blocker other than `data-condition` (exit 1 names it),
|
|
90
90
|
then runs the Exit check (300 s): pass -> `done`; fail with a `data-condition` blocker -> `code-done/data-pending`;
|
|
91
91
|
fail otherwise -> an `external` blocker
|
|
92
|
-
`exit check failing (exit <n>)
|
|
93
|
-
|
|
92
|
+
`exit check failing (exit <n>): <tail>` (the last 3 non-empty output lines on one line, the whole reason at most
|
|
93
|
+
200 characters, masked as below). The part before `: ` is the blocker's identity: a later rollup adds no second
|
|
94
|
+
row, and `unblock --reason "exit check failing (exit <n>)"` removes every row of that prefix. A check that fails
|
|
95
|
+
on a missing environment (exit 9009/127/126, or output in its last 40 lines such as `No module named`,
|
|
96
|
+
`Cannot find module`, `ENOENT`, `run npm run build first`) is exit 3: no blocker, no PR. Either way the last 64 KB
|
|
97
|
+
of output (masked the same way) go to `.local/exit-check-<id>-<utc>.log` (the newest 10 stay), and rollup prints
|
|
98
|
+
the path. A milestone with no phase refs and no Exit check is refused (exit 4).
|
|
99
|
+
**Masked** in the reason and the log: the values of secret-named variables (`caddis_redact`); a whole
|
|
100
|
+
`-----BEGIN ... PRIVATE KEY-----` block up to its END line (or the end of the output); AWS, GitHub, Slack and JWT
|
|
101
|
+
tokens; a quoted value after a `password`/`secret`/`api_key`/`token` name, spaces included; an unquoted
|
|
102
|
+
`*PASSWORD*=`/`*TOKEN*=`-style line value; URL credentials (`scheme://***@`); and absolute paths as `<path>`: a
|
|
103
|
+
drive or UNC path up to the end of the line, a quote, `<`, `>` or `|`, and a `/home/`, `/Users/`, `/tmp/`, `/root/`,
|
|
104
|
+
`/var/`, `/etc/` or `/opt/` path up to the end of the line or a quote. Other text is published as printed.
|
|
105
|
+
- **`**Exit setup:** <command>`** (optional, one per roadmap, beside `Runner host:`; no `|`) runs in the temp worktree
|
|
106
|
+
before every Exit check (900 s). It must install fresh into that worktree, for example
|
|
107
|
+
`python -m venv .venv && .venv\Scripts\pip install -e .[dev]` or `npm ci && npm run build`. Each command runs in a
|
|
108
|
+
new shell, so the Exit check must call the venv itself: `.venv\Scripts\python -m pytest tests -q`, not
|
|
109
|
+
`python -m pytest`. Never link or junction a shared venv or `node_modules`: the worktree is removed with `--force`
|
|
110
|
+
after the check. A setup that fails or times out is exit 3 and writes nothing; the runner stops
|
|
111
|
+
`BLOCKED rollup not run` and the owner decides (the stop names a docs PR that was opened but not merged).
|
|
94
112
|
- **Owner-only changes:** `set` Status `not-needed`, any `set` Owner, `unblock` of an `owner-gate`, and `block --check`
|
|
95
113
|
(recheck runs that command unattended later). They need `--by-owner` and are refused headless: `CADDIS_HEADLESS`
|
|
96
114
|
or `CLAUDECODE` in the environment (even empty), stdin not a terminal, or on
|
|
@@ -179,8 +197,8 @@ Stops (each one notifies and releases the lock): a STOP file (`~/.caddis/STOP` o
|
|
|
179
197
|
`caddis_spend.py` still counts across runs), a lock or batch claim that cannot be written
|
|
180
198
|
(`BLOCKED claim not written`, before any session), the agy spend cap refusing a reservation, three sessions
|
|
181
199
|
with no newly merged phase, a roadmap write that fails, and the **snapshot guard**: one baseline for the whole run.
|
|
182
|
-
The Milestones and Blockers tables (every cell of every row, rows added, removed or moved)
|
|
183
|
-
are frozen. Every origin read (each `next`, after the runner's own writes, after each session) is compared with the
|
|
200
|
+
The Milestones and Blockers tables (every cell of every row, rows added, removed or moved), the `Runner host` line
|
|
201
|
+
and the `**Exit setup:**` line are frozen. Every origin read (each `next`, after the runner's own writes, after each session) is compared with the
|
|
184
202
|
previous one; the only differences allowed are the exact edits the runner itself made and recorded for that read: a
|
|
185
203
|
Status it set, a blocker row it added, and what a rollup's audit entry (`changes.jsonl`) says it actually wrote.
|
|
186
204
|
Anything else stops the run `FAILED roadmap changed`.
|
|
@@ -206,7 +224,10 @@ refuses a plan that a roadmap lock names, at start and before every session. `-D
|
|
|
206
224
|
the session command, the worktree and any pending rollup, skips the host check, writes no files and starts nothing; it
|
|
207
225
|
does run `git fetch`, which updates the remote-tracking refs. `-GhAccount <login>` (recorded in the launch options,
|
|
208
226
|
passed on by the recheck task and in the printed task) makes every gh call of the runner and of `--last-stop` use
|
|
209
|
-
GH_TOKEN from `gh auth token -u <login>`; on a machine with several gh logins, give the repo's account.
|
|
227
|
+
GH_TOKEN from `gh auth token -u <login>`; on a machine with several gh logins, give the repo's account. The sessions
|
|
228
|
+
never get that token, nor GH_TOKEN, GITHUB_TOKEN, GH_ENTERPRISE_TOKEN, NPM_TOKEN or NODE_AUTH_TOKEN from the
|
|
229
|
+
environment; with CADDIS_HEADLESS=1 the guard denies `git push`, `gh pr merge|create`, `gh release`, a write through
|
|
230
|
+
`gh api`, `gh workflow run` and package publishes. Only the runner publishes. A gh call that
|
|
210
231
|
cannot answer (gh missing, 401, 404) is an error, never "not merged": the run stops
|
|
211
232
|
`BLOCKED gh cannot see <repo> with account <login>`, notified and recorded.
|
|
212
233
|
|
|
@@ -223,7 +244,8 @@ phases) holds the whole plan for every other roadmap and for plan mode. At the t
|
|
|
223
244
|
every milestone that waits only for its rollup (Status not finished, every phase merged, and the same rule as
|
|
224
245
|
`next`: no blocker, dependencies finished, Owner the runner); `--last-stop` says `rollup-ready:` for such a milestone,
|
|
225
246
|
so recheck restarts the runner. A sweep rollup that writes nothing stops `BLOCKED rollup of <id> wrote nothing`
|
|
226
|
-
(recorded, not restartable) and is not retried or reported until the roadmap changes.
|
|
247
|
+
(recorded, not restartable) and is not retried or reported until the roadmap changes. A rollup that exits 3 (its
|
|
248
|
+
exit check or Exit setup could not run) stops `BLOCKED rollup not run: <id> ...` (not restartable; the owner decides). The dry run lists them first. If
|
|
227
249
|
the owner edits the roadmap during a merge wait, the restart stops `FAILED roadmap changed ...` and names the
|
|
228
250
|
recovery: `roadmap-run.ps1 -Roadmap <slug> -AcceptRoadmap` (owner only, refused headless) takes the runner lock (a live
|
|
229
251
|
runner refuses it), prints the diff from the published baseline, asks you to type `accept` (or `--yes`), and accepts
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: reference
|
|
3
3
|
title: Review protocol
|
|
4
|
-
description: The review method one model can rely on - invariants, inputs and writers, shared state,
|
|
4
|
+
description: The review method one model can rely on - invariants, inputs and writers, shared state, check what the change promises, tests, docs, then severity (only blocking stops the merge; each finding needs a reproduction), one FINDING line per finding and an END REVIEW line. caddis_review.py sends it to every review run.
|
|
5
5
|
status: current
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Review protocol (generic, any diff)
|
|
9
9
|
|
|
10
|
-
You review a diff. You
|
|
11
|
-
|
|
12
|
-
first finding. Include a short section per step, in order.
|
|
10
|
+
You review a diff. You read only: you have Read, Grep and Glob and no shell, so you run no test and no command, and
|
|
11
|
+
you do not edit, create or delete files. The diff is in the prompt. Tests are the implementer's and CI's job. Work
|
|
12
|
+
through ALL steps in order. Do not stop at the first finding. Include a short section per step, in order.
|
|
13
13
|
|
|
14
14
|
## Step 1 - Purpose and invariants
|
|
15
15
|
Read the card, the plan or design section it cites, and the diff. Write the list of INVARIANTS this change must keep:
|
|
@@ -26,12 +26,14 @@ accident or on purpose? This includes the agent or session the code is meant to
|
|
|
26
26
|
List state that two runs, two kinds of target, or two processes could share (files, locks, relays, logs, caches).
|
|
27
27
|
Can they collide? Can one read the other's output as its own?
|
|
28
28
|
|
|
29
|
-
## Step 4 -
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
and
|
|
33
|
-
with a real payload). Compare risky behaviour with the
|
|
34
|
-
something. Report any that fail or that cannot work as
|
|
29
|
+
## Step 4 - Check what the change promises
|
|
30
|
+
For every command that the plan, its exit gates, the docs or the skill text say should work for this change (the
|
|
31
|
+
documented usage lines, exactly as written), follow it through the code by reading: the argument parsing, the paths it
|
|
32
|
+
reads and writes, the repo's OWN fixtures and example files. Read unattended scripts (hooks, runners) as they are
|
|
33
|
+
really run (as a script, with a real payload). Compare risky behaviour with the code before the change (the `-` lines
|
|
34
|
+
of the diff) when the change claims to fix or tighten something. Report any that would fail or that cannot work as
|
|
35
|
+
documented. For a check you cannot settle by reading, write one line `not executed: <command> (reviewer has no
|
|
36
|
+
shell)`.
|
|
35
37
|
|
|
36
38
|
## Step 5 - Tests
|
|
37
39
|
For each new or changed test: could it pass for the wrong reason (no assertion that can fail, mocked away the thing
|
|
@@ -52,9 +54,10 @@ Severity rule. Only **blocking** stops the merge, so use it with care:
|
|
|
52
54
|
negative test, a doc that is wrong in a way that does not make a command fail, an error message that misleads.
|
|
53
55
|
- **nit** = style and wording.
|
|
54
56
|
|
|
55
|
-
Every finding needs a concrete reproduction: a command, an input or a test that
|
|
56
|
-
failure scenario. A finding without a reproduction is a **nit**,
|
|
57
|
-
write "might", "could in theory" or "a future change may": show it
|
|
57
|
+
Every finding needs a concrete reproduction: a command, an input or a test that would show the failure, written in
|
|
58
|
+
the failure scenario (you do not run it; the implementer does). A finding without a reproduction is a **nit**,
|
|
59
|
+
whatever its severity would otherwise be. Do not write "might", "could in theory" or "a future change may": show it
|
|
60
|
+
or call it a nit.
|
|
58
61
|
|
|
59
62
|
The gate exits by the findings. A **blocking** finding fails it. **should-fix** and **nit** findings do not: they are
|
|
60
63
|
listed in the report under "Follow-up (not blocking)". The tool allows 3 completed review rounds for a phase; the 4th completed round
|
|
@@ -9,11 +9,12 @@ Ship the current working changes via this repo's actual delivery pipeline. The p
|
|
|
9
9
|
repo, so **detect it first**, then follow the matching lane. Preflight, staging, and commit are
|
|
10
10
|
identical across lanes; only monitoring and validation differ.
|
|
11
11
|
|
|
12
|
-
> **This is the express lane** —
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
> PR, monitor CI, stop at green) **→ `/ship-merge`** (merge the green PR behind a
|
|
16
|
-
> validate, clean up).
|
|
12
|
+
> **This is the express lane** — commit, push the current feature branch and watch its CI, with no
|
|
13
|
+
> review pause. **It never pushes to the default branch.** On the default branch (Gitea or GitHub lane)
|
|
14
|
+
> it moves the change to a new branch and hands over to the reviewed lane: **`/caddis:ship-pr`** (open
|
|
15
|
+
> a PR, monitor CI, stop at green) **→ `/caddis:ship-merge`** (merge the green PR behind a
|
|
16
|
+
> deploy-confirm, validate, clean up). Why: a direct push skips the PR, the ci-watch `RESULT: pass` on
|
|
17
|
+
> the watched head and the check that no default-branch run is in progress.
|
|
17
18
|
|
|
18
19
|
Optional message: **$ARGUMENTS** (if empty, derive a conventional commit message from staged changes)
|
|
19
20
|
|
|
@@ -36,13 +37,32 @@ names, branch, and service identifiers — never assume.
|
|
|
36
37
|
- Tests: run only if the user says they're needed or a gate explicitly requires them
|
|
37
38
|
- Fix any failures before proceeding. Do not commit broken code.
|
|
38
39
|
|
|
39
|
-
**
|
|
40
|
+
**1b. BRANCH CHECK** — Read the default branch as a bare name (don't assume `main`) and the current
|
|
41
|
+
branch. `git rev-parse --abbrev-ref origin/HEAD` prints `origin/<default>`, so strip the `origin/`
|
|
42
|
+
prefix before you compare, or the check never matches:
|
|
43
|
+
```bash
|
|
44
|
+
d=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) && d=${d#origin/} # prints origin/<default>: strip origin/
|
|
45
|
+
[ -n "$d" ] || d=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name) # origin/HEAD not set
|
|
46
|
+
git branch --show-current # compare with "$d"
|
|
47
|
+
```
|
|
48
|
+
- **On a non-default branch:** continue at Step 2, then Step 3 pushes that branch.
|
|
49
|
+
- **On the default branch, Gitea or GitHub lane:** do not commit here. Run `git switch -c ship/<slug>`
|
|
50
|
+
(the uncommitted changes go with you) and commit on it (Step 2). Then **STOP: `/ship` ends here.**
|
|
51
|
+
Do not run Step 3 or later. Hand over to `/caddis:ship-pr` → `/caddis:ship-merge`.
|
|
52
|
+
A direct push to the default branch is refused: it skips the PR, the CI pass on the watched head
|
|
53
|
+
and the in-progress check.
|
|
54
|
+
- **Local-only lane:** there is no CI and no PR; commit where you are.
|
|
55
|
+
|
|
56
|
+
**2. STAGE + COMMIT** — Stage only the intended files, by name (never `git add -A`, `git add .`, `git add -u`, a folder, or `git commit -a`):
|
|
40
57
|
```
|
|
41
58
|
git status --short # confirm what's staged
|
|
42
59
|
git add <specific files>
|
|
43
|
-
git
|
|
60
|
+
git diff --cached --name-only # must list ONLY <specific files>
|
|
61
|
+
git commit -m "<type>(<scope>): <message>" -- <specific files>
|
|
44
62
|
git rev-parse HEAD # record SHA for monitoring
|
|
45
63
|
```
|
|
64
|
+
If `git diff --cached --name-only` lists a path you did not change, **stop**: a peer staged it. Do not
|
|
65
|
+
commit, unstage or stash it; report it. `-- <files>` commits only the named files even then.
|
|
46
66
|
Use conventional commits: `fix:`, `feat:`, `chore:`, `refactor:`, `docs:`. Scope = affected module.
|
|
47
67
|
|
|
48
68
|
**2b. CROSS-REVIEW TRIGGER** — `ship` has no review pause at all, which is how sixteen fixes reached production unreviewed in one day.
|
|
@@ -52,10 +72,12 @@ Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <
|
|
|
52
72
|
`<base>` is `origin/<default branch>` (on the default branch itself, the commit before this change). Tier 0 or 1-small: no model review. Tier 1: one `/caddis:cross-review`. Tier 2: two reviewers of two other vendors in one round. No `TIER:` line means tier 2.
|
|
53
73
|
<!-- /shared:cross-review-trigger -->
|
|
54
74
|
|
|
55
|
-
**3. PUSH** —
|
|
75
|
+
**3. PUSH** — only when Step 1b found a non-default branch (on the default branch, `/ship` stopped at Step 2):
|
|
56
76
|
```
|
|
57
|
-
git push origin <branch>
|
|
77
|
+
git push -u origin <feature branch>
|
|
58
78
|
```
|
|
79
|
+
Never `git push origin <default branch>`: the change reaches the default branch only through
|
|
80
|
+
`/caddis:ship-pr` → `/caddis:ship-merge`, which merge on ci-watch `RESULT: pass` at the watched head.
|
|
59
81
|
Confirm the push succeeded and the SHA is accepted by the remote. (Local-only lane: skip if there is
|
|
60
82
|
no remote, and note that nothing was pushed.)
|
|
61
83
|
|
|
@@ -119,7 +141,7 @@ Small work that does not meet a trigger skips its block.
|
|
|
119
141
|
|
|
120
142
|
## Rules
|
|
121
143
|
- Never push before preflight gates are green.
|
|
122
|
-
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies
|
|
144
|
+
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies all three, and `git add -u` and `git commit -a`). Commit with `git commit -m "..." -- <files>`, after `git diff --cached --name-only` shows only those files.
|
|
123
145
|
- Do not edit a workflow file (`.gitea/workflows/` or `.github/workflows/`) to make a failing gate
|
|
124
146
|
pass — fix the source.
|
|
125
147
|
- Gitea lane: tag-triggered runs after `release_metadata` are expected; verify `deploy_prod` is
|
|
@@ -28,6 +28,35 @@ Resolve the target PR from `$ARGUMENTS`, else the current branch's open PR. No o
|
|
|
28
28
|
that and point at `/ship-pr`. Read `AGENTS.md` + the workflow file(s) for the repo's real deploy
|
|
29
29
|
job names and default branch — never assume.
|
|
30
30
|
|
|
31
|
+
## Step 0b — Is this checkout safe to move?
|
|
32
|
+
|
|
33
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
34
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
35
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
36
|
+
```
|
|
37
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
38
|
+
```
|
|
39
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
40
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
41
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
42
|
+
|
|
43
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
44
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
45
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
46
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
47
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
48
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
49
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
50
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
51
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
52
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
53
|
+
checkout has it out.
|
|
54
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
55
|
+
|
|
56
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
57
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
58
|
+
<!-- /checkout-safety -->
|
|
59
|
+
|
|
31
60
|
## Step 1 — Refuse unless green + mergeable + reviewed
|
|
32
61
|
|
|
33
62
|
All of, per the repo's own rules:
|
|
@@ -102,6 +131,8 @@ attempt a silent re-deploy — and **skip cleanup** (Step 6).
|
|
|
102
131
|
**Only after** Step 5 is green:
|
|
103
132
|
- Run `git status --short`. If it shows changes you did not make, do not switch, stash, reset or commit:
|
|
104
133
|
leave them, report them, and stop cleanup here.
|
|
134
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), do not switch or pull. Clean up as Step 0b says:
|
|
135
|
+
`git fetch --prune`, `git fetch origin <default-branch>:<default-branch>`, then delete the branches.
|
|
105
136
|
- `git fetch --prune`, then switch to the default branch and fast-forward it to the merge commit.
|
|
106
137
|
- Delete the **remote** feature branch; delete the **local** feature branch (for a squash merge, compare
|
|
107
138
|
the branch tree with the merged tree first, not ancestry).
|
|
@@ -123,7 +154,7 @@ Cleanup: remote branch ✗ deleted / local ✗ deleted / backup ref droppe
|
|
|
123
154
|
## Rules
|
|
124
155
|
- Never merge without: green required checks **and** the explicit human deploy-confirm.
|
|
125
156
|
- Never delete a branch before its deploy is validated green.
|
|
126
|
-
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies
|
|
157
|
+
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies all three, and `git add -u` and `git commit -a`). Commit with `git commit -m "..." -- <files>`, after `git diff --cached --name-only` shows only those files. Never edit a workflow file to make a gate pass.
|
|
127
158
|
- Local-only lane: no PR, no merge — refuse and point at `/ship`.
|
|
128
159
|
|
|
129
160
|
## Skill reference
|
|
@@ -10,7 +10,7 @@ after. This command does the mechanics only: push safely, open (or update) the P
|
|
|
10
10
|
and **stop at green** with a mergeability verdict. It **never merges and never deploys** — on these
|
|
11
11
|
repos merge == deploy, so the merge stays a separate, deliberate act: `/ship-merge`.
|
|
12
12
|
|
|
13
|
-
For a
|
|
13
|
+
For a quick commit and push of a feature branch, use `/ship` (the express lane). It never pushes the default branch.
|
|
14
14
|
|
|
15
15
|
Optional argument: **$ARGUMENTS** (PR title override; default = derived from the branch's
|
|
16
16
|
conventional-commit summary).
|
|
@@ -27,11 +27,47 @@ conventional-commit summary).
|
|
|
27
27
|
Read `AGENTS.md` + the detected workflow file(s) first for the repo's real gate names, default
|
|
28
28
|
branch, and merge conventions — never assume `main`, never assume job names.
|
|
29
29
|
|
|
30
|
+
## Step 0b — Is this checkout safe to move?
|
|
31
|
+
|
|
32
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
33
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
34
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
35
|
+
```
|
|
36
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
37
|
+
```
|
|
38
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
39
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
40
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
41
|
+
|
|
42
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
43
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
44
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
45
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
46
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
47
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
48
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
49
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
50
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
51
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
52
|
+
checkout has it out.
|
|
53
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
54
|
+
|
|
55
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
56
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
57
|
+
<!-- /checkout-safety -->
|
|
58
|
+
|
|
30
59
|
## Step 1 — Refuse on the default branch
|
|
31
60
|
|
|
32
|
-
A PR is *branch → default*.
|
|
33
|
-
|
|
34
|
-
|
|
61
|
+
A PR is *branch → default*. Read the default branch as a bare name: `git rev-parse --abbrev-ref
|
|
62
|
+
origin/HEAD` prints `origin/<default>`, so strip the `origin/` prefix before you compare.
|
|
63
|
+
```bash
|
|
64
|
+
d=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) && d=${d#origin/} # prints origin/<default>: strip origin/
|
|
65
|
+
[ -n "$d" ] || d=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name) # origin/HEAD not set
|
|
66
|
+
git branch --show-current # compare with "$d"
|
|
67
|
+
```
|
|
68
|
+
If HEAD **is** the default branch, stop: there is nothing to open a PR from. Offer to move the
|
|
69
|
+
uncommitted work to a feature branch (`git switch -c <branch>`), or run `/ship`, which does that and
|
|
70
|
+
hands back here.
|
|
35
71
|
|
|
36
72
|
## Step 2 — Preflight (local gates mirroring CI)
|
|
37
73
|
|
|
@@ -56,7 +92,7 @@ source checkout; skip this step if the script is missing or the repo has no `.ca
|
|
|
56
92
|
- Exit **1** — **stop; do not open the PR.** Show each `CHECK VIOLATION` or `ERROR` line.
|
|
57
93
|
- `plan <path>: tracker done, status <s>` — run
|
|
58
94
|
`caddis_tidy.py --repo-root . --apply --only <path>`, `git add` the moved plan by name,
|
|
59
|
-
commit
|
|
95
|
+
commit with `git commit -m "..." -- <old path> <new path>`, and run this step again.
|
|
60
96
|
- `plan <path>: tracker done, but done/<name> already exists (rename one of them)` — `--apply`
|
|
61
97
|
cannot fix this; it changes nothing while the name is taken. Rename the plan or the old
|
|
62
98
|
`done/` copy with `git mv`, commit, and run this step again.
|
|
@@ -108,6 +144,8 @@ Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <
|
|
|
108
144
|
git rebase <default-branch>
|
|
109
145
|
git push --force-with-lease origin <branch> # never bare --force
|
|
110
146
|
```
|
|
147
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), never rebase here: rebase in a detached worktree, as
|
|
148
|
+
Step 0b says.
|
|
111
149
|
|
|
112
150
|
## Step 5 — Push + create/update the PR
|
|
113
151
|
|
|
@@ -146,7 +184,7 @@ human-confirmed door.
|
|
|
146
184
|
|
|
147
185
|
## Rules
|
|
148
186
|
- **Never merges, never deploys** — no merge action exists in this command, by design.
|
|
149
|
-
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies
|
|
187
|
+
- Never `git add -A`, `git add .` or `git add <dir>`, even after reading `git status`: stage named files only (the guard denies all three, and `git add -u` and `git commit -a`). Commit with `git commit -m "..." -- <files>`, after `git diff --cached --name-only` shows only those files.
|
|
150
188
|
- Never force-push without a `backup/*-preship` recovery ref; force pushes are `--force-with-lease` only.
|
|
151
189
|
- Never edit a workflow file (`.gitea/workflows/`, `.github/workflows/`) to make a gate pass — fix the source.
|
|
152
190
|
- Local-only lane: refuse + point at `/ship`. On the default branch: stop + point at `/ship`.
|