@mstar-harness/engine 3.6.2 → 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.
@@ -6,14 +6,14 @@
6
6
  * Source skills (semantic SSOT — this module implements their deterministic
7
7
  * rules, it never redefines them; roadmap §8.5 C2):
8
8
  * - `mstar-skill-authoring` SKILL.md § Frontmatter Contract — `name` stable
9
- * lowercase-hyphen; `description` is the trigger contract (not a workflow
10
- * summary), third person.
9
+ * lowercase-hyphen; `description` is the trigger contract (not a workflow
10
+ * summary), third person.
11
11
  * - `mstar-skill-authoring` SKILL.md § Body 必须回答的 5 问 + § 默认 Body
12
- * 结构 — a SKILL.md body answers five questions via key sections (Load
13
- * Order, Workflow, Decision Rules, Evidence, References).
12
+ * 结构 — a SKILL.md body answers five questions via key sections (Load
13
+ * Order, Workflow, Decision Rules, Evidence, References).
14
14
  * - `mstar-skill-authoring` SKILL.md § Skill-relative script and asset
15
- * paths ("skill `my-skill` → scripts/do-thing") + `mstar-host` SKILL.md
16
- * § Resolve loaded skill root (per-host resolution).
15
+ * paths ("skill `my-skill` → scripts/do-thing") + `mstar-host` SKILL.md
16
+ * § Resolve loaded skill root (per-host resolution).
17
17
  *
18
18
  * The SkillsBench six principles and trigger-contract reasoning stay prompt.
19
19
  */
@@ -46,10 +46,37 @@ export declare function stripFrontmatter(text: string): string;
46
46
  * or `runtime` (canonical plus the locked `RUNTIME_HEADING_ALIASES` table
47
47
  * — shipped `mstar-*` topic skills). */
48
48
  export type FiveQuestionMode = "authoring" | "runtime";
49
+ /** Skill-lint profile kind (spec A4): `core` = the `mstar-harness-core` hub
50
+ * (five-question exempt), `runtime` = shipped `mstar-*` topic skills, and
51
+ * `authoring` = the standard plus every non-`mstar-*`/unknown input. */
52
+ export type SkillLintKind = "core" | "runtime" | "authoring";
53
+ /** Classification result: the profile kind plus the five-question mode to
54
+ * apply — `null` mode means the five-question check is skipped entirely
55
+ * (core exemption only; every other check stays active). */
56
+ export type SkillLintProfile = {
57
+ kind: SkillLintKind;
58
+ mode: FiveQuestionMode | null;
59
+ };
60
+ /**
61
+ * One lint-classification policy (spec A4
62
+ * the single profile SSOT the CLI, dsh and drift Guard 5 consume.
63
+ * Semantics preserve the CLI `skill lint` selection verbatim:
64
+ * - exact `mstar-harness-core` → `core` / `null` (five-question exempt by
65
+ * design — hub headings; frontmatter + ephemeral checks still run);
66
+ * - exact `mstar-skill-authoring` → `authoring` (the standard's own
67
+ * definition stays strict despite the `mstar-` prefix);
68
+ * - any other `mstar-*` → `runtime` (locked alias table applies);
69
+ * - unknown / non-`mstar-*` / missing identity → `authoring` (strict
70
+ * default — greenfield inputs are never loosened).
71
+ * The `skillId` is the resolved target directory basename at the CLI and
72
+ * dsh configured skill-root boundaries — never an arbitrary YAML `name`
73
+ * alone (a misleading frontmatter name must not select a looser profile).
74
+ * These are lint profiles only: not authorization, not trusted origin.
75
+ */
76
+ export declare function classifySkillLint(skillId: string | undefined): SkillLintProfile;
49
77
  /**
50
- * Locked runtime alias table (plan 20260816-audit-001-five-question-runtime-
51
- * alignment, Step 2): heading synonyms that answer the same question for
52
- * shipped topic skills, verified against the corpus at `81480e7`. Tokens are
78
+ * Locked runtime alias table: heading synonyms that answer the same question
79
+ * for shipped topic skills, verified against the shipped-skill corpus. Tokens are
53
80
  * case-insensitive heading substrings (any heading level); the `decision-rules`
54
81
  * breadth is bounded by the corpus regression test pinning current state.
55
82
  * `load-order` has no aliases — the canonical label covers 15/16 skills and
package/dist/status.d.ts CHANGED
@@ -14,7 +14,7 @@ export type StatusDoc = {
14
14
  [key: string]: unknown;
15
15
  };
16
16
  /**
17
- * v2 root status document (`{HARNESS_DIR}/status.json`, plan Task 3 — hard
17
+ * v2 root status document (`{HARNESS_DIR}/status.json`( — hard
18
18
  * cutover): `version`, `updated_at`, `workflows[]` only. The list holds
19
19
  * ACTIVE (non-terminal) lifecycles; terminal writers unregister AFTER the
20
20
  * snapshot write (removal-at-terminal).
@@ -96,7 +96,7 @@ export declare function validatePlanRow(row: unknown): GateResult;
96
96
  */
