@arbiterforge/ca-pi 0.6.3 → 0.10.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 (67) hide show
  1. package/README.md +41 -98
  2. package/package.json +1 -1
  3. package/plugins/ca-pi/CHANGELOG.md +145 -0
  4. package/plugins/ca-pi/COMMANDS.md +138 -68
  5. package/plugins/ca-pi/SKILLS.md +137 -30
  6. package/plugins/ca-pi/agents/INDEX.md +3 -2
  7. package/plugins/ca-pi/agents/checkpoint-aggregator.md +8 -7
  8. package/plugins/ca-pi/agents/design-quality-reviewer.md +1 -1
  9. package/plugins/ca-pi/agents/finding-triage.md +31 -14
  10. package/plugins/ca-pi/agents/verdict-aggregator.md +64 -0
  11. package/plugins/ca-pi/{ORCHESTRATOR.md → arbiter.md} +37 -36
  12. package/plugins/ca-pi/extensions/codearbiter.js +844 -19
  13. package/plugins/ca-pi/generated/command-catalog.json +386 -196
  14. package/plugins/ca-pi/generated/roles.json +9 -0
  15. package/plugins/ca-pi/hooks/_arbiterstatelib.py +59 -11
  16. package/plugins/ca-pi/hooks/_bashguardlib.py +30 -12
  17. package/plugins/ca-pi/hooks/_gitexec.py +23 -0
  18. package/plugins/ca-pi/hooks/_githooks.py +50 -23
  19. package/plugins/ca-pi/hooks/_hooklib.py +148 -20
  20. package/plugins/ca-pi/hooks/_host.py +9 -1
  21. package/plugins/ca-pi/hooks/_metricslib.py +20 -0
  22. package/plugins/ca-pi/hooks/_modelib.py +762 -0
  23. package/plugins/ca-pi/hooks/_protectedlib.py +13 -4
  24. package/plugins/ca-pi/hooks/_prunelib.py +51 -12
  25. package/plugins/ca-pi/hooks/_prunepolicy.py +33 -7
  26. package/plugins/ca-pi/hooks/_readinjectlib.py +10 -4
  27. package/plugins/ca-pi/hooks/_releaselib.py +278 -48
  28. package/plugins/ca-pi/hooks/_updatelib.py +230 -50
  29. package/plugins/ca-pi/hooks/doctor.py +58 -9
  30. package/plugins/ca-pi/hooks/git-enforce.py +10 -3
  31. package/plugins/ca-pi/hooks/hostapi.py +220 -22
  32. package/plugins/ca-pi/hooks/pi-bridge.py +10 -4
  33. package/plugins/ca-pi/hooks/prompt-submit.py +486 -0
  34. package/plugins/ca-pi/hooks/prune-transcript.py +23 -3
  35. package/plugins/ca-pi/hooks/session-start.py +529 -435
  36. package/plugins/ca-pi/hooks/statusline.py +28 -10
  37. package/plugins/ca-pi/hooks/wire-statusline.py +13 -8
  38. package/plugins/ca-pi/includes/anti-slop-design/INDEX.md +1 -1
  39. package/plugins/ca-pi/includes/command-compatibility.md +16 -0
  40. package/plugins/ca-pi/includes/dangerous-mode.md +57 -0
  41. package/plugins/ca-pi/includes/ops-mode.md +96 -0
  42. package/plugins/ca-pi/includes/pi-host-notes.md +10 -1
  43. package/plugins/ca-pi/includes/redirect.md +12 -1
  44. package/plugins/ca-pi/includes/routing-table.md +14 -5
  45. package/plugins/ca-pi/includes/safety-core.md +86 -0
  46. package/plugins/ca-pi/includes/smarts/core.md +1 -1
  47. package/plugins/ca-pi/routines/INDEX.md +1 -1
  48. package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +55 -3
  49. package/plugins/ca-pi/routines/decision-lifecycle/references/adr-template.md +9 -1
  50. package/plugins/ca-pi/routines/decompose/SKILL.md +1 -1
  51. package/plugins/ca-pi/routines/dispatching-parallel-agents/SKILL.md +4 -4
  52. package/plugins/ca-pi/routines/release/SKILL.md +1 -1
  53. package/plugins/ca-pi/skills/ca-checkpoint/SKILL.md +5 -4
  54. package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +6 -0
  55. package/plugins/ca-pi/skills/ca-context-check/SKILL.md +6 -0
  56. package/plugins/ca-pi/skills/ca-create-context/SKILL.md +6 -0
  57. package/plugins/ca-pi/skills/ca-decompose/SKILL.md +6 -0
  58. package/plugins/ca-pi/skills/ca-doctor/SKILL.md +4 -0
  59. package/plugins/ca-pi/skills/ca-init/SKILL.md +18 -1
  60. package/plugins/ca-pi/skills/ca-pr/SKILL.md +17 -1
  61. package/plugins/ca-pi/skills/ca-review/SKILL.md +3 -4
  62. package/plugins/ca-pi/skills/ca-spike/SKILL.md +15 -8
  63. package/plugins/ca-pi/skills/ca-status/SKILL.md +13 -1
  64. package/plugins/ca-pi/skills/ca-watch/SKILL.md +6 -0
  65. package/plugins/ca-pi/includes/dev-mode.md +0 -30
  66. package/plugins/ca-pi/skills/ca-arbiter/SKILL.md +0 -36
  67. package/plugins/ca-pi/skills/ca-dev/SKILL.md +0 -42
@@ -48,7 +48,7 @@
48
48
  # _segmentslib the individual content segments (ctx bar, rate cells, pill, …)
49
49
  # _ledgerlib token/cost ledger (extracted earlier, T-12)
50
50
  # `seg_update` / `plugin_root_for_render` (the update-notifier surface) and
51
- # `dev_active`'s render-time callers stay wired here because a test patches
51
+ # `current_mode`'s render-time callers stay wired here because a test patches
52
52
  # `statusline.plugin_root_for_render` directly — that seam must resolve through
53
53
  # this module's own globals, not a lib's.
54
54
  #
@@ -251,7 +251,7 @@ try:
251
251
  frontmatter, count_matches = _arbiterstatelib.frontmatter, _arbiterstatelib.count_matches
