arkgate 3.1.0 → 3.3.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,88 @@ All notable changes to ArkGate (`arkgate`; formerly `ark-runtime-kernel`) are do
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 3.3.0 — 2026-07-16
8
+
9
+ Understandable execution, first slice (Phase U: U01–U03): typed effect capabilities as
10
+ **evidence-only** architecture facts, a locked ADR boundary, and a legibility dogfood of the
11
+ engine itself. Nothing blocks on capabilities in this release — walls arrive with the second
12
+ slice (U04+) after the corpus matures in the field. **No breaking** CLI or `ark.config.json`
13
+ changes. **No gate weaken.**
14
+
15
+ ### Added
16
+
17
+ - **ADR 0009 (U01):** the accepted architecture-vs-style boundary — seven closed capability ids
18
+ (`network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence`),
19
+ direct-evidence-only blocking threshold (transitive inference never blocks), config lowering
20
+ design (`forbiddenGlobals` and future capability policy lower to one semantic space;
21
+ `pure: true` planned as the casual surface), coverage-faithful lowering for prefix-matched
22
+ globals (bare `process` covers `environment` too), surface-ownership dedup rule, and the
23
+ W02 governance-weight reconciliation. Backed by a 25-case executable fixture corpus
24
+ (`tests/fixtures/capability-corpus/`) with a content-aware structural guard.
25
+ - **Effect capabilities in the canonical analysis (U03):** `collectCapabilityUses(ts, sourceFile)`
26
+ composes the existing symbol-aware collectors (shadowing / type-only / `globalThis`-alias
27
+ precision; no second scanner); the Domain vocabulary ships as
28
+ `CAPABILITY_IDS` / `capabilityForModuleSpecifier` / `capabilityForAmbientName` /
29
+ `lowerForbiddenGlobal`; the compiler-free IR engine now populates `ir.capabilityUses` with
30
+ import-based evidence (exact module/subpath matching — never substring; textual
31
+ `import type` / `export type` erasure). Additive within IR `1.0`; evidence only.
32
+
33
+ ### Changed
34
+
35
+ - **Engine legibility dogfood (U02):** `src/kernel/analysis.ts` is now a pure facade over six
36
+ cohesive kernel modules and the `ark.config.json` contract types moved to
37
+ `src/domain/configTypes.ts` — zero consumer import changes, byte-identical generated
38
+ config artifacts, identical hashes and verdicts (verified by execution old-vs-new). ArkGate's
39
+ own doctor now reports **zero design smells** on this repository.
40
+ - The experimental `@arkgate/runtime` distribution is minified with `keepNames` (stable
41
+ class/function names for reflection and Nest diagnostics) and stays well inside its
42
+ release-artifact budget.
43
+
44
+ ## 3.2.0 — 2026-07-15
45
+
46
+ Contract health (Phase W): ArkGate now also meta-lints the contract itself and describes its
47
+ governance weight, and the docs name the enforcement-boundary trade-off explicitly. Everything in
48
+ this release is **advisory only** — no verdict, `designFitness`, `patternBets`, or gate result
49
+ changes. **No breaking** CLI or `ark.config.json` changes. **No gate weaken.**
50
+
51
+ ### Added
52
+
53
+ - **W01 contract smells:** `ark-check --doctor --json` gains `doctor.contractHealth` with four
54
+ stable, deterministic smell ids that lint the contract rather than the code:
55
+ `contract-bidirectional-allow` (both directions explicitly allowed between two layers),
56
+ `contract-peripheral-depends-core` (audit/observability layer allowed into
57
+ orchestration/persistence), `contract-lateral-adapter-allow` (adapter layer allowed into a
58
+ sibling adapter layer), and `contract-dead-rule` (rule referencing an unknown or empty layer, or
59
+ a same-layer no-op; `optional: true` layers are exempt). Each smell carries `severity`,
60
+ sorted `evidence[]` with honest `…(+N more)` truncation, technical `message`, plain-language
61
+ `outcome`, and `fix`. Human doctor prints a "Contract health (advisory)" section.
62
+ - **Acknowledgment sidecar:** deliberate edges are recorded in an optional
63
+ `.ark/contract-smell-acks.json` (`{ acks: [{ id, edge, reason }] }`; bidirectional edges
64
+ order-insensitive) — the versioned `ark.config.json` schema is untouched. The file is bounded
65
+ (≤64 KB, ≤200 entries); a malformed file or edge grammar is reported via `ackFile.invalid` and
66
+ never suppresses a smell. `contractHealth.acknowledged` counts applied acks only.
67
+ - **W02 governance weight:** `doctor.contractHealth.governanceWeight` reports raw facts
68
+ (declared/populated layers, governed files, rules, denied/allowed edges, files-per-layer,
69
+ rules-per-layer) plus a fixed comparative band — `heavy` (fewer than 25 governed files per layer
70
+ AND 6+ layers or 4+ rules per layer), `light` (≤2 layers over 150+ governed files), `typical`,
71
+ or `unknown` — with fixed wording and an explicit `notAScore: true`. Banding uses raw ratios;
72
+ reported ratios are rounded for display. The heavy note asks to justify NEW layers with
73
+ demonstrated pressure and never suggests deleting working ones.
74
+ - **W03 enforcement-boundary positioning:** README explains why the hard guarantee lives at the
75
+ required merge status ("deliberate trade-off, not a gap"; the contract doubles as a pressure
76
+ sensor), and `docs/ai-gates.md` / `docs/agent-guide.md` carry the same framing next to the
77
+ canonical host support matrix. A docs regression pins the wording without strengthening any
78
+ guarantee claim.
79
+
80
+ ### Fixed
81
+
82
+ - Contract meta-lint reads the rules actually in force (manifest-aware), not only `config.rules`.
83
+ - Hostile ack-file inputs (FIFO/symlink targets, oversized files, sloppy edge strings) can no
84
+ longer hang `--doctor`, exhaust memory, or silently suppress findings; null rule entries and
85
+ malformed coverage rows no longer throw.
86
+ - Governance-weight banding is size-relative in both clauses: a large tree with a proportionate
87
+ dense rule matrix never reads `heavy`, and NaN/negative counts read `unknown`.
88
+
7
89
  ## 3.1.0 — 2026-07-15
