@gobing-ai/spur 0.3.47 → 0.3.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/config.example.yaml +94 -15
  3. package/config/transition-shims.json +33 -0
  4. package/config/workflows/basic.yaml +2 -0
  5. package/config/workflows/docs-pipeline.yaml +2 -0
  6. package/config/workflows/feature-dev.yaml +8 -0
  7. package/config/workflows/idea-pipeline.yaml +10 -0
  8. package/config/workflows/planning-pipeline.yaml +4 -0
  9. package/config/workflows/pr-review.yaml +338 -0
  10. package/config/workflows/task-pipeline.yaml +8 -0
  11. package/config/workflows/wayfinder-resolution.yaml +4 -0
  12. package/config/workflows/wrapup-pipeline.yaml +18 -1
  13. package/package.json +8 -8
  14. package/plugins/sp/README.md +9 -6
  15. package/plugins/sp/agents/expert-spur.md +1 -0
  16. package/plugins/sp/commands/dev-arch.md +2 -1
  17. package/plugins/sp/commands/dev-brainstorm.md +2 -1
  18. package/plugins/sp/commands/dev-changelog.md +1 -0
  19. package/plugins/sp/commands/dev-daily.md +1 -0
  20. package/plugins/sp/commands/dev-debug.md +2 -1
  21. package/plugins/sp/commands/dev-dogfood.md +2 -1
  22. package/plugins/sp/commands/{dev-featurechange.md → dev-feature-change.md} +8 -10
  23. package/plugins/sp/commands/dev-find-conflict.md +2 -1
  24. package/plugins/sp/commands/dev-find-issue.md +36 -43
  25. package/plugins/sp/commands/dev-find-next.md +5 -4
  26. package/plugins/sp/commands/dev-fixall.md +1 -0
  27. package/plugins/sp/commands/dev-gitmsg.md +1 -0
  28. package/plugins/sp/commands/dev-gtd.md +12 -12
  29. package/plugins/sp/commands/dev-handover.md +1 -0
  30. package/plugins/sp/commands/dev-history-load.md +63 -0
  31. package/plugins/sp/commands/dev-idea.md +1 -0
  32. package/plugins/sp/commands/dev-next.md +2 -1
  33. package/plugins/sp/commands/dev-parallel.md +2 -1
  34. package/plugins/sp/commands/dev-plan.md +2 -1
  35. package/plugins/sp/commands/dev-pr-review.md +39 -0
  36. package/plugins/sp/commands/dev-refine.md +5 -3
  37. package/plugins/sp/commands/dev-refineall.md +2 -1
  38. package/plugins/sp/commands/dev-refresh.md +2 -1
  39. package/plugins/sp/commands/dev-reverse.md +2 -1
  40. package/plugins/sp/commands/dev-review.md +2 -1
  41. package/plugins/sp/commands/dev-run.md +3 -2
  42. package/plugins/sp/commands/dev-runall.md +3 -2
  43. package/plugins/sp/commands/dev-simplify.md +2 -1
  44. package/plugins/sp/commands/dev-unit.md +2 -1
  45. package/plugins/sp/commands/dev-verify.md +2 -1
  46. package/plugins/sp/commands/dev-verifyall.md +2 -1
  47. package/plugins/sp/commands/dev-wrap.md +7 -5
  48. package/plugins/sp/commands/dev-wrapall.md +7 -5
  49. package/plugins/sp/commands/rule-add.md +1 -0
  50. package/plugins/sp/commands/rule-refine.md +1 -0
  51. package/plugins/sp/commands/rule-scan.md +1 -0
  52. package/plugins/sp/commands/spur-init.md +1 -0
  53. package/plugins/sp/commands/workflow-add.md +1 -0
  54. package/plugins/sp/commands/workflow-refine.md +1 -0
  55. package/plugins/sp/hooks/careful-guard.ts +5 -80
  56. package/plugins/sp/hooks/destructive-policy.ts +146 -0
  57. package/plugins/sp/hooks/pi/guard-extension.ts +33 -46
  58. package/plugins/sp/hooks/task-file-policy.ts +31 -0
  59. package/plugins/sp/hooks/task-write-guard.ts +4 -0
  60. package/plugins/sp/plugin.json +1 -1
  61. package/plugins/sp/references/roles.md +106 -0
  62. package/plugins/sp/scripts/feature-sync-bounded.ts +28 -2
  63. package/plugins/sp/scripts/history-load.ts +400 -0
  64. package/plugins/sp/scripts/pr-reviewing.ts +867 -0
  65. package/plugins/sp/scripts/stage-registry-adapter.ts +66 -31
  66. package/plugins/sp/scripts/surface-drift-inventory.ts +908 -0
  67. package/plugins/sp/scripts/task-size-precheck.ts +30 -4
  68. package/plugins/sp/scripts/transition-shim-check.ts +238 -0
  69. package/plugins/sp/scripts/validate-commands.ts +33 -2
  70. package/plugins/sp/scripts/validate-flag-contracts.ts +5 -2
  71. package/plugins/sp/skills/code-implementation/SKILL.md +9 -1
  72. package/plugins/sp/skills/code-verification/SKILL.md +29 -28
  73. package/plugins/sp/skills/issue-finding/SKILL.md +123 -141
  74. package/plugins/sp/skills/issue-finding/examples/expected-findings.json +1 -1
  75. package/plugins/sp/skills/issue-finding/references/session-formats.md +87 -90
  76. package/plugins/sp/skills/next-feature/SKILL.md +6 -6
  77. package/plugins/sp/skills/next-feature/references/handoff-routing.md +5 -5
  78. package/plugins/sp/skills/next-feature/references/signal-derivation.md +7 -2
  79. package/plugins/sp/skills/next-router/SKILL.md +1 -1
  80. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +40 -2
  81. package/plugins/sp/skills/pr-reviewing/SKILL.md +285 -0
  82. package/plugins/sp/skills/spur-cli/SKILL.md +3 -0
  83. package/plugins/sp/skills/spur-cli/references/agent.md +12 -7
  84. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +5 -5
  85. package/plugins/sp/skills/spur-cli/references/features.md +1 -1
  86. package/plugins/sp/skills/spur-cli/references/team.md +10 -3
  87. package/plugins/sp/skills/spur-dev/SKILL.md +2 -0
  88. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +17 -0
  89. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +44 -23
  90. package/plugins/sp/skills/spur-dev/references/dev-operations.md +14 -11
  91. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +14 -12
  92. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +28 -7
  93. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +2 -0
  94. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +12 -2
  95. package/schemas/spur-config.schema.json +47 -3
  96. package/spur.js +12223 -7716
  97. package/web/_astro/BoardApp.8hiqShQn.js +1 -0
  98. package/web/_astro/{BoardApp.DKyrGxdo.js → BoardApp.BjQUNhuj.js} +74 -74
  99. package/web/_astro/{TaskDetail.6-27_LMa.js → TaskDetail.CVBuD6dF.js} +1 -1
  100. package/web/_astro/{arc.Df-9AQvS.js → arc.BMMjdODi.js} +1 -1
  101. package/web/_astro/{architectureDiagram-3BPJPVTR.VAI_-paS.js → architectureDiagram-3BPJPVTR.BU5ShzXf.js} +1 -1
  102. package/web/_astro/{blockDiagram-GPEHLZMM.DFpUY1ue.js → blockDiagram-GPEHLZMM.Bj1iEqPD.js} +1 -1
  103. package/web/_astro/{c4Diagram-AAUBKEIU.CF8doOpg.js → c4Diagram-AAUBKEIU.vX8wepCL.js} +1 -1
  104. package/web/_astro/channel.EwdSemIC.js +1 -0
  105. package/web/_astro/{chunk-2J33WTMH.BnjK3fjt.js → chunk-2J33WTMH.BKAipTym.js} +1 -1
  106. package/web/_astro/{chunk-4BX2VUAB.x6ZDnJKq.js → chunk-4BX2VUAB.B68XkPG7.js} +1 -1
  107. package/web/_astro/{chunk-55IACEB6.zY-0uu7w.js → chunk-55IACEB6.BmeDLcrc.js} +1 -1
  108. package/web/_astro/{chunk-727SXJPM.BZxKg_Vi.js → chunk-727SXJPM.PDuBA3Kw.js} +1 -1
  109. package/web/_astro/{chunk-AQP2D5EJ.Cpi9G9Td.js → chunk-AQP2D5EJ.C7A044za.js} +1 -1
  110. package/web/_astro/{chunk-FMBD7UC4.DWTB-Pif.js → chunk-FMBD7UC4.BtzKKFqR.js} +1 -1
  111. package/web/_astro/{chunk-ND2GUHAM.BPDQbiOG.js → chunk-ND2GUHAM.BJuDeeOy.js} +1 -1
  112. package/web/_astro/{chunk-QZHKN3VN.BRWIcuoM.js → chunk-QZHKN3VN.DSeMDgcQ.js} +1 -1
  113. package/web/_astro/{classDiagram-4FO5ZUOK.mGTCZsDO.js → classDiagram-4FO5ZUOK.D53Q4tCw.js} +1 -1
  114. package/web/_astro/{classDiagram-v2-Q7XG4LA2.mGTCZsDO.js → classDiagram-v2-Q7XG4LA2.D53Q4tCw.js} +1 -1
  115. package/web/_astro/{cose-bilkent-S5V4N54A.D1GEut-z.js → cose-bilkent-S5V4N54A.c712AFRH.js} +1 -1
  116. package/web/_astro/{dagre-BM42HDAG.BV0XG9Do.js → dagre-BM42HDAG.D-idisph.js} +1 -1
  117. package/web/_astro/{diagram-2AECGRRQ.DzpYxsjo.js → diagram-2AECGRRQ.DLgnsJCU.js} +1 -1
  118. package/web/_astro/{diagram-5GNKFQAL.Cm9YzJh4.js → diagram-5GNKFQAL.BiaxBVqx.js} +1 -1
  119. package/web/_astro/{diagram-KO2AKTUF.BjhottUj.js → diagram-KO2AKTUF.C8HX1vd8.js} +1 -1
  120. package/web/_astro/{diagram-LMA3HP47.BFsQW5kb.js → diagram-LMA3HP47.CfqDLLes.js} +1 -1
  121. package/web/_astro/{diagram-OG6HWLK6.8pdpzSWO.js → diagram-OG6HWLK6.15SDiEed.js} +1 -1
  122. package/web/_astro/{erDiagram-TEJ5UH35.Bd7KUJmJ.js → erDiagram-TEJ5UH35.DksYtOYM.js} +1 -1
  123. package/web/_astro/{flowDiagram-I6XJVG4X.7LWffkaE.js → flowDiagram-I6XJVG4X.DR_Au-HV.js} +1 -1
  124. package/web/_astro/{ganttDiagram-6RSMTGT7.BeDcO5tI.js → ganttDiagram-6RSMTGT7.CHhHrffI.js} +1 -1
  125. package/web/_astro/{gitGraphDiagram-PVQCEYII.Ca4n730A.js → gitGraphDiagram-PVQCEYII.B2Xehvam.js} +1 -1
  126. package/web/_astro/{index.Dbvuw6d4.css → index.DAxu50UF.css} +1 -1
  127. package/web/_astro/{infoDiagram-5YYISTIA.B0OakQYb.js → infoDiagram-5YYISTIA.C9c3CNNN.js} +1 -1
  128. package/web/_astro/{ishikawaDiagram-YF4QCWOH.DSmNQe-1.js → ishikawaDiagram-YF4QCWOH.BibUHkh8.js} +1 -1
  129. package/web/_astro/{journeyDiagram-JHISSGLW.Cy5ruEUu.js → journeyDiagram-JHISSGLW.BYoVHiyO.js} +1 -1
  130. package/web/_astro/{kanban-definition-UN3LZRKU.CUJXub0p.js → kanban-definition-UN3LZRKU.CM1K5wHE.js} +1 -1
  131. package/web/_astro/{linear.DC1jCCXn.js → linear.SPpjJUb-.js} +1 -1
  132. package/web/_astro/{mermaid.core.DxVP99Ab.js → mermaid.core.BAgx3nnb.js} +4 -4
  133. package/web/_astro/{mindmap-definition-RKZ34NQL.D0MaV6sJ.js → mindmap-definition-RKZ34NQL.D35oPG1R.js} +1 -1
  134. package/web/_astro/{pieDiagram-4H26LBE5.DCC6_q32.js → pieDiagram-4H26LBE5.DiWuRwk7.js} +1 -1
  135. package/web/_astro/{quadrantDiagram-W4KKPZXB.BeUOAM7C.js → quadrantDiagram-W4KKPZXB.B9PBzTWn.js} +1 -1
  136. package/web/_astro/{requirementDiagram-4Y6WPE33.Dbl4MASO.js → requirementDiagram-4Y6WPE33.CYuuamFN.js} +1 -1
  137. package/web/_astro/{sankeyDiagram-5OEKKPKP.HsLg0VS4.js → sankeyDiagram-5OEKKPKP.W24UhhtD.js} +1 -1
  138. package/web/_astro/{sequenceDiagram-3UESZ5HK.DT7DJTnZ.js → sequenceDiagram-3UESZ5HK.BpbNjA51.js} +1 -1
  139. package/web/_astro/{stateDiagram-AJRCARHV.d_ju1Vr1.js → stateDiagram-AJRCARHV.DqVsHudf.js} +1 -1
  140. package/web/_astro/{stateDiagram-v2-BHNVJYJU.DMCAjMJ4.js → stateDiagram-v2-BHNVJYJU.CzwHYX81.js} +1 -1
  141. package/web/_astro/{timeline-definition-PNZ67QCA.DNOHr62_.js → timeline-definition-PNZ67QCA.Bc3B6djw.js} +1 -1
  142. package/web/_astro/{vennDiagram-CIIHVFJN.B7dUy-1W.js → vennDiagram-CIIHVFJN.C-D5rh8O.js} +1 -1
  143. package/web/_astro/{wardley-L42UT6IY.DEqOXvBh.js → wardley-L42UT6IY.D7PdYCqn.js} +1 -1
  144. package/web/_astro/{wardleyDiagram-YWT4CUSO.BCRb2p6x.js → wardleyDiagram-YWT4CUSO.CwmJKXF3.js} +1 -1
  145. package/web/_astro/{xychartDiagram-2RQKCTM6.NxVQLdBh.js → xychartDiagram-2RQKCTM6.avDYnLsb.js} +1 -1
  146. package/web/index.html +2 -2
  147. package/web/_astro/BoardApp.Ce6zJYAH.js +0 -1
  148. package/web/_astro/channel.Uhm9O3UV.js +0 -1
