axstack 0.10.1 → 0.11.1
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 +5 -6
- package/docs/workflows.md +28 -29
- package/package.json +1 -1
- package/skills/axstack/references/automations.md +327 -448
- package/skills/axstack/references/lifecycle.md +12 -16
- package/skills/axstack-relay/SKILL.md +24 -6
- package/skills/axstack-review/SKILL.md +32 -53
- package/skills/axstack-watch/SKILL.md +13 -14
- package/skills/axstack-watch/references/repair-publication.md +5 -3
- package/skills/axstack-watch/references/watch-runtime.md +16 -22
|
@@ -1,463 +1,342 @@
|
|
|
1
1
|
# Automation sessions
|
|
2
2
|
|
|
3
|
-
Read this when the current session is
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- **
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
an
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
3
|
+
Read this when the current session is the native Orca PR **driver** or its
|
|
4
|
+
**watchdog**. The approved contract is
|
|
5
|
+
`docs/specs/pr-automations.md` revision 4; this reference restates the parts an
|
|
6
|
+
automation session must execute and does not widen them.
|
|
7
|
+
|
|
8
|
+
Pair A/B is retired for this contract; its artefacts remain untouched.
|
|
9
|
+
|
|
10
|
+
## Roles and authority
|
|
11
|
+
|
|
12
|
+
- **driver** — every 15 minutes, fresh Opus session in the dedicated Axstack
|
|
13
|
+
automations worktree. It discovers GitHub work, binds the persistent Orca
|
|
14
|
+
Run, creates one project-local child worktree per selected PR, dispatches the
|
|
15
|
+
matching Axstack agent, reconciles completions and decisions, then exits. The
|
|
16
|
+
driver is the automation session itself, with no `axstack-monitor` or
|
|
17
|
+
`axstack-owner` role row. It never performs review or repair in its own
|
|
18
|
+
session. Its only direct GitHub mutation is an already-approved decision:
|
|
19
|
+
one `gh pr review` or one fast-forward push of a preserved candidate.
|
|
20
|
+
- **watchdog** — hourly at a distinct minute. It is a shell precheck with no
|
|
21
|
+
model, never launches an agent session, never mutates GitHub, and only sends
|
|
22
|
+
the health notifications defined below.
|
|
23
|
+
- `axstack-monitor` remains an optional read-only observer that never sends.
|
|
24
|
+
|
|
25
|
+
Self is resolved on every run with `gh api user --jq .login`; never hardcode
|
|
26
|
+
it. The review allowlist is `defi-com/monorepo`, `defi-com/mobile`, and
|
|
27
|
+
`defi-com/azure-next-hybrid`. The repair allowlist is `defi-com/monorepo` and
|
|
28
|
+
`defi-com/mobile`. State both lists verbatim in the driver prompt. An own PR is
|
|
29
|
+
open, authored by self, on the repair allowlist, and not a draft. A peer PR is
|
|
30
|
+
open, on the review allowlist, authored by someone else, and either officially
|
|
31
|
+
review-requested from self or has a non-self comment that both mentions self
|
|
32
|
+
and asks for review or response. The driver reads and records the comment id
|
|
33
|
+
and its interpretation; incidental mentions are discovery only.
|
|
34
|
+
|
|
35
|
+
Outside the union of both allowlists, record only and exclude the PR from the
|
|
36
|
+
fingerprint. Peer code is read-only, though its worktree may install
|
|
37
|
+
dependencies and run repository tests. Own-PR authority permits repair, test,
|
|
38
|
+
commit, and fast-forward `git push` without lease or force. Force-push, rebase,
|
|
39
|
+
merge, close, every `gh stack` sync/restack/rebase/merge/link/submit action,
|
|
40
|
+
`COMMENT` reviews, and every GitHub write by the watchdog or Hermes are
|
|
41
|
+
prohibited.
|
|
42
|
+
|
|
43
|
+
## Discovery and wake
|
|
44
|
+
|
|
45
|
+
The bounded driver precheck contains no model and exits 0 only for changed or
|
|
46
|
+
due work.
|
|
47
|
+
|
|
48
|
+
1. If `cursor.json.tick_started_at` is newer than `tick_done_at` and younger
|
|
49
|
+
than 1 h, append `running` to `precheck.log` and exit 3. This overlap guard
|
|
50
|
+
inspects no terminal.
|
|
51
|
+
2. Resolve self, then run exactly four `gh search prs --state open --limit 100
|
|
52
|
+
--json url,number,repository,updatedAt` searches: `--author @me`,
|
|
53
|
+
`--review-requested @me`, `--mentions @me`, and
|
|
54
|
+
`--reviewed-by @me --review changes_requested`. A result count equal to 100
|
|
55
|
+
is truncation: append `error`, exit 2, and do not write a fingerprint.
|
|
56
|
+
Deduplicate by URL with own-PR precedence and drop repositories outside the
|
|
57
|
+
allowlist union.
|
|
58
|
+
3. For each retained PR, read `gh pr view --json headRefOid,baseRefName,isDraft,
|
|
59
|
+
statusCheckRollup,author,latestReviews` and resolve the base SHA with
|
|
60
|
+
`gh api repos/<repo>/commits/<base>`. Own PRs contribute head, base, draft,
|
|
61
|
+
checks reduced to `{name, conclusion|state}` pairs, and the set of
|
|
62
|
+
`latestReviews` `{id, state}` whose `commit` is the head; others contribute
|
|
63
|
+
head and base.
|
|
64
|
+
4. Debounce peer and fourth-search heads: they enter the hashed subset only on
|
|
65
|
+
the second consecutive precheck that observes them. The first observation
|
|
66
|
+
goes in `pending.json.seen[]`. Own heads enter immediately. Hash this subset
|
|
67
|
+
as the fingerprint.
|
|
68
|
+
|
|
69
|
+
### Due control work
|
|
70
|
+
|
|
71
|
+
Read `cursor.json` and `decisions/`. Work is due for:
|
|
72
|
+
|
|
73
|
+
- a decision in `approved` or `rejected` without `consumed_at`;
|
|
74
|
+
- a `spent` decision without a receipt, which needs reconciliation;
|
|
75
|
+
- a `deferred[]` entry whose head still matches discovery;
|
|
76
|
+
- an expired repair cap;
|
|
77
|
+
- a dispatch marker older than 3 h;
|
|
78
|
+
- an unsettled Orca delivery in `pending_settlement[]`.
|
|
79
|
+
|
|
80
|
+
An `open` decision is not due. Write `pending.json` with the fingerprint,
|
|
81
|
+
`observed_at`, `seen[]`, full discovery list, and hashed subset. Append
|
|
82
|
+
`<ts> changed|due|unchanged|running|error` to `precheck.log`; exit 0 for
|
|
83
|
+
`changed` or `due`, 1 for `unchanged`, 2 for `error`, and 3 for `running`.
|
|
84
|
+
|
|
85
|
+
## Driver tick
|
|
86
|
+
|
|
87
|
+
The driver performs this order and exits:
|
|
88
|
+
|
|
89
|
+
1. If `tick_started_at` is newer than `tick_done_at`, add `previous tick did
|
|
90
|
+
not finish` to `cursor.json.health[]`. Write `tick_started_at`. Match this
|
|
91
|
+
session's `ORCA_TERMINAL_HANDLE` to the driver's `terminalPtyId` from
|
|
92
|
+
`orca automations runs --id <driver>`, then verify the transcript model.
|
|
93
|
+
Non-Opus or unknown identity records a hold and `tick_outcome: held`, and
|
|
94
|
+
dispatches nothing.
|
|
95
|
+
2. Bind the persistent Run with `orca orchestration run-use` and read the
|
|
96
|
+
inbox. For a `worker_done` matching a live marker, verify the review id at
|
|
97
|
+
the bound head, push range, or opened token. Release the worker; remove its
|
|
98
|
+
child worktree only after confirmed process exit and accepted settlement;
|
|
99
|
+
then clear the marker. Unverifiable delivery stays in
|
|
100
|
+
`pending_settlement[]` and blocks only that PR.
|
|
101
|
+
3. Consume decisions as their sole consumer under "Decision tokens" below.
|
|
102
|
+
4. Reconcile every marker older than 3 h. A live worker gets `worker-stop`; an
|
|
103
|
+
exited worker gets `worker-abandon`. Unknown liveness or user takeover
|
|
104
|
+
retains worktree and marker and blocks only that PR. After confirmed
|
|
105
|
+
abandon, remove the worktree, append one health line, increment the head's
|
|
106
|
+
`abandon_count`, and drop that head so normal selection retries once. For a
|
|
107
|
+
review-triggered dispatch, use the marker's `trigger` to remove exactly its
|
|
108
|
+
review id and digest from `processed_reviews[]`. A second abandon at that
|
|
109
|
+
head is a user-owned hold.
|
|
110
|
+
5. Select changed PRs and matching `deferred[]` entries oldest `updatedAt`
|
|
111
|
+
first. Skip a current-head decision in `open` or `approved`, and skip a live
|
|
112
|
+
marker. Dispatch within the repair and review rules below.
|
|
113
|
+
6. Promote the `pending.json` fingerprint verbatim, because it records
|
|
114
|
+
observation rather than completion. Write `tick_done_at` and
|
|
115
|
+
`tick_outcome: ok`, then exit.
|
|
116
|
+
|
|
117
|
+
## Dispatch and repair selection
|
|
118
|
+
|
|
119
|
+
Every selected PR receives one dispatch marker with task id, dispatch id,
|
|
120
|
+
worktree, head, `started_at`, reservation (`verdict` or `repair`), and trigger:
|
|
121
|
+
`{kind: check, name, app_id}` or `{kind: review, review_id, digest}`. There is at
|
|
122
|
+
most one live marker per PR. The marker is the claim shared by scheduled and
|
|
123
|
+
attended sessions; revalidation immediately before an external call is its
|
|
124
|
+
second half. It makes no exactly-once claim against concurrent human GitHub
|
|
125
|
+
activity.
|
|
126
|
+
|
|
127
|
+
An own PR needs repair when either trigger applies:
|
|
128
|
+
|
|
129
|
+
1. a failing check has a base check-run with the same `name` and the same
|
|
130
|
+
producing `app.id` observed passing through
|
|
131
|
+
`gh api repos/<repo>/commits/<base>/check-runs`; for a legacy commit status,
|
|
132
|
+
its counterpart has the same `context`. A missing, pending, or same-name
|
|
133
|
+
different-app base check holds repair;
|
|
134
|
+
2. a `CHANGES_REQUESTED` review at the current head, by any account, has both
|
|
135
|
+
a review id absent from `cursor.json.processed_reviews[]` and a SHA-256 body
|
|
136
|
+
digest not recorded for that PR and head. Both keys are required: the same
|
|
137
|
+
finding under a new review id must not re-trigger repair. Record review id
|
|
138
|
+
and body digest when dispatching. A superseded head with a new review
|
|
139
|
+
triggers again subject to the 24 h cap.
|
|
140
|
+
|
|
141
|
+
Repair also requires no deploy-on-push head branch, no live repair cap, and
|
|
142
|
+
selection of the lowest own PR in its stack that needs repair. Create a child
|
|
143
|
+
worktree in that project's clone at the exact head, parented to the driver
|
|
144
|
+
worktree, and dispatch one `axstack-watch` agent in authored repair mode. Its
|
|
145
|
+
brief contains only the triggering checks or review findings. Each open
|
|
146
|
+
descendant records one user-owned `pending restack` hold until it stops needing
|
|
147
|
+
repair. The 24 h cap starts at dispatch and an abandon does not refund it.
|
|
148
|
+
|
|
149
|
+
A debounced peer PR is eligible when self has not reviewed its head. Read
|
|
150
|
+
`gh pr view --json reviews` before dispatch. Whenever any self review with
|
|
151
|
+
state `CHANGES_REQUESTED` exists on the PR, from whichever search it came,
|
|
152
|
+
dispatch only if the latest effective, non-dismissed self review body contains
|
|
153
|
+
the line prefix `<!-- axstack-automation verdict` or its id is listed in
|
|
154
|
+
`cursor.json.legacy_automation_reviews[]`; otherwise record and skip, so a
|
|
155
|
+
human-placed block is never overwritten. A dismissed block and a self-approved
|
|
156
|
+
PR are skipped. Dispatch one `axstack-review` agent in peer mode and link the
|
|
157
|
+
prior review in its brief.
|
|
158
|
+
|
|
159
|
+
Budgets are one `verdict` dispatch per tick, oldest first; at most six `repair`
|
|
160
|
+
markers live across all repositories; and one repair per PR per 24 h. Put every
|
|
161
|
+
eligible PR not dispatched because of a budget in `deferred[]` with repo, PR,
|
|
162
|
+
and head. Budget exhaustion records the count and is not a hold.
|
|
163
|
+
|
|
164
|
+
## Agents and verdicts
|
|
165
|
+
|
|
166
|
+
Every agent works in its own project-local Orca child worktree at the exact
|
|
167
|
+
head and reports only through the Orca worker protocol.
|
|
168
|
+
|
|
169
|
+
Peer review runs the two isolated configured reviewers on the identical brief,
|
|
170
|
+
then the Luna gate. `APPROVE` requires complete exact-head/base reviews, gate
|
|
171
|
+
`proceed`, and zero validated blockers. `REQUEST_CHANGES` requires the same
|
|
172
|
+
completeness and `proceed`, plus at least one evidenced blocking finding.
|
|
173
|
+
`INCOMPLETE`, unresolved disagreement, unavailable review or gate, or unknown
|
|
174
|
+
GitHub state publishes nothing. Immediately before `gh pr review`, the agent
|
|
175
|
+
re-reads self's reviews at the head and skips with the existing id when one is
|
|
176
|
+
already present, then re-checks head, base, draft, authorship, and allowlist.
|
|
177
|
+
The verdict body ends with this exact marker line:
|
|
96
178
|
|
|
97
179
|
```text
|
|
98
|
-
|
|
180
|
+
<!-- axstack-automation verdict head=<sha> -->
|
|
99
181
|
```
|
|
100
182
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
## Stack-aware repair sequencing (pair C/D)
|
|
108
|
-
|
|
109
|
-
These three sections govern pair C/D only. Pair A/B's behaviour is unchanged by
|
|
110
|
-
revision 4 except for the named cadence correction, so A does not apply stack
|
|
111
|
-
sequencing, bot-triggered repair, the caps, or the deployment push hold.
|
|
112
|
-
|
|
113
|
-
Own-PR repair covers every own PR in the allowlisted repositories; stacking
|
|
114
|
-
changes the order of repair, never the scope. Within one stack the driver
|
|
115
|
-
repairs only the lowest open failing PR of that stack. Every open descendant of
|
|
116
|
-
a repaired PR records exactly one `pending restack` hold naming the repaired
|
|
117
|
-
parent and its new head SHA, and receives no independent repair of the same
|
|
118
|
-
finding while that hold stands. A descendant carrying a different finding from
|
|
119
|
-
the repaired parent's is repaired on its own merits, subject to the budgets
|
|
120
|
-
below; the hold suppresses duplicate application of the same finding, not all
|
|
121
|
-
work on the descendant.
|
|
122
|
-
|
|
123
|
-
The hold names the user as owner. It is cleared by the user's own restack, or by
|
|
124
|
-
a later tick observing the descendant no longer failing; that is the single
|
|
125
|
-
clearing rule. It is exempt from the watchdog's hold with no owner threshold,
|
|
126
|
-
because its owner is the user by construction. The per-tick budget counts one
|
|
127
|
-
unit per stack, not one per PR.
|
|
128
|
-
|
|
129
|
-
The reason is duplication, not politeness: the same finding recurs across a
|
|
130
|
-
stack, so independent per-PR repair would apply the identical fix at several
|
|
131
|
-
levels and the user's next cascade rebase would then conflict on the duplicate.
|
|
132
|
-
A parent fast-forward also does not change a descendant's PR diff, so a
|
|
133
|
-
descendant's CI and reviewers never see the parent fix; the hold states that
|
|
134
|
-
honestly instead of implying the descendant was repaired.
|
|
135
|
-
|
|
136
|
-
`gh stack` sync, restack, rebase, merge, link and submit remain out of scope for
|
|
137
|
-
every automation, and force-push and rebase stay prohibited everywhere. A
|
|
138
|
-
descendant is held, never rewritten.
|
|
139
|
-
|
|
140
|
-
## Bot review feedback (pair C/D)
|
|
141
|
-
|
|
142
|
-
A review authored by a bot account may be actionable and may trigger a repair,
|
|
143
|
-
bounded as follows.
|
|
144
|
-
|
|
145
|
-
Dedup is by processed review ID and by a digest of the review body. A repair
|
|
146
|
-
fires only on a review whose review ID was never processed and whose body
|
|
147
|
-
digest is not already recorded against that PR at that head SHA. Review-ID dedup alone is
|
|
148
|
-
insufficient: a bot that re-posts the identical finding under a new review ID
|
|
149
|
-
would otherwise re-trigger a repair on every tick.
|
|
150
|
-
|
|
151
|
-
Caps: at most one repair per PR per 24 hours, counted regardless of trigger; a
|
|
152
|
-
per-tick push budget across all allowlisted repositories combined, configured
|
|
153
|
-
per pair and six for pair C/D; and, for pair C, a per-tick **review** budget
|
|
154
|
-
limiting how many binding verdicts may be submitted in one tick, configured per
|
|
155
|
-
pair and **one** for pair C. The review budget exists because C has no `COMMENT`
|
|
156
|
-
path, so an unbudgeted first tick over a backlog would place binding verdicts on
|
|
157
|
-
every discovered peer PR at once, unattended and on other people's work. Reviews
|
|
158
|
-
beyond the budget are left for the next tick, oldest `updatedAt` first so the
|
|
159
|
-
backlog drains in a stable order rather than by chance. Reaching any of the three caps records a hold naming the cap
|
|
160
|
-
and the value reached, rather than silently dropping the work. A budget hold
|
|
161
|
-
names the budget as its owner and is exempt from the hold with no owner
|
|
162
|
-
threshold. When a per-PR cap has expired the precheck wakes the driver even
|
|
163
|
-
if the forge is unchanged, so capped work is never stranded; the precheck
|
|
164
|
-
section below carries that trigger in its due-work list.
|
|
165
|
-
|
|
166
|
-
A bot review never satisfies the peer-PR trigger, which still requires self to
|
|
167
|
-
be officially review-requested or a comment that explicitly asks self to review
|
|
168
|
-
or respond.
|
|
169
|
-
|
|
170
|
-
## Watch window
|
|
171
|
-
|
|
172
|
-
Pair A/B keeps its 24 hours per own PR from first observation, ending early on
|
|
173
|
-
merge or close, with the deadline in `cursor.json`, the `expired` marking, and
|
|
174
|
-
the user re-arming an expired PR in the automation session.
|
|
175
|
-
|
|
176
|
-
Pair C/D uses a rolling window instead: a PR is in scope while it is open and
|
|
177
|
-
eligible, and leaves scope on merge or close. There is no expiry and no
|
|
178
|
-
re-arming, C/D's `cursor.json` stores no deadlines, and `expired` is not a state
|
|
179
|
-
a C/D PR can reach.
|
|
180
|
-
|
|
181
|
-
The difference is deliberate, not drift. A serves one low-volume repository
|
|
182
|
-
where expiry is cheap, while C would otherwise start twenty or more simultaneous
|
|
183
|
-
clocks on first observation and go dark a day later. Because that window
|
|
184
|
-
removes expiry as a cost brake, the per-PR and per-tick budgets and the watchdog
|
|
185
|
-
are the only brakes left on C, and D's thresholds are retuned for a fingerprint
|
|
186
|
-
that legitimately changes on nearly every tick.
|
|
187
|
-
|
|
188
|
-
## PR eligibility for repair (pair C/D)
|
|
189
|
-
|
|
190
|
-
A draft PR is discovered and recorded but never repaired; it becomes eligible
|
|
191
|
-
when it is marked ready for review, which the ordinary event state observes as
|
|
192
|
-
new work. A PR that already has a human reviewer requested is eligible for
|
|
193
|
-
repair and is not excluded, deliberately: most own PRs in these repositories
|
|
194
|
-
carry a requested human reviewer, and excluding them would empty the coverage.
|
|
195
|
-
`defi-com/mobile` has no workflows and therefore no check signal, so a repair
|
|
196
|
-
there is triggered only by actionable review feedback; if CI is later added the
|
|
197
|
-
ordinary check-rollup trigger applies with no contract change.
|
|
198
|
-
|
|
199
|
-
## Deployment safety (pair C/D)
|
|
200
|
-
|
|
201
|
-
A repair never pushes to a PR whose head branch is in that repository's
|
|
202
|
-
deploy-on-push set, and an attempt to do so is a recorded hold. The rule is
|
|
203
|
-
branch-name-agnostic: the set is enumerated per repository from that
|
|
204
|
-
repository's workflow files, recorded, and re-verified before enabling and on
|
|
205
|
-
any later allowlist change. It is never hardcoded to one branch name, because a
|
|
206
|
-
repository may deploy from more than one branch and may add another at any time.
|
|
207
|
-
|
|
208
|
-
## Binding review verdicts (pair C)
|
|
209
|
-
|
|
210
|
-
Automation C submits a real review verdict where pair A/B publishes a `COMMENT`.
|
|
211
|
-
The authority is narrow and every bound below is load-bearing.
|
|
212
|
-
|
|
213
|
-
Every review Automation C publishes is a binding verdict. C has no `COMMENT`
|
|
214
|
-
path: a peer PR reached through the qualifying mention trigger gets a verdict
|
|
215
|
-
exactly as an officially-requested one does. The only restriction is authorship
|
|
216
|
-
— GitHub rejects a verdict from a PR's own author, so an authored-mode review of
|
|
217
|
-
C's own repair stays internal and gates only the push. Automation D never writes
|
|
218
|
-
to GitHub at all.
|
|
219
|
-
|
|
220
|
-
`APPROVE` requires a complete mode-required review at the exact head SHA with a
|
|
221
|
-
current base, the gate's `proceed`, and zero unresolved validated blocking
|
|
222
|
-
findings. `REQUEST_CHANGES` requires the same completeness and gate token and at
|
|
223
|
-
least one validated blocking finding carrying its evidence and consequence; it
|
|
224
|
-
is the verdict that reports blockers and is not gated on their absence.
|
|
225
|
-
`INCOMPLETE`, unresolved material disagreement, an unavailable required
|
|
226
|
-
reviewer, or a gate `escalate` submits nothing and records a hold.
|
|
227
|
-
|
|
228
|
-
### Blocking obligations
|
|
229
|
-
|
|
230
|
-
A submitted `REQUEST_CHANGES` blocks the PR and a teammate's later push does not
|
|
231
|
-
clear it. Submitting a review also removes self from GitHub's `review-requested`
|
|
232
|
-
results, so a PR C has just blocked can leave discovery on the next tick and C
|
|
233
|
-
would never see it again to clear its own block.
|
|
234
|
-
|
|
235
|
-
C therefore records every unresolved blocking review in `cursor.json` as an open
|
|
236
|
-
obligation holding the PR URL, the review id, the head SHA it was bound to, and
|
|
237
|
-
the submission timestamp, and polls those PRs directly by URL every tick
|
|
238
|
-
regardless of discovery eligibility. An obligation is discharged only by
|
|
239
|
-
observing the PR merged, closed, or its blocking review resolved or superseded.
|
|
240
|
-
A failed poll retries next tick; three consecutive unpollable ticks is a health
|
|
241
|
-
finding routed to the gate.
|
|
242
|
-
|
|
243
|
-
While C holds any unresolved blocking review, every scheduled tick wakes it: an
|
|
244
|
-
outstanding obligation is due control work in the precheck's list, alongside a
|
|
245
|
-
watch deadline, a pending failed-relay retry, and an expired repair cap.
|
|
246
|
-
|
|
247
|
-
An obligation carries a narrow authority to resolve itself: C may submit exactly one superseding verdict on that PR,
|
|
248
|
-
including a clearing `APPROVE`, without a fresh review request. It follows the
|
|
249
|
-
obligation chain — an obligation opened by a verdict submitted under this
|
|
250
|
-
authority inherits it — so the authority persists on that one PR until it
|
|
251
|
-
merges, closes, or its block is resolved, and the deadlock does not reappear one
|
|
252
|
-
head later when a teammate pushes without fixing. It extends to nothing else: not
|
|
253
|
-
another PR, not a discharged obligation, and never more than one superseding
|
|
254
|
-
verdict per head SHA. A supersede whose head and base are both unchanged
|
|
255
|
-
additionally requires a recorded finding-level reason naming what changed about
|
|
256
|
-
the finding; without it C holds and submits nothing.
|
|
257
|
-
|
|
258
|
-
### Local review file
|
|
259
|
-
|
|
260
|
-
Every review C publishes, verdict or `COMMENT`, is also written to the
|
|
261
|
-
workspace review directory `~/defi/misc/reviews/`, carrying the same findings
|
|
262
|
-
and evidence as the submitted review plus the reviewed SHA. The naming is the
|
|
263
|
-
workspace convention and the prefix rules are load-bearing, because PR numbers
|
|
264
|
-
collide across repositories: `review-PR-<num>.html` with no prefix means
|
|
265
|
-
`defi-com/monorepo` by definition, and every other repository takes its prefix,
|
|
266
|
-
`review-azure-next-hybrid-PR-<num>.html` and `review-mobile-PR-<num>.html`. A
|
|
267
|
-
failure to write the file is a recorded hold; a review is never withheld or
|
|
268
|
-
retracted because the file could not be written, so the mismatch stays visible
|
|
269
|
-
rather than silent.
|
|
270
|
-
|
|
271
|
-
## Escalation gate
|
|
272
|
-
|
|
273
|
-
After every mode-required reviewer settles, the driver spawns `axstack-auditor`
|
|
274
|
-
with the verdicts and the candidate revision, instructing it to act as the
|
|
275
|
-
escalation gate. It returns exactly one literal token, `escalate` or `proceed`.
|
|
276
|
-
|
|
277
|
-
- The gate decides only whether the user is notified. Reviewer "yes" is input,
|
|
278
|
-
not a veto.
|
|
279
|
-
- `escalate` → records the hold, then one `hermes send` through
|
|
280
|
-
[axstack-relay](../../axstack-relay/SKILL.md) naming the PR, the criterion,
|
|
281
|
-
every reviewer's reason, where the user acts (Orca conversation, worktree, or
|
|
282
|
-
PR), and the hold; it publishes nothing.
|
|
283
|
-
- `proceed` → no notification; a push, a `COMMENT` publication, or an
|
|
284
|
-
`APPROVE` then additionally requires no unresolved validated blocking finding,
|
|
285
|
-
because `proceed` never overrides a validated blocking finding. A
|
|
286
|
-
`REQUEST_CHANGES` is the exception and the only one: it is the publication
|
|
287
|
-
that reports validated blocking findings, so it requires at least one and is
|
|
288
|
-
never gated on their absence. A reviewer security
|
|
289
|
-
"yes" that the gate does not escalate is recorded as rejected-with-evidence
|
|
290
|
-
or returned to the author before any mutation.
|
|
291
|
-
- Only `proceed` plus no unresolved validated blocking finding permits a push,
|
|
292
|
-
a `COMMENT` publication or an `APPROVE`; a `REQUEST_CHANGES` needs `proceed`
|
|
293
|
-
plus at least one such finding. A push or publication before the gate settles
|
|
294
|
-
is forbidden either way.
|
|
295
|
-
- Precedence: credible serious risk found by a reviewer still produces the
|
|
296
|
-
standing internal prompt and dependent-action hold immediately, and the gate
|
|
297
|
-
governs only external notification. That hold is the serious-risk rule of
|
|
298
|
-
[contracts](contracts.md#serious-risk). The internal prompt lands in the run
|
|
299
|
-
record and the automation's Orca conversation; no `hermes send` occurs
|
|
300
|
-
without `escalate`.
|
|
301
|
-
- The health gate takes a watchdog finding and its evidence, not reviewer
|
|
302
|
-
verdicts or a candidate; the same two tokens apply.
|
|
303
|
-
- An unavailable gate or required reviewer records a hold, pauses mutation for
|
|
304
|
-
that PR, and is treated as a watchdog health finding. An unavailable gate
|
|
305
|
-
cannot be escalated through itself: the hold stays, the gap is visible in
|
|
306
|
-
Orca run history and the sidecar, and no substitute or unauthorized send
|
|
307
|
-
occurs.
|
|
308
|
-
|
|
309
|
-
## Precheck (bounded shell, no model)
|
|
310
|
-
|
|
311
|
-
Resolve self; run the three searches with `--json url,number,repository,updatedAt`;
|
|
312
|
-
write the full discovery list to `pending.json`. For each allowlisted,
|
|
313
|
-
non-expired own PR add head SHA, base SHA, and the check rollup of that head via
|
|
314
|
-
`gh pr view --json headRefOid,baseRefOid,statusCheckRollup`; check state is
|
|
315
|
-
data, and only authentication, command, and network errors are `error`. For pair
|
|
316
|
-
C/D only, that call also requests `isDraft` and the precheck adds draft status
|
|
317
|
-
to the hashed fingerprint, so a draft becoming ready wakes the driver on its
|
|
318
|
-
own; pair A/B's queried fields and fingerprint are unchanged. Hash
|
|
319
|
-
only allowlisted PRs. Read `cursor.json` for the last processed fingerprint and
|
|
320
|
-
for due control work: a watch deadline at or before now (pair A/B only, since
|
|
321
|
-
pair C/D stores no deadlines), a pending failed-relay retry, a per-PR repair cap
|
|
322
|
-
that has expired, or an outstanding blocking-review obligation (both pair C/D
|
|
323
|
-
only, since pair A/B has neither caps nor binding verdicts). Exit 0 when the hash differs or control work is due;
|
|
324
|
-
otherwise exit non-zero. Exit non-zero without running when the previous driver
|
|
325
|
-
run is still active, or on `error`. Append one line
|
|
326
|
-
`<ts> <changed|due|unchanged|error|busy>` to `precheck.log`.
|
|
327
|
-
|
|
328
|
-
Terminal hygiene runs before the searches and covers driver terminals only.
|
|
329
|
-
Ownership is the driver automation's own recorded `terminalPtyId` from its Orca
|
|
330
|
-
run history, never a terminal title: Orca rewrites a Claude terminal's title to
|
|
331
|
-
the agent's current task summary, so a driver's title drifts and an unrelated
|
|
332
|
-
session can acquire one that reads like a driver. The precheck closes the
|
|
333
|
-
previous ticks' idle driver terminals with `--tab` — without it the pane closes
|
|
334
|
-
but the session stays listed and is never reclaimed, which also makes an
|
|
335
|
-
over-match destructive — and a driver terminal that is still working makes the
|
|
336
|
-
tick `busy`. It never closes a watchdog terminal or any terminal outside this
|
|
337
|
-
automation; an unreadable ownership source is `error`, never a silent empty
|
|
338
|
-
sweep. No two of the four automations may share a dispatch minute: A, B, C and D each
|
|
339
|
-
take a distinct minute, so a driver and its watchdog never collide and neither
|
|
340
|
-
pair can disturb the other's terminal hygiene.
|
|
341
|
-
|
|
342
|
-
The observed fingerprint is written to `pending.json`. After the processed
|
|
343
|
-
tick the driver promotes exactly that value to `cursor.json`, never a
|
|
344
|
-
recomputed one, so an event landing during a run is processed on the following
|
|
345
|
-
tick.
|
|
183
|
+
Write the local review file to the workspace review directory
|
|
184
|
+
`~/defi/misc/reviews/` under the existing convention:
|
|
185
|
+
`review-PR-<num>.html` with no prefix means `defi-com/monorepo`;
|
|
186
|
+
`review-mobile-PR-<num>.html` and
|
|
187
|
+
`review-azure-next-hybrid-PR-<num>.html` name the other repositories. A write
|
|
188
|
+
failure is recorded but does not withhold the verdict.
|
|
346
189
|
|
|
347
|
-
|
|
190
|
+
Authored repair commits a local candidate, obtains one Sol review at that
|
|
191
|
+
local SHA and the Luna gate, resolves every validated blocker, records test
|
|
192
|
+
evidence, re-reads remote head/base/draft/deploy set/allowlist, then pushes
|
|
193
|
+
fast-forward. The monorepo unit gate uses `~/.bun-1.2.2/bin/bun`; a suite that
|
|
194
|
+
cannot run locally is an explicit unverified boundary.
|
|
348
195
|
|
|
349
|
-
|
|
350
|
-
identity through Orca runtime inspection and records it; a self-written label
|
|
351
|
-
is not evidence. Expected model: Opus. A mismatch or unknown identity holds
|
|
352
|
-
repair and publication for that run and is a health finding.
|
|
353
|
-
|
|
354
|
-
For each changed PR:
|
|
355
|
-
|
|
356
|
-
- Own PR, and only when its repository is on the acting automation's repair
|
|
357
|
-
allowlist → [axstack-watch](../../axstack-watch/SKILL.md) on the exact head
|
|
358
|
-
SHA in a per-PR child worktree; the driver worktree never checks out a PR
|
|
359
|
-
branch, and an own PR in a review-only repository is recorded and nothing
|
|
360
|
-
else, with no repair, no worktree and no push. Follow its repair-publication reference: candidate committed locally,
|
|
361
|
-
authored review at the local SHA, gate, then fast-forward push with the
|
|
362
|
-
publication readback immediately before it.
|
|
363
|
-
- Peer PR → two isolated `axstack-review` passes on the exact head SHA, then
|
|
364
|
-
the gate, then one owner-synthesized review bound to the reviewed commit. For
|
|
365
|
-
pair A/B that is a `COMMENT` under the review skill's COMMENT branch; for
|
|
366
|
-
every pair C peer PR it is a binding verdict under "Binding review verdicts
|
|
367
|
-
(pair C)" above, whether the PR was reached by an official review request or
|
|
368
|
-
by the qualifying mention trigger. `INCOMPLETE` or an
|
|
369
|
-
unavailable required reviewer records a hold and publishes nothing.
|
|
370
|
-
|
|
371
|
-
Watch window, pair A/B only: 24 hours per own PR from first observation, ending
|
|
372
|
-
early on merge or close. The deadline is stored in `cursor.json`; a due deadline
|
|
373
|
-
wakes the driver through the precheck even when GitHub is unchanged, and the
|
|
374
|
-
driver rechecks the deadline immediately before any publication. Expiry marks
|
|
375
|
-
the PR `expired` in the record and sidecar, records a resumable handoff, and
|
|
376
|
-
stops silently. The driver skips an expired PR until the user re-arms it in the
|
|
377
|
-
automation session, and the precheck ignores it; an expired PR is never silently
|
|
378
|
-
re-adopted. Pair C/D does not use this window at all; see "Watch window" above
|
|
379
|
-
for its rolling replacement, and it stores no deadline and reaches no `expired`
|
|
380
|
-
state.
|
|
381
|
-
|
|
382
|
-
Per-PR event state: head SHA, base SHA, check rollup, and processed request and
|
|
383
|
-
comment IDs. A review receipt is reused only when head, base, and scope are
|
|
384
|
-
unchanged. A new failing check, base change, review request, or qualifying
|
|
385
|
-
comment at an unchanged head is new work. Pair C/D additionally carries draft
|
|
386
|
-
status in that state, and a draft status that has changed from true to false is
|
|
387
|
-
new work for C/D, which is how a draft becoming ready for review reaches its
|
|
388
|
-
driver.
|
|
389
|
-
|
|
390
|
-
## Watchdog tick
|
|
391
|
-
|
|
392
|
-
Before its gate dispatch the watchdog validates its own effective session
|
|
393
|
-
identity through Orca runtime inspection; unknown identity holds the dispatch
|
|
394
|
-
and is itself recorded in `watchdog.json`.
|
|
395
|
-
|
|
396
|
-
Read Orca run history for the driver, `precheck.log`, and the run record.
|
|
397
|
-
Thresholds: three consecutive `error` lines in `precheck.log`; three
|
|
398
|
-
consecutive failed driver runs; no successful driver run within two hours while
|
|
399
|
-
the precheck logged `changed` or `due`; any unrequested fresh-session fallback
|
|
400
|
-
or non-Opus effective identity recorded by the driver; any `failed` relay
|
|
401
|
-
receipt older than one tick or any `uncertain` receipt; a hold with no owner.
|
|
402
|
-
A quiet precheck history with no due work is healthy.
|
|
403
|
-
|
|
404
|
-
The two-hour stall threshold above is pair A/B's. Pair D uses a stall window
|
|
405
|
-
re-derived before enabling as `max(2h, 3 x the 95th-percentile observed C tick
|
|
406
|
-
duration over at least 10 ticks)`, recorded with its sample, because C's
|
|
407
|
-
fingerprint legitimately changes on nearly every tick and a literal two hours
|
|
408
|
-
would fire on the first slow tick. Every other threshold is identical for both
|
|
409
|
-
pairs.
|
|
410
|
-
|
|
411
|
-
Each health finding gets an occurrence id `(type, first-observed UTC
|
|
412
|
-
timestamp)`; it stays deduplicated while unresolved, and a later recurrence is
|
|
413
|
-
a new occurrence. Pass a finding to the gate under the automation-health
|
|
414
|
-
criterion. On `escalate` the watchdog itself performs that one gate-authorized
|
|
415
|
-
`hermes send` and records the receipt in `watchdog.json`; it never mutates
|
|
416
|
-
GitHub and never writes `progress.md` or `cursor.json`. Failed or uncertain
|
|
417
|
-
delivery stays visibly held in `watchdog.json` and Orca run history.
|
|
418
|
-
|
|
419
|
-
## Run record and sidecar
|
|
420
|
-
|
|
421
|
-
One run id per pair for the lifetime of that pair — `20260916-pr-automations`
|
|
422
|
-
for A/B and `20260916-defi-automations` for C/D — each in the
|
|
423
|
-
[run record](run-record.md) shape with that pair's driver as sole writer of its
|
|
424
|
-
own `progress.md`. C/D's run directory lives under the same axstack
|
|
425
|
-
`git-common-dir` as A/B's, in its own `axstack/runs/<run id>/` folder; no
|
|
426
|
-
sidecar, record, or cursor is shared between the pairs. Per PR it stores processed event IDs, exact head and base SHAs, review receipts
|
|
427
|
-
per SHA, gate decisions, `hermes send` receipts with `message_id` and state, and
|
|
428
|
-
holds. The watch deadline and `expired` fields are pair A/B only, since pair C/D
|
|
429
|
-
stores no deadline and cannot reach `expired`; draft status is pair C/D only,
|
|
430
|
-
since only C/D treats a draft transition as new work. Its
|
|
431
|
-
`Notification policy:` line reads, verbatim:
|
|
196
|
+
Every reviewer brief ends exactly:
|
|
432
197
|
|
|
433
198
|
```text
|
|
434
|
-
|
|
199
|
+
Escalate to user: yes | no — <criterion> — <reason>
|
|
435
200
|
```
|
|
436
201
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
202
|
+
PR work has exactly three criteria: a security concern, a permanent on-chain
|
|
203
|
+
state change, or an architectural change in approach. There is no
|
|
204
|
+
automation-health criterion for reviewers. The Luna gate returns exactly one
|
|
205
|
+
token, `escalate` or `proceed`; there is no gate for health findings.
|
|
206
|
+
`escalate` opens a decision token, sends its message, and exits without waiting
|
|
207
|
+
for a reply. `proceed` does not override a validated blocker. `worker_done`
|
|
208
|
+
names the PR, head, action, GitHub receipt or opened token. The driver alone
|
|
209
|
+
writes the run record.
|
|
210
|
+
|
|
211
|
+
## Decision tokens
|
|
212
|
+
|
|
213
|
+
Store `decisions/<token>.json`, where `<token>` contains at least 96 random
|
|
214
|
+
bits as lowercase hex, produced for example by `openssl rand -hex 16`.
|
|
215
|
+
Immutable bound fields are written once: `repo`, `pr`, `head`, `base`,
|
|
216
|
+
`action` (`approve-verdict`, `request-changes-verdict`, or `push`), plus exact
|
|
217
|
+
`body` and `commit` for verdicts or `candidate_sha`, `head_branch`, and
|
|
218
|
+
`expected_remote_head` for a push. Mutable fields are `state`, `created_at`,
|
|
219
|
+
`decided_at`, `decided_message_id`, `consumed_at`, `receipt`, `send`, and
|
|
220
|
+
`reason`. Never delete a token file.
|
|
221
|
+
|
|
222
|
+
Lifecycle has one named writer per transition, each by temp file + rename:
|
|
223
|
+
|
|
224
|
+
| transition | writer |
|
|
225
|
+
| --- | --- |
|
|
226
|
+
| create `open` | the agent that escalated |
|
|
227
|
+
| `open → approved` / `open → rejected` | the Hermes script only |
|
|
228
|
+
| `approved → spent` / `approved → stale` | the driver only |
|
|
229
|
+
| `rejected → closed` | the driver only |
|
|
230
|
+
| `spent` + `receipt` | the driver only |
|
|
231
|
+
|
|
232
|
+
### Opening
|
|
233
|
+
|
|
234
|
+
Before opening a `push` token, the repair agent pins its candidate with local
|
|
235
|
+
ref `refs/axstack/decisions/<token>` in the project clone, so the candidate
|
|
236
|
+
survives worktree removal. It then sends one
|
|
237
|
+
`hermes send --to telegram` message naming the PR, criterion, every reviewer's
|
|
238
|
+
reason, and the exact replies `approve <token>` and `reject <token>`. Store the
|
|
239
|
+
send receipt. The driver retries a `failed` send once next tick and reconciles
|
|
240
|
+
an `uncertain` send against Hermes output before any retry.
|
|
241
|
+
|
|
242
|
+
The Hermes gateway's fixed `axstack-decide` script accepts only those two exact
|
|
243
|
+
commands. It validates the private user/channel configuration on every call,
|
|
244
|
+
restricts tokens to `^[0-9a-f]{24,}$`, locks and re-reads an `open` token,
|
|
245
|
+
writes only its decision fields by temp file and rename, and prints one line.
|
|
246
|
+
Hermes never runs `gh`, `git`, or `orca`.
|
|
247
|
+
|
|
248
|
+
### Consuming
|
|
249
|
+
|
|
250
|
+
The driver is the only consumer. Immediately before acting it re-reads that
|
|
251
|
+
`state == approved`, then revalidates open/unmerged state, bound head/base,
|
|
252
|
+
absence of a self review for a verdict, or expected remote head plus reachable
|
|
253
|
+
candidate for a push. It writes `spent` before the GitHub call, executes
|
|
254
|
+
exactly the bound action with no second gate, then stores the receipt. A spent
|
|
255
|
+
token without a receipt is
|
|
256
|
+
reconciliation: match the exact review commit/body or destination
|
|
257
|
+
ref/candidate on GitHub; record a match, or the driver retries once under the
|
|
258
|
+
same approval after proving non-execution, or hold ambiguity. A revalidation
|
|
259
|
+
failure writes `stale`
|
|
260
|
+
with the reason and drops the PR's head from `cursor.json`; the driver never
|
|
261
|
+
mints a token. Close rejected files and skip that head. After `spent` or
|
|
262
|
+
`stale`, delete the candidate ref. Tokens do not expire; the watchdog reports
|
|
263
|
+
one open longer than 24 h.
|
|
264
|
+
|
|
265
|
+
## Watchdog
|
|
266
|
+
|
|
267
|
+
The hourly shell precheck only reads `cursor.json`, `precheck.log`,
|
|
268
|
+
`decisions/`, and `orca automations runs --id <driver>`. It performs exactly
|
|
269
|
+
these four checks and always exits non-zero, so no model session launches:
|
|
270
|
+
|
|
271
|
+
| check | trips when |
|
|
272
|
+
| --- | --- |
|
|
273
|
+
| driver stuck | a `changed` or `due` precheck is older than 1 h with no later `tick_done_at`, including a driver that never wrote `tick_started_at` (Orca run status alone is not evidence of completion) |
|
|
274
|
+
| precheck failing | the last three `precheck.log` entries are `error` |
|
|
275
|
+
| worker stuck | a dispatch marker is older than 3 h 30 min and remains uncleared |
|
|
276
|
+
| decision waiting | an `open` decision is older than 24 h |
|
|
277
|
+
|
|
278
|
+
Each trip is `(check, first_observed)`. Write one JSON line per tick to
|
|
279
|
+
`watchdog.log` with `{ts, checks, trips, sent}` and send each occurrence once
|
|
280
|
+
through `hermes send --to telegram`. Persist `sent`, `failed`, or `uncertain`;
|
|
281
|
+
retry `failed` next tick and reconcile `uncertain` before retry. Re-send only
|
|
282
|
+
after the check was observed clear and later recurs. Unreadable evidence is an
|
|
283
|
+
`unknown` occurrence. A healthy tick writes its line and sends nothing. There
|
|
284
|
+
is no gate for health findings.
|
|
285
|
+
|
|
286
|
+
## Run directory
|
|
287
|
+
|
|
288
|
+
One `.git/axstack/runs/<run id>/` directory under the Axstack git-common-dir
|
|
289
|
+
contains:
|
|
290
|
+
|
|
291
|
+
- `cursor.json` — driver only, with these exact keys: `fingerprint`,
|
|
292
|
+
`tick_started_at`, `tick_done_at`, `tick_outcome`, `prs{url: {head, base,
|
|
293
|
+
draft, checks, reviews, last_self_review}}`, `dispatch_markers[]` (`pr`,
|
|
294
|
+
`task_id`, `dispatch_id`, `worktree`, `head`, `started_at`, `reservation`,
|
|
295
|
+
`trigger`), `deferred[]`, `pending_settlement[]`,
|
|
296
|
+
`repair_caps{url: {expires_at}}`, `abandon_count{head: n}`,
|
|
297
|
+
`processed_reviews[]` (`review_id`, `pr`, `head`, `digest`),
|
|
298
|
+
`deploy_on_push{repo: [branches]}`,
|
|
299
|
+
`legacy_automation_reviews[]`, `health[]`;
|
|
300
|
+
- `pending.json`, `precheck.log` — driver precheck only;
|
|
301
|
+
- `decisions/<token>.json` — writers assigned by the lifecycle table;
|
|
302
|
+
- `watchdog.log` and `watchdog-state.json` (occurrence `first_observed` values
|
|
303
|
+
and send receipts) — watchdog only;
|
|
304
|
+
- `progress.md` — driver only, one line per tick plus holds and mention
|
|
305
|
+
readings, with no per-PR prose.
|
|
306
|
+
|
|
307
|
+
Timestamps are UTC `YYYY-MM-DDTHH:MM:SSZ`; an unparsable timestamp is an
|
|
308
|
+
`error` for the precheck and `unknown` for the watchdog, never silently
|
|
309
|
+
ignored.
|
|
310
|
+
|
|
311
|
+
Orca run history is the authoritative log. The launch worktree is a dedicated
|
|
312
|
+
Axstack worktree where nobody develops. The current `defi-automations`
|
|
313
|
+
worktree retires with the old pair. Keep this notification-policy edge in the
|
|
314
|
+
run record: `Notification policy` authorizes the token and watchdog sends;
|
|
315
|
+
delivery uses [axstack-relay](../../axstack-relay/SKILL.md).
|
|
452
316
|
|
|
453
317
|
## Safety holds
|
|
454
318
|
|
|
455
|
-
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
319
|
+
- Non-Opus or unknown driver identity records a hold and dispatches nothing.
|
|
320
|
+
- A GitHub API error makes PR state unknown; never publish or push for it.
|
|
321
|
+
- Enumerate deploy-on-push branches from both repair repositories before
|
|
322
|
+
enabling and store them in `cursor.json`; re-check on allowlist changes.
|
|
323
|
+
- A later tick observing resolution or an explicit user decision clears a
|
|
324
|
+
hold. Silence never clears one.
|
|
325
|
+
|
|
326
|
+
## Cutover
|
|
327
|
+
|
|
328
|
+
Perform this order: the new pair exists disabled; the amended skills and
|
|
329
|
+
references are installed; C and D are disabled; every old driver and worker
|
|
330
|
+
attempt is reconciled to confirmed settlement and each unfinished candidate
|
|
331
|
+
is preserved; the old worktree is removed; the old run directory is made
|
|
332
|
+
read-only; the new pair is enabled at distinct minutes; the first real driver
|
|
333
|
+
tick is recorded. A failure leaves the new pair disabled, and both pairs never
|
|
334
|
+
run together. Historical artefacts are untouched.
|
|
335
|
+
|
|
336
|
+
## Exclusions
|
|
337
|
+
|
|
338
|
+
No obligations table, supersede counter, or review-budget hold. No `COMMENT`
|
|
339
|
+
reviews. No watch deadline or `expired` state. No terminal hygiene or global
|
|
340
|
+
busy guard. No terminal nudge from Hermes. No Hermes access to `gh`, `git`, or
|
|
341
|
+
`orca`. No re-review of human-placed blocks. No per-project state. No changes
|
|
342
|
+
to retired artefacts. No gate for health findings.
|