arkgate 3.2.0 → 3.4.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/CHANGELOG.md CHANGED
@@ -4,6 +4,83 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 3.4.0 — 2026-07-16
8
+
9
+ Understandable execution, second slice (Phase U: U04–U07): the capability evidence shipped in
10
+ 3.3 becomes **opt-in enforcement** across every adapter, plus the advisory ambient-state sensor
11
+ and the measured pre-tool path. Everything remains opt-in — a config without `capabilities` /
12
+ `pure` keys behaves exactly as before. **No breaking** CLI or `ark.config.json` changes.
13
+ **No gate weaken.**
14
+
15
+ ### Added
16
+
17
+ - **Capability walls (U04):** a layer may declare `capabilities: { deny: [...] }` (seven-id enum
18
+ in the versioned schema) or the casual shorthand `pure: true` (denies all seven). Enforcement
19
+ is judgment-class `CAPABILITY_VIOLATION` — never mechanical-safe, never auto-patched — with a
20
+ port-injection `nextAction`, across the CLI scan (ambient + import evidence), the pure IR
21
+ engine and atomic preflight (a multi-file batch cannot hide a denied capability), the real
22
+ PreToolUse hook and MCP gate (`capabilityWalls`), and ESLint
23
+ (`ark/no-denied-capabilities`, import dimension, in the recommended config). One violation,
24
+ one voice: an ambient use covered by the layer's `forbiddenGlobals` reports only
25
+ `FORBIDDEN_GLOBAL`.
26
+ - **Coverage-atom policy delta (U04/D6):** T01 classifies the ambient/wall surface on coverage
27
+ atoms (`ambient:<entry>` prefix-expanded + `import:<capability>`): any lost atom is weakening
28
+ (`fetch`→`XMLHttpRequest`, `Date`→`Date.now`, wall→`forbiddenGlobals` all require the
29
+ hash-bound acknowledgment); migrating `forbiddenGlobals` to an equivalent-or-stronger wall
30
+ never needs one.
31
+ - **Ambient-state sensor (U05, advisory + opt-in):** `doctor.ambientState` flags module-scope
32
+ `let`/`var` in `pure: true` layers only, with bounded sidecar acknowledgments at
33
+ `.ark/ambient-state-acks.json`. `declare` ambients and `using` bindings never count; skipped
34
+ oversized files are reported. No strict mode exists.
35
+ - **Measured pre-tool path (U06):** `npm run bench:hook-path` measures the complete
36
+ hook/doctor child-process paths; `eval/performance/hook-budgets.v1.json` locks the D5 method
37
+ (Linux baseline first, ceilings = baseline + fixed headroom, recording mode until then); CI
38
+ runs the bench. Dual-depth remediation everywhere: plain port hints for casual users, stable
39
+ `ruleId`/`capability`/`fixClass`/`nextAction` JSON for tooling.
40
+
41
+ ### Fixed
42
+
43
+ - The scan cache is version-bumped (v8) so a warm cache from an older ArkGate cannot miss wall
44
+ verdicts; template-literal text and `require()` handling in the pure scanner are
45
+ capability-correct (templates skipped; require counts as evidence, never as a graph edge).
46
+
47
+ ## 3.3.0 — 2026-07-16
48
+
49
+ Understandable execution, first slice (Phase U: U01–U03): typed effect capabilities as
50
+ **evidence-only** architecture facts, a locked ADR boundary, and a legibility dogfood of the
51
+ engine itself. Nothing blocks on capabilities in this release — walls arrive with the second
52
+ slice (U04+) after the corpus matures in the field. **No breaking** CLI or `ark.config.json`
53
+ changes. **No gate weaken.**
54
+
55
+ ### Added
56
+
57
+ - **ADR 0009 (U01):** the accepted architecture-vs-style boundary — seven closed capability ids
58
+ (`network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence`),
59
+ direct-evidence-only blocking threshold (transitive inference never blocks), config lowering
60
+ design (`forbiddenGlobals` and future capability policy lower to one semantic space;
61
+ `pure: true` planned as the casual surface), coverage-faithful lowering for prefix-matched
62
+ globals (bare `process` covers `environment` too), surface-ownership dedup rule, and the
63
+ W02 governance-weight reconciliation. Backed by a 25-case executable fixture corpus
64
+ (`tests/fixtures/capability-corpus/`) with a content-aware structural guard.
65
+ - **Effect capabilities in the canonical analysis (U03):** `collectCapabilityUses(ts, sourceFile)`
66
+ composes the existing symbol-aware collectors (shadowing / type-only / `globalThis`-alias
67
+ precision; no second scanner); the Domain vocabulary ships as
68
+ `CAPABILITY_IDS` / `capabilityForModuleSpecifier` / `capabilityForAmbientName` /
69
+ `lowerForbiddenGlobal`; the compiler-free IR engine now populates `ir.capabilityUses` with
70
+ import-based evidence (exact module/subpath matching — never substring; textual
71
+ `import type` / `export type` erasure). Additive within IR `1.0`; evidence only.
72
+
73
+ ### Changed
74
+
75
+ - **Engine legibility dogfood (U02):** `src/kernel/analysis.ts` is now a pure facade over six
76
+ cohesive kernel modules and the `ark.config.json` contract types moved to
77
+ `src/domain/configTypes.ts` — zero consumer import changes, byte-identical generated
78
+ config artifacts, identical hashes and verdicts (verified by execution old-vs-new). ArkGate's
79
+ own doctor now reports **zero design smells** on this repository.
80
+ - The experimental `@arkgate/runtime` distribution is minified with `keepNames` (stable
81
+ class/function names for reflection and Nest diagnostics) and stays well inside its
82
+ release-artifact budget.
83
+
7
84
  ## 3.2.0 — 2026-07-15
8
85
 
9
86
  Contract health (Phase W): ArkGate now also meta-lints the contract itself and describes its
package/README.md CHANGED
@@ -16,9 +16,10 @@ and makes sure a “green” check means something real.
16
16
 
17
17
  </div>
18
18
 
19
- > **ArkGate 3.2.0** is current stable: contract health (advisory meta-lint of the contract +
20
- > governance weight), on top of 3.1's policy-transition checks, atomic multi-file preflight, and
21
- > optional structural convergence. [Release notes](docs/releases/3.2.0.md).
19
+ > **ArkGate 3.4.0** is current stable: opt-in capability walls (`pure: true` or
20
+ > `capabilities.deny` per layer, enforced on every adapter), the advisory ambient-state sensor,
21
+ > and the measured pre-tool path — completing 3.3's evidence slice.
22
+ > [Release notes](docs/releases/3.4.0.md).
22
23
 
23
24
  ---
24
25
 
package/bin/ark-check.mjs CHANGED
@@ -1148,6 +1148,7 @@ async function main() {
1148
1148
  configPath: path.isAbsolute(args.config) ? args.config : path.join(root, args.config),
1149
1149
  configMissing: !fs.existsSync(path.isAbsolute(args.config) ? args.config : path.join(root, args.config)),
1150
1150
  safety,
1151
+ ts,
1151
1152
  });
1152
1153
  return;
1153
1154
  }
package/bin/ark-mcp.mjs CHANGED
@@ -58,6 +58,7 @@ import {
58
58
  detectTsPackageRoots,
59
59
  resolveIncludeRoots,
60
60
  } from './ark-shared.mjs';
61
+ import { effectiveCapabilityDeny } from './lib/analysis-engine.mjs';
61
62
  import { createImportTargetResolver } from './lib/import-resolve.mjs';
62
63
  import { validateWithAutoPatch, resolveImportFileAbs } from './lib/auto-patch.mjs';
63
64
  import { composePrepareWrite } from './lib/prepare-write.mjs';
@@ -765,6 +766,14 @@ async function main() {
765
766
  ])
766
767
  );
767
768
 
769
+ // Layer → effective capability deny set (U04 walls). Same opt-in surface the
770
+ // CLI enforces; the gate applies it whenever the target file's layer is known.
771
+ const capabilityWalls = Object.fromEntries(
772
+ configLayers
773
+ .map((layer) => [layer.name, effectiveCapabilityDeny(layer)])
774
+ .filter(([name, deny]) => name && deny.length > 0)
775
+ );
776
+
768
777
  // Layers explicitly flagged as infrastructure in ark.config.json may import
769
778
  // infrastructure — the built-in infra-import heuristics skip them (in addition
770
779
  // to layers whose name conventionally signals an infra role). Lets a project
