mustflow 2.18.2 → 2.18.3

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.
@@ -13,6 +13,7 @@ import { createVerifyEvidenceModel } from '../../core/verification-evidence.js';
13
13
  import { createScopeDiffRisks } from '../../core/scope-risk.js';
14
14
  import { countValidationRatchetVerdictEffects, createValidationRatchetRisks, } from '../../core/validation-ratchet.js';
15
15
  import { readCommandContract } from '../../core/config-loading.js';
16
+ import { DEFAULT_VERIFY_PARALLELISM, parseVerifyArgs } from './verify/args.js';
16
17
  import { printUsageError, renderHelp } from '../lib/cli-output.js';
17
18
  import { t } from '../lib/i18n.js';
18
19
  import { readLocalCommandEffectGraph, readLocalPathSurfaces, readLocalSourceAnchorVerdictRisks, } from '../lib/local-index.js';
@@ -20,7 +21,6 @@ import { resolveMustflowRoot } from '../lib/project-root.js';
20
21
  const VERIFY_SCHEMA_VERSION = '1';
21
22
  const RUN_STATE_DIR = path.join('.mustflow', 'state', 'runs');
22
23
  const LATEST_RUN_RECEIPT_PATH = path.join(RUN_STATE_DIR, 'latest.json');
23
- const DEFAULT_VERIFY_PARALLELISM = 1;
24
24
  function createBufferedOutput() {
25
25
  const stdout = [];
26
26
  const stderr = [];
@@ -73,267 +73,6 @@ export function getVerifyHelp(lang = 'en') {
73
73
  ],
74
74
  }, lang);
75
75
  }