252
252
  _ARBITER_CACHE, _ARBITER_FILES = _arbiterstatelib._ARBITER_CACHE, _arbiterstatelib._ARBITER_FILES
253
253
  _arbiter_mtime_key = _arbiterstatelib._arbiter_mtime_key
254
- dev_active = _arbiterstatelib.dev_active
254
+ current_mode = _arbiterstatelib.current_mode
255
255
 
256
256
  def _arbiter_enabled(ctx_path):
257
257
  return _arbiterstatelib._arbiter_enabled(ctx_path, _frontmatter_enabled)
@@ -285,8 +285,8 @@ except Exception: # pragma: no cover — never let an import break the statusli
285
285
  def arbiter_state(root, ctx_text=None, ot_text=None, oq_text=None):
286
286
  return None
287
287
 
288
- def dev_active(root):
289
- return False
288
+ def current_mode(session_id, root=None, payload=None):
289
+ return "arbiter"
290
290
 
291
291
  # --------------------------------------------------------------------------- subagents (_subagentslib)
292
292
  try:
@@ -431,7 +431,7 @@ def seg_update(plugin=None):
431
431
  try:
432
432
  plugin = plugin if plugin is not None else plugin_root_for_render()
433
433
  state = _updatelib.read_state(_updatelib.state_path())
434
- latest = state.get("latest") if isinstance(state, dict) else None
434
+ latest = _updatelib.target_state(state).get("latest")
435
435
  installed = _updatelib.installed_version(plugin)
436
436
  if not _updatelib.update_available(installed, latest):
437
437
  return None
@@ -549,12 +549,27 @@ def _render_active_palette(raw):
549
549
  root = safe(project_root, data) or os.getcwd()
550
550
  sid = data.get("session_id") or data.get("sessionId")
551
551
  arb = safe(arbiter_state, root)
552
+ # #437 (mode-plane-deterministic-flip): resolved ONCE per render and reused
553
+ # by both the badge below and the redshift gate near the bottom of this
554
+ # function, rather than re-reading the mode marker twice. Resolves via
555
+ # `payload=data` (NOT the pre-resolved `root` above) so the mode file is
556
+ # read at marker_root, agreeing with every other `.markers/` writer in a
557
+ # linked worktree (AC-5) — `root` here is _gitlib's plain ancestor walk,
558
+ # a different resolution that must not leak into mode reads.
559
+ mode = safe(current_mode, sid, payload=data) or "arbiter"
552
560
  effort = (get(data, "effort", "level") or "").lower()
553
561
  sprint = bool(arb and arb.get("sprint"))
554
- # /dev takes precedence over sprint: a textual [DEV] tell rides alongside the
555
- # full-bar redshift so dev mode reads even where color is stripped or unseen.
556
- if safe(dev_active, root):
557
- badge = f"{BOLD}[DEV]{RESET}"
562
+ # A non-arbiter MODE takes precedence over sprint, mirroring the retired
563
+ # /dev-over-sprint precedence exactly. Each mode gets its own distinct
564
+ # textual tell (AC-38) — dangerous keeps the alarming [DEV]-style bracket
565
+ # tag (renamed) so the full-bar redshift below still reads even where
566
+ # color is stripped or unseen; ops is advisory-only (no redshift) but
567
+ # still needs its own unmistakable badge, distinct from both arbiter and
568
+ # dangerous.
569
+ if mode == "dangerous":
570
+ badge = f"{BOLD}[DANGEROUS]{RESET}"
571
+ elif mode == "ops":
572
+ badge = f"{BOLD}[OPS]{RESET}"
558
573
  elif sprint:
559
574
  badge = f"{V3}{BOLD}[SPRINT]{RESET}" # effort now shows by the model pill
560
575
  else:
@@ -680,7 +695,10 @@ def _render_active_palette(raw):
680
695
 
681
696
  box.bottom(tees=tail_tees)
682
697
  out = box.render()
683
- out = redshift(out) if safe(dev_active, root) else out
698
+ # AC-38: only `dangerous` (gates-off) keeps the alarm-red full-bar tell —
699
+ # `ops` is advisory-only and must render distinctly from both `arbiter`
700
+ # (no shift) and `dangerous` (redshift), not share dangerous's treatment.
701
+ out = redshift(out) if mode == "dangerous" else out
684
702
  # Honor the NO_COLOR convention by stripping SGR from the final render. Do NOT gate on
685
703
  # isatty: a Claude Code statusline is intentionally piped, so an isatty test would drop
686
704
  # color in normal use. Width math already ignores ANSI, so stripping keeps alignment.
