New:Socket for Asana Is Now Available.Learn more
Get Started

arkgate

Package Overview
Dependencies
Maintainers
1
Versions
72
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

arkgate - npm Package Compare versions

Comparing version
4.6.7
to
4.7.0
+144
bin/lib/ark-run-doctor.mjs
/**
* GENERATED FILE — do not edit by hand.
*
* Canonical algorithm: src/domain/arkRunDoctor.ts
* Regenerate: node scripts/generate-cli-pure.mjs
* Drift check: node scripts/generate-cli-pure.mjs --check
*
* Pure CLI helper (bin/lib/ark-run-doctor.mjs). Zero Node I/O.
*/
import { composeMergePlanesHonesty, extraMergeTeethAllowed, isArkRunRuleId, } from './extra-merge-teeth.mjs';
export const ARK_RUN_DOCTOR_SCHEMA_VERSION = '1.0';
const RESIDUAL_RULE_CAP = 12;
function closedMode(value) {
return value === 'enforced' || value === 'advisory' ? value : null;
}
function uniqueArkRunRuleIds(findings) {
const seen = new Set();
if (!Array.isArray(findings))
return [];
for (const finding of findings) {
const id = finding?.ruleId;
if (typeof id !== 'string' || !isArkRunRuleId(id) || seen.has(id))
continue;
seen.add(id);
}
return [...seen].sort((left, right) => (left < right ? -1 : left > right ? 1 : 0));
}
function extraFromConfig(arkRun) {
if (!arkRun || typeof arkRun !== 'object') {
return { present: false, mode: null, roots: 0, layers: 0, requireDeclarations: null };
}
return {
present: true,
mode: closedMode(arkRun.mode),
roots: Array.isArray(arkRun.compositionRoots) ? arkRun.compositionRoots.length : 0,
layers: Array.isArray(arkRun.managedLayers) ? arkRun.managedLayers.length : 0,
requireDeclarations: arkRun.requireDeclarations === true,
};
}
/**
* Doctor / HTML ArkRun advisory. Always emitted; absence is an honest silent row.
*/
export function summarizeArkRunSection(input = {}) {
const extra = extraFromConfig(input.arkRun);
const uniqueIds = extra.present ? uniqueArkRunRuleIds(input.findings) : [];
const ruleIds = uniqueIds.slice(0, RESIDUAL_RULE_CAP);
const residualCount = uniqueIds.length;
const mergePlanes = composeMergePlanesHonesty({
classification: input.classification,
arkRules: {
active: input.arkRules?.active === true,
structureEnforced: input.arkRules?.structureEnforced,
structureTotal: input.arkRules?.structureTotal,
structureAdvisory: input.arkRules?.structureAdvisory,
invariantEnforced: input.arkRules?.invariantEnforced,
invariantTotal: input.arkRules?.invariantTotal,
invariantAdvisory: input.arkRules?.invariantAdvisory,
covered: input.arkRules?.covered,
uncovered: input.arkRules?.uncovered,
},
arkRun: {
present: extra.present,
mode: extra.mode,
residualCount,
},
});
const extraMergeTeeth = extra.present && extra.mode === 'enforced' && extraMergeTeethAllowed(input.classification);
let note;
if (!extra.present) {
note =
'Absence of arkRun is silent — Layers and ArkRules verdicts unchanged. Not a score.';
}
else if (extra.mode === 'advisory') {
note =
'Advisory ArkRun residual only — never flips valid or --strict-merge. Residual is a finding-id count, never a score.';
}
else if (extraMergeTeeth) {
note =
'Enforced ArkRun is on the extra merge plane. Residual is a finding-id count, never a score.';
}
else {
note =
'Enforced ArkRun extra teeth stay demoted until the layer plane is honestly classified. Residual is a finding-id count, never a score.';
}
return {
schemaVersion: ARK_RUN_DOCTOR_SCHEMA_VERSION,
notAScore: true,
active: extra.present,
mode: extra.mode,
compositionRoots: extra.roots,
managedLayers: extra.layers,
requireDeclarations: extra.requireDeclarations,
residual: { count: residualCount, ruleIds },
extraMergeTeeth,
failMergeWhen: mergePlanes.failMergeWhen,
note,
mergePlanes,
};
}
/** Thin status slice — counts only; residual null means unknown, not green. */
export function projectStatusArkRun(input = {}) {
const present = input.present === true;
const mode = closedMode(input.mode);
const residualRaw = input.residual;
let residual = null;
if (typeof residualRaw === 'number' && Number.isFinite(residualRaw) && residualRaw >= 0) {
residual = Math.floor(residualRaw);
}
if (!present)
residual = residual == null ? 0 : residual;
return {
notAScore: true,
present,
mode: present ? mode : null,
extraMergeTeeth: present && mode === 'enforced' && input.extraMergeTeeth === true,
residual,
};
}
export function formatArkRunDoctorLines(section) {
if (!section || section.notAScore !== true)
return [];
if (section.active !== true) {
return ['ArkRun extra is off — silent on Layers/ArkRules (not a score).'];
}
const mode = section.mode ?? 'unknown';
const teeth = section.extraMergeTeeth === true ? 'armed' : 'not armed';
const lines = [
`mode: ${mode} · extra merge teeth ${teeth} · not a score`,
];
if (section.residual.count > 0) {
const shown = section.residual.ruleIds.join(', ');
const more = section.residual.count > section.residual.ruleIds.length
? ` (+${section.residual.count - section.residual.ruleIds.length} more)`
: '';
lines.push(`Residual: ${shown}${more}`);
}
else {
lines.push('Residual: none on this scan (not a score — green extras ≠ finished kernel wiring).');
}
if (section.failMergeWhen)
lines.push(section.failMergeWhen);
return lines;
}
/**
* GENERATED FILE — do not edit by hand.
*
* Canonical algorithm: src/domain/arkRunFacts.ts
* Regenerate: node scripts/generate-cli-pure.mjs
* Drift check: node scripts/generate-cli-pure.mjs --check
*
* Pure CLI helper (bin/lib/ark-run-facts.mjs). Zero Node I/O.
*/
export const ARKRUN_KERNEL_FACTORY_CALLEES = [
'createArkKernel',
'createStrictArkKernel',
'createArkKernelFromConfig',
'createStrictArkKernelFromConfig',
];
/** Closed interaction callees from ADR 0022 undeclared-emit/handle/depend. */
export const ARKRUN_KERNEL_INTERACTION_CALLEES = [
'publisher',
'publish',
'raise',
'raiseAsync',
'send',
'sendTo',
'subscribe',
'registerHandler',
'resolve',
'resolveSingleton',
];
const FACTORY_CALLEES = new Set(ARKRUN_KERNEL_FACTORY_CALLEES);
const BUILTIN_CTORS = new Set([
'AggregateError',
'Array',
'ArrayBuffer',
'BigInt64Array',
'BigUint64Array',
'Boolean',
'DataView',
'Date',
'Error',
'EvalError',
'FinalizationRegistry',
'Float32Array',
'Float64Array',
'Function',
'Int8Array',
'Int16Array',
'Int32Array',
'Map',
'Number',
'Object',
'Promise',
'Proxy',
'RangeError',
'ReferenceError',
'RegExp',
'Set',
'SharedArrayBuffer',
'String',
'Symbol',
'SyntaxError',
'TypeError',
'URIError',
'Uint8Array',
'Uint8ClampedArray',
'Uint16Array',
'Uint32Array',
'WeakMap',
'WeakRef',
'WeakSet',
]);
/** Receivers whose `.resolve`/`.publish` are ambient, not kernel APIs. */
const SKIP_INTERACTION_RECEIVERS = new Set([
'Array',
'Atomics',
'Buffer',
'JSON',
'Math',
'Number',
'Object',
'Promise',
'Reflect',
'String',
'console',
'fs',
'path',
'url',
'util',
]);
export function isArkRunKernelModuleSpecifier(specifier) {
return (specifier === '@arkgate/runtime' ||
specifier.startsWith('@arkgate/runtime/') ||
specifier === 'arkgate/runtime' ||
specifier.startsWith('arkgate/runtime/'));
}
/**
* Closed broker / queue / emitter specifiers for `arkrun-transport-bypass`
* (ADR 0022 D4). Exact entry or package-root subpath only — never substring.
*/
export const ARKRUN_TRANSPORT_BYPASS_SPECIFIERS = [
'events',
'node:events',
'eventemitter2',
'eventemitter3',
'emittery',
'kafkajs',
'kafka-node',
'amqplib',
'amqp',
'bull',
'bullmq',
'mqtt',
'nats',
'@aws-sdk/client-sqs',
'@aws-sdk/client-sns',
'@aws-sdk/client-eventbridge',
'@google-cloud/pubsub',
'@azure/service-bus',
];
const TRANSPORT_BYPASS = new Set(ARKRUN_TRANSPORT_BYPASS_SPECIFIERS);
export function isArkRunTransportBypassSpecifier(specifier) {
if (!specifier || specifier.startsWith('.') || specifier.startsWith('/'))
return false;
if (TRANSPORT_BYPASS.has(specifier))
return true;
const first = specifier.indexOf('/');
if (first < 0)
return false;
const root = specifier.slice(0, first);
if (TRANSPORT_BYPASS.has(root))
return true;
const second = specifier.indexOf('/', first + 1);
if (second < 0)
return false;
return TRANSPORT_BYPASS.has(specifier.slice(0, second));
}
export function arkRunKernelCallKind(callee) {
if (FACTORY_CALLEES.has(callee))
return 'factory';
switch (callee) {
case 'publisher':
return 'publisher';
case 'publish':
return 'publish';
case 'raise':
case 'raiseAsync':
return 'raise';
case 'send':
case 'sendTo':
return 'send';
case 'subscribe':
return 'subscribe';
case 'registerHandler':
return 'register-handler';
case 'resolve':
return 'resolve';
case 'resolveSingleton':
return 'resolve-singleton';
default:
return undefined;
}
}
function lineAt(content, index) {
let line = 1;
for (let i = 0; i < index; i += 1) {
if (content.charCodeAt(i) === 10)
line += 1;
}
return line;
}
/** Replace comments with spaces so line numbers stay aligned. */
function stripCommentsPreservingLines(content) {
return content
.replace(/\/\*[\s\S]*?\*\//g, (block) => block.replace(/[^\n]/g, ' '))
.replace(/(^|[^:\\])\/\/.*$/gm, (line) => line.replace(/\/\/.*$/, (tail) => ' '.repeat(tail.length)));
}
function firstStringLiteralArg(content, openParenEnd) {
const slice = content.slice(openParenEnd);
const match = /^\s*(['"])((?:\\.|[^\\])*?)\1/.exec(slice);
if (!match)
return undefined;
const value = match[2] ?? '';
return value.length > 0 ? value : undefined;
}
function keywordBefore(content, index, keyword) {
const start = Math.max(0, index - keyword.length - 8);
const before = content.slice(start, index);
return new RegExp(`\\b${keyword}\\s+$`).test(before);
}
function parseValueImportClause(content, onClause) {
const importRe = /\b(?:import|export)(\s+type)?\s+([\s\S]*?)\s+from\s*['"]([^'"]+)['"]/g;
let match;
while ((match = importRe.exec(content)) !== null) {
if (match[1])
continue;
onClause(match[2] ?? '', match[3] ?? '');
}
}
/** Value `import`/`export … from` clauses. Strips comments so callers may pass raw source. */
export function forEachArkRunValueImportClause(content, onClause) {
parseValueImportClause(stripCommentsPreservingLines(content), onClause);
}
/**
* Lexical import/export-from and require/import() specifier edges for the
* editor / snippet envelope. Resolution stays unresolved-external — sensors
* only need the specifier and from-file.
*/
export function extractArkRunValueImportDependenciesFromSource(file, content) {
const source = stripCommentsPreservingLines(content);
const out = [];
const fromRe = /\b(?:import|export)(\s+type)?\s+([\s\S]*?)\s+from\s*['"]([^'"]+)['"]/g;
let match;
while ((match = fromRe.exec(source)) !== null) {
const specifier = match[3] ?? '';
if (!specifier)
continue;
const statement = match[0] ?? '';
out.push({
from: file,
specifier,
kind: /^\s*export/.test(statement) ? 'export' : 'import',
typeOnly: Boolean(match[1]),
line: lineAt(content, match.index),
resolution: 'resolved-external',
});
}
const callRe = /\b(?:require|import)\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
while ((match = callRe.exec(source)) !== null) {
const specifier = match[1] ?? '';
if (!specifier)
continue;
const kind = match[0]?.startsWith('import') ? 'dynamic-import' : 'require';
out.push({
from: file,
specifier,
kind,
typeOnly: false,
line: lineAt(content, match.index),
resolution: 'resolved-external',
});
}
return out;
}
/** PascalCase named bindings from value import clauses (snippet admitted constructors). */
export function extractArkRunImportedConstructorNamesFromSource(content) {
const names = [];
forEachArkRunValueImportClause(content, (clause) => {
const braced = /\{([^}]*)\}/.exec(clause);
if (!braced?.[1])
return;
for (const part of braced[1].split(',')) {
const piece = part.trim();
if (!piece || piece.startsWith('type '))
continue;
const alias = /^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(piece);
const local = alias?.[2] ?? /^([A-Za-z_][A-Za-z0-9_]*)$/.exec(piece)?.[1];
const original = alias?.[1] ?? local;
if (local && original && /^[A-Z]/.test(original))
names.push(local, original);
}
});
return uniqueSorted(names);
}
function collectKernelImportBindings(content) {
const named = new Map();
const namespaces = new Set();
parseValueImportClause(content, (clause, specifier) => {
if (!isArkRunKernelModuleSpecifier(specifier))
return;
const namespace = /\*\s+as\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(clause);
if (namespace?.[1])
namespaces.add(namespace[1]);
const defaultIdent = /^([A-Za-z_][A-Za-z0-9_]*)\s*(?:,|$)/.exec(clause.trim());
if (defaultIdent?.[1])
named.set(defaultIdent[1], defaultIdent[1]);
const braced = /\{([^}]*)\}/.exec(clause);
if (!braced?.[1])
return;
for (const part of braced[1].split(',')) {
const piece = part.trim();
if (!piece || piece.startsWith('type '))
continue;
const alias = /^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(piece);
if (alias) {
named.set(alias[2], alias[1]);
continue;
}
const ident = /^([A-Za-z_][A-Za-z0-9_]*)$/.exec(piece);
if (ident?.[1])
named.set(ident[1], ident[1]);
}
});
return { named, namespaces };
}
function collectImportedConstructors(content, admitted) {
const out = new Set(admitted);
parseValueImportClause(content, (clause, specifier) => {
const braced = /\{([^}]*)\}/.exec(clause);
if (!braced?.[1])
return;
for (const part of braced[1].split(',')) {
const piece = part.trim();
if (!piece || piece.startsWith('type '))
continue;
const alias = /^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(piece);
const local = alias?.[2] ?? /^([A-Za-z_][A-Za-z0-9_]*)$/.exec(piece)?.[1];
const original = alias?.[1] ?? local;
if (!local || !original || !/^[A-Z]/.test(original))
continue;
if (isArkRunKernelModuleSpecifier(specifier) || admitted.has(original) || admitted.has(local)) {
out.add(local);
out.add(original);
}
}
});
return out;
}
function importedFromForName(content, localName) {
let found;
parseValueImportClause(content, (clause, specifier) => {
if (!found && new RegExp(`\\b${localName}\\b`).test(clause))
found = specifier;
});
return found;
}
export function extractArkRunKernelCallsFromSource(file, content) {
const source = stripCommentsPreservingLines(content);
const bindings = collectKernelImportBindings(source);
const facts = [];
const callRe = /\b([A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/g;
let match;
while ((match = callRe.exec(source)) !== null) {
const callee = match[1];
const index = match.index;
if (keywordBefore(source, index, 'function') || keywordBefore(source, index, 'class'))
continue;
const dotted = source.slice(0, index).match(/([A-Za-z_][A-Za-z0-9_]*)\s*\.\s*$/);
const receiver = dotted?.[1];
const original = bindings.named.get(callee) ?? callee;
const kind = arkRunKernelCallKind(original) ?? arkRunKernelCallKind(callee);
if (!kind)
continue;
const viaImport = bindings.named.has(callee) || (receiver !== undefined && bindings.namespaces.has(receiver));
if (kind !== 'factory') {
if (!viaImport && receiver === undefined)
continue;
if (receiver && SKIP_INTERACTION_RECEIVERS.has(receiver) && !viaImport)
continue;
}
const nameLiteral = firstStringLiteralArg(source, index + match[0].length);
facts.push({
file,
line: lineAt(content, index),
kind,
callee,
viaImport,
...(receiver ? { receiver } : {}),
...(nameLiteral ? { nameLiteral } : {}),
});
}
return facts;
}
export function extractArkRunManagedNewsFromSource(file, content, admittedTypeNames) {
const source = stripCommentsPreservingLines(content);
const admitted = collectImportedConstructors(source, admittedTypeNames);
const facts = [];
const newRe = /\bnew\s+(?:[A-Za-z_][A-Za-z0-9_]*\s*\.\s*)*([A-Z][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/g;
let match;
while ((match = newRe.exec(source)) !== null) {
const typeName = match[1];
if (BUILTIN_CTORS.has(typeName) || !admitted.has(typeName))
continue;
const importedFrom = importedFromForName(source, typeName);
facts.push({
file,
line: lineAt(content, match.index),
typeName,
...(importedFrom ? { importedFrom } : {}),
});
}
return facts;
}
function matchingBracketEnd(source, openIndex) {
let depth = 0;
let quote;
for (let i = openIndex; i < source.length; i += 1) {
const ch = source[i];
if (quote) {
if (ch === '\\') {
i += 1;
continue;
}
if (ch === quote)
quote = undefined;
continue;
}
if (ch === "'" || ch === '"' || ch === '`') {
quote = ch;
continue;
}
if (ch === '[')
depth += 1;
else if (ch === ']') {
depth -= 1;
if (depth === 0)
return i;
}
}
return -1;
}
function stringLiteralsInList(source, openIndex, closeIndex) {
const slice = source.slice(openIndex + 1, closeIndex);
const out = [];
const re = /(['"])((?:\\.|[^\\])*?)\1/g;
let match;
while ((match = re.exec(slice)) !== null) {
const value = match[2] ?? '';
if (value.length > 0)
out.push(value);
}
return out;
}
function uniqueSorted(values) {
return [...new Set(values)].sort((left, right) => (left < right ? -1 : left > right ? 1 : 0));
}
/** File-scoped `uses` / `reactsTo` / `raises` / `sends` string-literal lists (ADR 0023). */
export function extractArkRunDeclarationsFromSource(file, content) {
const source = stripCommentsPreservingLines(content);
const fieldRe = /\b(uses|reactsTo|raises|sends)\s*:/g;
const uses = [];
const reactsTo = [];
const raises = [];
const sends = [];
let firstIndex;
let match;
while ((match = fieldRe.exec(source)) !== null) {
const after = source.slice(match.index + match[0].length);
const bracket = /^\s*\[/.exec(after);
if (!bracket)
continue;
const openIndex = match.index + match[0].length + (bracket[0].length - 1);
const closeIndex = matchingBracketEnd(source, openIndex);
if (closeIndex < 0)
continue;
const names = stringLiteralsInList(source, openIndex, closeIndex);
if (names.length === 0)
continue;
if (firstIndex === undefined)
firstIndex = match.index;
const field = match[1];
if (field === 'uses')
uses.push(...names);
else if (field === 'reactsTo')
reactsTo.push(...names);
else if (field === 'raises')
raises.push(...names);
else
sends.push(...names);
}
if (firstIndex === undefined)
return [];
return [
{
file,
line: lineAt(content, firstIndex),
uses: uniqueSorted(uses),
reactsTo: uniqueSorted(reactsTo),
raises: uniqueSorted(raises),
sends: uniqueSorted(sends),
},
];
}
/**
* HTML for the doctor ArkRun advisory (report parity: data-advisory="arkRun").
*/
export function formatArkRunHtml(section, esc) {
if (!section || typeof section !== 'object' || section.notAScore !== true) return '';
const escape = typeof esc === 'function' ? esc : (v) => String(v);
const note = section.note ? `<p class="muted">${escape(section.note)}</p>` : '';
if (section.active !== true) {
return `
<section class="section card" data-advisory="arkRun">
<h2>ArkRun <span class="muted">(opt-in extra — not a score)</span></h2>
<p class="dim" style="margin:.15rem 0 .55rem;font-size:.88rem">
Kernel usage + complete declarations. Absence is silent — Layers and ArkRules verdicts stay the same.
</p>
${note}
</section>`;
}
const residual = section.residual && typeof section.residual === 'object' ? section.residual : { count: 0, ruleIds: [] };
const ids = Array.isArray(residual.ruleIds) ? residual.ruleIds : [];
const residualHtml =
residual.count > 0
? `<p><span class="tag warn">residual</span> ${ids
.map((id) => `<code>${escape(id)}</code>`)
.join(' · ')}${
residual.count > ids.length ? ` <span class="muted">(+${residual.count - ids.length} more)</span>` : ''
}</p>`
: '<p class="muted">Residual: none on this scan (not a score — green extras ≠ finished kernel wiring).</p>';
const teeth = section.extraMergeTeeth === true
? '<span class="tag">extra merge teeth armed</span>'
: '<span class="tag warn">extra merge teeth not armed</span>';
const mergeSentence =
section.mergePlanes && typeof section.mergePlanes.failMergeWhen === 'string'
? section.mergePlanes.failMergeWhen
: section.failMergeWhen;
const merge =
mergeSentence
? `<p class="muted" style="margin:.35rem 0 .55rem;font-size:.86rem"><b>Merge planes:</b> ${escape(mergeSentence)}</p>`
: '';
return `
<section class="section card" data-advisory="arkRun">
<h2>ArkRun <span class="muted">(not a score)</span></h2>
<p class="dim" style="margin:.15rem 0 .55rem;font-size:.88rem">
<b>[ArkRun]</b> Kernel usage + declarations — separate from <b>[Layer]</b> imports and <b>[ArkRules]</b> shape.
Advisory never flips <code>valid</code>. Enforced extra teeth only when the layer plane is classified.
</p>
${merge}
<div class="kpis" style="margin-bottom:.55rem">
<div class="kpi"><b>${escape(section.mode || '—')}</b><span>Mode</span></div>
<div class="kpi"><b>${Number(residual.count) || 0}</b><span>Residual ids</span></div>
<div class="kpi"><b>${Number(section.compositionRoots) || 0}</b><span>Composition roots</span></div>
<div class="kpi"><b>${Number(section.managedLayers) || 0}</b><span>Managed layers</span></div>
</div>
<p>${teeth} · <code>notAScore</code></p>
${residualHtml}
${note}
</section>`;
}
/**
* GENERATED FILE — do not edit by hand.
*
* Canonical algorithm: src/domain/arkRunSensors.ts
* Regenerate: node scripts/generate-cli-pure.mjs
* Drift check: node scripts/generate-cli-pure.mjs --check
*
* Pure CLI helper (bin/lib/ark-run-sensors.mjs). Zero Node I/O.
*/
import { extractArkRunImportedConstructorNamesFromSource, extractArkRunKernelCallsFromSource, extractArkRunManagedNewsFromSource, extractArkRunValueImportDependenciesFromSource, isArkRunKernelModuleSpecifier, isArkRunTransportBypassSpecifier, } from './ark-run-facts.mjs';
import { extraMergeTeethAllowed, } from './extra-merge-teeth.mjs';
import { deterministicNextAction } from './remediation.mjs';
export const ARKRUN_TIER1_SENSOR_IDS = [
'arkrun-missing-root',
'arkrun-kernel-in-domain',
'arkrun-direct-new',
'arkrun-undeclared-emit',
'arkrun-undeclared-handle',
'arkrun-undeclared-depend',
'arkrun-transport-bypass',
];
/**
* Import / `new` envelope for `arkgate/eslint`.
* Missing-root and undeclared-* stay CLI/MCP/preflight (project-wide or declaration facts).
*/
export const ARKRUN_EDITOR_SENSOR_IDS = [
'arkrun-kernel-in-domain',
'arkrun-direct-new',
'arkrun-transport-bypass',
];
const EDITOR_SENSOR_SET = new Set(ARKRUN_EDITOR_SENSOR_IDS);
export function isArkRunEditorSensor(sensor) {
return EDITOR_SENSOR_SET.has(sensor);
}
export const ARKRUN_RULE_IDS = {
'arkrun-missing-root': 'ARKRUN_MISSING_ROOT',
'arkrun-kernel-in-domain': 'ARKRUN_KERNEL_IN_DOMAIN',
'arkrun-direct-new': 'ARKRUN_DIRECT_NEW',
'arkrun-undeclared-emit': 'ARKRUN_UNDECLARED_EMIT',
'arkrun-undeclared-handle': 'ARKRUN_UNDECLARED_HANDLE',
'arkrun-undeclared-depend': 'ARKRUN_UNDECLARED_DEPEND',
'arkrun-transport-bypass': 'ARKRUN_TRANSPORT_BYPASS',
};
export const ARKRUN_INTERACTION_NAME_INCOMPLETE = 'ARKRUN_INTERACTION_NAME_INCOMPLETE';
function isDomainRoleLayer(layer, intentPrefixes = []) {
const name = layer.trim();
// Start-anchored Domain/entity/aggregate — unanchored "model" matches ReportingReadModels.
if (/^domain(?:model)?$/i.test(name) || /^domain(?=[A-Z_\-\s])/i.test(name))
return true;
if (/^(?:entit(?:y|ies)|aggregates?)(?:$|(?=[A-Z_\-\s]))/i.test(name))
return true;
return intentPrefixes.some((prefix) => {
const normalized = prefix.trim().replace(/\.+$/, '');
return normalized === 'Domain' || normalized.startsWith('Domain.');
});
}
function compareFindings(left, right) {
return (left.file.localeCompare(right.file) ||
left.ruleId.localeCompare(right.ruleId) ||
left.line - right.line ||
left.message.localeCompare(right.message));
}
function finding(extra, sensor, file, line, message, extras, teethAllowed) {
const failsStrict = extra.mode === 'enforced' && teethAllowed;
return {
ruleId: ARKRUN_RULE_IDS[sensor],
sensor,
message,
file,
line,
...(extras?.fromLayer ? { fromLayer: extras.fromLayer } : {}),
...(extras?.target ? { target: extras.target } : {}),
severity: failsStrict ? 'error' : 'warning',
failsStrict,
nextAction: deterministicNextAction({
ruleId: ARKRUN_RULE_IDS[sensor],
fromLayer: extras?.fromLayer,
target: extras?.target,
}),
};
}
function bagForFile(declarations, file) {
const uses = [];
const reactsTo = [];
const raises = [];
const sends = [];
for (const entry of declarations) {
if (entry.file !== file)
continue;
uses.push(...entry.uses);
reactsTo.push(...entry.reactsTo);
raises.push(...entry.raises);
sends.push(...entry.sends);
}
return {
uses: new Set(uses),
reactsTo: new Set(reactsTo),
raises: new Set(raises),
sends: new Set(sends),
};
}
function emitKinds(kind) {
return kind === 'publisher' || kind === 'publish' || kind === 'raise' || kind === 'send';
}
function handleKinds(kind) {
return kind === 'subscribe' || kind === 'register-handler';
}
function dependKinds(kind) {
return kind === 'resolve' || kind === 'resolve-singleton';
}
function evaluateMissingRoot(extra, hits, teethAllowed) {
const out = [];
const roots = extra.compositionRoots;
if (roots.length === 0) {
out.push(finding(extra, 'arkrun-missing-root', 'ark.config.json', 1, 'ArkRun compositionRoots is empty; no createArkKernel factory site is declared.', undefined, teethAllowed));
return out;
}
const hitsByRoot = new Map();
for (const hit of hits) {
const list = hitsByRoot.get(hit.matchedRoot) ?? [];
list.push(hit);
hitsByRoot.set(hit.matchedRoot, list);
}
for (const pattern of roots) {
const matched = [...(hitsByRoot.get(pattern) ?? [])].sort((left, right) => left.file.localeCompare(right.file));
if (matched.length === 0) {
out.push(finding(extra, 'arkrun-missing-root', 'ark.config.json', 1, `ArkRun composition root ${JSON.stringify(pattern)} matched no governed files and has no createArkKernel factory.`, { target: pattern }, teethAllowed));
continue;
}
// Factory required in the root set, not in every glob hit.
if (matched.some((hit) => hit.hasKernelFactory))
continue;
const first = matched[0];
out.push(finding(extra, 'arkrun-missing-root', first.file, 1, `ArkRun composition root ${JSON.stringify(pattern)} has no createArkKernel / createStrictArkKernel factory.`, { target: pattern }, teethAllowed));
}
return out;
}
function evaluateKernelInDomain(extra, layers, dependencies, layerForFile, teethAllowed) {
const prefixes = new Map(layers.map((layer) => [layer.name, layer.intentPrefixes ?? []]));
const out = [];
for (const dependency of dependencies) {
const specifier = dependency.specifier;
if (!specifier || !isArkRunKernelModuleSpecifier(specifier))
continue;
const fromLayer = layerForFile(dependency.from);
if (!fromLayer)
continue;
if (!isDomainRoleLayer(fromLayer, prefixes.get(fromLayer) ?? []))
continue;
out.push(finding(extra, 'arkrun-kernel-in-domain', dependency.from, dependency.line, `${fromLayer} must not import kernel module ${JSON.stringify(specifier)}.`, { fromLayer, target: specifier }, teethAllowed));
}
return out;
}
function evaluateDirectNew(extra, layers, managedNews, hits, layerForFile, teethAllowed) {
const managed = new Set(extra.managedLayers);
if (managed.size === 0)
return [];
const prefixes = new Map(layers.map((layer) => [layer.name, layer.intentPrefixes ?? []]));
const admittedFactories = new Set(hits.filter((hit) => hit.hasKernelFactory).map((hit) => hit.file));
const out = [];
for (const constructed of managedNews) {
if (admittedFactories.has(constructed.file))
continue;
const fromLayer = layerForFile(constructed.file);
if (!fromLayer || !managed.has(fromLayer))
continue;
if (isDomainRoleLayer(fromLayer, prefixes.get(fromLayer) ?? []))
continue;
out.push(finding(extra, 'arkrun-direct-new', constructed.file, constructed.line, `${fromLayer} must not construct ${constructed.typeName} with new outside an ArkRun composition-root factory.`, { fromLayer, target: constructed.typeName }, teethAllowed));
}
return out;
}
function evaluateUndeclared(extra, kernelCalls, declarations, layerForFile, teethAllowed) {
const findings = [];
const completenessReasons = [];
if (extra.requireDeclarations !== true) {
return { findings, completenessReasons };
}
const managed = new Set(extra.managedLayers);
if (managed.size === 0)
return { findings, completenessReasons };
for (const call of kernelCalls) {
if (!emitKinds(call.kind) && !handleKinds(call.kind) && !dependKinds(call.kind))
continue;
const fromLayer = layerForFile(call.file);
if (!fromLayer || !managed.has(fromLayer))
continue;
if (!call.nameLiteral) {
if (extra.mode === 'enforced') {
completenessReasons.push({
code: ARKRUN_INTERACTION_NAME_INCOMPLETE,
file: call.file,
message: `ArkRun ${call.kind} call in ${call.file} has no string-literal name; enforced extra cannot prove the declaration.`,
});
}
continue;
}
const bag = bagForFile(declarations, call.file);
if (emitKinds(call.kind)) {
if (bag.raises.has(call.nameLiteral) || bag.sends.has(call.nameLiteral))
continue;
findings.push(finding(extra, 'arkrun-undeclared-emit', call.file, call.line, `Emit ${JSON.stringify(call.nameLiteral)} is not declared in raises or sends.`, { fromLayer, target: call.nameLiteral }, teethAllowed));
continue;
}
if (handleKinds(call.kind)) {
if (bag.reactsTo.has(call.nameLiteral))
continue;
findings.push(finding(extra, 'arkrun-undeclared-handle', call.file, call.line, `Handle ${JSON.stringify(call.nameLiteral)} is not declared in reactsTo.`, { fromLayer, target: call.nameLiteral }, teethAllowed));
continue;
}
if (bag.uses.has(call.nameLiteral))
continue;
findings.push(finding(extra, 'arkrun-undeclared-depend', call.file, call.line, `Depend ${JSON.stringify(call.nameLiteral)} is not declared in uses.`, { fromLayer, target: call.nameLiteral }, teethAllowed));
}
return { findings, completenessReasons };
}
function evaluateTransportBypass(extra, dependencies, layerForFile, teethAllowed) {
const managed = new Set(extra.managedLayers);
if (managed.size === 0)
return [];
const out = [];
for (const dependency of dependencies) {
if (dependency.typeOnly)
continue;
const specifier = dependency.specifier;
if (!specifier || !isArkRunTransportBypassSpecifier(specifier))
continue;
const fromLayer = layerForFile(dependency.from);
if (!fromLayer || !managed.has(fromLayer))
continue;
out.push(finding(extra, 'arkrun-transport-bypass', dependency.from, dependency.line, `${fromLayer} must not import broker/queue/emitter ${JSON.stringify(specifier)}; use the ArkRun kernel transport.`, { fromLayer, target: specifier }, teethAllowed));
}
return out;
}
/**
* Evaluate closed tier-1 ArkRun sensors. Empty extra → no findings (silent).
*/
export function evaluateArkRunSensors(input) {
const extra = input.arkRun;
if (!extra)
return { findings: [], completenessReasons: [] };
const teethAllowed = extraMergeTeethAllowed(input.classification);
const undeclared = evaluateUndeclared(extra, input.kernelCalls, input.declarations, input.layerForFile, teethAllowed);
const findings = [
...evaluateMissingRoot(extra, input.compositionRootHits, teethAllowed),
...evaluateKernelInDomain(extra, input.layers, input.dependencies, input.layerForFile, teethAllowed),
...evaluateDirectNew(extra, input.layers, input.managedNews, input.compositionRootHits, input.layerForFile, teethAllowed),
...undeclared.findings,
...evaluateTransportBypass(extra, input.dependencies, input.layerForFile, teethAllowed),
].sort(compareFindings);
const completenessReasons = [...undeclared.completenessReasons].sort((left, right) => {
const leftKey = `${left.code}\0${left.file ?? ''}\0${left.message}`;
const rightKey = `${right.code}\0${right.file ?? ''}\0${right.message}`;
return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
});
return { findings, completenessReasons };
}
/**
* Same sensors as `evaluateArkRunSensors`, filtered to the ESLint import/`new` envelope.
* Does not emit missing-root or undeclared-* (those need project-wide / declaration facts).
*/
export function evaluateArkRunEditorSensors(input) {
const result = evaluateArkRunSensors(input);
return {
findings: result.findings.filter((item) => isArkRunEditorSensor(item.sensor)),
completenessReasons: [],
};
}
function fileMatchesCompositionRoot(pattern, file) {
if (pattern === file)
return true;
const star = pattern.indexOf('*');
if (star < 0)
return false;
const prefix = pattern.slice(0, star).replace(/\/$/, '');
return prefix.length > 0 && (file === prefix || file.startsWith(`${prefix}/`));
}
function compositionRootHitsForSource(extra, file, source) {
const hasFactory = extractArkRunKernelCallsFromSource(file, source).some((call) => call.kind === 'factory');
const hits = [];
for (const pattern of extra.compositionRoots) {
if (!fileMatchesCompositionRoot(pattern, file))
continue;
hits.push({ file, matchedRoot: pattern, hasKernelFactory: hasFactory });
}
return hits;
}
/**
* Import / `new` envelope from one proposed source (hook Write/Edit, snippet MCP).
* Missing-root and undeclared-* stay project-wide CLI/MCP/preflight.
*/
export function evaluateArkRunEditorSensorsFromSource(input) {
const extra = input.arkRun;
if (!extra)
return { findings: [], completenessReasons: [] };
const admitted = new Set(extractArkRunImportedConstructorNamesFromSource(input.source));
return evaluateArkRunEditorSensors({
arkRun: extra,
layers: input.layers,
kernelCalls: [],
managedNews: extractArkRunManagedNewsFromSource(input.file, input.source, admitted),
compositionRootHits: compositionRootHitsForSource(extra, input.file, input.source),
declarations: [],
dependencies: extractArkRunValueImportDependenciesFromSource(input.file, input.source),
layerForFile: input.layerForFile,
classification: input.classification,
});
}
/**
* GENERATED FILE — do not edit by hand.
*
* Canonical algorithm: src/domain/extraMergeTeeth.ts
* Regenerate: node scripts/generate-cli-pure.mjs
* Drift check: node scripts/generate-cli-pure.mjs --check
*
* Pure CLI helper (bin/lib/extra-merge-teeth.mjs). Zero Node I/O.
*/
export const EXTRA_MERGE_TEETH_GOVERNED_FLOOR = 50;
export function normalizeExtraMergeTeethClassification(classification) {
if (!classification)
return {};
const governedPercent = typeof classification.governedPercent === 'number' ? classification.governedPercent : null;
let populatedLayerCount = typeof classification.populatedLayerCount === 'number'
? classification.populatedLayerCount
: null;
if (populatedLayerCount == null &&
typeof classification.classifiedFiles === 'number') {
populatedLayerCount = classification.classifiedFiles > 0 ? 1 : 0;
}
return { governedPercent, populatedLayerCount };
}
export function extraMergeTeethAllowed(classification) {
const normalized = normalizeExtraMergeTeethClassification(classification);
const governed = typeof normalized.governedPercent === 'number' ? normalized.governedPercent : null;
const populated = typeof normalized.populatedLayerCount === 'number' ? normalized.populatedLayerCount : null;
if (governed == null && populated == null)
return true;
return ((governed ?? 0) >= EXTRA_MERGE_TEETH_GOVERNED_FLOOR && (populated ?? 0) >= 1);
}
export function classifyResolvedLayerCoverage(files) {
const total = files.length;
let classified = 0;
const populated = new Set();
for (const file of files) {
const layer = typeof file.layer === 'string' && file.layer.length > 0 ? file.layer : null;
if (!layer)
continue;
classified += 1;
populated.add(layer);
}
return {
governedPercent: total > 0 ? Math.round((classified / total) * 100) : 0,
populatedLayerCount: populated.size,
};
}
export function isArkRunRuleId(ruleId) {
return typeof ruleId === 'string' && ruleId.startsWith('ARKRUN_');
}
export function isExtraPlaneFinding(violation) {
if (violation?.arkruleId != null)
return true;
const id = typeof violation?.ruleId === 'string' ? violation.ruleId : '';
return id.startsWith('ARKRULE') || id.startsWith('arkrule') || id.startsWith('ARKRUN_');
}
/**
* Under the classification floor, demote enforced extra-plane findings in place
* so merge/write/CI match (layer graph only). Unknown classification is a no-op.
*/
export function demoteExtraPlaneTeethUnderClassificationFloor(violations, classification = {}) {
if (!Array.isArray(violations))
return violations;
if (extraMergeTeethAllowed(classification))
return violations;
for (const violation of violations) {
if (isExtraPlaneFinding(violation) && violation.failsStrict !== false) {
violation.failsStrict = false;
if (violation.severity === 'error')
violation.severity = 'warning';
}
}
return violations;
}
/** Stamp for extra-plane honesty: never one architecture score. */
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score). Extra planes never merge into one architecture score. Advisory ArkRules ≠ merge teeth. Advisory ArkRun ≠ merge teeth.';
function countOrZero(value) {
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
}
/**
* Which extra planes can fail merge. Counts and stamps only — never a score.
*/
export function composeMergePlanesHonesty(input = {}) {
const normalized = normalizeExtraMergeTeethClassification(input.classification);
const governedPercent = typeof normalized.governedPercent === 'number' ? normalized.governedPercent : null;
const populatedLayerCount = typeof normalized.populatedLayerCount === 'number' ? normalized.populatedLayerCount : null;
const classificationKnown = governedPercent != null || populatedLayerCount != null;
const classificationAllowsTeeth = extraMergeTeethAllowed(normalized);
const arkRules = input.arkRules;
const structureEnforced = countOrZero(arkRules?.structureEnforced);
const structureTotal = countOrZero(arkRules?.structureTotal);
const structureAdvisory = typeof arkRules?.structureAdvisory === 'number'
? countOrZero(arkRules.structureAdvisory)
: Math.max(0, structureTotal - structureEnforced);
const invariantEnforced = countOrZero(arkRules?.invariantEnforced);
const invariantTotal = countOrZero(arkRules?.invariantTotal);
const invariantAdvisory = typeof arkRules?.invariantAdvisory === 'number'
? countOrZero(arkRules.invariantAdvisory)
: Math.max(0, invariantTotal - invariantEnforced);
const arkRulesHasEnforced = structureEnforced > 0 || invariantEnforced > 0;
const arkRunPresent = input.arkRun?.present === true;
const arkRunMode = input.arkRun?.mode === 'enforced' || input.arkRun?.mode === 'advisory'
? input.arkRun.mode
: null;
const arkRunResidual = countOrZero(input.arkRun?.residualCount);
const arkRunHasEnforced = arkRunPresent && arkRunMode === 'enforced';
const arkRunTeeth = arkRunHasEnforced && classificationAllowsTeeth;
const hasEnforcedTeeth = arkRulesHasEnforced || arkRunHasEnforced;
const extraMergeTeeth = hasEnforcedTeeth && classificationAllowsTeeth;
const teethDeferredForClassification = hasEnforcedTeeth && classificationKnown && !classificationAllowsTeeth;
let failMergeWhen;
if (extraMergeTeeth) {
const extras = [];
if (arkRulesHasEnforced)
extras.push('enforced structure/invariant findings');
if (arkRunHasEnforced)
extras.push('enforced ArkRun skip findings');
failMergeWhen = `Layer graph failures plus ${extras.join(' and ')} (advisory extras never fail merge alone).`;
}
else if (teethDeferredForClassification) {
const which = [
arkRulesHasEnforced ? 'ArkRules structure/invariant' : null,
arkRunHasEnforced ? 'ArkRun' : null,
]
.filter((part) => Boolean(part))
.join(' and ');
failMergeWhen = `Layer graph only — enforced ${which} findings are demoted under the teeth floor (need ≥${EXTRA_MERGE_TEETH_GOVERNED_FLOOR}% governed and ≥1 populated layer); they do not merge-block until classification is honest.`;
}
else {
const arkRunBit = !arkRunPresent
? ' Absence of arkRun is silent.'
: arkRunMode === 'advisory'
? ' Advisory ArkRun never merge-blocks.'
: ' ArkRun extra is present but does not arm merge teeth.';
failMergeWhen =
'Layer graph only — no enforced ArkRules structure/invariant teeth on this tree. Advisory packs do not arm merge teeth.' +
arkRunBit;
}
const out = {
layers: {
role: 'inter-layer-edges',
alwaysOnGate: true,
note: 'Import/export layer graph — the default merge plane. Absent arkRules or arkRun changes nothing here.',
},
structureSensors: {
role: 'intra-layer-heuristics',
total: structureTotal,
enforced: structureEnforced,
advisory: structureAdvisory,
note: 'Structure sensors are heuristics (prefer false negatives). Only mode:enforced fails merge; noisy sensors stay advisory by default. Advisory-only packs never add merge teeth (FG-ARKRULES-ADVISORY-ONLY).',
},
invariants: {
role: 'catalog-plus-coverage',
total: invariantTotal,
enforced: invariantEnforced,
advisory: invariantAdvisory,
covered: countOrZero(arkRules?.covered),
uncovered: countOrZero(arkRules?.uncovered),
note: 'Invariants are catalog + coverage evidence, not a business runtime. Enforced + proven-uncovered fails merge; absence of enforced rules adds no extra teeth.',
},
arkRun: {
role: 'kernel-usage-and-declarations',
present: arkRunPresent,
mode: arkRunMode,
residualCount: arkRunResidual,
extraMergeTeeth: arkRunTeeth,
note: arkRunPresent
? arkRunMode === 'enforced'
? 'Enforced ArkRun arms extra merge teeth only when the layer plane is classified. Residual is a count, never a score.'
: 'Advisory ArkRun never adds merge teeth and never flips valid. Residual is a count, never a score.'
: 'Absence of arkRun is silent — Layers and ArkRules verdicts unchanged. The extra never becomes a score.',
},
extraMergeTeeth,
dualPlaneStamp: MERGE_PLANES_DUAL_STAMP,
failMergeWhen,
};
if (classificationKnown) {
out.classificationGate = {
governedPercent,
populatedLayerCount,
floorPercent: EXTRA_MERGE_TEETH_GOVERNED_FLOOR,
allowsTeeth: classificationAllowsTeeth,
};
}
return out;
}
/**
* Type vocabulary for the ark.config.json contract (U02 pilot 1).
*
* Pure declarations only — no runtime values. The loader/validator logic and the
* published JSON Schema live in ./configContract.ts, whose generated CLI artifact
* must stay self-contained: type-only imports/exports are erased on transpile, so
* this split never reaches bin/lib/config-contract.mjs.
*/
type ArkConfigSchemaVersion = '1.0' | '1.1' | '1.2';
type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
type ArkConfigLayerCapabilities = {
deny?: string[];
};
type ArkConfigLayer = {
name: string;
patterns: string[];
exclude?: string[];
intentPrefixes?: string[];
description?: string;
forbiddenGlobals?: string[];
/** ADR 0009 D2 — opt-in effect-capability walls; absence changes no verdict. */
capabilities?: ArkConfigLayerCapabilities;
/** Dual-depth sugar: `pure: true` denies all seven capabilities. */
pure?: boolean;
mayImportInfrastructure?: boolean;
optional?: boolean;
/**
* Future house: empty globs are expected. `--strict-config` must not fail.
* Typo warning (`CONFIG_LAYER_PATTERN_NO_MATCHES`) is skipped.
*/
reserved?: boolean;
/** Alias of reserved — empty pattern matches are allowed. */
allowEmpty?: boolean;
};
type ArkConfigRule = {
from: string;
to: string;
allowed: boolean;
message?: string;
peerIsolation?: boolean;
sliceFolders?: string[];
};
type ArkConfigSafety = {
maxTsSuppressions?: number;
maxAnyCasts?: number;
allowInMemory?: boolean;
allowDisabledPeerIsolation?: boolean;
};
/**
* ADR 0012 — optional map of layer name → project-relative ArkRules file path.
* Absence changes no inter-layer verdict.
*/
type ArkConfigArkRulesRefs = Record<string, string>;
/** ADR 0020 — advisory never adds merge teeth; enforced is the extra's merge plane. */
type ArkConfigArkRunMode = 'advisory' | 'enforced';
/**
* ADR 0020 — optional inline ArkRun extra (schema 1.2+). Absence is silent.
* Present objects are fully defaulted by the loader.
*/
type ArkConfigArkRun = {
mode: ArkConfigArkRunMode;
compositionRoots: string[];
managedLayers: string[];
requireDeclarations: boolean;
};
type ArkConfig = {
$schema: string;
schemaVersion: ArkConfigSchemaVersion;
name?: string;
include: string[];
exclude?: string[];
excludeGenerated?: boolean;
frameworkOverlay?: string;
layers: ArkConfigLayer[];
rules: ArkConfigRule[];
cyclePolicy?: ArkConfigCyclePolicy;
dynamicImportAllowlist?: string[];
safety?: ArkConfigSafety;
/** ADR 0012 — modular ArkRules references (schema 1.1+). */
arkRules?: ArkConfigArkRulesRefs;
/** ADR 0020 — optional ArkRun extra (schema 1.2+). Absence changes no Layers/ArkRules verdict. */
arkRun?: ArkConfigArkRun;
/**
* Optional GitHub handles or emails who may loosen the contract or grow the baseline.
* Metadata — excluded from policy hash. Absence means no steward lock (policy-ack still applies).
*/
stewards?: string[];
};
type ArkConfigIssue = {
path: string;
message: string;
};
/** Original input version when the loader rewrote schemaVersion toward current. */
type ArkConfigMigratedFrom = 'unversioned' | '1.0' | '1.1' | null;
type ArkConfigLoadResult = {
config: ArkConfig;
migratedFrom: ArkConfigMigratedFrom;
};
export type { ArkConfig as A, ArkConfigRule as a, ArkConfigSchemaVersion as b, ArkConfigLoadResult as c, ArkConfigLayer as d, ArkConfigIssue as e, ArkConfigArkRun as f };
+17
-36

@@ -11,3 +11,3 @@ /**

import { layerImportNextAction } from './remediation.mjs';
import { deterministicNextAction } from './remediation.mjs';
/** Versioned public result contract shared by every ArkGate enforcement adapter. */

@@ -81,37 +81,18 @@ /**

function nextActionForDiagnostic(ruleId, evidence, violation) {
if (ruleId === 'LAYER_IMPORT_VIOLATION') {
return layerImportNextAction({
ruleId,
typeOnly: evidence.typeOnly === true,
targetTypeOnlyExports: violation.targetTypeOnlyExports === true,
namedBindingsTypeOnly: violation.namedBindingsTypeOnly === true,
peerIsolation: violation.peerIsolation === true,
portProofEligible: violation.portProofEligible === true,
fromLayer: text(evidence.fromLayer) ?? undefined,
toLayer: text(evidence.toLayer) ?? undefined,
target: text(evidence.target) ?? text(violation.target) ?? undefined,
});
}
if (ruleId === 'FORBIDDEN_GLOBAL') {
return `Inject ${evidence.target ?? 'the capability'} through a port, test at the public interface, then preflight again.`;
}
if (ruleId === 'CAPABILITY_VIOLATION') {
return `Define a ${text(violation.capability) ?? 'capability'} port in ${evidence.fromLayer ?? 'the walled layer'}, bind the implementation outside it, test at the public interface, then preflight again.`;
}
if (ruleId === 'CIRCULAR_DEPENDENCY') {
return 'Extract the shared dependency into a third module, test at the public interface, then preflight again.';
}
if (ruleId === 'RAW_EVENT_PUBLISH')
return 'Publish through a registered intent creator, then run Ark again.';
if (ruleId === 'PUBLISH_MISSING_SOURCE')
return 'Add metadata.source to the publish call, then run Ark again.';
if (ruleId === 'ARKRULE_STRUCTURE' ||
ruleId === 'ARKRULE_INVARIANT' ||
ruleId === 'INVARIANT_UNCOVERED' ||
ruleId.startsWith('ARKRULE_')) {
const source = evidence.arkruleSource ?? 'arkrules/<Layer>.json';
const id = evidence.arkruleId ?? 'the ArkRule';
return `Fix the structure or invariant for ${id} (declared in ${source}), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.`;
}
return `Resolve ${ruleId} without weakening ark.config.json, then run Ark again.`;
return deterministicNextAction({
ruleId,
target: text(evidence.target) ?? text(violation.target) ?? undefined,
fromLayer: text(evidence.fromLayer) ?? undefined,
toLayer: text(evidence.toLayer) ?? undefined,
typeOnly: evidence.typeOnly === true,
targetTypeOnlyExports: evidence.targetTypeOnlyExports === true,
namedBindingsTypeOnly: evidence.namedBindingsTypeOnly === true,
portProofEligible: evidence.portProofEligible === true,
peerIsolation: evidence.peerIsolation === true,
sourcePureTypeModule: evidence.sourcePureTypeModule === true,
edgeKind: text(evidence.edgeKind) ?? undefined,
capability: text(evidence.capability) ?? text(violation.capability) ?? undefined,
arkruleId: text(evidence.arkruleId) ?? undefined,
arkruleSource: text(evidence.arkruleSource) ?? undefined,
});
}

@@ -118,0 +99,0 @@ export function toAdapterDiagnostic(violation, fallbackSeverity = 'error',

@@ -11,4 +11,4 @@ /**

/** Current published ark.config.json schema version (ADR 0012: 1.1 adds optional arkRules). */
export const ARK_CONFIG_SCHEMA_VERSION = '1.1';
/** Current published ark.config.json schema version (ADR 0020: 1.2 adds optional arkRun). */
export const ARK_CONFIG_SCHEMA_VERSION = '1.2';
export const ARK_CONFIG_SCHEMA_URL = 'https://unpkg.com/arkgate@2/schemas/ark.config.schema.json';

@@ -54,2 +54,3 @@ const DEFAULT_LAYER_NAMES = [

{ from: '1.0', to: '1.1' },
{ from: '1.1', to: '1.2' },
];

@@ -117,2 +118,4 @@ const stringArraySchema = {

},
/** ADR 0020 — optional ArkRun extra. Absence is silent; unknown keys fail closed. */
arkRun: { $ref: '#/$defs/arkRun' },
/** Team parliament — GitHub handles or emails who may loosen the law (not part of policy hash). */

@@ -187,2 +190,16 @@ stewards: { ...stringArraySchema, default: [] },

},
arkRun: {
type: 'object',
additionalProperties: false,
properties: {
mode: {
type: 'string',
enum: ['advisory', 'enforced'],
default: 'advisory',
},
compositionRoots: { ...stringArraySchema, default: [] },
managedLayers: { ...stringArraySchema, default: [] },
requireDeclarations: { type: 'boolean', default: true },
},
},
},

@@ -321,4 +338,15 @@ };

}
function defaultedArkRun(value) {
if (!isObject(value))
return value;
return {
...value,
mode: value.mode === undefined ? 'advisory' : value.mode,
compositionRoots: value.compositionRoots === undefined ? [] : value.compositionRoots,
managedLayers: value.managedLayers === undefined ? [] : value.managedLayers,
requireDeclarations: value.requireDeclarations === undefined ? true : value.requireDeclarations,
};
}
function defaultedConfig(input) {
return {
const result = {
...input,

@@ -333,3 +361,54 @@ $schema: input.$schema === undefined ? ARK_CONFIG_SCHEMA_URL : input.$schema,

};
if (input.arkRun !== undefined)
result.arkRun = defaultedArkRun(input.arkRun);
return result;
}
function validateArkRunExtra(config, issues) {
const extra = config.arkRun;
if (extra === undefined || !isObject(extra))
return;
const layerNames = new Set();
if (Array.isArray(config.layers)) {
for (const layer of config.layers) {
if (isObject(layer) && typeof layer.name === 'string' && layer.name.length > 0) {
layerNames.add(layer.name);
}
}
}
const managed = extra.managedLayers;
if (Array.isArray(managed)) {
managed.forEach((name, index) => {
if (typeof name === 'string' && name.length > 0 && !layerNames.has(name)) {
issues.push({
path: `$.arkRun.managedLayers[${index}]`,
message: `layer ${JSON.stringify(name)} is not declared in layers[]`,
});
}
});
}
if (extra.mode === 'enforced') {
const roots = extra.compositionRoots;
if (!Array.isArray(roots) || roots.length === 0) {
issues.push({
path: '$.arkRun.compositionRoots',
message: 'ARKRUN_MISSING_ROOT: enforced mode requires at least one composition root',
});
}
if (!Array.isArray(managed) || managed.length === 0) {
issues.push({
path: '$.arkRun.managedLayers',
message: 'enforced mode requires at least one managed layer',
});
}
}
}
function migratedFromOf(originalVersion) {
if (originalVersion === ARK_CONFIG_SCHEMA_VERSION)
return null;
if (originalVersion === 'unversioned')
return 'unversioned';
if (originalVersion === '1.0' || originalVersion === '1.1')
return originalVersion;
return null;
}
function knownInputVersions() {

@@ -378,4 +457,4 @@ const versions = new Set([ARK_CONFIG_SCHEMA_VERSION]);

const working = { ...input };
// Walk the migration table. Each step is a pure version stamp for 1.0→1.1
// (arkRules is optional; absence needs no field rewrite).
// Walk the migration table. Each step is a pure version stamp (optional extras
// like arkRules / arkRun need no field rewrite when absent).
let guard = 0;

@@ -404,8 +483,3 @@ while (version !== ARK_CONFIG_SCHEMA_VERSION && guard < ARK_CONFIG_MIGRATIONS.length + 1) {

}
const migratedFrom = originalVersion === 'unversioned'
? 'unversioned'
: originalVersion === '1.0'
? '1.0'
: null;
return { candidate: defaultedConfig(working), migratedFrom };
return { candidate: defaultedConfig(working), migratedFrom: migratedFromOf(originalVersion) };
}

@@ -416,2 +490,3 @@ export function loadArkConfigContract(input, source = 'ark.config.json') {

validateNode(candidate, ARK_CONFIG_SCHEMA, '$', ARK_CONFIG_SCHEMA, issues);
validateArkRunExtra(candidate, issues);
if (issues.length > 0)

@@ -418,0 +493,0 @@ throw new ArkConfigValidationError(source, issues);

@@ -59,2 +59,10 @@ /**

entry('INVARIANT_UNCOVERED', 'arkrules', 'Invariant without coverage evidence', 'An ArkRules invariant is under contract but no covering test title or declared symbol evidence was found (or coverage is partial). Kind is never-had-tests (adopt residual) vs tests-disappeared (suite exists).', 'Add a test title or declared symbol covering the arkruleId, then preflight again. Treat never-had-tests as adopt residual; treat tests-disappeared as a regression. Missing test globs report partial — never fake green.'),
// ── ArkRun (opt-in extra; RN05 dual-depth nextAction) ────────────────────
entry('ARKRUN_MISSING_ROOT', 'arkrun', 'No kernel factory in composition roots', 'The ArkRun extra is on but no createArkKernel / createStrictArkKernel / createArkKernelFromConfig / createStrictArkKernelFromConfig factory was found in arkRun.compositionRoots, so agents can skip the kernel while the write gate stays green.', 'Import createStrictArkKernel from @arkgate/runtime (never a removed arkgate/runtime shim) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.'),
entry('ARKRUN_KERNEL_IN_DOMAIN', 'arkrun', 'Domain-role layer imports the kernel', 'A Domain-role layer imports @arkgate/runtime or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.', 'Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again. Never mechanical-safe.'),
entry('ARKRUN_DIRECT_NEW', 'arkrun', 'Managed type constructed with new', 'A managed non-Domain file constructs an admitted type with new outside an ArkRun composition-root factory, skipping kernel resolve/registration.', 'Resolve the type from the kernel instead of constructing it with new, then preflight again. Never mechanical-safe — rewiring construction is a design decision.'),
entry('ARKRUN_UNDECLARED_EMIT', 'arkrun', 'Emit name not in raises/sends', 'A publisher / publish / raise / send call-site literal is not listed in the file’s raises or sends declaration.', 'Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.'),
entry('ARKRUN_UNDECLARED_HANDLE', 'arkrun', 'Handle name not in reactsTo', 'A subscribe / registerHandler call-site literal is not listed in the file’s reactsTo declaration.', 'Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.'),
entry('ARKRUN_UNDECLARED_DEPEND', 'arkrun', 'Depend name not in uses', 'A resolve / resolveSingleton call-site literal is not listed in the file’s uses declaration.', 'Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.'),
entry('ARKRUN_TRANSPORT_BYPASS', 'arkrun', 'Homemade broker or emitter import', 'A managed layer imports a closed broker/queue/emitter specifier (EventEmitter, queue clients, …) instead of the ArkRun kernel transport.', 'Send through the ArkRun kernel transport instead of importing that broker or emitter, then preflight again. Never mechanical-safe — homemade buses stay judgment.'),
// ── atomic preflight / change set ────────────────────────────────────────

@@ -61,0 +69,0 @@ entry('INVALID_CHANGE_PATH', 'preflight', 'Unsafe change path', 'A change set entry is not a safe, non-empty project-relative path (absolute, escape, empty, or NUL).', 'Use canonical project-relative paths only in the atomic change set, then preflight again.'),

@@ -23,4 +23,16 @@ /**

import { collectStewardNudge } from './team-parliament-io.mjs';
import { formatArkRunDoctorLines, summarizeArkRunSection } from './ark-run-doctor.mjs';
export function computeDoctorAdvisories(root, config, cov, rules, files, ts, parseHealth, facts) {
function classificationFromCoverage(cov) {
return {
governedPercent: cov?.governed?.percent ?? null,
populatedLayerCount: Array.isArray(cov?.layers)
? cov.layers.filter((row) => (row?.files ?? 0) > 0).length
: null,
classifiedFiles: cov?.governed?.classifiedFiles ?? null,
};
}
/** `activeViolations` must already exclude frozen baseline keys (report residual parity). */
export function computeDoctorAdvisories(root, config, cov, rules, files, ts, parseHealth, facts, activeViolations) {
const physicalCohesion = computePhysicalCohesion(root, files);

@@ -45,2 +57,23 @@ const decisionMemory = computeReshapeDecisionMemory(root, files);

: undefined);
const classification = classificationFromCoverage(cov);
const rulesUnderContract = summarizeRulesUnderContract(root, config, factPaths, classification);
const arkRun = summarizeArkRunSection({
arkRun: config?.arkRun,
findings: activeViolations,
classification,
arkRules: {
active: rulesUnderContract?.active === true,
structureEnforced: rulesUnderContract?.mergePlanes?.structureSensors?.enforced,
structureTotal: rulesUnderContract?.mergePlanes?.structureSensors?.total,
structureAdvisory: rulesUnderContract?.mergePlanes?.structureSensors?.advisory,
invariantEnforced: rulesUnderContract?.mergePlanes?.invariants?.enforced,
invariantTotal: rulesUnderContract?.mergePlanes?.invariants?.total,
invariantAdvisory: rulesUnderContract?.mergePlanes?.invariants?.advisory,
covered: rulesUnderContract?.mergePlanes?.invariants?.covered,
uncovered: rulesUnderContract?.mergePlanes?.invariants?.uncovered,
},
});
if (rulesUnderContract?.mergePlanes) {
rulesUnderContract.mergePlanes = arkRun.mergePlanes;
}
return {

@@ -56,9 +89,4 @@ contractHealth: computeContractHealth(root, config, cov, rules),

stewardNudge: collectStewardNudge(root, config),
rulesUnderContract: summarizeRulesUnderContract(root, config, factPaths, {
governedPercent: cov?.governed?.percent ?? null,
populatedLayerCount: Array.isArray(cov?.layers)
? cov.layers.filter((row) => (row?.files ?? 0) > 0).length
: null,
classifiedFiles: cov?.governed?.classifiedFiles ?? null,
}),
rulesUnderContract,
arkRun,
};

@@ -85,2 +113,11 @@ }

}
const arkRun = advisories.arkRun;
if (arkRun && arkRun.notAScore === true) {
console.log('');
console.log(io.color.bold('ArkRun (not a score)'));
const mark = arkRun.active && arkRun.residual?.count > 0 ? io.warn : ' ';
for (const text of formatArkRunDoctorLines(arkRun)) {
io.line(mark, text);
}
}
}

@@ -143,2 +143,12 @@ /**

const arkRun = doctorAdvisories.arkRun;
if (arkRun?.active === true && arkRun.notAScore === true) {
console.log('');
const residual = Number(arkRun.residual?.count) || 0;
line(
residual > 0 ? warn : ' ',
`ArkRun: ${arkRun.mode || 'on'} · residual=${residual} · not a score`
);
}
if (violations.length === 0) {

@@ -145,0 +155,0 @@ if (!analysisComplete) {

@@ -602,17 +602,18 @@ /** Coverage, plan, and doctor CLI surfaces (roadmap #11). */

});
const doctorAdvisories = computeDoctorAdvisories(root, config, cov, rules, files, options.ts, options.parseHealth);
// AR12 — compute once for JSON + product honesty + human lines.
// P1M: classification gate on extraMergeTeeth (no teeth at empty graph).
const rulesUnderContract = summarizeRulesUnderContract(
const activeViolations = baseline.exists
? violations.filter((_, index) => !baseline.keys.has(occurrenceKeys[index]))
: violations;
const doctorAdvisories = computeDoctorAdvisories(
root,
config,
cov,
rules,
files,
options.ts,
options.parseHealth,
options.facts ?? options.architectureFacts,
{
governedPercent: cov.governed?.percent ?? null,
populatedLayerCount: Array.isArray(cov.layers)
? cov.layers.filter((row) => (row?.files ?? 0) > 0).length
: null,
classifiedFiles: cov.governed?.classifiedFiles ?? null,
}
activeViolations
);
const rulesUnderContract = doctorAdvisories.rulesUnderContract;
const arkRun = doctorAdvisories.arkRun;
// Single residual expression (nextPilot || extractionCard) — HTML report uses the same.

@@ -657,5 +658,8 @@ const residualPilot = pilotLoop?.nextPilot || pilotLoop?.extractionCard || null;

arkRulesMergeHonesty: rulesUnderContract?.mergePlanes
? { active: rulesUnderContract.active === true, ...rulesUnderContract.mergePlanes }
: rulesUnderContract?.active === true
? { active: true, extraMergeTeeth: false }
? {
active: rulesUnderContract.active === true || arkRun?.active === true,
...rulesUnderContract.mergePlanes,
}
: rulesUnderContract?.active === true || arkRun?.active === true
? { active: true, extraMergeTeeth: arkRun?.extraMergeTeeth === true }
: null,

@@ -751,6 +755,6 @@ primaryNextAction:

// Advisories, never a verdict: W01/U05/X04/Y03 + graph-blind spots.
// (rulesUnderContract is also in advisories; re-assert after spread so mergePlanes wins.)
// Re-assert after spread so mergePlanes from this scan wins.
...doctorAdvisories,
// AR12 + P1-M mergePlanes (authoritative; after advisories spread).
rulesUnderContract,
arkRun,
// P0-B — single anti-false-green honesty surface (never a score).

@@ -757,0 +761,0 @@ productHonesty,

@@ -13,2 +13,3 @@ /**

import { formatRulesUnderContractHtml } from './rules-under-contract.mjs';
import { formatArkRunHtml } from './ark-run-report.mjs';
import { primaryImprovementCompassNextAction } from './improvement-compass.mjs';

@@ -355,2 +356,3 @@

rulesUnderContractHtml(advisories.rulesUnderContract),
formatArkRunHtml(advisories.arkRun, esc),
]

@@ -357,0 +359,0 @@ .filter(Boolean)

@@ -22,2 +22,3 @@ /**

import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
import { summarizeArkRunSection } from './ark-run-doctor.mjs';
import { readBaseline, baselineOccurrenceKeys } from './violations.mjs';

@@ -131,3 +132,3 @@ import { describePackageVersionDualTruth } from './field-install.mjs';

});
const rulesUnderContract = summarizeRulesUnderContract(root, config, undefined, {
const classification = {
governedPercent: coverage?.governed?.percent ?? null,

@@ -138,3 +139,21 @@ populatedLayerCount: Array.isArray(coverage?.layers)

classifiedFiles: coverage?.governed?.classifiedFiles ?? null,
};
const rulesUnderContract = summarizeRulesUnderContract(root, config, undefined, classification);
const arkRun = summarizeArkRunSection({
arkRun: config?.arkRun,
findings: activeViolations,
classification,
arkRules: {
active: rulesUnderContract?.active === true,
structureEnforced: rulesUnderContract?.mergePlanes?.structureSensors?.enforced,
structureTotal: rulesUnderContract?.mergePlanes?.structureSensors?.total,
structureAdvisory: rulesUnderContract?.mergePlanes?.structureSensors?.advisory,
invariantEnforced: rulesUnderContract?.mergePlanes?.invariants?.enforced,
invariantTotal: rulesUnderContract?.mergePlanes?.invariants?.total,
invariantAdvisory: rulesUnderContract?.mergePlanes?.invariants?.advisory,
covered: rulesUnderContract?.mergePlanes?.invariants?.covered,
uncovered: rulesUnderContract?.mergePlanes?.invariants?.uncovered,
},
});
if (rulesUnderContract?.mergePlanes) rulesUnderContract.mergePlanes = arkRun.mergePlanes;
// Single residual expression (parity with doctor): nextPilot || extractionCard.

@@ -161,3 +180,3 @@ const residualPilot =

arkRulesMergeHonesty: rulesUnderContract?.mergePlanes
? { active: rulesUnderContract.active === true, ...rulesUnderContract.mergePlanes }
? { active: rulesUnderContract.active === true || arkRun?.active === true, ...rulesUnderContract.mergePlanes }
: null,

@@ -205,2 +224,3 @@ primaryNextAction: postGreenPath?.action ?? dualTruthNext,

mergePlanes: rulesUnderContract?.mergePlanes ?? null,
arkRun,
improvementCompass,

@@ -207,0 +227,0 @@ deepModuleCoach,

@@ -22,2 +22,3 @@ /**

'import-type-of-type-exports',
'arkrun-declaration-list',
// port-proof-inject-binding is intentionally NOT mechanical-safe (signature change).

@@ -44,2 +45,3 @@ ];

'review-contract',
'arkrun-usage',
];

@@ -92,2 +94,97 @@ const PURE_SHARED_RE = /(^|\/)(constants|types|enums|shared-types|shared\/(?:types|constants)|test-projects)(\/|\.|$)|(?:^|\/)[^/]*(?:constants|types)(?:\.[cm]?[jt]sx?)?$/i;

}
const ARKRUN_UNDECLARED_RULE_IDS = new Set([
'ARKRUN_UNDECLARED_EMIT',
'ARKRUN_UNDECLARED_HANDLE',
'ARKRUN_UNDECLARED_DEPEND',
]);
const ARKRUN_JUDGMENT_RULE_IDS = new Set([
'ARKRUN_MISSING_ROOT',
'ARKRUN_KERNEL_IN_DOMAIN',
'ARKRUN_DIRECT_NEW',
'ARKRUN_TRANSPORT_BYPASS',
]);
function arkRunCallSiteName(violation) {
return typeof violation.target === 'string' && violation.target.trim().length > 0
? violation.target.trim()
: undefined;
}
function isArkRunDeclarationListSafe(violation) {
return (typeof violation.ruleId === 'string' &&
ARKRUN_UNDECLARED_RULE_IDS.has(violation.ruleId) &&
arkRunCallSiteName(violation) !== undefined);
}
/** Catalog `fix` is the no-target form; a present `target` specializes it. */
function arkRunNextAction(violation) {
const target = arkRunCallSiteName(violation);
const fromLayer = typeof violation.fromLayer === 'string' && violation.fromLayer.length > 0
? violation.fromLayer
: undefined;
switch (violation.ruleId) {
case 'ARKRUN_MISSING_ROOT':
return target
? `Import createStrictArkKernel from @arkgate/runtime and call it in composition root ${target} listed in arkRun.compositionRoots, then preflight again.`
: 'Import createStrictArkKernel from @arkgate/runtime (never a removed arkgate/runtime shim) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.';
case 'ARKRUN_KERNEL_IN_DOMAIN':
return target
? `Move the kernel import of ${target} out of ${fromLayer ?? 'the Domain-role layer'} into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again.`
: 'Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again. Never mechanical-safe.';
case 'ARKRUN_DIRECT_NEW':
return target
? `Resolve ${target} from the kernel instead of constructing it with new, then preflight again.`
: 'Resolve the type from the kernel instead of constructing it with new, then preflight again. Never mechanical-safe — rewiring construction is a design decision.';
case 'ARKRUN_UNDECLARED_EMIT':
return target
? `Add ${target} to raises or sends on the managed component, then preflight again.`
: 'Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.';
case 'ARKRUN_UNDECLARED_HANDLE':
return target
? `Add ${target} to reactsTo on the managed component, then preflight again.`
: 'Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.';
case 'ARKRUN_UNDECLARED_DEPEND':
return target
? `Add ${target} to uses on the managed component, then preflight again.`
: 'Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.';
case 'ARKRUN_TRANSPORT_BYPASS':
return target
? `Send through the ArkRun kernel transport instead of importing ${target}, then preflight again.`
: 'Send through the ArkRun kernel transport instead of importing that broker or emitter, then preflight again. Never mechanical-safe — homemade buses stay judgment.';
default:
return `Resolve ${typeof violation.ruleId === 'string' && violation.ruleId.length > 0 ? violation.ruleId : 'ARK_UNKNOWN'} without weakening ark.config.json, then run Ark again.`;
}
}
function arkRunEnthusiastHint(violation) {
const target = arkRunCallSiteName(violation);
switch (violation.ruleId) {
case 'ARKRUN_MISSING_ROOT':
return target
? `Call createStrictArkKernel from @arkgate/runtime in ${target} so the app actually uses the kernel.`
: 'Call createStrictArkKernel from @arkgate/runtime in a listed composition root so the app actually uses the kernel.';
case 'ARKRUN_KERNEL_IN_DOMAIN':
return target
? `Domain stays kernel-free. Move the ${target} import to a composition root or adapter — never a removed arkgate/runtime shim.`
: 'Domain stays kernel-free. Move that @arkgate/runtime import to a composition root or adapter — never a removed arkgate/runtime shim.';
case 'ARKRUN_DIRECT_NEW':
return target
? `Do not construct ${target} with new. Resolve it from the kernel instead.`
: 'Do not construct that managed type with new. Resolve it from the kernel instead.';
case 'ARKRUN_UNDECLARED_EMIT':
return target
? `Add "${target}" to raises or sends. Do not invent a new emit.`
: 'Add the name you already publish to raises or sends. Do not invent a new emit.';
case 'ARKRUN_UNDECLARED_HANDLE':
return target
? `Add "${target}" to reactsTo. Do not invent a new handle.`
: 'Add the name you already subscribe to reactsTo.';
case 'ARKRUN_UNDECLARED_DEPEND':
return target
? `Add "${target}" to uses. Do not invent a new depend.`
: 'Add the name you already resolve to uses.';
case 'ARKRUN_TRANSPORT_BYPASS':
return target
? `Do not import ${target} here. Send through the ArkRun kernel transport.`
: 'Do not import that broker or EventEmitter here. Send through the ArkRun kernel transport.';
default:
return 'Read the ArkRun finding and use the kernel instead of skipping it.';
}
}
/** One deterministic re-entry action shared by human and machine denial surfaces. */

@@ -116,2 +213,10 @@ export function deterministicNextAction(violation) {

: 'arkrules/<Layer>.json'}), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.`;
case 'ARKRUN_MISSING_ROOT':
case 'ARKRUN_KERNEL_IN_DOMAIN':
case 'ARKRUN_DIRECT_NEW':
case 'ARKRUN_UNDECLARED_EMIT':
case 'ARKRUN_UNDECLARED_HANDLE':
case 'ARKRUN_UNDECLARED_DEPEND':
case 'ARKRUN_TRANSPORT_BYPASS':
return arkRunNextAction(violation);
default:

@@ -233,2 +338,18 @@ if (typeof violation.ruleId === 'string' && violation.ruleId.startsWith('ARKRULE_')) {

}
if (violation && isArkRunDeclarationListSafe(violation)) {
return {
class: 'mechanical-safe',
confidence: 0.9,
remediationKind: 'arkrun-declaration-list',
rationale: 'Call-site literal already exists; adding it to the declaration list is behavior-preserving. Inventing a new emit/handle/depend stays judgment.',
};
}
if (typeof ruleId === 'string' &&
(ARKRUN_JUDGMENT_RULE_IDS.has(ruleId) || ARKRUN_UNDECLARED_RULE_IDS.has(ruleId))) {
return {
class: 'judgment',
confidence: 0.85,
rationale: 'ArkRun usage, construction, and homemade-transport findings are never mechanical-safe. Declaration-list edits are mechanical-safe only when the call-site literal is already present as target.',
};
}
if (typeof ruleId === 'string' && ruleId.length > 0) {

@@ -346,2 +467,13 @@ return {

break;
case 'ARKRUN_MISSING_ROOT':
case 'ARKRUN_KERNEL_IN_DOMAIN':
case 'ARKRUN_DIRECT_NEW':
case 'ARKRUN_UNDECLARED_EMIT':
case 'ARKRUN_UNDECLARED_HANDLE':
case 'ARKRUN_UNDECLARED_DEPEND':
case 'ARKRUN_TRANSPORT_BYPASS':
enriched.fixClass = 'arkrun-usage';
enriched.effort = ARKRUN_UNDECLARED_RULE_IDS.has(violation.ruleId ?? '') ? 'small' : 'medium';
enriched.enthusiastHint = arkRunEnthusiastHint(violation);
break;
default:

@@ -348,0 +480,0 @@ enriched.fixClass = 'review-contract';

@@ -11,3 +11,3 @@ /**

import { isScanExcludedRelative } from '../ark-shared.mjs';
import { globToRegExp, isScanExcludedRelative } from '../ark-shared.mjs';
import {

@@ -40,2 +40,7 @@ AMBIENT_CAPABILITY_ENTRIES,

import {
extractArkRunDeclarationsFromSource,
extractArkRunKernelCallsFromSource,
extractArkRunManagedNewsFromSource,
} from './ark-run-facts.mjs';
import {
collectGovernedFiles,

@@ -1003,2 +1008,8 @@ isGovernableSourceFile,

const classShapes = [];
/** ADR 0022 / RN03 — syntax evidence only; sensors emit in RN04. */
const arkRunKernelCalls = [];
const arkRunManagedNews = [];
const arkRunCompositionRootHits = [];
const arkRunDeclarations = [];
const compositionRootPatterns = [...(config.arkRun?.compositionRoots ?? [])];

@@ -1093,5 +1104,55 @@ for (const candidate of candidateFiles) {

}
try {
arkRunKernelCalls.push(
...extractArkRunKernelCallsFromSource(candidate.path, candidate.content)
);
} catch {
// Never fail the resolver for ArkRun call extraction.
}
try {
arkRunDeclarations.push(
...extractArkRunDeclarationsFromSource(candidate.path, candidate.content)
);
} catch {
// Never fail the resolver for ArkRun declaration extraction.
}
}
}
const admittedTypeNames = new Set(classShapes.map((shape) => shape.className));
for (const candidate of candidateFiles) {
if (!/\.(tsx?|mts|cts)$/i.test(candidate.path)) continue;
try {
arkRunManagedNews.push(
...extractArkRunManagedNewsFromSource(
candidate.path,
candidate.content,
admittedTypeNames
)
);
} catch {
// Never fail the resolver for managed-new extraction.
}
}
if (compositionRootPatterns.length > 0) {
const factoryFiles = new Set(
arkRunKernelCalls.filter((call) => call.kind === 'factory').map((call) => call.file)
);
for (const candidate of candidateFiles) {
for (const pattern of compositionRootPatterns) {
try {
if (!globToRegExp(pattern).test(candidate.path)) continue;
} catch {
continue;
}
arkRunCompositionRootHits.push({
file: candidate.path,
matchedRoot: pattern,
hasKernelFactory: factoryFiles.has(candidate.path),
});
}
}
}
const dependencies = [];

@@ -1159,3 +1220,3 @@ for (const source of parsed.values()) {

return createTrustedResolvedCandidateFacts({
schemaVersion: '1.1',
schemaVersion: '1.2',
completeness: completenessReasons.length === 0 ? 'complete' : 'partial',

@@ -1177,3 +1238,7 @@ completenessReasons,

classShapes,
arkRunKernelCalls,
arkRunManagedNews,
arkRunCompositionRootHits,
arkRunDeclarations,
});
}

@@ -10,2 +10,7 @@ /**

import { loadInvariantCoverageInputs } from './invariant-coverage-io.mjs';
import {
EXTRA_MERGE_TEETH_GOVERNED_FLOOR,
composeMergePlanesHonesty,
demoteExtraPlaneTeethUnderClassificationFloor,
} from './extra-merge-teeth.mjs';

@@ -20,8 +25,7 @@ /**

/** Minimum governed % before enforced ArkRules may arm extra merge teeth (P1M / FG-EXTRATEETH). */
export const EXTRA_MERGE_TEETH_GOVERNED_FLOOR = 50;
export { EXTRA_MERGE_TEETH_GOVERNED_FLOOR };
/**
* P1M / extraMergeTeeth: under the classification floor, demote enforced ArkRules
* structure/invariant findings so merge matches doctor stamp (layer graph only).
* and ArkRun findings so merge matches doctor stamp (layer graph only).
* Unknown classification (null/null) → do not demote (contract-only callers).

@@ -34,24 +38,3 @@ *

export function demoteArkRuleTeethUnderClassificationFloor(violations, classification = {}) {
if (!Array.isArray(violations)) return violations;
const governed =
typeof classification.governedPercent === 'number' ? classification.governedPercent : null;
const populated =
typeof classification.populatedLayerCount === 'number'
? classification.populatedLayerCount
: null;
if (governed == null && populated == null) return violations;
const allowsTeeth =
(governed ?? 0) >= EXTRA_MERGE_TEETH_GOVERNED_FLOOR && (populated ?? 0) >= 1;
if (allowsTeeth) return violations;
for (const v of violations) {
const isArkRule =
v?.arkruleId != null ||
(typeof v?.ruleId === 'string' &&
(v.ruleId.startsWith('ARKRULE') || v.ruleId.startsWith('arkrule')));
if (isArkRule && v.failsStrict !== false) {
v.failsStrict = false;
if (v.severity === 'error') v.severity = 'warning';
}
}
return violations;
return demoteExtraPlaneTeethUnderClassificationFloor(violations, classification);
}

@@ -69,2 +52,14 @@

*/
function arkRunMergeInput(config, residualCount = 0) {
const extra = config?.arkRun;
if (!extra || typeof extra !== 'object') {
return { present: false, mode: null, residualCount: 0 };
}
return {
present: true,
mode: extra.mode === 'enforced' || extra.mode === 'advisory' ? extra.mode : null,
residualCount: Number(residualCount) || 0,
};
}
export function summarizeRulesUnderContract(root, config, facts, classification) {

@@ -78,2 +73,7 @@ if (!config?.arkRules || Object.keys(config.arkRules).length === 0) {

uncoveredInvariants: 0,
mergePlanes: composeMergePlanesHonesty({
classification,
arkRules: { active: false },
arkRun: arkRunMergeInput(config),
}),
notAScore: true,

@@ -170,69 +170,17 @@ note: 'No arkRules map — intra-layer ArkRules are opt-in.',

const uncoveredInvariants = coverage.coverage.filter((c) => !c.covered).length;
const hasEnforcedTeeth = structureEnforced > 0 || invariantEnforced > 0;
// P1M-EXTRATEETH-EMPTY-GRAPH / FG-EXTRATEETH-EMPTY-CLASSIFICATION:
// Do not arm structure/invariant merge teeth when the layer plane is empty or
// barely classified (e.g. 0% governed). Classification unknown → allow teeth
// (contract-only callers / unit tests without coverage).
const governedPercent =
classification && typeof classification.governedPercent === 'number'
? classification.governedPercent
: null;
const populatedLayerCount =
classification && typeof classification.populatedLayerCount === 'number'
? classification.populatedLayerCount
: classification && typeof classification.classifiedFiles === 'number'
? classification.classifiedFiles > 0
? 1
: 0
: null;
const classificationKnown = governedPercent != null || populatedLayerCount != null;
const classificationAllowsTeeth = !classificationKnown
? true
: (governedPercent ?? 0) >= EXTRA_MERGE_TEETH_GOVERNED_FLOOR &&
(populatedLayerCount ?? 0) >= 1;
const extraMergeTeeth = hasEnforcedTeeth && classificationAllowsTeeth;
const teethDeferredForClassification =
hasEnforcedTeeth && classificationKnown && !classificationAllowsTeeth;
// P1-M — which plane can fail merge (layers vs enforced structure vs invariants).
const mergePlanes = {
layers: {
role: 'inter-layer-edges',
alwaysOnGate: true,
note: 'Import/export layer graph — the default merge plane. Absent arkRules changes nothing here.',
},
structureSensors: {
role: 'intra-layer-heuristics',
total: structureRules,
enforced: structureEnforced,
advisory: structureAdvisory,
note: 'Structure sensors are heuristics (prefer false negatives). Only mode:enforced fails merge; noisy sensors stay advisory by default. Advisory-only packs never add merge teeth (FG-ARKRULES-ADVISORY-ONLY).',
},
invariants: {
role: 'catalog-plus-coverage',
total: invariants,
enforced: invariantEnforced,
advisory: invariantAdvisory,
const mergePlanes = composeMergePlanesHonesty({
classification,
arkRules: {
active: true,
structureEnforced,
structureTotal: structureRules,
structureAdvisory,
invariantEnforced,
invariantTotal: invariants,
invariantAdvisory,
covered: coveredInvariants,
uncovered: uncoveredInvariants,
note: 'Invariants are catalog + coverage evidence, not a business runtime. Enforced + proven-uncovered fails merge; absence of enforced rules adds no extra teeth.',
},
dualPlaneStamp:
'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime). The two planes never merge into one architecture score. Advisory ArkRules ≠ merge teeth.',
extraMergeTeeth,
...(classificationKnown
? {
classificationGate: {
governedPercent: governedPercent ?? null,
populatedLayerCount: populatedLayerCount ?? null,
floorPercent: EXTRA_MERGE_TEETH_GOVERNED_FLOOR,
allowsTeeth: classificationAllowsTeeth,
},
}
: {}),
failMergeWhen: extraMergeTeeth
? 'Layer graph failures plus enforced structure/invariant findings (advisory sensors never fail merge alone).'
: teethDeferredForClassification
? `Layer graph only — enforced ArkRules structure/invariant findings are demoted under the teeth floor (need ≥${EXTRA_MERGE_TEETH_GOVERNED_FLOOR}% governed and ≥1 populated layer); they do not merge-block until classification is honest.`
: 'Layer graph only — no enforced ArkRules structure/invariant teeth on this tree. Advisory packs do not arm merge teeth.',
};
arkRun: arkRunMergeInput(config),
});

@@ -239,0 +187,0 @@ return {

/** Fail-closed completeness evidence for one proposed source snippet. */
import { layerForRelativePath } from '../ark-layer-match.mjs';
import { ANALYSIS_COMPLETENESS } from './analysis-completeness.mjs';
import { evaluateArkRunEditorSensorsFromSource } from './ark-run-sensors.mjs';

@@ -34,7 +36,46 @@ export function flattenTsParseDiagnostics(ts, diagnostics, sourceFile) {

function arkRunSnippetViolations(source, context = {}) {
const extra = context.arkRun;
const layers = context.layers;
const file = context.relFile || context.filePath;
if (!extra || !Array.isArray(layers) || typeof file !== 'string' || file.length === 0) {
return [];
}
const layerForFile = (pathValue) => {
if (pathValue === file && typeof context.layer === 'string') return context.layer;
return layerForRelativePath(pathValue, layers);
};
const { findings } = evaluateArkRunEditorSensorsFromSource({
arkRun: extra,
layers,
file,
source,
layerForFile,
classification: context.classification,
});
return findings
.filter((finding) => finding.failsStrict)
.map((finding) => ({
ruleId: finding.ruleId,
code: finding.ruleId,
message: finding.message,
file: finding.file,
line: finding.line,
fromLayer: finding.fromLayer,
target: finding.target,
nextAction: finding.nextAction,
failsStrict: true,
severity: 'error',
}));
}
export function validateSnippetAnalysis({ gate, ts, source, context = {} }) {
const observed = gate.validate(source, context);
const arkRunViolations = arkRunSnippetViolations(source, context);
const base = {
valid: Boolean(observed.lexicalValid ?? observed.valid),
violations: Array.isArray(observed.violations) ? observed.violations : [],
valid: Boolean(observed.lexicalValid ?? observed.valid) && arkRunViolations.length === 0,
violations: [
...(Array.isArray(observed.violations) ? observed.violations : []),
...arkRunViolations,
],
};

@@ -41,0 +82,0 @@ const file = context.filePath;

@@ -28,2 +28,3 @@ /**

import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
import { projectStatusArkRun } from './ark-run-doctor.mjs';
import { collectVsBaseFacts, discoverTeamBaseRef } from './team-parliament-io.mjs';

@@ -344,2 +345,15 @@ import { classifyAdopted, readAdoptionStance } from './adoption-stance.mjs';

const arkRun = (() => {
const extra = config?.arkRun;
if (!extra || typeof extra !== 'object') {
return projectStatusArkRun({ present: false, residual: 0 });
}
const snap = latest?.arkRun && typeof latest.arkRun === 'object' ? latest.arkRun : null;
const mode = extra.mode === 'enforced' || extra.mode === 'advisory' ? extra.mode : null;
const extraMergeTeeth =
snap && typeof snap.extraMergeTeeth === 'boolean' ? snap.extraMergeTeeth === true : false;
const residual = typeof snap?.residual === 'number' ? snap.residual : null;
return projectStatusArkRun({ present: true, mode, extraMergeTeeth, residual });
})();
// DF02 — always project compass with honesty mode (never invent green residual).

@@ -393,2 +407,3 @@ // Prefer explicit override (tests/MCP inject doctor-facts); else report snapshot.

latest?.doctor?.designFitness?.designWeak === true,
arkRun: options.arkRun ?? arkRun,
adopted:

@@ -512,2 +527,15 @@ options.adopted ??

if (manifest.vsBase?.line) write(` ${manifest.vsBase.line}`);
const arkRunLine = manifest.arkRun;
if (arkRunLine && arkRunLine.notAScore === true) {
const residual =
arkRunLine.residual == null ? 'unknown' : String(arkRunLine.residual);
write(
` arkRun: ${arkRunLine.present ? arkRunLine.mode || 'on' : 'absent'}` +
` · residual=${residual}` +
(arkRunLine.present
? ` · extraMergeTeeth=${arkRunLine.extraMergeTeeth === true}`
: '') +
' · not a score'
);
}
write(` next: [${manifest.nextAction.id}] ${manifest.nextAction.summary}`);

@@ -514,0 +542,0 @@ }

@@ -11,2 +11,3 @@ /**

import { projectStatusArkRun } from './ark-run-doctor.mjs';
export const ARK_STATUS_MANIFEST_SCHEMA_VERSION = '1.0';

@@ -246,2 +247,8 @@ export const ARK_STATUS_MANIFEST_SCHEMA_URL = 'https://unpkg.com/arkgate@4/schemas/ark.status-manifest.schema.json';

}
if (facts.arkRun?.present === true && (facts.arkRun.residual ?? 0) > 0) {
return {
id: 'review-arkrun-residual',
summary: 'ArkRun residual remains — wire kernel usage or declarations through @arkgate/runtime. Not a score.',
};
}
if (facts.adopted === 'required-merge' || facts.adopted === 'advisory-only-acked') {

@@ -331,2 +338,5 @@ return {

}
if (facts.arkRun && typeof facts.arkRun === 'object') {
status.arkRun = projectStatusArkRun(facts.arkRun);
}
return status;

@@ -611,3 +621,16 @@ }

},
arkRun: {
type: 'object',
description: 'ArkRun extra residual (notAScore). present/mode from config; residual is a finding-id count (null = unknown, not green). extraMergeTeeth is honesty, never a score.',
additionalProperties: false,
required: ['notAScore', 'present', 'mode', 'extraMergeTeeth', 'residual'],
properties: {
notAScore: { const: true },
present: { type: 'boolean' },
mode: { anyOf: [{ enum: ['advisory', 'enforced'] }, { type: 'null' }] },
extraMergeTeeth: { type: 'boolean' },
residual: { anyOf: [{ type: 'integer', minimum: 0 }, { type: 'null' }] },
},
},
},
};

@@ -8,2 +8,111 @@ # Changelog

## 4.7.0 — 2026-08-25
**Minor** over **4.6.7**. Ships **ArkRun**: an opt-in extra on schema `1.2` for kernel
usage and complete declarations, plus companion `@arkgate/runtime` DX. Absence is
silent (Layers / ArkRules verdicts unchanged). In-memory stores remain
reference-only. **No required config migration.** Does not close Z09 / K01.
**Status: prepared** (see `docs/releases/4.7.0.md`). npm `latest` remains **4.6.7**
until publish.
### Added
- **`arkRun` extra on `ark.config.json` schema `1.2` (RN02):** optional inline
`{ mode, compositionRoots, managedLayers, requireDeclarations }`. `1.1` and
earlier configs migrate in memory; absence is silent (Layers / ArkRules
verdicts unchanged). Unknown keys, unknown `managedLayers` names, and empty
`compositionRoots` in `enforced` mode fail closed (`ARKRUN_MISSING_ROOT`).
Advisory → enforced is a strengthening policy delta; demotion or deletion is
weakening and needs the existing hash-bound ack. ESLint envelope is RN06
(landed below); CI extra teeth landed in RN07. Does not close Z09 / K01.
- **ArkRun resolver facts on resolved-candidate-facts schema `1.2` (RN03):**
additive optional `arkRunKernelCalls`, `arkRunManagedNews`, and
`arkRunCompositionRootHits`. `1.0`/`1.1` payloads stay loadable (empty
arrays). Syntax evidence only — sensors consume these in RN04. Absence of
`arkRun` still leaves Layers / ArkRules verdicts unchanged. Does not close
Z09 / K01.
- **ArkRun tier-1 sensors (RN04):** when `arkRun` is present, closed sensors
emit `ARKRUN_MISSING_ROOT`, `ARKRUN_KERNEL_IN_DOMAIN`, `ARKRUN_DIRECT_NEW`,
`ARKRUN_UNDECLARED_EMIT`, `ARKRUN_UNDECLARED_HANDLE`, `ARKRUN_UNDECLARED_DEPEND`,
and `ARKRUN_TRANSPORT_BYPASS`. Advisory findings never flip `valid`; enforced
blocks. Absence of the extra is still silent on Layers / ArkRules verdicts.
Optional `arkRunDeclarations` facts stay additive on schema `1.2`. Dual-depth
catalog nextAction is RN05 (landed below). Does not close Z09 / K01.
- **ArkRun diagnostic catalog dual-depth (RN05):** closed `ARKRUN_*` catalog
entries have dual-depth remediation: casual `enthusiastHint` plus engineer
`nextAction` (target interpolates the call-site literal or specifier). Adding
an existing declaration-list string is `mechanical-safe` (`arkrun-declaration-list`)
only when that literal is already present; other ArkRun findings stay
`judgment`. Sensors, adapter fallback, and CLI remediation share
`deterministicNextAction`. Does not close Z09 / K01.
- **ArkRun ESLint envelope (RN06):** `arkgate/eslint` recommended config adds
`ark/no-arkrun-kernel-in-domain`, `ark/no-arkrun-direct-new`, and
`ark/no-arkrun-transport-bypass`. Same `ARKRUN_*` sensors as ark-check for
the import / `new` envelope; silent when `arkRun` is absent. Missing-root and
undeclared-* stay CLI/MCP/preflight. Does not close Z09 / K01.
- **ArkRun extra-teeth parity (RN07):** CLI `--strict-merge`, MCP `ark_check` /
snippet write, PreToolUse hook, atomic preflight, and CI share one ArkRun
verdict. Enforced extra teeth arm only when the layer plane is classified
(same ≥50% governed / ≥1 populated-layer floor as ArkRules); advisory and
absence stay silent on `valid`. Doctor/status `arkRun` section landed in
RN08 below. Does not close Z09 / K01.
- **ArkRun doctor / status / report (RN08):** `ark-check --doctor`, HTML
`--report`, and `ark status` / MCP `ark_status` expose an `arkRun` section
that is always `notAScore`. Residual is a finding-id count, never a score or
LLM verdict. `mergePlanes.arkRun` states whether the extra can fail merge;
advisory and absence never arm extra teeth. Report parity requires
`data-advisory="arkRun"`. Does not close Z09 / K01.
- **ArkRun companion branding (RN09):** `@arkgate/runtime` README and public
docs brand the kernel **ArkRun**. `createStrictArkKernel` stays the factory
(per-instance; no process-wide singleton). Kernel implementation stays out of
the `arkgate` tarball. Branding is not a production-durability claim. Does not
close Z09 / K01.
- **ArkRun interaction declarations (RN10):** `@arkgate/runtime` `register()`
accepts `uses` / `reactsTo` / `raises` / `sends` plus optional tooling-only
`extendedInfo`. `getDependencyInformationPackage()` returns a JSON-serializable
snapshot of ids, lifetime, and declarations — never factories, live instances,
or input DTOs. Companion registrations may omit declarations for local
experiments; enforced `arkRun` on the gate still requires them. Does not close
Z09 / K01.
- **ArkRun transport ports (RN11):** `@arkgate/runtime` `send()` is one call site
for `local` / `localBlocking` / `broker`. `ephemeral` defaults true (await local
recording or adapter accept — not a durability claim). Missing broker adapter
falls back to in-process local delivery, not cloud portability. No cloud SDKs
ship in the package. Does not close Z09 / K01.
- **ArkRun dev inspector (RN12):** `@arkgate/runtime` `startInspector()` /
`startArkRunInspector()` is opt-in. Default bind is `127.0.0.1`; `NODE_ENV=production`
vetoes start; public hosts (`0.0.0.0`, `::`) are rejected. HTTP is lazy-loaded.
`GET /snapshot` and `GET /events` (SSE) serve the information package plus
transport facts (no factories, no shipped cloud SDKs). Does not close Z09 / K01.
- **ArkRun graph slices (RN13):** `@arkgate/runtime` `requestGraph()` slices the
information package into `process` (raises / reactsTo / sends) or `technical`
(`uses`) graphs. Optional `nodeIds`, `degreesOfSeparation`, and include/exclude
query keep a neighborhood. `formatArkRunGraphMermaid()` / `graph.mermaid` is a
helper string, never a score. Inspector `GET /graph` serves the same slice.
Does not close Z09 / K01.
- **ArkRun skip corpus (RN14):** `tests/fixtures/arkrun-skip-corpus/` is the
executable proof: Application `new`, same-layer peer import, and homemade
`EventEmitter` stay green when `arkRun` is absent (Layers / ArkRules match
schema `1.1`) and fail write path, CLI, MCP, and `--strict-merge` when the
extra is enforced. Does not close Z09 / K01.
- **ArkRun skill-body deepen (RN15):** `/ark-runtime`, `/ark-place`, and
`/ark-adopt` teach the extra vs companion (advisory adopt, kernel-only
scaffold, composition-root wiring). Frozen **13** names — no `/ark-run`.
Skills never enforce; doctor `arkRun` stays `notAScore`. Agent Skills layout
stays 1:1 with `templates/skills`. Does not close Z09 / K01.
## 4.6.7 — 2026-08-24

@@ -10,0 +119,0 @@

@@ -1,3 +0,7 @@

"use strict";var _e=Object.create;var N=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var Pe=Object.getOwnPropertyNames;var $e=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var De=(e,t)=>{for(var r in t)N(e,r,{get:t[r],enumerable:!0})},Q=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Pe(t))!je.call(e,s)&&s!==r&&N(e,s,{get:()=>t[s],enumerable:!(n=Te(t,s))||n.enumerable});return e};var ee=(e,t,r)=>(r=e!=null?_e($e(e)):{},Q(t||!e||!e.__esModule?N(r,"default",{value:e,enumerable:!0}):r,e)),ve=e=>Q(N({},"__esModule",{value:!0}),e);var ht={};De(ht,{default:()=>yt,findConfigPath:()=>j,globToRegExp:()=>L,isEdgeDenied:()=>M,layerForRelativePath:()=>S,loadArkConfig:()=>D,noDeniedCapabilities:()=>Oe,noDomainInfraImports:()=>Le,noForbiddenGlobals:()=>Ne,noRawEventPublish:()=>Ce,patternSpecificity:()=>V,plugin:()=>$,readTsconfigPathAliases:()=>Ae,requirePublishSource:()=>we,resolveImportSpecifier:()=>ke,resolveRelativeImport:()=>Ie});module.exports=ve(ht);var R=ee(require("fs"),1),p=ee(require("path"),1);var te=new Map;function re(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function O(e){let t="";for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"&&r+1<e.length){let s=e[r+1];if("*?{}[],".includes(s)||s==="\\"){t+="\\"+s,r+=1;continue}t+="/";continue}t+=n}return t}function Ve(e){let t=0;for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"){r+=1;continue}if(n==="{")t+=1;else if(n==="}"&&(t-=1,t<0))return!1}return t===0}function L(e){let t=te.get(e);if(t)return t;let r=O(e),n=Ve(r),s="",o=0;for(let c=0;c<r.length;c+=1){let g=r[c];g==="\\"&&c+1<r.length?(s+=re(r[c+1]),c+=1):g==="*"?r[c+1]==="*"?r[c+2]==="/"?(s+="(?:.*/)?",c+=2):(s+=".*",c+=1):s+="[^/]*":g==="?"?s+="[^/]":g==="{"&&n?(s+="(?:",o+=1):g==="}"&&n&&o>0?(s+=")",o-=1):g===","&&n&&o>0?s+="|":s+=re(g)}let a=new RegExp(`^${s}$`);return te.set(e,a),a}function Ke(e){return O(String(e)).split("/").filter(Boolean).filter(r=>r!=="**"&&r!=="*"&&!r.includes("*")&&!r.includes("?")&&!r.includes("{")&&!r.includes("["))}function V(e,t){let r=O(String(e)),n=Ke(r),s=r.replace(/\*/g,"").length,o=n.length*1e4+s;if(t==null||t==="")return o;let a=String(t).split(/[/\\]/).filter(Boolean);if(n.length===0)return s;let c=0,g=-1;for(let f of n){let d=-1;for(let i=c;i<a.length;i+=1)if(a[i]===f){d=i;break}if(d<0)return o;g=d,c=d+1}return(g+1)*1e6+n.length*1e4+s}function S(e,t){let r=String(e).split(/[/\\]/).join("/"),n,s=-1;for(let o of t??[])if(!(o.exclude??[]).some(a=>L(a).test(r))){for(let a of o.patterns??[])if(L(a).test(r)){let c=V(a,r);c>s&&(s=c,n=o.name)}}return n}function ne(e,t){if(!t?.length)return;let r=String(e).split(/[/\\]/).filter(Boolean),n=new Set(t.map(s=>String(s).toLowerCase()));for(let s=0;s<r.length-1;s+=1)if(n.has(r[s].toLowerCase()))return`${r[s].toLowerCase()}/${r[s+1].toLowerCase()}`}function Me(e){let t=new Set;for(let r of e??[]){let s=O(String(r)).split("/").filter(Boolean);for(let o=0;o<s.length;o+=1){let a=s[o];if((a==="**"||a==="*")&&o>0){let c=s[o-1];c&&!c.includes("*")&&!c.includes("{")&&!c.includes("}")&&t.add(c)}}}return[...t]}function He(e,t,r){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(s=>typeof s=="string"&&s.length>0);let n=(r??[]).find(s=>s.name===t);return Me(n?.patterns)}function Fe(e){return!e.fromPath||!e.toPath||e.folderCount<=0||!e.fromSlice||!e.toSlice?!0:e.fromSlice!==e.toSlice}function K(e,t,r,n){for(let s of e??[])if(!(s.from!==t||s.to!==r)&&s.allowed===!1){if(s.peerIsolation){let o=n?.fromPath,a=n?.toPath,c=He(s,t,n?.layers),g=o&&a?ne(o,c):void 0,f=o&&a?ne(a,c):void 0;if(Fe({fromPath:o,toPath:a,folderCount:c.length,fromSlice:g,toSlice:f}))return s;continue}if(t!==r)return s}}function M(e,t,r,n){return K(e,t,r,n)!==void 0}var Ue=["**/*.gen.ts","**/*.gen.tsx","**/*.generated.ts","**/*.generated.tsx"];function Be(e){let t=Array.isArray(e?.exclude)?e.exclude.filter(n=>typeof n=="string"):[];return[...e?.excludeGenerated===!1?[]:Ue,...t]}function se(e,t){let r=String(e).split(/[/\\]/).join("/");return Be(t).some(n=>L(n).test(r))}var ie=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),Ge=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),It=Object.freeze(Object.keys(Ge).sort()),H=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"}),qe=Object.freeze({process:Object.freeze(["process","node:process"])});function oe(e){if(!e||e.startsWith(".")||e.startsWith("/"))return null;let t=H[e];if(t)return t;let r=e.indexOf("/");if(r<0)return null;let n=e.slice(0,r),s=H[n];if(s)return s;let o=e.indexOf("/",r+1);return o<0?null:H[e.slice(0,o)]??null}function F(e,t){for(let r of t)if(qe[r]?.includes(e))return r;return null}function ae(e){if(e?.pure===!0)return[...ie].sort();let r=(e?.capabilities?.deny??[]).filter(n=>ie.includes(n));return[...new Set(r)].sort()}var U="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",le=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],We=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function Ye(){let e=[];for(let t of le)for(let r of le)t===r||We.has(`${t}->${r}`)||e.push({from:t,to:r,allowed:!1});return e}var de=Ye(),B=[{from:"unversioned",to:"1.0"},{from:"1.0",to:"1.1"}],I={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},ce={$schema:"https://json-schema.org/draft/2020-12/schema",$id:U,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:U,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.1",default:"1.1"},name:{type:"string",minLength:1},include:{...I,minItems:1,default:["src"]},exclude:{...I,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:de,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...I,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}},arkRules:{type:"object",additionalProperties:{type:"string",minLength:1},default:{}},stewards:{...I,default:[]}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...I,minItems:1},exclude:I,intentPrefixes:I,description:{type:"string",minLength:1},forbiddenGlobals:I,capabilities:{type:"object",additionalProperties:!1,properties:{deny:{type:"array",uniqueItems:!0,items:{type:"string",enum:["network","filesystem","clock","randomness","environment","process","persistence"]}}}},pure:{type:"boolean"},mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"},reserved:{type:"boolean"},allowEmpty:{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:{...I,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}}}}},k=class extends Error{issues;source;constructor(t,r){super(`Invalid ArkGate config (${t}):
"use strict";var gt=Object.create;var H=Object.defineProperty;var mt=Object.getOwnPropertyDescriptor;var yt=Object.getOwnPropertyNames;var ht=Object.getPrototypeOf,Rt=Object.prototype.hasOwnProperty;var At=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Ae=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of yt(t))!Rt.call(e,s)&&s!==r&&H(e,s,{get:()=>t[s],enumerable:!(n=mt(t,s))||n.enumerable});return e};var j=(e,t,r)=>(r=e!=null?gt(ht(e)):{},Ae(t||!e||!e.__esModule?H(r,"default",{value:e,enumerable:!0}):r,e)),kt=e=>Ae(H({},"__esModule",{value:!0}),e);var Pr={};At(Pr,{default:()=>Dr,findConfigPath:()=>K,globToRegExp:()=>v,isEdgeDenied:()=>te,layerForRelativePath:()=>S,loadArkConfig:()=>M,noArkRunDirectNew:()=>lt,noArkRunKernelInDomain:()=>at,noArkRunTransportBypass:()=>ct,noDeniedCapabilities:()=>it,noDomainInfraImports:()=>rt,noForbiddenGlobals:()=>ot,noRawEventPublish:()=>nt,patternSpecificity:()=>Q,plugin:()=>Z,readTsconfigPathAliases:()=>Ye,requirePublishSource:()=>st,resolveImportSpecifier:()=>ge,resolveRelativeImport:()=>Je});module.exports=kt(Pr);var x=j(require("fs"),1),g=j(require("path"),1);var ke=new Map;function be(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function V(e){let t="";for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"&&r+1<e.length){let s=e[r+1];if("*?{}[],".includes(s)||s==="\\"){t+="\\"+s,r+=1;continue}t+="/";continue}t+=n}return t}function bt(e){let t=0;for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"){r+=1;continue}if(n==="{")t+=1;else if(n==="}"&&(t-=1,t<0))return!1}return t===0}function v(e){let t=ke.get(e);if(t)return t;let r=V(e),n=bt(r),s="",i=0;for(let a=0;a<r.length;a+=1){let l=r[a];l==="\\"&&a+1<r.length?(s+=be(r[a+1]),a+=1):l==="*"?r[a+1]==="*"?r[a+2]==="/"?(s+="(?:.*/)?",a+=2):(s+=".*",a+=1):s+="[^/]*":l==="?"?s+="[^/]":l==="{"&&n?(s+="(?:",i+=1):l==="}"&&n&&i>0?(s+=")",i-=1):l===","&&n&&i>0?s+="|":s+=be(l)}let o=new RegExp(`^${s}$`);return ke.set(e,o),o}function St(e){return V(String(e)).split("/").filter(Boolean).filter(r=>r!=="**"&&r!=="*"&&!r.includes("*")&&!r.includes("?")&&!r.includes("{")&&!r.includes("["))}function Q(e,t){let r=V(String(e)),n=St(r),s=r.replace(/\*/g,"").length,i=n.length*1e4+s;if(t==null||t==="")return i;let o=String(t).split(/[/\\]/).filter(Boolean);if(n.length===0)return s;let a=0,l=-1;for(let d of n){let u=-1;for(let c=a;c<o.length;c+=1)if(o[c]===d){u=c;break}if(u<0)return i;l=u,a=u+1}return(l+1)*1e6+n.length*1e4+s}function S(e,t){let r=String(e).split(/[/\\]/).join("/"),n,s=-1;for(let i of t??[])if(!(i.exclude??[]).some(o=>v(o).test(r))){for(let o of i.patterns??[])if(v(o).test(r)){let a=Q(o,r);a>s&&(s=a,n=i.name)}}return n}function Se(e,t){if(!t?.length)return;let r=String(e).split(/[/\\]/).filter(Boolean),n=new Set(t.map(s=>String(s).toLowerCase()));for(let s=0;s<r.length-1;s+=1)if(n.has(r[s].toLowerCase()))return`${r[s].toLowerCase()}/${r[s+1].toLowerCase()}`}function Et(e){let t=new Set;for(let r of e??[]){let s=V(String(r)).split("/").filter(Boolean);for(let i=0;i<s.length;i+=1){let o=s[i];if((o==="**"||o==="*")&&i>0){let a=s[i-1];a&&!a.includes("*")&&!a.includes("{")&&!a.includes("}")&&t.add(a)}}}return[...t]}function It(e,t,r){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(s=>typeof s=="string"&&s.length>0);let n=(r??[]).find(s=>s.name===t);return Et(n?.patterns)}function xt(e){return!e.fromPath||!e.toPath||e.folderCount<=0||!e.fromSlice||!e.toSlice?!0:e.fromSlice!==e.toSlice}function ee(e,t,r,n){for(let s of e??[])if(!(s.from!==t||s.to!==r)&&s.allowed===!1){if(s.peerIsolation){let i=n?.fromPath,o=n?.toPath,a=It(s,t,n?.layers),l=i&&o?Se(i,a):void 0,d=i&&o?Se(o,a):void 0;if(xt({fromPath:i,toPath:o,folderCount:a.length,fromSlice:l,toSlice:d}))return s;continue}if(t!==r)return s}}function te(e,t,r,n){return ee(e,t,r,n)!==void 0}var Nt=["**/*.gen.ts","**/*.gen.tsx","**/*.generated.ts","**/*.generated.tsx"];function Ct(e){let t=Array.isArray(e?.exclude)?e.exclude.filter(n=>typeof n=="string"):[];return[...e?.excludeGenerated===!1?[]:Nt,...t]}function Ee(e,t){let r=String(e).split(/[/\\]/).join("/");return Ct(t).some(n=>v(n).test(r))}var Ie=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),vt=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),Ur=Object.freeze(Object.keys(vt).sort()),re=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"}),_t=Object.freeze({process:Object.freeze(["process","node:process"])});function xe(e){if(!e||e.startsWith(".")||e.startsWith("/"))return null;let t=re[e];if(t)return t;let r=e.indexOf("/");if(r<0)return null;let n=e.slice(0,r),s=re[n];if(s)return s;let i=e.indexOf("/",r+1);return i<0?null:re[e.slice(0,i)]??null}function ne(e,t){for(let r of t)if(_t[r]?.includes(e))return r;return null}function Ne(e){if(e?.pure===!0)return[...Ie].sort();let r=(e?.capabilities?.deny??[]).filter(n=>Ie.includes(n));return[...new Set(r)].sort()}var se="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",Ce=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],wt=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function Lt(){let e=[];for(let t of Ce)for(let r of Ce)t===r||wt.has(`${t}->${r}`)||e.push({from:t,to:r,allowed:!1});return e}var _e=Lt(),oe=[{from:"unversioned",to:"1.0"},{from:"1.0",to:"1.1"},{from:"1.1",to:"1.2"}],b={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},ve={$schema:"https://json-schema.org/draft/2020-12/schema",$id:se,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:se,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.2",default:"1.2"},name:{type:"string",minLength:1},include:{...b,minItems:1,default:["src"]},exclude:{...b,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:_e,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...b,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}},arkRules:{type:"object",additionalProperties:{type:"string",minLength:1},default:{}},arkRun:{$ref:"#/$defs/arkRun"},stewards:{...b,default:[]}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...b,minItems:1},exclude:b,intentPrefixes:b,description:{type:"string",minLength:1},forbiddenGlobals:b,capabilities:{type:"object",additionalProperties:!1,properties:{deny:{type:"array",uniqueItems:!0,items:{type:"string",enum:["network","filesystem","clock","randomness","environment","process","persistence"]}}}},pure:{type:"boolean"},mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"},reserved:{type:"boolean"},allowEmpty:{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:{...b,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}}},arkRun:{type:"object",additionalProperties:!1,properties:{mode:{type:"string",enum:["advisory","enforced"],default:"advisory"},compositionRoots:{...b,default:[]},managedLayers:{...b,default:[]},requireDeclarations:{type:"boolean",default:!0}}}}},E=class extends Error{issues;source;constructor(t,r){super(`Invalid ArkGate config (${t}):
${r.map(n=>`- ${n.path}: ${n.message}`).join(`
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=r}};function pe(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function _(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function x(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function ze(e,t){let r="#/$defs/";if(e.startsWith(r))return t.$defs[e.slice(r.length)]}function C(e,t,r,n,s){if(t.$ref){let o=ze(t.$ref,n);if(!o){s.push({path:r,message:`schema reference ${t.$ref} cannot be resolved`});return}C(e,o,r,n,s);return}if(t.const!==void 0&&!Object.is(e,t.const)){s.push({path:r,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(o=>Object.is(o,e))){s.push({path:r,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!pe(e)){s.push({path:r,message:`must be an object; received ${x(e)}`});return}let o=t.properties??{};for(let a of t.required??[])e[a]===void 0&&s.push({path:_(r,a),message:"is required"});if(t.additionalProperties===!1)for(let a of Object.keys(e))a in o||s.push({path:_(r,a),message:"unknown field"});else if(t.additionalProperties!==void 0&&t.additionalProperties!==!0&&typeof t.additionalProperties=="object"){let a=t.additionalProperties;for(let c of Object.keys(e))c in o||C(e[c],a,_(r,c),n,s)}for(let[a,c]of Object.entries(o))e[a]!==void 0&&C(e[a],c,_(r,a),n,s);return}if(t.type==="array"){if(!Array.isArray(e)){s.push({path:r,message:`must be an array; received ${x(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&s.push({path:r,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let o=e.map(a=>JSON.stringify(a));new Set(o).size!==o.length&&s.push({path:r,message:"must not contain duplicate items"})}t.items&&e.forEach((o,a)=>C(o,t.items,`${r}[${a}]`,n,s));return}if(t.type==="string"){if(typeof e!="string"){s.push({path:r,message:`must be a string; received ${x(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&s.push({path:r,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&s.push({path:r,message:`must be a boolean; received ${x(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){s.push({path:r,message:`must be an integer; received ${x(e)}`});return}t.minimum!==void 0&&e<t.minimum&&s.push({path:r,message:`must be at least ${t.minimum}`})}}function Je(e){return{...e,$schema:e.$schema===void 0?U:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.1":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?de.map(t=>({...t})):e.rules}}function Xe(){let e=new Set(["1.1"]);for(let t of B)t.from!=="unversioned"&&e.add(t.from),e.add(t.to);return e}function Ze(e,t="ark.config.json"){if(!pe(e))throw new k(t,[{path:"$",message:`must be an object; received ${x(e)}`}]);let r=Xe(),n=e.schemaVersion===void 0?"unversioned":typeof e.schemaVersion=="string"?e.schemaVersion:null;if(n===null)throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.1`}]);if(n!=="unversioned"&&!r.has(n))throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.1`}]);let s=n,o={...e},a=0;for(;s!=="1.1"&&a<B.length+1;){a+=1;let g=B.find(f=>f.from===s);if(!g)throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(s)}; expected 1.1`}]);s=g.to,o.schemaVersion=s}if(s!=="1.1")throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.1`}]);let c=n==="unversioned"?"unversioned":n==="1.0"?"1.0":null;return{candidate:Je(o),migratedFrom:c}}function Qe(e,t="ark.config.json"){let{candidate:r,migratedFrom:n}=Ze(e,t),s=[];if(C(r,ce,"$",ce,s),s.length>0)throw new k(t,s);return{config:r,migratedFrom:n}}function ue(e,t="ark.config.json"){let r;try{r=JSON.parse(e)}catch(n){throw new k(t,[{path:"$",message:`invalid JSON: ${n instanceof Error?n.message:String(n)}`}])}return Qe(r,t)}var et=/(^|\/)(constants|types|enums|shared-types|shared\/(?:types|constants)|test-projects)(\/|\.|$)|(?:^|\/)[^/]*(?:constants|types)(?:\.[cm]?[jt]sx?)?$/i,tt=/(^|\/)(?:kernel(?:\/|$)|events?(?:\/|\.|$)|bootstrap(?:\.[cm]?[jt]sx?)?$|emitter(?:\.[cm]?[jt]sx?)?$)|(?:^|\/)(?:intents?|publish)(?:\/|\.|$)/i,rt=/(use-?cases?|usecases?|application|orchestrat|services?|handlers?)(\/|\.|$)/i;function nt(e,t){let r=String(e??"").replace(/\\/g,"/").trim(),n=String(t?.fromLayer??""),s=String(t?.toLayer??"");return et.test(r)?"pure-shared":n==="PersistenceAdapters"&&(tt.test(r)||/events?|intents?|kernel|bootstrap/i.test(`${s} ${r}`))?"kernel-emit":rt.test(r)||(n==="DomainModel"||n==="ApplicationOrchestration")&&s==="PersistenceAdapters"?"use-case":"unknown"}function fe(e){if(e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly)return"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.";if(e.peerIsolation)return"Extract the shared dependency to a shared layer, test at the public interface, then preflight again.";let t=nt(typeof e.target=="string"?e.target:"",{fromLayer:typeof e.fromLayer=="string"?e.fromLayer:void 0,toLayer:typeof e.toLayer=="string"?e.toLayer:void 0});return t==="pure-shared"?"Adopt the imported constants/types/pure module into DomainModel or SharedKernel (do not inject a port). Then preflight again.":t==="kernel-emit"?"Persistence must not emit. Inject a port or move the event map to SharedTypes; do not import kernel/events/bootstrap from a repository. Then preflight again.":t==="use-case"||e.portProofEligible?`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, test at the public interface, then preflight again.`:"Classify the import: if it is constants/types/pure, adopt into DomainModel or SharedKernel; define a port only if the target is a real use-case. Then preflight again."}var st="docs/diagnostics.md";function y(e){return typeof e=="string"&&e.length>0?e:void 0}function ge(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}function it(e){let t=typeof e.ruleId=="string"?e.ruleId:typeof e.code=="string"?e.code:void 0,r=typeof e.file=="string"?e.file:void 0,n=typeof e.fromLayer=="string"?e.fromLayer:void 0,s=typeof e.toLayer=="string"?e.toLayer:void 0,o=typeof e.target=="string"?e.target:void 0;return[t,r,n??"",s??"",o??""].join("|")}function ot(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function at(e){return`${st}#${e}`}function lt(e,t,r){if(e==="LAYER_IMPORT_VIOLATION")return fe({ruleId:e,typeOnly:t.typeOnly===!0,targetTypeOnlyExports:r.targetTypeOnlyExports===!0,namedBindingsTypeOnly:r.namedBindingsTypeOnly===!0,peerIsolation:r.peerIsolation===!0,portProofEligible:r.portProofEligible===!0,fromLayer:y(t.fromLayer)??void 0,toLayer:y(t.toLayer)??void 0,target:y(t.target)??y(r.target)??void 0});if(e==="FORBIDDEN_GLOBAL")return`Inject ${t.target??"the capability"} through a port, test at the public interface, then preflight again.`;if(e==="CAPABILITY_VIOLATION")return`Define a ${y(r.capability)??"capability"} port in ${t.fromLayer??"the walled layer"}, bind the implementation outside it, test at the public interface, then preflight again.`;if(e==="CIRCULAR_DEPENDENCY")return"Extract the shared dependency into a third module, test at the public interface, then preflight again.";if(e==="RAW_EVENT_PUBLISH")return"Publish through a registered intent creator, then run Ark again.";if(e==="PUBLISH_MISSING_SOURCE")return"Add metadata.source to the publish call, then run Ark again.";if(e==="ARKRULE_STRUCTURE"||e==="ARKRULE_INVARIANT"||e==="INVARIANT_UNCOVERED"||e.startsWith("ARKRULE_")){let n=t.arkruleSource??"arkrules/<Layer>.json";return`Fix the structure or invariant for ${t.arkruleId??"the ArkRule"} (declared in ${n}), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.`}return`Resolve ${e} without weakening ark.config.json, then run Ark again.`}function me(e,t="error",r){let n=y(e.ruleId)??y(e.code)??"ARK_UNKNOWN",s=e.severity==="warning"||e.failsStrict===!1||e.typeOnly===!0&&e.peerIsolation!==!0?"warning":t,o={...y(e.target)?{target:y(e.target)}:{},...y(e.fromLayer)?{fromLayer:y(e.fromLayer)}:{},...y(e.toLayer)?{toLayer:y(e.toLayer)}:{},...typeof e.typeOnly=="boolean"?{typeOnly:e.typeOnly}:{},...typeof e.targetTypeOnlyExports=="boolean"?{targetTypeOnlyExports:e.targetTypeOnlyExports}:{},...typeof e.sourcePureTypeModule=="boolean"?{sourcePureTypeModule:e.sourcePureTypeModule}:{},...typeof e.namedBindingsTypeOnly=="boolean"?{namedBindingsTypeOnly:e.namedBindingsTypeOnly}:{},...typeof e.portProofEligible=="boolean"?{portProofEligible:e.portProofEligible}:{},...typeof e.peerIsolation=="boolean"?{peerIsolation:e.peerIsolation}:{},...y(e.capability)?{capability:y(e.capability)}:{},...y(e.edgeKind)?{edgeKind:y(e.edgeKind)}:{},...y(e.arkruleId)?{arkruleId:y(e.arkruleId)}:{},...y(e.arkruleSource)?{arkruleSource:y(e.arkruleSource)}:{}},a=r??it(e),c=ot(a);return{ruleId:n,severity:s,message:y(e.message)??n,location:{file:y(e.file)??"<unknown>",line:ge(e.line,1),column:ge(e.column,1)},evidence:o,nextAction:y(e.nextAction)??lt(n,o,e),findingRef:c,targetKey:a,docsCodePath:at(n)}}var ye={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."},Lt=Object.freeze([{layer:"DomainModel",prefixes:["Domain."]},{layer:"ApplicationOrchestration",prefixes:["Application."]},{layer:"PersistenceAdapters",prefixes:["Adapter.Persistence.","Adapter.Repository."]},{layer:"IntegrationAdapters",prefixes:["Adapter.Integration.","Adapter.External."]},{layer:"WorkflowSagaEngine",prefixes:["Workflow."]},{layer:"BackgroundJobsScheduling",prefixes:["Job."]},{layer:"PresentationAdapters",prefixes:["Presentation.","Adapter.Presentation.","Adapter.Api."]},{layer:"ReportingReadModels",prefixes:["Reporting."]},{layer:"ExtensibilityMetadata",prefixes:["Metadata."]},{layer:"SecurityAuditObservability",prefixes:["Security.","Audit.","Observability."]},{layer:"Kernel",prefixes:["Kernel."]}]);function ct(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function G(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&ct(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ye.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ye.PUBLISH_MISSING_SOURCE}),t}function w(e){if(typeof e.physicalFilename=="string"&&e.physicalFilename.length>0)return e.physicalFilename;if(typeof e.filename=="string"&&e.filename.length>0)return e.filename;if(typeof e.getFilename=="function")try{let t=e.getFilename();if(typeof t=="string"&&t.length>0)return t}catch{}return""}function E(e,t,r,n,s){let o=me({...n,line:n.line??t.loc?.start?.line,column:n.column??(typeof t.loc?.start?.column=="number"?t.loc.start.column+1:void 0)});return e.report({node:t,messageId:r,...s?{data:s}:{},diagnostic:o}),o}function j(e){if(!e||e==="<input>"||e.startsWith("stdin"))return null;let t=p.default.dirname(p.default.resolve(e));for(;;){let r=p.default.join(t,"ark.config.json");if(R.default.existsSync(r))return r;let n=p.default.dirname(t);if(n===t)return null;t=n}}var he=new Map;function D(e){if(!R.default.existsSync(e))return null;let t=R.default.readFileSync(e,"utf8"),r=he.get(e);if(r?.source===t)return r.config;let n=ue(t,e).config;return he.set(e,{source:t,config:n}),n}function W(e,t){return(e.include??[]).some(n=>{let s=String(n).replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/$/,"");return s==="."||t===s||t.startsWith(`${s}/`)})&&!se(t,e)}function be(e){let t=[e,`${e}.ts`,`${e}.tsx`,`${e}.mts`,`${e}.cts`,`${e}.js`,`${e}.jsx`,p.default.join(e,"index.ts"),p.default.join(e,"index.tsx"),p.default.join(e,"index.js")];for(let r of t)try{if(R.default.existsSync(r)&&R.default.statSync(r).isFile())return r}catch{}return null}function Ae(e){let t=p.default.resolve(e),r=null;for(;;){let f=p.default.join(t,"tsconfig.json");if(R.default.existsSync(f)){r=f;break}let d=p.default.dirname(t);if(d===t)break;t=d}if(!r)return{baseUrl:e,aliases:[]};let n=f=>{try{let d=R.default.readFileSync(f,"utf8");return d=d.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1"),JSON.parse(d)}catch{return null}},s=(f,d)=>{if(d>4)return{};let i=n(f);if(!i)return{};let l=i.compilerOptions??{},u=l.baseUrl,m=l.paths,h=i.extends;if(typeof h=="string"&&!h.startsWith("@")){let b=p.default.resolve(p.default.dirname(f),h.endsWith(".json")?h:`${h}.json`);if(R.default.existsSync(b)){let A=s(b,d+1);u=u??A.baseUrl,m={...A.paths??{},...m??{}}}}return{baseUrl:u,paths:m}},o=s(r,0),a=p.default.dirname(r),c=p.default.resolve(a,o.baseUrl||"."),g=[];for(let[f,d]of Object.entries(o.paths||{})){if(!Array.isArray(d)||d.length===0)continue;let i=f.replace(/\*$/,"");i&&g.push({from:i,to:String(d[0]).replace(/\*$/,"")})}return g.sort((f,d)=>d.from.length-f.from.length),{baseUrl:c,aliases:g}}function Ie(e,t){if(!t.startsWith("."))return null;let r=p.default.resolve(p.default.dirname(e),t);return be(r)}function ke(e,t,r){if(!t)return null;if(t.startsWith("."))return Ie(e,t);let n=r||p.default.dirname(e),{baseUrl:s,aliases:o}=Ae(n),a=o.find(g=>t.startsWith(g.from));if(!a)return null;let c=p.default.resolve(s,`${a.to}${t.slice(a.from.length)}`);return be(c)}function v(e){return typeof e?.value=="string"?e.value:void 0}function Y(e){return e?.name??v(e)}function z(e){return e.sourceCode??e.getSourceCode?.()}function Re(e,t){let r=z(e)?.getScope?.(t);for(;r;){let n=r.references?.find(s=>s.identifier===t);if(n)return n;r=r.upper??void 0}}function T(e,t,r){let n=Re(e,t);if(n?.resolved)return(n.resolved.defs?.length??0)>0;let s=z(e)?.getScope?.(t);for(;s;){let o=s.set?.get(r);if(o)return(o.defs?.length??0)>0;s=s.upper??void 0}return!1}function dt(e,t){let r=Re(e,t);return r?r.isValueReference!==!1:t.parent?.type==="VariableDeclarator"&&t.parent.init===t}function Se(e){if(e?.type==="Identifier"&&e.name)return{root:e,segments:[e.name]};if(!e||!(e.type==="MemberExpression"||!!(e.object&&e.property))||e.computed===!0)return;let r=Se(e.object),n=Y(e.property);if(!(!r||!n))return{root:r.root,segments:[...r.segments,n]}}function pt(e){return Y(e.callee?.property)}function xe(e,t){return e?.properties?.find(r=>Y(r.key)===t)}function P(e,t){return xe(e,t)!==void 0}function ut(e){let t=xe(e,"metadata")?.value;return P(t,"source")}function Ee(e){return pt(e)==="publish"}function q(e){if(e.importKind==="type"||e.exportKind==="type")return!0;let t=e.specifiers??[];return t.length===0?!1:t.every(r=>r.type==="ImportSpecifier")?t.every(r=>r.importKind==="type"):t.every(r=>r.exportKind==="type")}function ft(e){let t=e;for(;t?.parent;)t=t.parent;return t?.type==="Program"?t:void 0}function gt(e){let t=ft(e)?.body;if(!t)return!1;let r=!1;for(let n of t){if(n.type==="ImportDeclaration"){if(!q(n))return!1;continue}if(!(n.type==="TSInterfaceDeclaration"||n.type==="TSTypeAliasDeclaration")){if(n.type==="ExportNamedDeclaration"){if(n.declaration){if(n.declaration.type!=="TSInterfaceDeclaration"&&n.declaration.type!=="TSTypeAliasDeclaration")return!1}else if(!q(n))return!1;r=!0;continue}return!1}}return r}var Le={meta:{type:"problem",docs:{description:"Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."},messages:{forbiddenImport:"Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",forbiddenImportHeuristic:"Domain code must not import infrastructure, adapters, repositories, or database modules."},schema:[]},create(e){let t=w(e),r=j(t),n=r?D(r):null,s=r?p.default.dirname(r):null,o=a=>{let c=v(a.source);if(c&&n&&s&&t){let g=p.default.isAbsolute(t)?t:p.default.resolve(t),f=p.default.relative(s,g).split(p.default.sep).join("/");if(!W(n,f))return;let d=S(f,n.layers);if(!d)return;let i=ke(g,c,s);if(!i)return;let l=p.default.relative(s,i).split(p.default.sep).join("/");if(l.startsWith(".."))return;let u=S(l,n.layers);if(!u)return;let m={fromPath:f,toPath:l,layers:n.layers},h=K(n.rules,d,u,m);if(h||M(n.rules,d,u,m)){let b=a.type?.startsWith("Export")?"export":"import",A=q(a),J=!!h?.peerIsolation,X=A&&!J,Z=h?.message??`${d} must not ${b} ${u}.`;E(e,a,"forbiddenImport",{ruleId:"LAYER_IMPORT_VIOLATION",file:f,fromLayer:d,toLayer:u,target:l,edgeKind:b,...J?{peerIsolation:!0}:{},...A?{typeOnly:!0}:{},...X?{severity:"warning"}:{},...gt(a)?{sourcePureTypeModule:!0}:{},message:X?`${Z} (type-only \u2014 type placement debt; prefer SharedTypes / owning layer; not runtime coupling)`:Z},{fromLayer:d,toLayer:u,specifier:c})}return}};return{ImportDeclaration:o,ExportNamedDeclaration:o,ExportAllDeclaration:o}}},Ce={meta:{type:"problem",docs:{description:"Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings."},messages:{rawPublish:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=v(r),s=G({publishCall:Ee(t),rawIntentName:n,objectHasIntent:P(r,"intent"),arkPublishCandidate:!1,hasSource:!0});if(s.some(o=>o.ruleId==="RAW_EVENT_PUBLISH")){let o=s.find(a=>a.ruleId==="RAW_EVENT_PUBLISH");E(e,t,"rawPublish",{...o,file:w(e)})}}}}},we={meta:{type:"problem",docs:{description:"Require event bus publish calls to include source metadata."},messages:{missingSource:"Strict Ark publish calls must include metadata.source."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=t.arguments?.[2],o=G({publishCall:Ee(t),rawIntentName:v(r),objectHasIntent:P(r,"intent"),arkPublishCandidate:!0,hasSource:ut(r)||P(n,"source")}).find(a=>a.ruleId==="PUBLISH_MISSING_SOURCE");o&&E(e,t,"missingSource",{...o,file:w(e)})}}}},Ne={meta:{type:"problem",docs:{description:"Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` is a standalone fallback when no project config applies."},messages:{forbiddenGlobal:'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',forbiddenGlobalDefault:'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.',forbiddenModule:'{{layer}} must not use module "{{specifier}}" because it is the import form of forbidden global "{{name}}".'},schema:[{type:"object",properties:{globals:{type:"array",items:{type:"string"}}},additionalProperties:!1}]},create(e){let t=w(e),r=e.options?.[0],n=j(t),s=n?D(n):null,o=n?p.default.dirname(n):null,a=null,c="this layer";if(s&&o&&t){let i=p.default.isAbsolute(t)?t:p.default.resolve(t),l=p.default.relative(o,i).split(p.default.sep).join("/");if(!W(s,l))return{};let u=s.layers?.find(m=>m.name===S(l,s.layers));u?.forbiddenGlobals?.length?(a=new Set(u.forbiddenGlobals),c=u.name):a=null}else r?.globals&&(a=new Set(r.globals));if(!a)return{};let g=typeof z(e)?.getScope=="function",f=(i,l)=>{let u=p.default.isAbsolute(t)?t:p.default.resolve(t),m=o?p.default.relative(o,u).split(p.default.sep).join("/"):t;E(e,i,s?"forbiddenGlobal":"forbiddenGlobalDefault",{ruleId:"FORBIDDEN_GLOBAL",file:m,fromLayer:c,target:l,message:`${c} must not use the ambient global "${l}".`},{name:l,layer:c})},d=(i,l,u,m)=>{if(u||typeof l!="string")return;let h=F(l,a);if(!h)return;let b=p.default.isAbsolute(t)?t:p.default.resolve(t),A=o?p.default.relative(o,b).split(p.default.sep).join("/"):t;E(e,i,"forbiddenModule",{ruleId:"FORBIDDEN_GLOBAL",file:A,fromLayer:c,target:l,edgeKind:m,message:`${c} must not use module "${l}" because it is the import form of forbidden global "${h}".`},{layer:c,name:h,specifier:l,importKind:m})};return{MemberExpression(i){if(i.parent?.type==="MemberExpression"&&i.parent.object===i)return;let l=Se(i);if(!l||T(e,l.root,l.segments[0]))return;let u=l.segments[0]==="globalThis",m=u?l.segments.slice(1):l.segments,h;for(let b=m.length;b>=(u?1:2);b-=1){let A=m.slice(0,b).join(".");if(a.has(A)){h=A;break}}h?f(i,h):!g&&a.has(l.segments[0])&&f(i,l.segments[0])},CallExpression(i){let l=i;if(l.callee?.type==="Identifier"&&l.callee.name==="require"&&l.arguments?.[0]?.type==="Literal"&&!T(e,i,"require")&&d(i,l.arguments[0].value,!1,"require"),g)return;let u=l.callee?.type==="Identifier"?l.callee.name:void 0;u&&a.has(u)&&f(i,u)},ImportDeclaration(i){let l=i,u=(l.specifiers??[]).filter(h=>h.type==="ImportSpecifier"),m=u.length>0&&u.length===(l.specifiers??[]).length&&u.every(h=>h.importKind==="type");d(i,l.source?.value,l.importKind==="type"||m,"import")},ImportExpression(i){let l=i;l.source?.type==="Literal"&&d(i,l.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(i){let l=i;d(i,l.moduleReference?.expression?.value,l.importKind==="type"||l.isTypeOnly===!0,"require")},ExportNamedDeclaration(i){let l=i;if(!l.source)return;let u=l.specifiers??[],m=u.length>0&&u.every(h=>h.exportKind==="type");d(i,l.source.value,l.exportKind==="type"||m,"export")},ExportAllDeclaration(i){let l=i;d(i,l.source?.value,l.exportKind==="type","export")},NewExpression(i){if(g)return;let l=i.callee?.type==="Identifier"?i.callee.name:void 0;l&&a.has(l)&&f(i,l)},Identifier(i){!g||!i.name||!a.has(i.name)||!dt(e,i)||T(e,i,i.name)||f(i,i.name)}}}},Oe={meta:{type:"problem",docs:{description:"Disallow importing modules whose effect capability the layer denies (ark.config.json capabilities.deny / pure \u2014 same wall surface as ark-check). Import dimension only: ambient globals stay with no-forbidden-globals and the CLI/hook symbol path."},messages:{deniedCapability:'{{layer}} denies the {{capability}} capability (ark.config.json); "{{specifier}}" imports it. Define a port and bind the implementation in an adapter layer.'},schema:[]},create(e){let t=w(e),r=j(t),n=r?D(r):null,s=r?p.default.dirname(r):null;if(!n||!s||!t)return{};let o=p.default.isAbsolute(t)?t:p.default.resolve(t),a=p.default.relative(s,o).split(p.default.sep).join("/");if(!W(n,a))return{};let c=n.layers?.find(d=>d.name===S(a,n.layers));if(!c)return{};let g=new Set(ae(c));if(g.size===0)return{};let f=(d,i,l,u)=>{if(l||typeof i!="string"||F(i,c.forbiddenGlobals??[]))return;let m=oe(i);!m||!g.has(m)||E(e,d,"deniedCapability",{ruleId:"CAPABILITY_VIOLATION",file:a,fromLayer:c.name,target:i,capability:m,edgeKind:u,message:`${c.name} denies the ${m} capability; found import of "${i}".`},{layer:c.name,capability:m,specifier:i})};return{ImportDeclaration(d){let i=d,l=(i.specifiers??[]).filter(m=>m.type==="ImportSpecifier"),u=l.length>0&&l.length===(i.specifiers??[]).length&&l.every(m=>m.importKind==="type");f(d,i.source?.value,i.importKind==="type"||u,"import")},ImportExpression(d){let i=d;i.source?.type==="Literal"&&f(d,i.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(d){let i=d;f(d,i.moduleReference?.expression?.value,i.importKind==="type"||i.isTypeOnly===!0,"require")},ExportNamedDeclaration(d){let i=d;if(!i.source)return;let l=i.specifiers??[],u=l.length>0&&l.every(m=>m.exportKind==="type");f(d,i.source.value,i.exportKind==="type"||u,"export")},ExportAllDeclaration(d){let i=d;f(d,i.source?.value,i.exportKind==="type","export")},CallExpression(d){let i=d;i.callee?.type==="Identifier"&&i.callee.name==="require"&&i.arguments?.[0]?.type==="Literal"&&!T(e,d,"require")&&f(d,i.arguments[0].value,!1,"require")}}}},mt={"no-domain-infra-imports":Le,"no-raw-event-publish":Ce,"require-publish-source":we,"no-forbidden-globals":Ne,"no-denied-capabilities":Oe},$={rules:mt};$.configs={recommended:{plugins:{ark:$},rules:{"ark/no-domain-infra-imports":"error","ark/no-raw-event-publish":"error","ark/require-publish-source":"error","ark/no-forbidden-globals":"error","ark/no-denied-capabilities":"error"}}};var yt=$;0&&(module.exports={findConfigPath,globToRegExp,isEdgeDenied,layerForRelativePath,loadArkConfig,noDeniedCapabilities,noDomainInfraImports,noForbiddenGlobals,noRawEventPublish,patternSpecificity,plugin,readTsconfigPathAliases,requirePublishSource,resolveImportSpecifier,resolveRelativeImport});
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=r}};function D(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 w(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function Tt(e,t){let r="#/$defs/";if(e.startsWith(r))return t.$defs[e.slice(r.length)]}function O(e,t,r,n,s){if(t.$ref){let i=Tt(t.$ref,n);if(!i){s.push({path:r,message:`schema reference ${t.$ref} cannot be resolved`});return}O(e,i,r,n,s);return}if(t.const!==void 0&&!Object.is(e,t.const)){s.push({path:r,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(i=>Object.is(i,e))){s.push({path:r,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!D(e)){s.push({path:r,message:`must be an object; received ${w(e)}`});return}let i=t.properties??{};for(let o of t.required??[])e[o]===void 0&&s.push({path:B(r,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in i||s.push({path:B(r,o),message:"unknown field"});else if(t.additionalProperties!==void 0&&t.additionalProperties!==!0&&typeof t.additionalProperties=="object"){let o=t.additionalProperties;for(let a of Object.keys(e))a in i||O(e[a],o,B(r,a),n,s)}for(let[o,a]of Object.entries(i))e[o]!==void 0&&O(e[o],a,B(r,o),n,s);return}if(t.type==="array"){if(!Array.isArray(e)){s.push({path:r,message:`must be an array; received ${w(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&s.push({path:r,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let i=e.map(o=>JSON.stringify(o));new Set(i).size!==i.length&&s.push({path:r,message:"must not contain duplicate items"})}t.items&&e.forEach((i,o)=>O(i,t.items,`${r}[${o}]`,n,s));return}if(t.type==="string"){if(typeof e!="string"){s.push({path:r,message:`must be a string; received ${w(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&s.push({path:r,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&s.push({path:r,message:`must be a boolean; received ${w(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){s.push({path:r,message:`must be an integer; received ${w(e)}`});return}t.minimum!==void 0&&e<t.minimum&&s.push({path:r,message:`must be at least ${t.minimum}`})}}function Ft(e){return D(e)?{...e,mode:e.mode===void 0?"advisory":e.mode,compositionRoots:e.compositionRoots===void 0?[]:e.compositionRoots,managedLayers:e.managedLayers===void 0?[]:e.managedLayers,requireDeclarations:e.requireDeclarations===void 0?!0:e.requireDeclarations}:e}function Ot(e){let t={...e,$schema:e.$schema===void 0?se:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.2":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?_e.map(r=>({...r})):e.rules};return e.arkRun!==void 0&&(t.arkRun=Ft(e.arkRun)),t}function Dt(e,t){let r=e.arkRun;if(r===void 0||!D(r))return;let n=new Set;if(Array.isArray(e.layers))for(let i of e.layers)D(i)&&typeof i.name=="string"&&i.name.length>0&&n.add(i.name);let s=r.managedLayers;if(Array.isArray(s)&&s.forEach((i,o)=>{typeof i=="string"&&i.length>0&&!n.has(i)&&t.push({path:`$.arkRun.managedLayers[${o}]`,message:`layer ${JSON.stringify(i)} is not declared in layers[]`})}),r.mode==="enforced"){let i=r.compositionRoots;(!Array.isArray(i)||i.length===0)&&t.push({path:"$.arkRun.compositionRoots",message:"ARKRUN_MISSING_ROOT: enforced mode requires at least one composition root"}),(!Array.isArray(s)||s.length===0)&&t.push({path:"$.arkRun.managedLayers",message:"enforced mode requires at least one managed layer"})}}function Pt(e){return e==="1.2"?null:e==="unversioned"?"unversioned":e==="1.0"||e==="1.1"?e:null}function Kt(){let e=new Set(["1.2"]);for(let t of oe)t.from!=="unversioned"&&e.add(t.from),e.add(t.to);return e}function Mt(e,t="ark.config.json"){if(!D(e))throw new E(t,[{path:"$",message:`must be an object; received ${w(e)}`}]);let r=Kt(),n=e.schemaVersion===void 0?"unversioned":typeof e.schemaVersion=="string"?e.schemaVersion:null;if(n===null)throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.2`}]);if(n!=="unversioned"&&!r.has(n))throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.2`}]);let s=n,i={...e},o=0;for(;s!=="1.2"&&o<oe.length+1;){o+=1;let a=oe.find(l=>l.from===s);if(!a)throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(s)}; expected 1.2`}]);s=a.to,i.schemaVersion=s}if(s!=="1.2")throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.2`}]);return{candidate:Ot(i),migratedFrom:Pt(n)}}function $t(e,t="ark.config.json"){let{candidate:r,migratedFrom:n}=Mt(e,t),s=[];if(O(r,ve,"$",ve,s),Dt(r,s),s.length>0)throw new E(t,s);return{config:r,migratedFrom:n}}function we(e,t="ark.config.json"){let r;try{r=JSON.parse(e)}catch(n){throw new E(t,[{path:"$",message:`invalid JSON: ${n instanceof Error?n.message:String(n)}`}])}return $t(r,t)}var Ut=/(^|\/)(constants|types|enums|shared-types|shared\/(?:types|constants)|test-projects)(\/|\.|$)|(?:^|\/)[^/]*(?:constants|types)(?:\.[cm]?[jt]sx?)?$/i,Ht=/(^|\/)(?:kernel(?:\/|$)|events?(?:\/|\.|$)|bootstrap(?:\.[cm]?[jt]sx?)?$|emitter(?:\.[cm]?[jt]sx?)?$)|(?:^|\/)(?:intents?|publish)(?:\/|\.|$)/i,jt=/(use-?cases?|usecases?|application|orchestrat|services?|handlers?)(\/|\.|$)/i;function Vt(e,t){let r=String(e??"").replace(/\\/g,"/").trim(),n=String(t?.fromLayer??""),s=String(t?.toLayer??"");return Ut.test(r)?"pure-shared":n==="PersistenceAdapters"&&(Ht.test(r)||/events?|intents?|kernel|bootstrap/i.test(`${s} ${r}`))?"kernel-emit":jt.test(r)||(n==="DomainModel"||n==="ApplicationOrchestration")&&s==="PersistenceAdapters"?"use-case":"unknown"}function Bt(e){if(e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly)return"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.";if(e.peerIsolation)return"Extract the shared dependency to a shared layer, test at the public interface, then preflight again.";let t=Vt(typeof e.target=="string"?e.target:"",{fromLayer:typeof e.fromLayer=="string"?e.fromLayer:void 0,toLayer:typeof e.toLayer=="string"?e.toLayer:void 0});return t==="pure-shared"?"Adopt the imported constants/types/pure module into DomainModel or SharedKernel (do not inject a port). Then preflight again.":t==="kernel-emit"?"Persistence must not emit. Inject a port or move the event map to SharedTypes; do not import kernel/events/bootstrap from a repository. Then preflight again.":t==="use-case"||e.portProofEligible?`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, test at the public interface, then preflight again.`:"Classify the import: if it is constants/types/pure, adopt into DomainModel or SharedKernel; define a port only if the target is a real use-case. Then preflight again."}function Gt(e){return typeof e.target=="string"&&e.target.trim().length>0?e.target.trim():void 0}function zt(e){let t=Gt(e),r=typeof e.fromLayer=="string"&&e.fromLayer.length>0?e.fromLayer:void 0;switch(e.ruleId){case"ARKRUN_MISSING_ROOT":return t?`Import createStrictArkKernel from @arkgate/runtime and call it in composition root ${t} listed in arkRun.compositionRoots, then preflight again.`:"Import createStrictArkKernel from @arkgate/runtime (never a removed arkgate/runtime shim) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe \u2014 factory placement is a design decision.";case"ARKRUN_KERNEL_IN_DOMAIN":return t?`Move the kernel import of ${t} out of ${r??"the Domain-role layer"} into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again.`:"Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again. Never mechanical-safe.";case"ARKRUN_DIRECT_NEW":return t?`Resolve ${t} from the kernel instead of constructing it with new, then preflight again.`:"Resolve the type from the kernel instead of constructing it with new, then preflight again. Never mechanical-safe \u2014 rewiring construction is a design decision.";case"ARKRUN_UNDECLARED_EMIT":return t?`Add ${t} to raises or sends on the managed component, then preflight again.`:"Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.";case"ARKRUN_UNDECLARED_HANDLE":return t?`Add ${t} to reactsTo on the managed component, then preflight again.`:"Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.";case"ARKRUN_UNDECLARED_DEPEND":return t?`Add ${t} to uses on the managed component, then preflight again.`:"Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.";case"ARKRUN_TRANSPORT_BYPASS":return t?`Send through the ArkRun kernel transport instead of importing ${t}, then preflight again.`:"Send through the ArkRun kernel transport instead of importing that broker or emitter, then preflight again. Never mechanical-safe \u2014 homemade buses stay judgment.";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 G(e){switch(e.ruleId){case"LAYER_IMPORT_VIOLATION":return Bt(e);case"FORBIDDEN_GLOBAL":return`Inject ${e.target??"the capability"} through a port, test at the public interface, then preflight again.`;case"CAPABILITY_VIOLATION":return`Define a ${String(e.capability??"capability")} port in ${e.fromLayer??"the walled layer"}, bind the implementation outside it, test at the public interface, then preflight again.`;case"CIRCULAR_DEPENDENCY":return"Extract the shared dependency into a third module, test at the public interface, 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.";case"ARKRULE_STRUCTURE":case"ARKRULE_INVARIANT":case"INVARIANT_UNCOVERED":return`Fix the structure or invariant for ${typeof e.arkruleId=="string"&&e.arkruleId.length>0?e.arkruleId:"the ArkRule"} (declared in ${typeof e.arkruleSource=="string"&&e.arkruleSource.length>0?e.arkruleSource:"arkrules/<Layer>.json"}), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.`;case"ARKRUN_MISSING_ROOT":case"ARKRUN_KERNEL_IN_DOMAIN":case"ARKRUN_DIRECT_NEW":case"ARKRUN_UNDECLARED_EMIT":case"ARKRUN_UNDECLARED_HANDLE":case"ARKRUN_UNDECLARED_DEPEND":case"ARKRUN_TRANSPORT_BYPASS":return zt(e);default:return typeof e.ruleId=="string"&&e.ruleId.startsWith("ARKRULE_")?`Fix the ArkRule ${typeof e.arkruleId=="string"?e.arkruleId:e.ruleId}, then preflight again.`:`Resolve ${typeof e.ruleId=="string"&&e.ruleId.length>0?e.ruleId:"ARK_UNKNOWN"} without weakening ark.config.json, then run Ark again.`}}var qt="docs/diagnostics.md";function y(e){return typeof e=="string"&&e.length>0?e:void 0}function Le(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}function Wt(e){let t=typeof e.ruleId=="string"?e.ruleId:typeof e.code=="string"?e.code:void 0,r=typeof e.file=="string"?e.file:void 0,n=typeof e.fromLayer=="string"?e.fromLayer:void 0,s=typeof e.toLayer=="string"?e.toLayer:void 0,i=typeof e.target=="string"?e.target:void 0;return[t,r,n??"",s??"",i??""].join("|")}function Zt(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function Yt(e){return`${qt}#${e}`}function Jt(e,t,r){return G({ruleId:e,target:y(t.target)??y(r.target)??void 0,fromLayer:y(t.fromLayer)??void 0,toLayer:y(t.toLayer)??void 0,typeOnly:t.typeOnly===!0,targetTypeOnlyExports:t.targetTypeOnlyExports===!0,namedBindingsTypeOnly:t.namedBindingsTypeOnly===!0,portProofEligible:t.portProofEligible===!0,peerIsolation:t.peerIsolation===!0,sourcePureTypeModule:t.sourcePureTypeModule===!0,edgeKind:y(t.edgeKind)??void 0,capability:y(t.capability)??y(r.capability)??void 0,arkruleId:y(t.arkruleId)??void 0,arkruleSource:y(t.arkruleSource)??void 0})}function Te(e,t="error",r){let n=y(e.ruleId)??y(e.code)??"ARK_UNKNOWN",s=e.severity==="warning"||e.failsStrict===!1||e.typeOnly===!0&&e.peerIsolation!==!0?"warning":t,i={...y(e.target)?{target:y(e.target)}:{},...y(e.fromLayer)?{fromLayer:y(e.fromLayer)}:{},...y(e.toLayer)?{toLayer:y(e.toLayer)}:{},...typeof e.typeOnly=="boolean"?{typeOnly:e.typeOnly}:{},...typeof e.targetTypeOnlyExports=="boolean"?{targetTypeOnlyExports:e.targetTypeOnlyExports}:{},...typeof e.sourcePureTypeModule=="boolean"?{sourcePureTypeModule:e.sourcePureTypeModule}:{},...typeof e.namedBindingsTypeOnly=="boolean"?{namedBindingsTypeOnly:e.namedBindingsTypeOnly}:{},...typeof e.portProofEligible=="boolean"?{portProofEligible:e.portProofEligible}:{},...typeof e.peerIsolation=="boolean"?{peerIsolation:e.peerIsolation}:{},...y(e.capability)?{capability:y(e.capability)}:{},...y(e.edgeKind)?{edgeKind:y(e.edgeKind)}:{},...y(e.arkruleId)?{arkruleId:y(e.arkruleId)}:{},...y(e.arkruleSource)?{arkruleSource:y(e.arkruleSource)}:{}},o=r??Wt(e),a=Zt(o);return{ruleId:n,severity:s,message:y(e.message)??n,location:{file:y(e.file)??"<unknown>",line:Le(e.line,1),column:Le(e.column,1)},evidence:i,nextAction:y(e.nextAction)??Jt(n,i,e),findingRef:a,targetKey:o,docsCodePath:Yt(n)}}var Fe={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."},zr=Object.freeze([{layer:"DomainModel",prefixes:["Domain."]},{layer:"ApplicationOrchestration",prefixes:["Application."]},{layer:"PersistenceAdapters",prefixes:["Adapter.Persistence.","Adapter.Repository."]},{layer:"IntegrationAdapters",prefixes:["Adapter.Integration.","Adapter.External."]},{layer:"WorkflowSagaEngine",prefixes:["Workflow."]},{layer:"BackgroundJobsScheduling",prefixes:["Job."]},{layer:"PresentationAdapters",prefixes:["Presentation.","Adapter.Presentation.","Adapter.Api."]},{layer:"ReportingReadModels",prefixes:["Reporting."]},{layer:"ExtensibilityMetadata",prefixes:["Metadata."]},{layer:"SecurityAuditObservability",prefixes:["Security.","Audit.","Observability."]},{layer:"Kernel",prefixes:["Kernel."]}]);function Xt(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function ie(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&Xt(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:Fe.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:Fe.PUBLISH_MISSING_SOURCE}),t}var pe=j(require("fs"),1),N=j(require("path"),1);var Qt=["createArkKernel","createStrictArkKernel","createArkKernelFromConfig","createStrictArkKernelFromConfig"];var er=new Set(Qt),tr=new Set(["AggregateError","Array","ArrayBuffer","BigInt64Array","BigUint64Array","Boolean","DataView","Date","Error","EvalError","FinalizationRegistry","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Number","Object","Promise","Proxy","RangeError","ReferenceError","RegExp","Set","SharedArrayBuffer","String","Symbol","SyntaxError","TypeError","URIError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","WeakRef","WeakSet"]),rr=new Set(["Array","Atomics","Buffer","JSON","Math","Number","Object","Promise","Reflect","String","console","fs","path","url","util"]);function L(e){return e==="@arkgate/runtime"||e.startsWith("@arkgate/runtime/")||e==="arkgate/runtime"||e.startsWith("arkgate/runtime/")}var nr=["events","node:events","eventemitter2","eventemitter3","emittery","kafkajs","kafka-node","amqplib","amqp","bull","bullmq","mqtt","nats","@aws-sdk/client-sqs","@aws-sdk/client-sns","@aws-sdk/client-eventbridge","@google-cloud/pubsub","@azure/service-bus"],ae=new Set(nr);function Pe(e){if(!e||e.startsWith(".")||e.startsWith("/"))return!1;if(ae.has(e))return!0;let t=e.indexOf("/");if(t<0)return!1;let r=e.slice(0,t);if(ae.has(r))return!0;let n=e.indexOf("/",t+1);return n<0?!1:ae.has(e.slice(0,n))}function Oe(e){if(er.has(e))return"factory";switch(e){case"publisher":return"publisher";case"publish":return"publish";case"raise":case"raiseAsync":return"raise";case"send":case"sendTo":return"send";case"subscribe":return"subscribe";case"registerHandler":return"register-handler";case"resolve":return"resolve";case"resolveSingleton":return"resolve-singleton";default:return}}function Ke(e,t){let r=1;for(let n=0;n<t;n+=1)e.charCodeAt(n)===10&&(r+=1);return r}function le(e){return e.replace(/\/\*[\s\S]*?\*\//g,t=>t.replace(/[^\n]/g," ")).replace(/(^|[^:\\])\/\/.*$/gm,t=>t.replace(/\/\/.*$/,r=>" ".repeat(r.length)))}function sr(e,t){let r=e.slice(t),n=/^\s*(['"])((?:\\.|[^\\])*?)\1/.exec(r);if(!n)return;let s=n[2]??"";return s.length>0?s:void 0}function De(e,t,r){let n=Math.max(0,t-r.length-8),s=e.slice(n,t);return new RegExp(`\\b${r}\\s+$`).test(s)}function z(e,t){let r=/\b(?:import|export)(\s+type)?\s+([\s\S]*?)\s+from\s*['"]([^'"]+)['"]/g,n;for(;(n=r.exec(e))!==null;)n[1]||t(n[2]??"",n[3]??"")}function Me(e,t){z(le(e),t)}function or(e){let t=new Map,r=new Set;return z(e,(n,s)=>{if(!L(s))return;let i=/\*\s+as\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(n);i?.[1]&&r.add(i[1]);let o=/^([A-Za-z_][A-Za-z0-9_]*)\s*(?:,|$)/.exec(n.trim());o?.[1]&&t.set(o[1],o[1]);let a=/\{([^}]*)\}/.exec(n);if(a?.[1])for(let l of a[1].split(",")){let d=l.trim();if(!d||d.startsWith("type "))continue;let u=/^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(d);if(u){t.set(u[2],u[1]);continue}let c=/^([A-Za-z_][A-Za-z0-9_]*)$/.exec(d);c?.[1]&&t.set(c[1],c[1])}}),{named:t,namespaces:r}}function ir(e,t){let r=new Set(t);return z(e,(n,s)=>{let i=/\{([^}]*)\}/.exec(n);if(i?.[1])for(let o of i[1].split(",")){let a=o.trim();if(!a||a.startsWith("type "))continue;let l=/^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(a),d=l?.[2]??/^([A-Za-z_][A-Za-z0-9_]*)$/.exec(a)?.[1],u=l?.[1]??d;!d||!u||!/^[A-Z]/.test(u)||(L(s)||t.has(u)||t.has(d))&&(r.add(d),r.add(u))}}),r}function ar(e,t){let r;return z(e,(n,s)=>{!r&&new RegExp(`\\b${t}\\b`).test(n)&&(r=s)}),r}function q(e,t){let r=le(t),n=or(r),s=[],i=/\b([A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/g,o;for(;(o=i.exec(r))!==null;){let a=o[1],l=o.index;if(De(r,l,"function")||De(r,l,"class"))continue;let u=r.slice(0,l).match(/([A-Za-z_][A-Za-z0-9_]*)\s*\.\s*$/)?.[1],c=n.named.get(a)??a,p=Oe(c)??Oe(a);if(!p)continue;let f=n.named.has(a)||u!==void 0&&n.namespaces.has(u);if(p!=="factory"&&(!f&&u===void 0||u&&rr.has(u)&&!f))continue;let m=sr(r,l+o[0].length);s.push({file:e,line:Ke(t,l),kind:p,callee:a,viaImport:f,...u?{receiver:u}:{},...m?{nameLiteral:m}:{}})}return s}function ce(e,t,r){let n=le(t),s=ir(n,r),i=[],o=/\bnew\s+(?:[A-Za-z_][A-Za-z0-9_]*\s*\.\s*)*([A-Z][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/g,a;for(;(a=o.exec(n))!==null;){let l=a[1];if(tr.has(l)||!s.has(l))continue;let d=ar(n,l);i.push({file:e,line:Ke(t,a.index),typeName:l,...d?{importedFrom:d}:{}})}return i}function ue(e,t){let r=[],n=/export\s+(?:abstract\s+)?class\s+([A-Za-z_][A-Za-z0-9_]*)\s*(?:extends\s+[^{]+)?(?:implements\s+[^{]+)?\{/g,s;for(;(s=n.exec(t))!==null;){let i=s[1],o=s.index+s[0].length,a=1,l=o;for(;l<t.length&&a>0;){let k=t[l];k==="{"?a+=1:k==="}"&&(a-=1),l+=1}let d=t.slice(o,l-1),u=d.split(`
`).map(k=>/^\s*\/\//.test(k)||/^\s*\/\*|\*\//.test(k)?k:k.replace(/(?:public\s+|protected\s+)?readonly\s+[a-zA-Z_][a-zA-Z0-9_]*\s*(?::[^=;]+)?(?:=\s*[^;]+)?[;,]?/g,"").replace(/(?:^|[\s;{])readonly\s+[a-zA-Z_][a-zA-Z0-9_]*\s*(?::[^=;]+)?(?:=\s*[^;]+)?[;,]?/g," ")).join(`
`),c=/(?:^|\n)\s*(?:public\s+)?[a-zA-Z_][a-zA-Z0-9_]*\s*[:=]/m.test(u.replace(/(?:public\s+|private\s+|protected\s+|static\s+|async\s+|get\s+|set\s+)/g,""))&&/(?:^|\n)\s*(public\s+)?(?!constructor|static|get|set|private|protected|readonly)[a-zA-Z_][a-zA-Z0-9_]*\s*[:=]/m.test(u),p=/(?:^|\n)\s*public\s+(?!static|async|get|set|constructor|readonly)[a-zA-Z_]/.test(u)||/(?:^|[\n;])\s*[a-zA-Z_][a-zA-Z0-9_]*\s*:\s*[^=;\n]+[;=]/m.test(u.split(`
`).filter(k=>!/^\s*(private|protected|static|constructor|get |set |async |\/)/.test(k)).join(`
`)),f=/(?:^|[\n;{])\s*(?:public\s+)?set\s+[a-zA-Z_]/.test(d),m=/(?:^|[\n;{])\s*private\s+constructor\s*\(/.test(d),h=/(?:^|[\n;{])\s*(?:public\s+)?constructor\s*\(/.test(d)&&!m,R=/(?:^|[\n;{])\s*static\s+(?:async\s+)?(?:create|of|from|parse|build|make|new)\s*[<(]/.test(d)||/(?:^|[\n;{])\s*static\s+(?:async\s+)?[A-Za-z_][A-Za-z0-9_]*\s*\([^)]*\)\s*:\s*[A-Za-z_]/.test(d),A=[],$=new Set(["if","match","when"]),U=/(?:^|\n)\s*(?:public\s+|private\s+|protected\s+|async\s+)*(?!constructor|get|set|static)([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*(?::\s*[^{]+)?\{/g,C;for(;(C=U.exec(d))!==null;){let k=C[1];if($.has(k))continue;let he=C.index+C[0].length,X=1,F=he;for(;F<d.length&&X>0;)d[F]==="{"?X+=1:d[F]==="}"&&(X-=1),F+=1;let Re=d.slice(he,F-1);if(!/this\.\w+\s*=/.test(Re))continue;let ft=/\b(ensureInvariants|assertInvariants|validate|publish|emit|raise|record)\b/.test(Re);A.push({name:k,referencesGuardOrPublish:ft})}let ut=(d.match(/(?:^|\n)\s*(?:public\s+|private\s+|protected\s+)?(?:async\s+)?[a-zA-Z_][a-zA-Z0-9_]*\s*\(/g)??[]).length,dt=(u.match(/(?:^|[\n;])\s*(?:public\s+)?(?!constructor|static|get|set|private|protected|readonly)[a-zA-Z_][a-zA-Z0-9_]*\s*[:=]/g)??[]).length,pt=ut<=1&&dt>=2&&(p||c);r.push({file:e,className:i,exported:!0,hasPublicMutableFields:p||c,hasPublicSetters:f,hasPublicConstructor:h,hasStaticFactory:R,mutatingMethods:[...A],dataOnly:pt})}return r}function lr(e){if(!e)return{};let t=typeof e.governedPercent=="number"?e.governedPercent:null,r=typeof e.populatedLayerCount=="number"?e.populatedLayerCount:null;return r==null&&typeof e.classifiedFiles=="number"&&(r=e.classifiedFiles>0?1:0),{governedPercent:t,populatedLayerCount:r}}function $e(e){let t=lr(e),r=typeof t.governedPercent=="number"?t.governedPercent:null,n=typeof t.populatedLayerCount=="number"?t.populatedLayerCount:null;return r==null&&n==null?!0:(r??0)>=50&&(n??0)>=1}var cr=["arkrun-kernel-in-domain","arkrun-direct-new","arkrun-transport-bypass"],ur=new Set(cr);function dr(e){return ur.has(e)}var Ue={"arkrun-missing-root":"ARKRUN_MISSING_ROOT","arkrun-kernel-in-domain":"ARKRUN_KERNEL_IN_DOMAIN","arkrun-direct-new":"ARKRUN_DIRECT_NEW","arkrun-undeclared-emit":"ARKRUN_UNDECLARED_EMIT","arkrun-undeclared-handle":"ARKRUN_UNDECLARED_HANDLE","arkrun-undeclared-depend":"ARKRUN_UNDECLARED_DEPEND","arkrun-transport-bypass":"ARKRUN_TRANSPORT_BYPASS"},pr="ARKRUN_INTERACTION_NAME_INCOMPLETE";function Ve(e,t=[]){let r=e.trim();return/^domain(?:model)?$/i.test(r)||/^domain(?=[A-Z_\-\s])/i.test(r)||/^(?:entit(?:y|ies)|aggregates?)(?:$|(?=[A-Z_\-\s]))/i.test(r)?!0:t.some(n=>{let s=n.trim().replace(/\.+$/,"");return s==="Domain"||s.startsWith("Domain.")})}function fr(e,t){return e.file.localeCompare(t.file)||e.ruleId.localeCompare(t.ruleId)||e.line-t.line||e.message.localeCompare(t.message)}function I(e,t,r,n,s,i,o){let a=e.mode==="enforced"&&o;return{ruleId:Ue[t],sensor:t,message:s,file:r,line:n,...i?.fromLayer?{fromLayer:i.fromLayer}:{},...i?.target?{target:i.target}:{},severity:a?"error":"warning",failsStrict:a,nextAction:G({ruleId:Ue[t],fromLayer:i?.fromLayer,target:i?.target})}}function gr(e,t){let r=[],n=[],s=[],i=[];for(let o of e)o.file===t&&(r.push(...o.uses),n.push(...o.reactsTo),s.push(...o.raises),i.push(...o.sends));return{uses:new Set(r),reactsTo:new Set(n),raises:new Set(s),sends:new Set(i)}}function He(e){return e==="publisher"||e==="publish"||e==="raise"||e==="send"}function je(e){return e==="subscribe"||e==="register-handler"}function mr(e){return e==="resolve"||e==="resolve-singleton"}function yr(e,t,r){let n=[],s=e.compositionRoots;if(s.length===0)return n.push(I(e,"arkrun-missing-root","ark.config.json",1,"ArkRun compositionRoots is empty; no createArkKernel factory site is declared.",void 0,r)),n;let i=new Map;for(let o of t){let a=i.get(o.matchedRoot)??[];a.push(o),i.set(o.matchedRoot,a)}for(let o of s){let a=[...i.get(o)??[]].sort((d,u)=>d.file.localeCompare(u.file));if(a.length===0){n.push(I(e,"arkrun-missing-root","ark.config.json",1,`ArkRun composition root ${JSON.stringify(o)} matched no governed files and has no createArkKernel factory.`,{target:o},r));continue}if(a.some(d=>d.hasKernelFactory))continue;let l=a[0];n.push(I(e,"arkrun-missing-root",l.file,1,`ArkRun composition root ${JSON.stringify(o)} has no createArkKernel / createStrictArkKernel factory.`,{target:o},r))}return n}function hr(e,t,r,n,s){let i=new Map(t.map(a=>[a.name,a.intentPrefixes??[]])),o=[];for(let a of r){let l=a.specifier;if(!l||!L(l))continue;let d=n(a.from);d&&Ve(d,i.get(d)??[])&&o.push(I(e,"arkrun-kernel-in-domain",a.from,a.line,`${d} must not import kernel module ${JSON.stringify(l)}.`,{fromLayer:d,target:l},s))}return o}function Rr(e,t,r,n,s,i){let o=new Set(e.managedLayers);if(o.size===0)return[];let a=new Map(t.map(u=>[u.name,u.intentPrefixes??[]])),l=new Set(n.filter(u=>u.hasKernelFactory).map(u=>u.file)),d=[];for(let u of r){if(l.has(u.file))continue;let c=s(u.file);!c||!o.has(c)||Ve(c,a.get(c)??[])||d.push(I(e,"arkrun-direct-new",u.file,u.line,`${c} must not construct ${u.typeName} with new outside an ArkRun composition-root factory.`,{fromLayer:c,target:u.typeName},i))}return d}function Ar(e,t,r,n,s){let i=[],o=[];if(e.requireDeclarations!==!0)return{findings:i,completenessReasons:o};let a=new Set(e.managedLayers);if(a.size===0)return{findings:i,completenessReasons:o};for(let l of t){if(!He(l.kind)&&!je(l.kind)&&!mr(l.kind))continue;let d=n(l.file);if(!d||!a.has(d))continue;if(!l.nameLiteral){e.mode==="enforced"&&o.push({code:pr,file:l.file,message:`ArkRun ${l.kind} call in ${l.file} has no string-literal name; enforced extra cannot prove the declaration.`});continue}let u=gr(r,l.file);if(He(l.kind)){if(u.raises.has(l.nameLiteral)||u.sends.has(l.nameLiteral))continue;i.push(I(e,"arkrun-undeclared-emit",l.file,l.line,`Emit ${JSON.stringify(l.nameLiteral)} is not declared in raises or sends.`,{fromLayer:d,target:l.nameLiteral},s));continue}if(je(l.kind)){if(u.reactsTo.has(l.nameLiteral))continue;i.push(I(e,"arkrun-undeclared-handle",l.file,l.line,`Handle ${JSON.stringify(l.nameLiteral)} is not declared in reactsTo.`,{fromLayer:d,target:l.nameLiteral},s));continue}u.uses.has(l.nameLiteral)||i.push(I(e,"arkrun-undeclared-depend",l.file,l.line,`Depend ${JSON.stringify(l.nameLiteral)} is not declared in uses.`,{fromLayer:d,target:l.nameLiteral},s))}return{findings:i,completenessReasons:o}}function kr(e,t,r,n){let s=new Set(e.managedLayers);if(s.size===0)return[];let i=[];for(let o of t){if(o.typeOnly)continue;let a=o.specifier;if(!a||!Pe(a))continue;let l=r(o.from);!l||!s.has(l)||i.push(I(e,"arkrun-transport-bypass",o.from,o.line,`${l} must not import broker/queue/emitter ${JSON.stringify(a)}; use the ArkRun kernel transport.`,{fromLayer:l,target:a},n))}return i}function br(e){let t=e.arkRun;if(!t)return{findings:[],completenessReasons:[]};let r=$e(e.classification),n=Ar(t,e.kernelCalls,e.declarations,e.layerForFile,r),s=[...yr(t,e.compositionRootHits,r),...hr(t,e.layers,e.dependencies,e.layerForFile,r),...Rr(t,e.layers,e.managedNews,e.compositionRootHits,e.layerForFile,r),...n.findings,...kr(t,e.dependencies,e.layerForFile,r)].sort(fr),i=[...n.completenessReasons].sort((o,a)=>{let l=`${o.code}\0${o.file??""}\0${o.message}`,d=`${a.code}\0${a.file??""}\0${a.message}`;return l<d?-1:l>d?1:0});return{findings:s,completenessReasons:i}}function de(e){return{findings:br(e).findings.filter(r=>dr(r.sensor)),completenessReasons:[]}}function Sr(e){if(e.importKind==="type"||e.exportKind==="type")return!0;let t=e.specifiers??[];return t.length===0?!1:t.every(r=>r.type==="ImportSpecifier")?t.every(r=>r.importKind==="type"):t.every(r=>r.exportKind==="type")}function Ge(e){try{return pe.default.existsSync(e)?pe.default.readFileSync(e,"utf8"):null}catch{return null}}function Be(e,t){let r=e.lintedFilename(t),n=e.findConfigPath(r),s=n?e.loadArkConfig(n):null;if(!s?.arkRun||!n||!r)return null;let i=N.default.dirname(n),o=N.default.isAbsolute(r)?r:N.default.resolve(r),a=N.default.relative(i,o).split(N.default.sep).join("/");if(!e.sourceIsInAnalysisScope(s,a))return null;let l=S(a,s.layers);return l?{extra:s.arkRun,config:s,root:i,absFile:o,relFile:a,fromLayer:l}:null}function Er(e,t,r){let n=q(t,r).some(i=>i.kind==="factory"),s=[];for(let i of e.compositionRoots){try{if(!v(i).test(t))continue}catch{continue}s.push({file:t,matchedRoot:i,hasKernelFactory:n})}return s}function Ir(e,t,r){let n=new Set(ue(t.relFile,r).map(s=>s.className));return Me(r,(s,i)=>{if(L(i))return;let o=e.resolveImportSpecifier(t.absFile,i,t.root);if(!o)return;let a=N.default.relative(t.root,o).split(N.default.sep).join("/");if(a.startsWith(".."))return;let l=Ge(o);if(l!==null)for(let d of ue(a,l))n.add(d.className)}),n}function ze(e,t,r,n,s,i){e.reportAdapterDiagnostic(t,r,n,{ruleId:s.ruleId,file:s.file,fromLayer:s.fromLayer,target:s.target,message:s.message,line:s.line,severity:s.severity,failsStrict:s.failsStrict,nextAction:s.nextAction},i)}function xr(e){let t=e.callee;if(t?.type==="Identifier"&&t.name&&/^[A-Z]/.test(t.name))return t.name;let r=t?.property?.name;if(r&&/^[A-Z]/.test(r)&&t?.computed!==!0)return r}function Nr(e,t){return e.type?.startsWith("Export")?"export":t}function Cr(e,t,r,n,s){let i=(o,a,l,d)=>{if(typeof a!="string"||a.length===0)return;let u=o.loc?.start?.line??1,c={from:r.relFile,specifier:a,kind:d,typeOnly:l,line:u,resolution:"resolved-external"},{findings:p}=de({arkRun:r.extra,layers:r.config.layers,kernelCalls:[],managedNews:[],compositionRootHits:[],declarations:[],dependencies:[c],layerForFile:f=>f===r.relFile?r.fromLayer:S(f,r.config.layers)});for(let f of p)f.sensor===n&&ze(e,t,o,s,f,{fromLayer:f.fromLayer??r.fromLayer,specifier:a,target:f.target??a})};return{ImportDeclaration(o){let a=o,l=(a.specifiers??[]).filter(u=>u.type==="ImportSpecifier"),d=l.length>0&&l.length===(a.specifiers??[]).length&&l.every(u=>u.importKind==="type");i(o,a.source?.value,a.importKind==="type"||d||Sr(o),"import")},ImportExpression(o){let a=o;a.source?.type==="Literal"&&i(o,a.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(o){let a=o;i(o,a.moduleReference?.expression?.value,a.importKind==="type"||a.isTypeOnly===!0,"require")},ExportNamedDeclaration(o){let a=o;if(!a.source)return;let l=a.specifiers??[],d=l.length>0&&l.every(u=>u.exportKind==="type");i(o,a.source.value,a.exportKind==="type"||d,Nr(o,"export"))},ExportAllDeclaration(o){let a=o;i(o,a.source?.value,a.exportKind==="type","export")},CallExpression(o){let a=o;a.callee?.type==="Identifier"&&a.callee.name==="require"&&a.arguments?.[0]?.type==="Literal"&&!e.isLocallyBound(t,o,"require")&&i(o,a.arguments[0].value,!1,"require")}}}function vr(e,t,r){let n=Ge(r.absFile)??"",s=Ir(e,r,n),i=ce(r.relFile,n,s),{findings:o}=de({arkRun:r.extra,layers:r.config.layers,kernelCalls:q(r.relFile,n),managedNews:i,compositionRootHits:Er(r.extra,r.relFile,n),declarations:[],dependencies:[],layerForFile:l=>l===r.relFile?r.fromLayer:S(l,r.config.layers)}),a=o.filter(l=>l.sensor==="arkrun-direct-new");return{NewExpression(l){let d=xr(l);if(!d)return;let u=l.loc?.start?.line,c=a.find(p=>p.target===d&&(u===void 0||p.line===u))??a.find(p=>p.target===d);c&&ze(e,t,l,"directNew",c,{fromLayer:c.fromLayer??r.fromLayer,typeName:d,target:c.target??d})}}}function qe(e){let t=(r,n,s,i)=>({meta:{type:"problem",docs:{description:n},messages:{[s]:i},schema:[]},create(o){let a=Be(e,o);return a?Cr(e,o,a,r,s):{}}});return{noArkRunKernelInDomain:t("arkrun-kernel-in-domain","Disallow Domain-role imports of @arkgate/runtime when arkRun is on (same sensor as ark-check).","kernelInDomain",'{{fromLayer}} must not import kernel module "{{specifier}}".'),noArkRunTransportBypass:t("arkrun-transport-bypass","Disallow homemade broker/queue/emitter imports in arkRun managed layers (same sensor as ark-check).","transportBypass",'{{fromLayer}} must not import broker/queue/emitter "{{specifier}}"; use the ArkRun kernel transport.'),noArkRunDirectNew:{meta:{type:"problem",docs:{description:"Disallow `new` of ArkRun-admitted types outside a composition-root factory (on-disk import/`new` envelope)."},messages:{directNew:"{{fromLayer}} must not construct {{typeName}} with new outside an ArkRun composition-root factory."},schema:[]},create(r){let n=Be(e,r);return n?vr(e,r,n):{}}}}}function T(e){if(typeof e.physicalFilename=="string"&&e.physicalFilename.length>0)return e.physicalFilename;if(typeof e.filename=="string"&&e.filename.length>0)return e.filename;if(typeof e.getFilename=="function")try{let t=e.getFilename();if(typeof t=="string"&&t.length>0)return t}catch{}return""}function _(e,t,r,n,s){let i=Te({...n,line:n.line??t.loc?.start?.line,column:n.column??(typeof t.loc?.start?.column=="number"?t.loc.start.column+1:void 0)});return e.report({node:t,messageId:r,...s?{data:s}:{},diagnostic:i}),i}function K(e){if(!e||e==="<input>"||e.startsWith("stdin"))return null;let t=g.default.dirname(g.default.resolve(e));for(;;){let r=g.default.join(t,"ark.config.json");if(x.default.existsSync(r))return r;let n=g.default.dirname(t);if(n===t)return null;t=n}}var We=new Map;function M(e){if(!x.default.existsSync(e))return null;let t=x.default.readFileSync(e,"utf8"),r=We.get(e);if(r?.source===t)return r.config;let n=we(t,e).config;return We.set(e,{source:t,config:n}),n}function Y(e,t){return(e.include??[]).some(n=>{let s=String(n).replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/$/,"");return s==="."||t===s||t.startsWith(`${s}/`)})&&!Ee(t,e)}function Ze(e){let t=[e,`${e}.ts`,`${e}.tsx`,`${e}.mts`,`${e}.cts`,`${e}.js`,`${e}.jsx`,g.default.join(e,"index.ts"),g.default.join(e,"index.tsx"),g.default.join(e,"index.js")];for(let r of t)try{if(x.default.existsSync(r)&&x.default.statSync(r).isFile())return r}catch{}return null}function Ye(e){let t=g.default.resolve(e),r=null;for(;;){let d=g.default.join(t,"tsconfig.json");if(x.default.existsSync(d)){r=d;break}let u=g.default.dirname(t);if(u===t)break;t=u}if(!r)return{baseUrl:e,aliases:[]};let n=d=>{try{let u=x.default.readFileSync(d,"utf8");return u=u.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1"),JSON.parse(u)}catch{return null}},s=(d,u)=>{if(u>4)return{};let c=n(d);if(!c)return{};let p=c.compilerOptions??{},f=p.baseUrl,m=p.paths,h=c.extends;if(typeof h=="string"&&!h.startsWith("@")){let R=g.default.resolve(g.default.dirname(d),h.endsWith(".json")?h:`${h}.json`);if(x.default.existsSync(R)){let A=s(R,u+1);f=f??A.baseUrl,m={...A.paths??{},...m??{}}}}return{baseUrl:f,paths:m}},i=s(r,0),o=g.default.dirname(r),a=g.default.resolve(o,i.baseUrl||"."),l=[];for(let[d,u]of Object.entries(i.paths||{})){if(!Array.isArray(u)||u.length===0)continue;let c=d.replace(/\*$/,"");c&&l.push({from:c,to:String(u[0]).replace(/\*$/,"")})}return l.sort((d,u)=>u.from.length-d.from.length),{baseUrl:a,aliases:l}}function Je(e,t){if(!t.startsWith("."))return null;let r=g.default.resolve(g.default.dirname(e),t);return Ze(r)}function ge(e,t,r){if(!t)return null;if(t.startsWith("."))return Je(e,t);let n=r||g.default.dirname(e),{baseUrl:s,aliases:i}=Ye(n),o=i.find(l=>t.startsWith(l.from));if(!o)return null;let a=g.default.resolve(s,`${o.to}${t.slice(o.from.length)}`);return Ze(a)}function J(e){return typeof e?.value=="string"?e.value:void 0}function me(e){return e?.name??J(e)}function ye(e){return e.sourceCode??e.getSourceCode?.()}function Xe(e,t){let r=ye(e)?.getScope?.(t);for(;r;){let n=r.references?.find(s=>s.identifier===t);if(n)return n;r=r.upper??void 0}}function P(e,t,r){let n=Xe(e,t);if(n?.resolved)return(n.resolved.defs?.length??0)>0;let s=ye(e)?.getScope?.(t);for(;s;){let i=s.set?.get(r);if(i)return(i.defs?.length??0)>0;s=s.upper??void 0}return!1}function _r(e,t){let r=Xe(e,t);return r?r.isValueReference!==!1:t.parent?.type==="VariableDeclarator"&&t.parent.init===t}function Qe(e){if(e?.type==="Identifier"&&e.name)return{root:e,segments:[e.name]};if(!e||!(e.type==="MemberExpression"||!!(e.object&&e.property))||e.computed===!0)return;let r=Qe(e.object),n=me(e.property);if(!(!r||!n))return{root:r.root,segments:[...r.segments,n]}}function wr(e){return me(e.callee?.property)}function et(e,t){return e?.properties?.find(r=>me(r.key)===t)}function W(e,t){return et(e,t)!==void 0}function Lr(e){let t=et(e,"metadata")?.value;return W(t,"source")}function tt(e){return wr(e)==="publish"}function fe(e){if(e.importKind==="type"||e.exportKind==="type")return!0;let t=e.specifiers??[];return t.length===0?!1:t.every(r=>r.type==="ImportSpecifier")?t.every(r=>r.importKind==="type"):t.every(r=>r.exportKind==="type")}function Tr(e){let t=e;for(;t?.parent;)t=t.parent;return t?.type==="Program"?t:void 0}function Fr(e){let t=Tr(e)?.body;if(!t)return!1;let r=!1;for(let n of t){if(n.type==="ImportDeclaration"){if(!fe(n))return!1;continue}if(!(n.type==="TSInterfaceDeclaration"||n.type==="TSTypeAliasDeclaration")){if(n.type==="ExportNamedDeclaration"){if(n.declaration){if(n.declaration.type!=="TSInterfaceDeclaration"&&n.declaration.type!=="TSTypeAliasDeclaration")return!1}else if(!fe(n))return!1;r=!0;continue}return!1}}return r}var rt={meta:{type:"problem",docs:{description:"Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."},messages:{forbiddenImport:"Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",forbiddenImportHeuristic:"Domain code must not import infrastructure, adapters, repositories, or database modules."},schema:[]},create(e){let t=T(e),r=K(t),n=r?M(r):null,s=r?g.default.dirname(r):null,i=o=>{let a=J(o.source);if(a&&n&&s&&t){let l=g.default.isAbsolute(t)?t:g.default.resolve(t),d=g.default.relative(s,l).split(g.default.sep).join("/");if(!Y(n,d))return;let u=S(d,n.layers);if(!u)return;let c=ge(l,a,s);if(!c)return;let p=g.default.relative(s,c).split(g.default.sep).join("/");if(p.startsWith(".."))return;let f=S(p,n.layers);if(!f)return;let m={fromPath:d,toPath:p,layers:n.layers},h=ee(n.rules,u,f,m);if(h||te(n.rules,u,f,m)){let R=o.type?.startsWith("Export")?"export":"import",A=fe(o),$=!!h?.peerIsolation,U=A&&!$,C=h?.message??`${u} must not ${R} ${f}.`;_(e,o,"forbiddenImport",{ruleId:"LAYER_IMPORT_VIOLATION",file:d,fromLayer:u,toLayer:f,target:p,edgeKind:R,...$?{peerIsolation:!0}:{},...A?{typeOnly:!0}:{},...U?{severity:"warning"}:{},...Fr(o)?{sourcePureTypeModule:!0}:{},message:U?`${C} (type-only \u2014 type placement debt; prefer SharedTypes / owning layer; not runtime coupling)`:C},{fromLayer:u,toLayer:f,specifier:a})}return}};return{ImportDeclaration:i,ExportNamedDeclaration:i,ExportAllDeclaration:i}}},nt={meta:{type:"problem",docs:{description:"Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings."},messages:{rawPublish:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=J(r),s=ie({publishCall:tt(t),rawIntentName:n,objectHasIntent:W(r,"intent"),arkPublishCandidate:!1,hasSource:!0});if(s.some(i=>i.ruleId==="RAW_EVENT_PUBLISH")){let i=s.find(o=>o.ruleId==="RAW_EVENT_PUBLISH");_(e,t,"rawPublish",{...i,file:T(e)})}}}}},st={meta:{type:"problem",docs:{description:"Require event bus publish calls to include source metadata."},messages:{missingSource:"Strict Ark publish calls must include metadata.source."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=t.arguments?.[2],i=ie({publishCall:tt(t),rawIntentName:J(r),objectHasIntent:W(r,"intent"),arkPublishCandidate:!0,hasSource:Lr(r)||W(n,"source")}).find(o=>o.ruleId==="PUBLISH_MISSING_SOURCE");i&&_(e,t,"missingSource",{...i,file:T(e)})}}}},ot={meta:{type:"problem",docs:{description:"Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` is a standalone fallback when no project config applies."},messages:{forbiddenGlobal:'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',forbiddenGlobalDefault:'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.',forbiddenModule:'{{layer}} must not use module "{{specifier}}" because it is the import form of forbidden global "{{name}}".'},schema:[{type:"object",properties:{globals:{type:"array",items:{type:"string"}}},additionalProperties:!1}]},create(e){let t=T(e),r=e.options?.[0],n=K(t),s=n?M(n):null,i=n?g.default.dirname(n):null,o=null,a="this layer";if(s&&i&&t){let c=g.default.isAbsolute(t)?t:g.default.resolve(t),p=g.default.relative(i,c).split(g.default.sep).join("/");if(!Y(s,p))return{};let f=s.layers?.find(m=>m.name===S(p,s.layers));f?.forbiddenGlobals?.length?(o=new Set(f.forbiddenGlobals),a=f.name):o=null}else r?.globals&&(o=new Set(r.globals));if(!o)return{};let l=typeof ye(e)?.getScope=="function",d=(c,p)=>{let f=g.default.isAbsolute(t)?t:g.default.resolve(t),m=i?g.default.relative(i,f).split(g.default.sep).join("/"):t;_(e,c,s?"forbiddenGlobal":"forbiddenGlobalDefault",{ruleId:"FORBIDDEN_GLOBAL",file:m,fromLayer:a,target:p,message:`${a} must not use the ambient global "${p}".`},{name:p,layer:a})},u=(c,p,f,m)=>{if(f||typeof p!="string")return;let h=ne(p,o);if(!h)return;let R=g.default.isAbsolute(t)?t:g.default.resolve(t),A=i?g.default.relative(i,R).split(g.default.sep).join("/"):t;_(e,c,"forbiddenModule",{ruleId:"FORBIDDEN_GLOBAL",file:A,fromLayer:a,target:p,edgeKind:m,message:`${a} must not use module "${p}" because it is the import form of forbidden global "${h}".`},{layer:a,name:h,specifier:p,importKind:m})};return{MemberExpression(c){if(c.parent?.type==="MemberExpression"&&c.parent.object===c)return;let p=Qe(c);if(!p||P(e,p.root,p.segments[0]))return;let f=p.segments[0]==="globalThis",m=f?p.segments.slice(1):p.segments,h;for(let R=m.length;R>=(f?1:2);R-=1){let A=m.slice(0,R).join(".");if(o.has(A)){h=A;break}}h?d(c,h):!l&&o.has(p.segments[0])&&d(c,p.segments[0])},CallExpression(c){let p=c;if(p.callee?.type==="Identifier"&&p.callee.name==="require"&&p.arguments?.[0]?.type==="Literal"&&!P(e,c,"require")&&u(c,p.arguments[0].value,!1,"require"),l)return;let f=p.callee?.type==="Identifier"?p.callee.name:void 0;f&&o.has(f)&&d(c,f)},ImportDeclaration(c){let p=c,f=(p.specifiers??[]).filter(h=>h.type==="ImportSpecifier"),m=f.length>0&&f.length===(p.specifiers??[]).length&&f.every(h=>h.importKind==="type");u(c,p.source?.value,p.importKind==="type"||m,"import")},ImportExpression(c){let p=c;p.source?.type==="Literal"&&u(c,p.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(c){let p=c;u(c,p.moduleReference?.expression?.value,p.importKind==="type"||p.isTypeOnly===!0,"require")},ExportNamedDeclaration(c){let p=c;if(!p.source)return;let f=p.specifiers??[],m=f.length>0&&f.every(h=>h.exportKind==="type");u(c,p.source.value,p.exportKind==="type"||m,"export")},ExportAllDeclaration(c){let p=c;u(c,p.source?.value,p.exportKind==="type","export")},NewExpression(c){if(l)return;let p=c.callee?.type==="Identifier"?c.callee.name:void 0;p&&o.has(p)&&d(c,p)},Identifier(c){!l||!c.name||!o.has(c.name)||!_r(e,c)||P(e,c,c.name)||d(c,c.name)}}}},it={meta:{type:"problem",docs:{description:"Disallow importing modules whose effect capability the layer denies (ark.config.json capabilities.deny / pure \u2014 same wall surface as ark-check). Import dimension only: ambient globals stay with no-forbidden-globals and the CLI/hook symbol path."},messages:{deniedCapability:'{{layer}} denies the {{capability}} capability (ark.config.json); "{{specifier}}" imports it. Define a port and bind the implementation in an adapter layer.'},schema:[]},create(e){let t=T(e),r=K(t),n=r?M(r):null,s=r?g.default.dirname(r):null;if(!n||!s||!t)return{};let i=g.default.isAbsolute(t)?t:g.default.resolve(t),o=g.default.relative(s,i).split(g.default.sep).join("/");if(!Y(n,o))return{};let a=n.layers?.find(u=>u.name===S(o,n.layers));if(!a)return{};let l=new Set(Ne(a));if(l.size===0)return{};let d=(u,c,p,f)=>{if(p||typeof c!="string"||ne(c,a.forbiddenGlobals??[]))return;let m=xe(c);!m||!l.has(m)||_(e,u,"deniedCapability",{ruleId:"CAPABILITY_VIOLATION",file:o,fromLayer:a.name,target:c,capability:m,edgeKind:f,message:`${a.name} denies the ${m} capability; found import of "${c}".`},{layer:a.name,capability:m,specifier:c})};return{ImportDeclaration(u){let c=u,p=(c.specifiers??[]).filter(m=>m.type==="ImportSpecifier"),f=p.length>0&&p.length===(c.specifiers??[]).length&&p.every(m=>m.importKind==="type");d(u,c.source?.value,c.importKind==="type"||f,"import")},ImportExpression(u){let c=u;c.source?.type==="Literal"&&d(u,c.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(u){let c=u;d(u,c.moduleReference?.expression?.value,c.importKind==="type"||c.isTypeOnly===!0,"require")},ExportNamedDeclaration(u){let c=u;if(!c.source)return;let p=c.specifiers??[],f=p.length>0&&p.every(m=>m.exportKind==="type");d(u,c.source.value,c.exportKind==="type"||f,"export")},ExportAllDeclaration(u){let c=u;d(u,c.source?.value,c.exportKind==="type","export")},CallExpression(u){let c=u;c.callee?.type==="Identifier"&&c.callee.name==="require"&&c.arguments?.[0]?.type==="Literal"&&!P(e,u,"require")&&d(u,c.arguments[0].value,!1,"require")}}}},{noArkRunKernelInDomain:at,noArkRunDirectNew:lt,noArkRunTransportBypass:ct}=qe({findConfigPath:K,loadArkConfig:M,resolveImportSpecifier:ge,lintedFilename:T,sourceIsInAnalysisScope:Y,isLocallyBound:P,reportAdapterDiagnostic:_});var Or={"no-domain-infra-imports":rt,"no-raw-event-publish":nt,"require-publish-source":st,"no-forbidden-globals":ot,"no-denied-capabilities":it,"no-arkrun-kernel-in-domain":at,"no-arkrun-direct-new":lt,"no-arkrun-transport-bypass":ct},Z={rules:Or};Z.configs={recommended:{plugins:{ark:Z},rules:{"ark/no-domain-infra-imports":"error","ark/no-raw-event-publish":"error","ark/require-publish-source":"error","ark/no-forbidden-globals":"error","ark/no-denied-capabilities":"error","ark/no-arkrun-kernel-in-domain":"error","ark/no-arkrun-direct-new":"error","ark/no-arkrun-transport-bypass":"error"}}};var Dr=Z;0&&(module.exports={findConfigPath,globToRegExp,isEdgeDenied,layerForRelativePath,loadArkConfig,noArkRunDirectNew,noArkRunKernelInDomain,noArkRunTransportBypass,noDeniedCapabilities,noDomainInfraImports,noForbiddenGlobals,noRawEventPublish,patternSpecificity,plugin,readTsconfigPathAliases,requirePublishSource,resolveImportSpecifier,resolveRelativeImport});

@@ -1,3 +0,31 @@

import { A as ArkConfig } from '../configTypes-l6XiwiC1.js';
import { A as ArkConfig } from '../configTypes-CgJimx9o.js';
type RuleContext$1 = {
report(descriptor: Record<string, unknown>): void;
filename?: string;
physicalFilename?: string;
getFilename?: () => string;
options?: unknown[];
};
type AstNode$1 = {
type?: string;
name?: string;
value?: unknown;
source?: AstNode$1;
callee?: AstNode$1;
object?: AstNode$1;
property?: AstNode$1;
arguments?: AstNode$1[];
importKind?: string;
exportKind?: string;
specifiers?: AstNode$1[];
loc?: {
start?: {
line?: number;
column?: number;
};
};
computed?: boolean;
};
/**

@@ -170,4 +198,44 @@ * Pure layer-glob matching for ark.config.json.

declare const noDeniedCapabilities: ArkRule;
declare const noArkRunKernelInDomain: {
meta: {
type: "problem";
docs: {
description: string;
};
messages: Record<string, string>;
schema: unknown[];
};
create(context: RuleContext$1): {
[x: string]: (node: AstNode$1) => void;
};
};
declare const noArkRunDirectNew: {
meta: {
type: "problem";
docs: {
description: string;
};
messages: Record<string, string>;
schema: unknown[];
};
create(context: RuleContext$1): {
[x: string]: (node: AstNode$1) => void;
};
};
declare const noArkRunTransportBypass: {
meta: {
type: "problem";
docs: {
description: string;
};
messages: Record<string, string>;
schema: unknown[];
};
create(context: RuleContext$1): {
[x: string]: (node: AstNode$1) => void;
};
};
declare const plugin: ArkEslintPlugin;
export { plugin as default, findConfigPath, globToRegExp, isEdgeDenied, layerForRelativePath, loadArkConfig, noDeniedCapabilities, noDomainInfraImports, noForbiddenGlobals, noRawEventPublish, patternSpecificity, plugin, readTsconfigPathAliases, requirePublishSource, resolveImportSpecifier, resolveRelativeImport };
export { plugin as default, findConfigPath, globToRegExp, isEdgeDenied, layerForRelativePath, loadArkConfig, noArkRunDirectNew, noArkRunKernelInDomain, noArkRunTransportBypass, noDeniedCapabilities, noDomainInfraImports, noForbiddenGlobals, noRawEventPublish, patternSpecificity, plugin, readTsconfigPathAliases, requirePublishSource, resolveImportSpecifier, resolveRelativeImport };

@@ -1,3 +0,7 @@

import R from"fs";import p from"path";var J=new Map;function X(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function N(e){let t="";for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"&&r+1<e.length){let s=e[r+1];if("*?{}[],".includes(s)||s==="\\"){t+="\\"+s,r+=1;continue}t+="/";continue}t+=n}return t}function Ie(e){let t=0;for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"){r+=1;continue}if(n==="{")t+=1;else if(n==="}"&&(t-=1,t<0))return!1}return t===0}function w(e){let t=J.get(e);if(t)return t;let r=N(e),n=Ie(r),s="",o=0;for(let c=0;c<r.length;c+=1){let g=r[c];g==="\\"&&c+1<r.length?(s+=X(r[c+1]),c+=1):g==="*"?r[c+1]==="*"?r[c+2]==="/"?(s+="(?:.*/)?",c+=2):(s+=".*",c+=1):s+="[^/]*":g==="?"?s+="[^/]":g==="{"&&n?(s+="(?:",o+=1):g==="}"&&n&&o>0?(s+=")",o-=1):g===","&&n&&o>0?s+="|":s+=X(g)}let a=new RegExp(`^${s}$`);return J.set(e,a),a}function ke(e){return N(String(e)).split("/").filter(Boolean).filter(r=>r!=="**"&&r!=="*"&&!r.includes("*")&&!r.includes("?")&&!r.includes("{")&&!r.includes("["))}function Q(e,t){let r=N(String(e)),n=ke(r),s=r.replace(/\*/g,"").length,o=n.length*1e4+s;if(t==null||t==="")return o;let a=String(t).split(/[/\\]/).filter(Boolean);if(n.length===0)return s;let c=0,g=-1;for(let f of n){let d=-1;for(let i=c;i<a.length;i+=1)if(a[i]===f){d=i;break}if(d<0)return o;g=d,c=d+1}return(g+1)*1e6+n.length*1e4+s}function E(e,t){let r=String(e).split(/[/\\]/).join("/"),n,s=-1;for(let o of t??[])if(!(o.exclude??[]).some(a=>w(a).test(r))){for(let a of o.patterns??[])if(w(a).test(r)){let c=Q(a,r);c>s&&(s=c,n=o.name)}}return n}function Z(e,t){if(!t?.length)return;let r=String(e).split(/[/\\]/).filter(Boolean),n=new Set(t.map(s=>String(s).toLowerCase()));for(let s=0;s<r.length-1;s+=1)if(n.has(r[s].toLowerCase()))return`${r[s].toLowerCase()}/${r[s+1].toLowerCase()}`}function Re(e){let t=new Set;for(let r of e??[]){let s=N(String(r)).split("/").filter(Boolean);for(let o=0;o<s.length;o+=1){let a=s[o];if((a==="**"||a==="*")&&o>0){let c=s[o-1];c&&!c.includes("*")&&!c.includes("{")&&!c.includes("}")&&t.add(c)}}}return[...t]}function Se(e,t,r){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(s=>typeof s=="string"&&s.length>0);let n=(r??[]).find(s=>s.name===t);return Re(n?.patterns)}function xe(e){return!e.fromPath||!e.toPath||e.folderCount<=0||!e.fromSlice||!e.toSlice?!0:e.fromSlice!==e.toSlice}function $(e,t,r,n){for(let s of e??[])if(!(s.from!==t||s.to!==r)&&s.allowed===!1){if(s.peerIsolation){let o=n?.fromPath,a=n?.toPath,c=Se(s,t,n?.layers),g=o&&a?Z(o,c):void 0,f=o&&a?Z(a,c):void 0;if(xe({fromPath:o,toPath:a,folderCount:c.length,fromSlice:g,toSlice:f}))return s;continue}if(t!==r)return s}}function ee(e,t,r,n){return $(e,t,r,n)!==void 0}var Ee=["**/*.gen.ts","**/*.gen.tsx","**/*.generated.ts","**/*.generated.tsx"];function Le(e){let t=Array.isArray(e?.exclude)?e.exclude.filter(n=>typeof n=="string"):[];return[...e?.excludeGenerated===!1?[]:Ee,...t]}function te(e,t){let r=String(e).split(/[/\\]/).join("/");return Le(t).some(n=>w(n).test(r))}var re=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),Ce=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),at=Object.freeze(Object.keys(Ce).sort()),j=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"}),we=Object.freeze({process:Object.freeze(["process","node:process"])});function ne(e){if(!e||e.startsWith(".")||e.startsWith("/"))return null;let t=j[e];if(t)return t;let r=e.indexOf("/");if(r<0)return null;let n=e.slice(0,r),s=j[n];if(s)return s;let o=e.indexOf("/",r+1);return o<0?null:j[e.slice(0,o)]??null}function D(e,t){for(let r of t)if(we[r]?.includes(e))return r;return null}function se(e){if(e?.pure===!0)return[...re].sort();let r=(e?.capabilities?.deny??[]).filter(n=>re.includes(n));return[...new Set(r)].sort()}var v="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",ie=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],Ne=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function Oe(){let e=[];for(let t of ie)for(let r of ie)t===r||Ne.has(`${t}->${r}`)||e.push({from:t,to:r,allowed:!1});return e}var ae=Oe(),V=[{from:"unversioned",to:"1.0"},{from:"1.0",to:"1.1"}],I={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},oe={$schema:"https://json-schema.org/draft/2020-12/schema",$id:v,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:v,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.1",default:"1.1"},name:{type:"string",minLength:1},include:{...I,minItems:1,default:["src"]},exclude:{...I,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:ae,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...I,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}},arkRules:{type:"object",additionalProperties:{type:"string",minLength:1},default:{}},stewards:{...I,default:[]}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...I,minItems:1},exclude:I,intentPrefixes:I,description:{type:"string",minLength:1},forbiddenGlobals:I,capabilities:{type:"object",additionalProperties:!1,properties:{deny:{type:"array",uniqueItems:!0,items:{type:"string",enum:["network","filesystem","clock","randomness","environment","process","persistence"]}}}},pure:{type:"boolean"},mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"},reserved:{type:"boolean"},allowEmpty:{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:{...I,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}}}}},k=class extends Error{issues;source;constructor(t,r){super(`Invalid ArkGate config (${t}):
import x from"fs";import g from"path";var fe=new Map;function ge(e){return/[.*+?^${}()|[\]\\]/.test(e)?`\\${e}`:e}function $(e){let t="";for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"&&r+1<e.length){let s=e[r+1];if("*?{}[],".includes(s)||s==="\\"){t+="\\"+s,r+=1;continue}t+="/";continue}t+=n}return t}function tt(e){let t=0;for(let r=0;r<e.length;r+=1){let n=e[r];if(n==="\\"){r+=1;continue}if(n==="{")t+=1;else if(n==="}"&&(t-=1,t<0))return!1}return t===0}function _(e){let t=fe.get(e);if(t)return t;let r=$(e),n=tt(r),s="",i=0;for(let a=0;a<r.length;a+=1){let l=r[a];l==="\\"&&a+1<r.length?(s+=ge(r[a+1]),a+=1):l==="*"?r[a+1]==="*"?r[a+2]==="/"?(s+="(?:.*/)?",a+=2):(s+=".*",a+=1):s+="[^/]*":l==="?"?s+="[^/]":l==="{"&&n?(s+="(?:",i+=1):l==="}"&&n&&i>0?(s+=")",i-=1):l===","&&n&&i>0?s+="|":s+=ge(l)}let o=new RegExp(`^${s}$`);return fe.set(e,o),o}function rt(e){return $(String(e)).split("/").filter(Boolean).filter(r=>r!=="**"&&r!=="*"&&!r.includes("*")&&!r.includes("?")&&!r.includes("{")&&!r.includes("["))}function ye(e,t){let r=$(String(e)),n=rt(r),s=r.replace(/\*/g,"").length,i=n.length*1e4+s;if(t==null||t==="")return i;let o=String(t).split(/[/\\]/).filter(Boolean);if(n.length===0)return s;let a=0,l=-1;for(let d of n){let u=-1;for(let c=a;c<o.length;c+=1)if(o[c]===d){u=c;break}if(u<0)return i;l=u,a=u+1}return(l+1)*1e6+n.length*1e4+s}function S(e,t){let r=String(e).split(/[/\\]/).join("/"),n,s=-1;for(let i of t??[])if(!(i.exclude??[]).some(o=>_(o).test(r))){for(let o of i.patterns??[])if(_(o).test(r)){let a=ye(o,r);a>s&&(s=a,n=i.name)}}return n}function me(e,t){if(!t?.length)return;let r=String(e).split(/[/\\]/).filter(Boolean),n=new Set(t.map(s=>String(s).toLowerCase()));for(let s=0;s<r.length-1;s+=1)if(n.has(r[s].toLowerCase()))return`${r[s].toLowerCase()}/${r[s+1].toLowerCase()}`}function nt(e){let t=new Set;for(let r of e??[]){let s=$(String(r)).split("/").filter(Boolean);for(let i=0;i<s.length;i+=1){let o=s[i];if((o==="**"||o==="*")&&i>0){let a=s[i-1];a&&!a.includes("*")&&!a.includes("{")&&!a.includes("}")&&t.add(a)}}}return[...t]}function st(e,t,r){if(Array.isArray(e.sliceFolders)&&e.sliceFolders.length>0)return e.sliceFolders.filter(s=>typeof s=="string"&&s.length>0);let n=(r??[]).find(s=>s.name===t);return nt(n?.patterns)}function ot(e){return!e.fromPath||!e.toPath||e.folderCount<=0||!e.fromSlice||!e.toSlice?!0:e.fromSlice!==e.toSlice}function Y(e,t,r,n){for(let s of e??[])if(!(s.from!==t||s.to!==r)&&s.allowed===!1){if(s.peerIsolation){let i=n?.fromPath,o=n?.toPath,a=st(s,t,n?.layers),l=i&&o?me(i,a):void 0,d=i&&o?me(o,a):void 0;if(ot({fromPath:i,toPath:o,folderCount:a.length,fromSlice:l,toSlice:d}))return s;continue}if(t!==r)return s}}function he(e,t,r,n){return Y(e,t,r,n)!==void 0}var it=["**/*.gen.ts","**/*.gen.tsx","**/*.generated.ts","**/*.generated.tsx"];function at(e){let t=Array.isArray(e?.exclude)?e.exclude.filter(n=>typeof n=="string"):[];return[...e?.excludeGenerated===!1?[]:it,...t]}function Re(e,t){let r=String(e).split(/[/\\]/).join("/");return at(t).some(n=>_(n).test(r))}var Ae=Object.freeze(["network","filesystem","clock","randomness","environment","process","persistence"]),lt=Object.freeze({fetch:"network",XMLHttpRequest:"network",Date:"clock","Date.now":"clock","Math.random":"randomness","process.env":"environment",process:"process"}),Cr=Object.freeze(Object.keys(lt).sort()),J=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"}),ct=Object.freeze({process:Object.freeze(["process","node:process"])});function ke(e){if(!e||e.startsWith(".")||e.startsWith("/"))return null;let t=J[e];if(t)return t;let r=e.indexOf("/");if(r<0)return null;let n=e.slice(0,r),s=J[n];if(s)return s;let i=e.indexOf("/",r+1);return i<0?null:J[e.slice(0,i)]??null}function X(e,t){for(let r of t)if(ct[r]?.includes(e))return r;return null}function be(e){if(e?.pure===!0)return[...Ae].sort();let r=(e?.capabilities?.deny??[]).filter(n=>Ae.includes(n));return[...new Set(r)].sort()}var Q="https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",Se=["DomainModel","ApplicationOrchestration","PersistenceAdapters","IntegrationAdapters","WorkflowSagaEngine","BackgroundJobsScheduling","PresentationAdapters","ReportingReadModels","ExtensibilityMetadata","SecurityAuditObservability","Kernel"],ut=new Set(["PresentationAdapters->ApplicationOrchestration","ApplicationOrchestration->DomainModel","WorkflowSagaEngine->ApplicationOrchestration","WorkflowSagaEngine->DomainModel","BackgroundJobsScheduling->ApplicationOrchestration"]);function dt(){let e=[];for(let t of Se)for(let r of Se)t===r||ut.has(`${t}->${r}`)||e.push({from:t,to:r,allowed:!1});return e}var Ie=dt(),ee=[{from:"unversioned",to:"1.0"},{from:"1.0",to:"1.1"},{from:"1.1",to:"1.2"}],b={type:"array",items:{type:"string",minLength:1},uniqueItems:!0},Ee={$schema:"https://json-schema.org/draft/2020-12/schema",$id:Q,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:Q,description:"Editor-facing URL or local path for this JSON Schema."},schemaVersion:{type:"string",const:"1.2",default:"1.2"},name:{type:"string",minLength:1},include:{...b,minItems:1,default:["src"]},exclude:{...b,default:[]},excludeGenerated:{type:"boolean",default:!0},frameworkOverlay:{type:"string",minLength:1},layers:{type:"array",default:[],items:{$ref:"#/$defs/layer"}},rules:{type:"array",default:Ie,items:{$ref:"#/$defs/rule"}},cyclePolicy:{type:"string",enum:["strict","soft","framework-soft","off"],default:"strict"},dynamicImportAllowlist:{...b,default:[]},safety:{$ref:"#/$defs/safety",default:{maxTsSuppressions:0,maxAnyCasts:0,allowInMemory:!1,allowDisabledPeerIsolation:!1}},arkRules:{type:"object",additionalProperties:{type:"string",minLength:1},default:{}},arkRun:{$ref:"#/$defs/arkRun"},stewards:{...b,default:[]}},$defs:{layer:{type:"object",additionalProperties:!1,required:["name","patterns"],properties:{name:{type:"string",minLength:1},patterns:{...b,minItems:1},exclude:b,intentPrefixes:b,description:{type:"string",minLength:1},forbiddenGlobals:b,capabilities:{type:"object",additionalProperties:!1,properties:{deny:{type:"array",uniqueItems:!0,items:{type:"string",enum:["network","filesystem","clock","randomness","environment","process","persistence"]}}}},pure:{type:"boolean"},mayImportInfrastructure:{type:"boolean"},optional:{type:"boolean"},reserved:{type:"boolean"},allowEmpty:{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:{...b,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}}},arkRun:{type:"object",additionalProperties:!1,properties:{mode:{type:"string",enum:["advisory","enforced"],default:"advisory"},compositionRoots:{...b,default:[]},managedLayers:{...b,default:[]},requireDeclarations:{type:"boolean",default:!0}}}}},E=class extends Error{issues;source;constructor(t,r){super(`Invalid ArkGate config (${t}):
${r.map(n=>`- ${n.path}: ${n.message}`).join(`
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=r}};function le(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function O(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function S(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function _e(e,t){let r="#/$defs/";if(e.startsWith(r))return t.$defs[e.slice(r.length)]}function L(e,t,r,n,s){if(t.$ref){let o=_e(t.$ref,n);if(!o){s.push({path:r,message:`schema reference ${t.$ref} cannot be resolved`});return}L(e,o,r,n,s);return}if(t.const!==void 0&&!Object.is(e,t.const)){s.push({path:r,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(o=>Object.is(o,e))){s.push({path:r,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!le(e)){s.push({path:r,message:`must be an object; received ${S(e)}`});return}let o=t.properties??{};for(let a of t.required??[])e[a]===void 0&&s.push({path:O(r,a),message:"is required"});if(t.additionalProperties===!1)for(let a of Object.keys(e))a in o||s.push({path:O(r,a),message:"unknown field"});else if(t.additionalProperties!==void 0&&t.additionalProperties!==!0&&typeof t.additionalProperties=="object"){let a=t.additionalProperties;for(let c of Object.keys(e))c in o||L(e[c],a,O(r,c),n,s)}for(let[a,c]of Object.entries(o))e[a]!==void 0&&L(e[a],c,O(r,a),n,s);return}if(t.type==="array"){if(!Array.isArray(e)){s.push({path:r,message:`must be an array; received ${S(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&s.push({path:r,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let o=e.map(a=>JSON.stringify(a));new Set(o).size!==o.length&&s.push({path:r,message:"must not contain duplicate items"})}t.items&&e.forEach((o,a)=>L(o,t.items,`${r}[${a}]`,n,s));return}if(t.type==="string"){if(typeof e!="string"){s.push({path:r,message:`must be a string; received ${S(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&s.push({path:r,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&s.push({path:r,message:`must be a boolean; received ${S(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){s.push({path:r,message:`must be an integer; received ${S(e)}`});return}t.minimum!==void 0&&e<t.minimum&&s.push({path:r,message:`must be at least ${t.minimum}`})}}function Te(e){return{...e,$schema:e.$schema===void 0?v:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.1":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?ae.map(t=>({...t})):e.rules}}function Pe(){let e=new Set(["1.1"]);for(let t of V)t.from!=="unversioned"&&e.add(t.from),e.add(t.to);return e}function $e(e,t="ark.config.json"){if(!le(e))throw new k(t,[{path:"$",message:`must be an object; received ${S(e)}`}]);let r=Pe(),n=e.schemaVersion===void 0?"unversioned":typeof e.schemaVersion=="string"?e.schemaVersion:null;if(n===null)throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.1`}]);if(n!=="unversioned"&&!r.has(n))throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.1`}]);let s=n,o={...e},a=0;for(;s!=="1.1"&&a<V.length+1;){a+=1;let g=V.find(f=>f.from===s);if(!g)throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(s)}; expected 1.1`}]);s=g.to,o.schemaVersion=s}if(s!=="1.1")throw new k(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.1`}]);let c=n==="unversioned"?"unversioned":n==="1.0"?"1.0":null;return{candidate:Te(o),migratedFrom:c}}function je(e,t="ark.config.json"){let{candidate:r,migratedFrom:n}=$e(e,t),s=[];if(L(r,oe,"$",oe,s),s.length>0)throw new k(t,s);return{config:r,migratedFrom:n}}function ce(e,t="ark.config.json"){let r;try{r=JSON.parse(e)}catch(n){throw new k(t,[{path:"$",message:`invalid JSON: ${n instanceof Error?n.message:String(n)}`}])}return je(r,t)}var De=/(^|\/)(constants|types|enums|shared-types|shared\/(?:types|constants)|test-projects)(\/|\.|$)|(?:^|\/)[^/]*(?:constants|types)(?:\.[cm]?[jt]sx?)?$/i,ve=/(^|\/)(?:kernel(?:\/|$)|events?(?:\/|\.|$)|bootstrap(?:\.[cm]?[jt]sx?)?$|emitter(?:\.[cm]?[jt]sx?)?$)|(?:^|\/)(?:intents?|publish)(?:\/|\.|$)/i,Ve=/(use-?cases?|usecases?|application|orchestrat|services?|handlers?)(\/|\.|$)/i;function Ke(e,t){let r=String(e??"").replace(/\\/g,"/").trim(),n=String(t?.fromLayer??""),s=String(t?.toLayer??"");return De.test(r)?"pure-shared":n==="PersistenceAdapters"&&(ve.test(r)||/events?|intents?|kernel|bootstrap/i.test(`${s} ${r}`))?"kernel-emit":Ve.test(r)||(n==="DomainModel"||n==="ApplicationOrchestration")&&s==="PersistenceAdapters"?"use-case":"unknown"}function de(e){if(e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly)return"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.";if(e.peerIsolation)return"Extract the shared dependency to a shared layer, test at the public interface, then preflight again.";let t=Ke(typeof e.target=="string"?e.target:"",{fromLayer:typeof e.fromLayer=="string"?e.fromLayer:void 0,toLayer:typeof e.toLayer=="string"?e.toLayer:void 0});return t==="pure-shared"?"Adopt the imported constants/types/pure module into DomainModel or SharedKernel (do not inject a port). Then preflight again.":t==="kernel-emit"?"Persistence must not emit. Inject a port or move the event map to SharedTypes; do not import kernel/events/bootstrap from a repository. Then preflight again.":t==="use-case"||e.portProofEligible?`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, test at the public interface, then preflight again.`:"Classify the import: if it is constants/types/pure, adopt into DomainModel or SharedKernel; define a port only if the target is a real use-case. Then preflight again."}var Me="docs/diagnostics.md";function y(e){return typeof e=="string"&&e.length>0?e:void 0}function pe(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}function He(e){let t=typeof e.ruleId=="string"?e.ruleId:typeof e.code=="string"?e.code:void 0,r=typeof e.file=="string"?e.file:void 0,n=typeof e.fromLayer=="string"?e.fromLayer:void 0,s=typeof e.toLayer=="string"?e.toLayer:void 0,o=typeof e.target=="string"?e.target:void 0;return[t,r,n??"",s??"",o??""].join("|")}function Fe(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function Ue(e){return`${Me}#${e}`}function Be(e,t,r){if(e==="LAYER_IMPORT_VIOLATION")return de({ruleId:e,typeOnly:t.typeOnly===!0,targetTypeOnlyExports:r.targetTypeOnlyExports===!0,namedBindingsTypeOnly:r.namedBindingsTypeOnly===!0,peerIsolation:r.peerIsolation===!0,portProofEligible:r.portProofEligible===!0,fromLayer:y(t.fromLayer)??void 0,toLayer:y(t.toLayer)??void 0,target:y(t.target)??y(r.target)??void 0});if(e==="FORBIDDEN_GLOBAL")return`Inject ${t.target??"the capability"} through a port, test at the public interface, then preflight again.`;if(e==="CAPABILITY_VIOLATION")return`Define a ${y(r.capability)??"capability"} port in ${t.fromLayer??"the walled layer"}, bind the implementation outside it, test at the public interface, then preflight again.`;if(e==="CIRCULAR_DEPENDENCY")return"Extract the shared dependency into a third module, test at the public interface, then preflight again.";if(e==="RAW_EVENT_PUBLISH")return"Publish through a registered intent creator, then run Ark again.";if(e==="PUBLISH_MISSING_SOURCE")return"Add metadata.source to the publish call, then run Ark again.";if(e==="ARKRULE_STRUCTURE"||e==="ARKRULE_INVARIANT"||e==="INVARIANT_UNCOVERED"||e.startsWith("ARKRULE_")){let n=t.arkruleSource??"arkrules/<Layer>.json";return`Fix the structure or invariant for ${t.arkruleId??"the ArkRule"} (declared in ${n}), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.`}return`Resolve ${e} without weakening ark.config.json, then run Ark again.`}function ue(e,t="error",r){let n=y(e.ruleId)??y(e.code)??"ARK_UNKNOWN",s=e.severity==="warning"||e.failsStrict===!1||e.typeOnly===!0&&e.peerIsolation!==!0?"warning":t,o={...y(e.target)?{target:y(e.target)}:{},...y(e.fromLayer)?{fromLayer:y(e.fromLayer)}:{},...y(e.toLayer)?{toLayer:y(e.toLayer)}:{},...typeof e.typeOnly=="boolean"?{typeOnly:e.typeOnly}:{},...typeof e.targetTypeOnlyExports=="boolean"?{targetTypeOnlyExports:e.targetTypeOnlyExports}:{},...typeof e.sourcePureTypeModule=="boolean"?{sourcePureTypeModule:e.sourcePureTypeModule}:{},...typeof e.namedBindingsTypeOnly=="boolean"?{namedBindingsTypeOnly:e.namedBindingsTypeOnly}:{},...typeof e.portProofEligible=="boolean"?{portProofEligible:e.portProofEligible}:{},...typeof e.peerIsolation=="boolean"?{peerIsolation:e.peerIsolation}:{},...y(e.capability)?{capability:y(e.capability)}:{},...y(e.edgeKind)?{edgeKind:y(e.edgeKind)}:{},...y(e.arkruleId)?{arkruleId:y(e.arkruleId)}:{},...y(e.arkruleSource)?{arkruleSource:y(e.arkruleSource)}:{}},a=r??He(e),c=Fe(a);return{ruleId:n,severity:s,message:y(e.message)??n,location:{file:y(e.file)??"<unknown>",line:pe(e.line,1),column:pe(e.column,1)},evidence:o,nextAction:y(e.nextAction)??Be(n,o,e),findingRef:c,targetKey:a,docsCodePath:Ue(n)}}var fe={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."},ft=Object.freeze([{layer:"DomainModel",prefixes:["Domain."]},{layer:"ApplicationOrchestration",prefixes:["Application."]},{layer:"PersistenceAdapters",prefixes:["Adapter.Persistence.","Adapter.Repository."]},{layer:"IntegrationAdapters",prefixes:["Adapter.Integration.","Adapter.External."]},{layer:"WorkflowSagaEngine",prefixes:["Workflow."]},{layer:"BackgroundJobsScheduling",prefixes:["Job."]},{layer:"PresentationAdapters",prefixes:["Presentation.","Adapter.Presentation.","Adapter.Api."]},{layer:"ReportingReadModels",prefixes:["Reporting."]},{layer:"ExtensibilityMetadata",prefixes:["Metadata."]},{layer:"SecurityAuditObservability",prefixes:["Security.","Audit.","Observability."]},{layer:"Kernel",prefixes:["Kernel."]}]);function Ge(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function K(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&Ge(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:fe.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:fe.PUBLISH_MISSING_SOURCE}),t}function C(e){if(typeof e.physicalFilename=="string"&&e.physicalFilename.length>0)return e.physicalFilename;if(typeof e.filename=="string"&&e.filename.length>0)return e.filename;if(typeof e.getFilename=="function")try{let t=e.getFilename();if(typeof t=="string"&&t.length>0)return t}catch{}return""}function x(e,t,r,n,s){let o=ue({...n,line:n.line??t.loc?.start?.line,column:n.column??(typeof t.loc?.start?.column=="number"?t.loc.start.column+1:void 0)});return e.report({node:t,messageId:r,...s?{data:s}:{},diagnostic:o}),o}function F(e){if(!e||e==="<input>"||e.startsWith("stdin"))return null;let t=p.dirname(p.resolve(e));for(;;){let r=p.join(t,"ark.config.json");if(R.existsSync(r))return r;let n=p.dirname(t);if(n===t)return null;t=n}}var ge=new Map;function U(e){if(!R.existsSync(e))return null;let t=R.readFileSync(e,"utf8"),r=ge.get(e);if(r?.source===t)return r.config;let n=ce(t,e).config;return ge.set(e,{source:t,config:n}),n}function B(e,t){return(e.include??[]).some(n=>{let s=String(n).replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/$/,"");return s==="."||t===s||t.startsWith(`${s}/`)})&&!te(t,e)}function me(e){let t=[e,`${e}.ts`,`${e}.tsx`,`${e}.mts`,`${e}.cts`,`${e}.js`,`${e}.jsx`,p.join(e,"index.ts"),p.join(e,"index.tsx"),p.join(e,"index.js")];for(let r of t)try{if(R.existsSync(r)&&R.statSync(r).isFile())return r}catch{}return null}function qe(e){let t=p.resolve(e),r=null;for(;;){let f=p.join(t,"tsconfig.json");if(R.existsSync(f)){r=f;break}let d=p.dirname(t);if(d===t)break;t=d}if(!r)return{baseUrl:e,aliases:[]};let n=f=>{try{let d=R.readFileSync(f,"utf8");return d=d.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1"),JSON.parse(d)}catch{return null}},s=(f,d)=>{if(d>4)return{};let i=n(f);if(!i)return{};let l=i.compilerOptions??{},u=l.baseUrl,m=l.paths,h=i.extends;if(typeof h=="string"&&!h.startsWith("@")){let b=p.resolve(p.dirname(f),h.endsWith(".json")?h:`${h}.json`);if(R.existsSync(b)){let A=s(b,d+1);u=u??A.baseUrl,m={...A.paths??{},...m??{}}}}return{baseUrl:u,paths:m}},o=s(r,0),a=p.dirname(r),c=p.resolve(a,o.baseUrl||"."),g=[];for(let[f,d]of Object.entries(o.paths||{})){if(!Array.isArray(d)||d.length===0)continue;let i=f.replace(/\*$/,"");i&&g.push({from:i,to:String(d[0]).replace(/\*$/,"")})}return g.sort((f,d)=>d.from.length-f.from.length),{baseUrl:c,aliases:g}}function We(e,t){if(!t.startsWith("."))return null;let r=p.resolve(p.dirname(e),t);return me(r)}function Ye(e,t,r){if(!t)return null;if(t.startsWith("."))return We(e,t);let n=r||p.dirname(e),{baseUrl:s,aliases:o}=qe(n),a=o.find(g=>t.startsWith(g.from));if(!a)return null;let c=p.resolve(s,`${a.to}${t.slice(a.from.length)}`);return me(c)}function P(e){return typeof e?.value=="string"?e.value:void 0}function G(e){return e?.name??P(e)}function q(e){return e.sourceCode??e.getSourceCode?.()}function ye(e,t){let r=q(e)?.getScope?.(t);for(;r;){let n=r.references?.find(s=>s.identifier===t);if(n)return n;r=r.upper??void 0}}function _(e,t,r){let n=ye(e,t);if(n?.resolved)return(n.resolved.defs?.length??0)>0;let s=q(e)?.getScope?.(t);for(;s;){let o=s.set?.get(r);if(o)return(o.defs?.length??0)>0;s=s.upper??void 0}return!1}function ze(e,t){let r=ye(e,t);return r?r.isValueReference!==!1:t.parent?.type==="VariableDeclarator"&&t.parent.init===t}function he(e){if(e?.type==="Identifier"&&e.name)return{root:e,segments:[e.name]};if(!e||!(e.type==="MemberExpression"||!!(e.object&&e.property))||e.computed===!0)return;let r=he(e.object),n=G(e.property);if(!(!r||!n))return{root:r.root,segments:[...r.segments,n]}}function Je(e){return G(e.callee?.property)}function be(e,t){return e?.properties?.find(r=>G(r.key)===t)}function T(e,t){return be(e,t)!==void 0}function Xe(e){let t=be(e,"metadata")?.value;return T(t,"source")}function Ae(e){return Je(e)==="publish"}function M(e){if(e.importKind==="type"||e.exportKind==="type")return!0;let t=e.specifiers??[];return t.length===0?!1:t.every(r=>r.type==="ImportSpecifier")?t.every(r=>r.importKind==="type"):t.every(r=>r.exportKind==="type")}function Ze(e){let t=e;for(;t?.parent;)t=t.parent;return t?.type==="Program"?t:void 0}function Qe(e){let t=Ze(e)?.body;if(!t)return!1;let r=!1;for(let n of t){if(n.type==="ImportDeclaration"){if(!M(n))return!1;continue}if(!(n.type==="TSInterfaceDeclaration"||n.type==="TSTypeAliasDeclaration")){if(n.type==="ExportNamedDeclaration"){if(n.declaration){if(n.declaration.type!=="TSInterfaceDeclaration"&&n.declaration.type!=="TSTypeAliasDeclaration")return!1}else if(!M(n))return!1;r=!0;continue}return!1}}return r}var et={meta:{type:"problem",docs:{description:"Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."},messages:{forbiddenImport:"Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",forbiddenImportHeuristic:"Domain code must not import infrastructure, adapters, repositories, or database modules."},schema:[]},create(e){let t=C(e),r=F(t),n=r?U(r):null,s=r?p.dirname(r):null,o=a=>{let c=P(a.source);if(c&&n&&s&&t){let g=p.isAbsolute(t)?t:p.resolve(t),f=p.relative(s,g).split(p.sep).join("/");if(!B(n,f))return;let d=E(f,n.layers);if(!d)return;let i=Ye(g,c,s);if(!i)return;let l=p.relative(s,i).split(p.sep).join("/");if(l.startsWith(".."))return;let u=E(l,n.layers);if(!u)return;let m={fromPath:f,toPath:l,layers:n.layers},h=$(n.rules,d,u,m);if(h||ee(n.rules,d,u,m)){let b=a.type?.startsWith("Export")?"export":"import",A=M(a),W=!!h?.peerIsolation,Y=A&&!W,z=h?.message??`${d} must not ${b} ${u}.`;x(e,a,"forbiddenImport",{ruleId:"LAYER_IMPORT_VIOLATION",file:f,fromLayer:d,toLayer:u,target:l,edgeKind:b,...W?{peerIsolation:!0}:{},...A?{typeOnly:!0}:{},...Y?{severity:"warning"}:{},...Qe(a)?{sourcePureTypeModule:!0}:{},message:Y?`${z} (type-only \u2014 type placement debt; prefer SharedTypes / owning layer; not runtime coupling)`:z},{fromLayer:d,toLayer:u,specifier:c})}return}};return{ImportDeclaration:o,ExportNamedDeclaration:o,ExportAllDeclaration:o}}},tt={meta:{type:"problem",docs:{description:"Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings."},messages:{rawPublish:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=P(r),s=K({publishCall:Ae(t),rawIntentName:n,objectHasIntent:T(r,"intent"),arkPublishCandidate:!1,hasSource:!0});if(s.some(o=>o.ruleId==="RAW_EVENT_PUBLISH")){let o=s.find(a=>a.ruleId==="RAW_EVENT_PUBLISH");x(e,t,"rawPublish",{...o,file:C(e)})}}}}},rt={meta:{type:"problem",docs:{description:"Require event bus publish calls to include source metadata."},messages:{missingSource:"Strict Ark publish calls must include metadata.source."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=t.arguments?.[2],o=K({publishCall:Ae(t),rawIntentName:P(r),objectHasIntent:T(r,"intent"),arkPublishCandidate:!0,hasSource:Xe(r)||T(n,"source")}).find(a=>a.ruleId==="PUBLISH_MISSING_SOURCE");o&&x(e,t,"missingSource",{...o,file:C(e)})}}}},nt={meta:{type:"problem",docs:{description:"Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` is a standalone fallback when no project config applies."},messages:{forbiddenGlobal:'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',forbiddenGlobalDefault:'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.',forbiddenModule:'{{layer}} must not use module "{{specifier}}" because it is the import form of forbidden global "{{name}}".'},schema:[{type:"object",properties:{globals:{type:"array",items:{type:"string"}}},additionalProperties:!1}]},create(e){let t=C(e),r=e.options?.[0],n=F(t),s=n?U(n):null,o=n?p.dirname(n):null,a=null,c="this layer";if(s&&o&&t){let i=p.isAbsolute(t)?t:p.resolve(t),l=p.relative(o,i).split(p.sep).join("/");if(!B(s,l))return{};let u=s.layers?.find(m=>m.name===E(l,s.layers));u?.forbiddenGlobals?.length?(a=new Set(u.forbiddenGlobals),c=u.name):a=null}else r?.globals&&(a=new Set(r.globals));if(!a)return{};let g=typeof q(e)?.getScope=="function",f=(i,l)=>{let u=p.isAbsolute(t)?t:p.resolve(t),m=o?p.relative(o,u).split(p.sep).join("/"):t;x(e,i,s?"forbiddenGlobal":"forbiddenGlobalDefault",{ruleId:"FORBIDDEN_GLOBAL",file:m,fromLayer:c,target:l,message:`${c} must not use the ambient global "${l}".`},{name:l,layer:c})},d=(i,l,u,m)=>{if(u||typeof l!="string")return;let h=D(l,a);if(!h)return;let b=p.isAbsolute(t)?t:p.resolve(t),A=o?p.relative(o,b).split(p.sep).join("/"):t;x(e,i,"forbiddenModule",{ruleId:"FORBIDDEN_GLOBAL",file:A,fromLayer:c,target:l,edgeKind:m,message:`${c} must not use module "${l}" because it is the import form of forbidden global "${h}".`},{layer:c,name:h,specifier:l,importKind:m})};return{MemberExpression(i){if(i.parent?.type==="MemberExpression"&&i.parent.object===i)return;let l=he(i);if(!l||_(e,l.root,l.segments[0]))return;let u=l.segments[0]==="globalThis",m=u?l.segments.slice(1):l.segments,h;for(let b=m.length;b>=(u?1:2);b-=1){let A=m.slice(0,b).join(".");if(a.has(A)){h=A;break}}h?f(i,h):!g&&a.has(l.segments[0])&&f(i,l.segments[0])},CallExpression(i){let l=i;if(l.callee?.type==="Identifier"&&l.callee.name==="require"&&l.arguments?.[0]?.type==="Literal"&&!_(e,i,"require")&&d(i,l.arguments[0].value,!1,"require"),g)return;let u=l.callee?.type==="Identifier"?l.callee.name:void 0;u&&a.has(u)&&f(i,u)},ImportDeclaration(i){let l=i,u=(l.specifiers??[]).filter(h=>h.type==="ImportSpecifier"),m=u.length>0&&u.length===(l.specifiers??[]).length&&u.every(h=>h.importKind==="type");d(i,l.source?.value,l.importKind==="type"||m,"import")},ImportExpression(i){let l=i;l.source?.type==="Literal"&&d(i,l.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(i){let l=i;d(i,l.moduleReference?.expression?.value,l.importKind==="type"||l.isTypeOnly===!0,"require")},ExportNamedDeclaration(i){let l=i;if(!l.source)return;let u=l.specifiers??[],m=u.length>0&&u.every(h=>h.exportKind==="type");d(i,l.source.value,l.exportKind==="type"||m,"export")},ExportAllDeclaration(i){let l=i;d(i,l.source?.value,l.exportKind==="type","export")},NewExpression(i){if(g)return;let l=i.callee?.type==="Identifier"?i.callee.name:void 0;l&&a.has(l)&&f(i,l)},Identifier(i){!g||!i.name||!a.has(i.name)||!ze(e,i)||_(e,i,i.name)||f(i,i.name)}}}},st={meta:{type:"problem",docs:{description:"Disallow importing modules whose effect capability the layer denies (ark.config.json capabilities.deny / pure \u2014 same wall surface as ark-check). Import dimension only: ambient globals stay with no-forbidden-globals and the CLI/hook symbol path."},messages:{deniedCapability:'{{layer}} denies the {{capability}} capability (ark.config.json); "{{specifier}}" imports it. Define a port and bind the implementation in an adapter layer.'},schema:[]},create(e){let t=C(e),r=F(t),n=r?U(r):null,s=r?p.dirname(r):null;if(!n||!s||!t)return{};let o=p.isAbsolute(t)?t:p.resolve(t),a=p.relative(s,o).split(p.sep).join("/");if(!B(n,a))return{};let c=n.layers?.find(d=>d.name===E(a,n.layers));if(!c)return{};let g=new Set(se(c));if(g.size===0)return{};let f=(d,i,l,u)=>{if(l||typeof i!="string"||D(i,c.forbiddenGlobals??[]))return;let m=ne(i);!m||!g.has(m)||x(e,d,"deniedCapability",{ruleId:"CAPABILITY_VIOLATION",file:a,fromLayer:c.name,target:i,capability:m,edgeKind:u,message:`${c.name} denies the ${m} capability; found import of "${i}".`},{layer:c.name,capability:m,specifier:i})};return{ImportDeclaration(d){let i=d,l=(i.specifiers??[]).filter(m=>m.type==="ImportSpecifier"),u=l.length>0&&l.length===(i.specifiers??[]).length&&l.every(m=>m.importKind==="type");f(d,i.source?.value,i.importKind==="type"||u,"import")},ImportExpression(d){let i=d;i.source?.type==="Literal"&&f(d,i.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(d){let i=d;f(d,i.moduleReference?.expression?.value,i.importKind==="type"||i.isTypeOnly===!0,"require")},ExportNamedDeclaration(d){let i=d;if(!i.source)return;let l=i.specifiers??[],u=l.length>0&&l.every(m=>m.exportKind==="type");f(d,i.source.value,i.exportKind==="type"||u,"export")},ExportAllDeclaration(d){let i=d;f(d,i.source?.value,i.exportKind==="type","export")},CallExpression(d){let i=d;i.callee?.type==="Identifier"&&i.callee.name==="require"&&i.arguments?.[0]?.type==="Literal"&&!_(e,d,"require")&&f(d,i.arguments[0].value,!1,"require")}}}},it={"no-domain-infra-imports":et,"no-raw-event-publish":tt,"require-publish-source":rt,"no-forbidden-globals":nt,"no-denied-capabilities":st},H={rules:it};H.configs={recommended:{plugins:{ark:H},rules:{"ark/no-domain-infra-imports":"error","ark/no-raw-event-publish":"error","ark/require-publish-source":"error","ark/no-forbidden-globals":"error","ark/no-denied-capabilities":"error"}}};var Rt=H;export{Rt as default,F as findConfigPath,w as globToRegExp,ee as isEdgeDenied,E as layerForRelativePath,U as loadArkConfig,st as noDeniedCapabilities,et as noDomainInfraImports,nt as noForbiddenGlobals,tt as noRawEventPublish,Q as patternSpecificity,H as plugin,qe as readTsconfigPathAliases,rt as requirePublishSource,Ye as resolveImportSpecifier,We as resolveRelativeImport};
`)}`),this.name="ArkConfigValidationError",this.source=t,this.issues=r}};function D(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function U(e,t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)?`${e}.${t}`:`${e}[${JSON.stringify(t)}]`}function w(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function pt(e,t){let r="#/$defs/";if(e.startsWith(r))return t.$defs[e.slice(r.length)]}function O(e,t,r,n,s){if(t.$ref){let i=pt(t.$ref,n);if(!i){s.push({path:r,message:`schema reference ${t.$ref} cannot be resolved`});return}O(e,i,r,n,s);return}if(t.const!==void 0&&!Object.is(e,t.const)){s.push({path:r,message:`must equal ${JSON.stringify(t.const)}`});return}if(t.enum&&!t.enum.some(i=>Object.is(i,e))){s.push({path:r,message:`must be one of ${t.enum.map(String).join(", ")}`});return}if(t.type==="object"){if(!D(e)){s.push({path:r,message:`must be an object; received ${w(e)}`});return}let i=t.properties??{};for(let o of t.required??[])e[o]===void 0&&s.push({path:U(r,o),message:"is required"});if(t.additionalProperties===!1)for(let o of Object.keys(e))o in i||s.push({path:U(r,o),message:"unknown field"});else if(t.additionalProperties!==void 0&&t.additionalProperties!==!0&&typeof t.additionalProperties=="object"){let o=t.additionalProperties;for(let a of Object.keys(e))a in i||O(e[a],o,U(r,a),n,s)}for(let[o,a]of Object.entries(i))e[o]!==void 0&&O(e[o],a,U(r,o),n,s);return}if(t.type==="array"){if(!Array.isArray(e)){s.push({path:r,message:`must be an array; received ${w(e)}`});return}if(t.minItems!==void 0&&e.length<t.minItems&&s.push({path:r,message:`must contain at least ${t.minItems} item(s)`}),t.uniqueItems){let i=e.map(o=>JSON.stringify(o));new Set(i).size!==i.length&&s.push({path:r,message:"must not contain duplicate items"})}t.items&&e.forEach((i,o)=>O(i,t.items,`${r}[${o}]`,n,s));return}if(t.type==="string"){if(typeof e!="string"){s.push({path:r,message:`must be a string; received ${w(e)}`});return}t.minLength!==void 0&&e.length<t.minLength&&s.push({path:r,message:`must contain at least ${t.minLength} character(s)`});return}if(t.type==="boolean"){typeof e!="boolean"&&s.push({path:r,message:`must be a boolean; received ${w(e)}`});return}if(t.type==="integer"){if(!Number.isInteger(e)){s.push({path:r,message:`must be an integer; received ${w(e)}`});return}t.minimum!==void 0&&e<t.minimum&&s.push({path:r,message:`must be at least ${t.minimum}`})}}function ft(e){return D(e)?{...e,mode:e.mode===void 0?"advisory":e.mode,compositionRoots:e.compositionRoots===void 0?[]:e.compositionRoots,managedLayers:e.managedLayers===void 0?[]:e.managedLayers,requireDeclarations:e.requireDeclarations===void 0?!0:e.requireDeclarations}:e}function gt(e){let t={...e,$schema:e.$schema===void 0?Q:e.$schema,schemaVersion:e.schemaVersion===void 0?"1.2":e.schemaVersion,include:e.include===void 0?["src"]:e.include,layers:e.layers===void 0?[]:e.layers,rules:e.rules===void 0?Ie.map(r=>({...r})):e.rules};return e.arkRun!==void 0&&(t.arkRun=ft(e.arkRun)),t}function mt(e,t){let r=e.arkRun;if(r===void 0||!D(r))return;let n=new Set;if(Array.isArray(e.layers))for(let i of e.layers)D(i)&&typeof i.name=="string"&&i.name.length>0&&n.add(i.name);let s=r.managedLayers;if(Array.isArray(s)&&s.forEach((i,o)=>{typeof i=="string"&&i.length>0&&!n.has(i)&&t.push({path:`$.arkRun.managedLayers[${o}]`,message:`layer ${JSON.stringify(i)} is not declared in layers[]`})}),r.mode==="enforced"){let i=r.compositionRoots;(!Array.isArray(i)||i.length===0)&&t.push({path:"$.arkRun.compositionRoots",message:"ARKRUN_MISSING_ROOT: enforced mode requires at least one composition root"}),(!Array.isArray(s)||s.length===0)&&t.push({path:"$.arkRun.managedLayers",message:"enforced mode requires at least one managed layer"})}}function yt(e){return e==="1.2"?null:e==="unversioned"?"unversioned":e==="1.0"||e==="1.1"?e:null}function ht(){let e=new Set(["1.2"]);for(let t of ee)t.from!=="unversioned"&&e.add(t.from),e.add(t.to);return e}function Rt(e,t="ark.config.json"){if(!D(e))throw new E(t,[{path:"$",message:`must be an object; received ${w(e)}`}]);let r=ht(),n=e.schemaVersion===void 0?"unversioned":typeof e.schemaVersion=="string"?e.schemaVersion:null;if(n===null)throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(e.schemaVersion)}; expected 1.2`}]);if(n!=="unversioned"&&!r.has(n))throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.2`}]);let s=n,i={...e},o=0;for(;s!=="1.2"&&o<ee.length+1;){o+=1;let a=ee.find(l=>l.from===s);if(!a)throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(s)}; expected 1.2`}]);s=a.to,i.schemaVersion=s}if(s!=="1.2")throw new E(t,[{path:"$.schemaVersion",message:`unsupported version ${JSON.stringify(n)}; expected 1.2`}]);return{candidate:gt(i),migratedFrom:yt(n)}}function At(e,t="ark.config.json"){let{candidate:r,migratedFrom:n}=Rt(e,t),s=[];if(O(r,Ee,"$",Ee,s),mt(r,s),s.length>0)throw new E(t,s);return{config:r,migratedFrom:n}}function xe(e,t="ark.config.json"){let r;try{r=JSON.parse(e)}catch(n){throw new E(t,[{path:"$",message:`invalid JSON: ${n instanceof Error?n.message:String(n)}`}])}return At(r,t)}var kt=/(^|\/)(constants|types|enums|shared-types|shared\/(?:types|constants)|test-projects)(\/|\.|$)|(?:^|\/)[^/]*(?:constants|types)(?:\.[cm]?[jt]sx?)?$/i,bt=/(^|\/)(?:kernel(?:\/|$)|events?(?:\/|\.|$)|bootstrap(?:\.[cm]?[jt]sx?)?$|emitter(?:\.[cm]?[jt]sx?)?$)|(?:^|\/)(?:intents?|publish)(?:\/|\.|$)/i,St=/(use-?cases?|usecases?|application|orchestrat|services?|handlers?)(\/|\.|$)/i;function Et(e,t){let r=String(e??"").replace(/\\/g,"/").trim(),n=String(t?.fromLayer??""),s=String(t?.toLayer??"");return kt.test(r)?"pure-shared":n==="PersistenceAdapters"&&(bt.test(r)||/events?|intents?|kernel|bootstrap/i.test(`${s} ${r}`))?"kernel-emit":St.test(r)||(n==="DomainModel"||n==="ApplicationOrchestration")&&s==="PersistenceAdapters"?"use-case":"unknown"}function It(e){if(e.typeOnly||e.targetTypeOnlyExports||e.namedBindingsTypeOnly)return"Move the referenced type to a mutually allowed layer, use `import type`, then preflight again.";if(e.peerIsolation)return"Extract the shared dependency to a shared layer, test at the public interface, then preflight again.";let t=Et(typeof e.target=="string"?e.target:"",{fromLayer:typeof e.fromLayer=="string"?e.fromLayer:void 0,toLayer:typeof e.toLayer=="string"?e.toLayer:void 0});return t==="pure-shared"?"Adopt the imported constants/types/pure module into DomainModel or SharedKernel (do not inject a port). Then preflight again.":t==="kernel-emit"?"Persistence must not emit. Inject a port or move the event map to SharedTypes; do not import kernel/events/bootstrap from a repository. Then preflight again.":t==="use-case"||e.portProofEligible?`Define a port in ${e.fromLayer??"the source layer"}, inject the ${e.toLayer??"outer-layer"} implementation, test at the public interface, then preflight again.`:"Classify the import: if it is constants/types/pure, adopt into DomainModel or SharedKernel; define a port only if the target is a real use-case. Then preflight again."}function xt(e){return typeof e.target=="string"&&e.target.trim().length>0?e.target.trim():void 0}function Nt(e){let t=xt(e),r=typeof e.fromLayer=="string"&&e.fromLayer.length>0?e.fromLayer:void 0;switch(e.ruleId){case"ARKRUN_MISSING_ROOT":return t?`Import createStrictArkKernel from @arkgate/runtime and call it in composition root ${t} listed in arkRun.compositionRoots, then preflight again.`:"Import createStrictArkKernel from @arkgate/runtime (never a removed arkgate/runtime shim) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe \u2014 factory placement is a design decision.";case"ARKRUN_KERNEL_IN_DOMAIN":return t?`Move the kernel import of ${t} out of ${r??"the Domain-role layer"} into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again.`:"Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again. Never mechanical-safe.";case"ARKRUN_DIRECT_NEW":return t?`Resolve ${t} from the kernel instead of constructing it with new, then preflight again.`:"Resolve the type from the kernel instead of constructing it with new, then preflight again. Never mechanical-safe \u2014 rewiring construction is a design decision.";case"ARKRUN_UNDECLARED_EMIT":return t?`Add ${t} to raises or sends on the managed component, then preflight again.`:"Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.";case"ARKRUN_UNDECLARED_HANDLE":return t?`Add ${t} to reactsTo on the managed component, then preflight again.`:"Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.";case"ARKRUN_UNDECLARED_DEPEND":return t?`Add ${t} to uses on the managed component, then preflight again.`:"Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.";case"ARKRUN_TRANSPORT_BYPASS":return t?`Send through the ArkRun kernel transport instead of importing ${t}, then preflight again.`:"Send through the ArkRun kernel transport instead of importing that broker or emitter, then preflight again. Never mechanical-safe \u2014 homemade buses stay judgment.";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 H(e){switch(e.ruleId){case"LAYER_IMPORT_VIOLATION":return It(e);case"FORBIDDEN_GLOBAL":return`Inject ${e.target??"the capability"} through a port, test at the public interface, then preflight again.`;case"CAPABILITY_VIOLATION":return`Define a ${String(e.capability??"capability")} port in ${e.fromLayer??"the walled layer"}, bind the implementation outside it, test at the public interface, then preflight again.`;case"CIRCULAR_DEPENDENCY":return"Extract the shared dependency into a third module, test at the public interface, 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.";case"ARKRULE_STRUCTURE":case"ARKRULE_INVARIANT":case"INVARIANT_UNCOVERED":return`Fix the structure or invariant for ${typeof e.arkruleId=="string"&&e.arkruleId.length>0?e.arkruleId:"the ArkRule"} (declared in ${typeof e.arkruleSource=="string"&&e.arkruleSource.length>0?e.arkruleSource:"arkrules/<Layer>.json"}), then preflight again. Do not demote the rule without a hash-bound policy acknowledgement.`;case"ARKRUN_MISSING_ROOT":case"ARKRUN_KERNEL_IN_DOMAIN":case"ARKRUN_DIRECT_NEW":case"ARKRUN_UNDECLARED_EMIT":case"ARKRUN_UNDECLARED_HANDLE":case"ARKRUN_UNDECLARED_DEPEND":case"ARKRUN_TRANSPORT_BYPASS":return Nt(e);default:return typeof e.ruleId=="string"&&e.ruleId.startsWith("ARKRULE_")?`Fix the ArkRule ${typeof e.arkruleId=="string"?e.arkruleId:e.ruleId}, then preflight again.`:`Resolve ${typeof e.ruleId=="string"&&e.ruleId.length>0?e.ruleId:"ARK_UNKNOWN"} without weakening ark.config.json, then run Ark again.`}}var Ct="docs/diagnostics.md";function y(e){return typeof e=="string"&&e.length>0?e:void 0}function Ne(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}function vt(e){let t=typeof e.ruleId=="string"?e.ruleId:typeof e.code=="string"?e.code:void 0,r=typeof e.file=="string"?e.file:void 0,n=typeof e.fromLayer=="string"?e.fromLayer:void 0,s=typeof e.toLayer=="string"?e.toLayer:void 0,i=typeof e.target=="string"?e.target:void 0;return[t,r,n??"",s??"",i??""].join("|")}function _t(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,16777619);return`fnv1a-${(t>>>0).toString(16).padStart(8,"0")}`}function wt(e){return`${Ct}#${e}`}function Lt(e,t,r){return H({ruleId:e,target:y(t.target)??y(r.target)??void 0,fromLayer:y(t.fromLayer)??void 0,toLayer:y(t.toLayer)??void 0,typeOnly:t.typeOnly===!0,targetTypeOnlyExports:t.targetTypeOnlyExports===!0,namedBindingsTypeOnly:t.namedBindingsTypeOnly===!0,portProofEligible:t.portProofEligible===!0,peerIsolation:t.peerIsolation===!0,sourcePureTypeModule:t.sourcePureTypeModule===!0,edgeKind:y(t.edgeKind)??void 0,capability:y(t.capability)??y(r.capability)??void 0,arkruleId:y(t.arkruleId)??void 0,arkruleSource:y(t.arkruleSource)??void 0})}function Ce(e,t="error",r){let n=y(e.ruleId)??y(e.code)??"ARK_UNKNOWN",s=e.severity==="warning"||e.failsStrict===!1||e.typeOnly===!0&&e.peerIsolation!==!0?"warning":t,i={...y(e.target)?{target:y(e.target)}:{},...y(e.fromLayer)?{fromLayer:y(e.fromLayer)}:{},...y(e.toLayer)?{toLayer:y(e.toLayer)}:{},...typeof e.typeOnly=="boolean"?{typeOnly:e.typeOnly}:{},...typeof e.targetTypeOnlyExports=="boolean"?{targetTypeOnlyExports:e.targetTypeOnlyExports}:{},...typeof e.sourcePureTypeModule=="boolean"?{sourcePureTypeModule:e.sourcePureTypeModule}:{},...typeof e.namedBindingsTypeOnly=="boolean"?{namedBindingsTypeOnly:e.namedBindingsTypeOnly}:{},...typeof e.portProofEligible=="boolean"?{portProofEligible:e.portProofEligible}:{},...typeof e.peerIsolation=="boolean"?{peerIsolation:e.peerIsolation}:{},...y(e.capability)?{capability:y(e.capability)}:{},...y(e.edgeKind)?{edgeKind:y(e.edgeKind)}:{},...y(e.arkruleId)?{arkruleId:y(e.arkruleId)}:{},...y(e.arkruleSource)?{arkruleSource:y(e.arkruleSource)}:{}},o=r??vt(e),a=_t(o);return{ruleId:n,severity:s,message:y(e.message)??n,location:{file:y(e.file)??"<unknown>",line:Ne(e.line,1),column:Ne(e.column,1)},evidence:i,nextAction:y(e.nextAction)??Lt(n,i,e),findingRef:a,targetKey:o,docsCodePath:wt(n)}}var ve={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."},Fr=Object.freeze([{layer:"DomainModel",prefixes:["Domain."]},{layer:"ApplicationOrchestration",prefixes:["Application."]},{layer:"PersistenceAdapters",prefixes:["Adapter.Persistence.","Adapter.Repository."]},{layer:"IntegrationAdapters",prefixes:["Adapter.Integration.","Adapter.External."]},{layer:"WorkflowSagaEngine",prefixes:["Workflow."]},{layer:"BackgroundJobsScheduling",prefixes:["Job."]},{layer:"PresentationAdapters",prefixes:["Presentation.","Adapter.Presentation.","Adapter.Api."]},{layer:"ReportingReadModels",prefixes:["Reporting."]},{layer:"ExtensibilityMetadata",prefixes:["Metadata."]},{layer:"SecurityAuditObservability",prefixes:["Security.","Audit.","Observability."]},{layer:"Kernel",prefixes:["Kernel."]}]);function Tt(e){return/^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\.[A-Za-z0-9_.]+$/.test(e)}function te(e){if(!e.publishCall)return[];let t=[];return(e.rawIntentName!==void 0&&Tt(e.rawIntentName)||e.objectHasIntent)&&t.push({ruleId:"RAW_EVENT_PUBLISH",message:ve.RAW_EVENT_PUBLISH}),e.arkPublishCandidate&&!e.hasSource&&t.push({ruleId:"PUBLISH_MISSING_SOURCE",message:ve.PUBLISH_MISSING_SOURCE}),t}import $e from"fs";import C from"path";var Ft=["createArkKernel","createStrictArkKernel","createArkKernelFromConfig","createStrictArkKernelFromConfig"];var Ot=new Set(Ft),Dt=new Set(["AggregateError","Array","ArrayBuffer","BigInt64Array","BigUint64Array","Boolean","DataView","Date","Error","EvalError","FinalizationRegistry","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Number","Object","Promise","Proxy","RangeError","ReferenceError","RegExp","Set","SharedArrayBuffer","String","Symbol","SyntaxError","TypeError","URIError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","WeakRef","WeakSet"]),Pt=new Set(["Array","Atomics","Buffer","JSON","Math","Number","Object","Promise","Reflect","String","console","fs","path","url","util"]);function L(e){return e==="@arkgate/runtime"||e.startsWith("@arkgate/runtime/")||e==="arkgate/runtime"||e.startsWith("arkgate/runtime/")}var Kt=["events","node:events","eventemitter2","eventemitter3","emittery","kafkajs","kafka-node","amqplib","amqp","bull","bullmq","mqtt","nats","@aws-sdk/client-sqs","@aws-sdk/client-sns","@aws-sdk/client-eventbridge","@google-cloud/pubsub","@azure/service-bus"],re=new Set(Kt);function Le(e){if(!e||e.startsWith(".")||e.startsWith("/"))return!1;if(re.has(e))return!0;let t=e.indexOf("/");if(t<0)return!1;let r=e.slice(0,t);if(re.has(r))return!0;let n=e.indexOf("/",t+1);return n<0?!1:re.has(e.slice(0,n))}function _e(e){if(Ot.has(e))return"factory";switch(e){case"publisher":return"publisher";case"publish":return"publish";case"raise":case"raiseAsync":return"raise";case"send":case"sendTo":return"send";case"subscribe":return"subscribe";case"registerHandler":return"register-handler";case"resolve":return"resolve";case"resolveSingleton":return"resolve-singleton";default:return}}function Te(e,t){let r=1;for(let n=0;n<t;n+=1)e.charCodeAt(n)===10&&(r+=1);return r}function ne(e){return e.replace(/\/\*[\s\S]*?\*\//g,t=>t.replace(/[^\n]/g," ")).replace(/(^|[^:\\])\/\/.*$/gm,t=>t.replace(/\/\/.*$/,r=>" ".repeat(r.length)))}function Mt(e,t){let r=e.slice(t),n=/^\s*(['"])((?:\\.|[^\\])*?)\1/.exec(r);if(!n)return;let s=n[2]??"";return s.length>0?s:void 0}function we(e,t,r){let n=Math.max(0,t-r.length-8),s=e.slice(n,t);return new RegExp(`\\b${r}\\s+$`).test(s)}function j(e,t){let r=/\b(?:import|export)(\s+type)?\s+([\s\S]*?)\s+from\s*['"]([^'"]+)['"]/g,n;for(;(n=r.exec(e))!==null;)n[1]||t(n[2]??"",n[3]??"")}function Fe(e,t){j(ne(e),t)}function $t(e){let t=new Map,r=new Set;return j(e,(n,s)=>{if(!L(s))return;let i=/\*\s+as\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(n);i?.[1]&&r.add(i[1]);let o=/^([A-Za-z_][A-Za-z0-9_]*)\s*(?:,|$)/.exec(n.trim());o?.[1]&&t.set(o[1],o[1]);let a=/\{([^}]*)\}/.exec(n);if(a?.[1])for(let l of a[1].split(",")){let d=l.trim();if(!d||d.startsWith("type "))continue;let u=/^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(d);if(u){t.set(u[2],u[1]);continue}let c=/^([A-Za-z_][A-Za-z0-9_]*)$/.exec(d);c?.[1]&&t.set(c[1],c[1])}}),{named:t,namespaces:r}}function Ut(e,t){let r=new Set(t);return j(e,(n,s)=>{let i=/\{([^}]*)\}/.exec(n);if(i?.[1])for(let o of i[1].split(",")){let a=o.trim();if(!a||a.startsWith("type "))continue;let l=/^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/.exec(a),d=l?.[2]??/^([A-Za-z_][A-Za-z0-9_]*)$/.exec(a)?.[1],u=l?.[1]??d;!d||!u||!/^[A-Z]/.test(u)||(L(s)||t.has(u)||t.has(d))&&(r.add(d),r.add(u))}}),r}function Ht(e,t){let r;return j(e,(n,s)=>{!r&&new RegExp(`\\b${t}\\b`).test(n)&&(r=s)}),r}function V(e,t){let r=ne(t),n=$t(r),s=[],i=/\b([A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/g,o;for(;(o=i.exec(r))!==null;){let a=o[1],l=o.index;if(we(r,l,"function")||we(r,l,"class"))continue;let u=r.slice(0,l).match(/([A-Za-z_][A-Za-z0-9_]*)\s*\.\s*$/)?.[1],c=n.named.get(a)??a,p=_e(c)??_e(a);if(!p)continue;let f=n.named.has(a)||u!==void 0&&n.namespaces.has(u);if(p!=="factory"&&(!f&&u===void 0||u&&Pt.has(u)&&!f))continue;let m=Mt(r,l+o[0].length);s.push({file:e,line:Te(t,l),kind:p,callee:a,viaImport:f,...u?{receiver:u}:{},...m?{nameLiteral:m}:{}})}return s}function se(e,t,r){let n=ne(t),s=Ut(n,r),i=[],o=/\bnew\s+(?:[A-Za-z_][A-Za-z0-9_]*\s*\.\s*)*([A-Z][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*\(/g,a;for(;(a=o.exec(n))!==null;){let l=a[1];if(Dt.has(l)||!s.has(l))continue;let d=Ht(n,l);i.push({file:e,line:Te(t,a.index),typeName:l,...d?{importedFrom:d}:{}})}return i}function oe(e,t){let r=[],n=/export\s+(?:abstract\s+)?class\s+([A-Za-z_][A-Za-z0-9_]*)\s*(?:extends\s+[^{]+)?(?:implements\s+[^{]+)?\{/g,s;for(;(s=n.exec(t))!==null;){let i=s[1],o=s.index+s[0].length,a=1,l=o;for(;l<t.length&&a>0;){let k=t[l];k==="{"?a+=1:k==="}"&&(a-=1),l+=1}let d=t.slice(o,l-1),u=d.split(`
`).map(k=>/^\s*\/\//.test(k)||/^\s*\/\*|\*\//.test(k)?k:k.replace(/(?:public\s+|protected\s+)?readonly\s+[a-zA-Z_][a-zA-Z0-9_]*\s*(?::[^=;]+)?(?:=\s*[^;]+)?[;,]?/g,"").replace(/(?:^|[\s;{])readonly\s+[a-zA-Z_][a-zA-Z0-9_]*\s*(?::[^=;]+)?(?:=\s*[^;]+)?[;,]?/g," ")).join(`
`),c=/(?:^|\n)\s*(?:public\s+)?[a-zA-Z_][a-zA-Z0-9_]*\s*[:=]/m.test(u.replace(/(?:public\s+|private\s+|protected\s+|static\s+|async\s+|get\s+|set\s+)/g,""))&&/(?:^|\n)\s*(public\s+)?(?!constructor|static|get|set|private|protected|readonly)[a-zA-Z_][a-zA-Z0-9_]*\s*[:=]/m.test(u),p=/(?:^|\n)\s*public\s+(?!static|async|get|set|constructor|readonly)[a-zA-Z_]/.test(u)||/(?:^|[\n;])\s*[a-zA-Z_][a-zA-Z0-9_]*\s*:\s*[^=;\n]+[;=]/m.test(u.split(`
`).filter(k=>!/^\s*(private|protected|static|constructor|get |set |async |\/)/.test(k)).join(`
`)),f=/(?:^|[\n;{])\s*(?:public\s+)?set\s+[a-zA-Z_]/.test(d),m=/(?:^|[\n;{])\s*private\s+constructor\s*\(/.test(d),h=/(?:^|[\n;{])\s*(?:public\s+)?constructor\s*\(/.test(d)&&!m,R=/(?:^|[\n;{])\s*static\s+(?:async\s+)?(?:create|of|from|parse|build|make|new)\s*[<(]/.test(d)||/(?:^|[\n;{])\s*static\s+(?:async\s+)?[A-Za-z_][A-Za-z0-9_]*\s*\([^)]*\)\s*:\s*[A-Za-z_]/.test(d),A=[],K=new Set(["if","match","when"]),M=/(?:^|\n)\s*(?:public\s+|private\s+|protected\s+|async\s+)*(?!constructor|get|set|static)([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*(?::\s*[^{]+)?\{/g,N;for(;(N=M.exec(d))!==null;){let k=N[1];if(K.has(k))continue;let de=N.index+N[0].length,Z=1,F=de;for(;F<d.length&&Z>0;)d[F]==="{"?Z+=1:d[F]==="}"&&(Z-=1),F+=1;let pe=d.slice(de,F-1);if(!/this\.\w+\s*=/.test(pe))continue;let et=/\b(ensureInvariants|assertInvariants|validate|publish|emit|raise|record)\b/.test(pe);A.push({name:k,referencesGuardOrPublish:et})}let Je=(d.match(/(?:^|\n)\s*(?:public\s+|private\s+|protected\s+)?(?:async\s+)?[a-zA-Z_][a-zA-Z0-9_]*\s*\(/g)??[]).length,Xe=(u.match(/(?:^|[\n;])\s*(?:public\s+)?(?!constructor|static|get|set|private|protected|readonly)[a-zA-Z_][a-zA-Z0-9_]*\s*[:=]/g)??[]).length,Qe=Je<=1&&Xe>=2&&(p||c);r.push({file:e,className:i,exported:!0,hasPublicMutableFields:p||c,hasPublicSetters:f,hasPublicConstructor:h,hasStaticFactory:R,mutatingMethods:[...A],dataOnly:Qe})}return r}function jt(e){if(!e)return{};let t=typeof e.governedPercent=="number"?e.governedPercent:null,r=typeof e.populatedLayerCount=="number"?e.populatedLayerCount:null;return r==null&&typeof e.classifiedFiles=="number"&&(r=e.classifiedFiles>0?1:0),{governedPercent:t,populatedLayerCount:r}}function Oe(e){let t=jt(e),r=typeof t.governedPercent=="number"?t.governedPercent:null,n=typeof t.populatedLayerCount=="number"?t.populatedLayerCount:null;return r==null&&n==null?!0:(r??0)>=50&&(n??0)>=1}var Vt=["arkrun-kernel-in-domain","arkrun-direct-new","arkrun-transport-bypass"],Bt=new Set(Vt);function Gt(e){return Bt.has(e)}var De={"arkrun-missing-root":"ARKRUN_MISSING_ROOT","arkrun-kernel-in-domain":"ARKRUN_KERNEL_IN_DOMAIN","arkrun-direct-new":"ARKRUN_DIRECT_NEW","arkrun-undeclared-emit":"ARKRUN_UNDECLARED_EMIT","arkrun-undeclared-handle":"ARKRUN_UNDECLARED_HANDLE","arkrun-undeclared-depend":"ARKRUN_UNDECLARED_DEPEND","arkrun-transport-bypass":"ARKRUN_TRANSPORT_BYPASS"},zt="ARKRUN_INTERACTION_NAME_INCOMPLETE";function Me(e,t=[]){let r=e.trim();return/^domain(?:model)?$/i.test(r)||/^domain(?=[A-Z_\-\s])/i.test(r)||/^(?:entit(?:y|ies)|aggregates?)(?:$|(?=[A-Z_\-\s]))/i.test(r)?!0:t.some(n=>{let s=n.trim().replace(/\.+$/,"");return s==="Domain"||s.startsWith("Domain.")})}function qt(e,t){return e.file.localeCompare(t.file)||e.ruleId.localeCompare(t.ruleId)||e.line-t.line||e.message.localeCompare(t.message)}function I(e,t,r,n,s,i,o){let a=e.mode==="enforced"&&o;return{ruleId:De[t],sensor:t,message:s,file:r,line:n,...i?.fromLayer?{fromLayer:i.fromLayer}:{},...i?.target?{target:i.target}:{},severity:a?"error":"warning",failsStrict:a,nextAction:H({ruleId:De[t],fromLayer:i?.fromLayer,target:i?.target})}}function Wt(e,t){let r=[],n=[],s=[],i=[];for(let o of e)o.file===t&&(r.push(...o.uses),n.push(...o.reactsTo),s.push(...o.raises),i.push(...o.sends));return{uses:new Set(r),reactsTo:new Set(n),raises:new Set(s),sends:new Set(i)}}function Pe(e){return e==="publisher"||e==="publish"||e==="raise"||e==="send"}function Ke(e){return e==="subscribe"||e==="register-handler"}function Zt(e){return e==="resolve"||e==="resolve-singleton"}function Yt(e,t,r){let n=[],s=e.compositionRoots;if(s.length===0)return n.push(I(e,"arkrun-missing-root","ark.config.json",1,"ArkRun compositionRoots is empty; no createArkKernel factory site is declared.",void 0,r)),n;let i=new Map;for(let o of t){let a=i.get(o.matchedRoot)??[];a.push(o),i.set(o.matchedRoot,a)}for(let o of s){let a=[...i.get(o)??[]].sort((d,u)=>d.file.localeCompare(u.file));if(a.length===0){n.push(I(e,"arkrun-missing-root","ark.config.json",1,`ArkRun composition root ${JSON.stringify(o)} matched no governed files and has no createArkKernel factory.`,{target:o},r));continue}if(a.some(d=>d.hasKernelFactory))continue;let l=a[0];n.push(I(e,"arkrun-missing-root",l.file,1,`ArkRun composition root ${JSON.stringify(o)} has no createArkKernel / createStrictArkKernel factory.`,{target:o},r))}return n}function Jt(e,t,r,n,s){let i=new Map(t.map(a=>[a.name,a.intentPrefixes??[]])),o=[];for(let a of r){let l=a.specifier;if(!l||!L(l))continue;let d=n(a.from);d&&Me(d,i.get(d)??[])&&o.push(I(e,"arkrun-kernel-in-domain",a.from,a.line,`${d} must not import kernel module ${JSON.stringify(l)}.`,{fromLayer:d,target:l},s))}return o}function Xt(e,t,r,n,s,i){let o=new Set(e.managedLayers);if(o.size===0)return[];let a=new Map(t.map(u=>[u.name,u.intentPrefixes??[]])),l=new Set(n.filter(u=>u.hasKernelFactory).map(u=>u.file)),d=[];for(let u of r){if(l.has(u.file))continue;let c=s(u.file);!c||!o.has(c)||Me(c,a.get(c)??[])||d.push(I(e,"arkrun-direct-new",u.file,u.line,`${c} must not construct ${u.typeName} with new outside an ArkRun composition-root factory.`,{fromLayer:c,target:u.typeName},i))}return d}function Qt(e,t,r,n,s){let i=[],o=[];if(e.requireDeclarations!==!0)return{findings:i,completenessReasons:o};let a=new Set(e.managedLayers);if(a.size===0)return{findings:i,completenessReasons:o};for(let l of t){if(!Pe(l.kind)&&!Ke(l.kind)&&!Zt(l.kind))continue;let d=n(l.file);if(!d||!a.has(d))continue;if(!l.nameLiteral){e.mode==="enforced"&&o.push({code:zt,file:l.file,message:`ArkRun ${l.kind} call in ${l.file} has no string-literal name; enforced extra cannot prove the declaration.`});continue}let u=Wt(r,l.file);if(Pe(l.kind)){if(u.raises.has(l.nameLiteral)||u.sends.has(l.nameLiteral))continue;i.push(I(e,"arkrun-undeclared-emit",l.file,l.line,`Emit ${JSON.stringify(l.nameLiteral)} is not declared in raises or sends.`,{fromLayer:d,target:l.nameLiteral},s));continue}if(Ke(l.kind)){if(u.reactsTo.has(l.nameLiteral))continue;i.push(I(e,"arkrun-undeclared-handle",l.file,l.line,`Handle ${JSON.stringify(l.nameLiteral)} is not declared in reactsTo.`,{fromLayer:d,target:l.nameLiteral},s));continue}u.uses.has(l.nameLiteral)||i.push(I(e,"arkrun-undeclared-depend",l.file,l.line,`Depend ${JSON.stringify(l.nameLiteral)} is not declared in uses.`,{fromLayer:d,target:l.nameLiteral},s))}return{findings:i,completenessReasons:o}}function er(e,t,r,n){let s=new Set(e.managedLayers);if(s.size===0)return[];let i=[];for(let o of t){if(o.typeOnly)continue;let a=o.specifier;if(!a||!Le(a))continue;let l=r(o.from);!l||!s.has(l)||i.push(I(e,"arkrun-transport-bypass",o.from,o.line,`${l} must not import broker/queue/emitter ${JSON.stringify(a)}; use the ArkRun kernel transport.`,{fromLayer:l,target:a},n))}return i}function tr(e){let t=e.arkRun;if(!t)return{findings:[],completenessReasons:[]};let r=Oe(e.classification),n=Qt(t,e.kernelCalls,e.declarations,e.layerForFile,r),s=[...Yt(t,e.compositionRootHits,r),...Jt(t,e.layers,e.dependencies,e.layerForFile,r),...Xt(t,e.layers,e.managedNews,e.compositionRootHits,e.layerForFile,r),...n.findings,...er(t,e.dependencies,e.layerForFile,r)].sort(qt),i=[...n.completenessReasons].sort((o,a)=>{let l=`${o.code}\0${o.file??""}\0${o.message}`,d=`${a.code}\0${a.file??""}\0${a.message}`;return l<d?-1:l>d?1:0});return{findings:s,completenessReasons:i}}function ie(e){return{findings:tr(e).findings.filter(r=>Gt(r.sensor)),completenessReasons:[]}}function rr(e){if(e.importKind==="type"||e.exportKind==="type")return!0;let t=e.specifiers??[];return t.length===0?!1:t.every(r=>r.type==="ImportSpecifier")?t.every(r=>r.importKind==="type"):t.every(r=>r.exportKind==="type")}function He(e){try{return $e.existsSync(e)?$e.readFileSync(e,"utf8"):null}catch{return null}}function Ue(e,t){let r=e.lintedFilename(t),n=e.findConfigPath(r),s=n?e.loadArkConfig(n):null;if(!s?.arkRun||!n||!r)return null;let i=C.dirname(n),o=C.isAbsolute(r)?r:C.resolve(r),a=C.relative(i,o).split(C.sep).join("/");if(!e.sourceIsInAnalysisScope(s,a))return null;let l=S(a,s.layers);return l?{extra:s.arkRun,config:s,root:i,absFile:o,relFile:a,fromLayer:l}:null}function nr(e,t,r){let n=V(t,r).some(i=>i.kind==="factory"),s=[];for(let i of e.compositionRoots){try{if(!_(i).test(t))continue}catch{continue}s.push({file:t,matchedRoot:i,hasKernelFactory:n})}return s}function sr(e,t,r){let n=new Set(oe(t.relFile,r).map(s=>s.className));return Fe(r,(s,i)=>{if(L(i))return;let o=e.resolveImportSpecifier(t.absFile,i,t.root);if(!o)return;let a=C.relative(t.root,o).split(C.sep).join("/");if(a.startsWith(".."))return;let l=He(o);if(l!==null)for(let d of oe(a,l))n.add(d.className)}),n}function je(e,t,r,n,s,i){e.reportAdapterDiagnostic(t,r,n,{ruleId:s.ruleId,file:s.file,fromLayer:s.fromLayer,target:s.target,message:s.message,line:s.line,severity:s.severity,failsStrict:s.failsStrict,nextAction:s.nextAction},i)}function or(e){let t=e.callee;if(t?.type==="Identifier"&&t.name&&/^[A-Z]/.test(t.name))return t.name;let r=t?.property?.name;if(r&&/^[A-Z]/.test(r)&&t?.computed!==!0)return r}function ir(e,t){return e.type?.startsWith("Export")?"export":t}function ar(e,t,r,n,s){let i=(o,a,l,d)=>{if(typeof a!="string"||a.length===0)return;let u=o.loc?.start?.line??1,c={from:r.relFile,specifier:a,kind:d,typeOnly:l,line:u,resolution:"resolved-external"},{findings:p}=ie({arkRun:r.extra,layers:r.config.layers,kernelCalls:[],managedNews:[],compositionRootHits:[],declarations:[],dependencies:[c],layerForFile:f=>f===r.relFile?r.fromLayer:S(f,r.config.layers)});for(let f of p)f.sensor===n&&je(e,t,o,s,f,{fromLayer:f.fromLayer??r.fromLayer,specifier:a,target:f.target??a})};return{ImportDeclaration(o){let a=o,l=(a.specifiers??[]).filter(u=>u.type==="ImportSpecifier"),d=l.length>0&&l.length===(a.specifiers??[]).length&&l.every(u=>u.importKind==="type");i(o,a.source?.value,a.importKind==="type"||d||rr(o),"import")},ImportExpression(o){let a=o;a.source?.type==="Literal"&&i(o,a.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(o){let a=o;i(o,a.moduleReference?.expression?.value,a.importKind==="type"||a.isTypeOnly===!0,"require")},ExportNamedDeclaration(o){let a=o;if(!a.source)return;let l=a.specifiers??[],d=l.length>0&&l.every(u=>u.exportKind==="type");i(o,a.source.value,a.exportKind==="type"||d,ir(o,"export"))},ExportAllDeclaration(o){let a=o;i(o,a.source?.value,a.exportKind==="type","export")},CallExpression(o){let a=o;a.callee?.type==="Identifier"&&a.callee.name==="require"&&a.arguments?.[0]?.type==="Literal"&&!e.isLocallyBound(t,o,"require")&&i(o,a.arguments[0].value,!1,"require")}}}function lr(e,t,r){let n=He(r.absFile)??"",s=sr(e,r,n),i=se(r.relFile,n,s),{findings:o}=ie({arkRun:r.extra,layers:r.config.layers,kernelCalls:V(r.relFile,n),managedNews:i,compositionRootHits:nr(r.extra,r.relFile,n),declarations:[],dependencies:[],layerForFile:l=>l===r.relFile?r.fromLayer:S(l,r.config.layers)}),a=o.filter(l=>l.sensor==="arkrun-direct-new");return{NewExpression(l){let d=or(l);if(!d)return;let u=l.loc?.start?.line,c=a.find(p=>p.target===d&&(u===void 0||p.line===u))??a.find(p=>p.target===d);c&&je(e,t,l,"directNew",c,{fromLayer:c.fromLayer??r.fromLayer,typeName:d,target:c.target??d})}}}function Ve(e){let t=(r,n,s,i)=>({meta:{type:"problem",docs:{description:n},messages:{[s]:i},schema:[]},create(o){let a=Ue(e,o);return a?ar(e,o,a,r,s):{}}});return{noArkRunKernelInDomain:t("arkrun-kernel-in-domain","Disallow Domain-role imports of @arkgate/runtime when arkRun is on (same sensor as ark-check).","kernelInDomain",'{{fromLayer}} must not import kernel module "{{specifier}}".'),noArkRunTransportBypass:t("arkrun-transport-bypass","Disallow homemade broker/queue/emitter imports in arkRun managed layers (same sensor as ark-check).","transportBypass",'{{fromLayer}} must not import broker/queue/emitter "{{specifier}}"; use the ArkRun kernel transport.'),noArkRunDirectNew:{meta:{type:"problem",docs:{description:"Disallow `new` of ArkRun-admitted types outside a composition-root factory (on-disk import/`new` envelope)."},messages:{directNew:"{{fromLayer}} must not construct {{typeName}} with new outside an ArkRun composition-root factory."},schema:[]},create(r){let n=Ue(e,r);return n?lr(e,r,n):{}}}}}function T(e){if(typeof e.physicalFilename=="string"&&e.physicalFilename.length>0)return e.physicalFilename;if(typeof e.filename=="string"&&e.filename.length>0)return e.filename;if(typeof e.getFilename=="function")try{let t=e.getFilename();if(typeof t=="string"&&t.length>0)return t}catch{}return""}function v(e,t,r,n,s){let i=Ce({...n,line:n.line??t.loc?.start?.line,column:n.column??(typeof t.loc?.start?.column=="number"?t.loc.start.column+1:void 0)});return e.report({node:t,messageId:r,...s?{data:s}:{},diagnostic:i}),i}function G(e){if(!e||e==="<input>"||e.startsWith("stdin"))return null;let t=g.dirname(g.resolve(e));for(;;){let r=g.join(t,"ark.config.json");if(x.existsSync(r))return r;let n=g.dirname(t);if(n===t)return null;t=n}}var Be=new Map;function z(e){if(!x.existsSync(e))return null;let t=x.readFileSync(e,"utf8"),r=Be.get(e);if(r?.source===t)return r.config;let n=xe(t,e).config;return Be.set(e,{source:t,config:n}),n}function q(e,t){return(e.include??[]).some(n=>{let s=String(n).replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/$/,"");return s==="."||t===s||t.startsWith(`${s}/`)})&&!Re(t,e)}function Ge(e){let t=[e,`${e}.ts`,`${e}.tsx`,`${e}.mts`,`${e}.cts`,`${e}.js`,`${e}.jsx`,g.join(e,"index.ts"),g.join(e,"index.tsx"),g.join(e,"index.js")];for(let r of t)try{if(x.existsSync(r)&&x.statSync(r).isFile())return r}catch{}return null}function cr(e){let t=g.resolve(e),r=null;for(;;){let d=g.join(t,"tsconfig.json");if(x.existsSync(d)){r=d;break}let u=g.dirname(t);if(u===t)break;t=u}if(!r)return{baseUrl:e,aliases:[]};let n=d=>{try{let u=x.readFileSync(d,"utf8");return u=u.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1"),JSON.parse(u)}catch{return null}},s=(d,u)=>{if(u>4)return{};let c=n(d);if(!c)return{};let p=c.compilerOptions??{},f=p.baseUrl,m=p.paths,h=c.extends;if(typeof h=="string"&&!h.startsWith("@")){let R=g.resolve(g.dirname(d),h.endsWith(".json")?h:`${h}.json`);if(x.existsSync(R)){let A=s(R,u+1);f=f??A.baseUrl,m={...A.paths??{},...m??{}}}}return{baseUrl:f,paths:m}},i=s(r,0),o=g.dirname(r),a=g.resolve(o,i.baseUrl||"."),l=[];for(let[d,u]of Object.entries(i.paths||{})){if(!Array.isArray(u)||u.length===0)continue;let c=d.replace(/\*$/,"");c&&l.push({from:c,to:String(u[0]).replace(/\*$/,"")})}return l.sort((d,u)=>u.from.length-d.from.length),{baseUrl:a,aliases:l}}function ur(e,t){if(!t.startsWith("."))return null;let r=g.resolve(g.dirname(e),t);return Ge(r)}function ze(e,t,r){if(!t)return null;if(t.startsWith("."))return ur(e,t);let n=r||g.dirname(e),{baseUrl:s,aliases:i}=cr(n),o=i.find(l=>t.startsWith(l.from));if(!o)return null;let a=g.resolve(s,`${o.to}${t.slice(o.from.length)}`);return Ge(a)}function W(e){return typeof e?.value=="string"?e.value:void 0}function ce(e){return e?.name??W(e)}function ue(e){return e.sourceCode??e.getSourceCode?.()}function qe(e,t){let r=ue(e)?.getScope?.(t);for(;r;){let n=r.references?.find(s=>s.identifier===t);if(n)return n;r=r.upper??void 0}}function P(e,t,r){let n=qe(e,t);if(n?.resolved)return(n.resolved.defs?.length??0)>0;let s=ue(e)?.getScope?.(t);for(;s;){let i=s.set?.get(r);if(i)return(i.defs?.length??0)>0;s=s.upper??void 0}return!1}function dr(e,t){let r=qe(e,t);return r?r.isValueReference!==!1:t.parent?.type==="VariableDeclarator"&&t.parent.init===t}function We(e){if(e?.type==="Identifier"&&e.name)return{root:e,segments:[e.name]};if(!e||!(e.type==="MemberExpression"||!!(e.object&&e.property))||e.computed===!0)return;let r=We(e.object),n=ce(e.property);if(!(!r||!n))return{root:r.root,segments:[...r.segments,n]}}function pr(e){return ce(e.callee?.property)}function Ze(e,t){return e?.properties?.find(r=>ce(r.key)===t)}function B(e,t){return Ze(e,t)!==void 0}function fr(e){let t=Ze(e,"metadata")?.value;return B(t,"source")}function Ye(e){return pr(e)==="publish"}function ae(e){if(e.importKind==="type"||e.exportKind==="type")return!0;let t=e.specifiers??[];return t.length===0?!1:t.every(r=>r.type==="ImportSpecifier")?t.every(r=>r.importKind==="type"):t.every(r=>r.exportKind==="type")}function gr(e){let t=e;for(;t?.parent;)t=t.parent;return t?.type==="Program"?t:void 0}function mr(e){let t=gr(e)?.body;if(!t)return!1;let r=!1;for(let n of t){if(n.type==="ImportDeclaration"){if(!ae(n))return!1;continue}if(!(n.type==="TSInterfaceDeclaration"||n.type==="TSTypeAliasDeclaration")){if(n.type==="ExportNamedDeclaration"){if(n.declaration){if(n.declaration.type!=="TSInterfaceDeclaration"&&n.declaration.type!=="TSTypeAliasDeclaration")return!1}else if(!ae(n))return!1;r=!0;continue}return!1}}return r}var yr={meta:{type:"problem",docs:{description:"Disallow imports that violate ark.config.json layer rules (same contract as arkgate-check)."},messages:{forbiddenImport:"Architecture: {{fromLayer}} must not import {{toLayer}} (ark.config.json). Specifier: {{specifier}}",forbiddenImportHeuristic:"Domain code must not import infrastructure, adapters, repositories, or database modules."},schema:[]},create(e){let t=T(e),r=G(t),n=r?z(r):null,s=r?g.dirname(r):null,i=o=>{let a=W(o.source);if(a&&n&&s&&t){let l=g.isAbsolute(t)?t:g.resolve(t),d=g.relative(s,l).split(g.sep).join("/");if(!q(n,d))return;let u=S(d,n.layers);if(!u)return;let c=ze(l,a,s);if(!c)return;let p=g.relative(s,c).split(g.sep).join("/");if(p.startsWith(".."))return;let f=S(p,n.layers);if(!f)return;let m={fromPath:d,toPath:p,layers:n.layers},h=Y(n.rules,u,f,m);if(h||he(n.rules,u,f,m)){let R=o.type?.startsWith("Export")?"export":"import",A=ae(o),K=!!h?.peerIsolation,M=A&&!K,N=h?.message??`${u} must not ${R} ${f}.`;v(e,o,"forbiddenImport",{ruleId:"LAYER_IMPORT_VIOLATION",file:d,fromLayer:u,toLayer:f,target:p,edgeKind:R,...K?{peerIsolation:!0}:{},...A?{typeOnly:!0}:{},...M?{severity:"warning"}:{},...mr(o)?{sourcePureTypeModule:!0}:{},message:M?`${N} (type-only \u2014 type placement debt; prefer SharedTypes / owning layer; not runtime coupling)`:N},{fromLayer:u,toLayer:f,specifier:a})}return}};return{ImportDeclaration:i,ExportNamedDeclaration:i,ExportAllDeclaration:i}}},hr={meta:{type:"problem",docs:{description:"Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings."},messages:{rawPublish:"Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=W(r),s=te({publishCall:Ye(t),rawIntentName:n,objectHasIntent:B(r,"intent"),arkPublishCandidate:!1,hasSource:!0});if(s.some(i=>i.ruleId==="RAW_EVENT_PUBLISH")){let i=s.find(o=>o.ruleId==="RAW_EVENT_PUBLISH");v(e,t,"rawPublish",{...i,file:T(e)})}}}}},Rr={meta:{type:"problem",docs:{description:"Require event bus publish calls to include source metadata."},messages:{missingSource:"Strict Ark publish calls must include metadata.source."},schema:[]},create(e){return{CallExpression(t){let r=t.arguments?.[0],n=t.arguments?.[2],i=te({publishCall:Ye(t),rawIntentName:W(r),objectHasIntent:B(r,"intent"),arkPublishCandidate:!0,hasSource:fr(r)||B(n,"source")}).find(o=>o.ruleId==="PUBLISH_MISSING_SOURCE");i&&v(e,t,"missingSource",{...i,file:T(e)})}}}},Ar={meta:{type:"problem",docs:{description:"Disallow ambient globals from the layer\u2019s forbiddenGlobals in ark.config.json (same purity surface as ark-check). Option `globals` is a standalone fallback when no project config applies."},messages:{forbiddenGlobal:'Ambient global "{{name}}" is forbidden in {{layer}} (ark.config.json); inject the capability through a port instead.',forbiddenGlobalDefault:'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.',forbiddenModule:'{{layer}} must not use module "{{specifier}}" because it is the import form of forbidden global "{{name}}".'},schema:[{type:"object",properties:{globals:{type:"array",items:{type:"string"}}},additionalProperties:!1}]},create(e){let t=T(e),r=e.options?.[0],n=G(t),s=n?z(n):null,i=n?g.dirname(n):null,o=null,a="this layer";if(s&&i&&t){let c=g.isAbsolute(t)?t:g.resolve(t),p=g.relative(i,c).split(g.sep).join("/");if(!q(s,p))return{};let f=s.layers?.find(m=>m.name===S(p,s.layers));f?.forbiddenGlobals?.length?(o=new Set(f.forbiddenGlobals),a=f.name):o=null}else r?.globals&&(o=new Set(r.globals));if(!o)return{};let l=typeof ue(e)?.getScope=="function",d=(c,p)=>{let f=g.isAbsolute(t)?t:g.resolve(t),m=i?g.relative(i,f).split(g.sep).join("/"):t;v(e,c,s?"forbiddenGlobal":"forbiddenGlobalDefault",{ruleId:"FORBIDDEN_GLOBAL",file:m,fromLayer:a,target:p,message:`${a} must not use the ambient global "${p}".`},{name:p,layer:a})},u=(c,p,f,m)=>{if(f||typeof p!="string")return;let h=X(p,o);if(!h)return;let R=g.isAbsolute(t)?t:g.resolve(t),A=i?g.relative(i,R).split(g.sep).join("/"):t;v(e,c,"forbiddenModule",{ruleId:"FORBIDDEN_GLOBAL",file:A,fromLayer:a,target:p,edgeKind:m,message:`${a} must not use module "${p}" because it is the import form of forbidden global "${h}".`},{layer:a,name:h,specifier:p,importKind:m})};return{MemberExpression(c){if(c.parent?.type==="MemberExpression"&&c.parent.object===c)return;let p=We(c);if(!p||P(e,p.root,p.segments[0]))return;let f=p.segments[0]==="globalThis",m=f?p.segments.slice(1):p.segments,h;for(let R=m.length;R>=(f?1:2);R-=1){let A=m.slice(0,R).join(".");if(o.has(A)){h=A;break}}h?d(c,h):!l&&o.has(p.segments[0])&&d(c,p.segments[0])},CallExpression(c){let p=c;if(p.callee?.type==="Identifier"&&p.callee.name==="require"&&p.arguments?.[0]?.type==="Literal"&&!P(e,c,"require")&&u(c,p.arguments[0].value,!1,"require"),l)return;let f=p.callee?.type==="Identifier"?p.callee.name:void 0;f&&o.has(f)&&d(c,f)},ImportDeclaration(c){let p=c,f=(p.specifiers??[]).filter(h=>h.type==="ImportSpecifier"),m=f.length>0&&f.length===(p.specifiers??[]).length&&f.every(h=>h.importKind==="type");u(c,p.source?.value,p.importKind==="type"||m,"import")},ImportExpression(c){let p=c;p.source?.type==="Literal"&&u(c,p.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(c){let p=c;u(c,p.moduleReference?.expression?.value,p.importKind==="type"||p.isTypeOnly===!0,"require")},ExportNamedDeclaration(c){let p=c;if(!p.source)return;let f=p.specifiers??[],m=f.length>0&&f.every(h=>h.exportKind==="type");u(c,p.source.value,p.exportKind==="type"||m,"export")},ExportAllDeclaration(c){let p=c;u(c,p.source?.value,p.exportKind==="type","export")},NewExpression(c){if(l)return;let p=c.callee?.type==="Identifier"?c.callee.name:void 0;p&&o.has(p)&&d(c,p)},Identifier(c){!l||!c.name||!o.has(c.name)||!dr(e,c)||P(e,c,c.name)||d(c,c.name)}}}},kr={meta:{type:"problem",docs:{description:"Disallow importing modules whose effect capability the layer denies (ark.config.json capabilities.deny / pure \u2014 same wall surface as ark-check). Import dimension only: ambient globals stay with no-forbidden-globals and the CLI/hook symbol path."},messages:{deniedCapability:'{{layer}} denies the {{capability}} capability (ark.config.json); "{{specifier}}" imports it. Define a port and bind the implementation in an adapter layer.'},schema:[]},create(e){let t=T(e),r=G(t),n=r?z(r):null,s=r?g.dirname(r):null;if(!n||!s||!t)return{};let i=g.isAbsolute(t)?t:g.resolve(t),o=g.relative(s,i).split(g.sep).join("/");if(!q(n,o))return{};let a=n.layers?.find(u=>u.name===S(o,n.layers));if(!a)return{};let l=new Set(be(a));if(l.size===0)return{};let d=(u,c,p,f)=>{if(p||typeof c!="string"||X(c,a.forbiddenGlobals??[]))return;let m=ke(c);!m||!l.has(m)||v(e,u,"deniedCapability",{ruleId:"CAPABILITY_VIOLATION",file:o,fromLayer:a.name,target:c,capability:m,edgeKind:f,message:`${a.name} denies the ${m} capability; found import of "${c}".`},{layer:a.name,capability:m,specifier:c})};return{ImportDeclaration(u){let c=u,p=(c.specifiers??[]).filter(m=>m.type==="ImportSpecifier"),f=p.length>0&&p.length===(c.specifiers??[]).length&&p.every(m=>m.importKind==="type");d(u,c.source?.value,c.importKind==="type"||f,"import")},ImportExpression(u){let c=u;c.source?.type==="Literal"&&d(u,c.source.value,!1,"dynamic-import")},TSImportEqualsDeclaration(u){let c=u;d(u,c.moduleReference?.expression?.value,c.importKind==="type"||c.isTypeOnly===!0,"require")},ExportNamedDeclaration(u){let c=u;if(!c.source)return;let p=c.specifiers??[],f=p.length>0&&p.every(m=>m.exportKind==="type");d(u,c.source.value,c.exportKind==="type"||f,"export")},ExportAllDeclaration(u){let c=u;d(u,c.source?.value,c.exportKind==="type","export")},CallExpression(u){let c=u;c.callee?.type==="Identifier"&&c.callee.name==="require"&&c.arguments?.[0]?.type==="Literal"&&!P(e,u,"require")&&d(u,c.arguments[0].value,!1,"require")}}}},{noArkRunKernelInDomain:br,noArkRunDirectNew:Sr,noArkRunTransportBypass:Er}=Ve({findConfigPath:G,loadArkConfig:z,resolveImportSpecifier:ze,lintedFilename:T,sourceIsInAnalysisScope:q,isLocallyBound:P,reportAdapterDiagnostic:v});var Ir={"no-domain-infra-imports":yr,"no-raw-event-publish":hr,"require-publish-source":Rr,"no-forbidden-globals":Ar,"no-denied-capabilities":kr,"no-arkrun-kernel-in-domain":br,"no-arkrun-direct-new":Sr,"no-arkrun-transport-bypass":Er},le={rules:Ir};le.configs={recommended:{plugins:{ark:le},rules:{"ark/no-domain-infra-imports":"error","ark/no-raw-event-publish":"error","ark/require-publish-source":"error","ark/no-forbidden-globals":"error","ark/no-denied-capabilities":"error","ark/no-arkrun-kernel-in-domain":"error","ark/no-arkrun-direct-new":"error","ark/no-arkrun-transport-bypass":"error"}}};var an=le;export{an as default,G as findConfigPath,_ as globToRegExp,he as isEdgeDenied,S as layerForRelativePath,z as loadArkConfig,Sr as noArkRunDirectNew,br as noArkRunKernelInDomain,Er as noArkRunTransportBypass,kr as noDeniedCapabilities,yr as noDomainInfraImports,Ar as noForbiddenGlobals,hr as noRawEventPublish,ye as patternSpecificity,le as plugin,cr as readTsconfigPathAliases,Rr as requirePublishSource,ze as resolveImportSpecifier,ur as resolveRelativeImport};

@@ -690,2 +690,4 @@ # Gating AI Agents with ArkGate

// ark/no-denied-capabilities → layer.capabilities.deny / layer.pure
// ark/no-arkrun-kernel-in-domain + no-arkrun-direct-new + no-arkrun-transport-bypass
// → arkRun extra (silent when absent; import / `new` envelope only)
// no-raw-event-publish + require-publish-source → runtime event hygiene

@@ -718,2 +720,13 @@ ];

- Without `ark.config.json`, `no-domain-infra-imports` emits no contract verdict.
- **ArkRun (RN06):** when `arkRun` is present, `no-arkrun-kernel-in-domain`,
`no-arkrun-direct-new`, and `no-arkrun-transport-bypass` reuse the same
`ARKRUN_*` sensors as ark-check. Envelope is the current file: package
specifiers (kernel / closed broker list), `require` / export / dynamic-literal
of those specifiers, and `new` of constructors admitted from this file's
exported classes, `@arkgate/runtime` PascalCase imports, or on-disk
relative/alias import targets. Absence of the extra is silent. Composition-root
factory files skip `direct-new`. Domain-role layers skip `direct-new` and flag
kernel imports (including type-only). Type-only broker imports do not flag
transport-bypass. Missing-root and undeclared emit/handle/depend are **not**
in this adapter — use CLI / preflight / CI.

@@ -720,0 +733,0 @@ Rule ids are `ark/<kebab-name>`. Individual rules are also on `ark.rules` if you wire them by hand.

@@ -13,3 +13,3 @@ # Versioned `ark.config.json`

"$schema": "https://unpkg.com/arkgate@2/schemas/ark.config.schema.json",
"schemaVersion": "1.1",
"schemaVersion": "1.2",
"include": ["src"],

@@ -23,5 +23,7 @@ "layers": [],

independent from the npm package version. Schema **`1.1`** is additive over `1.0` and adds the
optional top-level **`arkRules`** map (ADR 0012). Absence of `arkRules` changes no inter-layer
verdict. Per-layer structure/invariant files use sibling schema
`arkgate/schema/arkrules` (`schemas/ark.arkrules.schema.json`).
optional top-level **`arkRules`** map (ADR 0012). Schema **`1.2`** is additive over `1.1` and
adds the optional top-level **`arkRun`** extra (ADR 0020). Absence of `arkRules` or `arkRun`
changes no Layers / ArkRules verdict. Per-layer structure/invariant files use sibling schema
`arkgate/schema/arkrules` (`schemas/ark.arkrules.schema.json`). ArkRun v1 stays **inline**
(no sibling file).

@@ -44,3 +46,3 @@ For offline editor completion, point `$schema` at the installed file instead:

Configs without `schemaVersion` are the legacy shape shipped through ArkGate 1.x and early 2.x.
The loader deterministically projects them through `unversioned → 1.0 → 1.1` in memory by adding
The loader deterministically projects them through `unversioned → 1.0 → 1.1 → 1.2` in memory by adding
contract metadata and the established defaults. It never rewrites the user's file during a check.

@@ -91,2 +93,11 @@ Newly generated

layer. Missing/invalid referenced files **fail closed**.
- **`arkRun`** (optional, schema `1.2+`) — inline ArkRun extra (`mode`, `compositionRoots`,
`managedLayers`, `requireDeclarations`). Absence is silent. Unknown keys fail closed.
`managedLayers` must name existing `layers[].name` values. Empty `compositionRoots` in
`enforced` mode fails closed (`ARKRUN_MISSING_ROOT`); empty `managedLayers` in `enforced`
mode also fails closed (direct-new / undeclared / transport-bypass would otherwise no-op).
Compact starters do not enable this extra. Demotion (`enforced` → `advisory`) or deletion
is a policy-delta **weakening**. Enforced extra teeth share the CLI / MCP / hook /
preflight / CI verdict and arm only when the layer plane is classified (same ≥50%
governed and ≥1 populated-layer floor as ArkRules).

@@ -149,10 +160,12 @@ Layer fields:

| **Invariants** | Catalog + coverage evidence (not a business runtime) | Only enforced + proven-uncovered |
| **ArkRun** (opt-in extra) | Kernel usage + complete declarations | Only `arkRun.mode: "enforced"` when classified |
Absence of `arkRules` adds **no** extra merge teeth. **Advisory** structure sensors and advisory
invariants also add **no** merge teeth (FG-ARKRULES-ADVISORY-ONLY) — packing every starter
`arkrules/*` file does not make merge fail structure alone. Enforced structure/invariants arm
Absence of `arkRules` or `arkRun` adds **no** extra merge teeth. **Advisory** structure sensors, advisory
invariants, and advisory ArkRun also add **no** merge teeth (FG-ARKRULES-ADVISORY-ONLY / ADR 0020) — packing every starter
`arkrules/*` file does not make merge fail structure alone. Enforced structure/invariants/ArkRun arm
`mergePlanes.extraMergeTeeth` only when the layer plane is honestly classified
(governed ≥ 50% and ≥ 1 populated layer); empty classification never gets structure teeth
(P1M-EXTRATEETH-EMPTY-GRAPH). Structure and invariants **never** merge into one architecture
score. Doctor exposes `rulesUnderContract.mergePlanes` for which plane can fail.
(governed ≥ 50% and ≥ 1 populated layer); empty classification never gets extra-plane teeth
(P1M-EXTRATEETH-EMPTY-GRAPH). Extra planes **never** merge into one architecture
score. Doctor exposes `rulesUnderContract.mergePlanes` (including `mergePlanes.arkRun`) for which plane can fail,
and a dedicated `doctor.arkRun` section that is always `notAScore`.

@@ -159,0 +172,0 @@ Safety fields:

@@ -158,6 +158,15 @@ # Develop with ArkGate

## Optional experimental runtime
## Optional ArkRun extra and kernel
Gates need **no** runtime kernel. `@arkgate/runtime` is experimental, separate package, not the day-zero product. See [package-surface.md](package-surface.md) and [production-hardening.md](production-hardening.md).
Gates need **no** runtime kernel. Optional **`arkRun`** on `ark.config.json` (schema `1.2`)
is a *gate* extra: kernel usage + complete declarations on the same write/CI plane as
Layers and ArkRules. Absence is silent. Compact starters leave it off.
The companion **ArkRun** kernel (`@arkgate/runtime`) is experimental, a separate package,
and not the day-zero product. `createStrictArkKernel` is the factory (per instance; no
process-wide singleton). The kernel is not bundled in the `arkgate` tarball. Built-in
stores are in-memory **reference only** — not production durability; `K01` stays parked.
See [configuration.md](configuration.md), [package-surface.md](package-surface.md), and
[production-hardening.md](production-hardening.md).
---

@@ -164,0 +173,0 @@

@@ -47,2 +47,9 @@ # ArkGate diagnostic code catalog

| [`INVARIANT_UNCOVERED`](#INVARIANT_UNCOVERED) | arkrules | Invariant without coverage evidence |
| [`ARKRUN_MISSING_ROOT`](#ARKRUN_MISSING_ROOT) | arkrun | No kernel factory in composition roots |
| [`ARKRUN_KERNEL_IN_DOMAIN`](#ARKRUN_KERNEL_IN_DOMAIN) | arkrun | Domain-role layer imports the kernel |
| [`ARKRUN_DIRECT_NEW`](#ARKRUN_DIRECT_NEW) | arkrun | Managed type constructed with new |
| [`ARKRUN_UNDECLARED_EMIT`](#ARKRUN_UNDECLARED_EMIT) | arkrun | Emit name not in raises/sends |
| [`ARKRUN_UNDECLARED_HANDLE`](#ARKRUN_UNDECLARED_HANDLE) | arkrun | Handle name not in reactsTo |
| [`ARKRUN_UNDECLARED_DEPEND`](#ARKRUN_UNDECLARED_DEPEND) | arkrun | Depend name not in uses |
| [`ARKRUN_TRANSPORT_BYPASS`](#ARKRUN_TRANSPORT_BYPASS) | arkrun | Homemade broker or emitter import |
| [`INVALID_CHANGE_PATH`](#INVALID_CHANGE_PATH) | preflight | Unsafe change path |

@@ -275,2 +282,70 @@ | [`DUPLICATE_CHANGE_PATH`](#DUPLICATE_CHANGE_PATH) | preflight | Duplicate path in change set |

## ArkRun (opt-in extra)
Live adapters specialize `nextAction` with the call-site name or specifier when present
(casual `enthusiastHint` + engineer `nextAction`). Catalog **Fix** is the stable no-target form.
<a id="ARKRUN_MISSING_ROOT"></a>
### `ARKRUN_MISSING_ROOT`
**No kernel factory in composition roots**
- **Why:** The ArkRun extra is on but no createArkKernel / createStrictArkKernel / createArkKernelFromConfig / createStrictArkKernelFromConfig factory was found in arkRun.compositionRoots, so agents can skip the kernel while the write gate stays green.
- **Fix:** Import createStrictArkKernel from @arkgate/runtime (never a removed arkgate/runtime shim) and call it in a composition root listed in arkRun.compositionRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.
<a id="ARKRUN_KERNEL_IN_DOMAIN"></a>
### `ARKRUN_KERNEL_IN_DOMAIN`
**Domain-role layer imports the kernel**
- **Why:** A Domain-role layer imports @arkgate/runtime or kernel types. Domain stays kernel-free; composition roots and adapters own the factory.
- **Fix:** Move the kernel import out of the Domain-role layer into a composition root or adapter. Import from @arkgate/runtime, never a removed arkgate/runtime shim, then preflight again. Never mechanical-safe.
<a id="ARKRUN_DIRECT_NEW"></a>
### `ARKRUN_DIRECT_NEW`
**Managed type constructed with new**
- **Why:** A managed non-Domain file constructs an admitted type with new outside an ArkRun composition-root factory, skipping kernel resolve/registration.
- **Fix:** Resolve the type from the kernel instead of constructing it with new, then preflight again. Never mechanical-safe — rewiring construction is a design decision.
<a id="ARKRUN_UNDECLARED_EMIT"></a>
### `ARKRUN_UNDECLARED_EMIT`
**Emit name not in raises/sends**
- **Why:** A publisher / publish / raise / send call-site literal is not listed in the file’s raises or sends declaration.
- **Fix:** Add the existing call-site name to raises or sends on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new emit stays judgment.
<a id="ARKRUN_UNDECLARED_HANDLE"></a>
### `ARKRUN_UNDECLARED_HANDLE`
**Handle name not in reactsTo**
- **Why:** A subscribe / registerHandler call-site literal is not listed in the file’s reactsTo declaration.
- **Fix:** Add the existing call-site name to reactsTo on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new handle stays judgment.
<a id="ARKRUN_UNDECLARED_DEPEND"></a>
### `ARKRUN_UNDECLARED_DEPEND`
**Depend name not in uses**
- **Why:** A resolve / resolveSingleton call-site literal is not listed in the file’s uses declaration.
- **Fix:** Add the existing call-site name to uses on the managed component, then preflight again. Mechanical-safe only when that literal already exists and the edit is the declaration list; inventing a new depend stays judgment.
<a id="ARKRUN_TRANSPORT_BYPASS"></a>
### `ARKRUN_TRANSPORT_BYPASS`
**Homemade broker or emitter import**
- **Why:** A managed layer imports a closed broker/queue/emitter specifier (EventEmitter, queue clients, …) instead of the ArkRun kernel transport.
- **Fix:** Send through the ArkRun kernel transport instead of importing that broker or emitter, then preflight again. Never mechanical-safe — homemade buses stay judgment.
## Atomic preflight and change sets

@@ -277,0 +352,0 @@

@@ -30,6 +30,7 @@ # ArkGate — Architecture Co-pilot (enthusiast track)

| **ArkRules** (optional) | Habits *inside* a layer — structure and named invariants as data |
| **ArkRun** (optional extra) | Kernel usage + complete declarations (`arkRun` on schema `1.2`) |
You can stay on layers only. When you add ArkRules, start **advisory** and promote only with
coverage. Residual labels: **`[Layer]`** vs **`[ArkRules]`**. Details:
[use.md](../use.md) · [configuration](../configuration.md#arkrules-intra-layer-opt-in).
You can stay on layers only. When you add ArkRules or ArkRun, start **advisory** and promote only with
coverage. Compact starters leave ArkRun off. Residual labels: **`[Layer]`** vs **`[ArkRules]`**. Details:
[use.md](../use.md) · [configuration](../configuration.md).

@@ -36,0 +37,0 @@ ## Start here

# ArkGate package surface policy
**Product wedge:** write gate · CI gate · co-pilot (plan / loop / skills).
**Not the wedge:** the optional in-process runtime kernel.
**Not the wedge:** the optional in-process **ArkRun** kernel (`@arkgate/runtime`).

@@ -24,2 +24,3 @@ **Public product site:** [arkgate.online](https://www.arkgate.online/) (promise + only flow).

| **Deep-module coach (post-4.5 advisory)** | `ark-check --doctor --json` → `doctor.deepModuleCoach`; human doctor section **Deep-module coach (advisory — not a score)** always when doctor runs (empty candidates / hot-path `unavailable` are honesty, not omission); HTML `data-advisory="deepModuleCoach"`. | Additive schema `1.0`. Always **`notAScore: true`**. **`hotPaths`**: recent-churn heuristic from bounded git log; `available` + `status` `ok` \| `unavailable`; empty `paths` when history missing/incomplete — **never invent**. **`deepeningCandidates`**: cards projected only from existing design smells / physical cohesion / reshape pilot / pilotLoop / residual compass lenses — **empty when no evidence** (no fake candidates). Never flips `valid`, strict-merge, completeness green, or `goal.met`. Prefer deep modules / named seams / test-at-public-interface process language in skills. Domain pure + CLI gen mirror (`deepeningCoach.ts` / `bin/lib/deepening-coach.mjs`); **not** a root package export — consume via `doctor.deepModuleCoach` (or the gen mirror in Tooling). |
| **ArkRun doctor / status / report (RN08)** | `ark-check --doctor --json` → `doctor.arkRun`; HTML `data-advisory="arkRun"`; `ark status --json` / MCP `ark_status` → `arkRun`; `rulesUnderContract.mergePlanes.arkRun` | Additive. Always **`notAScore: true`**. Residual is a finding-id count (status residual `null` = unknown, not green). Advisory and absence never arm extra merge teeth; enforced teeth follow the classified-layer floor. Never a score or LLM verdict. |
| **Upgrade what’s new (4.5.6+)** | `ark upgrade --json` → `whatsNew` (+ human **Suggested improvements** block; also on preview). | Always **`notAScore: true`**, **`neverGateInput: true`**. Closed try/inspect list: deep-module coach, improvement compass, session/status honesty, two-axis done, self-service honesty, registry-aware upgrade, skill drift/refresh, multi-project MCP, Codex hard-write refresh/trust/restart/verify, stale MCP/global CLI recovery. Never invents residual or flips gates. |

@@ -42,6 +43,6 @@ | **Field upgrade truth (4.5.6)** | `ark upgrade` registry-aware install; JSON `reasonCode` / `suggestedInstallCmd`; `skillDrift`; `--refresh-skills`; `postUpgradeChecks`; `hostSelection`. | No false-skip when registry ahead; offline honesty; customized skills preserved unless opt-in refresh; checks are advisory only. |

| **Governance weight** | `ark-check --doctor --json` → `doctor.contractHealth.governanceWeight` | Additive, **advisory only** — raw facts (`declaredLayers`, `populatedLayers`, `governedFiles`, `rules`, `deniedEdges`, `allowedEdges`, `filesPerLayer`, `rulesPerLayer`) plus a fixed comparative band `weight: heavy | typical | light | unknown` and its fixed `note`. Fixed deterministic thresholds: **heavy** = fewer than 25 governed files per declared layer AND (6+ layers OR 4+ well-formed rules per layer); **light** = at most 2 layers over 150+ governed files; **unknown** = no layers or no governed files; everything else is **typical** (banding uses raw ratios; the reported ratios are rounded for display). `notAScore: true` is explicit: never a composite score, ranking, or gate input; the heavy note asks to justify NEW layers/rules and never suggests deleting working ones. Human doctor prints a line only for `heavy`/`light`. |
| **Report parity and snapshot evidence (4.2)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth"`, nested `governanceWeight`) + layer wall badges; `.ark/reports/*.json` | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. Snapshots add best-effort Git `HEAD`/branch/dirty provenance without a shell; unavailable Git is explicit. Evolution renders the Ark score delta only when both snapshots name the same ArkGate version, while retaining raw facts across versions. |
| **Report parity and snapshot evidence (4.2)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth\|arkRun"`, nested `governanceWeight`) + layer wall badges; `.ark/reports/*.json` | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. Snapshots add best-effort Git `HEAD`/branch/dirty provenance without a shell; unavailable Git is explicit. Evolution renders the Ark score delta only when both snapshots name the same ArkGate version, while retaining raw facts across versions. Thin `arkRun` on `latest.json` is `notAScore` residual honesty for `ark status`. |
| **MCP project identity (4.2)** | `ark_identity`; `arkgate/schema/project-identity` or `arkgate/schema/ark.project-identity.schema.json`; root API constants/helpers/types | Schema `1.0`. `projectId` hashes canonical root + config path and stays stable across contract edits/restarts; runtime id/start time are separate. Every project-bound tool result and error carries `projectIdentity`, `binding` (`matched` / `unverified` / `mismatch`), and `authoritative`. Canonical out-of-root config/file evidence fails before project data. |
| **MCP tools and compatibility resource** | `arkgate-mcp`; `ark_manifest`; `ark_status`; `ark://manifest` | Tool names and primary argument shapes are stable within a major. Every tool accepts additive `project.expectedRoot` / optional `expectedProjectId`. The initial handshake requires the exact project root; a contained descendant is authoritative only together with the matching project id. Legacy tool calls remain callable but `unverified` and non-authoritative. `ark_manifest` is the authoritative contract surface after binding. **`ark_status`** returns the status manifest envelope (parity with `ark status --json`). Standard `resources/read` cannot portably carry the expectation, so `ark://manifest` remains compatibility-only and always unverified/non-authoritative. The server never retargets from input. |
| **`ark.config.json`** | Layer globs, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds; optional **`arkRules`** map (schema `1.1+`) | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. Absence of `arkRules` is byte-for-byte silent on inter-layer verdicts. |
| **`ark.config.json`** | Layer globs, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds; optional **`arkRules`** map (schema `1.1+`); optional **`arkRun`** extra (schema `1.2+`) | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. Absence of `arkRules` or `arkRun` is byte-for-byte silent on Layers / ArkRules verdicts. Enforced `arkRun` extra teeth share the CLI / MCP / hook / preflight / CI verdict and arm only when the layer plane is classified (same ArkRules floor). |
| **ArkRules inventory / under-contract (4.0; layer context 4.2)** | `ark-check --rules-inventory [--json]`; doctor `rulesUnderContract`; MCP `ark_rules_inventory` | Additive. Honest counts (inventoried / under-contract / frozen) — **never a score**. When configured layer evidence exists it overrides filename role guesses: a Domain file named `handler` is not a controller candidate. Test/fixture/seed/migration/exclusion surfaces plus narrow development-identity, PostgreSQL OID, and technical I/O constants are silent. Without layer evidence, backward-compatible path/content heuristics remain. Structure/invariant diagnostics use adapter `1.4` provenance. |

@@ -62,11 +63,11 @@ | **`arkgate/schema/project-identity`** or **`arkgate/schema/ark.project-identity.schema.json`** | MCP canonical project, contract, runtime, expectation, and binding envelope | Schema `1.0`. Initial `expectedRoot` must be the exact project root. A contained descendant can match only when `expectedProjectId` is also present and correct; id-only matching stays non-authoritative. Mismatch codes are `PROJECT_ROOT_MISMATCH`, `PROJECT_ID_MISMATCH`, and `INVALID_PROJECT_EXPECTATION`. |

| **Stable finding refs (4.3)** | Root API `adapterFindingTargetKey` / `adapterFindingRefFromTargetKey` / `toAdapterDiagnostic` / `createAdapterResult`; CLI/MCP/repair envelopes via analysis-result diagnostics | Multi-turn re-address without fuzzy message match. `targetKey` **is** the baseline (occurrence) key so freeze identity is never orphaned; `findingRef` is a compact FNV-1a of that key. Line/message drift does not change the ref. Multi-turn fixture: `tests/fixtures/finding-refs/multi-turn-stability.json`. |
| **Diagnostic code catalog** | Root API `DIAGNOSTIC_CATALOG` / `getDiagnosticCatalogEntry` / `diagnosticDocsPath`; docs [diagnostics.md](diagnostics.md) (`#RULE_ID` anchors) | Closed vocabulary of public `ruleId`s with why/fix anchors. Cataloguing only — no new rule semantics. Remediation parity is test-guarded. Docs ship in the npm tarball. |
| **Status manifest** | CLI `ark status [--json] [--vs <ref>]`; MCP `ark_status`; `arkgate/schema/status-manifest`; root API `buildStatusManifest` / `ARK_STATUS_MANIFEST_SCHEMA` / `projectStatusImprovementCompass` | Schema `1.0`. One session/project snapshot: identity binding, honest write-path activation (`hard`\|`advisory`\|`unavailable`), last-check summary, rules residual counts, primary next action, **`improvementCompass`** with honesty **`mode`** `full`\|`subset`\|`unavailable` (residual ids only; always `notAScore: true`; optional `reasonCode`/`reason`/`factsSource`/`contractHash`), and optional **`vsBase`** (pin / contract / baseline grow vs a git ref; advisory only). **Not a score.** Residual never changes gate verdicts. Never prompts (`CI=1` forces JSON). Optional `--expected-root` / `--expected-project-id` (MCP `project`) for matched vs stale identity. |
| **Diagnostic code catalog** | Root API `DIAGNOSTIC_CATALOG` / `getDiagnosticCatalogEntry` / `diagnosticDocsPath`; docs [diagnostics.md](diagnostics.md) (`#RULE_ID` anchors) | Closed vocabulary of public `ruleId`s with why/fix anchors. Cataloguing only — no new rule semantics. Remediation parity is test-guarded. ArkRun `ARKRUN_*` codes (RN05) share dual-depth `nextAction` / `enthusiastHint`; declaration-list adds are mechanical-safe only when the call-site literal already exists. Docs ship in the npm tarball. |
| **Status manifest** | CLI `ark status [--json] [--vs <ref>]`; MCP `ark_status`; `arkgate/schema/status-manifest`; root API `buildStatusManifest` / `ARK_STATUS_MANIFEST_SCHEMA` / `projectStatusImprovementCompass` | Schema `1.0`. One session/project snapshot: identity binding, honest write-path activation (`hard`\|`advisory`\|`unavailable`), last-check summary, rules residual counts, primary next action, **`improvementCompass`** with honesty **`mode`** `full`\|`subset`\|`unavailable` (residual ids only; always `notAScore: true`; optional `reasonCode`/`reason`/`factsSource`/`contractHash`), optional **`vsBase`** (pin / contract / baseline grow vs a git ref; advisory only), and additive **`arkRun`** (`notAScore`; `present` / `mode` / `extraMergeTeeth` / residual count — null residual is unknown, not green). **Not a score.** Residual never changes gate verdicts. Never prompts (`CI=1` forces JSON). Optional `--expected-root` / `--expected-project-id` (MCP `project`) for matched vs stale identity. |
| **Agent contract projection** | CLI `ark agents-md [--write] [--check] [--stdout] [--json]`; install/upgrade AGENTS templates; root API `buildAgentProjectionBlock` / `mergeAgentProjectionDocument` | Schema `1.0` (projection markers). Version-stamped managed block (`arkgateVersion` + contract summary + diagnostic short list). **Non-authoritative** — not a gate input; enforcement is ark-check / hooks / CI. Content-identity merge preserves customized regions outside markers. Drift: `--check` vs package version. |
| **Agent Skills packaging** | `templates/agent-skills/<name>/SKILL.md` (+ package README); root API `ARK_SKILL_NAMES` / `validateAgentSkillsPackage`; `npm run check:agent-skills` | Schema `1.0` (package contract). Same **13** skill names as flat templates; Agent Skills–compatible layout for `npx skills add`. No new skill names. Layout is generated 1:1 from `templates/skills/*.md`. |
| **`arkgate/schema/arkrules`** or **`arkgate/schema/ark.arkrules.schema.json`** | Per-layer structure sensors + invariant catalog (ADR 0012) | Schema `1.0`. Opt-in via root `arkRules` map (`ark.config` schema `1.1`). |
| **`arkgate/schema/resolved-candidate-facts`** or **`arkgate/schema/ark.resolved-candidate-facts.schema.json`** | Versioned parity-capable input for `analyzeResolvedProject` / `preflightResolvedChange` | Schema `1.0` is serializable and deterministic. Tooling owns filesystem/compiler resolution; Domain/Kernel validate and evaluate supplied facts without importing those effects. Facts name resolver/compiler inputs, governed files, dependency evidence, completeness reasons, and candidate tree/facts hashes. |
| **`arkgate/schema/resolved-candidate-facts`** or **`arkgate/schema/ark.resolved-candidate-facts.schema.json`** | Versioned parity-capable input for `analyzeResolvedProject` / `preflightResolvedChange` | Schema `1.2` is additive: optional `classShapes` (1.1) plus ArkRun `arkRunKernelCalls` / `arkRunManagedNews` / `arkRunCompositionRootHits` / `arkRunDeclarations` (RN03–RN04). `1.0`/`1.1` payloads remain loadable. Tooling owns filesystem/compiler resolution; Domain/Kernel validate and evaluate supplied facts without importing those effects. Facts name resolver/compiler inputs, governed files, dependency evidence, completeness reasons, candidate tree/facts hashes, and (when present) ArkRun call-site and declaration evidence. Tier-1 sensors emit `ARKRUN_*` diagnostics from those facts: advisory never flips `valid`; enforced blocks. |
| **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. |
| **Agent skills** | `/ark-*` templates; install via `--install-agent-gates` (often `--skills-only` on top of compact) **or** Agent Skills ecosystem path | **Day zero** is the compact router from `ark start` / `start --apply` + doctor control plane — not the full skill pack. Skill *names* (frozen **13**) and the guided expert path (`/ark-autopilot` after pack install) are stable; internal skill prose may evolve. **4.0:** all skills except experimental `/ark-runtime` integrate **layers + ArkRules** and must label residual `[Layer]` vs `[ArkRules]`. **4.2:** repo catalogs are content-idempotent; the optional shared Codex home catalog is monotonic across 4.2.0+ installers. Pre-4.2 writers are outside that protocol and must be upgraded first. A durable pending-catalog journal preserves the floor across an interrupted install and is cleared only by its owning same/newer recovery. **4.3:** Agent Skills–compatible layout at `templates/agent-skills/<name>/SKILL.md` (1:1 with flat `templates/skills/*.md`); install via `npx skills add ./node_modules/arkgate/templates/agent-skills` (or the GitHub tree). Domain `ARK_SKILL_NAMES` + `validateAgentSkillsPackage`; drift `npm run check:agent-skills`. Skills never enforce. |
| **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import rules; loads consumer `ark.config.json`. |
| **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import/purity rules plus ArkRun import/`new` envelope (`ark/no-arkrun-kernel-in-domain`, `ark/no-arkrun-direct-new`, `ark/no-arkrun-transport-bypass`) when `arkRun` is on; loads consumer `ark.config.json`. Absence of the extra is silent. Missing-root and undeclared-* stay CLI/MCP. |
| **GitHub Action** | `pedroknigge/arkgate` (see `action.yml`) | The `uses:` tag/SHA selects the checker source; `version` remains an optional exact npm compatibility override. |

@@ -158,3 +159,3 @@ | **Package metadata** | `arkgate/package.json` | Stable resource subpath for tooling that needs the installed manifest. |

helpers are deliberately absent from this root. Use `@arkgate/runtime` for the experimental
runtime, and `analyzeProject(...).ir.capabilityUses` for public capability evidence.
**ArkRun** kernel, and `analyzeProject(...).ir.capabilityUses` for public capability evidence.

@@ -170,4 +171,4 @@ ---

|---------|-------------|--------|
| **Runtime kernel** | **`@arkgate/runtime`** | Separate 0.x source package configured for the `experimental` tag. It is not currently present in the npm registry, and the root `publish-npm.yml` workflow does not publish it automatically. Event bus, intents, policies, sagas, event buffer, projections, and strict helpers. Built-in stores are **InMemory reference only**. |
| **NestJS adapter** | `@arkgate/runtime/nestjs` | Experimental optional peer `@nestjs/common`. Root `arkgate/nestjs` and `arkgate/runtime` forwarders were **removed in AR04 / ArkGate 4** — import the companion package directly. |
| **ArkRun kernel** | **`@arkgate/runtime`** | Public brand **ArkRun**. Separate 0.x companion; `createStrictArkKernel` is the factory (each call is an isolated instance; no process-wide `getKernel()` singleton). Not bundled in the `arkgate` tarball (ADR 0004 / 0021). Not currently in the npm registry; root `publish-npm.yml` does not publish it automatically. Event bus, intents, policies, sagas, event buffer, projections, and strict helpers. Managed components declare `uses` / `reactsTo` / `raises` / `sends` on `register()`; `getDependencyInformationPackage()` is a JSON snapshot of ids, lifetime, and declarations and never includes factories, live instances, or input DTOs (ADR 0023). `requestGraph()` slices that snapshot into **process** or **technical** graphs with optional `nodeIds`, `degreesOfSeparation`, and include/exclude query; `formatArkRunGraphMermaid()` (also `graph.mermaid`) is a helper string, never a score. `send()` is the transport port (local / localBlocking / broker); missing broker falls back to in-process local delivery, `ephemeral` defaults true, and **no cloud SDKs ship** in the package (ADR 0024). Opt-in `startInspector()` / `startArkRunInspector()` binds **`127.0.0.1` only**, refuses `NODE_ENV=production`, lazy-loads HTTP, and serves JSON snapshots, SSE, and `/graph` slices of the information package (no public / authless bind). Built-in stores are **InMemory reference only**. Branding ArkRun is not a production-durability claim. |
| **NestJS adapter** | `@arkgate/runtime/nestjs` | Experimental optional peer `@nestjs/common` for the ArkRun kernel. Root `arkgate/nestjs` and `arkgate/runtime` forwarders were **removed in AR04 / ArkGate 4** — import the companion package directly. |

@@ -179,3 +180,3 @@ ---

```ts
// Preferred path when evaluating the experimental runtime kernel
// Preferred ArkRun factory — each call is a new isolated instance (no getKernel() singleton)
import { createStrictArkKernel, createStrictArkKernelFromConfig } from '@arkgate/runtime';

@@ -213,3 +214,3 @@

| Bugfix with no contract change | **patch** |
| Additive experimental runtime API | `@arkgate/runtime` prerelease/minor |
| Additive experimental ArkRun kernel API | `@arkgate/runtime` prerelease/minor |
| Remove deprecated `arkgate/runtime` / `arkgate/nestjs` forwarding shims | **Done (AR04)** — use `@arkgate/runtime` / `@arkgate/runtime/nestjs` |

@@ -222,5 +223,7 @@

Ship notes for a version live under [releases/](https://github.com/pedroknigge/arkgate/tree/main/docs/releases)
(current published: [4.6.7.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.7.md);
(current tree: [4.7.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.7.0.md);
current published: [4.6.7.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.7.md);
prior published: [4.6.6.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.6.md);
prior published: [4.6.5.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.5.md);
prior published: [4.6.4.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.4.md);
prior published: [4.6.3.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.3.md);

@@ -227,0 +230,0 @@ prior published: [4.6.2.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.2.md), [4.6.1.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.1.md), [4.6.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.6.0.md), [4.5.7.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.5.7.md), [4.5.6.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.5.6.md), [4.5.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.5.0.md), [4.4.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.4.0.md), [4.3.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.3.0.md),

@@ -22,3 +22,4 @@ # ArkGate product voice

Two planes: **import rules** (who may import whom) always; **ArkRules** (structure rules
inside a layer) opt-in.
inside a layer) opt-in. Third extra: **ArkRun** (kernel usage + declarations) via companion
`@arkgate/runtime` — not a durability claim.
- **Coach side:** where code belongs, who talks to whom, how; fix imports first, then leftover

@@ -67,4 +68,5 @@ design work; one small refactor at a time; never silent auto-reshape; never weaken the config.

**Brands (keep):** **ArkGate** (product / npm `arkgate`) and **ArkRules** (opt-in structure rules
inside a layer). Gloss on first mention; do not rebrand.
**Brands (keep):** **ArkGate** (product / npm `arkgate`), **ArkRules** (opt-in structure rules
inside a layer), and **ArkRun** (opt-in kernel-usage extra + companion `@arkgate/runtime`). Gloss
on first mention; do not rebrand. Branding ArkRun is not a durability claim.

@@ -79,2 +81,3 @@ Human copy prefers the **common** column. JSON field names (`designWeak`, `ruleId`, MCP tools)

| **ArkRules** (opt-in; gloss: structure rules inside a layer) | ArkRules | Intra-layer sensors + domain invariant catalogs (`arkrules/*`) |
| **ArkRun** (opt-in; gloss: kernel usage + complete declarations) | arkRun | Extra plane on the gate; companion kernel is `@arkgate/runtime`; factory `createStrictArkKernel` (per instance, no singleton). Never a score. |
| **advisory ArkRules** | advisory ArkRules | Default sensor mode — **not** merge teeth; does not fail CI/merge alone |

@@ -81,0 +84,0 @@ | **extra merge checks** | extraMergeTeeth | Only when enforced structure/invariant rules exist **and** classification is honest |

@@ -56,3 +56,3 @@ # ArkGate documentation

| Release notes (by version) | [releases/](releases/) · npm [CHANGELOG.md](../CHANGELOG.md) (Unreleased + 4.6.x) · [pre-4.6 archive](archive/CHANGELOG-pre-4.6.md) |
| Epic plans | [plans/](plans/) — maintainer seeds, not required to use the package. Live: [alive-in-six-months](plans/alive-in-six-months/README.md) (`AL01`–`AL04` done on `main`; `AL05` parked). |
| Epic plans | [plans/](plans/) — maintainer seeds, not required to use the package. Live: [alive-in-six-months](plans/alive-in-six-months/README.md) (`AL01`–`AL04` done; `AL05` parked). [arkrun](plans/arkrun/README.md) (Phase RN; `RN01`–`RN15` done; `RN16` preparing **4.7.0**; ADRs [0020](adr/0020-arkrun-gated-extra-plane.md)–[0024](adr/0024-arkrun-transport-ports.md) accepted). |
| Claims audit | [audit/claims-matrix.md](audit/claims-matrix.md) |

@@ -62,2 +62,3 @@ | Field adoption kit (scaffolding, not closed) | [field/](field/) |

Current tree: [releases/4.7.0.md](releases/4.7.0.md) (`arkgate@4.7.0` prepared).
Current published: [releases/4.6.7.md](releases/4.6.7.md) (`arkgate@4.6.7` on npm `latest`).

@@ -64,0 +65,0 @@ Prior: [releases/4.6.6.md](releases/4.6.6.md) · [4.6.5](releases/4.6.5.md) · [4.6.4](releases/4.6.4.md) · [4.6.3](releases/4.6.3.md) · [4.6.2](releases/4.6.2.md) · [4.6.1](releases/4.6.1.md) · [4.6.0](releases/4.6.0.md).

# Threat model — ArkGate
**Scope:** architecture write/CI gates, agent hooks/MCP, and the experimental optional runtime.
**Scope:** architecture write/CI gates, agent hooks/MCP, and the experimental optional **ArkRun** kernel (`@arkgate/runtime`).
**Not in scope:** full org identity platforms, browser XSS in consumer apps, or npm registry

@@ -5,0 +5,0 @@ infrastructure beyond how this package is published.

@@ -62,3 +62,3 @@ # Use ArkGate

### Two planes (you choose)
### Planes (you choose)

@@ -68,7 +68,8 @@ | Plane | Plain English | Config | Enforces |

| **Layers** | Who may talk to whom | `layers[]` + `rules[]` | Import direction, purity, forbidden globals, capabilities, peer isolation |
| **ArkRules** (optional) | Habits *inside* a layer + named policies | `arkRules` + `arkrules/<Layer>.json` | Structure **heuristics** (module shape); invariant **catalog + coverage evidence** (not full business proof) |
| **ArkRules** (optional extra) | Habits *inside* a layer + named policies | `arkRules` + `arkrules/<Layer>.json` | Structure **heuristics** (module shape); invariant **catalog + coverage evidence** (not full business proof) |
| **ArkRun** (optional extra) | Kernel usage + complete declarations | `arkRun` on schema `1.2` | Only `mode: "enforced"` when the tree is classified. Absence is silent. Doctor `arkRun` is **not a score**. |
Start always gives you **layers**. ArkRules templates may ship with start/init; they begin **advisory** until you promote them. Doctor / HTML show `rulesUnderContract` (catalog, **not a score**). No `arkRules` map is fine — only Layers run.
Start always gives you **layers**. ArkRules templates may ship with start/init; they begin **advisory** until you promote them. Compact starters do **not** turn on ArkRun — add it only if the project uses `@arkgate/runtime`. Doctor / HTML show `rulesUnderContract` (catalog, **not a score**). No `arkRules` / `arkRun` map is fine — only Layers run. In-memory kernel stores are **not** production durability.
**Do not confuse:** green Layers ≠ perfect design (Shape residual can remain). Covered invariants ≠ “the business always does the right thing” — they mean the named policy is declared and has symbol/test evidence.
**Do not confuse:** green Layers ≠ perfect design (Shape residual can remain). Covered invariants ≠ “the business always does the right thing” — they mean the named policy is declared and has symbol/test evidence. ArkRun branding ≠ durable stores.

@@ -75,0 +76,0 @@ ### New modules vs config edits

{
"name": "arkgate",
"version": "4.6.7",
"version": "4.7.0",
"description": "One architecture config. One check. One coach.",

@@ -5,0 +5,0 @@ "type": "module",

@@ -19,7 +19,7 @@ <div align="center">

> **ArkGate 4.6.7** is current on npm `latest`.
> **ArkGate 4.7.0** is prepared on this tree. **4.6.7** remains npm `latest` until publish.
> A tree is **adopted** only with a required GitHub status running `arkgate-check --strict-merge`,
> or `.ark/adoption-stance.json` `stance: "advisory-only"`. Doctor is compact (`--doctor --all`
> for Details). [4.6.7 notes](docs/releases/4.6.7.md) · [4.6.6](docs/releases/4.6.6.md) ·
> [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
> for Details). [4.7.0 notes](docs/releases/4.7.0.md) · [4.6.7](docs/releases/4.6.7.md) ·
> [4.6.6](docs/releases/4.6.6.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)

@@ -82,7 +82,8 @@ ---

| **ArkRules** (opt-in; structure rules inside a layer) | Habits *inside* a layer — structure sensors + domain invariants as data | `arkRules` → `arkrules/<Layer>.json` |
| **ArkRun** (opt-in extra) | Kernel usage + complete declarations | `arkRun` on schema `1.2` |
Absence of ArkRules changes no inter-layer verdict. Label residual **`[Layer]`** vs **`[ArkRules]`**.
Details: [configuration](docs/configuration.md#arkrules-intra-layer-opt-in) · [use path](docs/use.md).
Absence of ArkRules or ArkRun changes no inter-layer verdict. Label residual **`[Layer]`** vs **`[ArkRules]`**.
Details: [configuration](docs/configuration.md) · [use path](docs/use.md).
**Not** a web framework, ORM, or job runner. Optional experimental runtime is separate and not required for the gate.
**Not** a web framework, ORM, or job runner. Optional **ArkRun** extra and companion kernel (`@arkgate/runtime`) are separate and not required for the gate. In-memory stores are not production durability.

@@ -197,5 +198,14 @@ **Name note:** npm package `arkgate` — not affiliated with the separate Archgate CLI project.

## Optional experimental runtime
## Optional ArkRun kernel
Gates need **no** app runtime. The experimental `@arkgate/runtime` companion is separate and is not a production-readiness claim.
Gates need **no** app runtime. The experimental **ArkRun** companion (`@arkgate/runtime`) is separate
and is not a production-readiness claim. `createStrictArkKernel` is the factory: each call creates
an isolated instance (no process-wide singleton). Managed components declare `uses` / `reactsTo` /
`raises` / `sends`; `getDependencyInformationPackage()` is a JSON snapshot and never leaks factories.
`requestGraph()` slices that snapshot into process or technical graphs (`nodeIds`,
`degreesOfSeparation`, include/exclude query) with a Mermaid helper. `send()` is local /
localBlocking / broker (broker falls back to in-process local; `ephemeral`
defaults true; no cloud SDKs in the package). Opt-in `startInspector()` binds `127.0.0.1`,
refuses `NODE_ENV=production`, and lazy-loads HTTP for JSON snapshots, SSE, and `/graph`. The kernel is
not bundled in the `arkgate` tarball.

@@ -223,3 +233,4 @@ ### Durability stance

| Security | [SECURITY.md](SECURITY.md) |
| Current published (4.6.7 on npm `latest`) | [docs/releases/4.6.7.md](docs/releases/4.6.7.md) · [CHANGELOG](CHANGELOG.md) |
| Current tree (4.7.0 prepared) | [docs/releases/4.7.0.md](docs/releases/4.7.0.md) · [CHANGELOG](CHANGELOG.md) |
| Current published (4.6.7 on npm `latest`) | [docs/releases/4.6.7.md](docs/releases/4.6.7.md) |
| Prior published (4.6.6) | [docs/releases/4.6.6.md](docs/releases/4.6.6.md) |

@@ -226,0 +237,0 @@ | Prior published (4.6.5) | [docs/releases/4.6.5.md](docs/releases/4.6.5.md) |

@@ -24,4 +24,4 @@ {

"type": "string",
"const": "1.1",
"default": "1.1"
"const": "1.2",
"default": "1.2"
},

@@ -637,2 +637,5 @@ "name": {

},
"arkRun": {
"$ref": "#/$defs/arkRun"
},
"stewards": {

@@ -798,4 +801,40 @@ "type": "array",

}
},
"arkRun": {
"type": "object",
"additionalProperties": false,
"properties": {
"mode": {
"type": "string",
"enum": [
"advisory",
"enforced"
],
"default": "advisory"
},
"compositionRoots": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true,
"default": []
},
"managedLayers": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true,
"default": []
},
"requireDeclarations": {
"type": "boolean",
"default": true
}
}
}
}
}

@@ -1,1 +0,1 @@

{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://unpkg.com/arkgate@3/schemas/ark.resolved-candidate-facts.schema.json","title":"ArkGate resolved candidate facts","type":"object","additionalProperties":false,"required":["schemaVersion","completeness","completenessReasons","resolverIdentity","compilerIdentity","compilerOptionsHash","tsconfigHash","candidateTreeHash","evidenceRequirementsHash","files","dependencies","capabilityUses","ambientUses","publishCalls","intentReferences","safetyUses","factsHash"],"properties":{"schemaVersion":{"enum":["1.0","1.1"]},"completeness":{"enum":["complete","partial","unavailable"]},"completenessReasons":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","minLength":1},"message":{"type":"string","minLength":1},"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"}}}},"resolverIdentity":{"type":"string","minLength":1},"compilerIdentity":{"type":"string","minLength":1},"compilerOptionsHash":{"type":"string","minLength":1},"tsconfigHash":{"type":"string","minLength":1},"candidateTreeHash":{"type":"string","minLength":1},"evidenceRequirementsHash":{"type":"string","minLength":1},"projectPackageName":{"type":"string","minLength":1},"files":{"type":"array","uniqueItems":true,"items":{"type":"object","additionalProperties":false,"required":["path","contentHash","parseStatus","parseDiagnosticCount","exportsOnlyTypes","typeOnlyExportNames","hasTopLevelSideEffects"],"properties":{"path":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"contentHash":{"type":"string","minLength":1},"parseStatus":{"enum":["parsed","invalid"]},"parseDiagnosticCount":{"type":"integer","minimum":0},"exportsOnlyTypes":{"type":"boolean"},"typeOnlyExportNames":{"type":"array","items":{"type":"string","minLength":1}},"hasTopLevelSideEffects":{"type":"boolean"}},"allOf":[{"if":{"properties":{"parseStatus":{"const":"parsed"}}},"then":{"properties":{"parseDiagnosticCount":{"const":0}}}},{"if":{"properties":{"parseStatus":{"const":"invalid"}}},"then":{"properties":{"parseDiagnosticCount":{"minimum":1}}}}]}},"dependencies":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["from","kind","typeOnly","line","resolution"],"properties":{"from":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"specifier":{"type":"string","minLength":1},"kind":{"enum":["import","export","dynamic-import","require"]},"typeOnly":{"type":"boolean"},"line":{"type":"integer","minimum":1},"resolution":{"enum":["resolved-project","resolved-external","unresolved","dynamic"]},"target":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"namedBindings":{"type":"array","items":{"type":"string","minLength":1}},"targetTypeOnlyExports":{"type":"boolean"},"sourcePureTypeModule":{"type":"boolean"},"namedBindingsTypeOnly":{"type":"boolean"},"portProofEligible":{"type":"boolean"}},"allOf":[{"if":{"properties":{"resolution":{"const":"resolved-project"}}},"then":{"required":["target"]},"else":{"not":{"required":["target"]}}},{"if":{"properties":{"resolution":{"const":"dynamic"}}},"else":{"required":["specifier"]}}]}},"capabilityUses":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","symbol","capability","source"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"symbol":{"type":"string","minLength":1},"capability":{"enum":["network","filesystem","clock","randomness","environment","process","persistence"]},"source":{"enum":["ambient-global","import-based"]}}}},"ambientUses":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","symbol"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"symbol":{"type":"string","minLength":1}}}},"publishCalls":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","objectHasIntent","arkPublishCandidate","hasSource"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"rawIntentName":{"type":"string","minLength":1},"objectHasIntent":{"type":"boolean"},"arkPublishCandidate":{"type":"boolean"},"hasSource":{"type":"boolean"},"sourceIntent":{"type":"string","minLength":1}}}},"intentReferences":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","intent"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"intent":{"type":"string","minLength":1}}}},"safetyUses":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","kind"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"kind":{"enum":["ts-suppression","any-cast","dynamic-import","dynamic-require","in-memory-store"]},"symbol":{"type":"string","minLength":1}},"allOf":[{"if":{"properties":{"kind":{"const":"in-memory-store"}}},"then":{"required":["symbol"]},"else":{"not":{"required":["symbol"]}}}]}},"classShapes":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","className","exported","hasPublicMutableFields","hasPublicSetters","hasPublicConstructor","hasStaticFactory","mutatingMethods"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"className":{"type":"string","minLength":1},"exported":{"type":"boolean"},"hasPublicMutableFields":{"type":"boolean"},"hasPublicSetters":{"type":"boolean"},"hasPublicConstructor":{"type":"boolean"},"hasStaticFactory":{"type":"boolean"},"dataOnly":{"type":"boolean"},"mutatingMethods":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["name","referencesGuardOrPublish"],"properties":{"name":{"type":"string","minLength":1},"referencesGuardOrPublish":{"type":"boolean"}}}}}}},"factsHash":{"type":"string","minLength":1}},"allOf":[{"if":{"properties":{"completeness":{"const":"complete"}}},"then":{"properties":{"completenessReasons":{"maxItems":0},"files":{"items":{"properties":{"parseStatus":{"const":"parsed"}}}}}}},{"if":{"properties":{"completeness":{"enum":["partial","unavailable"]}}},"then":{"properties":{"completenessReasons":{"minItems":1}}}}]}
{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://unpkg.com/arkgate@3/schemas/ark.resolved-candidate-facts.schema.json","title":"ArkGate resolved candidate facts","type":"object","additionalProperties":false,"required":["schemaVersion","completeness","completenessReasons","resolverIdentity","compilerIdentity","compilerOptionsHash","tsconfigHash","candidateTreeHash","evidenceRequirementsHash","files","dependencies","capabilityUses","ambientUses","publishCalls","intentReferences","safetyUses","factsHash"],"properties":{"schemaVersion":{"enum":["1.0","1.1","1.2"]},"completeness":{"enum":["complete","partial","unavailable"]},"completenessReasons":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","minLength":1},"message":{"type":"string","minLength":1},"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"}}}},"resolverIdentity":{"type":"string","minLength":1},"compilerIdentity":{"type":"string","minLength":1},"compilerOptionsHash":{"type":"string","minLength":1},"tsconfigHash":{"type":"string","minLength":1},"candidateTreeHash":{"type":"string","minLength":1},"evidenceRequirementsHash":{"type":"string","minLength":1},"projectPackageName":{"type":"string","minLength":1},"files":{"type":"array","uniqueItems":true,"items":{"type":"object","additionalProperties":false,"required":["path","contentHash","parseStatus","parseDiagnosticCount","exportsOnlyTypes","typeOnlyExportNames","hasTopLevelSideEffects"],"properties":{"path":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"contentHash":{"type":"string","minLength":1},"parseStatus":{"enum":["parsed","invalid"]},"parseDiagnosticCount":{"type":"integer","minimum":0},"exportsOnlyTypes":{"type":"boolean"},"typeOnlyExportNames":{"type":"array","items":{"type":"string","minLength":1}},"hasTopLevelSideEffects":{"type":"boolean"}},"allOf":[{"if":{"properties":{"parseStatus":{"const":"parsed"}}},"then":{"properties":{"parseDiagnosticCount":{"const":0}}}},{"if":{"properties":{"parseStatus":{"const":"invalid"}}},"then":{"properties":{"parseDiagnosticCount":{"minimum":1}}}}]}},"dependencies":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["from","kind","typeOnly","line","resolution"],"properties":{"from":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"specifier":{"type":"string","minLength":1},"kind":{"enum":["import","export","dynamic-import","require"]},"typeOnly":{"type":"boolean"},"line":{"type":"integer","minimum":1},"resolution":{"enum":["resolved-project","resolved-external","unresolved","dynamic"]},"target":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"namedBindings":{"type":"array","items":{"type":"string","minLength":1}},"targetTypeOnlyExports":{"type":"boolean"},"sourcePureTypeModule":{"type":"boolean"},"namedBindingsTypeOnly":{"type":"boolean"},"portProofEligible":{"type":"boolean"}},"allOf":[{"if":{"properties":{"resolution":{"const":"resolved-project"}}},"then":{"required":["target"]},"else":{"not":{"required":["target"]}}},{"if":{"properties":{"resolution":{"const":"dynamic"}}},"else":{"required":["specifier"]}}]}},"capabilityUses":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","symbol","capability","source"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"symbol":{"type":"string","minLength":1},"capability":{"enum":["network","filesystem","clock","randomness","environment","process","persistence"]},"source":{"enum":["ambient-global","import-based"]}}}},"ambientUses":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","symbol"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"symbol":{"type":"string","minLength":1}}}},"publishCalls":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","objectHasIntent","arkPublishCandidate","hasSource"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"rawIntentName":{"type":"string","minLength":1},"objectHasIntent":{"type":"boolean"},"arkPublishCandidate":{"type":"boolean"},"hasSource":{"type":"boolean"},"sourceIntent":{"type":"string","minLength":1}}}},"intentReferences":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","intent"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"intent":{"type":"string","minLength":1}}}},"safetyUses":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","kind"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"kind":{"enum":["ts-suppression","any-cast","dynamic-import","dynamic-require","in-memory-store"]},"symbol":{"type":"string","minLength":1}},"allOf":[{"if":{"properties":{"kind":{"const":"in-memory-store"}}},"then":{"required":["symbol"]},"else":{"not":{"required":["symbol"]}}}]}},"classShapes":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","className","exported","hasPublicMutableFields","hasPublicSetters","hasPublicConstructor","hasStaticFactory","mutatingMethods"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"className":{"type":"string","minLength":1},"exported":{"type":"boolean"},"hasPublicMutableFields":{"type":"boolean"},"hasPublicSetters":{"type":"boolean"},"hasPublicConstructor":{"type":"boolean"},"hasStaticFactory":{"type":"boolean"},"dataOnly":{"type":"boolean"},"mutatingMethods":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["name","referencesGuardOrPublish"],"properties":{"name":{"type":"string","minLength":1},"referencesGuardOrPublish":{"type":"boolean"}}}}}}},"arkRunKernelCalls":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","kind","callee","viaImport"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"kind":{"enum":["factory","publisher","publish","raise","send","subscribe","register-handler","resolve","resolve-singleton"]},"callee":{"type":"string","minLength":1},"viaImport":{"type":"boolean"},"receiver":{"type":"string","minLength":1},"nameLiteral":{"type":"string","minLength":1}}}},"arkRunManagedNews":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","typeName"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"typeName":{"type":"string","minLength":1},"importedFrom":{"type":"string","minLength":1}}}},"arkRunCompositionRootHits":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","matchedRoot","hasKernelFactory"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"matchedRoot":{"type":"string","minLength":1},"hasKernelFactory":{"type":"boolean"}}}},"arkRunDeclarations":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["file","line","uses","reactsTo","raises","sends"],"properties":{"file":{"type":"string","minLength":1,"pattern":"^(?!/)(?![A-Za-z]:/)(?!.*\\\\)(?!.*//)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*[\\u0000-\\u001f\\u007f])(?!.*\\/$).+$"},"line":{"type":"integer","minimum":1},"uses":{"type":"array","items":{"type":"string","minLength":1}},"reactsTo":{"type":"array","items":{"type":"string","minLength":1}},"raises":{"type":"array","items":{"type":"string","minLength":1}},"sends":{"type":"array","items":{"type":"string","minLength":1}}}}},"factsHash":{"type":"string","minLength":1}},"allOf":[{"if":{"properties":{"completeness":{"const":"complete"}}},"then":{"properties":{"completenessReasons":{"maxItems":0},"files":{"items":{"properties":{"parseStatus":{"const":"parsed"}}}}}}},{"if":{"properties":{"completeness":{"enum":["partial","unavailable"]}}},"then":{"properties":{"completenessReasons":{"minItems":1}}}}]}

@@ -346,4 +346,51 @@ {

}
},
"arkRun": {
"type": "object",
"description": "ArkRun extra residual (notAScore). present/mode from config; residual is a finding-id count (null = unknown, not green). extraMergeTeeth is honesty, never a score.",
"additionalProperties": false,
"required": [
"notAScore",
"present",
"mode",
"extraMergeTeeth",
"residual"
],
"properties": {
"notAScore": {
"const": true
},
"present": {
"type": "boolean"
},
"mode": {
"anyOf": [
{
"enum": [
"advisory",
"enforced"
]
},
{
"type": "null"
}
]
},
"extraMergeTeeth": {
"type": "boolean"
},
"residual": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
]
}
}
}
}
}

@@ -21,3 +21,3 @@ # Security Policy

- whether the issue affects `arkgate-check` / `ark-check`, `arkgate-mcp` / `ark-mcp`,
generated agent gates, the GitHub Action, or the optional runtime kernel
generated agent gates, the GitHub Action, or the optional ArkRun kernel

@@ -24,0 +24,0 @@ If private vulnerability reporting is unavailable, open a minimal public issue asking for

@@ -9,3 +9,3 @@ {

},
"version": "4.6.7",
"version": "4.7.0",
"packages": [

@@ -15,3 +15,3 @@ {

"identifier": "arkgate",
"version": "4.6.7",
"version": "4.7.0",
"runtimeHint": "npx",

@@ -18,0 +18,0 @@ "transport": {

@@ -23,2 +23,4 @@ ---

- CLI-first: if `arkgate-check` already resolved the root, do not wait on MCP.
- Do not add `arkRun` unless the user wants the extra. When they do, write **advisory** `arkRun`
(schema `1.2+`) in this turn. Absence is silent and valid. Skills never enforce.

@@ -98,2 +100,3 @@ Invoking this skill **is** the approval. Write the architecture config in this turn.

| Freeze **real** debt after the config is honest | User said map only |
| Turn **advisory** ArkRun on (`arkRun` extra, schema `1.2+`) | Evaluate / wire a hand-rolled bus → `/ark-runtime`; new kernel-managed file → `/ark-place` |

@@ -126,5 +129,6 @@ ## Dual engine (mandatory)

| **ArkRules** (intra-layer) | Structure inside a layer + domain invariants as data | `arkRules` map + `arkrules/<ExactLayerName>.json` | structure sensors, invariant coverage, `--rules-inventory`, doctor `rulesUnderContract` |
| **ArkRun** (extra) | Kernel usage + complete declarations | `arkRun` on `ark.config.json` (schema `1.2+`) + companion `@arkgate/runtime` | `ARKRUN_*`, doctor `arkRun` (`notAScore`) |
**Rules for every report / answer:**
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** (or a two-column table with those headers).
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** or **`[ArkRun]`** (or a two-column table with those headers).
2. Never call an import-edge violation an “invariant” or an aggregate sensor a “layer deny.”

@@ -134,2 +138,3 @@ 3. Absence of `arkRules` is **valid** — do not force ArkRules unless the user wants them or residual inventory clearly wants a pilot.

5. CLI helpers: `ark-check --rules-inventory --json`, doctor JSON `rulesUnderContract`, sensors emit `ARKRULE_*` / `INVARIANT_UNCOVERED` with `evidence.arkruleId`.
6. Absence of `arkRun` is **valid**. Write it only when the user wants the extra. Skills never enforce.

@@ -142,2 +147,12 @@

### Adopt + ArkRun
- User asked to turn the extra on: write **advisory** `arkRun` on `ark.config.json` (`schemaVersion` `1.2+`) **in this turn**. Default `"mode": "advisory"`.
- Required shape: `compositionRoots` (real files; empty + enforced fails closed), `managedLayers` (existing `layers[].name` only), `requireDeclarations` (default true).
- Do **not** put `arkRun` on the compact starter / `ark start` scaffold. Brownfield stays advisory until the team promotes.
- Absence is valid and **silent** — never force the extra. Never force the kernel over existing Nest/DI. Do not invent `/ark-run`.
- Import the companion from `@arkgate/runtime` (factory `createStrictArkKernel`, per instance, no process-wide singleton). Never a removed `arkgate/runtime` shim. No shipped cloud broker SDKs.
- In-memory stores are **not** production durability. Branding ArkRun is not a durability claim. Doctor / status `arkRun` is `notAScore`.
- Demoting enforced → advisory or deleting the extra is policy-delta **weakening**.
- After the extra is honest: handoff `/ark-runtime` to wire one candidate, `/ark-place` for new kernel-managed files. Skills never enforce.
## Subagent fan-out (optional, host-dependent)

@@ -192,2 +207,5 @@

**ApplicationOrchestration**, not Presentation — do not reclassify API shells as UI.
User wants the ArkRun extra → write **advisory** `arkRun` (schema `1.2+`, real
`compositionRoots`, existing `managedLayers`) **in this turn**. Do not add it to a compact
starter. Do not promote to enforced as the session-0 default.
2. **Check + diagnose** — `summary.concentrated` / dominant edge → fix contract first, don’t freeze.

@@ -235,2 +253,5 @@ Cross-slice / cross-context `peerIsolation` hits are judgment: extract shared or events.

- Force runtime kernel over existing Nest/DI.
- Put `arkRun` on the compact starter / `ark start` scaffold.
- Claim in-memory kernel stores are production durability.
- Invent `/ark-run`.
- Claim Enforce while governed% is low, cores empty with I/O in Application, or core bags ungoverned.

@@ -247,3 +268,3 @@ - End adopt with only “baseline written” when design-weak residual is visible in files you opened.

- **Result:** one-line outcome
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused)
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** vs **[ArkRun]** (or `n/a` if unused)
- **Compass:** top residual lenses | `n/a`

@@ -250,0 +271,0 @@ - **Done axes:** architecture residual (status/doctor/compass) | feature/ticket residual (outside package). Enforce green ≠ feature done

@@ -22,2 +22,5 @@ ---

- Do not default a repository to Presentation.
- When `arkRun` is on: scaffold through the kernel (no `new` of managed types; declare
`uses` / `reactsTo` / `raises` / `sends`). Extra off → do not introduce the kernel. Enable it
via `/ark-adopt`. Skills never enforce.

@@ -66,2 +69,3 @@ ## Autonomy contract

| Naming / directory for a known kind | Session 0 / config missing or lying → `/ark-adopt` (then come back) |
| Kernel-managed artifact when `arkRun` is already on | Extra not chosen yet → `/ark-adopt` (advisory `arkRun`); evaluate / migrate a hand-rolled bus → `/ark-runtime` |

@@ -109,5 +113,6 @@ The user describes something they need to build (a saga, a background job, an

| **ArkRules** (intra-layer) | Structure inside a layer + domain invariants as data | `arkRules` map + `arkrules/<ExactLayerName>.json` | structure sensors, invariant coverage, `--rules-inventory`, doctor `rulesUnderContract` |
| **ArkRun** (extra) | Kernel usage + complete declarations | `arkRun` on `ark.config.json` (schema `1.2+`) + companion `@arkgate/runtime` | `ARKRUN_*`, doctor `arkRun` (`notAScore`) |
**Rules for every report / answer:**
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** (or a two-column table with those headers).
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** or **`[ArkRun]`** (or a two-column table with those headers).
2. Never call an import-edge violation an “invariant” or an aggregate sensor a “layer deny.”

@@ -117,2 +122,3 @@ 3. Absence of `arkRules` is **valid** — do not force ArkRules unless the user wants them or residual inventory clearly wants a pilot.

5. CLI helpers: `ark-check --rules-inventory --json`, doctor JSON `rulesUnderContract`, sensors emit `ARKRULE_*` / `INVARIANT_UNCOVERED` with `evidence.arkruleId`.
6. Absence of `arkRun` is **valid**. Do not introduce the kernel speculatively. Skills never enforce this extra.

@@ -124,2 +130,13 @@

### Place + ArkRun
When `arkRun` is present on the architecture config:
- Scaffold kernel-managed artifacts **through the kernel**, not `new` of an admitted type (`ARKRUN_DIRECT_NEW`).
- Call `createStrictArkKernel` (or an admission sibling) only inside `arkRun.compositionRoots`. Each call is a new instance — no process-wide `getKernel()`.
- Domain-role files stay kernel-free (`ARKRUN_KERNEL_IN_DOMAIN`). Import from `@arkgate/runtime` (or `/nestjs`), never a removed `arkgate/runtime` shim.
- List `uses` / `reactsTo` / `raises` / `sends` when `requireDeclarations` is on. Adding an existing call-site literal to the declaration list is the only mechanical-safe ArkRun edit; inventing a new emit / handle / depend is judgment.
- Do not import a homemade bus (`EventEmitter`, queue clients) in `managedLayers` — send on the kernel transport (`local` / `localBlocking` / `broker`; `ephemeral` defaults true). No shipped cloud SDKs.
- In-memory stores are **not** production durability. Doctor `arkRun` is `notAScore`.
- Absence of the extra: place with **[Layer]** + **[ArkRules]** only. Enable advisory extra via `/ark-adopt`; evaluate a hand-rolled bus via `/ark-runtime`. Do not invent `/ark-run`.
- Skills never enforce.
## Subagent fan-out (optional, host-dependent)

@@ -156,2 +173,6 @@

jobs, projections → the event/workflow layers if the config declares them.
When `arkRun` is on, wire those through the kernel (register + declarations),
not a homemade emitter.
- Kernel-managed application service when `arkRun` is on → composition-root factory
+ `register({ uses, reactsTo, raises, sends })`; never `new` of the admitted type.
- **`vertical-slice` contract:** put co-located feature code under

@@ -184,2 +205,5 @@ `src/features/<slice>/…` (never import a sibling slice); shared primitives

batch reshape from this skill.
- If `arkRun` is on and the user is grinding skip violations (`new` of managed types, homemade
bus) across many files: place this artifact through the kernel, then leftover `/ark-fix` /
`/ark-autopilot`. Extra not on → `/ark-adopt` (advisory) or `/ark-runtime` (evaluate).

@@ -217,3 +241,3 @@ ## Operating rules

- **Result:** one-line outcome
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused)
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** vs **[ArkRun]** (or `n/a` if unused)
- **Compass:** top residual lenses | `n/a`

@@ -220,0 +244,0 @@ - **Done axes:** architecture residual (status/doctor/compass) | feature/ticket residual (outside package). Enforce green ≠ feature done

---
name: ark-runtime
description: Evaluate the experimental Ark runtime kernel against hand-rolled event bus, outbox, audit, saga, projection, policy, or NestJS code. Finds one candidate, wires one, verifies.
description: Evaluate and wire the experimental ArkRun companion (@arkgate/runtime) against hand-rolled event bus, outbox, saga, projection, policy, or NestJS code. One candidate. Extra on via /ark-adopt; new files via /ark-place. Skills never enforce.
---
# /ark-runtime — Evaluate the runtime kernel (experimental opt-in)
# /ark-runtime — Evaluate and wire ArkRun (experimental opt-in)
The runtime kernel is currently **experimental** and is not required for ArkGate enforcement or
presented as production-ready. Use this skill only when the user explicitly wants to evaluate it.
The ArkRun companion (`@arkgate/runtime`) is currently **experimental**. It is **not** required
for ArkGate enforcement and is **not** production durability. Use this skill when the user wants
to evaluate or wire the kernel. **This skill never enforces** — the write / CI / ESLint plane
does when the `arkRun` extra is on. Do **not** invent `/ark-run`.
The separate `@arkgate/runtime` source package contains the experimental runtime kernel
(`createArkKernel`) with an event bus, event contracts, outbox, audit trail,
policy engine, workflow/saga coordination, projections, observability hooks,
and NestJS adapters. The stable `arkgate` package is the architecture gate; it does not bundle
the runtime implementation. This skill migrates hand-rolled versions of those to the kernel,
one feature at a time.
**When:** evaluate a hand-rolled bus / outbox / saga / projection / policy / Nest adapter against
the companion, or wire an extra that is already on (composition root, declarations, transport).
**Not when:** session 0 / extra not chosen (`/ark-adopt`); one new file (`/ark-place`); skip-violation
grind (`/ark-autopilot` / leftover `/ark-fix`).
## Extra vs companion (mandatory)
| Piece | What it is | What it is not |
|-------|------------|----------------|
| **ArkRun extra** (`arkRun` on `ark.config.json`, schema `1.2+`) | Gate contract: kernel usage + complete declarations | A score; Layers / ArkRules replacement; merge teeth while `advisory` |
| **Companion** `@arkgate/runtime` | Kernel you construct with `createStrictArkKernel` (one instance per call) | Bundled in the `arkgate` tarball; a process-wide `getKernel()`; shipped cloud broker SDKs |
Absence of the extra is **silent** — Layers and ArkRules verdicts stay identical. Doctor / status
`arkRun` is always `notAScore`. Never invent 0–10 scores or pass/fail from this skill.
## Improvement compass note

@@ -23,2 +33,3 @@

for static architecture residual; hand static residual to `/ark-explore` / `/ark-autopilot`.
Doctor `arkRun` residual is a finding-id count (`ARKRUN_*`), never a compass score.

@@ -45,3 +56,3 @@ ## Dual engine (mandatory)

This skill is **runtime-kernel only**. Do not mix ArkRules structure/invariants here; hand off to `/ark-contract` / `/ark-adopt` / `/ark-explore` for static contract planes.
This skill is **runtime-kernel only**. Do not mix ArkRules structure/invariants here; hand off to `/ark-contract` / `/ark-adopt` / `/ark-explore` for static contract planes. Label kernel-usage residual **`[ArkRun]`** so it never blurs with **`[Layer]`** or **`[ArkRules]`**.

@@ -67,6 +78,11 @@ ## Subagent fan-out (optional, host-dependent)

adapters apply.
2. **Pick ONE target** — the smallest, most self-contained candidate (fewest
2. **Read the extra** — open `ark.config.json`. If `arkRun` is absent and the user wants the extra,
**STOP — do not continue this skill as complete.** Handoff **`/ark-adopt`** to write **advisory**
`arkRun` (schema `1.2+`; `compositionRoots`, `managedLayers`, `requireDeclarations`). Do not
invent the extra here. If the extra is present, note `mode`, roots, managed layers, and
`requireDeclarations`; doctor `arkRun` is `notAScore`.
3. **Pick ONE target** — the smallest, most self-contained candidate (fewest
call sites). Migrating everything at once is how adoptions die. List the
rest as follow-ups in the report.
3. **Resolve availability** — run `npm view @arkgate/runtime dist-tags --json`. If an
rest as follow-ups in the report. New files after the extra is on go through **`/ark-place`**.
4. **Resolve availability** — run `npm view @arkgate/runtime dist-tags --json`. If an
`experimental` tag exists, install that exact companion. Otherwise continue only from an

@@ -76,11 +92,28 @@ ArkGate source checkout: run `npm run build:runtime` at its root and install its local

runtime is unavailable; never fall back to the deprecated root shims as if they contained it.
4. **Migrate** — import from `@arkgate/runtime` or `@arkgate/runtime/nestjs`, and read the
Import from `@arkgate/runtime` (or `@arkgate/runtime/nestjs`) — never a removed `arkgate/runtime`
shim.
5. **Wire through the kernel** — read the
[runtime package guide](https://github.com/pedroknigge/arkgate/blob/main/packages/runtime/README.md)
plus the [experimental surface policy](https://github.com/pedroknigge/arkgate/blob/main/docs/package-surface.md#experimental-opt-in-surfaces) before
writing code. Wire the kernel at the composition root; keep the domain
ignorant of it (handlers/ports, not kernel imports inside domain code —
the architecture check enforces this; Claude/Grok hooks can block it earlier). Note: the kernel bounds in-memory
history by default (`maxHistorySize` 1000); mention this if the hand-rolled
version retained everything.
5. **Delete the hand-rolled version** once call sites are moved — the point is
writing code.
- Call `createStrictArkKernel` (or an admission sibling: `createArkKernel`, `*FromConfig`) **only**
inside `arkRun.compositionRoots`. Each call is a new instance — no process-wide singleton.
- Keep Domain-role layers kernel-free (`ARKRUN_KERNEL_IN_DOMAIN`).
- Resolve managed types from the kernel; do not construct admitted types with `new`
(`ARKRUN_DIRECT_NEW`).
- On `register()`, declare `uses` / `reactsTo` / `raises` / `sends`. `extendedInfo` is
tooling-only and is **not** a gate verdict. Adding an existing call-site literal to the
declaration list is the only mechanical-safe ArkRun edit; inventing a new emit / handle /
depend is judgment.
- Send on kernel transport: `local` / `localBlocking` / `broker`. `ephemeral` defaults **true**.
Broker adapters are ports you inject — this package does not ship cloud SDKs. Unbound
`broker` falls back in-process local. Do not import `EventEmitter` or a homemade bus in
`managedLayers` (`ARKRUN_TRANSPORT_BYPASS`).
- Optional inspector: `startInspector()` on `127.0.0.1`, refuses `NODE_ENV=production`, no
public bind. Snapshots / `requestGraph` (process or technical + Mermaid) are tooling, not a
score. `getDependencyInformationPackage()` never includes factories, live instances, or
input DTOs.
- In-memory stores lose state on restart — **not** production durability. Note bounded history
(`maxHistorySize` 1000) if the hand-rolled version retained everything.
6. **Delete the hand-rolled version** once call sites are moved — the point is
less code, not a second parallel system. Deleting code is a destructive move:

@@ -94,2 +127,4 @@ confirm with the user before removing the old implementation, and never delete

- No static gates yet: **STOP — do not continue this skill as complete.** Run `/ark-adopt` first (`ark-check --recommend` / leftover `/ark-architect`).
- Extra absent and the user wants it: **STOP — do not continue this skill as complete.** **`/ark-adopt`** writes advisory `arkRun`.
- Skip cluster (`new` of managed types, homemade bus, kernel in Domain) after the extra is on: leftover **`/ark-fix`** / **`/ark-loop`** or **`/ark-autopilot`** — this skill still wires one candidate.
- Runtime companion unavailable from npm and no ArkGate source checkout: **STOP** and report the distribution boundary.

@@ -104,2 +139,5 @@ - Inventory finds nothing: stop; do not introduce kernel speculatively.

- Keep the migration diff reviewable: one feature per invocation.
- Skills never enforce; never weaken `ark.config.json` to skip `ARKRUN_*`.
- Never a process-wide kernel singleton. Never shipped cloud broker SDKs.
- Never claim in-memory stores are production-durable.
- Plain-language reporting: one sentence per concept ("outbox = events are

@@ -111,4 +149,6 @@ saved in the same transaction as your data, then published — so you never

- Adopt static gates and application shape **first** (`/ark-adopt`).
- Runtime kernel is optional and separate from enthusiast onboarding.
- Adopt static gates and application shape **first** (`/ark-adopt`). Brownfield: same door —
advisory extra only until the team promotes; absence is valid.
- Runtime kernel is optional and separate from enthusiast onboarding. Do not put `arkRun` on the
compact starter.

@@ -119,3 +159,4 @@ ## Verify and report

--strict-config`. Report: what was migrated, lines deleted vs added, remaining
candidates ranked, and any behavior differences (e.g. bounded history).
candidates ranked, behavior differences (e.g. bounded history), and **`[ArkRun]`** residual
(`ARKRUN_*` / doctor `arkRun`, `notAScore`) separately from Layers / ArkRules.

@@ -130,2 +171,3 @@ ## Completion contract (skill incomplete if missing)

- **Result:** one-line outcome
- **Planes:** **`[ArkRun]`** residual (or `n/a` if extra absent) — do not mix with `[Layer]` / `[ArkRules]`
- **Compass:** `n/a` (runtime skill; static residual → explore/fix) | top residual if doctor was run

@@ -132,0 +174,0 @@ - **Handoff:** `/ark-…` / CLI / `none`

@@ -10,3 +10,3 @@ # ArkGate Agent Skills package

Package version when last generated context: **arkgate@4.6.7**
Package version when last generated context: **arkgate@4.7.0**
Schema: agent-skills package contract `1.0`

@@ -13,0 +13,0 @@

@@ -23,2 +23,4 @@ ---

- CLI-first: if `arkgate-check` already resolved the root, do not wait on MCP.
- Do not add `arkRun` unless the user wants the extra. When they do, write **advisory** `arkRun`
(schema `1.2+`) in this turn. Absence is silent and valid. Skills never enforce.

@@ -98,2 +100,3 @@ Invoking this skill **is** the approval. Write the architecture config in this turn.

| Freeze **real** debt after the config is honest | User said map only |
| Turn **advisory** ArkRun on (`arkRun` extra, schema `1.2+`) | Evaluate / wire a hand-rolled bus → `/ark-runtime`; new kernel-managed file → `/ark-place` |

@@ -126,5 +129,6 @@ ## Dual engine (mandatory)

| **ArkRules** (intra-layer) | Structure inside a layer + domain invariants as data | `arkRules` map + `arkrules/<ExactLayerName>.json` | structure sensors, invariant coverage, `--rules-inventory`, doctor `rulesUnderContract` |
| **ArkRun** (extra) | Kernel usage + complete declarations | `arkRun` on `ark.config.json` (schema `1.2+`) + companion `@arkgate/runtime` | `ARKRUN_*`, doctor `arkRun` (`notAScore`) |
**Rules for every report / answer:**
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** (or a two-column table with those headers).
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** or **`[ArkRun]`** (or a two-column table with those headers).
2. Never call an import-edge violation an “invariant” or an aggregate sensor a “layer deny.”

@@ -134,2 +138,3 @@ 3. Absence of `arkRules` is **valid** — do not force ArkRules unless the user wants them or residual inventory clearly wants a pilot.

5. CLI helpers: `ark-check --rules-inventory --json`, doctor JSON `rulesUnderContract`, sensors emit `ARKRULE_*` / `INVARIANT_UNCOVERED` with `evidence.arkruleId`.
6. Absence of `arkRun` is **valid**. Write it only when the user wants the extra. Skills never enforce.

@@ -142,2 +147,12 @@

### Adopt + ArkRun
- User asked to turn the extra on: write **advisory** `arkRun` on `ark.config.json` (`schemaVersion` `1.2+`) **in this turn**. Default `"mode": "advisory"`.
- Required shape: `compositionRoots` (real files; empty + enforced fails closed), `managedLayers` (existing `layers[].name` only), `requireDeclarations` (default true).
- Do **not** put `arkRun` on the compact starter / `ark start` scaffold. Brownfield stays advisory until the team promotes.
- Absence is valid and **silent** — never force the extra. Never force the kernel over existing Nest/DI. Do not invent `/ark-run`.
- Import the companion from `@arkgate/runtime` (factory `createStrictArkKernel`, per instance, no process-wide singleton). Never a removed `arkgate/runtime` shim. No shipped cloud broker SDKs.
- In-memory stores are **not** production durability. Branding ArkRun is not a durability claim. Doctor / status `arkRun` is `notAScore`.
- Demoting enforced → advisory or deleting the extra is policy-delta **weakening**.
- After the extra is honest: handoff `/ark-runtime` to wire one candidate, `/ark-place` for new kernel-managed files. Skills never enforce.
## Subagent fan-out (optional, host-dependent)

@@ -192,2 +207,5 @@

**ApplicationOrchestration**, not Presentation — do not reclassify API shells as UI.
User wants the ArkRun extra → write **advisory** `arkRun` (schema `1.2+`, real
`compositionRoots`, existing `managedLayers`) **in this turn**. Do not add it to a compact
starter. Do not promote to enforced as the session-0 default.
2. **Check + diagnose** — `summary.concentrated` / dominant edge → fix contract first, don’t freeze.

@@ -235,2 +253,5 @@ Cross-slice / cross-context `peerIsolation` hits are judgment: extract shared or events.

- Force runtime kernel over existing Nest/DI.
- Put `arkRun` on the compact starter / `ark start` scaffold.
- Claim in-memory kernel stores are production durability.
- Invent `/ark-run`.
- Claim Enforce while governed% is low, cores empty with I/O in Application, or core bags ungoverned.

@@ -247,3 +268,3 @@ - End adopt with only “baseline written” when design-weak residual is visible in files you opened.

- **Result:** one-line outcome
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused)
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** vs **[ArkRun]** (or `n/a` if unused)
- **Compass:** top residual lenses | `n/a`

@@ -250,0 +271,0 @@ - **Done axes:** architecture residual (status/doctor/compass) | feature/ticket residual (outside package). Enforce green ≠ feature done

@@ -22,2 +22,5 @@ ---

- Do not default a repository to Presentation.
- When `arkRun` is on: scaffold through the kernel (no `new` of managed types; declare
`uses` / `reactsTo` / `raises` / `sends`). Extra off → do not introduce the kernel. Enable it
via `/ark-adopt`. Skills never enforce.

@@ -66,2 +69,3 @@ ## Autonomy contract

| Naming / directory for a known kind | Session 0 / config missing or lying → `/ark-adopt` (then come back) |
| Kernel-managed artifact when `arkRun` is already on | Extra not chosen yet → `/ark-adopt` (advisory `arkRun`); evaluate / migrate a hand-rolled bus → `/ark-runtime` |

@@ -109,5 +113,6 @@ The user describes something they need to build (a saga, a background job, an

| **ArkRules** (intra-layer) | Structure inside a layer + domain invariants as data | `arkRules` map + `arkrules/<ExactLayerName>.json` | structure sensors, invariant coverage, `--rules-inventory`, doctor `rulesUnderContract` |
| **ArkRun** (extra) | Kernel usage + complete declarations | `arkRun` on `ark.config.json` (schema `1.2+`) + companion `@arkgate/runtime` | `ARKRUN_*`, doctor `arkRun` (`notAScore`) |
**Rules for every report / answer:**
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** (or a two-column table with those headers).
1. Prefix each finding or next step with **`[Layer]`** or **`[ArkRules]`** or **`[ArkRun]`** (or a two-column table with those headers).
2. Never call an import-edge violation an “invariant” or an aggregate sensor a “layer deny.”

@@ -117,2 +122,3 @@ 3. Absence of `arkRules` is **valid** — do not force ArkRules unless the user wants them or residual inventory clearly wants a pilot.

5. CLI helpers: `ark-check --rules-inventory --json`, doctor JSON `rulesUnderContract`, sensors emit `ARKRULE_*` / `INVARIANT_UNCOVERED` with `evidence.arkruleId`.
6. Absence of `arkRun` is **valid**. Do not introduce the kernel speculatively. Skills never enforce this extra.

@@ -124,2 +130,13 @@

### Place + ArkRun
When `arkRun` is present on the architecture config:
- Scaffold kernel-managed artifacts **through the kernel**, not `new` of an admitted type (`ARKRUN_DIRECT_NEW`).
- Call `createStrictArkKernel` (or an admission sibling) only inside `arkRun.compositionRoots`. Each call is a new instance — no process-wide `getKernel()`.
- Domain-role files stay kernel-free (`ARKRUN_KERNEL_IN_DOMAIN`). Import from `@arkgate/runtime` (or `/nestjs`), never a removed `arkgate/runtime` shim.
- List `uses` / `reactsTo` / `raises` / `sends` when `requireDeclarations` is on. Adding an existing call-site literal to the declaration list is the only mechanical-safe ArkRun edit; inventing a new emit / handle / depend is judgment.
- Do not import a homemade bus (`EventEmitter`, queue clients) in `managedLayers` — send on the kernel transport (`local` / `localBlocking` / `broker`; `ephemeral` defaults true). No shipped cloud SDKs.
- In-memory stores are **not** production durability. Doctor `arkRun` is `notAScore`.
- Absence of the extra: place with **[Layer]** + **[ArkRules]** only. Enable advisory extra via `/ark-adopt`; evaluate a hand-rolled bus via `/ark-runtime`. Do not invent `/ark-run`.
- Skills never enforce.
## Subagent fan-out (optional, host-dependent)

@@ -156,2 +173,6 @@

jobs, projections → the event/workflow layers if the config declares them.
When `arkRun` is on, wire those through the kernel (register + declarations),
not a homemade emitter.
- Kernel-managed application service when `arkRun` is on → composition-root factory
+ `register({ uses, reactsTo, raises, sends })`; never `new` of the admitted type.
- **`vertical-slice` contract:** put co-located feature code under

@@ -184,2 +205,5 @@ `src/features/<slice>/…` (never import a sibling slice); shared primitives

batch reshape from this skill.
- If `arkRun` is on and the user is grinding skip violations (`new` of managed types, homemade
bus) across many files: place this artifact through the kernel, then leftover `/ark-fix` /
`/ark-autopilot`. Extra not on → `/ark-adopt` (advisory) or `/ark-runtime` (evaluate).

@@ -217,3 +241,3 @@ ## Operating rules

- **Result:** one-line outcome
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused)
- **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** vs **[ArkRun]** (or `n/a` if unused)
- **Compass:** top residual lenses | `n/a`

@@ -220,0 +244,0 @@ - **Done axes:** architecture residual (status/doctor/compass) | feature/ticket residual (outside package). Enforce green ≠ feature done

---
name: ark-runtime
description: Evaluate the experimental Ark runtime kernel against hand-rolled event bus, outbox, audit, saga, projection, policy, or NestJS code. Finds one candidate, wires one, verifies.
description: Evaluate and wire the experimental ArkRun companion (@arkgate/runtime) against hand-rolled event bus, outbox, saga, projection, policy, or NestJS code. One candidate. Extra on via /ark-adopt; new files via /ark-place. Skills never enforce.
---
# /ark-runtime — Evaluate the runtime kernel (experimental opt-in)
# /ark-runtime — Evaluate and wire ArkRun (experimental opt-in)
The runtime kernel is currently **experimental** and is not required for ArkGate enforcement or
presented as production-ready. Use this skill only when the user explicitly wants to evaluate it.
The ArkRun companion (`@arkgate/runtime`) is currently **experimental**. It is **not** required
for ArkGate enforcement and is **not** production durability. Use this skill when the user wants
to evaluate or wire the kernel. **This skill never enforces** — the write / CI / ESLint plane
does when the `arkRun` extra is on. Do **not** invent `/ark-run`.
The separate `@arkgate/runtime` source package contains the experimental runtime kernel
(`createArkKernel`) with an event bus, event contracts, outbox, audit trail,
policy engine, workflow/saga coordination, projections, observability hooks,
and NestJS adapters. The stable `arkgate` package is the architecture gate; it does not bundle
the runtime implementation. This skill migrates hand-rolled versions of those to the kernel,
one feature at a time.
**When:** evaluate a hand-rolled bus / outbox / saga / projection / policy / Nest adapter against
the companion, or wire an extra that is already on (composition root, declarations, transport).
**Not when:** session 0 / extra not chosen (`/ark-adopt`); one new file (`/ark-place`); skip-violation
grind (`/ark-autopilot` / leftover `/ark-fix`).
## Extra vs companion (mandatory)
| Piece | What it is | What it is not |
|-------|------------|----------------|
| **ArkRun extra** (`arkRun` on `ark.config.json`, schema `1.2+`) | Gate contract: kernel usage + complete declarations | A score; Layers / ArkRules replacement; merge teeth while `advisory` |
| **Companion** `@arkgate/runtime` | Kernel you construct with `createStrictArkKernel` (one instance per call) | Bundled in the `arkgate` tarball; a process-wide `getKernel()`; shipped cloud broker SDKs |
Absence of the extra is **silent** — Layers and ArkRules verdicts stay identical. Doctor / status
`arkRun` is always `notAScore`. Never invent 0–10 scores or pass/fail from this skill.
## Improvement compass note

@@ -23,2 +33,3 @@

for static architecture residual; hand static residual to `/ark-explore` / `/ark-autopilot`.
Doctor `arkRun` residual is a finding-id count (`ARKRUN_*`), never a compass score.

@@ -45,3 +56,3 @@ ## Dual engine (mandatory)

This skill is **runtime-kernel only**. Do not mix ArkRules structure/invariants here; hand off to `/ark-contract` / `/ark-adopt` / `/ark-explore` for static contract planes.
This skill is **runtime-kernel only**. Do not mix ArkRules structure/invariants here; hand off to `/ark-contract` / `/ark-adopt` / `/ark-explore` for static contract planes. Label kernel-usage residual **`[ArkRun]`** so it never blurs with **`[Layer]`** or **`[ArkRules]`**.

@@ -67,6 +78,11 @@ ## Subagent fan-out (optional, host-dependent)

adapters apply.
2. **Pick ONE target** — the smallest, most self-contained candidate (fewest
2. **Read the extra** — open `ark.config.json`. If `arkRun` is absent and the user wants the extra,
**STOP — do not continue this skill as complete.** Handoff **`/ark-adopt`** to write **advisory**
`arkRun` (schema `1.2+`; `compositionRoots`, `managedLayers`, `requireDeclarations`). Do not
invent the extra here. If the extra is present, note `mode`, roots, managed layers, and
`requireDeclarations`; doctor `arkRun` is `notAScore`.
3. **Pick ONE target** — the smallest, most self-contained candidate (fewest
call sites). Migrating everything at once is how adoptions die. List the
rest as follow-ups in the report.
3. **Resolve availability** — run `npm view @arkgate/runtime dist-tags --json`. If an
rest as follow-ups in the report. New files after the extra is on go through **`/ark-place`**.
4. **Resolve availability** — run `npm view @arkgate/runtime dist-tags --json`. If an
`experimental` tag exists, install that exact companion. Otherwise continue only from an

@@ -76,11 +92,28 @@ ArkGate source checkout: run `npm run build:runtime` at its root and install its local

runtime is unavailable; never fall back to the deprecated root shims as if they contained it.
4. **Migrate** — import from `@arkgate/runtime` or `@arkgate/runtime/nestjs`, and read the
Import from `@arkgate/runtime` (or `@arkgate/runtime/nestjs`) — never a removed `arkgate/runtime`
shim.
5. **Wire through the kernel** — read the
[runtime package guide](https://github.com/pedroknigge/arkgate/blob/main/packages/runtime/README.md)
plus the [experimental surface policy](https://github.com/pedroknigge/arkgate/blob/main/docs/package-surface.md#experimental-opt-in-surfaces) before
writing code. Wire the kernel at the composition root; keep the domain
ignorant of it (handlers/ports, not kernel imports inside domain code —
the architecture check enforces this; Claude/Grok hooks can block it earlier). Note: the kernel bounds in-memory
history by default (`maxHistorySize` 1000); mention this if the hand-rolled
version retained everything.
5. **Delete the hand-rolled version** once call sites are moved — the point is
writing code.
- Call `createStrictArkKernel` (or an admission sibling: `createArkKernel`, `*FromConfig`) **only**
inside `arkRun.compositionRoots`. Each call is a new instance — no process-wide singleton.
- Keep Domain-role layers kernel-free (`ARKRUN_KERNEL_IN_DOMAIN`).
- Resolve managed types from the kernel; do not construct admitted types with `new`
(`ARKRUN_DIRECT_NEW`).
- On `register()`, declare `uses` / `reactsTo` / `raises` / `sends`. `extendedInfo` is
tooling-only and is **not** a gate verdict. Adding an existing call-site literal to the
declaration list is the only mechanical-safe ArkRun edit; inventing a new emit / handle /
depend is judgment.
- Send on kernel transport: `local` / `localBlocking` / `broker`. `ephemeral` defaults **true**.
Broker adapters are ports you inject — this package does not ship cloud SDKs. Unbound
`broker` falls back in-process local. Do not import `EventEmitter` or a homemade bus in
`managedLayers` (`ARKRUN_TRANSPORT_BYPASS`).
- Optional inspector: `startInspector()` on `127.0.0.1`, refuses `NODE_ENV=production`, no
public bind. Snapshots / `requestGraph` (process or technical + Mermaid) are tooling, not a
score. `getDependencyInformationPackage()` never includes factories, live instances, or
input DTOs.
- In-memory stores lose state on restart — **not** production durability. Note bounded history
(`maxHistorySize` 1000) if the hand-rolled version retained everything.
6. **Delete the hand-rolled version** once call sites are moved — the point is
less code, not a second parallel system. Deleting code is a destructive move:

@@ -94,2 +127,4 @@ confirm with the user before removing the old implementation, and never delete

- No static gates yet: **STOP — do not continue this skill as complete.** Run `/ark-adopt` first (`ark-check --recommend` / leftover `/ark-architect`).
- Extra absent and the user wants it: **STOP — do not continue this skill as complete.** **`/ark-adopt`** writes advisory `arkRun`.
- Skip cluster (`new` of managed types, homemade bus, kernel in Domain) after the extra is on: leftover **`/ark-fix`** / **`/ark-loop`** or **`/ark-autopilot`** — this skill still wires one candidate.
- Runtime companion unavailable from npm and no ArkGate source checkout: **STOP** and report the distribution boundary.

@@ -104,2 +139,5 @@ - Inventory finds nothing: stop; do not introduce kernel speculatively.

- Keep the migration diff reviewable: one feature per invocation.
- Skills never enforce; never weaken `ark.config.json` to skip `ARKRUN_*`.
- Never a process-wide kernel singleton. Never shipped cloud broker SDKs.
- Never claim in-memory stores are production-durable.
- Plain-language reporting: one sentence per concept ("outbox = events are

@@ -111,4 +149,6 @@ saved in the same transaction as your data, then published — so you never

- Adopt static gates and application shape **first** (`/ark-adopt`).
- Runtime kernel is optional and separate from enthusiast onboarding.
- Adopt static gates and application shape **first** (`/ark-adopt`). Brownfield: same door —
advisory extra only until the team promotes; absence is valid.
- Runtime kernel is optional and separate from enthusiast onboarding. Do not put `arkRun` on the
compact starter.

@@ -119,3 +159,4 @@ ## Verify and report

--strict-config`. Report: what was migrated, lines deleted vs added, remaining
candidates ranked, and any behavior differences (e.g. bounded history).
candidates ranked, behavior differences (e.g. bounded history), and **`[ArkRun]`** residual
(`ARKRUN_*` / doctor `arkRun`, `notAScore`) separately from Layers / ArkRules.

@@ -130,2 +171,3 @@ ## Completion contract (skill incomplete if missing)

- **Result:** one-line outcome
- **Planes:** **`[ArkRun]`** residual (or `n/a` if extra absent) — do not mix with `[Layer]` / `[ArkRules]`
- **Compass:** `n/a` (runtime skill; static residual → explore/fix) | top residual if doctor was run

@@ -132,0 +174,0 @@ - **Handoff:** `/ark-…` / CLI / `none`

/**
* Type vocabulary for the ark.config.json contract (U02 pilot 1).
*
* Pure declarations only — no runtime values. The loader/validator logic and the
* published JSON Schema live in ./configContract.ts, whose generated CLI artifact
* must stay self-contained: type-only imports/exports are erased on transpile, so
* this split never reaches bin/lib/config-contract.mjs.
*/
type ArkConfigSchemaVersion = '1.0' | '1.1';
type ArkConfigCyclePolicy = 'strict' | 'soft' | 'framework-soft' | 'off';
type ArkConfigLayerCapabilities = {
deny?: string[];
};
type ArkConfigLayer = {
name: string;
patterns: string[];
exclude?: string[];
intentPrefixes?: string[];
description?: string;
forbiddenGlobals?: string[];
/** ADR 0009 D2 — opt-in effect-capability walls; absence changes no verdict. */
capabilities?: ArkConfigLayerCapabilities;
/** Dual-depth sugar: `pure: true` denies all seven capabilities. */
pure?: boolean;
mayImportInfrastructure?: boolean;
optional?: boolean;
/**
* Future house: empty globs are expected. `--strict-config` must not fail.
* Typo warning (`CONFIG_LAYER_PATTERN_NO_MATCHES`) is skipped.
*/
reserved?: boolean;
/** Alias of reserved — empty pattern matches are allowed. */
allowEmpty?: boolean;
};
type ArkConfigRule = {
from: string;
to: string;
allowed: boolean;
message?: string;
peerIsolation?: boolean;
sliceFolders?: string[];
};
type ArkConfigSafety = {
maxTsSuppressions?: number;
maxAnyCasts?: number;
allowInMemory?: boolean;
allowDisabledPeerIsolation?: boolean;
};
/**
* ADR 0012 — optional map of layer name → project-relative ArkRules file path.
* Absence changes no inter-layer verdict.
*/
type ArkConfigArkRulesRefs = Record<string, string>;
type ArkConfig = {
$schema: string;
schemaVersion: ArkConfigSchemaVersion;
name?: string;
include: string[];
exclude?: string[];
excludeGenerated?: boolean;
frameworkOverlay?: string;
layers: ArkConfigLayer[];
rules: ArkConfigRule[];
cyclePolicy?: ArkConfigCyclePolicy;
dynamicImportAllowlist?: string[];
safety?: ArkConfigSafety;
/** ADR 0012 — modular ArkRules references (schema 1.1+). */
arkRules?: ArkConfigArkRulesRefs;
/**
* Optional GitHub handles or emails who may loosen the contract or grow the baseline.
* Metadata — excluded from policy hash. Absence means no steward lock (policy-ack still applies).
*/
stewards?: string[];
};
type ArkConfigIssue = {
path: string;
message: string;
};
/** Original input version when the loader rewrote schemaVersion toward current. */
type ArkConfigMigratedFrom = 'unversioned' | '1.0' | null;
type ArkConfigLoadResult = {
config: ArkConfig;
migratedFrom: ArkConfigMigratedFrom;
};
export type { ArkConfig as A, ArkConfigRule as a, ArkConfigSchemaVersion as b, ArkConfigLoadResult as c, ArkConfigLayer as d, ArkConfigIssue as e };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display