@mstar-harness/dsh 3.6.3 → 3.7.1

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 (71) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +8 -8
  3. package/README.zh.md +7 -5
  4. package/dist/client/panel/PanelView.d.ts +8 -11
  5. package/dist/client/panel/TabNav.d.ts +2 -2
  6. package/dist/client/panel/graph/event-log.d.ts +5 -9
  7. package/dist/client/panel/graph/project-graph.d.ts +53 -72
  8. package/dist/client/panel/graph/schema.d.ts +31 -37
  9. package/dist/client/panel/locale.d.ts +19 -19
  10. package/dist/client/panel/pages/AgentCanvasPage.d.ts +40 -58
  11. package/dist/client/panel/pages/EventLogPage.d.ts +6 -6
  12. package/dist/client/panel/pages/IterationInfoSection.d.ts +9 -11
  13. package/dist/client/panel/pages/IterationTaskPage.d.ts +3 -3
  14. package/dist/client/panel/plan-sort.d.ts +3 -6
  15. package/dist/client/panel/state-section.d.ts +1 -1
  16. package/dist/client/panel/zones/Legend.d.ts +2 -2
  17. package/dist/client/panel/zones/ProjectRollup.d.ts +1 -2
  18. package/dist/client/panel/zones/TaskBoard.d.ts +1 -2
  19. package/dist/gates/_shared.d.ts +24 -16
  20. package/dist/gates/adapter.d.ts +6 -9
  21. package/dist/gates/agent-flow.d.ts +49 -59
  22. package/dist/gates/agent-personas.d.ts +1 -2
  23. package/dist/gates/catalog.d.ts +2 -5
  24. package/dist/gates/dispatch.d.ts +9 -11
  25. package/dist/gates/fallbacks-advisory.d.ts +55 -18
  26. package/dist/gates/fallbacks-probe.d.ts +2 -2
  27. package/dist/gates/fallbacks-seeds.d.ts +1 -1
  28. package/dist/gates/fallbacks-structural.d.ts +1 -1
  29. package/dist/gates/goal-bridge.d.ts +6 -9
  30. package/dist/gates/role-persona.d.ts +123 -7
  31. package/dist/gates/skill-lint.d.ts +19 -2
  32. package/dist/gates/system-prompt.d.ts +7 -11
  33. package/dist/gates/tools.d.ts +1 -1
  34. package/dist/gates/workflow-ledger.d.ts +21 -28
  35. package/dist/gates/workflow-policy.d.ts +15 -19
  36. package/dist/gates/workflow-selection.d.ts +3 -3
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.js +472 -183
  39. package/dist/types.d.ts +4 -7
  40. package/harness-commands/iteration-drive.md +6 -6
  41. package/harness-commands/iteration-loop.md +7 -7
  42. package/harness-commands/iteration-start.md +8 -8
  43. package/harness-skills/mstar-coding-behavior/SKILL.md +3 -20
  44. package/harness-skills/mstar-dispatch-gates/SKILL.md +7 -13
  45. package/harness-skills/mstar-dispatch-gates/references/leaf-executor-checklist.md +1 -1
  46. package/harness-skills/mstar-harness-core/SKILL.md +16 -53
  47. package/harness-skills/mstar-host/references/zcode.md +7 -0
  48. package/harness-skills/mstar-iteration/SKILL.md +32 -318
  49. package/harness-skills/mstar-iteration/references/command-shared-invariants.md +1 -1
  50. package/harness-skills/mstar-iteration/references/phase-1-prepare.md +155 -0
  51. package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +113 -3
  52. package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +1 -1
  53. package/harness-skills/mstar-roles/SKILL.md +14 -12
  54. package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +5 -6
  55. package/harness-skills/mstar-roles/references/architect.md +1 -1
  56. package/harness-skills/mstar-roles/references/code-reviewer.md +11 -1
  57. package/harness-skills/mstar-roles/references/frontend-dev.md +1 -1
  58. package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +1 -1
  59. package/harness-skills/mstar-roles/references/ops-engineer.md +1 -1
  60. package/harness-skills/mstar-roles/references/product-manager.md +1 -1
  61. package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +4 -0
  62. package/harness-skills/mstar-roles/references/project-manager.md +6 -4
  63. package/harness-skills/mstar-roles/references/prompt-engineer.md +1 -1
  64. package/harness-skills/mstar-roles/references/qa-engineer.md +1 -1
  65. package/harness-skills/mstar-roles/references/qc-specialist-shared.md +1 -1
  66. package/harness-skills/mstar-roles/references/writing-specialist.md +1 -1
  67. package/harness-skills/mstar-sdd/references/file-handoffs.md +40 -7
  68. package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +9 -0
  69. package/harness-skills/mstar-sdd/references/implementer-prompt.md +9 -0
  70. package/harness-skills/mstar-sdd/references/task-reviewer-prompt.md +7 -0
  71. package/package.json +1 -1
@@ -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.
@@ -11,14 +11,13 @@ export declare const DISPATCH_LOGGER = "mstar/dispatch-gate";
11
11
  * default id + its fork sibling — roadmap §9 W-B1: fork dispatches carry the
12
12
  * same Assignment-shaped `{ description, prompt }` args and must be gated
13
13
  * like `subagent`). Exported SHARED with the agent-flow settle pairing
