mustflow 1.30.0 → 2.11.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 (82) hide show
  1. package/README.md +35 -11
  2. package/dist/cli/commands/classify.js +61 -6
  3. package/dist/cli/commands/contract-lint.js +13 -4
  4. package/dist/cli/commands/dashboard.js +6 -0
  5. package/dist/cli/commands/index.js +5 -0
  6. package/dist/cli/commands/run.js +224 -48
  7. package/dist/cli/commands/upgrade.js +65 -0
  8. package/dist/cli/commands/verify.js +550 -33
  9. package/dist/cli/i18n/en.js +73 -10
  10. package/dist/cli/i18n/es.js +73 -10
  11. package/dist/cli/i18n/fr.js +73 -10
  12. package/dist/cli/i18n/hi.js +73 -10
  13. package/dist/cli/i18n/ko.js +73 -10
  14. package/dist/cli/i18n/zh.js +73 -10
  15. package/dist/cli/index.js +27 -46
  16. package/dist/cli/lib/command-registry.js +5 -0
  17. package/dist/cli/lib/dashboard-export.js +62 -12
  18. package/dist/cli/lib/dashboard-html/client-script.js +1936 -0
  19. package/dist/cli/lib/dashboard-html/locale-bootstrap.js +8 -0
  20. package/dist/cli/lib/dashboard-html/styles.js +572 -0
  21. package/dist/cli/lib/dashboard-html/template.js +134 -0
  22. package/dist/cli/lib/dashboard-html/types.js +1 -0
  23. package/dist/cli/lib/dashboard-html.js +1 -1907
  24. package/dist/cli/lib/dashboard-locale.js +37 -0
  25. package/dist/cli/lib/local-index/constants.js +48 -0
  26. package/dist/cli/lib/local-index/index.js +2256 -0
  27. package/dist/cli/lib/local-index/sql.js +15 -0
  28. package/dist/cli/lib/local-index/types.js +1 -0
  29. package/dist/cli/lib/local-index.js +1 -1908
  30. package/dist/cli/lib/reporter.js +6 -0
  31. package/dist/cli/lib/run-plan.js +96 -4
  32. package/dist/cli/lib/templates.js +18 -1
  33. package/dist/cli/lib/validation/command-intents.js +11 -0
  34. package/dist/cli/lib/validation/constants.js +238 -0
  35. package/dist/cli/lib/validation/index.js +1384 -0
  36. package/dist/cli/lib/validation/primitives.js +198 -0
  37. package/dist/cli/lib/validation/test-selection.js +95 -0
  38. package/dist/cli/lib/validation/types.js +1 -0
  39. package/dist/cli/lib/validation.js +1 -1661
  40. package/dist/core/bounded-output.js +38 -0
  41. package/dist/core/change-classification.js +6 -2
  42. package/dist/core/change-verification.js +240 -6
  43. package/dist/core/check-issues.js +12 -0
  44. package/dist/core/command-contract-validation.js +20 -0
  45. package/dist/core/command-effects.js +13 -0
  46. package/dist/core/completion-verdict.js +209 -0
  47. package/dist/core/contract-lint.js +316 -7
  48. package/dist/core/dashboard-verification.js +8 -0
  49. package/dist/core/external-evidence.js +9 -0
  50. package/dist/core/public-json-contracts.js +28 -0
  51. package/dist/core/repeated-failure.js +17 -0
  52. package/dist/core/repro-evidence.js +53 -0
  53. package/dist/core/run-performance-history.js +307 -0
  54. package/dist/core/run-profile.js +87 -0
  55. package/dist/core/run-receipt.js +171 -4
  56. package/dist/core/run-write-drift.js +18 -2
  57. package/dist/core/scope-risk.js +64 -0
  58. package/dist/core/skill-route-alignment.js +110 -0
  59. package/dist/core/source-anchor-status.js +4 -1
  60. package/dist/core/test-selection.js +227 -0
  61. package/dist/core/validation-ratchet.js +52 -0
  62. package/dist/core/verification-decision-graph.js +67 -0
  63. package/dist/core/verification-evidence.js +249 -0
  64. package/dist/core/verification-scheduler.js +96 -2
  65. package/examples/README.md +12 -4
  66. package/package.json +1 -1
  67. package/schemas/README.md +18 -4
  68. package/schemas/change-verification-report.schema.json +169 -5
  69. package/schemas/commands.schema.json +51 -1
  70. package/schemas/contract-lint-report.schema.json +80 -0
  71. package/schemas/dashboard-export.schema.json +500 -0
  72. package/schemas/explain-report.schema.json +2 -0
  73. package/schemas/latest-run-pointer.schema.json +384 -0
  74. package/schemas/run-receipt.schema.json +113 -0
  75. package/schemas/test-selection.schema.json +81 -0
  76. package/schemas/verify-report.schema.json +361 -1
  77. package/schemas/verify-run-manifest.schema.json +410 -0
  78. package/templates/default/common/.mustflow/config/commands.toml +1 -1
  79. package/templates/default/i18n.toml +1 -1
  80. package/templates/default/locales/en/.mustflow/skills/INDEX.md +124 -29
  81. package/templates/default/locales/en/.mustflow/skills/routes.toml +289 -0
  82. package/templates/default/manifest.toml +29 -2
