arkgate 4.8.22 → 4.8.24
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 +91 -0
- package/README.md +7 -5
- package/bin/ark-check-runtime.mjs +27 -78
- package/bin/ark-dashboard.mjs +56 -53
- package/bin/ark-layer-match.mjs +1117 -38
- package/bin/ark-mcp-runtime.mjs +412 -138
- package/bin/ark-mcp.mjs +68 -4
- package/bin/ark-shared.mjs +39 -0
- package/bin/ark.mjs +65 -97
- package/bin/lib/adapter-contract-types.mjs +5 -0
- package/bin/lib/adapter-contract.mjs +15 -0
- package/bin/lib/agent-projection-command.mjs +5 -1
- package/bin/lib/analysis-engine.mjs +15 -11
- package/bin/lib/architecture-scan.mjs +50 -6
- package/bin/lib/ark-order-doctor.mjs +1 -1
- package/bin/lib/ark-order-facts.mjs +410 -15
- package/bin/lib/ark-order-invariants.mjs +51 -9
- package/bin/lib/ark-order-sensors.mjs +28 -101
- package/bin/lib/ark-order-types.mjs +2 -0
- package/bin/lib/ark-run-doctor.mjs +14 -0
- package/bin/lib/ark-run-facts.mjs +434 -11
- package/bin/lib/ark-run-sensors.mjs +5 -3
- package/bin/lib/arkgate-pins.mjs +91 -0
- package/bin/lib/arkrules-sensors.mjs +50 -249
- package/bin/lib/check-args.mjs +23 -1
- package/bin/lib/ci-and-commands.mjs +16 -6
- package/bin/lib/class-source-scan.mjs +479 -0
- package/bin/lib/codex-home.mjs +4 -2
- package/bin/lib/config-contract-slices.mjs +701 -0
- package/bin/lib/config-contract.mjs +5 -2
- package/bin/lib/config-warnings.mjs +32 -0
- package/bin/lib/dashboard-cli.mjs +62 -0
- package/bin/lib/design-delta.mjs +1 -1
- package/bin/lib/diagnostic-catalog.mjs +45 -6
- package/bin/lib/doctor-advisories.mjs +84 -1
- package/bin/lib/doctor-next-actions.mjs +17 -2
- package/bin/lib/doctor-plan.mjs +7 -9
- package/bin/lib/effective-contract-load.mjs +121 -59
- package/bin/lib/enforcement-honesty.mjs +22 -0
- package/bin/lib/enforcement-profiles.mjs +40 -4
- package/bin/lib/first-run-help.mjs +3 -2
- package/bin/lib/flat-parent-importers.mjs +137 -0
- package/bin/lib/flat-parent-pilot.mjs +192 -0
- package/bin/lib/gate-files.mjs +29 -2
- package/bin/lib/git-change-scope.mjs +109 -0
- package/bin/lib/github-enforcement.mjs +1 -1
- package/bin/lib/hook-templates.mjs +18 -16
- package/bin/lib/host-support-matrix.mjs +3 -1
- package/bin/lib/html-report-advisories.mjs +2 -0
- package/bin/lib/html-report-depth.mjs +3 -1
- package/bin/lib/import-resolve.mjs +13 -1
- package/bin/lib/install-migrate.mjs +50 -73
- package/bin/lib/invariant-coverage.mjs +59 -11
- package/bin/lib/mcp-adoption.mjs +9 -1
- package/bin/lib/mcp-hook-payload.mjs +401 -61
- package/bin/lib/package-manager.mjs +59 -1
- package/bin/lib/passthrough-commands.mjs +83 -0
- package/bin/lib/persistence-write-hint.mjs +81 -0
- package/bin/lib/physical-cohesion.mjs +16 -18
- package/bin/lib/pilot-loop.mjs +21 -8
- package/bin/lib/pin-dependent-gates.mjs +117 -0
- package/bin/lib/policy-delta-io.mjs +168 -10
- package/bin/lib/prepare-change.mjs +120 -6
- package/bin/lib/prepare-write.mjs +1 -0
- package/bin/lib/presets.mjs +3 -5
- package/bin/lib/remediation.mjs +23 -4
- package/bin/lib/resolved-candidate-facts.mjs +315 -55
- package/bin/lib/rules-inventory.mjs +22 -3
- package/bin/lib/rules-under-contract.mjs +179 -5
- package/bin/lib/scan-files.mjs +32 -0
- package/bin/lib/snippet-analysis.mjs +140 -6
- package/bin/lib/source-policy.mjs +34 -0
- package/bin/lib/stable-hash.mjs +90 -0
- package/bin/lib/start-install-recovery.mjs +71 -1
- package/bin/lib/start-preview.mjs +30 -0
- package/bin/lib/status-command.mjs +33 -4
- package/bin/lib/status-manifest.mjs +32 -4
- package/bin/lib/team-parliament-io.mjs +79 -75
- package/bin/lib/team-parliament.mjs +6 -1
- package/bin/lib/write-path-capabilities.mjs +4 -2
- package/dist/chunk-A5EIY3HI.cjs +5 -0
- package/dist/chunk-MBXCFLO4.js +16 -0
- package/dist/chunk-RNQHRDCQ.cjs +16 -0
- package/dist/chunk-SVSQVGFJ.js +5 -0
- package/dist/{configTypes-CTELo87-.d.ts → configTypes-BJbaeoj4.d.cts} +53 -4
- package/dist/configTypes-BJbaeoj4.d.ts +246 -0
- package/dist/eslint/index.cjs +17 -4
- package/dist/eslint/index.d.cts +359 -0
- package/dist/eslint/index.d.ts +178 -158
- package/dist/eslint/index.js +10 -4
- package/dist/index.cjs +38 -37
- package/dist/index.d.cts +5475 -0
- package/dist/index.d.ts +3408 -296
- package/dist/index.js +38 -37
- package/dist/inspectorListen-6DQVJ4DC.js +1 -0
- package/dist/inspectorListen-KGMIQ2TF.cjs +1 -0
- package/dist/nestjs/index.cjs +1 -18
- package/dist/nestjs/index.d.cts +22 -0
- package/dist/nestjs/index.d.ts +1 -3
- package/dist/nestjs/index.js +1 -18
- package/dist/order/index.cjs +1 -1
- package/dist/order/index.d.cts +155 -0
- package/dist/order/index.d.ts +15 -3
- package/dist/order/index.js +1 -1
- package/dist/runtime/index.cjs +13 -30
- package/dist/{diagnosticCatalog-WD2TPSwZ.d.ts → runtime/index.d.cts} +814 -290
- package/dist/runtime/index.d.ts +2678 -108
- package/dist/runtime/index.js +13 -30
- package/dist/{types-yDNEQ603.d.ts → types-DRinG-vT.d.cts} +576 -140
- package/dist/types-DRinG-vT.d.ts +1792 -0
- package/docs/README.md +3 -1
- package/docs/agent-guide.md +92 -15
- package/docs/ai-gates.md +160 -26
- package/docs/arkorder.md +32 -15
- package/docs/brownfield-adoption.md +5 -1
- package/docs/configuration.md +273 -12
- package/docs/develop.md +2 -1
- package/docs/diagnostics.md +122 -13
- package/docs/package-surface.md +31 -8
- package/docs/product-voice.md +1 -1
- package/package.json +59 -18
- package/schemas/ark.analysis-result.schema.json +15 -0
- package/schemas/ark.config.schema.json +163 -4
- package/schemas/ark.resolved-candidate-facts.schema.json +1 -1
- package/schemas/ark.status-manifest.schema.json +22 -0
- package/server.json +3 -9
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +4 -1
- package/templates/agent-skills/ark-order/SKILL.md +4 -2
- package/templates/agent-skills/ark-runtime/SKILL.md +6 -1
- package/templates/arkrules/PersistenceAdapters.json +1 -1
- package/templates/arkrules/PresentationAdapters.json +1 -1
- package/templates/skills/ark-adopt.md +4 -1
- package/templates/skills/ark-order.md +4 -2
- package/templates/skills/ark-runtime.md +6 -1
- package/dist/types-fQ9-KrBj.d.ts +0 -183
|
@@ -3,17 +3,31 @@ import path from 'node:path';
|
|
|
3
3
|
import {
|
|
4
4
|
loadArchitectureChangeMap,
|
|
5
5
|
loadContract,
|
|
6
|
-
|
|
6
|
+
preflightTrustedResolvedChange,
|
|
7
7
|
} from './analysis-engine.mjs';
|
|
8
8
|
import { createAdapterResult } from './adapter-contract.mjs';
|
|
9
9
|
import { isGovernableSourceFile } from './scan-files.mjs';
|
|
10
10
|
import {
|
|
11
11
|
canonicalizeCandidateChanges,
|
|
12
|
+
createResolverIngestCache,
|
|
12
13
|
resolveCandidateFacts,
|
|
13
14
|
} from './resolved-candidate-facts.mjs';
|
|
14
15
|
import { effectiveAnalysisConfig } from './analysis-policy.mjs';
|
|
15
16
|
import { isScanExcludedRelative } from '../ark-shared.mjs';
|
|
16
17
|
import { classifyChangeSet, evaluateTeamGate } from './team-parliament.mjs';
|
|
18
|
+
import { loadEffectiveArkRulesFromDisk } from './effective-contract-load.mjs';
|
|
19
|
+
import {
|
|
20
|
+
coverageOptionsFromConfig,
|
|
21
|
+
invariantIdsFromCatalog,
|
|
22
|
+
loadInvariantCoverageInputs,
|
|
23
|
+
} from './invariant-coverage-io.mjs';
|
|
24
|
+
import { catalogHasEnforcedInvariant } from './invariant-coverage.mjs';
|
|
25
|
+
import {
|
|
26
|
+
declaredCoverageRootsPresent,
|
|
27
|
+
declaredInvariantTestsPathPresent,
|
|
28
|
+
scanDemandsInvariantTestsPath,
|
|
29
|
+
} from './invariant-tests-path.mjs';
|
|
30
|
+
import { loadArkRuleFileHints } from './arkrule-file-hints.mjs';
|
|
17
31
|
|
|
18
32
|
function candidatePath(value) {
|
|
19
33
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
@@ -88,6 +102,73 @@ export function normalizeChangeSet(input) {
|
|
|
88
102
|
});
|
|
89
103
|
}
|
|
90
104
|
|
|
105
|
+
function overlayContents(contents, overlay) {
|
|
106
|
+
const out = { ...(contents ?? {}) };
|
|
107
|
+
for (const change of overlay) {
|
|
108
|
+
if (change.delete === true) delete out[change.path];
|
|
109
|
+
else out[change.path] = change.content;
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* ArkRules engine inputs for base (disk) and candidate (disk + in-memory overlay):
|
|
116
|
+
* invariant coverage contents and structural file hints, loaded exactly the way
|
|
117
|
+
* architecture-scan loads them for ark-check. Undefined when ArkRules is off.
|
|
118
|
+
*/
|
|
119
|
+
function arkRulesAnalysisInputs({ root, config, arkRules, baseFacts, candidateFacts, overlay }) {
|
|
120
|
+
const structure = arkRules?.structure ?? [];
|
|
121
|
+
const invariants = arkRules?.invariants ?? [];
|
|
122
|
+
if (structure.length === 0 && invariants.length === 0) return {};
|
|
123
|
+
const adopted = scanDemandsInvariantTestsPath(root, {});
|
|
124
|
+
const shared = {
|
|
125
|
+
...(adopted ? { adopted: true } : {}),
|
|
126
|
+
...(adopted && declaredInvariantTestsPathPresent(root, config.coverage) === false
|
|
127
|
+
? { invariantTestsPathPresent: false }
|
|
128
|
+
: {}),
|
|
129
|
+
...(catalogHasEnforcedInvariant(invariants) &&
|
|
130
|
+
declaredCoverageRootsPresent(root, config.coverage) === false
|
|
131
|
+
? { coverageRootsPresent: false }
|
|
132
|
+
: {}),
|
|
133
|
+
};
|
|
134
|
+
const baseCoverage =
|
|
135
|
+
invariants.length > 0
|
|
136
|
+
? loadInvariantCoverageInputs(root, baseFacts, {
|
|
137
|
+
invariantIds: invariantIdsFromCatalog(arkRules),
|
|
138
|
+
...coverageOptionsFromConfig(config),
|
|
139
|
+
})
|
|
140
|
+
: undefined;
|
|
141
|
+
const candidateCoverage = baseCoverage
|
|
142
|
+
? {
|
|
143
|
+
...baseCoverage,
|
|
144
|
+
fileContents: overlayContents(baseCoverage.fileContents, overlay),
|
|
145
|
+
testFiles: (baseCoverage.testFiles ?? []).filter(
|
|
146
|
+
(file) => !overlay.some((change) => change.delete === true && change.path === file)
|
|
147
|
+
),
|
|
148
|
+
}
|
|
149
|
+
: undefined;
|
|
150
|
+
const baseHints = loadArkRuleFileHints(root, baseFacts, arkRules, baseCoverage?.fileContents);
|
|
151
|
+
// Candidate hints must read the overlay, never the stale on-disk text of a changed file.
|
|
152
|
+
const candidateHints = loadArkRuleFileHints(
|
|
153
|
+
root,
|
|
154
|
+
candidateFacts,
|
|
155
|
+
arkRules,
|
|
156
|
+
overlayContents(candidateCoverage?.fileContents ?? {}, overlay)
|
|
157
|
+
);
|
|
158
|
+
return {
|
|
159
|
+
baseAnalysisInputs: {
|
|
160
|
+
...shared,
|
|
161
|
+
...(baseCoverage ? { coverageInputs: baseCoverage } : {}),
|
|
162
|
+
...(baseHints ? { fileHints: baseHints } : {}),
|
|
163
|
+
},
|
|
164
|
+
candidateAnalysisInputs: {
|
|
165
|
+
...shared,
|
|
166
|
+
...(candidateCoverage ? { coverageInputs: candidateCoverage } : {}),
|
|
167
|
+
...(candidateHints ? { fileHints: candidateHints } : {}),
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
91
172
|
export function prepareChangeFromRoot({
|
|
92
173
|
root,
|
|
93
174
|
config,
|
|
@@ -115,10 +196,22 @@ export function prepareChangeFromRoot({
|
|
|
115
196
|
for (const change of normalizedChanges) {
|
|
116
197
|
assertInsideProject(root, change.path);
|
|
117
198
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
);
|
|
199
|
+
const contractSource = configSource ?? path.join(root, 'ark.config.json');
|
|
200
|
+
// Same Effective Contract as ark-check: ArkRules ride policyHash and the verdict,
|
|
201
|
+
// and a broken reference fails closed instead of silently dropping the catalog.
|
|
202
|
+
const arkRulesLoad = loadEffectiveArkRulesFromDisk(root, effectiveConfig);
|
|
203
|
+
if (arkRulesLoad.errors.length > 0) {
|
|
204
|
+
const message = arkRulesLoad.errors
|
|
205
|
+
.map((issue) => (typeof issue === 'string' ? issue : `- ${issue.path}: ${issue.message}`))
|
|
206
|
+
.join('\n');
|
|
207
|
+
const error = new Error(`Invalid Effective Contract (${contractSource}):\n${message}`);
|
|
208
|
+
error.code = 'ARKRULES_LOAD_FAILED';
|
|
209
|
+
error.issues = arkRulesLoad.errors;
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
const contract = loadContract(effectiveConfig, contractSource, {
|
|
213
|
+
arkRules: arkRulesLoad.arkRules,
|
|
214
|
+
});
|
|
122
215
|
const loadedChangeMap =
|
|
123
216
|
changeMap === undefined
|
|
124
217
|
? undefined
|
|
@@ -129,24 +222,45 @@ export function prepareChangeFromRoot({
|
|
|
129
222
|
changes: normalizedChanges,
|
|
130
223
|
});
|
|
131
224
|
for (const change of canonicalChanges) assertGovernedSource(effectiveConfig, change.path);
|
|
225
|
+
// Files the overlay does not touch are parsed once for both trees.
|
|
226
|
+
const ingestCache = createResolverIngestCache(contract.config);
|
|
132
227
|
const baseFacts = resolveCandidateFacts({
|
|
133
228
|
root,
|
|
134
229
|
config: contract.config,
|
|
135
230
|
ts,
|
|
231
|
+
ingestCache,
|
|
136
232
|
...(tsconfig ? { tsconfig } : {}),
|
|
137
233
|
});
|
|
138
234
|
const candidateFacts = resolveCandidateFacts({
|
|
139
235
|
root,
|
|
140
236
|
config: contract.config,
|
|
141
237
|
ts,
|
|
238
|
+
ingestCache,
|
|
142
239
|
changes: normalizedOverlayChanges,
|
|
143
240
|
...(tsconfig ? { tsconfig } : {}),
|
|
144
241
|
});
|
|
145
|
-
|
|
242
|
+
ingestCache.records.clear();
|
|
243
|
+
const { baseAnalysisInputs, candidateAnalysisInputs } = arkRulesAnalysisInputs({
|
|
244
|
+
root,
|
|
245
|
+
config: effectiveConfig,
|
|
246
|
+
arkRules: arkRulesLoad.arkRules,
|
|
247
|
+
baseFacts,
|
|
248
|
+
candidateFacts,
|
|
249
|
+
overlay: canonicalizeCandidateChanges({
|
|
250
|
+
root,
|
|
251
|
+
config: contract.config,
|
|
252
|
+
changes: normalizedOverlayChanges,
|
|
253
|
+
}),
|
|
254
|
+
});
|
|
255
|
+
// Both fact sets were created (validated, frozen) by this bundle instance just
|
|
256
|
+
// above: skip re-validating two whole-project copies of each.
|
|
257
|
+
const result = preflightTrustedResolvedChange({
|
|
146
258
|
contract,
|
|
147
259
|
baseFacts,
|
|
148
260
|
candidateFacts,
|
|
149
261
|
changes: canonicalChanges,
|
|
262
|
+
...(baseAnalysisInputs ? { baseAnalysisInputs } : {}),
|
|
263
|
+
...(candidateAnalysisInputs ? { candidateAnalysisInputs } : {}),
|
|
150
264
|
...(loadedChangeMap ? { changeMap: loadedChangeMap } : {}),
|
|
151
265
|
});
|
|
152
266
|
const completeness =
|
|
@@ -41,6 +41,7 @@ export function buildJudgmentBrief(violations) {
|
|
|
41
41
|
targetTypeOnlyExports: v.targetTypeOnlyExports,
|
|
42
42
|
namedBindingsTypeOnly: v.namedBindingsTypeOnly,
|
|
43
43
|
peerIsolation: v.peerIsolation ?? v.details?.peerIsolation,
|
|
44
|
+
reasonId: v.reasonId ?? v.details?.reasonId,
|
|
44
45
|
edgeKind: v.edgeKind ?? v.details?.importKind,
|
|
45
46
|
fromLayer: v.fromLayer,
|
|
46
47
|
toLayer: v.toLayer,
|
package/bin/lib/presets.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import path from 'node:path';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import {
|
|
8
8
|
applyFrameworkLayoutOverlays,
|
|
9
|
+
cloneArchetypeForLayer,
|
|
9
10
|
createElevenLayerConfig,
|
|
10
11
|
DEFAULT_DOMAIN_FORBIDDEN_GLOBALS,
|
|
11
12
|
discoverRepoUnits,
|
|
@@ -371,11 +372,8 @@ export function buildArkRulesTemplateForLayer(layerName, role = resolveLayerSens
|
|
|
371
372
|
const sourcePath = path.join(ARKRULES_TEMPLATES_DIR, archetype);
|
|
372
373
|
if (fs.existsSync(sourcePath)) {
|
|
373
374
|
try {
|
|
374
|
-
|
|
375
|
-
return
|
|
376
|
-
...parsed,
|
|
377
|
-
layer: layerName,
|
|
378
|
-
};
|
|
375
|
+
// Unique ids across arkrules/*.json so `--promote <id> --apply` works on the starter.
|
|
376
|
+
return cloneArchetypeForLayer(JSON.parse(fs.readFileSync(sourcePath, 'utf8')), layerName);
|
|
379
377
|
} catch {
|
|
380
378
|
// Fall through to generic mold.
|
|
381
379
|
}
|
package/bin/lib/remediation.mjs
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Pure CLI helper (bin/lib/remediation.mjs). Zero Node I/O.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { sliceReasonHint } from './diagnostic-catalog.mjs';
|
|
11
12
|
export const REMEDIATION_CLASSES = [
|
|
12
13
|
'mechanical-safe',
|
|
13
14
|
'judgment',
|
|
@@ -67,7 +68,15 @@ export function classifyLayerImportKind(target, extra) {
|
|
|
67
68
|
return 'unknown';
|
|
68
69
|
return 'unknown';
|
|
69
70
|
}
|
|
71
|
+
/** The reason's fix, plus its advisory note only when this finding is a warning. */
|
|
72
|
+
function sliceHintAction(hint, violation) {
|
|
73
|
+
return violation.failsStrict === false && hint.advisoryNote ? `${hint.fix} ${hint.advisoryNote}` : hint.fix;
|
|
74
|
+
}
|
|
70
75
|
export function layerImportNextAction(violation) {
|
|
76
|
+
// A nested-wall reason has its own fix. It wins over the generic peer text.
|
|
77
|
+
const hint = sliceReasonHint(typeof violation.reasonId === 'string' ? violation.reasonId : undefined);
|
|
78
|
+
if (hint)
|
|
79
|
+
return `${sliceHintAction(hint, violation)} Then preflight again.`;
|
|
71
80
|
if (violation.typeOnly || violation.targetTypeOnlyExports || violation.namedBindingsTypeOnly) {
|
|
72
81
|
return 'Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.';
|
|
73
82
|
}
|
|
@@ -198,6 +207,11 @@ export function deterministicNextAction(violation) {
|
|
|
198
207
|
switch (violation.ruleId) {
|
|
199
208
|
case 'LAYER_IMPORT_VIOLATION':
|
|
200
209
|
return layerImportNextAction(violation);
|
|
210
|
+
case 'CONFIG_CHILD_SLICES_VERSION':
|
|
211
|
+
// The finding already names the pinned file and the version to bump to.
|
|
212
|
+
return typeof violation.nextAction === 'string' && violation.nextAction.length > 0
|
|
213
|
+
? violation.nextAction
|
|
214
|
+
: 'Bump the pinned arkgate named in the finding to the version it gives, then run Ark again.';
|
|
201
215
|
case 'FORBIDDEN_GLOBAL':
|
|
202
216
|
return `Inject ${violation.target ?? 'the capability'} through a port, test at the public interface, then preflight again.`;
|
|
203
217
|
case 'CAPABILITY_VIOLATION':
|
|
@@ -423,11 +437,13 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
423
437
|
? 'The imported module only exports types — use `import type` and place the type in a layer both sides may share.'
|
|
424
438
|
: 'This is a type-only import — move the type to a layer both sides may share, or relocate the file to match its role.';
|
|
425
439
|
}
|
|
426
|
-
else if (violation.peerIsolation) {
|
|
440
|
+
else if (violation.peerIsolation || sliceReasonHint(violation.reasonId)) {
|
|
441
|
+
const hint = sliceReasonHint(violation.reasonId);
|
|
427
442
|
enriched.fixClass = 'cross-slice-boundary';
|
|
428
443
|
enriched.effort = 'medium';
|
|
429
|
-
enriched.enthusiastHint =
|
|
430
|
-
|
|
444
|
+
enriched.enthusiastHint = hint
|
|
445
|
+
? `${hint.why} ${sliceHintAction(hint, violation)}`
|
|
446
|
+
: 'Cross-slice import blocked (peerIsolation). Do not import another feature/context directly — extract shared code to a shared layer, or coordinate via events/ports. Moving code across slices is a judgment call, not a mechanical auto-fix.';
|
|
431
447
|
}
|
|
432
448
|
else {
|
|
433
449
|
const kind = classifyLayerImportKind(typeof violation.target === 'string' ? violation.target : '', {
|
|
@@ -539,6 +555,7 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
539
555
|
case 'ARKORDER_XI_TTL':
|
|
540
556
|
case 'ARKORDER_STALE_SIGMA':
|
|
541
557
|
case 'ARKORDER_UNVALVED_RELEASE':
|
|
558
|
+
case 'ARKORDER_STALE_PROPOSAL':
|
|
542
559
|
enriched.fixClass = 'arkorder-usage';
|
|
543
560
|
enriched.effort = 'medium';
|
|
544
561
|
enriched.enthusiastHint =
|
|
@@ -560,7 +577,9 @@ export function enrichViolationWithFixClass(violation) {
|
|
|
560
577
|
? 'Refresh σ. ξ does not expire.'
|
|
561
578
|
: violation.ruleId === 'ARKORDER_UNVALVED_RELEASE'
|
|
562
579
|
? 'The choice is already frozen. proposeRelease then apply — do not call release() again with a different value.'
|
|
563
|
-
:
|
|
580
|
+
: violation.ruleId === 'ARKORDER_STALE_PROPOSAL'
|
|
581
|
+
? 'That proposal was computed against an older pattern. Propose again, review the new blast radius, then apply.'
|
|
582
|
+
: 'Call createOrderPlane from arkgate/order in a listed plane root so the app actually freezes a pattern.';
|
|
564
583
|
break;
|
|
565
584
|
default:
|
|
566
585
|
enriched.fixClass = 'review-contract';
|