@arbiterforge/ca-pi 0.15.2 → 0.15.3

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.
Files changed (59) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/plugins/ca-pi/CHANGELOG.md +62 -0
  4. package/plugins/ca-pi/COMMANDS.md +3 -9
  5. package/plugins/ca-pi/SKILLS.md +16 -22
  6. package/plugins/ca-pi/agents/coverage-auditor.md +16 -2
  7. package/plugins/ca-pi/generated/command-catalog.json +13 -22
  8. package/plugins/ca-pi/helpers/artifacts/ca-artifact-darwin-amd64 +0 -0
  9. package/plugins/ca-pi/helpers/artifacts/ca-artifact-darwin-arm64 +0 -0
  10. package/plugins/ca-pi/helpers/artifacts/ca-artifact-linux-amd64 +0 -0
  11. package/plugins/ca-pi/helpers/artifacts/ca-artifact-linux-arm64 +0 -0
  12. package/plugins/ca-pi/helpers/artifacts/ca-artifact-windows-amd64.exe +0 -0
  13. package/plugins/ca-pi/helpers/artifacts/ca-artifact-windows-arm64.exe +0 -0
  14. package/plugins/ca-pi/helpers/artifacts/release.json +6 -6
  15. package/plugins/ca-pi/hooks/_artifactauthoritylib.py +383 -32
  16. package/plugins/ca-pi/hooks/_artifactlib.py +3 -1
  17. package/plugins/ca-pi/hooks/_host.py +1 -1
  18. package/plugins/ca-pi/hooks/artifact-authority-hook.py +4 -21
  19. package/plugins/ca-pi/hooks/artifact-authority.py +11 -0
  20. package/plugins/ca-pi/hooks/hostapi.py +1 -1
  21. package/plugins/ca-pi/includes/command-compatibility.md +31 -0
  22. package/plugins/ca-pi/includes/farm.md +187 -36
  23. package/plugins/ca-pi/includes/maturity-coverage.md +57 -17
  24. package/plugins/ca-pi/includes/routing-table.md +10 -11
  25. package/plugins/ca-pi/includes/safety-core.md +2 -2
  26. package/plugins/ca-pi/package.json +1 -1
  27. package/plugins/ca-pi/routines/INDEX.md +12 -11
  28. package/plugins/ca-pi/routines/context-check/SKILL.md +17 -1
  29. package/plugins/ca-pi/routines/context-creation/SKILL.md +8 -1
  30. package/plugins/ca-pi/routines/debug/SKILL.md +18 -2
  31. package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +72 -118
  32. package/plugins/ca-pi/routines/decision-lifecycle/references/authoring.md +152 -0
  33. package/plugins/ca-pi/routines/decision-variance/SKILL.md +107 -133
  34. package/plugins/ca-pi/routines/decision-variance/references/analysis.md +136 -0
  35. package/plugins/ca-pi/routines/decompose/SKILL.md +8 -1
  36. package/plugins/ca-pi/routines/finishing-a-development-branch/SKILL.md +85 -7
  37. package/plugins/ca-pi/routines/post-merge-cleanup/SKILL.md +19 -2
  38. package/plugins/ca-pi/routines/refactor/SKILL.md +27 -8
  39. package/plugins/ca-pi/routines/release/SKILL.md +2 -1
  40. package/plugins/ca-pi/routines/security-architecture/SKILL.md +14 -3
  41. package/plugins/ca-pi/routines/tdd/SKILL.md +9 -5
  42. package/plugins/ca-pi/routines/tribunal/SKILL.md +28 -14
  43. package/plugins/ca-pi/skills/ca-adr/SKILL.md +103 -18
  44. package/plugins/ca-pi/skills/ca-adr-status/SKILL.md +6 -24
  45. package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +241 -52
  46. package/plugins/ca-pi/skills/ca-context-check/SKILL.md +87 -24
  47. package/plugins/ca-pi/skills/ca-create-context/SKILL.md +159 -19
  48. package/plugins/ca-pi/skills/ca-debug/SKILL.md +100 -27
  49. package/plugins/ca-pi/skills/ca-decompose/SKILL.md +156 -17
  50. package/plugins/ca-pi/skills/ca-pr/SKILL.md +161 -26
  51. package/plugins/ca-pi/skills/ca-reconcile/SKILL.md +108 -30
  52. package/plugins/ca-pi/skills/ca-refactor/SKILL.md +96 -30
  53. package/plugins/ca-pi/skills/ca-release/SKILL.md +614 -39
  54. package/plugins/ca-pi/skills/ca-status/SKILL.md +1 -1
  55. package/plugins/ca-pi/skills/ca-threat-model/SKILL.md +56 -27
  56. package/plugins/ca-pi/skills/ca-tribunal/SKILL.md +105 -26
  57. package/plugins/ca-pi/routines/skill-author/SKILL.md +0 -129
  58. package/plugins/ca-pi/routines/skill-author/references/skill-template.md +0 -58
  59. package/plugins/ca-pi/skills/ca-new-skill/SKILL.md +0 -129
