@arbiterforge/ca-pi 0.15.1 → 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 (60) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/plugins/ca-pi/CHANGELOG.md +71 -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 +618 -58
  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/artifacts.md +20 -1
  22. package/plugins/ca-pi/includes/command-compatibility.md +31 -0
  23. package/plugins/ca-pi/includes/farm.md +187 -36
  24. package/plugins/ca-pi/includes/maturity-coverage.md +57 -17
  25. package/plugins/ca-pi/includes/routing-table.md +10 -11
  26. package/plugins/ca-pi/includes/safety-core.md +2 -2
  27. package/plugins/ca-pi/package.json +1 -1
  28. package/plugins/ca-pi/routines/INDEX.md +12 -11
  29. package/plugins/ca-pi/routines/context-check/SKILL.md +17 -1
  30. package/plugins/ca-pi/routines/context-creation/SKILL.md +8 -1
  31. package/plugins/ca-pi/routines/debug/SKILL.md +18 -2
  32. package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +72 -118
  33. package/plugins/ca-pi/routines/decision-lifecycle/references/authoring.md +152 -0
  34. package/plugins/ca-pi/routines/decision-variance/SKILL.md +107 -133
  35. package/plugins/ca-pi/routines/decision-variance/references/analysis.md +136 -0
  36. package/plugins/ca-pi/routines/decompose/SKILL.md +8 -1
  37. package/plugins/ca-pi/routines/finishing-a-development-branch/SKILL.md +85 -7
  38. package/plugins/ca-pi/routines/post-merge-cleanup/SKILL.md +19 -2
  39. package/plugins/ca-pi/routines/refactor/SKILL.md +27 -8
  40. package/plugins/ca-pi/routines/release/SKILL.md +2 -1
  41. package/plugins/ca-pi/routines/security-architecture/SKILL.md +14 -3
  42. package/plugins/ca-pi/routines/tdd/SKILL.md +9 -5
  43. package/plugins/ca-pi/routines/tribunal/SKILL.md +28 -14
  44. package/plugins/ca-pi/skills/ca-adr/SKILL.md +103 -18
  45. package/plugins/ca-pi/skills/ca-adr-status/SKILL.md +6 -24
  46. package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +241 -52
  47. package/plugins/ca-pi/skills/ca-context-check/SKILL.md +87 -24
  48. package/plugins/ca-pi/skills/ca-create-context/SKILL.md +159 -19
  49. package/plugins/ca-pi/skills/ca-debug/SKILL.md +100 -27
  50. package/plugins/ca-pi/skills/ca-decompose/SKILL.md +156 -17
  51. package/plugins/ca-pi/skills/ca-pr/SKILL.md +161 -26
  52. package/plugins/ca-pi/skills/ca-reconcile/SKILL.md +108 -30
  53. package/plugins/ca-pi/skills/ca-refactor/SKILL.md +96 -30
  54. package/plugins/ca-pi/skills/ca-release/SKILL.md +614 -39
  55. package/plugins/ca-pi/skills/ca-status/SKILL.md +1 -1
  56. package/plugins/ca-pi/skills/ca-threat-model/SKILL.md +56 -27
  57. package/plugins/ca-pi/skills/ca-tribunal/SKILL.md +105 -26
  58. package/plugins/ca-pi/routines/skill-author/SKILL.md +0 -129
  59. package/plugins/ca-pi/routines/skill-author/references/skill-template.md +0 -58
  60. package/plugins/ca-pi/skills/ca-new-skill/SKILL.md +0 -129
@@ -345,7 +345,9 @@ def _installed_workflow_preflight(installation: Path) -> dict[str, object]:
345
345
 
346
346
  required = [("UserPromptSubmit", None, "prompt-submit.py")]
347
347
  tools = ("Bash", "Agent") if host == "claude" else (
348
- "Bash", "shell_command", "exec_command", "unified_exec", "spawn_agent")
348
+ "Bash", "shell_command", "exec_command", "unified_exec", "spawn_agent",
349
+ "collaborationspawn_agent", "multi_agent_v1send_input", "multi_agent_v1resume_agent",
350
+ "multi_agent_v1close_agent")
349
351
  required += [(event, tool, "artifact-authority-hook.py")
350
352
  for event in ("PreToolUse", "PostToolUse") for tool in tools]
351
353
  required += [(event, None, "artifact-authority-hook.py")
@@ -11,7 +11,7 @@ import hostapi # noqa: E402
11
11
  class PiHost(hostapi.Host):
12
12
  name = "pi"
13
13
  adapter_name = "@arbiterforge/ca-pi"
14
- adapter_version = "0.15.1"
14
+ adapter_version = "0.15.3"
15
15
  update_target = "ca-pi"
16
16
  update_tag_prefix = "ca-pi-v"
17
17
  update_command = "pi update npm:@arbiterforge/ca-pi"
@@ -25,7 +25,7 @@ def main() -> int:
25
25
  tool = payload.get("tool_name")
26
26
  root = _hooklib.project_root(payload)
27
27
  try:
28
- if event in {"PreToolUse", "PostToolUse"} and tool != "spawn_agent":
28
+ if event in {"PreToolUse", "PostToolUse"} and tool not in _artifactauthoritylib.CODEX_REVIEW_TOOLS:
29
29
  result = _artifactauthoritylib.observe_verifier_hook(root, payload)
30
30
  if result is None:
31
31
  return 0
@@ -40,26 +40,9 @@ def main() -> int:
40
40
  else:
41
41
  sys.stderr.write(reason + "\n")
42
42
  return 0
43
- if event == "PreToolUse" and result.get("state") == "AUTHORIZED":
44
- print(json.dumps({
45
- "decision": "allow",
46
- "reason": (
47
- "codeArbiter authorized this wrapper for the exact resolved child set: "
48
- + json.dumps(result["command_bindings"], sort_keys=True)
49
- ),
50
- }))
51
- if event == "SubagentStop" and result.get("state") == "COMPLETED":
52
- print(json.dumps({
53
- "continue": True,
54
- "hookSpecificOutput": {
55
- "hookEventName": "SubagentStop",
56
- "additionalContext": (
57
- "codeArbiter: independent review observation recorded for request "
58
- + result["request_id"]
59
- + "; publish it through the production authority adapter."
60
- ),
61
- },
62
- }))
43
+ # Saved observations are the result. Success is silent: Codex's closed
44
+ # SubagentStop schema has no additionalContext, and an explicit approval
45
+ # would unnecessarily override the host's normal permission processing.
63
46
  return 0
64
47
 
65
48
 
@@ -46,6 +46,10 @@ def main(argv=None) -> int:
46
46
  "--reviewer-model", choices=sorted(_artifactauthoritylib.CLAUDE_REVIEWER_MODELS),
47
47
  default="opus", help="Claude reviewer model pinned into the launch envelope",
48
48
  )