@@ -0,0 +1,249 @@
1
+ function uniqueSorted(values) {
2
+ return [...new Set([...values].filter((value) => typeof value === 'string' && value.length > 0))].sort((left, right) => left.localeCompare(right));
3
+ }
4
+ function receiptEntries(results) {
5
+ return results
6
+ .filter((result) => !result.skipped)
7
+ .map((result) => ({
8
+ intent: result.intent,
9
+ status: result.status,
10
+ skipped: false,
11
+ verification_plan_id: result.verification_plan_id,
12
+ receipt_path: result.receipt_path,
13
+ receipt_sha256: result.receipt_sha256,
14
+ }));
15
+ }
16
+ function skippedCheckEntries(results) {
17
+ return results
18
+ .filter((result) => result.skipped)
19
+ .map((result) => ({
20
+ intent: result.intent,
21
+ reason: result.reason,
22
+ detail: result.detail,
23
+ }));
24
+ }
25
+ function resultForIntent(results, intent) {
26
+ return results.find((result) => result.intent === intent && !result.skipped) ?? null;
27
+ }
28
+ function requirementOutcome(input) {
29
+ if (input.selectedIntents.some((intent) => {
30
+ const result = resultForIntent(input.results, intent);
31
+ return result?.status === 'failed' || result?.status === 'timed_out' || result?.status === 'start_failed';
32
+ })) {
33
+ return 'contradicted';
34
+ }
35
+ if (input.gapCount > 0 || (input.selectedIntents.length === 0 && input.skippedIntents.length > 0)) {
36
+ return 'blocked';
37
+ }
38
+ if (input.selectedIntents.length === 0) {
39
+ return 'unverified';
40
+ }
41
+ if (input.skippedIntents.length > 0) {
42
+ return 'partially_verified';
43
+ }
44
+ return input.selectedIntents.every((intent) => resultForIntent(input.results, intent)?.status === 'passed')
45
+ ? 'verified'
46
+ : 'unverified';
47
+ }
48
+ function explanationFromVerdict(verdict) {
49
+ return {
50
+ verified_by: verdict.status === 'verified' ? [verdict.primary_reason] : [],
51
+ downgraded_by: verdict.status === 'partially_verified' || verdict.status === 'unverified' ? verdict.limitations : [],
52
+ blocked_by: verdict.status === 'blocked' ? verdict.blockers : [],
53
+ contradicted_by: verdict.status === 'contradicted' ? verdict.contradictions : [],
54
+ };
55
+ }
56
+ function coverageStatusFromOutcome(outcome) {
57
+ if (outcome === 'verified') {
58
+ return 'covered';
59
+ }
60
+ if (outcome === 'partially_verified') {
61
+ return 'partially_covered';
62
+ }
63
+ if (outcome === 'unverified') {
64
+ return 'uncovered';
65
+ }
66
+ return outcome;
67
+ }
68
+ function receiptPathsForIntents(receipts, intents) {
69
+ const selected = new Set(intents);
70
+ return uniqueSorted(receipts
71
+ .filter((receipt) => receipt.intent !== null && selected.has(receipt.intent))
72
+ .map((receipt) => receipt.receipt_path));
73
+ }
74
+ function coverageMatrixFromRequirements(input) {
75
+ return input.requirements.map((requirement, index) => {
76
+ const matchingGaps = input.source === 'dashboard_snapshot'
77
+ ? input.gaps
78
+ : input.gaps.filter((gap) => gap.reason === requirement.reason);
79
+ const matchingSourceAnchorRisks = input.sourceAnchorRisks.filter((risk) => requirement.files.includes(risk.path));
80
+ const status = coverageStatusFromOutcome(requirement.outcome);
81
+ return {
82
+ criterion_id: `${input.source}:${index + 1}:${requirement.reason}`,
83
+ source: input.source,
84
+ statement: `Verification requirement: ${requirement.reason}`,
85
+ status: matchingSourceAnchorRisks.length > 0 && status === 'covered' ? 'partially_covered' : status,
86
+ requirement_reason: requirement.reason,
87
+ evidence: {
88
+ intents: uniqueSorted([...requirement.selected_intents, ...requirement.skipped_intents]),
89
+ receipt_paths: receiptPathsForIntents(input.receipts, requirement.selected_intents),
90
+ gap_reasons: uniqueSorted(matchingGaps.map((gap) => gap.detail)),
91
+ source_anchor_ids: uniqueSorted(matchingSourceAnchorRisks.map((risk) => risk.anchorId)),
92
+ },
93
+ };
94
+ });
95
+ }
96
+ function sourceAnchorRemainingRisks(sourceAnchorRisks) {
97
+ return sourceAnchorRisks.map((risk) => ({
98
+ code: 'source_anchor_invariant_review_required',
99
+ severity: 'high',
100
+ detail: `${risk.anchorId} in ${risk.path}:${risk.lineStart} is ${risk.status}; review its invariant before marking the task verified.`,
101
+ }));
102
+ }
103
+ function scopeDiffRemainingRisks(scopeDiffRisks) {
104
+ return scopeDiffRisks.map((risk) => ({
105
+ code: risk.code,
106
+ severity: risk.severity,
107
+ detail: risk.detail,
108
+ }));
109
+ }
110
+ function repeatedFailureRemainingRisks(repeatedFailureRisks) {
111
+ return repeatedFailureRisks.map((risk) => ({
112
+ code: risk.code,
113
+ severity: risk.severity,
114
+ detail: risk.detail,
115
+ }));
116
+ }
117
+ function validationRatchetRemainingRisks(validationRatchetRisks) {
118
+ return validationRatchetRisks.map((risk) => ({
119
+ code: risk.code,
120
+ severity: risk.severity,
121
+ detail: risk.detail,
122
+ }));
123
+ }
124
+ function reproEvidenceRemainingRisks(reproEvidenceRisks) {
125
+ return reproEvidenceRisks.map((risk) => ({
126
+ code: risk.code,
127
+ severity: risk.severity,
128
+ detail: risk.detail,
129
+ }));
130
+ }
131
+ function externalEvidenceRemainingRisks(externalEvidenceRisks) {
132
+ return externalEvidenceRisks.map((risk) => ({
133
+ code: risk.code,
134
+ severity: risk.severity,
135
+ detail: risk.detail,
136
+ }));
137
+ }
138
+ export function createVerifyEvidenceModel(input) {
139
+ const requirements = input.report.requirements.map((requirement) => {
140
+ const candidates = input.report.candidates.filter((candidate) => candidate.reason === requirement.reason);
141
+ const selectedIntents = uniqueSorted(candidates
142
+ .filter((candidate) => candidate.selectionState === 'selected')
143
+ .map((candidate) => candidate.intent));
144
+ const skippedIntents = uniqueSorted(candidates
145
+ .filter((candidate) => candidate.status !== 'runnable')
146
+ .map((candidate) => candidate.intent));
147
+ const gapCount = input.report.gaps.filter((gap) => gap.reason === requirement.reason).length;
148
+ return {
149
+ reason: requirement.reason,
150
+ files: [...requirement.files],
151
+ surfaces: [...requirement.surfaces],
152
+ candidate_intents: uniqueSorted(candidates.map((candidate) => candidate.intent)),
153
+ selected_intents: selectedIntents,
154
+ skipped_intents: skippedIntents,
155
+ gap_count: gapCount,
156
+ outcome: requirementOutcome({
157
+ selectedIntents,
158
+ skippedIntents,
159
+ gapCount,
160
+ results: input.results,
161
+ }),
162
+ };
163
+ });
164
+ const receipts = receiptEntries(input.results);
165
+ const sourceAnchorRisks = input.sourceAnchorRisks ?? [];
166
+ const scopeDiffRisks = input.scopeDiffRisks ?? [];
167
+ const repeatedFailureRisks = input.repeatedFailureRisks ?? [];
168
+ const validationRatchetRisks = input.validationRatchetRisks ?? [];
169
+ const reproEvidence = input.reproEvidence ?? null;
170
+ const reproEvidenceRisks = input.reproEvidenceRisks ?? [];
171
+ const externalChecks = input.externalChecks ?? [];
172
+ const externalEvidenceRisks = input.externalEvidenceRisks ?? [];
173
+ const gaps = input.report.gaps.map((gap) => ({
174
+ reason: gap.reason,
175
+ intent: null,
176
+ status: 'missing',
177
+ detail: gap.detail,
178
+ files: [...gap.files],
179
+ surfaces: [...gap.surfaces],
180
+ }));
181
+ return {
182
+ schema_version: '1',
183
+ source: 'mf_verify',
184
+ verification_plan_id: input.verificationPlanId,
185
+ requirements,
186
+ coverage_matrix: coverageMatrixFromRequirements({
187
+ source: 'verification_requirement',
188
+ requirements,
189
+ receipts,
190
+ gaps,
191
+ sourceAnchorRisks,
192
+ }),
193
+ receipts,
194
+ skipped_checks: skippedCheckEntries(input.results),
195
+ gaps,
196
+ remaining_risks: [
197
+ ...sourceAnchorRemainingRisks(sourceAnchorRisks),
198
+ ...scopeDiffRemainingRisks(scopeDiffRisks),
199
+ ...repeatedFailureRemainingRisks(repeatedFailureRisks),
200
+ ...validationRatchetRemainingRisks(validationRatchetRisks),
201
+ ...reproEvidenceRemainingRisks(reproEvidenceRisks),
202
+ ...externalEvidenceRemainingRisks(externalEvidenceRisks),
203
+ ],
204
+ ...(reproEvidence ? { repro_evidence: reproEvidence } : {}),
205
+ ...(externalChecks.length > 0 ? { external_checks: externalChecks } : {}),
206
+ explanation: explanationFromVerdict(input.verdict),
207
+ };
208
+ }
209
+ export function createDashboardEvidenceModel(input) {
210
+ const requirements = input.changedSurfaces.length > 0 || input.runnableIntents.length > 0
211
+ ? [
212
+ {
213
+ reason: 'dashboard_snapshot',
214
+ files: [],
215
+ surfaces: [...input.changedSurfaces],
216
+ candidate_intents: uniqueSorted(input.runnableIntents),
217
+ selected_intents: [],
218
+ skipped_intents: uniqueSorted(input.skippedChecks.map((check) => check.intent)),
219
+ gap_count: input.gaps.length,
220
+ outcome: input.verdict.status,
221
+ },
222
+ ]
223
+ : [];
224
+ const receipts = input.latestReceipt ? [input.latestReceipt] : [];
225
+ const sourceAnchorRisks = input.sourceAnchorRisks ?? [];
226
+ const scopeDiffRisks = input.scopeDiffRisks ?? [];
227
+ return {
228
+ schema_version: '1',
229
+ source: 'dashboard_export',
230
+ verification_plan_id: null,
231
+ requirements,
232
+ coverage_matrix: coverageMatrixFromRequirements({
233
+ source: 'dashboard_snapshot',
234
+ requirements,
235
+ receipts,
236
+ gaps: input.gaps,
237
+ sourceAnchorRisks,
238
+ }),
239
+ receipts,
240
+ skipped_checks: input.skippedChecks,
241
+ gaps: input.gaps,
242
+ remaining_risks: [
243
+ ...input.remainingRisks,
244
+ ...sourceAnchorRemainingRisks(sourceAnchorRisks),
245
+ ...scopeDiffRemainingRisks(scopeDiffRisks),
246
+ ],
247
+ explanation: explanationFromVerdict(input.verdict),
248
+ };
249
+ }
@@ -1,3 +1,5 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
1
3
  import { commandEffectsConflict, normalizeCommandEffects, } from './command-effects.js';