@@ -10,6 +10,12 @@
10
10
  * Self-contained: no @gobing-ai/spur-domain dependency (plugins/sp is outside
11
11
  * the workspace). Types are defined inline, mirroring the domain schema.
12
12
  *
13
+ * Stage floor tiers read from Layer 1 (`references/roles.md`, 0538 R4 /
14
+ * 0348 Follow-up C): the stage → role → tier table is the single pointer for
15
+ * floor tiers; this file no longer hardcodes a floor value. Regex-parsed
16
+ * (no `yaml` dependency — the plugin installs into foreign repos; same
17
+ * discipline as the parity tests).
18
+ *
13
19
  * CLI usage:
14
20
  * bun plugins/sp/scripts/stage-registry-adapter.ts --wbs 0307 [--dry-run]
15
21
  * bun plugins/sp/scripts/stage-registry-adapter.ts --wbs 0307 --auto
@@ -18,6 +24,9 @@
18
24
  * bun plugins/sp/scripts/stage-registry-adapter.ts --help
19
25
  */
20
26
 
27
+ import { readFileSync } from 'node:fs';
28
+ import { join } from 'node:path';
29
+
21
30
  // ─── Inline type definitions (mirrors packages/domain/src/stage-registry/) ─
22
31
 
23
32
  export type SchemaVersion = { major: number; minor: number };