49
+ arm.add_argument(
50
+ "--codex-review-profile", choices=("native-v1",), default=None,
51
+ help="select only after qualifying the actual registered native V1 UUID interface",
52
+ )
49
53
  verify = sub.add_parser("verify")
50
54
  verify.add_argument("--root", required=True)
51
55
  verify.add_argument("--request-id", required=True)
@@ -68,10 +72,17 @@ def main(argv=None) -> int:
68
72
  raise _artifactauthoritylib.AuthorityError(
69
73
  "UNSUPPORTED_HOST_SEAM", f"host {host} has no verification or review authority"
70
74
  )
75
+ if (host == "codex" and args.activity in _artifactauthoritylib.REVIEW_ACTIVITIES
76
+ and args.codex_review_profile is None):
77
+ raise _artifactauthoritylib.AuthorityError(
78
+ "UNSUPPORTED_HOST_SEAM",
79
+ "Codex review requires explicit --codex-review-profile native-v1 after live interface qualification",
80
+ )
71
81
  result = _artifactauthoritylib.arm_request(
72
82
  root, client, args.artifact_id, args.record_id, args.activity,
73
83
  workspace_roots=workspaces or None, host=host,
74
84
  reviewer_model=args.reviewer_model,
85
+ codex_review_profile=args.codex_review_profile,
75
86
  )
76
87
  if host == "claude" and args.activity == "verification":
77
88
  # The Claude verifier hook pins this exact shipped script and
@@ -313,7 +313,7 @@ class Host:
313
313
 
314
314
  name = "claude"
315
315
  adapter_name = "ca"
316
- adapter_version = "2.22.1"
316
+ adapter_version = "2.22.3"
317
317
 
318
318
  # Update-notifier descriptor. Each independently versioned host overrides
319
319
  # these three values in its per-plugin _host.py. Keeping the target,
@@ -278,7 +278,13 @@ separate and cannot be relabelled as qualified launch evidence.
278
278
 
279
279
  For `spec_review` or `quality_review`, arm the corresponding activity without
280
280
  workspace mappings and dispatch the returned `launch_envelope` unchanged to one
281
- fresh host subagent. The host hooks bind the exact launch call, child start and
281
+ fresh host subagent. The bounded prompt names the retained, content-addressed
282
+ evidence context instead of embedding its full input manifest. The reviewer
283
+ must read that context and inspect its subject, coverage and source inputs.
284
+ The adapter verifies the context's canonical bytes and digest before launch and
285
+ publication; a missing or changed context blocks authority. Never shorten or
286
+ rewrite the returned envelope yourself.
287
+ The host hooks bind the exact launch call, child start and
282
288
  the child's first stop; a pasted or coordinator-authored decision is not review
283
289
  authority.
284
290
  Publish the completed request through the same `publish` command. `task-review`
@@ -287,6 +293,19 @@ the scope reaches `REVIEW`, reverify against one current source snapshot, run th
287
293
  combined quality review, and use `accept-scope` once. Do not accept tasks
288
294
  individually.
289
295
 
296
+ An ARMED review that never launched can be abandoned through the adapter:
297
+
298
+ ```sh
299
+ python "<plugin-root>/hooks/artifact-authority.py" recover --root "<project-root>" --request-id <request-id> --disposition abandoned
300
+ ```
301
+
302
+ The adapter requires no attempt, launch, observation, receipt or prior recovery.
303
+ It retains the request and its evidence, creates no receipt, and prohibits
304
+ dispatching that request again. This also covers bounded legacy requests whose
305
+ inline manifests made them too large for normal dispatch. Launched or captured
306
+ requests remain subject to their existing recovery rules. Arm a new request
307
+ only after the retained request is terminal.
308
+
290
309
  An interrupted or `BLOCKED` HTML task never resumes by editing its status. Arm
291
310
  the installed reconciliation adapter for the exact task or scope, present its
292
311
  returned `short_reply` (`reconcile <STATE> <code>` for a task, `reconcile <code>`
@@ -14,3 +14,34 @@ contain the compatibility metadata. ca retains these routes through every 2.x re
14
14
  before a separately approved 3.0.0. ca-codex and ca-pi retain them through every later 0.x release,
15
15
  with no removal before a separately approved 1.0.0. Passing a version floor never authorizes removal:
16
16
  removal needs a new governed decision and fresh compatibility evidence.
17
+ ## Explicitly retired capability: skill authoring
18
+
19
+ The maintainer explicitly approved removal of `new-skill` and `skill-author` on
20
+ 2026-09-25 in PR #854. This one named exception supersedes the earlier
21
+ retain-every-route requirement for that workflow only. Its command, owning skill,
22
+ template and generated host entries are removed, not deprecated aliases. No
23
+ `extend skill` replacement or hidden callable routine is installed.
24
+
25
+ Requests to author or change repository resources use the applicable existing
26
+ change workflow and its authorization, verification and commit requirements.
27
+ CodeArbiter maintainers can read the format conventions in the source repository's
28
+ `core/surface/README.md`; that document is not an installed workflow.
29
+
30
+ This is an intentional command-compatibility break, not a claim that older
31
+ invocations continue to resolve. Existing installed older releases are unchanged.
32
+ The five other compatibility aliases and their publication clocks remain intact;
33
+ this retirement is not permission to remove any other entry.
34
+
35
+ ## Reviewed single-owner entries
36
+
37
+ PR #854 composes `tribunal`, `threat-model`, `context-check`, `cleanup`, and `pr`
38
+ from their existing skill owners. These operations are retained, not retired or
39
+ renamed. Their explicit argument grammars, mode markers, compatibility clocks and
40
+ host availability remain unchanged. `status drift` and `pr --cleanup` reach the
41
+ same owners directly; PR watch mode retains its existing watcher resource.
42
+
43
+ The wrapper text is no longer an independent policy source. Drift and cleanup
44
+ retain their full operational body, and PR retains current acceptance/ancestry
45
+ preflight plus one shared opening procedure. Tests keep historical wrapper
46
+ fingerprints while checking these named migrations against the owning contracts.
47
+ This permission does not authorize an unrelated route removal or gate change.
@@ -35,8 +35,14 @@ the same hard gates; **only the cheap HTTP-chat worker ships today** — premium
35
35
  model) and agentic (a worker that reads files and iterates) are what the seam is designed for, roadmap
36
36
  not built. Cost arbitrage is one worker policy, not the definition.
37
37
 