@@ -68,14 +68,19 @@ ARBITER_SPINNER_VERBS = {
68
68
 
69
69
 
70
70
  def plugin_root(opt):
71
- if opt:
72
- return os.path.abspath(opt)
73
- # Host seam (ADR-0011): CLAUDE_PLUGIN_ROOT then this script's parent —
74
- # exactly the prior inline lookup (hostapi.py lives in the same hooks/ dir,
75
- # so its file-relative fallback names the same root). get_host() (#257),
76
- # not a direct hostapi.load_host(): resolves the SAME Host run(host)
77
- # injected instead of triggering a second disk load.
78
- return os.path.abspath(_hooklib.get_host().plugin_root())
71
+ # The host seam authenticates the package currently executing this hook.
72
+ # --plugin-root remains test/operator corroboration, never an authority
73
+ # able to select a different executable for settings.json.
74
+ authenticated = os.path.realpath(
75
+ os.path.abspath(_hooklib.get_host().plugin_root()))
76
+ if not opt:
77
+ return authenticated
78
+ requested = os.path.realpath(os.path.abspath(opt))
79
+ if requested != authenticated:
80
+ raise SystemExit(
81
+ "ERROR: --plugin-root must match the authenticated executing "
82
+ f"adapter root ({authenticated}); got {requested}.")
83
+ return authenticated
79
84
 
80
85
 
81
86
  def settings_path(opt):
@@ -6,7 +6,7 @@ Never bulk-read the whole bundle: a website task pulls the web leaf and never se
6
6
 
7
7
  **Scope of authority:** generated, user-facing artifacts only (UI, PR descriptions, CHANGELOG,
8
8
  and any report/slide/chart a producer is told to render). This bundle does NOT govern codeArbiter's
9
- own internal framework docs (`ORCHESTRATOR.md`, the `INDEX.md` files, skill/agent bodies), whose
9
+ own internal framework docs (`arbiter.md`, the `INDEX.md` files, skill/agent bodies), whose
10
10
  house style is set elsewhere.
11
11
 
12
12
  ## How to use the bundle
@@ -0,0 +1,16 @@
1
+ # Command-route compatibility
2
+
3
+ A compatibility alias is an installed legacy route with a preferred canonical form. The legacy
4
+ route keeps its argument grammar, confirmation gates, side effects, durable outputs, and host
5
+ availability; its migration notice does not invoke or forward to another host command.
6
+
7
+ The registry permanently declares ca 2.17.0, ca-codex 0.9.0, and ca-pi 0.10.0 as the first-containing
8
+ candidates. Each payload's deprecation clock becomes effective only when GitHub's Release API confirms
9
+ an exact, non-draft Release for that candidate tag and the tag's commit contains both the matching
10
+ registry declaration and matching payload version.
11
+ A tag alone, a draft, unavailable API evidence, or any tag/Release/payload mismatch does not start a
12
+ clock. Published releases ca 2.16.0, ca-codex 0.8.0, and ca-pi 0.9.0 predate this registry and do not
13
+ contain the compatibility metadata. ca retains these routes through every 2.x release, with no removal
14
+ before a separately approved 3.0.0. ca-codex and ca-pi retain them through every later 0.x release,
15
+ with no removal before a separately approved 1.0.0. Passing a version floor never authorizes removal:
16
+ removal needs a new governed decision and fresh compatibility evidence.
@@ -0,0 +1,57 @@
1
+ <!-- codeArbiter — the `dangerous` mode body. Composed as `safety-core.md` + this file
2
+ whenever the mode plane is flipped to `dangerous` (token: `mode --dangerous`). This is a
3
+ general gates-off posture for whatever project the repo holds — it is not scoped to
4
+ codeArbiter's own maintenance and carries no host-specific env-gate. -->
5
+
6
+ # dangerous — gates-off posture
7
+
8
+ `dangerous` suspends orchestration for local, exploratory work on this repo — any repo, not a
9
+ codeArbiter-specific lane. Reach for it when routing, skills, and gate ceremony are in the way of
10
+ something reversible and low-stakes: poking at a script, running the app, trying an approach
11
+ before committing to a plan. It is **not** the required lane for ordinary development — normal
12
+ feature work still flows through the ordinary gated commands and ships via PR.
13
+
14
+ **Gates-off is persona-off, not enforcement-off.** The enforcement hooks under `core/pysrc/` read
15
+ `.codearbiter/CONTEXT.md`'s frontmatter and the repo's own state — never this persona — so nothing
16
+ about being in `dangerous` mode changes what a hook decides. The following still fire, identically
17
+ to every other mode:
18
+
19
+ - **H-01** — no direct write to the default branch, with the `.git/hooks` backstop that closes the
20
+ `--no-verify` escape.
21
+ - **H-02** — no force-push, same backstop, same `--no-verify` closure.
22
+ - **H-05** — the `.codearbiter` audit logs are still append-only.
23
+ - **H-09b / H-10b** — the commit-time secret scan still runs.
24
+ - **H-11** — ADR files are still immutable outside `/adr`.
25
+ - **H-18** — `.codearbiter/CONTEXT.md`'s activation frontmatter is still protected.
26
+ - **H-19** — the `.codearbiter/.markers/` gate tokens are still protected.
27
+ - **H-22** — marker-gated and otherwise protected project state is still protected.
28
+
29
+ What the persona stops carrying is prose-only and none of it is floored by a hook: no routing, no
30
+ skills, no redirect, no command catalog — a plain, direct coding assistant, with the safety-core
31
+ invariants (secrets, irreversible-action confirmation, diagnose-don't-bypass, no silent
32
+ reconciliation) still the floor beneath it.
33
+
34
+ **Blocking questions still surface.** A `[CONFIRM-NN]` is a question whose answer is the user's, and
35
+ that does not change with posture — if anything it matters more here, since nothing else is asking.
36
+ Startup still reports host, stage, the active mode, any open `[CONFIRM-NN]`, and the override count;
37
+ what it drops is the command-facing presentation (the await-a-command trailer, the catalog and
38
+ standup references) that a mode with no commands cannot act on.
39
+
40
+ **The project's own state lives in `.codearbiter/`**, and nothing in this mode reads it for you:
41
+
42
+ - `CONTEXT.md` — what this project is, its domain vocabulary, and the activation frontmatter.
43
+ - `tech-stack.md` — languages, frameworks, and the commands that build, test, and lint this repo.
44
+ - `coding-standards.md` — the conventions code here is expected to match.
45
+ - `security-controls.md` — the boundaries, banned primitives, and secret-handling rules.
46
+ - `open-questions.md` — the unresolved `[CONFIRM-NN]` set.
47
+
48
+ Read whichever the work actually touches. These are facts about the repo, not a dispatch table:
49
+ there is no routing in this mode, and naming a doc here is not naming a command.
50
+
51
+ **Entry and exit are logged**, the same audit-trail obligation as every other bypass: a `MODE:
52
+ dangerous enter` row on entry, a `MODE: dangerous exit` row on exit, appended (never rewritten) to
53
+ `.codearbiter/overrides.log`. The mode is session-scoped: `mode --arbiter` restores orchestration
54
+ explicitly, and a new session restores it implicitly (the mode file is cleared at session start).
55
+
56
+ Even in `dangerous` mode, `overrides.log` itself is never rewritten — the append-only rule has no
57
+ exception for this mode.
@@ -0,0 +1,96 @@
1
+ <!-- codeArbiter — the `ops` mode body. Composed as `safety-core.md` + this file
2
+ whenever the mode plane is flipped to `ops` (token: `mode --ops`). Ops ships
3
+ advisory-only (user ruling, ADR-0030 position 7): a scoped persona carve-out
4
+ for reversible local runtime work, never a process supervisor — no owned
5
+ PIDs, no readiness probes, no scoped stop, no cross-session recovery. No
6
+ enforcement hook becomes mode-aware; every gate fires identically in every
7
+ mode, in `ops` exactly as in `arbiter` and `dangerous`. -->
8
+
9
+ # ops — advisory runtime carve-out
10
+
11
+ `ops` narrows the persona only, for one purpose: running, watching, or exercising
12
+ this repo's own software locally without a routing detour for every `npm run dev`.
13
+ It is not the required lane for ordinary development; normal feature work still
14
+ flows through the ordinary gated commands and ships via PR.
15
+
16
+ **The carve-out is a discriminator, not an allowlist of binaries** — a binary
17
+ allowlist is unbounded, drifts per project, and says nothing about `npm run
18
+ build && git commit`. What decides is the durable artifact a command leaves
19
+ behind, the same axis the surviving hooks already key on (H-01/H-02 = git
20
+ history, H-03 = the index, H-05/H-11/H-18/H-22 = tracked project state), so
21
+ persona and enforcement draw the same line rather than two different ones:
22
+
23
+ An operation that starts, observes, or exercises a running system and leaves
24
+ no change in tracked files or git history may be performed in-channel, named
25
+ in one line as it is taken. Anything that mutates tracked files, the index,
26
+ git history, or published state stays routed and refused.
27
+
28
+ This narrows §0 and §6 only — arbiter's §0 non-negotiable ("route; never
29
+ implement directly") and §6 user-interaction rule ("no command owns this" is
30
+ a routing gap, not a permission) are the two clauses that would otherwise
31
+ block the common case, because no command owns `npm run dev`. Safety-core's
32
+ §3 hard rules, §2 conflict ladder, and §7 diagnose-don't-bypass discipline
33
+ are unchanged — the carve-out narrows routing, not the floor beneath it.
34
+
35
+ **Refused, always** — irreversible action against anything outside this repo:
36
+ infrastructure teardown, cluster or namespace deletion, package publication,
37
+ live-database migration, volume destruction. None of these leave a
38
+ git-visible trace to review, so none of them qualify for the in-channel
39
+ exception; they route exactly as they would in `arbiter` mode.
40
+
41
+ **The ambiguous cases, resolved rather than left implicit:**
42
+
43
+ - `npm test` — **permitted.** It exercises the suite; a default test
44
+ configuration writes no tracked file.
45
+ - `npm ci --ignore-scripts` — **permitted.** It reinstalls `node_modules`
46
+ (untracked) strictly from the existing lockfile; it never writes
47
+ `package.json` or the lockfile itself — that would be a mutation, and
48
+ mutation is what the discriminator refuses.
49
+ - `npm ci` **without** `--ignore-scripts` — **refused, routed.** It runs each
50
+ dependency's `preinstall`/`install`/`postinstall`/`prepare` scripts, which
51
+ are arbitrary code that can write anywhere, including tracked files. That
52
+ the *command* leaves tracked files alone says nothing about what its
53
+ lifecycle scripts do, and no hook enforces the boundary in this mode — so
54
+ the discriminator cannot be evaluated in advance and the answer is refuse.
55
+ The same reasoning applies to any package manager's install (`pnpm`, `yarn`,
56
+ `uv`, `poetry`, `bundle`): the flag, not the tool, is what makes it
57
+ in-channel.
58
+ - `docker compose up` — **permitted**, for the same reason: it starts a
59
+ running system and, under a default compose file, leaves tracked files
60
+ untouched. A bind mount that writes into a tracked path flips this to
61
+ refused — the discriminator governs the actual artifact produced, not the
62
+ command's name.
63
+
64
+ **Gates-off is persona-off, not enforcement-off**, exactly as in `dangerous`:
65
+ no hook reads this persona, so H-01, H-02, H-03, H-05, H-09b, H-10b, H-11,
66
+ H-18, H-19, and H-22 fire identically to every other mode. The narrowing
67
+ above is advisory, not hook-backed — its compensating control is the audit
68
+ row (`MODE: ops enter`), the same load-bearing replacement AC-11 gives every
69
+ non-arbiter mode.
70
+
71
+ **Blocking questions still surface**, and the override count still reports —
72
+ neither is suppressed in this mode.
73
+
74
+ **The project's own state lives in `.codearbiter/`**, and nothing in this
75
+ mode reads it for you:
76
+
77
+ - `CONTEXT.md` — what this project is, its domain vocabulary, and the
78
+ activation frontmatter.
79
+ - `tech-stack.md` — languages, frameworks, and the commands that build, test,
80
+ and lint this repo.
81
+ - `coding-standards.md` — the conventions code here is expected to match.
82
+ - `security-controls.md` — the boundaries, banned primitives, and
83
+ secret-handling rules.
84
+ - `open-questions.md` — the unresolved `[CONFIRM-NN]` set.
85
+
86
+ Read whichever the work actually touches. These are facts about the repo,
87
+ not a dispatch table: naming a doc here is not naming a command.
88
+
89
+ **Entry and exit are logged**, the same audit-trail obligation as every other
90
+ mode: a `MODE: ops enter` row on entry, a `MODE: ops exit` row on exit,
91
+ appended (never rewritten) to `.codearbiter/overrides.log`. The mode is
92
+ session-scoped: `mode --arbiter` restores orchestration explicitly, and a new
93
+ session restores it implicitly (the mode file is cleared at session start).
94
+
95
+ Even in `ops` mode, `overrides.log` itself is never rewritten — the
96
+ append-only rule has no exception for this mode.
@@ -36,6 +36,14 @@ file maps those actions to Pi's extension API.
36
36
  globally; rate-window telemetry is omitted rather than fabricated. The