@@ -1,61 +1,250 @@
1
1
  ---
2
2
  name: ca-cleanup
3
- description: Finish an already-merged branch — classify the leftover artifacts, return to a fast-forwarded default checkout, and delete the merged local branch. Every discard confirmed per item; containment proven, never assumed.
4
- argument-hint: (none)
3
+ description: "Clean up an already-merged local branch after proving containment. Confirm each discard and preserve unique work."
4
+ argument-hint: "(none)"
5
5
  ---
6
6
 
7
- # /ca-cleanup — post-merge branch transition
7
+ # post-merge-cleanup
8
+
9
+ The walk back from a merged PR, selected by cleanup intent or an explicit entry.
10
+
11
+ The work has landed on the default branch. What is left is local: the branch you
12
+ are standing on, and whatever the run left in the tree. This skill returns you to
13
+ a clean, fast-forwarded default checkout without losing anything you have not
14
+ explicitly agreed to lose.
15
+
16
+ **It is ordinary lifecycle work and never needs `/ca-override`.** When it
17
+ cannot proceed, it names the gate that stopped it. Issue #308 recorded the
18
+ alternative: with no owner for this transition, the routing loop reached for
19
+ `/ca-chore`, then for `/ca-override` — a bypass manufactured to cover a
20
+ coverage hole.
8
21
 
9
22
  <!-- catalog-compatibility-notice:start -->
10
- > Compatibility route. Prefer `/ca-pr --cleanup` for new usage. This installed route remains
11
- > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
- > continue with the unchanged cleanup workflow below.
23
+ > Compatibility route. Prefer `/ca-pr --cleanup` for new explicit usage. The retained entry
24
+ > and natural-language intent use this owner under
25
+ > <plugin-root>/includes/command-compatibility.md.
13
26
  <!-- catalog-compatibility-notice:end -->
14
27
 