38
- The worker prompt is enriched with the failing-test source and current in-scope file contents, byte-capped
39
- (`FARM_ENRICH_MAX_BYTES`) and secret-redacted before transmission to the endpoint.
38
+ The worker prompt includes the failing-test source, current in-scope files, and available prior output.
39
+ `FARM_ENRICH_MAX_BYTES` limits their rendered UTF-8 enrichment, including section text, file labels,
40
+ separators, and any truncation notice. Complete source is redacted before truncation; a cut never splits
41
+ an encoded code point. Current source takes priority over prior output. When a file does not fit, its
42
+ body is shortened and later files are omitted. A label that cannot fit is omitted rather than split.
43
+ Small limits use a compact notice; limits too small for that notice omit enrichment entirely.
44
+ This is not a cap on task instructions, failure details, the full JSON request, model tokens, or local
45
+ file-read memory. No additional model request or user checkpoint is made solely because context was cut.
40
46
 
41
47
  **Swapping the worker changes who writes the code, never whether it's reviewed.** Every task the farm
42
48
  reports green is still routed through the normal spec-compliance, quality, and fresh-verification
@@ -47,18 +53,84 @@ capable of the slice).
47
53
 
48
54
  ### Zero-token quality guards
49
55
 
50
- 1. **Literal-leak** — rejects an impl that simply hard-codes the literal value the test asserts
51
- (`return 42` for `expect(f()).toBe(42)`).
56
+ 1. **Literal-leak** — flags repeated whole, same-kind string or numeric spellings in a small
57
+ implementation (`return 42` for `expect(f()).toBe(42)`). A number inside an identifier, a larger
58
+ number/string, or a conventional source comment is not a match. String `"42"` and number `42`
59
+ are distinct. The existing five-code-line boundary determines rejection versus warning; a
60
+ rejection names the actual small-file match, not an earlier substantial-file match.
52
61
  2. **Mutation** — after the gate is green, mutates the worker's in-scope impl (operator flips, return
53
62
  replacement, boolean inversion) and re-runs **only the task's narrow test** (`gate.commands[0]`). A
54
- surviving mutant is code the test does not constrain — gaming, dead code, or a weak test. The score
55
- is **bounded by test strength**: a low score is a strong red flag, a high score is necessary but not
56
- sufficient (Phases 3–5 remain the real quality gate). A low score attaches a **warning that rides
57
- into Phase 3** for Claude to judge (worker gaming vs. weak test); only a near-zero score on a
58
- non-trivial impl hard-escalates. Sampled and time-boxed so it never balloons wall-clock. Set
63
+ surviving mutant is an implementation change the test command did not reject. It can indicate
64
+ weak tests, dead code or an equivalent change; it does not by itself prove gaming. Bare nonzero
65
+ exits do not establish valid, assertion-killed mutants. Built-in positive rejection ratios remain
66
+ unverified bounds, not measured scores; see the accounting rule below. Any completed nonzero
67
+ built-in rerun leaves the measurement unavailable, whatever its ratio. It attaches a
68
+ **warning that rides into Phase 3** for independent review unless the existing near-zero bound
69
+ with sufficient evaluated evidence rejects the candidate. `FARM_MUTATION_WARN_BELOW` applies
70
+ only to measured scores from a successful external hook or a built-in all-pass zero result;
71
+ it cannot suppress an unavailable-measurement warning. Screening is sampled and time-boxed. Set
59
72
  `FARM_MUTATION_CMD` to swap the built-in text mutator for a real per-language framework (Stryker,
60
73
  mutmut, …); it runs in the worktree with `FARM_MUTATION_FILES` / `FARM_MUTATION_TEST_PATH` /
61
- `FARM_MUTATION_TEST_CMD` set and must print a trailing JSON line with a numeric `score`.
74
+ `FARM_MUTATION_TEST_CMD` set. A measured hook score requires successful completion (exit 0,
75
+ no timeout, verified timeout cleanup when needed) and a trailing stdout JSON report with a finite
76
+ `score` in `[0, 1]`. A wrapper around a percentage-based framework must normalize its measurement;
77
+ stderr diagnostics are not the score channel. Optional counts and survivors remain absent unless
78
+ the hook actually reports them.
79
+
80
+ The literal check is a bounded lexical heuristic, not an assertion parser or proof of intent. It
81
+ ignores conventional slash comments in recognized C-family source suffixes and hash comments in
82
+ Python; other suffixes do not acquire a guessed comment grammar. Plain quote delimiters and numeric
83
+ spellings are compared without evaluating escapes or constant expressions. Dynamic templates are not
84
+ constant-string evidence; only unambiguous expression-start regex forms are skipped. Language-specific
85
+ prefixes, JSX and other ambiguous grammar are not fully interpreted. Test labels, inputs and legitimate
86
+ shared constants can still match. Normal independent review remains authoritative; an absent lexical
87
+ match neither skips the mutation check nor accepts the work.
88
+
89
+ A configured hook that fails, times out, or reports invalid output supplies diagnostics, not a
90
+ measured `mutationScore`. Ordinary unavailable measurements retain the existing warning policy and
91
+ continue through normal independent review; this does not add a user checkpoint. Do not hide adverse
92
+ evidence: a failed hook's parseable stdout report at or below the existing near-zero floor, with at
93
+ least five explicitly reported evaluated mutants, still rejects that candidate pending successful
94
+ remeasurement. It is not published as a valid score. No evaluated count is invented from absence or a
95
+ survivor list. A retained alternative can qualify under the same rules before another model round.
96
+
97
+ If timeout cleanup cannot establish that the mutation process tree stopped, qualification is fatal
98
+ for that task: no further candidate, retry, commit or integration may run against a possibly live
99
+ writer. Existing task reporting retains known spend and cleanup diagnostics. Neither an adverse
100
+ report nor failed process containment can be converted into acceptance by scoring prose.
101
+
102
+ The built-in text mutator bounds each test launch by the remaining mutation budget and any shorter
103
+ configured gate timeout. Zero mutation budget launches no tests; disabling the general gate timeout
104
+ does not disable this budget. Mutant writes count against the trial budget. Verified process teardown
105
+ and defensive restoration can take additional time and must finish or refuse safely before work
106
+ advances. An interrupted trial is not a killed mutant: stop screening, restore the worker's output,
107
+ and return diagnostics without a measured score. Completed observations before the interruption stay
108
+ explicitly unverified; the existing near-zero/five-completed-reruns floor still rejects an adverse
109
+ candidate. A clean timeout otherwise warns through independent review, without another default
110
+ user checkpoint. Unverified process cleanup retains the fatal containment boundary above.
111
+
112
+ A completed nonzero rerun is an **unclassified gate rejection**, not a proved mutant kill. The
113
+ built-in runner cannot distinguish a compiler, loader, infrastructure or assertion failure from an
114
+ arbitrary command's exit status. Diagnostic wording and printed score-like JSON do not grant that
115
+ classification. Preserve a bounded, redacted first-rejection witness and completed/pass counts;
116
+ do not publish a positive `mutationScore` from these exits. For real language-specific measurements,
117
+ use the existing explicitly configured external framework hook rather than another public command.
118
+
119
+ For at least three completed reruns, retain `R / (S + R)` as an **unverified gate-rejection upper
120
+ bound**, where `R` is completed nonzero reruns and `S` is successful reruns. Treating every rejected
121
+ trial as a valid kill is the most favorable interpretation of those observations; excluding invalid
122
+ rejections cannot increase that fraction. This is not a language-aware mutation score and does not
123
+ classify equivalent or unexercised changes. Preserve the existing near-zero/five-completed-reruns
124
+ rejection floor even on this bound: uncertainty cannot erase an already adverse result. Otherwise
125
+ retain the ordinary warning and independent review, without spending another model round or adding a
126
+ user checkpoint solely because the measurement is unavailable.
127
+
128
+ With no rejected or interrupted trial, at least three successful reruns still produce the existing
129
+ zero screening score and survivor list. A shorter all-pass run stays too thin to score; a short
130
+ nonzero run reports its diagnostic without inventing a usable evaluated count. A budget ending
131
+ between trials follows these same rules; interruption never publishes a partial measured score.
132
+ Language-aware validity and semantic interpretation of literal overlap remain separate work. None
133
+ of these screening outcomes is task or scope acceptance proof.
62
134
 