14
- * (`registerSettleListener` matches the same tool set — plan
15
- * `20260811-panel-f4-timeliness` Task 1) so the default cannot drift between
14
+ * (`registerSettleListener` matches the same tool set) so the default cannot drift between
16
15
  * the gate and the settle seam.
17
16
  */
18
17
  export declare const DEFAULT_DISPATCH_TOOLS: readonly ["subagent", "subagent_fork"];
19
18
  /**
20
19
  * The fixed workflow/ralph tool names the workflow gate matches (plan
21
- * `20260815-dsh-workflow-gate` — architect-verified): the workflow tool
20
+ * — architect-verified): the workflow tool
22
21
  * registers under Config-default name `'workflow'` and is RENAMEABLE per
23
22
  * instance (`toolName`, `tool-workflow/src/index.ts:41`); `ralph` is a
24
23
  * fixed name (`tool-ralph/src/index.ts:413`). A renamed instance is out
@@ -51,7 +50,7 @@ export interface DispatchGateAdvisory {
51
50
  * stay silent — no false-positive warnings. Callers MUST pass the engine
52
51
  * `assignmentHeaderRegion` slice: a `## Assignment` heading or
53
52
  * field line quoted in the task body must not shape a non-assignment prompt.
54
- * Exported for the agent-flow ledger's shape guard (qc2 F-2 — the shared
53
+ * Exported for the agent-flow ledger's shape guard — the shared
55
54
  * `DshHostAdapter.dispatchGate` core applies the SAME guard on both dispatch
56
55
  * surfaces, so the exec-less host-hook path records nothing for
57
56
  * non-Assignment text either).
@@ -65,7 +64,7 @@ export declare function isAssignmentShaped(assignmentText: string): boolean;
65
64
  * frontmatter, else warn-only.
66
65
  */
67
66
  export declare function resolveDispatchHard(harnessDir: string | null, config: Config, assignmentText: string): boolean;
68
- /** A header value that means "no value" (placeholder conventions). Type guard so callers narrow to `string`. Shared with the agent-flow ledger (qc1 F-003 — one grammar, no copy-paste drift). */
67
+ /** A header value that means "no value" (placeholder conventions). Type guard so callers narrow to `string`. Shared with the agent-flow ledger (one grammar, no copy-paste drift). */
69
68
  export declare function isNaValue(value: string | undefined): value is undefined;
70
69
  /**
71
70
  * Resolve the target plan id from the Assignment HEADER region: `Plan Path`
@@ -95,7 +94,7 @@ export declare function sessionIdOf(exec: ToolExecution): string | undefined;
95
94
  * whose plan row is `InProgress`.
96
95
  *
97
96
  * Contract (status-and-residuals.md § Pre-dispatch re-verify; v3
98
- * relocation — plan `20260819-workflow-dsh-viz` Task 3): before any
97
+ * relocation —): before any
99
98
  * writable implement dispatch, reread the ACTIVE workflow snapshot
100
99
  * (`workflows/<id>/snapshot.json` — the v1 root `plans[]` home is gone; the
101
100
  * root v2 `status.json` supplies the active `workflows[]`) and confirm
@@ -150,8 +149,7 @@ export declare function dispatchGateCore(config: Config, harnessDir: string | nu
150
149
  };
151
150
  /**
152
151
  * The workflow-gate input composed from one `workflow`/`ralph` tool call
153
- * (plan `20260815-dsh-workflow-gate` Task 1 — consumed by the Task 2 P-a /
154
- * P-c and Task 3 P-b policies): the tool name + the structural reads of
152
+ * : the tool name + the structural reads of
155
153
  * `meta` (workflow) / `objective` (ralph) + the in-flight call.
156
154
  */
