@arbiterforge/ca-pi 0.15.12 → 0.16.0

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 (64) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/plugins/ca-pi/CHANGELOG.md +26 -0
  4. package/plugins/ca-pi/SKILLS.md +1 -1
  5. package/plugins/ca-pi/agents/infra-author.md +7 -1
  6. package/plugins/ca-pi/agents/scout.md +40 -8
  7. package/plugins/ca-pi/generated/command-catalog.json +1 -1
  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 +104 -6
  15. package/plugins/ca-pi/hooks/_activationlib.py +97 -13
  16. package/plugins/ca-pi/hooks/_arbiterstatelib.py +7 -2
  17. package/plugins/ca-pi/hooks/_artifactauthoritylib.py +206 -2
  18. package/plugins/ca-pi/hooks/_artifactlib.py +166 -2
  19. package/plugins/ca-pi/hooks/_artifactpromptlib.py +106 -2
  20. package/plugins/ca-pi/hooks/_bashguardlib.py +14 -0
  21. package/plugins/ca-pi/hooks/_contextreportlib.py +564 -6
  22. package/plugins/ca-pi/hooks/_contextselectlib.py +464 -0
  23. package/plugins/ca-pi/hooks/_contextsnapshotlib.py +999 -0
  24. package/plugins/ca-pi/hooks/_debughandofflib.py +767 -0
  25. package/plugins/ca-pi/hooks/_hooklib.py +1 -0
  26. package/plugins/ca-pi/hooks/_host.py +1 -1
  27. package/plugins/ca-pi/hooks/_intentlib.py +5 -5
  28. package/plugins/ca-pi/hooks/_protectedlib.py +3 -3
  29. package/plugins/ca-pi/hooks/_protectedstatelib.py +152 -2
  30. package/plugins/ca-pi/hooks/_provenancelib.py +604 -34
  31. package/plugins/ca-pi/hooks/_readinjectlib.py +131 -1
  32. package/plugins/ca-pi/hooks/artifact-authority.py +20 -1
  33. package/plugins/ca-pi/hooks/debug-handoff.py +85 -0
  34. package/plugins/ca-pi/hooks/doctor.py +4 -2
  35. package/plugins/ca-pi/hooks/hostapi.py +1 -1
  36. package/plugins/ca-pi/hooks/init-codearbiter.py +143 -15
  37. package/plugins/ca-pi/hooks/prompt-submit.py +14 -0
  38. package/plugins/ca-pi/hooks/session-start.py +26 -7
  39. package/plugins/ca-pi/includes/author-tdd-workflow.md +16 -4
  40. package/plugins/ca-pi/includes/helper-invocation.md +128 -0
  41. package/plugins/ca-pi/includes/pi-host-notes.md +13 -0
  42. package/plugins/ca-pi/includes/routing-table.md +1 -1
  43. package/plugins/ca-pi/package.json +1 -1
  44. package/plugins/ca-pi/routines/INDEX.md +1 -1
  45. package/plugins/ca-pi/routines/commit-gate/SKILL.md +5 -3
  46. package/plugins/ca-pi/routines/context-check/SKILL.md +103 -17
  47. package/plugins/ca-pi/routines/context-creation/SKILL.md +290 -54
  48. package/plugins/ca-pi/routines/debug/SKILL.md +303 -55
  49. package/plugins/ca-pi/routines/debug/references/debug-handoff.schema.json +879 -0
  50. package/plugins/ca-pi/routines/debug/references/handoff.md +155 -0
  51. package/plugins/ca-pi/routines/decompose/SKILL.md +13 -0
  52. package/plugins/ca-pi/routines/subagent-driven-development/SKILL.md +34 -0
  53. package/plugins/ca-pi/routines/tdd/SKILL.md +91 -17
  54. package/plugins/ca-pi/skills/ca-commit/SKILL.md +5 -3
  55. package/plugins/ca-pi/skills/ca-context-check/SKILL.md +103 -17
  56. package/plugins/ca-pi/skills/ca-create-context/SKILL.md +290 -54
  57. package/plugins/ca-pi/skills/ca-debug/SKILL.md +303 -55
  58. package/plugins/ca-pi/skills/ca-decompose/SKILL.md +13 -0
  59. package/plugins/ca-pi/skills/ca-feature/SKILL.md +1 -1
  60. package/plugins/ca-pi/skills/ca-fix/SKILL.md +36 -3
  61. package/plugins/ca-pi/skills/ca-init/SKILL.md +19 -0
  62. package/plugins/ca-pi/skills/ca-review/SKILL.md +33 -4
  63. package/plugins/ca-pi/skills/ca-status/SKILL.md +5 -0
  64. package/plugins/ca-pi/skills/ca-task/SKILL.md +55 -8