63
135
  Note: `writing-plans --farm` MUST place the task's narrow behavioral test first in `gate.commands` —
64
136
  the mutation guard runs `gate.commands[0]` as the per-mutant test (running an exhaustive suite per mutant
@@ -66,22 +138,56 @@ would be too slow).
66
138
 
67
139
  ### Best-of-N sampling and iterative retries
68
140
 
69
- By default the farm draws one worker completion per task attempt (`FARM_SAMPLES=1` — unchanged
70
- behavior). Because the gate is a deterministic pass/fail oracle and each task runs in an isolated
71
- worktree, you can instead draw **N candidates in parallel** and accept the first that passes the gate:
72
- set `FARM_SAMPLES=N`. Each sample runs in its own scratch worktree cut from the integration HEAD; the
73
- winner's files are taken into the task worktree and merged, the losers discarded. Total in-flight
74
- worker calls never exceed `FARM_CONCURRENCY` — sampling **shares** that budget, it does not multiply
75
- it. The cost is up to N× worker tokens (the cheap axis) for a higher first-time-go rate;
76
- `farm-report.json` records both the summed sample-token spend (`promptTokens`/`completionTokens`) and
77
- the accepted candidate's own tokens (`acceptedPromptTokens`/`acceptedCompletionTokens`) so the
78
- trade-off is visible. With `FARM_SAMPLES>1` the worker temperature is auto-bumped off 0 (to 0.7) so the
79
- samples actually diversify; set `FARM_TEMPERATURE` to control it.
80
-
81
- On a **retry** — a failed gate, or a sampling round with no green — the worker is shown its own previous
82
- in-scope output, not just the gate-failure tail, so it refines rather than restarts blind. That prior
83
- output rides the same byte-cap (`FARM_ENRICH_MAX_BYTES`) and secret-redaction chokepoint as all other
84
- injected context; out-of-scope drift is never carried forward.
141
+ By default the farm draws one worker completion per task attempt (`FARM_SAMPLES=1`). With
142
+ `FARM_SAMPLES=N`, it draws **N candidates** in isolated scratch worktrees from the task's frozen
143
+ baseline. Total in-flight worker calls share `FARM_CONCURRENCY`; sampling does not multiply that cap.
144
+
145
+ Sample gate success is only a shortlist. In deterministic sample-index order, each shortlisted
146
+ candidate is materialized into the task worktree and receives the same containment, immutable-test,
147
+ drift, task-gate, literal-risk and mutation checks as the single-worker path. Alternatives remain
148
+ available until one passes those checks. A gate or high-risk rejection tries the next existing
149
+ candidate before spending another model round. An integrity failure or an unusable reset/setup
150
+ stops that task rather than disguising the failure with an unrelated passing candidate.
151
+
152
+ Between candidates, tracked and non-ignored worker changes are reset to the task baseline and the
153
+ existing setup phases are reapplied. Ignored dependency caches retain their existing policy. Cleanup
154
+ is attempted for every sample, including exception paths; unresolved cleanup is reported. The same
155
+ selection applies to detached canary work, which still stops before commit or merge.
156
+
157
+ `farm-report.json` records summed known sample usage (`promptTokens`/`completionTokens`) separately from
158
+ the selected candidate's own tokens (`acceptedPromptTokens`/`acceptedCompletionTokens`). Qualification
159
+ makes no additional model requests, but can run local gates and mutation checks for multiple
160
+ candidates. It is not comparative quality ranking or a measured savings claim. Normal independent
161
+ reviews and acceptance still follow. With `FARM_SAMPLES>1` and no explicit temperature, sampling
162
+ defaults to `0.7`; `FARM_TEMPERATURE` remains the operator override. An explicit
163
+ `FARM_TEMPERATURE=0` is respected even with multiple samples and disables this automatic
164
+ bump. Leave the override unset or choose a supported nonzero temperature when seeking
165
+ more varied candidates; a temperature setting is not a guarantee of distinct outputs.
166
+
167
+ On a **retry**, available output reported written by the selected previous candidate is retained only
168
+ where it intersects implementation scope. Untouched baseline files remain current-source context, not
169
+ previous work. Partial output and file evidence can survive rejection or a later qualification exception;
170
+ sibling candidates are not mixed. Prior output uses the same byte cap and redaction as other context.
171
+ Labels say **not accepted**, not that a test necessarily failed. Actual failure details distinguish a
172
+ worker response, qualification, transport, or integration problem so valid work need not be rewritten
173
+ blindly. Retained context grants no acceptance, new retry allowance, or permission.
174
+ If the retry cannot reset its worktree, the task escalates without another model call.
175
+ Its report retains the completed attempts' known token usage, last output/risk evidence,
176
+ and any unresolved sample cleanup outcomes; a failed reset cannot erase them.
177
+
178
+ A decoded provider response can contain reported usage even when its output is
179
+ rejected. The worker preserves valid counters through malformed message content,
180
+ read-only or escaping paths, and guarded-write refusals, including any already
181
+ written file list. A malformed non-text response becomes an ordinary worker
182
+ failure under the existing retry/selection policy, not an unhandled parser error.
183
+ Counters must be explicitly reported nonnegative safe integers; validate prompt
184
+ and completion independently. Explicit zero is valid; missing, invalid or
185
+ undecodable counts stay absent at the worker boundary. The existing report sums
186
+ known counts, so its total is not proof of complete usage or verified billing.
187
+ No extra provider request is made to recover a missing counter. HTTP failures,
188
+ transport retries without usable usage and provider pricing remain outside this
189
+ accounting correction. Output rejection still enforces the original write,
190
+ test, gate and independent-review requirements.
85
191
 
