axstack 0.20.8 → 0.20.10
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/docs/workflows.md +1 -1
- package/package.json +1 -1
- package/profiles/presets/claude-only.json +9 -9
- package/profiles/presets/codex-only.json +23 -23
- package/profiles/presets/mixed.json +14 -14
- package/skills/axstack/references/evidence-archive.md +38 -6
- package/skills/axstack/references/routing.md +4 -4
- package/skills/axstack/scripts/archive-evidence.js +213 -2
- package/skills/axstack-audit/SKILL.md +1 -1
- package/skills/axstack-cleanup/SKILL.md +9 -3
- package/skills/axstack-explain/SKILL.md +15 -3
- package/skills/axstack-review/SKILL.md +4 -4
- package/src/roles.js +4 -4
package/docs/workflows.md
CHANGED
|
@@ -51,7 +51,7 @@ role.
|
|
|
51
51
|
| Preset | Author | Ordered peer reviewers | Astra / Fable advisers | Auditor |
|
|
52
52
|
| --- | --- | --- | --- | --- |
|
|
53
53
|
| `mixed` | Sol medium | Sol medium; Opus medium | Astra high / Fable high | Luna max |
|
|
54
|
-
| `codex-only` | Sol medium | Sol medium;
|
|
54
|
+
| `codex-only` | Sol medium | Sol medium; Luna xhigh | Astra high / unavailable | Luna max |
|
|
55
55
|
| `claude-only` | Opus medium | Opus medium; Sonnet xhigh | unavailable / Fable high | Sonnet xhigh |
|
|
56
56
|
|
|
57
57
|
The installed `<skills-dir>/axstack/roles.json` adds the selected preset name:
|
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"id": "axstack-owner",
|
|
24
24
|
"name": "Axstack PR owner",
|
|
25
25
|
"provider": "claude",
|
|
26
|
-
"model": "claude-opus-5",
|
|
26
|
+
"model": "claude-opus-5-5",
|
|
27
27
|
"modeId": "bypassPermissions",
|
|
28
28
|
"thinkingOptionId": "high",
|
|
29
29
|
"notes": "Persistent PR owner: one owner per PR, accountable for candidate, fixes, verification evidence, and monitoring. May delegate coding but never edits a worker-owned candidate concurrently. Launches eligible independent reviewers."
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"id": "axstack-author",
|
|
33
33
|
"name": "Axstack author",
|
|
34
34
|
"provider": "claude",
|
|
35
|
-
"model": "claude-opus-5",
|
|
35
|
+
"model": "claude-opus-5-5",
|
|
36
36
|
"modeId": "bypassPermissions",
|
|
37
37
|
"thinkingOptionId": "medium",
|
|
38
38
|
"notes": "Ordinary implementation and repairs. Uses strict red-green-refactor and remains the exclusive writer for a candidate. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"id": "axstack-reviewer-primary",
|
|
42
42
|
"name": "Axstack reviewer (primary)",
|
|
43
43
|
"provider": "claude",
|
|
44
|
-
"model": "claude-opus-5",
|
|
44
|
+
"model": "claude-opus-5-5",
|
|
45
45
|
"modeId": "bypassPermissions",
|
|
46
46
|
"thinkingOptionId": "medium",
|
|
47
47
|
"notes": "Primary reviewer in the ordered claude-only peer pair: Opus medium followed by Sonnet xhigh. Never author or owner; review exact SHA and base across all six angles and acceptance. Peer first pass stays isolated."
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"id": "axstack-research-requirements",
|
|
69
69
|
"name": "Axstack research requirements",
|
|
70
70
|
"provider": "claude",
|
|
71
|
-
"model": "claude-opus-5",
|
|
71
|
+
"model": "claude-opus-5-5",
|
|
72
72
|
"modeId": "bypassPermissions",
|
|
73
73
|
"thinkingOptionId": "medium",
|
|
74
74
|
"notes": "Research requirements analyst: scopes bounded questions and acceptance for a research task. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"id": "axstack-research-code",
|
|
78
78
|
"name": "Axstack research code",
|
|
79
79
|
"provider": "claude",
|
|
80
|
-
"model": "claude-opus-5",
|
|
80
|
+
"model": "claude-opus-5-5",
|
|
81
81
|
"modeId": "bypassPermissions",
|
|
82
82
|
"thinkingOptionId": "medium",
|
|
83
83
|
"notes": "Research code investigator: verifies behavior against inspected code and executable evidence. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -167,10 +167,10 @@
|
|
|
167
167
|
"id": "axstack-debug-investigator-1",
|
|
168
168
|
"name": "Axstack debug investigator 1",
|
|
169
169
|
"provider": "claude",
|
|
170
|
-
"model": "claude-opus-5",
|
|
170
|
+
"model": "claude-opus-5-5",
|
|
171
171
|
"modeId": "bypassPermissions",
|
|
172
172
|
"thinkingOptionId": "medium",
|
|
173
|
-
"notes": "Debug investigator seat 1. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats claude-opus-5 at medium effort because it has fewer model families."
|
|
173
|
+
"notes": "Debug investigator seat 1. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats claude-opus-5-5 at medium effort because it has fewer model families."
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"id": "axstack-debug-investigator-2",
|
|
@@ -185,10 +185,10 @@
|
|
|
185
185
|
"id": "axstack-debug-investigator-3",
|
|
186
186
|
"name": "Axstack debug investigator 3",
|
|
187
187
|
"provider": "claude",
|
|
188
|
-
"model": "claude-opus-5",
|
|
188
|
+
"model": "claude-opus-5-5",
|
|
189
189
|
"modeId": "bypassPermissions",
|
|
190
190
|
"thinkingOptionId": "high",
|
|
191
|
-
"notes": "Debug investigator seat 3. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats claude-opus-5 at high effort because it has fewer model families."
|
|
191
|
+
"notes": "Debug investigator seat 3. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats claude-opus-5-5 at high effort because it has fewer model families."
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
"id": "axstack-debug-investigator-4",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"id": "axstack-owner",
|
|
24
24
|
"name": "Axstack PR owner",
|
|
25
25
|
"provider": "codex",
|
|
26
|
-
"model": "gpt-
|
|
26
|
+
"model": "gpt-6-sol",
|
|
27
27
|
"modeId": "full-access",
|
|
28
28
|
"thinkingOptionId": "high",
|
|
29
29
|
"notes": "Persistent PR owner: one owner per PR, accountable for candidate, fixes, verification evidence, and monitoring. May delegate coding but never edits a worker-owned candidate concurrently. Launches eligible independent reviewers."
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"id": "axstack-author",
|
|
33
33
|
"name": "Axstack author",
|
|
34
34
|
"provider": "codex",
|
|
35
|
-
"model": "gpt-
|
|
35
|
+
"model": "gpt-6-sol",
|
|
36
36
|
"modeId": "full-access",
|
|
37
37
|
"thinkingOptionId": "medium",
|
|
38
38
|
"notes": "Ordinary implementation and repairs. Uses strict red-green-refactor and remains the exclusive writer for a candidate. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -41,25 +41,25 @@
|
|
|
41
41
|
"id": "axstack-reviewer-primary",
|
|
42
42
|
"name": "Axstack reviewer (primary)",
|
|
43
43
|
"provider": "codex",
|
|
44
|
-
"model": "gpt-
|
|
44
|
+
"model": "gpt-6-sol",
|
|
45
45
|
"modeId": "full-access",
|
|
46
46
|
"thinkingOptionId": "medium",
|
|
47
|
-
"notes": "Primary reviewer in the ordered codex-only peer pair: Sol medium followed by
|
|
47
|
+
"notes": "Primary reviewer in the ordered codex-only peer pair: Sol medium followed by Luna xhigh. Never author or owner; review exact SHA and base across all six angles and acceptance. Peer first pass stays isolated."
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"id": "axstack-reviewer-secondary",
|
|
51
51
|
"name": "Axstack reviewer (secondary)",
|
|
52
52
|
"provider": "codex",
|
|
53
|
-
"model": "gpt-
|
|
53
|
+
"model": "gpt-6-luna",
|
|
54
54
|
"modeId": "full-access",
|
|
55
55
|
"thinkingOptionId": "xhigh",
|
|
56
|
-
"notes": "Secondary reviewer in the ordered codex-only peer pair: Sol medium followed by
|
|
56
|
+
"notes": "Secondary reviewer in the ordered codex-only peer pair: Sol medium followed by Luna xhigh. Eligible authored reviewer for a Sol-authored candidate. Never author or owner; review exact SHA and base across all six angles and acceptance. Peer first pass stays isolated."
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"id": "axstack-checker",
|
|
60
60
|
"name": "Axstack tracker checker",
|
|
61
61
|
"provider": "codex",
|
|
62
|
-
"model": "gpt-
|
|
62
|
+
"model": "gpt-6-luna",
|
|
63
63
|
"modeId": "full-access",
|
|
64
64
|
"thinkingOptionId": "low",
|
|
65
65
|
"notes": "Report-only discrepancy checker for the selected external tracker (Linear or GitHub Issues). Never mutates the tracker; the driver independently verifies evidence before applying updates. A null model means explicit user selection is required before dispatch and must never launch a provider default."
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"id": "axstack-research-code",
|
|
78
78
|
"name": "Axstack research code",
|
|
79
79
|
"provider": "codex",
|
|
80
|
-
"model": "gpt-
|
|
80
|
+
"model": "gpt-6-sol",
|
|
81
81
|
"modeId": "full-access",
|
|
82
82
|
"thinkingOptionId": "medium",
|
|
83
83
|
"notes": "Research code investigator: verifies behavior against inspected code and executable evidence. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"id": "axstack-research-web",
|
|
87
87
|
"name": "Axstack research web",
|
|
88
88
|
"provider": "codex",
|
|
89
|
-
"model": "gpt-
|
|
89
|
+
"model": "gpt-6-sol",
|
|
90
90
|
"modeId": "full-access",
|
|
91
91
|
"thinkingOptionId": "low",
|
|
92
92
|
"notes": "Research web reader: gathers primary-source facts efficiently. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"id": "axstack-explainer",
|
|
114
114
|
"name": "Axstack explainer",
|
|
115
115
|
"provider": "codex",
|
|
116
|
-
"model": "gpt-
|
|
116
|
+
"model": "gpt-6-sol",
|
|
117
117
|
"modeId": "full-access",
|
|
118
118
|
"thinkingOptionId": "high",
|
|
119
119
|
"notes": "Complex visual explanation author: traces systems, changes, and implementation gaps in requested artifacts and verifies rendered behavior where applicable. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"id": "axstack-explainer-review",
|
|
123
123
|
"name": "Axstack explainer reviewer",
|
|
124
124
|
"provider": "codex",
|
|
125
|
-
"model": "gpt-
|
|
125
|
+
"model": "gpt-6-luna",
|
|
126
126
|
"modeId": "full-access",
|
|
127
127
|
"thinkingOptionId": "max",
|
|
128
128
|
"notes": "Independent visual explanation reviewer: checks the exact artifact for source fidelity and rendered behavior where warranted. Any artifact change invalidates its review. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"id": "axstack-explore-codebase",
|
|
132
132
|
"name": "Axstack codebase explorer",
|
|
133
133
|
"provider": "codex",
|
|
134
|
-
"model": "gpt-
|
|
134
|
+
"model": "gpt-6-sol",
|
|
135
135
|
"modeId": "full-access",
|
|
136
136
|
"thinkingOptionId": "xhigh",
|
|
137
137
|
"notes": "Codebase mapper: explores repository structure and interfaces for research and handoff context. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
"id": "axstack-explore-execution",
|
|
141
141
|
"name": "Axstack execution explorer",
|
|
142
142
|
"provider": "codex",
|
|
143
|
-
"model": "gpt-
|
|
143
|
+
"model": "gpt-6-sol",
|
|
144
144
|
"modeId": "full-access",
|
|
145
145
|
"thinkingOptionId": "low",
|
|
146
146
|
"notes": "Execution explorer: runs bounded checks of runtime behavior where authorized. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"id": "axstack-monitor",
|
|
150
150
|
"name": "Axstack monitor",
|
|
151
151
|
"provider": "codex",
|
|
152
|
-
"model": "gpt-
|
|
152
|
+
"model": "gpt-6-sol",
|
|
153
153
|
"modeId": "full-access",
|
|
154
154
|
"thinkingOptionId": "low",
|
|
155
155
|
"notes": "Optional independent read-only observer for a standalone PR watch. Reads GitHub, feedback, and checks, persists event IDs, and wakes the owner only for a new actionable event. Never sends, authors, reviews, replies, or acts as either reusable PR manager. Healthy snapshots stay quiet."
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"id": "axstack-auditor",
|
|
159
159
|
"name": "Axstack auditor",
|
|
160
160
|
"provider": "codex",
|
|
161
|
-
"model": "gpt-
|
|
161
|
+
"model": "gpt-6-luna",
|
|
162
162
|
"modeId": "full-access",
|
|
163
163
|
"thinkingOptionId": "max",
|
|
164
164
|
"notes": "Read-only end-of-run and checkpoint auditor. Collects scope and outcome evidence with counts and denominators and reports PASS, FAIL, or UNKNOWN without inventing numbers. Never edits, merges, activates, or audits itself."
|
|
@@ -167,37 +167,37 @@
|
|
|
167
167
|
"id": "axstack-debug-investigator-1",
|
|
168
168
|
"name": "Axstack debug investigator 1",
|
|
169
169
|
"provider": "codex",
|
|
170
|
-
"model": "gpt-
|
|
170
|
+
"model": "gpt-6-sol",
|
|
171
171
|
"modeId": "full-access",
|
|
172
172
|
"thinkingOptionId": "medium",
|
|
173
|
-
"notes": "Debug investigator seat 1. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-
|
|
173
|
+
"notes": "Debug investigator seat 1. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-6-sol at medium effort because it has fewer model families."
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"id": "axstack-debug-investigator-2",
|
|
177
177
|
"name": "Axstack debug investigator 2",
|
|
178
178
|
"provider": "codex",
|
|
179
|
-
"model": "gpt-
|
|
179
|
+
"model": "gpt-6-sol",
|
|
180
180
|
"modeId": "full-access",
|
|
181
181
|
"thinkingOptionId": "low",
|
|
182
|
-
"notes": "Debug investigator seat 2. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-
|
|
182
|
+
"notes": "Debug investigator seat 2. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-6-sol at low effort because it has fewer model families."
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
"id": "axstack-debug-investigator-3",
|
|
186
186
|
"name": "Axstack debug investigator 3",
|
|
187
187
|
"provider": "codex",
|
|
188
|
-
"model": "gpt-
|
|
188
|
+
"model": "gpt-6-sol",
|
|
189
189
|
"modeId": "full-access",
|
|
190
190
|
"thinkingOptionId": "high",
|
|
191
|
-
"notes": "Debug investigator seat 3. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-
|
|
191
|
+
"notes": "Debug investigator seat 3. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-6-sol at high effort because it has fewer model families."
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
"id": "axstack-debug-investigator-4",
|
|
195
195
|
"name": "Axstack debug investigator 4",
|
|
196
196
|
"provider": "codex",
|
|
197
|
-
"model": "gpt-
|
|
197
|
+
"model": "gpt-6-sol",
|
|
198
198
|
"modeId": "full-access",
|
|
199
199
|
"thinkingOptionId": "xhigh",
|
|
200
|
-
"notes": "Debug investigator seat 4. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-
|
|
200
|
+
"notes": "Debug investigator seat 4. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity. This preset repeats gpt-6-sol at xhigh effort because it has fewer model families."
|
|
201
201
|
},
|
|
202
202
|
{
|
|
203
203
|
"id": "axstack-arena-judge-astra",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"id": "axstack-owner",
|
|
24
24
|
"name": "Axstack PR owner",
|
|
25
25
|
"provider": "claude",
|
|
26
|
-
"model": "claude-opus-5",
|
|
26
|
+
"model": "claude-opus-5-5",
|
|
27
27
|
"modeId": "bypassPermissions",
|
|
28
28
|
"thinkingOptionId": "medium",
|
|
29
29
|
"notes": "Persistent PR owner: one owner per PR, accountable for candidate, fixes, verification evidence, and monitoring. May delegate coding but never edits a worker-owned candidate concurrently. Launches eligible independent reviewers."
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"id": "axstack-author",
|
|
33
33
|
"name": "Axstack author",
|
|
34
34
|
"provider": "codex",
|
|
35
|
-
"model": "gpt-
|
|
35
|
+
"model": "gpt-6-sol",
|
|
36
36
|
"modeId": "full-access",
|
|
37
37
|
"thinkingOptionId": "medium",
|
|
38
38
|
"notes": "Ordinary implementation and repairs. Uses strict red-green-refactor and remains the exclusive writer for a candidate. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"id": "axstack-reviewer-primary",
|
|
42
42
|
"name": "Axstack reviewer (primary)",
|
|
43
43
|
"provider": "codex",
|
|
44
|
-
"model": "gpt-
|
|
44
|
+
"model": "gpt-6-sol",
|
|
45
45
|
"modeId": "full-access",
|
|
46
46
|
"thinkingOptionId": "medium",
|
|
47
47
|
"notes": "Primary reviewer in the ordered mixed peer pair: Sol medium followed by Opus medium. Eligible authored reviewer for an Opus-authored candidate. Never author or owner; review exact SHA and base across all six angles and acceptance. Peer first pass stays isolated."
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"id": "axstack-reviewer-secondary",
|
|
51
51
|
"name": "Axstack reviewer (secondary)",
|
|
52
52
|
"provider": "claude",
|
|
53
|
-
"model": "claude-opus-5",
|
|
53
|
+
"model": "claude-opus-5-5",
|
|
54
54
|
"modeId": "bypassPermissions",
|
|
55
55
|
"thinkingOptionId": "medium",
|
|
56
56
|
"notes": "Secondary reviewer in the ordered mixed peer pair: Sol medium followed by Opus medium. Eligible authored reviewer for a Sol-authored candidate. Never author or owner; review exact SHA and base across all six angles and acceptance. Peer first pass stays isolated."
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"id": "axstack-research-requirements",
|
|
69
69
|
"name": "Axstack research requirements",
|
|
70
70
|
"provider": "claude",
|
|
71
|
-
"model": "claude-opus-5",
|
|
71
|
+
"model": "claude-opus-5-5",
|
|
72
72
|
"modeId": "bypassPermissions",
|
|
73
73
|
"thinkingOptionId": "medium",
|
|
74
74
|
"notes": "Research requirements analyst: scopes bounded questions and acceptance for a research task. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"id": "axstack-research-code",
|
|
78
78
|
"name": "Axstack research code",
|
|
79
79
|
"provider": "codex",
|
|
80
|
-
"model": "gpt-
|
|
80
|
+
"model": "gpt-6-sol",
|
|
81
81
|
"modeId": "full-access",
|
|
82
82
|
"thinkingOptionId": "medium",
|
|
83
83
|
"notes": "Research code investigator: verifies behavior against inspected code and executable evidence. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"id": "axstack-research-web",
|
|
87
87
|
"name": "Axstack research web",
|
|
88
88
|
"provider": "claude",
|
|
89
|
-
"model": "claude-opus-5",
|
|
89
|
+
"model": "claude-opus-5-5",
|
|
90
90
|
"modeId": "bypassPermissions",
|
|
91
91
|
"thinkingOptionId": "low",
|
|
92
92
|
"notes": "Research web reader: gathers primary-source facts efficiently. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"id": "axstack-explainer-review",
|
|
123
123
|
"name": "Axstack explainer reviewer",
|
|
124
124
|
"provider": "codex",
|
|
125
|
-
"model": "gpt-
|
|
125
|
+
"model": "gpt-6-luna",
|
|
126
126
|
"modeId": "full-access",
|
|
127
127
|
"thinkingOptionId": "max",
|
|
128
128
|
"notes": "Independent visual explanation reviewer: checks the exact artifact for source fidelity and rendered behavior where warranted. Any artifact change invalidates its review. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
"id": "axstack-explore-execution",
|
|
141
141
|
"name": "Axstack execution explorer",
|
|
142
142
|
"provider": "codex",
|
|
143
|
-
"model": "gpt-
|
|
143
|
+
"model": "gpt-6-sol",
|
|
144
144
|
"modeId": "full-access",
|
|
145
145
|
"thinkingOptionId": "low",
|
|
146
146
|
"notes": "Execution explorer: runs bounded checks of runtime behavior where authorized. Validate configured availability at launch; hold affected work without fallback."
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"id": "axstack-monitor",
|
|
150
150
|
"name": "Axstack monitor",
|
|
151
151
|
"provider": "claude",
|
|
152
|
-
"model": "claude-opus-5",
|
|
152
|
+
"model": "claude-opus-5-5",
|
|
153
153
|
"modeId": "bypassPermissions",
|
|
154
154
|
"thinkingOptionId": "medium",
|
|
155
155
|
"notes": "Optional independent read-only observer for a standalone PR watch. Reads GitHub, feedback, and checks, persists event IDs, and wakes the owner only for a new actionable event. Never sends, authors, reviews, replies, or acts as either reusable PR manager. Healthy snapshots stay quiet."
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"id": "axstack-auditor",
|
|
159
159
|
"name": "Axstack auditor",
|
|
160
160
|
"provider": "codex",
|
|
161
|
-
"model": "gpt-
|
|
161
|
+
"model": "gpt-6-luna",
|
|
162
162
|
"modeId": "full-access",
|
|
163
163
|
"thinkingOptionId": "max",
|
|
164
164
|
"notes": "Read-only end-of-run and checkpoint auditor. Collects scope and outcome evidence with counts and denominators and reports PASS, FAIL, or UNKNOWN without inventing numbers. Never edits, merges, activates, or audits itself."
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
"id": "axstack-debug-investigator-1",
|
|
168
168
|
"name": "Axstack debug investigator 1",
|
|
169
169
|
"provider": "claude",
|
|
170
|
-
"model": "claude-opus-5",
|
|
170
|
+
"model": "claude-opus-5-5",
|
|
171
171
|
"modeId": "bypassPermissions",
|
|
172
172
|
"thinkingOptionId": "medium",
|
|
173
173
|
"notes": "Debug investigator seat 1. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity."
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
"id": "axstack-debug-investigator-2",
|
|
177
177
|
"name": "Axstack debug investigator 2",
|
|
178
178
|
"provider": "codex",
|
|
179
|
-
"model": "gpt-
|
|
179
|
+
"model": "gpt-6-sol",
|
|
180
180
|
"modeId": "full-access",
|
|
181
181
|
"thinkingOptionId": "medium",
|
|
182
182
|
"notes": "Debug investigator seat 2. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity."
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
"id": "axstack-debug-investigator-4",
|
|
195
195
|
"name": "Axstack debug investigator 4",
|
|
196
196
|
"provider": "codex",
|
|
197
|
-
"model": "gpt-
|
|
197
|
+
"model": "gpt-6-sol",
|
|
198
198
|
"modeId": "full-access",
|
|
199
199
|
"thinkingOptionId": "low",
|
|
200
200
|
"notes": "Debug investigator seat 4. Dispatched only by axstack-debug at L1 with the shared evidence packet and one distinct brief; never reads another investigator's output. Works in its own disposable worktree at the pinned revision plus the recorded dirty patch; may instrument there for probes; never commits, pushes, publishes, or creates children. Returns one receipt per brief. Independence comes from brief isolation, not model diversity."
|
|
@@ -59,12 +59,44 @@ state and require exit proof for that exact terminal incarnation. A task
|
|
|
59
59
|
terminal, manual chat, unexpected terminal, failed close, or uncertain exit
|
|
60
60
|
remains protected.
|
|
61
61
|
|
|
62
|
-
After receipt and continuity readback,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
After receipt and continuity readback, invoke the same installed helper with
|
|
63
|
+
the same identity and complete `--file` set, plus the recorded manifest hash:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
bun scripts/archive-evidence.js \
|
|
67
|
+
--source-root <absolute-worktree-or-evidence-root> \
|
|
68
|
+
--archive-root <absolute-private-archive-root> \
|
|
69
|
+
--repo <owner/repository> --pr <number> --head <40-character-sha> \
|
|
70
|
+
--dispatch <exact-dispatch-id> \
|
|
71
|
+
--file <classified-relative-file> [--file <classified-relative-file> ...] \
|
|
72
|
+
--operation retire --manifest-hash <recorded-64-character-sha256>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Use the corresponding `--run` and `--task` identity for a non-PR archive. The
|
|
76
|
+
retirement operation independently verifies the immutable private archive, its
|
|
77
|
+
exact identity and complete file set, the caller-recorded manifest hash, the
|
|
78
|
+
exact Git top-level and HEAD, and every remaining source file. It refuses
|
|
79
|
+
tracked, staged, or unclassified dirt; changed bytes; unsafe or overlapping
|
|
80
|
+
roots; symlinks; hard links; and non-regular files. It applies exact unlinks only
|
|
81
|
+
to matching listed files and never removes directories.
|
|
82
|
+
|
|
83
|
+
Record the retirement receipt's `removed`, `alreadyAbsent`, and `pending` file
|
|
84
|
+
sets. A repeat invocation reconciles already absent files without changing the
|
|
85
|
+
manifest. A partial or failed invocation preserves the archive; resolve its
|
|
86
|
+
exact hold and retry the same operation until `pending` is empty. Never replace
|
|
87
|
+
this operation with a shell loop, broad deletion, force, or a waiver.
|
|
88
|
+
|
|
89
|
+
Re-read Git and native state after successful retirement. Any remaining or
|
|
90
|
+
uncertain dirt holds worktree removal. Settlement, liveness/no-writer proof,
|
|
91
|
+
useful-work and publication checks, evidence classification, and removal
|
|
92
|
+
authority remain driver decisions; archive or retirement success proves none of
|
|
93
|
+
them.
|
|
94
|
+
|
|
95
|
+
Before native worktree removal, verify the effective **Archive Script**
|
|
96
|
+
provenance. An unknown hook or a required hook whose provenance is not trusted
|
|
97
|
+
holds removal. Record its native outcome as exactly `unconfigured`, `passed`,
|
|
98
|
+
`failed`, or `unknown`; only `unconfigured` or a trusted `passed` outcome may
|
|
99
|
+
advance, while `failed` and `unknown` preserve the resource.
|
|
68
100
|
|
|
69
101
|
Only then use the version-matched Orca guide's native worktree cleanup operation
|
|
70
102
|
with the exact workspace identity. Never use shell recursive deletion and never
|
|
@@ -34,10 +34,10 @@ Role IDs:
|
|
|
34
34
|
|
|
35
35
|
| Preset | Author | Reviewer (model/effort) |
|
|
36
36
|
| --- | --- | --- |
|
|
37
|
-
| `mixed` | Codex / Sol (`codex/gpt-
|
|
38
|
-
| `mixed` | Claude / Opus (`claude/claude-opus-5`) | `axstack-reviewer-primary` (`codex/gpt-
|
|
39
|
-
| `codex-only` | Codex / Sol (`codex/gpt-
|
|
40
|
-
| `claude-only` | Claude / Opus (`claude/claude-opus-5`) | `axstack-reviewer-secondary` (`claude/claude-sonnet-5` xhigh) |
|
|
37
|
+
| `mixed` | Codex / Sol (`codex/gpt-6-sol`) | `axstack-reviewer-secondary` (`claude/claude-opus-5-5` medium) |
|
|
38
|
+
| `mixed` | Claude / Opus (`claude/claude-opus-5-5`) | `axstack-reviewer-primary` (`codex/gpt-6-sol` medium) |
|
|
39
|
+
| `codex-only` | Codex / Sol (`codex/gpt-6-sol`) | `axstack-reviewer-secondary` (`codex/gpt-6-luna` xhigh) |
|
|
40
|
+
| `claude-only` | Claude / Opus (`claude/claude-opus-5-5`) | `axstack-reviewer-secondary` (`claude/claude-sonnet-5` xhigh) |
|
|
41
41
|
- `axstack-advisor-astra` and `axstack-advisor-fable` advise independently
|
|
42
42
|
and author align arena candidates; `axstack-arena-judge-astra` and
|
|
43
43
|
`axstack-arena-judge-fable` judge them. `axstack-auditor` audits;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
readFile,
|
|
8
8
|
rename,
|
|
9
9
|
rm,
|
|
10
|
+
unlink,
|
|
10
11
|
writeFile,
|
|
11
12
|
} from 'node:fs/promises';
|
|
12
13
|
|
|
@@ -68,7 +69,7 @@ function parseArgs(argv) {
|
|
|
68
69
|
if (!flag?.startsWith('--') || value === undefined) fail(`invalid argument near ${flag ?? '(end)'}`);
|
|
69
70
|
const key = flag.slice(2);
|
|
70
71
|
if (key === 'file') values.files.push(value);
|
|
71
|
-
else if (['source-root', 'archive-root', 'repo', 'pr', 'run', 'task', 'head', 'dispatch'].includes(key)) {
|
|
72
|
+
else if (['source-root', 'archive-root', 'repo', 'pr', 'run', 'task', 'head', 'dispatch', 'operation', 'manifest-hash'].includes(key)) {
|
|
72
73
|
if (values[key] !== undefined) fail(`duplicate --${key}`);
|
|
73
74
|
values[key] = value;
|
|
74
75
|
} else fail(`unknown argument: ${flag}`);
|
|
@@ -76,6 +77,7 @@ function parseArgs(argv) {
|
|
|
76
77
|
for (const key of ['source-root', 'archive-root', 'repo', 'head', 'dispatch']) {
|
|
77
78
|
if (!values[key]) fail(`missing --${key}`);
|
|
78
79
|
}
|
|
80
|
+
values.operation ??= 'archive';
|
|
79
81
|
if (values.files.length === 0) fail('at least one --file is required');
|
|
80
82
|
if (!isAbsolute(values['source-root']) || !isAbsolute(values['archive-root'])) {
|
|
81
83
|
fail('source and archive roots must be absolute');
|
|
@@ -95,6 +97,13 @@ function parseArgs(argv) {
|
|
|
95
97
|
}
|
|
96
98
|
if (!/^[0-9a-f]{40}$/.test(values.head)) fail('head must be an exact 40-character lowercase SHA');
|
|
97
99
|
if (!/^[A-Za-z0-9_-]+$/.test(values.dispatch)) fail('dispatch contains unsafe characters');
|
|
100
|
+
if (!['archive', 'retire'].includes(values.operation)) fail('operation must be archive or retire');
|
|
101
|
+
if (values.operation === 'retire' && !/^[0-9a-f]{64}$/.test(values['manifest-hash'] ?? '')) {
|
|
102
|
+
fail('retirement requires an exact lowercase --manifest-hash');
|
|
103
|
+
}
|
|
104
|
+
if (values.operation === 'archive' && values['manifest-hash'] !== undefined) {
|
|
105
|
+
fail('--manifest-hash applies only to retirement');
|
|
106
|
+
}
|
|
98
107
|
values.files = [...new Set(values.files)].sort();
|
|
99
108
|
for (const file of values.files) {
|
|
100
109
|
const parts = file.split('/');
|
|
@@ -212,6 +221,203 @@ async function verifyArchive(archiveDir, identity, collected) {
|
|
|
212
221
|
};
|
|
213
222
|
}
|
|
214
223
|
|
|
224
|
+
function sameJson(left, right) {
|
|
225
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async function verifyRetirementArchive(archiveRoot, archiveDir, identity, files, manifestHash) {
|
|
229
|
+
const archiveRel = relative(archiveRoot, archiveDir);
|
|
230
|
+
let current = archiveRoot;
|
|
231
|
+
for (const part of ['', ...archiveRel.split('/')]) {
|
|
232
|
+
if (part) current = join(current, part);
|
|
233
|
+
const st = await assertRealPath(current, 'directory');
|
|
234
|
+
if ((st.mode & 0o077) !== 0) fail(`archive permissions are not private: ${current}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const manifestPath = join(archiveDir, 'manifest.json');
|
|
238
|
+
const manifestStat = await assertRealPath(manifestPath, 'file');
|
|
239
|
+
if (manifestStat.nlink !== 1) fail(`refusing hard-linked archive file: ${manifestPath}`);
|
|
240
|
+
if ((manifestStat.mode & 0o077) !== 0) fail(`archive manifest permissions are not private: ${manifestPath}`);
|
|
241
|
+
const manifestBytes = await readFile(manifestPath);
|
|
242
|
+
if (sha256(manifestBytes) !== manifestHash) fail('recorded manifest hash mismatch');
|
|
243
|
+
|
|
244
|
+
let manifest;
|
|
245
|
+
try {
|
|
246
|
+
manifest = JSON.parse(manifestBytes.toString());
|
|
247
|
+
} catch {
|
|
248
|
+
fail(`invalid archive manifest: ${manifestPath}`);
|
|
249
|
+
}
|
|
250
|
+
if (manifest.version !== 1 || !sameJson(manifest.identity, identity)) {
|
|
251
|
+
fail(`archive manifest identity mismatch: ${manifestPath}`);
|
|
252
|
+
}
|
|
253
|
+
const manifestFiles = Object.keys(manifest.files ?? {}).sort();
|
|
254
|
+
if (!sameJson(manifestFiles, files)) fail(`archive manifest file set mismatch: ${manifestPath}`);
|
|
255
|
+
if (!manifestBytes.equals(Buffer.from(JSON.stringify(manifest, null, 2) + '\n'))) {
|
|
256
|
+
fail(`archive manifest bytes are not canonical: ${manifestPath}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const filesRoot = join(archiveDir, 'files');
|
|
260
|
+
const filesRootStat = await assertRealPath(filesRoot, 'directory');
|
|
261
|
+
if ((filesRootStat.mode & 0o077) !== 0) fail(`archive permissions are not private: ${filesRoot}`);
|
|
262
|
+
for (const rel of files) {
|
|
263
|
+
const expected = manifest.files[rel];
|
|
264
|
+
if (!expected || !/^[0-9a-f]{64}$/.test(expected.sha256) || !Number.isSafeInteger(expected.size) || expected.size < 0) {
|
|
265
|
+
fail(`invalid archive manifest entry: ${rel}`);
|
|
266
|
+
}
|
|
267
|
+
await assertNoSymlinkComponents(filesRoot, rel);
|
|
268
|
+
const archived = join(filesRoot, rel);
|
|
269
|
+
const st = await assertRealPath(archived, 'file');
|
|
270
|
+
if (st.nlink !== 1) fail(`refusing hard-linked archive file: ${archived}`);
|
|
271
|
+
if ((st.mode & 0o077) !== 0) fail(`archived evidence permissions are not private: ${archived}`);
|
|
272
|
+
const bytes = await readFile(archived);
|
|
273
|
+
if (bytes.length !== expected.size || sha256(bytes) !== expected.sha256) {
|
|
274
|
+
fail(`archived evidence hash mismatch: ${rel}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const actualFiles = await listArchiveFiles(archiveDir);
|
|
278
|
+
const expectedFiles = ['manifest.json', ...files.map((rel) => `files/${rel}`)].sort();
|
|
279
|
+
if (!sameJson(actualFiles, expectedFiles)) fail(`archive contains unexpected or missing files: ${archiveDir}`);
|
|
280
|
+
return { archiveDir, manifestPath, manifestHash, files: files.length, manifest };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function gitOutput(sourceRoot, args) {
|
|
284
|
+
const result = Bun.spawnSync(['git', '-C', sourceRoot, ...args], { stdout: 'pipe', stderr: 'pipe' });
|
|
285
|
+
if (result.exitCode !== 0) {
|
|
286
|
+
fail(`git ${args.join(' ')} failed: ${result.stderr.toString().trim() || `exit ${result.exitCode}`}`);
|
|
287
|
+
}
|
|
288
|
+
return result.stdout.toString();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function inspectSource(sourceRoot, rel) {
|
|
292
|
+
let current = sourceRoot;
|
|
293
|
+
const parts = rel.split('/');
|
|
294
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
295
|
+
current = join(current, parts[index]);
|
|
296
|
+
const st = await lstat(current, { bigint: true }).catch((err) => {
|
|
297
|
+
if (err?.code === 'ENOENT') return null;
|
|
298
|
+
throw err;
|
|
299
|
+
});
|
|
300
|
+
if (!st) return null;
|
|
301
|
+
if (st.isSymbolicLink()) fail(`refusing symlink: ${current}`);
|
|
302
|
+
if (index < parts.length - 1 && !st.isDirectory()) fail(`not a directory: ${current}`);
|
|
303
|
+
if (index === parts.length - 1) {
|
|
304
|
+
if (!st.isFile()) fail(`not a regular file: ${current}`);
|
|
305
|
+
if (st.nlink !== 1n) fail(`refusing hard-linked source file: ${current}`);
|
|
306
|
+
const bytes = await readFile(current);
|
|
307
|
+
const after = await lstat(current, { bigint: true }).catch((err) => {
|
|
308
|
+
if (err?.code === 'ENOENT') fail(`source changed during verification: ${rel}`);
|
|
309
|
+
throw err;
|
|
310
|
+
});
|
|
311
|
+
for (const key of ['dev', 'ino', 'size', 'mtimeNs', 'nlink']) {
|
|
312
|
+
if (st[key] !== after[key]) fail(`source changed during verification: ${rel}`);
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
bytes,
|
|
316
|
+
sha256: sha256(bytes),
|
|
317
|
+
size: bytes.length,
|
|
318
|
+
fingerprint: Object.fromEntries(
|
|
319
|
+
['dev', 'ino', 'size', 'mtimeNs', 'ctimeNs', 'nlink'].map((key) => [key, after[key]]),
|
|
320
|
+
),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function sameSource(left, right) {
|
|
327
|
+
return left.size === right.size &&
|
|
328
|
+
left.sha256 === right.sha256 &&
|
|
329
|
+
Object.keys(left.fingerprint).every((key) => left.fingerprint[key] === right.fingerprint[key]);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async function verifyRetirementSource(sourceRoot, head, files, manifest) {
|
|
333
|
+
await assertSafeAncestors(sourceRoot);
|
|
334
|
+
await assertRealPath(sourceRoot, 'directory');
|
|
335
|
+
const topLevel = resolve(gitOutput(sourceRoot, ['rev-parse', '--show-toplevel']).trim());
|
|
336
|
+
if (topLevel !== sourceRoot) fail(`source root is not the exact Git top-level: ${sourceRoot}`);
|
|
337
|
+
const actualHead = gitOutput(sourceRoot, ['rev-parse', 'HEAD']).trim();
|
|
338
|
+
if (actualHead !== head) fail(`Git HEAD mismatch: expected ${head}, found ${actualHead}`);
|
|
339
|
+
|
|
340
|
+
const states = {};
|
|
341
|
+
for (const rel of files) {
|
|
342
|
+
const state = await inspectSource(sourceRoot, rel);
|
|
343
|
+
if (state && (state.size !== manifest.files[rel].size || state.sha256 !== manifest.files[rel].sha256)) {
|
|
344
|
+
fail(`source evidence hash mismatch: ${rel}`);
|
|
345
|
+
}
|
|
346
|
+
states[rel] = state;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const expectedUntracked = new Set(files.filter((rel) => states[rel]));
|
|
350
|
+
const statusEntries = gitOutput(sourceRoot, [
|
|
351
|
+
'status', '--porcelain=v1', '-z', '--untracked-files=all', '--ignored=no',
|
|
352
|
+
]).split('\0').filter(Boolean);
|
|
353
|
+
for (const entry of statusEntries) {
|
|
354
|
+
const code = entry.slice(0, 2);
|
|
355
|
+
const rel = entry.slice(3);
|
|
356
|
+
if (code !== '??' || !expectedUntracked.delete(rel)) {
|
|
357
|
+
fail(`tracked, staged, or unclassified Git dirt: ${rel || '(unknown)'}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (expectedUntracked.size > 0) {
|
|
361
|
+
fail(`source evidence is not classified as untracked: ${[...expectedUntracked].sort()[0]}`);
|
|
362
|
+
}
|
|
363
|
+
return states;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async function retireEvidence(args, sourceRoot, archiveRoot, archiveDir, identity) {
|
|
367
|
+
const archive = await verifyRetirementArchive(
|
|
368
|
+
archiveRoot, archiveDir, identity, args.files, args['manifest-hash'],
|
|
369
|
+
);
|
|
370
|
+
const states = await verifyRetirementSource(sourceRoot, args.head, args.files, archive.manifest);
|
|
371
|
+
const removed = [];
|
|
372
|
+
const alreadyAbsent = args.files.filter((rel) => !states[rel]);
|
|
373
|
+
|
|
374
|
+
for (const rel of args.files) {
|
|
375
|
+
if (!states[rel]) continue;
|
|
376
|
+
const current = await inspectSource(sourceRoot, rel);
|
|
377
|
+
if (!current || !sameSource(current, states[rel])) fail(`source changed before retirement: ${rel}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
for (let index = 0; index < args.files.length; index += 1) {
|
|
381
|
+
const rel = args.files[index];
|
|
382
|
+
if (!states[rel]) continue;
|
|
383
|
+
const current = await inspectSource(sourceRoot, rel);
|
|
384
|
+
if (!current || !sameSource(current, states[rel])) {
|
|
385
|
+
fail(`source changed before retirement: ${rel}`);
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
await unlink(join(sourceRoot, rel));
|
|
389
|
+
} catch (err) {
|
|
390
|
+
const pending = args.files.slice(index).filter((file) => states[file]);
|
|
391
|
+
console.log(JSON.stringify({
|
|
392
|
+
status: 'partial',
|
|
393
|
+
archiveDir: archive.archiveDir,
|
|
394
|
+
manifestPath: archive.manifestPath,
|
|
395
|
+
manifestHash: archive.manifestHash,
|
|
396
|
+
files: archive.files,
|
|
397
|
+
removed,
|
|
398
|
+
alreadyAbsent,
|
|
399
|
+
pending,
|
|
400
|
+
}));
|
|
401
|
+
fail(`retirement stopped at ${rel}: ${err.message}`);
|
|
402
|
+
}
|
|
403
|
+
if (await lstat(join(sourceRoot, rel)).catch((err) => err?.code === 'ENOENT' ? null : Promise.reject(err))) {
|
|
404
|
+
fail(`source still exists after unlink: ${rel}`);
|
|
405
|
+
}
|
|
406
|
+
removed.push(rel);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
console.log(JSON.stringify({
|
|
410
|
+
status: 'retired',
|
|
411
|
+
archiveDir: archive.archiveDir,
|
|
412
|
+
manifestPath: archive.manifestPath,
|
|
413
|
+
manifestHash: archive.manifestHash,
|
|
414
|
+
files: archive.files,
|
|
415
|
+
removed,
|
|
416
|
+
alreadyAbsent,
|
|
417
|
+
pending: [],
|
|
418
|
+
}));
|
|
419
|
+
}
|
|
420
|
+
|
|
215
421
|
async function listArchiveFiles(root, prefix = '') {
|
|
216
422
|
const files = [];
|
|
217
423
|
const entries = await readdir(join(root, prefix), { withFileTypes: true });
|
|
@@ -238,7 +444,6 @@ async function main() {
|
|
|
238
444
|
archiveToSource === '' || (!archiveToSource.startsWith('..') && !isAbsolute(archiveToSource))
|
|
239
445
|
) fail('source and archive roots must not contain each other');
|
|
240
446
|
|
|
241
|
-
const collected = await collectSource(sourceRoot, args.files);
|
|
242
447
|
const identity = args.pr
|
|
243
448
|
? { repo: args.repo, pr: Number(args.pr), head: args.head, dispatch: args.dispatch }
|
|
244
449
|
: { repo: args.repo, run: args.run, task: args.task, head: args.head, dispatch: args.dispatch };
|
|
@@ -249,6 +454,12 @@ async function main() {
|
|
|
249
454
|
const archiveDir = join(archiveRoot, repoSlug, ...identityParts, args.head, args.dispatch);
|
|
250
455
|
|
|
251
456
|
await assertSafeAncestors(archiveRoot);
|
|
457
|
+
if (args.operation === 'retire') {
|
|
458
|
+
await retireEvidence(args, sourceRoot, archiveRoot, archiveDir, identity);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const collected = await collectSource(sourceRoot, args.files);
|
|
252
463
|
let current = archiveRoot;
|
|
253
464
|
const generated = [repoSlug, ...identityParts, args.head];
|
|
254
465
|
await ensurePrivateDir(current);
|
|
@@ -25,7 +25,7 @@ immediately before an actual auditor profile or session dispatch. Ordinary
|
|
|
25
25
|
audit reading and record writing do not load it, and the auditor never
|
|
26
26
|
dispatches.
|
|
27
27
|
|
|
28
|
-
Core owns the `axstack-auditor` profile (codex/gpt-
|
|
28
|
+
Core owns the `axstack-auditor` profile (codex/gpt-6-luna max) and its
|
|
29
29
|
invocation. This skill governs what that auditor reads, measures, and proposes.
|
|
30
30
|
The user-chosen improvement mode is a tested, independently reviewed PR that a
|
|
31
31
|
human merges.
|
|
@@ -81,9 +81,15 @@ Treat these operations as separate decisions and receipts:
|
|
|
81
81
|
3. **Worktree removal.** Re-read Git status, branch/upstream divergence,
|
|
82
82
|
unpushed commits, forge merge/publication state, children, terminals, and
|
|
83
83
|
archived evidence immediately before the native exact-workspace removal.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
When archived evidence is the last dirt, use the evidence archive helper's
|
|
85
|
+
manifest-bound retirement operation and require an empty pending set; never
|
|
86
|
+
unlink through prose or a shell loop. Verify the effective Archive Script
|
|
87
|
+
provenance before native removal: an unknown or required-but-untrusted hook
|
|
88
|
+
holds. Record its native outcome as `unconfigured`, `passed`, `failed`, or
|
|
89
|
+
`unknown`; only `unconfigured` or trusted `passed` may advance. Account for
|
|
90
|
+
branch-deletion side effects explicitly, then re-list both native workspaces
|
|
91
|
+
and Git refs. A failed or unknown hook outcome or uncertain response preserves
|
|
92
|
+
the resource; never force or substitute shell deletion.
|
|
87
93
|
4. **Chat archival.** Attempt it only if the version-matched runtime guide
|
|
88
94
|
advertises a distinct supported operation and the scoped chat is eligible.
|
|
89
95
|
Otherwise record chat archival as unsupported. Process exit, worker release,
|
|
@@ -48,12 +48,24 @@ immediately before an actual profile dispatch.
|
|
|
48
48
|
|
|
49
49
|
## 2. Choose proportional output
|
|
50
50
|
|
|
51
|
-
1.
|
|
51
|
+
1. Keep the primary reader-facing explanation to a maximum of 700 words in
|
|
52
|
+
chat, HTML, and every other requested format. Preserve in that primary view
|
|
53
|
+
the answer or purpose, key rationale, meaningful alternatives, main data or
|
|
54
|
+
operational boundary, status and uncertainty, and live reader questions
|
|
55
|
+
with evidence-supported answers, labeling any question the inspected
|
|
56
|
+
evidence does not answer as **unknown** or **open** rather than inventing an
|
|
57
|
+
answer. Count the primary artifact's reader-visible words, including
|
|
58
|
+
headings, table text, and diagram or figure labels and captions. An appendix
|
|
59
|
+
or collapsible content in the same artifact counts toward the 700-word
|
|
60
|
+
maximum. If the draft is longer, compress repetition first and move only
|
|
61
|
+
supporting detail to a separate linked ticket or appendix. Essential answers
|
|
62
|
+
must not be hidden behind links, and evidence must not be silently discarded.
|
|
63
|
+
2. For a simple request, answer concisely in the current chat. Use a compact
|
|
52
64
|
diagram when useful. This needs no mandatory agent or intermediate artifact.
|
|
53
|
-
|
|
65
|
+
3. For a complex visual, use the configured `axstack-explainer` role to create
|
|
54
66
|
self-contained HTML, or use the requested artifact format. An explicit user
|
|
55
67
|
theme wins; otherwise use the dark default.
|
|
56
|
-
|
|
68
|
+
4. Profile IDs are presets, not availability proof. Before dispatch, follow the
|
|
57
69
|
launch sequence and preserve the configured model, mode, and effort. Report
|
|
58
70
|
an unavailable route; never substitute a model.
|
|
59
71
|
|
|
@@ -116,10 +116,10 @@ owns the event and settles after its skill-owned reviewers settle.
|
|
|
116
116
|
|
|
117
117
|
| Preset | Actual author provider/model | Reviewer role (configured model/effort) |
|
|
118
118
|
| --- | --- | --- |
|
|
119
|
-
| `mixed` | Codex / Sol (`codex/gpt-
|
|
120
|
-
| `mixed` | Claude / Opus (`claude/claude-opus-5`) | `axstack-reviewer-primary` (`codex/gpt-
|
|
121
|
-
| `codex-only` | Codex / Sol (`codex/gpt-
|
|
122
|
-
| `claude-only` | Claude / Opus (`claude/claude-opus-5`) | `axstack-reviewer-secondary` (`claude/claude-sonnet-5` xhigh) |
|
|
119
|
+
| `mixed` | Codex / Sol (`codex/gpt-6-sol`) | `axstack-reviewer-secondary` (`claude/claude-opus-5-5` medium) |
|
|
120
|
+
| `mixed` | Claude / Opus (`claude/claude-opus-5-5`) | `axstack-reviewer-primary` (`codex/gpt-6-sol` medium) |
|
|
121
|
+
| `codex-only` | Codex / Sol (`codex/gpt-6-sol`) | `axstack-reviewer-secondary` (`codex/gpt-6-luna` xhigh) |
|
|
122
|
+
| `claude-only` | Claude / Opus (`claude/claude-opus-5-5`) | `axstack-reviewer-secondary` (`claude/claude-sonnet-5` xhigh) |
|
|
123
123
|
|
|
124
124
|
Provenance is matched on provider/model ID; record effort, but never use
|
|
125
125
|
effort to create a mapping. Any other author provenance for the
|
package/src/roles.js
CHANGED
|
@@ -6,14 +6,14 @@ const PROVIDER_BOUNDS = Object.freeze({
|
|
|
6
6
|
|
|
7
7
|
const AUTHORED_ROUTES = Object.freeze({
|
|
8
8
|
mixed: {
|
|
9
|
-
'codex/gpt-
|
|
10
|
-
'claude/claude-opus-5': ['axstack-reviewer-primary', 'codex/gpt-
|
|
9
|
+
'codex/gpt-6-sol': ['axstack-reviewer-secondary', 'claude/claude-opus-5-5', 'medium'],
|
|
10
|
+
'claude/claude-opus-5-5': ['axstack-reviewer-primary', 'codex/gpt-6-sol', 'medium'],
|
|
11
11
|
},
|
|
12
12
|
'codex-only': {
|
|
13
|
-
'codex/gpt-
|
|
13
|
+
'codex/gpt-6-sol': ['axstack-reviewer-secondary', 'codex/gpt-6-luna', 'xhigh'],
|
|
14
14
|
},
|
|
15
15
|
'claude-only': {
|
|
16
|
-
'claude/claude-opus-5': ['axstack-reviewer-secondary', 'claude/claude-sonnet-5', 'xhigh'],
|
|
16
|
+
'claude/claude-opus-5-5': ['axstack-reviewer-secondary', 'claude/claude-sonnet-5', 'xhigh'],
|
|
17
17
|
},
|
|
18
18
|
});
|
|
19
19
|
|