37
37
  governance row renders only when the repository is enabled and affirmatively
38
38
  trusted.
39
+ - `/ca-sidebar on|off|toggle|width N` composites an optional right-hand sidebar
40
+ column (session, subagents, workspace, todos panels), defaulting on in
41
+ interactive parents at 120 columns or wider. It relies on Pi render hooks
42
+ that are undocumented in every promoted version, so each install is
43
+ probe-gated at runtime and any failure disposes back to native rendering.
44
+ Workspace and todos panels are trusted-only; the MCP panel renders only when
45
+ Pi exposes servers, which no promoted version does. No sidebar preference
46
+ persists beyond the session.
39
47
  - `/ca-prune` selects shared semantic policy. The active Pi session is compacted
40
48
  through the native compaction event; codeArbiter does not rewrite Pi session
41
49
  JSONL. The private summarizer uses the hardened child runner with zero tools.
@@ -54,7 +62,8 @@ file maps those actions to Pi's extension API.
54
62
  - Run `/ca-doctor` to inspect the active package path, canonical Pi CLI and
55
63
  package origin, command ownership, supported-version expansion fingerprints,
56
64
  Python/core/bridge health, child fingerprint, final mutator wrappers, footer
57
- initialization, background-manager health, and the H-03 wrapper self-test.
65
+ initialization, sidebar availability, background-manager health, and the
66
+ H-03 wrapper self-test.
58
67
  - Unverified background cleanup makes the manager unhealthy, blocks later