@@ -235,24 +244,50 @@ const inlineHitl = (timing: 'pre' | 'post' | 'both'): ExecutionVariantHitl => ({
235
244
  gate_timing: timing,
236
245
  });
237
246
  const defaultRetry: StageRetryPolicy = { max_attempts: 3, terminal_stop: 'block', timeout_seconds: 300 };
238
- const standardModel: StageModelPolicy = {
239
- min_tier: 'standard',
240
- fallback: [{ tier: 'capable-1', trigger: 'gate-fail' }],
241
- };
242
- const capableModel: StageModelPolicy = {
243
- min_tier: 'capable-1',
244
- fallback: [],
245
- };
246
- /** Plan/create: capable-first (Design authored into tasks by default). */
247
- const planModel: StageModelPolicy = {
248
- min_tier: 'capable-2',
249
- fallback: [{ tier: 'capable-3', trigger: 'gate-fail' }],
250
- };
251
- /** Refine: cheap fallback when Design/AC/Plan still blank after create. */
252
- const refineModel: StageModelPolicy = {
253
- min_tier: 'standard',
254
- fallback: [{ tier: 'capable-2', trigger: 'gate-fail' }],
255
- };
247
+
248
+ export const TIER_ORDER: AdapterCapabilityTier[] = ['cheap', 'standard', 'capable-1', 'capable-2', 'capable-3'];
249
+
250
+ /**
251
+ * Layer-1 stage → floor tier map (0538 R4 / 0348 Follow-up C): derived from
252
+ * `references/roles.md` (role → tier → stages). This is the single pointer for
253
+ * floor tiers; a stage's `model_policy.min_tier` never hardcodes a value here.
254
+ * Stages Layer 1 does not fold keep the local `standard` floor. A missing or
255
+ * unreadable roles.md degrades every floor to `standard` (the pre-reconcile
256
+ * default) rather than failing the routing adapter.
257
+ */
258
+ export const STAGE_FLOOR_TIER: ReadonlyMap<string, AdapterCapabilityTier> = (() => {
259
+ const map = new Map<string, AdapterCapabilityTier>();
260
+ try {
261
+ const source = readFileSync(join(import.meta.dir, '..', 'references', 'roles.md'), 'utf8');
262
+ const roleRe = /id: ([a-z-]+)[\s\S]*?tier: ([a-z0-9-]+)[\s\S]*?stages: \[([^\]]*)\]/g;
263
+ for (const m of source.matchAll(roleRe)) {
264
+ const tier = m[2] as AdapterCapabilityTier;
265
+ for (const stage of (m[3] ?? '').split(',')) {
266
+ const id = stage.trim();
267
+ if (id !== '') map.set(id, tier);
268
+ }
269
+ }
270
+ } catch {
271
+ // roles.md unreachable — every floor falls back to `standard` below.
272
+ }
273
+ return map;
274
+ })();
275
+
276
+ /**
277
+ * Build a stage model policy whose floor reads from Layer 1. A declared fallback
278
+ * at or below the floor (review/refine/brainstorm floors rose with roles.md)
279
+ * escalates to the next tier above the floor instead of degrading.
280
+ */
281
+ function policy(stage: string, fallback: AdapterCapabilityTier[] = []): StageModelPolicy {
282
+ const floor = STAGE_FLOOR_TIER.get(stage) ?? 'standard';
283
+ const kept = fallback.filter((t) => TIER_ORDER.indexOf(t) > TIER_ORDER.indexOf(floor));
284
+ if (kept.length > 0) return { min_tier: floor, fallback: kept.map((tier) => ({ tier, trigger: 'gate-fail' })) };
285
+ if (fallback.length === 0) return { min_tier: floor, fallback: [] };
286
+ // Escalate one tier above the floor; a floor already at the top of the
287
+ // vocabulary keeps itself as the bound (no higher tier exists to escalate to).
288
+ const next = TIER_ORDER[TIER_ORDER.indexOf(floor) + 1] ?? floor;
289
+ return { min_tier: floor, fallback: [{ tier: next, trigger: 'gate-fail' }] };
290
+ }
256
291
 