97
97
  export declare function validateResidual(entry: unknown): GateResult;
98
98
  /**
99
- * Validate one v2 root `workflows[]` entry (plan Task 3): required `id`,
99
+ * Validate one v2 root `workflows[]` entry (): required `id`,
100
100
  * `type` (plan | iteration), `started_at`, `dir` — harness-relative, never
101
101
  * absolute and never containing `..`. The removal-at-terminal invariant
102
102
  * (snapshot exists and is non-terminal) is checked at document level by
@@ -104,7 +104,7 @@ export declare function validateResidual(entry: unknown): GateResult;
104
104
  */
105
105
  export declare function validateWorkflowEntry(entry: unknown): GateResult;
106
106
  /**
107
- * Validate a v2 status.json document (plan Task 3 — hard cutover). Accepts a
107
+ * Validate a v2 status.json document ( — hard cutover). Accepts a
108
108
  * parsed document or a file path (malformed JSON yields a
109
109
  * `status.invalid-json` violation, never a throw). v1 or unknown-version
110
110
  * inputs — including v1-shaped documents carrying a root `plans[]` — fail
@@ -122,14 +122,14 @@ export declare function validateWorkflowEntry(entry: unknown): GateResult;
122
122
  * root holds active lifecycles only, and terminal writers unregister AFTER
123
123
  * the snapshot write. The snapshot must also PHYSICALLY live under the
124
124
  * harness: a symlinked `workflows/<id>/` (or snapshot file) resolving
125
- * outside the harness dir is rejected fail-closed (QC wave-1 S-f). Doc
125
+ * outside the harness dir is rejected fail-closed . Doc
126
126
  * input without a harness dir is structure-only.
127
127
  */
128
128
  export declare function validateStatusV2(docOrPath: StatusV2Doc | string, opts?: {
129
129
  harnessDir?: string;
130
130
  }): GateResult;
131
131
  /**
132
- * Relocated v2 root validator (plan Task 3 — hard cutover, no dual path):
132
+ * Relocated v2 root validator ( — hard cutover, no dual path):
133
133
  * the v1 `validateStatus` implementation was deleted in the same task that
134
134
  * introduced the v2 surface; the public export name survives so external
135
135
  * consumers (CLI, host hooks — cut over in P2) keep compiling and now fail
@@ -158,14 +158,14 @@ export declare const validateStatus: typeof validateStatusV2;
158
158
  * Async-only (architect-locked 2026-08-27): the durable write goes through
159
159
  * `getArtifactStore().put({ kind: "status", key: "root", ... })` inside the
160
160
  * caller's lock — the store is the persist backend, never a second lock.
161
- * Fails loud (qc3 F-201) when the active FsStore would resolve its
161
+ * Fails loud when the active FsStore would resolve its
162
162
  * `status.json` to a path other than `statusPath` — callers whose root
163
163
  * differs from the active store's root MUST
164
164
  * `setArtifactStore(createFsStore(root))` first.
165
165
  */
166
166
  export declare function registerWorkflowEntryLocked(statusPath: string, entry: WorkflowEntry): Promise<StatusV2Doc>;
167
167
  /**
168
- * Register one active workflow entry in the v2 root file (plan Task 3).
168
+ * Register one active workflow entry in the v2 root file ().
169
169
  * Idempotent upsert by entry `id` under the root-file `withStatusWriteLock`,
170
170
  * bumping root `updated_at`. A missing/empty root file is initialized from
171
171
  * the v2 template (never a v1 tree); a v1 root is refused with the
@@ -178,7 +178,7 @@ export declare function registerWorkflowEntryLocked(statusPath: string, entry: W
178
178
  */
