@mstar-harness/engine 2.4.1 → 3.0.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.
- package/dist/core.d.ts +1 -1
- package/dist/dispatch.d.ts +1 -1
- package/dist/engine.js +1568 -515
- package/dist/host.d.ts +2 -2
- package/dist/index.d.ts +12 -4
- package/dist/iteration.d.ts +37 -6
- package/dist/lease.d.ts +26 -25
- package/dist/lint.d.ts +1 -2
- package/dist/migrate.d.ts +134 -0
- package/dist/mstarc.d.ts +72 -0
- package/dist/path.d.ts +61 -21
- package/dist/project.d.ts +134 -0
- package/dist/sdd.d.ts +6 -4
- package/dist/status.d.ts +93 -65
- package/dist/workflow.d.ts +78 -0
- package/package.json +1 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type GateResult, type ValidationResult } from "./core.js";
|
|
2
|
+
import { type ResidualEntry } from "./status.js";
|
|
3
|
+
/** Roadmap file name inside `projects/<id>/` (plan Task 4 — writer contract). */
|
|
4
|
+
export declare const PROJECT_ROADMAP_FILE = "roadmap.md";
|
|
5
|
+
/** Project register file name inside `projects/<id>/` (plan Task 4). */
|
|
6
|
+
export declare const PROJECT_REGISTER_FILE = "residuals.json";
|
|
7
|
+
/** Fallback project id for project-less flows (plan Task 4 — compass ruling 2). */
|
|
8
|
+
export declare const _DEFAULT_PROJECT = "_default";
|
|
9
|
+
/** Roadmap status enum (plan Task 4 — frontmatter schema). */
|
|
10
|
+
export declare const ROADMAP_STATUSES: readonly ["active", "paused", "completed"];
|
|
11
|
+
export type RoadmapStatus = (typeof ROADMAP_STATUSES)[number];
|
|
12
|
+
/**
|
|
13
|
+
* Roadmap frontmatter (plan Task 4): machine-checkable subset. All fields
|
|
14
|
+
* are `unknown` because documents come from YAML at runtime; the validator
|
|
15
|
+
* narrows them. `milestones` / `residuals_ref` are optional; goal-item body
|
|
16
|
+
* conventions are warnings only.
|
|
17
|
+
*/
|
|
18
|
+
export type RoadmapFrontmatter = {
|
|
19
|
+
project_id?: unknown;
|
|
20
|
+
title?: unknown;
|
|
21
|
+
status?: unknown;
|
|
22
|
+
created_at?: unknown;
|
|
23
|
+
milestones?: unknown;
|
|
24
|
+
residuals_ref?: unknown;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
/** One register entry: the v1 residual entry verbatim + register provenance. */
|
|
28
|
+
export type ProjectRegisterEntry = ResidualEntry & {
|
|
29
|
+
source_plan: string;
|
|
30
|
+
registered_at: string;
|
|
31
|
+
lifecycle_id?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Register document shape (`projects/<id>/residuals.json`, plan Task 4;
|
|
35
|
+
* QC wave-1 W-E): `entries` keyed by plan id, each value an ARRAY of
|
|
36
|
+
* register entries — v1 `residual_findings[plan-id] = entries[]`
|
|
37
|
+
* multi-finding semantics preserved verbatim (a plan can hold 2+ open
|
|
38
|
+
* residuals). `migration_notes[]` (the old single-entry collapse record)
|
|
39
|
+
* is gone: no entries are ever skipped.
|
|
40
|
+
*/
|
|
41
|
+
export type ProjectRegisterDoc = {
|
|
42
|
+
entries?: Record<string, ProjectRegisterEntry[]>;
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Roadmap validation result: schema violations decide `ok`; body-convention
|
|
47
|
+
* findings are collected as `warnings` and never flip `ok` (plan Task 4 —
|
|
48
|
+
* goal-item body is not a hard gate).
|
|
49
|
+
*/
|
|
50
|
+
export type RoadmapValidation = GateResult & {
|
|
51
|
+
warnings: ValidationResult[];
|
|
52
|
+
};
|
|
53
|
+
/** Findings cleanup policy mirror of Assignment `Findings cleanup`. */
|
|
54
|
+
export type FindingsCleanupMode = "zero-residual" | "allow-residual";
|
|
55
|
+
/** Computed rollup aggregates (jq semantics). */
|
|
56
|
+
export type TechDebtSummary = {
|
|
57
|
+
total_open: number;
|
|
58
|
+
by_severity: Record<string, number>;
|
|
59
|
+
by_target: Record<string, number>;
|
|
60
|
+
by_plan: Record<string, number>;
|
|
61
|
+
};
|
|
62
|
+
export type TechDebtCheck = {
|
|
63
|
+
field: "total_open" | "by_severity" | "by_target" | "by_plan";
|
|
64
|
+
status: "PASS" | "DRIFT";
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Result of the project-register rollup. `stored`/`checks`/`overall` are
|
|
68
|
+
* retained for export-surface compatibility (the P2 CLI cutover): the v1
|
|
69
|
+
* stored-summary drift check (`metadata.tech_debt_summary`) is deleted in
|
|
70
|
+
* the v3 cutover — the project register is the source of truth, so `stored`
|
|
71
|
+
* is always null and every check reports DRIFT.
|
|
72
|
+
*/
|
|
73
|
+
export type TechDebtRollup = {
|
|
74
|
+
computed: TechDebtSummary;
|
|
75
|
+
stored: Record<string, unknown> | null;
|
|
76
|
+
checks: TechDebtCheck[];
|
|
77
|
+
overall: "PASS" | "DRIFT";
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Validate a roadmap.md file (plan Task 4): parse the frontmatter with the
|
|
81
|
+
* shared flat-subset parser and check the schema
|
|
82
|
+
* `{ project_id, title, status: active|paused|completed, created_at,
|
|
83
|
+
* milestones[]?, residuals_ref? }`. A roadmap file whose body follows the
|
|
84
|
+
* documented conventions (a `## Direction` section + goal items as markdown
|
|
85
|
+
* task-list items) is fully green; convention misses are `warnings` only
|
|
86
|
+
* and never flip `ok` (compass Non-Goal / AC-P1).
|
|
87
|
+
*/
|
|
88
|
+
export declare function validateRoadmap(filePath: string): RoadmapValidation;
|
|
89
|
+
/**
|
|
90
|
+
* Validate a project register document (`projects/<id>/residuals.json`,
|
|
91
|
+
* plan Task 4; QC wave-1 W-E): `{ entries: { [key]: entry[] } }` keyed by
|
|
92
|
+
* plan id, each value an ARRAY of entries (v1 `residual_findings[plan-id]`
|
|
93
|
+
* multi-finding semantics preserved — a plan may hold 2+ open residuals).
|
|
94
|
+
* Each entry is validated by the v1 `validateResidual` verbatim (severity
|
|
95
|
+
* enum + lifecycle semantics preserved — the register re-hosts, never
|
|
96
|
+
* copies) plus the register provenance fields `source_plan` (must match its
|
|
97
|
+
* entries key) and `registered_at` (YYYY-MM-DD), and the optional
|
|
98
|
+
* `lifecycle_id`.
|
|
99
|
+
*/
|
|
100
|
+
export declare function validateProjectRegister(doc: unknown): GateResult;
|
|
101
|
+
/**
|
|
102
|
+
* Findings cleanup gate (status-and-residuals.md § Findings cleanup modes;
|
|
103
|
+
* QC wave-1 W-D relocation — the input is the project register
|
|
104
|
+
* `projects/<id>/residuals.json`, entries keyed by plan id with an ARRAY of
|
|
105
|
+
* residuals per plan, and the plan id links the register entries to the
|
|
106
|
+
* snapshot's plan row). Every OPEN entry of the plan is checked.
|
|
107
|
+
* `zero-residual`: only true blocker-defers (`decision: defer` + non-empty
|
|
108
|
+
* `target`) may stay open — fixable findings, `nit`s, and waived/
|
|
109
|
+
* risk-accepted entries are violations. `allow-residual` (default): open
|
|
110
|
+
* residuals are fine unless an unresolved Critical remains. Mode resolution:
|
|
111
|
+
* explicit `opts.mode` → `allow-residual` (the v1
|
|
112
|
+
* `plans[].metadata.findings_cleanup` mirror is deleted — no dual-track).
|
|
113
|
+
*/
|
|
114
|
+
export declare function findingsCleanupGate(register: ProjectRegisterDoc, planId: string, opts?: {
|
|
115
|
+
mode?: FindingsCleanupMode;
|
|
116
|
+
}): GateResult;
|
|
117
|
+
/**
|
|
118
|
+
* Compute the tech-debt rollup over the project registers (QC wave-1 W-D
|
|
119
|
+
* relocation — status-and-residuals.md § `metadata.tech_debt_summary`
|
|
120
|
+
* semantics preserved at the project layer): `total_open` / `by_severity` /
|
|
121
|
+
* `by_target` / `by_plan` over open entries of every
|
|
122
|
+
* `projects/<id>/residuals.json` register under `projectDir` (legacy
|
|
123
|
+
* `"warning"` → `low`, `null`/`""` → `medium`; closed entries skipped;
|
|
124
|
+
* missing `target` groups under `"unspecified"`; `by_plan` keyed by plan id —
|
|
125
|
+
* the snapshot plan linkage; register values are ARRAYS per plan id, so
|
|
126
|
+
* every open entry of a plan counts).
|
|
127
|
+
*
|
|
128
|
+
* The v1 stored-summary drift check (`metadata.tech_debt_summary`) is a v1
|
|
129
|
+
* dead path — the register is the source of truth, so `stored` is always
|
|
130
|
+
* null and the retained `checks`/`overall` fields report DRIFT
|
|
131
|
+
* (export-surface compatibility until the P2 CLI cutover). Does not write
|
|
132
|
+
* anything.
|
|
133
|
+
*/
|
|
134
|
+
export declare function techDebtRollup(projectDir: string): TechDebtRollup;
|
package/dist/sdd.d.ts
CHANGED
|
@@ -35,10 +35,12 @@ export type ReviewPackageOptions = {
|
|
|
35
35
|
* resolves or creates any SDD tree under the feature checkout (refuses a
|
|
36
36
|
* second SDD tree; no override or probe may bypass this guard);
|
|
37
37
|
* 2. explicit harness-root override (`opts.harnessDir` / `MSTAR_HARNESS_DIR`)
|
|
38
|
-
* — plan finding 2026-08-08: covers
|
|
39
|
-
*
|
|
40
|
-
* 3. `
|
|
41
|
-
*
|
|
38
|
+
* — plan finding 2026-08-08: covers repos the status.json probe misses;
|
|
39
|
+
* resolved relative to the established root;
|
|
40
|
+
* 3. `.mstarc` `[config] harness_dir` at `root` (repo-declared root;
|
|
41
|
+
* resolved against the config file's directory);
|
|
42
|
+
* 4. `status.json` probe at root (`.mstar` → `.agents`);
|
|
43
|
+
* 5. fallback: existing `.mstar`/`.agents` dir, else `.mstar`.
|
|
42
44
|
*
|
|
43
45
|
* `controlRoot` (CLI 2nd arg / `MSTAR_CONTROL_ROOT`) pins `root` to the
|
|
44
46
|
* control worktree instead of the cwd's git top-level.
|
package/dist/status.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GateResult } from "./core.js";
|
|
2
2
|
import { type EnforcementFlag } from "./dispatch.js";
|
|
3
|
+
import { type WorkflowLifecycleType } from "./workflow.js";
|
|
3
4
|
/**
|
|
4
5
|
* Loose shape of a parsed status.json document. All fields are `unknown`
|
|
5
6
|
* because documents come from JSON at runtime; validators narrow them.
|
|
@@ -12,6 +13,25 @@ export type StatusDoc = {
|
|
|
12
13
|
metadata?: unknown;
|
|
13
14
|
[key: string]: unknown;
|
|
14
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* v2 root status document (`{HARNESS_DIR}/status.json`, plan Task 3 — hard
|
|
18
|
+
* cutover): `version`, `updated_at`, `workflows[]` only. The list holds
|
|
19
|
+
* ACTIVE (non-terminal) lifecycles; terminal writers unregister AFTER the
|
|
20
|
+
* snapshot write (removal-at-terminal).
|
|
21
|
+
*/
|
|
22
|
+
export type StatusV2Doc = {
|
|
23
|
+
version: 2;
|
|
24
|
+
updated_at: string;
|
|
25
|
+
workflows: WorkflowEntry[];
|
|
26
|
+
};
|
|
27
|
+
/** One active lifecycle entry of the v2 root `workflows[]` list. */
|
|
28
|
+
export type WorkflowEntry = {
|
|
29
|
+
id: string;
|
|
30
|
+
type: WorkflowLifecycleType;
|
|
31
|
+
started_at: string;
|
|
32
|
+
/** Harness-relative snapshot dir (e.g. `workflows/<id>`), never absolute. */
|
|
33
|
+
dir: string;
|
|
34
|
+
};
|
|
15
35
|
/** Residual entry as parsed from status.json (loose — validated by `validateResidual`). */
|
|
16
36
|
export type ResidualEntry = {
|
|
17
37
|
id?: unknown;
|
|
@@ -42,31 +62,6 @@ export type PlanRow = {
|
|
|
42
62
|
execution_lease?: unknown;
|
|
43
63
|
[key: string]: unknown;
|
|
44
64
|
};
|
|
45
|
-
/** Findings cleanup policy mirror of Assignment `Findings cleanup`. */
|
|
46
|
-
export type FindingsCleanupMode = "zero-residual" | "allow-residual";
|
|
47
|
-
/** Computed rollup aggregates (jq semantics). */
|
|
48
|
-
export type TechDebtSummary = {
|
|
49
|
-
total_open: number;
|
|
50
|
-
by_severity: Record<string, number>;
|
|
51
|
-
by_target: Record<string, number>;
|
|
52
|
-
by_plan: Record<string, number>;
|
|
53
|
-
};
|
|
54
|
-
export type TechDebtCheck = {
|
|
55
|
-
field: "total_open" | "by_severity" | "by_target" | "by_plan";
|
|
56
|
-
status: "PASS" | "DRIFT";
|
|
57
|
-
};
|
|
58
|
-
/** Result of the rollup + drift check vs stored `metadata.tech_debt_summary`. */
|
|
59
|
-
export type TechDebtRollup = {
|
|
60
|
-
computed: TechDebtSummary;
|
|
61
|
-
stored: Record<string, unknown> | null;
|
|
62
|
-
checks: TechDebtCheck[];
|
|
63
|
-
overall: "PASS" | "DRIFT";
|
|
64
|
-
};
|
|
65
|
-
export type ArchiveResult = {
|
|
66
|
-
planId: string;
|
|
67
|
-
archived: number;
|
|
68
|
-
archivePath: string;
|
|
69
|
-
};
|
|
70
65
|
/**
|
|
71
66
|
* Normalize a residual `severity` value for reading/rolling up
|
|
72
67
|
* (status-and-residuals.md § severity 5 + rollup `norm_sev`):
|
|
@@ -101,44 +96,69 @@ export declare function validatePlanRow(row: unknown): GateResult;
|
|
|
101
96
|
*/
|
|
102
97
|
export declare function validateResidual(entry: unknown): GateResult;
|
|
103
98
|
/**
|
|
104
|
-
* Validate
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* `metadata.residual_findings` key is flagged as dual-write.
|
|
99
|
+
* Validate one v2 root `workflows[]` entry (plan Task 3): required `id`,
|
|
100
|
+
* `type` (plan | iteration), `started_at`, `dir` — harness-relative, never
|
|
101
|
+
* absolute and never containing `..`. The removal-at-terminal invariant
|
|
102
|
+
* (snapshot exists and is non-terminal) is checked at document level by
|
|
103
|
+
* `validateStatusV2` when a harness dir is known.
|
|
110
104
|
*/
|
|
111
|
-
export declare function
|
|
105
|
+
export declare function validateWorkflowEntry(entry: unknown): GateResult;
|
|
112
106
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* `
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
107
|
+
* Validate a v2 status.json document (plan Task 3 — hard cutover). Accepts a
|
|
108
|
+
* parsed document or a file path (malformed JSON yields a
|
|
109
|
+
* `status.invalid-json` violation, never a throw). v1 or unknown-version
|
|
110
|
+
* inputs — including v1-shaped documents carrying a root `plans[]` — fail
|
|
111
|
+
* closed with an explicit `status.migration-required` violation carrying the
|
|
112
|
+
* `mstar migrate` hint; there is no v1 read path anymore (v1 `validateStatus`
|
|
113
|
+
* was deleted in the same task).
|
|
119
114
|
*
|
|
120
|
-
* `
|
|
121
|
-
*
|
|
122
|
-
* `
|
|
123
|
-
* `withStatusWriteLock` so concurrent coordination writers serialize.
|
|
115
|
+
* Required: `version: 2`, `updated_at` (YYYY-MM-DD, same convention as the
|
|
116
|
+
* v1 root), `workflows[]` of active entries (each validated by
|
|
117
|
+
* `validateWorkflowEntry`, duplicate ids rejected).
|
|
124
118
|
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
119
|
+
* Removal-at-terminal invariant: when a harness dir is known (path input, or
|
|
120
|
+
* `opts.harnessDir` for doc input), every listed entry's snapshot at
|
|
121
|
+
* `{HARNESS_DIR}/<dir>/snapshot.json` must exist and be non-terminal — the
|
|
122
|
+
* root holds active lifecycles only, and terminal writers unregister AFTER
|
|
123
|
+
* the snapshot write. The snapshot must also PHYSICALLY live under the
|
|
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
|
|
126
|
+
* input without a harness dir is structure-only.
|
|
129
127
|
*/
|
|
130
|
-
export declare function
|
|
128
|
+
export declare function validateStatusV2(docOrPath: StatusV2Doc | string, opts?: {
|
|
129
|
+
harnessDir?: string;
|
|
130
|
+
}): GateResult;
|
|
131
131
|
/**
|
|
132
|
-
*
|
|
133
|
-
* `
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* explicit `opts.mode` → `plans[].metadata.findings_cleanup` → `allow-residual`.
|
|
132
|
+
* Relocated v2 root validator (plan Task 3 — hard cutover, no dual path):
|
|
133
|
+
* the v1 `validateStatus` implementation was deleted in the same task that
|
|
134
|
+
* introduced the v2 surface; the public export name survives so external
|
|
135
|
+
* consumers (CLI, host hooks — cut over in P2) keep compiling and now fail
|
|
136
|
+
* closed on v1 input with the `mstar migrate` hint.
|
|
138
137
|
*/
|
|
139
|
-
export declare
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
export declare const validateStatus: typeof validateStatusV2;
|
|
139
|
+
/**
|
|
140
|
+
* Register one active workflow entry in the v2 root file (plan Task 3).
|
|
141
|
+
* Idempotent upsert by entry `id` under the root-file `withStatusWriteLock`,
|
|
142
|
+
* bumping root `updated_at`. A missing/empty root file is initialized from
|
|
143
|
+
* the v2 template (never a v1 tree); a v1 root is refused with the
|
|
144
|
+
* `mstar migrate` hint (no silent mutation of an un-migrated tree).
|
|
145
|
+
*
|
|
146
|
+
* The final document is validated with `validateStatusV2` (including the
|
|
147
|
+
* removal-at-terminal snapshot invariant against `dirname(root)`) before the
|
|
148
|
+
* write — an entry whose snapshot is missing or terminal is refused and
|
|
149
|
+
* nothing is written.
|
|
150
|
+
*/
|
|
151
|
+
export declare function registerWorkflow(root: string, entry: WorkflowEntry): Promise<StatusV2Doc>;
|
|
152
|
+
/**
|
|
153
|
+
* Remove one workflow entry from the v2 root file (plan Task 3). Idempotent:
|
|
154
|
+
* removing an absent id is a no-op with no write; a missing/empty root file
|
|
155
|
+
* is a no-op that never creates the file. Runs under the root-file
|
|
156
|
+
* `withStatusWriteLock`, bumping root `updated_at` only when an entry was
|
|
157
|
+
* actually removed. The final document is validated (removal-at-terminal
|
|
158
|
+
* invariant included) before the write — a v1 root is refused with the
|
|
159
|
+
* `mstar migrate` hint.
|
|
160
|
+
*/
|
|
161
|
+
export declare function unregisterWorkflow(root: string, id: string): Promise<StatusV2Doc>;
|
|
142
162
|
/**
|
|
143
163
|
* Resolve the repo-level hard-enforcement flag from the iteration compass
|
|
144
164
|
* (roadmap §8.5 C4/D2): `{ITERATION_DIR}/<id>/delivery-compass.md` files are
|
|
@@ -156,13 +176,21 @@ export declare function findingsCleanupGate(doc: StatusDoc, planId: string, opts
|
|
|
156
176
|
*/
|
|
157
177
|
export declare function resolveCompassEnforcement(harnessDir: string): EnforcementFlag;
|
|
158
178
|
/**
|
|
159
|
-
*
|
|
160
|
-
* § `
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
|
|
166
|
-
|
|
179
|
+
* Resolve the repo-declared hard-enforcement flag from `.mstarc`
|
|
180
|
+
* `[config] enforcement` (plan-conventions § `.mstarc` 格式): the nearest
|
|
181
|
+
* config at the harness dir or its parent (the repo root) wins —
|
|
182
|
+
* `hard` → hard, `soft` → soft, absent/invalid value → `none`. Same
|
|
183
|
+
* discovery scope as the sub-directory keys; a config above the repo
|
|
184
|
+
* root is never adopted.
|
|
185
|
+
*/
|
|
186
|
+
export declare function resolveMstarcEnforcement(harnessDir: string): EnforcementFlag;
|
|
187
|
+
/**
|
|
188
|
+
* Repo-level hard-enforcement flag: `.mstarc` `[config] enforcement` wins,
|
|
189
|
+
* else the iteration compass frontmatter (`resolveCompassEnforcement`),
|
|
190
|
+
* else warn-only. Hosts compose this BELOW their explicit Config override
|
|
191
|
+
* and the per-dispatch Assignment flag (precedence: Config > Assignment
|
|
192
|
+
* flag > repo `.mstarc` > compass > warn-only) — `.mstarc` `soft` is a
|
|
193
|
+
* local rollback against a hard compass, `.mstarc` `hard` hardens
|
|
194
|
+
* flag-less dispatches and gates.
|
|
167
195
|
*/
|
|
168
|
-
export declare function
|
|
196
|
+
export declare function resolveRepoEnforcement(harnessDir: string): EnforcementFlag;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { GateResult } from "./core.js";
|
|
2
|
+
import { type IntegrationMergeLease } from "./lease.js";
|
|
3
|
+
import { type PlanRow } from "./status.js";
|
|
4
|
+
/** Snapshot file name inside `workflows/<id>/` (plan Task 2 — writer contract). */
|
|
5
|
+
export declare const WORKFLOW_SNAPSHOT_FILE = "snapshot.json";
|
|
6
|
+
/** Lifecycle status enum (plan Task 2 — terminal set = completed|failed|stopped). */
|
|
7
|
+
export declare const WORKFLOW_LIFECYCLE_STATUSES: readonly ["running", "paused", "completed", "failed", "stopped"];
|
|
8
|
+
/** Terminal statuses: snapshot must carry `ended_at` and no dangling leases. */
|
|
9
|
+
export declare const WORKFLOW_TERMINAL_STATUSES: readonly ["completed", "failed", "stopped"];
|
|
10
|
+
/** Lifecycle type enum (plan Task 2 — id reuses the orchestration id). */
|
|
11
|
+
export declare const WORKFLOW_LIFECYCLE_TYPES: readonly ["plan", "iteration"];
|
|
12
|
+
export type WorkflowLifecycleStatus = (typeof WORKFLOW_LIFECYCLE_STATUSES)[number];
|
|
13
|
+
export type WorkflowLifecycleType = (typeof WORKFLOW_LIFECYCLE_TYPES)[number];
|
|
14
|
+
/**
|
|
15
|
+
* First-class lifecycle execution policy (plan Task 2 — keys copied from root
|
|
16
|
+
* `metadata` at migrate; values accepted-but-opaque this iteration, no
|
|
17
|
+
* semantic gate).
|
|
18
|
+
*/
|
|
19
|
+
export type WorkflowExecutionPolicy = {
|
|
20
|
+
plan_parallelism?: unknown;
|
|
21
|
+
worktree_mode?: unknown;
|
|
22
|
+
push_policy?: unknown;
|
|
23
|
+
};
|
|
24
|
+
/** Iteration branch anchors (plan Task 2 — from root metadata anchors). */
|
|
25
|
+
export type WorkflowBranchAnchors = {
|
|
26
|
+
base?: string;
|
|
27
|
+
integration?: string;
|
|
28
|
+
target?: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* v3 workflow snapshot (`workflows/<id>/snapshot.json`) — final schema
|
|
32
|
+
* (plan Task 2). `plans[]` rows are the legacy PlanRow shape verbatim;
|
|
33
|
+
* per-row `execution_lease` stays on the row, `integration_merge_lease` is
|
|
34
|
+
* top-level.
|
|
35
|
+
*
|
|
36
|
+
* Notes dual-home SSOT (qc wave-1 S-e): a plan row's `notes` array is the
|
|
37
|
+
* LEGACY VERBATIM copy preserved at migrate time — the RUNTIME ledger is
|
|
38
|
+
* `notes.jsonl` in the workflow dir (`migrate.ts` NOTES_LEDGER_FILE). New
|
|
39
|
+
* notes append to the ledger only; row `notes` is read-only legacy and is
|
|
40
|
+
* never a dual-write target, so the two never diverge by construction.
|
|
41
|
+
*/
|
|
42
|
+
export type WorkflowSnapshot = {
|
|
43
|
+
schema_version: 1;
|
|
44
|
+
id: string;
|
|
45
|
+
type: WorkflowLifecycleType;
|
|
46
|
+
status: WorkflowLifecycleStatus;
|
|
47
|
+
started_at: string;
|
|
48
|
+
ended_at?: string;
|
|
49
|
+
updated_at: string;
|
|
50
|
+
phase?: string;
|
|
51
|
+
plans: PlanRow[];
|
|
52
|
+
execution_policy?: WorkflowExecutionPolicy;
|
|
53
|
+
integration_merge_lease?: IntegrationMergeLease;
|
|
54
|
+
branch?: WorkflowBranchAnchors;
|
|
55
|
+
control_worktree_path?: string;
|
|
56
|
+
legacy_metadata?: Record<string, unknown>;
|
|
57
|
+
compass_ref?: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Validate a v3 workflow snapshot document (plan Task 2 — final schema):
|
|
61
|
+
* enum/type/id checks, `schema_version: 1`, required timestamps, `plans[]`
|
|
62
|
+
* rows validated by the legacy `validatePlanRow` with row-level
|
|
63
|
+
* `execution_lease` shape delegated to `validateExecutionLease`,
|
|
64
|
+
* `integration_merge_lease` shape delegated to
|
|
65
|
+
* `validateIntegrationMergeLease`, `execution_policy` keys accepted-but-
|
|
66
|
+
* opaque. Terminal invariant: `status` ∈ completed|failed|stopped ⇒
|
|
67
|
+
* `ended_at` present AND no row carries `execution_lease` AND no
|
|
68
|
+
* `integration_merge_lease` (no dangling leases).
|
|
69
|
+
*/
|
|
70
|
+
export declare function validateWorkflowSnapshot(doc: unknown): GateResult;
|
|
71
|
+
/**
|
|
72
|
+
* Write a workflow snapshot as a whole-rewrite of `dir/snapshot.json` under
|
|
73
|
+
* `withStatusWriteLock(snapshotPath)` (plan Task 2 — the `.status-write.lockdir`
|
|
74
|
+
* lands inside `workflows/<id>/`, dirname of the snapshot; no harness-root
|
|
75
|
+
* pollution). The snapshot is validated first — an invalid snapshot throws
|
|
76
|
+
* and nothing is written. `dir` is created recursively.
|
|
77
|
+
*/
|
|
78
|
+
export declare function writeWorkflowSnapshot(snapshot: WorkflowSnapshot, dir: string): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mstar-harness/engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
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": {
|