arkgate 4.8.20 → 4.8.21
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/CHANGELOG.md +124 -5
- package/README.md +107 -117
- package/bin/ark-check-runtime.mjs +3 -4
- package/bin/ark-layer-match.mjs +110 -18
- package/bin/lib/analysis-engine.mjs +13 -6
- package/bin/lib/config-contract.mjs +5 -0
- package/bin/lib/diagnostic-catalog.mjs +1 -0
- package/bin/lib/doctor-advisories.mjs +20 -0
- package/bin/lib/doctor-human.mjs +11 -9
- package/bin/lib/doctor-plan.mjs +15 -14
- package/bin/lib/first-run-help.mjs +7 -1
- package/bin/lib/html-report-advisories.mjs +8 -0
- package/bin/lib/html-report-depth.mjs +9 -8
- package/bin/lib/invariant-coverage.mjs +396 -75
- package/bin/lib/managed-upgrade.mjs +59 -14
- package/bin/lib/pilot-loop.mjs +183 -37
- package/bin/lib/upgrade-behavior-changes.mjs +83 -0
- package/bin/lib/upgrade-command.mjs +69 -31
- package/bin/lib/upgrade-outcome.mjs +359 -0
- package/bin/lib/violations.mjs +109 -0
- package/dist/{configTypes-VVknqcTJ.d.ts → configTypes-CTELo87-.d.ts} +7 -0
- package/dist/{diagnosticCatalog-BPYWNyJR.d.ts → diagnosticCatalog-B7BXlet6.d.ts} +73 -5
- package/dist/eslint/index.cjs +4 -4
- package/dist/eslint/index.d.ts +26 -3
- package/dist/eslint/index.js +4 -4
- package/dist/index.cjs +24 -17
- package/dist/index.d.ts +9 -4
- package/dist/index.js +25 -18
- package/dist/nestjs/index.cjs +9 -9
- package/dist/nestjs/index.d.ts +3 -3
- package/dist/nestjs/index.js +9 -9
- package/dist/runtime/index.cjs +18 -11
- package/dist/runtime/index.d.ts +6 -6
- package/dist/runtime/index.js +18 -11
- package/dist/{types-p_fCp6P-.d.ts → types-fQ9-KrBj.d.ts} +1 -1
- package/dist/{types-Cs-46DRu.d.ts → types-yDNEQ603.d.ts} +1 -1
- package/docs/README.md +4 -3
- package/docs/agent-guide.md +15 -7
- package/docs/brownfield-adoption.md +4 -3
- package/docs/configuration.md +34 -11
- package/docs/diagnostics.md +12 -2
- package/docs/package-surface.md +3 -2
- package/docs/product-voice.md +11 -3
- package/package.json +1 -1
- package/schemas/ark.config.schema.json +8 -0
- package/server.json +2 -2
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +5 -2
- package/templates/agent-skills/ark-architect/SKILL.md +2 -0
- package/templates/agent-skills/ark-autopilot/SKILL.md +6 -4
- package/templates/agent-skills/ark-contract/SKILL.md +2 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +2 -0
- package/templates/agent-skills/ark-explain/SKILL.md +2 -0
- package/templates/agent-skills/ark-explore/SKILL.md +4 -2
- package/templates/agent-skills/ark-fix/SKILL.md +2 -0
- package/templates/agent-skills/ark-loop/SKILL.md +2 -0
- package/templates/agent-skills/ark-order/SKILL.md +2 -0
- package/templates/agent-skills/ark-place/SKILL.md +2 -0
- package/templates/agent-skills/ark-runtime/SKILL.md +2 -0
- package/templates/agent-skills/ark-think/SKILL.md +2 -0
- package/templates/agent-skills/ark-upgrade/SKILL.md +20 -7
- package/templates/skills/ark-adopt.md +5 -2
- package/templates/skills/ark-architect.md +2 -0
- package/templates/skills/ark-autopilot.md +6 -4
- package/templates/skills/ark-contract.md +2 -0
- package/templates/skills/ark-coverage.md +2 -0
- package/templates/skills/ark-explain.md +2 -0
- package/templates/skills/ark-explore.md +4 -2
- package/templates/skills/ark-fix.md +2 -0
- package/templates/skills/ark-loop.md +2 -0
- package/templates/skills/ark-order.md +2 -0
- package/templates/skills/ark-place.md +2 -0
- package/templates/skills/ark-runtime.md +2 -0
- package/templates/skills/ark-think.md +2 -0
- package/templates/skills/ark-upgrade.md +20 -7
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UpgradeOutcome — one value for `upgrade --apply`.
|
|
3
|
+
*
|
|
4
|
+
* Sketch (D2). Callers see one object and one exit mapping. Gitignore
|
|
5
|
+
* detection, rule aggregation, and version-note lookup stay in here.
|
|
6
|
+
*
|
|
7
|
+
* classifyManagedAsset({ ..., gitignored }) →
|
|
8
|
+
* { state: 'absent-local', requiresConsent: false } when recorded + gitignored + missing
|
|
9
|
+
*
|
|
10
|
+
* runPostUpgradeVerification(root) →
|
|
11
|
+
* { verdict: 'green'|'red'|'skipped', failing: [{ ruleId, count, sample }], behaviorChanges: string[] }
|
|
12
|
+
*
|
|
13
|
+
* exitCodeFor(outcome) →
|
|
14
|
+
* 0 applied+green (also nothing-to-apply / verification skipped)
|
|
15
|
+
* 3 applied+red
|
|
16
|
+
* 2 blocked
|
|
17
|
+
* 1 error
|
|
18
|
+
*
|
|
19
|
+
* JSON fields on the existing upgrade payload are additive (`outcome`, `postUpgrade`,
|
|
20
|
+
* per-asset `reason` / `nextCommand`, state `absent-local`).
|
|
21
|
+
*/
|
|
22
|
+
import { spawnSync } from 'node:child_process';
|
|
23
|
+
|
|
24
|
+
import { behaviorChangeLines } from './upgrade-behavior-changes.mjs';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {'applied-green'|'applied-skipped'|'applied-red'|'blocked'|'error'|'nothing'|'preview'} UpgradeOutcomeKind
|
|
28
|
+
* @typedef {{ ruleId: string, count: number, sample: string }} FailingRule
|
|
29
|
+
* @typedef {{
|
|
30
|
+
* verdict: 'green'|'red'|'skipped',
|
|
31
|
+
* failing: FailingRule[],
|
|
32
|
+
* behaviorChanges: string[],
|
|
33
|
+
* mode: 'strict-merge'|'skipped',
|
|
34
|
+
* exitCode: number,
|
|
35
|
+
* stderr?: string,
|
|
36
|
+
* }} PostUpgradeVerification
|
|
37
|
+
* @typedef {{
|
|
38
|
+
* kind: UpgradeOutcomeKind,
|
|
39
|
+
* applied: boolean,
|
|
40
|
+
* blocked: boolean,
|
|
41
|
+
* postUpgrade: PostUpgradeVerification|null,
|
|
42
|
+
* error?: string,
|
|
43
|
+
* }} UpgradeOutcome
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
export const ABSENT_LOCAL_REASON =
|
|
47
|
+
'Recorded managed file is missing and gitignored (per-machine file). Recreated without consent.';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} state
|
|
51
|
+
* @returns {string}
|
|
52
|
+
*/
|
|
53
|
+
export function blockedAssetReason(state) {
|
|
54
|
+
if (state === 'missing') {
|
|
55
|
+
return 'Recorded managed file is missing and is not gitignored. Apply will not recreate a deleted file without consent.';
|
|
56
|
+
}
|
|
57
|
+
if (state === 'conflicted') {
|
|
58
|
+
return 'Managed base and local edits both changed. Apply will not overwrite without consent.';
|
|
59
|
+
}
|
|
60
|
+
return 'Apply needs consent before changing this managed file.';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Paths git would ignore. Not a git repo, or git missing → empty set
|
|
65
|
+
* (fail closed toward consent). Global excludes are not consulted.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} root
|
|
68
|
+
* @param {string[]} relativePaths
|
|
69
|
+
* @returns {Set<string>}
|
|
70
|
+
*/
|
|
71
|
+
export function gitignoredPathSet(root, relativePaths) {
|
|
72
|
+
const paths = [...new Set(relativePaths.filter((entry) => typeof entry === 'string' && entry.length > 0))];
|
|
73
|
+
if (paths.length === 0) return new Set();
|
|
74
|
+
let result;
|
|
75
|
+
try {
|
|
76
|
+
result = spawnSync(
|
|
77
|
+
'git',
|
|
78
|
+
['-c', 'core.excludesFile=/dev/null', 'check-ignore', '-z', '--stdin'],
|
|
79
|
+
{
|
|
80
|
+
cwd: root,
|
|
81
|
+
input: `${paths.join('\0')}\0`,
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
timeout: 5000,
|
|
84
|
+
env: {
|
|
85
|
+
...process.env,
|
|
86
|
+
GIT_CONFIG_NOSYSTEM: '1',
|
|
87
|
+
GIT_CONFIG_GLOBAL: '/dev/null',
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
} catch {
|
|
92
|
+
return new Set();
|
|
93
|
+
}
|
|
94
|
+
if (!result || result.error || (result.status !== 0 && result.status !== 1)) return new Set();
|
|
95
|
+
const ignored = new Set();
|
|
96
|
+
for (const entry of String(result.stdout ?? '').split('\0')) {
|
|
97
|
+
if (entry) ignored.add(entry);
|
|
98
|
+
}
|
|
99
|
+
return ignored;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {unknown} check
|
|
104
|
+
* @returns {FailingRule[]}
|
|
105
|
+
*/
|
|
106
|
+
export function aggregateFailingRules(check) {
|
|
107
|
+
const violations = Array.isArray(check?.violations) ? check.violations : [];
|
|
108
|
+
/** @type {Map<string, FailingRule>} */
|
|
109
|
+
const groups = new Map();
|
|
110
|
+
for (const violation of violations) {
|
|
111
|
+
if (!violation || typeof violation !== 'object') continue;
|
|
112
|
+
if (violation.failsStrict === false) continue;
|
|
113
|
+
const ruleId = typeof violation.ruleId === 'string' && violation.ruleId.trim()
|
|
114
|
+
? violation.ruleId.trim()
|
|
115
|
+
: 'UNKNOWN';
|
|
116
|
+
const existing = groups.get(ruleId) ?? { ruleId, count: 0, sample: '' };
|
|
117
|
+
existing.count += 1;
|
|
118
|
+
if (!existing.sample) existing.sample = sampleForViolation(violation, ruleId);
|
|
119
|
+
groups.set(ruleId, existing);
|
|
120
|
+
}
|
|
121
|
+
return [...groups.values()].sort(
|
|
122
|
+
(left, right) => right.count - left.count || left.ruleId.localeCompare(right.ruleId)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {Record<string, unknown>} violation
|
|
128
|
+
* @param {string} ruleId
|
|
129
|
+
*/
|
|
130
|
+
function sampleForViolation(violation, ruleId) {
|
|
131
|
+
const file = typeof violation.file === 'string'
|
|
132
|
+
? violation.file
|
|
133
|
+
: typeof violation.path === 'string'
|
|
134
|
+
? violation.path
|
|
135
|
+
: '';
|
|
136
|
+
const line = Number.isInteger(violation.line) ? `:${violation.line}` : '';
|
|
137
|
+
const where = file ? `${file}${line}` : '';
|
|
138
|
+
const message = typeof violation.message === 'string' ? violation.message.trim() : '';
|
|
139
|
+
const sample = [where, message].filter(Boolean).join(' — ') || ruleId;
|
|
140
|
+
return sample.length > 180 ? `${sample.slice(0, 177)}...` : sample;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} stdout
|
|
145
|
+
* @returns {Record<string, unknown>|null}
|
|
146
|
+
*/
|
|
147
|
+
export function parseCheckStdout(stdout) {
|
|
148
|
+
const text = typeof stdout === 'string' ? stdout.trim() : '';
|
|
149
|
+
if (!text) return null;
|
|
150
|
+
try {
|
|
151
|
+
const parsed = JSON.parse(text);
|
|
152
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
153
|
+
} catch {
|
|
154
|
+
const start = text.indexOf('{');
|
|
155
|
+
const end = text.lastIndexOf('}');
|
|
156
|
+
if (start === -1 || end <= start) return null;
|
|
157
|
+
try {
|
|
158
|
+
const parsed = JSON.parse(text.slice(start, end + 1));
|
|
159
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {string} root
|
|
168
|
+
* @param {string} arkCheck
|
|
169
|
+
* @returns {{ exitCode: number, stdout: string, stderr: string }}
|
|
170
|
+
*/
|
|
171
|
+
function spawnArchitectureCheck(root, arkCheck) {
|
|
172
|
+
if (typeof arkCheck !== 'string' || !arkCheck) {
|
|
173
|
+
return { exitCode: 1, stdout: '', stderr: 'architecture check binary is missing' };
|
|
174
|
+
}
|
|
175
|
+
const result = spawnSync(
|
|
176
|
+
process.execPath,
|
|
177
|
+
[arkCheck, '--root', root, '--config', 'ark.config.json', '--strict-merge', '--json'],
|
|
178
|
+
{
|
|
179
|
+
cwd: root,
|
|
180
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
181
|
+
encoding: 'utf8',
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
return {
|
|
185
|
+
exitCode: result.status ?? 1,
|
|
186
|
+
stdout: result.stdout ?? '',
|
|
187
|
+
stderr: result.stderr ?? '',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Structured post-upgrade verification. Reuses check JSON (rule ids), and
|
|
193
|
+
* attaches behavior-change lines from the shipped per-version table.
|
|
194
|
+
*
|
|
195
|
+
* @param {string} root
|
|
196
|
+
* @param {{
|
|
197
|
+
* strict?: boolean,
|
|
198
|
+
* arkCheck?: string,
|
|
199
|
+
* packageVersion?: string,
|
|
200
|
+
* checkResult?: { exitCode?: number, status?: number, stdout?: string, stderr?: string },
|
|
201
|
+
* }} [options]
|
|
202
|
+
* @returns {PostUpgradeVerification}
|
|
203
|
+
*/
|
|
204
|
+
export function runPostUpgradeVerification(root, options = {}) {
|
|
205
|
+
const behaviorChanges = behaviorChangeLines();
|
|
206
|
+
if (options.strict === false) {
|
|
207
|
+
return {
|
|
208
|
+
verdict: 'skipped',
|
|
209
|
+
failing: [],
|
|
210
|
+
behaviorChanges,
|
|
211
|
+
mode: 'skipped',
|
|
212
|
+
exitCode: 0,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const raw = options.checkResult ?? spawnArchitectureCheck(root, options.arkCheck);
|
|
216
|
+
const parsed = parseCheckStdout(raw.stdout ?? '');
|
|
217
|
+
const failing = aggregateFailingRules(parsed);
|
|
218
|
+
const exitCode = raw.exitCode ?? raw.status ?? 1;
|
|
219
|
+
const red = exitCode !== 0 || parsed?.ok === false || parsed?.valid === false;
|
|
220
|
+
if (red && failing.length === 0) {
|
|
221
|
+
const sampleSource = String(raw.stderr || 'architecture check failed').trim() || 'architecture check failed';
|
|
222
|
+
failing.push({
|
|
223
|
+
ruleId: 'ARCHITECTURE_CHECK',
|
|
224
|
+
count: 1,
|
|
225
|
+
sample: sampleSource.length > 180 ? `${sampleSource.slice(0, 177)}...` : sampleSource,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const stderr = typeof raw.stderr === 'string' && raw.stderr.trim() ? raw.stderr.trim() : undefined;
|
|
229
|
+
return {
|
|
230
|
+
verdict: red ? 'red' : 'green',
|
|
231
|
+
failing: red ? failing : [],
|
|
232
|
+
behaviorChanges,
|
|
233
|
+
mode: 'strict-merge',
|
|
234
|
+
exitCode: red ? (exitCode || 1) : 0,
|
|
235
|
+
...(stderr ? { stderr } : {}),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @param {{
|
|
241
|
+
* applied?: boolean,
|
|
242
|
+
* blocked?: boolean,
|
|
243
|
+
* nothingToApply?: boolean,
|
|
244
|
+
* postUpgrade?: PostUpgradeVerification|null,
|
|
245
|
+
* error?: unknown,
|
|
246
|
+
* }} input
|
|
247
|
+
* @returns {UpgradeOutcome}
|
|
248
|
+
*/
|
|
249
|
+
export function upgradeOutcome(input) {
|
|
250
|
+
if (input.error != null && input.error !== false) {
|
|
251
|
+
const message = input.error instanceof Error ? input.error.message : String(input.error);
|
|
252
|
+
return { kind: 'error', applied: false, blocked: false, postUpgrade: null, error: message };
|
|
253
|
+
}
|
|
254
|
+
if (input.blocked) {
|
|
255
|
+
return { kind: 'blocked', applied: false, blocked: true, postUpgrade: null };
|
|
256
|
+
}
|
|
257
|
+
if (input.nothingToApply && !input.applied) {
|
|
258
|
+
return { kind: 'nothing', applied: false, blocked: false, postUpgrade: null };
|
|
259
|
+
}
|
|
260
|
+
const postUpgrade = input.postUpgrade ?? null;
|
|
261
|
+
if (postUpgrade?.verdict === 'red') {
|
|
262
|
+
return { kind: 'applied-red', applied: true, blocked: false, postUpgrade };
|
|
263
|
+
}
|
|
264
|
+
if (postUpgrade?.verdict === 'skipped') {
|
|
265
|
+
return { kind: 'applied-skipped', applied: Boolean(input.applied), blocked: false, postUpgrade };
|
|
266
|
+
}
|
|
267
|
+
return { kind: 'applied-green', applied: Boolean(input.applied), blocked: false, postUpgrade };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @param {UpgradeOutcome|null|undefined} outcome
|
|
272
|
+
* @returns {0|1|2|3}
|
|
273
|
+
*/
|
|
274
|
+
export function exitCodeFor(outcome) {
|
|
275
|
+
switch (outcome?.kind) {
|
|
276
|
+
case 'applied-green':
|
|
277
|
+
case 'applied-skipped':
|
|
278
|
+
case 'nothing':
|
|
279
|
+
case 'preview':
|
|
280
|
+
return 0;
|
|
281
|
+
case 'applied-red':
|
|
282
|
+
return 3;
|
|
283
|
+
case 'blocked':
|
|
284
|
+
return 2;
|
|
285
|
+
case 'error':
|
|
286
|
+
return 1;
|
|
287
|
+
default:
|
|
288
|
+
return 1;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @param {{ mode?: string, exitCode?: number, verdict?: string }} [verification]
|
|
294
|
+
* @returns {boolean|null}
|
|
295
|
+
*/
|
|
296
|
+
export function architectureVerificationOk(verification) {
|
|
297
|
+
if (!verification || verification.mode === 'skipped' || verification.verdict === 'skipped') return null;
|
|
298
|
+
if (verification.verdict === 'green') return true;
|
|
299
|
+
if (verification.verdict === 'red') return false;
|
|
300
|
+
if (verification.exitCode === 0) return true;
|
|
301
|
+
if (typeof verification.exitCode === 'number') return false;
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @param {{ mode?: string, exitCode?: number, verdict?: string, failing?: FailingRule[] }} [verification]
|
|
307
|
+
* @returns {string}
|
|
308
|
+
*/
|
|
309
|
+
export function architectureVerificationDetail(verification) {
|
|
310
|
+
if (!verification || verification.mode === 'skipped' || verification.verdict === 'skipped') {
|
|
311
|
+
return 'Strict architecture verification was skipped (--no-strict).';
|
|
312
|
+
}
|
|
313
|
+
const code = verification.exitCode;
|
|
314
|
+
if (architectureVerificationOk(verification) === true) {
|
|
315
|
+
return 'Strict-merge architecture verification passed.';
|
|
316
|
+
}
|
|
317
|
+
const failing = Array.isArray(verification.failing) ? verification.failing : [];
|
|
318
|
+
const rules = failing.map((row) => `${row.ruleId} ×${row.count}`).join(', ');
|
|
319
|
+
const head = `Architecture verification exit ${code ?? 'unknown'}.`;
|
|
320
|
+
if (!rules) return head;
|
|
321
|
+
return `${head} Failing rules: ${rules}. Read behaviorChanges before editing code.`;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @param {{ assets?: Array<{ blocked?: boolean, path?: string, state?: string, reason?: string, nextCommand?: string }>, blocked?: boolean, nextCommand?: string }} plan
|
|
326
|
+
* @param {{ refused?: boolean }} [options]
|
|
327
|
+
* @returns {string[]}
|
|
328
|
+
*/
|
|
329
|
+
export function formatBlockedAssets(plan, options = {}) {
|
|
330
|
+
const blocked = (plan?.assets ?? []).filter((asset) => asset?.blocked);
|
|
331
|
+
if (blocked.length === 0) return [];
|
|
332
|
+
const lines = [options.refused ? 'Apply refused.' : 'Blocked until you consent:'];
|
|
333
|
+
for (const asset of blocked) {
|
|
334
|
+
const reason = asset.reason || blockedAssetReason(asset.state ?? '');
|
|
335
|
+
lines.push(` ${asset.path} — ${reason}`);
|
|
336
|
+
}
|
|
337
|
+
const next = blocked.find((asset) => asset.nextCommand)?.nextCommand ?? plan?.nextCommand;
|
|
338
|
+
if (next) lines.push(`Next: ${next}`);
|
|
339
|
+
return lines;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @param {PostUpgradeVerification|null|undefined} postUpgrade
|
|
344
|
+
* @returns {string[]}
|
|
345
|
+
*/
|
|
346
|
+
export function formatPostUpgradeHuman(postUpgrade) {
|
|
347
|
+
if (!postUpgrade) return [];
|
|
348
|
+
const lines = [`Post-upgrade verification: ${postUpgrade.verdict}.`];
|
|
349
|
+
if (postUpgrade.verdict !== 'red') return lines;
|
|
350
|
+
lines.push('Failing rules:');
|
|
351
|
+
const failing = postUpgrade.failing ?? [];
|
|
352
|
+
if (failing.length === 0) lines.push(' (check returned red without a rule id)');
|
|
353
|
+
for (const row of failing) {
|
|
354
|
+
lines.push(` ${row.ruleId} ×${row.count} — ${row.sample}`);
|
|
355
|
+
}
|
|
356
|
+
lines.push('Read behaviorChanges before editing code.');
|
|
357
|
+
for (const note of postUpgrade.behaviorChanges ?? []) lines.push(` ${note}`);
|
|
358
|
+
return lines;
|
|
359
|
+
}
|
package/bin/lib/violations.mjs
CHANGED
|
@@ -97,6 +97,115 @@ export function printWarning(warning) {
|
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/** Advisory the engine emits once per shared-root → slice edge. Humans see a group. */
|
|
101
|
+
export const SHARED_IMPORTS_SLICE_RULE_ID = 'SHARED_IMPORTS_SLICE';
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Where the full per-edge list lives. Human check output names this on every
|
|
105
|
+
* grouped line. `--json` is the machine list; `--doctor` prints every edge.
|
|
106
|
+
*/
|
|
107
|
+
export const SHARED_IMPORTS_SLICE_FULL_LIST =
|
|
108
|
+
'Full list: ark-check --json or ark-check --doctor';
|
|
109
|
+
|
|
110
|
+
const SHARED_IMPORTS_SLICE_EXAMPLE_LIMIT = 3;
|
|
111
|
+
|
|
112
|
+
function formatAdvisoryCount(count) {
|
|
113
|
+
return String(count).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function layerLabel(value) {
|
|
117
|
+
return typeof value === 'string' && value.trim() ? value.trim() : '?';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Group key: one fact per rule and layer edge. */
|
|
121
|
+
export function sharedImportsSliceGroupKey(warning) {
|
|
122
|
+
return [
|
|
123
|
+
typeof warning?.ruleId === 'string' ? warning.ruleId : SHARED_IMPORTS_SLICE_RULE_ID,
|
|
124
|
+
layerLabel(warning?.fromLayer),
|
|
125
|
+
layerLabel(warning?.toLayer),
|
|
126
|
+
].join('\0');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function formatSharedImportsSliceExample(warning) {
|
|
130
|
+
const file = typeof warning?.file === 'string' && warning.file.trim() ? warning.file.trim() : 'unknown';
|
|
131
|
+
const line = Number.isInteger(warning?.line) && warning.line > 0 ? warning.line : 1;
|
|
132
|
+
const slice =
|
|
133
|
+
typeof warning?.toSlice === 'string' && warning.toSlice.trim() ? warning.toSlice.trim() : 'slice';
|
|
134
|
+
const target =
|
|
135
|
+
typeof warning?.target === 'string' && warning.target.trim() ? ` (${warning.target.trim()})` : '';
|
|
136
|
+
return `${file}:${line} → ${slice}${target}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** One human line for a (ruleId, fromLayer → toLayer) group. Count plus top 3 edges. */
|
|
140
|
+
export function formatSharedImportsSliceSummary(group) {
|
|
141
|
+
const sample = group[0] ?? {};
|
|
142
|
+
const ruleId =
|
|
143
|
+
typeof sample.ruleId === 'string' ? sample.ruleId : SHARED_IMPORTS_SLICE_RULE_ID;
|
|
144
|
+
const count = group.length;
|
|
145
|
+
const noun = count === 1 ? 'bridge' : 'bridges';
|
|
146
|
+
const examples = group
|
|
147
|
+
.slice(0, SHARED_IMPORTS_SLICE_EXAMPLE_LIMIT)
|
|
148
|
+
.map(formatSharedImportsSliceExample)
|
|
149
|
+
.join('; ');
|
|
150
|
+
return (
|
|
151
|
+
`warning ${ruleId} ${layerLabel(sample.fromLayer)} → ${layerLabel(sample.toLayer)}: ` +
|
|
152
|
+
`${formatAdvisoryCount(count)} shared-root → slice ${noun} (e.g. ${examples}). ` +
|
|
153
|
+
`The wall is direct-only. ${SHARED_IMPORTS_SLICE_FULL_LIST}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Human check lines. SHARED_IMPORTS_SLICE collapses to one line per group.
|
|
159
|
+
* Every other warning stays one line. Does not mutate `warnings` — `--json`
|
|
160
|
+
* and doctor still walk the per-edge array.
|
|
161
|
+
*/
|
|
162
|
+
export function humanWarningLines(warnings) {
|
|
163
|
+
const groups = new Map();
|
|
164
|
+
const slots = [];
|
|
165
|
+
for (const warning of warnings ?? []) {
|
|
166
|
+
if (warning?.ruleId !== SHARED_IMPORTS_SLICE_RULE_ID) {
|
|
167
|
+
slots.push({ kind: 'line', line: formatWarningLine(warning) });
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const key = sharedImportsSliceGroupKey(warning);
|
|
171
|
+
let group = groups.get(key);
|
|
172
|
+
if (!group) {
|
|
173
|
+
group = [];
|
|
174
|
+
groups.set(key, group);
|
|
175
|
+
slots.push({ kind: 'group', key });
|
|
176
|
+
}
|
|
177
|
+
group.push(warning);
|
|
178
|
+
}
|
|
179
|
+
return slots.map((slot) =>
|
|
180
|
+
slot.kind === 'line' ? slot.line : formatSharedImportsSliceSummary(groups.get(slot.key))
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function printColoredWarningLine(line) {
|
|
185
|
+
const painted = line.startsWith('warning ')
|
|
186
|
+
? `${color.yellow('warning')}${line.slice('warning'.length)}`
|
|
187
|
+
: line;
|
|
188
|
+
console.error(painted);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** ark-check human renderer. Grouping stops here; the warnings array is unchanged. */
|
|
192
|
+
export function printHumanWarnings(warnings) {
|
|
193
|
+
for (const line of humanWarningLines(warnings)) {
|
|
194
|
+
printColoredWarningLine(line);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Doctor human list: every shared-root → slice edge, not the grouped summary. */
|
|
199
|
+
export function printSharedImportsSliceBridgeList(warnings) {
|
|
200
|
+
const lines = (warnings ?? [])
|
|
201
|
+
.filter((warning) => warning?.ruleId === SHARED_IMPORTS_SLICE_RULE_ID)
|
|
202
|
+
.map((warning) => formatWarningLine(warning));
|
|
203
|
+
if (lines.length === 0) return;
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(`Shared-root → slice bridges (${formatAdvisoryCount(lines.length)}):`);
|
|
206
|
+
for (const line of lines) console.log(line);
|
|
207
|
+
}
|
|
208
|
+
|
|
100
209
|
/** Non-blocking type-only placement debt: exit stays 0; do not paint ✖. */
|
|
101
210
|
export function isNonBlockingPlacementDebt(violation) {
|
|
102
211
|
return violation?.failsStrict === false;
|
|
@@ -49,6 +49,8 @@ type ArkConfigLayer = {
|
|
|
49
49
|
/** Alias of reserved — empty pattern matches are allowed. */
|
|
50
50
|
allowEmpty?: boolean;
|
|
51
51
|
};
|
|
52
|
+
/** How a starred `sliceFolders` prefix is named. Absent equals `path`. */
|
|
53
|
+
type ArkConfigSliceIdentity = 'path' | 'stars';
|
|
52
54
|
type ArkConfigRule = {
|
|
53
55
|
from: string;
|
|
54
56
|
to: string;
|
|
@@ -56,6 +58,11 @@ type ArkConfigRule = {
|
|
|
56
58
|
message?: string;
|
|
57
59
|
peerIsolation?: boolean;
|
|
58
60
|
sliceFolders?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* How a starred `sliceFolders` prefix is named.
|
|
63
|
+
* Absent and `path` keep today's ids. `stars` is the last literal plus the star bindings.
|
|
64
|
+
*/
|
|
65
|
+
sliceIdentity?: ArkConfigSliceIdentity;
|
|
59
66
|
/** Roots the repo declares shared on purpose — evidence, not unclassifiable. */
|
|
60
67
|
sharedRoots?: string[];
|
|
61
68
|
/** Directed slice→slice edges the repo declares on purpose. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as CreateArchitectureProfileOptions, b as ArchitectureProfile, d as ArkCheckConfig, C as CreateArchitectureProfileFromArkConfigOptions, f as CreateElevenLayerArkConfigOptions, i as Policy, j as IntentCreator, I as IntentName } from './types-
|
|
2
|
-
import { A as ArkConfig, c as ArkConfigLoadResult } from './configTypes-
|
|
1
|
+
import { e as CreateArchitectureProfileOptions, b as ArchitectureProfile, d as ArkCheckConfig, C as CreateArchitectureProfileFromArkConfigOptions, f as CreateElevenLayerArkConfigOptions, i as Policy, j as IntentCreator, I as IntentName } from './types-fQ9-KrBj.js';
|
|
2
|
+
import { A as ArkConfig, c as ArkConfigLoadResult } from './configTypes-CTELo87-.js';
|
|
3
3
|
|
|
4
4
|
/** Versioned public result contract types + JSON Schema (adapter envelope). */
|
|
5
5
|
/**
|
|
@@ -392,7 +392,7 @@ declare function createAdapterResult(input: {
|
|
|
392
392
|
}): CurrentAdapterResult;
|
|
393
393
|
|
|
394
394
|
/** ArkGate library version — single source of truth. */
|
|
395
|
-
declare const version = "4.8.
|
|
395
|
+
declare const version = "4.8.21";
|
|
396
396
|
|
|
397
397
|
/**
|
|
398
398
|
* AI Code Gate (basic).
|
|
@@ -1722,10 +1722,60 @@ type EffectiveArkRules = {
|
|
|
1722
1722
|
/**
|
|
1723
1723
|
* Pure invariant coverage evidence (ADR 0014 / AR09–AR10).
|
|
1724
1724
|
*
|
|
1725
|
-
* Mines test titles and symbol
|
|
1725
|
+
* Mines test titles and symbol declarations against the Effective ArkRules catalog.
|
|
1726
|
+
* `classifyCoverage` returns one verdict; `countsAsCoverage` is the policy;
|
|
1727
|
+
* `describeCoverage` is the sentence. A bare mention is never coverage.
|
|
1726
1728
|
* No filesystem — Tooling supplies file contents and test globs.
|
|
1727
1729
|
*/
|
|
1728
1730
|
|
|
1731
|
+
/**
|
|
1732
|
+
* How a `coverage.symbol` identifier is declared. `type`, `interface`, and
|
|
1733
|
+
* `enum` are declarations — the same witness as function, class, const, and
|
|
1734
|
+
* method.
|
|
1735
|
+
*/
|
|
1736
|
+
type DeclarationShape = 'function' | 'class' | 'const' | 'method' | 'type' | 'interface' | 'enum';
|
|
1737
|
+
/** Where a bare mention of an id or symbol sat. Never coverage. */
|
|
1738
|
+
type MentionContext = 'test-body' | 'comment' | 'string' | 'import';
|
|
1739
|
+
/**
|
|
1740
|
+
* One coverage verdict. Best evidence wins: test-title, then declaration,
|
|
1741
|
+
* then mention-only, then none. Regexes, the test-file vs source split, and
|
|
1742
|
+
* `Aggregate.method` lookup stay behind this value.
|
|
1743
|
+
*/
|
|
1744
|
+
type CoverageEvidence = {
|
|
1745
|
+
kind: 'test-title';
|
|
1746
|
+
file: string;
|
|
1747
|
+
title: string;
|
|
1748
|
+
} | {
|
|
1749
|
+
kind: 'declaration';
|
|
1750
|
+
file: string;
|
|
1751
|
+
shape: DeclarationShape;
|
|
1752
|
+
} | {
|
|
1753
|
+
kind: 'mention-only';
|
|
1754
|
+
file: string;
|
|
1755
|
+
context: MentionContext;
|
|
1756
|
+
} | {
|
|
1757
|
+
kind: 'none';
|
|
1758
|
+
};
|
|
1759
|
+
/** Invariant fields the classifier reads. A full catalog entry is assignable. */
|
|
1760
|
+
type CoverageInvariant = {
|
|
1761
|
+
id: string;
|
|
1762
|
+
coverage?: {
|
|
1763
|
+
test?: boolean;
|
|
1764
|
+
symbol?: string;
|
|
1765
|
+
} | null;
|
|
1766
|
+
};
|
|
1767
|
+
/** File set the classifier reads. Tooling has already loaded the contents. */
|
|
1768
|
+
type CoverageFiles = {
|
|
1769
|
+
/** Project-relative path → file contents (tests and sources). */
|
|
1770
|
+
fileContents: Readonly<Record<string, string>>;
|
|
1771
|
+
/** Paths already classified as tests. */
|
|
1772
|
+
testFiles?: readonly string[];
|
|
1773
|
+
/**
|
|
1774
|
+
* Declared runner roots. A test title inside a root beats one outside it.
|
|
1775
|
+
* The outside-roots finding stays a separate verdict.
|
|
1776
|
+
*/
|
|
1777
|
+
coverageRoots?: readonly string[];
|
|
1778
|
+
};
|
|
1729
1779
|
type InvariantCoverageEvidence = {
|
|
1730
1780
|
invariantId: string;
|
|
1731
1781
|
layer: string;
|
|
@@ -1744,6 +1794,11 @@ type InvariantCoverageEvidence = {
|
|
|
1744
1794
|
* declaration text, not a passing suite.
|
|
1745
1795
|
*/
|
|
1746
1796
|
symbolEvidenceFile?: string;
|
|
1797
|
+
/**
|
|
1798
|
+
* Declaration shape when `evidence` includes `symbol`. Additive: readers that
|
|
1799
|
+
* only know `test-title` | `symbol` ignore it.
|
|
1800
|
+
*/
|
|
1801
|
+
shape?: DeclarationShape;
|
|
1747
1802
|
/**
|
|
1748
1803
|
* The only covering test found sits outside `coverage.coverageRoots` — the
|
|
1749
1804
|
* places the project declares its runner executes. ArkGate never runs tests,
|
|
@@ -1841,6 +1896,19 @@ type InvariantCoverageStats = {
|
|
|
1841
1896
|
outOfRoot: number;
|
|
1842
1897
|
};
|
|
1843
1898
|
};
|
|
1899
|
+
/**
|
|
1900
|
+
* Best coverage evidence for `invariant` in `files`.
|
|
1901
|
+
* test-title beats a declaration; a declaration beats a bare mention; a bare
|
|
1902
|
+
* mention beats silence. Callers do not re-scan to explain the verdict.
|
|
1903
|
+
*/
|
|
1904
|
+
declare function classifyCoverage(invariant: CoverageInvariant, files: CoverageFiles): CoverageEvidence;
|
|
1905
|
+
/**
|
|
1906
|
+
* Policy: a test title or any declaration counts, including type, interface,
|
|
1907
|
+
* and enum. A mention-only verdict never counts. `none` does not count.
|
|
1908
|
+
*/
|
|
1909
|
+
declare function countsAsCoverage(ev: CoverageEvidence): boolean;
|
|
1910
|
+
/** Sentence for the verdict. `INVARIANT_UNCOVERED` prints this; it does not re-derive it. */
|
|
1911
|
+
declare function describeCoverage(invariant: CoverageInvariant, ev: CoverageEvidence): string;
|
|
1844
1912
|
declare function evaluateInvariantCoverage(input: EvaluateInvariantCoverageInput): {
|
|
1845
1913
|
coverage: InvariantCoverageEvidence[];
|
|
1846
1914
|
violations: InvariantCoverageViolation[];
|
|
@@ -2490,4 +2558,4 @@ declare function catalogFixForRuleId(ruleId: string | null | undefined): string
|
|
|
2490
2558
|
*/
|
|
2491
2559
|
declare function catalogWhyForRuleId(ruleId: string | null | undefined): string | undefined;
|
|
2492
2560
|
|
|
2493
|
-
export { type ArchitectureChangeMapFile as $, type AdapterViolationInput as A, type AdapterResult as B, type AdapterSeverity as C, type AnalysisCapabilityUse as D, type EffectiveArkRules as E, type AnalysisCompilerOptions as F, type AnalysisCompleteness as G, type AnalysisContract as H, type AnalysisEvidence as I, type AnalysisFile as J, type AnalysisFileChange as K, type AnalysisFileInput as L, type AnalysisImportEdge as M, type AnalysisIr as N, type AnalysisMode as O, type AnalysisResult as P, type AnalysisViolation as Q, type ResolvedArkRunKernelCallKind as R, type AnalyzeArchitectureConvergenceInput as S, type AnalyzeChangeInput as T, type AnalyzePolicyDeltaInput as U, type AnalyzeProjectInput as V, type AnalyzeResolvedProjectInput as W, type ArchitectureActualChange as X, type ArchitectureChangeMap as Y, type ArchitectureChangeMapContract as Z, type ArchitectureChangeMapDependency as _, type ArkRulesFile as a, type
|
|
2561
|
+
export { type ArchitectureChangeMapFile as $, type AdapterViolationInput as A, type AdapterResult as B, type AdapterSeverity as C, type AnalysisCapabilityUse as D, type EffectiveArkRules as E, type AnalysisCompilerOptions as F, type AnalysisCompleteness as G, type AnalysisContract as H, type AnalysisEvidence as I, type AnalysisFile as J, type AnalysisFileChange as K, type AnalysisFileInput as L, type AnalysisImportEdge as M, type AnalysisIr as N, type AnalysisMode as O, type AnalysisResult as P, type AnalysisViolation as Q, type ResolvedArkRunKernelCallKind as R, type AnalyzeArchitectureConvergenceInput as S, type AnalyzeChangeInput as T, type AnalyzePolicyDeltaInput as U, type AnalyzeProjectInput as V, type AnalyzeResolvedProjectInput as W, type ArchitectureActualChange as X, type ArchitectureChangeMap as Y, type ArchitectureChangeMapContract as Z, type ArchitectureChangeMapDependency as _, type ArkRulesFile as a, type ResolvedPublishFact as a$, type ArchitectureChangeOperation as a0, type ArchitectureConvergenceClassification as a1, type ArchitectureConvergenceFinding as a2, type ArchitectureConvergenceResult as a3, type ArchitectureDependency as a4, type ArchitectureEngineEdge as a5, type ArchitectureEngineResult as a6, type ArchitectureEngineViolation as a7, type ArkDesignDeltaResult as a8, type ArkEnforcementHost as a9, type ForbiddenCapabilityUse as aA, type InvariantCoverageEvidence as aB, type MentionContext as aC, POLICY_DELTA_SCHEMA_VERSION as aD, type PolicyDelta as aE, type PolicyDeltaAcknowledgement as aF, type PolicyDeltaAnalysis as aG, type PolicyDeltaClassification as aH, type PolicyDeltaFinding as aI, type PreflightResolvedChangeInput as aJ, type PreparedChangeFile as aK, RESOLVED_CANDIDATE_FACTS_SCHEMA as aL, RESOLVED_CANDIDATE_FACTS_SCHEMA_VERSION as aM, type ResolvedAmbientFact as aN, type ResolvedAnalysisFile as aO, type ResolvedAnalysisIr as aP, type ResolvedAnalysisResult as aQ, type ResolvedCandidateFacts as aR, type ResolvedCandidateFactsInput as aS, type ResolvedCapability as aT, type ResolvedCapabilityFact as aU, type ResolvedChangePreflightResult as aV, type ResolvedDependencyKind as aW, type ResolvedDependencyState as aX, type ResolvedFactsCompleteness as aY, type ResolvedFileFact as aZ, type ResolvedIntentReferenceFact as a_, type ArkEnforcementState as aa, type ArkRuleSensorViolation as ab, type ChangePreflightResult as ac, type ClassShapeFact as ad, type CollectAnalysisConfigWarningsInput as ae, type CoverageEvidence as af, type CoverageFiles as ag, type CoverageInvariant as ah, DIAGNOSTIC_CATALOG as ai, DIAGNOSTIC_CATALOG_SCHEMA_VERSION as aj, DIAGNOSTIC_DOCS_RELATIVE_PATH as ak, DIAGNOSTIC_RULE_IDS as al, type DeclarationShape as am, type DesignDeltaChange as an, type DesignDeltaEnforcementScope as ao, type DesignDeltaIdentity as ap, type DesignSmellEvidence as aq, type DesignSmellFinding as ar, type DesignSmellId as as, type DiagnosticCatalogEntry as at, type DiagnosticCategory as au, type EnforcementBoundaryState as av, type EnforcementEvidence as aw, type EnforcementEvidenceField as ax, type EnforcementVerification as ay, type EvaluateArchitectureGraphInput as az, type ResolvedArkRunDeclarationFact as b, type ResolvedSafetyFact as b0, type ResolvedSafetyKind as b1, type ResolvedSafetyReport as b2, type SemanticDependency as b3, type SemanticDependencyKind as b4, analyzeArchitectureConvergence as b5, analyzeChange as b6, analyzePolicyDelta as b7, analyzeProject as b8, analyzeResolvedProject as b9, explainViolation as bA, extractClassShapesFromSource as bB, extractSemanticDependencies as bC, getDiagnosticCatalogEntry as bD, isCataloguedOrArkRuleFamily as bE, isKnownDiagnosticCode as bF, loadContract as bG, loadResolvedCandidateFacts as bH, policyDeltaAcknowledgementMatches as bI, preflightChange as bJ, preflightResolvedChange as bK, resolvedFactsEvidenceRequirementsHash as bL, serializeDiagnosticCatalog as bM, stableSerialize as bN, toAdapterDiagnostic as bO, version as bP, buildArkRuleFileHints as ba, canPromoteInvariant as bb, catalogFixForRuleId as bc, catalogWhyForRuleId as bd, classifyArkPolicyDelta as be, classifyCoverage as bf, collectAnalysisConfigWarnings as bg, collectEmptyAppliesToFindings as bh, collectForbiddenCapabilityUses as bi, countsAsCoverage as bj, createAICodeGate as bk, createAdapterResult as bl, createArchitectureProfile as bm, createArchitectureProfileFromArkConfig as bn, createElevenLayerArkConfig as bo, createResolvedCandidateFacts as bp, deriveArkRuleFileHints as bq, describeCoverage as br, detectArchitectureCycles as bs, deterministicHash as bt, diagnosticDocsFragment as bu, diagnosticDocsPath as bv, elevenLayerProfile as bw, evaluateArchitectureGraph as bx, evaluateArkRuleSensors as by, evaluateInvariantCoverage as bz, type ResolvedArkRunKernelCallFact as c, type ResolvedArkRunManagedNewFact as d, type ResolvedDependencyFact as e, type ResolvedArkRunCompositionRootHitFact as f, type ResolvedFactsReason as g, type ResolvedArkOrderPlaneCallFact as h, type ResolvedArkOrderGenericUpdateFact as i, type ResolvedArkOrderRootHitFact as j, type ResolvedArkOrderXiFieldWriteFact as k, type ResolvedArkOrderIngestWriteFact as l, ADAPTER_DIAGNOSTIC_DOCS_RELATIVE_PATH as m, type AICodeGate as n, type AICodeGateContext as o, type AICodeGateOptions as p, type AICodeGateResult as q, type AICodeGateViolation as r, type AIGateExtension as s, ANALYSIS_IR_SCHEMA_VERSION as t, ARK_ANALYSIS_RESULT_SCHEMA as u, ARK_ANALYSIS_RESULT_SCHEMA_VERSION as v, ARK_DESIGN_DELTA_SCHEMA_VERSION as w, ARK_ENFORCEMENT_STATE_SCHEMA_VERSION as x, type AdapterCompletenessReason as y, type AdapterDiagnostic as z };
|