create-agent-rig 0.6.1 → 0.7.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/CHANGELOG.md +143 -0
- package/package.json +3 -1
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +2 -3
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +122 -81
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +19 -12
- package/templates/agent-os/universal/.claude/hooks/block-no-verify.mjs +24 -8
- package/templates/agent-os/universal/.claude/hooks/gate-stop-dod.mjs +3 -6
- package/templates/agent-os/universal/.claude/hooks/guard-bash.mjs +67 -12
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +5 -9
- package/templates/agent-os/universal/.claude/hooks/guard-rulebook.mjs +20 -11
- package/templates/agent-os/universal/.claude/hooks/guard-secret-file.mjs +3 -7
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +5 -9
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +3 -6
- package/templates/agent-os/universal/.claude/hooks/lib/hook-input.mjs +164 -0
- package/templates/agent-os/universal/.claude/rules/invariants.md +19 -0
- package/templates/agent-os/universal/.claude/scripts/lib/claim-records.mjs +800 -0
- package/templates/agent-os/universal/.claude/scripts/lib/revalidation-evidence.mjs +56 -0
- package/templates/agent-os/universal/.claude/scripts/lib/shell-tools.mjs +81 -0
- package/templates/agent-os/universal/.claude/scripts/preflight.mjs +19 -1
- package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +17 -66
- package/templates/agent-os/universal/.claude/scripts/queue/github-issues.mjs +29 -7
- package/templates/agent-os/universal/.claude/scripts/queue/index.mjs +159 -23
- package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +61 -27
- package/templates/agent-os/universal/.claude/scripts/queue/plan-md.mjs +4 -2
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +268 -48
- package/templates/agent-os/universal/.claude/scripts/revalidation-report.mjs +32 -15
- package/templates/agent-os/universal/.claude/scripts/run-state.mjs +180 -37
- package/templates/agent-os/universal/.claude/scripts/unattended-flag.mjs +33 -19
- package/templates/agent-os/universal/.claude/settings.json +1 -1
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +122 -81
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +19 -12
- package/templates/agent-os/universal/.codex/hooks.json +17 -17
- package/templates/agent-os/universal/.rig/revalidation.json +10 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +3 -2
- package/templates/agent-os/universal/docs/decisions/content-blind-revalidation.md +144 -0
- package/templates/agent-os/universal/docs/decisions/spacing-rations-mechanisms.md +15 -0
- package/templates/agent-os/universal/layers.json +6 -0
- package/templates/hash-history.json +71 -28
- package/templates/release-ledger.json +3 -1
|
@@ -45,7 +45,7 @@ composed file:
|
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
node .claude/scripts/queue/index.mjs board # the active board and the declared ones
|
|
48
|
-
node .claude/scripts/queue/index.mjs board
|
|
48
|
+
node .claude/scripts/queue/index.mjs board <board-id> # switch this checkout: writes .claude/queue.board
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
The selector is per-checkout runtime state, the same class as
|
|
@@ -59,7 +59,11 @@ and the `board` command itself refuses a switch while the checkout is unattended
|
|
|
59
59
|
does not prevent an arbitrary direct shell write to the selector — edit-tool
|
|
60
60
|
hooks cannot see one. `.claude/queue.state.json` stays per config, not per board:
|
|
61
61
|
the tier the last close recorded rations the next selection whichever board it
|
|
62
|
-
lands on.
|
|
62
|
+
lands on. This is repository-risk state, not tracker metadata: switching from
|
|
63
|
+
one independent queue to another must not turn a previous mechanism close into
|
|
64
|
+
permission for a second one in the same checkout. Pinned in the generator's
|
|
65
|
+
`test/template/queue-board.test.ts` (absent in a generated rig) › "keeps
|
|
66
|
+
completed-tier spacing repository-global when the active board switches".
|
|
63
67
|
|
|
64
68
|
Adding a fourth is an adapter, not a rewrite: `core.mjs` holds every selection
|
|
65
69
|
decision and each adapter only maps its tracker's records onto the neutral shape.
|
|
@@ -75,13 +79,14 @@ state-vs-queue split exists to prevent.
|
|
|
75
79
|
node .claude/scripts/preflight.mjs
|
|
76
80
|
```
|
|
77
81
|
|
|
78
|
-
|
|
79
|
-
exported ·
|
|
80
|
-
|
|
82
|
+
Five items are scripted (kill switch absent · `RIG_RUN_DIR` not already
|
|
83
|
+
exported · the versioned revalidation detection contract is supported · local
|
|
84
|
+
default branch matches the remote · the last deploy concluded successfully)
|
|
85
|
+
and the script **prints the ones it did not check, every time**. Paste the block into the journal: a checklist that
|
|
81
86
|
leaves no record cannot tell you it was skipped.
|
|
82
87
|
|
|
83
88
|
Verdicts: **STOP** → do not start, deal with the cause. **CAUTION** → start,
|
|
84
|
-
knowing which ground is soft. **GO** → the scripted
|
|
89
|
+
knowing which ground is soft. **GO** → the scripted five are clean; the rest are
|
|
85
90
|
still yours.
|
|
86
91
|
|
|
87
92
|
**An `unknown` never becomes a `pass`.** A probe that could not run tells you
|
|
@@ -114,9 +119,31 @@ mkdir -p "$RIG_RUN_DIR"
|
|
|
114
119
|
never with a variable the session exported — pinned in the generator's
|
|
115
120
|
`test/template/guard-rulebook.test.ts` (absent in a generated rig) › "only a
|
|
116
121
|
flag arms it — an exported RIG_UNATTENDED=1 with no flag changes nothing" —
|
|
117
|
-
and in some harnesses the export does not even survive to the next Bash call
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
and in some harnesses the export does not even survive to the next Bash call.
|
|
123
|
+
|
|
124
|
+
🔴 **So re-export it in every call that needs it.** `RIG_RUN_DIR` is how the run
|
|
125
|
+
directory reaches the commands that read it from the environment — and two of
|
|
126
|
+
the commands this skill invokes read it from somewhere else instead.
|
|
127
|
+
`unattended-flag.mjs` does not read the variable; it takes the directory as
|
|
128
|
+
`--run-dir`, which is why the call below passes it explicitly.
|
|
129
|
+
`revalidation-report.mjs` does not read it either; it takes `--runs <dir>`.
|
|
130
|
+
For every other command this skill invokes the variable is the whole of it, and
|
|
131
|
+
passing the flag is not a fallback but an unrecognised argument — after which a
|
|
132
|
+
command writes into a run directory nobody declared, or refuses for want of one
|
|
133
|
+
while the caller believes it was told. Modules this skill *imports* rather than
|
|
134
|
+
invokes are a third case again: `run-journal.mjs` and `queue/state.mjs` are
|
|
135
|
+
handed a `runDir` by their caller, which is why §9 lists it among the details
|
|
136
|
+
that must be copied rather than re-derived.
|
|
137
|
+
|
|
138
|
+
`--run-dir` is taken by `unattended-flag.mjs`, and by no other script under
|
|
139
|
+
`.claude/scripts/`. That is measured over the whole tree rather than against a
|
|
140
|
+
list, in both directions, by the generator's
|
|
141
|
+
`test/template/correspondence.test.ts` (absent in a generated rig) › "names
|
|
142
|
+
exactly the commands that take --run-dir, and only those" — so a script anywhere
|
|
143
|
+
in that tree that gains the flag without this sentence gaining its name goes
|
|
144
|
+
red.
|
|
145
|
+
|
|
146
|
+
What a hook CAN see is a file, so the unattended signal is one:
|
|
120
147
|
|
|
121
148
|
```bash
|
|
122
149
|
# at claim time, from the paths the item names (repo-relative prefixes, with
|
|
@@ -137,12 +164,11 @@ rig — › "blocks a hook-config edit with an empty allow-list, naming path, it
|
|
|
137
164
|
|
|
138
165
|
⚠ **The export outlives the run's own calls.** Everything the session spawns
|
|
139
166
|
inherits it — and a test suite that spawns the queue CLI would write fixture
|
|
140
|
-
records into this run's trace
|
|
141
|
-
|
|
142
|
-
to start on a `RIG_RUN_DIR` already exported. The generator's own test harness
|
|
167
|
+
records into this run's trace. So preflight refuses to start on a
|
|
168
|
+
`RIG_RUN_DIR` already exported. The generator's own test harness
|
|
143
169
|
also scrubs the variable before any test file loads — its `test/setup-env.ts`,
|
|
144
|
-
pinned by its `test/template/rig-run-dir-scrub.test.ts`
|
|
145
|
-
variable exported around the whole vitest process" — and **neither file ships
|
|
170
|
+
pinned by its `test/template/rig-run-dir-scrub.test.ts` (absent in a generated
|
|
171
|
+
rig) › "holds with the variable exported around the whole vitest process" — and **neither file ships
|
|
146
172
|
into a generated rig**: here, nothing scrubs it, and a rig's own test setup is
|
|
147
173
|
the place to do the same.
|
|
148
174
|
|
|
@@ -194,12 +220,12 @@ reported by `hygiene` as `owner-mismatch`. It clears the way `trigger-human`
|
|
|
194
220
|
does: a human moves the item or re-marks it. An unmarked item is unconditional.
|
|
195
221
|
Two items of another product once entered this queue as normal spacers and
|
|
196
222
|
escalated `PREMISE FALSE` back to back — a run-level stop spent on work that
|
|
197
|
-
was never this checkout's
|
|
223
|
+
was never this checkout's. Pinned in the generator's
|
|
198
224
|
`test/template/queue-owner.test.ts` — absent in a generated rig — › "holds an
|
|
199
225
|
item whose owner is another repository, with the cause named".
|
|
200
226
|
|
|
201
227
|
🔴 **An item's lifecycle is a label a human wrote, and the loop infers none of
|
|
202
|
-
it
|
|
228
|
+
it**. Four words, read by `lifecycleOf` in `core.mjs` so every adapter
|
|
203
229
|
means the same thing — three of lifecycle, one of scheduling:
|
|
204
230
|
|
|
205
231
|
- `keep-core` — the problem and the responsibility are valid and the item is
|
|
@@ -281,59 +307,72 @@ and the work turns out to touch an elevated path (`CLAUDE.md` →
|
|
|
281
307
|
`elevated-paths`), run the gate anyway, record the verdict on the PR, and treat it
|
|
282
308
|
as this run's elevated item for spacing.
|
|
283
309
|
|
|
284
|
-
**Selection
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
310
|
+
**Selection is the first point of the one revalidation chain.** On the first
|
|
311
|
+
successful SELECT, `next` creates a versioned content-blind baseline at
|
|
312
|
+
`.rig/claims/<item-id>.json` and reports `BASELINE_CREATED`. Add that record to
|
|
313
|
+
the task's branch: a later SELECT, BEFORE_PR or BEFORE_CLOSE refuses an
|
|
314
|
+
untracked record, and a resumed checkpoint with no record is `UNVERIFIABLE`.
|
|
315
|
+
The `scope` fingerprint set is authoritative at SELECT and BEFORE_PR and
|
|
316
|
+
includes workflow state normalised to the state that checkpoint expects;
|
|
317
|
+
`commentary` is observed there but becomes hold-authoritative only at
|
|
318
|
+
BEFORE_CLOSE. Neither set stores title, description or comment bodies.
|
|
319
|
+
For Jira and GitHub issues, the adapter's successful `claim` writes its
|
|
320
|
+
observable `in-progress` transition into that same record as `workflowClaim`.
|
|
321
|
+
Only that durable acknowledgement makes the claimed state expected at a resumed
|
|
322
|
+
SELECT, BEFORE_PR or BEFORE_CLOSE; the same tracker state reached without it is
|
|
323
|
+
external drift and HOLDs. PLAN.md remains `open` because it has no observable
|
|
324
|
+
claim transition. The checkpoint-aware edge is pinned in the generator's
|
|
325
|
+
`test/template/content-blind-revalidation.test.ts` (absent in a generated rig)
|
|
326
|
+
› "keeps a resumed SELECT current after the Jira adapter records its own claim
|
|
327
|
+
transition", › "GitHub claim records the durable transition that makes
|
|
328
|
+
in-progress CURRENT", › "holds claim:scope at resumed SELECT for the same transition
|
|
329
|
+
made outside the adapter", › "accepts an in-progress transition performed by
|
|
330
|
+
the Jira adapter claim operation", and › "holds claim:scope when an external
|
|
331
|
+
actor moves the item to the expected claimed state".
|
|
332
|
+
The durable/evidence boundary and rollback rule are recorded in
|
|
333
|
+
`docs/decisions/content-blind-revalidation.md`.
|
|
334
|
+
|
|
335
|
+
`takeUps` and `updatedAt` remain in run state and in the event's `task` field as
|
|
336
|
+
evidence/compatibility state. They do not decide `CURRENT`, `CHANGED`,
|
|
337
|
+
`CONFLICT` or `UNVERIFIABLE`, do not decide whether a first baseline may be
|
|
338
|
+
created, and never appear as a drift source. The event may still name
|
|
339
|
+
`baseline: this-run | previous-run | null` so older evidence remains readable.
|
|
340
|
+
First sight versus resume comes only from the SELECT events in the current and
|
|
341
|
+
bounded sibling run journals. If those journals cannot prove first sight, a
|
|
342
|
+
missing claim is `UNVERIFIABLE`; an `updatedAt` marker can neither create nor
|
|
343
|
+
withhold the claim. Hitting the sibling entry/read cap makes that proof
|
|
344
|
+
incomplete and therefore fails closed; "not found in the bounded subset" never
|
|
345
|
+
means "never selected".
|
|
346
|
+
|
|
347
|
+
On `CHANGED`, `CONFLICT` or `UNVERIFIABLE`, **re-read before acting**, then
|
|
348
|
+
record what the re-read concluded:
|
|
300
349
|
|
|
301
350
|
```bash
|
|
302
351
|
node .claude/scripts/revalidate.mjs outcome --point SELECT --ticket <item-id> --action-changed <true | false> --note '<what changed, or why it changes nothing>'
|
|
303
352
|
```
|
|
304
353
|
|
|
305
|
-
It appends one `revalidation-outcome` record whose `
|
|
306
|
-
|
|
354
|
+
It appends one typed `revalidation-outcome` record whose `detectionId` names the
|
|
355
|
+
stable detection it resolves (and retains the legacy `answers` sequence), so
|
|
356
|
+
the report can pair the two across harness runs without guessing. The
|
|
307
357
|
note is stored verbatim from argv, so keep it in single quotes: inside double
|
|
308
358
|
quotes the shell expands a backtick or a `$` before the command sees it.
|
|
309
359
|
Nothing forces this record — a `revalidation` event with no matching outcome is
|
|
310
360
|
counted as `unresolved`, which is the honest word for a re-read the run skipped.
|
|
311
361
|
|
|
312
|
-
Under a declared run directory, every selection logs one
|
|
313
|
-
`
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
`
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
re-record the take-up after each write they make — claim, comment, close,
|
|
320
|
-
escalate — so a move made through the adapter is not a hold (AR-140, from the
|
|
321
|
-
journal's RX3/RX4 entry: every BEFORE_PR catch of that run was the run's own
|
|
322
|
-
comment, counted by `revalidation-report.mjs`); a
|
|
323
|
-
comment posted by any other route — a REST call by hand, a connector — still
|
|
324
|
-
moves it like anyone else's, and a `true` can still be self-inflicted that way
|
|
325
|
-
— the re-read decides, which is why the outcome is recorded separately, and a
|
|
326
|
-
hold the re-read overturns is counted as a false hold with its source named.
|
|
327
|
-
Pinned in the generator's `test/template/self-inflicted-marker.test.ts` — absent
|
|
328
|
-
in a generated rig — › "%s leaves the take-up at the marker the write produced",
|
|
329
|
-
an `it.each` over claim, comment, close and escalate. The
|
|
362
|
+
Under a declared run directory, every selection logs one versioned
|
|
363
|
+
`revalidation` detection — the same shape BEFORE_PR and BEFORE_CLOSE write.
|
|
364
|
+
**No-change is always recorded**, one line per selection and no sampling: the
|
|
365
|
+
rule is explicit so the report's `opportunities` is a count and not an estimate.
|
|
366
|
+
The `jira` and `github-issues` adapters still re-record take-ups after their own
|
|
367
|
+
writes for compatibility and attribution evidence; that state is never the
|
|
368
|
+
fingerprint baseline. The
|
|
330
369
|
four-week view is `node .claude/scripts/revalidation-report.mjs --since <date>`,
|
|
331
370
|
over this rig's `.claude/runs/` (or a `--runs <dir>`). The behaviour is pinned in the
|
|
332
|
-
generator's `test/template/
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
371
|
+
generator's `test/template/content-blind-revalidation.test.ts` (absent in a generated rig) › "creates a
|
|
372
|
+
versioned content-blind claim and returns BASELINE_CREATED" and › "defers an
|
|
373
|
+
added comment through SELECT and BEFORE_PR, then holds at BEFORE_CLOSE", plus
|
|
374
|
+
`test/template/revalidation-evidence.test.ts` (absent in a generated rig) › "the journaled events of SELECT,
|
|
375
|
+
BEFORE_PR and BEFORE_CLOSE share exactly the common keys and value types".
|
|
337
376
|
|
|
338
377
|
**Then, before the Red step: `check-premises`.** The item was written by someone
|
|
339
378
|
who was not reading the code at the time, and everything downstream — the failing
|
|
@@ -367,7 +406,7 @@ exits 1 whatever the reviewer said. Save the whole answer to a file under the ru
|
|
|
367
406
|
directory — `$RIG_RUN_DIR/check-premises.md`, one file per gate so two answers
|
|
368
407
|
never overwrite each other — and pass that path (`-` reads stdin instead). The
|
|
369
408
|
same holds for every `<report>` in this skill, as `pr-ship` already does for its
|
|
370
|
-
reviewers
|
|
409
|
+
reviewers. Pinned in the generator's `test/template/loop-report-file.test.ts`
|
|
371
410
|
— absent in a generated rig — › "states that the report is a file the session
|
|
372
411
|
writes from the subagent answer, before the first check".
|
|
373
412
|
|
|
@@ -412,8 +451,8 @@ reviewer verdict, an exhausted gate-round cap, a false premise in the item itsel
|
|
|
412
451
|
|
|
413
452
|
The run-level conditions are in `stopConditionOf` in `core.mjs`, checked in
|
|
414
453
|
severity order: **queue unreadable** · **runtime regression** · **kill switch** ·
|
|
415
|
-
**two escalations in a row** · **budget** · **nothing
|
|
416
|
-
empty**.
|
|
454
|
+
**revalidation hold** · **two escalations in a row** · **budget** · **nothing
|
|
455
|
+
selectable** · **queue empty**.
|
|
417
456
|
|
|
418
457
|
🔴 **Their inputs come from a file, not from your memory — and that is why they
|
|
419
458
|
fire at all.** `escalations` and `lastDeployVerdict` live in
|
|
@@ -563,7 +602,7 @@ inventory of findings** — and this had to be settled, because the two readings
|
|
|
563
602
|
disagreed the first time a stop arrived without an inventory. An exhausted
|
|
564
603
|
gate-round cap names its stage (the gate) and its wall (the branch's rounds are
|
|
565
604
|
spent — the count, not a verdict on whether the fixes were converging, which the
|
|
566
|
-
counter never measured
|
|
605
|
+
counter never measured), while the individual blockers behind it are not persisted anywhere until
|
|
567
606
|
per-round verdicts exist. That is a `documented-stall`: the record locates the wall
|
|
568
607
|
and the next reader knows where to look.
|
|
569
608
|
|
|
@@ -699,10 +738,13 @@ declared in §1. Five things about it are worth knowing before relying on it:
|
|
|
699
738
|
so a stale record cannot read as the current one — which is the whole failure a
|
|
700
739
|
journal exists to prevent.
|
|
701
740
|
- ⚠ **The trace can stop before the run does, and the two failures part ways
|
|
702
|
-
here.**
|
|
703
|
-
broken, a file that will not parse, a run already
|
|
704
|
-
trace, **not** a reason to withhold work the
|
|
705
|
-
selection prints, stderr carries a `run journal:`
|
|
741
|
+
here.** After a durable claim exists, a journal that can no longer accept
|
|
742
|
+
records — a sequence already broken, a file that will not parse, a run already
|
|
743
|
+
marked ended — is a lost trace, **not** by itself a reason to withhold work the
|
|
744
|
+
queue can still hand out: the selection prints, stderr carries a `run journal:`
|
|
745
|
+
line, and the claim still decides drift. Before the first claim, the boundary
|
|
746
|
+
is stricter: an unreadable current or bounded sibling journal means SELECT
|
|
747
|
+
cannot prove first sight, so an absent claim is `UNVERIFIABLE` and exits 2.
|
|
706
748
|
The refusals are the ones where nothing has happened yet and a second fixes
|
|
707
749
|
it, and there are **four**: the declaration is empty, its directory does not
|
|
708
750
|
exist, the path is not a directory, or the journal module is missing. Each
|
|
@@ -789,10 +831,10 @@ node --input-type=module -e '
|
|
|
789
831
|
|
|
790
832
|
A proposal missing any of the four parts is refused rather than filed half-formed.
|
|
791
833
|
|
|
792
|
-
**A finding can say what it measured and what it inferred, as two paired fields
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
was traced to a probe that had touched one hook. So `measured` and `inferred`
|
|
834
|
+
**A finding can say what it measured and what it inferred, as two paired fields.**
|
|
835
|
+
A proposal whose premise was never true had no check at filing, only at take-up
|
|
836
|
+
— one such proposal was filed, promoted and claimed before its platform
|
|
837
|
+
conclusion was traced to a probe that had touched one hook. So `measured` and `inferred`
|
|
796
838
|
are separate, and `validateProposal` refuses an `inferred` that cites a path
|
|
797
839
|
`measured` does not, naming both fields and the path; one field without the
|
|
798
840
|
other is refused too, and neither files as before. The surface is a cited path
|
|
@@ -801,7 +843,7 @@ catches the path-shaped overreach and nothing subtler.
|
|
|
801
843
|
|
|
802
844
|
⚠ **The pair is how a proposal opts into the check, and a proposal filed without
|
|
803
845
|
it is not checked at all** — `validateProposal` keeps the four-part contract, so
|
|
804
|
-
|
|
846
|
+
that shape with neither field still files as it always did. That is the
|
|
805
847
|
stated limit, not an oversight: making the fields mandatory would refuse every
|
|
806
848
|
proposal the three adapters already file, and the loop is the author this rule
|
|
807
849
|
is for. So **every proposal this loop files carries both fields** — the snippet
|
|
@@ -822,7 +864,7 @@ reports one whose cited paths changed since its `asOf` as
|
|
|
822
864
|
one git cannot diff from as `proposal-asof-unanswerable` — never as clean. Two
|
|
823
865
|
proposals in a row once escalated `PREMISE FALSE` because the merge that
|
|
824
866
|
falsified each landed after it was filed, and selection hands out the oldest
|
|
825
|
-
first
|
|
867
|
+
first. The behaviour is pinned in the generator's
|
|
826
868
|
`test/template/proposal-asof.test.ts` — absent in a generated rig — ›
|
|
827
869
|
"names the overtaken one, the unanswerable one, and stays silent on the current one".
|
|
828
870
|
|
|
@@ -839,7 +881,7 @@ the selection query cannot reach. Add the heading — never the Agent queue.
|
|
|
839
881
|
|
|
840
882
|
One adapter needs the second argument the snippet above carries: `jira` requires
|
|
841
883
|
`options.project` and throws rather than filing without it — loudly, so nothing
|
|
842
|
-
is lost, but a call that drops it files nothing
|
|
884
|
+
is lost, but a call that drops it files nothing.
|
|
843
885
|
|
|
844
886
|
🔴 **The loop proposes; the owner patches.** Self-applying a change to its own
|
|
845
887
|
rulebook is how an unattended run drifts irreversibly, and it collides head-on
|
|
@@ -875,20 +917,19 @@ three poisons the only channel by which this project learns.
|
|
|
875
917
|
the very next query.
|
|
876
918
|
- **Closing:** first ask whether the item is still the item you took up — a
|
|
877
919
|
late comment or a status somebody else moved is not published as `Done`
|
|
878
|
-
underneath it
|
|
920
|
+
underneath it:
|
|
879
921
|
|
|
880
922
|
```bash
|
|
881
923
|
node .claude/scripts/revalidate.mjs --point BEFORE_CLOSE --ticket <item-id>
|
|
882
924
|
```
|
|
883
925
|
|
|
884
|
-
It compares the
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
event at `point: BEFORE_CLOSE`, and lists the item's dependants with each
|
|
926
|
+
It compares the tracked claim's `scope` and `commentary` fingerprint sets;
|
|
927
|
+
commentary becomes hold-authoritative only here. Marker/take-up movement is
|
|
928
|
+
retained in evidence but cannot decide drift. A missing claim is
|
|
929
|
+
`UNVERIFIABLE` and stops the close. The adapter's expected claimed state is
|
|
930
|
+
part of the same `claim:scope` comparison rather than a second state-drift
|
|
931
|
+
decision. The check journals one `revalidation` event at `point:
|
|
932
|
+
BEFORE_CLOSE` and lists the item's dependants with each
|
|
892
933
|
one's state re-read for the write-back below — pinned in the generator's
|
|
893
934
|
`test/template/revalidate.test.ts` (absent in a generated rig) › "appends
|
|
894
935
|
exactly one BEFORE_CLOSE revalidation event after the BEFORE_PR one, and does
|
|
@@ -35,7 +35,7 @@ blockers.
|
|
|
35
35
|
flow, and this gate with it, begins when the project has a remote
|
|
36
36
|
(`workflow.md`, "PR flow"). The refusal exists because two rounds were once counted ahead of a
|
|
37
37
|
commit pre-commit then refused, so the counter and the fan-out's verdicts
|
|
38
|
-
named a head that never shipped
|
|
38
|
+
named a head that never shipped — pinned in the generator's
|
|
39
39
|
`test/template/gate-rounds.test.ts` — absent in a generated rig — ›
|
|
40
40
|
"refuses to count a round on a dirty tree, and counts nothing".
|
|
41
41
|
|
|
@@ -57,26 +57,33 @@ blockers.
|
|
|
57
57
|
confidently-wrong reviews. Everything below is scoped to this diff.
|
|
58
58
|
|
|
59
59
|
Then, on the fetched ref, ask whether the branch is still the branch the run
|
|
60
|
-
took up
|
|
60
|
+
took up:
|
|
61
61
|
|
|
62
62
|
```sh
|
|
63
63
|
node .claude/scripts/revalidate.mjs --point BEFORE_PR --ticket <item-id> --base origin/<default>
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
It
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
It runs the existing revalidation chain against the tracked, versioned
|
|
67
|
+
`.rig/claims/<item-id>.json`: the content-blind `scope` fingerprint set is
|
|
68
|
+
authoritative here, while `takeUps` / `updatedAt` remain evidence only. It
|
|
69
|
+
also names what the default branch changed since this branch forked on paths
|
|
70
|
+
the branch touches or a `check-premises` record cited (`main:<path>`). It
|
|
70
71
|
journals one `revalidation` event at `point: BEFORE_PR`; **exit code 2 is a HOLD**, with one blocker per named source: re-read the item, or the default
|
|
71
72
|
branch on that path, record what the re-read concluded —
|
|
72
73
|
`node .claude/scripts/revalidate.mjs outcome --point BEFORE_PR --ticket <item-id> --action-changed <true | false> --note '…'`
|
|
73
74
|
— and come back through step 0. A hold with no outcome is counted by the
|
|
74
|
-
report as a re-read the run skipped.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
report as a re-read the run skipped. A missing, untracked, unreadable or
|
|
76
|
+
unsupported claim is `UNVERIFIABLE`, exits 2, and stops automatic progress;
|
|
77
|
+
so is a tracker whose adapter the command cannot READ, which means the
|
|
78
|
+
question was never put rather than that the claim record is unreadable.
|
|
79
|
+
Neither is ever read as a pass. Exit 1 is the command refusing (unknown
|
|
80
|
+
point, no ticket, a base that is not a revision, or a queue config that does
|
|
81
|
+
not resolve): fix the call or the config — the message says which. Its limits are its own header's; the
|
|
82
|
+
cited-path set is a labelled assumption, not a recorded fact. Pinned in the
|
|
83
|
+
generator's `test/template/revalidate.test.ts` (absent in a generated rig) ›
|
|
84
|
+
"continues when only updatedAt moved and still reports the marker evidence"
|
|
85
|
+
and `test/template/content-blind-revalidation.test.ts` › "refuses a deleted
|
|
86
|
+
tracked claim in a fresh run without take-up markers".
|
|
80
87
|
2. **Route the diff before you spend on it.** This gate always ran its most
|
|
81
88
|
expensive path, so a typo fix in a README bought the same fan-out as a
|
|
82
89
|
rewrite of the storage layer. The dispatcher decides which lane the change
|
|
@@ -7,38 +7,38 @@
|
|
|
7
7
|
"hooks": [
|
|
8
8
|
{
|
|
9
9
|
"type": "command",
|
|
10
|
-
"command": "
|
|
11
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
10
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-core-purity.mjs\"",
|
|
11
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAGMAbwByAGUALQBwAHUAcgBpAHQAeQAuAG0AagBzACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8AIAA9ACAATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBTAHQAYQByAHQASQBuAGYAbwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEYAaQBsAGUATgBhAG0AZQAgAD0AIAAnAG4AbwBkAGUAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEEAcgBnAHUAbQBlAG4AdABzACAAPQAgACcAIgAnACAAKwAgACQAaABvAG8AawBQAGEAdABoACAAKwAgACcAIgAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AVQBzAGUAUwBoAGUAbABsAEUAeABlAGMAdQB0AGUAIAA9ACAAJABmAGEAbABzAGUAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBSAGUAZABpAHIAZQBjAHQAUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAgAD0AIAAkAHQAcgB1AGUAOwAgACQAYwBoAGkAbABkACAAPQAgAFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAF0AOgA6AFMAdABhAHIAdAAoACQAcwB0AGEAcgB0AEkAbgBmAG8AKQA7ACAAWwBDAG8AbgBzAG8AbABlAF0AOgA6AE8AcABlAG4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAoACkALgBDAG8AcAB5AFQAbwAoACQAYwBoAGkAbABkAC4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAuAEIAYQBzAGUAUwB0AHIAZQBhAG0AKQA7ACAAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQwBsAG8AcwBlACgAKQA7ACAAJABjAGgAaQBsAGQALgBXAGEAaQB0AEYAbwByAEUAeABpAHQAKAApADsAIABlAHgAaQB0ACAAJABjAGgAaQBsAGQALgBFAHgAaQB0AEMAbwBkAGUA"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"type": "command",
|
|
15
|
-
"command": "
|
|
16
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
15
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-web-boundary.mjs\"",
|
|
16
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAHcAZQBiAC0AYgBvAHUAbgBkAGEAcgB5AC4AbQBqAHMAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAFMAdABhAHIAdABJAG4AZgBvADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4ARgBpAGwAZQBOAGEAbQBlACAAPQAgACcAbgBvAGQAZQAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AQQByAGcAdQBtAGUAbgB0AHMAIAA9ACAAJwAiACcAIAArACAAJABoAG8AbwBrAFAAYQB0AGgAIAArACAAJwAiACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBVAHMAZQBTAGgAZQBsAGwARQB4AGUAYwB1AHQAZQAgAD0AIAAkAGYAYQBsAHMAZQA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAFIAZQBkAGkAcgBlAGMAdABTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACAAPQAgACQAdAByAHUAZQA7ACAAJABjAGgAaQBsAGQAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAXQA6ADoAUwB0AGEAcgB0ACgAJABzAHQAYQByAHQASQBuAGYAbwApADsAIABbAEMAbwBuAHMAbwBsAGUAXQA6ADoATwBwAGUAbgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACgAKQAuAEMAbwBwAHkAVABvACgAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQgBhAHMAZQBTAHQAcgBlAGEAbQApADsAIAAkAGMAaABpAGwAZAAuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQALgBDAGwAbwBzAGUAKAApADsAIAAkAGMAaABpAGwAZAAuAFcAYQBpAHQARgBvAHIARQB4AGkAdAAoACkAOwAgAGUAeABpAHQAIAAkAGMAaABpAGwAZAAuAEUAeABpAHQAQwBvAGQAZQA="
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"type": "command",
|
|
20
|
-
"command": "
|
|
21
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
20
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-secret-file.mjs\"",
|
|
21
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAHMAZQBjAHIAZQB0AC0AZgBpAGwAZQAuAG0AagBzACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8AIAA9ACAATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBTAHQAYQByAHQASQBuAGYAbwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEYAaQBsAGUATgBhAG0AZQAgAD0AIAAnAG4AbwBkAGUAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEEAcgBnAHUAbQBlAG4AdABzACAAPQAgACcAIgAnACAAKwAgACQAaABvAG8AawBQAGEAdABoACAAKwAgACcAIgAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AVQBzAGUAUwBoAGUAbABsAEUAeABlAGMAdQB0AGUAIAA9ACAAJABmAGEAbABzAGUAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBSAGUAZABpAHIAZQBjAHQAUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAgAD0AIAAkAHQAcgB1AGUAOwAgACQAYwBoAGkAbABkACAAPQAgAFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAF0AOgA6AFMAdABhAHIAdAAoACQAcwB0AGEAcgB0AEkAbgBmAG8AKQA7ACAAWwBDAG8AbgBzAG8AbABlAF0AOgA6AE8AcABlAG4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAoACkALgBDAG8AcAB5AFQAbwAoACQAYwBoAGkAbABkAC4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAuAEIAYQBzAGUAUwB0AHIAZQBhAG0AKQA7ACAAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQwBsAG8AcwBlACgAKQA7ACAAJABjAGgAaQBsAGQALgBXAGEAaQB0AEYAbwByAEUAeABpAHQAKAApADsAIABlAHgAaQB0ACAAJABjAGgAaQBsAGQALgBFAHgAaQB0AEMAbwBkAGUA"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"type": "command",
|
|
25
|
-
"command": "
|
|
26
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
25
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-rulebook.mjs\"",
|
|
26
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAHIAdQBsAGUAYgBvAG8AawAuAG0AagBzACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8AIAA9ACAATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBTAHQAYQByAHQASQBuAGYAbwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEYAaQBsAGUATgBhAG0AZQAgAD0AIAAnAG4AbwBkAGUAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEEAcgBnAHUAbQBlAG4AdABzACAAPQAgACcAIgAnACAAKwAgACQAaABvAG8AawBQAGEAdABoACAAKwAgACcAIgAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AVQBzAGUAUwBoAGUAbABsAEUAeABlAGMAdQB0AGUAIAA9ACAAJABmAGEAbABzAGUAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBSAGUAZABpAHIAZQBjAHQAUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAgAD0AIAAkAHQAcgB1AGUAOwAgACQAYwBoAGkAbABkACAAPQAgAFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAF0AOgA6AFMAdABhAHIAdAAoACQAcwB0AGEAcgB0AEkAbgBmAG8AKQA7ACAAWwBDAG8AbgBzAG8AbABlAF0AOgA6AE8AcABlAG4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAoACkALgBDAG8AcAB5AFQAbwAoACQAYwBoAGkAbABkAC4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAuAEIAYQBzAGUAUwB0AHIAZQBhAG0AKQA7ACAAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQwBsAG8AcwBlACgAKQA7ACAAJABjAGgAaQBsAGQALgBXAGEAaQB0AEYAbwByAEUAeABpAHQAKAApADsAIABlAHgAaQB0ACAAJABjAGgAaQBsAGQALgBFAHgAaQB0AEMAbwBkAGUA"
|
|
27
27
|
}
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
|
-
"matcher": "Bash",
|
|
31
|
+
"matcher": "Bash|PowerShell",
|
|
32
32
|
"hooks": [
|
|
33
33
|
{
|
|
34
34
|
"type": "command",
|
|
35
|
-
"command": "
|
|
36
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
35
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/block-no-verify.mjs\"",
|
|
36
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGIAbABvAGMAawAtAG4AbwAtAHYAZQByAGkAZgB5AC4AbQBqAHMAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAFMAdABhAHIAdABJAG4AZgBvADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4ARgBpAGwAZQBOAGEAbQBlACAAPQAgACcAbgBvAGQAZQAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AQQByAGcAdQBtAGUAbgB0AHMAIAA9ACAAJwAiACcAIAArACAAJABoAG8AbwBrAFAAYQB0AGgAIAArACAAJwAiACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBVAHMAZQBTAGgAZQBsAGwARQB4AGUAYwB1AHQAZQAgAD0AIAAkAGYAYQBsAHMAZQA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAFIAZQBkAGkAcgBlAGMAdABTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACAAPQAgACQAdAByAHUAZQA7ACAAJABjAGgAaQBsAGQAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAXQA6ADoAUwB0AGEAcgB0ACgAJABzAHQAYQByAHQASQBuAGYAbwApADsAIABbAEMAbwBuAHMAbwBsAGUAXQA6ADoATwBwAGUAbgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACgAKQAuAEMAbwBwAHkAVABvACgAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQgBhAHMAZQBTAHQAcgBlAGEAbQApADsAIAAkAGMAaABpAGwAZAAuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQALgBDAGwAbwBzAGUAKAApADsAIAAkAGMAaABpAGwAZAAuAFcAYQBpAHQARgBvAHIARQB4AGkAdAAoACkAOwAgAGUAeABpAHQAIAAkAGMAaABpAGwAZAAuAEUAeABpAHQAQwBvAGQAZQA="
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"type": "command",
|
|
40
|
-
"command": "
|
|
41
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
40
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-bash.mjs\"",
|
|
41
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAGIAYQBzAGgALgBtAGoAcwAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAUwB0AGEAcgB0AEkAbgBmAG8AOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBGAGkAbABlAE4AYQBtAGUAIAA9ACAAJwBuAG8AZABlACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBBAHIAZwB1AG0AZQBuAHQAcwAgAD0AIAAnACIAJwAgACsAIAAkAGgAbwBvAGsAUABhAHQAaAAgACsAIAAnACIAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAFUAcwBlAFMAaABlAGwAbABFAHgAZQBjAHUAdABlACAAPQAgACQAZgBhAGwAcwBlADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AUgBlAGQAaQByAGUAYwB0AFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQAIAA9ACAAJAB0AHIAdQBlADsAIAAkAGMAaABpAGwAZAAgAD0AIABbAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBdADoAOgBTAHQAYQByAHQAKAAkAHMAdABhAHIAdABJAG4AZgBvACkAOwAgAFsAQwBvAG4AcwBvAGwAZQBdADoAOgBPAHAAZQBuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQAKAApAC4AQwBvAHAAeQBUAG8AKAAkAGMAaABpAGwAZAAuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQALgBCAGEAcwBlAFMAdAByAGUAYQBtACkAOwAgACQAYwBoAGkAbABkAC4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAuAEMAbABvAHMAZQAoACkAOwAgACQAYwBoAGkAbABkAC4AVwBhAGkAdABGAG8AcgBFAHgAaQB0ACgAKQA7ACAAZQB4AGkAdAAgACQAYwBoAGkAbABkAC4ARQB4AGkAdABDAG8AZABlAA=="
|
|
42
42
|
}
|
|
43
43
|
]
|
|
44
44
|
}
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"hooks": [
|
|
49
49
|
{
|
|
50
50
|
"type": "command",
|
|
51
|
-
"command": "
|
|
51
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/gate-stop-dod.mjs\"",
|
|
52
52
|
"timeout": 900,
|
|
53
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
53
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAYQB0AGUALQBzAHQAbwBwAC0AZABvAGQALgBtAGoAcwAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAUwB0AGEAcgB0AEkAbgBmAG8AOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBGAGkAbABlAE4AYQBtAGUAIAA9ACAAJwBuAG8AZABlACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBBAHIAZwB1AG0AZQBuAHQAcwAgAD0AIAAnACIAJwAgACsAIAAkAGgAbwBvAGsAUABhAHQAaAAgACsAIAAnACIAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAFUAcwBlAFMAaABlAGwAbABFAHgAZQBjAHUAdABlACAAPQAgACQAZgBhAGwAcwBlADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AUgBlAGQAaQByAGUAYwB0AFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQAIAA9ACAAJAB0AHIAdQBlADsAIAAkAGMAaABpAGwAZAAgAD0AIABbAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBdADoAOgBTAHQAYQByAHQAKAAkAHMAdABhAHIAdABJAG4AZgBvACkAOwAgAFsAQwBvAG4AcwBvAGwAZQBdADoAOgBPAHAAZQBuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQAKAApAC4AQwBvAHAAeQBUAG8AKAAkAGMAaABpAGwAZAAuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQALgBCAGEAcwBlAFMAdAByAGUAYQBtACkAOwAgACQAYwBoAGkAbABkAC4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAuAEMAbABvAHMAZQAoACkAOwAgACQAYwBoAGkAbABkAC4AVwBhAGkAdABGAG8AcgBFAHgAaQB0ACgAKQA7ACAAZQB4AGkAdAAgACQAYwBoAGkAbABkAC4ARQB4AGkAdABDAG8AZABlAA=="
|
|
54
54
|
}
|
|
55
55
|
]
|
|
56
56
|
}
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"hooks": [
|
|
61
61
|
{
|
|
62
62
|
"type": "command",
|
|
63
|
-
"command": "
|
|
64
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand
|
|
63
|
+
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/inject-rules.mjs\"",
|
|
64
|
+
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGkAbgBqAGUAYwB0AC0AcgB1AGwAZQBzAC4AbQBqAHMAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAFMAdABhAHIAdABJAG4AZgBvADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4ARgBpAGwAZQBOAGEAbQBlACAAPQAgACcAbgBvAGQAZQAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AQQByAGcAdQBtAGUAbgB0AHMAIAA9ACAAJwAiACcAIAArACAAJABoAG8AbwBrAFAAYQB0AGgAIAArACAAJwAiACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBVAHMAZQBTAGgAZQBsAGwARQB4AGUAYwB1AHQAZQAgAD0AIAAkAGYAYQBsAHMAZQA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAFIAZQBkAGkAcgBlAGMAdABTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACAAPQAgACQAdAByAHUAZQA7ACAAJABjAGgAaQBsAGQAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAXQA6ADoAUwB0AGEAcgB0ACgAJABzAHQAYQByAHQASQBuAGYAbwApADsAIABbAEMAbwBuAHMAbwBsAGUAXQA6ADoATwBwAGUAbgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACgAKQAuAEMAbwBwAHkAVABvACgAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQgBhAHMAZQBTAHQAcgBlAGEAbQApADsAIAAkAGMAaABpAGwAZAAuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQALgBDAGwAbwBzAGUAKAApADsAIAAkAGMAaABpAGwAZAAuAFcAYQBpAHQARgBvAHIARQB4AGkAdAAoACkAOwAgAGUAeABpAHQAIAAkAGMAaABpAGwAZAAuAEUAeABpAHQAQwBvAGQAZQA="
|
|
65
65
|
}
|
|
66
66
|
]
|
|
67
67
|
}
|
|
@@ -94,8 +94,9 @@ names the platform never sends. The guards therefore accept
|
|
|
94
94
|
that documented string form. A command that is ABSENT still fails open — a
|
|
95
95
|
payload the hook does not understand — while one that is present and is not a
|
|
96
96
|
shape the normalizer reads is REFUSED, because that is a condition it detects
|
|
97
|
-
and can report rather than an error it threw. See
|
|
98
|
-
|
|
97
|
+
and can report rather than an error it threw. See the generator's
|
|
98
|
+
`codex.test.ts` (absent in a generated rig) › "refuses, rather than failing
|
|
99
|
+
open, when apply_patch command is supplied as %s".
|
|
99
100
|
Hook output is the JSON `description` plus event arrays accepted by
|
|
100
101
|
`.codex/hooks.json`; command portability is carried by generated POSIX and
|
|
101
102
|
Windows commands. In this generated project, `.claude/settings.json` and
|