179
179
  export declare function registerWorkflow(root: string, entry: WorkflowEntry): Promise<StatusV2Doc>;
180
180
  /**
181
- * Remove one workflow entry from the v2 root file (plan Task 3). Idempotent:
181
+ * Remove one workflow entry from the v2 root file (). Idempotent:
182
182
  * removing an absent id is a no-op with no write; a missing/empty root file
183
183
  * is a no-op that never creates the file. Runs under the root-file
184
184
  * `withStatusWriteLock`, bumping root `updated_at` only when an entry was
@@ -186,7 +186,7 @@ export declare function registerWorkflow(root: string, entry: WorkflowEntry): Pr
186
186
  * invariant included) before the write — a v1 root is refused with the
187
187
  * `mstar migrate` hint.
188
188
  *
189
- * Fails loud (qc3 F-201) when the active FsStore would resolve its
189
+ * Fails loud when the active FsStore would resolve its
190
190
  * `status.json` to a path other than the caller's root — the no-op branches
191
191
  * below never mask a store/path mismatch.
192
192
  */
@@ -199,8 +199,7 @@ export declare function unregisterWorkflow(root: string, id: string): Promise<St
199
199
  * frontmatter declares `enforcement: hard` hardens the gate in this repo.
200
200
  * A COMPLETED (or status-less/archived) iteration's compass NEVER hardens:
201
201
  * D2 rollback = unset the flag in the ACTIVE compass, and that must work
202
- * while older completed compasses still declare hard (qc1 F-001 / qc2 F-002).
203
- * A counting compass declaring a non-hard value, or no compass at all,
202
+ * while older completed compasses still declare hard. * A counting compass declaring a non-hard value, or no compass at all,
204
203
  * leaves the flag unset (`source: none`) — hard gates are never the default
205
204
  * and the flag is inert when the engine is absent. Frontmatter is