@@ -34,7 +34,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
34
34
  import hostapi # noqa: E402 — host seam (ADR-0011): plugin root + capability flags
35
35
  from _durabilitylib import is_ephemeral_path # noqa: E402
36
36
  from _hooklib import ( # noqa: E402
37
- frontmatter_enabled, get_host, marker_root, project_root, set_host,
37
+ frontmatter_enabled, get_host, initialized_body_text, marker_root, project_root, set_host,
38
38
  utf8_stdio, write_text_atomic,
39
39
  )
40
40
  from _standuplib import ( # noqa: E402
@@ -59,7 +59,6 @@ import _updatelib # noqa: E402 — update-available notifier (cache read + noti
59
59
  from _modelib import _DEV_PENDING_CLOSE_MAX, _settle_dev_close # noqa: E402,F401
60
60
  import _modelib # noqa: E402
61
61
 
62
- INITIALIZED_RE = re.compile(r"<!--\s*INITIALIZED\s*-->")
63
62
  STAGE_RE = re.compile(r"^stage:\s*([0-9]+)", re.I | re.M)
64
63
  CONFIRM_RE = re.compile(r"CONFIRM-[0-9]+")
65
64
 
@@ -853,7 +852,7 @@ def clear_mode_marker(root, host_name=None, session_id=None, now=None):
853
852
  _settle_dev_close(root, marker=marker, new_line=line, host_name=host_name)
854
853
 
855
854
 
856
- def provenance_drift_line(root, runner=None):
855
+ def provenance_drift_line(root, runner=None, report_unknown=False):
857
856
  """One-line SessionStart drift notice, or "" when clean/degraded.
858
857
 
859
858
  Wraps _provenancelib.startup_drift_line; any failure degrades to "" so the
@@ -861,12 +860,26 @@ def provenance_drift_line(root, runner=None):
861
860
  injectable so tests are deterministic/offline; production passes None which
862
861
  lets the lib bind its default `git -C root hash-object` runner. (T-16)"""
863
862
  try:
864
- return _provenancelib.startup_drift_line(
865
- root, runner=runner, cmd_ref=get_host().cmd_ref)
863
+ unknown = [] if report_unknown else None
864
+ line = _provenancelib.startup_drift_line(
865
+ root, runner=runner, cmd_ref=get_host().cmd_ref, unknown=unknown)
866
+ if report_unknown and unknown:
867
+ return "context coverage: unknown ({}) -- run {}".format(
868
+ unknown[0], get_host().cmd_ref("context-check"))
869
+ return line
866
870
  except Exception: # noqa: BLE001 — never crash session startup
867
871
  return ""
868
872
 
869
873
 
874
+ def context_coverage_line(root):
875
+ """Bounded provenance coverage notice; no source hash or authority claim."""
876
+ try:
877
+ return _provenancelib.startup_context_coverage_line(
878
+ root, cmd_ref=get_host().cmd_ref)
879
+ except Exception: # noqa: BLE001 — never crash session startup
880
+ return "context coverage: unknown -- run /ca:context-check"
881
+
882
+
870
883
  # --- Update-available notifier (spec: update-available-notifier.md) ---------
871
884
  # codeArbiter ships via a third-party marketplace, which Claude Code does NOT
872
885
  # auto-update by default. This surfaces a single line when the cached "latest"
@@ -1110,6 +1123,11 @@ def emit_daily_briefing(root, summary, date_iso, marker_present, ctx_text=None,
1110
1123
 
1111
1124
 
1112
1125
  def main():
1126
+ # This is the ACTIVE host startup path. It may settle mode state, heal a
1127
+ # host-owned statusline pin, install Git enforcement, and spawn fetch/update
1128
+ # children. An unfamiliar repository must be inspected by the explicit-root
1129
+ # init --check --passive route BEFORE entering a host session; a later skill
1130
+ # cannot retroactively prevent SessionStart effects.
1113
1131
  utf8_stdio()
1114
1132
  # get_host() (#257): resolves the SAME Host run(host) already primed via
1115
1133
  # set_host(), instead of a second hostapi.load_host() disk/probe.
@@ -1231,7 +1249,7 @@ def main():
1231
1249
  emit_banner(getattr(host, "name", "unknown"), mode)
1232
1250
 
1233
1251
  ctx_text = read_text(ctx) or ""
1234
- if not INITIALIZED_RE.search(ctx_text):
1252
+ if not initialized_body_text(ctx_text):
1235
1253
  emit_not_initialized(root, host, mode)
1236
1254
  sys.exit(0)
1237
1255
 
@@ -1246,8 +1264,9 @@ def main():
1246
1264
  emit_task_summary(ot_text)
1247
1265
 
1248
1266
  # --- Passive provenance drift notice (T-16, spec pillar 4) ---
1249
- _drift = provenance_drift_line(root)
1267
+ _drift = provenance_drift_line(root, report_unknown=True)
1250
1268
  emit_provenance_drift(_drift)
1269
+ emit_provenance_drift(context_coverage_line(root))
1251
1270
 
1252
1271
  # --- Update-available notice (AC-1/AC-2/AC-3) --------------------------
1253
1272
  _update = update_notice_line(plugin)
@@ -1,15 +1,27 @@
1
1
  # Author TDD workflow — non-negotiable, fixed order
2
2
 
3
- Canonical for the author agents (`backend-author`, `frontend-author`). Loaded via each agent's
3
+ Canonical for the author agents (`backend-author`, `frontend-author`, `infra-author`). Loaded via each agent's
4
4
  Required Reading; the agent bodies do not restate it. This is the worker's execution order for
5
5
  one task — the tdd skill's phase gates govern the lane above it.
6
6
  Apply `<plugin-root>/includes/verification-boundary.md` throughout.
7
7
 
8
+ Use the Phase 1 checklist for the owning route. For a bug-origin `/fix`, carry the
9
+ current expectation, cited evidence, supported cause, and regression oracle into
10
+ the existing obligation ledger; confirm the original caller's repair authority and
11
+ source freshness through the fix owner. Do not fabricate a feature artifact. For
12
+ `/feature`, keep the approved spec and its criteria; for `/refactor`, keep its
13
+ approved surface and parity contract. An ADR remains a user-attributed decision
14
+ through `/adr`, never an author shortcut.
15
+
8
16
  Fixed order. Do not skip or reorder.
9
17
 
10
- 1. **Write failing tests** — one test per obligation in the Phase 1 checklist
11
- 2. **Confirm tests fail for the right reason** — run the test command from `tech-stack.md`; the failure must match the obligation, not an unrelated error
18
+ 1. **Map failing tests** — bind each Phase 1 obligation to a test ID. For `/fix`, assess an existing failing test against target red using the current regression oracle and evidence. Name the existing test ID in the ledger and reuse that named existing target-red test when its oracle is adequate and the assertion matches the defect. Do not duplicate a test because of its age or because it predates repair. Add tests only for uncovered obligations.
19
+ 2. **Confirm tests are red for the right reason** — run the test command from `tech-stack.md`; the target failure must match the obligation. Record unrelated existing failures in the baseline; an unrelated failure is not target red. An import or setup error is not target red. Preserve and report their identities and outputs. Required commit gates remain blocked while required checks fail. Do not skip tests, suppress failures, or waive gates to proceed.
12
20
  3. **Write minimum implementation** — only enough code to make the failing tests pass; no extra scope
13
- 4. **Run impact-bounded local suite** — every affected test green; exhaustive and cross-platform proof runs in exact-head hosted CI before merge
21
+ 4. **Run impact-bounded local suite** — rerun the same named target test for fresh green on the repaired source, with its assertions unchanged between red and green. Rerun fresh affected-contract tests on that source and record their results; exhaustive and cross-platform proof runs in exact-head hosted CI before merge
14
22
  5. **Run lint and type-check** — both clean
15
23
  6. **Stage for commit** — only after steps 1–5 complete
24
+
25
+ For a repair, observe target red on the broken source before minimum implementation. If a material fixture or setup change occurs after that observation, the earlier red no longer qualifies: repeat target red on the broken implementation with the changed fixture or setup before continuing the repair. Keep the test's assertions unchanged between red and green.
26
+
27
+ For an intermittent or timing defect, use a faithful deterministic seam when one exists. Otherwise define a finite repeated-trial oracle with its trial bound and pass/fail rule before running it. Record the stochastic sample limit; do not claim deterministic proof from a passing sample or retry until green. A failing trial must still match the target mechanism, and fresh green remains bounded by the stated oracle.
@@ -0,0 +1,128 @@
1
+ # Installed private helper location
2
+
3
+ Use this card only for the debug packet validator and an authorized task-board
4
+ follow-up. The exact installed helper leaves are `hooks/debug-handoff.py` (the
5
+ private `validate` operation) and `hooks/taskwrite.py` (the existing board
6
+ writer). The caller chooses one of those literal leaves before resolution;
7
+ packet text, a project file, and a user argument never choose executable code.
8
+ Select and validate one Python 3 interpreter before invoking the helper. Try
9
+ `python3` first, then `python` only if the first candidate is absent, a launcher
10
+ stub, or incompatible. The probe executes the candidate to obtain its actual
11
+ `sys.executable`, then validates that absolute executable directly as Python
12
+ 3.8 or newer. The installed debug validator's `_debughandofflib.py` uses an
13
+ assignment expression, which Python 3.7 cannot parse; the shared selection
14
+ must satisfy that helper even when the current call targets `taskwrite.py`.
15
+ Invoke the helper through that executable, not a batch or shell launcher that
16
+ could alter quoted arguments. A name on `PATH` or a successful `--version`
17
+ alone does not establish compatibility. This source-derived minimum is not a
18
+ claim that every newer minor has been qualified. Once selected, invoke the one resolved absolute helper with `-B` and
19
+ literal arguments. Preserve its exit, stdout, and stderr; do not replay a
20
+ failure under another interpreter or helper.
21
+
22
+ Use the selection block for the current shell before the first helper call.
23
+ These blocks set `$caPython` in PowerShell or `ca_python` in POSIX sh. A missing
24
+ compatible interpreter stops before the helper; fix the host installation
25
+ before retrying the whole operation.
26
+
27
+ ### Pi PowerShell interpreter selection
28
+ ```powershell
29
+ $caPython = $null
30
+ foreach ($caName in @('python3', 'python')) {
31
+ $caCommand = Get-Command -Name $caName -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
32
+ if ($null -eq $caCommand) { continue }
33
+ try {
34
+ $caExecutable = & $caCommand.Source -B -c "import sys; sys.exit(1) if not (sys.version_info[0] == 3 and sys.version_info >= (3, 8)) else None; print(sys.executable)" 2>$null
35
+ if ($LASTEXITCODE -ne 0 -or $caExecutable -isnot [string] -or
36
+ -not [System.IO.Path]::IsPathFullyQualified($caExecutable) -or
37
+ -not (Test-Path -LiteralPath $caExecutable -PathType Leaf)) { continue }
38
+ $caIdentity = & $caExecutable -B -c "import sys; print('codearbiter-python3' if sys.version_info[0] == 3 and sys.version_info >= (3, 8) else 'incompatible')" 2>$null
39
+ if ($LASTEXITCODE -eq 0 -and $caIdentity -ceq 'codearbiter-python3') {
40
+ $caPython = $caExecutable
41
+ break
42
+ }
43
+ } catch { continue }
44
+ }
45
+ if (-not $caPython) { throw 'compatible Python 3 interpreter unavailable' }
46
+ ```
47
+
48
+ ### Pi POSIX interpreter selection
49
+ ```sh
50
+ ca_python=
51
+ for ca_candidate in python3 python; do
52
+ ca_path=$(command -v "$ca_candidate" 2>/dev/null) || continue
53
+ case "$ca_path" in /*) ;; *) continue;; esac
54
+ [ -f "$ca_path" ] || continue
55
+ ca_executable=$("$ca_path" -B -c 'import sys; sys.exit(1) if not (sys.version_info[0] == 3 and sys.version_info >= (3, 8)) else None; print(sys.executable)' 2>/dev/null) || continue
56
+ case "$ca_executable" in
57
+ /*) ;;
58
+ [A-Za-z]:'\'*)
59
+ command -v cygpath >/dev/null 2>&1 || continue
60
+ ca_executable=$(cygpath -u "$ca_executable") || continue ;;
61
+ *) continue ;;
62
+ esac
63
+ [ -f "$ca_executable" ] && [ -x "$ca_executable" ] || continue
64
+ ca_identity=$("$ca_executable" -B -c 'import sys; print("codearbiter-python3" if sys.version_info[0] == 3 and sys.version_info >= (3, 8) else "incompatible")' 2>/dev/null) || continue
65
+ if [ "$ca_identity" = codearbiter-python3 ]; then ca_python=$ca_executable; break; fi
66
+ done
67
+ if [ -z "$ca_python" ]; then printf '%s\n' 'compatible Python 3 interpreter unavailable' >&2; exit 2; fi
68
+ ```
69
+
70
+ Start from the absolute path of the **loaded installed entry resource** that
71
+ the host actually supplied: `commands/task.md` or `commands/debug.md` on
72
+ Claude, `skills/ca-task/SKILL.md` or `skills/ca-debug/SKILL.md` on Codex and
73
+ Pi. The Codex and Pi skill directories are two levels below the package root;
74
+ Claude's command directory is one level below it. Do not use the current directory, a project checkout,
75
+ an unset `PLUGIN_ROOT`/`CLAUDE_PLUGIN_ROOT` token from a hook runner, `/hooks`,
76
+ a source clone, or a recursive cache search. If the loaded resource, package
77
+ identity, or exact helper is absent, report that failure and stop. Keep the
78
+ current working directory at the intended project when invoking `taskwrite.py`.
79
+
80
+
81
+ Pi's loaded `skills/ca-task/SKILL.md` or `skills/ca-debug/SKILL.md` is the
82
+ anchor. `package.json` is the installed package identity marker; a written
83
+ `<plugin-root>` string is not an executable path. Bind the selected resource
84
+ and one literal helper leaf as above.
85
+
86
+ ### Pi PowerShell resolution
87
+ ```powershell
88
+ $caResolvedResource = (Resolve-Path -LiteralPath $caLoadedResource -ErrorAction Stop).ProviderPath
89
+ $caResourceDirectory = Split-Path -Parent $caResolvedResource
90
+ $caInstalledRoot = (Resolve-Path -LiteralPath (Join-Path $caResourceDirectory '..\..') -ErrorAction Stop).ProviderPath
91
+ $caManifest = Join-Path $caInstalledRoot 'package.json'
92
+ if (-not (Test-Path -LiteralPath $caManifest -PathType Leaf)) { throw "installed ca-pi package identity missing" }
93
+ $caHelper = Join-Path $caInstalledRoot $caHelperRelative
94
+ if (-not (Test-Path -LiteralPath $caHelper -PathType Leaf)) { throw "installed helper missing: $caHelper" }
95
+ ```
96
+
97
+ ### Pi POSIX resolution
98
+ ```sh
99
+ case "$ca_loaded_resource" in /*) ;; *) printf '%s\n' 'loaded installed resource must be absolute' >&2; exit 2;; esac
100
+ if [ ! -f "$ca_loaded_resource" ]; then printf '%s\n' 'loaded installed resource missing' >&2; exit 2; fi
101
+ ca_installed_root=$(CDPATH= cd -P "$(dirname "$ca_loaded_resource")/../.." && pwd -P) || exit 2
102
+ if [ ! -f "$ca_installed_root/package.json" ]; then printf '%s\n' 'installed ca-pi package identity missing' >&2; exit 2; fi
103
+ ca_helper=$ca_installed_root/$ca_helper_relative
104
+ if [ ! -f "$ca_helper" ]; then printf '%s\n' 'installed helper missing' >&2; exit 2; fi
105
+ ```
106
+
107
+
108
+ Never repair a missing installed helper by selecting a similarly named file
109
+ from a checkout or cache. A missing or partial package blocks the operation.
110
+
111
+ For private debug validation, select the literal leaf
112
+ `hooks/debug-handoff.py` with the resolution block above. Supply one finite
113
+ packet of at most 65,536 bytes through the host execution tool's stdin and
114
+ retain that tool's timeout and output controls. The helper owns rejection of
115
+ oversize input; never build a shell pipeline, command string, path argument,
116
+ or unbounded read to transport the packet. Invoke only once with the literal
117
+ `validate` operation and retain its original exit, stdout, and stderr.
118
+
119
+ ### Pi PowerShell validate invocation
120
+ ```powershell
121
+ & $caPython -B $caHelper validate
122
+ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
123
+ ```
124
+
125
+ ### Pi POSIX validate invocation
126
+ ```sh
127
+ "$ca_python" -B "$ca_helper" validate
128
+ ```
@@ -22,6 +22,19 @@ file maps those actions to Pi's extension API.
22
22
  silently allows classified reads. Plan mode is read-only except for the
23
23
  current canonical spec, plan, and plan-ledger files; source, configuration,
24
24
  unrelated project-state, and external mutations deny.
25
+ - For an authorized debug validator or task-board writer call, load
26
+ [helper-invocation.md](helper-invocation.md) relative to this installed host
27
+ note. Derive the installed package
28
+ from the absolute path of the currently loaded `ca-debug` or `ca-task`
29
+ `SKILL.md`, then check the exact helper and run the card's PowerShell or POSIX
30
+ Python 3 selection block before invoking it. Select once by an executed
31
+ identity probe; preserve a failed helper's original output and exit status
32
+ without a second-interpreter attempt. Put task options before `--` and pass
33
+ user text as one literal argument. Feed validation one finite packet of at
34
+ most 65,536 bytes through the host tool's stdin using the card's direct
35
+ `validate` call. The literal `<plugin-root>` spelling
36
+ is not a shell path. A missing helper blocks the call; preserve the current
37
+ project working directory for board writes.
25
38
  - `codearbiter_background_bash` and `/ca-jobs list|tail|cancel` are bounded,
26
39
  session-only parent capabilities. Jobs and their metadata terminate at
27
40
  shutdown and are never restored from Pi session entries.
@@ -27,7 +27,7 @@ reached the same way.
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
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 |
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 of confirmed_code_defect, confirmed_noncode_cause, design_question, no_action, or unresolved with evidence; continuation retains caller authority |
31
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
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 |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbiterforge/ca-pi",
3
- "version": "0.15.12",
3
+ "version": "0.16.0",
4
4
  "private": true,
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
@@ -15,7 +15,7 @@ not both merely to repeat the same procedure. This index lists what each skill O
15
15
  | [tdd](tdd/SKILL.md) | `/feature` (after spec approval), `/fix`, `/refactor` | The test-first gate: six phases — obligation scan → red → green → obligation verify → coverage → lint. No implementation before Phase 1; no path to `commit-gate` until all six gates are green. |
16
16
  | [commit-gate](commit-gate/SKILL.md) | `/commit` | The commit gate: nine phases — permission, branch, classification, impact-bounded local verification under the shared [verification boundary](../includes/verification-boundary.md), behavioral proof, diff review, selective stage, message, commit. No commit while an applicable check is red, the behavior unproven, or secrets/cruft present; exhaustive exact-head proof remains a hosted-CI merge gate. |
17
17
  | [decision-variance](decision-variance/SKILL.md) | Architectural reconciliation or variance report; explicit `/reconcile` retained | One SMARTS arbitration owner; report-only is non-mutating. Analysis card loads on demand; only explicit user choices enter the append-only log. |
18
- | [debug](debug/SKILL.md) | Diagnosis intent or `/debug` | Investigate-then-decide root-cause analysis: five phases. Investigation only, no code change here; forces one named exit — `/fix`, `/adr`, or a no-action close. |
18
+ | [debug](debug/SKILL.md) | Diagnosis intent or `/debug` | Investigate-then-decide root-cause analysis: five phases. Investigation only, no code change here; returns one evidence-backed result: confirmed_code_defect, confirmed_noncode_cause, design_question, no_action, or unresolved. Follow-up action retains caller authority; no default task or ADR write. |
19
19
  | [refactor](refactor/SKILL.md) | Behavior-preserving restructure intent or `/refactor` | Behavior-preserving change behind a parity-coverage proof gate; routes to `tdd` Phase 1 for coverage backfill or new test seams. |
20
20
  | [context-creation](context-creation/SKILL.md) | `/create-context` (brownfield) | Back-fills `.codearbiter/` from existing source via parallel scouts; writes `CONTEXT.md` (`arbiter: enabled` + `stage:`) and locks it `<!--INITIALIZED-->`. |
21
21
  | [decompose](decompose/SKILL.md) | greenfield startup, `/decompose` | Six-layer senior-architect interview, compaction-resilient via per-layer disk drafts + DRAFT ADRs; populates `.codearbiter/` and locks it initialized. |
@@ -107,10 +107,12 @@ Gate: the change is proven to do what it claimed by fresh evidence — command o
107
107
 
108
108
  Compute the heal worklist from the staged set via `_provenancelib.heal_worklist(staged_paths, provenance, current_hashes)` — the subset of staged paths that are `drift_trigger:true` provenance entries whose recorded hash has diverged or is absent. **Empty worklist → skip this phase entirely; most commits pay nothing** (cost guarantee: ordinary commits touching no provenance source do zero re-scout work).
109
109
 
110
- Non-empty worklist → run an **incremental re-scout scoped to those paths only** (not the full repo). For each path, re-examine whether the claims in the backing doc still hold:
110
+ Non-empty worklist → call `_provenancelib.compute_drift(provenance, current_hashes)` to retain the document/source mapping. For each stale document in that drift report, get its record as `doc_provenance` and call `_provenancelib.changed_scope(doc_provenance, drift)`. Intersect that document's drifted paths with the worklist; skip a document when the intersection is empty. The hash map can omit unstaged paths, so a missing entry outside the worklist must not broaden this commit's re-scout. Confirm that every selected worklist path maps to at least one stale document after this filtering; if a record is malformed or the mapping is incomplete, STOP and report the gap rather than treating the path as fresh.
111
111
 
112
- - **Claim still holds → silently re-baseline.** Call `_provenancelib.rebaseline` to update the stored hash in `.codearbiter/.provenance/<doc>.json` and stage that file by explicit path so the re-baselined record rides THIS commit (ADR-0008 ride-along pattern — nothing is surfaced to the user). After staging, re-run the secrets scan from `tech-stack.md` over the newly-staged path(s) — any file staged after Phase 4 must still pass the automated secrets scan before the commit proceeds.
113
- - **Claim changed → route to the existing Phase 6 diff-review.** The doc or code-map edit required to reflect the changed claim is proposed in diff review — the user reviews it as part of the normal diff; nothing is silently rewritten.
112
+ Run an **incremental re-scout for each affected document**, scoped to its selected staged paths only (not the full repo). A fresh first document does not discharge a stale second document's claims for the same source. Resolve each selected document/path dependency independently:
113
+
114
+ - **Claim still holds → silently re-baseline only that document's provenance record.** Call `_provenancelib.rebaseline(doc_provenance, selected_current_hashes)` where `selected_current_hashes` contains current hashes only for the selected staged paths whose claims in that document were inspected and still hold. Do not re-baseline a path whose claim changed or was not inspected. Stage only `.codearbiter/.provenance/<doc>.json` by explicit path so the re-baselined record rides THIS commit (ADR-0008 ride-along pattern — nothing is surfaced to the user). After staging, re-run the secrets scan from `tech-stack.md` over the newly-staged path(s) — any file staged after Phase 4 must still pass the automated secrets scan before the commit proceeds. A missing current hash (deletion or rename) cannot be silently re-baselined; surface it in Phase 6 for review.
115
+ - **Claim changed → route to the existing Phase 6 diff-review.** Propose only the affected doc or code-map edit required to reflect its changed claim. The user reviews that edit in the normal diff, and Phase 7 stages approved paths explicitly; do not silently rewrite or add unrelated documentation.
114
116
 
115
117
  ## Phase 6 — Diff review · gate: BLOCK
116
118
 
@@ -31,6 +31,13 @@ Report first. Write only after the user selects re-scout or re-baseline for that
31
31
  document; never change an unselected derived document. This owner neither stages
32
32
  nor commits. Routine commit-gate auto-heal is unchanged.
33
33
 
34
+ An **initialized refresh** belongs to this existing owner after an explicit
35
+ selection. It is separate from initial population: do not call the initialized
36
+ `/ca-create-context`/`/ca-init --brownfield` path, rerun the scaffolder,
37
+ clear `<!--INITIALIZED-->`, or repeat context finalization. An ordinary status
38
+ snapshot and the initial `/ca-status drift` report are read-only. A declined
39
+ refresh leaves every file unchanged.
40
+
34
41
  ## Pre-flight
35
42
 
36
43
  Read these before computing drift:
@@ -57,8 +64,23 @@ Use `_provenancelib` helpers in this order:
57
64
  Alternatively reuse the same logic as `startup_drift_line` by calling it for
58
65
  a human-readable summary, then inspecting `compute_drift` directly for detail.
59
66
 
60
- If the drift report is empty: report "no stale docs — provenance is fresh"
61
- and exit. No further action required.
67
+ The `entries`/Git-hash comparison above covers legacy v1 records only. For
68
+ every enrolled v2 document, call `assess_context_provenance` with the bounded
69
+ current source/target snapshot and an action-boundary snapshot probe. Inspect
70
+ its per-document states as well as aggregate coverage. A missing, corrupt or
71
+ unsupported record, incomplete acquisition, partial hash or unchecked identity
72
+ is unknown coverage, even when a neighboring v1 or v2 record is usable. Report
73
+ the usable records and the unknowns separately; never turn an empty legacy
74
+ drift report into a fresh verdict for v2. `v2_current` acknowledges matching
75
+ identities only. `semantic: unverified` and `verified_fresh: false` remain in
76
+ force until the owning semantic review and writer receipt establish otherwise;
77
+ changing hashes or choosing re-baseline does not perform that review.
78
+
79
+ Only if the relevant legacy drift report is empty and v2 coverage/identities
80
+ have been checked without unknowns may this audit report no stale identities.
81
+ That is not a claim that instruction-bearing facts are semantically verified.
82
+ Only a separately explicit full initialized refresh selection may proceed
83
+ without a stale-document list.
62
84
 
63
85
  ### Step 2 — Report stale docs
64
86
 
@@ -71,28 +93,92 @@ Stale docs (N):
71
93
  ...
72
94
  ```
73
95
 
74
- ### Step 3 — Per-doc action loop
75
-
76
- For each stale doc, present three choices and wait for the user to select one:
96
+ Also present every enrolled v2 document's `v2_current`, `v2_stale` or unknown
97
+ state from Step 1. For `v2_stale`, derive a proposed affected scope from that
98
+ document's bounded evidence references and recheck the exact paths before
99
+ selection; the legacy `changed_scope` list cannot discover v2 drift. An
100
+ unknown state needs a bounded recovery/inspection, not an inferred fresh or
101
+ stale path. Do not offer an automatic write for an unbounded scope.
102
+
103
+ ### Unsupported human content and owner reconciliation
104
+
105
+ An unsupported human Markdown layout, ambiguous duplicate anchor, unparseable
106
+ custom section, oversized document or absent managed ownership record is a
107
+ write refusal for that document, not a reason to erase it or abandon safe
108
+ task-time reading. An unrelated unknown section in an otherwise supported
109
+ document remains unowned and byte-identical during a supported field update.
110
+ Preserve exact bytes and report the specific unsupported or unowned span.
111
+ Use the existing applicable instructions under their actual precedence for the
112
+ current task; referencing those instructions unchanged does not create a new
113
+ normative rule or require a new approval. Keep observed upstream conventions
114
+ and accepted ADR references source-scoped when they do not already govern this
115
+ project. Surface a real conflict without silently displacing either source.
116
+
117
+ If the requested change would adopt or replace normative instructions, route
118
+ the proposal to its actual owner and obtain that owner's actual approval before
119
+ any supported bounded update. An unsupported template needs explicit
120
+ reconciliation or a qualified per-kind transition through the existing context
121
+ writer. Its refusal never authorizes raw Write/Edit fallback or a regex rewrite.
122
+ Task, question, audit, release and ADR files remain with their existing writers;
123
+ do not normalize, recreate or edit their history during context refresh.
124
+
125
+ ### Step 3 — Selected initialized refresh
126
+
127
+ For each stale or bounded affected document, present supported re-scout,
128
+ re-baseline and defer choices; wait for the user's selection. A user may instead
129
+ explicitly select full refresh. Do not interpret
130
+ `status drift`, the drift report itself or an ordinary status request as that
131
+ selection. Record the selected documents and declared affected source paths
132
+ before any scout or write. An incremental refresh re-scouts only the selected
133
+ drifted paths and affected logical assignments. A full refresh declares all six
134
+ logical assignments and all five content documents. Retain prior coverage as
135
+ prior evidence; a scoped `join_scout_reports` result has `full_coverage: false`
136
+ and must never be described as a newly completed full scan.
77
137
 
78
138
  **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.
84
-
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.
139
+ doc, scoped to those paths only. Use the context-creation containment profile,
140
+ run budget, `admit_scout_attempt` and `join_scout_reports` contract for exactly
141
+ the declared affected assignments. A missing/failed report, changed snapshot,
142
+ contradiction or unresolved task-dependent decision blocks the selected write.
143
+ If the claims still hold, a valid selected owned-field metadata refresh may
144
+ keep document bytes identical only when proposed v2 provenance actually
145
+ changes. Missing selection and unchanged proposed provenance refuse; retain
146
+ the stale pair and do not claim freshness in those cases. Any update still
147
+ requires current source evidence, exact preview approval and receipt-only
148
+ apply. Surface the proposed content and provenance pair for exact review.
149
+
150
+ **re-baseline** — the legacy v1 provenance choice may acknowledge a verified
151
+ cosmetic change through its existing owner, where applicable. For an enrolled
152
+ v2 content document, use only a selected owned field and the native bounded
153
+ update with new, validated source evidence and changed proposed provenance.
154
+ If no field is selected or the proposed pair is a true no-op, retain the stale
155
+ pair and defer that selection. Never directly write the v2 provenance or use
156
+ the legacy `rebaseline` helper as a fallback for it.
157
+
158
+ **full refresh** — only after explicit selection, use the same qualified
159
+ containment and bounded join with `mode: full` and six complete logical reports.
160
+ Synthesize all five content documents from the new evidence and reconcile gaps
161
+ under the context-creation Phase 3–4 rules. Do not enter its Phase 6 lock.
162
+
163
+ For each selected document, submit its finite typed `update` preview through
164
+ `python "<plugin-root>/hooks/init-codearbiter.py" --root <exact-root> --context-request <request-file>`.
165
+ The installed qualified context writer checks the existing document/provenance
166
+ pair, current source evidence, field ownership and protected target set. Review
167
+ the exact proposed pair and obtain its own native `approve-context` reply; apply
168
+ only its receipt through the same `--context-request` bridge. Read back the
169
+ committed pair and confirm the standalone `<!--INITIALIZED-->` marker remains
170
+ for `CONTEXT.md`. The writer's five content targets exclude task, question and
171
+ audit history. Never edit those owners as a side effect, hand-write a provenance
172
+ record, bypass a refusal, stage or commit here. If the installed writer or
173
+ qualified scout profile is unavailable, report that boundary and retain state.
89
174
 
90
175
  **defer** — do nothing for this doc now. The drift line will reappear at the
91
176
  next SessionStart. Use when the change is in-progress and the doc update should
92
177
  wait for a later commit.
93
178
 
94
- After processing all stale docs, summarize which docs were re-scouted,
95
- re-baselined, or deferred.
179
+ After processing selections, summarize changed documents, deferred selections,
180
+ the declared coverage, and whether the run was full or incremental. Keep
181
+ unselected content, initialized state and prior history intact.
96
182
 
97
183
  ## Hard rule
98
184