76
- function parseVerifyArgs(args) {
77
- let reason;
78
- let fromClassification;
79
- let fromPlan;
80
- let writePlan;
81
- let reproEvidence;
82
- let externalEvidence;
83
- let json = false;
84
- let planOnly = false;
85
- let changed = false;
86
- let parallelism = DEFAULT_VERIFY_PARALLELISM;
87
- for (let index = 0; index < args.length; index += 1) {
88
- const arg = args[index];
89
- if (arg === '--json') {
90
- json = true;
91
- continue;
92
- }
93
- if (arg === '--plan-only') {
94
- planOnly = true;
95
- continue;
96
- }
97
- if (arg === '--changed') {
98
- changed = true;
99
- continue;
100
- }
101
- if (arg === '--parallel') {
102
- const value = args[index + 1];
103
- if (!value || value.startsWith('-')) {
104
- return { json, planOnly, changed, reason, parallelism, error: 'missing_parallel_value' };
105
- }
106
- const parsedParallelism = parseVerifyParallelism(value);
107
- if (parsedParallelism === null) {
108
- return { json, planOnly, changed, reason, parallelism, error: 'invalid_parallel_value' };
109
- }
110
- parallelism = parsedParallelism;
111
- index += 1;
112
- continue;
113
- }
114
- if (arg === '--reason') {
115
- const value = args[index + 1];
116
- if (!value || value.startsWith('-')) {
117
- return { json, planOnly, changed, reason, error: 'missing_reason_value' };
118
- }
119
- reason = value;
120
- index += 1;
121
- continue;
122
- }
123
- if (arg === '--from-plan') {
124
- const value = args[index + 1];
125
- if (!value || value.startsWith('-')) {
126
- return { json, planOnly, changed, reason, fromClassification, fromPlan, error: 'missing_from_plan_value' };
127
- }
128
- fromPlan = value;
129
- index += 1;
130
- continue;
131
- }
132
- if (arg === '--from-classification') {
133
- const value = args[index + 1];
134
- if (!value || value.startsWith('-')) {
135
- return {
136
- json,
137
- planOnly,
138
- changed,
139
- reason,
140
- fromClassification,
141
- fromPlan,
142
- error: 'missing_from_classification_value',
143
- };
144
- }
145
- fromClassification = value;
146
- index += 1;
147
- continue;
148
- }
149
- if (arg === '--write-plan') {
150
- const value = args[index + 1];
151
- if (!value || value.startsWith('-')) {
152
- return {
153
- json,
154
- planOnly,
155
- changed,
156
- reason,
157
- fromClassification,
158
- fromPlan,
159
- writePlan,
160
- error: 'missing_write_plan_value',
161
- };
162
- }
163
- writePlan = value;
164
- index += 1;
165
- continue;
166
- }
167
- if (arg === '--external-evidence') {
168
- const value = args[index + 1];
169
- if (!value || value.startsWith('-')) {
170
- return {
171
- json,
172
- planOnly,
173
- changed,
174
- reason,
175
- fromClassification,
176
- fromPlan,
177
- writePlan,
178
- externalEvidence,
179
- error: 'missing_external_evidence_value',
180
- };
181
- }
182
- externalEvidence = value;
183
- index += 1;
184
- continue;
185
- }
186
- if (arg === '--repro-evidence') {
187
- const value = args[index + 1];
188
- if (!value || value.startsWith('-')) {
189
- return {
190
- json,
191
- planOnly,
192
- changed,
193
- reason,
194
- fromClassification,
195
- fromPlan,
196
- writePlan,
197
- reproEvidence,
198
- externalEvidence,
199
- error: 'missing_repro_evidence_value',
200
- };
201
- }
202
- reproEvidence = value;
203
- index += 1;
204
- continue;
205
- }
206
- if (arg.startsWith('--reason=')) {
207
- const value = arg.slice('--reason='.length);
208
- if (value.length === 0) {
209
- return { json, planOnly, changed, reason, error: 'missing_reason_value' };
210
- }
211
- reason = value;
212
- continue;
213
- }
214
- if (arg.startsWith('--parallel=')) {
215
- const value = arg.slice('--parallel='.length);
216
- const parsedParallelism = parseVerifyParallelism(value);
217
- if (parsedParallelism === null) {
218
- return { json, planOnly, changed, reason, parallelism, error: 'invalid_parallel_value' };
219
- }
220
- parallelism = parsedParallelism;
221
- continue;
222
- }
223
- if (arg.startsWith('--from-plan=')) {
224
- const value = arg.slice('--from-plan='.length);
225
- if (value.length === 0) {
226
- return { json, planOnly, changed, reason, fromClassification, fromPlan, error: 'missing_from_plan_value' };
227
- }
228
- fromPlan = value;
229
- continue;
230
- }
231
- if (arg.startsWith('--from-classification=')) {
232
- const value = arg.slice('--from-classification='.length);
233
- if (value.length === 0) {
234
- return {
235
- json,
236
- planOnly,
237
- changed,
238
- reason,
239
- fromClassification,
240
- fromPlan,
241
- error: 'missing_from_classification_value',
242
- };
243
- }
244
- fromClassification = value;
245
- continue;
246
- }
247
- if (arg.startsWith('--write-plan=')) {
248
- const value = arg.slice('--write-plan='.length);
249
- if (value.length === 0) {
250
- return {
251
- json,
252
- planOnly,
253
- changed,
254
- reason,
255
- fromClassification,
256
- fromPlan,
257
- writePlan,
258
- error: 'missing_write_plan_value',
259
- };
260
- }
261
- writePlan = value;
262
- continue;
263
- }
264
- if (arg.startsWith('--external-evidence=')) {
265
- const value = arg.slice('--external-evidence='.length);
266
- if (value.length === 0) {
267
- return {
268
- json,
269
- planOnly,
270
- changed,
271
- reason,
272
- fromClassification,
273
- fromPlan,
274
- writePlan,
275
- externalEvidence,
276
- error: 'missing_external_evidence_value',
277
- };
278
- }
279
- externalEvidence = value;
280
- continue;
281
- }
282
- if (arg.startsWith('--repro-evidence=')) {
283
- const value = arg.slice('--repro-evidence='.length);
284
- if (value.length === 0) {
285
- return {
286
- json,
287
- planOnly,
288
- changed,
289
- reason,
290
- fromClassification,
291
- fromPlan,
292
- writePlan,
293
- reproEvidence,
294
- externalEvidence,
295
- error: 'missing_repro_evidence_value',
296
- };
297
- }
298
- reproEvidence = value;
299
- continue;
300
- }
301
- if (arg.startsWith('-')) {
302
- return { json, planOnly, changed, reason, fromClassification, fromPlan, writePlan, reproEvidence, externalEvidence, error: arg };
303
- }
304
- return {
305
- json,
306
- planOnly,
307
- changed,
308
- reason,
309
- fromClassification,
310
- fromPlan,
311
- writePlan,
312
- reproEvidence,
313
- externalEvidence,
314
- error: `unexpected:${arg}`,
315
- };
316
- }
317
- return {
318
- json,
319
- planOnly,
320
- changed,
321
- reason,
322
- fromClassification,
323
- fromPlan,
324
- writePlan,
325
- reproEvidence,
326
- externalEvidence,
327
- parallelism,
328
- };
329
- }
330
- function parseVerifyParallelism(value) {
331
- if (!/^[1-9][0-9]*$/u.test(value)) {
332
- return null;
333
- }
334
- const parsed = Number(value);
335
- return Number.isSafeInteger(parsed) ? parsed : null;
336
- }
337
76
  function uniqueStrings(values) {
338
77
  return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];