206
205
  * `---`-fenced; hard declarations in the compass BODY do not count (the
package/dist/store.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- /** JSON coordination-doc kinds the store persists (spec SP2). */
2
- export type ArtifactKind = "status" | "snapshot" | "residuals" | "review" | "json";
1
+ /** JSON coordination-doc kinds the store persists */ export type ArtifactKind = "status" | "snapshot" | "residuals" | "review" | "json";
3
2
  /** Stable key inside the kind. Workflow id, project id, or review id;
4
3
  * `kind: "status"` always uses key `"root"`. */
5
4
  export type ArtifactRef = {
@@ -23,14 +22,13 @@ export interface ArtifactStore {
23
22
  get<T = unknown>(ref: ArtifactRef): Promise<T | undefined>;
24
23
  delete?(ref: ArtifactRef): Promise<void>;
25
24
  /** Enumerate refs of `kind`, sorted by key ascending (spec D4). Uniform
26
- * rule: report what exists — missing backing dir/file → `[]`; every
27
- * listed key round-trips through `get`. `json` is not enumerable. */
25
+ * rule: report what exists — missing backing dir/file → `[]`; every
26
+ * listed key round-trips through `get`. `json` is not enumerable. */
28
27
  list?(kind: ArtifactKind): Promise<ArtifactRef[]>;
29
28
  }
30
- /** Map an artifact ref to its file path under `harnessRoot` (spec SP2
31
- * FsStore path table the single kind→path mapping, shared with SP3;
32
- * SP3 never re-implements or extends it). Exported (qc1 S-002) so SP3
33
- * imports the contract instead of re-deriving it textually. */
29
+ /** Map an artifact ref to its file path under `harnessRoot` (the store contract — the single kind→path
30
+ * mapping). Exported so host adapters import the contract instead of
31
+ * re-deriving it textually. */
34
32
  export declare function resolveArtifactPath(harnessRoot: string, ref: ArtifactRef): string;
35
33
  /** Default local adapter: maps kinds to the existing `.mstar/` paths.
36
34
  * `put` uses the sync `writeJson` (atomic temp+rename unchanged) and
@@ -39,7 +37,7 @@ export declare function resolveArtifactPath(harnessRoot: string, ref: ArtifactRe
39
37
  * malformed JSON → throw with the path in the message. The returned store
40
38
  * also exposes its resolved `root` so the routed writers can fail loud
41
39
  * when a caller's explicit target path diverges from the store-resolved
42
- * path (qc3 F-201); `root` is not part of the `ArtifactStore` contract.
40
+ * path ; `root` is not part of the `ArtifactStore` contract.
43
41
  * `list` enumerates per the D4 table: report what exists — missing
44
42
  * backing dir/file → `[]`, `json` throws, keys sorted ascending. */
45
43
  export declare function createFsStore(harnessRoot: string): ArtifactStore & {
@@ -52,7 +50,7 @@ export declare function setArtifactStore(store: ArtifactStore | undefined): void
52
50
  * `resolveHarnessSubdir` — never a silent cwd fallback. */
53
51
  export declare function getArtifactStore(): ArtifactStore;
54
52
  /**
55
- * Fail-loud path-agreement guard for the routed writers (qc3 F-201): when
53
+ * Fail-loud path-agreement guard for the routed writers : when
56
54
  * `store` is an FsStore, resolve the path the store would compute for
57
55
  * `ref` and require it to equal `expectedPath` (the caller's explicit
58
56
  * target). A divergence means the caller's path lives outside the active
@@ -62,8 +60,7 @@ export declare function getArtifactStore(): ArtifactStore;
62
60
  * Cheap: pure path resolution, no I/O.
63
61
  */
64
62
  export declare function assertFsStorePath(store: ArtifactStore, ref: ArtifactRef, expectedPath: string): void;
65
- /** Load a store module from a filesystem path (spec SP2 § Injection 2–3,
66
- * SP2-AC6 / SP2-AC7). Resolves against cwd; rejects empty values and any
63
+ /** Load a store module from a filesystem path (the store module-loading trust boundary). Resolves against cwd; rejects empty values and any
67
64
  * URI scheme before `import()`; throws when the file is missing. Accepts a
68
65
  * `createArtifactStore` named export, a default-exported factory, or a
69
66
  * default-exported object; the result is structurally verified (`put` +
@@ -1,18 +1,18 @@
1
1
  import type { GateResult } from "./core.js";
2
2
  import { type IntegrationMergeLease } from "./lease.js";
3
3
  import { type PlanRow } from "./status.js";
4
- /** Snapshot file name inside `workflows/<id>/` (plan Task 2 — writer contract). */
4
+ /** Snapshot file name inside `workflows/<id>/` ( — writer contract). */
5
5
  export declare const WORKFLOW_SNAPSHOT_FILE = "snapshot.json";
6
- /** Lifecycle status enum (plan Task 2 — terminal set = completed|failed|stopped). */
6
+ /** Lifecycle status enum ( — terminal set = completed|failed|stopped). */
7
7
  export declare const WORKFLOW_LIFECYCLE_STATUSES: readonly ["running", "paused", "completed", "failed", "stopped"];
8
8
  /** Terminal statuses: snapshot must carry `ended_at` and no dangling leases. */
9
9
  export declare const WORKFLOW_TERMINAL_STATUSES: readonly ["completed", "failed", "stopped"];
10
- /** Lifecycle type enum (plan Task 2 — id reuses the orchestration id). */
10
+ /** Lifecycle type enum ( — id reuses the orchestration id). */
11
11
  export declare const WORKFLOW_LIFECYCLE_TYPES: readonly ["plan", "iteration"];
12
12
  export type WorkflowLifecycleStatus = (typeof WORKFLOW_LIFECYCLE_STATUSES)[number];
13
13
  export type WorkflowLifecycleType = (typeof WORKFLOW_LIFECYCLE_TYPES)[number];
14
14
  /**
15
- * First-class lifecycle execution policy (plan Task 2 — keys copied from root
15
+ * First-class lifecycle execution policy ( — keys copied from root
16
16
  * `metadata` at migrate; values accepted-but-opaque this iteration, no
17
17
  * semantic gate).
18
18
  */
@@ -21,7 +21,7 @@ export type WorkflowExecutionPolicy = {
21
21
  worktree_mode?: unknown;
22
22
  push_policy?: unknown;
23
23
  };
24
- /** Iteration branch anchors (plan Task 2 — from root metadata anchors). */
24
+ /** Iteration branch anchors ( — from root metadata anchors). */
25
25
  export type WorkflowBranchAnchors = {
26
26
  base?: string;
27
27
  integration?: string;
@@ -29,11 +29,11 @@ export type WorkflowBranchAnchors = {
29
29
  };
30
30
  /**
31
31
  * v3 workflow snapshot (`workflows/<id>/snapshot.json`) — final schema
32
- * (plan Task 2). `plans[]` rows are the legacy PlanRow shape verbatim;
32
+ * (). `plans[]` rows are the legacy PlanRow shape verbatim;
33
33
  * per-row `execution_lease` stays on the row, `integration_merge_lease` is
34
34
  * top-level.
35
35
  *
36
- * Notes dual-home SSOT (qc wave-1 S-e): a plan row's `notes` array is the
36
+ * Notes dual-home SSOT: a plan row's `notes` array is the
37
37
  * LEGACY VERBATIM copy preserved at migrate time — the RUNTIME ledger is
38
38
  * `notes.jsonl` in the workflow dir (`migrate.ts` NOTES_LEDGER_FILE). New
39
39
  * notes append to the ledger only; row `notes` is read-only legacy and is
@@ -57,7 +57,7 @@ export type WorkflowSnapshot = {
57
57
  compass_ref?: string;
58
58
  };
59
59
  /**
60
- * Validate a v3 workflow snapshot document (plan Task 2 — final schema):
60
+ * Validate a v3 workflow snapshot document ( — final schema):
61
61
  * enum/type/id checks, `schema_version: 1`, required timestamps, `plans[]`
62
62
  * rows validated by the legacy `validatePlanRow` with row-level
63
63
  * `execution_lease` shape delegated to `validateExecutionLease`,
@@ -70,16 +70,16 @@ export type WorkflowSnapshot = {
70
70
  export declare function validateWorkflowSnapshot(doc: unknown): GateResult;
71
71
  /**
72
72
  * Write a workflow snapshot as a whole-rewrite of `dir/snapshot.json` under
73
- * `withStatusWriteLock(snapshotPath)` (plan Task 2 — the `.status-write.lockdir`
73
+ * `withStatusWriteLock(snapshotPath)` ( — the `.status-write.lockdir`
74
74
  * lands inside `workflows/<id>/`, dirname of the snapshot; no harness-root
75
75
  * pollution). The snapshot is validated first — an invalid snapshot throws
76
76
  * and nothing is written. `dir` is created recursively. The durable write
77
- * routes through the active `ArtifactStore` (spec SP2: snapshot →
77
+ * routes through the active `ArtifactStore` (the store contract: snapshot →
78
78
  * `{ kind: "snapshot", key: <workflow id> }`) inside the existing lock — the
79
79
  * default FsStore resolves `{WORKFLOW_DIR}/<key>/snapshot.json`, identical
80
80
  * to `join(dir, WORKFLOW_SNAPSHOT_FILE)` for canonical callers. The write
81
81
  * fails loud when the active FsStore would resolve a different path than
82
- * the caller's `join(dir, WORKFLOW_SNAPSHOT_FILE)` (qc3 F-201) — callers
82
+ * the caller's `join(dir, WORKFLOW_SNAPSHOT_FILE)` — callers
83
83
  * whose target root differs from the active store's root MUST
84
84
  * `setArtifactStore(createFsStore(root))` first.
85
85
  */
@@ -38,8 +38,7 @@ export type BranchProbeOptions = {
38
38
  /**
39
39
  * Git probe timeout in ms (default 10s; `MSTAR_GIT_PROBE_TIMEOUT_MS` env
40
40
  * overrides; per-call value wins). On timeout the probe fails closed into
41
- * `branch-probe-failed` — never hangs, never guesses a branch (qc3 F-4).
42
- */
41
+ * `branch-probe-failed` — never hangs, never guesses a branch. */
43
42
  timeoutMs?: number;
44
43
  };
45
44
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/engine",
3
- "version": "3.6.2",
3
+ "version": "3.7.0",
4
4
  "description": "Morning Star Harness Workflow Engine — deterministic workflow enforcement library (path, status, lease, dispatch, sdd, iteration, lint gates).",
5
5
  "license": "MIT",
6
6
  "repository": {