257
292
  const layer = (name: ContextLayerName): StageContextLayer => ({ layer: name, required: true });
258
293
  const event = (name: string, description?: string): StageEvent => ({ name, description });
@@ -279,7 +314,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
279
314
  ],
280
315
  mutation_class: 'corpus',
281
316
  retry: defaultRetry,
282
- model_policy: refineModel,
317
+ model_policy: policy('refine', ['capable-2']),
283
318
  context_layers: [layer('project-authority'), layer('task-state'), layer('stage-contract')],
284
319
  observability: [event('stage-started'), event('feature-created'), event('batch-created')],
285
320
  execution: inlineInline(true),
@@ -300,7 +335,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
300
335
  ],
301
336
  mutation_class: 'corpus',
302
337
  retry: defaultRetry,
303
- model_policy: planModel,
338
+ model_policy: policy('plan', ['capable-3']),
304
339
  context_layers: [layer('project-authority'), layer('task-state'), layer('stage-contract')],
305
340
  observability: [event('stage-started'), event('feature-created'), event('batch-created')],
306
341
  execution: inlineInline(true),
@@ -317,7 +352,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
317
352
  gates: [],
318
353
  mutation_class: 'code',
319
354
  retry: defaultRetry,
320
- model_policy: standardModel,
355
+ model_policy: policy('implement', ['capable-1']),
321
356
  context_layers: [layer('task-state'), layer('run-state')],
