mustflow 2.70.0 → 2.74.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.
- package/README.md +19 -5
- package/dist/cli/commands/api.js +17 -0
- package/dist/cli/commands/evidence.js +71 -0
- package/dist/cli/commands/script-pack.js +124 -0
- package/dist/cli/commands/verify.js +50 -15
- package/dist/cli/commands/workspace.js +2 -0
- package/dist/cli/i18n/en.js +38 -0
- package/dist/cli/i18n/es.js +38 -0
- package/dist/cli/i18n/fr.js +38 -0
- package/dist/cli/i18n/hi.js +38 -0
- package/dist/cli/i18n/ko.js +38 -0
- package/dist/cli/i18n/zh.js +38 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/lib/agent-context.js +179 -10
- package/dist/cli/lib/command-registry.js +6 -0
- package/dist/cli/lib/dashboard-export.js +1 -0
- package/dist/cli/lib/script-pack-registry.js +27 -0
- package/dist/cli/script-packs/core-text-budget.js +241 -0
- package/dist/core/change-verification.js +10 -0
- package/dist/core/completion-verdict.js +14 -1
- package/dist/core/complexity-budget.js +206 -0
- package/dist/core/conflict-ledger.js +122 -0
- package/dist/core/failure-replay-capsule.js +213 -0
- package/dist/core/public-json-contracts.js +27 -0
- package/dist/core/risk-priced-evidence.js +213 -0
- package/dist/core/script-check-result.js +1 -0
- package/dist/core/text-budget.js +262 -0
- package/dist/core/verification-evidence.js +61 -13
- package/package.json +1 -1
- package/schemas/README.md +23 -11
- package/schemas/change-verification-report.schema.json +29 -0
- package/schemas/context-report.schema.json +58 -2
- package/schemas/dashboard-export.schema.json +42 -1
- package/schemas/diff-risk.schema.json +6 -0
- package/schemas/evidence-report.schema.json +45 -0
- package/schemas/latest-run-pointer.schema.json +50 -1
- package/schemas/script-pack-catalog.schema.json +68 -0
- package/schemas/text-budget-report.schema.json +131 -0
- package/schemas/verification-plan.schema.json +32 -0
- package/schemas/verify-report.schema.json +360 -1
- package/schemas/verify-run-manifest.schema.json +50 -1
- package/schemas/workspace-verification-plan.schema.json +32 -0
- package/templates/default/i18n.toml +2 -2
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +2 -2
- package/templates/default/locales/en/.mustflow/skills/adapter-boundary/SKILL.md +19 -2
- package/templates/default/locales/en/.mustflow/skills/routes.toml +1 -1
- package/templates/default/manifest.toml +1 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ensureInside, readFileInsideWithoutSymlinks } from './safe-filesystem.js';
|
|
4
|
+
export const TEXT_BUDGET_PACK_ID = 'core';
|
|
5
|
+
export const TEXT_BUDGET_SCRIPT_ID = 'text-budget';
|
|
6
|
+
export const TEXT_BUDGET_SCRIPT_REF = `${TEXT_BUDGET_PACK_ID}/${TEXT_BUDGET_SCRIPT_ID}`;
|
|
7
|
+
const DEFAULT_TEXT_BUDGET_UNIT = 'grapheme';
|
|
8
|
+
const DEFAULT_MAX_FILE_BYTES = 1024 * 1024;
|
|
9
|
+
const ERROR_FINDING_CODES = new Set([
|
|
10
|
+
'text_budget_unreadable',
|
|
11
|
+
'text_budget_json_parse_failed',
|
|
12
|
+
'text_budget_json_pointer_invalid',
|
|
13
|
+
'text_budget_json_pointer_missing',
|
|
14
|
+
'text_budget_json_pointer_not_string',
|
|
15
|
+
]);
|
|
16
|
+
export const TEXT_BUDGET_UNITS = [
|
|
17
|
+
'grapheme',
|
|
18
|
+
'code-point',
|
|
19
|
+
'utf16',
|
|
20
|
+
'utf8-byte',
|
|
21
|
+
'word',
|
|
22
|
+
'line',
|
|
23
|
+
];
|
|
24
|
+
function toPosixPath(value) {
|
|
25
|
+
return value.split(path.sep).join('/');
|
|
26
|
+
}
|
|
27
|
+
function sha256Hex(buffer) {
|
|
28
|
+
return createHash('sha256').update(buffer).digest('hex');
|
|
29
|
+
}
|
|
30
|
+
function sha256Tagged(buffer) {
|
|
31
|
+
return `sha256:${sha256Hex(buffer)}`;
|
|
32
|
+
}
|
|
33
|
+
function createSegmenter(granularity) {
|
|
34
|
+
const Segmenter = Intl.Segmenter;
|
|
35
|
+
return Segmenter ? new Segmenter(undefined, { granularity }) : null;
|
|
36
|
+
}
|
|
37
|
+
function countGraphemes(text) {
|
|
38
|
+
const segmenter = createSegmenter('grapheme');
|
|
39
|
+
return segmenter ? [...segmenter.segment(text)].length : [...text].length;
|
|
40
|
+
}
|
|
41
|
+
function countWords(text) {
|
|
42
|
+
const segmenter = createSegmenter('word');
|
|
43
|
+
if (segmenter) {
|
|
44
|
+
return [...segmenter.segment(text)].filter((segment) => segment.isWordLike === true).length;
|
|
45
|
+
}
|
|
46
|
+
return text.trim().length === 0 ? 0 : (text.trim().match(/\S+/gu) ?? []).length;
|
|
47
|
+
}
|
|
48
|
+
function countLines(text) {
|
|
49
|
+
return text.length === 0 ? 0 : text.split(/\r\n|\r|\n/u).length;
|
|
50
|
+
}
|
|
51
|
+
export function countTextBudgetUnits(text, unit) {
|
|
52
|
+
switch (unit) {
|
|
53
|
+
case 'grapheme':
|
|
54
|
+
return countGraphemes(text);
|
|
55
|
+
case 'code-point':
|
|
56
|
+
return [...text].length;
|
|
57
|
+
case 'utf16':
|
|
58
|
+
return text.length;
|
|
59
|
+
case 'utf8-byte':
|
|
60
|
+
return Buffer.byteLength(text, 'utf8');
|
|
61
|
+
case 'word':
|
|
62
|
+
return countWords(text);
|
|
63
|
+
case 'line':
|
|
64
|
+
return countLines(text);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function decodeJsonPointerSegment(segment) {
|
|
68
|
+
return segment.replace(/~1/gu, '/').replace(/~0/gu, '~');
|
|
69
|
+
}
|
|
70
|
+
function resolveJsonPointer(value, pointer) {
|
|
71
|
+
if (pointer === '') {
|
|
72
|
+
return { ok: true, value };
|
|
73
|
+
}
|
|
74
|
+
if (!pointer.startsWith('/')) {
|
|
75
|
+
return { ok: false, error: 'invalid' };
|
|
76
|
+
}
|
|
77
|
+
let current = value;
|
|
78
|
+
for (const rawSegment of pointer.slice(1).split('/')) {
|
|
79
|
+
if (/~(?![01])/u.test(rawSegment)) {
|
|
80
|
+
return { ok: false, error: 'invalid' };
|
|
81
|
+
}
|
|
82
|
+
const segment = decodeJsonPointerSegment(rawSegment);
|
|
83
|
+
if (Array.isArray(current)) {
|
|
84
|
+
if (!/^(?:0|[1-9]\d*)$/u.test(segment)) {
|
|
85
|
+
return { ok: false, error: 'missing' };
|
|
86
|
+
}
|
|
87
|
+
const index = Number(segment);
|
|
88
|
+
if (index >= current.length) {
|
|
89
|
+
return { ok: false, error: 'missing' };
|
|
90
|
+
}
|
|
91
|
+
current = current[index];
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!current || typeof current !== 'object' || !Object.hasOwn(current, segment)) {
|
|
95
|
+
return { ok: false, error: 'missing' };
|
|
96
|
+
}
|
|
97
|
+
current = current[segment];
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, value: current };
|
|
100
|
+
}
|
|
101
|
+
function makeFinding(code, severity, pathValue, jsonPointer, message, actual = null, expected = null, metric = 'text_length') {
|
|
102
|
+
return {
|
|
103
|
+
code,
|
|
104
|
+
severity,
|
|
105
|
+
message,
|
|
106
|
+
path: pathValue,
|
|
107
|
+
json_pointer: jsonPointer,
|
|
108
|
+
metric,
|
|
109
|
+
actual,
|
|
110
|
+
expected,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function compareAgainstPolicy(relativePath, pointer, value, policy) {
|
|
114
|
+
const findings = [];
|
|
115
|
+
if (policy.exact !== null && value !== policy.exact) {
|
|
116
|
+
findings.push(makeFinding('text_budget_not_exact', 'medium', relativePath, pointer, `${relativePath} has ${value} ${policy.unit}; expected exactly ${policy.exact}.`, value, policy.exact));
|
|
117
|
+
}
|
|
118
|
+
if (policy.min !== null && value < policy.min) {
|
|
119
|
+
findings.push(makeFinding('text_budget_below_min', 'medium', relativePath, pointer, `${relativePath} has ${value} ${policy.unit}; expected at least ${policy.min}.`, value, policy.min));
|
|
120
|
+
}
|
|
121
|
+
if (policy.max !== null && value > policy.max) {
|
|
122
|
+
findings.push(makeFinding('text_budget_above_max', 'medium', relativePath, pointer, `${relativePath} has ${value} ${policy.unit}; expected at most ${policy.max}.`, value, policy.max));
|
|
123
|
+
}
|
|
124
|
+
return findings;
|
|
125
|
+
}
|
|
126
|
+
function createInputHash(policy, artifacts, findings) {
|
|
127
|
+
const inputState = {
|
|
128
|
+
policy,
|
|
129
|
+
artifacts: artifacts.map((artifact) => ({
|
|
130
|
+
path: artifact.path,
|
|
131
|
+
sha256: artifact.sha256,
|
|
132
|
+
size_bytes: artifact.size_bytes,
|
|
133
|
+
})),
|
|
134
|
+
input_errors: findings
|
|
135
|
+
.filter((finding) => ERROR_FINDING_CODES.has(finding.code))
|
|
136
|
+
.map((finding) => ({
|
|
137
|
+
code: finding.code,
|
|
138
|
+
path: finding.path,
|
|
139
|
+
json_pointer: finding.json_pointer,
|
|
140
|
+
})),
|
|
141
|
+
};
|
|
142
|
+
return sha256Tagged(JSON.stringify(inputState));
|
|
143
|
+
}
|
|
144
|
+
function normalizeTargetPath(projectRoot, targetPath) {
|
|
145
|
+
const absolutePath = path.resolve(process.cwd(), targetPath);
|
|
146
|
+
ensureInside(projectRoot, absolutePath);
|
|
147
|
+
const relativePath = toPosixPath(path.relative(projectRoot, absolutePath));
|
|
148
|
+
return {
|
|
149
|
+
absolutePath,
|
|
150
|
+
relativePath: relativePath.length === 0 ? '.' : relativePath,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export function inspectTextBudget(projectRoot, options) {
|
|
154
|
+
const root = path.resolve(projectRoot);
|
|
155
|
+
const policy = {
|
|
156
|
+
min: options.min ?? null,
|
|
157
|
+
max: options.max ?? null,
|
|
158
|
+
exact: options.exact ?? null,
|
|
159
|
+
unit: options.unit ?? DEFAULT_TEXT_BUDGET_UNIT,
|
|
160
|
+
json_pointer: options.jsonPointer ?? null,
|
|
161
|
+
max_file_bytes: options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES,
|
|
162
|
+
};
|
|
163
|
+
const metrics = [];
|
|
164
|
+
const findings = [];
|
|
165
|
+
const artifacts = [];
|
|
166
|
+
const issues = [];
|
|
167
|
+
for (const targetPath of options.paths) {
|
|
168
|
+
let relativePath = targetPath;
|
|
169
|
+
let absolutePath;
|
|
170
|
+
try {
|
|
171
|
+
const normalized = normalizeTargetPath(root, targetPath);
|
|
172
|
+
absolutePath = normalized.absolutePath;
|
|
173
|
+
relativePath = normalized.relativePath;
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
177
|
+
issues.push(message);
|
|
178
|
+
findings.push(makeFinding('text_budget_unreadable', 'high', targetPath, policy.json_pointer, message, null, null, null));
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
let buffer;
|
|
182
|
+
try {
|
|
183
|
+
buffer = readFileInsideWithoutSymlinks(root, absolutePath, { maxBytes: policy.max_file_bytes });
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
187
|
+
issues.push(message);
|
|
188
|
+
findings.push(makeFinding('text_budget_unreadable', 'high', relativePath, policy.json_pointer, message, null, null, null));
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const contentSha256 = sha256Tagged(buffer);
|
|
192
|
+
artifacts.push({
|
|
193
|
+
kind: 'input',
|
|
194
|
+
path: relativePath,
|
|
195
|
+
sha256: contentSha256,
|
|
196
|
+
size_bytes: buffer.byteLength,
|
|
197
|
+
});
|
|
198
|
+
const rawText = buffer.toString('utf8');
|
|
199
|
+
let selectedText = rawText;
|
|
200
|
+
if (policy.json_pointer !== null) {
|
|
201
|
+
let parsed;
|
|
202
|
+
try {
|
|
203
|
+
parsed = JSON.parse(rawText);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
207
|
+
issues.push(`${relativePath}: ${message}`);
|
|
208
|
+
findings.push(makeFinding('text_budget_json_parse_failed', 'high', relativePath, policy.json_pointer, `${relativePath} could not be parsed as JSON: ${message}`, null, null, null));
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const resolution = resolveJsonPointer(parsed, policy.json_pointer);
|
|
212
|
+
if (!resolution.ok) {
|
|
213
|
+
const code = resolution.error === 'invalid' ? 'text_budget_json_pointer_invalid' : 'text_budget_json_pointer_missing';
|
|
214
|
+
const message = resolution.error === 'invalid'
|
|
215
|
+
? `Invalid JSON pointer: ${policy.json_pointer}`
|
|
216
|
+
: `JSON pointer not found: ${policy.json_pointer}`;
|
|
217
|
+
issues.push(`${relativePath}: ${message}`);
|
|
218
|
+
findings.push(makeFinding(code, 'high', relativePath, policy.json_pointer, message, null, null, null));
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (typeof resolution.value !== 'string') {
|
|
222
|
+
const message = `JSON pointer ${policy.json_pointer} does not resolve to a string.`;
|
|
223
|
+
issues.push(`${relativePath}: ${message}`);
|
|
224
|
+
findings.push(makeFinding('text_budget_json_pointer_not_string', 'high', relativePath, policy.json_pointer, message, null, null, null));
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
selectedText = resolution.value;
|
|
228
|
+
}
|
|
229
|
+
const value = countTextBudgetUnits(selectedText, policy.unit);
|
|
230
|
+
metrics.push({
|
|
231
|
+
name: 'text_length',
|
|
232
|
+
value,
|
|
233
|
+
unit: policy.unit,
|
|
234
|
+
path: relativePath,
|
|
235
|
+
json_pointer: policy.json_pointer,
|
|
236
|
+
content_sha256: contentSha256,
|
|
237
|
+
});
|
|
238
|
+
findings.push(...compareAgainstPolicy(relativePath, policy.json_pointer, value, policy));
|
|
239
|
+
}
|
|
240
|
+
const status = findings.some((finding) => ERROR_FINDING_CODES.has(finding.code))
|
|
241
|
+
? 'error'
|
|
242
|
+
: findings.length > 0
|
|
243
|
+
? 'failed'
|
|
244
|
+
: 'passed';
|
|
245
|
+
return {
|
|
246
|
+
schema_version: '1',
|
|
247
|
+
command: 'script-pack',
|
|
248
|
+
pack_id: TEXT_BUDGET_PACK_ID,
|
|
249
|
+
script_id: TEXT_BUDGET_SCRIPT_ID,
|
|
250
|
+
script_ref: TEXT_BUDGET_SCRIPT_REF,
|
|
251
|
+
action: 'check',
|
|
252
|
+
status,
|
|
253
|
+
ok: status === 'passed',
|
|
254
|
+
mustflow_root: root,
|
|
255
|
+
policy,
|
|
256
|
+
input_hash: createInputHash(policy, artifacts, findings),
|
|
257
|
+
metrics,
|
|
258
|
+
findings,
|
|
259
|
+
artifacts,
|
|
260
|
+
issues,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createComplexityBudgetReport, createComplexityBudgetReportFromVerification, } from './complexity-budget.js';
|
|
2
|
+
import { createConflictLedger } from './conflict-ledger.js';
|
|
1
3
|
function uniqueSorted(values) {
|
|
2
4
|
return [...new Set([...values].filter((value) => typeof value === 'string' && value.length > 0))].sort((left, right) => left.localeCompare(right));
|
|
3
5
|
}
|
|
@@ -138,6 +140,18 @@ function externalEvidenceRemainingRisks(externalEvidenceRisks) {
|
|
|
138
140
|
detail: risk.detail,
|
|
139
141
|
}));
|
|
140
142
|
}
|
|
143
|
+
function riskPricedEvidenceRemainingRisks(assessment) {
|
|
144
|
+
if (!assessment?.manual_review_required) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
return [
|
|
148
|
+
{
|
|
149
|
+
code: 'risk_priced_evidence_requires_review',
|
|
150
|
+
severity: assessment.level,
|
|
151
|
+
detail: `Verification risk is ${assessment.level}; required evidence: ${assessment.required_evidence.join(', ')}.`,
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
}
|
|
141
155
|
export function createVerifyEvidenceModel(input) {
|
|
142
156
|
const requirements = input.report.requirements.map((requirement) => {
|
|
143
157
|
const candidates = input.report.candidates.filter((candidate) => candidate.reason === requirement.reason);
|
|
@@ -173,6 +187,12 @@ export function createVerifyEvidenceModel(input) {
|
|
|
173
187
|
const reproEvidenceRisks = input.reproEvidenceRisks ?? [];
|
|
174
188
|
const externalChecks = input.externalChecks ?? [];
|
|
175
189
|
const externalEvidenceRisks = input.externalEvidenceRisks ?? [];
|
|
190
|
+
const hasSpecificRemainingRisks = sourceAnchorRisks.length > 0 ||
|
|
191
|
+
scopeDiffRisks.length > 0 ||
|
|
192
|
+
repeatedFailureRisks.length > 0 ||
|
|
193
|
+
validationRatchetRisks.length > 0 ||
|
|
194
|
+
reproEvidenceRisks.length > 0 ||
|
|
195
|
+
externalEvidenceRisks.length > 0;
|
|
176
196
|
const gaps = input.report.gaps.map((gap) => ({
|
|
177
197
|
reason: gap.reason,
|
|
178
198
|
intent: null,
|
|
@@ -181,6 +201,15 @@ export function createVerifyEvidenceModel(input) {
|
|
|
181
201
|
files: [...gap.files],
|
|
182
202
|
surfaces: [...gap.surfaces],
|
|
183
203
|
}));
|
|
204
|
+
const remainingRisks = [
|
|
205
|
+
...sourceAnchorRemainingRisks(sourceAnchorRisks),
|
|
206
|
+
...scopeDiffRemainingRisks(scopeDiffRisks),
|
|
207
|
+
...repeatedFailureRemainingRisks(repeatedFailureRisks),
|
|
208
|
+
...validationRatchetRemainingRisks(validationRatchetRisks),
|
|
209
|
+
...reproEvidenceRemainingRisks(reproEvidenceRisks),
|
|
210
|
+
...externalEvidenceRemainingRisks(externalEvidenceRisks),
|
|
211
|
+
...(hasSpecificRemainingRisks ? [] : riskPricedEvidenceRemainingRisks(input.report.risk_assessment)),
|
|
212
|
+
];
|
|
184
213
|
return {
|
|
185
214
|
schema_version: '1',
|
|
186
215
|
source: 'mf_verify',
|
|
@@ -196,14 +225,15 @@ export function createVerifyEvidenceModel(input) {
|
|
|
196
225
|
receipts,
|
|
197
226
|
skipped_checks: skippedCheckEntries(input.results),
|
|
198
227
|
gaps,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
228
|
+
complexity_budget: createComplexityBudgetReportFromVerification(input.report),
|
|
229
|
+
risk_assessment: input.report.risk_assessment,
|
|
230
|
+
...(input.failureReplayCapsule ? { failure_replay_capsule: input.failureReplayCapsule } : {}),
|
|
231
|
+
remaining_risks: remainingRisks,
|
|
232
|
+
conflict_ledger: createConflictLedger({
|
|
233
|
+
verdict: input.verdict,
|
|
234
|
+
gaps,
|
|
235
|
+
remainingRisks,
|
|
236
|
+
}),
|
|
207
237
|
...(reproEvidence ? { repro_evidence: reproEvidence } : {}),
|
|
208
238
|
...(externalChecks.length > 0 ? { external_checks: externalChecks } : {}),
|
|
209
239
|
explanation: explanationFromVerdict(input.verdict),
|
|
@@ -227,6 +257,11 @@ export function createDashboardEvidenceModel(input) {
|
|
|
227
257
|
const receipts = input.latestReceipt ? [input.latestReceipt] : [];
|
|
228
258
|
const sourceAnchorRisks = input.sourceAnchorRisks ?? [];
|
|
229
259
|
const scopeDiffRisks = input.scopeDiffRisks ?? [];
|
|
260
|
+
const remainingRisks = [
|
|
261
|
+
...input.remainingRisks,
|
|
262
|
+
...sourceAnchorRemainingRisks(sourceAnchorRisks),
|
|
263
|
+
...scopeDiffRemainingRisks(scopeDiffRisks),
|
|
264
|
+
];
|
|
230
265
|
return {
|
|
231
266
|
schema_version: '1',
|
|
232
267
|
source: 'dashboard_export',
|
|
@@ -242,11 +277,24 @@ export function createDashboardEvidenceModel(input) {
|
|
|
242
277
|
receipts,
|
|
243
278
|
skipped_checks: input.skippedChecks,
|
|
244
279
|
gaps: input.gaps,
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
280
|
+
complexity_budget: createComplexityBudgetReport({
|
|
281
|
+
files: [],
|
|
282
|
+
summary: {
|
|
283
|
+
fileCount: 0,
|
|
284
|
+
publicSurfaceCount: input.changedSurfaces.length,
|
|
285
|
+
changeKinds: input.changedSurfaces.length > 0 ? ['unknown'] : [],
|
|
286
|
+
validationReasons: [],
|
|
287
|
+
updatePolicies: [],
|
|
288
|
+
driftChecks: [],
|
|
289
|
+
affectedContracts: [],
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
remaining_risks: remainingRisks,
|
|
293
|
+
conflict_ledger: createConflictLedger({
|
|
294
|
+
verdict: input.verdict,
|
|
295
|
+
gaps: input.gaps,
|
|
296
|
+
remainingRisks,
|
|
297
|
+
}),
|
|
250
298
|
explanation: explanationFromVerdict(input.verdict),
|
|
251
299
|
};
|
|
252
300
|
}
|
package/package.json
CHANGED
package/schemas/README.md
CHANGED
|
@@ -7,12 +7,14 @@ Current schemas:
|
|
|
7
7
|
|
|
8
8
|
- `doctor-report.schema.json`: output of `mf doctor --json`
|
|
9
9
|
- `adapter-compatibility-report.schema.json`: output of `mf adapters status --json`
|
|
10
|
-
- `context-report.schema.json`: output of `mf context --json`, including prompt-cache profiles and optional cache audit data
|
|
10
|
+
- `context-report.schema.json`: output of `mf context --json`, including context trust metadata, prompt-cache profiles, and optional cache audit data
|
|
11
11
|
- `workspace-summary.schema.json`: output of `mf api workspace-summary --json`
|
|
12
12
|
- `command-catalog.schema.json`: output of `mf api command-catalog --json`
|
|
13
|
-
- `verification-plan.schema.json`: output of `mf api verification-plan --changed --json
|
|
13
|
+
- `verification-plan.schema.json`: output of `mf api verification-plan --changed --json`, including
|
|
14
|
+
risk-priced evidence assessment for the changed surfaces and selected command contract
|
|
14
15
|
- `latest-evidence.schema.json`: output of `mf api latest-evidence --json`
|
|
15
|
-
- `diff-risk.schema.json`: output of `mf api diff-risk --changed --json
|
|
16
|
+
- `diff-risk.schema.json`: output of `mf api diff-risk --changed --json`, including a read-only
|
|
17
|
+
complexity budget for structural additions
|
|
16
18
|
- `health.schema.json`: output of `mf api health --json`
|
|
17
19
|
- `locks.schema.json`: output of `mf api locks --json`
|
|
18
20
|
- `api-serve-response.schema.json`: each newline-delimited response from `mf api serve --stdio`
|
|
@@ -29,7 +31,8 @@ Current schemas:
|
|
|
29
31
|
- `next-report.schema.json`: output of `mf next --json`, containing the next safe action,
|
|
30
32
|
changed-file verification gaps, and read-only command recommendations
|
|
31
33
|
- `evidence-report.schema.json`: output of `mf evidence --changed --json`, containing verification
|
|
32
|
-
requirements, latest bounded evidence,
|
|
34
|
+
requirements, risk-priced evidence assessment, latest bounded evidence, failure replay capsules,
|
|
35
|
+
conflict ledgers, receipts, remaining risks, and gaps without running commands
|
|
33
36
|
- `workspace-status.schema.json`: output of `mf workspace status --json`, containing configured
|
|
34
37
|
workspace roots, discovered nested repositories, and per-root command-contract readiness without
|
|
35
38
|
granting command authority
|
|
@@ -38,11 +41,12 @@ Current schemas:
|
|
|
38
41
|
strings
|
|
39
42
|
- `workspace-verification-plan.schema.json`: output of
|
|
40
43
|
`mf workspace verify --changed --plan-only --json`, containing per-root changed-file
|
|
41
|
-
verification plans without running commands or granting
|
|
44
|
+
verification plans and risk-priced evidence assessment without running commands or granting
|
|
45
|
+
parent-to-child command authority
|
|
42
46
|
- `dashboard-export.schema.json`: bounded static export written by `mf dashboard --export-json <path>`,
|
|
43
47
|
including output policy, redaction and truncation metadata, the dashboard harness report, and
|
|
44
|
-
the evidence-based completion verdict,
|
|
45
|
-
exported snapshot
|
|
48
|
+
the evidence-based completion verdict, conflict ledger, complexity budget, evidence model, and
|
|
49
|
+
conservative coverage matrix for the exported snapshot
|
|
46
50
|
- `classify-report.schema.json`: output of `mf classify --changed --json` and
|
|
47
51
|
`mf classify <path...> --json`
|
|
48
52
|
- `impact-report.schema.json`: output of `mf impact --changed --json` and
|
|
@@ -52,6 +56,12 @@ Current schemas:
|
|
|
52
56
|
- `quality-gaming-report.schema.json`: output of `mf quality check --json`, containing changed-file
|
|
53
57
|
quality-gaming risks such as line stuffing, validation suppressions, test bypass markers, type
|
|
54
58
|
escapes, generated/vendor logic, empty catch swallowing, and placeholder implementations
|
|
59
|
+
- `script-pack-catalog.schema.json`: output of `mf script-pack list --json`, containing bundled
|
|
60
|
+
script-pack ids, script refs, action names, usage strings, and associated report schemas
|
|
61
|
+
- `text-budget-report.schema.json`: output of
|
|
62
|
+
`mf script-pack run core/text-budget check <path...> --json`, containing
|
|
63
|
+
exact text-budget metrics, input content hashes, policy metadata, findings, and JSON Pointer field
|
|
64
|
+
checks for bounded user-facing strings and generated text
|
|
55
65
|
- `skill-route-report.schema.json`: output of `mf skill route --json`, containing compact route
|
|
56
66
|
candidates, selected main and adjunct skills, score breakdowns, route read plans, and source
|
|
57
67
|
route shards without granting command authority or replacing selected `SKILL.md` reads
|
|
@@ -59,7 +69,7 @@ Current schemas:
|
|
|
59
69
|
skill-route golden cases with required and forbidden route expectations
|
|
60
70
|
- `latest-run-pointer.schema.json`: `.mustflow/state/runs/latest.json` when `mf verify` writes a
|
|
61
71
|
pointer to the latest verify run bundle, including the verify completion verdict, evidence model,
|
|
62
|
-
and coverage matrix
|
|
72
|
+
complexity budget, failure replay capsule, conflict ledger, and coverage matrix
|
|
63
73
|
- `handoff-validation-report.schema.json`: output of
|
|
64
74
|
`mf handoff validate <path> --json`
|
|
65
75
|
- `version-sources-report.schema.json`: output of `mf version-sources --json`
|
|
@@ -69,14 +79,16 @@ Current schemas:
|
|
|
69
79
|
`mf explain surface --json`, and `mf explain why <target> --json`. Verify explanations include the shared
|
|
70
80
|
`decisionGraph` evidence model; latest-failure explanations include bounded latest-run metadata only.
|
|
71
81
|
- `verify-report.schema.json`: output of `mf verify --reason <event> --json`, including an
|
|
72
|
-
explicit execution aggregate, evidence-based completion verdict,
|
|
82
|
+
explicit execution aggregate, risk-priced evidence assessment, evidence-based completion verdict,
|
|
83
|
+
failure replay capsule, conflict ledger, and evidence model with a read-only complexity budget and
|
|
73
84
|
conservative coverage matrix for the selected receipts and skipped checks
|
|
74
85
|
- `verify-run-manifest.schema.json`: `.mustflow/state/runs/verify-*/manifest.json`, including
|
|
75
|
-
the same execution aggregate,
|
|
86
|
+
the same execution aggregate, risk assessment, completion verdict, failure replay capsule,
|
|
87
|
+
conflict ledger, evidence model, complexity budget, and coverage matrix as the verify report
|
|
76
88
|
- `change-verification-report.schema.json`: output of `mf verify --reason <event> --plan-only --json` and
|
|
77
89
|
`mf verify --from-classification <classify-report.json> --plan-only --json`, including the `decision_graph` that links
|
|
78
90
|
changed surfaces, classification reasons, command candidates, eligibility, selected or not-selected state,
|
|
79
|
-
effects, and
|
|
91
|
+
effects, gaps, and risk-priced evidence requirements.
|
|
80
92
|
Local-index command-effect graphs and command preconditions are explanation-only and cannot grant command authority.
|
|
81
93
|
|
|
82
94
|
These schemas define stable, automation-facing fields. Human-readable command
|
|
@@ -55,6 +55,9 @@
|
|
|
55
55
|
"$ref": "#/$defs/verificationGap"
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
+
"risk_assessment": {
|
|
59
|
+
"$ref": "#/$defs/riskAssessment"
|
|
60
|
+
},
|
|
58
61
|
"schedule": {
|
|
59
62
|
"$ref": "#/$defs/verificationSchedule"
|
|
60
63
|
},
|
|
@@ -328,6 +331,32 @@
|
|
|
328
331
|
}
|
|
329
332
|
}
|
|
330
333
|
},
|
|
334
|
+
"riskAssessment": {
|
|
335
|
+
"type": "object",
|
|
336
|
+
"additionalProperties": false,
|
|
337
|
+
"required": [
|
|
338
|
+
"schema_version",
|
|
339
|
+
"source",
|
|
340
|
+
"level",
|
|
341
|
+
"reasons",
|
|
342
|
+
"required_evidence",
|
|
343
|
+
"blocking_gaps",
|
|
344
|
+
"rollback_required",
|
|
345
|
+
"human_approval_required",
|
|
346
|
+
"manual_review_required"
|
|
347
|
+
],
|
|
348
|
+
"properties": {
|
|
349
|
+
"schema_version": { "const": "1" },
|
|
350
|
+
"source": { "const": "change_classification_and_command_contract" },
|
|
351
|
+
"level": { "enum": ["low", "medium", "high", "critical"] },
|
|
352
|
+
"reasons": { "$ref": "#/$defs/stringArray" },
|
|
353
|
+
"required_evidence": { "$ref": "#/$defs/stringArray" },
|
|
354
|
+
"blocking_gaps": { "$ref": "#/$defs/stringArray" },
|
|
355
|
+
"rollback_required": { "type": "boolean" },
|
|
356
|
+
"human_approval_required": { "type": "boolean" },
|
|
357
|
+
"manual_review_required": { "type": "boolean" }
|
|
358
|
+
}
|
|
359
|
+
},
|
|
331
360
|
"testSelectionReport": {
|
|
332
361
|
"type": "object",
|
|
333
362
|
"additionalProperties": false,
|
|
@@ -121,7 +121,61 @@
|
|
|
121
121
|
"required": ["path", "exists"],
|
|
122
122
|
"properties": {
|
|
123
123
|
"path": { "type": "string" },
|
|
124
|
-
"exists": { "type": "boolean" }
|
|
124
|
+
"exists": { "type": "boolean" },
|
|
125
|
+
"trust": { "$ref": "#/$defs/contextTrust" }
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"contextTrust": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"additionalProperties": false,
|
|
131
|
+
"required": [
|
|
132
|
+
"source_kind",
|
|
133
|
+
"authority",
|
|
134
|
+
"cache_layer",
|
|
135
|
+
"freshness",
|
|
136
|
+
"content_hash",
|
|
137
|
+
"can_instruct_agent",
|
|
138
|
+
"grants_command_authority",
|
|
139
|
+
"notes"
|
|
140
|
+
],
|
|
141
|
+
"properties": {
|
|
142
|
+
"source_kind": {
|
|
143
|
+
"enum": [
|
|
144
|
+
"workflow_file",
|
|
145
|
+
"command_contract",
|
|
146
|
+
"skill_file",
|
|
147
|
+
"context_file",
|
|
148
|
+
"generated_cache",
|
|
149
|
+
"generated_state",
|
|
150
|
+
"source_placeholder",
|
|
151
|
+
"runtime_volatile",
|
|
152
|
+
"unknown_file"
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
"authority": {
|
|
156
|
+
"enum": [
|
|
157
|
+
"binding",
|
|
158
|
+
"workflow_policy",
|
|
159
|
+
"configuration",
|
|
160
|
+
"command_contract",
|
|
161
|
+
"procedure",
|
|
162
|
+
"contextual",
|
|
163
|
+
"hint",
|
|
164
|
+
"generated",
|
|
165
|
+
"evidence_only",
|
|
166
|
+
"volatile",
|
|
167
|
+
"unknown"
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"cache_layer": { "enum": ["stable", "task", "volatile", null] },
|
|
171
|
+
"freshness": { "enum": ["hash_verified", "missing", "dynamic", "runtime_volatile", "unchecked"] },
|
|
172
|
+
"content_hash": { "type": ["string", "null"] },
|
|
173
|
+
"can_instruct_agent": { "type": "boolean" },
|
|
174
|
+
"grants_command_authority": { "type": "boolean" },
|
|
175
|
+
"notes": {
|
|
176
|
+
"type": "array",
|
|
177
|
+
"items": { "type": "string" }
|
|
178
|
+
}
|
|
125
179
|
}
|
|
126
180
|
},
|
|
127
181
|
"intentContext": {
|
|
@@ -364,7 +418,8 @@
|
|
|
364
418
|
"properties": {
|
|
365
419
|
"path": { "type": "string" },
|
|
366
420
|
"exists": { "type": "boolean" },
|
|
367
|
-
"content_hash": { "type": ["string", "null"] }
|
|
421
|
+
"content_hash": { "type": ["string", "null"] },
|
|
422
|
+
"trust": { "$ref": "#/$defs/contextTrust" }
|
|
368
423
|
}
|
|
369
424
|
},
|
|
370
425
|
"taskContextLayer": {
|
|
@@ -617,6 +672,7 @@
|
|
|
617
672
|
"type": "array",
|
|
618
673
|
"items": { "type": "string" }
|
|
619
674
|
},
|
|
675
|
+
"trust": { "$ref": "#/$defs/contextTrust" },
|
|
620
676
|
"issue": { "type": ["string", "null"] }
|
|
621
677
|
}
|
|
622
678
|
},
|
|
@@ -197,6 +197,9 @@
|
|
|
197
197
|
"type": "array",
|
|
198
198
|
"items": { "$ref": "#/$defs/evidenceGap" }
|
|
199
199
|
},
|
|
200
|
+
"complexity_budget": { "$ref": "verify-report.schema.json#/$defs/complexityBudget" },
|
|
201
|
+
"risk_assessment": { "$ref": "#/$defs/riskAssessment" },
|
|
202
|
+
"conflict_ledger": { "$ref": "verify-report.schema.json#/$defs/conflictLedger" },
|
|
200
203
|
"remaining_risks": {
|
|
201
204
|
"type": "array",
|
|
202
205
|
"items": { "$ref": "#/$defs/evidenceRemainingRisk" }
|
|
@@ -304,6 +307,41 @@
|
|
|
304
307
|
"detail": { "type": "string" }
|
|
305
308
|
}
|
|
306
309
|
},
|
|
310
|
+
"riskAssessment": {
|
|
311
|
+
"type": "object",
|
|
312
|
+
"additionalProperties": false,
|
|
313
|
+
"required": [
|
|
314
|
+
"schema_version",
|
|
315
|
+
"source",
|
|
316
|
+
"level",
|
|
317
|
+
"reasons",
|
|
318
|
+
"required_evidence",
|
|
319
|
+
"blocking_gaps",
|
|
320
|
+
"rollback_required",
|
|
321
|
+
"human_approval_required",
|
|
322
|
+
"manual_review_required"
|
|
323
|
+
],
|
|
324
|
+
"properties": {
|
|
325
|
+
"schema_version": { "const": "1" },
|
|
326
|
+
"source": { "const": "change_classification_and_command_contract" },
|
|
327
|
+
"level": { "enum": ["low", "medium", "high", "critical"] },
|
|
328
|
+
"reasons": {
|
|
329
|
+
"type": "array",
|
|
330
|
+
"items": { "type": "string" }
|
|
331
|
+
},
|
|
332
|
+
"required_evidence": {
|
|
333
|
+
"type": "array",
|
|
334
|
+
"items": { "type": "string" }
|
|
335
|
+
},
|
|
336
|
+
"blocking_gaps": {
|
|
337
|
+
"type": "array",
|
|
338
|
+
"items": { "type": "string" }
|
|
339
|
+
},
|
|
340
|
+
"rollback_required": { "type": "boolean" },
|
|
341
|
+
"human_approval_required": { "type": "boolean" },
|
|
342
|
+
"manual_review_required": { "type": "boolean" }
|
|
343
|
+
}
|
|
344
|
+
},
|
|
307
345
|
"evidenceExplanation": {
|
|
308
346
|
"type": "object",
|
|
309
347
|
"additionalProperties": false,
|
|
@@ -377,6 +415,7 @@
|
|
|
377
415
|
"receipt_binding_risk_count": { "type": "integer" },
|
|
378
416
|
"stale_receipt_count": { "type": "integer" },
|
|
379
417
|
"plan_mismatch_count": { "type": "integer" },
|
|
418
|
+
"risk_priced_evidence_risk_count": { "type": "integer" },
|
|
380
419
|
"risks": { "$ref": "#/$defs/completionVerdictRisks" },
|
|
381
420
|
"receipt_binding": { "$ref": "#/$defs/completionVerdictReceiptBinding" },
|
|
382
421
|
"latest_run_status": { "type": ["string", "null"] }
|
|
@@ -434,7 +473,8 @@
|
|
|
434
473
|
"write_drift": { "type": "integer" },
|
|
435
474
|
"receipt_binding": { "type": "integer" },
|
|
436
475
|
"stale_receipt": { "type": "integer" },
|
|
437
|
-
"plan_mismatch": { "type": "integer" }
|
|
476
|
+
"plan_mismatch": { "type": "integer" },
|
|
477
|
+
"risk_priced_evidence": { "type": "integer" }
|
|
438
478
|
}
|
|
439
479
|
},
|
|
440
480
|
"completionVerdictReceiptBinding": {
|
|
@@ -505,6 +545,7 @@
|
|
|
505
545
|
"properties": {
|
|
506
546
|
"completion_verdict": { "$ref": "#/$defs/completionVerdict" },
|
|
507
547
|
"evidence_model": { "$ref": "#/$defs/evidenceModel" },
|
|
548
|
+
"conflict_ledger": { "$ref": "verify-report.schema.json#/$defs/conflictLedger" },
|
|
508
549
|
"changed_file_count": { "type": "integer" },
|
|
509
550
|
"changed_surfaces": { "$ref": "#/$defs/stringArray" },
|
|
510
551
|
"decision_graph_summary": {
|