8
90
 
9
91
  Deterministic change integrity. **No breaking** CLI or `ark.config.json` changes. **No gate
package/README.md CHANGED
@@ -16,8 +16,9 @@ and makes sure a “green” check means something real.
16
16
 
17
17
  </div>
18
18
 
19
- > **ArkGate 3.0** passed its independent beta-exit audit. The npm badge reports the version
20
- > currently available in the registry.
19
+ > **ArkGate 3.3.0** is current stable: typed effect-capability evidence (seven closed ids,
20
+ > evidence-only until walls opt in), on top of 3.2's contract health and 3.1's change-integrity
21
+ > loop. [Release notes](docs/releases/3.3.0.md).
21
22
 
22
23
  ---
23
24
 
@@ -156,7 +157,7 @@ Aliases `ark` / `ark-check` / `ark-mcp` still work. **npm / pnpm / yarn**. No in
156
157
  <details>
157
158
  <summary>What <code>/ark-autopilot</code> does under the hood (optional detail)</summary>
158
159
 
159
- 1. Setup if needed (`ark start` — compact contract + active-host router + CI gate; create an HTML/origin report explicitly when you need one).
160
+ 1. Setup if needed (`ark start` previews; review, then `ark start --apply`).
160
161
  2. **Explore pass** (decision-grade map of *this* product; field path when demos exist).
161
162
  3. **Dual plan:** **A** remediation from `--plan` (mechanical-safe only by default); **B** pattern/evolution bets (never auto-applied as mechanical-safe). Empty plan ≠ “healthy” without explore/B.
162
163
  4. Apply A → re-check; judgment only when you ask for full apply.
@@ -243,6 +244,22 @@ Brownfield phases: **Align** (honest contract) → **Stabilize** (real baseline)
243
244
  This table describes the supported profile **after its files are installed and the host loads/trusts them**. A hard local boundary covers only the listed hook operations; alternate tools, direct filesystem writes, and human edits still rely on CI. MCP validation is advisory because the agent must call it. The CI check blocks a merge only when the repository makes that status required. Repair payloads never write code silently: the host must re-inject the candidate and ArkGate revalidates it. Run `arkgate-check --doctor` for the evidence actually detected in the current repository.
244
245
  <!-- arkgate-host-support:end -->
245
246
 