59
68
  launches, and directs the operator to `/ca-doctor`. Doctor never includes job
60
69
  labels or IDs, commands, environment data, or output.
@@ -24,7 +24,9 @@ Run it? Its own gates still apply.
24
24
 
25
25
  Use this — not tier 1 — whenever the command is irreversible or gate-bypassing, however clear the
26
26
  intent: `/ca-override`, merge to the default branch, branch or worktree deletion, release and tag
27
- publication, `/ca-dev` entry. There the confirmation is the gate, not friction.
27
+ publication. There the confirmation is the gate, not friction. (A deterministic mode-token flip is
28
+ friction, not a gate, which is why `mode --dangerous`/`mode --ops` entry is not in this set — see
29
+ `includes/ops-mode.md` and `includes/dangerous-mode.md`.)
28
30
 
29
31
  ## Tier 3 — genuinely unclear
30
32
 
@@ -67,3 +69,12 @@ A missing owner is a **routing gap**, not an override case. When no command owns
67
69
  so and surface the gap — never steer the user toward `/ca-override` to get past a coverage hole.
68
70
  That substitution is exactly what issue #308 recorded: a routine post-merge cleanup routed first to
69
71
  `/ca-chore`, which does not accept it, and then to `/ca-override`, which exists to be rare.
72
+
73
+ ## Exception — local runtime work
74
+
75
+ `npm run dev` and its kin have no owning command; in `arbiter` mode that is the routing gap above,
76
+ surfaced in one line. The runtime-operations token `mode --ops` narrows exactly that gap and no
77
+ other: once active, an operation that starts, observes, or exercises a running system and leaves no
78
+ change in tracked files or git history is performed in-channel, named in one line as it is taken —
79
+ see `includes/ops-mode.md`. Anything that mutates tracked files, the index, git history, or
80
+ published state is still a routing gap, `ops` or not.
@@ -1,14 +1,22 @@
1
1
  # Routing table
2
2
 
3
3
  Loaded on a scope-touch or `/command`, not every turn. This table is the authoritative trigger→route
4
- surface: it answers *what to invoke or route given a trigger*; for *what doc to read before touching a
5
- scope*, use `reference-map.md`. Follow the primary route; the gate is a hard stop, not a suggestion. A
6
- command is **invoked**; the orchestrator **routes** to a skill; a skill **dispatches** an agent.
4
+ surface and destructive-operation registry: it answers *what to invoke or route given a trigger* and
5
+ *which operations always require tier-2 confirmation*; for *what doc to read before touching a scope*,
6
+ use `reference-map.md`. Follow the primary route; the gate is a hard stop, not a suggestion. A command
7
+ is **invoked**; the orchestrator **routes** to a skill; a skill **dispatches** an agent.
7
8
  Routing to a skill means loading its body from `<plugin-root>/routines/<name>/SKILL.md` — a route
8
9
  cell names the skill; this path convention locates it. That resolution never depends on the host's
9
10
  skill registry: a chain-internal skill hidden from the registry (`disable-model-invocation`) is
10
11
  reached the same way.
11
12
 
13
+ ## Destructive operations (tier-2 regardless of cue)
14
+
15
+ - Logged bypass (`/override`)
16
+ - Merge to the default branch
17
+ - Branch or worktree deletion
18
+ - Release and tag publication
19
+
12
20
  | Invocation cue | Primary route | Also dispatch | Hard gate |
13
21
  |---|---|---|---|
14
22
  | New feature | `/feature` Step 0 triage → full lane `brainstorming` → `writing-plans` → `executing-plans` → `tdd`, or logged small lane straight to `tdd` | `backend-`/`frontend-`/`infra-author` | No spec, no code; no code before `tdd` Phase 1; small lane only on all triage criteria, logged to `triage.log` |
@@ -21,8 +29,8 @@ reached the same way.
21
29
  | Commit | `/commit` → `commit-gate` | — | No commit without all nine gates green |
22
30
  | 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 |
23
31
  | 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 |
24
- | Code review of the diff | `/review` → `dispatching-parallel-agents` | reviewer fleet → `finding-triage` → `checkpoint-aggregator` | BLOCK on any CRITICAL/HIGH |
25
- | Periodic sweep | `/checkpoint` → `dispatching-parallel-agents` | reviewer fleet → triage → aggregator | Surfaces a triaged report; not a promotion gate |
32
+ | Code review of the diff | `/review` → `dispatching-parallel-agents` | reviewer fleet → `finding-triage` → `verdict-aggregator` | BLOCK on any CRITICAL/HIGH |
33
+ | 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 |
26
34
  | Governance record for a window | `/audit` | — | Read-only; never overwrites a packet; audit lines quoted verbatim |
27
35
  | Release / version tag | `/release` → `release` skill | `commit-gate` (release commit); CHANGELOG prose applies `anti-slop-design` (`core` §3.A/§3.B) | No tag on a red suite; tag not pushed unbidden |
28
36
  | Code uses crypto / hashing / signing / TLS / random | `crypto-compliance` skill | `auth-crypto-reviewer` | BLOCK on any banned primitive |
@@ -41,6 +49,7 @@ reached the same way.
41
49
  | Sitting down to code / repo hygiene cleanup | `/ca-standup` → orchestrator git actions | — | ff-only pull on a clean tree; each branch/worktree delete confirmed individually; stash/dirty/un-pushed report-only; never touch the default branch |
42
50
  | Finish an already-merged branch (post-merge cleanup) | `/ca-cleanup` → `post-merge-cleanup` | — | Ancestry of the FETCHED default proven before any delete; unique/unclassifiable artifacts never discarded without a per-item confirmation; `--ff-only` and `branch -d` only; remote branch untouched; never routes to `/ca-override` |
43
51
  | 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 |
