axstack 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/bin/axstack.js +396 -0
  4. package/docs/installation.md +239 -0
  5. package/docs/workflows.md +220 -0
  6. package/package.json +40 -0
  7. package/profiles/presets/claude-only.json +194 -0
  8. package/profiles/presets/codex-only.json +194 -0
  9. package/profiles/presets/mixed.json +194 -0
  10. package/skills/axstack/SKILL.md +81 -0
  11. package/skills/axstack/references/automations.md +368 -0
  12. package/skills/axstack/references/candidate-publication.md +45 -0
  13. package/skills/axstack/references/contracts.md +102 -0
  14. package/skills/axstack/references/lifecycle.md +137 -0
  15. package/skills/axstack/references/orca-runtime.md +109 -0
  16. package/skills/axstack/references/pr-shape.md +39 -0
  17. package/skills/axstack/references/routing.md +129 -0
  18. package/skills/axstack/references/run-record.md +109 -0
  19. package/skills/axstack-align/SKILL.md +121 -0
  20. package/skills/axstack-audit/SKILL.md +137 -0
  21. package/skills/axstack-audit/references/record.md +28 -0
  22. package/skills/axstack-debug/SKILL.md +157 -0
  23. package/skills/axstack-debug/references/packet.md +80 -0
  24. package/skills/axstack-explain/SKILL.md +66 -0
  25. package/skills/axstack-explain/references/visual-qa.md +15 -0
  26. package/skills/axstack-implement/SKILL.md +164 -0
  27. package/skills/axstack-improve/SKILL.md +69 -0
  28. package/skills/axstack-relay/SKILL.md +102 -0
  29. package/skills/axstack-research/SKILL.md +57 -0
  30. package/skills/axstack-research/references/checklist.md +25 -0
  31. package/skills/axstack-review/SKILL.md +343 -0
  32. package/skills/axstack-spec/SKILL.md +67 -0
  33. package/skills/axstack-tickets/SKILL.md +86 -0
  34. package/skills/axstack-watch/SKILL.md +160 -0
  35. package/skills/axstack-watch/references/repair-publication.md +69 -0
  36. package/skills/axstack-watch/references/watch-runtime.md +60 -0
  37. package/src/capabilities.js +138 -0
  38. package/src/claude-settings.js +230 -0
  39. package/src/installer.js +980 -0
  40. package/src/instructions.js +100 -0
  41. package/src/locations.js +43 -0
  42. package/src/manifest.js +251 -0
  43. package/src/posixpath.js +108 -0
  44. package/src/roles.js +142 -0
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: axstack
3
+ description: When routing an engineering run through Axstack, use axstack to select the applicable phase and scope identity.
4
+ ---
5
+
6
+ # Axstack entry
7
+
8
+ Route the current request to one Axstack phase with the right scope identity.
9
+ The current chat remains the driver; Orca owns runtime orchestration.
10
+
11
+ For an explicit relay message or transport test, use
12
+ [axstack-relay](../axstack-relay/SKILL.md) directly. No engineering scope
13
+ identity or decision workflow is needed for that send. The same skill handles
14
+ urgent or blocking notifications under an explicit standing instruction.
15
+
16
+ ## Route the request
17
+
18
+ 1. Classify the request with [Shared routing](references/routing.md). Direct
19
+ research, explanation, improvement discovery, peer-review, adopted-watch,
20
+ and handoff routes need no spec
21
+ ceremony. Only an explicit user-requested ownership transfer can use the
22
+ capability-gated native route in
23
+ [Lifecycle and receipts](references/lifecycle.md#native-handoff-and-resume),
24
+ not an Axstack handoff phase. Preparation completion, watch expiry, and
25
+ ordinary resume update or reconcile the run record without launching it.
26
+ 2. For new engineering work, validate scope identity before invoking any phase.
27
+ Record `small`, `substantial`, or `unclear` plus a brief reason, then apply the
28
+ [proportional scope identity](references/routing.md#proportional-scope-identity).
29
+ A small clear change proceeds from its snapshotted small-change intent.
30
+ Substantial work proceeds only from an approved spec and matching ticket
31
+ map. Clarify unclear size before dispatch.
32
+ 3. Only after validation passes, invoke exactly the selected phase. A directly
33
+ invoked later phase starts there and must pass its own identity check. When
34
+ substantial work lacks an approved spec or matching ticket map, return that
35
+ exact gap, name `axstack-align` as the next route, and stop the current
36
+ invocation; do not invoke align, spec, or tickets. Apply the same stop to a
37
+ mismatched or invalidated identity. Never admit work that a deeper phase
38
+ would reject.
39
+
40
+ The route is settled when one applicable phase is named with its valid scope
41
+ identity, or the exact preparation/setup gap is reported with affected work
42
+ held.
43
+
44
+ ## Load at the action boundary
45
+
46
+ - Every independently called phase loads [Standing contracts](references/contracts.md),
47
+ which requires lifecycle and audit loading before action.
48
+ - Before an actual Axstack role dispatch, delivery, settlement, or handoff, load
49
+ [Orca runtime](references/orca-runtime.md). Ordinary reading, writing, and
50
+ local checks do not require launch discovery.
51
+ - Substantive delegated or resumable work uses the
52
+ [Local run record](references/run-record.md).
53
+ - When the current session is an Orca PR automation (driver or watchdog), load
54
+ [Automation sessions](references/automations.md) before any discovery,
55
+ review, gate, or mutation.
56
+ - When review escalation or watch notification is eligible and the brief has a
57
+ `Notification policy`, use the optional
58
+ [axstack-relay](../axstack-relay/SKILL.md); otherwise keep notification in
59
+ the current Orca conversation.
60
+
61
+ ## Lifecycle
62
+
63
+ This is a phase map, not an automatic dispatch sequence.
64
+
65
+ 1. `axstack-align` settles substantial scope and decisions.
66
+ 2. `axstack-spec` creates the single user-approved execution baseline.
67
+ 3. `axstack-tickets` maps capabilities, tasks, and dependencies, then
68
+ preparation stops with a resumable handoff.
69
+ 4. `axstack-implement` produces owned candidates with strict TDD.
70
+ 5. `axstack-review` gives peer PRs the two configured independent same-brief
71
+ reviewer roles; authored PRs get one complete eligible non-author/non-owner
72
+ review based on actual author provenance and the routing snapshot.
73
+ 6. `axstack-watch` monitors within the shared deadline and hands off remaining
74
+ work.
75
+ 7. The human merges by default, bottom-up for a stack. Review approval never
76
+ grants merge authority.
77
+
78
+ Autonomous progress, model holds, serious-risk handling, mutation authority,
79
+ and the one-host ownership contract live in
80
+ [Standing contracts](references/contracts.md). Load only the selected phase
81
+ and the references its action requires.
@@ -0,0 +1,368 @@
1
+ # Automation sessions
2
+
3
+ Read this when the current session is an Orca automation running a PR driver or
4
+ a watchdog.
5
+
6
+ ## Pair identity
7
+
8
+ There are two independent automation pairs. Before acting, resolve which pair
9
+ this session belongs to from its own run id and the verbatim allowlist in its
10
+ own prompt; never assume.
11
+
12
+ - **Pair A/B** — driver Automation A (`*/30`) and watchdog Automation B, run id
13
+ `20260916-pr-automations`, allowlist `axatbhardwaj/axstack`.
14
+ - **Pair C/D** — driver Automation C (hourly) and watchdog Automation D, run id
15
+ `20260916-defi-automations`, allowlist
16
+ `defi-com/monorepo, defi-com/mobile, defi-com/azure-next-hybrid`.
17
+
18
+ The two pairs share no state: each has its own run id, run directory,
19
+ `progress.md` and sidecars, and no sidecar is shared between them. A clause
20
+ below that names a pair applies only to that pair; every other clause applies to
21
+ both. Where this reference says "the driver" it means the driver of the current
22
+ pair. It restates the operational contract of the approved
23
+ `docs/specs/orca-automations.md`; that spec is authoritative, and nothing here
24
+ widens it. Orca owns scheduling, sessions, retries, and run history. Axstack
25
+ owns policy, the run record, and evidence.
26
+
27
+ ## Identity and scope
28
+
29
+ - **Self** is `gh api user --jq .login`, resolved at the start of every run and
30
+ never hardcoded.
31
+ - **Own PR:** an open PR authored by self. Authority equals the user at the
32
+ keyboard: repair, test, commit, and fast-forward push to the PR branch
33
+ (`git push`, no lease or force). `gh stack` sync or restack is out of scope.
34
+ - **Peer PR:** an open PR where self is officially review-requested, or where a
35
+ PR comment @-mentions self asking for a response. Unsolicited reviews never
36
+ happen. Peer code is read-only. A mention counts as a peer request only when
37
+ the driver reads the comment and it explicitly asks self to review or
38
+ respond. An incidental mention is discovery data and never review authority.
39
+ - **Discovery** covers every repository the account can see:
40
+ `gh search prs --state open --limit 100` with `--author @me`,
41
+ `--review-requested @me`, and `--mentions @me`. A result count equal to the
42
+ limit is a detectable truncation and is logged as `error`. Results are
43
+ deduplicated canonically by PR URL across the three searches with own-PR
44
+ precedence.
45
+ - **Mutation allowlist:** stated verbatim in the automation prompt, per
46
+ automation rather than as one global list. One allowlist gates both own-PR
47
+ repair and peer review for its own automation; there is no separate
48
+ review-only list. Outside the
49
+ allowlist the automation discovers and records only. The precheck writes the
50
+ full discovery list to `pending.json`; no review, watch, gate, or other model
51
+ work is launched for an external PR. External changes do not enter the wake
52
+ fingerprint, so external churn never wakes the session. External PR contents
53
+ never produce an escalation. This is a deliberate coverage reduction, not an
54
+ implied clean review; discovery errors themselves remain automation-health
55
+ findings.
56
+ - **Prohibited everywhere:** force-push, rebase, merge, close, `APPROVE`,
57
+ `REQUEST_CHANGES`. A need for any of these becomes a recorded hold.
58
+
59
+ ## Roles per mode
60
+
61
+ The automation session is the driver and the owner for every PR it handles;
62
+ the driver is the automation session itself, with no `axstack-monitor` or
63
+ `axstack-owner` role row materialized, and the standalone-owner branches
64
+ of `axstack-watch` and `axstack-review` do not fire. `axstack-monitor` stays
65
+ an optional read-only observer that never sends.
66
+
67
+ - Peer PR → peer mode of [axstack-review](../../axstack-review/SKILL.md):
68
+ `axstack-reviewer-primary` and `axstack-reviewer-secondary`, isolated.
69
+ - Own-PR repair → authored mode: the repair author is the automation session
70
+ (provider `claude`), so the one cross-family reviewer comes from actual
71
+ provenance (`axstack-reviewer-primary`, Sol, in `mixed`). A repair delegated
72
+ to `axstack-author` (Sol) takes `axstack-reviewer-secondary`.
73
+ - "Every mode-required reviewer" means both reviewers in peer mode and the one
74
+ selected reviewer in authored mode.
75
+ - Gate → `axstack-auditor`.
76
+ - Watchdog → `axstack-watchdog`, which never mutates GitHub and performs
77
+ exactly one kind of send, a gate-authorized automation-health escalation
78
+ recorded in `watchdog.json`.
79
+
80
+ ## Reviewer brief and criteria
81
+
82
+ Every reviewer brief ends with a required field, exactly:
83
+
84
+ ```text
85
+ Escalate to user: yes | no — <criterion> — <reason>
86
+ ```
87
+
88
+ Criteria, exactly four: a security concern; a permanent on-chain state change;
89
+ an architectural change in approach; and automation health (a
90
+ model-substitution, session, precheck, discovery, or relay-delivery hold). The
91
+ automation health criterion is usable only by the watchdog and the safety-hold
92
+ path, never by a reviewer.
93
+
94
+ ## Stack-aware repair sequencing (pair C/D)
95
+
96
+ These three sections govern pair C/D only. Pair A/B's behaviour is unchanged by
97
+ revision 4 except for the named cadence correction, so A does not apply stack
98
+ sequencing, bot-triggered repair, the caps, or the deployment push hold.
99
+
100
+ Own-PR repair covers every own PR in the allowlisted repositories; stacking
101
+ changes the order of repair, never the scope. Within one stack the driver
102
+ repairs only the lowest open failing PR of that stack. Every open descendant of
103
+ a repaired PR records exactly one `pending restack` hold naming the repaired
104
+ parent and its new head SHA, and receives no independent repair of the same
105
+ finding while that hold stands. A descendant carrying a different finding from
106
+ the repaired parent's is repaired on its own merits, subject to the budgets
107
+ below; the hold suppresses duplicate application of the same finding, not all
108
+ work on the descendant.
109
+
110
+ The hold names the user as owner. It is cleared by the user's own restack, or by
111
+ a later tick observing the descendant no longer failing; that is the single
112
+ clearing rule. It is exempt from the watchdog's hold with no owner threshold,
113
+ because its owner is the user by construction. The per-tick budget counts one
114
+ unit per stack, not one per PR.
115
+
116
+ The reason is duplication, not politeness: the same finding recurs across a
117
+ stack, so independent per-PR repair would apply the identical fix at several
118
+ levels and the user's next cascade rebase would then conflict on the duplicate.
119
+ A parent fast-forward also does not change a descendant's PR diff, so a
120
+ descendant's CI and reviewers never see the parent fix; the hold states that
121
+ honestly instead of implying the descendant was repaired.
122
+
123
+ `gh stack` sync, restack, rebase, merge, link and submit remain out of scope for
124
+ every automation, and force-push and rebase stay prohibited everywhere. A
125
+ descendant is held, never rewritten.
126
+
127
+ ## Bot review feedback (pair C/D)
128
+
129
+ A review authored by a bot account may be actionable and may trigger a repair,
130
+ bounded as follows.
131
+
132
+ Dedup is by processed review ID and by a digest of the review body. A repair
133
+ fires only on a review whose review ID was never processed and whose body
134
+ digest is not already recorded against that PR at that head SHA. Review-ID dedup alone is
135
+ insufficient: a bot that re-posts the identical finding under a new review ID
136
+ would otherwise re-trigger a repair on every tick.
137
+
138
+ Caps: at most one repair per PR per 24 hours, counted regardless of trigger; and
139
+ a per-tick push budget across all allowlisted repositories combined, configured
140
+ per pair and six for pair C/D. Reaching either cap records a hold naming the cap
141
+ and the value reached, rather than silently dropping the work. A budget hold
142
+ names the budget as its owner and is exempt from the hold with no owner
143
+ threshold. When a per-PR cap has expired the precheck wakes the driver even
144
+ if the forge is unchanged, so capped work is never stranded; the precheck
145
+ section below carries that trigger in its due-work list.
146
+
147
+ A bot review never satisfies the peer-PR trigger, which still requires self to
148
+ be officially review-requested or a comment that explicitly asks self to review
149
+ or respond.
150
+
151
+ ## Watch window
152
+
153
+ Pair A/B keeps its 24 hours per own PR from first observation, ending early on
154
+ merge or close, with the deadline in `cursor.json`, the `expired` marking, and
155
+ the user re-arming an expired PR in the automation session.
156
+
157
+ Pair C/D uses a rolling window instead: a PR is in scope while it is open and
158
+ eligible, and leaves scope on merge or close. There is no expiry and no
159
+ re-arming, C/D's `cursor.json` stores no deadlines, and `expired` is not a state
160
+ a C/D PR can reach.
161
+
162
+ The difference is deliberate, not drift. A serves one low-volume repository
163
+ where expiry is cheap, while C would otherwise start twenty or more simultaneous
164
+ clocks on first observation and go dark a day later. Because that window
165
+ removes expiry as a cost brake, the per-PR and per-tick budgets and the watchdog
166
+ are the only brakes left on C, and D's thresholds are retuned for a fingerprint
167
+ that legitimately changes on nearly every tick.
168
+
169
+ ## PR eligibility for repair (pair C/D)
170
+
171
+ A draft PR is discovered and recorded but never repaired; it becomes eligible
172
+ when it is marked ready for review, which the ordinary event state observes as
173
+ new work. A PR that already has a human reviewer requested is eligible for
174
+ repair and is not excluded, deliberately: most own PRs in these repositories
175
+ carry a requested human reviewer, and excluding them would empty the coverage.
176
+ `defi-com/mobile` has no workflows and therefore no check signal, so a repair
177
+ there is triggered only by actionable review feedback; if CI is later added the
178
+ ordinary check-rollup trigger applies with no contract change.
179
+
180
+ ## Deployment safety (pair C/D)
181
+
182
+ A repair never pushes to a PR whose head branch is in that repository's
183
+ deploy-on-push set, and an attempt to do so is a recorded hold. The rule is
184
+ branch-name-agnostic: the set is enumerated per repository from that
185
+ repository's workflow files, recorded, and re-verified before enabling and on
186
+ any later allowlist change. It is never hardcoded to one branch name, because a
187
+ repository may deploy from more than one branch and may add another at any time.
188
+
189
+ ## Escalation gate
190
+
191
+ After every mode-required reviewer settles, the driver spawns `axstack-auditor`
192
+ with the verdicts and the candidate revision, instructing it to act as the
193
+ escalation gate. It returns exactly one literal token, `escalate` or `proceed`.
194
+
195
+ - The gate decides only whether the user is notified. Reviewer "yes" is input,
196
+ not a veto.
197
+ - `escalate` → records the hold, then one `hermes send` through
198
+ [axstack-relay](../../axstack-relay/SKILL.md) naming the PR, the criterion,
199
+ every reviewer's reason, where the user acts (Orca conversation, worktree, or
200
+ PR), and the hold; it publishes nothing.
201
+ - `proceed` → no notification; a push or `COMMENT` publication then
202
+ additionally requires no unresolved validated blocking finding, because
203
+ `proceed` never overrides a validated blocking finding. A reviewer security
204
+ "yes" that the gate does not escalate is recorded as rejected-with-evidence
205
+ or returned to the author before any mutation.
206
+ - Only `proceed` plus no unresolved validated blocking finding permits a push
207
+ or publication; a push before the gate settles is forbidden.
208
+ - Precedence: credible serious risk found by a reviewer still produces the
209
+ standing internal prompt and dependent-action hold immediately, and the gate
210
+ governs only external notification. That hold is the serious-risk rule of
211
+ [contracts](contracts.md#serious-risk). The internal prompt lands in the run
212
+ record and the automation's Orca conversation; no `hermes send` occurs
213
+ without `escalate`.
214
+ - The health gate takes a watchdog finding and its evidence, not reviewer
215
+ verdicts or a candidate; the same two tokens apply.
216
+ - An unavailable gate or required reviewer records a hold, pauses mutation for
217
+ that PR, and is treated as a watchdog health finding. An unavailable gate
218
+ cannot be escalated through itself: the hold stays, the gap is visible in
219
+ Orca run history and the sidecar, and no substitute or unauthorized send
220
+ occurs.
221
+
222
+ ## Precheck (bounded shell, no model)
223
+
224
+ Resolve self; run the three searches with `--json url,number,repository,updatedAt`;
225
+ write the full discovery list to `pending.json`. For each allowlisted,
226
+ non-expired own PR add head SHA, base SHA, and the check rollup of that head via
227
+ `gh pr view --json headRefOid,baseRefOid,statusCheckRollup`; check state is
228
+ data, and only authentication, command, and network errors are `error`. For pair
229
+ C/D only, that call also requests `isDraft` and the precheck adds draft status
230
+ to the hashed fingerprint, so a draft becoming ready wakes the driver on its
231
+ own; pair A/B's queried fields and fingerprint are unchanged. Hash
232
+ only allowlisted PRs. Read `cursor.json` for the last processed fingerprint and
233
+ for due control work: a watch deadline at or before now (pair A/B only, since
234
+ pair C/D stores no deadlines), a pending failed-relay retry, or a per-PR repair
235
+ cap that has expired (pair C/D only, since pair A/B has no caps). Exit 0 when the hash differs or control work is due;
236
+ otherwise exit non-zero. Exit non-zero without running when the previous driver
237
+ run is still active, or on `error`. Append one line
238
+ `<ts> <changed|due|unchanged|error|busy>` to `precheck.log`.
239
+
240
+ Terminal hygiene runs before the searches and covers driver terminals only.
241
+ Ownership is the driver automation's own recorded `terminalPtyId` from its Orca
242
+ run history, never a terminal title: Orca rewrites a Claude terminal's title to
243
+ the agent's current task summary, so a driver's title drifts and an unrelated
244
+ session can acquire one that reads like a driver. The precheck closes the
245
+ previous ticks' idle driver terminals with `--tab` — without it the pane closes
246
+ but the session stays listed and is never reclaimed, which also makes an
247
+ over-match destructive — and a driver terminal that is still working makes the
248
+ tick `busy`. It never closes a watchdog terminal or any terminal outside this
249
+ automation; an unreadable ownership source is `error`, never a silent empty
250
+ sweep. No two of the four automations may share a dispatch minute: A, B, C and D each
251
+ take a distinct minute, so a driver and its watchdog never collide and neither
252
+ pair can disturb the other's terminal hygiene.
253
+
254
+ The observed fingerprint is written to `pending.json`. After the processed
255
+ tick the driver promotes exactly that value to `cursor.json`, never a
256
+ recomputed one, so an event landing during a run is processed on the following
257
+ tick.
258
+
259
+ ## Driver tick
260
+
261
+ Before any repair or publication the driver validates its effective session
262
+ identity through Orca runtime inspection and records it; a self-written label
263
+ is not evidence. Expected model: Opus. A mismatch or unknown identity holds
264
+ repair and publication for that run and is a health finding.
265
+
266
+ For each changed PR:
267
+
268
+ - Own PR → [axstack-watch](../../axstack-watch/SKILL.md) on the exact head
269
+ SHA in a per-PR child worktree; the driver worktree never checks out a PR
270
+ branch. Follow its repair-publication reference: candidate committed locally,
271
+ authored review at the local SHA, gate, then fast-forward push with the
272
+ publication readback immediately before it.
273
+ - Peer PR → two isolated `axstack-review` passes on the exact head SHA, then
274
+ the gate, then one owner-synthesized `COMMENT` review under the review skill's
275
+ COMMENT branch. `INCOMPLETE` or an unavailable required reviewer records a
276
+ hold and publishes nothing.
277
+
278
+ Watch window, pair A/B only: 24 hours per own PR from first observation, ending
279
+ early on merge or close. The deadline is stored in `cursor.json`; a due deadline
280
+ wakes the driver through the precheck even when GitHub is unchanged, and the
281
+ driver rechecks the deadline immediately before any publication. Expiry marks
282
+ the PR `expired` in the record and sidecar, records a resumable handoff, and
283
+ stops silently. The driver skips an expired PR until the user re-arms it in the
284
+ automation session, and the precheck ignores it; an expired PR is never silently
285
+ re-adopted. Pair C/D does not use this window at all; see "Watch window" above
286
+ for its rolling replacement, and it stores no deadline and reaches no `expired`
287
+ state.
288
+
289
+ Per-PR event state: head SHA, base SHA, check rollup, and processed request and
290
+ comment IDs. A review receipt is reused only when head, base, and scope are
291
+ unchanged. A new failing check, base change, review request, or qualifying
292
+ comment at an unchanged head is new work. Pair C/D additionally carries draft
293
+ status in that state, and a draft status that has changed from true to false is
294
+ new work for C/D, which is how a draft becoming ready for review reaches its
295
+ driver.
296
+
297
+ ## Watchdog tick
298
+
299
+ Before its gate dispatch the watchdog validates its own effective session
300
+ identity through Orca runtime inspection; unknown identity holds the dispatch
301
+ and is itself recorded in `watchdog.json`.
302
+
303
+ Read Orca run history for the driver, `precheck.log`, and the run record.
304
+ Thresholds: three consecutive `error` lines in `precheck.log`; three
305
+ consecutive failed driver runs; no successful driver run within two hours while
306
+ the precheck logged `changed` or `due`; any unrequested fresh-session fallback
307
+ or non-Opus effective identity recorded by the driver; any `failed` relay
308
+ receipt older than one tick or any `uncertain` receipt; a hold with no owner.
309
+ A quiet precheck history with no due work is healthy.
310
+
311
+ The two-hour stall threshold above is pair A/B's. Pair D uses a stall window
312
+ re-derived before enabling as `max(2h, 3 x the 95th-percentile observed C tick
313
+ duration over at least 10 ticks)`, recorded with its sample, because C's
314
+ fingerprint legitimately changes on nearly every tick and a literal two hours
315
+ would fire on the first slow tick. Every other threshold is identical for both
316
+ pairs.
317
+
318
+ Each health finding gets an occurrence id `(type, first-observed UTC
319
+ timestamp)`; it stays deduplicated while unresolved, and a later recurrence is
320
+ a new occurrence. Pass a finding to the gate under the automation-health
321
+ criterion. On `escalate` the watchdog itself performs that one gate-authorized
322
+ `hermes send` and records the receipt in `watchdog.json`; it never mutates
323
+ GitHub and never writes `progress.md` or `cursor.json`. Failed or uncertain
324
+ delivery stays visibly held in `watchdog.json` and Orca run history.
325
+
326
+ ## Run record and sidecar
327
+
328
+ One run id per pair for the lifetime of that pair — `20260916-pr-automations`
329
+ for A/B and `20260916-defi-automations` for C/D — each in the
330
+ [run record](run-record.md) shape with that pair's driver as sole writer of its
331
+ own `progress.md`. C/D's run directory lives under the same axstack
332
+ `git-common-dir` as A/B's, in its own `axstack/runs/<run id>/` folder; no
333
+ sidecar, record, or cursor is shared between the pairs. Per PR it stores processed event IDs, exact head and base SHAs, review receipts
334
+ per SHA, gate decisions, `hermes send` receipts with `message_id` and state, and
335
+ holds. The watch deadline and `expired` fields are pair A/B only, since pair C/D
336
+ stores no deadline and cannot reach `expired`; draft status is pair C/D only,
337
+ since only C/D treats a draft transition as new work. Its
338
+ `Notification policy:` line reads, verbatim:
339
+
340
+ ```text
341
+ hermes send, target telegram (home), host VPS, gate-authorized escalations only
342
+ ```
343
+
344
+ Machine-readable sidecars in the same directory: `pending.json` (observed
345
+ fingerprint plus full discovery list, written by the precheck), `cursor.json`
346
+ (last processed fingerprint promoted verbatim from `pending.json`, expired PR
347
+ list and per-PR watch deadlines for pair A/B only, pending failed-relay
348
+ retries; written by the driver after each processed tick), `precheck.log` (precheck only), and
349
+ `watchdog.json` (watchdog only). Orca run history remains the authoritative
350
+ log; the record is derived progress, never authority.
351
+
352
+ Dedup: a processed event ID is never processed twice; a review receipt is
353
+ reused only for an unchanged head, base, and scope. PR notifications dedup on
354
+ (PR, criterion, head SHA); health notifications dedup on the occurrence id. A
355
+ `failed` relay receipt may be retried once, on the next tick, as due control
356
+ work; an `uncertain` one is never auto-resent.
357
+
358
+ ## Safety holds
359
+
360
+ - The driver records its effective identity on every tick. An unrequested
361
+ fresh-session fallback, or a recorded identity different from the expected
362
+ one, pauses mutation for that run, is recorded, and goes to the watchdog
363
+ path. A user-run `--fresh-session` reconciles from the run record and is not
364
+ a hold.
365
+ - GitHub API errors leave the PR state unknown; nothing is pushed or published
366
+ on unknown state.
367
+ - A hold is cleared only by a later run observing the condition resolved, or by
368
+ the user in the Orca conversation. Silence never clears a hold.
@@ -0,0 +1,45 @@
1
+ # Candidate publication
2
+
3
+ This is the author-to-review boundary for an owned candidate. The author stops
4
+ after returning its revision-bound implementation receipt and does not push.
5
+ Within recorded PR-scoped publication authority, the owner reconciles that
6
+ receipt against the actual local candidate SHA and base. The owner does not edit
7
+ the author's candidate; required code changes return to the author.
8
+
9
+ Publish the existing commits through `gh stack`. Prefer a fast-forward push.
10
+ Before a history rewrite, confirm the expected-old remote SHA and use lease
11
+ protection; a mismatch holds publication. If the push outcome is ambiguous,
12
+ inspect remote state before retrying.
13
+
14
+ Before reviewer dispatch, read the remote ref back and confirm that it resolves
15
+ to the candidate SHA; also pin the current base. Record:
16
+
17
+ ```text
18
+ Candidate: <sha>
19
+ Base: <sha>
20
+ Remote ref: <branch>
21
+ Expected-old remote SHA: <sha | absent>
22
+ Confirmed remote SHA: <sha>
23
+ PR: <url>
24
+ CI: <run ID or URL and triggered/pending/completed status>
25
+ ```
26
+
27
+ Local green is not CI green: immediately after publication CI is pending until
28
+ its required checks complete. Review may run in parallel with CI only after the
29
+ remote confirmation. Reviewers inspect a detached immutable checkout of the
30
+ confirmed candidate SHA and pinned base, never only the movable branch name.
31
+ Any author repair creates a new revision and repeats this boundary.
32
+
33
+ ## Automation repair exception
34
+
35
+ For an automation repair under
36
+ [Automation sessions](automations.md), the candidate is a local immutable
37
+ commit SHA in the per-PR child worktree, not a published remote ref. The
38
+ reviewer confirms that exact local SHA with `git rev-parse` in the worktree
39
+ instead of remote equality, and inspects a detached checkout of it with the
40
+ pinned base. The remote ref is expected to still be the pre-repair head; record
41
+ it as the expected-old remote SHA rather than requiring it to equal the
42
+ candidate. Remote equality is re-checked at the publication readback of the
43
+ watch skill's repair-publication reference immediately before the fast-forward
44
+ push. Ordinary workflows keep the remote confirmation above; the
45
+ exception never applies outside an automation session.
@@ -0,0 +1,102 @@
1
+ # Standing contracts (standalone phases load this, then follow its pointers)
2
+
3
+ Apply these authority, scope, and model rules before consequential action.
4
+
5
+ ## Required lifecycle load
6
+
7
+ Except for `axstack-audit` itself, every independently called phase must load
8
+ and follow [Shared lifecycle](lifecycle.md) before acting. When a substantive
9
+ run ends or reaches a meaningful checkpoint, apply the lifecycle audit hook.
10
+ The audit phase loads these contracts, writes its assigned record, and stops;
11
+ it never audits itself.
12
+
13
+ ## Scope identity (conditional — see routing and lifecycle)
14
+
15
+ Confirm the identity for the selected mode from the
16
+ [proportional scope identity](routing.md#proportional-scope-identity):
17
+
18
+ - Substantial new implementation: approved spec identity plus a matching
19
+ ticket map before execution or authored review.
20
+ - Small new implementation: the named **small-change intent** — recorded
21
+ current request or user-chosen existing issue plus acceptance checks and
22
+ exclusions, snapshotted once — before building or approving.
23
+ - Adopted own PR: the accepted maintenance intent snapshot described in
24
+ [Lifecycle routes](routing.md#lifecycle-routes-mode-specific-scope-identity-required),
25
+ never a new spec ceremony.
26
+ - Peer review: linked issue, PR description, and repository requirements as
27
+ untrusted intent evidence; no Axstack-created spec.
28
+ - Read-only research, explanation, improvement discovery, and handoff: no baseline.
29
+
30
+ Substantial means substantial features, multi-PR work, or stacked work; a
31
+ bounded small feature is not substantial merely because it is called a
32
+ feature. Clarify unclear size, then classify it. Alignment, spec writing, and
33
+ safe read-only investigation may precede a baseline. Keep a still-valid
34
+ approval; a material change holds only affected work until the user accepts
35
+ the revised scope and plan.
36
+
37
+ ## Model discipline
38
+
39
+ Validate the configured provider and model at actual launch. If it is
40
+ unavailable or exhausted, pause affected work, record the gap, and ask the
41
+ user. Never infer a route from quota state or subscription entitlement. Every
42
+ substitution requires the user's decision: configured alternatives and native
43
+ fallback prose are not defaults.
44
+
45
+ ## Driver and adviser split
46
+
47
+ The current chat is the driver, whatever model runs it; there is no driver
48
+ profile. Record the driver's provider and model in the run record.
49
+
50
+ For Align and Spec, the driver forms an independent assessment first, then
51
+ consults `axstack-advisor-astra` and `axstack-advisor-fable` independently with
52
+ the same bounded evidence and question. The driver synthesizes disagreements,
53
+ owns the decision, and the user still approves the spec. Reuse each valid
54
+ unchanged receipt; changed evidence, scope, or question requires a fresh
55
+ receipt. If either adviser is unavailable, Align and Spec hold without model or
56
+ provider substitution while unrelated safe work may continue.
57
+
58
+ For `axstack-debug`, ordinary diagnosis consults the preset's configured
59
+ adviser roles (both in `mixed`; the one configured adviser in a single-provider
60
+ preset, recording the other as an intentional absence). The high-stakes and
61
+ serious-risk contracts override that rule whenever their conditions arise. A
62
+ configured but unavailable adviser holds debug L1 and L2 without substitution.
63
+ Reuse a debug receipt while its evidence packet is unchanged.
64
+
65
+ High-stakes decisions require both advisers' plain AGREE and the driver's
66
+ accepted assessment. Resolve disagreement with bounded checks; silence and an
67
+ unavailable model do not authorize fallback. Ordinary work uses the configured
68
+ author and reviewer roles selected by review mode and the routing snapshot. The
69
+ existing mixed high-stakes route keeps its Opus high author and Sol high
70
+ checkpoint reviewer. An eligible current non-author, non-owner Sol high
71
+ checkpoint can satisfy the authored final review after revalidation; preserve
72
+ its effort and do not add a redundant reviewer. No single-provider high-stakes
73
+ mapping is defined: pause for an explicit user decision rather than borrowing
74
+ another preset or inventing a route. There is no silent fallback.
75
+
76
+ ## Serious risk
77
+
78
+ Raise credible serious security, downtime, data-loss, or major-design risk
79
+ immediately through a prompt. Hold approval, merge-ready declarations, and
80
+ dependent dangerous actions while safe independent work continues. Present
81
+ the evidence, likely impact, options, and needed user decision. Disagreement
82
+ or silence is not permission. This remains a prompt contract, not a runtime
83
+ gate.
84
+
85
+ ## Authority
86
+
87
+ - The driver owns run scope, cross-PR coordination, integration, and every
88
+ Linear mutation. The checker reports discrepancies only.
89
+ - One Orca execution host owns a run. There is no fixed active-PR count;
90
+ fanout is dependency- and capacity-driven within configured host resource and
91
+ spending limits. The driver reduces fanout when the run record shows rework,
92
+ review backlog, or resource pressure, queues conflicting or dependent work,
93
+ and uses `gh stack` for dependent PRs. Routine shape, split, fanout, and
94
+ exception choices are autonomous driver decisions within the approved scope;
95
+ size alone never requires user approval.
96
+ - Exactly one writer per candidate acts at a time, with one persistent owner
97
+ accountable for each PR. Each PR carries one theme and a measured size under
98
+ [PR shape](pr-shape.md). Unknown capacity metrics are reported as unknown,
99
+ never as a telemetry prerequisite or blocker. Parent changes invalidate
100
+ affected child evidence, which must be refreshed against the new parent.
101
+ - The human merges by default, bottom-up for a stack. Review approval and
102
+ reviewer votes never grant mutation or merge authority.