@arbiterforge/ca-pi 0.15.10 → 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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/plugins/ca-pi/CHANGELOG.md +45 -0
- package/plugins/ca-pi/SKILLS.md +1 -1
- package/plugins/ca-pi/agents/infra-author.md +7 -1
- package/plugins/ca-pi/agents/scout.md +40 -8
- package/plugins/ca-pi/generated/command-catalog.json +1 -1
- 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 +104 -6
- package/plugins/ca-pi/hooks/_activationlib.py +97 -13
- package/plugins/ca-pi/hooks/_arbiterstatelib.py +7 -2
- package/plugins/ca-pi/hooks/_artifactauthoritylib.py +519 -16
- package/plugins/ca-pi/hooks/_artifactlib.py +244 -7
- package/plugins/ca-pi/hooks/_artifactpromptlib.py +106 -2
- package/plugins/ca-pi/hooks/_bashguardlib.py +23 -8
- package/plugins/ca-pi/hooks/_contextreportlib.py +564 -6
- package/plugins/ca-pi/hooks/_contextselectlib.py +464 -0
- package/plugins/ca-pi/hooks/_contextsnapshotlib.py +999 -0
- package/plugins/ca-pi/hooks/_debughandofflib.py +767 -0
- package/plugins/ca-pi/hooks/_hooklib.py +2 -1
- package/plugins/ca-pi/hooks/_host.py +1 -1
- package/plugins/ca-pi/hooks/_intentlib.py +5 -5
- package/plugins/ca-pi/hooks/_protectedlib.py +3 -3
- package/plugins/ca-pi/hooks/_protectedstatelib.py +152 -2
- package/plugins/ca-pi/hooks/_provenancelib.py +604 -34
- package/plugins/ca-pi/hooks/_readinjectlib.py +131 -1
- package/plugins/ca-pi/hooks/_sensitivelib.py +28 -14
- package/plugins/ca-pi/hooks/artifact-authority-hook.py +1 -0
- package/plugins/ca-pi/hooks/artifact-authority.py +25 -1
- package/plugins/ca-pi/hooks/debug-handoff.py +85 -0
- package/plugins/ca-pi/hooks/doctor.py +4 -2
- package/plugins/ca-pi/hooks/git-enforce.py +7 -6
- package/plugins/ca-pi/hooks/hostapi.py +1 -1
- package/plugins/ca-pi/hooks/init-codearbiter.py +143 -15
- package/plugins/ca-pi/hooks/prompt-submit.py +14 -0
- package/plugins/ca-pi/hooks/session-start.py +26 -7
- package/plugins/ca-pi/includes/artifacts.md +41 -0
- package/plugins/ca-pi/includes/author-tdd-workflow.md +16 -4
- package/plugins/ca-pi/includes/helper-invocation.md +128 -0
- package/plugins/ca-pi/includes/pi-host-notes.md +13 -0
- package/plugins/ca-pi/includes/routing-table.md +1 -1
- package/plugins/ca-pi/includes/security-gate-record.md +5 -3
- package/plugins/ca-pi/package.json +1 -1
- package/plugins/ca-pi/routines/INDEX.md +1 -1
- package/plugins/ca-pi/routines/commit-gate/SKILL.md +5 -3
- package/plugins/ca-pi/routines/context-check/SKILL.md +103 -17
- package/plugins/ca-pi/routines/context-creation/SKILL.md +290 -54
- package/plugins/ca-pi/routines/debug/SKILL.md +303 -55
- package/plugins/ca-pi/routines/debug/references/debug-handoff.schema.json +879 -0
- package/plugins/ca-pi/routines/debug/references/handoff.md +155 -0
- package/plugins/ca-pi/routines/decompose/SKILL.md +13 -0
- package/plugins/ca-pi/routines/subagent-driven-development/SKILL.md +34 -0
- package/plugins/ca-pi/routines/tdd/SKILL.md +91 -17
- package/plugins/ca-pi/skills/ca-commit/SKILL.md +5 -3
- package/plugins/ca-pi/skills/ca-context-check/SKILL.md +103 -17
- package/plugins/ca-pi/skills/ca-create-context/SKILL.md +290 -54
- package/plugins/ca-pi/skills/ca-debug/SKILL.md +303 -55
- package/plugins/ca-pi/skills/ca-decompose/SKILL.md +13 -0
- package/plugins/ca-pi/skills/ca-feature/SKILL.md +1 -1
- package/plugins/ca-pi/skills/ca-fix/SKILL.md +36 -3
- package/plugins/ca-pi/skills/ca-init/SKILL.md +19 -0
- package/plugins/ca-pi/skills/ca-review/SKILL.md +33 -4
- package/plugins/ca-pi/skills/ca-status/SKILL.md +5 -0
- package/plugins/ca-pi/skills/ca-task/SKILL.md +55 -8
|
@@ -12,11 +12,16 @@
|
|
|
12
12
|
# Usage:
|
|
13
13
|
# python init-codearbiter.py [--root PATH] [--stage N]
|
|
14
14
|
# python init-codearbiter.py --check # report state, create nothing
|
|
15
|
+
# python init-codearbiter.py --check --passive --root PATH # external pre-session read
|
|
15
16
|
# python init-codearbiter.py --repair-lock-exclusion [--root PATH]
|
|
17
|
+
# python init-codearbiter.py --root PATH --context-request FILE # bounded writer bridge, including initialized refresh
|
|
16
18
|
|
|
17
19
|
import argparse
|
|
20
|
+
import json
|
|
18
21
|
import subprocess
|
|
19
22
|
import os
|
|
23
|
+
import re
|
|
24
|
+
import stat
|
|
20
25
|
import sys
|
|
21
26
|
|
|
22
27
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
@@ -25,6 +30,8 @@ from _taskboardlib import DONE_TASKS # noqa: E402 — shared archive template (
|
|
|
25
30
|
import hostapi # noqa: E402 — host seam (ADR-0011)
|
|
26
31
|
import _hooklib # noqa: E402 — set_host DI seam (#257)
|
|
27
32
|
import _entrylib # noqa: E402 — shared run() dispatch (jscpd dedup)
|
|
33
|
+
from _activationlib import passive_activation_inventory # noqa: E402
|
|
34
|
+
import _artifactlib # noqa: E402
|
|
28
35
|
|
|
29
36
|
# NOTE: this stub deliberately does NOT contain the initialization sentinel
|
|
30
37
|
# (an HTML comment wrapping the word INITIALIZED). The SessionStart hook greps
|
|
@@ -122,17 +129,132 @@ def project_root(opt):
|
|
|
122
129
|
return os.path.abspath(os.getcwd())
|
|
123
130
|
|
|
124
131
|
|
|
132
|
+
def _regular_scaffold_entry(path, *, directory):
|
|
133
|
+
"""Reject aliases and reparse points before reading or creating scaffold state."""
|
|
134
|
+
try:
|
|
135
|
+
info = os.lstat(path)
|
|
136
|
+
except OSError:
|
|
137
|
+
return False
|
|
138
|
+
reparse = getattr(info, "st_file_attributes", 0) & getattr(
|
|
139
|
+
stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0)
|
|
140
|
+
return not reparse and (stat.S_ISDIR(info.st_mode) if directory
|
|
141
|
+
else stat.S_ISREG(info.st_mode))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _scaffold_inventory(cad, ctx, requested_stage):
|
|
145
|
+
"""Return absent scaffold names only when surviving state is safe to retain."""
|
|
146
|
+
names = ("CONTEXT.md", *FILES)
|
|
147
|
+
if os.path.lexists(cad) and not _regular_scaffold_entry(cad, directory=True):
|
|
148
|
+
raise SystemExit(f"REFUSING: {cad} is not a regular project-state directory.")
|
|
149
|
+
present = {name for name in names if os.path.lexists(os.path.join(cad, name))}
|
|
150
|
+
if not present:
|
|
151
|
+
if os.path.isdir(cad) and os.listdir(cad):
|
|
152
|
+
raise SystemExit(f"REFUSING: {cad} has existing state without a scaffold; inspect it first.")
|
|
153
|
+
return list(names), False
|
|
154
|
+
for name in present:
|
|
155
|
+
path = os.path.join(cad, name)
|
|
156
|
+
if not _regular_scaffold_entry(path, directory=False):
|
|
157
|
+
raise SystemExit(f"REFUSING: {path} is not a regular scaffold file.")
|
|
158
|
+
if "CONTEXT.md" not in present:
|
|
159
|
+
# A missing stub amid content/provenance may be an interrupted native
|
|
160
|
+
# transaction. Only the known scaffold prefix can be resumed here.
|
|
161
|
+
unexpected = set(os.listdir(cad)) - set(FILES)
|
|
162
|
+
if unexpected:
|
|
163
|
+
raise SystemExit(f"REFUSING: {ctx} is absent amid other project state; inspect prior write outcome.")
|
|
164
|
+
else:
|
|
165
|
+
try:
|
|
166
|
+
with open(ctx, encoding="utf-8") as handle:
|
|
167
|
+
body = handle.read()
|
|
168
|
+
except (OSError, UnicodeError) as exc:
|
|
169
|
+
raise SystemExit(f"REFUSING: cannot inspect {ctx}: {exc}") from None
|
|
170
|
+
enabled, malformed = _hooklib.frontmatter_enabled_text(body)
|
|
171
|
+
lines = body.splitlines()
|
|
172
|
+
boundary = next((index for index, line in enumerate(lines[1:], 1)
|
|
173
|
+
if line.strip() == "---"), None)
|
|
174
|
+
stages = ([match.group(1) for line in lines[1:boundary]
|
|
175
|
+
if (match := re.fullmatch(r"\s*stage:\s*([1-9][0-9]*)\s*", line))]
|
|
176
|
+
if boundary is not None else [])
|
|
177
|
+
if (not enabled or malformed or len(stages) != 1 or
|
|
178
|
+
_hooklib.initialized_body_text(body)):
|
|
179
|
+
raise SystemExit(f"REFUSING: {ctx} is invalid or initialized; inspect before recovery.")
|
|
180
|
+
if requested_stage is not None and int(stages[0]) != requested_stage:
|
|
181
|
+
raise SystemExit(f"REFUSING: {ctx} stage differs from --stage; preserve existing context.")
|
|
182
|
+
headers = {"open-tasks.md": "# Open tasks", "done-tasks.md": "# Done tasks",
|
|
183
|
+
"open-questions.md": "# Open questions",
|
|
184
|
+
"overrides.log": "# codeArbiter override log"}
|
|
185
|
+
for name in present & headers.keys():
|
|
186
|
+
path = os.path.join(cad, name)
|
|
187
|
+
try:
|
|
188
|
+
with open(path, encoding="utf-8") as handle:
|
|
189
|
+
valid = handle.readline().rstrip("\r\n").startswith(headers[name])
|
|
190
|
+
except (OSError, UnicodeError):
|
|
191
|
+
valid = False
|
|
192
|
+
if not valid:
|
|
193
|
+
raise SystemExit(f"REFUSING: {path} has an unrecognized header; preserve it for review.")
|
|
194
|
+
if "last-checkpoint" in present:
|
|
195
|
+
try:
|
|
196
|
+
with open(os.path.join(cad, "last-checkpoint"), encoding="utf-8") as handle:
|
|
197
|
+
valid = bool(re.fullmatch(r"[0-9]+\s*", handle.read()))
|
|
198
|
+
except (OSError, UnicodeError):
|
|
199
|
+
valid = False
|
|
200
|
+
if not valid:
|
|
201
|
+
raise SystemExit("REFUSING: last-checkpoint is malformed; preserve it for review.")
|
|
202
|
+
return [name for name in names if name not in present], True
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _create_scaffold_file(path, content, *, newline=None):
|
|
206
|
+
"""Create once; a concurrent new file is a conflict, never an overwrite."""
|
|
207
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
|
|
208
|
+
flags |= getattr(os, "O_NOFOLLOW", 0)
|
|
209
|
+
try:
|
|
210
|
+
fd = os.open(path, flags, 0o666)
|
|
211
|
+
except FileExistsError:
|
|
212
|
+
raise SystemExit(f"REFUSING: {path} appeared during scaffold recovery.") from None
|
|
213
|
+
with os.fdopen(fd, "w", encoding="utf-8", newline=newline) as handle:
|
|
214
|
+
handle.write(content)
|
|
215
|
+
|
|
216
|
+
|
|
125
217
|
def main(argv=None):
|
|
126
218
|
ap = argparse.ArgumentParser(add_help=True)
|
|
127
219
|
ap.add_argument("--root")
|
|
128
220
|
ap.add_argument("--stage", type=int)
|
|
129
221
|
ap.add_argument("--check", action="store_true")
|
|
222
|
+
ap.add_argument("--passive", action="store_true", help=(
|
|
223
|
+
"inspect explicit root before host activation; no Git or network probes"))
|
|
224
|
+
ap.add_argument("--context-request", help=argparse.SUPPRESS)
|
|
130
225
|
ap.add_argument("--repair-lock-exclusion", action="store_true", help=(
|
|
131
226
|
"repair only Git-local info/exclude for an existing scaffold; retain the "
|
|
132
227
|
"task-board OS lock, never rewrite project state (cannot combine with --check/--stage)"))
|
|
133
228
|
args = ap.parse_args(argv)
|
|
229
|
+
if args.context_request:
|
|
230
|
+
if not args.root or args.stage is not None or args.check or args.passive or args.repair_lock_exclusion:
|
|
231
|
+
ap.error("--context-request requires --root and excludes scaffold flags")
|
|
232
|
+
try:
|
|
233
|
+
root = _artifactlib._trusted_directory(args.root, "UNSAFE_ROOT")
|
|
234
|
+
request = _artifactlib.read_context_preview_request(root, args.context_request)
|
|
235
|
+
operation, payload = _artifactlib.validate_context_writer_request(request)
|
|
236
|
+
client = _artifactlib.context_writer_client(root)
|
|
237
|
+
if operation == "preview":
|
|
238
|
+
from _artifactauthoritylib import arm_context_preview
|
|
239
|
+
result = arm_context_preview(root, client, payload)
|
|
240
|
+
else:
|
|
241
|
+
result = client.call("context-apply", payload)
|
|
242
|
+
except RuntimeError as exc:
|
|
243
|
+
raise SystemExit(f"REFUSING context request: {exc}") from None
|
|
244
|
+
print(json.dumps(result, sort_keys=True))
|
|
245
|
+
return
|
|
246
|
+
if args.passive:
|
|
247
|
+
if not args.check or not args.root or args.stage is not None or args.repair_lock_exclusion:
|
|
248
|
+
ap.error("--passive requires --check and --root; excludes --stage and repair")
|
|
249
|
+
try:
|
|
250
|
+
report = passive_activation_inventory(args.root)
|
|
251
|
+
except (OSError, UnicodeError, ValueError) as exc:
|
|
252
|
+
raise SystemExit(f"REFUSING passive inspection: {exc}") from None
|
|
253
|
+
print(json.dumps(report, sort_keys=True))
|
|
254
|
+
return
|
|
134
255
|
if args.repair_lock_exclusion and (args.check or args.stage is not None):
|
|
135
256
|
ap.error("--repair-lock-exclusion cannot combine with --check or --stage")
|
|
257
|
+
requested_stage = args.stage
|
|
136
258
|
if args.stage is None:
|
|
137
259
|
args.stage = 1
|
|
138
260
|
|
|
@@ -149,13 +271,17 @@ def main(argv=None):
|
|
|
149
271
|
name = os.path.basename(root.rstrip("/\\")) or "project"
|
|
150
272
|
|
|
151
273
|
if args.check:
|
|
274
|
+
if os.path.lexists(cad) and not _regular_scaffold_entry(cad, directory=True):
|
|
275
|
+
raise SystemExit(f"REFUSING: {cad} is not a regular project-state directory.")
|
|
276
|
+
if os.path.lexists(ctx) and not _regular_scaffold_entry(ctx, directory=False):
|
|
277
|
+
raise SystemExit(f"REFUSING: {ctx} is not a regular scaffold file.")
|
|
152
278
|
if os.path.exists(ctx):
|
|
153
279
|
print(f"ALREADY SCAFFOLDED: {ctx} exists.")
|
|
154
280
|
with open(ctx, encoding="utf-8", errors="replace") as f:
|
|
155
281
|
text = f.read()
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
print("arbiter: " + ("enabled" if
|
|
282
|
+
initd = _hooklib.initialized_body_text(text)
|
|
283
|
+
enabled, _malformed = _hooklib.frontmatter_enabled_text(text)
|
|
284
|
+
print("arbiter: " + ("enabled" if enabled else "not enabled"))
|
|
159
285
|
print("initialized body: " + ("yes" if initd else
|
|
160
286
|
"no (run " + _cc + " or " + _dc + ")"))
|
|
161
287
|
else:
|
|
@@ -164,7 +290,8 @@ def main(argv=None):
|
|
|
164
290
|
|
|
165
291
|
from _taskexcludelib import ensure_task_lock_excluded, TaskExclusionError
|
|
166
292
|
if args.repair_lock_exclusion:
|
|
167
|
-
if not
|
|
293
|
+
if (not _regular_scaffold_entry(cad, directory=True) or
|
|
294
|
+
not _regular_scaffold_entry(ctx, directory=False)):
|
|
168
295
|
raise SystemExit("REFUSING: task lock exclusion repair requires an existing scaffold.")
|
|
169
296
|
try:
|
|
170
297
|
result = ensure_task_lock_excluded(root, required=True)
|
|
@@ -173,7 +300,8 @@ def main(argv=None):
|
|
|
173
300
|
print(f"task lock exclusion: {result}")
|
|
174
301
|
return
|
|
175
302
|
|
|
176
|
-
|
|
303
|
+
absent, recovering = _scaffold_inventory(cad, ctx, requested_stage)
|
|
304
|
+
if recovering and not absent:
|
|
177
305
|
raise SystemExit(
|
|
178
306
|
f"REFUSING: {ctx} already exists. .codearbiter/ is already scaffolded here. "
|
|
179
307
|
f"To populate it, run {_cc} or {_dc}; to repair, edit by hand.")
|
|
@@ -187,19 +315,16 @@ def main(argv=None):
|
|
|
187
315
|
|
|
188
316
|
os.makedirs(cad, exist_ok=True)
|
|
189
317
|
created = []
|
|
190
|
-
if
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
create_context=_cc, decompose=_dc))
|
|
318
|
+
if "CONTEXT.md" in absent:
|
|
319
|
+
_create_scaffold_file(ctx, CONTEXT.format(stage=args.stage, name=name,
|
|
320
|
+
create_context=_cc, decompose=_dc))
|
|
194
321
|
created.append("CONTEXT.md")
|
|
195
322
|
for fname, content in FILES.items():
|
|
196
|
-
|
|
197
|
-
if not os.path.exists(fp):
|
|
323
|
+
if fname in absent:
|
|
198
324
|
# Match taskwrite's LF output for this shared append-only template
|
|
199
325
|
# on Windows too; other scaffold files retain their existing EOLs.
|
|
200
326
|
newline = "\n" if fname == "done-tasks.md" else None
|
|
201
|
-
|
|
202
|
-
f.write(content)
|
|
327
|
+
_create_scaffold_file(os.path.join(cad, fname), content, newline=newline)
|
|
203
328
|
created.append(fname)
|
|
204
329
|
|
|
205
330
|
# #161: install the git-level enforcement backstop (pre-commit/pre-push) so
|
|
@@ -215,9 +340,12 @@ def main(argv=None):
|
|
|
215
340
|
except Exception as e: # noqa: BLE001
|
|
216
341
|
print(f"git hooks: install skipped ({e})", file=sys.stderr)
|
|
217
342
|
|
|
218
|
-
print(f"SCAFFOLDED .codearbiter/ at {cad}")
|
|
343
|
+
print(f"{'RECOVERED' if recovering else 'SCAFFOLDED'} .codearbiter/ at {cad}")
|
|
219
344
|
print("created: " + ", ".join(created))
|
|
220
|
-
|
|
345
|
+
if recovering and "CONTEXT.md" not in created:
|
|
346
|
+
print("arbiter: enabled; existing uninitialized CONTEXT.md and history retained.")
|
|
347
|
+
else:
|
|
348
|
+
print(f"arbiter: enabled (stage {args.stage}); CONTEXT.md is a stub (no <!--INITIALIZED--> sentinel).")
|
|
221
349
|
print(f"Next: run {_cc} (source exists) or {_dc} (greenfield) to populate.")
|
|
222
350
|
|
|
223
351
|
|
|
@@ -65,6 +65,7 @@ import sys
|
|
|
65
65
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
66
66
|
import hostapi # noqa: E402 — host seam (ADR-0011)
|
|
67
67
|
import _approvallib # noqa: E402 — host-owned artifact approval capture
|
|
68
|
+
import _artifactauthoritylib # noqa: E402 — exact context preview approval capture
|
|
68
69
|
import _hooklib # noqa: E402
|
|
69
70
|
import _modelib # noqa: E402 — mode plane core (T-06..T-16, Lane A)
|
|
70
71
|
import _prerequisitelib # noqa: E402 — host-owned prerequisite capture
|
|
@@ -485,6 +486,15 @@ def _handle_user_prompt_submit(payload, host):
|
|
|
485
486
|
)
|
|
486
487
|
if reconciliation:
|
|
487
488
|
contexts.append(reconciliation)
|
|
489
|
+
context_preview = _artifactauthoritylib.capture_context_preview_from_hook(
|
|
490
|
+
root=root,
|
|
491
|
+
plugin_root=host.plugin_root(),
|
|
492
|
+
prompt=prompt,
|
|
493
|
+
host=host.name,
|
|
494
|
+
session_id=session_id,
|
|
495
|
+
)
|
|
496
|
+
if context_preview:
|
|
497
|
+
contexts.append(context_preview)
|
|
488
498
|
approval_context = "\n".join(contexts)
|
|
489
499
|
if not active:
|
|
490
500
|
if not approval_context:
|
|
@@ -513,6 +523,10 @@ def _handle_precompact(payload, host):
|
|
|
513
523
|
if not _hooklib.arbiter_active(root):
|
|
514
524
|
return 0
|
|
515
525
|
_bump_compaction_generation(_hooklib.marker_root(payload), session_id)
|
|
526
|
+
# Read-time context pointers have their own worktree-local epoch. A
|
|
527
|
+
# surviving read marker cannot prove that a compacted actor still carries
|
|
528
|
+
# those pointers. Keep this separate from the persona generation above.
|
|
529
|
+
_readinjectlib.bump_context_generation(root, session_id)
|
|
516
530
|
return 0
|
|
517
531
|
|
|
518
532
|
|
|
@@ -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
|
-
|
|
865
|
-
|
|
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
|
|
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)
|
|
@@ -301,6 +301,47 @@ rewrite the returned envelope yourself.
|
|
|
301
301
|
The host hooks bind the exact launch call, child start and
|
|
302
302
|
the child's first stop; a pasted or coordinator-authored decision is not review
|
|
303
303
|
authority.
|
|
304
|
+
|
|
305
|
+
When reviewing completed work that relies on a verification run, linked
|
|
306
|
+
worktrees or supporting evidence, explicitly select the completion path. Add
|
|
307
|
+
`--completion-receipt <exact-published-receipt>` once per task and
|
|
308
|
+
`--supporting-file <absolute-regular-file>` for each supporting document to the
|
|
309
|
+
review `arm` command. A task review selects one verification receipt; a scope
|
|
310
|
+
review selects the exact receipt for every member. Supporting files require a
|
|
311
|
+
receipt selection. The existing review-before-verification path remains
|
|
312
|
+
available; it does not satisfy an explicitly requested completion review.
|
|
313
|
+
|
|
314
|
+
The native engine validates the selected published verification chain and
|
|
315
|
+
derives the worktree mappings from its qualified observation. It retains the
|
|
316
|
+
selected identities, worktree closure and supporting bytes in the immutable
|
|
317
|
+
context. Supporting material is data for review, not authority. Selection is
|
|
318
|
+
explicit: no newest-receipt search, directory import or attachment execution.
|
|
319
|
+
At most 16 regular files are admitted, each at most 64 KiB and together at most
|
|
320
|
+
256 KiB; links, reparse indirection, duplicate paths and changed content fail
|
|
321
|
+
closed. Read canonical spec and plan artifacts through the native artifact API;
|
|
322
|
+
they cannot be imported as supporting files. The generated prompt directs the reviewer to assess performed work
|
|
323
|
+
against each criterion, step and `done_when` obligation, using selected evidence
|
|
324
|
+
and source references. A consistent plan or an empty diff is insufficient.
|
|
325
|
+
|
|
326
|
+
Use the returned `completion_sha256` in the native `task-review` or
|
|
327
|
+
`accept-scope` request. The completed review and its exact verification run must
|
|
328
|
+
agree; a definition-only review or a different successful run is rejected.
|
|
329
|
+
The recorded task selection remains required by downstream freshness and scope
|
|
330
|
+
acceptance. Scope review uses validated task completion bindings. If verification
|
|
331
|
+
is rerun, obtain and record its completed task review before selecting that run
|
|
332
|
+
for scope review; do not infer equivalence between receipts.
|
|
333
|
+
|
|
334
|
+
Creating the first completion context recomputes the current raw worktree
|
|
335
|
+
fingerprint and requires it to match the selected verifier's recorded fingerprint.
|
|
336
|
+
Later freshness checks allow native task-status and execution bookkeeping updates
|
|
337
|
+
in validated canonical artifacts while retaining their normative content hashes.
|
|
338
|
+
Changes to task definitions, other HTML or other governance files still affect
|
|
339
|
+
freshness under the normal snapshot policy. The closure covers
|
|
340
|
+
tracked working-tree bytes and non-ignored untracked files, not ignored
|
|
341
|
+
dependencies or outputs. The completion assessment is still an independent
|
|
342
|
+
reviewer's judgment; schema validation does not prove that every file was read
|
|
343
|
+
or every conclusion is correct. Preserve the unchanged launch envelope and
|
|
344
|
+
genuine host capture throughout this path.
|
|
304
345
|
Publish the completed request through the same `publish` command. `task-review`
|
|
305
346
|
records the separate verification and spec-review receipts. After every task in
|
|
306
347
|
the scope reaches `REVIEW`, reverify against one current source snapshot, run the
|
|
@@ -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. **
|
|
11
|
-
2. **Confirm tests
|
|
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** —
|
|
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
|
|
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 |
|
|
@@ -14,9 +14,11 @@ code instead of the first's (#577) — then run:
|
|
|
14
14
|
|
|
15
15
|
It writes `<project-root>/.codearbiter/.markers/security-gate-passed` containing a digest of
|
|
16
16
|
every sensitive added line it approved. The PreToolUse commit hook (**H-09b** for crypto/TLS, **H-10b**
|
|
17
|
-
for secrets) blocks any commit whose staged diff touches a guarded pattern until this marker
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
for secrets) blocks any commit whose staged diff touches a guarded pattern until this marker exists
|
|
18
|
+
AND covers every sensitive line being committed. There is no time window: a pass stays valid for
|
|
19
|
+
exactly the lines it reviewed, in the files it reviewed them in. Any new or changed sensitive line,
|
|
20
|
+
or a reviewed line moved to another file, is uncovered and blocks, so a pass recorded for one diff
|
|
21
|
+
cannot launder a later, different change.
|
|
20
22
|
|
|
21
23
|
On any BLOCK, do **not** record the pass — the commit stays blocked until the finding is resolved and
|
|
22
24
|
the gate genuinely passes. A premature or unconditional recording defeats the gate.
|
|
@@ -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;
|
|
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. |
|