@mstar-harness/dsh 3.6.3 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +4 -6
  2. package/README.zh.md +3 -3
  3. package/dist/client/panel/PanelView.d.ts +8 -11
  4. package/dist/client/panel/TabNav.d.ts +2 -2
  5. package/dist/client/panel/graph/event-log.d.ts +5 -9
  6. package/dist/client/panel/graph/project-graph.d.ts +53 -72
  7. package/dist/client/panel/graph/schema.d.ts +31 -37
  8. package/dist/client/panel/locale.d.ts +19 -19
  9. package/dist/client/panel/pages/AgentCanvasPage.d.ts +40 -58
  10. package/dist/client/panel/pages/EventLogPage.d.ts +6 -6
  11. package/dist/client/panel/pages/IterationInfoSection.d.ts +9 -11
  12. package/dist/client/panel/pages/IterationTaskPage.d.ts +3 -3
  13. package/dist/client/panel/plan-sort.d.ts +3 -6
  14. package/dist/client/panel/state-section.d.ts +1 -1
  15. package/dist/client/panel/zones/Legend.d.ts +2 -2
  16. package/dist/client/panel/zones/ProjectRollup.d.ts +1 -2
  17. package/dist/client/panel/zones/TaskBoard.d.ts +1 -2
  18. package/dist/gates/_shared.d.ts +7 -10
  19. package/dist/gates/adapter.d.ts +6 -9
  20. package/dist/gates/agent-flow.d.ts +49 -59
  21. package/dist/gates/agent-personas.d.ts +1 -2
  22. package/dist/gates/catalog.d.ts +2 -5
  23. package/dist/gates/dispatch.d.ts +9 -11
  24. package/dist/gates/fallbacks-advisory.d.ts +2 -3
  25. package/dist/gates/fallbacks-probe.d.ts +2 -2
  26. package/dist/gates/fallbacks-seeds.d.ts +1 -1
  27. package/dist/gates/fallbacks-structural.d.ts +1 -1
  28. package/dist/gates/goal-bridge.d.ts +6 -9
  29. package/dist/gates/role-persona.d.ts +2 -3
  30. package/dist/gates/skill-lint.d.ts +19 -2
  31. package/dist/gates/system-prompt.d.ts +7 -11
  32. package/dist/gates/tools.d.ts +1 -1
  33. package/dist/gates/workflow-ledger.d.ts +21 -28
  34. package/dist/gates/workflow-policy.d.ts +15 -19
  35. package/dist/gates/workflow-selection.d.ts +3 -3
  36. package/dist/index.js +215 -33
  37. package/dist/types.d.ts +4 -7
  38. package/harness-commands/iteration-drive.md +6 -6
  39. package/harness-commands/iteration-loop.md +7 -7
  40. package/harness-commands/iteration-start.md +8 -8
  41. package/harness-skills/mstar-coding-behavior/SKILL.md +3 -20
  42. package/harness-skills/mstar-dispatch-gates/SKILL.md +7 -13
  43. package/harness-skills/mstar-dispatch-gates/references/leaf-executor-checklist.md +1 -1
  44. package/harness-skills/mstar-harness-core/SKILL.md +9 -53
  45. package/harness-skills/mstar-host/references/zcode.md +1 -0
  46. package/harness-skills/mstar-iteration/SKILL.md +32 -318
  47. package/harness-skills/mstar-iteration/references/command-shared-invariants.md +1 -1
  48. package/harness-skills/mstar-iteration/references/phase-1-prepare.md +155 -0
  49. package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +113 -3
  50. package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +1 -1
  51. package/harness-skills/mstar-roles/SKILL.md +14 -12
  52. package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +5 -6
  53. package/harness-skills/mstar-roles/references/architect.md +1 -1
  54. package/harness-skills/mstar-roles/references/code-reviewer.md +11 -1
  55. package/harness-skills/mstar-roles/references/frontend-dev.md +1 -1
  56. package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +1 -1
  57. package/harness-skills/mstar-roles/references/ops-engineer.md +1 -1
  58. package/harness-skills/mstar-roles/references/product-manager.md +1 -1
  59. package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +4 -0
  60. package/harness-skills/mstar-roles/references/project-manager.md +6 -4
  61. package/harness-skills/mstar-roles/references/prompt-engineer.md +1 -1
  62. package/harness-skills/mstar-roles/references/qa-engineer.md +1 -1
  63. package/harness-skills/mstar-roles/references/qc-specialist-shared.md +1 -1
  64. package/harness-skills/mstar-roles/references/writing-specialist.md +1 -1
  65. package/harness-skills/mstar-sdd/references/file-handoffs.md +40 -7
  66. package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +9 -0
  67. package/harness-skills/mstar-sdd/references/implementer-prompt.md +9 -0
  68. package/harness-skills/mstar-sdd/references/task-reviewer-prompt.md +7 -0
  69. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
