sortie-dogs 0.2.6 → 0.2.7

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 CHANGED
@@ -160,7 +160,7 @@ Optional settings in `.opencode/sortie-dogs.json`:
160
160
  - `readOnlyTools` adds host-specific tool names that never change files, such as
161
161
  MCP tools. Unknown tools are denied for a bound session by default.
162
162
  - `dedicatedWorkerModel` selects the single model every worker role resolves to.
163
- It defaults to `openai/gpt-5.6-sol` with variant `medium`; declare your own when
163
+ It defaults to `openai/gpt-5.6-luna` with variant `max`; declare your own when
164
164
  that model is unavailable or when you want a different worker effort. Worker
165
165
  roles always resolve to this one target and cannot be routed per role.
166
166
  - `continuation` bounds the batch loop. After a terminal unit and its checkpoint,
@@ -180,7 +180,7 @@ Optional settings in `.opencode/sortie-dogs.json`:
180
180
  exactly three bounded scouts before implementation begins.
181
181
  - **Writes stay inside the assignment.** Exact source or operation manifests
182
182
  gate edits and handoffs.
183
- - **One accountable implementation path.** A dedicated Sol worker handles
183
+ - **One accountable implementation path.** One dedicated worker handles
184
184
  implementation, remediation, and blocker resolution.
185
185
  - **Evidence before completion.** Canonical validation, risk-based review, and
186
186
  terminal evidence gate coordinator-owned completion and commits.
@@ -207,8 +207,8 @@ dog-coordinator: completion evidence accepted
207
207
  criteria, a write manifest, and validation requirements.
208
208
  2. **Exactly three scouts** — bounded, read-only investigation collects
209
209
  complementary evidence without expanding the write scope.
210
- 3. **Dedicated worker** — the Sol worker implements only the approved manifest
211
- and also owns scoped remediation or blocker resolution.
210
+ 3. **Dedicated worker** — the dedicated worker implements only the approved
211
+ manifest and also owns scoped remediation or blocker resolution.
212
212
  4. **Canonical validation** — the declared test or build command must produce
213
213
  acceptable evidence.
214
214
  5. **Risk-based review** — high-risk candidates receive independent review;
@@ -258,19 +258,26 @@ untouched.
258
258
 
259
259
  ## Model routing
260
260
 
261
- `dog-coordinator` and `dog-scout` default to `openai/gpt-5.6-luna` with the
262
- `xhigh` variant. This is the recommended balance: bounded prompts, concise
263
- scout evidence, and fewer unnecessary context or tool turns can reduce token
264
- use while preserving quality. Project-local routing can override either
265
- default.
261
+ Every default route is one model at a different reasoning effort, because
262
+ published cost curves put a cheap model at high effort above an expensive model
263
+ at mid effort on both solve rate and price. Sortie-dogs therefore buys effort,
264
+ not model tiers, wherever the work allows it.
265
+
266
+ `dog-coordinator` defaults to `openai/gpt-5.6-luna` with the `max` variant. The
267
+ coordinator produces dispatches rather than code, and one malformed dispatch
268
+ discards an entire worker session, so top effort here costs less than the work it
269
+ protects. `dog-scout` defaults to the same model with the `high` variant, since
270
+ gathering bounded evidence is retrieval rather than reasoning and that tier is
271
+ where the curve gives the most per unit of cost. Project-local routing can
272
+ override either default.
266
273
 
267
274
  The `implementation`, `remediation`, `blocker-resolution`, and `dog-worker`
268
- roles always use the dedicated worker target, `openai/gpt-5.6-sol` with the
269
- `medium` variant. Worker effort is deliberately below review effort: source
270
- review is mandatory for risky candidates and returns findings the worker must
271
- remediate, so the loop already re-runs weak implementation work and top-of-range
272
- first-attempt effort mostly buys accuracy the reviewer supplies anyway. Raise
273
- `dedicatedWorkerModel` when you would rather pay for it up front. `modelRouting`
275
+ roles always use the dedicated worker target, `openai/gpt-5.6-luna` with the
276
+ `max` variant. Worker effort stays at the top of that model's range while review
277
+ effort stays above it on a stronger model, which is what mandatory source review
278
+ is for. Declare `dedicatedWorkerModel` as `openai/gpt-5.6-sol` when you would
279
+ rather pay for the stronger worker model up front; that target stays in the
280
+ built-in catalog for exactly this reason. `modelRouting`
274
281
  cannot replace those routes, and only `dedicatedWorkerModel` moves them. For other explicitly
275
282
  routed roles, resolution is deterministic: Sortie-dogs tries the preferred