247
+ #### Why the hard guarantee lives at the merge gate
248
+
249
+ The split above is a deliberate trade-off, not a gap. ArkGate validates at the earliest boundary
250
+ each host offers and enforces at the earliest boundary a repository can make non-bypassable: the
251
+ required merge status. Hard hooks (Claude Code, Grok Build) deny the listed write operations at
252
+ write time; advisory surfaces (MCP, rules) coach the agent while it works. But any local boundary
253
+ can be routed around — another tool, a direct filesystem write, a human edit — so the only
254
+ guarantee ArkGate claims for every path is the `arkgate-check --strict-merge` check, and only when
255
+ the repository makes that status required. Local checks optimize feedback speed; the merge gate
256
+ owns correctness.
257
+
258
+ A useful consequence: the contract doubles as a pressure sensor. Recurring violations or baseline
259
+ exceptions concentrated on one layer edge are evidence that the current design stopped fitting the
260
+ code — a reason to reshape the contract deliberately (start with `/ark-explore`), never to weaken
261
+ the gate.
262
+
246
263
  Detailed setup: [docs/ai-gates.md](docs/ai-gates.md).
247
264
 
248
265
  ---
@@ -264,7 +281,9 @@ ark.config.json
264
281
  finding ids. See the [configuration and editor guide](docs/configuration.md).
265
282
  - **Frameworks:** Nest / Next / express / library layouts get sensible globs on init so day-one coverage is real.
266
283
  - **Brownfield:** baseline ratchet, refuse to freeze a wrong contract, `/ark-adopt` for mature trees.
267
- - **Agents:** `ark start` asks for (or detects) one active host and writes one compact router, not copied skill packs, in at most five project files and 25 KB. Use `ark-check --install-agent-gates --skills-only --tools <host>` later when you explicitly want the full `/ark-*` skill set. Reports are opt-in with `ark-check --report`.
284
+ - **Agents:** `ark start` previews one compact active-host router (≤5 files / 25 KB); `--apply`
285
+ writes those exact bytes. Full skills remain explicit via `--install-agent-gates --skills-only`;
286
+ reports remain opt-in via `ark-check --report`.
268
287
  - **Write protocol (2.10 / Track W):** mechanical-safe **autoPatch** on the write gate (`import type`); MCP **`ark_prepare_write`** (place + validate + patch + judgmentBrief); opt-in hook **`--hook-repair`** (`ARK_REPAIR_JSON`); doctor **`writePath`** (repair vs reject-only); loop-cost eval (`npm run eval:loop-cost`). Port-proof inject is **judgment** (arity change), not silent auto-apply.
269
288
  - **Enforcement ladder (Phase T):** doctor JSON exposes `writePath.enforcementLadder` with separate
270
289
  `supported`, `installed`, `active`, `bypassable`, evidence, operation coverage, and required-status
@@ -274,11 +293,8 @@ ark.config.json
274
293
  casts, InMemory runtime defaults, and disabled peer isolation. `--strict` is a compatibility
275
294
  alias. Neither requires an editor hook; use `--require-write-hook claude|grok` when that local
276
295
  guarantee is part of the check.
277
- - **Trust / coverage (3.0 release baseline):** package unit-test floors on the broad product surface
278
- (statements/lines **≥80%**, branches/functions **≥85%**; enforcement-critical modules **≥95%**
279
- branch). The V05 beta-exit audit passed with 12 pinned public adoptions, 97% median governed
280
- coverage, and zero P0/P1 findings. Stable publication remains the signed-tag, GitHub Release,
281
- and provenance-backed npm workflow documented in [the 3.0.0 release notes](docs/releases/3.0.0.md).
296
+ - **Release evidence:** independent 3.0 audit baseline plus signed-tag, GitHub Release, and
297
+ provenance-backed npm publication; see the [3.1.0 release notes](docs/releases/3.1.0.md).
282
298
  - **TypeScript:** project compilers 5.x / 6.x / 7.x — gate falls back to a nested JS-API TypeScript when TS 7’s main export is version-only ([docs/typescript-support.md](docs/typescript-support.md)).
283
299
 
284
300
  ### Why not only ESLint / dependency-cruiser / Nx?