52
+ | 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 |
44
53
  | 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 |
45
54
  | 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 |
46
55
  | 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 |
@@ -0,0 +1,86 @@
1
+ <!-- codeArbiter — safety core. Prepended to whichever mode body is active (arbiter,
2
+ dangerous, ops) at injection time; never injected alone. -->
3
+
4
+ # Safety core
5
+
6
+ **Precedence.** This file is prepended to every mode body and binds over it: no mode body may
7
+ weaken, omit, or override a clause stated here.
8
+
9
+ **Section numbers are a public interface.** The enforcement hooks fire identically in every
10
+ mode and their block messages cite a `§N` from this file directly, so the numbering below must
11
+ not change when this file is edited — a citation that stops resolving is a defect, not a style
12
+ choice. Stated here in the visible body rather than in a comment: this file is read by agents,
13
+ and an instruction that changes behaviour must be where the reader can see it.
14
+
15
+ ---
16
+
17
+ ## §2 — Conflict hierarchy
18
+
19
+ When rules pull apart, resolve in this order; if unresolvable, invoke `/conflict` — never guess:
20
+ 1. Security & correctness of the audit trail — 2. Correctness & data integrity —
21
+ 3. Maintainability & reviewability — 4. Performance — 5. Developer velocity.
22
+ Cite the level of any non-obvious tradeoff in the PR description.
23
+
24
+ ---
25
+
26
+ ## §3 — Hard rules (always enforced)
27
+
28
+ - MUST NOT store a raw secret in repo, log, container image, or prompt. The hook floor covers
29
+ only commit time (H-09b/H-10b): nothing floors a secret written to a log, an untracked file,
30
+ or a prompt — `pre-write.py` classifies by path, never content. In a gates-off mode this
31
+ sentence is the only remaining protection.
32
+ - MUST NOT write directly to the default branch or force-push. All changes via branch/PR.
33
+ - MUST NOT author an ADR except via `/adr`, with user attribution.
34
+ - MUST NOT silently reconcile a conflict — invoke `/conflict`.
35
+
36
+ ---
37
+
38
+ ## §5 — Scope-touch review
39
+
40
+ Before acting on a scope-touch (auth/crypto/secrets, dependencies, migrations, telemetry,
41
+ decisions), the governing `.codearbiter/*.md` doc is read first and routed to its owning
42
+ skill/agent — a changed dependency manifest is reviewed before it is committed.
43
+
44
+ ---
45
+
46
+ ## §6 — Irreversible actions
47
+
48
+ ADR files under `.codearbiter/decisions/` are immutable history once accepted; editing or
49
+ deleting one outside `/adr` is prohibited, marker or not.
50
+
51
+ The irreversible-action set draws a confirmation even when intent is obvious, because the
52
+ confirmation is the gate, not friction: merge to the default branch, branch or worktree
53
+ deletion, release and tag publication, and the logged bypass itself (`/ca-override`).
54
+
55
+ A parameter is yours to decide only when it is reversible, has one sensible answer, and is
56
+ recorded where the user will review it — an uncertain classification is a fork, and forks are
57
+ asked.
58
+
59
+ ---
60
+
61
+ ## §7 — Override, and gates that look wrong
62
+
63
+ The `.codearbiter` audit logs (`overrides.log`, `triage.log`, `sprint-log.md`,
64
+ `gate-events.log`, `decisions/decision-log.md`) are append-only: MUST NOT truncate, overwrite,
65
+ or rewrite one — append with a single Edit or `>>`, never a bulk rewrite.
66
+
67
+ **A gate that looks wrong is diagnosed, not bypassed.** The instrument is the suspect, not the
68
+ rule: reproduce the block, read what the guard actually keyed on, name the defect. Until
69
+ diagnosed, the gate stands. A confirmed false positive is a bug filed through its lane;
70
+ `/override` remains for the judged exception, and its log line says which of the two it was.
71
+
72
+ ---
73
+
74
+ ## What survives every mode
75
+
76
+ Even with every gate off, this residual set holds:
77
+
78
+ - The secrets prohibition above has no mode exception.
79
+ - The §6 irreversible-action set is never taken without the confirmation it requires.
80
+ - A conflict is surfaced, never silently reconciled.
81
+ - The §2 conflict hierarchy still orders any tradeoff made unsupervised.
82
+ - The §7 diagnose-don't-bypass discipline still governs any guard actually encountered.
83
+ - State is read, not remembered — a claim about now uses an instrument run now.
84
+
85
+ The rules bind by what they protect, not by their spelling: a path that satisfies a rule's
86
+ letter while defeating its protection is a violation with extra steps.
@@ -20,7 +20,7 @@ the three `plans/` artifacts; `CONTEXT.md` and `open-questions.md` (including it
20
20
  Deferred-decisions sections) constrain at their recorded level. Load index-first: consult the ADR
21
21
  index (`decision-log.md` or the `decisions/` filename listing) and plan section headings only;
22
22
  load a body only after the index names it relevant; never bulk-read `plans/` or `decisions/`