339
78
  }
package/dist/cli/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { realpathSync } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { COMMAND_DEFINITIONS } from './lib/command-registry.js';
5
+ import { COMMAND_DEFINITIONS, findCommandDefinition } from './lib/command-registry.js';
6
6
  import { renderCliError, renderHelp } from './lib/cli-output.js';
7
7
  import { DEFAULT_CLI_LANG, SUPPORTED_CLI_LANGS, isCliLang, t } from './lib/i18n.js';
8
8
  import { consoleReporter } from './lib/reporter.js';
@@ -102,77 +102,11 @@ export async function runCli(argv, reporter = consoleReporter) {
102
102
  reporter.stdout(getTopLevelHelp(parsed.lang));
103
103
  return 0;
104
104
  }
105
- if (command === '--version' || command === '-v' || command === 'version') {
106
- return (await import('./commands/version.js')).runVersion(args, reporter, parsed.lang);
107
- }
108
- if (command === 'init') {
109
- return (await import('./commands/init.js')).runInit(args, reporter, parsed.lang);
110
- }
111
- if (command === 'adapters') {
112
- return (await import('./commands/adapters.js')).runAdapters(args, reporter, parsed.lang);
113
- }
114
- if (command === 'check') {
115
- return (await import('./commands/check.js')).runCheck(args, reporter, parsed.lang);
116
- }
117
- if (command === 'classify') {
118
- return (await import('./commands/classify.js')).runClassify(args, reporter, parsed.lang);
119
- }
120
- if (command === 'contract-lint') {
121
- return (await import('./commands/contract-lint.js')).runContractLint(args, reporter, parsed.lang);
122
- }
123
- if (command === 'status') {
124
- return (await import('./commands/status.js')).runStatus(args, reporter, parsed.lang);
125
- }
126
- if (command === 'update') {
127
- return (await import('./commands/update.js')).runUpdate(args, reporter, parsed.lang);
128
- }
129
- if (command === 'upgrade') {
130
- return (await import('./commands/upgrade.js')).runUpgrade(args, reporter, parsed.lang);
131
- }
132
- if (command === 'map') {
133
- return (await import('./commands/map.js')).runMap(args, reporter, parsed.lang);
134
- }
135
- if (command === 'line-endings') {
136
- return (await import('./commands/line-endings.js')).runLineEndings(args, reporter, parsed.lang);
137
- }
138
- if (command === 'run') {
139
- return (await import('./commands/run.js')).runRun(args, reporter, parsed.lang);
140
- }
141
- if (command === 'context') {
142
- return (await import('./commands/context.js')).runContext(args, reporter, parsed.lang);
143
- }
144
- if (command === 'doctor') {
145
- return (await import('./commands/doctor.js')).runDoctor(args, reporter, parsed.lang);
146
- }
147
- if (command === 'docs') {
148
- return (await import('./commands/docs.js')).runDocs(args, reporter, parsed.lang);
149
- }
150
- if (command === 'handoff') {
151
- return (await import('./commands/handoff.js')).runHandoff(args, reporter, parsed.lang);
152
- }
153
- if (command === 'index') {
154
- return (await import('./commands/index.js')).runIndex(args, reporter, parsed.lang);
155
- }
156
- if (command === 'search') {
157
- return (await import('./commands/search.js')).runSearch(args, reporter, parsed.lang);
158
- }
159
- if (command === 'dashboard') {
160
- return (await import('./commands/dashboard.js')).runDashboard(args, reporter, parsed.lang);
161
- }
162
- if (command === 'version-sources') {
163
- return (await import('./commands/version-sources.js')).runVersionSources(args, reporter, parsed.lang);
164
- }
165
- if (command === 'verify') {
166
- return (await import('./commands/verify.js')).runVerify(args, reporter, parsed.lang);
167
- }
168
- if (command === 'explain') {
169
- return (await import('./commands/explain.js')).runExplain(args, reporter, parsed.lang);
170
- }
171
- if (command === 'impact') {
172
- return (await import('./commands/impact.js')).runImpact(args, reporter, parsed.lang);
173
- }
174
- if (command === 'help') {
175
- return (await import('./commands/help.js')).runHelp(args, reporter, parsed.lang);
105
+ const commandId = command === '--version' || command === '-v' ? 'version' : command;
106
+ const commandDefinition = findCommandDefinition(commandId);
107
+ if (commandDefinition) {
108
+ const runner = await commandDefinition.loadRunner();
109
+ return runner(args, reporter, parsed.lang);
176
110
  }
177
111
  reporter.stderr(renderCliError(t(parsed.lang, 'cli.error.unknownCommand', { command }), 'mf --help', parsed.lang));
178
112
  reporter.stdout(getTopLevelHelp(parsed.lang));
@@ -3,120 +3,147 @@ export const COMMAND_DEFINITIONS = [
3
3
  id: 'adapters',
4
4
  usage: 'mf adapters',
5
5
  summaryKey: 'command.adapters.summary',
6
+ loadRunner: async () => (await import('../commands/adapters.js')).runAdapters,
6
7
  },
7
8
  {
8
9
  id: 'init',
9
10
  usage: 'mf init',
10
11
  summaryKey: 'command.init.summary',
12
+ loadRunner: async () => (await import('../commands/init.js')).runInit,
11
13
  },
12
14
  {
13
15
  id: 'check',
14
16
  usage: 'mf check',
15
17
  summaryKey: 'command.check.summary',
18
+ loadRunner: async () => (await import('../commands/check.js')).runCheck,
16
19
  },
17
20
  {
18
21
  id: 'classify',
19
22
  usage: 'mf classify',
20
23
  summaryKey: 'command.classify.summary',
24
+ loadRunner: async () => (await import('../commands/classify.js')).runClassify,
21
25
  },
22
26
  {
23
27
  id: 'contract-lint',
24
28
  usage: 'mf contract-lint',
25
29
  summaryKey: 'command.contractLint.summary',
30
+ loadRunner: async () => (await import('../commands/contract-lint.js')).runContractLint,
26
31
  },
27
32
  {
28
33
  id: 'status',
29
34
  usage: 'mf status',
30
35
  summaryKey: 'command.status.summary',
36
+ loadRunner: async () => (await import('../commands/status.js')).runStatus,
31
37
  },
32
38
  {
33
39
  id: 'update',
34
40
  usage: 'mf update',
35
41
  summaryKey: 'command.update.summary',
42
+ loadRunner: async () => (await import('../commands/update.js')).runUpdate,
36
43
  },
37
44
  {
38
45
  id: 'upgrade',
39
46
  usage: 'mf upgrade',
40
47
  summaryKey: 'command.upgrade.summary',
48
+ loadRunner: async () => (await import('../commands/upgrade.js')).runUpgrade,
41
49
  },
42
50
  {
43
51
  id: 'map',
44
52
  usage: 'mf map',
45
53
  summaryKey: 'command.map.summary',
54
+ loadRunner: async () => (await import('../commands/map.js')).runMap,
46
55
  },
47
56
  {
48
57
  id: 'line-endings',
49
58
  usage: 'mf line-endings',
50
59
  summaryKey: 'command.lineEndings.summary',
60
+ loadRunner: async () => (await import('../commands/line-endings.js')).runLineEndings,
51
61
  },
52
62
  {
53
63
  id: 'run',
54
64
  usage: 'mf run',
55
65
  summaryKey: 'command.run.summary',
66
+ loadRunner: async () => (await import('../commands/run.js')).runRun,
56
67
  },
57
68
  {
58
69
  id: 'context',
59
70
  usage: 'mf context',
60
71
  summaryKey: 'command.context.summary',
72
+ loadRunner: async () => (await import('../commands/context.js')).runContext,
61
73
  },
62
74
  {
63
75
  id: 'doctor',
64
76
  usage: 'mf doctor',
65
77
  summaryKey: 'command.doctor.summary',
78
+ loadRunner: async () => (await import('../commands/doctor.js')).runDoctor,
66
79
  },
67
80
  {
68
81
  id: 'docs',
69
82
  usage: 'mf docs',
70
83
  summaryKey: 'command.docs.summary',
84
+ loadRunner: async () => (await import('../commands/docs.js')).runDocs,
71
85
  },
72
86
  {
73
87
  id: 'handoff',
74
88
  usage: 'mf handoff',
75
89
  summaryKey: 'command.handoff.summary',
90
+ loadRunner: async () => (await import('../commands/handoff.js')).runHandoff,
76
91
  },
77
92
  {
78
93
  id: 'index',
79
94
  usage: 'mf index',
80
95
  summaryKey: 'command.index.summary',
96
+ loadRunner: async () => (await import('../commands/index.js')).runIndex,
81
97
  },
82
98
  {
83
99
  id: 'search',
84
100
  usage: 'mf search',
85
101
  summaryKey: 'command.search.summary',
102
+ loadRunner: async () => (await import('../commands/search.js')).runSearch,
86
103
  },
87
104
  {
88
105
  id: 'dashboard',
89
106
  usage: 'mf dashboard',
90
107
  summaryKey: 'command.dashboard.summary',
108
+ loadRunner: async () => (await import('../commands/dashboard.js')).runDashboard,
91
109
  },
92
110
  {
93
111
  id: 'version',
94
112
  usage: 'mf version',
95
113
  summaryKey: 'command.version.summary',
114
+ loadRunner: async () => (await import('../commands/version.js')).runVersion,
96
115
  },
97
116
  {
98
117
  id: 'version-sources',
99
118
  usage: 'mf version-sources',
100
119
  summaryKey: 'command.versionSources.summary',
120
+ loadRunner: async () => (await import('../commands/version-sources.js')).runVersionSources,
101
121
  },
102
122
  {
103
123
  id: 'verify',
104
124
  usage: 'mf verify',
105
125
  summaryKey: 'command.verify.summary',
126
+ loadRunner: async () => (await import('../commands/verify.js')).runVerify,
106
127
  },
107
128
  {
108
129
  id: 'explain',
109
130
  usage: 'mf explain',
110
131
  summaryKey: 'command.explain.summary',
132
+ loadRunner: async () => (await import('../commands/explain.js')).runExplain,
111
133
  },
112
134
  {
113
135
  id: 'impact',
114
136
  usage: 'mf impact',
115
137
  summaryKey: 'command.impact.summary',
138
+ loadRunner: async () => (await import('../commands/impact.js')).runImpact,
116
139
  },
117
140
  {
118
141
  id: 'help',
119
142
  usage: 'mf help',
120
143
  summaryKey: 'command.help.summary',
144
+ loadRunner: async () => (await import('../commands/help.js')).runHelp,
121
145
  },
122
146
  ];
