sortie-dogs 0.9.8 → 0.9.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/README.md +196 -196
- package/dist/asset-version.d.ts +1 -1
- package/dist/asset-version.js +1 -1
- package/dist/core/goal-bound.js +2 -2
- package/dist/core/goal-declaration-format.js +32 -32
- package/dist/core/run-flight-ledger.js +10 -0
- package/dist/core/worktree-commit-artifact.js +326 -326
- package/dist/plugin/continuation.js +16 -1
- package/dist/plugin/index.js +59 -12
- package/dist/reflection/policy.js +82 -82
- package/dist/runtime-assets.d.ts +30 -14
- package/dist/runtime-assets.js +1451 -1413
- package/package.json +77 -77
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Sortie-dogs
|
|
2
2
|
|
|
3
|
-
**Add a bounded, cost-aware execution loop to OpenCode without taking OpenCode over.**
|
|
4
|
-
|
|
5
|
-
Sortie-dogs is an opt-in overlay, not a replacement. It stays passive until you
|
|
6
|
-
invoke `/sortie` or select `dog-coordinator`. Standard OpenCode agents and
|
|
7
|
-
unrelated sessions remain available and unchanged.
|
|
8
|
-
|
|
9
|
-
> **Project status: Beta.** v0.9.x is under active stabilization. Runtime
|
|
10
|
-
> behavior, configuration, and runtime assets may still change before 1.0.
|
|
3
|
+
**Add a bounded, cost-aware execution loop to OpenCode without taking OpenCode over.**
|
|
4
|
+
|
|
5
|
+
Sortie-dogs is an opt-in overlay, not a replacement. It stays passive until you
|
|
6
|
+
invoke `/sortie` or select `dog-coordinator`. Standard OpenCode agents and
|
|
7
|
+
unrelated sessions remain available and unchanged.
|
|
8
|
+
|
|
9
|
+
> **Project status: Beta.** v0.9.x is under active stabilization. Runtime
|
|
10
|
+
> behavior, configuration, and runtime assets may still change before 1.0.
|
|
11
11
|
|
|
12
12
|
[](https://www.npmjs.com/package/sortie-dogs)
|
|
13
13
|
[](LICENSE)
|
|
@@ -15,63 +15,63 @@ unrelated sessions remain available and unchanged.
|
|
|
15
15
|
|
|
16
16
|

|
|
17
17
|
|
|
18
|
-
Sortie-dogs turns selected work into a scoped plan, optional evidence gathering,
|
|
19
|
-
bounded implementation, canonical validation, and evidence-backed completion.
|
|
18
|
+
Sortie-dogs turns selected work into a scoped plan, optional evidence gathering,
|
|
19
|
+
bounded implementation, canonical validation, and evidence-backed completion.
|
|
20
20
|
|
|
21
21
|
Requirements: Node.js 22.6 or newer, npm, and OpenCode.
|
|
22
22
|
|
|
23
|
-
Guides: [日本語](docs/guide-ja.md) · [简体中文](docs/guide-zh-CN.md) · [CLI testing](docs/cli-testing.md)
|
|
24
|
-
|
|
25
|
-
Release: [v0.9.
|
|
26
|
-
|
|
27
|
-
## Why Sortie-dogs?
|
|
28
|
-
|
|
29
|
-
### Invisible until invited
|
|
30
|
-
|
|
31
|
-
Use normal OpenCode normally. Sortie activates only for `/sortie` or
|
|
32
|
-
`dog-coordinator`; it does not disable or replace OpenCode's standard agents.
|
|
33
|
-
|
|
34
|
-
### Spend strong models only where they matter
|
|
35
|
-
|
|
36
|
-
Lower-cost models handle bounded retrieval and parallel volume work. Stronger
|
|
37
|
-
models are reserved for implementation, escalation, and independent review.
|
|
38
|
-
|
|
39
|
-
### Return with proof
|
|
40
|
-
|
|
41
|
-
Writes stay scoped, and completion requires validation evidence. Every completed
|
|
42
|
-
run can return a concise Speed / Cost / Proof debrief.
|
|
43
|
-
|
|
44
|
-
## Designed to coexist with OpenCode
|
|
45
|
-
|
|
46
|
-
Sortie-dogs adds a workflow to your existing setup rather than replacing it.
|
|
47
|
-
|
|
48
|
-
- It does not disable OpenCode's native agents or replace standard roles such as
|
|
49
|
-
`build`, `plan`, `explore`, or `general`.
|
|
50
|
-
- Ordinary sessions are not automatically converted into Sortie workflows.
|
|
51
|
-
- Project-local initialization is the recommended setup and does not change
|
|
52
|
-
user settings.
|
|
53
|
-
- Global runtime availability and cross-project reflection require separate,
|
|
54
|
-
explicit opt-in. Reflection is disabled by default.
|
|
55
|
-
- Unknown or user-owned runtime files are preserved rather than overwritten.
|
|
56
|
-
- Manual removal targets only known Sortie-owned runtime assets.
|
|
57
|
-
|
|
58
|
-
Use OpenCode normally. Invoke the pack only when you want it.
|
|
59
|
-
|
|
60
|
-
## Quick start
|
|
61
|
-
|
|
62
|
-
Install the public npm package in the project and generate the project-local
|
|
63
|
-
OpenCode runtime files:
|
|
23
|
+
Guides: [日本語](docs/guide-ja.md) · [简体中文](docs/guide-zh-CN.md) · [CLI testing](docs/cli-testing.md)
|
|
24
|
+
|
|
25
|
+
Release: [v0.9.10](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.9.10)
|
|
26
|
+
|
|
27
|
+
## Why Sortie-dogs?
|
|
28
|
+
|
|
29
|
+
### Invisible until invited
|
|
30
|
+
|
|
31
|
+
Use normal OpenCode normally. Sortie activates only for `/sortie` or
|
|
32
|
+
`dog-coordinator`; it does not disable or replace OpenCode's standard agents.
|
|
33
|
+
|
|
34
|
+
### Spend strong models only where they matter
|
|
35
|
+
|
|
36
|
+
Lower-cost models handle bounded retrieval and parallel volume work. Stronger
|
|
37
|
+
models are reserved for implementation, escalation, and independent review.
|
|
38
|
+
|
|
39
|
+
### Return with proof
|
|
40
|
+
|
|
41
|
+
Writes stay scoped, and completion requires validation evidence. Every completed
|
|
42
|
+
run can return a concise Speed / Cost / Proof debrief.
|
|
43
|
+
|
|
44
|
+
## Designed to coexist with OpenCode
|
|
45
|
+
|
|
46
|
+
Sortie-dogs adds a workflow to your existing setup rather than replacing it.
|
|
47
|
+
|
|
48
|
+
- It does not disable OpenCode's native agents or replace standard roles such as
|
|
49
|
+
`build`, `plan`, `explore`, or `general`.
|
|
50
|
+
- Ordinary sessions are not automatically converted into Sortie workflows.
|
|
51
|
+
- Project-local initialization is the recommended setup and does not change
|
|
52
|
+
user settings.
|
|
53
|
+
- Global runtime availability and cross-project reflection require separate,
|
|
54
|
+
explicit opt-in. Reflection is disabled by default.
|
|
55
|
+
- Unknown or user-owned runtime files are preserved rather than overwritten.
|
|
56
|
+
- Manual removal targets only known Sortie-owned runtime assets.
|
|
57
|
+
|
|
58
|
+
Use OpenCode normally. Invoke the pack only when you want it.
|
|
59
|
+
|
|
60
|
+
## Quick start
|
|
61
|
+
|
|
62
|
+
Install the public npm package in the project and generate the project-local
|
|
63
|
+
OpenCode runtime files:
|
|
64
64
|
|
|
65
65
|
```sh
|
|
66
66
|
npm install --save-dev sortie-dogs
|
|
67
|
-
npx sortie-dogs init .
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
This is the recommended setup. Runtime assets stay project-local.
|
|
71
|
-
|
|
72
|
-
Installing the runtime assets does not load the plugin, and without the plugin
|
|
73
|
-
every role runs on whichever model the caller happened to use. Add the package
|
|
74
|
-
to the `plugin` array in the project's `.opencode/opencode.json`:
|
|
67
|
+
npx sortie-dogs init .
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This is the recommended setup. Runtime assets stay project-local.
|
|
71
|
+
|
|
72
|
+
Installing the runtime assets does not load the plugin, and without the plugin
|
|
73
|
+
every role runs on whichever model the caller happened to use. Add the package
|
|
74
|
+
to the `plugin` array in the project's `.opencode/opencode.json`:
|
|
75
75
|
|
|
76
76
|
```json
|
|
77
77
|
{
|
|
@@ -82,8 +82,8 @@ to the `plugin` array in the project's `.opencode/opencode.json`:
|
|
|
82
82
|
Restart OpenCode afterwards. A `plugin` entry must name the package, not a
|
|
83
83
|
subpath: `sortie-dogs/plugin` is an import specifier, not a plugin specifier.
|
|
84
84
|
|
|
85
|
-
`dog-coordinator` defaults to `openai/gpt-5.6-terra` with the `high` variant; `dog-scout` defaults to
|
|
86
|
-
`openai/gpt-5.6-luna`. To pin either role to another model, save this
|
|
85
|
+
`dog-coordinator` defaults to `openai/gpt-5.6-terra` with the `high` variant; `dog-scout` defaults to
|
|
86
|
+
`openai/gpt-5.6-luna`. To pin either role to another model, save this
|
|
87
87
|
as `.opencode/sortie-dogs.json`:
|
|
88
88
|
|
|
89
89
|
```json
|
|
@@ -166,83 +166,83 @@ Optional settings in `.opencode/sortie-dogs.json`:
|
|
|
166
166
|
{
|
|
167
167
|
"operationManifestPath": "operation-manifest.json",
|
|
168
168
|
"handoffPaths": ["handoff.json"],
|
|
169
|
-
"readOnlyTools": ["my_mcp_search"],
|
|
170
|
-
"dedicatedWorkerModel": { "model": "provider/model", "variant": "deep" },
|
|
171
|
-
"continuation": { "enabled": true, "maxAutoContinues": 10 },
|
|
172
|
-
"reflection": {
|
|
173
|
-
"enabled": false,
|
|
174
|
-
"layers": { "run": true, "project": true, "global": false },
|
|
175
|
-
"maxInjectedTokens": 500
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
The same schema may be saved globally as
|
|
181
|
-
`~/.config/opencode/sortie-dogs.json` (on Windows,
|
|
182
|
-
`%USERPROFILE%\.config\opencode\sortie-dogs.json`). Precedence is built-in
|
|
183
|
-
defaults, global file, project file, `SORTIE_DOGS_CONFIG`, then plugin factory
|
|
184
|
-
options. OpenCode plugin normalization may omit factory options, so use the
|
|
185
|
-
global file for durable global settings.
|
|
169
|
+
"readOnlyTools": ["my_mcp_search"],
|
|
170
|
+
"dedicatedWorkerModel": { "model": "provider/model", "variant": "deep" },
|
|
171
|
+
"continuation": { "enabled": true, "maxAutoContinues": 10 },
|
|
172
|
+
"reflection": {
|
|
173
|
+
"enabled": false,
|
|
174
|
+
"layers": { "run": true, "project": true, "global": false },
|
|
175
|
+
"maxInjectedTokens": 500
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The same schema may be saved globally as
|
|
181
|
+
`~/.config/opencode/sortie-dogs.json` (on Windows,
|
|
182
|
+
`%USERPROFILE%\.config\opencode\sortie-dogs.json`). Precedence is built-in
|
|
183
|
+
defaults, global file, project file, `SORTIE_DOGS_CONFIG`, then plugin factory
|
|
184
|
+
options. OpenCode plugin normalization may omit factory options, so use the
|
|
185
|
+
global file for durable global settings.
|
|
186
186
|
|
|
187
187
|
- `operationManifestPath` moves the manifest; the path is project-relative.
|
|
188
|
-
- `handoffPaths` lists the handoff files the plugin inspects. A worker can only
|
|
188
|
+
- `handoffPaths` lists the handoff files the plugin inspects. A worker can only
|
|
189
189
|
bind after one of these files passes inspection, so an empty list disables
|
|
190
190
|
binding entirely. Relative entries are also candidate-relative in a nested
|
|
191
191
|
repository: a child candidate may use its own `handoff.json` while OpenCode is
|
|
192
192
|
opened at the parent workspace. For operational work the coordinator creates
|
|
193
193
|
that valid handoff before dispatch and sends its exact absolute path; the
|
|
194
|
-
binding child must use the built-in Read tool on it immediately before bind.
|
|
195
|
-
New coordinator contracts are emitted under the candidate-relative
|
|
196
|
-
`.sortie-dogs/contracts/` directory as `handoff.<id>.json` and
|
|
197
|
-
`<id>.operation-manifest.json`. The directory is ignored by this repository's
|
|
198
|
-
`.gitignore`; legacy root/scoped paths and configured custom paths remain
|
|
199
|
-
readable and preflight-compatible, but are never moved or deleted.
|
|
200
|
-
Remove the directory only when no Sortie run is active.
|
|
194
|
+
binding child must use the built-in Read tool on it immediately before bind.
|
|
195
|
+
New coordinator contracts are emitted under the candidate-relative
|
|
196
|
+
`.sortie-dogs/contracts/` directory as `handoff.<id>.json` and
|
|
197
|
+
`<id>.operation-manifest.json`. The directory is ignored by this repository's
|
|
198
|
+
`.gitignore`; legacy root/scoped paths and configured custom paths remain
|
|
199
|
+
readable and preflight-compatible, but are never moved or deleted.
|
|
200
|
+
Remove the directory only when no Sortie run is active.
|
|
201
201
|
- `readOnlyTools` adds host-specific tool names that never change files, such as
|
|
202
202
|
MCP tools. Unknown tools are denied for a bound session by default.
|
|
203
|
-
- `dedicatedWorkerModel` selects the serial implementation target used by
|
|
204
|
-
`implementation`, `remediation`, `blocker-resolution`, `sol-worker-mk2a2`, and
|
|
205
|
-
`dog-worker`. It defaults to `openai/gpt-5.6-sol` with variant `medium`.
|
|
206
|
-
The installed `dog-luna-worker` fabric route remains fixed to
|
|
207
|
-
`openai/gpt-5.6-luna` with variant `max`; pointing the serial target at that
|
|
203
|
+
- `dedicatedWorkerModel` selects the serial implementation target used by
|
|
204
|
+
`implementation`, `remediation`, `blocker-resolution`, `sol-worker-mk2a2`, and
|
|
205
|
+
`dog-worker`. It defaults to `openai/gpt-5.6-sol` with variant `medium`.
|
|
206
|
+
The installed `dog-luna-worker` fabric route remains fixed to
|
|
207
|
+
`openai/gpt-5.6-luna` with variant `max`; pointing the serial target at that
|
|
208
208
|
Luna model is invalid because it would collapse the two route identities. The
|
|
209
209
|
coordinator dispatches this role only for a ready descriptor of a prepared
|
|
210
|
-
`luna-fabric` run; a `sol-serial` run keeps `dog-worker`.
|
|
210
|
+
`luna-fabric` run; a `sol-serial` run keeps `dog-worker`.
|
|
211
211
|
- `continuation` bounds the batch loop. After a terminal unit and its checkpoint,
|
|
212
212
|
`dog-coordinator` calls `sortie_compact_and_continue`, which compacts the run
|
|
213
213
|
and resumes the same root session on the next independent unit. Only a root
|
|
214
214
|
`dog-coordinator` session is ever resumed: a child session is never promoted and
|
|
215
215
|
another coordinator is never adopted. Set `enabled` to `false` to keep every
|
|
216
|
-
batch manual, lower `maxAutoContinues` (default and maximum `10`) to change the
|
|
217
|
-
ceiling, and set `summarizeModel` to override the latest coordinator
|
|
218
|
-
model used for compaction. Normal OpenCode auto-compaction keeps the
|
|
219
|
-
host's auto-continue behavior; Sortie suppresses it only while its own
|
|
220
|
-
explicitly queued rollover owns the resume.
|
|
221
|
-
Every terminal root-coordinator response that does not resume another unit
|
|
222
|
-
compacts without auto-continuing, so completed tool output is not carried into
|
|
223
|
-
the next user request.
|
|
224
|
-
- `reflection` is an opt-in process-prevention companion for an activated root
|
|
225
|
-
`dog-coordinator`. It is disabled by default. Run and project layers default
|
|
226
|
-
to enabled after opt-in; the cross-project global storage layer remains
|
|
227
|
-
disabled unless explicitly enabled. Child and non-coordinator sessions fail
|
|
228
|
-
closed, and `SORTIE_REFLECTION=0` is an immediate kill switch. The coordinator
|
|
229
|
-
injects the governing `REFLECTION_POLICY` only while reflection is enabled.
|
|
230
|
-
`maxInjectedTokens` budgets the dynamic `SORTIE_PROCESS_REFLECTIONS` heading
|
|
231
|
-
and persisted entry lines; the policy is outside that entry budget.
|
|
232
|
-
The coordinator
|
|
233
|
-
evaluates it only after a resolved blocker/review defect and at a terminal
|
|
234
|
-
unit, with a maximum of three records per run; routine bugs and external
|
|
235
|
-
failures are never journaled.
|
|
236
|
-
|
|
237
|
-
## Example run
|
|
216
|
+
batch manual, lower `maxAutoContinues` (default and maximum `10`) to change the
|
|
217
|
+
ceiling, and set `summarizeModel` to override the latest coordinator
|
|
218
|
+
model used for compaction. Normal OpenCode auto-compaction keeps the
|
|
219
|
+
host's auto-continue behavior; Sortie suppresses it only while its own
|
|
220
|
+
explicitly queued rollover owns the resume.
|
|
221
|
+
Every terminal root-coordinator response that does not resume another unit
|
|
222
|
+
compacts without auto-continuing, so completed tool output is not carried into
|
|
223
|
+
the next user request.
|
|
224
|
+
- `reflection` is an opt-in process-prevention companion for an activated root
|
|
225
|
+
`dog-coordinator`. It is disabled by default. Run and project layers default
|
|
226
|
+
to enabled after opt-in; the cross-project global storage layer remains
|
|
227
|
+
disabled unless explicitly enabled. Child and non-coordinator sessions fail
|
|
228
|
+
closed, and `SORTIE_REFLECTION=0` is an immediate kill switch. The coordinator
|
|
229
|
+
injects the governing `REFLECTION_POLICY` only while reflection is enabled.
|
|
230
|
+
`maxInjectedTokens` budgets the dynamic `SORTIE_PROCESS_REFLECTIONS` heading
|
|
231
|
+
and persisted entry lines; the policy is outside that entry budget.
|
|
232
|
+
The coordinator
|
|
233
|
+
evaluates it only after a resolved blocker/review defect and at a terminal
|
|
234
|
+
unit, with a maximum of three records per run; routine bugs and external
|
|
235
|
+
failures are never journaled.
|
|
236
|
+
|
|
237
|
+
## Example run
|
|
238
238
|
|
|
239
239
|
An illustrative low-risk run stays bounded and reports its gates:
|
|
240
240
|
|
|
241
241
|
```text
|
|
242
242
|
You: /sortie Add the requested behavior
|
|
243
243
|
dog-coordinator: manifest confirmed
|
|
244
|
-
dog-scout: skipped — no concrete evidence gap
|
|
245
|
-
dog-worker: implementation complete
|
|
244
|
+
dog-scout: skipped — no concrete evidence gap
|
|
245
|
+
dog-worker: implementation complete
|
|
246
246
|
validation: npm test — PASS
|
|
247
247
|
review: skipped — low risk
|
|
248
248
|
dog-coordinator: completion evidence accepted
|
|
@@ -252,8 +252,8 @@ dog-coordinator: completion evidence accepted
|
|
|
252
252
|
|
|
253
253
|
1. **Brief and plan** — `dog-coordinator` turns the request into acceptance
|
|
254
254
|
criteria, a write manifest, and validation requirements.
|
|
255
|
-
2. **Optional scout** — one bounded, read-only investigation runs only for a
|
|
256
|
-
concrete pre-worker evidence gap.
|
|
255
|
+
2. **Optional scout** — one bounded, read-only investigation runs only for a
|
|
256
|
+
concrete pre-worker evidence gap.
|
|
257
257
|
3. **Dedicated worker** — the dedicated worker implements only the approved
|
|
258
258
|
manifest and also owns scoped remediation or blocker resolution.
|
|
259
259
|
4. **Canonical validation** — the declared test or build command must produce
|
|
@@ -305,16 +305,16 @@ untouched.
|
|
|
305
305
|
|
|
306
306
|
## Model routing
|
|
307
307
|
|
|
308
|
-
Default routes split work by required capability and repeated-context cost.
|
|
309
|
-
Sortie-dogs keeps retrieval on Luna, coordinator routing on Terra, and independent
|
|
310
|
-
review on Sol unless the host declares another target.
|
|
308
|
+
Default routes split work by required capability and repeated-context cost.
|
|
309
|
+
Sortie-dogs keeps retrieval on Luna, coordinator routing on Terra, and independent
|
|
310
|
+
review on Sol unless the host declares another target.
|
|
311
311
|
|
|
312
|
-
`dog-coordinator` defaults to `openai/gpt-5.6-terra` with the `high` variant. Coordinator quality controls
|
|
313
|
-
planning and forward progress, so Terra High is the default balance between capability and cost.
|
|
314
|
-
Project or global `modelRouting` can override
|
|
315
|
-
this default. If the host proves Terra unavailable,
|
|
316
|
-
the existing availability policy uses a configured free-tier fallback when present
|
|
317
|
-
and otherwise preserves the session model.
|
|
312
|
+
`dog-coordinator` defaults to `openai/gpt-5.6-terra` with the `high` variant. Coordinator quality controls
|
|
313
|
+
planning and forward progress, so Terra High is the default balance between capability and cost.
|
|
314
|
+
Project or global `modelRouting` can override
|
|
315
|
+
this default. If the host proves Terra unavailable,
|
|
316
|
+
the existing availability policy uses a configured free-tier fallback when present
|
|
317
|
+
and otherwise preserves the session model.
|
|
318
318
|
|
|
319
319
|
`dog-scout` defaults to `openai/gpt-5.6-luna` with the `high` variant, since
|
|
320
320
|
gathering bounded evidence is retrieval rather than reasoning and that tier is
|
|
@@ -322,46 +322,46 @@ where the curve gives the most per unit of cost. Nobody selects a model for a
|
|
|
322
322
|
session the loop spawns, which is why delegated roles carry defaults and the
|
|
323
323
|
coordinator does not. Project-local routing can override this default.
|
|
324
324
|
|
|
325
|
-
The `implementation`, `remediation`, `blocker-resolution`, `sol-worker-mk2a2`,
|
|
326
|
-
and `dog-worker` roles always use the stable serial target,
|
|
327
|
-
`openai/gpt-5.6-sol` with the `medium` variant. `dedicatedWorkerModel` may move
|
|
328
|
-
that serial target when a host cannot serve it. The installed `dog-luna-worker`
|
|
329
|
-
route is separately fixed to `openai/gpt-5.6-luna` with the `max` variant. Its
|
|
325
|
+
The `implementation`, `remediation`, `blocker-resolution`, `sol-worker-mk2a2`,
|
|
326
|
+
and `dog-worker` roles always use the stable serial target,
|
|
327
|
+
`openai/gpt-5.6-sol` with the `medium` variant. `dedicatedWorkerModel` may move
|
|
328
|
+
that serial target when a host cannot serve it. The installed `dog-luna-worker`
|
|
329
|
+
route is separately fixed to `openai/gpt-5.6-luna` with the `max` variant. Its
|
|
330
330
|
shared worker contract requires one validated fabric descriptor: the coordinator
|
|
331
|
-
admits a v0.8 DAG contract with `sortie_admit_luna_fabric`, prepares it with
|
|
332
|
-
`sortie_prepare_luna_fabric`, and materializes only the current ready wave, with
|
|
333
|
-
at most five distinct Luna units. The complete DAG may contain up to 64 units.
|
|
334
|
-
After every active artifact is verified, `sortie_advance_luna_fabric_wave`
|
|
335
|
-
integrates them into a runtime-owned hidden candidate, cleans those worktrees,
|
|
336
|
-
and creates fresh worktrees from that exact snapshot. After the final wave,
|
|
337
|
-
`sortie_validate_luna_fabric_candidate` runs canonical validation once and
|
|
338
|
-
`sortie_accept_luna_fabric_candidate` records review before one target CAS.
|
|
339
|
-
Declared shared-path ownership serializes overlapping units
|
|
340
|
-
across waves; unowned overlap or any admission defect routes the whole job back
|
|
341
|
-
to one `dog-worker`. The fabric never duplicates one unit across lanes.
|
|
342
|
-
`modelRouting` cannot replace either fixed
|
|
343
|
-
route, and a serial override naming the Luna fabric model is invalid rather than
|
|
344
|
-
silently collapsing both identities. Version 0.7.0 routed `dog-worker` to Luna
|
|
345
|
-
Max; v0.8 intentionally preserves that history while splitting stable Sol and
|
|
346
|
-
fabric Luna roles. Other explicit routes try the preferred target, then ordered
|
|
347
|
-
fallbacks. Roles without a built-in default or explicit route keep OpenCode's
|
|
348
|
-
already selected model.
|
|
331
|
+
admits a v0.8 DAG contract with `sortie_admit_luna_fabric`, prepares it with
|
|
332
|
+
`sortie_prepare_luna_fabric`, and materializes only the current ready wave, with
|
|
333
|
+
at most five distinct Luna units. The complete DAG may contain up to 64 units.
|
|
334
|
+
After every active artifact is verified, `sortie_advance_luna_fabric_wave`
|
|
335
|
+
integrates them into a runtime-owned hidden candidate, cleans those worktrees,
|
|
336
|
+
and creates fresh worktrees from that exact snapshot. After the final wave,
|
|
337
|
+
`sortie_validate_luna_fabric_candidate` runs canonical validation once and
|
|
338
|
+
`sortie_accept_luna_fabric_candidate` records review before one target CAS.
|
|
339
|
+
Declared shared-path ownership serializes overlapping units
|
|
340
|
+
across waves; unowned overlap or any admission defect routes the whole job back
|
|
341
|
+
to one `dog-worker`. The fabric never duplicates one unit across lanes.
|
|
342
|
+
`modelRouting` cannot replace either fixed
|
|
343
|
+
route, and a serial override naming the Luna fabric model is invalid rather than
|
|
344
|
+
silently collapsing both identities. Version 0.7.0 routed `dog-worker` to Luna
|
|
345
|
+
Max; v0.8 intentionally preserves that history while splitting stable Sol and
|
|
346
|
+
fabric Luna roles. Other explicit routes try the preferred target, then ordered
|
|
347
|
+
fallbacks. Roles without a built-in default or explicit route keep OpenCode's
|
|
348
|
+
already selected model.
|
|
349
349
|
|
|
350
350
|
`dog-reviewer` and `dog-advisor` must never inherit the caller's model, because
|
|
351
351
|
review and strategy lose their value when they run on the model that produced
|
|
352
352
|
the candidate. Both default to `anthropic/claude-opus-5` when the catalog
|
|
353
353
|
declares it, and otherwise fall back to `openai/gpt-5.6-sol` with the `xhigh`
|
|
354
|
-
variant. That fallback uses higher effort than the Sol Medium worker because
|
|
355
|
-
review has to be able to reject work the worker just produced. Moving
|
|
356
|
-
`dedicatedWorkerModel` does not change consultation policy. Nothing here requires
|
|
357
|
-
a particular vendor: both roles stay fully configurable, so declare whichever
|
|
358
|
-
model you can actually serve.
|
|
354
|
+
variant. That fallback uses higher effort than the Sol Medium worker because
|
|
355
|
+
review has to be able to reject work the worker just produced. Moving
|
|
356
|
+
`dedicatedWorkerModel` does not change consultation policy. Nothing here requires
|
|
357
|
+
a particular vendor: both roles stay fully configurable, so declare whichever
|
|
358
|
+
model you can actually serve.
|
|
359
359
|
|
|
360
360
|
```json
|
|
361
361
|
{
|
|
362
362
|
"modelRouting": {
|
|
363
|
-
"dog-coordinator": {
|
|
364
|
-
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "max" }
|
|
363
|
+
"dog-coordinator": {
|
|
364
|
+
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "max" }
|
|
365
365
|
},
|
|
366
366
|
"dog-scout": {
|
|
367
367
|
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "high" }
|
|
@@ -375,8 +375,8 @@ model you can actually serve.
|
|
|
375
375
|
}
|
|
376
376
|
},
|
|
377
377
|
"modelCatalog": {
|
|
378
|
-
"project": [
|
|
379
|
-
{ "model": "openai/gpt-5.6-sol", "variants": ["medium", "xhigh"] },
|
|
378
|
+
"project": [
|
|
379
|
+
{ "model": "openai/gpt-5.6-sol", "variants": ["medium", "xhigh"] },
|
|
380
380
|
{ "model": "openai/gpt-5.6-luna", "variants": ["max", "high"] },
|
|
381
381
|
{ "model": "anthropic/claude-opus-5" }
|
|
382
382
|
]
|
|
@@ -397,52 +397,52 @@ coordinator. `dog-reviewer` independently checks high-risk candidates after
|
|
|
397
397
|
canonical validation. Neither role implements, stages, commits, or acts as a
|
|
398
398
|
user-facing worker.
|
|
399
399
|
|
|
400
|
-
## Optional global availability
|
|
401
|
-
|
|
402
|
-
If you intentionally want the Sortie roles available across projects, install
|
|
403
|
-
the CLI and runtime assets globally:
|
|
404
|
-
|
|
405
|
-
```sh
|
|
406
|
-
npm install --global sortie-dogs
|
|
407
|
-
sortie-dogs init --global
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
This writes canonical Sortie runtime assets to OpenCode's global configuration;
|
|
411
|
-
it does not make project-local initialization global. Load the plugin from the
|
|
412
|
-
global `~/.config/opencode/opencode.json` when using these assets:
|
|
413
|
-
|
|
414
|
-
```json
|
|
415
|
-
{
|
|
416
|
-
"plugin": ["sortie-dogs"]
|
|
417
|
-
}
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
Project-local configuration and plugin loading remain available when a project
|
|
421
|
-
needs its own settings or dependency.
|
|
422
|
-
|
|
423
|
-
## Updates and migration
|
|
400
|
+
## Optional global availability
|
|
401
|
+
|
|
402
|
+
If you intentionally want the Sortie roles available across projects, install
|
|
403
|
+
the CLI and runtime assets globally:
|
|
404
|
+
|
|
405
|
+
```sh
|
|
406
|
+
npm install --global sortie-dogs
|
|
407
|
+
sortie-dogs init --global
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
This writes canonical Sortie runtime assets to OpenCode's global configuration;
|
|
411
|
+
it does not make project-local initialization global. Load the plugin from the
|
|
412
|
+
global `~/.config/opencode/opencode.json` when using these assets:
|
|
413
|
+
|
|
414
|
+
```json
|
|
415
|
+
{
|
|
416
|
+
"plugin": ["sortie-dogs"]
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Project-local configuration and plugin loading remain available when a project
|
|
421
|
+
needs its own settings or dependency.
|
|
422
|
+
|
|
423
|
+
## Updates and migration
|
|
424
424
|
|
|
425
425
|
After replacing the dependency with a newer release asset, run:
|
|
426
426
|
|
|
427
427
|
```sh
|
|
428
|
-
npx sortie-dogs init .
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
After initialization, fully restart the OpenCode host before resuming a coordinator or opening a
|
|
432
|
-
fresh session. Plugin modules are process-scoped, so a new session alone cannot load the update.
|
|
433
|
-
|
|
434
|
-
`init` is idempotent. It updates files owned by Sortie-dogs, migrates recognized
|
|
428
|
+
npx sortie-dogs init .
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
After initialization, fully restart the OpenCode host before resuming a coordinator or opening a
|
|
432
|
+
fresh session. Plugin modules are process-scoped, so a new session alone cannot load the update.
|
|
433
|
+
|
|
434
|
+
`init` is idempotent. It updates files owned by Sortie-dogs, migrates recognized
|
|
435
435
|
older runtime files, and records the installed version in
|
|
436
436
|
`.opencode/sortie-dogs.version`. Conflicting or unrecognized files remain
|
|
437
437
|
untouched and initialization stops safely. User-owned configuration—including
|
|
438
438
|
`.opencode/sortie-dogs.json`—and standard OpenCode files are preserved.
|
|
439
439
|
|
|
440
|
-
## Maintainer releases
|
|
441
|
-
|
|
442
|
-
The [release batch guide](docs/release-batch.md) covers fixed-tarball CLI verification,
|
|
443
|
-
global application, resumable GitHub publication, and manual npm publication checks.
|
|
444
|
-
|
|
445
|
-
## Safe manual removal
|
|
440
|
+
## Maintainer releases
|
|
441
|
+
|
|
442
|
+
The [release batch guide](docs/release-batch.md) covers fixed-tarball CLI verification,
|
|
443
|
+
global application, resumable GitHub publication, and manual npm publication checks.
|
|
444
|
+
|
|
445
|
+
## Safe manual removal
|
|
446
446
|
|
|
447
447
|
There is no supported Sortie-dogs uninstall command. Remove the npm dependency
|
|
448
448
|
separately, then follow the [safe manual removal guide](docs/uninstall.md) to
|
package/dist/asset-version.d.ts
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Version of the installable runtime assets. Kept in its own module so the plugin can compare an
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
|
-
export declare const RUNTIME_ASSET_VERSION = "0.3.
|
|
5
|
+
export declare const RUNTIME_ASSET_VERSION = "0.3.86-codegen-proof-v1";
|
|
6
6
|
export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION;
|
package/dist/asset-version.js
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Version of the installable runtime assets. Kept in its own module so the plugin can compare an
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
|
-
export const RUNTIME_ASSET_VERSION = "0.3.
|
|
5
|
+
export const RUNTIME_ASSET_VERSION = "0.3.86-codegen-proof-v1";
|
package/dist/core/goal-bound.js
CHANGED
|
@@ -119,7 +119,7 @@ export function reduceGoalFlight(records) {
|
|
|
119
119
|
continue;
|
|
120
120
|
requireState(instant(event.at), "invalid", "Goal event timestamp is invalid.");
|
|
121
121
|
if (event.kind === "goal.accepted") {
|
|
122
|
-
requireState(state.goal_id === null || state.phase === "terminal", "transition", "An active goal already owns this root.");
|
|
122
|
+
requireState(state.goal_id === null || state.phase === "terminal" || state.phase === "stopped", "transition", "An active goal already owns this root.");
|
|
123
123
|
requireState(text(event.goal_id) && HASH.test(event.acceptance_fingerprint) && text(event.origin_user_message_id) &&
|
|
124
124
|
text(event.origin_session_id) && text(event.selected_agent) && event.budget.max_units > 0 &&
|
|
125
125
|
validAcceptanceContract(event.acceptance_contract), "invalid", "Accepted goal identity is incomplete.");
|
|
@@ -221,7 +221,7 @@ export function reduceGoalFlight(records) {
|
|
|
221
221
|
event.consumed >= 0 && event.consumed <= event.limit && event.operation_id.length > 0 && event.evidence_key.length > 0, "invalid", "Validation admission is malformed.");
|
|
222
222
|
if (event.decision === "ALLOW") {
|
|
223
223
|
requireState(event.scope !== null && event.consumed === state.validation_budget.consumed + 1 &&
|
|
224
|
-
(state.validation_budget.limit === null ||
|
|
224
|
+
(state.validation_budget.limit === null || event.limit >= state.validation_budget.limit) &&
|
|
225
225
|
!state.validation_budget.evidence_keys.includes(event.evidence_key) &&
|
|
226
226
|
!state.validation_budget.reservations.some((entry) => entry.reservation_id === event.reservation_id), "budget", "Validation admission is stale, duplicated, or exhausted.");
|
|
227
227
|
state = { ...state, validation_budget: { consumed: event.consumed, limit: event.limit,
|
|
@@ -2,38 +2,38 @@ import { goalFingerprint } from "./goal-bound.js";
|
|
|
2
2
|
/** Shared planner guidance and admission enums; no inferred acceptance or dispatch authority. */
|
|
3
3
|
export const GOAL_DELIVERY_INTENTS = ["design", "registration", "implementation", "repair", "controlled-change"];
|
|
4
4
|
export const GOAL_DELIVERY_MODES = ["planning-only", "mvp-first", "repair-first", "controlled-change"];
|
|
5
|
-
export const GOAL_DECLARATION_FORMAT = `Declare a goal once, then reference it with goal_declaration_path in the Task prompt.
|
|
6
|
-
The referenced JSON may contain shared defaults and a criteria array; the host expands them privately.
|
|
7
|
-
An inline ext["sortie-dogs/goal-declaration"] in the registered handoff is also supported.
|
|
8
|
-
Existing accepted goals need no repeated declaration; budget-only revisions retain their criteria.
|
|
9
|
-
Legacy flat goal_* fields remain supported. No need to rewrite unrelated files or repeat common fields for each criterion.
|
|
10
|
-
delivery_intent must be exactly one of: ${GOAL_DELIVERY_INTENTS.join(" | ")}. Never use prose or a boolean.
|
|
11
|
-
delivery_mode is a separate optional enum: ${GOAL_DELIVERY_MODES.join(" | ")}.
|
|
12
|
-
Use flat key: value lines. Each criterion begins with its own goal_criterion_id: line.
|
|
13
|
-
For legacy flat input each criterion has a goal_criterion_id line. Prefer shared JSON defaults for multiple criteria.
|
|
14
|
-
Replace every placeholder with the accepted task's actual value; preserve its acceptance and validation:
|
|
15
|
-
goal_acceptance_fingerprint: <sha256: followed by exactly 64 lowercase hexadecimal characters>
|
|
16
|
-
delivery_intent: implementation
|
|
17
|
-
delivery_mode: mvp-first
|
|
18
|
-
usable_path_established: false
|
|
19
|
-
controlled_change: false
|
|
20
|
-
goal_budget_units: <accepted positive integer>
|
|
21
|
-
goal_criterion_id: <stable criterion id>
|
|
22
|
-
goal_target: <requested behavior>
|
|
23
|
-
goal_entrypoint: <real entrypoint>
|
|
24
|
-
goal_workload: <requested workload>
|
|
25
|
-
goal_oracle_coverage: ["<actual oracle>"]
|
|
26
|
-
goal_build_boundary: <included | excluded | not-applicable>
|
|
27
|
-
goal_source: <fixed source label>
|
|
28
|
-
goal_candidate: <fixed candidate label>
|
|
29
|
-
goal_source_binding: current-protected
|
|
30
|
-
goal_candidate_binding: current-protected
|
|
31
|
-
goal_fixture: <actual fixture identity>
|
|
32
|
-
goal_proof_scope: requested-full
|
|
33
|
-
goal_expected_outcome: pass
|
|
34
|
-
goal_validation_command: <exact operation manifest validation command>
|
|
35
|
-
The example's implementation/mvp-first selections apply only to an implementation without its usable path;
|
|
36
|
-
select other enum values only from the accepted request. A declaration rejection launches no child.
|
|
5
|
+
export const GOAL_DECLARATION_FORMAT = `Declare a goal once, then reference it with goal_declaration_path in the Task prompt.
|
|
6
|
+
The referenced JSON may contain shared defaults and a criteria array; the host expands them privately.
|
|
7
|
+
An inline ext["sortie-dogs/goal-declaration"] in the registered handoff is also supported.
|
|
8
|
+
Existing accepted goals need no repeated declaration; budget-only revisions retain their criteria.
|
|
9
|
+
Legacy flat goal_* fields remain supported. No need to rewrite unrelated files or repeat common fields for each criterion.
|
|
10
|
+
delivery_intent must be exactly one of: ${GOAL_DELIVERY_INTENTS.join(" | ")}. Never use prose or a boolean.
|
|
11
|
+
delivery_mode is a separate optional enum: ${GOAL_DELIVERY_MODES.join(" | ")}.
|
|
12
|
+
Use flat key: value lines. Each criterion begins with its own goal_criterion_id: line.
|
|
13
|
+
For legacy flat input each criterion has a goal_criterion_id line. Prefer shared JSON defaults for multiple criteria.
|
|
14
|
+
Replace every placeholder with the accepted task's actual value; preserve its acceptance and validation:
|
|
15
|
+
goal_acceptance_fingerprint: <sha256: followed by exactly 64 lowercase hexadecimal characters>
|
|
16
|
+
delivery_intent: implementation
|
|
17
|
+
delivery_mode: mvp-first
|
|
18
|
+
usable_path_established: false
|
|
19
|
+
controlled_change: false
|
|
20
|
+
goal_budget_units: <accepted positive integer>
|
|
21
|
+
goal_criterion_id: <stable criterion id>
|
|
22
|
+
goal_target: <requested behavior>
|
|
23
|
+
goal_entrypoint: <real entrypoint>
|
|
24
|
+
goal_workload: <requested workload>
|
|
25
|
+
goal_oracle_coverage: ["<actual oracle>"]
|
|
26
|
+
goal_build_boundary: <included | excluded | not-applicable>
|
|
27
|
+
goal_source: <fixed source label>
|
|
28
|
+
goal_candidate: <fixed candidate label>
|
|
29
|
+
goal_source_binding: current-protected
|
|
30
|
+
goal_candidate_binding: current-protected
|
|
31
|
+
goal_fixture: <actual fixture identity>
|
|
32
|
+
goal_proof_scope: requested-full
|
|
33
|
+
goal_expected_outcome: pass
|
|
34
|
+
goal_validation_command: <exact operation manifest validation command>
|
|
35
|
+
The example's implementation/mvp-first selections apply only to an implementation without its usable path;
|
|
36
|
+
select other enum values only from the accepted request. A declaration rejection launches no child.
|
|
37
37
|
Repair the Task prompt's named fields, not unrelated files; retry only with the corrected declaration.`;
|
|
38
38
|
/** Normalize a shared declaration without guessing acceptance, coverage, delivery, or validation. */
|
|
39
39
|
export function expandGoalDeclaration(value) {
|
|
@@ -824,6 +824,16 @@ export class RunFlightLedger {
|
|
|
824
824
|
throw new RunFlightLedgerError("conflict", "Ledger lock remained busy.");
|
|
825
825
|
try {
|
|
826
826
|
const records = await this.#readGoalRecords();
|
|
827
|
+
if (event.kind === "goal.accepted") {
|
|
828
|
+
const prior = records.find(({ event: stored }) => stored.kind === "goal.accepted" &&
|
|
829
|
+
stored.origin_user_message_id === event.origin_user_message_id);
|
|
830
|
+
if (prior !== undefined) {
|
|
831
|
+
if (recordHash(1, null, { ...event, at: prior.event.at }) !== recordHash(1, null, prior.event)) {
|
|
832
|
+
throw new RunFlightLedgerError("transition", "Accepted goal conflicts with its durable user message identity.");
|
|
833
|
+
}
|
|
834
|
+
return reduceGoalFlight(records);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
827
837
|
if (event.kind === "goal.reported" && records.some(({ event: stored }) => stored.kind === "goal.reported" &&
|
|
828
838
|
stored.goal_id === event.goal_id && stored.report?.terminal_key === event.report.terminal_key)) {
|
|
829
839
|
return reduceGoalFlight(records);
|