@@ -779,6 +788,7 @@ async function main() {
779
788
  enforceIntentAllowlist: intents.length > 0,
780
789
  typescript: ts,
781
790
  forbiddenGlobals,
791
+ capabilityWalls,
782
792
  infrastructureLayers,
783
793
  // Contract-first: one resolve step yields layer + relPath for rules + peerIsolation.
784
794
  resolveImportTarget: createImportTargetResolver(ts, args.root, config),
@@ -30,6 +30,9 @@ function nextActionForDiagnostic(ruleId, evidence, violation) {
30
30
  if (ruleId === 'FORBIDDEN_GLOBAL') {
31
31
  return `Inject ${evidence.target ?? 'the capability'} through a port, then preflight again.`;
32
32
  }
33
+ if (ruleId === 'CAPABILITY_VIOLATION') {
34
+ return `Define a ${text(violation.capability) ?? 'capability'} port in ${evidence.fromLayer ?? 'the walled layer'}, bind the implementation outside it, then preflight again.`;
35
+ }
33
36
  if (ruleId === 'CIRCULAR_DEPENDENCY') {
34
37
  return 'Extract the shared dependency into a third module, then preflight again.';
35
38
  }
@@ -0,0 +1,221 @@
1
+ /**
2
+ * U05 — ambient mutable-state sensor (ADR 0009 D4 / A5).
3
+ *
4
+ * Advisory and OPT-IN: only layers declared `pure: true` are scanned; the MVP
5
+ * shape is module-scope `let`/`var`. Legitimate registries/caches are
6
+ * acknowledged in a bounded `.ark/` sidecar (W01 precedent) — a malformed file
7
+ * suppresses nothing. Doctor-only: no strict default may be introduced from
8
+ * this sensor until the fixed corpus proves blocker-grade precision (A5).
9
+ *
10
+ * Documented envelope: only top-level statements are walked — `let` inside a
11
+ * `namespace` body (real runtime state on the namespace object) is out of the
12
+ * MVP shape; `declare` ambients and `using` bindings never count (no state /
13
+ * not reassignable).
14
+ */
15
+ import fs from 'node:fs';
16
+ import path from 'node:path';
17
+ import { layerForFile } from '../ark-shared.mjs';
18
+
19
+ export const AMBIENT_STATE_ACKS_PATH = '.ark/ambient-state-acks.json';
20
+
21
+ const MAX_ACK_BYTES = 64 * 1024;
22
+ const MAX_ACK_ENTRIES = 200;
23
+ const MAX_FILE_BYTES = 256 * 1024;
24
+ const MAX_FINDINGS = 50;
25
+
26
+ /** Bounded, fail-loud sidecar loader (same discipline as contract-smell acks). */
27
+ export function loadAmbientStateAcks(root) {
28
+ const relPath = AMBIENT_STATE_ACKS_PATH;
29
+ const abs = path.join(root, relPath);
30
+ let stats;
31
+ try {
32
+ stats = fs.statSync(abs);
33
+ } catch {
34
+ return { path: relPath, exists: false, acks: [] };
35
+ }
36
+ const invalid = (error) => ({ path: relPath, exists: true, invalid: true, error, acks: [] });
37
+ if (!stats.isFile()) return invalid('not a regular file');
38
+ if (stats.size > MAX_ACK_BYTES) return invalid(`larger than ${MAX_ACK_BYTES} bytes`);
39
+ let parsed;
40
+ try {
41
+ parsed = JSON.parse(fs.readFileSync(abs, 'utf8'));
42
+ } catch (error) {
43
+ return invalid(error instanceof Error ? error.message : 'unreadable JSON');
44
+ }
45
+ const acks = Array.isArray(parsed?.acks) ? parsed.acks : null;
46
+ if (!acks) return invalid('expected { acks: [{ file, name, reason? }] }');
47
+ if (acks.length > MAX_ACK_ENTRIES) return invalid(`more than ${MAX_ACK_ENTRIES} entries`);
48
+ const wellFormed = acks.every(
49
+ (a) =>
50
+ a !== null &&
51
+ typeof a === 'object' &&
52
+ typeof a.file === 'string' &&
53
+ a.file.length > 0 &&
54
+ typeof a.name === 'string' &&
55
+ a.name.length > 0
56
+ );
57
+ if (!wellFormed) return invalid('every ack needs string file and name');
58
+ // Normalize separators so a Windows-authored ack file still matches.
59
+ const normalized = acks.map((a) => ({ ...a, file: a.file.replace(/\\/g, '/') }));
60
+ return { path: relPath, exists: true, acks: normalized };
61
+ }
62
+
63
+ function isAcknowledged(ackState, file, name) {
64
+ if (!ackState || ackState.invalid || !Array.isArray(ackState.acks)) return false;
65
+ return ackState.acks.some((a) => a.file === file && a.name === name);
66
+ }
67
+
68
+ function bindingIdentifiers(ts, name, out) {
69
+ if (ts.isIdentifier(name)) {
70
+ out.push(name.text);
71
+ return;
72
+ }
73
+ if (ts.isObjectBindingPattern(name) || ts.isArrayBindingPattern(name)) {
74
+ for (const element of name.elements) {
75
+ if (element && !ts.isOmittedExpression(element) && element.name) {
76
+ bindingIdentifiers(ts, element.name, out);
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Detect module-scope mutable state in `pure: true` layers.
84
+ *
85
+ * @returns {{ active: boolean, findings: Array<{file: string, line: number, name: string, kind: 'module-let'|'module-var'}>, acknowledgedCount: number, truncated: number }}
86
+ */
87
+ export function detectAmbientState(ts, root, config, files, ackState = { exists: false, acks: [] }) {
88
+ const layers = Array.isArray(config?.layers) ? config.layers : [];
89
+ const pureLayers = new Set(
90
+ layers.filter((layer) => layer?.pure === true).map((layer) => layer.name)
91
+ );
92
+ if (pureLayers.size === 0) return { active: false, findings: [], acknowledgedCount: 0, truncated: 0 };
93
+
94
+ const resolvedRoot = path.resolve(root);
95
+ const findings = [];
96
+ const acknowledgedPairs = new Set();
97
+ let skippedFiles = 0;
98
+ for (const file of files) {
99
+ const layer = layerForFile(root, file, layers);
100
+ if (!layer || !pureLayers.has(layer)) continue;
101
+ const rel = path.relative(resolvedRoot, path.resolve(file)).split(path.sep).join('/');
102
+ let source;
103
+ try {
104
+ const stats = fs.statSync(file);
105
+ if (!stats.isFile() || stats.size === 0) continue;
106
+ if (stats.size > MAX_FILE_BYTES) {
107
+ skippedFiles += 1;
108
+ continue;
109
+ }
110
+ source = fs.readFileSync(file, 'utf8');
111
+ } catch {
112
+ continue;
113
+ }
114
+ const sourceFile = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);
115
+ for (const statement of sourceFile.statements) {
116
+ if (!ts.isVariableStatement(statement)) continue;
117
+ // `declare` ambients allocate no runtime state.
118
+ if (
119
+ statement.modifiers?.some(
120
+ (modifier) => modifier.kind === ts.SyntaxKind.DeclareKeyword
121
+ )
122
+ ) {
123
+ continue;
124
+ }
125
+ const flags = statement.declarationList.flags;
126
+ // const never reassigns; `using`/`await using` bindings are not reassignable.
127
+ const immutableFlags =
128
+ ts.NodeFlags.Const | (ts.NodeFlags.Using ?? 0) | (ts.NodeFlags.AwaitUsing ?? 0);
129
+ if ((flags & immutableFlags) !== 0) continue;
130
+ const kind = (flags & ts.NodeFlags.Let) !== 0 ? 'module-let' : 'module-var';
131
+ for (const declaration of statement.declarationList.declarations) {
132
+ const names = [];
133
+ bindingIdentifiers(ts, declaration.name, names);
134
+ for (const name of names) {
135
+ if (isAcknowledged(ackState, rel, name)) {
136
+ acknowledgedPairs.add(`${rel}\u0000${name}`);
137
+ continue;
138
+ }
139
+ const line =
140
+ sourceFile.getLineAndCharacterOfPosition(declaration.getStart(sourceFile)).line + 1;
141
+ findings.push({ file: rel, line, name, kind });
142
+ }
143
+ }
144
+ }
145
+ }
146
+ const acknowledgedCount = acknowledgedPairs.size;
147
+ findings.sort(
148
+ (left, right) =>
149
+ left.file.localeCompare(right.file) ||
150
+ left.line - right.line ||
151
+ left.name.localeCompare(right.name)
152
+ );
153
+ const truncated = Math.max(0, findings.length - MAX_FINDINGS);
154
+ return {
155
+ active: true,
156
+ findings: findings.slice(0, MAX_FINDINGS),
157
+ acknowledgedCount,
158
+ truncated,
159
+ skippedFiles,
160
+ };
161
+ }
162
+
163
+ /** JSON summary for doctor. Advisory only — never a verdict input. */
164
+ export function summarizeAmbientState(result, ackState = { exists: false, acks: [] }) {
165
+ return {
166
+ available: true,
167
+ active: result.active,
168
+ advisory: true,
169
+ findingCount: result.findings.length,
170
+ acknowledged: ackState?.invalid ? 0 : result.acknowledgedCount,
171
+ ...(result.truncated > 0 ? { truncated: result.truncated } : {}),
172
+ ...(result.skippedFiles > 0 ? { skippedFiles: result.skippedFiles } : {}),
173
+ note: result.active
174
+ ? 'Module-scope mutable state in pure layers — advisory only; acknowledge deliberate registries in the sidecar or move the state behind a port.'
175
+ : 'No pure: true layer opted in; the sensor is idle.',
176
+ ackFile: {
177
+ path: ackState?.path ?? AMBIENT_STATE_ACKS_PATH,
178
+ present: ackState?.exists === true,
179
+ invalid: ackState?.invalid === true,
180
+ ...(ackState?.invalid ? { error: ackState.error ?? 'invalid' } : {}),
181
+ },
182
+ };
183
+ }
184
+
185
+ /** One-call compute for doctor; `ts` may be absent (report unavailable honestly). */
186
+ export function computeAmbientState(ts, root, config, files) {
187
+ if (!ts) {
188
+ return {
189
+ available: false,
190
+ active: false,
191
+ advisory: true,
192
+ findings: [],
193
+ findingCount: 0,
194
+ acknowledged: 0,
195
+ note: 'TypeScript was not available to the doctor run; the ambient-state sensor did not execute.',
196
+ };
197
+ }
198
+ const ackState = loadAmbientStateAcks(root);
199
+ const result = detectAmbientState(ts, root, config, files, ackState);
200
+ return { ...summarizeAmbientState(result, ackState), findings: result.findings };
201
+ }
202
+
203
+ /** Human doctor section (advisory); silent when idle and healthy. */
204
+ export function printAmbientStateSection(state, io) {
205
+ if (!state.available || (!state.findingCount && !state.ackFile?.invalid)) return;
206
+ console.log('');
207
+ console.log(io.color.bold('Ambient state (advisory)'));
208
+ if (state.ackFile?.invalid) {
209
+ io.line(io.warn, `${state.ackFile.path} is present but invalid — acknowledgments are ignored.`);
210
+ }
211
+ for (const finding of state.findings.slice(0, 5)) {
212
+ io.line(io.warn, `[${finding.kind}] ${finding.file}:${finding.line} — \`${finding.name}\``);
213
+ }
214
+ if (state.findingCount > 5) {
215
+ io.line(' ', io.color.dim(`…(+${state.findingCount - 5} more in doctor JSON)`));
216
+ }
217
+ if (state.acknowledged > 0) {
218
+ io.line(' ', io.color.dim(`acknowledged module state: ${state.acknowledged}`));
219
+ }
220
+ io.line(' ', io.color.dim('advisory only — never blocks; move state behind a port or acknowledge it'));
221
+ }
@@ -1,9 +1,10 @@
1
1
  // GENERATED from src/kernel/analysis.ts by scripts/generate-analysis-engine.mjs.
2
2
  // Do not edit this file directly.
3
- function $(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function E(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return`[${e.map(E).join(",")}]`;let t=e;return`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${E(t[n])}`).join(",")}}`}var K="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",ie=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],Ee=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function we(){let e=[];for(let t of ie)for(let n of ie)t===n||Ee.has(`${t}->${n}`)||e.push({from:t,to:n,allowed:!1});return e}var se=we();var w={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},ae={$schema:"https://json-schema.org/draft/2020-12/schema",$id:K,title:"ArkGate architecture contract",description:"Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",type:"object",additionalProperties:!1,required:["$schema","schemaVersion","include","layers","rules"],properties:{$schema:{type:"string",minLength:1,default:K,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.0",default:"1.0"},name:{type:"string",minLength:1},include:{...w,minItems:1,default:["src"]},exclude:{...w,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:se,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...w,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...w,minItems:1},exclude:w,intentPrefixes:w,description:{type:"string",minLength:1},forbiddenGlobals:w,mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"}}},rule:{type:"object",additionalProperties:!1,required:["from","to","allowed"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},allowed:{type:"boolean"},message:{type:"string",minLength:1},peerIsolation:{type:"boolean"},sliceFolders:{...w,minItems:1}}},safety:{type:"object",additionalProperties:!1,properties:{maxTsSuppressions:{type:"integer",minimum:0,default:0},maxAnyCasts:{type:"integer",minimum:0,default:0},allowInMemory:{type:"boolean",default:!1},allowDisabledPeerIsolation:{type:"boolean",default:!1}}}}},P=class extends Error{issues;source;constructor(t,n){super(`Invalid ArkGate config (${t}):
3
+ function $(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function x(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return`[${e.map(x).join(",")}]`;let t=e;return`{${Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${x(t[n])}`).join(",")}}`}var Ae=new Map;function be(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function X(e){let t="";for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"&&n+1<e.length){let i=e[n+1];if("*?{}[],".includes(i)||i==="\\"){t+="\\"+i,n+=1;continue}t+="/";continue}t+=r}return t}function He(e){let t=0;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"){n+=1;continue}if(r==="{")t+=1;else if(r==="}"&&(t-=1,t<0))return!1}return t===0}function D(e){let t=Ae.get(e);if(t)return t;let n=X(e),r=He(n),i="",a=0;for(let l=0;l<n.length;l+=1){let p=n[l];p==="\\"&&l+1<n.length?(i+=be(n[l+1]),l+=1):p==="*"?n[l+1]==="*"?n[l+2]==="/"?(i+="(?:.*/)?",l+=2):(i+=".*",l+=1):i+="[^/]*":p==="?"?i+="[^/]":p==="{"&&r?(i+="(?:",a+=1):p==="}"&&r&&a>0?(i+=")",a-=1):p===","&&r&&a>0?i+="|":i+=be(p)}let o=new RegExp(`^${i}$`);return Ae.set(e,o),o}function Q(e){let t=X(String(e)),r=t.split("*")[0].split("/").filter(Boolean).length,i=t.replace(/\*/g,"").length;return r*1e4+i}function _(e,t){let n=String(e).split(/[/\\]/).join("/"),r,i=-1;for(let a of t??[])if(!(a.exclude??[]).some(o=>D(o).test(n))){for(let o of a.patterns??[])if(D(o).test(n)){let l=Q(o);l>i&&(i=l,r=a.name)}}return r}function Ce(e,t){if(!t?.length)return;let n=String(e).split(/[/\\]/).filter(Boolean),r=new Set(t.map(i=>String(i).toLowerCase()));for(let i=0;i<n.length-1;i+=1)if(r.has(n[i].toLowerCase()))return`${n[i]}/${n[i+1]}`}function Ge(e){let t=new Set;for(let n of e??[]){let i=X(String(n)).split("/").filter(Boolean);for(let a=0;a<i.length;a+=1){let o=i[a];if((o==="**"||o==="*")&&a>0){let l=i[a-1];l&&!l.includes("*")&&!l.includes("{")&&!l.includes("}")&&t.add(l)}}}return[...t]}function Ue(e,t,n){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(i=>typeof i=="string"&&i.length>0);let r=(n??[]).find(i=>i.name===t);return Ge(r?.patterns)}function G(e,t,n,r){for(let i of e??[])if(!(i.from!==t||i.to!==n)&&i.allowed===!1){if(i.peerIsolation){let a=r?.fromPath,o=r?.toPath;if(!a||!o)continue;let l=Ue(i,t,r?.layers);if(l.length===0)continue;let p=Ce(a,l),u=Ce(o,l);if(!p||!u)continue;if(p!==u)return i;continue}if(t!==n)return i}}var ee="1.0";var U=class extends Error{issues;source;constructor(t,n){super(`Invalid architecture change map (${t}):
4
4
  ${n.map(r=>`- ${r.path}: ${r.message}`).join(`
5
- `)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=n}};function oe(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function B(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function R(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function $e(e,t){let n="#/$defs/";if(e.startsWith(n))return t.$defs[e.slice(n.length)]}function F(e,t,n,r,i){if(t.$ref){let a=$e(t.$ref,r);if(!a){i.push({path:n,message:`schema reference ${t.$ref} cannot be resolved`});return}F(e,a,n,r,i);return}if(t.const!==void 0&&!Object.is(e,t.const)){i.push({path:n,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(a=>Object.is(a,e))){i.push({path:n,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!oe(e)){i.push({path:n,message:`must be an object; received ${R(e)}`});return}let a=t.properties??{};for(let o of t.required??[])e[o]===void 0&&i.push({path:B(n,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in a||i.push({path:B(n,o),message:"unknown field"});for(let[o,l]of Object.entries(a))e[o]!==void 0&&F(e[o],l,B(n,o),r,i);return}if(t.type==="array"){if(!Array.isArray(e)){i.push({path:n,message:`must be an array; received ${R(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&i.push({path:n,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let a=e.map(o=>JSON.stringify(o));new Set(a).size!==a.length&&i.push({path:n,message:"must not contain duplicate items"})}t.items&&e.forEach((a,o)=>F(a,t.items,`${n}[${o}]`,r,i));return}if(t.type==="string"){if(typeof e!="string"){i.push({path:n,message:`must be a string; received ${R(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&i.push({path:n,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&i.push({path:n,message:`must be a boolean; received ${R(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){i.push({path:n,message:`must be an integer; received ${R(e)}`});return}t.minimum!==void 0&&e<t.minimum&&i.push({path:n,message:`must be at least ${t.minimum}`})}}function Oe(e){return{...e,$schema:e.$schema===void 0?K:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.0":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?se.map(t=>({...t})):e.rules}}function Re(e,t="ark.config.json"){if(!oe(e))throw new P(t,[{path:"$",message:`must be an object; received ${R(e)}`}]);let n=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new P(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:Oe(e),migratedFrom:n}}function q(e,t="ark.config.json"){let{candidate:n,migratedFrom:r}=Re(e,t),i=[];if(F(n,ae,"$",ae,i),i.length>0)throw new P(t,i);return{config:n,migratedFrom:r}}function ce(e,t="ark.config.json"){let n;try{n=JSON.parse(e)}catch(r){throw new P(t,[{path:"$",message:`invalid JSON: ${r instanceof Error?r.message:String(r)}`}])}return q(n,t)}var le=new Map;function de(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function z(e){let t="";for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"&&n+1<e.length){let i=e[n+1];if("*?{}[],".includes(i)||i==="\\"){t+="\\"+i,n+=1;continue}t+="/";continue}t+=r}return t}function Pe(e){let t=0;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"){n+=1;continue}if(r==="{")t+=1;else if(r==="}"&&(t-=1,t<0))return!1}return t===0}function _(e){let t=le.get(e);if(t)return t;let n=z(e),r=Pe(n),i="",a=0;for(let l=0;l<n.length;l+=1){let d=n[l];d==="\\"&&l+1<n.length?(i+=de(n[l+1]),l+=1):d==="*"?n[l+1]==="*"?n[l+2]==="/"?(i+="(?:.*/)?",l+=2):(i+=".*",l+=1):i+="[^/]*":d==="?"?i+="[^/]":d==="{"&&r?(i+="(?:",a+=1):d==="}"&&r&&a>0?(i+=")",a-=1):d===","&&r&&a>0?i+="|":i+=de(d)}let o=new RegExp(`^${i}$`);return le.set(e,o),o}function Y(e){let t=z(String(e)),r=t.split("*")[0].split("/").filter(Boolean).length,i=t.replace(/\*/g,"").length;return r*1e4+i}function M(e,t){let n=String(e).split(/[/\\]/).join("/"),r,i=-1;for(let a of t??[])if(!(a.exclude??[]).some(o=>_(o).test(n))){for(let o of a.patterns??[])if(_(o).test(n)){let l=Y(o);l>i&&(i=l,r=a.name)}}return r}function pe(e,t){if(!t?.length)return;let n=String(e).split(/[/\\]/).filter(Boolean),r=new Set(t.map(i=>String(i).toLowerCase()));for(let i=0;i<n.length-1;i+=1)if(r.has(n[i].toLowerCase()))return`${n[i]}/${n[i+1]}`}function Le(e){let t=new Set;for(let n of e??[]){let i=z(String(n)).split("/").filter(Boolean);for(let a=0;a<i.length;a+=1){let o=i[a];if((o==="**"||o==="*")&&a>0){let l=i[a-1];l&&!l.includes("*")&&!l.includes("{")&&!l.includes("}")&&t.add(l)}}}return[...t]}function ve(e,t,n){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(i=>typeof i=="string"&&i.length>0);let r=(n??[]).find(i=>i.name===t);return Le(r?.patterns)}function W(e,t,n,r){for(let i of e??[])if(!(i.from!==t||i.to!==n)&&i.allowed===!1){if(i.peerIsolation){let a=r?.fromPath,o=r?.toPath;if(!a||!o)continue;let l=ve(i,t,r?.layers);if(l.length===0)continue;let d=pe(a,l),u=pe(o,l);if(!d||!u)continue;if(d!==u)return i;continue}if(t!==n)return i}}function C(e,t){e.push({id:`${t.classification}:${t.path}:${t.kind}`,path:t.path,classification:t.classification,message:t.message,...t.classification==="weakening"||t.classification==="judgment-required"?{nextAction:`Restore the previous protection at ${t.path}, then run ArkGate again.`}:{},...t.before===void 0?{}:{before:t.before},...t.after===void 0?{}:{after:t.after}})}function S(e){return[...new Set(e??[])].sort()}function L(e,t,n,r,i){let a=S(n),o=S(r),l=new Set(a),d=new Set(o),u=o.filter(g=>!l.has(g)),m=a.filter(g=>!d.has(g));u.length===0&&m.length===0||(u.length>0&&C(e,{kind:"added",path:t,classification:i.added,message:i.addedMessage,before:a,after:o}),m.length>0&&C(e,{kind:"removed",path:t,classification:i.removed,message:i.removedMessage,before:a,after:o}))}function j(e,t,n,r,i,a,o){if(n===r)return;C(e,{kind:r?"enabled":"disabled",path:t,classification:r?i:i==="strengthening"?"weakening":"strengthening",message:r?a:o,before:n,after:r})}function H(e,t){let n=new Map,r=new Set;for(let i of e){let a=t(i);n.has(a)?r.add(a):n.set(a,i)}return{values:n,duplicates:[...r].sort()}}function _e(e,t,n){let r=H(t,a=>a.name),i=H(n,a=>a.name);(r.duplicates.length>0||i.duplicates.length>0)&&C(e,{kind:"duplicate-layer",path:"$.layers",classification:"judgment-required",message:"Duplicate layer names make policy ownership ambiguous.",before:r.duplicates,after:i.duplicates});for(let a of[...new Set([...r.values.keys(),...i.values.keys()])].sort()){let o=r.values.get(a),l=i.values.get(a),d=`$.layers[${a}]`;if(!o&&l){C(e,{kind:"layer-added",path:d,classification:"judgment-required",message:"A layer was added; verify overlap, ownership, and rule coverage.",after:l});continue}if(o&&!l){C(e,{kind:"layer-removed",path:d,classification:"weakening",message:"Removing a layer can leave its source paths ungoverned.",before:o});continue}!o||!l||(L(e,`${d}.patterns`,o.patterns,l.patterns,{added:"strengthening",removed:"weakening",addedMessage:"Additional paths are governed by this layer.",removedMessage:"Paths were removed from this layer and may become ungoverned."}),L(e,`${d}.exclude`,o.exclude,l.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional paths are excluded from this layer.",removedMessage:"Fewer paths are excluded from this layer."}),L(e,`${d}.forbiddenGlobals`,o.forbiddenGlobals,l.forbiddenGlobals,{added:"strengthening",removed:"weakening",addedMessage:"Additional forbidden globals are enforced in this layer.",removedMessage:"A forbidden-global protection was removed from this layer."}),S(o.intentPrefixes).join("\0")!==S(l.intentPrefixes).join("\0")&&C(e,{kind:"intent-prefixes-changed",path:`${d}.intentPrefixes`,classification:"judgment-required",message:"Intent ownership changed and must be reviewed against publishers and consumers.",before:S(o.intentPrefixes),after:S(l.intentPrefixes)}),j(e,`${d}.mayImportInfrastructure`,o.mayImportInfrastructure===!0,l.mayImportInfrastructure===!0,"weakening","The layer may now import infrastructure directly.","Direct infrastructure imports are no longer allowed for this layer."),j(e,`${d}.optional`,o.optional===!0,l.optional===!0,"weakening","The layer is now optional and can be absent without a strict warning.","The layer is now required when its contract is active."))}}function Me(e,t,n){let r=o=>`${o.from}->${o.to}`,i=H(t,r),a=H(n,r);(i.duplicates.length>0||a.duplicates.length>0)&&C(e,{kind:"duplicate-rule",path:"$.rules",classification:"judgment-required",message:"Duplicate rule edges make the effective verdict order-dependent.",before:i.duplicates,after:a.duplicates});for(let o of[...new Set([...i.values.keys(),...a.values.keys()])].sort()){let l=i.values.get(o),d=a.values.get(o),u=`$.rules[${o}]`;if(!l&&d){d.allowed===!1&&C(e,{kind:"deny-added",path:u,classification:"strengthening",message:"A denied dependency edge was added.",after:d});continue}if(l&&!d){l.allowed===!1&&C(e,{kind:"deny-removed",path:u,classification:"weakening",message:"A denied dependency edge was removed.",before:l});continue}if(!l||!d)continue;l.allowed!==d.allowed&&C(e,{kind:d.allowed?"deny-disabled":"deny-enabled",path:`${u}.allowed`,classification:d.allowed?"weakening":"strengthening",message:d.allowed?"A previously denied dependency edge is now allowed.":"A dependency edge is now denied.",before:l.allowed,after:d.allowed});let m=l.peerIsolation===!0,g=d.peerIsolation===!0;if(m!==g){let s=l.from===l.to&&d.from===d.to;C(e,{kind:g?"peer-isolation-enabled":"peer-isolation-disabled",path:`${u}.peerIsolation`,classification:s?g?"strengthening":"weakening":"judgment-required",message:s?g?"Cross-slice dependencies inside this layer are now denied.":"Cross-slice dependencies inside this layer are no longer denied.":"Changing peer isolation on a cross-layer edge changes the denial scope.",before:m,after:g})}S(l.sliceFolders).join("\0")!==S(d.sliceFolders).join("\0")&&C(e,{kind:"slice-folders-changed",path:`${u}.sliceFolders`,classification:"judgment-required",message:"Slice ownership folders changed and can reclassify existing dependencies.",before:S(l.sliceFolders),after:S(d.sliceFolders)})}}function Ne(e,t,n){let r=t.safety??{},i=n.safety??{};for(let a of["maxTsSuppressions","maxAnyCasts"]){let o=r[a]??0,l=i[a]??0;o!==l&&C(e,{kind:l>o?"threshold-raised":"threshold-lowered",path:`$.safety.${a}`,classification:l>o?"weakening":"strengthening",message:l>o?"The safety threshold allows more violations.":"The safety threshold allows fewer violations.",before:o,after:l})}for(let a of["allowInMemory","allowDisabledPeerIsolation"])j(e,`$.safety.${a}`,r[a]===!0,i[a]===!0,"weakening","A safety exception was enabled.","A safety exception was disabled.")}function De(e){return e.some(t=>t.classification==="weakening")?"weakening":e.some(t=>t.classification==="judgment-required")?"judgment-required":e.some(t=>t.classification==="strengthening")?"strengthening":"neutral"}function fe(e,t){let n=[];L(n,"$.include",e.include,t.include,{added:"strengthening",removed:"weakening",addedMessage:"Additional project roots are governed.",removedMessage:"Project roots were removed from governance."}),L(n,"$.exclude",e.exclude,t.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional project paths are excluded from governance.",removedMessage:"Fewer project paths are excluded from governance."}),L(n,"$.dynamicImportAllowlist",e.dynamicImportAllowlist,t.dynamicImportAllowlist,{added:"weakening",removed:"strengthening",addedMessage:"Additional files may use non-literal dynamic imports.",removedMessage:"Fewer files may use non-literal dynamic imports."}),j(n,"$.excludeGenerated",e.excludeGenerated!==!1,t.excludeGenerated!==!1,"weakening","Generated source is now excluded from governance.","Generated source is now governed.");let r={off:0,soft:1,"framework-soft":1,strict:2},i=e.cyclePolicy??"strict",a=t.cyclePolicy??"strict";if(i!==a){let o=r[a]===r[i]?"judgment-required":r[a]>r[i]?"strengthening":"weakening";C(n,{kind:"cycle-policy-changed",path:"$.cyclePolicy",classification:o,message:"The cycle enforcement level changed.",before:i,after:a})}return(e.frameworkOverlay??null)!==(t.frameworkOverlay??null)&&C(n,{kind:"framework-overlay-changed",path:"$.frameworkOverlay",classification:"judgment-required",message:"The framework overlay changed and may alter effective layer matching.",before:e.frameworkOverlay??null,after:t.frameworkOverlay??null}),_e(n,e.layers,t.layers),Me(n,e.rules,t.rules),Ne(n,e,t),n.sort((o,l)=>o.path.localeCompare(l.path)||o.id.localeCompare(l.id)),{schemaVersion:"1.0",classification:De(n),findings:n}}function ue(e,t){if(!e||e.schemaVersion!=="1.0"||typeof e.basePolicyHash!="string"||typeof e.candidatePolicyHash!="string"||typeof e.reason!="string"||!Array.isArray(e.findingIds)||e.findingIds.some(i=>typeof i!="string")||e.reason.trim().length===0||e.basePolicyHash!==t.basePolicyHash||e.candidatePolicyHash!==t.candidatePolicyHash)return!1;let n=S(e.findingIds),r=S(t.findingIds);return n.length===r.length&&n.every((i,a)=>i===r[a])}function k(e){return`${e.from}->${e.to}`}function N(e,t,n,r="dependency"){return{id:`${e}:${r}:${k(t)}`,classification:e,subject:"dependency",from:t.from,to:t.to,message:n,...e==="missing"?{nextAction:`Add the planned dependency ${k(t)} to the candidate, then preflight again.`}:e==="contradictory"?{nextAction:`Replace the reverse dependency with ${k(t)}, then preflight again.`}:e==="unplanned"?{nextAction:`Remove the unplanned dependency ${k(t)} from the candidate, then preflight again.`}:{}}}function J(e){let t=[],n=new Map(e.changeMap.map.files.map(s=>[s.path,s])),r=new Map(e.changes.map(s=>[s.path,s])),i=new Map(e.changeMap.map.dependencies.map(s=>[k(s),s])),a=new Map(e.baseDependencies.map(s=>[k(s),s])),o=new Map(e.candidateDependencies.map(s=>[k(s),s]));for(let s of[...n.values()].sort((c,p)=>c.path.localeCompare(p.path))){let c=r.get(s.path);c?c.operation!==s.operation?t.push({id:`contradictory:file:${s.path}`,classification:"contradictory",subject:"file",path:s.path,expectedOperation:s.operation,actualOperation:c.operation,message:`${s.path} was planned as ${s.operation} but the actual operation is ${c.operation}.`,nextAction:`Change ${s.path} to the planned ${s.operation} operation, then preflight again.`}):t.push({id:`satisfied:file:${s.path}`,classification:"satisfied",subject:"file",path:s.path,expectedOperation:s.operation,actualOperation:c.operation,message:`${s.path} matches the planned ${s.operation} operation.`}):t.push({id:`missing:file:${s.path}`,classification:"missing",subject:"file",path:s.path,expectedOperation:s.operation,message:`${s.path} was planned as ${s.operation} but is absent from the actual change.`,nextAction:`${s.operation[0].toUpperCase()}${s.operation.slice(1)} ${s.path} in the complete change set, then preflight again.`})}for(let s of[...r.values()].sort((c,p)=>c.path.localeCompare(p.path)))n.has(s.path)||t.push({id:`unplanned:file:${s.path}`,classification:"unplanned",subject:"file",path:s.path,actualOperation:s.operation,message:`${s.path} has an unplanned ${s.operation} operation.`,nextAction:`Remove ${s.path} from the change set, then preflight again.`});let l=new Set;for(let s of[...i.values()].sort((c,p)=>k(c).localeCompare(k(p)))){if(o.has(k(s))){t.push(N("satisfied",s,`${s.from} -> ${s.to} exists in the candidate architecture.`));continue}let c={from:s.to,to:s.from};o.has(k(c))?(l.add(k(c)),t.push(N("contradictory",s,`${s.from} -> ${s.to} was planned, but the candidate contains the reverse edge.`))):t.push(N("missing",s,`${s.from} -> ${s.to} is absent from the candidate architecture.`))}let d=new Set([...n.keys(),...r.keys()]);for(let[s,c]of[...o].sort(([p],[f])=>p.localeCompare(f)))a.has(s)||i.has(s)||l.has(s)||!d.has(c.from)&&!d.has(c.to)||t.push({...N("unplanned",c,`${c.from} -> ${c.to} was added without a matching planned dependency.`,"dependency-added"),actualOperation:"added"});let u=new Set(e.changeMap.map.files.filter(s=>s.operation==="delete").map(s=>s.path));for(let[s,c]of[...a].sort(([p],[f])=>p.localeCompare(f)))o.has(s)||u.has(c.from)||u.has(c.to)||!d.has(c.from)&&!d.has(c.to)||t.push({...N("unplanned",c,`${c.from} -> ${c.to} was removed without a planned file deletion.`,"dependency-removed"),actualOperation:"removed"});let m={satisfied:0,missing:1,contradictory:2,unplanned:3};t.sort((s,c)=>m[s.classification]-m[c.classification]||(s.subject===c.subject?0:s.subject==="file"?-1:1)||s.id.localeCompare(c.id));let g={satisfied:t.filter(s=>s.classification==="satisfied").length,missing:t.filter(s=>s.classification==="missing").length,contradictory:t.filter(s=>s.classification==="contradictory").length,unplanned:t.filter(s=>s.classification==="unplanned").length};return{schemaVersion:"1.0",readOnly:!0,changeMapHash:e.changeMap.hash,structurallyConverged:g.missing===0&&g.contradictory===0&&g.unplanned===0,behavioralCompletion:"not-evaluated",summary:g,findings:t}}function ge(e){switch(e.ruleId){case"LAYER_IMPORT_VIOLATION":return e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly?"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.":e.peerIsolation?"Extract the shared dependency to a shared layer, then preflight again.":`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, then preflight again.`;case"FORBIDDEN_GLOBAL":return`Inject ${e.target??"the capability"} through a port, then preflight again.`;case"CIRCULAR_DEPENDENCY":return"Extract the shared dependency into a third module, then preflight again.";case"RAW_EVENT_PUBLISH":return"Publish through a registered intent creator, then run Ark again.";case"PUBLISH_MISSING_SOURCE":return"Add metadata.source to the publish call, then run Ark again.";default:return`Resolve ${typeof e.ruleId=="string"&&e.ruleId.length>0?e.ruleId:"ARK_UNKNOWN"} without weakening ark.config.json, then run Ark again.`}}var Z="1.0";var V=class extends Error{issues;source;constructor(t,n){super(`Invalid architecture change map (${t}):
5
+ `)}`),this.name="ArchitectureChangeMapValidationError",this.source=t,this.issues=n}};function te(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function ne(e,t,n,r){for(let i of Object.keys(e))t.includes(i)||r.push({path:`${n}.${i}`,message:"unknown field"})}function P(e,t,n,r){let i=e[t];if(typeof i=="string"&&i.length>0)return i;r.push({path:`${n}.${t}`,message:"must be a non-empty string"})}function Be(e){let t=e.replace(/\\/g,"/");if(!t||t.startsWith("/")||/^[A-Za-z]:\//.test(t)||t.includes("\0"))return;let n=[];for(let i of t.split("/"))if(!(!i||i==="."))if(i===".."){if(n.length===0)return;n.pop()}else n.push(i);let r=n.join("/");return r&&r===t?r:void 0}function ze(e,t,n="architecture change map"){let r=[];if(!te(e))throw new U(n,[{path:"$",message:"must be an object"}]);ne(e,["$schema","schemaVersion","files","dependencies"],"$",r);let i=P(e,"$schema","$",r),a=P(e,"schemaVersion","$",r);a&&a!==ee&&r.push({path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(a)}; expected ${ee}`});let o=new Set(t.layers.map(d=>d.name)),l=[],p=new Set;!Array.isArray(e.files)||e.files.length===0?r.push({path:"$.files",message:"must be a non-empty array"}):e.files.forEach((d,f)=>{let y=`$.files[${f}]`;if(!te(d)){r.push({path:y,message:"must be an object"});return}ne(d,["path","operation","layer"],y,r);let h=P(d,"path",y,r),A=P(d,"operation",y,r),C=P(d,"layer",y,r),k=h?Be(h):void 0;h&&!k&&r.push({path:`${y}.path`,message:"must be a canonical project-relative path"}),A&&!["create","update","delete"].includes(A)&&r.push({path:`${y}.operation`,message:"must be create, update, or delete"}),C&&!o.has(C)&&r.push({path:`${y}.layer`,message:`references unknown layer ${JSON.stringify(C)}`}),k&&p.has(k)&&r.push({path:`${y}.path`,message:`duplicates planned path ${k}`}),k&&p.add(k);let Z=k?_(k,t.layers):void 0;k&&C&&o.has(C)&&Z!==C&&r.push({path:`${y}.layer`,message:Z?`${k} resolves to ${Z}, not ${C}`:`${k} is not assigned to an architecture layer`}),k&&A&&["create","update","delete"].includes(A)&&C&&l.push({path:k,operation:A,layer:C})});let u=[],m=new Map(l.map(d=>[d.path,d.operation])),g=new Set,c=e.dependencies??[];if(Array.isArray(c)?c.forEach((d,f)=>{let y=`$.dependencies[${f}]`;if(!te(d)){r.push({path:y,message:"must be an object"});return}ne(d,["from","to"],y,r);let h=P(d,"from",y,r),A=P(d,"to",y,r);h&&!p.has(h)&&r.push({path:`${y}.from`,message:`must reference a planned file path: ${h}`}),A&&!p.has(A)&&r.push({path:`${y}.to`,message:`must reference a planned file path: ${A}`}),h&&m.get(h)==="delete"&&r.push({path:`${y}.from`,message:`cannot depend from deleted file ${h}`}),A&&m.get(A)==="delete"&&r.push({path:`${y}.to`,message:`cannot depend on deleted file ${A}`}),h&&A&&h===A&&r.push({path:y,message:"must not declare a self dependency"});let C=h&&A?`${h}\0${A}`:void 0;C&&g.has(C)&&r.push({path:y,message:`duplicates dependency ${h} -> ${A}`}),C&&g.add(C),h&&A&&u.push({from:h,to:A})}):r.push({path:"$.dependencies",message:"must be an array"}),r.length>0)throw new U(n,r);let s={$schema:i,schemaVersion:ee,files:l.sort((d,f)=>d.path.localeCompare(f.path)),dependencies:u.sort((d,f)=>d.from.localeCompare(f.from)||d.to.localeCompare(f.to))};return{map:s,hash:$(x(s))}}function w(e){return`${e.from}->${e.to}`}function F(e,t,n,r="dependency"){return{id:`${e}:${r}:${w(t)}`,classification:e,subject:"dependency",from:t.from,to:t.to,message:n,...e==="missing"?{nextAction:`Add the planned dependency ${w(t)} to the candidate, then preflight again.`}:e==="contradictory"?{nextAction:`Replace the reverse dependency with ${w(t)}, then preflight again.`}:e==="unplanned"?{nextAction:`Remove the unplanned dependency ${w(t)} from the candidate, then preflight again.`}:{}}}function re(e){let t=[],n=new Map(e.changeMap.map.files.map(c=>[c.path,c])),r=new Map(e.changes.map(c=>[c.path,c])),i=new Map(e.changeMap.map.dependencies.map(c=>[w(c),c])),a=new Map(e.baseDependencies.map(c=>[w(c),c])),o=new Map(e.candidateDependencies.map(c=>[w(c),c]));for(let c of[...n.values()].sort((s,d)=>s.path.localeCompare(d.path))){let s=r.get(c.path);s?s.operation!==c.operation?t.push({id:`contradictory:file:${c.path}`,classification:"contradictory",subject:"file",path:c.path,expectedOperation:c.operation,actualOperation:s.operation,message:`${c.path} was planned as ${c.operation} but the actual operation is ${s.operation}.`,nextAction:`Change ${c.path} to the planned ${c.operation} operation, then preflight again.`}):t.push({id:`satisfied:file:${c.path}`,classification:"satisfied",subject:"file",path:c.path,expectedOperation:c.operation,actualOperation:s.operation,message:`${c.path} matches the planned ${c.operation} operation.`}):t.push({id:`missing:file:${c.path}`,classification:"missing",subject:"file",path:c.path,expectedOperation:c.operation,message:`${c.path} was planned as ${c.operation} but is absent from the actual change.`,nextAction:`${c.operation[0].toUpperCase()}${c.operation.slice(1)} ${c.path} in the complete change set, then preflight again.`})}for(let c of[...r.values()].sort((s,d)=>s.path.localeCompare(d.path)))n.has(c.path)||t.push({id:`unplanned:file:${c.path}`,classification:"unplanned",subject:"file",path:c.path,actualOperation:c.operation,message:`${c.path} has an unplanned ${c.operation} operation.`,nextAction:`Remove ${c.path} from the change set, then preflight again.`});let l=new Set;for(let c of[...i.values()].sort((s,d)=>w(s).localeCompare(w(d)))){if(o.has(w(c))){t.push(F("satisfied",c,`${c.from} -> ${c.to} exists in the candidate architecture.`));continue}let s={from:c.to,to:c.from};o.has(w(s))?(l.add(w(s)),t.push(F("contradictory",c,`${c.from} -> ${c.to} was planned, but the candidate contains the reverse edge.`))):t.push(F("missing",c,`${c.from} -> ${c.to} is absent from the candidate architecture.`))}let p=new Set([...n.keys(),...r.keys()]);for(let[c,s]of[...o].sort(([d],[f])=>d.localeCompare(f)))a.has(c)||i.has(c)||l.has(c)||!p.has(s.from)&&!p.has(s.to)||t.push({...F("unplanned",s,`${s.from} -> ${s.to} was added without a matching planned dependency.`,"dependency-added"),actualOperation:"added"});let u=new Set(e.changeMap.map.files.filter(c=>c.operation==="delete").map(c=>c.path));for(let[c,s]of[...a].sort(([d],[f])=>d.localeCompare(f)))o.has(c)||u.has(s.from)||u.has(s.to)||!p.has(s.from)&&!p.has(s.to)||t.push({...F("unplanned",s,`${s.from} -> ${s.to} was removed without a planned file deletion.`,"dependency-removed"),actualOperation:"removed"});let m={satisfied:0,missing:1,contradictory:2,unplanned:3};t.sort((c,s)=>m[c.classification]-m[s.classification]||(c.subject===s.subject?0:c.subject==="file"?-1:1)||c.id.localeCompare(s.id));let g={satisfied:t.filter(c=>c.classification==="satisfied").length,missing:t.filter(c=>c.classification==="missing").length,contradictory:t.filter(c=>c.classification==="contradictory").length,unplanned:t.filter(c=>c.classification==="unplanned").length};return{schemaVersion:"1.0",readOnly:!0,changeMapHash:e.changeMap.hash,structurallyConverged:g.missing===0&&g.contradictory===0&&g.unplanned===0,behavioralCompletion:"not-evaluated",summary:g,findings:t}}function M(e,t){return t&&e.isStringLiteralLike(t)?t.text:void 0}function we(e,t){return e.getLineAndCharacterOfPosition(t.getStart(e)).line+1}function Ie(e,t){if(e.isImportDeclaration(t)){let n=t.importClause;if(!n)return!1;if(n.isTypeOnly)return!0;let r=n.namedBindings;return!!(r&&e.isNamedImports(r)&&r.elements.length>0&&r.elements.every(i=>i.isTypeOnly))}if(e.isExportDeclaration(t)){if(t.isTypeOnly)return!0;let n=t.exportClause;return!!(n&&e.isNamedExports(n)&&n.elements.length>0&&n.elements.every(r=>r.isTypeOnly))}return!1}function Se(e,t){let n={noLib:!0,noResolve:!0,target:e.ScriptTarget.Latest},r=e.createCompilerHost(n,!0);return r.getSourceFile=i=>i===t.fileName?t:void 0,r.fileExists=i=>i===t.fileName,r.readFile=i=>i===t.fileName?t.text:void 0,e.createProgram([t.fileName],n,r).getTypeChecker()}function ie(e,t){try{return e.getSymbolAtLocation(t)}catch{return}}function ae(e,t,n,r){let i=r.parent&&e.isShorthandPropertyAssignment(r.parent)&&r.parent.name===r,a;try{a=i?t.getShorthandAssignmentValueSymbol(r.parent):ie(t,r)}catch{a=void 0}return!!a?.declarations?.some(o=>o.getSourceFile().fileName===n.fileName)}function se(e,t){let n,r=[],i=(o,l,p,u=!1)=>r.push({specifier:p,kind:l,line:we(t,o),typeOnly:u,unresolved:p===void 0,node:o}),a=o=>{if(e.isImportDeclaration(o))i(o,"import",M(e,o.moduleSpecifier),Ie(e,o));else if(e.isExportDeclaration(o)&&o.moduleSpecifier)i(o,"export",M(e,o.moduleSpecifier),Ie(e,o));else if(e.isImportEqualsDeclaration(o)&&e.isExternalModuleReference(o.moduleReference))i(o,"require",M(e,o.moduleReference.expression));else if(e.isCallExpression(o)){let l=o.expression.kind===e.SyntaxKind.ImportKeyword,u=e.isIdentifier(o.expression)&&o.expression.text==="require"&&!ae(e,n??(n=Se(e,t)),t,o.expression);(l||u)&&i(o,u?"require":"dynamic-import",M(e,o.arguments[0]))}e.forEachChild(o,a)};return a(t),r}function qe(e,t){let n=[],r=t;for(;e.isPropertyAccessExpression(r)||e.isElementAccessExpression(r);){if(e.isPropertyAccessExpression(r))n.unshift(r.name.text);else{let i=M(e,r.argumentExpression);if(i===void 0)return;n.unshift(i)}r=r.expression}if(e.isIdentifier(r))return n.unshift(r.text),{root:r,segments:n}}function Ke(e,t){let n=t.parent;return e.isPropertyAccessExpression(n)||e.isElementAccessExpression(n)?!1:e.isExpressionNode(t)&&!e.isInTypeQuery(t)||e.isShorthandPropertyAssignment(n)&&n.name===t}function ke(e,t){let n=t[0]==="globalThis"?t.slice(1):t;for(let r=n.length;r>=1;r-=1){let i=n.slice(0,r).join(".");if(e.has(i))return i}}function oe(e,t,n){if(n.length===0)return[];let r=new Set(n),i=Se(e,t),a=new Map,o=new Set;for(let c of t.statements)if(e.isVariableStatement(c))for(let s of c.declarationList.declarations)e.isIdentifier(s.name)&&o.add(s.name.text);let l=c=>{let s=qe(e,c);if(!s)return;let d=ie(i,s.root),f=d?a.get(d):void 0;return f?[...f,...s.segments.slice(1)]:ae(e,i,t,s.root)||o.has(s.root.text)?void 0:s.segments};for(let c of t.statements)if(e.isVariableStatement(c))for(let s of c.declarationList.declarations){if(!s.initializer||!e.isIdentifier(s.name))continue;let d=l(s.initializer),f=ie(i,s.name);!d||!f||a.set(f,d)}let p=[],u=new Set,m=(c,s)=>{let d=we(t,s),f=`${c}:${s.getStart(t)}`;u.has(f)||(u.add(f),p.push({name:c,line:d,node:s}))},g=c=>{let s=c.parent&&(e.isPropertyAccessExpression(c.parent)||e.isElementAccessExpression(c.parent))&&c.parent.expression===c;if((e.isPropertyAccessExpression(c)||e.isElementAccessExpression(c))&&!s){let d=l(c),f=d?ke(r,d):void 0;f&&m(f,c)}else e.isIdentifier(c)&&r.has(c.text)&&Ke(e,c)&&!ae(e,i,t,c)&&m(c.text,c);if(e.isVariableDeclaration(c)&&e.isObjectBindingPattern(c.name)&&c.initializer){let d=l(c.initializer);if(d)for(let f of c.name.elements){if(!e.isIdentifier(f.name))continue;let y=f.propertyName?M(e,f.propertyName)??f.propertyName.text:f.name.text,h=ke(r,[...d,y]);h&&m(h,c.initializer)}}e.forEachChild(c,g)};return g(t),p}var ce={RAW_EVENT_PUBLISH:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",PUBLISH_MISSING_SOURCE:"Strict Ark publish calls must include metadata.source."};function xe(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function Ye(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&xe(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ce.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ce.PUBLISH_MISSING_SOURCE}),t}var pe=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),B=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),de=Object.freeze(Object.keys(B).sort()),le=Object.freeze({fs:"filesystem","node:fs":"filesystem","fs/promises":"filesystem","node:fs/promises":"filesystem","fs-extra":"filesystem","graceful-fs":"filesystem",memfs:"filesystem",chokidar:"filesystem",http:"network",https:"network",http2:"network",net:"network",tls:"network",dgram:"network",dns:"network","node:http":"network","node:https":"network","node:http2":"network","node:net":"network","node:tls":"network","node:dgram":"network","node:dns":"network",axios:"network",undici:"network","node-fetch":"network",got:"network",ky:"network",superagent:"network",ws:"network",process:"process","node:process":"process",child_process:"process","node:child_process":"process","@prisma/client":"persistence",prisma:"persistence",pg:"persistence",mysql:"persistence",mysql2:"persistence",mongodb:"persistence",mongoose:"persistence",sqlite3:"persistence","better-sqlite3":"persistence",redis:"persistence",ioredis:"persistence",typeorm:"persistence",knex:"persistence","drizzle-orm":"persistence",sequelize:"persistence",kysely:"persistence","@supabase/supabase-js":"persistence"});function j(e){if(!e||e.startsWith(".")||e.startsWith("/"))return null;let t=le[e];if(t)return t;let n=e.indexOf("/");if(n<0)return null;let r=e.slice(0,n),i=le[r];if(i)return i;let a=e.indexOf("/",n+1);return a<0?null:le[e.slice(0,a)]??null}function V(e){let t=e.split(".");for(let n=t.length;n>=1;n-=1){let r=t.slice(0,n).join("."),i=B[r];if(i)return i}return null}function z(e){if(e?.pure===!0)return[...pe].sort();let n=(e?.capabilities?.deny??[]).filter(r=>pe.includes(r));return[...new Set(n)].sort()}function We(e,t){if(t.length===0)return!1;let n=new Set(t),r=e.split(".");for(let i=r.length;i>=1;i-=1)if(n.has(r.slice(0,i).join(".")))return!0;return!1}function q(e){let t=new Set,n=new Set,r=Object.keys(B);for(let i of e?.forbiddenGlobals??[]){let a=r.filter(o=>o===i||o.startsWith(`${i}.`));if(a.length===0)n.add(i);else for(let o of a)t.add(`ambient:${o}`)}for(let i of z(e)){t.add(`import:${i}`);for(let a of r)V(a)===i&&t.add(`ambient:${a}`)}return{atoms:[...t].sort(),rawGlobals:[...n].sort()}}function Je(e){let t=new Set,n=V(e);n&&t.add(n);for(let[r,i]of Object.entries(B))(r===e||r.startsWith(`${e}.`))&&t.add(i);return[...t].sort()}function Ze(e,t){let n=[];for(let r of se(e,t)){if(r.typeOnly||!r.specifier)continue;let i=j(r.specifier);i&&n.push({capability:i,symbol:r.specifier,line:r.line,source:"import-based"})}for(let r of oe(e,t,de)){let i=V(r.name);i&&n.push({capability:i,symbol:r.name,line:r.line,source:"ambient-global"})}return n.sort((r,i)=>r.line-i.line||r.capability.localeCompare(i.capability)||r.symbol.localeCompare(i.symbol))}var ue="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",Ee=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],Xe=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function Qe(){let e=[];for(let t of Ee)for(let n of Ee)t===n||Xe.has(`${t}->${n}`)||e.push({from:t,to:n,allowed:!1});return e}var Oe=Qe();var O={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},$e={$schema:"https://json-schema.org/draft/2020-12/schema",$id:ue,title:"ArkGate architecture contract",description:"Versioned contract consumed identically by ArkGate CLI, MCP, and ESLint surfaces.",type:"object",additionalProperties:!1,required:["$schema","schemaVersion","include","layers","rules"],properties:{$schema:{type:"string",minLength:1,default:ue,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.0",default:"1.0"},name:{type:"string",minLength:1},include:{...O,minItems:1,default:["src"]},exclude:{...O,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:Oe,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...O,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...O,minItems:1},exclude:O,intentPrefixes:O,description:{type:"string",minLength:1},forbiddenGlobals:O,capabilities:{type:"object",additionalProperties:!1,properties:{deny:{type:"array",uniqueItems:!0,items:{type:"string",enum:["network","filesystem","clock","randomness","environment","process","persistence"]}}}},pure:{type:"boolean"},mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"}}},rule:{type:"object",additionalProperties:!1,required:["from","to","allowed"],properties:{from:{type:"string",minLength:1},to:{type:"string",minLength:1},allowed:{type:"boolean"},message:{type:"string",minLength:1},peerIsolation:{type:"boolean"},sliceFolders:{...O,minItems:1}}},safety:{type:"object",additionalProperties:!1,properties:{maxTsSuppressions:{type:"integer",minimum:0,default:0},maxAnyCasts:{type:"integer",minimum:0,default:0},allowInMemory:{type:"boolean",default:!1},allowDisabledPeerIsolation:{type:"boolean",default:!1}}}}},T=class extends Error{issues;source;constructor(t,n){super(`Invalid ArkGate config (${t}):
6
6
  ${n.map(r=>`- ${r.path}: ${r.message}`).join(`
7
- `)}`),this.name="ArchitectureChangeMapValidationError",this.source=t,this.issues=n}};function Q(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function X(e,t,n,r){for(let i of Object.keys(e))t.includes(i)||r.push({path:`${n}.${i}`,message:"unknown field"})}function O(e,t,n,r){let i=e[t];if(typeof i=="string"&&i.length>0)return i;r.push({path:`${n}.${t}`,message:"must be a non-empty string"})}function Te(e){let t=e.replace(/\\/g,"/");if(!t||t.startsWith("/")||/^[A-Za-z]:\//.test(t)||t.includes("\0"))return;let n=[];for(let i of t.split("/"))if(!(!i||i==="."))if(i===".."){if(n.length===0)return;n.pop()}else n.push(i);let r=n.join("/");return r&&r===t?r:void 0}function Fe(e,t,n="architecture change map"){let r=[];if(!Q(e))throw new V(n,[{path:"$",message:"must be an object"}]);X(e,["$schema","schemaVersion","files","dependencies"],"$",r);let i=O(e,"$schema","$",r),a=O(e,"schemaVersion","$",r);a&&a!==Z&&r.push({path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(a)}; expected ${Z}`});let o=new Set(t.layers.map(p=>p.name)),l=[],d=new Set;!Array.isArray(e.files)||e.files.length===0?r.push({path:"$.files",message:"must be a non-empty array"}):e.files.forEach((p,f)=>{let h=`$.files[${f}]`;if(!Q(p)){r.push({path:h,message:"must be an object"});return}X(p,["path","operation","layer"],h,r);let y=O(p,"path",h,r),A=O(p,"operation",h,r),b=O(p,"layer",h,r),x=y?Te(y):void 0;y&&!x&&r.push({path:`${h}.path`,message:"must be a canonical project-relative path"}),A&&!["create","update","delete"].includes(A)&&r.push({path:`${h}.operation`,message:"must be create, update, or delete"}),b&&!o.has(b)&&r.push({path:`${h}.layer`,message:`references unknown layer ${JSON.stringify(b)}`}),x&&d.has(x)&&r.push({path:`${h}.path`,message:`duplicates planned path ${x}`}),x&&d.add(x);let U=x?M(x,t.layers):void 0;x&&b&&o.has(b)&&U!==b&&r.push({path:`${h}.layer`,message:U?`${x} resolves to ${U}, not ${b}`:`${x} is not assigned to an architecture layer`}),x&&A&&["create","update","delete"].includes(A)&&b&&l.push({path:x,operation:A,layer:b})});let u=[],m=new Map(l.map(p=>[p.path,p.operation])),g=new Set,s=e.dependencies??[];if(Array.isArray(s)?s.forEach((p,f)=>{let h=`$.dependencies[${f}]`;if(!Q(p)){r.push({path:h,message:"must be an object"});return}X(p,["from","to"],h,r);let y=O(p,"from",h,r),A=O(p,"to",h,r);y&&!d.has(y)&&r.push({path:`${h}.from`,message:`must reference a planned file path: ${y}`}),A&&!d.has(A)&&r.push({path:`${h}.to`,message:`must reference a planned file path: ${A}`}),y&&m.get(y)==="delete"&&r.push({path:`${h}.from`,message:`cannot depend from deleted file ${y}`}),A&&m.get(A)==="delete"&&r.push({path:`${h}.to`,message:`cannot depend on deleted file ${A}`}),y&&A&&y===A&&r.push({path:h,message:"must not declare a self dependency"});let b=y&&A?`${y}\0${A}`:void 0;b&&g.has(b)&&r.push({path:h,message:`duplicates dependency ${y} -> ${A}`}),b&&g.add(b),y&&A&&u.push({from:y,to:A})}):r.push({path:"$.dependencies",message:"must be an array"}),r.length>0)throw new V(n,r);let c={$schema:i,schemaVersion:Z,files:l.sort((p,f)=>p.path.localeCompare(f.path)),dependencies:u.sort((p,f)=>p.from.localeCompare(f.from)||p.to.localeCompare(f.to))};return{map:c,hash:$(E(c))}}function v(e,t){return t&&e.isStringLiteralLike(t)?t.text:void 0}function me(e,t){return e.getLineAndCharacterOfPosition(t.getStart(e)).line+1}function he(e,t){if(e.isImportDeclaration(t)){let n=t.importClause;if(!n)return!1;if(n.isTypeOnly)return!0;let r=n.namedBindings;return!!(r&&e.isNamedImports(r)&&r.elements.length>0&&r.elements.every(i=>i.isTypeOnly))}if(e.isExportDeclaration(t)){if(t.isTypeOnly)return!0;let n=t.exportClause;return!!(n&&e.isNamedExports(n)&&n.elements.length>0&&n.elements.every(r=>r.isTypeOnly))}return!1}function Ae(e,t){let n={noLib:!0,noResolve:!0,target:e.ScriptTarget.Latest},r=e.createCompilerHost(n,!0);return r.getSourceFile=i=>i===t.fileName?t:void 0,r.fileExists=i=>i===t.fileName,r.readFile=i=>i===t.fileName?t.text:void 0,e.createProgram([t.fileName],n,r).getTypeChecker()}function ee(e,t){try{return e.getSymbolAtLocation(t)}catch{return}}function te(e,t,n,r){let i=r.parent&&e.isShorthandPropertyAssignment(r.parent)&&r.parent.name===r,a;try{a=i?t.getShorthandAssignmentValueSymbol(r.parent):ee(t,r)}catch{a=void 0}return!!a?.declarations?.some(o=>o.getSourceFile().fileName===n.fileName)}function je(e,t){let n,r=[],i=(o,l,d,u=!1)=>r.push({specifier:d,kind:l,line:me(t,o),typeOnly:u,unresolved:d===void 0,node:o}),a=o=>{if(e.isImportDeclaration(o))i(o,"import",v(e,o.moduleSpecifier),he(e,o));else if(e.isExportDeclaration(o)&&o.moduleSpecifier)i(o,"export",v(e,o.moduleSpecifier),he(e,o));else if(e.isImportEqualsDeclaration(o)&&e.isExternalModuleReference(o.moduleReference))i(o,"require",v(e,o.moduleReference.expression));else if(e.isCallExpression(o)){let l=o.expression.kind===e.SyntaxKind.ImportKeyword,u=e.isIdentifier(o.expression)&&o.expression.text==="require"&&!te(e,n??(n=Ae(e,t)),t,o.expression);(l||u)&&i(o,u?"require":"dynamic-import",v(e,o.arguments[0]))}e.forEachChild(o,a)};return a(t),r}function He(e,t){let n=[],r=t;for(;e.isPropertyAccessExpression(r)||e.isElementAccessExpression(r);){if(e.isPropertyAccessExpression(r))n.unshift(r.name.text);else{let i=v(e,r.argumentExpression);if(i===void 0)return;n.unshift(i)}r=r.expression}if(e.isIdentifier(r))return n.unshift(r.text),{root:r,segments:n}}function Ve(e,t){let n=t.parent;return e.isPropertyAccessExpression(n)||e.isElementAccessExpression(n)?!1:e.isExpressionNode(t)&&!e.isInTypeQuery(t)||e.isShorthandPropertyAssignment(n)&&n.name===t}function ye(e,t){let n=t[0]==="globalThis"?t.slice(1):t;for(let r=n.length;r>=1;r-=1){let i=n.slice(0,r).join(".");if(e.has(i))return i}}function Ge(e,t,n){if(n.length===0)return[];let r=new Set(n),i=Ae(e,t),a=new Map,o=new Set;for(let s of t.statements)if(e.isVariableStatement(s))for(let c of s.declarationList.declarations)e.isIdentifier(c.name)&&o.add(c.name.text);let l=s=>{let c=He(e,s);if(!c)return;let p=ee(i,c.root),f=p?a.get(p):void 0;return f?[...f,...c.segments.slice(1)]:te(e,i,t,c.root)||o.has(c.root.text)?void 0:c.segments};for(let s of t.statements)if(e.isVariableStatement(s))for(let c of s.declarationList.declarations){if(!c.initializer||!e.isIdentifier(c.name))continue;let p=l(c.initializer),f=ee(i,c.name);!p||!f||a.set(f,p)}let d=[],u=new Set,m=(s,c)=>{let p=me(t,c),f=`${s}:${c.getStart(t)}`;u.has(f)||(u.add(f),d.push({name:s,line:p,node:c}))},g=s=>{let c=s.parent&&(e.isPropertyAccessExpression(s.parent)||e.isElementAccessExpression(s.parent))&&s.parent.expression===s;if((e.isPropertyAccessExpression(s)||e.isElementAccessExpression(s))&&!c){let p=l(s),f=p?ye(r,p):void 0;f&&m(f,s)}else e.isIdentifier(s)&&r.has(s.text)&&Ve(e,s)&&!te(e,i,t,s)&&m(s.text,s);if(e.isVariableDeclaration(s)&&e.isObjectBindingPattern(s.name)&&s.initializer){let p=l(s.initializer);if(p)for(let f of s.name.elements){if(!e.isIdentifier(f.name))continue;let h=f.propertyName?v(e,f.propertyName)??f.propertyName.text:f.name.text,y=ye(r,[...p,h]);y&&m(y,s.initializer)}}e.forEachChild(s,g)};return g(t),d}var ne={RAW_EVENT_PUBLISH:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts and tooling.",PUBLISH_MISSING_SOURCE:"Strict Ark publish calls must include metadata.source."};function Ce(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function Ue(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&Ce(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ne.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ne.PUBLISH_MISSING_SOURCE}),t}function be(e,t){let n=typeof e=="string"?ce(e,t):q(e,t);return{...n,policyHash:$(E(n.config))}}function mt(e){let t=be(e.baseConfig,e.baseSource??"base ark.config.json"),n=be(e.candidateConfig,e.candidateSource??"candidate ark.config.json"),r=fe(t.config,n.config),i=r.findings.filter(l=>l.classification==="weakening"||l.classification==="judgment-required").map(l=>l.id).sort(),a=i.length>0,o=a&&ue(e.acknowledgement,{basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,findingIds:i});return{schemaVersion:r.schemaVersion,basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,classification:r.classification,findings:r.findings,blockingFindingIds:i,requiresAcknowledgement:a,acknowledged:o,valid:!a||o}}function T(e){let t=[];for(let n of e.replace(/\\/g,"/").split("/"))!n||n==="."||(n===".."&&t.length>0&&t.at(-1)!==".."?t.pop():t.push(n));return t.join("/")}function Ie(e){return e!==void 0&&/[A-Za-z0-9_$]/.test(e)}function re(e,t){for(;t<e.length&&/\s/.test(e[t]);)t+=1;return t}function G(e,t){let n=e[t];if(n!=="'"&&n!=='"')return;let r=t,i="";for(t+=1;t<e.length;t+=1){let a=e[t];if(a===n)return{value:i,offset:r,excerpt:e.slice(r,t+1)};a==="\\"&&t+1<e.length?(i+=e[t+1],t+=1):i+=a}}function D(e,t,n){return e.startsWith(t,n)&&!Ie(e[n-1])&&!Ie(e[n+t.length])}function Ke(e,t){return t=re(e,t+6),e[t]==="("?G(e,re(e,t+1)):Se(e,t,!0)}function qe(e,t){return Se(e,t+6,!1)}function Se(e,t,n){for(;t<e.length;t+=1){if(e[t]===";")return;if(D(e,"from",t))return G(e,re(e,t+4));if(n&&(e[t]==="'"||e[t]==='"'))return G(e,t);if(t>0&&(D(e,"import",t)||D(e,"export",t)))return}}function ze(e){let t=[];for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="/"&&e[n+1]==="/"){if(n=e.indexOf(`
8
- `,n+2),n<0)break;continue}if(r==="/"&&e[n+1]==="*"){let a=e.indexOf("*/",n+2);if(a<0)break;n=a+1;continue}if(r==="'"||r==='"'||r==="`"){let a=G(e,n);a&&(n=a.offset+a.excerpt.length-1);continue}let i=D(e,"import",n)?Ke(e,n):D(e,"export",n)?qe(e,n):void 0;i&&t.push(i)}return t}function Ye(e,t){let n=[];for(let r of ze(e.content)){let i=r.value;if(!i.startsWith("."))continue;let a=e.content.slice(0,r.offset).split(`
9
- `).length,o={kind:"import",file:e.path,line:a,excerpt:r.excerpt},l=We(e.path,i,t);n.push({from:e.path,specifier:i,to:l?.path??null,resolution:l?"resolved":"unresolved",fromLayer:e.layer,toLayer:l?.layer??null,evidence:o})}return n}function We(e,t,n){let r=e.split("/");r.pop();for(let a of t.split("/"))a==="."||a===""||(a===".."?r.pop():r.push(a));let i=r.join("/");for(let a of[i,`${i}.ts`,`${i}.tsx`,`${i}.mts`,`${i}.cts`,`${i}/index.ts`,`${i}/index.tsx`]){let o=n.get(a);if(o)return o}}function Je(e,t){let n=[];for(let r of e){if(!r.to||!r.fromLayer||!r.toLayer)continue;let i=W(t.rules,r.fromLayer,r.toLayer,{fromPath:r.from,toPath:r.to,layers:t.layers});i&&n.push({ruleId:`layer-dependency:${i.from}->${i.to}`,message:i.message??`${i.from} must not depend on ${i.to}.`,edge:r,evidence:r.evidence})}return n}function ke(e){let t=e.files.map(o=>{let l=T(o.path);return{path:l,content:o.content,contentHash:$(o.content),layer:M(l,e.contract.config.layers)??null}}).sort((o,l)=>o.path.localeCompare(l.path)),n=new Map(t.map(o=>[o.path,o])),r=t.flatMap(o=>Ye(o,n)),i=[],a=Je(r,e.contract.config);return{ir:{schemaVersion:"1.0",policyHash:e.contract.policyHash,compilerOptionsHash:$(E(e.compilerOptions??{})),files:t,layers:e.contract.config.layers.map(o=>o.name),edges:r,capabilityUses:i,violations:a}}}function Ze(e){let t=new Map(e.files.map(n=>[T(n.path),n]));for(let n of e.changes){let r=T(n.path);"delete"in n&&n.delete?t.delete(r):"content"in n&&t.set(r,{path:r,content:n.content})}return ke({contract:e.contract,files:[...t.values()],compilerOptions:e.compilerOptions})}function At(e){let t=`${e.evidence.file}:${e.evidence.line}`;if(!e.edge)return`${e.ruleId} at ${t}: ${e.message}`;let n=e.edge.to??e.edge.specifier;return`${e.ruleId} at ${t}: ${e.edge.from} imports ${n}. ${e.message}`}function Qe(e){let t=0,n=new Map,r=new Map,i=new Set,a=[],o=[],l=d=>{n.set(d,t),r.set(d,t),t+=1,a.push(d),i.add(d);for(let g of[...e.get(d)??[]].sort())e.has(g)&&(n.has(g)?i.has(g)&&r.set(d,Math.min(r.get(d)??0,n.get(g)??0)):(l(g),r.set(d,Math.min(r.get(d)??0,r.get(g)??0))));if(r.get(d)!==n.get(d))return;let u=[],m;do{if(m=a.pop(),m===void 0)break;i.delete(m),u.push(m)}while(m!==d);u.length>1&&o.push(u.sort())};for(let d of[...e.keys()].sort())n.has(d)||l(d);return o.sort((d,u)=>d[0].localeCompare(u[0])).map(d=>({ruleId:"CIRCULAR_DEPENDENCY",file:d[0],line:1,target:d.join(" \u2192 "),message:`Circular dependency among ${d.length} files: ${d.join(" \u2192 ")} \u2192 ${d[0]}.`,cycleKind:"value"}))}function Xe(e){let t=e.contentViolations.map(a=>({...a})),n=(e.warnings??[]).map(a=>({...a})),r=new Map(e.files.map(a=>[a,new Set]));for(let a of e.edges){if(a.to&&a.to!==a.from&&!a.typeOnly&&r.has(a.from)&&r.get(a.from)?.add(a.to),!a.to||!a.toLayer)continue;let o=W(e.rules,a.fromLayer,a.toLayer,{fromPath:a.from,toPath:a.to,layers:e.config.layers});if(!o)continue;let l=!!o.peerIsolation;t.push({ruleId:"LAYER_IMPORT_VIOLATION",file:a.from,line:a.line,fromLayer:a.fromLayer,toLayer:a.toLayer,target:a.to,...a.typeOnly?{typeOnly:!0}:{},...a.targetTypeOnlyExports?{targetTypeOnlyExports:!0}:{},...a.sourcePureTypeModule?{sourcePureTypeModule:!0}:{},...a.namedBindingsTypeOnly?{namedBindingsTypeOnly:!0}:{},...!l&&a.portProofEligible?{portProofEligible:!0}:{},...a.kind?{edgeKind:a.kind}:{},...l?{peerIsolation:!0}:{},message:o.message??(l?`${a.fromLayer} must not ${a.kind} another slice of ${a.toLayer} (${a.from} \u2192 ${a.to}). Extract shared code or use events/ports across slices.`:`${a.fromLayer} must not ${a.kind} ${a.toLayer}.`)})}let i=String(e.config.cyclePolicy??"strict").toLowerCase();if(i!=="off"){let a=Qe(r);i==="soft"||i==="framework-soft"?n.push(...a.map(o=>({...o,message:`${o.message} (soft cycle policy \u2014 advisory only; set cyclePolicy: "strict" to fail the check)`,failsStrict:!1}))):t.push(...a)}return{violations:t,warnings:n,safety:e.safety}}function xe(e){return $(E(e.map(({path:t,contentHash:n})=>({path:t,contentHash:n}))))}function Ct(e){let t=ke(e),n=new Map(t.ir.files.map(s=>[s.path,s])),r=[],i=new Set,a=[];for(let s of e.changes){let c=s.path.replace(/\\/g,"/"),p=T(s.path);if(!p||p===".."||p.startsWith("../")||c.startsWith("/")||/^[A-Za-z]:\//.test(c)||c.includes("\0")){a.push({ruleId:"INVALID_CHANGE_PATH",file:"<change-set>",line:1,message:"Every change requires a safe, non-empty project-relative path."});continue}if(i.has(p)){a.push({ruleId:"DUPLICATE_CHANGE_PATH",file:p,line:1,message:`The atomic change set contains more than one operation for ${p}.`});continue}i.add(p),"delete"in s&&s.delete&&!n.has(p)&&a.push({ruleId:"DELETE_TARGET_MISSING",file:p,line:1,message:`Cannot delete ${p} because it is not present in the supplied base tree.`}),r.push("delete"in s&&s.delete?{path:p,delete:!0}:{path:p,content:"content"in s?s.content:""})}e.changes.length===0&&a.push({ruleId:"CHANGE_SET_EMPTY",file:"<change-set>",line:1,message:"Atomic preflight requires at least one create, update, or delete."});let o=Ze({...e,changes:r}),l=new Map(o.ir.files.map(s=>[s.path,s])),d=Xe({config:e.contract.config,rules:e.contract.config.rules,files:o.ir.files.map(s=>s.path),contentViolations:[],edges:o.ir.edges.filter(s=>!!s.fromLayer).map(s=>({from:s.from,fromLayer:s.fromLayer,...s.to?{to:s.to}:{},...s.toLayer?{toLayer:s.toLayer}:{},line:s.evidence.line,kind:"import"}))}),u=r.map(s=>{let c=T(s.path),p=n.get(c),f=l.get(c);return{path:c,operation:"delete"in s&&s.delete?"delete":p?"update":"create",...p?{beforeContentHash:p.contentHash}:{},...f?{candidateContentHash:f.contentHash}:{}}}).sort((s,c)=>s.path.localeCompare(c.path)),m=[...a,...d.violations].map(s=>({...s,nextAction:ge(s)})),g=e.changeMap?J({changeMap:e.changeMap,changes:u,baseDependencies:t.ir.edges.flatMap(s=>s.to?[{from:s.from,to:s.to}]:[]),candidateDependencies:o.ir.edges.flatMap(s=>s.to?[{from:s.from,to:s.to}]:[])}):void 0;return{schemaVersion:"1.0",valid:m.length===0&&(g?.structurallyConverged??!0),readOnly:!0,policyHash:e.contract.policyHash,compilerOptionsHash:o.ir.compilerOptionsHash,baseTreeHash:xe(t.ir.files),candidateTreeHash:xe(o.ir.files),...e.changeMap?{changeMapHash:e.changeMap.hash}:{},...g?{convergence:g}:{},changes:u,violations:m,warnings:d.warnings}}function I(e,t,n={}){return{ruleId:e,message:t,...n}}function bt(e){let{config:t,rules:n,files:r,manifest:i}=e,a=[];if(t.dynamicImportAllowlist!==void 0&&(!Array.isArray(t.dynamicImportAllowlist)||t.dynamicImportAllowlist.some(c=>typeof c!="string"))&&a.push(I("CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST","dynamicImportAllowlist must be an array of file globs.")),t.safety!==void 0&&(t.safety===null||typeof t.safety!="object"||Array.isArray(t.safety)))a.push(I("CONFIG_INVALID_SAFETY","safety must be an object."));else if(t.safety)for(let c of["maxTsSuppressions","maxAnyCasts"]){let p=t.safety[c];p!==void 0&&(!Number.isInteger(p)||p<0)&&a.push(I("CONFIG_INVALID_SAFETY_THRESHOLD",`safety.${c} must be a non-negative integer.`))}let o=Array.isArray(t.layers)?t.layers:[],l=Array.isArray(i?.architecture?.layers)?i.architecture.layers:[],d=new Set([...o.map(c=>c.name).filter(Boolean),...l.map(c=>c.name).filter(c=>!!c)]);o.length===0&&a.push(I("CONFIG_NO_LAYERS","No file layers are configured; ark-check cannot classify files for import-boundary enforcement."));let u=new Set,m=new Set;for(let c of o){if(!c.name){a.push(I("CONFIG_LAYER_WITHOUT_NAME","A configured layer is missing a name."));continue}u.has(c.name)&&m.add(c.name),u.add(c.name),c.forbiddenGlobals!==void 0&&(!Array.isArray(c.forbiddenGlobals)||c.forbiddenGlobals.some(f=>typeof f!="string"))&&a.push(I("CONFIG_INVALID_FORBIDDEN_GLOBALS",`Layer "${c.name}" has an invalid forbiddenGlobals value; expected an array of strings (e.g. ["fetch", "Date.now"]). The entry is ignored.`,{layer:c.name}));let p=Array.isArray(c.patterns)?c.patterns:[];if(p.length===0){a.push(I("CONFIG_LAYER_WITHOUT_PATTERNS",`Layer "${c.name}" has no file patterns and will never classify files.`,{layer:c.name}));continue}for(let f of p){let h;try{h=_(f)}catch(y){a.push(I("CONFIG_INVALID_LAYER_PATTERN",`Layer "${c.name}" has an invalid pattern "${f}": ${y instanceof Error?y.message:String(y)}`,{layer:c.name,pattern:f}));continue}!r.some(y=>h.test(y))&&!c.optional&&a.push(I("CONFIG_LAYER_PATTERN_NO_MATCHES",`Layer "${c.name}" pattern "${f}" matched no included files.`,{layer:c.name,pattern:f,failsStrict:!1}))}}for(let c of m)a.push(I("CONFIG_DUPLICATE_LAYER",`Layer "${c}" is configured more than once.`,{layer:c}));if(d.size>0)for(let c of n??[])c.from&&!d.has(c.from)&&a.push(I("CONFIG_RULE_UNKNOWN_FROM_LAYER",`Rule references unknown source layer "${c.from}".`,{fromLayer:c.from,toLayer:c.to})),c.to&&!d.has(c.to)&&a.push(I("CONFIG_RULE_UNKNOWN_TO_LAYER",`Rule references unknown target layer "${c.to}".`,{fromLayer:c.from,toLayer:c.to}));let g=new Set;if(o.length>1)for(let c of r){let p=-1,f=[];for(let h of o)for(let y of h.patterns??[]){if(!_(y).test(c))continue;let A=Y(y);A>p?(p=A,f=[h.name]):A===p&&!f.includes(h.name)&&f.push(h.name)}f.length>1&&g.add([...f].sort().join(" + "))}g.size>0&&a.push(I("CONFIG_AMBIGUOUS_LAYERS",`Some files match multiple layers at equal specificity; classification falls back to declaration order. Disambiguate the overlapping patterns: ${[...g].join(", ")}.`,{pairs:[...g]}));let s=r.filter(c=>!M(c,o));return s.length>0&&a.push(I("CONFIG_UNCLASSIFIED_FILES",`${s.length} included source file(s) are not matched by any configured layer; ark-check will not enforce import rules for those source files.`,{count:s.length,samples:s.slice(0,5)})),a}export{ne as SOURCE_POLICY_MESSAGES,J as analyzeArchitectureConvergence,Ze as analyzeChange,mt as analyzePolicyDelta,ke as analyzeProject,Ue as classifyPublishFacts,bt as collectAnalysisConfigWarnings,Ge as collectForbiddenCapabilityUses,Qe as detectArchitectureCycles,Xe as evaluateArchitectureGraph,At as explainViolation,je as extractSemanticDependencies,Fe as loadArchitectureChangeMap,be as loadContract,Ce as looksLikeArkIntent,Ct as preflightChange};
7
+ `)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=n}};function Le(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function fe(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function N(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function et(e,t){let n="#/$defs/";if(e.startsWith(n))return t.$defs[e.slice(n.length)]}function K(e,t,n,r,i){if(t.$ref){let a=et(t.$ref,r);if(!a){i.push({path:n,message:`schema reference ${t.$ref} cannot be resolved`});return}K(e,a,n,r,i);return}if(t.const!==void 0&&!Object.is(e,t.const)){i.push({path:n,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(a=>Object.is(a,e))){i.push({path:n,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!Le(e)){i.push({path:n,message:`must be an object; received ${N(e)}`});return}let a=t.properties??{};for(let o of t.required??[])e[o]===void 0&&i.push({path:fe(n,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in a||i.push({path:fe(n,o),message:"unknown field"});for(let[o,l]of Object.entries(a))e[o]!==void 0&&K(e[o],l,fe(n,o),r,i);return}if(t.type==="array"){if(!Array.isArray(e)){i.push({path:n,message:`must be an array; received ${N(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&i.push({path:n,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let a=e.map(o=>JSON.stringify(o));new Set(a).size!==a.length&&i.push({path:n,message:"must not contain duplicate items"})}t.items&&e.forEach((a,o)=>K(a,t.items,`${n}[${o}]`,r,i));return}if(t.type==="string"){if(typeof e!="string"){i.push({path:n,message:`must be a string; received ${N(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&i.push({path:n,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&i.push({path:n,message:`must be a boolean; received ${N(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){i.push({path:n,message:`must be an integer; received ${N(e)}`});return}t.minimum!==void 0&&e<t.minimum&&i.push({path:n,message:`must be at least ${t.minimum}`})}}function tt(e){return{...e,$schema:e.$schema===void 0?ue:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.0":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?Oe.map(t=>({...t})):e.rules}}function nt(e,t="ark.config.json"){if(!Le(e))throw new T(t,[{path:"$",message:`must be an object; received ${N(e)}`}]);let n=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new T(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:tt(e),migratedFrom:n}}function ge(e,t="ark.config.json"){let{candidate:n,migratedFrom:r}=nt(e,t),i=[];if(K(n,$e,"$",$e,i),i.length>0)throw new T(t,i);return{config:n,migratedFrom:r}}function Pe(e,t="ark.config.json"){let n;try{n=JSON.parse(e)}catch(r){throw new T(t,[{path:"$",message:`invalid JSON: ${r instanceof Error?r.message:String(r)}`}])}return ge(n,t)}var Re="1.0";function b(e,t){e.push({id:`${t.classification}:${t.path}:${t.kind}`,path:t.path,classification:t.classification,message:t.message,...t.classification==="weakening"||t.classification==="judgment-required"?{nextAction:`Restore the previous protection at ${t.path}, then run ArkGate again.`}:{},...t.before===void 0?{}:{before:t.before},...t.after===void 0?{}:{after:t.after}})}function S(e){return[...new Set(e??[])].sort()}function R(e,t,n,r,i){let a=S(n),o=S(r),l=new Set(a),p=new Set(o),u=o.filter(g=>!l.has(g)),m=a.filter(g=>!p.has(g));u.length===0&&m.length===0||(u.length>0&&b(e,{kind:"added",path:t,classification:i.added,message:i.addedMessage,before:a,after:o}),m.length>0&&b(e,{kind:"removed",path:t,classification:i.removed,message:i.removedMessage,before:a,after:o}))}function Y(e,t,n,r,i,a,o){if(n===r)return;b(e,{kind:r?"enabled":"disabled",path:t,classification:r?i:i==="strengthening"?"weakening":"strengthening",message:r?a:o,before:n,after:r})}function W(e,t){let n=new Map,r=new Set;for(let i of e){let a=t(i);n.has(a)?r.add(a):n.set(a,i)}return{values:n,duplicates:[...r].sort()}}function rt(e,t,n){let r=W(t,a=>a.name),i=W(n,a=>a.name);(r.duplicates.length>0||i.duplicates.length>0)&&b(e,{kind:"duplicate-layer",path:"$.layers",classification:"judgment-required",message:"Duplicate layer names make policy ownership ambiguous.",before:r.duplicates,after:i.duplicates});for(let a of[...new Set([...r.values.keys(),...i.values.keys()])].sort()){let o=r.values.get(a),l=i.values.get(a),p=`$.layers[${a}]`;if(!o&&l){b(e,{kind:"layer-added",path:p,classification:"judgment-required",message:"A layer was added; verify overlap, ownership, and rule coverage.",after:l});continue}if(o&&!l){b(e,{kind:"layer-removed",path:p,classification:"weakening",message:"Removing a layer can leave its source paths ungoverned.",before:o});continue}if(!o||!l)continue;R(e,`${p}.patterns`,o.patterns,l.patterns,{added:"strengthening",removed:"weakening",addedMessage:"Additional paths are governed by this layer.",removedMessage:"Paths were removed from this layer and may become ungoverned."}),R(e,`${p}.exclude`,o.exclude,l.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional paths are excluded from this layer.",removedMessage:"Fewer paths are excluded from this layer."});let u=q(o),m=q(l);R(e,`${p}.forbiddenGlobals`,u.rawGlobals,m.rawGlobals,{added:"strengthening",removed:"weakening",addedMessage:"Additional forbidden globals are enforced in this layer.",removedMessage:"A forbidden-global protection was removed from this layer."}),R(e,`${p}.capabilities`,u.atoms,m.atoms,{added:"strengthening",removed:"weakening",addedMessage:"Additional ambient/import protection is enforced in this layer (coverage atoms).",removedMessage:"An ambient/import protection was lost from this layer (coverage atoms)."}),S(o.intentPrefixes).join("\0")!==S(l.intentPrefixes).join("\0")&&b(e,{kind:"intent-prefixes-changed",path:`${p}.intentPrefixes`,classification:"judgment-required",message:"Intent ownership changed and must be reviewed against publishers and consumers.",before:S(o.intentPrefixes),after:S(l.intentPrefixes)}),Y(e,`${p}.mayImportInfrastructure`,o.mayImportInfrastructure===!0,l.mayImportInfrastructure===!0,"weakening","The layer may now import infrastructure directly.","Direct infrastructure imports are no longer allowed for this layer."),Y(e,`${p}.optional`,o.optional===!0,l.optional===!0,"weakening","The layer is now optional and can be absent without a strict warning.","The layer is now required when its contract is active.")}}function it(e,t,n){let r=o=>`${o.from}->${o.to}`,i=W(t,r),a=W(n,r);(i.duplicates.length>0||a.duplicates.length>0)&&b(e,{kind:"duplicate-rule",path:"$.rules",classification:"judgment-required",message:"Duplicate rule edges make the effective verdict order-dependent.",before:i.duplicates,after:a.duplicates});for(let o of[...new Set([...i.values.keys(),...a.values.keys()])].sort()){let l=i.values.get(o),p=a.values.get(o),u=`$.rules[${o}]`;if(!l&&p){p.allowed===!1&&b(e,{kind:"deny-added",path:u,classification:"strengthening",message:"A denied dependency edge was added.",after:p});continue}if(l&&!p){l.allowed===!1&&b(e,{kind:"deny-removed",path:u,classification:"weakening",message:"A denied dependency edge was removed.",before:l});continue}if(!l||!p)continue;l.allowed!==p.allowed&&b(e,{kind:p.allowed?"deny-disabled":"deny-enabled",path:`${u}.allowed`,classification:p.allowed?"weakening":"strengthening",message:p.allowed?"A previously denied dependency edge is now allowed.":"A dependency edge is now denied.",before:l.allowed,after:p.allowed});let m=l.peerIsolation===!0,g=p.peerIsolation===!0;if(m!==g){let c=l.from===l.to&&p.from===p.to;b(e,{kind:g?"peer-isolation-enabled":"peer-isolation-disabled",path:`${u}.peerIsolation`,classification:c?g?"strengthening":"weakening":"judgment-required",message:c?g?"Cross-slice dependencies inside this layer are now denied.":"Cross-slice dependencies inside this layer are no longer denied.":"Changing peer isolation on a cross-layer edge changes the denial scope.",before:m,after:g})}S(l.sliceFolders).join("\0")!==S(p.sliceFolders).join("\0")&&b(e,{kind:"slice-folders-changed",path:`${u}.sliceFolders`,classification:"judgment-required",message:"Slice ownership folders changed and can reclassify existing dependencies.",before:S(l.sliceFolders),after:S(p.sliceFolders)})}}function at(e,t,n){let r=t.safety??{},i=n.safety??{};for(let a of["maxTsSuppressions","maxAnyCasts"]){let o=r[a]??0,l=i[a]??0;o!==l&&b(e,{kind:l>o?"threshold-raised":"threshold-lowered",path:`$.safety.${a}`,classification:l>o?"weakening":"strengthening",message:l>o?"The safety threshold allows more violations.":"The safety threshold allows fewer violations.",before:o,after:l})}for(let a of["allowInMemory","allowDisabledPeerIsolation"])Y(e,`$.safety.${a}`,r[a]===!0,i[a]===!0,"weakening","A safety exception was enabled.","A safety exception was disabled.")}function st(e){return e.some(t=>t.classification==="weakening")?"weakening":e.some(t=>t.classification==="judgment-required")?"judgment-required":e.some(t=>t.classification==="strengthening")?"strengthening":"neutral"}function ve(e,t){let n=[];R(n,"$.include",e.include,t.include,{added:"strengthening",removed:"weakening",addedMessage:"Additional project roots are governed.",removedMessage:"Project roots were removed from governance."}),R(n,"$.exclude",e.exclude,t.exclude,{added:"weakening",removed:"strengthening",addedMessage:"Additional project paths are excluded from governance.",removedMessage:"Fewer project paths are excluded from governance."}),R(n,"$.dynamicImportAllowlist",e.dynamicImportAllowlist,t.dynamicImportAllowlist,{added:"weakening",removed:"strengthening",addedMessage:"Additional files may use non-literal dynamic imports.",removedMessage:"Fewer files may use non-literal dynamic imports."}),Y(n,"$.excludeGenerated",e.excludeGenerated!==!1,t.excludeGenerated!==!1,"weakening","Generated source is now excluded from governance.","Generated source is now governed.");let r={off:0,soft:1,"framework-soft":1,strict:2},i=e.cyclePolicy??"strict",a=t.cyclePolicy??"strict";if(i!==a){let o=r[a]===r[i]?"judgment-required":r[a]>r[i]?"strengthening":"weakening";b(n,{kind:"cycle-policy-changed",path:"$.cyclePolicy",classification:o,message:"The cycle enforcement level changed.",before:i,after:a})}return(e.frameworkOverlay??null)!==(t.frameworkOverlay??null)&&b(n,{kind:"framework-overlay-changed",path:"$.frameworkOverlay",classification:"judgment-required",message:"The framework overlay changed and may alter effective layer matching.",before:e.frameworkOverlay??null,after:t.frameworkOverlay??null}),rt(n,e.layers,t.layers),it(n,e.rules,t.rules),at(n,e,t),n.sort((o,l)=>o.path.localeCompare(l.path)||o.id.localeCompare(l.id)),{schemaVersion:Re,classification:st(n),findings:n}}function _e(e,t){if(!e||e.schemaVersion!==Re||typeof e.basePolicyHash!="string"||typeof e.candidatePolicyHash!="string"||typeof e.reason!="string"||!Array.isArray(e.findingIds)||e.findingIds.some(i=>typeof i!="string")||e.reason.trim().length===0||e.basePolicyHash!==t.basePolicyHash||e.candidatePolicyHash!==t.candidatePolicyHash)return!1;let n=S(e.findingIds),r=S(t.findingIds);return n.length===r.length&&n.every((i,a)=>i===r[a])}function v(e){let t=[];for(let n of e.replace(/\\/g,"/").split("/"))!n||n==="."||(n===".."&&t.length>0&&t.at(-1)!==".."?t.pop():t.push(n));return t.join("/")}function Me(e){return e!==void 0&&/[A-Za-z0-9_$]/.test(e)}function L(e,t){for(;t<e.length&&/\s/.test(e[t]);)t+=1;return t}function H(e,t){let n=e[t];if(n!=="'"&&n!=='"')return;let r=t,i="";for(t+=1;t<e.length;t+=1){let a=e[t];if(a===n)return{value:i,offset:r,excerpt:e.slice(r,t+1)};a==="\\"&&t+1<e.length?(i+=e[t+1],t+=1):i+=a}}function E(e,t,n){return e.startsWith(t,n)&&!Me(e[n-1])&&!Me(e[n+t.length])}function ot(e,t){if(t=L(e,t+6),e[t]==="(")return H(e,L(e,t+1));let n=!1;if(E(e,"type",t)){let i=L(e,t+4);e[i]!==","&&!E(e,"from",i)&&(n=!0)}let r=Ne(e,t,!0);return r&&n?{...r,typeOnly:!0}:r}function ct(e,t){t=t+6;let n=L(e,t),r=!1;if(E(e,"type",n)){let a=L(e,n+4);(e[a]==="{"||e[a]==="*")&&(r=!0)}let i=Ne(e,t,!1);return i&&r?{...i,typeOnly:!0}:i}function Ne(e,t,n){for(;t<e.length;t+=1){if(e[t]===";")return;if(E(e,"from",t))return H(e,L(e,t+4));if(n&&(e[t]==="'"||e[t]==='"'))return H(e,t);if(t>0&&(E(e,"import",t)||E(e,"export",t)))return}}function lt(e,t){for(t+=1;t<e.length;t+=1){let n=e[t];if(n==="\\")t+=1;else if(n==="`")return t}return e.length}function pt(e,t){let n=t-1;for(;n>=0&&/\s/.test(e[n]);)n-=1;if(e[n]===".")return;let r=L(e,t+7);if(e[r]!=="(")return;r=L(e,r+1);let i=H(e,r);return i?{...i,requireCall:!0}:void 0}function dt(e){let t=[];for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="/"&&e[n+1]==="/"){if(n=e.indexOf(`
8
+ `,n+2),n<0)break;continue}if(r==="/"&&e[n+1]==="*"){let a=e.indexOf("*/",n+2);if(a<0)break;n=a+1;continue}if(r==="`"){n=lt(e,n);continue}if(r==="'"||r==='"'){let a=H(e,n);a&&(n=a.offset+a.excerpt.length-1);continue}let i=r==="i"&&E(e,"import",n)?ot(e,n):r==="e"&&E(e,"export",n)?ct(e,n):r==="r"&&E(e,"require",n)?pt(e,n):void 0;i&&t.push(i)}return t}function Te(e,t){let n=[],r=[];for(let i of dt(e.content)){let a=i.value;if(i.requireCall&&a.startsWith("."))continue;if(!a.startsWith(".")){if(i.typeOnly)continue;let u=j(a);if(!u)continue;let m=e.content.slice(0,i.offset).split(`
9
+ `).length;r.push({file:e.path,symbol:a,capability:u,evidence:{kind:"import",file:e.path,line:m,excerpt:i.excerpt}});continue}let o=e.content.slice(0,i.offset).split(`
10
+ `).length,l={kind:"import",file:e.path,line:o,excerpt:i.excerpt},p=ft(e.path,a,t);n.push({from:e.path,specifier:a,to:p?.path??null,resolution:p?"resolved":"unresolved",fromLayer:e.layer,toLayer:p?.layer??null,evidence:l})}return{edges:n,capabilityUses:r}}function ft(e,t,n){let r=e.split("/");r.pop();for(let a of t.split("/"))a==="."||a===""||(a===".."?r.pop():r.push(a));let i=r.join("/");for(let a of[i,`${i}.ts`,`${i}.tsx`,`${i}.mts`,`${i}.cts`,`${i}/index.ts`,`${i}/index.tsx`]){let o=n.get(a);if(o)return o}}function De(e,t){let n=[];for(let r of e){if(!r.to||!r.fromLayer||!r.toLayer)continue;let i=G(t.rules,r.fromLayer,r.toLayer,{fromPath:r.from,toPath:r.to,layers:t.layers});i&&n.push({ruleId:`layer-dependency:${i.from}->${i.to}`,message:i.message??`${i.from} must not depend on ${i.to}.`,edge:r,evidence:r.evidence})}return n}function ye(e,t){let n=typeof e=="string"?Pe(e,t):ge(e,t);return{...n,policyHash:$(x(n.config))}}function gt(e){let t=ye(e.baseConfig,e.baseSource??"base ark.config.json"),n=ye(e.candidateConfig,e.candidateSource??"candidate ark.config.json"),r=ve(t.config,n.config),i=r.findings.filter(l=>l.classification==="weakening"||l.classification==="judgment-required").map(l=>l.id).sort(),a=i.length>0,o=a&&_e(e.acknowledgement,{basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,findingIds:i});return{schemaVersion:r.schemaVersion,basePolicyHash:t.policyHash,candidatePolicyHash:n.policyHash,classification:r.classification,findings:r.findings,blockingFindingIds:i,requiresAcknowledgement:a,acknowledged:o,valid:!a||o}}function J(e){let t=e.files.map(l=>{let p=v(l.path);return{path:p,content:l.content,contentHash:$(l.content),layer:_(p,e.contract.config.layers)??null}}).sort((l,p)=>l.path.localeCompare(p.path)),n=new Map(t.map(l=>[l.path,l])),r=[],i=[];for(let l of t){let p=Te(l,n);r.push(...p.edges),i.push(...p.capabilityUses)}let a=De(r,e.contract.config),o=new Map(e.contract.config.layers.map(l=>[l.name,new Set(z(l))]));for(let l of i){let p=n.get(l.file)?.layer;!p||!o.get(p)?.has(l.capability)||a.push({ruleId:"CAPABILITY_VIOLATION",message:`${p} denies the ${l.capability} capability; found import of "${l.symbol}".`,capability:l.capability,symbol:l.symbol,evidence:l.evidence})}return{ir:{schemaVersion:"1.0",policyHash:e.contract.policyHash,compilerOptionsHash:$(x(e.compilerOptions??{})),files:t,layers:e.contract.config.layers.map(l=>l.name),edges:r,capabilityUses:i,violations:a}}}function me(e){let t=new Map(e.files.map(n=>[v(n.path),n]));for(let n of e.changes){let r=v(n.path);"delete"in n&&n.delete?t.delete(r):"content"in n&&t.set(r,{path:r,content:n.content})}return J({contract:e.contract,files:[...t.values()],compilerOptions:e.compilerOptions})}function yt(e){let t=`${e.evidence.file}:${e.evidence.line}`;if(!e.edge)return`${e.ruleId} at ${t}: ${e.message}`;let n=e.edge.to??e.edge.specifier;return`${e.ruleId} at ${t}: ${e.edge.from} imports ${n}. ${e.message}`}function Fe(e){let t=0,n=new Map,r=new Map,i=new Set,a=[],o=[],l=p=>{n.set(p,t),r.set(p,t),t+=1,a.push(p),i.add(p);for(let g of[...e.get(p)??[]].sort())e.has(g)&&(n.has(g)?i.has(g)&&r.set(p,Math.min(r.get(p)??0,n.get(g)??0)):(l(g),r.set(p,Math.min(r.get(p)??0,r.get(g)??0))));if(r.get(p)!==n.get(p))return;let u=[],m;do{if(m=a.pop(),m===void 0)break;i.delete(m),u.push(m)}while(m!==p);u.length>1&&o.push(u.sort())};for(let p of[...e.keys()].sort())n.has(p)||l(p);return o.sort((p,u)=>p[0].localeCompare(u[0])).map(p=>({ruleId:"CIRCULAR_DEPENDENCY",file:p[0],line:1,target:p.join(" \u2192 "),message:`Circular dependency among ${p.length} files: ${p.join(" \u2192 ")} \u2192 ${p[0]}.`,cycleKind:"value"}))}function he(e){let t=e.contentViolations.map(a=>({...a})),n=(e.warnings??[]).map(a=>({...a})),r=new Map(e.files.map(a=>[a,new Set]));for(let a of e.edges){if(a.to&&a.to!==a.from&&!a.typeOnly&&r.has(a.from)&&r.get(a.from)?.add(a.to),!a.to||!a.toLayer)continue;let o=G(e.rules,a.fromLayer,a.toLayer,{fromPath:a.from,toPath:a.to,layers:e.config.layers});if(!o)continue;let l=!!o.peerIsolation;t.push({ruleId:"LAYER_IMPORT_VIOLATION",file:a.from,line:a.line,fromLayer:a.fromLayer,toLayer:a.toLayer,target:a.to,...a.typeOnly?{typeOnly:!0}:{},...a.targetTypeOnlyExports?{targetTypeOnlyExports:!0}:{},...a.sourcePureTypeModule?{sourcePureTypeModule:!0}:{},...a.namedBindingsTypeOnly?{namedBindingsTypeOnly:!0}:{},...!l&&a.portProofEligible?{portProofEligible:!0}:{},...a.kind?{edgeKind:a.kind}:{},...l?{peerIsolation:!0}:{},message:o.message??(l?`${a.fromLayer} must not ${a.kind} another slice of ${a.toLayer} (${a.from} \u2192 ${a.to}). Extract shared code or use events/ports across slices.`:`${a.fromLayer} must not ${a.kind} ${a.toLayer}.`)})}let i=String(e.config.cyclePolicy??"strict").toLowerCase();if(i!=="off"){let a=Fe(r);i==="soft"||i==="framework-soft"?n.push(...a.map(o=>({...o,message:`${o.message} (soft cycle policy \u2014 advisory only; set cyclePolicy: "strict" to fail the check)`,failsStrict:!1}))):t.push(...a)}return{violations:t,warnings:n,safety:e.safety}}function je(e){switch(e.ruleId){case"LAYER_IMPORT_VIOLATION":return e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly?"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.":e.peerIsolation?"Extract the shared dependency to a shared layer, then preflight again.":`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, then preflight again.`;case"FORBIDDEN_GLOBAL":return`Inject ${e.target??"the capability"} through a port, then preflight again.`;case"CAPABILITY_VIOLATION":return`Define a ${String(e.capability??"capability")} port in ${e.fromLayer??"the walled layer"}, bind the implementation outside it, then preflight again.`;case"CIRCULAR_DEPENDENCY":return"Extract the shared dependency into a third module, then preflight again.";case"RAW_EVENT_PUBLISH":return"Publish through a registered intent creator, then run Ark again.";case"PUBLISH_MISSING_SOURCE":return"Add metadata.source to the publish call, then run Ark again.";default:return`Resolve ${typeof e.ruleId=="string"&&e.ruleId.length>0?e.ruleId:"ARK_UNKNOWN"} without weakening ark.config.json, then run Ark again.`}}function Ve(e){return $(x(e.map(({path:t,contentHash:n})=>({path:t,contentHash:n}))))}function mt(e){let t=J(e),n=new Map(t.ir.files.map(s=>[s.path,s])),r=[],i=new Set,a=[];for(let s of e.changes){let d=s.path.replace(/\\/g,"/"),f=v(s.path);if(!f||f===".."||f.startsWith("../")||d.startsWith("/")||/^[A-Za-z]:\//.test(d)||d.includes("\0")){a.push({ruleId:"INVALID_CHANGE_PATH",file:"<change-set>",line:1,message:"Every change requires a safe, non-empty project-relative path."});continue}if(i.has(f)){a.push({ruleId:"DUPLICATE_CHANGE_PATH",file:f,line:1,message:`The atomic change set contains more than one operation for ${f}.`});continue}i.add(f),"delete"in s&&s.delete&&!n.has(f)&&a.push({ruleId:"DELETE_TARGET_MISSING",file:f,line:1,message:`Cannot delete ${f} because it is not present in the supplied base tree.`}),r.push("delete"in s&&s.delete?{path:f,delete:!0}:{path:f,content:"content"in s?s.content:""})}e.changes.length===0&&a.push({ruleId:"CHANGE_SET_EMPTY",file:"<change-set>",line:1,message:"Atomic preflight requires at least one create, update, or delete."});let o=me({...e,changes:r}),l=new Map(o.ir.files.map(s=>[s.path,s])),p=o.ir.violations.filter(s=>s.ruleId==="CAPABILITY_VIOLATION").map(s=>({ruleId:s.ruleId,file:s.evidence.file,line:s.evidence.line,target:s.symbol,capability:s.capability,message:s.message})),u=he({config:e.contract.config,rules:e.contract.config.rules,files:o.ir.files.map(s=>s.path),contentViolations:p,edges:o.ir.edges.filter(s=>!!s.fromLayer).map(s=>({from:s.from,fromLayer:s.fromLayer,...s.to?{to:s.to}:{},...s.toLayer?{toLayer:s.toLayer}:{},line:s.evidence.line,kind:"import"}))}),m=r.map(s=>{let d=v(s.path),f=n.get(d),y=l.get(d);return{path:d,operation:"delete"in s&&s.delete?"delete":f?"update":"create",...f?{beforeContentHash:f.contentHash}:{},...y?{candidateContentHash:y.contentHash}:{}}}).sort((s,d)=>s.path.localeCompare(d.path)),g=[...a,...u.violations].map(s=>({...s,nextAction:je(s)})),c=e.changeMap?re({changeMap:e.changeMap,changes:m,baseDependencies:t.ir.edges.flatMap(s=>s.to?[{from:s.from,to:s.to}]:[]),candidateDependencies:o.ir.edges.flatMap(s=>s.to?[{from:s.from,to:s.to}]:[])}):void 0;return{schemaVersion:"1.0",valid:g.length===0&&(c?.structurallyConverged??!0),readOnly:!0,policyHash:e.contract.policyHash,compilerOptionsHash:o.ir.compilerOptionsHash,baseTreeHash:Ve(t.ir.files),candidateTreeHash:Ve(o.ir.files),...e.changeMap?{changeMapHash:e.changeMap.hash}:{},...c?{convergence:c}:{},changes:m,violations:g,warnings:u.warnings}}function I(e,t,n={}){return{ruleId:e,message:t,...n}}function ht(e){let{config:t,rules:n,files:r,manifest:i}=e,a=[];if(t.dynamicImportAllowlist!==void 0&&(!Array.isArray(t.dynamicImportAllowlist)||t.dynamicImportAllowlist.some(s=>typeof s!="string"))&&a.push(I("CONFIG_INVALID_DYNAMIC_IMPORT_ALLOWLIST","dynamicImportAllowlist must be an array of file globs.")),t.safety!==void 0&&(t.safety===null||typeof t.safety!="object"||Array.isArray(t.safety)))a.push(I("CONFIG_INVALID_SAFETY","safety must be an object."));else if(t.safety)for(let s of["maxTsSuppressions","maxAnyCasts"]){let d=t.safety[s];d!==void 0&&(!Number.isInteger(d)||d<0)&&a.push(I("CONFIG_INVALID_SAFETY_THRESHOLD",`safety.${s} must be a non-negative integer.`))}let o=Array.isArray(t.layers)?t.layers:[],l=Array.isArray(i?.architecture?.layers)?i.architecture.layers:[],p=new Set([...o.map(s=>s.name).filter(Boolean),...l.map(s=>s.name).filter(s=>!!s)]);o.length===0&&a.push(I("CONFIG_NO_LAYERS","No file layers are configured; ark-check cannot classify files for import-boundary enforcement."));let u=new Set,m=new Set;for(let s of o){if(!s.name){a.push(I("CONFIG_LAYER_WITHOUT_NAME","A configured layer is missing a name."));continue}u.has(s.name)&&m.add(s.name),u.add(s.name),s.forbiddenGlobals!==void 0&&(!Array.isArray(s.forbiddenGlobals)||s.forbiddenGlobals.some(f=>typeof f!="string"))&&a.push(I("CONFIG_INVALID_FORBIDDEN_GLOBALS",`Layer "${s.name}" has an invalid forbiddenGlobals value; expected an array of strings (e.g. ["fetch", "Date.now"]). The entry is ignored.`,{layer:s.name}));let d=Array.isArray(s.patterns)?s.patterns:[];if(d.length===0){a.push(I("CONFIG_LAYER_WITHOUT_PATTERNS",`Layer "${s.name}" has no file patterns and will never classify files.`,{layer:s.name}));continue}for(let f of d){let y;try{y=D(f)}catch(h){a.push(I("CONFIG_INVALID_LAYER_PATTERN",`Layer "${s.name}" has an invalid pattern "${f}": ${h instanceof Error?h.message:String(h)}`,{layer:s.name,pattern:f}));continue}!r.some(h=>y.test(h))&&!s.optional&&a.push(I("CONFIG_LAYER_PATTERN_NO_MATCHES",`Layer "${s.name}" pattern "${f}" matched no included files.`,{layer:s.name,pattern:f,failsStrict:!1}))}}for(let s of m)a.push(I("CONFIG_DUPLICATE_LAYER",`Layer "${s}" is configured more than once.`,{layer:s}));if(p.size>0)for(let s of n??[])s.from&&!p.has(s.from)&&a.push(I("CONFIG_RULE_UNKNOWN_FROM_LAYER",`Rule references unknown source layer "${s.from}".`,{fromLayer:s.from,toLayer:s.to})),s.to&&!p.has(s.to)&&a.push(I("CONFIG_RULE_UNKNOWN_TO_LAYER",`Rule references unknown target layer "${s.to}".`,{fromLayer:s.from,toLayer:s.to}));let g=new Set;if(o.length>1)for(let s of r){let d=-1,f=[];for(let y of o)for(let h of y.patterns??[]){if(!D(h).test(s))continue;let A=Q(h);A>d?(d=A,f=[y.name]):A===d&&!f.includes(y.name)&&f.push(y.name)}f.length>1&&g.add([...f].sort().join(" + "))}g.size>0&&a.push(I("CONFIG_AMBIGUOUS_LAYERS",`Some files match multiple layers at equal specificity; classification falls back to declaration order. Disambiguate the overlapping patterns: ${[...g].join(", ")}.`,{pairs:[...g]}));let c=r.filter(s=>!_(s,o));return c.length>0&&a.push(I("CONFIG_UNCLASSIFIED_FILES",`${c.length} included source file(s) are not matched by any configured layer; ark-check will not enforce import rules for those source files.`,{count:c.length,samples:c.slice(0,5)})),a}export{de as AMBIENT_CAPABILITY_ENTRIES,pe as CAPABILITY_IDS,ce as SOURCE_POLICY_MESSAGES,We as ambientCoveredByForbiddenGlobals,re as analyzeArchitectureConvergence,me as analyzeChange,gt as analyzePolicyDelta,J as analyzeProject,V as capabilityForAmbientName,j as capabilityForModuleSpecifier,Ye as classifyPublishFacts,ht as collectAnalysisConfigWarnings,Ze as collectCapabilityUses,oe as collectForbiddenCapabilityUses,Fe as detectArchitectureCycles,z as effectiveCapabilityDeny,he as evaluateArchitectureGraph,yt as explainViolation,se as extractSemanticDependencies,ze as loadArchitectureChangeMap,ye as loadContract,xe as looksLikeArkIntent,Je as lowerForbiddenGlobal,q as loweredLayerCoverage,mt as preflightChange};