147
+ export function findCommandDefinition(command) {
148
+ return COMMAND_DEFINITIONS.find((definition) => definition.id === command);
149
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mustflow",
3
- "version": "2.18.2",
3
+ "version": "2.18.3",
4
4
  "description": "Agent workflow documents and CLI for mustflow repository roots.",
5
5
  "type": "module",
6
6
  "license": "MIT-0",
@@ -56,7 +56,7 @@ translations = {}
56
56
  [documents."skills.index"]
57
57
  source = "locales/en/.mustflow/skills/INDEX.md"
58
58
  source_locale = "en"
59
- revision = 54
59
+ revision = 55
60
60
  translations = {}
61
61
 
62
62
  [documents."skill.adapter-boundary"]
@@ -274,6 +274,12 @@ source_locale = "en"
274
274
  revision = 2
275
275
  translations = {}
276
276
 
277
+ [documents."skill.source-anchor-authoring"]
278
+ source = "locales/en/.mustflow/skills/source-anchor-authoring/SKILL.md"
279
+ source_locale = "en"
280
+ revision = 1
281
+ translations = {}
282
+
277
283
  [documents."skill.project-context-authoring"]
278
284
  source = "locales/en/.mustflow/skills/project-context-authoring/SKILL.md"
279
285
  source_locale = "en"
@@ -2,7 +2,7 @@
2
2
  mustflow_doc: skills.index
3
3
  locale: en
4
4
  canonical: true
5
- revision: 54
5
+ revision: 55
6
6
  authority: router
7
7
  lifecycle: mustflow-owned
8
8
  ---
@@ -94,6 +94,7 @@ stay inactive until their event occurs.
94
94
  | --- | --- | --- | --- | --- | --- | --- |
95
95
  | Code changes need review before report | `.mustflow/skills/code-review/SKILL.md` | Diff and task goal | Changed files | behavior and regression | `test`, `test_related`, `test_audit`, `lint` | Findings or no-issue note |
96
96
  | An unfamiliar codebase area needs an evidence-based map before planning, implementation, or reporting | `.mustflow/skills/codebase-orientation/SKILL.md` | User request, target area, relevant instructions, and current source, test, schema, template, configuration, or documentation files | Read-only orientation notes and any smallest follow-up edit chosen from inspected evidence | stale documentation, wrong ownership boundary, or invented architecture claim | `changes_status`, `changes_diff_summary`, `mustflow_check` | Scope inspected, entrypoints, flow map, ownership boundaries, verification options, risks, unknowns, and smallest safe next step |
97
+ | Source anchors are added, revised, reviewed, or used to mark a module boundary | `.mustflow/skills/source-anchor-authoring/SKILL.md` | Target files, anchor reason, nearby anchors, source-anchor policy, and validation surface | Source anchors and directly related workflow docs or comments | comment bloat, authority drift, false verification claims, or hidden module pressure | `mustflow_check`, `docs_validate_fast` | Anchor placement decision, field choices, module-boundary handoff, and verification |
97
98
  | Changed files need risk classification and verification selection | `.mustflow/skills/diff-risk-review/SKILL.md` | Changed-file list, diff summary, and task goal | Changed surfaces and verification report | under- or over-verification | `changes_status`, `changes_diff_summary`, `test`, `test_related`, `test_audit`, `lint`, `build`, `docs_validate`, `mustflow_check` | Risk level, verification choice, rollback notes |
98
99
  | Performance budgets, bundle size, page weight, startup time, command duration, memory use, asset size, throughput, latency, benchmark output, or performance claims are planned, edited, reviewed, or reported | `.mustflow/skills/performance-budget-check/SKILL.md` | Performance surface, budget source, measurement method, environment boundary, and command contract entries | Budget checks, thresholds, measurements, dependency tradeoff notes, tests, docs, package metadata, and reports | invented budgets, stale measurements, hidden performance cost, or unverified speed claim | `changes_status`, `changes_diff_summary`, `build`, `test_related`, `docs_validate_fast`, `test_release`, `mustflow_check` | Performance surface, budget source, measurement boundary, synchronized claims, skipped measurements, and remaining performance risk |
99
100
  | New feature, module, folder layout, architecture, scaffold, refactor, routing, data model, or external service integration may require hidden structure decisions before coding | `.mustflow/skills/structure-discovery-gate/SKILL.md` | User request, intended capability, hidden assumptions, named technologies or services, and relevant local patterns | Questions, assumptions, proposed file boundaries, and the smallest resulting implementation | brittle structure, vendor-name leakage, over-questioning, or speculative abstraction | `changes_status`, `changes_diff_summary`, `docs_validate_fast`, `test_release`, `mustflow_check` | Blocking questions, assumptions, proposed files and responsibilities, dependency direction, local pattern, verification, and remaining structure risk |
@@ -90,6 +90,12 @@ route_type = "primary"
90
90
  priority = 20
91
91
  applies_to_reasons = ["unknown_change", "code_change"]
92
92
 
93
+ [routes."source-anchor-authoring"]
94
+ category = "general_code"
95
+ route_type = "primary"
96
+ priority = 60
97
+ applies_to_reasons = ["code_change", "mustflow_docs_change"]
98
+
93
99
  [routes."repo-improvement-loop"]
94
100
  category = "workflow_contracts"
95
101
  route_type = "primary"