@@ -357,16 +373,17 @@ for real systems. Details: [production-hardening.md](https://github.com/pedrokni
357
373
  | Audience | Link |
358
374
  |----------|------|
359
375
  | New builders (plain language) | [docs/enthusiast/](docs/enthusiast/README.md) |
360
- | **Package surface (stable vs experimental)** | [docs/package-surface.md](docs/package-surface.md) |
361
- | Wire Claude / Cursor / Codex / Grok + **ESLint (CI-parity)** | [docs/ai-gates.md](docs/ai-gates.md) |
376
+ | **Package surface and configuration** | [package policy](docs/package-surface.md) · [contract](docs/configuration.md) |
377
+ | Wire agents + **ESLint (CI-parity)** | [docs/ai-gates.md](docs/ai-gates.md) · [threat model](docs/threat-model.md) |
362
378
  | **TypeScript 5 / 6 / 7 support** | [docs/typescript-support.md](docs/typescript-support.md) |
363
379
  | Migrate from `ark-runtime-kernel` | [docs/migrate-from-ark-runtime-kernel.md](https://github.com/pedroknigge/arkgate/blob/main/docs/migrate-from-ark-runtime-kernel.md) |
364
380
  | Messy existing repo | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
365
381
  | Agent / MCP tools | [docs/agent-guide.md](docs/agent-guide.md) |
382
+ | Security reporting | [SECURITY.md](SECURITY.md) |
366
383
  | Demos | [docs/demos/](docs/demos/) |
367
384
  | Examples | [examples/](examples/README.md) |
368
385
  | Latest release (3.1.0) | [release notes](docs/releases/3.1.0.md) · [3.0.0 baseline](docs/releases/3.0.0.md) |
369
- | Roadmap | [ROADMAP.md](ROADMAP.md) · [Changelog](CHANGELOG.md) |
386
+ | Roadmap and decisions | [ROADMAP.md](ROADMAP.md) · [ADRs](docs/adr/) · [Changelog](CHANGELOG.md) |
370
387
 
371
388
  ---
372
389
 
@@ -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 w(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 ye=new Map;function he(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function W(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 De(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=ye.get(e);if(t)return t;let n=W(e),r=De(n),i="",a=0;for(let l=0;l<n.length;l+=1){let p=n[l];p==="\\"&&l+1<n.length?(i+=he(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+=he(p)}let o=new RegExp(`^${i}$`);return ye.set(e,o),o}function J(e){let t=W(String(e)),r=t.split("*")[0].split("/").filter(Boolean).length,i=t.replace(/\*/g,"").length;return r*1e4+i}function L(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=J(o);l>i&&(i=l,r=a.name)}}return r}function me(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 Fe(e){let t=new Set;for(let n of e??[]){let i=W(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 je(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 Fe(r?.patterns)}function H(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=je(i,t,r?.layers);if(l.length===0)continue;let p=me(a,l),u=me(o,l);if(!p||!u)continue;if(p!==u)return i;continue}if(t!==n)return i}}var Z="1.0";var V=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 X(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Q(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 He(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 Ve(e,t,n="architecture change map"){let r=[];if(!X(e))throw new V(n,[{path:"$",message:"must be an object"}]);Q(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(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(!X(d)){r.push({path:y,message:"must be an object"});return}Q(d,["path","operation","layer"],y,r);let m=O(d,"path",y,r),A=O(d,"operation",y,r),C=O(d,"layer",y,r),k=m?He(m):void 0;m&&!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 Y=k?L(k,t.layers):void 0;k&&C&&o.has(C)&&Y!==C&&r.push({path:`${y}.layer`,message:Y?`${k} resolves to ${Y}, 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=[],h=new Map(l.map(d=>[d.path,d.operation])),g=new Set,s=e.dependencies??[];if(Array.isArray(s)?s.forEach((d,f)=>{let y=`$.dependencies[${f}]`;if(!X(d)){r.push({path:y,message:"must be an object"});return}Q(d,["from","to"],y,r);let m=O(d,"from",y,r),A=O(d,"to",y,r);m&&!p.has(m)&&r.push({path:`${y}.from`,message:`must reference a planned file path: ${m}`}),A&&!p.has(A)&&r.push({path:`${y}.to`,message:`must reference a planned file path: ${A}`}),m&&h.get(m)==="delete"&&r.push({path:`${y}.from`,message:`cannot depend from deleted file ${m}`}),A&&h.get(A)==="delete"&&r.push({path:`${y}.to`,message:`cannot depend on deleted file ${A}`}),m&&A&&m===A&&r.push({path:y,message:"must not declare a self dependency"});let C=m&&A?`${m}\0${A}`:void 0;C&&g.has(C)&&r.push({path:y,message:`duplicates dependency ${m} -> ${A}`}),C&&g.add(C),m&&A&&u.push({from:m,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((d,f)=>d.path.localeCompare(f.path)),dependencies:u.sort((d,f)=>d.from.localeCompare(f.from)||d.to.localeCompare(f.to))};return{map:c,hash:w(E(c))}}function S(e){return`${e.from}->${e.to}`}function F(e,t,n,r="dependency"){return{id:`${e}:${r}:${S(t)}`,classification:e,subject:"dependency",from:t.from,to:t.to,message:n,...e==="missing"?{nextAction:`Add the planned dependency ${S(t)} to the candidate, then preflight again.`}:e==="contradictory"?{nextAction:`Replace the reverse dependency with ${S(t)}, then preflight again.`}:e==="unplanned"?{nextAction:`Remove the unplanned dependency ${S(t)} from the candidate, then preflight again.`}:{}}}function ee(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=>[S(s),s])),a=new Map(e.baseDependencies.map(s=>[S(s),s])),o=new Map(e.candidateDependencies.map(s=>[S(s),s]));for(let s of[...n.values()].sort((c,d)=>c.path.localeCompare(d.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,d)=>c.path.localeCompare(d.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,d)=>S(c).localeCompare(S(d)))){if(o.has(S(s))){t.push(F("satisfied",s,`${s.from} -> ${s.to} exists in the candidate architecture.`));continue}let c={from:s.to,to:s.from};o.has(S(c))?(l.add(S(c)),t.push(F("contradictory",s,`${s.from} -> ${s.to} was planned, but the candidate contains the reverse edge.`))):t.push(F("missing",s,`${s.from} -> ${s.to} is absent from the candidate architecture.`))}let p=new Set([...n.keys(),...r.keys()]);for(let[s,c]of[...o].sort(([d],[f])=>d.localeCompare(f)))a.has(s)||i.has(s)||l.has(s)||!p.has(c.from)&&!p.has(c.to)||t.push({...F("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(([d],[f])=>d.localeCompare(f)))o.has(s)||u.has(c.from)||u.has(c.to)||!p.has(c.from)&&!p.has(c.to)||t.push({...F("unplanned",c,`${c.from} -> ${c.to} was removed without a planned file deletion.`,"dependency-removed"),actualOperation:"removed"});let h={satisfied:0,missing:1,contradictory:2,unplanned:3};t.sort((s,c)=>h[s.classification]-h[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 _(e,t){return t&&e.isStringLiteralLike(t)?t.text:void 0}function Ce(e,t){return e.getLineAndCharacterOfPosition(t.getStart(e)).line+1}function Ae(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 Ie(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 te(e,t){try{return e.getSymbolAtLocation(t)}catch{return}}function ne(e,t,n,r){let i=r.parent&&e.isShorthandPropertyAssignment(r.parent)&&r.parent.name===r,a;try{a=i?t.getShorthandAssignmentValueSymbol(r.parent):te(t,r)}catch{a=void 0}return!!a?.declarations?.some(o=>o.getSourceFile().fileName===n.fileName)}function re(e,t){let n,r=[],i=(o,l,p,u=!1)=>r.push({specifier:p,kind:l,line:Ce(t,o),typeOnly:u,unresolved:p===void 0,node:o}),a=o=>{if(e.isImportDeclaration(o))i(o,"import",_(e,o.moduleSpecifier),Ae(e,o));else if(e.isExportDeclaration(o)&&o.moduleSpecifier)i(o,"export",_(e,o.moduleSpecifier),Ae(e,o));else if(e.isImportEqualsDeclaration(o)&&e.isExternalModuleReference(o.moduleReference))i(o,"require",_(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"&&!ne(e,n??(n=Ie(e,t)),t,o.expression);(l||u)&&i(o,u?"require":"dynamic-import",_(e,o.arguments[0]))}e.forEachChild(o,a)};return a(t),r}function Ge(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=_(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 Ue(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 be(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 ie(e,t,n){if(n.length===0)return[];let r=new Set(n),i=Ie(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=Ge(e,s);if(!c)return;let d=te(i,c.root),f=d?a.get(d):void 0;return f?[...f,...c.segments.slice(1)]:ne(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 d=l(c.initializer),f=te(i,c.name);!d||!f||a.set(f,d)}let p=[],u=new Set,h=(s,c)=>{let d=Ce(t,c),f=`${s}:${c.getStart(t)}`;u.has(f)||(u.add(f),p.push({name:s,line:d,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 d=l(s),f=d?be(r,d):void 0;f&&h(f,s)}else e.isIdentifier(s)&&r.has(s.text)&&Ue(e,s)&&!ne(e,i,t,s)&&h(s.text,s);if(e.isVariableDeclaration(s)&&e.isObjectBindingPattern(s.name)&&s.initializer){let d=l(s.initializer);if(d)for(let f of s.name.elements){if(!e.isIdentifier(f.name))continue;let y=f.propertyName?_(e,f.propertyName)??f.propertyName.text:f.name.text,m=be(r,[...d,y]);m&&h(m,s.initializer)}}e.forEachChild(s,g)};return g(t),p}var ae={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 ke(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function Be(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&ke(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ae.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ae.PUBLISH_MISSING_SOURCE}),t}var ze=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),oe=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),ce=Object.freeze(Object.keys(oe).sort()),se=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=se[e];if(t)return t;let n=e.indexOf("/");if(n<0)return null;let r=e.slice(0,n),i=se[r];if(i)return i;let a=e.indexOf("/",n+1);return a<0?null:se[e.slice(0,a)]??null}function G(e){let t=e.split(".");for(let n=t.length;n>=1;n-=1){let r=t.slice(0,n).join("."),i=oe[r];if(i)return i}return null}function qe(e){let t=new Set,n=G(e);n&&t.add(n);for(let[r,i]of Object.entries(oe))(r===e||r.startsWith(`${e}.`))&&t.add(i);return[...t].sort()}function Ke(e,t){let n=[];for(let r of re(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 ie(e,t,ce)){let i=G(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 pe="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",Se=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],Ye=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function We(){let e=[];for(let t of Se)for(let n of Se)t===n||Ye.has(`${t}->${n}`)||e.push({from:t,to:n,allowed:!1});return e}var Ee=We();var $={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},xe={$schema:"https://json-schema.org/draft/2020-12/schema",$id:pe,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:pe,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:{...$,minItems:1,default:["src"]},exclude:{...$,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:Ee,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...$,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:{...$,minItems:1},exclude:$,intentPrefixes:$,description:{type:"string",minLength:1},forbiddenGlobals:$,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:{...$,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}}}}},M=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 we(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function le(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function v(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function Je(e,t){let n="#/$defs/";if(e.startsWith(n))return t.$defs[e.slice(n.length)]}function U(e,t,n,r,i){if(t.$ref){let a=Je(t.$ref,r);if(!a){i.push({path:n,message:`schema reference ${t.$ref} cannot be resolved`});return}U(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(!we(e)){i.push({path:n,message:`must be an object; received ${v(e)}`});return}let a=t.properties??{};for(let o of t.required??[])e[o]===void 0&&i.push({path:le(n,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in a||i.push({path:le(n,o),message:"unknown field"});for(let[o,l]of Object.entries(a))e[o]!==void 0&&U(e[o],l,le(n,o),r,i);return}if(t.type==="array"){if(!Array.isArray(e)){i.push({path:n,message:`must be an array; received ${v(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)=>U(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 ${v(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 ${v(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){i.push({path:n,message:`must be an integer; received ${v(e)}`});return}t.minimum!==void 0&&e<t.minimum&&i.push({path:n,message:`must be at least ${t.minimum}`})}}function Ze(e){return{...e,$schema:e.$schema===void 0?pe: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?Ee.map(t=>({...t})):e.rules}}function Xe(e,t="ark.config.json"){if(!we(e))throw new M(t,[{path:"$",message:`must be an object; received ${v(e)}`}]);let n=e.schemaVersion===void 0?"unversioned":null;if(e.schemaVersion!==void 0&&e.schemaVersion!=="1.0")throw new M(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.0`}]);return{candidate:Ze(e),migratedFrom:n}}function de(e,t="ark.config.json"){let{candidate:n,migratedFrom:r}=Xe(e,t),i=[];if(U(n,xe,"$",xe,i),i.length>0)throw new M(t,i);return{config:n,migratedFrom:r}}function $e(e,t="ark.config.json"){let n;try{n=JSON.parse(e)}catch(r){throw new M(t,[{path:"$",message:`invalid JSON: ${r instanceof Error?r.message:String(r)}`}])}return de(n,t)}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 x(e){return[...new Set(e??[])].sort()}function N(e,t,n,r,i){let a=x(n),o=x(r),l=new Set(a),p=new Set(o),u=o.filter(g=>!l.has(g)),h=a.filter(g=>!p.has(g));u.length===0&&h.length===0||(u.length>0&&b(e,{kind:"added",path:t,classification:i.added,message:i.addedMessage,before:a,after:o}),h.length>0&&b(e,{kind:"removed",path:t,classification:i.removed,message:i.removedMessage,before:a,after:o}))}function B(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 z(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 Qe(e,t,n){let r=z(t,a=>a.name),i=z(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}!o||!l||(N(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."}),N(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."}),N(e,`${p}.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."}),x(o.intentPrefixes).join("\0")!==x(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:x(o.intentPrefixes),after:x(l.intentPrefixes)}),B(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."),B(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 et(e,t,n){let r=o=>`${o.from}->${o.to}`,i=z(t,r),a=z(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 h=l.peerIsolation===!0,g=p.peerIsolation===!0;if(h!==g){let s=l.from===l.to&&p.from===p.to;b(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:h,after:g})}x(l.sliceFolders).join("\0")!==x(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:x(l.sliceFolders),after:x(p.sliceFolders)})}}function tt(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"])B(e,`$.safety.${a}`,r[a]===!0,i[a]===!0,"weakening","A safety exception was enabled.","A safety exception was disabled.")}function nt(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 Re(e,t){let n=[];N(n,"$.include",e.include,t.include,{added:"strengthening",removed:"weakening",addedMessage:"Additional project roots are governed.",removedMessage:"Project roots were removed from governance."}),N(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."}),N(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."}),B(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}),Qe(n,e.layers,t.layers),et(n,e.rules,t.rules),tt(n,e,t),n.sort((o,l)=>o.path.localeCompare(l.path)||o.id.localeCompare(l.id)),{schemaVersion:"1.0",classification:nt(n),findings:n}}function Oe(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=x(e.findingIds),r=x(t.findingIds);return n.length===r.length&&n.every((i,a)=>i===r[a])}function P(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 Pe(e){return e!==void 0&&/[A-Za-z0-9_$]/.test(e)}function T(e,t){for(;t<e.length&&/\s/.test(e[t]);)t+=1;return t}function q(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 R(e,t,n){return e.startsWith(t,n)&&!Pe(e[n-1])&&!Pe(e[n+t.length])}function rt(e,t){if(t=T(e,t+6),e[t]==="(")return q(e,T(e,t+1));let n=!1;if(R(e,"type",t)){let i=T(e,t+4);e[i]!==","&&!R(e,"from",i)&&(n=!0)}let r=Le(e,t,!0);return r&&n?{...r,typeOnly:!0}:r}function it(e,t){t=t+6;let n=T(e,t),r=!1;if(R(e,"type",n)){let a=T(e,n+4);(e[a]==="{"||e[a]==="*")&&(r=!0)}let i=Le(e,t,!1);return i&&r?{...i,typeOnly:!0}:i}function Le(e,t,n){for(;t<e.length;t+=1){if(e[t]===";")return;if(R(e,"from",t))return q(e,T(e,t+4));if(n&&(e[t]==="'"||e[t]==='"'))return q(e,t);if(t>0&&(R(e,"import",t)||R(e,"export",t)))return}}function at(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=q(e,n);a&&(n=a.offset+a.excerpt.length-1);continue}let i=R(e,"import",n)?rt(e,n):R(e,"export",n)?it(e,n):void 0;i&&t.push(i)}return t}function _e(e,t){let n=[],r=[];for(let i of at(e.content)){let a=i.value;if(!a.startsWith(".")){if(i.typeOnly)continue;let u=j(a);if(!u)continue;let h=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:h,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=st(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 st(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 ve(e,t){let n=[];for(let r of e){if(!r.to||!r.fromLayer||!r.toLayer)continue;let i=H(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 fe(e,t){let n=typeof e=="string"?$e(e,t):de(e,t);return{...n,policyHash:w(E(n.config))}}function ct(e){let t=fe(e.baseConfig,e.baseSource??"base ark.config.json"),n=fe(e.candidateConfig,e.candidateSource??"candidate ark.config.json"),r=Re(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&&Oe(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 K(e){let t=e.files.map(o=>{let l=P(o.path);return{path:l,content:o.content,contentHash:w(o.content),layer:L(l,e.contract.config.layers)??null}}).sort((o,l)=>o.path.localeCompare(l.path)),n=new Map(t.map(o=>[o.path,o])),r=[],i=[];for(let o of t){let l=_e(o,n);r.push(...l.edges),i.push(...l.capabilityUses)}let a=ve(r,e.contract.config);return{ir:{schemaVersion:"1.0",policyHash:e.contract.policyHash,compilerOptionsHash:w(E(e.compilerOptions??{})),files:t,layers:e.contract.config.layers.map(o=>o.name),edges:r,capabilityUses:i,violations:a}}}function ue(e){let t=new Map(e.files.map(n=>[P(n.path),n]));for(let n of e.changes){let r=P(n.path);"delete"in n&&n.delete?t.delete(r):"content"in n&&t.set(r,{path:r,content:n.content})}return K({contract:e.contract,files:[...t.values()],compilerOptions:e.compilerOptions})}function lt(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 Me(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=[],h;do{if(h=a.pop(),h===void 0)break;i.delete(h),u.push(h)}while(h!==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 ge(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=H(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=Me(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 Ne(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.`}}function Te(e){return w(E(e.map(({path:t,contentHash:n})=>({path:t,contentHash:n}))))}function pt(e){let t=K(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,"/"),d=P(s.path);if(!d||d===".."||d.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(d)){a.push({ruleId:"DUPLICATE_CHANGE_PATH",file:d,line:1,message:`The atomic change set contains more than one operation for ${d}.`});continue}i.add(d),"delete"in s&&s.delete&&!n.has(d)&&a.push({ruleId:"DELETE_TARGET_MISSING",file:d,line:1,message:`Cannot delete ${d} because it is not present in the supplied base tree.`}),r.push("delete"in s&&s.delete?{path:d,delete:!0}:{path:d,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=ue({...e,changes:r}),l=new Map(o.ir.files.map(s=>[s.path,s])),p=ge({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=P(s.path),d=n.get(c),f=l.get(c);return{path:c,operation:"delete"in s&&s.delete?"delete":d?"update":"create",...d?{beforeContentHash:d.contentHash}:{},...f?{candidateContentHash:f.contentHash}:{}}}).sort((s,c)=>s.path.localeCompare(c.path)),h=[...a,...p.violations].map(s=>({...s,nextAction:Ne(s)})),g=e.changeMap?ee({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:h.length===0&&(g?.structurallyConverged??!0),readOnly:!0,policyHash:e.contract.policyHash,compilerOptionsHash:o.ir.compilerOptionsHash,baseTreeHash:Te(t.ir.files),candidateTreeHash:Te(o.ir.files),...e.changeMap?{changeMapHash:e.changeMap.hash}:{},...g?{convergence:g}:{},changes:u,violations:h,warnings:p.warnings}}function I(e,t,n={}){return{ruleId:e,message:t,...n}}function dt(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 d=t.safety[c];d!==void 0&&(!Number.isInteger(d)||d<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:[],p=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,h=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)&&h.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 d=Array.isArray(c.patterns)?c.patterns:[];if(d.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 d){let y;try{y=D(f)}catch(m){a.push(I("CONFIG_INVALID_LAYER_PATTERN",`Layer "${c.name}" has an invalid pattern "${f}": ${m instanceof Error?m.message:String(m)}`,{layer:c.name,pattern:f}));continue}!r.some(m=>y.test(m))&&!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 h)a.push(I("CONFIG_DUPLICATE_LAYER",`Layer "${c}" is configured more than once.`,{layer:c}));if(p.size>0)for(let c of n??[])c.from&&!p.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&&!p.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 d=-1,f=[];for(let y of o)for(let m of y.patterns??[]){if(!D(m).test(c))continue;let A=J(m);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 s=r.filter(c=>!L(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{ce as AMBIENT_CAPABILITY_ENTRIES,ze as CAPABILITY_IDS,ae as SOURCE_POLICY_MESSAGES,ee as analyzeArchitectureConvergence,ue as analyzeChange,ct as analyzePolicyDelta,K as analyzeProject,G as capabilityForAmbientName,j as capabilityForModuleSpecifier,Be as classifyPublishFacts,dt as collectAnalysisConfigWarnings,Ke as collectCapabilityUses,ie as collectForbiddenCapabilityUses,Me as detectArchitectureCycles,ge as evaluateArchitectureGraph,lt as explainViolation,re as extractSemanticDependencies,Ve as loadArchitectureChangeMap,fe as loadContract,ke as looksLikeArkIntent,qe as lowerForbiddenGlobal,pt as preflightChange};