@mstar-harness/dsh 3.8.0 → 3.8.2

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 (51) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +142 -194
  3. package/README.zh.md +29 -17
  4. package/bundle/README.md +83 -171
  5. package/dist/client/index.d.ts +17 -8
  6. package/dist/client/panel/MstarPanelTitle.d.ts +13 -0
  7. package/dist/client/panel/PanelView.d.ts +56 -52
  8. package/dist/client/panel/TabNav.d.ts +17 -14
  9. package/dist/client/panel/definition.d.ts +23 -0
  10. package/dist/client/panel/engine-status-client.d.ts +84 -6
  11. package/dist/client/panel/graph/project-graph.d.ts +35 -64
  12. package/dist/client/panel/graph/schema.d.ts +1 -2
  13. package/dist/client/panel/guards.d.ts +41 -1
  14. package/dist/client/panel/locale.d.ts +1 -1
  15. package/dist/client/panel/mstar-glyph.d.ts +22 -0
  16. package/dist/client/panel/pages/AgentListPage.d.ts +71 -0
  17. package/dist/client/panel/pages/EventLogPage.d.ts +7 -4
  18. package/dist/client/panel/pages/IterationInfoSection.d.ts +16 -13
  19. package/dist/client/panel/pages/IterationTaskPage.d.ts +13 -14
  20. package/dist/client/panel/panel-store.d.ts +28 -0
  21. package/dist/client/panel/sidebar.d.ts +13 -7
  22. package/dist/client/panel/state-section.d.ts +25 -3
  23. package/dist/client/panel/use-mstar-engine-status.d.ts +39 -14
  24. package/dist/client/panel/zones/Legend.d.ts +5 -3
  25. package/dist/client/panel/zones/TaskBoard.d.ts +13 -9
  26. package/dist/client.js +1038 -1242
  27. package/dist/engine-status-endpoint.d.ts +85 -8
  28. package/dist/engine-status-store.d.ts +91 -1
  29. package/dist/engine-status-wire.d.ts +9 -0
  30. package/dist/gates/_shared.d.ts +61 -9
  31. package/dist/gates/adapter.d.ts +32 -2
  32. package/dist/gates/agent-flow.d.ts +312 -60
  33. package/dist/gates/catalog.d.ts +59 -38
  34. package/dist/gates/dispatch.d.ts +11 -2
  35. package/dist/gates/goal-bridge.d.ts +10 -130
  36. package/dist/gates/plan-mode-bridge.d.ts +20 -11
  37. package/dist/gates/role-persona.d.ts +16 -0
  38. package/dist/gates/steering.d.ts +41 -0
  39. package/dist/gates/workflow-ledger.d.ts +31 -4
  40. package/dist/gates/workflow-selection.d.ts +41 -20
  41. package/dist/index.js +1208 -394
  42. package/dist/types.d.ts +50 -18
  43. package/harness-commands/amazing-pr-review.md +2 -0
  44. package/harness-commands/codebase-audit.md +2 -0
  45. package/harness-skills/mstar-host/SKILL.md +3 -1
  46. package/harness-skills/mstar-host/references/dsh-workflow-scripts.md +424 -0
  47. package/harness-skills/mstar-host/references/dsh.md +259 -266
  48. package/harness-skills/mstar-roles/references/project-manager.md +2 -0
  49. package/harness-skills/mstar-sdd/SKILL.md +2 -0
  50. package/package.json +66 -64
  51. package/dist/client/panel/pages/AgentCanvasPage.d.ts +0 -345
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `mstar-engine-status` catalog source + payload: the durable `catalog`-form
2
+ * `mstar-engine` catalog source + payload: the durable `catalog`-form
3
3
  * MessageSource the plugin appends to every composed step at
4
4
  * `agent/pre-step`, so the model-visible engine-status row is
5
5
  * reconstructable from the session log without re-parsing its prose
@@ -25,15 +25,22 @@ import type { EnforcementFlag } from '@mstar-harness/engine';
25
25
  * `plugin` arm with a CLOSED member set — exactly these three keys, never a
26
26
  * fourth.
27
27
  *
28
- * `plugin` carries the plugin's identity literal and `form: 'catalog'` the
29
- * row's first-party presentation; both are opaque, already-admitted
30
- * vocabulary at every released session-format edge. Everything the row
31
- * publishes about the workspace lives in
32
- * {@link MstarEngineStatusPayload}, which never rides `source`.
28
+ * `plugin` carries the plugin's identity and `form: 'catalog'` the row's
29
+ * first-party presentation; both are opaque, already-admitted vocabulary at
30
+ * every released session-format edge. Everything the row publishes about the
31
+ * workspace lives in {@link MstarEngineStatusPayload}, which never rides
32
+ * `source`.
33
+ *
34
+ * The `plugin` union is the PERSISTED-LOG vocabulary, not a write-time
35
+ * choice: the plugin emits `mstar-engine`, while rows emitted by shipped
36
+ * builds before 2026-09-11 persist `mstar-engine-status` in already-written
37
+ * session logs. Both are valid persisted rows; the panel's anchor reader
38
+ * accepts both (data compat for persisted session logs, not a code-compat
39
+ * layer).
33
40
  */