276
283
  target, then ordered fallbacks. Roles without either a built-in default or an
@@ -280,7 +287,9 @@ explicit route keep OpenCode's already selected model.
280
287
  review and strategy lose their value when they run on the model that produced
281
288
  the candidate. Both default to `anthropic/claude-opus-5` when the catalog
282
289
  declares it, and otherwise fall back to `openai/gpt-5.6-sol` with the `xhigh`
283
- variant, one effort step above the worker target. A host that redeclares
290
+ variant. That fallback stays on the stronger model rather than matching the
291
+ worker target, because review has to be able to reject work the worker just
292
+ produced. A host that redeclares
284
293
  `dedicatedWorkerModel` keeps that target as its first fallback, since such a
285
294
  host may not serve the shipped model at all. Nothing here requires a particular
286
295
  vendor: both roles stay fully configurable, so declare whichever model you can
@@ -290,10 +299,10 @@ actually serve.
290
299
  {
291
300
  "modelRouting": {
292
301
  "dog-coordinator": {
293
- "preferred": { "model": "openai/gpt-5.6-luna", "variant": "xhigh" }
302
+ "preferred": { "model": "openai/gpt-5.6-luna", "variant": "max" }
294
303
  },
295
304
  "dog-scout": {
296
- "preferred": { "model": "openai/gpt-5.6-luna", "variant": "xhigh" }
305
+ "preferred": { "model": "openai/gpt-5.6-luna", "variant": "high" }
297
306
  },
298
307
  "dog-reviewer": {
299
308
  "preferred": { "model": "anthropic/claude-opus-5" },
@@ -306,7 +315,7 @@ actually serve.
306
315
  "modelCatalog": {
307
316
  "project": [
308
317
  { "model": "openai/gpt-5.6-sol", "variants": ["medium", "xhigh"] },
309
- { "model": "openai/gpt-5.6-luna", "variants": ["xhigh"] },
318
+ { "model": "openai/gpt-5.6-luna", "variants": ["max", "high"] },
310
319
  { "model": "anthropic/claude-opus-5" }
311
320
  ]
312
321
  }
@@ -7,28 +7,50 @@ export interface RoleModelRoute {
7
7
  readonly fallback?: readonly ModelTarget[];
8
8
  }
9
9
  export type ModelRoutingConfig = Readonly<Record<string, RoleModelRoute>>;
10
- export declare const DEDICATED_SOL_MODEL = "openai/gpt-5.6-sol";
11
10
  /**
12
- * Worker reasoning effort is deliberately below the review effort. Source review is mandatory and
13
- * returns findings the worker must remediate, so the loop already re-runs weak implementation work;
14
- * paying top-of-range effort on the first attempt buys accuracy the reviewer would otherwise supply.
11
+ * The published DeepSWE cost curve settles the worker target: the cheap model at top reasoning effort
12
+ * solves more than the expensive model at mid effort while costing a fraction of it, so paying for the
13
+ * expensive model by default bought a lower solve rate. Worker effort therefore sits at the top of the
14
+ * cheap model's range, and review effort stays above it on a stronger model, which is what the
15
+ * mandatory source review is for.
15
16
  */
16
- export declare const DEDICATED_SOL_VARIANT = "medium";
17
- export declare const DEDICATED_SOL_ROLES: readonly ["implementation", "remediation", "blocker-resolution", "sol-worker-mk2a2", "dog-worker"];
17
+ export declare const DEDICATED_WORKER_MODEL = "openai/gpt-5.6-luna";
18
+ export declare const DEDICATED_WORKER_VARIANT = "max";
19
+ /**
20
+ * The stronger, far more expensive worker target a host may still select deliberately. It is no longer
21
+ * a default route: it stays declared so an explicit dedicatedWorkerModel resolves against the catalog
22
+ * without extra host configuration.
23
+ */
24
+ export declare const ESCALATION_WORKER_MODEL = "openai/gpt-5.6-sol";
25
+ export declare const ESCALATION_WORKER_VARIANT = "medium";
26
+ export declare const DEDICATED_WORKER_ROLES: readonly ["implementation", "remediation", "blocker-resolution", "sol-worker-mk2a2", "dog-worker"];
18
27
  /** Ordered last-resort targets used only when the host proves a policy target unavailable. */
19
28
  export declare const DEFAULT_FREE_TIER_FALLBACK_MODELS: readonly string[];
20
29
  /** The dedicated worker target this build ships with when a host declares no target of its own. */
21
30
  export declare const DEFAULT_DEDICATED_WORKER_TARGET: ModelTarget;
31
+ /** The declared escalation target for a host that chooses to pay for the stronger worker model. */
32
+ export declare const ESCALATION_WORKER_TARGET: ModelTarget;
22
33
  /**
23
34
  * Fixed worker routes for one dedicated target. Which target is dedicated is a host decision, but
24
35
  * every worker role resolves to that single target and never to a fallback.
25
36
  */
26
37
  export declare function dedicatedWorkerRouting(target?: ModelTarget): ModelRoutingConfig;
27
- export declare const DEDICATED_SOL_ROUTING: ModelRoutingConfig;
38
+ export declare const DEDICATED_WORKER_ROUTING: ModelRoutingConfig;
28
39
  export declare const FIXED_MODEL_ROUTING: ModelRoutingConfig;
29
40
  export declare const RECOMMENDED_LUNA_MODEL = "openai/gpt-5.6-luna";
30
- export declare const RECOMMENDED_LUNA_VARIANT = "xhigh";
31
- export declare const RECOMMENDED_LUNA_ROLES: readonly ["dog-coordinator", "dog-scout"];
41
+ /**
42
+ * Dispatch quality, not code output, is what the coordinator spends effort on, and one malformed
43
+ * dispatch discards an entire worker session, so the coordinator runs at the top of the cheap model's
44
+ * range where that whole session costs less than the work it protects. Evidence gathering is retrieval
45
+ * rather than reasoning, so the scout sits one tier lower where the cost curve is steepest per point.
46
+ */
47
+ export declare const RECOMMENDED_COORDINATOR_VARIANT = "max";
48
+ export declare const RECOMMENDED_SCOUT_VARIANT = "high";
49
+ export declare const RECOMMENDED_LUNA_ROLE_VARIANTS: Readonly<{
50
+ readonly "dog-coordinator": "max";
51
+ readonly "dog-scout": "high";
52
+ }>;
53
+ export declare const RECOMMENDED_LUNA_ROLES: readonly string[];
32
54
  /** Configurable MkII defaults. Project-local and global configuration may override these routes. */
33
55
  export declare const RECOMMENDED_LUNA_ROUTING: ModelRoutingConfig;
34
56
  /**
@@ -39,8 +61,12 @@ export declare const RECOMMENDED_LUNA_ROUTING: ModelRoutingConfig;
39
61
  export declare const RECOMMENDED_CONSULTATION_MODEL = "anthropic/claude-opus-5";
40
62
  export declare const RECOMMENDED_CONSULTATION_ROLES: readonly string[];
41
63
  /** Review and advice carry the reasoning effort the worker target intentionally does not spend. */
42
- export declare const CONSULTATION_SOL_VARIANT = "xhigh";
43
- /** The shipped consultation fallback; higher effort than the worker target on the same model. */
64
+ export declare const CONSULTATION_FALLBACK_VARIANT = "xhigh";
65
+ /**
66
+ * The shipped consultation fallback. Review has to be able to reject work the worker just produced, so
67
+ * it stays on the stronger model even though the worker no longer defaults to it; a fallback equal to
68
+ * the worker target would review that work with exactly the capability that produced it.
69
+ */
44
70
  export declare const DEFAULT_CONSULTATION_FALLBACK_TARGET: ModelTarget;
45
71
  /**
46
72
  * Consultation prefers the strongest declared reasoning model. A host that relocated the dedicated
@@ -55,7 +81,7 @@ export declare const RECOMMENDED_CONSULTATION_ROUTING: ModelRoutingConfig;
55
81
  /** Every configurable role route this build recommends before host configuration is applied. */
56
82
  export declare function recommendedRoleRouting(fallbackTarget?: ModelTarget): ModelRoutingConfig;
57
83
  export declare const RECOMMENDED_ROLE_ROUTING: ModelRoutingConfig;
58
- export declare function isDedicatedSolRole(role: string): boolean;
84
+ export declare function isDedicatedWorkerRole(role: string): boolean;
59
85
  export declare function isFixedModelRole(role: string): boolean;
60
86
  export interface CatalogModel {
61
87
  readonly model: string;
@@ -1,12 +1,21 @@
1
1
  import { CONSULTATION_ROLE_POLICY } from "../core/consultation.js";
2
- export const DEDICATED_SOL_MODEL = "openai/gpt-5.6-sol";
3
2
  /**
4
- * Worker reasoning effort is deliberately below the review effort. Source review is mandatory and
5
- * returns findings the worker must remediate, so the loop already re-runs weak implementation work;
6
- * paying top-of-range effort on the first attempt buys accuracy the reviewer would otherwise supply.
3
+ * The published DeepSWE cost curve settles the worker target: the cheap model at top reasoning effort
4
+ * solves more than the expensive model at mid effort while costing a fraction of it, so paying for the
5
+ * expensive model by default bought a lower solve rate. Worker effort therefore sits at the top of the
6
+ * cheap model's range, and review effort stays above it on a stronger model, which is what the
7
+ * mandatory source review is for.
7
8
  */
8
- export const DEDICATED_SOL_VARIANT = "medium";
9
- export const DEDICATED_SOL_ROLES = [
9
+ export const DEDICATED_WORKER_MODEL = "openai/gpt-5.6-luna";
10
+ export const DEDICATED_WORKER_VARIANT = "max";
11
+ /**
12
+ * The stronger, far more expensive worker target a host may still select deliberately. It is no longer
13
+ * a default route: it stays declared so an explicit dedicatedWorkerModel resolves against the catalog
14
+ * without extra host configuration.
15
+ */
16
+ export const ESCALATION_WORKER_MODEL = "openai/gpt-5.6-sol";
17
+ export const ESCALATION_WORKER_VARIANT = "medium";
18
+ export const DEDICATED_WORKER_ROLES = [
10
19
  "implementation",
11
20
  "remediation",
12
21
  "blocker-resolution",
@@ -17,34 +26,50 @@ export const DEDICATED_SOL_ROLES = [
17
26
  export const DEFAULT_FREE_TIER_FALLBACK_MODELS = Object.freeze([
18
27
  "opencode/deepseek-v4-flash-free",
19
28
  ]);
20
- const dedicatedSolRoleSet = new Set(DEDICATED_SOL_ROLES);
29
+ const dedicatedWorkerRoleSet = new Set(DEDICATED_WORKER_ROLES);
21
30
  /** The dedicated worker target this build ships with when a host declares no target of its own. */
22
31
  export const DEFAULT_DEDICATED_WORKER_TARGET = Object.freeze({
23
- model: DEDICATED_SOL_MODEL,
24
- variant: DEDICATED_SOL_VARIANT,
32
+ model: DEDICATED_WORKER_MODEL,
33
+ variant: DEDICATED_WORKER_VARIANT,
34
+ });
35
+ /** The declared escalation target for a host that chooses to pay for the stronger worker model. */
36
+ export const ESCALATION_WORKER_TARGET = Object.freeze({
37
+ model: ESCALATION_WORKER_MODEL,
38
+ variant: ESCALATION_WORKER_VARIANT,
25
39
  });
26
40
  /**
27
41
  * Fixed worker routes for one dedicated target. Which target is dedicated is a host decision, but
28
42
  * every worker role resolves to that single target and never to a fallback.
29
43
  */
30
44
  export function dedicatedWorkerRouting(target = DEFAULT_DEDICATED_WORKER_TARGET) {
31
- return Object.freeze(Object.fromEntries(DEDICATED_SOL_ROLES.map((role) => [role, Object.freeze({
45
+ return Object.freeze(Object.fromEntries(DEDICATED_WORKER_ROLES.map((role) => [role, Object.freeze({
32
46
  preferred: Object.freeze(target.variant === undefined
33
47
  ? { model: target.model }
34
48
  : { model: target.model, variant: target.variant }),
35
49
  })])));
36
50
  }
37
- export const DEDICATED_SOL_ROUTING = dedicatedWorkerRouting();
38
- export const FIXED_MODEL_ROUTING = DEDICATED_SOL_ROUTING;
51
+ export const DEDICATED_WORKER_ROUTING = dedicatedWorkerRouting();
52
+ export const FIXED_MODEL_ROUTING = DEDICATED_WORKER_ROUTING;
39
53
  const fixedModelRoleSet = new Set(Object.keys(FIXED_MODEL_ROUTING));
40
54
  export const RECOMMENDED_LUNA_MODEL = "openai/gpt-5.6-luna";
41
- export const RECOMMENDED_LUNA_VARIANT = "xhigh";
42
- export const RECOMMENDED_LUNA_ROLES = ["dog-coordinator", "dog-scout"];
55
+ /**
56
+ * Dispatch quality, not code output, is what the coordinator spends effort on, and one malformed
57
+ * dispatch discards an entire worker session, so the coordinator runs at the top of the cheap model's
58
+ * range where that whole session costs less than the work it protects. Evidence gathering is retrieval
59
+ * rather than reasoning, so the scout sits one tier lower where the cost curve is steepest per point.
60
+ */
61
+ export const RECOMMENDED_COORDINATOR_VARIANT = "max";
62
+ export const RECOMMENDED_SCOUT_VARIANT = "high";
63
+ export const RECOMMENDED_LUNA_ROLE_VARIANTS = Object.freeze({
64
+ "dog-coordinator": RECOMMENDED_COORDINATOR_VARIANT,
65
+ "dog-scout": RECOMMENDED_SCOUT_VARIANT,
66
+ });
67
+ export const RECOMMENDED_LUNA_ROLES = Object.freeze(Object.keys(RECOMMENDED_LUNA_ROLE_VARIANTS));
43
68
  /** Configurable MkII defaults. Project-local and global configuration may override these routes. */
44
- export const RECOMMENDED_LUNA_ROUTING = Object.freeze(Object.fromEntries(RECOMMENDED_LUNA_ROLES.map((role) => [role, Object.freeze({
69
+ export const RECOMMENDED_LUNA_ROUTING = Object.freeze(Object.fromEntries(Object.entries(RECOMMENDED_LUNA_ROLE_VARIANTS).map(([role, variant]) => [role, Object.freeze({
45
70
  preferred: Object.freeze({
46
71
  model: RECOMMENDED_LUNA_MODEL,
47
- variant: RECOMMENDED_LUNA_VARIANT,
72
+ variant,
48
73
  }),
49
74
  })])));
50
75
  /**
@@ -55,11 +80,15 @@ export const RECOMMENDED_LUNA_ROUTING = Object.freeze(Object.fromEntries(RECOMME
55
80
  export const RECOMMENDED_CONSULTATION_MODEL = "anthropic/claude-opus-5";
56
81
  export const RECOMMENDED_CONSULTATION_ROLES = Object.freeze(Object.values(CONSULTATION_ROLE_POLICY));
57
82
  /** Review and advice carry the reasoning effort the worker target intentionally does not spend. */
58
- export const CONSULTATION_SOL_VARIANT = "xhigh";
59
- /** The shipped consultation fallback; higher effort than the worker target on the same model. */
83
+ export const CONSULTATION_FALLBACK_VARIANT = "xhigh";
84
+ /**
85
+ * The shipped consultation fallback. Review has to be able to reject work the worker just produced, so
86
+ * it stays on the stronger model even though the worker no longer defaults to it; a fallback equal to
87
+ * the worker target would review that work with exactly the capability that produced it.
88
+ */
60
89
  export const DEFAULT_CONSULTATION_FALLBACK_TARGET = Object.freeze({
61
- model: DEDICATED_SOL_MODEL,
62
- variant: CONSULTATION_SOL_VARIANT,
90
+ model: ESCALATION_WORKER_MODEL,
91
+ variant: CONSULTATION_FALLBACK_VARIANT,
63
92
  });
64
93
  function frozenTarget(target) {
65
94
  return Object.freeze(target.variant === undefined
@@ -97,8 +126,8 @@ export function recommendedRoleRouting(fallbackTarget = DEFAULT_DEDICATED_WORKER
97
126
  });
98
127
  }
99
128
  export const RECOMMENDED_ROLE_ROUTING = recommendedRoleRouting();
100
- export function isDedicatedSolRole(role) {
101
- return dedicatedSolRoleSet.has(role);
129
+ export function isDedicatedWorkerRole(role) {
130
+ return dedicatedWorkerRoleSet.has(role);
102
131
  }
103
132
  export function isFixedModelRole(role) {
104
133
  return fixedModelRoleSet.has(role);
@@ -107,12 +136,16 @@ export function isFixedModelRole(role) {
107
136
  export const BUILT_IN_MODEL_CATALOG = Object.freeze({
108
137
  global: Object.freeze([
109
138
  Object.freeze({
110
- model: DEDICATED_SOL_MODEL,
111
- variants: Object.freeze([DEDICATED_SOL_VARIANT, CONSULTATION_SOL_VARIANT]),
139
+ model: DEDICATED_WORKER_MODEL,
140
+ variants: Object.freeze([
141
+ DEDICATED_WORKER_VARIANT,
142
+ RECOMMENDED_COORDINATOR_VARIANT,
143
+ RECOMMENDED_SCOUT_VARIANT,
144
+ ].filter((variant, index, all) => all.indexOf(variant) === index)),
112
145
  }),
113
146
  Object.freeze({
114
- model: RECOMMENDED_LUNA_MODEL,
115
- variants: Object.freeze([RECOMMENDED_LUNA_VARIANT]),
147
+ model: ESCALATION_WORKER_MODEL,
148
+ variants: Object.freeze([ESCALATION_WORKER_VARIANT, CONSULTATION_FALLBACK_VARIANT]),
116
149
  }),
117
150
  ]),
118
151
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sortie-dogs",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Bounded, validated orchestration loop plugin for OpenCode",
5
5
  "keywords": [
6
6
  "opencode",