322
357
  observability: [event('stage-started'), event('code-modified')],
323
358
  execution: inlineInline(),
@@ -338,7 +373,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
338
373
  gates: [{ name: 'coverage-floor', timing: 'post', min_verdict: 'pass', description: '≥90% function coverage' }],
339
374
  mutation_class: 'tests',
340
375
  retry: defaultRetry,
341
- model_policy: standardModel,
376
+ model_policy: policy('test', ['capable-1']),
342
377
  context_layers: [layer('task-state'), layer('run-state')],
343
378
  observability: [event('stage-started'), event('gate-passed'), event('coverage-measured')],
344
379
  execution: inlineInline(),
@@ -357,7 +392,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
357
392
  ],
358
393
  mutation_class: 'code',
359
394
  retry: { max_attempts: 2, terminal_stop: 'block', timeout_seconds: 600 },
360
- model_policy: standardModel,
395
+ model_policy: policy('quality-gate', ['capable-1']),
361
396
  context_layers: [layer('task-state'), layer('run-state')],
362
397
  observability: [event('stage-started'), event('gate-passed')],
363
398
  execution: inlineInline(),
@@ -378,7 +413,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
378
413
  ],
379
414
  mutation_class: 'verdict',
380
415
  retry: { max_attempts: 2, terminal_stop: 'escalate', timeout_seconds: 600 },
