@arbiterforge/ca-pi 0.15.2 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +1 -1
- package/plugins/ca-pi/CHANGELOG.md +62 -0
- package/plugins/ca-pi/COMMANDS.md +3 -9
- package/plugins/ca-pi/SKILLS.md +16 -22
- package/plugins/ca-pi/agents/coverage-auditor.md +16 -2
- package/plugins/ca-pi/generated/command-catalog.json +13 -22
- package/plugins/ca-pi/helpers/artifacts/ca-artifact-darwin-amd64 +0 -0
- package/plugins/ca-pi/helpers/artifacts/ca-artifact-darwin-arm64 +0 -0
- package/plugins/ca-pi/helpers/artifacts/ca-artifact-linux-amd64 +0 -0
- package/plugins/ca-pi/helpers/artifacts/ca-artifact-linux-arm64 +0 -0
- package/plugins/ca-pi/helpers/artifacts/ca-artifact-windows-amd64.exe +0 -0
- package/plugins/ca-pi/helpers/artifacts/ca-artifact-windows-arm64.exe +0 -0
- package/plugins/ca-pi/helpers/artifacts/release.json +6 -6
- package/plugins/ca-pi/hooks/_artifactauthoritylib.py +383 -32
- package/plugins/ca-pi/hooks/_artifactlib.py +3 -1
- package/plugins/ca-pi/hooks/_host.py +1 -1
- package/plugins/ca-pi/hooks/artifact-authority-hook.py +4 -21
- package/plugins/ca-pi/hooks/artifact-authority.py +11 -0
- package/plugins/ca-pi/hooks/hostapi.py +1 -1
- package/plugins/ca-pi/includes/command-compatibility.md +31 -0
- package/plugins/ca-pi/includes/farm.md +187 -36
- package/plugins/ca-pi/includes/maturity-coverage.md +57 -17
- package/plugins/ca-pi/includes/routing-table.md +10 -11
- package/plugins/ca-pi/includes/safety-core.md +2 -2
- package/plugins/ca-pi/package.json +1 -1
- package/plugins/ca-pi/routines/INDEX.md +12 -11
- package/plugins/ca-pi/routines/context-check/SKILL.md +17 -1
- package/plugins/ca-pi/routines/context-creation/SKILL.md +8 -1
- package/plugins/ca-pi/routines/debug/SKILL.md +18 -2
- package/plugins/ca-pi/routines/decision-lifecycle/SKILL.md +72 -118
- package/plugins/ca-pi/routines/decision-lifecycle/references/authoring.md +152 -0
- package/plugins/ca-pi/routines/decision-variance/SKILL.md +107 -133
- package/plugins/ca-pi/routines/decision-variance/references/analysis.md +136 -0
- package/plugins/ca-pi/routines/decompose/SKILL.md +8 -1
- package/plugins/ca-pi/routines/finishing-a-development-branch/SKILL.md +85 -7
- package/plugins/ca-pi/routines/post-merge-cleanup/SKILL.md +19 -2
- package/plugins/ca-pi/routines/refactor/SKILL.md +27 -8
- package/plugins/ca-pi/routines/release/SKILL.md +2 -1
- package/plugins/ca-pi/routines/security-architecture/SKILL.md +14 -3
- package/plugins/ca-pi/routines/tdd/SKILL.md +9 -5
- package/plugins/ca-pi/routines/tribunal/SKILL.md +28 -14
- package/plugins/ca-pi/skills/ca-adr/SKILL.md +103 -18
- package/plugins/ca-pi/skills/ca-adr-status/SKILL.md +6 -24
- package/plugins/ca-pi/skills/ca-cleanup/SKILL.md +241 -52
- package/plugins/ca-pi/skills/ca-context-check/SKILL.md +87 -24
- package/plugins/ca-pi/skills/ca-create-context/SKILL.md +159 -19
- package/plugins/ca-pi/skills/ca-debug/SKILL.md +100 -27
- package/plugins/ca-pi/skills/ca-decompose/SKILL.md +156 -17
- package/plugins/ca-pi/skills/ca-pr/SKILL.md +161 -26
- package/plugins/ca-pi/skills/ca-reconcile/SKILL.md +108 -30
- package/plugins/ca-pi/skills/ca-refactor/SKILL.md +96 -30
- package/plugins/ca-pi/skills/ca-release/SKILL.md +614 -39
- package/plugins/ca-pi/skills/ca-status/SKILL.md +1 -1
- package/plugins/ca-pi/skills/ca-threat-model/SKILL.md +56 -27
- package/plugins/ca-pi/skills/ca-tribunal/SKILL.md +105 -26
- package/plugins/ca-pi/routines/skill-author/SKILL.md +0 -129
- package/plugins/ca-pi/routines/skill-author/references/skill-template.md +0 -58
- package/plugins/ca-pi/skills/ca-new-skill/SKILL.md +0 -129
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context-check
|
|
3
|
-
description:
|
|
3
|
+
description: "Audit stale provenance-tracked docs on request. Report first; re-scout or re-baseline only for selected docs."
|
|
4
|
+
argument-hint: "(none)"
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# context-check
|
|
@@ -15,6 +16,21 @@ This skill is NOT in the daily loop. Commit-gate auto-heal (Phase 5.5,
|
|
|
15
16
|
was introduced outside a commit (e.g. a direct push, a merge you did not
|
|
16
17
|
author, a manual file edit).
|
|
17
18
|
|
|
19
|
+
<!-- catalog-compatibility-notice:start -->
|
|
20
|
+
> Compatibility route. Prefer `/ca-status drift` for new explicit usage. The retained entry
|
|
21
|
+
> and natural-language intent use this owner under
|
|
22
|
+
> <plugin-root>/includes/command-compatibility.md.
|
|
23
|
+
<!-- catalog-compatibility-notice:end -->
|
|
24
|
+
|
|
25
|
+
## Entry boundaries
|
|
26
|
+
|
|
27
|
+
Use this owner for a requested provenance drift audit, `/ca-status drift`, or
|
|
28
|
+
the explicit `/ca-context-check` compatibility entry. Explanation-only questions
|
|
29
|
+
and ordinary status snapshots remain read-only answers, not repair requests.
|
|
30
|
+
Report first. Write only after the user selects re-scout or re-baseline for that
|
|
31
|
+
document; never change an unselected derived document. This owner neither stages
|
|
32
|
+
nor commits. Routine commit-gate auto-heal is unchanged.
|
|
33
|
+
|
|
18
34
|
## Pre-flight
|
|
19
35
|
|
|
20
36
|
Read these before computing drift:
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context-creation
|
|
3
|
-
description:
|
|
3
|
+
description: Build project context from an existing codebase through isolated scouts, resolve gaps, and preserve initialization gates.
|
|
4
|
+
argument-hint: (none)
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# context-creation
|
|
7
8
|
|
|
9
|
+
<!-- catalog-compatibility-notice:start -->
|
|
10
|
+
> Compatibility route. Prefer `/ca-init --brownfield` for new usage. This installed route remains
|
|
11
|
+
> functional under the command-route compatibility policy at <plugin-root>/includes/command-compatibility.md;
|
|
12
|
+
> continue with the unchanged brownfield workflow below.
|
|
13
|
+
<!-- catalog-compatibility-notice:end -->
|
|
14
|
+
|
|
8
15
|
Wrap an existing codebase in project state, without guessing. Routed to by `/create-context`, and by startup when `.codearbiter/CONTEXT.md` exists but carries no `<!--INITIALIZED-->` body marker and meaningful source code is present. When no meaningful source exists, this is the wrong skill — route to `decompose` instead.
|
|
9
16
|
|
|
10
17
|
This back-fills from existing source. It complements `/ca-init`, which scaffolds an empty `.codearbiter/` for a fresh project; here the docs are derived from what is already on disk.
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: debug
|
|
3
|
-
description: "Investigate
|
|
3
|
+
description: "Investigate an unexplained defect or unexpected behavior without changing application code. Use for root-cause diagnosis and an evidence-backed handoff. A no-action close records a board note. Not for implementing a known fix, new features, or explanation-only questions."
|
|
4
|
+
argument-hint: "<observed symptom>"
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# debug
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
Select this owning procedure for a root-cause investigation, whether requested in
|
|
10
|
+
plain language or through `/debug`. The command spelling is not a prerequisite.
|
|
11
|
+
Investigation and implementation remain separate: this procedure never changes code.
|
|
12
|
+
It closes the reproduce, evidence, and regression-test handoff loop through `/fix`.
|
|
13
|
+
|
|
14
|
+
## Entry boundaries
|
|
15
|
+
|
|
16
|
+
- A known bug with a named regression test belongs to `/fix` directly.
|
|
17
|
+
- A design discussion without failing behavior belongs to `/adr`; attribution is
|
|
18
|
+
still required before authoring an ADR. New behavior belongs to `/feature`.
|
|
19
|
+
- An explanation-only question stays in the non-mutating question-answer path;
|
|
20
|
+
it does not require a debug invocation or a command spelled by the user.
|
|
21
|
+
- Do not re-enter from an active `/fix` or `/adr` invocation. Complete that
|
|
22
|
+
invocation before a separate investigation; do not create a routing cycle.
|
|
23
|
+
- The phase gates below own symptom precision, evidence, and the one named exit.
|
|
24
|
+
A no-action close uses the board helper in Phase 5, never a direct file append.
|
|
9
25
|
|
|
10
26
|
## Pre-flight
|
|
11
27
|
|
|
@@ -1,116 +1,61 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: decision-lifecycle
|
|
3
|
-
description:
|
|
3
|
+
description: "Record user-decided ADRs or inspect their health read-only. Preserve attribution and acceptance evidence."
|
|
4
|
+
argument-hint: "<decision title>"
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# decision-lifecycle
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
rm -f "$(git rev-parse --show-toplevel)/.codearbiter/.markers/adr-authoring-active"
|
|
56
|
-
```
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
4. Preserve **ADR source ancestry** through delivery. Before opening the PR and again before
|
|
85
|
-
its merge offer, follow the finishing skill's `--merge-method` preflight on the exact base/head.
|
|
86
|
-
A source not already in base ancestry requires a true merge commit with `--match-head-commit`;
|
|
87
|
-
squash or rebase would orphan its identity. Missing source ancestry blocks delivery. Never
|
|
88
|
-
rewrite the acceptance binding or rely on deleted branch objects remaining remotely fetchable.
|
|
89
|
-
|
|
90
|
-
The lifecycle ledger is append-only. A legacy accepted ADR receives a `baseline` with no fabricated
|
|
91
|
-
acceptance commit, an `observed_commit` whose Git blob is rechecked as the migration snapshot, an
|
|
92
|
-
empty or incrementally mapped obligation list, and
|
|
93
|
-
`obligations_sealed: false`; it remains Accepted/Planned. Later delivery evidence appends records:
|
|
94
|
-
`implemented` binds one declared obligation to a source commit and relevant input digests;
|
|
95
|
-
`verified` additionally binds a unique event ID, explicit proof contract, repository-scoped claim,
|
|
96
|
-
producer, command/workflow identity, timezone-aware observation and expiry times, and the same current
|
|
97
|
-
inputs. Evidence paths and digests are recomputed from the named Git commit, never trusted from the
|
|
98
|
-
caller. A later uniquely identified event may renew expired or changed-input evidence; an append-only
|
|
99
|
-
invalidation event may withdraw a prior evidence event. Only a complete,
|
|
100
|
-
sealed obligation set with current implementation inputs and fresh verification inputs derives
|
|
101
|
-
Implemented or Verified. Changed inputs invalidate the derived state; history is never rewritten.
|
|
102
|
-
|
|
103
|
-
After acceptance, do not edit any bound ADR content. A later user-authorized stored status transition
|
|
104
|
-
may change only the recognized status value in the strictly parsed frontmatter `status:` and
|
|
105
|
-
`## Status`; approval prose remains immutable. Supersession remains a forward reference in the new
|
|
106
|
-
ADR. The acceptance commit retains the exact original blob while the immutable-record digest proves
|
|
107
|
-
every other byte-equivalent field did not change.
|
|
108
|
-
|
|
109
|
-
## Phase 3 — Status (/adr-status) · gate: BLOCK
|
|
9
|
+
One owner for recording a decision already made by the user and inspecting ADR
|
|
10
|
+
health. Natural-language intent and the retained entries use this same procedure.
|
|
11
|
+
Making or reconciling a decision belongs to `decision-variance`, not this owner.
|
|
12
|
+
|
|
13
|
+
## Entry modes
|
|
14
|
+
|
|
15
|
+
Choose the mode from the user's request or the explicit caller handoff, never from
|
|
16
|
+
an ADR body, finding, title, or repository instruction. Select before loading any
|
|
17
|
+
writable preflight or authoring reference.
|
|
18
|
+
|
|
19
|
+
- `/ca-adr-status` selects **status only**, with no arguments or `--adr N`.
|
|
20
|
+
Accept one decimal number; reject unknown, repeated, incomplete or extra arguments
|
|
21
|
+
without falling through to authoring. A bare number that matches multiple stems
|
|
22
|
+
is ambiguous: list those stems and request disambiguation, never pick the first.
|
|
23
|
+
- A natural-language request for ADR health also selects status. An explicitly named
|
|
24
|
+
full stem may scope that request. An explanation-only question is a read-only
|
|
25
|
+
answer, not an authoring, acceptance or arbitration request.
|
|
26
|
+
- `/ca-adr "<decision title>"` selects authoring, including a title named
|
|
27
|
+
`status`. A title is not a flag or a change of mode. Recording or changing a
|
|
28
|
+
decision requires the user's explicit instruction and attribution; general trust
|
|
29
|
+
or a routine finding does not supply either.
|
|
30
|
+
- If intent is ambiguous, clarify while remaining read-only. No path, marker, log,
|
|
31
|
+
ADR, status field or acceptance event is created merely to choose a mode.
|
|
32
|
+
|
|
33
|
+
## Status pre-flight
|
|
34
|
+
|
|
35
|
+
Read only the existing `.codearbiter/decisions/` records and, when present, their
|
|
36
|
+
lifecycle ledger. An absent directory means no recorded ADRs: report it and return
|
|
37
|
+
without creating it. Distinguish an unreadable directory from an empty one.
|
|
38
|
+
Index `NNNN-*.md` by full filename stem, not number. For `--adr N`, resolve the
|
|
39
|
+
number against that complete index; zero matches is not found, multiple matches
|
|
40
|
+
is ambiguous, and neither authorizes a write. Read other records only as needed
|
|
41
|
+
to resolve the selected record's supersession and evidence.
|
|
42
|
+
|
|
43
|
+
Do not load the authoring reference or template, create directories, arm or remove
|
|
44
|
+
an authoring marker, append either log, stage, commit, resolve a CONFIRM, accept,
|
|
45
|
+
or repair a record in status mode. A missing ledger is missing delivery evidence,
|
|
46
|
+
not permission to create a baseline. Invalid evidence is reported, not repaired.
|
|
47
|
+
Report recorded age and challenge evidence; flag aged/unchallenged decisions using
|
|
48
|
+
available project criteria and dates, not an invented age cutoff or inferred review.
|
|
49
|
+
A missing challenge record is unknown, not proof that no challenge ever happened.
|
|
50
|
+
Optional `decision-challenger` dispatch inherits read-only scope and returns findings;
|
|
51
|
+
missing prerequisites for that optional dispatch never authorize initialization.
|
|
52
|
+
|
|
53
|
+
## Status mode — read-only report
|
|
110
54
|
|
|
111
55
|
Read-only. For each ADR (or the `--adr N` target), report: stem, title, stored governance status,
|
|
112
56
|
derived delivery state, date, and supersession state. Read `adr-lifecycle.jsonl` when present. Display
|
|
113
|
-
stored `accepted` as **Accepted/Planned**.
|
|
57
|
+
stored `accepted` as **Accepted/Planned**. Draft or proposed records without an
|
|
58
|
+
acceptance binding remain unaccepted; report no accepted binding, never promote them. Display Implemented or Verified only when every obligation
|
|
114
59
|
in a sealed binding has the required current, input-bound evidence; otherwise name the narrow reason
|
|
115
60
|
(unsealed, incomplete, stale, expired, or mismatched) and do not promote the ADR. Repository evidence
|
|
116
61
|
never implies live-host, publication, support, legal, or other external truth. Find supersession by
|
|
@@ -122,7 +67,9 @@ Resolve a `supersedes:` value like this, and never guess:
|
|
|
122
67
|
- The value is a **bare number** → collect every stem with that number. Exactly one → it names that ADR. More than one → **ambiguous: report it as an error and resolve nothing.** Zero → a dangling reference; report that too.
|
|
123
68
|
- `none` (or empty) → no predecessor.
|
|
124
69
|
|
|
125
|
-
`.github/scripts/check_adr_identity.py` enforces this
|
|
70
|
+
The CI-only checker `.github/scripts/check_adr_identity.py` enforces this rule
|
|
71
|
+
in the codeArbiter source repository. It is not shipped to consumer repositories;
|
|
72
|
+
do not invent or require an installed copy. Follow the same full-stem rule there.
|
|
126
73
|
|
|
127
74
|
If a supersession candidate contradicts an `accepted` ADR with no clear direction, do not pick one — flag it for `/conflict`.
|
|
128
75
|
|
|
@@ -130,7 +77,7 @@ If a supersession candidate contradicts an `accepted` ADR with no clear directio
|
|
|
130
77
|
## ADR Status — YYYY-MM-DD
|
|
131
78
|
|
|
132
79
|
### Active
|
|
133
|
-
- ADR-NNNN-<slug> — <title> — governance: <status>; delivery: <Accepted/Planned | Implemented | Verified> (<date>)
|
|
80
|
+
- ADR-NNNN-<slug> — <title> — governance: <status>; delivery: <no accepted binding | Accepted/Planned | Implemented | Verified> (<date>)
|
|
134
81
|
|
|
135
82
|
### Superseded
|
|
136
83
|
- ADR-NNNN-<slug> — <title> — superseded by ADR-MMMM-<slug>
|
|
@@ -144,18 +91,25 @@ If a supersession candidate contradicts an `accepted` ADR with no clear directio
|
|
|
144
91
|
|
|
145
92
|
Every ADR is named by its stem, so a shared number never collapses two rows into one. An empty section is marked "None" — not omitted. MAY dispatch `decision-challenger` (`<plugin-root>/agents/decision-challenger.md`) to stress-test an ADR; optional, never forced.
|
|
146
93
|
|
|
147
|
-
Gate: every
|
|
94
|
+
Gate: every selected ADR appears with its current status and supersession state; no `[CONFIRM-NN]` resolved; no file modified.
|
|
95
|
+
|
|
96
|
+
## Authoring mode — on-demand procedure
|
|
97
|
+
|
|
98
|
+
Only after selecting explicitly authorized authoring or a stored status transition,
|
|
99
|
+
load `<plugin-root>/routines/decision-lifecycle/references/authoring.md` and follow
|
|
100
|
+
that procedure. It owns indexing for numbering, confirmed content, marker lifetime,
|
|
101
|
+
the shared ADR template, append-only logs and exact acceptance/delivery binding.
|
|
102
|
+
Do not return through a command wrapper or load it again. A status report returns
|
|
103
|
+
to its caller and never continues into this authoring path.
|
|
148
104
|
|
|
149
105
|
## Hard rules
|
|
150
106
|
|
|
151
|
-
-
|
|
152
|
-
|
|
153
|
-
-
|
|
154
|
-
|
|
155
|
-
-
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
|
|
159
|
-
-
|
|
160
|
-
- MUST NOT modify any file under `/adr-status` — it is read-only.
|
|
161
|
-
- MUST NOT force the `decision-challenger` agent — its dispatch is MAY only.
|
|
107
|
+
- Read-only status never modifies a file, index, marker or ledger, even to repair
|
|
108
|
+
evidence or resolve a `[CONFIRM-NN]`. Surface unresolved questions and stop.
|
|
109
|
+
- Every authored decision is explicitly user-attributed, never an inferred
|
|
110
|
+
disposition of a routine finding. Explicit status changes are separate authority.
|
|
111
|
+
- Stored `accepted` means **Accepted/Planned**, not Implemented or Verified.
|
|
112
|
+
Delivery claims need complete, sealed, current input-bound lifecycle evidence.
|
|
113
|
+
- Preserve full-stem identity and forward-only supersession. Report ambiguous or
|
|
114
|
+
dangling references; never collapse records sharing a number or repair a fork.
|
|
115
|
+
- Optional challenge is MAY, not another mandatory approval or authoring step.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# ADR authoring and acceptance
|
|
2
|
+
|
|
3
|
+
Load only after `decision-lifecycle` selects an explicitly authorized authoring or
|
|
4
|
+
status-transition action. Do not load this procedure for read-only ADR health.
|
|
5
|
+
Read `<plugin-root>/includes/smarts/decision-log-format.md` before any log append.
|
|
6
|
+
A confirmed decision need not be confirmed again unchanged; missing content and
|
|
7
|
+
new status transitions still require their existing explicit user authorization.
|
|
8
|
+
|
|
9
|
+
## Existing-record transitions
|
|
10
|
+
|
|
11
|
+
For a user-requested stored status change, resolve the exact existing stem first.
|
|
12
|
+
Do not create a missing directory, allocate a new number, or author a replacement
|
|
13
|
+
Proposed record for that request. Apply only the explicitly authorized transition
|
|
14
|
+
under the marker and immutable-record rules below. Acceptance uses the exact
|
|
15
|
+
Accepted/Planned binding sequence; a stored status update alone is not evidence.
|
|
16
|
+
A health scan never enters this procedure. New-record authoring follows the phases below.
|
|
17
|
+
|
|
18
|
+
## Pre-flight
|
|
19
|
+
|
|
20
|
+
Read existing storage before changing it; never guess a path:
|
|
21
|
+
|
|
22
|
+
- `<project-root>/.codearbiter/decisions/` — if present, read the directory and
|
|
23
|
+
its existing records. Unreadable existing storage is a STOP, not an empty index.
|
|
24
|
+
Only an explicitly authorized new-record request may create an absent directory.
|
|
25
|
+
Read-only status and changes to an existing record never create a missing directory.
|
|
26
|
+
- For `/adr`: confirm the user explicitly authorized this decision and supplied (or confirmed) its content. An ADR is never authored as the disposition of a routine finding.
|
|
27
|
+
|
|
28
|
+
## Phase 1 — Index · gate: BLOCK
|
|
29
|
+
|
|
30
|
+
Scan `<project-root>/.codearbiter/decisions/` for existing `NNNN-*.md` ADR files. Record each by **filename stem** (`0014-githook-shim-dropin-fail-closed`), title, and status. Determine the next sequential number (no gaps) for `/adr`; for `/adr-status` this is the working set.
|
|
31
|
+
|
|
32
|
+
**The stem is the identifier; the number is only a sort key.** Two ADRs may already share a number — this repository holds two numbered 0014 — so a bare number can name more than one document. Index by stem, and never assume `NNNN` resolves to one file until you have checked.
|
|
33
|
+
|
|
34
|
+
Gate: the existing ADRs are indexed by stem and, for `/adr`, the next number is fixed and **unused** — a number already taken by an existing stem is not available, even for an unrelated decision.
|
|
35
|
+
|
|
36
|
+
## Phase 2 — Author (/adr) · gate: STOP
|
|
37
|
+
|
|
38
|
+
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.
|
|
39
|
+
|
|
40
|
+
**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 requires the authorized authoring workflow to arm its own marker. Direct owner routing executes the same `/adr` procedure, not a second authorization path. Immediately before writing, resolve the **same project root as the ADR guards**
|
|
41
|
+
using the installed `_hooklib.project_root()` in the current host/session context.
|
|
42
|
+
Those guards use `project_root()`, not the general security/migration `marker_root()`;
|
|
43
|
+
do not unconditionally climb to the main worktree or use a fresh Git toplevel guess.
|
|
44
|
+
Claude's project-directory signal can legitimately name the main checkout while
|
|
45
|
+
execution is in a linked checkout; Codex and Pi use their own host resolution.
|
|
46
|
+
|
|
47
|
+
Use the host's already resolved native Python 3 executable as `PY` in this Bash
|
|
48
|
+
form (equivalent native-shell filesystem operations are allowed). Pass the trusted
|
|
49
|
+
installed hooks directory, not a project module with the same name. Preserve the
|
|
50
|
+
resolved `ADR_MARKER_ROOT` and exact marker path in workflow context for cleanup,
|
|
51
|
+
including across separate shell calls. A resolver failure or empty result stops
|
|
52
|
+
before any marker write:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
ADR_MARKER_ROOT="$("$PY" -c 'import sys; from pathlib import Path; sys.path.insert(0, sys.argv[1]); from _hooklib import project_root; print(Path(project_root()).as_posix())' "<plugin-root>/hooks")" || exit 1
|
|
56
|
+
[ -n "$ADR_MARKER_ROOT" ] || exit 1
|
|
57
|
+
mkdir -p "$ADR_MARKER_ROOT/.codearbiter/.markers"
|
|
58
|
+
touch "$ADR_MARKER_ROOT/.codearbiter/.markers/adr-authoring-active"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The marker is honored for 30 minutes. Then write `<project-root>/.codearbiter/decisions/NNNN-<slug>.md` using the canonical ADR template — `<plugin-root>/routines/decision-lifecycle/references/adr-template.md` (the single source of truth for the ADR shape, shared with `decompose`). Author it with `status: proposed`. If this decision supersedes an existing one, set `supersedes:` to that ADR's **full filename stem** — `supersedes: 0014-githook-shim-dropin-fail-closed`, never `supersedes: 0014` — and leave the prior ADR's file untouched (forward-only chain — do not edit it to add a back-reference).
|
|
62
|
+
|
|
63
|
+
If the new ADR supersedes only *part* of the prior decision, say which part in the body. `supersedes:` names a document, not a clause, so a chain may legitimately fork — two ADRs can each supersede different clauses of one predecessor. That fork is correct and must not be "repaired"; only the prose can carry the scope.
|
|
64
|
+
|
|
65
|
+
After writing the ADR, append a corresponding entry to the decision log per the format in `<plugin-root>/includes/smarts/decision-log-format.md` — `Decided by:` names the user. Status transitions (`proposed → accepted → superseded | rejected`) require explicit user instruction; never advance status on this skill's own judgment.
|
|
66
|
+
|
|
67
|
+
**`governs:` makes the decision live.** When an ADR names path globs in `governs:`, the post-write
|
|
68
|
+
hook surfaces a one-line notice on any Write/Edit touching a matching file — "this file is governed
|
|
69
|
+
by ADR-NNNN" — so a recorded decision pushes back at edit time instead of waiting for a checkpoint
|
|
70
|
+
sweep. Offer the field whenever a decision constrains identifiable files; omit it for decisions
|
|
71
|
+
without a file footprint. Globs are fnmatch-style against repo-relative forward-slash paths.
|
|
72
|
+
|
|
73
|
+
On every exit after arming it, remove the marker, including ADR-write,
|
|
74
|
+
decision-log-append and status-edit failures, cancellation, or a controlled pause.
|
|
75
|
+
Run cleanup before returning or stopping after marker creation. On success, remove
|
|
76
|
+
it after the ADR file, log entry and any authorized status edit are written. Use
|
|
77
|
+
the exact previously resolved path, even if cwd changed or shell calls are separate.
|
|
78
|
+
Do not resolve a different root during cleanup; it exists only for one authoring pass.
|
|
79
|
+
Do not install an exit trap on the marker-creation shell alone: that would remove
|
|
80
|
+
authority before subsequent host Write/Edit calls. On a cleanup failure, report
|
|
81
|
+
the exact remaining marker path and original failure; do not claim the pass closed
|
|
82
|
+
or continue ADR writes. This cooperative procedure is not crash-safe cleanup after
|
|
83
|
+
a forcibly terminated process; the existing freshness limit is not immediate cleanup.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
rm -f "$ADR_MARKER_ROOT/.codearbiter/.markers/adr-authoring-active"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
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.
|
|
90
|
+
|
|
91
|
+
### Accepted/Planned binding
|
|
92
|
+
|
|
93
|
+
`accepted` means **Accepted/Planned**. It records the user's governance decision; it does not claim
|
|
94
|
+
that any obligation is Implemented or Verified. When the user explicitly authorizes acceptance:
|
|
95
|
+
|
|
96
|
+
1. Change only the ADR's status fields to accepted. Derive stable, stem-scoped obligations from every
|
|
97
|
+
normative clause in its immutable record, bind each obligation to exact ADR
|
|
98
|
+
text, and obtain independent review that the sealed obligation set is complete.
|
|
99
|
+
2. Route through `commit-gate` to commit the accepted ADR and decision-log append. Do not add the
|
|
100
|
+
acceptance binding to that commit: its `source_commit` cannot truthfully name a commit that does
|
|
101
|
+
not exist yet.
|
|
102
|
+
3. From that exact commit, hash the committed Git blob bytes and the separately canonicalized
|
|
103
|
+
immutable record: strict UTF-8 with LF-normalized line endings, containing the complete ADR while
|
|
104
|
+
replacing only the recognized status value in the strictly parsed frontmatter `status:` field and
|
|
105
|
+
`## Status` section with fixed sentinels. The two values must agree. All remaining Status prose,
|
|
106
|
+
including approval attribution, stays bound alongside title, date, `decided-by`, supersession,
|
|
107
|
+
governed paths, H1, and every other section. Malformed or duplicate frontmatter, status, or
|
|
108
|
+
headings fail closed. Append one
|
|
109
|
+
`acceptance` event to
|
|
110
|
+
`<project-root>/.codearbiter/decisions/adr-lifecycle.jsonl`, then persist that acceptance binding
|
|
111
|
+
in a subsequent commit. The event uses schema `adr-lifecycle/v1` and records `adr` (full stem),
|
|
112
|
+
`recorded_at`, `source_commit`, `blob_sha256`, `body_sha256`, `obligations`,
|
|
113
|
+
`obligations_sha256`, and `obligations_sealed: true`. A second acceptance or baseline binding for
|
|
114
|
+
the same stem is invalid.
|
|
115
|
+
4. Preserve **ADR source ancestry** through delivery. Before opening the PR and again before
|
|
116
|
+
its merge offer, follow the finishing skill's `--merge-method` preflight on the exact base/head.
|
|
117
|
+
A source not already in base ancestry requires a true merge commit with `--match-head-commit`;
|
|
118
|
+
squash or rebase would orphan its identity. Missing source ancestry blocks delivery. Never
|
|
119
|
+
rewrite the acceptance binding or rely on deleted branch objects remaining remotely fetchable.
|
|
120
|
+
|
|
121
|
+
The lifecycle ledger is append-only. A legacy accepted ADR receives a `baseline` with no fabricated
|
|
122
|
+
acceptance commit, an `observed_commit` whose Git blob is rechecked as the migration snapshot, an
|
|
123
|
+
empty or incrementally mapped obligation list, and
|
|
124
|
+
`obligations_sealed: false`; it remains Accepted/Planned. Later delivery evidence appends records:
|
|
125
|
+
`implemented` binds one declared obligation to a source commit and relevant input digests;
|
|
126
|
+
`verified` additionally binds a unique event ID, explicit proof contract, repository-scoped claim,
|
|
127
|
+
producer, command/workflow identity, timezone-aware observation and expiry times, and the same current
|
|
128
|
+
inputs. Evidence paths and digests are recomputed from the named Git commit, never trusted from the
|
|
129
|
+
caller. A later uniquely identified event may renew expired or changed-input evidence; an append-only
|
|
130
|
+
invalidation event may withdraw a prior evidence event. Only a complete,
|
|
131
|
+
sealed obligation set with current implementation inputs and fresh verification inputs derives
|
|
132
|
+
Implemented or Verified. Changed inputs invalidate the derived state; history is never rewritten.
|
|
133
|
+
|
|
134
|
+
After acceptance, do not edit any bound ADR content. A later user-authorized stored status transition
|
|
135
|
+
may change only the recognized status value in the strictly parsed frontmatter `status:` and
|
|
136
|
+
`## Status`; approval prose remains immutable. Supersession remains a forward reference in the new
|
|
137
|
+
ADR. The acceptance commit retains the exact original blob while the immutable-record digest proves
|
|
138
|
+
every other byte-equivalent field did not change.
|
|
139
|
+
|
|
140
|
+
## Hard rules
|
|
141
|
+
|
|
142
|
+
- MUST author an ADR only through this owner's authorized authoring mode with explicit user attribution. MUST NOT author an ADR as the disposition of a routine finding — an out-of-scope finding gets an inline `[NEEDS-TRIAGE]` marker instead.
|
|
143
|
+
- MUST NOT record a decision the user did not explicitly make. "Use your best judgment," "I trust you" are declined.
|
|
144
|
+
- MUST NOT resolve a `[CONFIRM-NN]` placeholder by guessing. Surface it and stop.
|
|
145
|
+
- MUST NOT advance an ADR's status without explicit user instruction.
|
|
146
|
+
- MUST NOT report accepted as Implemented or Verified without complete, sealed, current lifecycle evidence.
|
|
147
|
+
- MUST NOT rewrite or truncate a committed `adr-lifecycle.jsonl`, create a second binding, or fabricate legacy acceptance evidence.
|
|
148
|
+
- 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.
|
|
149
|
+
- **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.
|
|
150
|
+
- 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.
|
|
151
|
+
- MUST NOT modify any file under `/adr-status` — it is read-only.
|
|
152
|
+
- MUST NOT force the `decision-challenger` agent — its dispatch is MAY only.
|