15
- Your PR merged. You are still standing on the branch, with build output, worktree
16
- residue, and scratch files around you. This command owns the ordinary walk back:
17
- prove the branch actually landed, decide what the leftovers are, get to a clean
18
- fast-forwarded default checkout, and drop the merged local branch.
19
-
20
- It exists because nothing else owned it. `/ca-standup` is daily hygiene and
21
- deliberately never touches the current branch or the default one;
22
- `/ca-chore` takes docs, dependency bumps, and reverts. Issue #308 recorded
23
- what the gap produced: a routine cleanup routed to `/ca-chore`, which
24
- refused it, and then to `/ca-override` — a bypass invented to cover missing
25
- coverage. This is that coverage.
26
-
27
- ## Routes to
28
-
29
- The `post-merge-cleanup` skill (`<plugin-root>/routines/post-merge-cleanup/SKILL.md`),
30
- which owns the containment proof, the artifact classification, and the per-item
31
- confirmations.
32
-
33
- ## When NOT to use
34
-
35
- - The branch has NOT merged yet → `/ca-pr` (`finishing-a-development-branch`)
36
- owns the terminal decision; come back here after it lands.
37
- - Daily start-of-day hygiene across *other* branches and worktrees →
38
- `/ca-standup`.
39
- - A read-only look at what is dirty → `/ca-status`.
40
- - Uncommitted work you want to keep → `/ca-commit`. This command never
41
- commits for you.
42
-
43
- ## Hard gate
44
-
45
- - MUST prove the current branch is contained in the **fetched** default branch —
46
- SHA-ancestry, or a squash-merge proven by the merged PR record (`headRefOid`
47
- == HEAD) — before anything is deleted. An unproven or unfetched comparison
48
- STOPs — a branch that only *looks* merged is not merged.
49
- - MUST classify every dirty or untracked artifact as **unique**, **redundant**,
50
- or **superseded**, and MUST NOT discard a unique or unclassifiable one without
51
- explicit per-item confirmation naming it.
52
- - MUST confirm each removal individually — no batched yes, no implied yes.
53
- - MUST reach the default branch with a clean working tree, and MUST fast-forward
54
- with `--ff-only` only — never a merge commit, never a rebase, never a reset
55
- that discards work.
56
- - MUST use `git branch -d`, and MAY use `-D` only when the squash-merge PR-record
28
+ ## Entry boundaries
29
+
30
+ Select this owner for an already-merged branch cleanup request, `/ca-pr --cleanup`,
31
+ or the explicit `/ca-cleanup` compatibility entry. Do not require repeated slash
32
+ syntax. An explanation-only or dirty-state question is read-only, not a deletion
33
+ request. An unmerged branch belongs to the finishing owner, not this cleanup.
34
+ MUST NOT require `/ca-override` for ordinary cleanup; name a real blocker instead.
35
+ This owner neither stages nor commits. Keeping work may hand it to the existing
36
+ commit owner; no discard is implied by that handoff or by a cleanup request.
37
+
38
+ ## Pre-flight
39
+
40
+ Read this, or STOP and surface the gap — never guess the default-branch name:
41
+
42
+ - `<project-root>/.codearbiter/CONTEXT.md` — the default-branch name.
43
+
44
+ If HEAD is already the default branch, there is no transition to make. Report the
45
+ dirty state read-only and exit; branch pruning across *other* branches belongs to
46
+ `/ca-standup`.
47
+
48
+ ## Phase 1 — Prove the merge · gate: BLOCK
49
+
50
+ A branch that looks merged is not merged. Establish it against the network, not
51
+ against a stale local ref. This repo squash-merges by default, so SHA-ancestry
52
+ alone is the wrong instrument for most landings: it holds for a fast-forward or
53
+ a merge-commit landing, but a squash merge writes a new commit with no SHA
54
+ lineage back to the branch, and `--is-ancestor` will report non-zero for a
55
+ branch that landed cleanly. The gate is **content-containment**, proven by
56
+ whichever instrument fits the landing, always reported as a fact:
57
+
58
+ 1. `git fetch` the remote holding the default branch. A fetch that fails STOPs —
59
+ an unfetched comparison proves nothing.
60
+ 2. Prove containment with two primary instruments plus a fallback, tried in
61
+ order:
62
+ 1. **Ancestry** — `git merge-base --is-ancestor HEAD origin/<default>`. Holds
63
+ for a fast-forward or merge-commit landing. If it holds, that is the
64
+ proof: report it and move on.
65
+ 2. **Squash-merge proof via the PR record** — if ancestry fails, run
66
+ `gh pr list --head "$(git branch --show-current)" --state merged --json number,state,headRefOid,mergeCommit`.
67
+ A `MERGED` PR whose `headRefOid` equals local `git rev-parse HEAD` proves
68
+ every commit on this branch rode that PR's squash into the default
69
+ branch. Report the PR number, that `headRefOid == HEAD`, the merge
70
+ commit (`mergeCommit.oid` in that JSON), **and** the ancestry check's
71
+ negative result — all as facts, not as a failure. Corroborate with
72
+ `git diff --quiet origin/<default> HEAD` when it happens to hold; a
73
+ **non-empty** diff alongside a valid PR proof is normal (the default
74
+ branch advanced since the merge landed) and is reported as a fact, never
75
+ treated as a failure. The PR-record identity — `MERGED` plus
76
+ `headRefOid == HEAD` — is the load-bearing proof; the diff is
77
+ corroboration only when it happens to be fresh, never a requirement.
78
+ 3. **Fallback when `gh` is unavailable or no PR record exists** —
79
+ `git diff --quiet origin/<default> HEAD` (the tree is byte-identical to
80
+ the fetched default) is an acceptable fallback proof. Report it as such.
81
+ 3. Report whichever instrument held as a fact — the default branch, the fetched
82
+ SHA, and which of the three proofs established containment.
83
+
84
+ If none of the three hold, STOP exactly as today. Name the un-landed commits
85
+ and route to `/ca-pr`; nothing is deleted here.
86
+
87
+ > Deliberate deviation from issue #586's suggested contract: that suggestion
88
+ > required the squash-merge proof's diff to be empty. That requirement
89
+ > re-breaks this gate the moment any later PR merges to the default branch —
90
+ > the common state, not an edge case. The PR-record identity is what proves
91
+ > containment; the diff is corroboration, demoted from requirement to fact.
92
+
93
+ Gate: the remote is fetched and HEAD is proven contained in the fetched default
94
+ branch — by ancestry, by the PR-record squash proof, or by the byte-identical
95
+ fallback — or the skill has stopped.
96
+
97
+ ## Phase 2 — Classify the residue · gate: BLOCK
98
+
99
+ List every dirty tracked change, every untracked file, and every stash reachable
100
+ from this branch. Classify each into exactly one of three, and say *why* for each:
101
+
102
+ - **Redundant** — byte-identical to content already on the default branch, or a
103
+ regenerated build artifact whose generator is committed and rerunnable. Safe to
104
+ remove because removing it loses no information.
105
+ - **Superseded** — an earlier form of something the merged PR already landed in a
106
+ better shape. Name what supersedes it.
107
+ - **Unique** — anything else. This is the default: an artifact that cannot be
108
+ proven redundant or superseded IS unique. Uncertainty classifies as unique, not
109
+ as redundant.
110
+
111
+ Present the classification before touching anything. A file whose class you
112
+ cannot establish is reported as unique with the reason you could not classify it.
113
+
114
+ Gate: every dirty, untracked, and stashed artifact carries a class and a stated
115
+ reason, with unclassifiable items counted as unique.
116
+
117
+ ## Phase 3 — Resolve the residue · gate: STOP
118
+
119
+ Per item, in the order Phase 2 listed them. Never batch:
120
+
121
+ - **Unique** — offer to keep it: `/ca-commit` it on this branch before the
122
+ transition, move it aside, or leave it in place and stop the cleanup. It is
123
+ discarded only if the user explicitly confirms *that item by name*, with the
124
+ Phase 2 reasoning in view.
125
+ - **Redundant / superseded** — offer removal, one confirmation each, stating what
126
+ it is and why it is safe. Declining leaves it exactly where it is.
127
+
128
+ A stash is never dropped here. Stashes are reported with `git stash show` as the
129
+ suggested next step, the same report-and-route contract `/ca-standup` holds.
130
+
131
+ If anything the user chose to keep would block the checkout, STOP and say so
132
+ rather than removing it anyway — but distinguish the two causes before naming
133
+ the artifact as the blocker:
134
+
135
+ - **The kept artifact genuinely conflicts** — its content collides with what
136
+ checking out the default branch would need to change or remove. This is the
137
+ user's to resolve, as today.
138
+ - **The local default ref lags the fetched one** — git refuses a checkout when
139
+ a locally-modified tracked file differs between HEAD and the target ref, and
140
+ a stale local `<default>` makes that difference larger than reality: content
141
+ the kept artifact never actually touches can still collide with what a
142
+ *current* default branch would carry. That gap is not the user's problem and
143
+ not the kept artifact's fault. It is resolved by Phase 4's fast-forward-first
144
+ step, not by discarding anything here. Issue #586 recorded the observed
145
+ failure mode: a stale local `main` — 513 lines behind on
146
+ `.codearbiter/gate-events.log` alone — made this STOP name a correctly-kept
147
+ 38-line artifact as the blocker, which invites exactly the silent discard
148
+ this phase exists to prevent.
149
+
150
+ Gate: every item is resolved by an explicit per-item decision, and the working
151
+ tree is clean enough to check out the default branch — or the skill has stopped
152
+ with the blocker named, correctly attributed to a genuine conflict or a stale
153
+ local ref.
154
+
155
+ ## Phase 4 — Transition · gate: BLOCK
156
+
157
+ Only after Phase 3 leaves the tree safe:
158
+
159
+ 1. **Fast-forward the local default ref BEFORE checking it out:**
160
+ `git fetch origin <default>:<default>`. Git refuses a non-fast-forward
161
+ update of a ref that is not currently checked out, so the `--ff-only`
162
+ guarantee is preserved by the instrument itself — this cannot silently
163
+ rewrite the local default ref, only advance it or refuse. This is what
164
+ keeps a stale local default from blocking (or worse, misattributing) the
165
+ checkout below. This step can itself be refused for the same reason a
166
+ checkout can be — `<default>` checked out in another worktree — in which
167
+ case report that as the (correctly attributed) blocker, per Phase 3, and
168
+ stop; do not treat the refusal as license to skip ahead.
169
+ 2. Check out the default branch, then **verify the checkout actually happened**
170
+ (`git branch --show-current`). A checkout silently fails when another worktree
171
+ holds the branch, and every step after this one would otherwise run against
172
+ the wrong branch.
173
+ 3. Fast-forward with `--ff-only` (belt over the braces of step 1 — a no-op when
174
+ the pre-checkout fetch already brought the local ref current). A divergence
175
+ means the default branch moved in a way this skill will not reconcile:
176
+ report it and stop. Never a merge commit, never a rebase, never a reset.
177
+
178
+ Gate: the local default ref was fast-forwarded before the checkout — or the
179
+ fast-forward's refusal was itself reported as a fact and the skill stopped —
180
+ HEAD is confirmed on the default branch by re-read, and the belt-and-braces
181
+ `--ff-only` pull either succeeded (typically a no-op) or was reported as a
182
+ refused divergence.
183
+
184
+ ## Phase 5 — Delete the merged local branch · gate: STOP
185
+
186
+ Offer deletion of the now-merged local branch, with the Phase 1 containment
187
+ proof restated. One confirmation, naming the branch.
188
+
189
+ - `git branch -d` first, always. Never reach for `-D` on the assumption that a
190
+ refusal means `-d` can't handle a squash merge — it often can. `git branch
191
+ -d`'s safety check accepts a branch merged into its **upstream**, not only
192
+ into HEAD: with an upstream still configured and equal to the tip, `-d`
193
+ succeeds (with a warning) even for a squash merge that `--is-ancestor` alone
194
+ would call unmerged. Do not conclude a refusal here means `-D` is required —
195
+ check the reason first.
196
+ - **The sanctioned `-D` path.** `-d` typically refuses once the remote branch
197
+ has been auto-deleted and pruned, because there is then no upstream left for
198
+ `-d` to test reachability against. When that happens, `git branch -D` is
199
+ permitted, but ONLY when both hold:
200
+ 1. Phase 1's proof, established this run, was the PR-record squash proof
201
+ (`MERGED` and `headRefOid == HEAD`) — not a bare ancestry pass, not a
202
+ stale or assumed proof.
203
+ 2. The confirmation restates that Phase-1 proof and explicitly names the
204
+ branch.
205
+ Frame this precisely: `-d`'s safety check tests SHA-reachability, and the
206
+ squash proof has already shown that instrument is the wrong one for this
207
+ repo's merge mode. The PR-record proof plus a named confirmation **replaces**
208
+ the check that `-d` can no longer run — it does not bypass it. Everywhere
209
+ else, `-D` stays forbidden exactly as before: if `-d` refuses and Phase 1's
210
+ proof was anything other than the PR-record squash proof, report both and
211
+ stop.
212
+ - The **remote** branch is never touched. If the user wants it gone, that is
213
+ theirs to do or the platform's auto-delete-on-merge to do.
214
+
215
+ Declining leaves the branch in place. That is a normal outcome, not a failure.
216
+
217
+ Gate: the branch is deleted only after an explicit confirmation naming it, via
218
+ `-d`, or via `-D` restricted to the sanctioned path above with the proof
219
+ restated, with the remote untouched.
220
+
221
+ ## Phase 6 — Receipt
222
+
223
+ One short summary: what landed, what was removed, what was kept, and where HEAD
224
+ is now. State declines as declines — a cleanup the user stopped halfway is a
225
+ correct outcome reported plainly, not an error.
226
+
227
+ ## Hard rules
228
+
229
+ - MUST fetch and prove `HEAD` is **contained** in the fetched default branch
230
+ before any deletion — via ancestry, via the PR-record squash proof (`MERGED`
231
+ and `headRefOid == HEAD`), or, without `gh`, via a byte-identical tree diff.
232
+ MUST NOT infer merge state from a `: gone]` upstream alone.
233
+ - MUST classify every artifact, and MUST treat anything not provably redundant or
234
+ superseded as unique.
235
+ - MUST NOT discard a unique or unclassifiable artifact without an explicit
236
+ confirmation naming that item.
237
+ - MUST confirm every removal and the branch deletion individually — no batched or
238
+ implied yes.
239
+ - MUST fast-forward the local default ref (`git fetch origin <default>:<default>`)
240
+ before checking it out, or report the fast-forward's own refusal (e.g.
241
+ `<default>` checked out in another worktree) as the blocker and stop. MUST
242
+ re-read the current branch after checkout before acting on it.
243
+ - MUST use `--ff-only`, and MUST NOT merge, rebase, or reset to reach the default
244
+ branch.
245
+ - MUST use `git branch -d`, and MAY use `-D` ONLY when the Phase-1 squash-merge
57
246
  proof held this run and `-d` refused, with that proof restated and the branch
58
- named in the confirmation. MUST NOT otherwise force-delete a branch, force-push,
59
- delete a remote branch, or write to the default branch.
60
- - MUST NOT require `/ca-override`. This is ordinary lifecycle work; if it
61
- cannot proceed, the reason is a stated gate, not a bypass.
247
+ named in the confirmation. Everywhere else `-D` is forbidden. MUST NOT delete a
248
+ remote branch, force-push, or write to the default branch.
249
+ - MUST NOT drop a stash — report and route, as `/ca-standup` does.
250
+ - MUST NOT route to `/ca-override` when blocked. Name the gate instead.
@@ -1,38 +1,101 @@
1
1
  ---
2
2
  name: ca-context-check
3
- description: Optional manual drift audit — report stale provenance-tracked docs, then per stale doc offer re-scout, re-baseline, or defer. Not the daily loop; commit-gate auto-heal owns routine maintenance.
4
- argument-hint: (none)
3
+ description: "Audit stale provenance-tracked docs on request. Report first; re-scout or re-baseline only for selected docs."
4
+ argument-hint: "(none)"
5
5
  ---
6
6
 
7
- # /ca-context-check — manual drift audit
7
+ # context-check
8
+
9
+ An optional, on-demand drift audit for bypass cases: a merge or an external
10
+ edit drifted a tracked source file you are not about to commit, so commit-gate's
11
+ Phase 5.5 auto-heal did not fire. This skill reports stale docs and lets you
12
+ act on each one individually.
13
+
14
+ This skill is NOT in the daily loop. Commit-gate auto-heal (Phase 5.5,
15
+ `heal_worklist`) owns the routine maintenance path. Invoke this only when drift
16
+ was introduced outside a commit (e.g. a direct push, a merge you did not
17
+ author, a manual file edit).
8
18
 
9
19
  <!-- catalog-compatibility-notice:start -->
10
- > Compatibility route. Prefer `/ca-status drift` for new usage. This installed route remains
11
- > functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
12
- > continue with the unchanged drift workflow below.
20
+ > Compatibility route. Prefer `/ca-status drift` for new explicit usage. The retained entry
21
+ > and natural-language intent use this owner under
22
+ > <plugin-root>/includes/command-compatibility.md.
13
23
  <!-- catalog-compatibility-notice:end -->
14
24
 
15
- An optional, on-demand audit for bypass cases: a merge or external edit
16
- changed a tracked source file you are not about to commit, so commit-gate's
17
- auto-heal did not fire. Routes to the `context-check` skill.
25
+ ## Entry boundaries
26
+
27
+ Use this owner for a requested provenance drift audit, `/ca-status drift`, or
28
+ the explicit `/ca-context-check` compatibility entry. Explanation-only questions
29
+ and ordinary status snapshots remain read-only answers, not repair requests.
30
+ Report first. Write only after the user selects re-scout or re-baseline for that
31
+ document; never change an unselected derived document. This owner neither stages
32
+ nor commits. Routine commit-gate auto-heal is unchanged.
33
+
34
+ ## Pre-flight
35
+
36
+ Read these before computing drift:
37
+
38
+ 1. `.codearbiter/.provenance/` — the per-doc provenance records. Load all
39
+ records via `load_provenance_dir` from
40
+ `<plugin-root>/hooks/_provenancelib.py`.
41
+ 2. `.codearbiter/code-map.md` — coarse concern map; read to orient on which
42
+ modules the stale docs govern.
43
+
44
+ ## Flow
45
+
46
+ ### Step 1 — Compute drift
47
+
48
+ Use `_provenancelib` helpers in this order:
49
+
50
+ 1. `load_provenance_dir(root + "/.codearbiter/.provenance/")` — returns the
51
+ provenance map `{doc: record}`.
52
+ 2. Collect all `drift_trigger: true` paths across all records.
53
+ 3. `batch_hash(paths, runner)` — hash every existing path in one git call.
54
+ 4. `compute_drift(provenance_map, current_hashes)` — returns a drift report
55
+ `{doc: [{path, kind}]}` for docs that have stale sources.
56
+
57
+ Alternatively reuse the same logic as `startup_drift_line` by calling it for
58
+ a human-readable summary, then inspecting `compute_drift` directly for detail.
59
+
60
+ If the drift report is empty: report "no stale docs — provenance is fresh"
61
+ and exit. No further action required.
62
+
63
+ ### Step 2 — Report stale docs
64
+
65
+ For each doc in the drift report, call `changed_scope(doc_provenance, drift)`
66
+ to list its drifted paths. Present a concise report before offering actions:
67
+
68
+ ```
69
+ Stale docs (N):
70
+ <doc>: <path1>, <path2> (changed | missing)
71
+ ...
72
+ ```
73
+
74
+ ### Step 3 — Per-doc action loop
75
+
76
+ For each stale doc, present three choices and wait for the user to select one:
18
77
 
19
- ## When to use
78
+ **re-scout** — dispatch an incremental re-scout of the drifted paths for this
79
+ doc, scoped to those paths only (like commit-gate Phase 5.5 heal but manually
80
+ invoked). The scout re-reads the changed paths and reports whether claims still
81
+ hold. If claims still hold: silently re-baseline the hashes via `rebaseline`.
82
+ If claims changed: surface the proposed doc edits for the user to accept before
83
+ re-baselining.
20
84
 
21
- Use this only when you believe drift was introduced outside a commit (e.g. a
22
- direct push, a merge you did not author, a manual file edit while outside a
23
- normal commit workflow). The SessionStart drift line (backed by
24
- `startup_drift_line`) is the usual signal that this check is warranted.
85
+ **re-baseline** — acknowledge the drift without re-scouting: call
86
+ `rebaseline(provenance, current_hashes)` to update the stored hashes silently.
87
+ Use this when the source change is cosmetic (formatting, comments, whitespace)
88
+ and the derived doc claims are still accurate.
25
89
 
26
- ## When NOT to use
90
+ **defer** — do nothing for this doc now. The drift line will reappear at the
91
+ next SessionStart. Use when the change is in-progress and the doc update should
92
+ wait for a later commit.
27
93
 
28
- - **Routine maintenance** — commit-gate auto-heal runs automatically on every
29
- commit that touches a `drift_trigger` source. No manual intervention needed
30
- for the common case.
31
- - Full brownfield re-scan from scratch → `/ca-create-context`.
32
- - Project state snapshot → `/ca-status`.
94
+ After processing all stale docs, summarize which docs were re-scouted,
95
+ re-baselined, or deferred.
33
96
 
34
- ## Hard gate
97
+ ## Hard rule
35
98
 
36
- Read-only unless the user explicitly chooses re-scout (partial scout run) or
37
- re-baseline (hash update in `.codearbiter/.provenance/`). MUST NOT commit on
38
- its own. MUST NOT modify any derived doc without an explicit user selection.
99
+ This skill MUST NOT commit. If re-scout or re-baseline produces updated
100
+ `.codearbiter/.provenance/` records, those file changes ride the next
101
+ user-initiated commit through commit-gate normally. No staging, no commits here.