- * IterationInfoSection (spec panel-tabs §3, plan 20260812-panel-f5-design-system
3
- * Task 8 — the SHARED iteration info block, user 2026-08-12 feedback #4): the
2
+ * IterationInfoSection (spec panel-tabs §3
3
+ * — the SHARED iteration info block): the
4
4
  * Content Head — iteration summary (the collapsible toggle row) + the 5
5
5
  * horizontal iteration steps + the branches panel — rendered by BOTH tabs
6
6
  * from the SAME `view.iteration` data (the tasks tab inside IterationTaskPage
@@ -12,14 +12,13 @@
12
12
  *
13
13
  * - Content Head (spec §3): the iteration info (iterationId / gate verdict /
14
14
  * status note) rides the summary row, which IS the toggle (a native button
15
- * with aria-expanded + aria-controls pointing at the body — QC wave). The
15
+ * with aria-expanded + aria-controls pointing at the body). The
16
16
  * expanded body renders the Steps HORIZONTALLY as 5 EQUAL full-width unit
17
- * blocks (plan 20260811-panel-f2-quickfix Item 1 — badge/phase/chip
17
+ * blocks (badge/phase/chip
18
18
  * centered, --mstar-space-* gap; no connector bars) with the current step
19
19
  * highlighted on the block itself (the same honesty as the zone stepper:
20
20
  * no "completed" checkmarks) plus the branch panel (rendered ONLY while the
21
- * iteration is active, spec §3). Plan 20260811-panel-f4-iteration-zone
22
- * Task 2 (spec panel-f4 §2.3 R8/R9): the expanded body is a LEFT-RIGHT
21
+ * iteration is active, spec §3). Plan (spec panel-f4 §2.3 R8/R9): the expanded body is a LEFT-RIGHT
23
22
  * SPLIT — branches (small half, DOM-first) + steps (large half), with the
24
23
  * `data-iteration-head-split` container present only while branches render;
25
24
  * each step reserves the fixed-height verdict seat (`data-step-verdict-seat`)
@@ -27,13 +26,12 @@
27
26
  * verdict (`state === 'current' && verdict !== 'unknown'` — Phase 1 renders
28
27
  * no badge), so the centered content groups align across steps.
29
28
  *
30
- * Collapse/expand (spec §3 / Task 2 brief): a local `useState` defaulted to
29
+ * Collapse/expand (spec §3): a local `useState` defaulted to
31
30
  * the iteration state — `active === false` → collapsed to a one-line summary
32
31
  * (iterationId/verdict + the muted "not started" note, expandable to the idle
33
32
  * 5-step skeleton); `active === true` → expanded. SSR-stable: the default is
34
33
  * data-derived, so `renderToStaticMarkup` renders a deterministic state per
35
- * row that tests can pin statically. Live re-sync (Task 2 review
36
- * Important-1): a useEffect re-expands the head when the SAME mounted
34
+ * row that tests can pin statically. Live re-sync: a useEffect re-expands the head when the SAME mounted
37
35
  * instance sees `active` flip false→true on a catalog update (started
38
36
  * iterations must show the expanded steps, spec §3); the transition is
39
37
  * one-way — user collapse while already active is never overridden.
@@ -51,7 +49,7 @@ export interface IterationInfoSectionProps {
51
49
  t: TranslateNS<'mstar-panel'>;
52
50
  }
53
51
  /**
54
- * Activation re-sync (Task 2 review Important-1): the collapse/expand state
52
+ * Activation re-sync: the collapse/expand state
55
53
  * must follow a LIVE `active` flip on the SAME mounted instance — spec §3
56
54
  * says 启动迭代才展开 (an active iteration shows the expanded steps), and a
57
55
  * fresh catalog row can flip `iteration.active` false→true without a remount.
@@ -66,7 +64,7 @@ export interface IterationInfoSectionProps {
66
64
  */
67
65
  export declare function nextExpandedOnActivation(prev: boolean, prevActive: boolean, nextActive: boolean): boolean;
68
66
  /**
69
- * The split-layout wrapper decision (spec panel-f4 §2.3 R8, plan f4.3 Task 2
67
+ * The split-layout wrapper decision (spec panel-f4 §2.3 R8
70
68
  * — exported pure for the render tests, the `nextExpandedOnActivation`
71
69
  * precedent): the `data-iteration-head-split` container renders ONLY while
72
70
  * the branch panel renders (`active && branches !== null`); otherwise the
@@ -1,8 +1,8 @@
1
1
  /**
2
- * IterationTaskPage (spec panel-tabs §3, plan 20260811-panel-tabs-shell
3
- * Task 2) — the 任务迭代 tab: the SHARED IterationInfoSection (iteration
2
+ * IterationTaskPage (spec panel-tabs §3
3
+ * — the 任务迭代 tab: the SHARED IterationInfoSection (iteration
4
4
  * summary + the 5 horizontal iteration steps + branches — the same block the
5
- * agents tab renders, plan 20260812-panel-f5-design-system Task 8, user
5
+ * agents tab renders, user
6
6
  * 2026-08-12 feedback #4) above the full-width standard kanban. Replaces the
7
7
  * WorkflowCanvas zone dashboard on the tasks tab (WorkflowCanvas is removed
8
8
  * by the plan close; its zone-level components stay untouched here).
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Sidebar / Done-column plan ordering (spec panel-zones §3): the hard-coded
3
- * digitized sort keys shared by the sidebar plan board (this plan, Task 3)
4
- * and the canvas Done column (plan 20260810-panel-canvas-zones reuses the
5
- * same rule). Pure function — no rendering, no state.
3
+ * digitized sort keys shared by the sidebar plan board (this plan)
4
+ * and the canvas Done column . Pure function — no rendering, no state.
6
5
  *
7
6
  * Keys, compared in order (all DESC):
8
7
  * 1. `doneAt` matching /^\d{4}-\d{2}-\d{2}$/ → '.replaceAll('-','')'
@@ -36,9 +35,7 @@ export declare function sortPlans<T extends {
36
35
  readonly doneAt: string | null;
37
36
  }>(plans: readonly T[]): T[];
38
37
  /**
39
- * The「最近一次迭代」recency comparator (plan 20260813-panel-quick-fixes Task
40
- * 2 — shared by the current-iteration filter in `project-graph.ts`, which
41
- * previously duplicated this order as a local `moreRecentPlan`). DIFFERENT
38
+ * The「最近一次迭代」recency comparator . DIFFERENT
42
39
  * key order from {@link comparePlans}: the 8-digit id-date prefix is PRIMARY,
43
40
  * doneAt SECONDARY — the projection's former `moreRecentPlan` behavior, kept
44
41
  * EXACTLY. All keys DESC: `< 0` means `a` is more recent than `b` (id-date
@@ -8,7 +8,7 @@
8
8
  * `none`, never crash.
9
9
  *
10
10
  * The branches block was removed from the sidebar in this task (moved to the
11
- * iteration zone, plan 20260810-panel-canvas-zones); the branch anchor fields
11
+ * iteration zone); the branch anchor fields
12
12
  * stay in the catalog source (the iteration zone consumes them).
13
13
  */
14
14
  import * as React from 'react';
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Legend (spec panel-tabs §4/§6.2, plan 20260811-panel-agent-canvas Task 3):
2
+ * Legend (spec panel-tabs §4/§6.2):
3
3
  * mounted on the AgentCanvasPage (the zone-dashboard footer legend is gone
4
4
  * with the WorkflowCanvas — spec §6.1). Describes ONLY the role-card status
5
5
  * treatments of the agent canvas — plan
6
- * 20260813-panel-agent-canvas-legend-layout Task 1 (图例精简): the 7
6
+ * Task 1 (图例精简): the 7
7
7
  * collaboration-edge / layout entries (flow-actual / port / group /
8
8
  * sub-bucket / supervise / on-demand / unknown) are REMOVED — the legend is
9
9
  * the 3 entity card treatments (running glow, settled = the standalone GREEN
@@ -1,6 +1,5 @@
1
1
  /**
2
- * ProjectRollup (plan `20260819-workflow-dsh-viz` Task 3 — compass v3.0.0
3
- * AC-4/AC-P3): the ADDITIVE project rollup zone of the tasks page — roadmap
2
+ * ProjectRollup : the ADDITIVE project rollup zone of the tasks page — roadmap
4
3
  * milestones + open-residual severity counts from the project layer
5
4
  * (`state.project`, produced by the catalog from `projects/<id>/roadmap.md`
6
5
  * frontmatter `milestones[]` + `projects/<id>/residuals.json` registers).
@@ -1,6 +1,5 @@
1
1
  /**
2
- * TaskBoard (plan 20260810-panel-canvas-zones Task 4, spec panel-zones §3;
3
- * plan 20260813-panel-quick-fixes Task 1) — the tasks-zone kanban: the 5
2
+ * TaskBoard — the tasks-zone kanban: the 5
4
3
  * PLAN_STATE_IDS columns (Todo / InProgress / InReview / Done /
5
4
  * blocked-unknown, in the projection's constant order), each with a localized
6
5
  * state-name header + count badge, plan cards (mono ellipsized id + status
@@ -79,9 +79,7 @@ export interface Config {
79
79
  roleMap?: Record<string, string>;
80
80
  /**
81
81
  * mstar role id → persona text — the native persona channel's only
82
- * payload source (plan `20260814-dsh-fallbacks-integration` Task 2;
83
- * channel reworked onto the native `SubagentStartRequest.persona` slot by
84
- * plan `20260831-dsh-alpha2-optional-fallbacks` Task 3). A role-matched
82
+ * payload source . A role-matched
85
83
  * one-shot start merges the persona into the request's native `persona`
86
84
  * slot — dsh composes it as the scoped shadowing `deployment:persona`
87
85
  * section on the child, persists it in the child descriptor, and reapplies
@@ -103,7 +101,7 @@ export interface Config {
103
101
  */
104
102
  rolePersonas?: Record<string, string>;
105
103
  /**
106
- * Workflow/ralph gate mode (plan `20260815-dsh-workflow-gate` W-B3, AC-7):
104
+ * Workflow/ralph gate mode :
107
105
  * `off` disables the gate entirely (workflow/ralph calls pass through
108
106
  * untouched, NO verdict row); `warn` (default) logs an advisory for
109
107
  * policy-unknown fan-out without ever blocking; `ask` routes first-seen
@@ -120,7 +118,7 @@ export interface Config {
120
118
  */
121
119
  workflowNames?: string[];
122
120
  /**
123
- * Goal-bridge round cap (plan `20260816-dsh-nb2-goal-bridge` Task 2): the
121
+ * Goal-bridge round cap : the
124
122
  * flat `maxGoalRounds` the goal bridge passes to the goals service when it
125
123
  * mirrors the active iteration objective (bounds autonomous Phase 2
126
124
  * loops — the service itself throws on resume past the cap). Absent →
@@ -147,7 +145,7 @@ export interface Config {
147
145
  export declare const PERSONA_INTERPOLATION_HAZARD: RegExp;
148
146
  /**
149
147
  * Screen ONE dynamic string before it is embedded into dsh system-prompt
150
- * section/context text (plan QC fix wave W-1): break every COMPLETE
148
+ * section/context text (): break every COMPLETE
151
149
  * `{{...}}` group (the renderer's STRICT `interpolate` throws on any `{{`
152
150
  * paired with a later `}}` — unknown variable, malformed group, undefined
153
151
  * value), while leaving a LONE `{{` without a later `}}` verbatim (upstream
@@ -169,7 +167,7 @@ export declare function formatViolation(violation: ValidationResult): string;
169
167
  export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
170
168
  /**
171
169
  * Cap on the plan / lease rows joined into the `<mstar_engine_status>`
172
- * catalog state lines (plan `20260830-dsh-catalog-cap` D1): ONE catalog-owned
170
+ * catalog state lines : ONE catalog-owned
173
171
  * constant shared by the `plans:` and `leases:` joins so an oversized
174
172
  * workflow snapshot cannot balloon the single-line catalog state section.
175
173
  * Numeric precedent: `DIGEST_PLAN_CAP` in `system-prompt.ts` (digest-side,
@@ -188,7 +186,7 @@ export declare const CATALOG_STATE_JOIN_LIMIT = 8;
188
186
  * (`length === 0` → `none` / `none registered` / `none active`) — this
189
187
  * helper is never reached for empty arrays.
190
188
  *
191
- * Hoisted from `system-prompt.ts` (plan `20260830-dsh-catalog-cap` D3) so
189
+ * Hoisted from `system-prompt.ts` so
192
190
  * the GLOBAL digest and the catalog state lines share ONE join-capping
193
191
  * implementation; `_shared.ts` imports no gates-local module, so no import
194
192
  * cycle is introduced.
@@ -240,8 +238,7 @@ export declare function packagedSkillsDir(): string | undefined;
240
238
  /**
241
239
  * Resolve the plugin package's own `harness-agents/` mirror (synced from the
242
240
  * repo root by `bundle-assets` at build time; gitignored) — the
243
- * zero-config role-persona default source (plan
244
- * `20260815-dsh-fallbacks-personas` Task 3). Same dual-depth probe semantics
241
+ * zero-config role-persona default source. Same dual-depth probe semantics
245
242
  * as {@link resolvePackagedSkillsDir}: `'../harness-agents'` (dist layout
246
243
  * candidate) then `'../../harness-agents'` (source-layout candidate);
247
244
  * `src/harness-agents` is non-canonical and skipped shallow-first.
@@ -17,7 +17,7 @@ export interface DshHostAdapterOptions {
17
17
  readonly config: Config;
18
18
  /**
19
19
  * The apply-scoped agent-flow pairing store (plan
20
- * `20260811-panel-f4-timeliness` Task 1 — created by the entry `apply`,
20
+ * Task 1 — created by the entry `apply`,
21
21
  * shared with the settle listener): passed to `recordDispatch` so an
22
22
  * exec-bound dispatch registers `callId → dispatchRef` for the later
23
23
  * post-execute settle pairing. Absent (host-adapter tests / direct
@@ -25,8 +25,7 @@ export interface DshHostAdapterOptions {
25
25
  */
26
26
  readonly pairing?: AgentFlowPairing;
27
27
  /**
28
- * The P-c first-seen ask cache (plan `20260815-dsh-workflow-gate`
29
- * Task 2): workflow name → resolved decision, apply-scoped. Absent (the
28
+ * The P-c first-seen ask cache (plan workflow name → resolved decision, apply-scoped. Absent (the
30
29
  * entry relies on this default — `index.ts` constructs the adapter
31
30
  * without it) → the constructor builds ONE cache per adapter per apply,
32
31
  * shared by the gate and any answerer integration via the readonly
@@ -80,8 +79,7 @@ export declare class DshHostAdapter extends Service implements HostAdapter {
80
79
  private readonly config;
81
80
  private readonly pairing;
82
81
  /**
83
- * The P-c first-seen ask cache (plan `20260815-dsh-workflow-gate`
84
- * Task 2) — apply-scoped with the adapter: the dispatch gate reads it
82
+ * The P-c first-seen ask cache (apply-scoped with the adapter: the dispatch gate reads it
85
83
  * through `gateDispatch`, and tests/answerer integrations reach the same
86
84
  * instance via `ctx.dshHostAdapter.workflowAskCache`. Dies with the
87
85
  * fiber (no module-level reference — an HMR reload starts a fresh cache).
@@ -121,15 +119,14 @@ export declare class DshHostAdapter extends Service implements HostAdapter {
121
119
  * context and covers the field/branch/anti-recursion/worktree path.
122
120
  * @param prompt - the Assignment text (engine header grammar).
123
121
  * @param exec - the in-flight delegation tool call (listener path only).
124
- * @param hard - the caller's ONE `resolveDispatchHard` resolution (qc1
125
- * F-002 / qc2 F-3 / qc3 F-002 fix-wave): passed in so the record block and
122
+ * @param hard - the caller's ONE `resolveDispatchHard` resolution): passed in so the record block and
126
123
  * the caller's enforcement decision share a single compass resolution;
127
124
  * when omitted (external callers) the adapter resolves it itself.
128
125
  */
129
126
  dispatchGate(prompt: string, exec?: ToolExecution, hard?: boolean): GateResult;
130
127
  /**
131
128
  * Record one workflow/ralph gate verdict row (plan
132
- * `20260815-dsh-workflow-gate` Task 4 — the durable ledger row for every
129
+ * Task 4 — the durable ledger row for every
133
130
  * gated workflow/ralph call: verdict + metaName/objective + mode, via the
134
131
  * ledger plan's record path). `gateWorkflow` routes the record through
135
132
  * this adapter method so dispatch.ts stays free of a runtime agent-flow
@@ -171,7 +168,7 @@ export declare class DshHostAdapter extends Service implements HostAdapter {
171
168
  beforeDispatch(assignment: AssignmentFields | string): Promise<GateResult>;
172
169
  /**
173
170
  * `HostAdapter.beforeMerge` — reserve/validate the integration merge
174
- * lease. v3 relocation (plan `20260819-workflow-dsh-viz` Task 3): the
171
+ * lease. v3 relocation : the
175
172
  * `integration_merge_lease` home is the ACTIVE workflow snapshot
176
173
  * (`workflows/<id>/snapshot.json` top-level — the v1 root-metadata home
177
174
  * is gone), so the hook READS the snapshot's current lease and validates
@@ -8,7 +8,7 @@ export declare const AGENT_FLOW_MAX_EVENTS = 500;
8
8
  /** Default read limit (the catalog passes 50 per spec §2.2). */
9
9
  export declare const AGENT_FLOW_DEFAULT_LIMIT = 50;
10
10
  /**
11
- * The append size gate (qc2 F-1 / qc3 F-001/003 — fix-wave): the truncation
11
+ * The append size gate: the truncation
12
12
  * read-modify-write runs only when the file exceeds ~500 lines' typical
13
13
  * size (conservative ≈ 500 × 128 B average line); smaller files stay
14
14
  * append-only. The bound is therefore approximate ("~500 events") — a file
@@ -18,7 +18,7 @@ export declare const AGENT_FLOW_DEFAULT_LIMIT = 50;
18
18
  */
19
19
  export declare const AGENT_FLOW_SIZE_GATE_BYTES: number;
20
20
  /**
21
- * WORKFLOW field length caps (qc2 W-3 fix-wave) — ONE constant family at
21
+ * WORKFLOW field length caps — ONE constant family at
22
22
  * the ledger boundary, enforced on BOTH the consumer (workflow-ledger
23
23
  * `rowOf`) and the read narrow (`eventFromUnknown`): a hostile or
24
24
  * model-controlled multi-MB string must never defeat the
@@ -43,8 +43,7 @@ export declare const WORKFLOW_LEDGER_MAX_SEQ: number;
43
43
  * through unchanged; longer values are truncated to `cap − marker` chars
44
44
  * plus the {@link WORKFLOW_LEDGER_TRUNCATION_MARKER} suffix (the marker
45
45
  * guarantees the truncation is visible in the panel — never a silent cut).
46
- * CODE-POINT gated AND sliced (plan QC fix wave — qc2 S-5; PR #97 finding
47
- * 2): `String.prototype.slice` operates on UTF-16 code units and can split
46
+ * CODE-POINT gated AND sliced : `String.prototype.slice` operates on UTF-16 code units and can split
48
47
  * a surrogate pair at the cap boundary (a lone surrogate renders as U+FFFD
49
48
  * in the log line), and a UTF-16 `.length` gate would false-positive
50
49
  * truncate astral-dense values (≤ cap code points but > cap UTF-16 units)
@@ -62,21 +61,19 @@ export declare const AGENT_FLOW_LOGGER = "mstar/agent-flow";
62
61
  * waterfall. VERIFIED to be dispatched by the real registry for every tool
63
62
  * call (`runPostExecute` → `postExecute`, upstream source; pinned by the
64
63
  * real-call probe in `tests/agent-flow.spec.ts`), so settles are no longer
65
- * host-emission-dependent (plan `20260811-panel-f4-timeliness` Task 1 — the
64
+ * host-emission-dependent (the
66
65
  * old "not part of the verified surface" assumption is obsolete).
67
66
  */
68
67
  export declare const SETTLE_SEAM = "tools/post-execute";
69
68
  /**
70
- * The once-per-apply settle-pairing trace (plan `20260811-panel-f4-timeliness`
71
- * Task 1). Historical name `SETTLE_SEAM_UNAVAILABLE_NOTE` (qc1 F-105 / qc2
72
- * N-002 fix-wave): the old name claimed the seam was UNAVAILABLE, which the
69
+ * The once-per-apply settle-pairing trace . Historical name `SETTLE_SEAM_UNAVAILABLE_NOTE`: the old name claimed the seam was UNAVAILABLE, which the
73
70
  * message itself refutes — the seam IS a verified part of the registry
74
71
  * surface, so the constant was renamed to the accurate `PAIRING` name. The
75
72
  * message states the VERIFIED pairing facts: the seam is emitted by the
76
73
  * registry; foreground dispatch calls settle via it, background subagents
77
74
  * settle via `ctx.jobs.onJobDone` pairing; only unpaired payloads stay
78
75
  * dispatch-only (never fabricated settlement). Logged ONCE per logger binding
79
- * (≈ once per apply — the same module-level flag, qc1 F-006) when the pairing
76
+ * (≈ once per apply — the same module-level flag) when the pairing
80
77
  * listener is registered.
81
78
  */
82
79
  export declare const SETTLE_SEAM_PAIRING_NOTE = "settle seam \"tools/post-execute\" IS part of the verified dsh-tools registry surface (runPostExecute dispatches it for every tool call) \u2014 foreground dispatch calls settle here, background subagents settle via ctx.jobs.onJobDone pairing; only UNPAIRED payloads (non-dispatch tools, calls outside the apply-scoped pairing window) stay dispatch-only \u2014 never a fabricated settle";
@@ -87,8 +84,7 @@ export type SettleOutcome = 'ok' | 'error' | 'denied';
87
84
  /** Workflow run terminal reason (`tool-workflow` vocabulary — `workflow/src/types.ts:63`). */
88
85
  export type WorkflowStopReason = 'completed' | 'cancelled' | 'error';
89
86
  /**
90
- * Workflow/ralph gate verdict vocabulary (plan `20260815-dsh-workflow-gate`
91
- * Task 4): the RESOLVED outcomes reuse the dispatch verdict vocabulary
87
+ * Workflow/ralph gate verdict vocabulary : the RESOLVED outcomes reuse the dispatch verdict vocabulary
92
88
  * (`ok`/`advisory`/`denied` — the plan interface "the workflow verdict
93
89
  * vocabulary"); `ask` is the PENDING-decision member — the first-seen ask
94
90
  * itself is a gated call, so its row carries `ask` until the approval
@@ -97,15 +93,15 @@ export type WorkflowStopReason = 'completed' | 'cancelled' | 'error';
97
93
  export type WorkflowVerdict = DispatchVerdict | 'ask';
98
94
  /**
99
95
  * The workflow/ralph gate mode (Config `workflowGate` — plan
100
- * `20260815-dsh-workflow-gate` Task 1), recorded on every verdict row.
96
+ * verdict rows), recorded on every verdict row.
101
97
  * `off` rows never exist: the gate short-circuits `off` BEFORE the policy,
102
98
  * so no verdict is produced.
103
99
  */
104
100
  export type WorkflowGateMode = 'off' | 'warn' | 'ask' | 'hard';
105
101
  /**
106
- * One v1 workflow ledger event (plan `20260815-dsh-workflow-ledger` Task 2 —
102
+ * One v1 workflow ledger event (the JSONL row —
107
103
  * the W-B2 schema). Produced from the durable `tool-workflow/*` session events
108
- * by the Task 3 consumer (`run-start` → `workflow-run`, `agent-start` →
104
+ * by the session-event consumer (`run-start` → `workflow-run`, `agent-start` →
109
105
  * `workflow-agent`, `run-end` → `workflow-run-end`; the upstream `agent-end`
110
106
  * member outcome has no ledger kind). Optional fields (`agent` / `phase`) are
111
107
  * OMITTED from the serialized line when absent (lossless-JSON discipline).
@@ -144,8 +140,8 @@ export type AgentFlowWorkflowEvent = {
144
140
  stopReason: WorkflowStopReason;
145
141
  };
146
142
  /**
147
- * One v1 ledger event (spec §2.1.3 + plan `20260815-dsh-workflow-ledger`
148
- * Task 2 — the JSONL line). Optional fields are OMITTED from the serialized
143
+ * One v1 ledger event (spec §2.1.3 +
144
+ * the JSONL line). Optional fields are OMITTED from the serialized
149
145
  * line when absent (Session.append's lossless JSON discipline starts at the
150
146
  * record boundary). The three `workflow-*` kinds are the W-B2 addition —
151
147
  * see {@link AgentFlowWorkflowEvent}.
@@ -177,8 +173,7 @@ export type AgentFlowEvent = {
177
173
  outcome: SettleOutcome;
178
174
  durationMs?: number;
179
175
  /**
180
- * The PAIRED dispatch's identity (plan `20260811-panel-f4-timeliness`
181
- * Task 1) — same field names + semantics as the dispatch event:
176
+ * The PAIRED dispatch's identity (plan same field names + semantics as the dispatch event:
182
177
  * `role` is the Assignment `Execute as` ('' when missing), `planId` /
183
178
  * `taskId` the plan + `Task N` tags. Written for every paired settle;
184
179
  * ABSENT on unpaired (legacy) settles — the client pairs on identity
@@ -233,7 +228,7 @@ export interface AgentFlowDispatchRef {
233
228
  taskId?: string;
234
229
  }
235
230
  /**
236
- * The apply-scoped pairing store (plan `20260811-panel-f4-timeliness` Task 1,
231
+ * The apply-scoped pairing store (
237
232
  * decision D1 — created in the entry `apply`, same lifetime as the catalog
238
233
  * cache; an HMR restart resets it, and completions outside the window stay
239
234
  * unpaired → no settle, the documented honest degrade). Maps are keyed by
@@ -245,7 +240,7 @@ export interface AgentFlowPairing {
245
240
  /**
246
241
  * The agent-namespaced call key → the dispatch it recorded (populated by
247
242
  * `recordDispatch` when an exec is present). Key = `${sessionId}\u0000${callId}`
248
- * (qc1 F-101 fix-wave): a raw `ToolExecution.callId` is NOT globally unique
243
+ * : a raw `ToolExecution.callId` is NOT globally unique
249
244
  * in one process — dsh runs many sessions concurrently and upstream mints
250
245
  * per-message ids (`call-${index}`), so the dispatching session id must
251
246
  * namespace the key or session B's same-id call could overwrite session A's
@@ -259,19 +254,18 @@ export interface AgentFlowPairing {
259
254
  /** Module-scoped log sink (bound to `mstar/agent-flow` by the entry at apply). */
260
255
  type AgentFlowLogSink = (level: 'info' | 'warn' | 'error', message: string) => void;
261
256
  /**
262
- * Module-scoped catalog-invalidation hook (plan `20260811-panel-f4-timeliness`
263
- * Task 1 — the `invalidateCatalog` 挂钩 that Task 2 consumes): called with
257
+ * Module-scoped catalog-invalidation hook : called with
264
258
  * the affected `{HARNESS_DIR}` after every SUCCESSFUL ledger record
265
259
  * (`recordDispatch` / `recordSettle`). The entry binds the real invalidation
266
- * closure at apply (Task 2 shipped the apply-scoped harnessDir → cache-key
260
+ * closure at apply (the apply-scoped harnessDir → cache-key
267
261
  * reverse-map closure in `index.ts` — see `createCatalogInvalidation`);
268
262
  * unbound → no-op. Never throws into the record path.
269
263
  */
270
264
  type AgentFlowInvalidator = (harnessDir: string) => void;
271
265
  /**
272
266
  * Bind the module's catalog-invalidation hook (plan
273
- * `20260811-panel-f4-timeliness` Task 1 — same pattern as
274
- * {@link setAgentFlowLogger}; the entry binds at apply; Task 2 shipped the
267
+ * the settle-pairing upgrade — same pattern as
268
+ * {@link setAgentFlowLogger}; the entry binds at apply; the apply-scoped
275
269
  * real binding — the apply-scoped harnessDir → cache-key reverse-map
276
270
  * closure in `index.ts`).
277
271
  * @param invalidate - the hook (`undefined` clears the binding).
@@ -293,10 +287,10 @@ export declare function setAgentFlowLogger(sink: AgentFlowLogSink | undefined):
293
287
  * (spec §2.1.1 — `taskIdOf`). The engine `assignmentHeaderRegion` boundary is
294
288
  * reused: only text AFTER the header region is scanned, so a `## Task N`
295
289
  * example quoted in the header never resolves a task id. Only a LEVEL-2
296
- * heading (`^## Task N`) matches (qc2 F-8: an example or sub-heading at
290
+ * heading (`^## Task N`) matches (an example or sub-heading at
297
291
  * another depth before the real task must not resolve — lower false-hit
298
292
  * surface); normalized to `T<n>` (matches the panel render `planId#taskId`,
299
- * e.g. `20260810-x#T2`).
293
+ * e.g. #T2`).
300
294
  * @param prompt - the full Assignment text.
301
295
  */
302
296
  export declare function taskIdOf(prompt: string): string | undefined;
@@ -308,7 +302,7 @@ export declare function taskIdOf(prompt: string): string | undefined;
308
302
  * `workflows[]` MEMBERSHIP — non-terminal lifecycles (`running` AND
309
303
  * `paused`; terminal lifecycles are removed at terminal) — so a paused
310
304
  * lifecycle stays a valid append target (explicit decision, plan
311
- * `20260819-workflow-dsh-viz` Task 2).
305
+ * the workflow viz plan).
312
306
  *
313
307
  * No active entry → `null`: the record is SKIPPED with a one-time warn
314
308
  * (per sink binding) — never a silent write into the root v1 file, never a
@@ -320,7 +314,7 @@ export declare function taskIdOf(prompt: string): string | undefined;
320
314
  */
321
315
  export declare function resolveAgentFlowWriteDir(harnessDir: string): string | null;
322
316
  /**
323
- * Lock-directory name for the per-workflow write lock (qc3 W-1 fix-wave):
317
+ * Lock-directory name for the per-workflow write lock :
324
318
  * guards the ledger append + size-gated truncating read-modify-write AND
325
319
  * the workflow-ledger cursor sidecar read-modify-write against concurrent
326
320
  * dsh processes sharing one active lifecycle (compass ruling 3). The
@@ -330,8 +324,7 @@ export declare function resolveAgentFlowWriteDir(harnessDir: string): string | n
330
324
  */
331
325
  export declare const WORKFLOW_LEDGER_LOCKDIR = ".ledger-write.lockdir";
332
326
  /**
333
- * Run `fn` under the per-workflow inter-process write lock (qc3 W-1
334
- * fix-wave): atomic `mkdir` on `<workflowDir>/.ledger-write.lockdir/`
327
+ * Run `fn` under the per-workflow inter-process write lock: atomic `mkdir` on `<workflowDir>/.ledger-write.lockdir/`
335
328
  * acquires (success acquires; existing dir → another writer holds the
336
329
  * lock); while another writer holds it, wait up to
337
330
  * {@link WORKFLOW_LOCKER_TIMEOUT_MS} and then THROW (Blocked — the
@@ -375,21 +368,21 @@ export declare function withWorkflowDirLock<T>(workflowDir: string, fn: () => T,
375
368
  * identity derivation (role / planId / taskId / taskCategory) reuse the gate's
376
369
  * own parsers — one grammar.
377
370
  *
378
- * Pairing (plan `20260811-panel-f4-timeliness` Task 1): when the input
371
+ * Pairing: when the input
379
372
  * carries an `exec` AND the apply-scoped `pairing` store, the successful
380
373
  * record registers the agent-namespaced key `${sessionId}\u0000${callId}` →
381
374
  * dispatchRef (the full dispatch identity), so a later
382
375
  * `tools/post-execute` for the same call can settle with the SAME identity
383
- * (qc1 F-101 fix-wave: the session id namespaces the key — a raw callId is
376
+ * (the session id namespaces the key — a raw callId is
384
377
  * not globally unique across sessions in one process). The pairing registers
385
378
  * only after the ledger append SUCCEEDED — a failed record never pairs to a
386
379
  * phantom dispatch. An exec-less record (host-hook path) has no callId → no
387
- * pairing. The pairing sub-path has its OWN catch scope (qc1 F-106 / qc2
388
- * N-001 / qc3 F-006 fix-wave): a `Map.set` throw must not log "record
380
+ * pairing. The pairing sub-path has its OWN catch scope: a `Map.set` throw must not log "record
389
381
  * failed" after the dispatch was already appended.
390
- * @param input - harness dir + exec (agent id) + Assignment text + the gate's
391
- * violations + the hard-enforcement resolution + the apply-scoped pairing
392
- * store (the adapter passes its own; direct callers may omit it).
382
+ * @param input - the harness dir; the dispatching exec's agent id; the
383
+ * Assignment text; the gate's violations; the hard-enforcement resolution;
384
+ * the apply-scoped pairing store (the adapter passes its own; direct callers
385
+ * may omit it).
393
386
  */
394
387
  export declare function recordDispatch(input: {
395
388
  harnessDir: string;
@@ -425,9 +418,9 @@ export declare function recordSettle(input: {
425
418
  taskId?: string;
426
419
  }): void;
427
420
  /**
428
- * Record one workflow ledger event (plan `20260815-dsh-workflow-ledger` Task 2
421
+ * Record one workflow ledger event (the JSONL schema below
429
422
  * — the W-B2 schema). Fully try/catch-contained — NEVER throws into the
430
- * session-event consumer (Task 3 wires it); a failing record logs only
423
+ * session-event consumer wires it); a failing record logs only
431
424
  * (`mstar/agent-flow`), so a ledger write never crashes or alters a workflow
432
425
  * run (Global Constraint: observe-only events are never refusal channels).
433
426
  * The event is serialized lossless — optional fields (`agent` / `phase`) are
@@ -447,7 +440,7 @@ export declare function recordSettle(input: {
447
440
  * @returns `true` when the row was appended (the caller may durably advance
448
441
  * its watermark); `false` on a contained append failure OR when no active
449
442
  * lifecycle resolves — the caller must leave the cursor behind so the row
450
- * is re-attempted at the next scan (qc3 R-401: advance-then-record made a
443
+ * is re-attempted at the next scan (advance-then-record made a
451
444
  * failed append permanent loss).
452
445
  */
453
446
  export declare function recordWorkflowEvent(input: {
@@ -457,7 +450,7 @@ export declare function recordWorkflowEvent(input: {
457
450
  }): boolean;
458
451
  /**
459
452
  * Input for {@link recordWorkflowVerdict} — one gated workflow/ralph call's
460
- * decision identity (plan `20260815-dsh-workflow-gate` Task 4: verdict +
453
+ * decision identity (verdict +
461
454
  * metaName/objective + mode).
462
455
  */
463
456
  export interface WorkflowVerdictInput {
@@ -479,9 +472,7 @@ export interface WorkflowVerdictInput {
479
472
  code?: string;
480
473
  }
481
474
  /**
482
- * Record one workflow/ralph gate verdict row (plan `20260815-dsh-workflow-gate`
483
- * Task 4 — "one ledger row per gated workflow/ralph call" via the ledger
484
- * plan's record path, the `workflow-verdict` kind). Fully
475
+ * Record one workflow/ralph gate verdict row . Fully
485
476
  * try/catch-contained — NEVER throws into the gate (`gateWorkflow` calls
486
477
  * this on EVERY policy decision); a failing record logs only
487
478
  * (`mstar/agent-flow`), so a ledger write never crashes or alters a
@@ -490,7 +481,7 @@ export interface WorkflowVerdictInput {
490
481
  * display identity fields (`workflow` / `objective`) are capped at the
491
482
  * ledger boundary (same discipline as the W-B2 name cap) and the ralph
492
483
  * `objective` is routed through the SHARED `normalizeWorkflowName` strip at
493
- * this write boundary (qc2 W-2 — control-char discipline parity with the
484
+ * this write boundary (— control-char discipline parity with the
494
485
  * name/label/phase fields; the gate already normalizes `workflow`). The
495
486
  * JSONL line is line-safe either way (`JSON.stringify` escapes), but the
496
487
  * panel view passes the objective through raw — a hostile objective
@@ -500,8 +491,8 @@ export interface WorkflowVerdictInput {
500
491
  */
501
492
  export declare function recordWorkflowVerdict(input: WorkflowVerdictInput): void;
502
493
  /**
503
- * Read the agent-flow ledger as the catalog view (spec §2.1.3 — fix-wave
504
- * qc1 F-001 / qc2 F-6): the latest events first (bounded by `limit`) plus
494
+ * Read the agent-flow ledger as the catalog view (spec §2.1.3): the latest
495
+ * events first (bounded by `limit`) plus
505
496
  * the role × outcome summary over the SAME window (so `by role` counts sum
506
497
  * to the event count). A MISSING ledger file returns the EMPTY view
507
498
  * `{ events: [], summary: [] }` — recording hasn't started (it begins at
@@ -515,7 +506,7 @@ export declare function recordWorkflowVerdict(input: WorkflowVerdictInput): void
515
506
  * (the catalog passes `join(harnessDir, selection.dir)`; the writer appends
516
507
  * there via `resolveAgentFlowWriteDir`).
517
508
  *
518
- * Large-file reads (plan `20260820-dsh-ledger-tail-read`): ledgers above
509
+ * Large-file reads : ledgers above
519
510
  * `AGENT_FLOW_TAIL_READ_THRESHOLD_BYTES` are read as a bounded latest-first
520
511
  * tail — seek from EOF, aligned to a line boundary, doubling backward until
521
512
  * the window holds `limit` complete lines — so the catalog pays O(window) at
@@ -528,30 +519,29 @@ export declare function recordWorkflowVerdict(input: WorkflowVerdictInput): void
528
519
  */
529
520
  export declare function readAgentFlow(workflowDir: string, limit?: number): AgentFlowView | null;
530
521
  /**
531
- * The `tools/post-execute` settle pairing (plan `20260811-panel-f4-timeliness`
532
- * Task 1 — replaces the old defensive payload probing): the VERIFIED
522
+ * The `tools/post-execute` settle pairing : the VERIFIED
533
523
  * dsh-tools registry dispatches this seam for every tool call
534
524
  * (`runPostExecute` → `postExecute`, upstream source), so the listener only
535
525
  * decides whether a completion signal exists for the PAIRED dispatch:
536
526
  *
537
527
  * - non-dispatch tool (`exec.name` ∉ Config `dispatchTools`) → nothing;
538
528
  * - dispatch tool whose agent-namespaced call key
539
- * (`${sessionId}\u0000${callId}`, qc1 F-101 fix-wave) is not in the pairing
529
+ * (the exact call identity) is not in the pairing
540
530
  * store (HMR reset, host-hook dispatch, non-gate path) → nothing (warned
541
531
  * once per registration — honest degrade, never fabricated settlement);
542
532
  * - `result.isError === true` OR an `error` payload present → settle `error`
543
- * immediately (fabrication guard, qc2 F-001 / qc3 F-003a — the dispatch
533
+ * immediately (fabrication guard — the dispatch
544
534
  * call failed; a result carrying `error` without `isError` never settles ok);
545
535
  * - successful `result.value` shape `{ kind: 'background', taskId }` with a
546
536
  * valid taskId → store `taskId → dispatchRef` (the real settle arrives via
547
537
  * `ctx.jobs.onJobDone`); `{ kind: 'background' }` WITHOUT a valid taskId
548
- * → nothing mappable (no settle, qc3 F-003b);
538
+ * → nothing mappable (no settle);
549
539
  * - `{ kind: 'continuable', subagentId }` → no terminal signal this round →
550
540
  * no settle (documented limit — the child owns its turns);
551
541
  * - any other successful value (foreground `{ kind: 'foreground', … }`
552
542
  * included) → settle `ok` (the call completed synchronously).
553
543
  * The consumed `dispatchByCallId` entry is DELETED after the branch resolves
554
- * the call (map pruning, qc1 F-102 / qc2 F-002 / qc3 F-002 — each callId
544
+ * the call (map pruning — each callId
555
545
  * pairs exactly once; the map holds only in-flight calls).
556
546
  *
557
547
  * The waterfall MUST be delegated via `next()` on every path — returning
@@ -569,7 +559,7 @@ export declare function readAgentFlow(workflowDir: string, limit?: number): Agen
569
559
  export declare function registerSettleListener(ctx: Context, config: Config, pairing: AgentFlowPairing): void;
570
560
  /**
571
561
  * The structural read of the dsh-jobs terminal snapshot the pairing consumes
572
- * (plan `20260811-panel-f4-timeliness` Task 1). The `ctx.jobs.onJobDone`
562
+ * (the settle-pairing upgrade). The `ctx.jobs.onJobDone`
573
563
  * contract was verified against the upstream `@deepseek-ai/dsh-jobs`
574
564
  * `types.ts`: `JobDoneListener = (snapshot, owner) => …`, terminal
575
565
  * `snapshot.status` ∈ `completed | killed | failed`, `startedAt`/`finishedAt`
@@ -589,14 +579,14 @@ export interface TaskDoneSnapshot {
589
579
  }
590
580
  /**
591
581
  * Record the settle for one background-task terminal (plan
592
- * `20260811-panel-f4-timeliness` Task 1 — the `ctx.jobs.onJobDone` path):
582
+ * the `ctx.jobs.onJobDone` path):
593
583
  * the snapshot's task id must hit the pairing store's `dispatchByTaskId`
594
584
  * (populated by the post-execute background branch) — a miss records NOTHING
595
585
  * (honest degrade, never fabricated). Outcome mapping: `completed → ok` /
596
586
  * `killed → denied` / `failed → error`; `durationMs = finishedAt − startedAt`
597
587
  * when both are present. After a SUCCESSFUL settle the consumed
598
- * `dispatchByTaskId` entry is deleted (map pruning, qc1 F-102 / qc2 F-002 /
599
- * qc3 F-002 — the map holds only in-flight tasks; a contract-violating
588
+ * `dispatchByTaskId` entry is deleted (map pruning — the map holds only
589
+ * in-flight tasks; a contract-violating
600
590
  * non-terminal snapshot records nothing and KEEPS the entry so a later real
601
591
  * terminal can still settle). Fully contained — never throws into the task
602
592
  * registry's listener notification.
@@ -35,8 +35,7 @@ export declare function personaFor(roleId: string, lookup: PersonaLookup, warn?:
35
35
  * The mstar role-id set for one mirror: the file stems of the shells
36
36
  * eligible as subagent role defaults (`mode` absent-or-`subagent` — a
37
37
  * `primary` shell like `project-manager` is excluded), sorted for
38
- * deterministic warn listings. The adoption advisory (plan
39
- * `20260815-dsh-fallbacks-personas` Task 4) derives its taxonomy reference
38
+ * deterministic warn listings. The adoption advisory derives its taxonomy reference
40
39
  * from here — never hardcoded. Reads the mirror directory + each shell's
41
40
  * frontmatter once per call (the advisory invokes it once per apply — no
42
41
  * cache needed). Returns `[]` for an unreadable/absent mirror directory.
@@ -14,7 +14,7 @@ export interface CatalogCacheEntry {
14
14
  }
15
15
  /**
16
16
  * The apply-scoped `harnessDir → cache key` reverse map + invalidation
17
- * closure (plan `20260811-panel-f4-timeliness` Task 2, decision D3): the
17
+ * closure : the
18
18
  * catalog cache is keyed by {@link EXPLICIT_CACHE_KEY} or the session cwd,
19
19
  * while ledger records (dispatch/settle) identify the affected workspace by
20
20
  * `{HARNESS_DIR}` — the reverse map bridges the two so a ledger change
@@ -96,10 +96,7 @@ export declare function buildCatalogSources(ctx: Context, harnessDir: string | n
96
96
  * workspace root and TTL-refreshed — Config `catalogTtlMs`).
97
97
  * @param ttlMs - catalog refresh interval in milliseconds.
98
98
  * @param register - the apply-scoped `harnessDir → cache key` reverse-map
99
- * registration (plan `20260811-panel-f4-timeliness` Task 2 — keeps every
100
- * workspace's entry invalidatable by a ledger change; see
101
- * `createCatalogInvalidation`).
102
- * @param digests - per agent+workspace turn digests (last rendered text)
99
+ * registration. * @param digests - per agent+workspace turn digests (last rendered text)
103
100
  * for the digest-gated re-emission.
104
101
  * @param payload - the proposed step the loop is about to enter.
105
102
  * @param next - the remaining pre-step chain; its value is the delegated decision.