axstack 0.56.1 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/axstack/references/diligence.md +3 -1
- package/skills/axstack/references/fleet-dispatch.md +21 -6
- package/skills/axstack/references/fleet-route-schema.md +11 -1
- package/skills/axstack/references/lifecycle.md +6 -0
- package/skills/axstack/references/local-artifacts.md +100 -0
- package/skills/axstack/references/role-roster.md +5 -0
- package/skills/axstack/references/t3-runtime.md +7 -0
- package/skills/axstack/references/ui-verification.md +4 -1
- package/skills/axstack/scripts/dispatch-plan.js +11 -1
- package/skills/axstack/scripts/fleet-config.js +3 -1
- package/skills/axstack/scripts/fleet-destination.js +12 -3
- package/skills/axstack/scripts/fleet-dispatch.js +10 -2
- package/skills/axstack/scripts/fleet-facts.js +6 -1
- package/skills/axstack/scripts/fleet-receipt.js +39 -7
- package/skills/axstack/scripts/fleet-scope.js +24 -0
- package/skills/axstack-explain/SKILL.md +4 -0
- package/skills/axstack-explain/references/visual-qa.md +6 -1
- package/skills/axstack-publish/SKILL.md +4 -0
- package/skills/axstack-research/SKILL.md +4 -0
- package/skills/axstack-review/SKILL.md +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "axstack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.57.0",
|
|
4
4
|
"description": "Axstack installer and setup CLI: installs owned chat skills and role data, configures supported harness settings, and checks T3 Code capabilities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -5,7 +5,9 @@ and bounded follow-ups are defined in [Peer mode](../../axstack-review/SKILL.md#
|
|
|
5
5
|
|
|
6
6
|
Read the [T3 runtime boundary](t3-runtime.md) before dispatch.
|
|
7
7
|
Dispatch `axstack-diligence` with async `delegate_task` in the driver worktree,
|
|
8
|
-
using a pinned brief and private evidence paths.
|
|
8
|
+
using a pinned brief and private evidence paths. Explicit non-repository
|
|
9
|
+
research/article diligence uses [Local artifacts](local-artifacts.md) with
|
|
10
|
+
local shared isolation and independently reopened sources, without a fake Git repo.
|
|
9
11
|
It is read-only, never authors or edits, and returns `PASS`, `FINDINGS`, or `UNKNOWN`
|
|
10
12
|
with locations, observed evidence, and limits. A stale or missing receipt is
|
|
11
13
|
not a pass. Keep its first pass independent of other reviewers and workers.
|
|
@@ -7,6 +7,12 @@ records and forge actions. Helpers validate explicit saved inputs only: no
|
|
|
7
7
|
network, clock, dispatch, retry, merge, retained state or aggregate permission grant.
|
|
8
8
|
Synthetic evidence can pass binding checks; helpers cannot authenticate it.
|
|
9
9
|
|
|
10
|
+
For explicit local non-repository Research/Explain/Publish work, apply
|
|
11
|
+
[Local artifacts](local-artifacts.md): its discriminated scope, native read/list
|
|
12
|
+
null-identity proof and owned folders replace only the repository/checkout terms.
|
|
13
|
+
All native execution authority and independent exact-byte review remain required.
|
|
14
|
+
Engineering/code review and remote routes retain their existing rules.
|
|
15
|
+
|
|
10
16
|
## Observe before selecting
|
|
11
17
|
|
|
12
18
|
1. Record installed Axstack and both T3 versions, directed origin/target link,
|
|
@@ -70,7 +76,7 @@ read envelope is `{tool,environmentId,args,observedAt,evidence,value}` where arg
|
|
|
70
76
|
excludes the forwarding environmentId, and evidence points to the preserved raw
|
|
71
77
|
native call/result. environment/project/capabilities are read on the selected
|
|
72
78
|
host; links are read on origin. The capabilities envelope uses `valueText` for
|
|
73
|
-
exact raw catalog bytes instead of value.
|
|
79
|
+
exact raw catalog bytes instead of value. For repository scope, project repositoryIdentity.canonicalKey
|
|
74
80
|
must match the requested repositoryId. If project-read identity is null/omitted,
|
|
75
81
|
`projectList` may carry an ordered array of `t3_project_list` read envelopes on
|
|
76
82
|
that same environment. Collect from cursor 0 through native nextCursor:null,
|
|
@@ -78,7 +84,9 @@ recording actual cursor/limit arguments (native defaults: 0/20, limit at most 10
|
|
|
78
84
|
Every page must join without gaps, extra arguments or duplicate project IDs.
|
|
79
85
|
The selected project's ID and workspaceRoot must equal project-read; every
|
|
80
86
|
available canonicalKey must equal repositoryId, including when both reads have
|
|
81
|
-
identity.
|
|
87
|
+
identity. In repository scope, missing identity in both holds; local-artifact
|
|
88
|
+
scope instead requires explicit null in both reads. Incomplete pagination and
|
|
89
|
+
any conflict hold for either scope.
|
|
82
90
|
|
|
83
91
|
For observed T3 0.1.5 native Codex/Claude drivers, omitted provider runtimeModes
|
|
84
92
|
means no provider restriction: native resolveRuntimeMode and RuntimePolicy
|
|
@@ -98,9 +106,11 @@ recommendation, explicit evaluation time and config pin. Compare its target to t
|
|
|
98
106
|
independently selected host/environment/project/model/options/runtimeMode. Copy only
|
|
99
107
|
native supported fields, never inputs or fleetBinding. Call `delegate_task` with
|
|
100
108
|
that exact target, full-access, a role-labelled title, stable clientRequestId and
|
|
101
|
-
scope.
|
|
102
|
-
no shell-created child checkout.
|
|
103
|
-
|
|
109
|
+
scope. Code reviewers require native isolation:"worktree" and pinned candidate/base;
|
|
110
|
+
no shell-created child checkout. Explicit local artifact reviewers instead use
|
|
111
|
+
shared isolation and SHA-256 snapshots under [Local artifacts](local-artifacts.md);
|
|
112
|
+
artifact writers use only their owned artifact/evidence folders. Other nonwriters
|
|
113
|
+
write only their named private evidence directory on that host. Preserve requested arguments and native response.
|
|
104
114
|
|
|
105
115
|
Record taskId on the origin plus remoteChild.environmentId/threadId. The native
|
|
106
116
|
remoteChild schema need not return runId: normalize it from observed task/thread
|
|
@@ -117,7 +127,9 @@ recommendation at the same model/permission pins; record the exclusion evidence.
|
|
|
117
127
|
|
|
118
128
|
Preserve schemaVersion:1, recommendationJSON (exact bytes), configDigest,
|
|
119
129
|
attempt (key, exact title, clientRequestId, origin environmentId/threadId/taskId,
|
|
120
|
-
candidate/base SHAs
|
|
130
|
+
candidate/base SHAs for repositories, artifact SHA-256/null base for local artifacts),
|
|
131
|
+
requested target/runtimeMode/isolation and native submission. Artifact ownership
|
|
132
|
+
and byte readbacks follow [Local artifacts](local-artifacts.md#receipts).
|
|
121
133
|
The driver's independent fleetAttempt is the expected run-record identity;
|
|
122
134
|
never copy it from an arriving receipt to make a comparison pass.
|
|
123
135
|
|
|
@@ -137,6 +149,9 @@ submission.childRunId; never use lexical ordering of IDs or the original summary
|
|
|
137
149
|
Require completed/result_available/no pending children/no unanswered questions or
|
|
138
150
|
approval. Require exactly one AXSTACK-DONE key/candidate/report marker on both origin's
|
|
139
151
|
latestTerminalSummary and the destination's final current-run agent message.
|
|
152
|
+
For local artifacts only, T3 0.1.5's deduplicated summary uses the exact
|
|
153
|
+
run/byte-bound exception in [Local artifacts](local-artifacts.md#receipts);
|
|
154
|
+
never rewrite raw native fields or extend it to remote/engineering receipts.
|
|
140
155
|
A completion marker may be followed by the T3
|
|
141
156
|
`PR <url>, head <sha>, checks and reviews <state>` trailer. Other trailing text
|
|
142
157
|
or additional AXSTACK markers keep the receipt held.
|
|
@@ -112,6 +112,13 @@ for serial emulator use, desktop safety and declared thermal prechecks.
|
|
|
112
112
|
| `pendingAssignments` | Array of `{clientRequestId, environmentId, taskId?}` |
|
|
113
113
|
| `exclusions` | `{hosts: {hostId: reason}, routes: {routeId: reason}}`; nonempty reason strings |
|
|
114
114
|
|
|
115
|
+
`request.scope` may be `{kind:"repository"}` with a nonempty repositoryId;
|
|
116
|
+
legacy omitted scope retains that repository requirement. The explicit
|
|
117
|
+
`{kind:"local-artifact", ...}` alternative requires repositoryId:null and the
|
|
118
|
+
workflow, role, native project and ownership fields in [Local artifacts](local-artifacts.md).
|
|
119
|
+
Artifact destination project also carries workspaceRoot; only the bound local
|
|
120
|
+
environment/project/workspace is eligible. Null alone never selects a route.
|
|
121
|
+
|
|
115
122
|
`role` is `reader` (all nonwriter roles) or `author`. `requiredCapabilities`
|
|
116
123
|
is an array of strings. An authentication requirement names the actual session
|
|
117
124
|
capability; only the host proving that session is eligible. No credential
|
|
@@ -311,7 +318,10 @@ unavailable destination model/options, or role/settings/config disagreement.
|
|
|
311
318
|
It never reinterprets a requested model pin as a different available model.
|
|
312
319
|
|
|
313
320
|
Task plans add `environmentId`/`projectId` to `target`; launch plans add them
|
|
314
|
-
beside `modelSelection`. All requested options survive as T3 option entries.
|
|
321
|
+
beside `modelSelection`. All requested options survive as T3 option entries. Explicit local-artifact
|
|
322
|
+
plans require nativeDestination, the exact scope role and task kind; they emit
|
|
323
|
+
isolation:"shared" and artifactScope evidence. The latter is never a native
|
|
324
|
+
argument. Artifact readback compares scope and shared isolation as well.
|
|
315
325
|
Both include `fleetBinding: {configDigest, destinationSnapshotId,
|
|
316
326
|
destinationCapabilitiesDigest}`. This is preserved evidence, not a T3 launch
|
|
317
327
|
parameter. Copy only tool-supported launch fields. Coordinator author routes
|
|
@@ -29,6 +29,12 @@ Prefer parallel independent bounded work; no redundant workers. Fanout is depend
|
|
|
29
29
|
capacity-driven within host/spending limits. [PR shape](pr-shape.md) covers
|
|
30
30
|
theme/size; queue dependencies under [PR chains](pr-chain.md).
|
|
31
31
|
|
|
32
|
+
For explicit non-repository Research/Explain/Publish artifacts, use
|
|
33
|
+
[Local artifacts](local-artifacts.md) for owned shared delegates and SHA-256
|
|
34
|
+
receipts. The reviewer checkout row above applies to code candidates; article
|
|
35
|
+
review retains independent source/fact and exact-byte UI/design checks.
|
|
36
|
+
Null identity does not waive engineering isolation or authorize remote artifacts.
|
|
37
|
+
|
|
32
38
|
## Ownership
|
|
33
39
|
|
|
34
40
|
The PR owner is accountable for candidate, fixes, evidence, monitoring.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Local non-repository artifacts
|
|
2
|
+
|
|
3
|
+
Research, Explain and Publish may use an explicitly bound non-repository
|
|
4
|
+
artifact scope. Null repository identity alone never authorizes a route.
|
|
5
|
+
Engineering authors and code reviewers still require a repository and native
|
|
6
|
+
Git worktree isolation. Remote artifacts and remote author/coordinator work
|
|
7
|
+
remain outside this scope.
|
|
8
|
+
|
|
9
|
+
## Scope and ownership
|
|
10
|
+
|
|
11
|
+
Use `request.scope` below with `repositoryId:null` and `role:reader`.
|
|
12
|
+
Here reader means no product-code authority; an explainer may write only its
|
|
13
|
+
owned article artifacts. `task` remains a load preference, not role authority.
|
|
14
|
+
The scope is evidence for the helpers and brief, never a native T3 argument.
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"kind": "local-artifact",
|
|
19
|
+
"workflow": "explain",
|
|
20
|
+
"roleId": "axstack-explainer",
|
|
21
|
+
"environmentId": "<current environment>",
|
|
22
|
+
"projectId": "<actual parent project>",
|
|
23
|
+
"workspaceRoot": "/scratch",
|
|
24
|
+
"artifactRoot": "/scratch/run/artifacts/author-a1",
|
|
25
|
+
"evidenceRoot": "/scratch/run/evidence/author-a1",
|
|
26
|
+
"reservedRoots": ["/scratch/run/artifacts/other-attempt"]
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`workflow` is research, explain or publish. All three permit the configured
|
|
31
|
+
research requirements/code/code-sol/web/web-sol/X and explore-execution/
|
|
32
|
+
explore-execution-sol source roles plus diligence. Explain and Publish also
|
|
33
|
+
permit explainer, explainer-review and the configured UI verifier roles.
|
|
34
|
+
Use their full `axstack-` role IDs; this list does not make an absent seat
|
|
35
|
+
available or change provider/model/effort/options/runtime authority.
|
|
36
|
+
The selected role ID must equal scope.roleId in dispatch-plan.
|
|
37
|
+
No engineering author, code reviewer, owner or arbitrary role can use this scope.
|
|
38
|
+
|
|
39
|
+
The driver binds the native parent project and its real workspaceRoot. Require
|
|
40
|
+
explicit null repositoryIdentity in both project-read and complete project-list
|
|
41
|
+
reads; omitted, conflicting or incomplete observations hold. Native environment,
|
|
42
|
+
project, catalog, provider restrictions, options, runtime and access checks still
|
|
43
|
+
apply. Use only a local route in that environment/project/workspace. Do not
|
|
44
|
+
fabricate a repository ID, initialize Git or attach an unrelated repository.
|
|
45
|
+
|
|
46
|
+
Give every attempt separate owned artifact and evidence directories, strict
|
|
47
|
+
children of the observed workspaceRoot. They must be canonical absolute paths,
|
|
48
|
+
with no traversal, shared-root writes or ancestor/equal overlap. `reservedRoots`
|
|
49
|
+
is the driver's current list of other attempts' owned artifact/evidence roots;
|
|
50
|
+
include pending and retained attempts, never guess an empty inventory.
|
|
51
|
+
The helper checks lexical paths and overlaps; the driver must independently
|
|
52
|
+
verify real paths, no symlink escapes, ownership and exclusive writers on disk.
|
|
53
|
+
Unknown ownership holds. This is supplied evidence, not an authenticated lock.
|
|
54
|
+
|
|
55
|
+
## Native dispatch and review
|
|
56
|
+
|
|
57
|
+
Use async native `delegate_task` with `isolation:"shared"`, exact local target,
|
|
58
|
+
role-labelled title and stable clientRequestId. Native local projectId must equal
|
|
59
|
+
the parent's project; moving to another local project is unsupported. Preserve
|
|
60
|
+
requested arguments and native effective settings separately. Dispatch-plan
|
|
61
|
+
requires nativeDestination and `--kind task`; it returns artifactScope as evidence
|
|
62
|
+
and shared isolation. Copy only supported native arguments into delegate_task.
|
|
63
|
+
No top-level launch, shell checkout, live policy edit or per-run bypass is needed.
|
|
64
|
+
|
|
65
|
+
Research branches keep independent first passes and cited-source reopening.
|
|
66
|
+
Diligence reopens answer-changing claims; it never becomes the article author.
|
|
67
|
+
The explainer remains sole source writer. Reviewers/verifiers get their own
|
|
68
|
+
byte-identical snapshot in their owned artifact directory; their reports/probes
|
|
69
|
+
stay in their separate evidence directory and never edit the author's original.
|
|
70
|
+
Independent explainer review checks the exact SHA-256 bytes. Before public
|
|
71
|
+
publication require Playwright layout/interaction evidence and independent
|
|
72
|
+
source/fact and design review of those same bytes under Explain/Publish rules.
|
|
73
|
+
Changed bytes invalidate affected reviews and renders; unknown proof holds.
|
|
74
|
+
Shared filesystem access does not permit cross-reading independent first passes.
|
|
75
|
+
Publication remains the explicitly authorized driver's action.
|
|
76
|
+
|
|
77
|
+
## Receipts
|
|
78
|
+
|
|
79
|
+
Retain the normal native task/thread/run, pending-question and settings checks.
|
|
80
|
+
For artifact receipts, `attempt.candidate` and marker `head` are the exact
|
|
81
|
+
64-hex artifact SHA-256; `attempt.base` is null. They are not Git revisions.
|
|
82
|
+
Bind `artifactScope` to the requested scope and report to evidenceRoot.
|
|
83
|
+
Supply `artifact:{path,sha256,readback:{path,sha256,evidence}}` for the independently
|
|
84
|
+
hashed owned snapshot. Requested isolation must be shared. Native child worktreePath may be null;
|
|
85
|
+
on T3 0.1.5 it may also inherit the parent's non-Git scratch path. For the latter,
|
|
86
|
+
include `parent` as a saved `t3_thread_read` observation (tool, environmentId,
|
|
87
|
+
args.threadId, observedAt, evidence, value.thread). Bind it to the attempt's
|
|
88
|
+
origin thread, selected project, child parentThreadId/subagent relationship and
|
|
89
|
+
identical canonical path inside workspaceRoot. Verify the actual filesystem;
|
|
90
|
+
this is shared access, not a Git checkout or OS isolation. Checkout metadata
|
|
91
|
+
remains forbidden. Unknown or different parent/path evidence holds.
|
|
92
|
+
|
|
93
|
+
T3 0.1.5 deduplicates local task results: latestTerminalSummary can be null when
|
|
94
|
+
summary contains the same result. For local artifact receipts only, use that
|
|
95
|
+
summary when childRunId and latestTerminalRunId both equal the current completed
|
|
96
|
+
run and its bytes equal the destination final message. An explicit conflicting
|
|
97
|
+
terminal summary, stale run, other version or remote result does not use this
|
|
98
|
+
fallback. Preserve the raw native fields; do not rewrite them. Never synthesize an effective field from requested settings.
|
|
99
|
+
The driver checks actual bytes and readbacks; helpers validate saved data only.
|
|
100
|
+
Keep artifact receipts separate from Git candidate publication/PR/merge receipts.
|
|
@@ -6,6 +6,11 @@ native destination. Remote reviewers require T3 worktree isolation; no shell chi
|
|
|
6
6
|
checkout. Host names confer no role or permission. Remote authors/coordinator stay
|
|
7
7
|
disabled; local isolated authors remain supported even overloaded.
|
|
8
8
|
|
|
9
|
+
Explicit non-repository Research/Explain/Publish uses the bounded role allowlist
|
|
10
|
+
and local shared-artifact isolation in [Local artifacts](local-artifacts.md).
|
|
11
|
+
This changes no configured seat, source independence or exact-byte review duty.
|
|
12
|
+
Engineering authors and code reviewers cannot acquire this artifact authority.
|
|
13
|
+
|
|
9
14
|
- Chat drives (no role ID); `axstack-owner` owns one PR and
|
|
10
15
|
`axstack-author` its sole writer.
|
|
11
16
|
For own PRs, automatic merge is the default under the
|
|
@@ -204,6 +204,13 @@ a candidate follows [UI verification](ui-verification.md).
|
|
|
204
204
|
|
|
205
205
|
The driver must be the sole run-record writer and enforce one writer per
|
|
206
206
|
candidate; it never writes tracked candidate source or tests or repairs an author's source.
|
|
207
|
+
For explicit non-repository Research/Explain/Publish only,
|
|
208
|
+
[Local artifacts](local-artifacts.md) supplies the artifact branch of this table:
|
|
209
|
+
source readers, diligence, explainers and article/UI reviewers use local shared
|
|
210
|
+
native delegates with separate owned folders and exact SHA-256 snapshots.
|
|
211
|
+
Its role allowlist excludes engineering authors and code reviewers; their native
|
|
212
|
+
Git worktree rules above remain mandatory. Null repository alone grants nothing.
|
|
213
|
+
|
|
207
214
|
The driver may write planning artifacts (spec, ticket map) in its own worktree when the selected store is repository Markdown.
|
|
208
215
|
Repairs return to that author. Missing or idle sessions grant no ownership transfer.
|
|
209
216
|
The current chat/driver has no role row in any preset.
|
|
@@ -24,8 +24,11 @@ All other browser checks outside the two named exceptions remain delegated to co
|
|
|
24
24
|
|
|
25
25
|
Read the [T3 runtime boundary](t3-runtime.md) before dispatch; for candidate
|
|
26
26
|
checks use its driver-made disposable detached checkout at the pinned candidate SHA.
|
|
27
|
+
For explicit non-repository article checks, use the local shared delegate and
|
|
28
|
+
owned SHA-256 snapshot in [Local artifacts](local-artifacts.md); no Git candidate
|
|
29
|
+
is fabricated. Engineering candidate checks retain the checkout requirement.
|
|
27
30
|
Use the configured verifier browser and honor the user browser-tool policy.
|
|
28
|
-
|
|
31
|
+
Engineering candidate browser and visual checks must run in a delegated UI verifier role in its own detached checkout; outputs go to its private evidence folder, never the driver worktree.
|
|
29
32
|
|
|
30
33
|
For every interactive page, require a real-browser `axstack-ui-verifier` interaction pass.
|
|
31
34
|
Give the evidence path and SHA-256 of the exact bytes in the verifier brief.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { inspectFleetReceipt } from './fleet-receipt.js';
|
|
3
3
|
import { bindFleet } from './fleet-dispatch.js';
|
|
4
|
+
import { canonical } from './fleet-config.js';
|
|
4
5
|
|
|
5
6
|
const fleetFlags = ['--recommendation', '--fleet-input', '--now', '--config-digest'];
|
|
6
7
|
const flags = ['--role', '--roles', '--capabilities', '--kind', '--verify', '--out', ...fleetFlags];
|
|
@@ -34,6 +35,9 @@ by its destination facts. It is never the origin catalog by default.
|
|
|
34
35
|
Fleet verification requires environmentId/projectId and fleetBinding alongside
|
|
35
36
|
the effective T3 configuration. C3 collects that host-qualified evidence envelope.
|
|
36
37
|
Optional input.nativeDestination validates saved native forwarded reads.
|
|
38
|
+
Explicit local-artifact scope requires those reads and kind task; emits isolation:"shared".
|
|
39
|
+
artifactScope is preserved evidence only, never a native tool argument.
|
|
40
|
+
Artifact verification also requires artifactScope and independently checked isolation.
|
|
37
41
|
Optional --verify fleetAttempt/fleetReceipt validates host-qualified terminal facts;
|
|
38
42
|
--out retains per-term receipt evidence. Synthetic bindings cannot authenticate reads.
|
|
39
43
|
Coordinator routes remain unsupported here. A plan grants no launch authority.
|
|
@@ -98,6 +102,11 @@ function verify(configuration, provider, model, options, fleet) {
|
|
|
98
102
|
if (fleet) {
|
|
99
103
|
for (const [field, expected] of Object.entries(fleet.destination)) compare(field, expected, configuration?.[field]);
|
|
100
104
|
for (const [field, expected] of Object.entries(fleet.fleetBinding)) compare(field, expected, configuration?.fleetBinding?.[field]);
|
|
105
|
+
if (fleet.artifactScope) {
|
|
106
|
+
compare('artifactScope', fleet.artifactScope, configuration?.artifactScope,
|
|
107
|
+
canonical(fleet.artifactScope) === canonical(configuration?.artifactScope));
|
|
108
|
+
compare('isolation', 'shared', configuration?.isolation);
|
|
109
|
+
}
|
|
101
110
|
}
|
|
102
111
|
let receiptTerms;
|
|
103
112
|
if (fleet && configuration?.fleetReceipt !== undefined) {
|
|
@@ -175,7 +184,7 @@ function plan(argv, io) {
|
|
|
175
184
|
const recommendation = JSON.parse(recommendationJSON);
|
|
176
185
|
fleet = bindFleet(readJSON(args['--fleet-input']), recommendation,
|
|
177
186
|
args['--config-digest'], Number(args['--now']), readFileSync(args['--capabilities'], 'utf8'),
|
|
178
|
-
resolution, role.id === 'axstack-author');
|
|
187
|
+
resolution, role.id === 'axstack-author', role.id, args['--kind']);
|
|
179
188
|
fleet.recommendation = recommendation;
|
|
180
189
|
fleet.recommendationJSON = recommendationJSON;
|
|
181
190
|
fleet.now = Number(args['--now']);
|
|
@@ -189,6 +198,7 @@ function plan(argv, io) {
|
|
|
189
198
|
const selection = { [args['--kind'] === 'launch' ? 'instanceId' : 'providerInstanceId']: providerInstanceId,
|
|
190
199
|
model, options, ...(args['--kind'] === 'task' ? fleet?.destination : {}) };
|
|
191
200
|
emit({ [args['--kind'] === 'launch' ? 'modelSelection' : 'target']: selection, runtimeMode: 'full-access',
|
|
201
|
+
...(fleet?.artifactScope ? { artifactScope: fleet.artifactScope, isolation: fleet.isolation } : {}),
|
|
192
202
|
...(fleet ? { fleetBinding: fleet.fleetBinding, ...(args['--kind'] === 'launch' ? fleet.destination : {}) } : {}),
|
|
193
203
|
...(args['--kind'] === 'task' && role.id === 'axstack-author' ? { isolation: 'worktree' } : {}) });
|
|
194
204
|
return 0;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { validScope } from './fleet-scope.js';
|
|
2
|
+
|
|
1
3
|
// Configuration is reviewed data. This module does not read account-local files.
|
|
2
4
|
export function fail(code) { throw new Error(code); }
|
|
3
5
|
export const record = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -58,7 +60,7 @@ export function validateInput(input, now) {
|
|
|
58
60
|
const r = input.request;
|
|
59
61
|
if (!record(r) || !text(r.task) || !['reader', 'author'].includes(r.role)
|
|
60
62
|
|| !Array.isArray(r.requiredCapabilities) || !r.requiredCapabilities.every(text)
|
|
61
|
-
|| !
|
|
63
|
+
|| !validScope(r) || !text(r.providerInstanceId) || !text(r.model)
|
|
62
64
|
|| !record(r.options) || !text(r.runtimeMode)) fail('request-schema');
|
|
63
65
|
for (const key of ['destinations', 'routeFacts', 'telemetry', 'assignments', 'pendingAssignments']) {
|
|
64
66
|
if (!Array.isArray(input[key])) fail(`${key}-schema`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Validate explicit saved native reads. These bindings do not authenticate input.
|
|
2
|
+
import { isArtifact } from './fleet-scope.js';
|
|
2
3
|
import { canonical, text, time } from './fleet-config.js';
|
|
3
4
|
|
|
4
5
|
export function inspectDestination(observation, recommendation, capabilitiesText, now) {
|
|
@@ -51,9 +52,17 @@ export function inspectDestination(observation, recommendation, capabilitiesText
|
|
|
51
52
|
}
|
|
52
53
|
// ProjectService.listPage resolves the cold identity cache; getById need not.
|
|
53
54
|
const identities = [project?.repositoryIdentity, listed?.repositoryIdentity].filter((v) => v != null);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
if (isArtifact(recommendation.request)) {
|
|
56
|
+
const scope = recommendation.request.scope;
|
|
57
|
+
term('destination-artifact-project', project?.repositoryIdentity === null
|
|
58
|
+
&& listed?.repositoryIdentity === null && project?.workspaceRoot === scope.workspaceRoot
|
|
59
|
+
&& s.environmentId === scope.environmentId && s.projectId === scope.projectId,
|
|
60
|
+
{ project, listed });
|
|
61
|
+
} else {
|
|
62
|
+
term('destination-repository', identities.length > 0
|
|
63
|
+
&& identities.every((v) => v.canonicalKey === s.repositoryId), identities,
|
|
64
|
+
identities.length === 0);
|
|
65
|
+
}
|
|
57
66
|
term('destination-catalog', o.capabilities?.valueText === capabilitiesText, o.capabilities?.valueText);
|
|
58
67
|
const catalog = JSON.parse(capabilitiesText);
|
|
59
68
|
const providers = catalog.providers?.filter((v) => v.providerInstanceId === recommendation.request.providerInstanceId);
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
// Bind supplied placement facts to a plan. No reads, dispatch or authority grant.
|
|
2
|
+
import { isArtifact } from './fleet-scope.js';
|
|
2
3
|
import { inspectDestination } from './fleet-destination.js';
|
|
3
4
|
import { canonical, record, text } from './fleet-config.js';
|
|
4
5
|
import { recommend } from './fleet-route.js';
|
|
5
6
|
|
|
6
|
-
export function bindFleet(input, saved, configDigest, now, capabilitiesText, resolved, author) {
|
|
7
|
+
export function bindFleet(input, saved, configDigest, now, capabilitiesText, resolved, author, roleId, kind) {
|
|
7
8
|
const hold = (code) => { throw Object.assign(new Error(code), { exitCode: 2 }); };
|
|
8
9
|
if (saved?.schemaVersion !== 1) hold('schema-version: recommendation');
|
|
9
10
|
if (configDigest !== input?.configDigest) hold('config-digest-mismatch');
|
|
10
11
|
let current;
|
|
11
12
|
try { current = recommend(input, now); } catch (error) { hold(error.message); }
|
|
12
13
|
if (canonical(saved) !== canonical(current)) hold('recommendation-mismatch');
|
|
14
|
+
const artifact = isArtifact(current.request);
|
|
15
|
+
if (artifact) {
|
|
16
|
+
if (roleId !== current.request.scope.roleId) hold('artifact-role-mismatch');
|
|
17
|
+
if (kind !== 'task') hold('artifact-task-only');
|
|
18
|
+
if (input.nativeDestination === undefined) hold('artifact-native-destination-required');
|
|
19
|
+
}
|
|
13
20
|
const selected = current.selected;
|
|
14
21
|
if (!selected) hold('no-executable-route');
|
|
15
22
|
// Coordinator enablement/lifecycle is a later capability, never inferred here.
|
|
@@ -40,7 +47,8 @@ export function bindFleet(input, saved, configDigest, now, capabilitiesText, res
|
|
|
40
47
|
return { id, value };
|
|
41
48
|
});
|
|
42
49
|
return {
|
|
43
|
-
options,
|
|
50
|
+
options, ...(artifact ? { artifactScope: current.request.scope, isolation: 'shared' } : {}),
|
|
51
|
+
destination: { environmentId: selected.environmentId, projectId: selected.projectId },
|
|
44
52
|
fleetBinding: { configDigest, destinationSnapshotId: selected.destinationSnapshotId,
|
|
45
53
|
destinationCapabilitiesDigest: digest },
|
|
46
54
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isArtifact } from './fleet-scope.js';
|
|
1
2
|
import { nativeAssignments } from './fleet-inventory.js';
|
|
2
3
|
import { canonical, evidence, fail, record, text, time } from './fleet-config.js';
|
|
3
4
|
|
|
@@ -116,6 +117,8 @@ export function routeReasons(route, host, destination, facts, input, now) {
|
|
|
116
117
|
const add = (code) => { if (!reasons.includes(code)) reasons.push(code); };
|
|
117
118
|
const remote = route.environmentId !== input.origin.environmentId;
|
|
118
119
|
const r = input.request;
|
|
120
|
+
const artifact = isArtifact(r);
|
|
121
|
+
if (artifact && (remote || route.kind !== 'local' || r.scope.environmentId !== input.origin.environmentId)) add('artifact-local-only');
|
|
119
122
|
if (Object.hasOwn(input.exclusions.hosts, host.id)) add('excluded-host');
|
|
120
123
|
if (Object.hasOwn(input.exclusions.routes, route.id)) add('excluded-route');
|
|
121
124
|
if (!route.enabled) add('route-disabled');
|
|
@@ -134,7 +137,9 @@ export function routeReasons(route, host, destination, facts, input, now) {
|
|
|
134
137
|
|| !evidence(destination.evidence, host.environmentId, now)) add('evidence-unproven');
|
|
135
138
|
if (!text(destination.snapshotId) || facts?.destinationSnapshotId !== destination.snapshotId) add('target-snapshot-mismatch');
|
|
136
139
|
if (!record(destination.project) || !text(destination.project.id)) add('project-missing');
|
|
137
|
-
else if (destination.project.repositoryId !== r.repositoryId
|
|
140
|
+
else if (destination.project.repositoryId !== r.repositoryId
|
|
141
|
+
|| (artifact && (destination.project.id !== r.scope.projectId
|
|
142
|
+
|| destination.project.workspaceRoot !== r.scope.workspaceRoot))) add('project-mismatch');
|
|
138
143
|
const e = destination.execution;
|
|
139
144
|
if (!record(e) || e.available !== true) add('execution-unproven');
|
|
140
145
|
else if (e.providerInstanceId !== r.providerInstanceId || e.model !== r.model
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Saved evidence validator. A pass binds supplied facts; it cannot authenticate them.
|
|
2
2
|
import { canonical, record, text, time } from './fleet-config.js';
|
|
3
|
+
import { inside, isArtifact } from './fleet-scope.js';
|
|
3
4
|
import { inspectNativeFamily } from './fleet-native-receipt.js';
|
|
4
5
|
|
|
5
6
|
function options(value) {
|
|
@@ -21,6 +22,7 @@ export function inspectFleetReceipt(receipt, expected) {
|
|
|
21
22
|
const a = expected.attempt;
|
|
22
23
|
const s = expected.recommendation.selected;
|
|
23
24
|
const request = expected.recommendation.request;
|
|
25
|
+
const artifact = isArtifact(request);
|
|
24
26
|
term('receipt-origin', text(a?.origin?.threadId) && a?.origin?.environmentId === expected.recommendation.originEnvironmentId
|
|
25
27
|
&& same(r.attempt?.origin, a?.origin), r.attempt?.origin,
|
|
26
28
|
!text(a?.origin?.threadId) || r.attempt?.origin == null);
|
|
@@ -127,16 +129,46 @@ export function inspectFleetReceipt(receipt, expected) {
|
|
|
127
129
|
};
|
|
128
130
|
const items = r.thread?.value?.items;
|
|
129
131
|
const final = Array.isArray(items) ? items.filter((v) => v.runId === current && v.createdBy === 'agent').at(-1) : null;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
// T3 0.1.5 suppresses latestTerminalSummary when it equals summary.
|
|
133
|
+
// Only the same local result run may use that deduplicated value.
|
|
134
|
+
const localSummary = artifact && !remote && s.versions?.t3 === '0.1.5'
|
|
135
|
+
&& status?.latestTerminalSummary === null && text(current)
|
|
136
|
+
&& status?.childRunId === current && status?.latestTerminalRunId === current
|
|
137
|
+
&& status?.status === 'completed' && status?.summary === final?.text;
|
|
138
|
+
const resultSummary = localSummary ? status.summary : status?.latestTerminalSummary;
|
|
139
|
+
term('receipt-marker', (artifact ? /^[a-f0-9]{64}$/ : /^[a-f0-9]{40}$/).test(a?.candidate ?? '')
|
|
140
|
+
&& finalMarker(resultSummary) === marker && finalMarker(final?.text) === marker
|
|
141
|
+
&& (!initial || resultSummary === final?.text),
|
|
142
|
+
{ origin: resultSummary, destination: final?.text });
|
|
134
143
|
term('receipt-host-path', r.evidence?.hostId === s.hostId && r.evidence?.environmentId === s.environmentId
|
|
135
|
-
&& absolute(r.evidence?.path) && finalMarker(
|
|
136
|
-
if (
|
|
144
|
+
&& absolute(r.evidence?.path) && finalMarker(resultSummary)?.endsWith(` report=${r.evidence.path}`), r.evidence);
|
|
145
|
+
if (artifact) {
|
|
146
|
+
const scope = request.scope;
|
|
147
|
+
const bytes = r.artifact;
|
|
148
|
+
term('receipt-artifact-scope', a?.base === null && same(r.artifactScope, scope)
|
|
149
|
+
&& inside(r.evidence?.path, scope.evidenceRoot), r.artifactScope);
|
|
150
|
+
term('receipt-artifact-bytes', bytes?.sha256 === a?.candidate && inside(bytes?.path, scope.artifactRoot)
|
|
151
|
+
&& bytes?.readback?.path === bytes.path && bytes?.readback?.sha256 === bytes.sha256
|
|
152
|
+
&& text(bytes?.readback?.evidence), bytes);
|
|
153
|
+
// Shared native children can inherit a parent's non-Git scratch directory.
|
|
154
|
+
// Bind that value to an actual parent read; a path alone proves nothing.
|
|
155
|
+
const parent = r.parent;
|
|
156
|
+
const parentThread = parent?.value?.thread;
|
|
157
|
+
const inherited = !remote && s.versions?.t3 === '0.1.5'
|
|
158
|
+
&& parent?.tool === 't3_thread_read' && parent.environmentId === a?.origin?.environmentId
|
|
159
|
+
&& same(parent.args, { threadId: a?.origin?.threadId })
|
|
160
|
+
&& time(parent.observedAt) && parent.observedAt <= expected.now && text(parent.evidence)
|
|
161
|
+
&& parentThread?.threadId === a?.origin?.threadId && parentThread?.projectId === s.projectId
|
|
162
|
+
&& thread?.parentThreadId === parentThread?.threadId && thread?.relationshipToParent === 'subagent'
|
|
163
|
+
&& absolute(parentThread?.worktreePath) && inside(parentThread.worktreePath, scope.workspaceRoot)
|
|
164
|
+
&& thread?.worktreePath === parentThread.worktreePath;
|
|
165
|
+
term('receipt-isolation', r.requested?.isolation === 'shared'
|
|
166
|
+
&& (thread?.worktreePath === null || inherited) && r.checkout == null,
|
|
167
|
+
{ isolation: r.requested?.isolation, worktreePath: thread?.worktreePath, parent });
|
|
168
|
+
} else if (a?.title?.startsWith('Reviewer: ')) {
|
|
137
169
|
term('receipt-isolation', r.requested?.isolation === 'worktree', r.requested?.isolation);
|
|
138
170
|
}
|
|
139
|
-
if (a?.title?.startsWith('Reviewer: ') || r.checkout != null || thread?.worktreePath != null || r.requested?.isolation === 'worktree') {
|
|
171
|
+
if (!artifact && (a?.title?.startsWith('Reviewer: ') || r.checkout != null || thread?.worktreePath != null || r.requested?.isolation === 'worktree')) {
|
|
140
172
|
const c = r.checkout;
|
|
141
173
|
term('receipt-checkout', c?.hostId === s.hostId && c?.environmentId === s.environmentId
|
|
142
174
|
&& absolute(c?.path) && c.path === thread?.worktreePath
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Explicit artifact authority, separate from repository engineering authority.
|
|
2
|
+
const sourceRoles = ['axstack-research-requirements', 'axstack-research-code', 'axstack-research-code-sol',
|
|
3
|
+
'axstack-explore-execution', 'axstack-explore-execution-sol',
|
|
4
|
+
'axstack-research-web', 'axstack-research-web-sol', 'axstack-research-x', 'axstack-diligence'];
|
|
5
|
+
const articleRoles = ['axstack-explainer', 'axstack-explainer-review', 'axstack-ui-verifier', 'axstack-ui-verifier-sonnet'];
|
|
6
|
+
export const isArtifact = (request) => request?.scope?.kind === 'local-artifact';
|
|
7
|
+
const path = (value) => typeof value === 'string' && value.startsWith('/') && value !== '/'
|
|
8
|
+
&& !/[\s\x00-\x1f\x7f]/.test(value) && !value.slice(1).split('/').some((v) => ['', '.', '..'].includes(v));
|
|
9
|
+
export const inside = (value, root) => path(value) && path(root) && value.startsWith(`${root}/`);
|
|
10
|
+
const overlaps = (a, b) => a === b || inside(a, b) || inside(b, a);
|
|
11
|
+
|
|
12
|
+
export function validScope(request) {
|
|
13
|
+
const s = request.scope;
|
|
14
|
+
if (s === undefined) return typeof request.repositoryId === 'string' && request.repositoryId.trim().length > 0;
|
|
15
|
+
if (s?.kind === 'repository') return typeof request.repositoryId === 'string' && request.repositoryId.trim().length > 0;
|
|
16
|
+
if (!isArtifact(request) || request.repositoryId !== null || request.role !== 'reader'
|
|
17
|
+
|| !['research', 'explain', 'publish'].includes(s.workflow)
|
|
18
|
+
|| ![...sourceRoles, ...(s.workflow === 'research' ? [] : articleRoles)].includes(s.roleId)
|
|
19
|
+
|| ![s.environmentId, s.projectId].every((v) => typeof v === 'string' && v.trim().length > 0)
|
|
20
|
+
|| !inside(s.artifactRoot, s.workspaceRoot) || !inside(s.evidenceRoot, s.workspaceRoot)
|
|
21
|
+
|| overlaps(s.artifactRoot, s.evidenceRoot) || !Array.isArray(s.reservedRoots)
|
|
22
|
+
|| s.reservedRoots.some((root) => !path(root) || overlaps(root, s.artifactRoot) || overlaps(root, s.evidenceRoot))) return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
@@ -20,6 +20,10 @@ scope baseline. Ordinary work in the current chat needs no launch preflight;
|
|
|
20
20
|
load the [T3 runtime boundary](../axstack/references/t3-runtime.md) only
|
|
21
21
|
immediately before an actual profile dispatch.
|
|
22
22
|
|
|
23
|
+
For explicit local non-repository work, apply
|
|
24
|
+
[Local artifacts](../axstack/references/local-artifacts.md) before native dispatch.
|
|
25
|
+
Preserve this phase's independent source/fact and exact-byte review requirements.
|
|
26
|
+
|
|
23
27
|
## 1. Bound the question and evidence
|
|
24
28
|
|
|
25
29
|
1. Identify the audience, question, requested format, theme, and publication
|
|
@@ -24,7 +24,12 @@ Interaction checks remain with `axstack-ui-verifier`; source-fidelity review is
|
|
|
24
24
|
Use this checklist for every HTML explanation and other visual artifacts where
|
|
25
25
|
rendering matters.
|
|
26
26
|
|
|
27
|
-
Browser and visual checks
|
|
27
|
+
Browser and visual checks use delegated `axstack-ui-verifier`: engineering
|
|
28
|
+
candidates require its own detached checkout; explicit non-repository articles
|
|
29
|
+
use the local shared delegate with an owned exact-byte snapshot under
|
|
30
|
+
[Local artifacts](../../axstack/references/local-artifacts.md). Outputs stay in
|
|
31
|
+
its private evidence folder. Playwright checks and source/design review remain
|
|
32
|
+
bound to the exact final SHA-256 before public publication.
|
|
28
33
|
|
|
29
34
|
1. Identify the final artifact bytes and theme. The explicit user theme wins;
|
|
30
35
|
otherwise use `prefers-color-scheme`.
|
|
@@ -10,6 +10,10 @@ The current T3 driver owns publication; workers return checked artifacts.
|
|
|
10
10
|
Load [Standing contracts](../axstack/references/contracts.md) and follow its
|
|
11
11
|
lifecycle pointers. Keep page bytes, checks and receipts in private run evidence.
|
|
12
12
|
|
|
13
|
+
For explicit local non-repository work, apply
|
|
14
|
+
[Local artifacts](../axstack/references/local-artifacts.md) before native dispatch.
|
|
15
|
+
Preserve this phase's independent source/fact and exact-byte review requirements.
|
|
16
|
+
|
|
13
17
|
## 1. Bind the request
|
|
14
18
|
|
|
15
19
|
Read host-managed `~/.config/axstack/publish.json` containing string fields
|
|
@@ -20,6 +20,10 @@ baseline, ticket map, or author pipeline. Keep it read-only unless requested
|
|
|
20
20
|
and separately authorized to change product code or publish; otherwise, neither
|
|
21
21
|
is part of research.
|
|
22
22
|
|
|
23
|
+
For explicit local non-repository work, apply
|
|
24
|
+
[Local artifacts](../axstack/references/local-artifacts.md) before native dispatch.
|
|
25
|
+
Preserve this phase's independent source/fact and exact-byte review requirements.
|
|
26
|
+
|
|
23
27
|
## Procedure
|
|
24
28
|
|
|
25
29
|
1. **Frame the question.** Restate the question, what is in scope, what is
|
|
@@ -11,6 +11,11 @@ Include [Safe deletion](../axstack/references/workspace-hygiene.md#safe-deletion
|
|
|
11
11
|
|
|
12
12
|
Manual review keeps the user’s chat and workspace open.
|
|
13
13
|
|
|
14
|
+
For non-repository article/source review, follow
|
|
15
|
+
[Local artifacts](../axstack/references/local-artifacts.md); Explain/Publish own
|
|
16
|
+
the independent artifact review. PR/code-review modes below retain repository
|
|
17
|
+
and native worktree requirements; null identity never selects those modes.
|
|
18
|
+
|
|
14
19
|
Produce evidence-bound findings for an exact revision using the review count
|
|
15
20
|
and model routing required by its mode. Report within the requested authority;
|
|
16
21
|
for own PRs, automatic merge is the default under the
|