2
4
  function uniqueSorted(values) {
3
5
  return [...new Set(values)].sort((left, right) => left.localeCompare(right));
@@ -13,6 +15,79 @@ function toScheduleEffect(effect) {
13
15
  concurrency: effect.concurrency,
14
16
  };
15
17
  }
18
+ function isObject(value) {
19
+ return !!value && typeof value === 'object';
20
+ }
21
+ function readJsonFile(filePath) {
22
+ try {
23
+ return JSON.parse(readFileSync(filePath, 'utf8'));
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ function getUndeclaredWriteIntent(value) {
30
+ if (!isObject(value) || typeof value.intent !== 'string') {
31
+ return null;
32
+ }
33
+ const writeDrift = value.write_drift;
34
+ if (!isObject(writeDrift) || writeDrift.has_undeclared_changes !== true) {
35
+ return null;
36
+ }
37
+ return value.intent;
38
+ }
39
+ function resolveStateRelativePath(projectRoot, relativePath) {
40
+ if (typeof relativePath !== 'string' || relativePath.length === 0 || path.isAbsolute(relativePath)) {
41
+ return null;
42
+ }
43
+ const normalized = relativePath.replaceAll('\\', '/');
44
+ if (!normalized.startsWith('.mustflow/state/runs/')) {
45
+ return null;
46
+ }
47
+ const resolved = path.resolve(projectRoot, normalized);
48
+ const relative = path.relative(projectRoot, resolved);
49
+ if (relative.startsWith('..') || path.isAbsolute(relative)) {
50
+ return null;
51
+ }
52
+ return resolved;
53
+ }
54
+ function readVerifyManifestUndeclaredWriteIntents(projectRoot, latest) {
55
+ const manifestPath = resolveStateRelativePath(projectRoot, latest.manifest_path);
56
+ if (!manifestPath) {
57
+ return new Set();
58
+ }
59
+ const manifest = readJsonFile(manifestPath);
60
+ if (!isObject(manifest) || manifest.command !== 'verify' || !Array.isArray(manifest.receipts)) {
61
+ return new Set();
62
+ }
63
+ const intents = new Set();
64
+ for (const entry of manifest.receipts) {
65
+ if (!isObject(entry)) {
66
+ continue;
67
+ }
68
+ const receiptPath = resolveStateRelativePath(projectRoot, entry.receipt_path);
69
+ if (!receiptPath) {
70
+ continue;
71
+ }
72
+ const intent = getUndeclaredWriteIntent(readJsonFile(receiptPath));
73
+ if (intent) {
74
+ intents.add(intent);
75
+ }
76
+ }
77
+ return intents;
78
+ }
79
+ function readLatestUndeclaredWriteIntents(projectRoot) {
80
+ const latestPath = path.join(projectRoot, '.mustflow', 'state', 'runs', 'latest.json');
81
+ const parsed = readJsonFile(latestPath);
82
+ const directIntent = getUndeclaredWriteIntent(parsed);
83
+ if (directIntent) {
84
+ return new Set([directIntent]);
85
+ }
86
+ if (!isObject(parsed) || parsed.command !== 'verify') {
87
+ return new Set();
88
+ }
89
+ return readVerifyManifestUndeclaredWriteIntents(projectRoot, parsed);
90
+ }
16
91
  function entriesConflict(left, right) {
17
92
  const conflicts = [];
18
93
  for (const leftEffect of left.effects) {
@@ -33,7 +108,8 @@ function entriesConflict(left, right) {
33
108
  function addEntryToBatches(batches, batchEntries, entry) {
34
109
  for (let batchIndex = 0; batchIndex < batchEntries.length; batchIndex += 1) {
35
110
  const existingEntries = batchEntries[batchIndex] ?? [];
36
- const hasConflict = existingEntries.some((existing) => entriesConflict(entry, existing).length > 0);
111
+ const hasConflict = !entry.parallelEligible ||
112
+ existingEntries.some((existing) => !existing.parallelEligible || entriesConflict(entry, existing).length > 0);
37
113
  if (hasConflict) {
38
114
  continue;
39
115
  }
@@ -55,14 +131,24 @@ function addEntryToBatches(batches, batchEntries, entry) {
55
131
  });
56
132
  }
57
133
  export function createVerificationSchedule(projectRoot, commandContract, candidates) {
134
+ const latestUndeclaredWriteIntents = readLatestUndeclaredWriteIntents(projectRoot);
58
135
  const runnableIntents = uniqueSorted(candidates
59
136
  .filter((candidate) => candidate.status === 'runnable' && candidate.intent.length > 0)
60
137
  .map((candidate) => candidate.intent));
61
138
  const baseEntries = runnableIntents.map((intent) => {
62
139
  const effects = normalizeCommandEffects(projectRoot, commandContract, intent).map(toScheduleEffect);
140
+ const hasExplicitEffects = effects.length > 0 && effects.every((effect) => effect.source === 'effects');
141
+ const hasUndeclaredWriteDrift = latestUndeclaredWriteIntents.has(intent);
142
+ const parallelEligible = hasExplicitEffects && !hasUndeclaredWriteDrift;
63
143
  return {
64
144
  intent,
65
145
  status: 'runnable',
146
+ parallelEligible,
147
+ parallelReason: hasUndeclaredWriteDrift
148
+ ? 'undeclared_write_drift'
149
+ : hasExplicitEffects
150
+ ? 'explicit_effects'
151
+ : 'missing_explicit_effects',
66
152
  effects,
67
153
  locks: uniqueSorted(effects.map((effect) => effect.lock)),
68
154
  conflicts: [],
@@ -82,11 +168,19 @@ export function createVerificationSchedule(projectRoot, commandContract, candida
82
168
  }
83
169
  return {
84
170
  runner: 'serial_mf_run_receipts',
171
+ failurePolicy: {
172
+ mode: 'batch_boundary',
173
+ startedBatch: 'wait_for_completion',
174
+ nextBatch: 'stop_on_failure',
175
+ },
85
176
  batches,
86
177
  entries,
87
178
  notes: [
88
179
  'Batches explain resource compatibility for planning only.',
89
- 'mf run still writes the latest receipt to a single path, so execute copied commands serially.',
180
+ 'Only entries backed by explicit effects are marked parallel eligible; writes fallback remains serial-only.',
181
+ ...uniqueSorted(latestUndeclaredWriteIntents).map((intent) => `Latest receipt for ${intent} reported undeclared writes; it is not parallel eligible.`),
182
+ 'If a future parallel batch has already started, let it finish and stop before the next batch on failure.',
183
+ 'mf verify still executes copied commands serially and writes the latest run summary after the batch completes.',
90
184
  ],
91
185
  };
92
186
  }
@@ -4,10 +4,18 @@ This directory contains human-readable project examples.
4
4
 
5
5
  These examples are not test fixtures and are not copied by `mf init`. They illustrate the structure of a project before and after integrating mustflow, while excluding generated or template-owned files from the example content.
6
6
 
7
- Current examples:
7
+ ## Choose an Example
8
+
9
+ If you are new to mustflow:
8
10
 
9
- - `docs-only/`: A documentation-focused repository with explicit checks for missing code.
10
- - `host-instruction-conflicts/`: A repository where host-specific instructions overlap with mustflow rules.
11
11
  - `minimal-js/`: A small JavaScript package before and after adding mustflow.
12
+
13
+ If you are building or integrating an AI coding tool:
14
+
15
+ - `host-instruction-conflicts/`: A repository where host-specific instructions overlap with mustflow rules.
12
16
  - `missing-command-contracts/`: A repository with package scripts that are not yet defined as mustflow command intents.
13
- - `nested-repos/`: Parent and child repositories with separate local contracts.
17
+
18
+ If you are studying repository structure:
19
+
20
+ - `docs-only/`: A documentation-focused repository with explicit checks for missing code.
21
+ - `nested-repos/`: Parent and child repositories with separate local contracts.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mustflow",
3
- "version": "1.30.0",
3
+ "version": "2.11.0",
4
4
  "description": "Agent workflow documents and CLI for mustflow repository roots.",
5
5
  "type": "module",
6
6
  "license": "MIT-0",
package/schemas/README.md CHANGED
@@ -9,15 +9,24 @@ Current schemas:
9
9
  - `adapter-compatibility-report.schema.json`: output of `mf adapters status --json`
10
10
  - `context-report.schema.json`: output of `mf context --json`
11
11
  - `run-receipt.schema.json`: output of `mf run <intent> --json` and `.mustflow/state/runs/latest.json`,
12
- including bounded declared-write drift metadata
12
+ including bounded declared-write drift metadata, a safe latest-run performance summary, and optional
13
+ structured phase timings and selection summaries
13
14
  - `commands.schema.json`: parsed `.mustflow/config/commands.toml`
15
+ - `test-selection.schema.json`: parsed optional `.mustflow/config/test-selection.toml`
14
16
  - `contract-lint-report.schema.json`: output of `mf contract-lint --json`
17
+ - `dashboard-export.schema.json`: bounded static export written by `mf dashboard --export-json <path>`,
18
+ including output policy, redaction and truncation metadata, the dashboard harness report, and
19
+ the evidence-based completion verdict, evidence model, and conservative coverage matrix for the
20
+ exported snapshot
15
21
  - `classify-report.schema.json`: output of `mf classify --changed --json` and
16
22
  `mf classify <path...> --json`
17
23
  - `impact-report.schema.json`: output of `mf impact --changed --json` and
18
24
  `mf impact <path...> --json`
19
25
  - `line-endings-report.schema.json`: output of `mf line-endings check --json` and
20
26
  `mf line-endings normalize --json`
27
+ - `latest-run-pointer.schema.json`: `.mustflow/state/runs/latest.json` when `mf verify` writes a
28
+ pointer to the latest verify run bundle, including the verify completion verdict, evidence model,
29
+ and coverage matrix
21
30
  - `handoff-validation-report.schema.json`: output of
22
31
  `mf handoff validate <path> --json`
23
32
  - `version-sources-report.schema.json`: output of `mf version-sources --json`
@@ -25,10 +34,15 @@ Current schemas:
25
34
  - `explain-report.schema.json`: output of `mf explain authority --json`, `mf explain command --json`,
26
35
  `mf explain verify --reason <event> --json`, `mf explain retention --json`, `mf explain skills --json`,
27
36
  and `mf explain surface --json`. Verify explanations include the shared `decisionGraph` evidence model.
28
- - `verify-report.schema.json`: output of `mf verify --reason <event> --json`
37
+ - `verify-report.schema.json`: output of `mf verify --reason <event> --json`, including an
38
+ evidence-based completion verdict and evidence model with a conservative coverage matrix for the
39
+ selected receipts and skipped checks
40
+ - `verify-run-manifest.schema.json`: `.mustflow/state/runs/verify-latest/manifest.json`, including
41
+ the same completion verdict, evidence model, and coverage matrix as the verify report
29
42
  - `change-verification-report.schema.json`: output of `mf verify --reason <event> --plan-only --json` and
30
- `mf verify --from-plan <classify-report.json> --plan-only --json`, including the `decision_graph` that links
31
- changed surfaces, classification reasons, command candidates, eligibility, effects, and gaps.
43
+ `mf verify --from-classification <classify-report.json> --plan-only --json`, including the `decision_graph` that links
44
+ changed surfaces, classification reasons, command candidates, eligibility, selected or not-selected state,
45
+ effects, and gaps.
32
46
  Local-index command-effect graphs are explanation-only and cannot grant command authority.
33
47
 
34
48
  These schemas define stable, automation-facing fields. Human-readable command