86
192
  ## Required
87
193
 
@@ -110,8 +216,16 @@ picks a model by *measurement*, not hearsay:
110
216
  an acceptable canary pass-rate. Otherwise re-select.
111
217
  2. **Discovery** — websearch the current free Zen roster to enumerate candidate ids (codenames included).
112
218
  This finds *candidates*; it does not judge quality.
113
- 3. **Canary** — `farm.js --canary` runs the plan's smallest task against each candidate and ranks them by
114
- measured pass-rate / attempts / latency (`FARM_CANDIDATE_MODELS` carries the list). The top passer wins.
219
+ 3. **Canary** — `farm.js --canary` runs the plan's smallest no-dependency task against each candidate
220
+ and ranks that task's gate result / attempts / latency (`FARM_CANDIDATE_MODELS` carries the list).
221
+ It freezes the configured base commit before probing, uses separate detached scratch worktrees
222
+ for each model and sample, and records `baseCommit` in `.farm/canary-report.json`. Candidate
223
+ selection overrides `task.model` for the trial only; normal dispatch keeps its task override.
224
+ Worker containment, immutable tests, drift and verification checks still apply. Evaluation stops
225
+ before staging, committing or merging: it does not reset or advance an existing integration
226
+ branch. Existing task branches and worktrees are not its scratch. The top passer wins only after
227
+ verified cleanup; retained scratch is reported and exits nonzero without recursively erasing it.
228
+ A single task's result is not a general model pass-rate or promotion qualification.
115
229
  4. **Surface** — the choice is presented with its measured basis (and a one-line websearched identity note
116
230
  for the audit log), then written to `plan.meta.model` + `.farm/model-cache.json`.
117
231
  5. **Fallback ladder** — if the canary can't run or none pass: cached model → unmeasured websearch pick
@@ -125,21 +239,21 @@ picks a model by *measurement*, not hearsay:
125
239
  | `FARM_API_BASE_URL` | `https://opencode.ai/zen/v1` | Endpoint URL (env → plan.json → this default). |
126
240
  | `FARM_CANDIDATE_MODELS` | _(unset)_ | Comma-separated ids for `--canary` probing. Set by the dispatch skill. |
127
241
  | `FARM_CONCURRENCY` | `4` | Max concurrent task workers — and the shared ceiling on TOTAL in-flight worker calls, including best-of-N samples. |