34
41
  export interface MstarEngineStatusSource {
35
42
  readonly kind: 'plugin';
36
- readonly plugin: 'mstar-engine-status';
43
+ readonly plugin: 'mstar-engine' | 'mstar-engine-status';
37
44
  readonly form: 'catalog';
38
45
  }
39
46
  /**
@@ -172,20 +179,25 @@ export interface MstarHarnessProject {
172
179
  }
173
180
  /**
174
181
  * The catalog's workflow selection result (compass v3.0.0 § Catalog
175
- * selection rule): the lifecycle the state section aggregates.
176
- * `active` = the root v2 `workflows[]` first entry (with a structured
177
- * warning when multiple active lifecycles — no silent pick); `terminal` =
178
- * the latest terminal snapshot by mtime (history view); `error` = a clear
179
- * selection failure (v1/unmigrated root, no snapshots) — never a root v1
180
- * read. Structured and panel-renderable (not only a log line).
182
+ * selection rule): the lifecycle the state section aggregates, resolved by
183
+ * the locked binding order — lease (an `execution_lease` holder match or a
184
+ * `worktree_path` containing the session cwd) → cwd (a
185
+ * `control_worktree_path` containing it) → the session's durable
186
+ * `selectedWorkflowId` → the only active entry. `terminal` = the latest
187
+ * terminal snapshot by mtime (history view; reachable only when the active
188
+ * registry is EMPTY); `error` = a clear selection failure (v1/unmigrated
189
+ * root, no snapshots, or N>1 active lifecycles with no binding — then
190
+ * `activeWorkflowIds` carries the picker rows) — never a root v1 read and
191
+ * never the registry's first entry. Structured and panel-renderable (not
192
+ * only a log line).
181
193
  */