381
- model_policy: capableModel,
416
+ model_policy: policy('verify'),
382
417
  context_layers: [layer('task-state'), layer('run-state'), layer('indexed-evidence')],
383
418
  observability: [event('stage-started'), event('verdict-emitted'), event('gate-passed')],
384
419
  execution: inlineInline(),
@@ -403,7 +438,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
403
438
  ],
404
439
  mutation_class: 'learnings',
405
440
  retry: { max_attempts: 2, terminal_stop: 'block', timeout_seconds: 180 },
406
- model_policy: standardModel,
441
+ model_policy: policy('wrap', ['capable-1']),
407
442
  context_layers: [layer('task-state'), layer('indexed-evidence')],
408
443
  observability: [event('stage-started'), event('learnings-written'), event('doc-synced')],
409
444
  execution: inlineHitl('both'),
@@ -417,7 +452,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
417
452
  gates: [{ name: 'review-guard', timing: 'post', min_verdict: 'pass', description: 'No P1 findings blocking' }],
418
453
  mutation_class: 'verdict',
419
454
  retry: { max_attempts: 2, terminal_stop: 'block', timeout_seconds: 300 },
420
- model_policy: standardModel,
455
+ model_policy: policy('review', ['capable-1']),
421
456
  context_layers: [layer('task-state'), layer('run-state')],
422
457
  observability: [event('stage-started'), event('findings-produced')],
423
458
  execution: inlineInline(),
@@ -443,7 +478,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
443
478
  ],
444
479
  mutation_class: 'driver',
445
480
  retry: { max_attempts: 3, terminal_stop: 'block', timeout_seconds: 600 },
446
- model_policy: capableModel,
481
+ model_policy: policy('dogfood'),
447
482
  context_layers: [layer('task-state'), layer('run-state')],
448
483
  observability: [event('stage-started'), event('gate-passed'), event('report-emitted')],
449
484
  execution: inlineInline(),
@@ -457,7 +492,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
457
492
  gates: [],
458
493
  mutation_class: 'corpus',
459
494
  retry: { max_attempts: 1, terminal_stop: 'block', timeout_seconds: 120 },
460
- model_policy: standardModel,
495
+ model_policy: policy('handover', ['capable-1']),
461
496
  context_layers: [layer('task-state')],
462
497
  observability: [event('stage-started')],
463
498
  execution: inlineDeterministic('cli'),
@@ -474,7 +509,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
474
509
  gates: [],
475
510
  mutation_class: 'code',
476
511
  retry: { max_attempts: 1, terminal_stop: 'block', timeout_seconds: 120 },
477
- model_policy: standardModel,
512
+ model_policy: policy('fixall', ['capable-1']),
478
513
  context_layers: [layer('task-state')],
479
514
  observability: [event('stage-started')],
480
515
  execution: inlineDeterministic('script'),
@@ -488,7 +523,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
488
523
  gates: [],
489
524
  mutation_class: 'corpus',
490
525
  retry: { max_attempts: 2, terminal_stop: 'block', timeout_seconds: 300 },
491
- model_policy: standardModel,
526
+ model_policy: policy('brainstorm'),
492
527
  context_layers: [layer('project-authority'), layer('task-state')],
493
528
  observability: [event('stage-started')],
494
529
  execution: inlineInline(),
@@ -502,7 +537,7 @@ export const REGISTERED_STAGES: StageRecord[] = [
502
537
  gates: [],
503
538
  mutation_class: 'none',
504
539
  retry: { max_attempts: 1, terminal_stop: 'block', timeout_seconds: 60 },
505
- model_policy: { min_tier: 'cheap', fallback: [] },
540
+ model_policy: policy('changelog'),
506
541
  context_layers: [],
507
542
  observability: [event('stage-started')],
508
543
  execution: inlineDeterministic('cli'),