128
- | `FARM_SAMPLES` | `1` | Best-of-N: candidates drawn per task attempt; first to pass the gate wins. `1` = today's single-candidate path. N>1 trades up to N× worker tokens for higher first-time-go; shares the `FARM_CONCURRENCY` budget (never N× it). |
129
- | `FARM_TEMPERATURE` | `0` | Sampling temperature sent to the worker. Auto-bumped to `0.7` when `FARM_SAMPLES>1` and left at `0` (so samples diversify); set explicitly to override. |
242
+ | `FARM_SAMPLES` | `1` | Best-of-N: candidates drawn per attempt; first in index order to pass task-worktree gates and risk qualification is selected. `1` keeps the single-worker path. Shares `FARM_CONCURRENCY`; known reported usage from all candidates is summed. |
243
+ | `FARM_TEMPERATURE` | `0` (one sample); `0.7` (multiple, unset) | Sampling temperature sent to the worker. Defaults to `0` when `FARM_SAMPLES=1` and `0.7` when `FARM_SAMPLES>1`. Any explicit value, including `0`, overrides the automatic default. |
130
244
  | `FARM_MAX_TOKENS` | _(unset)_ | Max completion tokens per worker call. `0`/unset = provider default (today's unbounded behavior). |
131
245
  | `FARM_MAX_RETRIES` | `2` | Max gate retries per task before escalating. |
132
246
  | `FARM_BASE_BRANCH` | `main` | Branch the integration branch is cut from. |
133
- | `FARM_REQUEST_TIMEOUT_MS` | `120000` | Per-request hard timeout (prevents worker-slot deadlock). |
134
- | `FARM_API_MAX_RETRIES` | `3` | Transport retries for 429/5xx (honors `Retry-After`). |
247
+ | `FARM_REQUEST_TIMEOUT_MS` | `120000` | Per-request hard timeout. A valid provider `Retry-After` longer than this is not shortened; the task is deferred without another authoring attempt. |
248
+ | `FARM_API_MAX_RETRIES` | `3` | Transport retries for 429/5xx. Bounded `Retry-After` is honored; exhaustion defers new authoring for that task. |
135
249
  | `FARM_ENTITLEMENT_PROBE_TIMEOUT_MS` | `35000` | Per-candidate wall-clock cap for the `--canary` entitlement pre-screen (drops 401 promo-expired models). |
136
- | `FARM_ENRICH_MAX_BYTES` | `131072` | Cap on bytes of test-source + in-scope file context injected into the worker prompt (data-minimization; redacted for secrets). |
250
+ | `FARM_ENRICH_MAX_BYTES` | `131072` | UTF-8 cap on rendered current/prior file context, labels, separators and notices; not the complete prompt or request. |
137
251
  | `FARM_ABORT_ESCALATION_RATE` | `0.5` | Circuit breaker: abort once escalations exceed this fraction… |
138
252
  | `FARM_ABORT_MIN_TASKS` | `3` | …after at least this many tasks have settled. |
139
253
  | `FARM_MUTATION` | `on` | Mutation guard on/off. |
140
254
  | `FARM_MUTATION_SAMPLE` | `15` | Max mutants per task (sampled). |
141
255
  | `FARM_MUTATION_BUDGET_MS` | `30000` | Per-task mutation time box. |
142
- | `FARM_MUTATION_WARN_BELOW` | `0.5` | Score below this attaches a warning into Phase 3. |
256
+ | `FARM_MUTATION_WARN_BELOW` | `0.5` | Measured scores below this warn in Phase 3 unless the rejection floor applies. Unavailable or unverified measurements warn independently of this threshold. |
143
257
  | `FARM_MUTATION_ESCALATE_BELOW` | `0.1` | Score at/below this (≥5 mutants) hard-escalates. |
144
258
  | `FARM_MUTATION_CMD` | _(unset)_ | Pluggable external mutation framework hook. |
145
259
  | `FARM_RUN_ID` | _(random)_ | Pin this run's id — also the name of its artifact directory (`.farm/runs/<run-id>/`). Must be 1–64 chars of `[A-Za-z0-9._-]`; anything else is refused at startup. Reusing an id publishes over that directory's receipts, so pin a fresh one per run. |
@@ -217,7 +331,7 @@ Every run owns an artifact directory keyed by its run id — `<project-root>/.fa
217
331
  that directory is the **durable receipt**, written by that run alone. Two farm processes against one
218
332
  repository therefore cannot overwrite each other's *evidence* (see the concurrency caveat below — the
219
333
  receipts are isolated, the git state is not):
220
- - `farm-report.json` — structured results: per-task status, attempts, files written, worker token spend,
334
+ - `farm-report.json` — structured results: per-task status, attempts, files written, known reported worker usage,
221
335
  warnings (gaming-risk), and an `aborted` flag; plus a `blocked[]` array with reasons, and an
222
336
  `artifacts` block stating whether the streaming rail was complete and which tasks' diff evidence is
223
337
  unavailable.
@@ -230,7 +344,8 @@ own artifacts: `.farm/farm-report.json`, `.farm/farm-report.md`, `.farm/farm-res
230
344
  `.farm/diffs/<task-id>.patch`. Under concurrency the pointer is last-writer-wins — always a complete
231
345
  artifact, never a truncated one, but attributable only via its `run_id`. Reconcile against the run
232
346
  directory when it matters. Also in `.farm/`:
233
- - `canary-report.json` — model-probe ranking (when `--canary` was run).
347
+ - `canary-report.json` — model-probe ranking, frozen `baseCommit`, and any cleanup failures
348
+ (when `--canary` was run). This is evaluation evidence, not task acceptance or integration proof.
234
349
  - `model-cache.json` — last selected model + timestamp + canary pass-rate.
235
350
 
236
351
  Every report write is atomic (same-directory temp file, then rename), so a reader of a report path sees
@@ -258,3 +373,39 @@ To run two farms against one repository at the same time, give each process:
258
373
  Escalated tasks leave their worktrees at `.farm/worktrees/<task-id>/` for inspection.
259
374
 
260
375
  Canary ranking: `FARM_CANDIDATE_MODELS=a,b,c farm.js --canary <plan.json>` (cwd at the project root).
376
+
377
+ ### Transport retry boundaries
378
+
379
+ A 429 or server failure retries the HTTP request within `FARM_API_MAX_RETRIES`, not a fresh
380
+ implementation. Recognized `Retry-After` delay-seconds and HTTP-date values are honored only when
381
+ the wait fits the existing `FARM_REQUEST_TIMEOUT_MS` budget and the runtime timer range. An excessive
382
+ valid cooldown is not shortened or allowed to park a worker indefinitely. Missing or malformed fields
383
+ use the existing exponential backoff capped at 16 seconds; explicit zero or a past valid date permits
384
+ an immediate retry. Request deadlines still cover headers and successful body reads; between-request
385
+ waits are separate. Discarded error streams are aborted before waiting or returning.
386
+
387
+ Once that HTTP retry budget is exhausted, or a valid cooldown cannot fit locally, the worker returns
388
+ an explicit non-retryable transport disposition. The task does not spend another authoring attempt
389
+ against the same unavailable provider. Already-produced candidates may still qualify, independently
390
+ eligible tasks can continue under the existing circuit breaker, and dependent work remains unaccepted.
391
+ This is a reported task deferral, not a new user-approval gate or automatic delayed-resume service.
392
+ Network/body failures and ordinary implementation failures otherwise retain their existing retry
393
+ policy. This does not introduce a provider-wide cooldown coordinator, a new setting, or a spend claim.
394
+
395
+ ### Merge-conflict recovery
396
+
397
+ A failed integration merge uses the existing task retry budget, not a new interview.
398
+ The dispatcher verifies merge rollback and clean tracked integration state, pins that
399
+ integration commit, and checks task reset, cleanup and HEAD before the next author.
400
+ It keeps the prior qualified implementation as labeled feedback instead of presenting
401
+ replacement baseline files as the worker's previous output. A protected test brought
402
+ in by the verified integration commit becomes the next attempt's immutable baseline;
403
+ setup and worker edits to that test still fail the same checks. Retained samples use
404
+ this path too. Ignored setup caches keep their existing fingerprint contract.
405
+
406
+ The same explicit-path staging operation gets up to three attempts, with 150 ms
407
+ and 300 ms waits after refusal. This repeats no worker or commit and never removes
408
+ another process's index lock. Persistent staging refusal, unverified rollback/reset
409
+ or an unreadable replacement test cannot be repaired by another model call. The task retains its actual
410
+ attempt, written-file and known-usage evidence, without commit or acceptance bypass.
411
+ This does not add process resume, a provider fallback or a new approval checkpoint.
@@ -11,29 +11,69 @@ The single source of truth for the coverage threshold. Coverage scales with the
11
11
  | 3 | ≥ 85% |
12
12
  | 4 | ≥ 90% |
13
13
 
14
- ## Which metric (issue #507)
15
-
16
- **Lines and branches. Both must clear the threshold.** A report satisfying one and not the other
17
- does not pass.
18
-
19
- This was previously unstated, and the omission was load-bearing rather than cosmetic: a coverage
20
- report gives four numbers that disagree, so "≥ 70%" without a column named is not a threshold anyone
21
- can be held to. Measured on codeArbiter itself at the time of writing, one tree sat at 85.37% lines
22
- and 78.73% branches — compliant at maturity 3, or not, depending purely on which column the reader
23
- picked.
24
-
25
- - **Lines** catches code no test reaches at all — a `catch` block with zero executions inside a
26
- passing suite, which no assertion is ever going to surface.
27
- - **Branches** catches the untaken half of a condition a test does reach: the error arm of an `if`,
28
- the fallback of a `??`. Line coverage alone reports those as covered.
29
- - **Statements** duplicates lines closely enough to add nothing. **Functions** is the noisiest
30
- column at small counts, where one uncovered helper moves it several points.
14
+ ## Which metric: declared coverage profile
15
+
16
+ **Every required metric in the surface's declared coverage profile must clear the
17
+ maturity threshold.** `tech-stack.md` binds each source tree to one supported
18
+ profile and names its tool, command, production scope, exclusions and supported
19
+ hosts. This declaration selects a language-appropriate measurement; it does not
20
+ change the threshold table.
21
+
22
+ | profile | applicable surface | required metrics |
23
+ |---|---|---|
24
+ | `lines-branches` | JavaScript/TypeScript and existing surfaces with qualified line and branch tooling | lines, branches |
25
+ | `go-native` | Go measured with the native Go coverage toolchain | statements |
26
+
27
+ Existing documented line-and-branch requirements already declare
28
+ `lines-branches`, even without that label. Preserve them without another approval
29
+ or a metadata migration; adding the label during normal maintenance changes no
30
+ measurement requirement.
31
+
32
+ The `lines-branches` profile retains issue #507's rule: both metrics must pass.
33
+ For example, 85.37% lines and 78.73% branches fails maturity 3. A high line figure
34
+ does not establish that error and fallback outcomes have been exercised.
35
+
36
+ The `go-native` profile uses `go test -cover` and, for executable surfaces,
37
+ instrumented `go build -cover` integration runs. Include all production packages
38
+ in scope, including those reached through other packages' tests. Native Go
39
+ reports statements, not lines or branches; label those other metrics
40
+ **unmeasured**, never zero, inferred, or passed. A partial branch analyzer may
41
+ provide diagnostic findings but does not turn statement counts into branch
42
+ proof. Go native coverage is not the no-tooling exemption.
43
+
44
+ Existing stronger measurement contracts remain binding until explicit user
45
+ approval changes them. An agent MUST NOT switch profiles, remove required
46
+ metrics, narrow production scope or exclude source to obtain a pass. Adding a
47
+ profile or changing a surface's binding requires an explicit user approval of
48
+ the concrete change, recorded with its rationale. A missing declaration or an
49
+ unknown profile blocks; another language cannot silently borrow `go-native`.
50
+
51
+ Missing, malformed, stale, partial or mismatched reports block the overall
52
+ coverage verdict. Bind the reports to the tested source and declared tools,
53
+ scope and hosts. A scoped local result may be reported as PARTIAL under
54
+ `<plugin-root>/includes/verification-boundary.md`; the complete exact-head
55
+ hosted result must pass before merge. Never average host percentages, discard
56
+ an uncovered host-specific file, or relabel a metric to fill a missing column.
31
57
 
32
58
  **The number is the floor, not the goal.** A test written only to move a percentage is worse than
33
59
  the gap it closed, because it converts an honest red into a green that asserts nothing. When
34
60
  backfilling to clear this bar, work the uncovered *report* — error and refusal paths first — and let
35
61
  the number follow.
36
62
 
63
+ ## Behavioral evidence beyond percentages
64
+
65
+ Every profile also requires tests for the changed behavior. For changed critical
66
+ paths, cover approval and rejection, malformed or stale inputs, filesystem
67
+ containment, and recovery where applicable. Each test must exercise the actual
68
+ boundary and assert the expected outcome; merely reaching a line or avoiding an
69
+ exception is insufficient. Use focused mutation checks for critical safeguards:
70
+ removing or inverting the safeguard must make the relevant test fail.
71
+
72
+ Missing critical-path evidence blocks even when the numeric floor passes. Scope
73
+ this proof to the affected obligations and their callers; do not demand unrelated
74
+ test expansion merely because a different language uses different metrics. These
75
+ tests establish the named outcomes, not an unmeasured global branch percentage.
76
+
37
77
  ## Which host (issue #521)
38
78
 
39
79
  **A quoted coverage figure is the UNION of the supported hosts' reports for that tree.** Not any
@@ -26,10 +26,10 @@ reached the same way.
26
26
  | Bug fix | `/fix` → `tdd` (bug variant) | impl author | Failing regression test before any fix code |
27
27
  | Docs edit / dep bump / revert | `/chore` (type-scaled gates) | `dependency-reviewer` for deps | No behavioral code; suite green for deps/revert; exits via `commit-gate` |
28
28
  | Exploratory throwaway spike | `/spike` (self-contained command) → `spike/<slug>` branch | — | Never merges or PRs; `commit-gate`-exempt (nothing on the branch can land); exits to a findings note or `/feature` |
29
- | Behavior-preserving restructure | `/refactor` → `refactor` skill | `tdd` Phase 1 (new seams only) | No refactor without parity-coverage proof |
30
- | Unknown defect / investigation | `/debug` → `debug` skill | — | No code change in the skill; one named exit |
31
- | Commit | `/commit` → `commit-gate` | — | No commit without all nine gates green |
32
- | Open a PR / finish a branch | `/pr` → `finishing-a-development-branch` | reviewer fleet per path; PR-body prose applies `anti-slop-design` (`core` + `medium-documents` §7.A.1) | PR only; no direct-to-default, no force-push |
29
+ | Behavior-preserving restructure | `refactor` skill at `<plugin-root>/routines/refactor/SKILL.md` (explicit `/refactor` uses the same owner) | `tdd` Phase 1 (coverage backfill or new seams) | No refactor without parity-coverage proof |
30
+ | Unknown defect / investigation | `debug` skill at `<plugin-root>/routines/debug/SKILL.md` (explicit `/debug` uses the same owner) | — | No code change in the skill; one named exit |
31
+ | Commit | `commit-gate` skill at `<plugin-root>/routines/commit-gate/SKILL.md` (explicit `/commit` uses the same owner) | — | No commit without all nine gates green |
32
+ | Open a PR / finish a branch | `finishing-a-development-branch` at `<plugin-root>/routines/finishing-a-development-branch/SKILL.md`; select direct-open or caller mode first | reviewer fleet per path; PR-body prose applies `anti-slop-design` (`core` + `medium-documents` §7.A.1) | PR only; no direct-to-default, no force-push |
33
33
  | Watch a PR's CI / babysit checks | `/watch` → detached `gh pr checks --watch` | on-red diagnose (propose\|branch) | Never auto-merges; green → notify + offer; merge-to-default routes through the hard gate; no poll loop |
34
34
  | Code review of the diff | `/review` → `dispatching-parallel-agents` | reviewer fleet → `finding-triage` → `verdict-aggregator` | BLOCK on any CRITICAL/HIGH |
35
35
  | Periodic sweep | `/checkpoint` → `dispatching-parallel-agents` | reviewer fleet → finding-triage → read-only verdict; then explicit `checkpoint-aggregator` persistence | Surfaces and persists a triaged report; not a promotion gate |
@@ -41,18 +41,17 @@ reached the same way.
41
41
  | Migration file added or changed | `migration-reviewer` | — | BLOCK on missing classification or irreversible destructive op |
42
42
  | `package.json` / lockfile / base image changed | `/add-dep` → `dependency-reviewer` | — | BLOCK on denied license or supply-chain concern |
43
43
  | Run a pinned third-party tool ONCE, adopting nothing (`npx jscpd@4.0.5 .`) | `/ca-add-dep` → its *Ephemeral tool run* section (no `dependency-reviewer` dispatch) | — | Exact pinned version + approved registry + one confirmation; MUST NOT touch a manifest or lockfile, verified after the run, or it is adoption and takes the full review |
44
- | Sensitive feature / attack-surface change | `/threat-model` → `security-architecture` (optional) | `security-reviewer`, `auth-crypto-reviewer` | STOP only on a critical unmitigated threat |
45
- | Arbitration / variance / ADR reconciliation | `/reconcile` → `decision-variance` | `scout`, `grader`, `decision-challenger` | No decision recorded without user attribution |
46
- | New / aged ADR, unresolved `[CONFIRM-NN]` | `/adr`, `/adr-status` → `decision-lifecycle` | `decision-challenger` (optional) | No `[CONFIRM-NN]` resolved by guessing |
44
+ | Requested threat model of a sensitive design | `security-architecture` at `<plugin-root>/routines/security-architecture/SKILL.md` (opt-in; explicit `/threat-model` retained) | `security-reviewer`, `auth-crypto-reviewer` | STOP only on a critical unmitigated threat |
45
+ | Arbitration / variance / ADR reconciliation | `decision-variance` at `<plugin-root>/routines/decision-variance/SKILL.md` (explicit `/ca-reconcile` retained); select report-only or reconciliation first | `scout`, `grader`, `decision-challenger` (optional, read-only) | No decision recorded without explicit user choice and attribution; report-only writes nothing |
46
+ | New / aged ADR, unresolved `[CONFIRM-NN]` | `decision-lifecycle` at `<plugin-root>/routines/decision-lifecycle/SKILL.md`; select author or read-only status before prerequisites | `decision-challenger` (optional) | No `[CONFIRM-NN]` resolved by guessing |
47
47
  | Rule conflict (persona vs docs vs code) | `/conflict` | — | STOP all other work immediately |
48
48
  | Unsure `/reconcile` vs `/conflict`? | rules contradict and work cannot safely continue → `/conflict`; artifacts drifted, work continues → `/reconcile` | — | When genuinely ambiguous, `/conflict` wins — stopping is recoverable, drifting past a rule conflict is not |
49
- | New skill needed | `/new-skill` → `skill-author` | — | No skill until the gap is proven uncovered |
50
49
  | Subagent raises an out-of-scope finding | inline `[NEEDS-TRIAGE]` marker | — | Never an ADR disposition; never silently dropped |
51
50
  | Sitting down to code / repo hygiene cleanup | `/ca-standup` → orchestrator git actions | — | ff-only pull on a clean tree; branch deletions confirmed individually, worktree removals may be confirmed as one named enumerated group; stash/dirty/un-pushed report-only; never touch the default branch |
52
- | Finish an already-merged branch (post-merge cleanup) | `/ca-cleanup` → `post-merge-cleanup` | — | Merge proven against the FETCHED default by ancestry, PR-record squash proof, or a byte-identical fallback; unique/unclassifiable artifacts never discarded without a per-item confirmation; `--ff-only`; `branch -d`, or `-D` only under the restated squash-proof path; remote branch untouched; never routes to `/ca-override` |
51
+ | Finish an already-merged branch (post-merge cleanup) | `post-merge-cleanup` at `<plugin-root>/routines/post-merge-cleanup/SKILL.md` (explicit `/ca-cleanup` or `/ca-pr --cleanup`) | — | Merge proven against the FETCHED default by ancestry, PR-record squash proof, or a byte-identical fallback; unique/unclassifiable artifacts never discarded without a per-item confirmation; `--ff-only`; `branch -d`, or `-D` only under the restated squash-proof path; remote branch untouched; never routes to `/ca-override` |
53
52
  | Add / start / done a backlog task | `/ca-task` → `hooks/taskwrite.py` (the pure `_taskboardlib` transforms) | — | Board written only through the writer; `start` always stamps a date; `done` requires in-progress; never delete to complete |
54
53
  | Local runtime work (run, watch, exercise this repo's own app) | `mode --ops` → narrows the persona per `includes/ops-mode.md`, no skill/agent dispatch | — | Advisory only, no hook becomes mode-aware; permitted only when the operation starts, observes, or exercises and leaves no change in tracked files or git history — anything that mutates tracked files, the index, git history, or published state still routes normally |
55
54
  | Promote a workflow's un-actioned follow-ups | `includes/harvest.md` (run at a terminal step) → `/ca-task` (work) / `open-questions.md` (decision) | — | Batch-confirm interactive; SMARTS-logged auto under `/sprint`; dedup by `(from <origin>)`; a blocking decision escalates, never demoted |
56
55
  | Zero-onboarding dry-run of the reviewer fleet | `/ca-preview` (no skill; reuses `includes/review-matrix.md` to predict reviewers) | — | Read-only; writes nothing, stages nothing, `git status` unchanged; no `/ca-init` or `.codearbiter/` required; empty diff exits clean |
57
- | Manual drift audit of provenance-tracked docs (bypass / merge / external edit case) | `/ca-context-check` → `context-check` skill | — | Read-only unless user selects re-scout or re-baseline; MUST NOT commit on its own; not the daily loop — commit-gate auto-heal is the routine path |
58
- | Deep on-demand codebase audit | `/ca-tribunal` → `tribunal` skill | `tribunal-lens-reviewer` per active lens (+ optional `map-structure`/`map-deps` on large repos) | Read-only until the filing gate; runs only after the user acknowledges the token estimate; never blocks a merge/commit; nothing filed or sent without explicit authorization |
56
+ | Manual drift audit of provenance-tracked docs (bypass / merge / external edit case) | `context-check` at `<plugin-root>/routines/context-check/SKILL.md` (explicit `/ca-status drift` or `/ca-context-check`) | — | Read-only unless user selects re-scout or re-baseline; MUST NOT commit on its own; not the daily loop — commit-gate auto-heal is the routine path |
57
+ | Deep on-demand codebase audit | `tribunal` at `<plugin-root>/routines/tribunal/SKILL.md` (explicit `/ca-tribunal` retained) | `tribunal-lens-reviewer` per active lens (+ optional `map-structure`/`map-deps` on large repos) | Read-only until the filing gate; runs only after the user acknowledges the token estimate; never blocks a merge/commit; nothing filed or sent without explicit authorization |