23
- (ORCHESTRATOR §3's no-bulk-reads rule).
23
+ (arbiter.md §3's no-bulk-reads rule).
24
24
 
25
25
  Three outcomes:
26
26
 
@@ -18,7 +18,7 @@ Skill bodies load on routing only. This index is the surface scan; never bulk-re
18
18
  | [writing-plans](writing-plans/SKILL.md) | `/feature`, `/sprint` (after the spec) | Decomposes an approved spec into small tasks, each with a path + a verification that maps to a `tdd` obligation; writes `plans/<slug>.md` with bijective criterion↔task coverage. |
19
19
  | [executing-plans](executing-plans/SKILL.md) | `/feature` | Checkpoint coordinator — groups tasks into batches, delegates each to `subagent-driven-development` (fresh author agent per task, full review chain), stops for user acknowledgement between batches. |
20
20
  | [subagent-driven-development](subagent-driven-development/SKILL.md) | `/sprint` (engine), `executing-plans` (batch scope) | Fresh subagent per task → spec-compliance then quality review → fresh-run verification; accepts only on proof. Hard-stops on `tdd` BLOCK, security CRITICAL, `[CONFIRM-NN]`. |
21
- | [dispatching-parallel-agents](dispatching-parallel-agents/SKILL.md) | `subagent-driven-development`, `/sprint`, parallel `/review` | Reusable fan-out primitive: bound concurrency, collect, dedupe, funnel through `finding-triage`→`checkpoint-aggregator`. Results unused until the funnel runs. |
21
+ | [dispatching-parallel-agents](dispatching-parallel-agents/SKILL.md) | `subagent-driven-development`, `/sprint`, parallel `/review` | Reusable fan-out primitive: bound concurrency, collect, dedupe, funnel through `finding-triage`→`verdict-aggregator`. Results unused until the read-only funnel runs. |
22
22
  | [finishing-a-development-branch](finishing-a-development-branch/SKILL.md) | `/feature`, `/sprint` (terminal) | The terminal step after `commit-gate`: open-PR / merge-via-PR / discard. No direct-to-main, no force-push; `/sprint` auto-selects open-PR and never merges. |
23
23
  | [using-git-worktrees](using-git-worktrees/SKILL.md) | `subagent-driven-development`, `dispatching-parallel-agents` (opt-in) | OPTIONAL per-unit filesystem isolation for parallel work; integrates accepted units back onto the caller's working branch for its single `commit-gate` + finish. Never the default path. |
24
24
  | [secret-handling](secret-handling/SKILL.md) | changed code reads/writes/passes a secret | The secret-source gate: identify → source → sinks/persistence. Secrets only from the approved store in `security-controls.md`; never in source, log, error, telemetry, image, or LLM prompt. Dispatches `auth-crypto-reviewer`. |
@@ -30,7 +30,7 @@ Gate: the existing ADRs are indexed by stem and, for `/adr`, the next number is
30
30
 
31
31
  Confirm the decision content with the user — context, the decision itself, alternatives, consequences. MUST NOT fill these from inference. Surface any unknown as an inline `[CONFIRM-NN]` placeholder; do not resolve it by guessing.
32
32
 
33
- **Drop the authoring marker first.** The `pre-write`/`pre-edit` hooks block any write to `.codearbiter/decisions/NNNN-*.md` unless a fresh authoring marker is present — that block is the mechanism enforcing "ADRs only via `/adr`" (ORCHESTRATOR §3), so the sanctioned path must arm it itself. Immediately before writing, create the marker at the path the hooks check (project root = git top level):
33
+ **Drop the authoring marker first.** The `pre-write`/`pre-edit` hooks block any write to `.codearbiter/decisions/NNNN-*.md` unless a fresh authoring marker is present — that block is the mechanism enforcing "ADRs only via `/adr`" (arbiter.md §3), so the sanctioned path must arm it itself. Immediately before writing, create the marker at the path the hooks check (project root = git top level):
34
34
 
35
35
  ```bash
36
36
  mkdir -p "$(git rev-parse --show-toplevel)/.codearbiter/.markers"
@@ -57,9 +57,59 @@ rm -f "$(git rev-parse --show-toplevel)/.codearbiter/.markers/adr-authoring-acti
57
57
 
58
58
  Gate: the ADR file is written with a real `decided-by` user attribution, numbered without a gap, and its log entry is appended. An ADR with no user attribution, or authored as the disposition of a finding, does not pass — STOP.
59
59
 
60
+ ### Accepted/Planned binding
61
+
62
+ `accepted` means **Accepted/Planned**. It records the user's governance decision; it does not claim
63
+ that any obligation is Implemented or Verified. When the user explicitly authorizes acceptance:
64
+
65
+ 1. Change only the ADR's status fields to accepted. Derive stable, stem-scoped obligations from every
66
+ normative clause in its immutable record, bind each obligation to exact ADR
67
+ text, and obtain independent review that the sealed obligation set is complete.
68
+ 2. Route through `commit-gate` to commit the accepted ADR and decision-log append. Do not add the
69
+ acceptance binding to that commit: its `source_commit` cannot truthfully name a commit that does
70
+ not exist yet.
71
+ 3. From that exact commit, hash the committed Git blob bytes and the separately canonicalized
72
+ immutable record: strict UTF-8 with LF-normalized line endings, containing the complete ADR while
73
+ replacing only the recognized status value in the strictly parsed frontmatter `status:` field and
74
+ `## Status` section with fixed sentinels. The two values must agree. All remaining Status prose,
75
+ including approval attribution, stays bound alongside title, date, `decided-by`, supersession,
76
+ governed paths, H1, and every other section. Malformed or duplicate frontmatter, status, or
77
+ headings fail closed. Append one
78
+ `acceptance` event to
79
+ `<project-root>/.codearbiter/decisions/adr-lifecycle.jsonl`, then persist that acceptance binding
80
+ in a subsequent commit. The event uses schema `adr-lifecycle/v1` and records `adr` (full stem),
81
+ `recorded_at`, `source_commit`, `blob_sha256`, `body_sha256`, `obligations`,
82
+ `obligations_sha256`, and `obligations_sealed: true`. A second acceptance or baseline binding for
83
+ the same stem is invalid.
84
+
85
+ The lifecycle ledger is append-only. A legacy accepted ADR receives a `baseline` with no fabricated
86
+ acceptance commit, an `observed_commit` whose Git blob is rechecked as the migration snapshot, an
87
+ empty or incrementally mapped obligation list, and
88
+ `obligations_sealed: false`; it remains Accepted/Planned. Later delivery evidence appends records:
89
+ `implemented` binds one declared obligation to a source commit and relevant input digests;
90
+ `verified` additionally binds a unique event ID, explicit proof contract, repository-scoped claim,
91
+ producer, command/workflow identity, timezone-aware observation and expiry times, and the same current
92
+ inputs. Evidence paths and digests are recomputed from the named Git commit, never trusted from the
93
+ caller. A later uniquely identified event may renew expired or changed-input evidence; an append-only
94
+ invalidation event may withdraw a prior evidence event. Only a complete,
95
+ sealed obligation set with current implementation inputs and fresh verification inputs derives
96
+ Implemented or Verified. Changed inputs invalidate the derived state; history is never rewritten.
97
+
98
+ After acceptance, do not edit any bound ADR content. A later user-authorized stored status transition
99
+ may change only the recognized status value in the strictly parsed frontmatter `status:` and
100
+ `## Status`; approval prose remains immutable. Supersession remains a forward reference in the new
101
+ ADR. The acceptance commit retains the exact original blob while the immutable-record digest proves
102
+ every other byte-equivalent field did not change.
103
+
60
104
  ## Phase 3 — Status (/adr-status) · gate: BLOCK
61
105
 
62
- Read-only. For each ADR (or the `--adr N` target), report: stem, title, status, date, and supersession state — found by scanning forward for any later ADR whose `supersedes:` **resolves to** it.
106
+ Read-only. For each ADR (or the `--adr N` target), report: stem, title, stored governance status,
107
+ derived delivery state, date, and supersession state. Read `adr-lifecycle.jsonl` when present. Display
108
+ stored `accepted` as **Accepted/Planned**. Display Implemented or Verified only when every obligation
109
+ in a sealed binding has the required current, input-bound evidence; otherwise name the narrow reason
110
+ (unsealed, incomplete, stale, expired, or mismatched) and do not promote the ADR. Repository evidence
111
+ never implies live-host, publication, support, legal, or other external truth. Find supersession by
112
+ scanning forward for any later ADR whose `supersedes:` **resolves to** it.
63
113
 
64
114
  Resolve a `supersedes:` value like this, and never guess:
65
115
 
@@ -75,7 +125,7 @@ If a supersession candidate contradicts an `accepted` ADR with no clear directio
75
125
  ## ADR Status — YYYY-MM-DD
76
126
 
77
127
  ### Active
78
- - ADR-NNNN-<slug> — <title> — <status> (<date>)
128
+ - ADR-NNNN-<slug> — <title> — governance: <status>; delivery: <Accepted/Planned | Implemented | Verified> (<date>)
79
129
 
80
130
  ### Superseded
81
131
  - ADR-NNNN-<slug> — <title> — superseded by ADR-MMMM-<slug>
@@ -97,6 +147,8 @@ Gate: every indexed ADR appears with its current status and supersession state;
97
147
  - MUST NOT record a decision the user did not explicitly make. "Use your best judgment," "I trust you" are declined.
98
148
  - MUST NOT resolve a `[CONFIRM-NN]` placeholder by guessing. Surface it and stop.
99
149
  - MUST NOT advance an ADR's status without explicit user instruction.
150
+ - MUST NOT report accepted as Implemented or Verified without complete, sealed, current lifecycle evidence.
151
+ - MUST NOT rewrite or truncate a committed `adr-lifecycle.jsonl`, create a second binding, or fabricate legacy acceptance evidence.
100
152
  - MUST NOT edit a prior ADR or a prior decision-log entry to add a back-reference — supersession is a forward-only chain; append a new record whose `supersedes:` names the prior one.
101
153
  - **The never-edit rule protects decision CONTENT, not identifiers.** Rewriting what was decided corrupts the record; disambiguating *which document a pointer names* repairs it. Maintainer ruling, 2026-07-25: *"the never edit rule is meant to prevent this situation, not prevent this situation from being fixed."* So a correction that is provably identifier-only — a `supersedes:` value changed from a number to the stem it already meant — is permissible, and nothing else about the file is. Any such correction MUST be a single-line diff that alters not one word of any decision, MUST be visible in its own commit, and still requires the maintainer-armed `adr-authoring-active` marker. MUST NOT touch Context, Decision, Alternatives, Consequences, Risks, `status:`, `date:`, `decided-by:`, or `title:` under this allowance.
102
154
  - MUST NOT number an ADR with a gap, and MUST NOT reuse a number an existing stem already holds — a shared number makes every bare reference to it ambiguous.
@@ -55,8 +55,16 @@ governs: <optional, comma-separated path globs this decision constrains — e.g.
55
55
  mirrors it for human readers. Keep the two in agreement.
56
56
  - **Status lifecycle:** `proposed → accepted → superseded | rejected`. `decompose` authors Layer 4
57
57
  ADRs as **`status: draft`** during the interview and promotes each to `status: accepted` at its
58
- Phase 5 (a frontmatter `status:` edit only never a body rewrite). Status transitions otherwise
58
+ Phase 5 in one sanctioned status edit that changes both the frontmatter `status:` field and the `## Status` value,
59
+ without changing any other body content. Status transitions otherwise
59
60
  require explicit user instruction; never advance status on the skill's own judgment.
61
+ - **`accepted` means Accepted/Planned.** It records an approved governance decision and does not imply
62
+ implementation. Implemented and Verified are derived delivery states from the separate append-only
63
+ `adr-lifecycle.jsonl`; they are never written into ADR frontmatter. After acceptance, the decision
64
+ record is immutable except for the recognized, agreeing status value in the strictly parsed
65
+ frontmatter `status:` field and `## Status` section. Approval attribution and all other Status prose
66
+ remain bound with title, date, `decided-by`, supersession, governed paths, H1, and every other
67
+ section. A later explicit status transition changes only those recognized status values.
60
68
  - **`decided-by:`** names the user who made the decision — real attribution, never inferred.
61
69
  - **`supersedes:`** names the prior ADR's full filename stem — `supersedes:
62
70
  0014-githook-shim-dropin-fail-closed`, not `supersedes: 0014` — or `none`. A bare number is
@@ -12,7 +12,7 @@ Spec the project before a line of code exists. Routed to at greenfield startup,
12
12
  Run these ordered checks. Each passes silently or hard-stops with a routing action — never guess:
13
13
 
14
14
  1. Read `<project-root>/.codearbiter/CONTEXT.md`. If it already carries the `<!--INITIALIZED-->` body marker on its own line, STOP — context exists. Route to normal operation.
15
- 2. Scan for meaningful source code: any file outside `.git/`, `.codearbiter/`, `.claude/`, `ORCHESTRATOR.md`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `LICENSE`, `.gitignore`, `.gitmodules`, and standard tooling dotfiles. If any exist, STOP and route to `/create-context`.
15
+ 2. Scan for meaningful source code: any file outside `.git/`, `.codearbiter/`, `.claude/`, `arbiter.md`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `LICENSE`, `.gitignore`, `.gitmodules`, and standard tooling dotfiles. If any exist, STOP and route to `/create-context`.
16
16
  3. Confirm `<project-root>/.codearbiter/` exists and is writable. If not, surface the gap and STOP.
17
17
 
18
18
  All three pass → proceed to Phase 1. Later phases consume this pass-status; they do not re-run it.