182
194
  export type WorkflowSelectionView = {
183
195
  readonly kind: 'active';
184
- /** The selected active lifecycle id (root v2 `workflows[]` first entry). */
196
+ /** The selected active lifecycle id (a root v2 `workflows[]` entry). */
185
197
  readonly workflowId: string;
186
198
  /** Harness-relative workflow dir (e.g. `workflows/<id>`). */
187
199
  readonly dir: string;
188
- /** Present when multiple active lifecycles — the first was picked (no silent pick). */
200
+ /** Structured warning attached by a resolver, when it has one. */
189
201
  readonly warning?: {
190
202
  readonly code: string;
191
203
  readonly message: string;
@@ -198,6 +210,11 @@ export type WorkflowSelectionView = {
198
210
  readonly kind: 'error';
199
211
  readonly code: string;
200
212
  readonly message: string;
213
+ /**
214
+ * Present on the multi-active-unbound error: the validated active ids,
215
+ * in registry order — the actionable rows of the operator's picker.
216
+ */
217
+ readonly activeWorkflowIds?: readonly string[];
201
218
  };
202
219
  /**
203
220
  * The workspace-state digest section of the unified engine-status row: the
@@ -291,7 +308,7 @@ export interface MstarHarnessState {
291
308
  */
292
309
  export interface AgentFlowEventView {
293
310
  readonly ts: number;
294
- readonly kind: 'dispatch' | 'settle' | 'workflow-run' | 'workflow-agent' | 'workflow-run-end' | 'workflow-verdict';
311
+ readonly kind: 'dispatch' | 'settle' | 'subagent-link' | 'workflow-run' | 'workflow-agent' | 'workflow-run-end' | 'workflow-verdict';
295
312
  /** The session's stable id; null when the event carried none. */
296
313
  readonly agent: string | null;
297
314
  /** Assignment `Execute as` ('' for settle rows without a paired identity). */
@@ -321,12 +338,27 @@ export interface AgentFlowEventView {
321
338
  readonly name?: string;
322
339
  /** Run-member 1-based sequence within the run (workflow-agent events only). */
323
340
  readonly seq?: number;
324
- /** Run-member display label (workflow-agent events only). */
341
+ /** Run-member display label (workflow-agent events), or the delegation label a `subagent-link` correlated (link events). */
325
342
  readonly label?: string;
326
343
  /** Run-member phase — workflow-agent events only, when carried. */
327
344
  readonly phase?: string;
328
- /** The published member's child session identity (workflow-agent events only). */
345
+ /**
346
+ * The child session identity the row carries, when its source supplied one:
347
+ * workflow-agent rows — the published member's child; settle rows — the
348
+ * returned foreground `runId`, or a background child id the catalog join
349
+ * supplied (OMITTED when the completion knew none); `subagent-link` rows —
350
+ * the required catalog child id. Never a registry job id (that is
351
+ * `taskRef`) and never fabricated.
352
+ */
329
353
  readonly childId?: string;
354
+ /**
355
+ * Settle + `subagent-link` rows: the registry background-job id the row
356
+ * carries (`jobs.onJobDone` → `recordJobSettle`; the post-execute
357
+ * background branch for a link). A jobs-registry key (`<kind>-N`), never a
358
+ * child session id and never the Assignment `Task N` tag. A continuable
359
+ * link omits it (that path starts no registry job).
360
+ */
361
+ readonly taskRef?: string;
330
362
  /** Terminal workflow run reason (workflow-run-end events only). */
331
363
  readonly stopReason?: 'completed' | 'cancelled' | 'error';
332
364
  /** The matched workflow/ralph tool name (workflow-verdict events only). */
@@ -29,4 +29,6 @@ Execute **`mstar-audit` § `pr` variant end to end**(`references/pr-review.md`
29
29
  3. **Synthesize (main agent)** — dedupe + tiered three-way vet (full for must-fix/should-fix; evidence-verify for nits) → tally/verdict(**§ Tally and derived score**)→ persist the **`mstar.review/v1` envelope**(mandatory)→ report + GitHub Review POST per **§ Comment posting**(`posted: yes` / `n/a-no-pr` / `failed`;event fixed `COMMENT`)→ save local report + evidence files per **§ Local report archive**(all three posting branches;write `elapsed` into the report frontmatter — measured minutes since the step-2 worktree-setup start time)→ **then** worktree cleanup(`mstar pr-review worktree-cleanup`).
30
30
  4. **Batch** — one session = one PR per **§ Batch sibling PRs**;其余 PR → `mstar status backlog-register` 登记为 audit todos,建议各自独立 session.
31
31
 
32
+ **dsh host only.** On dsh the `deep` tier's seats go through the native **`workflow`** tool, not `subagent`: after `/amazing-pr-review deep`, take the `script` + `meta` (`meta.name: mstar-pr-seats`) from skill **`mstar-host`** → `references/dsh-workflow-scripts.md` (§ `mstar-pr-seats`) — 2–3 domain seats plus the optional cross-domain security seat, each `agent()` prompt opening with the Assignment header (`Execute as:` / `Delegation: forbidden`), all read-only, findings only (no verdict, no posting). The `default` tier (2 seats) and `quick` (1 seat) keep `subagent` — cards, no `workflow-run` node (expected). Other hosts unchanged.
33
+
32
34
  Findings that need fixing → self-contained plans per **`mstar-audit` SKILL.md `## Plan output (all variants)`**(normal Prepare → Execute flow). Report the verdict + findings + posted review URL; the `tier:` declaration and any downgrade/upgrade `- notes:` follow **§ Review depth (tiers)** report contract.
@@ -27,6 +27,8 @@ Run a read-only codebase audit that discovers what is worth doing and writes sel
27
27
  | **Large repo** (parallel categories needed) | `@code-reviewer` fans out read-only `scout` / `explore` subagents per category via Assignment `Delegation: allowed (scout/explore only, read-only)`, then vets and writes plans |
28
28
  | **Specialist depth needed** | PM orchestrates an `@architect` consult for architecture/tech-debt depth (separate dispatch, or folded into the audit delegation brief) |
29
29
 
30
+ **dsh host only.** On dsh the large-repo fan-out goes through the native **`workflow`** tool, not `subagent`: after the operator types `/codebase-audit`, take the `script` + `meta` (`meta.name: mstar-audit-fanout`) from skill **`mstar-host`** → `references/dsh-workflow-scripts.md` (§ `mstar-audit-fanout`) — N≥3 read-only category seats, each `agent()` prompt opening with the Assignment header (`Execute as:` / `Delegation: forbidden`), one conversation `workflow-run` node. Other hosts unchanged (they keep their own invoke tool: `task` / Task).
31
+
30
32
  This command is the PM entry point; the audit execution body is `code-reviewer`(PM dispatch).
31
33
 
32
34
  The audit is **advisory** — it does not enter the per-plan state machine (`Todo → InProgress → InReview → Done`). Its output is plan *candidates*.
@@ -48,9 +48,11 @@ Order matters: check `cursor` → `opencode` → `omp` → `dsh` → `kimi` →
48
48
 
49
49
  When PM dispatches **N >= 2** concurrent assignees (QC tri-review, dual-track implement, etc.) and the host exposes actual invoke / Task / subagent tools, read **`references/parallel-dispatch.md`** in the dispatch round (shared with `mstar-dispatch-gates`). Without a callable invoke tool when dispatch is required → **`Blocked`**; Assignment Markdown alone is not dispatch.
50
50
 
51
+ On **dsh** only, read-only fan-out of **N ≥ 3** seats runs through the native **`workflow`** tool instead of N `subagent` invokes (1–2 delegations keep `subagent`; writable fan-out never uses it) — scripts + operator path: `references/dsh.md` § Read-only fan-out via the `workflow` tool.
52
+
51
53
  ## `/goal` directive (host-agnostic)
52
54
 
53
- **Applicability is by capability, not host identity**: any host that exposes a `/goal` command (currently Codex Goal Mode and omp; other code agents may add it later) attaches a persistent objective to the thread. Rule — **always set the goal to running the complete flow to the end**, never a sub-stage:
55
+ **Applicability is by capability, not host identity**: any host that exposes a `/goal` command (currently Codex Goal Mode and omp; other code agents may add it later) attaches a persistent objective to the thread. **Exception — dsh:** mstar **stops arming** a goal there and never uses a `/goal` objective or a goal round loop as the progression driver — dsh runs on the native workflow (workflow snapshot phases + dispatch gates + **subagent settle notifications**; Phase 2 is a PM-local dispatch → wait for the child's settle notification → next dispatch, and a manually armed `/goal` stays outside mstar's flow). Full rule → `references/dsh.md`. Rule — **always set the goal to running the complete flow to the end**, never a sub-stage:
54
56
 
55
57
  - **Advancing an iteration**: set the goal to **complete the entire iteration flow** (`iteration-start → per-plan cycles → iteration-close → PR delivery → PR merge-ready loop`). Do not set a sub-stage goal (e.g. "finish Phase 1 only").
56
58
  - **Advancing non-iteration work** (single plan / hotfix / one-off task): set the goal to **complete the entire per-plan flow** (`specify → clarify → plan → tasks → implement → plan QC tri + QA gate → Done`). Do not set a sub-stage goal (e.g. "write the plan" or "implement one task").
@@ -0,0 +1,424 @@
1
+ # dsh workflow scripts — canonical read-only fan-out templates
2
+
3
+ Copy-paste templates for the dsh **`workflow`** tool (`@deepseek-ai/dsh-tool-workflow`, mounted by the
4
+ shipped agent presets; the `ptc` preset disables it). Use them for **read-only** fan-out of **N ≥ 3**
5
+ seats — plan QC tri, large-repo audit categories, `/amazing-pr-review deep` seats. House rules and the
6
+ operator path live in skill **`mstar-host`** → `references/dsh.md` § Read-only fan-out via the `workflow`
7
+ tool; this file holds only the scripts, their `meta`, and their `args`.
8
+
9
+ ## How to call
10
+
11
+ One `workflow` tool call carries three JSON/JS parameters:
12
+
13
+ - `script` — a plain-JavaScript body (NOT TypeScript, NO `export const meta` statement), top-level
14
+ `await` allowed, ending with `return <JSON value>`.
15
+ - `meta` — plain JSON identity: `name` (short kebab-case), `description`, optional `whenToUse`,
16
+ optional `phases[] = { title, detail? }`. `phase()` calls and `agent({ phase })` strings match
17
+ `phases[].title` by exact string.
18
+ - `args` — plain JSON object exposed to the script verbatim as the `args` global.
19
+
20
+ Script hooks: `agent(prompt, opts?)`, `parallel(thunks)`, `pipeline(items, ...stages)`, `phase(title)`,
21
+ `log(message)`, `args`. `agent()` opts are exactly `label`, `phase`, `schema`, `provider`, `model` —
22
+ anything else (including the deferred agent-type selector and `effort` / `isolation`) is rejected
23
+ loudly and kills the script. With `schema` the child resolves to the validated object; on child
24
+ failure `agent()` resolves `null` (`parallel()` maps a throwing thunk to `null` the same way). No
25
+ filesystem, network, timers or Node APIs; concurrency and total-agent caps apply; the parent turn
26
+ blocks until the whole run settles.
27
+
28
+ Supported `schema` subset (object-rooted): `type`, `properties`, `required`, `additionalProperties`,
29
+ `items`, `enum`, `const`, `oneOf`, plus the ignored annotations `description` / `title` / `default` /
30
+ `examples`. Anything else (`pattern`, `format`, numeric bounds) is fatal.
31
+
32
+ Every `agent()` prompt below opens with the Assignment header (`## Assignment` + `Execute as` /
33
+ `Delegation` / `Task category`) — header first, because the engine reads only the header region, and
34
+ the role persona is resolved from `Execute as` (`packages/dsh/src/gates/role-persona.ts`). Children are
35
+ delegated children: approval is pinned to `never`, so a seat must never depend on writing files —
36
+ return everything in the result payload.
37
+
38
+ | Operator path | Script | `meta.name` | Seats |
39
+ |---|---|---|---|
40
+ | Plan QC tri (`Execution mode: sdd`) | § 1 | `mstar-qc-tri` | 3 (`qc-specialist`, `qc-specialist-2`, `qc-specialist-3`) |
41
+ | `/codebase-audit` large-repo category fan-out | § 2 | `mstar-audit-fanout` | 9 (one per audit category) |
42
+ | `/amazing-pr-review deep` | § 3 | `mstar-pr-seats` | 3–4 (2–3 domain + optional cross-domain security) |
43
+ | Any 1–2 read-only delegation | — | — | keep `subagent` — no script, no `workflow-run` node |
44
+
45
+ ## 1. `mstar-qc-tri` — plan QC tri-review
46
+
47
+ Three independent read-only QC seats over one review range; each returns a verdict envelope. The
48
+ returned envelopes are the seat reports' content source: the caller persists
49
+ `{SDD_DIR}/review/qc1.md` … `qc3.md` from them (a seat may also write its own file best-effort when
50
+ its sandbox permits).
51
+
52
+ **`meta`**
53
+
54
+ ```json
55
+ {
56
+ "name": "mstar-qc-tri",
57
+ "description": "Plan QC tri-review: three independent read-only QC seats over one review range, each returning a verdict envelope.",
58
+ "whenToUse": "dsh host, Execution mode: sdd — the whole-branch plan QC tri instead of three subagent dispatches.",
59
+ "phases": [
60
+ { "title": "qc-tri", "detail": "Three concurrent read-only QC seats over the same review range." }
61
+ ]
62
+ }
63
+ ```
64
+
65
+ **`args`**
66
+
67
+ ```json
68
+ {
69
+ "planId": "<plan-id>",
70
+ "planPath": "<absolute path to the main plan file>",
71
+ "range": "<base>..<head>",
72
+ "reviewCwd": "<absolute review worktree path>",
73
+ "branch": "feature/<plan-id>",
74
+ "sddDir": "<absolute path to the SDD dir>"
75
+ }
76
+ ```
77
+
78
+ **`script`**
79
+
80
+ ```js
81
+ const a = args ?? {}
82
+ const missing = ['planId', 'planPath', 'range', 'reviewCwd', 'branch', 'sddDir']
83
+ .filter((key) => typeof a[key] !== 'string' || a[key].length === 0)
84
+ if (missing.length > 0) throw new Error('mstar-qc-tri missing args: ' + missing.join(', '))
85
+
86
+ const sddDir = a.sddDir.replace(/\/$/, '')
87
+
88
+ const VERDICT = {
89
+ type: 'object',
90
+ description: 'One QC seat verdict envelope.',
91
+ required: ['seat', 'verdict', 'summary', 'findings'],
92
+ properties: {
93
+ seat: {
94
+ type: 'string',
95
+ enum: ['qc-specialist', 'qc-specialist-2', 'qc-specialist-3'],
96
+ description: 'The seat that produced this envelope.',
97
+ },
98
+ verdict: {
99
+ type: 'string',
100
+ enum: ['Approve', 'Request Changes', 'Needs Discussion', 'Unconfirmed'],
101
+ },
102
+ summary: {
103
+ type: 'string',
104
+ description: 'Two or three sentences; state the critical/warning counts.',
105
+ },
106
+ findings: {
107
+ type: 'array',
108
+ items: {
109
+ type: 'object',
110
+ required: ['severity', 'title', 'verification', 'expectedVsObserved'],
111
+ properties: {
112
+ severity: { type: 'string', enum: ['Critical', 'Warning', 'Suggestion', 'Unconfirmed'] },
113
+ title: { type: 'string', description: 'Short imperative title.' },
114
+ location: { type: 'string', description: 'path/file.ts:123 evidence anchor.' },
115
+ verification: { type: 'string', description: 'The cross-check used (diff/read/grep anchor or repro).' },
116
+ expectedVsObserved: { type: 'string' },
117
+ fix: { type: 'string', description: 'One line.' },
118
+ },
119
+ },
120
+ },
121
+ },
122
+ }
123
+
124
+ const opts = { phase: 'qc-tri', schema: VERDICT }
125
+
126
+ phase('qc-tri')
127
+
128
+ const seats = await parallel([
129
+ () => agent(`## Assignment
130
+
131
+ Execute as: qc-specialist
132
+ Delegation: forbidden
133
+ Task category: audit
134
+
135
+ plan_id: ${a.planId}
136
+ Review range: ${a.range}
137
+ Review cwd: ${a.reviewCwd}
138
+ Working branch: ${a.branch}
139
+ Report path: ${sddDir}/review/qc1.md
140
+ Reviewer focus: architecture coherence and maintainability risk (reviewer_index 1)
141
+
142
+ You are the first of three INDEPENDENT read-only QC seats over the same review range. Do not consult or wait for the other seats.
143
+
144
+ Load in order: skill mstar-roles then references/qc-specialist-shared.md (identity first), then references/qc-specialist/report-template.md and references/qc-specialist/reviewer-checklist.md; the plan at ${a.planPath}.
145
+
146
+ Review the whole-branch diff for the review range above against that plan. Every finding needs a verification cross-check and an expected-vs-observed line; prefer omission to fabrication. Do not run build or test suites (they are not your evidence channel). Never edit the worktree, never post, never merge, never touch project registers.
147
+
148
+ Return ONLY the JSON object matching the provided schema (seat, verdict, summary, findings). If your sandbox permits, also write the full report to the report path above — never depend on being able to write.`, { ...opts, label: 'qc1-architecture' }),
149
+ () => agent(`## Assignment
150
+
151
+ Execute as: qc-specialist-2
152
+ Delegation: forbidden
153
+ Task category: audit
154
+
155
+ plan_id: ${a.planId}
156
+ Review range: ${a.range}
157
+ Review cwd: ${a.reviewCwd}
158
+ Working branch: ${a.branch}
159
+ Report path: ${sddDir}/review/qc2.md
160
+ Reviewer focus: security and correctness risk (reviewer_index 2)
161
+
162
+ You are the second of three INDEPENDENT read-only QC seats over the same review range. Do not consult or wait for the other seats.
163
+
164
+ Load in order: skill mstar-roles then references/qc-specialist-shared.md (identity first), then references/qc-specialist/report-template.md, references/qc-specialist/reviewer-checklist.md and references/qc-specialist/deep-review-lenses.md; the plan at ${a.planPath}.
165
+
166
+ Review the whole-branch diff for the review range above against that plan, with the security and correctness lenses. Every finding needs a verification cross-check and an expected-vs-observed line; prefer omission to fabrication. Do not run build or test suites. Never edit the worktree, never post, never merge, never touch project registers.
167
+
168
+ Return ONLY the JSON object matching the provided schema (seat, verdict, summary, findings). If your sandbox permits, also write the full report to the report path above — never depend on being able to write.`, { ...opts, label: 'qc2-security-correctness' }),
169
+ () => agent(`## Assignment
170
+
171
+ Execute as: qc-specialist-3
172
+ Delegation: forbidden
173
+ Task category: audit
174
+
175
+ plan_id: ${a.planId}
176
+ Review range: ${a.range}
177
+ Review cwd: ${a.reviewCwd}
178
+ Working branch: ${a.branch}
179
+ Report path: ${sddDir}/review/qc3.md
180
+ Reviewer focus: performance and reliability risk (reviewer_index 3)
181
+
182
+ You are the third of three INDEPENDENT read-only QC seats over the same review range. Do not consult or wait for the other seats.
183
+
184
+ Load in order: skill mstar-roles then references/qc-specialist-shared.md (identity first), then references/qc-specialist/report-template.md, references/qc-specialist/reviewer-checklist.md and references/qc-specialist/deep-review-lenses.md; the plan at ${a.planPath}.
185
+
186
+ Review the whole-branch diff for the review range above against that plan, with the performance and reliability lenses. Every finding needs a verification cross-check and an expected-vs-observed line; prefer omission to fabrication. Do not run build or test suites. Never edit the worktree, never post, never merge, never touch project registers.
187
+
188
+ Return ONLY the JSON object matching the provided schema (seat, verdict, summary, findings). If your sandbox permits, also write the full report to the report path above — never depend on being able to write.`, { ...opts, label: 'qc3-perf-reliability' }),
189
+ ])
190
+
191
+ // A null entry is a seat whose child failed: its verdict is missing and the caller
192
+ // must re-dispatch that seat (or report Blocked) — never synthesize a verdict for it.
193
+ return seats
194
+ ```
195
+
196
+ ## 2. `mstar-audit-fanout` — large-repo category fan-out
197
+
198
+ One read-only audit seat per category (the nine `mstar-audit` categories), each returning findings in
199
+ the audit finding format. Scope comes from `args.categories` (default: all nine); the reconciling,
200
+ vetting and plan-writing stay with the audit executor (main agent).
201
+
202
+ **`meta`**
203
+
204
+ ```json
205
+ {
206
+ "name": "mstar-audit-fanout",
207
+ "description": "Large-repo codebase audit: one read-only audit seat per category, each returning findings in the audit finding format.",
208
+ "whenToUse": "dsh host, /codebase-audit on a repo large enough to need per-category parallel read-only fan-out (N >= 3).",
209
+ "phases": [
210
+ { "title": "bug" },
211
+ { "title": "security" },
212
+ { "title": "perf" },
213
+ { "title": "tests" },
214
+ { "title": "tech-debt" },
215
+ { "title": "migration" },
216
+ { "title": "dx" },
217
+ { "title": "docs" },
218
+ { "title": "direction" }
219
+ ]
220
+ }
221
+ ```
222
+
223
+ **`args`**
224
+
225
+ ```json
226
+ {
227
+ "repo": "<absolute path to the repo under audit>",
228
+ "auditRef": "<absolute path to the mstar-audit skill references dir>",
229
+ "recon": "<recon facts: languages, frameworks, key directories, what to skip, decided tradeoffs>",
230
+ "categories": ["bug", "security", "perf"]
231
+ }
232
+ ```
233
+
234
+ `categories` is optional — omit it for all nine. Keep the batch at one seat per category (concurrency
235
+ caps apply above the fan-out width).
236
+
237
+ **`script`**
238
+
239
+ ```js
240
+ const a = args ?? {}
241
+ const missing = ['repo', 'auditRef', 'recon']
242
+ .filter((key) => typeof a[key] !== 'string' || a[key].length === 0)
243
+ if (missing.length > 0) throw new Error('mstar-audit-fanout missing args: ' + missing.join(', '))
244
+
245
+ const ALL = ['bug', 'security', 'perf', 'tests', 'tech-debt', 'migration', 'dx', 'docs', 'direction']
246
+ const categories = Array.isArray(a.categories) && a.categories.length > 0 ? a.categories : ALL
247
+
248
+ const FINDING = {
249
+ type: 'object',
250
+ description: 'One audit category seat payload.',
251
+ required: ['category', 'findings'],
252
+ properties: {
253
+ category: { type: 'string', enum: ALL },
254
+ findings: {
255
+ type: 'array',
256
+ items: {
257
+ type: 'object',
258
+ required: ['title', 'evidence', 'impact', 'effort', 'risk', 'confidence', 'fix'],
259
+ properties: {
260
+ title: { type: 'string', description: 'Short imperative title.' },
261
+ evidence: { type: 'string', description: 'path/file.ts:123 plus one sentence (2-5 strongest locations).' },
262
+ impact: { type: 'string', description: 'What goes wrong / what is being paid.' },
263
+ effort: { type: 'string', enum: ['XS', 'S', 'M', 'L', 'XL'] },
264
+ risk: { type: 'string', enum: ['LOW', 'MED', 'HIGH'], description: 'What the fix could break, plus one line why.' },
265
+ confidence: { type: 'string', enum: ['HIGH', 'MED', 'LOW'] },
266
+ fix: { type: 'string', description: 'One to three sentences — a sketch, not the plan.' },
267
+ },
268
+ },
269
+ },
270
+ notes: { type: 'string', description: 'Truncated coverage declaration and leads that are not findings.' },
271
+ },
272
+ }
273
+
274
+ const seatPrompt = (category) => `## Assignment
275
+
276
+ Execute as: code-reviewer
277
+ Delegation: forbidden
278
+ Task category: audit
279
+
280
+ Audit category: ${category}
281
+ Repo under audit: ${a.repo}
282
+ Reference root: ${a.auditRef}
283
+
284
+ Read-only audit seat (one category of a parallel fan-out; the audit executor reconciles, vets and writes plans — you do not).
285
+
286
+ Recon facts already established: ${a.recon}
287
+
288
+ Load in order: ${a.auditRef}/audit-playbook.md section for your category plus the section "Finding format" (read it first — findings must match that shape exactly); for the security category also read ${a.auditRef}/security-review.md. Open every location you cite yourself, in ${a.repo}.
289
+
290
+ Report only what you can evidence: exact file:line anchors, a concrete impact, an honest effort on the XS-XL scale, the risk of the fix, and a HIGH/MED/LOW confidence. LOW-confidence items are allowed but are leads, not plan candidates. Do not edit any file, do not run project-wide suites, never reproduce secret values.
291
+
292
+ Return ONLY the JSON object matching the provided schema (category, findings, notes). Put the truncated-coverage declaration and any non-finding leads in notes.`
293
+
294
+ const seats = await parallel(categories.map((category) => () =>
295
+ agent(seatPrompt(category), { label: category, phase: category, schema: FINDING })))
296
+
297
+ // A null entry is a category whose seat failed — the caller reports the uncollected
298
+ // category as such; it is never reported as "no findings".
299
+ return seats
300
+ ```
301
+
302
+ ## 3. `mstar-pr-seats` — `/amazing-pr-review deep` seats
303
+
304
+ Domain seats (2–3) plus an optional independent cross-domain security seat, all read-only, all
305
+ returning findings with a merge class and **no verdict** — synthesis (dedupe, tiered vet, tally,
306
+ verdict, posting) stays with the main agent, exactly as the `pr` variant requires. Do not use this
307
+ script for the `default` tier (two seats → `subagent`) or `quick` (one seat).
308
+
309
+ **`meta`**
310
+
311
+ ```json
312
+ {
313
+ "name": "mstar-pr-seats",
314
+ "description": "Deep PR review: read-only domain review seats (2-3) plus an optional independent cross-domain security seat, each returning findings with a merge class and no verdict.",
315
+ "whenToUse": "dsh host, /amazing-pr-review deep (3-4 seats) after the review worktree and diff basis are resolved.",
316
+ "phases": [
317
+ { "title": "pr-seats", "detail": "Domain review seats plus the cross-domain security seat." }
318
+ ]
319
+ }
320
+ ```
321
+
322
+ **`args`**
323
+
324
+ ```json
325
+ {
326
+ "worktree": "<absolute review worktree path>",
327
+ "target": "<owner>/<repo>#<n> or branch:<slug> or diff:<short-sha>",
328
+ "diffBase": "<base>..<head>",
329
+ "diffFile": "<absolute path to the pinned diff snapshot, when worktree-setup produced one>",
330
+ "reportsDir": "<absolute directory for the stage-2 evidence files>",
331
+ "auditRef": "<absolute path to the mstar-audit skill references dir>",
332
+ "domains": ["code", "tests"],
333
+ "security": true
334
+ }
335
+ ```
336
+
337
+ `domains` holds 2–3 domain labels (business domain / change surface / tech stack); with
338
+ `security: true` (the default) the seat count is 3 or 4.
339
+
340
+ **`script`**
341
+
342
+ ```js
343
+ const a = args ?? {}
344
+ const missing = ['worktree', 'target', 'diffBase', 'reportsDir', 'auditRef']
345
+ .filter((key) => typeof a[key] !== 'string' || a[key].length === 0)
346
+ if (missing.length > 0) throw new Error('mstar-pr-seats missing args: ' + missing.join(', '))
347
+
348
+ const domains = Array.isArray(a.domains) ? a.domains : []
349
+ if (domains.length < 2 || domains.length > 3) {
350
+ throw new Error('mstar-pr-seats: args.domains must hold 2-3 domain labels (deep tier) — got ' + domains.length)
351
+ }
352
+ const withSecurity = a.security !== false
353
+ const diffHint = typeof a.diffFile === 'string' && a.diffFile.length > 0
354
+ ? 'the pinned diff snapshot at ' + a.diffFile + ', plus ' + a.diffBase + ' in ' + a.worktree
355
+ : a.diffBase + ' in ' + a.worktree
356
+
357
+ const SEAT = {
358
+ type: 'object',
359
+ description: 'One read-only PR review seat payload (findings only — the seat produces no verdict).',
360
+ required: ['domain', 'findings'],
361
+ properties: {
362
+ domain: { type: 'string', description: 'The seat domain label.' },
363
+ findings: {
364
+ type: 'array',
365
+ items: {
366
+ type: 'object',
367
+ required: ['title', 'evidence', 'impact', 'effort', 'risk', 'confidence', 'mergeClass', 'fix'],
368
+ properties: {
369
+ title: { type: 'string', description: 'Short imperative title.' },
370
+ evidence: { type: 'string', description: 'path/file.ts:123 — code you opened yourself.' },
371
+ impact: { type: 'string' },
372
+ effort: { type: 'string', enum: ['XS', 'S', 'M', 'L', 'XL'] },
373
+ risk: { type: 'string', enum: ['LOW', 'MED', 'HIGH'] },
374
+ confidence: { type: 'string', enum: ['HIGH', 'MED', 'LOW'] },
375
+ mergeClass: { type: 'string', enum: ['must-fix', 'should-fix', 'nit'] },
376
+ fix: { type: 'string', description: 'One line.' },
377
+ },
378
+ },
379
+ },
380
+ leads: { type: 'array', items: { type: 'string' }, description: 'MEDIUM/unverified observations — leads, not findings.' },
381
+ notes: { type: 'string', description: 'Truncated-coverage declaration and cross-domain notes.' },
382
+ },
383
+ }
384
+
385
+ const seatPrompt = (domain, extra) => `## Assignment
386
+
387
+ Execute as: code-reviewer
388
+ Delegation: forbidden
389
+ Task category: audit
390
+
391
+ Review target: ${a.target}
392
+ Review worktree: ${a.worktree}
393
+ Domain: ${domain}
394
+ Diff basis: ${a.diffBase}
395
+ Stage: Stage 2 domain review — read-only, you never post and never produce the verdict.
396
+
397
+ Read-only audit seat in the three-stage PR review pipeline; the main agent synthesizes one verdict and posts.
398
+
399
+ Load in order: skill mstar-audit then SKILL.md and references/pr-review-seat-evidence.md; ${a.auditRef}/pr-review.md sections "Review pipeline", "Merge class" and "Verdict synthesis"; ${a.auditRef}/finding-format.md for the finding fields. Then read ${diffHint}. Open the cited code yourself — a relayed claim from another seat is not evidence.
400
+
401
+ Conclude ONLY on your own domain (${domain}).${extra} Return findings with merge class must-fix | should-fix | nit, an XS-XL effort, a risk level, a confidence and a one-line fix sketch. Cross-domain boundary issues go to notes, not findings. Do not edit the worktree, do not run project-wide suites, never reproduce secret values.
402
+
403
+ Return ONLY the JSON object matching the provided schema (domain, findings, leads, notes). No verdict.`
404
+
405
+ phase('pr-seats')
406
+
407
+ const thunks = domains.map((domain, index) => () => agent(
408
+ seatPrompt(domain, ''),
409
+ { label: 'domain-' + (index + 1), phase: 'pr-seats', schema: SEAT },
410
+ ))
411
+
412
+ if (withSecurity) {
413
+ thunks.push(() => agent(
414
+ seatPrompt('security (cross-domain)', ' Run the security lens from ' + a.auditRef + '/security-review.md across the whole diff, independent of the domain seats: trace data flow to its origin, never invent an attacker, never record secret values.'),
415
+ { label: 'security-cross-domain', phase: 'pr-seats', schema: SEAT },
416
+ ))
417
+ }
418
+
419
+ const seats = await parallel(thunks)
420
+
421
+ // A null entry is an uncollected domain (seat crashed or returned nothing) — the caller
422
+ // declares it as uncollected under the report notes and never reads it as "no findings".
423
+ return seats
424
+ ```