157
155
  export interface WorkflowGateInput {
@@ -164,7 +162,7 @@ export interface WorkflowGateInput {
164
162
  /** The in-flight tool call — Task 3 P-b lease attribution reads the calling agent/session off it. */
165
163
  exec: ToolExecution;
166
164
  /**
167
- * P-b lease attribution (plan Task 3): the calling workspace's first
165
+ * P-b lease attribution: the calling workspace's first
168
166
  * `InProgress` plan lacking `execution_lease` coverage (computed by
169
167
  * {@link writableFanOutUncovered} from the status.json read through the
170
168
  * contained resolver path — `preExecuteListener` already resolved the
@@ -177,7 +175,7 @@ export interface WorkflowGateInput {
177
175
  /**
178
176
  * Compose the {@link WorkflowGateInput} from one workflow/ralph tool call's
179
177
  * arguments — structural reads, NEVER throws (plan
180
- * `20260815-dsh-workflow-gate` Task 1; args shapes architect-verified:
178
+ * Task 1; args shapes architect-verified:
181
179
  * workflow `{ script, meta: { name, description, whenToUse?, phases? },
182
180
  * args? }` (`tool-workflow/src/index.ts:152-161`); ralph
183
181
  * `{ objective, maxRounds?, maxHandoffChars? }`
@@ -187,7 +185,7 @@ export interface WorkflowGateInput {
187
185
  *
188
186
  * `meta.name` is NORMALIZED through {@link normalizeWorkflowName} (control
189
187
  * chars stripped) BEFORE the empty check — the P-c cache-key congruence
190
- * fold-in (plan Task 5): the run-start observation (workflow-ledger.ts)
188
+ * fold-in: the run-start observation (workflow-ledger.ts)
191
189
  * keys the ask cache with the SAME normalized name, so a control-char name
192
190
  * (`au\u0000dit`) asks once and observes under one key instead of re-asking
193
191
  * forever. The length is NEVER capped here (the gate's identity axis is
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Warn-only adoption advisory for the OPTIONAL `dsh-llm-fallbacks` plugin
3
- * (plan `20260815-dsh-fallbacks-personas` Task 4 + `20260816-dsh-b4-seeds`
4
- * Task 3): when the capability is mounted, ONE advisory pass per apply
3
+ * (plan Task 4 + when the capability is mounted, ONE advisory pass per apply
5
4
  * reports the deployment's fallbacks taxonomy state (bounded: ≤1 warn per
6
5
  * category, logger `mstar/fallbacks-advisory`):
7
6
  *
@@ -28,12 +27,18 @@
28
27
  *
29
28
  * Unreadable row config (absent field / non-object, or an unreadable
30
29
  * `roles.list`) → skip + one debug log. Unmounted → the pass is not invoked
31
- * (returns `false`, no logs). The advisory NEVER writes the fallbacks config
32
- * — the read is read-only over the deployment's config layer (never the
33
- * fallbacks plugin's module internals); the only write path is the
34
- * idempotent seeds re-declare through the released seeds surface (no-delta
35
- * → no settings write upstream). The advisory never throws (the caller's
36
- * dispatch/apply flow is never affected).
30
+ * (`{ ran: false, converged: false }`, no logs). An aborted pass (any caught
31
+ * error, including a rejected re-declare) reports `{ ran: true, converged:
32
+ * false }` — the honest latch: the caller arms its one-shot latch only on
33
+ * `ran && converged`, so a failed pass never suppresses the decision-point
34
+ * retry. The degraded-abort warn is deduplicated to at most ONE per apply
35
+ * (module flag; the entry resets it via {@link resetAdvisoryAbortWarn}).
36
+ * The advisory NEVER writes the fallbacks config — the read is read-only
37
+ * over the deployment's config layer (never the fallbacks plugin's module
38
+ * internals); the only write path is the idempotent seeds re-declare
39
+ * through the released seeds surface (no-delta → no settings write
40
+ * upstream). The advisory never throws (the caller's dispatch/apply flow is
41
+ * never affected).
37
42
  *
38
43
  * Module boundary: no barrel — the entry imports this module by explicit
39
44
  * relative path (the role-persona module pattern).
@@ -54,24 +59,56 @@ export declare function setAdvisoryLogger(sink: AdvisoryLogSink): AdvisoryLogSin
54
59
  /**
55
60
  * Warn id-list cap: an id-list warn line lists at most this many ids before
56
61
  * the `… and K more` suffix — a huge registry (thousands of rows) must not
57
- * produce a multi-KB log line (plan QC fix wave S-cap). Exported for the
62
+ * produce a multi-KB log line (cap). Exported for the
58
63
  * suite's cap assertions; module surface only — the entry's frozen 47-name
59
64
  * export surface deliberately does not re-export it.
60
65
  */
61
66
  export declare const ADVISORY_ID_LIST_CAP = 20;
62
67
  /**
63
- * One advisory pass: unmounted → not invoked (`false`, no logs); mounted →
64
- * report the taxonomy adoption state (bounded: ≤1 warn per category). With
65
- * the service present the pass is ASYNC: it awaits the idempotent re-declare
66
- * before the effective-state readback (report determinism — the boot
67
- * dual-inject-child race window is closed). Never throws — every failure
68
- * mode degrades to skip + one debug/warn. Never writes the fallbacks config.
68
+ * One advisory pass outcome (the honest-latch contract):
69
+ * - `ran` — the pass executed (the capability is mounted); `false` means the
70
+ * pass was not invoked (unmounted). Carries the one-pass-per-apply
71
+ * bookkeeping.
72
+ * - `converged` — the pass reached its converged end. Per return path:
73
+ * unmounted → `false`; aborted pass (any caught error, including a
74
+ * rejected re-declare) → `false`; a no-re-declare path (loader-fallback
75
+ * structural read, unreadable config, or a service-present pass that
76
+ * never reaches the re-declare) → `true`; service-present path → reflects
77
+ * the re-declare resolving.
78
+ *
79
+ * The caller (entry `apply`) arms its one-shot latch only on
80
+ * `ran && converged` — a rejected re-declare must never suppress the
81
+ * `subagent/start` decision-point retry.
82
+ */
83
+ export interface AdvisoryPassReport {
84
+ ran: boolean;
85
+ converged: boolean;
86
+ }
87
+ /**
88
+ * Reset the degraded-abort warn dedup flag (one warn per apply budget).
89
+ * Called by the entry at `apply` (next to the advisory sink binding) and in
90
+ * the `llm-fallbacks` inject child's teardown (a fiber swap re-opens the
91
+ * budget for the re-applied fiber). Exported for the suite's dedup case.
92
+ */
93
+ export declare function resetAdvisoryAbortWarn(): void;
94
+ /**
95
+ * One advisory pass: unmounted → not invoked (`{ ran: false, converged:
96
+ * false }`, no logs); mounted → report the taxonomy adoption state (bounded:
97
+ * ≤1 warn per category). With the service present the pass is ASYNC: it
98
+ * awaits the idempotent re-declare before the effective-state readback
99
+ * (report determinism — the boot dual-inject-child race window is closed).
100
+ * Never throws — every failure mode degrades to skip + one debug/warn, and
101
+ * an aborted pass reports `converged: false` (the honest latch). Never
102
+ * writes the fallbacks config.
69
103
  *
70
104
  * @param ctx - the plugin's registrant context (the app composition root).
71
105
  * @param agentsDir - the `harness-agents/` mirror root the mstar role-id set
72
106
  * is derived from; absent → the taxonomy checks are skipped (one debug
73
107
  * log; the legacy-keys check is mirror-independent and still runs).
74
- * @returns `true` when the pass ran (mounted), `false` when unmounted — the
75
- * caller (entry `apply`) uses the boolean for the one-pass-per-apply latch.
108
+ * @returns the {@link AdvisoryPassReport} — `ran` marks a mounted pass (the
109
+ * one-pass-per-apply bookkeeping), `converged` marks a pass that reached
110
+ * its converged end; the caller (entry `apply`) arms the one-shot latch
111
+ * only on `ran && converged`, so an aborted pass (e.g. a rejected
112
+ * re-declare) never suppresses the decision-point retry.
76
113
  */
77
- export declare function runFallbacksAdvisory(ctx: Context, agentsDir: string | undefined): Promise<boolean>;
114
+ export declare function runFallbacksAdvisory(ctx: Context, agentsDir: string | undefined): Promise<AdvisoryPassReport>;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Capability probes for the OPTIONAL `dsh-llm-fallbacks` plugin (plan
3
- * `20260814-dsh-fallbacks-integration` Task 1 — probe foundation).
3
+ * Task 1 — probe foundation).
4
4
  *
5
5
  * The fallbacks plugin is an optional SEPARATE install (two-command
6
6
  * contract) and a dev-time-only dependency of this package: src carries
@@ -55,7 +55,7 @@ export declare function fallbacksService(ctx: Context): FallbacksServiceView | u
55
55
  * The fallbacks loader row when present and enabled (group rows skipped).
56
56
  * Unlike {@link fallbacksMounted}, NO live-fiber requirement: the entry is
57
57
  * declarative and `options.config` is set at entry creation, so the adoption
58
- * advisory (plan `20260815-dsh-fallbacks-personas` Task 4) can read the
58
+ * advisory can read the
59
59
  * deployment's row config even during HMR/fiber-swap windows — the advisory
60
60
  * caller gates on `fallbacksMounted` first.
61
61
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Zero-config seed declaration for the OPTIONAL `dsh-llm-fallbacks` plugin
3
- * (plan `20260816-dsh-b4-seeds` Task 2): when the `llm-fallbacks` service is
3
+ * : when the `llm-fallbacks` service is
4
4
  * applied, this module declares the 13 `mode: subagent` mstar roles into the
5
5
  * fallbacks seed registry — persona = mirror `description` (verbatim, the
6
6
  * SSOT stays `mstar-roles`) + one mandatory-load guide line.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Local structural mirrors of the consumed `dsh-llm-fallbacks` surface
3
- * (plan `20260831-dsh-alpha2-optional-fallbacks` Task 2). dsh natively
3
+ * . dsh natively
4
4
  * covers subagent customization, so the fallbacks
5
5
  * plugin is an OPTIONAL capability activated by the unchanged two-command
6
6
  * install contract — and a dev-time-only dependency of this package (type
@@ -4,7 +4,7 @@ import type { Config, HarnessResolver } from './_shared.ts';
4
4
  export declare const GOAL_BRIDGE_LOGGER = "mstar/goal-bridge";
5
5
  /**
6
6
  * Flat `maxGoalRounds` config fallback (architect decision — plan
7
- * `20260816-dsh-nb2-goal-bridge`): 256, aligned with the GoalService default
7
+ * ): 256, aligned with the GoalService default
8
8
  * (`goal/src/index.ts:187`) and ralph `maxRounds` (`tool-ralph/src/index.ts:37`).
9
9
  */
10
10
  export declare const DEFAULT_MAX_GOAL_ROUNDS = 256;
@@ -46,8 +46,7 @@ export interface GoalView extends GoalRefView {
46
46
  * index.ts:244-257`); `complete` is a CAS by `{ id, revision }`
47
47
  * (`GOAL_STALE_REVISION` on stale). The drift path uses complete+create
48
48
  * (never `edit`) so each new iteration gets a FRESH goal with a clean
49
- * round budget (plan QC fix wave — qc2 W-1 / qc3 F-001/F-008).
50
- */
49
+ * round budget. */
51
50
  export interface GoalsServiceView {
52
51
  get(agent: unknown): GoalView | undefined;
53
52
  create(agent: unknown, request: {
@@ -74,8 +73,7 @@ export declare function iterationGoalObjective(iterationId: string): string;
74
73
  * `status` is `active` or `locked` — the directory name IS the iteration id
75
74
  * (plan-conventions `{ITERATION_DIR}/<id>/`). Completed/status-less/archived
76
75
  * compasses do not steer. Silent on any read failure (advisory degrade).
77
- * Shared with the planMode bridge via explicit no-barrel import (Task 4b —
78
- * the same "is an active iteration steering" read).
76
+ * Shared with the planMode bridge via explicit no-barrel import (the same "is an active iteration steering" read).
79
77
  * @param harnessDir - the resolved `{HARNESS_DIR}`.
80
78
  */
81
79
  export declare function steeringCompass(harnessDir: string): {
@@ -115,13 +113,12 @@ export declare function mirrorIterationGoal(agent: unknown, input: MirrorIterati
115
113
  * first root-like ancestor. `undefined` when unresolvable (fork lineage,
116
114
  * non-in-process provider, registry gap, or a cycle) — the decision point
117
115
  * then silently skips. Cycle guard: a `seen` set over visited session ids
118
- * (the upstream `liveLineage` guard — plan QC fix wave qc2 W-2 / qc3
119
- * F-003) breaks on ANY revisited id — a 1-hop self-loop, a 2+ hop cycle
116
+ * (the upstream `liveLineage` guard) breaks on ANY revisited id — a 1-hop self-loop, a 2+ hop cycle
120
117
  * (A→B→A), or a longer malformed lineage — instead of spinning forever on
121
118
  * the synchronous `subagent/start` decision-point listeners (reachable via
122
119
  * HMR remounts, resumed/forked sessions with stale headers, or a future
123
120
  * host change). Shared with the planMode bridge via explicit no-barrel
124
- * import (Task 4b — the same `subagent/start` decision-point root walk).
121
+ * import (the same `subagent/start` decision-point root walk).
125
122
  */
126
123
  export declare function rootAgentOf(agent: unknown, agents: AgentsView): unknown | undefined;
127
124
  /**
@@ -131,7 +128,7 @@ export declare function rootAgentOf(agent: unknown, agents: AgentsView): unknown
131
128
  * decision point — index.ts advisory slot), resolving the delegating ROOT
132
129
  * via the `parentSession` walk — the two mirror edges are idempotent (get +
133
130
  * compare when the mirror is in place — no churn) — plus a THIRD, advisory
134
- * listener on the `session/event` firehose (Task 3): a `goal/change`
131
+ * listener on the `session/event` firehose : a `goal/change`
135
132
  * envelope whose goal is blocked logs ONE warn (code + objective summary +
136
133
  * project-register residual pointer) with ZERO harness writes
137
134
  * (the one-way mirror; see {@link warnBlockedGoal}). The goals service is an
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Native-first role-persona delivery (plan `20260831-dsh-alpha2-optional-fallbacks`
3
- * Task 3): a role-matched subagent start merges the persona into the request's
2
+ * Native-first role-persona delivery : a role-matched subagent start merges the persona into the request's
4
3
  * NATIVE `persona` slot (`@deepseek-ai/dsh-subagent`
5
4
  * `SubagentStartRequest.persona`) — the additive `mstar:role-persona`
6
5
  * system-prompt section is gone. Native semantics: the request persona
@@ -37,14 +36,20 @@
37
36
  * parsers the dispatch gate uses (`assignmentHeaderRegion` +
38
37
  * `parseAssignmentFields`) — over the start request's prompt text (the
39
38
  * `ContentBlock[]` the child receives as its first user message). Persona
40
- * lookup (plan `20260815-dsh-fallbacks-personas` Task 3) is the single
39
+ * lookup is the single
41
40
  * {@link personaFor} surface — `Config.rolePersonas[executeAs]` →
42
41
  * `harness-agents/` mirror default → skip (never gated on `roleMap` or on
43
42
  * the fallbacks mounted state: persona delivery is fallbacks-independent).
44
43
  * `roleMap` is a taxonomy bridge for logging + future rule-driven interop
45
44
  * only. The mirror root is bound at apply (`setRolePersonaAgentsDir` ←
46
45
  * `packagedAgentsDir()`), package-relative so the shipped bundle works from
47
- * any launch cwd.
46
+ * any launch cwd. Lifetime: the root is a module-level binding with ONE
47
+ * writer — the per-apply `setRolePersonaAgentsDir` call — and it is read
48
+ * per start, so every start observes an apply-constant value; re-calling
49
+ * the setter (an HMR re-apply) IS the re-bind, and that re-bind is the
50
+ * intended reset (it also re-arms the mirror-absent latch below). The
51
+ * per-apply payload `Config.rolePersonas` is the contrast: closed over per
52
+ * apply in `registerRolePersonaChannel`.
48
53
  *
49
54
  * Capability gates (native fail-loud contracts, per surface): one-shot
50
55
  * `SubagentRuntime.start` REJECTS a request carrying `persona` for a
@@ -69,6 +74,22 @@
69
74
  * per apply (S-002 latch); a throwing merge aborts the merge only — the
70
75
  * ORIGINAL request reaches the service and the start is never affected.
71
76
  *
77
+ * Seam probe (apply-time, observation only): a future cordis rename/removal
78
+ * of `internal/get` would stop the listener from ever firing — persona
79
+ * delivery would silently degrade to the raw service with no runtime
80
+ * signal. {@link probeRolePersonaSeam} runs ONCE per apply right after
81
+ * {@link registerRolePersonaChannel}: a temporary canary listener + ONE
82
+ * controlled proxied read (`ctx.subagents` — NEVER `ctx.get`, whose accessor
83
+ * bypasses the waterfall and would false-warn every healthy boot) assert
84
+ * that the seam dispatched AND the returned value carries the wrapper brand.
85
+ * A broken seam warns ONCE per apply (fail-loud); an unresolved service is
86
+ * `service-absent` (`ok: true` + one debug — the apply ctx does not resolve
87
+ * `subagents`; cordis resolves the service in dispatch scopes, where reads
88
+ * are intercepted per read); any probe-internal error fails
89
+ * OPEN (`ok` + one debug) — the probe never throws and never blocks a
90
+ * dispatch. The decision core is the pure {@link evaluateSeamProbe}, so the
91
+ * whole outcome table is unit-pinnable without cordis internals.
92
+ *
72
93
  * Persona text is rendered by dsh system-prompt's STRICT `{{...}}`
73
94
  * interpolation (the native persona has the same template semantics as the
74
95
  * deployment persona), so persona values MUST NOT contain `{{` paired with
@@ -78,7 +99,12 @@
78
99
  * boot throw).
79
100
  *
80
101
  * Module boundary: no barrel — the entry imports this module by explicit
81
- * relative path and re-exports the public names verbatim. No dsh-subagent
102
+ * relative path and re-exports the public names verbatim, EXCEPT the four
103
+ * probe exports (`PERSONA_SEAM_EVENT`, `ROLE_PERSONA_WRAPPER_BRAND`,
104
+ * `evaluateSeamProbe`, `probeRolePersonaSeam`), which are deliberately NOT
105
+ * re-exported from the entry: the frozen entry surface keeps the probe
106
+ * observable only through this module (tests import it directly; the
107
+ * shipped bundle exports no probe symbol). No dsh-subagent
82
108
  * dependency: the runtime surface is consumed structurally (same pattern as
83
109
  * the probe's `LoaderEntryView` and T2's `fallbacks-structural.ts`).
84
110
  */
@@ -86,6 +112,23 @@ import type { Context } from '@deepseek-ai/cordis';
86
112
  import type { Config } from './_shared.ts';
87
113
  /** Logger label for the role-persona channel (dsh logger naming: `<scope>/<subject>`). */
88
114
  export declare const ROLE_PERSONA_LOGGER = "mstar/role-persona";
115
+ /**
116
+ * The interception seam: the cordis service-read waterfall event the channel
117
+ * listener registers on. The registration and the apply-time seam probe both
118
+ * reference THIS constant — a future cordis rename of `internal/get` becomes
119
+ * a one-line, probe-family-caught edit here instead of a silent delivery
120
+ * stop (the probe family pins the literal; see `probeRolePersonaSeam`).
121
+ */
122
+ export declare const PERSONA_SEAM_EVENT = "internal/get";
123
+ /**
124
+ * Wrapper brand — the non-enumerable symbol own property every persona
125
+ * wrapper carries (`wrapSubagentsService` stamps it at creation). The apply-
126
+ * time seam probe reads it to assert the wrapper was actually installed on
127
+ * the controlled read. Non-enumerable + symbol keeps the wrapper's
128
+ * key/spread/JSON surface identical to the wrapped service's (behavior-
129
+ * neutral by construction).
130
+ */
131
+ export declare const ROLE_PERSONA_WRAPPER_BRAND: symbol;
89
132
  /** One consumed prompt content block (`@deepseek-ai/dsh-llm` `ContentBlock` text members). */
90
133
  interface PromptBlockView {
91
134
  readonly type: string;
@@ -167,8 +210,14 @@ export type RolePersonaLogSink = (level: RolePersonaLogLevel, message: string) =
167
210
  */
168
211
  export declare function setRolePersonaLogger(sink: RolePersonaLogSink): RolePersonaLogSink;
169
212
  /**
170
- * Bind the persona-defaults mirror root. Returns the PRIOR binding so a
171
- * caller can restore it (test pattern: {@link setRolePersonaLogger}).
213
+ * Bind the persona-defaults mirror root — the module sink's only writer,
214
+ * invoked once per apply from the entry with `packagedAgentsDir()`, so an
215
+ * HMR re-apply re-binds the root instead of inheriting the previous
216
+ * apply's binding. That re-bind is the intended reset: beyond swapping the
217
+ * root it re-arms the S-002 mirror-absent latch (`mirrorAbsentDebugged`),
218
+ * keeping the "no mirror" debug at most once per apply, and the returned
219
+ * PRIOR binding lets a caller restore the previous root (test pattern:
220
+ * {@link setRolePersonaLogger}).
172
221
  * @param dir - the mirror root, or `undefined` to disable mirror defaults.
173
222
  */
174
223
  export declare function setRolePersonaAgentsDir(dir: string | undefined): string | undefined;
@@ -188,4 +237,71 @@ export declare function setRolePersonaAgentsDir(dir: string | undefined): string
188
237
  * only payload source; `roleMap` is never consulted for the merge).
189
238
  */
190
239
  export declare function registerRolePersonaChannel(ctx: Context, config: Config): void;
240
+ /** Outcome of one apply-time seam probe ({@link probeRolePersonaSeam}). */
241
+ export interface PersonaSeamProbeResult {
242
+ /** `true` = the channel is healthy OR the probe failed open (never block apply). */
243
+ ok: boolean;
244
+ /**
245
+ * Why the probe classified the channel the way it did. `ok: false` ALWAYS
246
+ * carries a reason; `service-absent` may appear with `ok: true` (the
247
+ * sanctioned no-warn unresolved-service classification).
248
+ */
249
+ reason?: 'seam-absent' | 'wrap-skipped' | 'service-absent';
250
+ }
251
+ /** One probe observation — the inputs of the pure decision core. */
252
+ export interface SeamProbeInputs {
253
+ /** Whether the temporary canary listener fired during the controlled read. */
254
+ dispatched: boolean;
255
+ /** The value the controlled read threw (`undefined` = the read resolved). */
256
+ readError: unknown;
257
+ /** The controlled read's resolved value (`undefined` when the read threw). */
258
+ value: unknown;
259
+ }
260
+ /**
261
+ * Pure decision core of the seam probe — the ENTIRE outcome table, unit-
262
+ * pinnable without cordis internals:
263
+ *
264
+ * - canary silent → `{ ok: false, reason: 'seam-absent' }` — cordis no
265
+ * longer dispatches the seam; our listener can never run. Dominates the
266
+ * other inputs (a silent canary means the delivery channel is gone).
267
+ * - canary fired + read threw → `{ ok: true, reason: 'service-absent' }` —
268
+ * the seam works but the reading ctx does not resolve `subagents` (on the
269
+ * real composition the apply ctx is inject-guarded; cordis resolves the
270
+ * service in dispatch scopes, where reads are intercepted per read). Never
271
+ * a warn.
272
+ * - canary fired + branded value → `{ ok: true }` — healthy.
273
+ * - canary fired + any other resolved value (unbranded object, primitive,
274
+ * undefined) → `{ ok: false, reason: 'wrap-skipped' }` — the listener ran
275
+ * but the shape was unrecognized (the `wrapSubagentsService` pass-through).
276
+ */
277
+ export declare function evaluateSeamProbe({ dispatched, readError, value }: SeamProbeInputs): PersonaSeamProbeResult;
278
+ /**
279
+ * Apply-time seam probe — runs EXACTLY ONCE per apply, immediately after
280
+ * {@link registerRolePersonaChannel} (entry wiring), and classifies the
281
+ * channel's install state per {@link evaluateSeamProbe} (observation only —
282
+ * it never changes delivery semantics):
283
+ *
284
+ * 1. register a TEMPORARY {@link PERSONA_SEAM_EVENT} canary listener
285
+ * (`(ctx, name, error, next) => { dispatched = true; return next() }`),
286
+ * keeping the disposer `ctx.on` returns;
287
+ * 2. perform ONE controlled proxied read `ctx.subagents` inside try/catch —
288
+ * the exact read path the per-call `ctx.subagents.start(...)` dispatch
289
+ * takes. NEVER `ctx.get('subagents')`: the accessor reads the service
290
+ * store directly and bypasses the waterfall, which would false-warn
291
+ * `seam-absent` on every healthy boot;
292
+ * 3. dispose the canary SYNCHRONOUSLY (`finally` — also on the throwing
293
+ * read path);
294
+ * 4. classify via {@link evaluateSeamProbe} and log: `ok === false` → ONE
295
+ * warn ({@link SEAM_WARN} + reason); `service-absent` → one debug; a
296
+ * healthy probe stays silent.
297
+ *
298
+ * Contained failure: the body is fully try/catch-wrapped — any probe-
299
+ * internal error (e.g. a rejected listener registration) fails OPEN with
300
+ * `{ ok: true }` plus ONE debug naming the error. Never throws out of
301
+ * `apply`; never affects a subagent start.
302
+ *
303
+ * @param ctx - the plugin's registrant context (a runtime-bearing context —
304
+ * proxied property reads on it dispatch the seam waterfall).
305
+ */
306
+ export declare function probeRolePersonaSeam(ctx: Context): PersonaSeamProbeResult;
191
307
  export {};
@@ -56,9 +56,21 @@ export declare class SkillLintVetoError extends Error {
56
56
  * CLI `mstar skill lint` combination plus the ephemeral-citation gate;
57
57
  * violation codes `lint.frontmatter.*` / `skill-authoring.five-question.*`
58
58
  * / `skill.ephemeral.*`). Pure: no enforcement, no I/O.
59
+ *
60
+ * Five-question profile (spec A4): the shared Engine classifier
61
+ * (`classifySkillLint`) selects the mode from `options.skillId` — the
62
+ * trusted resolved skill-target basename passed by the fs-intent path and
63
+ * `lintSkillWrite`. A doc-only call (no `skillId`) stays strict authoring —
64
+ * the greenfield default is never loosened by an unparented document. The
65
+ * frontmatter and ephemeral-citation checks run in every profile; `core`
66
+ * (exact `mstar-harness-core`) skips only the five-question check.
59
67
  * @param doc - the full SKILL.md text.
68
+ * @param options - `skillId`: the resolved skill-target directory basename
69
+ * (trusted boundary identity — never the doc's YAML `name` alone).
60
70
  */
61
- export declare function lintSkillDoc(doc: string): GateResult;
71
+ export declare function lintSkillDoc(doc: string, options?: {
72
+ skillId?: string;
73
+ }): GateResult;
62
74
  /**
63
75
  * Enforce the skill-authoring lints over a KNOWN document (the brief's
64
76
  * "incoming doc when available" branch): `Enforcement: hard` + violations →
@@ -68,8 +80,13 @@ export declare function lintSkillDoc(doc: string): GateResult;
68
80
  * needed on this branch. The content-blind listener path (where the
69
81
  * incoming doc is never visible) routes through {@link gateSkillIntent}
70
82
  * instead, which applies the status-gate repair-escape decision.
83
+ *
84
+ * The lint profile is classified from the trusted resolved skill-target
85
+ * basename (spec A4): `basename(dirname(resolve(options.target)))` — the
86
+ * write's own target, never the document's YAML `name`.
71
87
  * @param doc - the document about to be written (the write's content).
72
- * @param options - target display path (veto message) + resolved hard flag.
88
+ * @param options - target display path (veto message + profile identity) +
89
+ * resolved hard flag.
73
90
  */
74
91
  export declare function lintSkillWrite(doc: string, options: {
75
92
  target: string;
@@ -1,11 +1,8 @@
1
1
  /**
2
- * Harness-rules system-prompt injection (plan `20260816-dsh-nb1-systemprompt`
3
- * Task 2): the root session's ONE `mstar:harness-rules` pointer section plus
4
- * the `mstar:engine-status` runtime-context summary, both registered on the
5
- * GLOBAL prompt layer — visible to the root session AND every dispatched
2
+ * Harness-rules system-prompt injection (visible to the root session AND every dispatched
6
3
  * child — on their own names and layers (the child persona rides the NATIVE
7
4
  * subagent persona channel since plan
8
- * `20260831-dsh-alpha2-optional-fallbacks` Task 3 — no child-scoped
5
+ * Task 3 — no child-scoped
9
6
  * `mstar:role-persona` section exists anymore; duplicate-name throws remain
10
7
  * per name per layer, verified `scope/src/store.ts`).
11
8
  *
@@ -18,13 +15,13 @@
18
15
  * interpolation and throws on unknown/malformed/undefined references
19
16
  * (`interpolate` in `@deepseek-ai/dsh-system-prompt`), so every injected
20
17
  * string must carry no complete group. The mechanism is LIVE, not static
21
- * (plan QC fix wave W-1): every operator-controlled value embedded below
18
+ * : every operator-controlled value embedded below
22
19
  * (harness dir, plan ids, iteration id, lease fields, direction prose)
23
20
  * is passed through `stripInterpolationHazard` — complete `{{…}}` groups
24
21
  * are screened so a hostile value can never break prompt assembly, while
25
22
  * a lone `{{` stays literal prose.
26
23
  * - The harness dir is resolved PER ASSEMBLY from the assembly context's
27
- * agent (plan QC fix wave W-2 — the catalog pre-step precedent): the
24
+ * agent : the
28
25
  * session cwd of the agent whose prompt is being assembled, via
29
26
  * `resolver.forAgent`, with the boot value (`forWorkspace(undefined)`,
30
27
  * the explicit config or null) as the fallback when the assembly carries
@@ -39,13 +36,12 @@
39
36
  * re-registration, in zero-config and explicit-config deployments alike.
40
37
  * - The context provider reuses the catalog's unified machine-summary
41
38
  * source (`buildCatalogSources` — the SAME builder the engine-status
42
- * pre-step catalog row uses) and projects the SLIM digest (plan
43
- * `20260820-dsh-engine-status-slim` Task 2): the version watermark
39
+ * pre-step catalog row uses) and projects the SLIM digest: the version watermark
44
40
  * ALWAYS, plus ONE `workflow … | plans: …` line only when the active set
45
41
  * selects a lifecycle (`state.selection.kind === 'active'`). Harness dir
46
42
  * and enforcement live in `mstar:harness-rules`; residuals / leases /
47
43
  * direction / iteration-gate detail stay exclusive to the pre-step row.
48
- * v3 (plan `20260819-workflow-dsh-viz` Task 3): the
44
+ * v3 : the
49
45
  * digest reads ONLY the catalog row (`state` — itself aggregated from the
50
46
  * SELECTED workflow snapshot + project registers) — no direct
51
47
  * status.json / snapshot file reads to change. The build is TTL-memoized
@@ -64,7 +60,7 @@
64
60
  * - Registration is deferred through `ctx.inject(['systemPrompt'], …)`
65
61
  * (HMR-safe re-apply): the `section()`/`context()` calls run on the
66
62
  * inject child, and the exact disposers they return are collected on
67
- * that child via `systemPromptCtx.effect` (plan QC fix wave W-HMR) — the
63
+ * that child via `systemPromptCtx.effect` — the
68
64
  * registrations therefore unwind with THIS plugin's apply by explicit
69
65
  * ownership, so a re-apply disposes the old registrations before
70
66
  * registering fresh ones (no duplicate-name throw, no stale closure from
@@ -18,7 +18,7 @@ import { HarnessResolver } from './_shared.ts';
18
18
  export declare function registerSddIterationTools(ctx: Context, resolver: HarnessResolver): void;
19
19
  /**
20
20
  * Register the on-demand seam validation tools (
21
- * 20260808-dsh-seams-bundle): `mstar design-md validate` / `mstar compound
21
+ * : `mstar design-md validate` / `mstar compound
22
22
  * validate` CLI mirrors plus the audit / roles validators — thin wrappers
23
23
  * running the engine in-app. The registrations are deferred with
24
24
  * `ctx.inject(['tools'], …)` (same optional-unit pattern as the sdd tools),