arkgate 4.8.11 → 4.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -2
- package/README.md +22 -32
- package/bin/ark-check-runtime.mjs +2 -0
- package/bin/lib/analysis-engine.mjs +4 -4
- package/bin/lib/ark-order-doctor.mjs +154 -0
- package/bin/lib/ark-order-report.mjs +64 -0
- package/bin/lib/ark-order-sensors.mjs +1 -1
- package/bin/lib/diagnostic-catalog.mjs +2 -2
- package/bin/lib/doctor-advisories.mjs +91 -18
- package/bin/lib/doctor-human.mjs +2 -10
- package/bin/lib/doctor-plan.mjs +4 -3
- package/bin/lib/extra-merge-teeth.mjs +32 -4
- package/bin/lib/html-report-advisories.mjs +2 -0
- package/bin/lib/html-report-depth.mjs +8 -18
- package/bin/lib/html-report.mjs +16 -0
- package/bin/lib/remediation.mjs +5 -5
- package/bin/lib/rules-under-contract.mjs +14 -0
- package/bin/lib/start-preview.mjs +1 -0
- package/bin/lib/status-command.mjs +28 -0
- package/bin/lib/status-manifest.mjs +23 -0
- package/bin/lib/violations.mjs +10 -1
- package/dist/{diagnosticCatalog-DiflIock.d.ts → diagnosticCatalog-DA565Lja.d.ts} +1 -1
- package/dist/eslint/index.cjs +4 -4
- package/dist/eslint/index.js +4 -4
- package/dist/index.cjs +31 -31
- package/dist/index.d.ts +71 -3
- package/dist/index.js +31 -31
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/runtime/index.cjs +15 -15
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +15 -15
- package/docs/README.md +4 -3
- package/docs/agent-guide.md +2 -1
- package/docs/arkorder.md +28 -10
- package/docs/package-surface.md +2 -1
- package/docs/product-voice.md +9 -8
- package/docs/use.md +1 -1
- package/package.json +1 -1
- package/schemas/ark.status-manifest.schema.json +47 -0
- package/server.json +2 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Canonical algorithm: src/domain/arkOrderDoctor.ts
|
|
5
|
+
* Regenerate: node scripts/generate-cli-pure.mjs
|
|
6
|
+
* Drift check: node scripts/generate-cli-pure.mjs --check
|
|
7
|
+
*
|
|
8
|
+
* Pure CLI helper (bin/lib/ark-order-doctor.mjs). Zero Node I/O.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { composeMergePlanesHonesty, extraMergeTeethAllowed, isArkOrderRuleId, } from './extra-merge-teeth.mjs';
|
|
12
|
+
export const ARK_ORDER_DOCTOR_SCHEMA_VERSION = '1.0';
|
|
13
|
+
const RESIDUAL_RULE_CAP = 12;
|
|
14
|
+
export const ARKORDER_ONE_BREATH = 'Layers stop a bad import. ArkOrder stops rewriting a big product choice — like the billing plan — as if it were a seat count. Change those choices through a valve, not a generic update.';
|
|
15
|
+
function closedMode(value) {
|
|
16
|
+
return value === 'enforced' || value === 'advisory' ? value : null;
|
|
17
|
+
}
|
|
18
|
+
function uniqueArkOrderRuleIds(findings) {
|
|
19
|
+
const seen = new Set();
|
|
20
|
+
if (!Array.isArray(findings))
|
|
21
|
+
return [];
|
|
22
|
+
for (const finding of findings) {
|
|
23
|
+
const id = finding?.ruleId;
|
|
24
|
+
if (typeof id !== 'string' || !isArkOrderRuleId(id) || seen.has(id))
|
|
25
|
+
continue;
|
|
26
|
+
seen.add(id);
|
|
27
|
+
}
|
|
28
|
+
return [...seen].sort((left, right) => (left < right ? -1 : left > right ? 1 : 0));
|
|
29
|
+
}
|
|
30
|
+
function extraFromConfig(arkOrder) {
|
|
31
|
+
if (!arkOrder || typeof arkOrder !== 'object') {
|
|
32
|
+
return { present: false, mode: null, roots: 0, layers: 0, xiKeys: [] };
|
|
33
|
+
}
|
|
34
|
+
const xiKeys = Array.isArray(arkOrder.xiKeys)
|
|
35
|
+
? arkOrder.xiKeys.filter((key) => typeof key === 'string' && key.length > 0)
|
|
36
|
+
: [];
|
|
37
|
+
return {
|
|
38
|
+
present: true,
|
|
39
|
+
mode: closedMode(arkOrder.mode),
|
|
40
|
+
roots: Array.isArray(arkOrder.planeRoots) ? arkOrder.planeRoots.length : 0,
|
|
41
|
+
layers: Array.isArray(arkOrder.managedLayers) ? arkOrder.managedLayers.length : 0,
|
|
42
|
+
xiKeys,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Doctor / HTML ArkOrder advisory. Always emitted; absence is an honest silent row.
|
|
47
|
+
*/
|
|
48
|
+
export function summarizeArkOrderSection(input = {}) {
|
|
49
|
+
const extra = extraFromConfig(input.arkOrder);
|
|
50
|
+
const uniqueIds = extra.present ? uniqueArkOrderRuleIds(input.findings) : [];
|
|
51
|
+
const ruleIds = uniqueIds.slice(0, RESIDUAL_RULE_CAP);
|
|
52
|
+
const residualCount = uniqueIds.length;
|
|
53
|
+
const mergePlanes = composeMergePlanesHonesty({
|
|
54
|
+
classification: input.classification,
|
|
55
|
+
arkRules: {
|
|
56
|
+
active: input.arkRules?.active === true,
|
|
57
|
+
structureEnforced: input.arkRules?.structureEnforced,
|
|
58
|
+
structureTotal: input.arkRules?.structureTotal,
|
|
59
|
+
structureAdvisory: input.arkRules?.structureAdvisory,
|
|
60
|
+
invariantEnforced: input.arkRules?.invariantEnforced,
|
|
61
|
+
invariantTotal: input.arkRules?.invariantTotal,
|
|
62
|
+
invariantAdvisory: input.arkRules?.invariantAdvisory,
|
|
63
|
+
covered: input.arkRules?.covered,
|
|
64
|
+
uncovered: input.arkRules?.uncovered,
|
|
65
|
+
},
|
|
66
|
+
arkRun: {
|
|
67
|
+
present: input.arkRun?.present === true,
|
|
68
|
+
mode: input.arkRun?.mode ?? null,
|
|
69
|
+
residualCount: input.arkRun?.residualCount,
|
|
70
|
+
},
|
|
71
|
+
arkOrder: {
|
|
72
|
+
present: extra.present,
|
|
73
|
+
mode: extra.mode,
|
|
74
|
+
residualCount,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
const extraMergeTeeth = extra.present && extra.mode === 'enforced' && extraMergeTeethAllowed(input.classification);
|
|
78
|
+
let note;
|
|
79
|
+
if (!extra.present) {
|
|
80
|
+
note = 'Absence of arkOrder is silent — Layers verdicts unchanged. Not a score.';
|
|
81
|
+
}
|
|
82
|
+
else if (extra.mode === 'advisory') {
|
|
83
|
+
note =
|
|
84
|
+
'Advisory ArkOrder residual only — never flips valid or --strict-merge. Residual is a finding-id count, never a score.';
|
|
85
|
+
}
|
|
86
|
+
else if (extraMergeTeeth) {
|
|
87
|
+
note =
|
|
88
|
+
'Enforced ArkOrder is on the extra merge plane. Residual is a finding-id count, never a score.';
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
note =
|
|
92
|
+
'Enforced ArkOrder extra teeth stay demoted until the layer plane is honestly classified. Residual is a finding-id count, never a score.';
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
schemaVersion: ARK_ORDER_DOCTOR_SCHEMA_VERSION,
|
|
96
|
+
notAScore: true,
|
|
97
|
+
active: extra.present,
|
|
98
|
+
mode: extra.mode,
|
|
99
|
+
planeRoots: extra.roots,
|
|
100
|
+
managedLayers: extra.layers,
|
|
101
|
+
xiKeys: extra.xiKeys,
|
|
102
|
+
residual: { count: residualCount, ruleIds },
|
|
103
|
+
extraMergeTeeth,
|
|
104
|
+
failMergeWhen: mergePlanes.failMergeWhen,
|
|
105
|
+
note,
|
|
106
|
+
mergePlanes,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Thin status slice — counts only; residual null means unknown, not green. */
|
|
110
|
+
export function projectStatusArkOrder(input = {}) {
|
|
111
|
+
const present = input.present === true;
|
|
112
|
+
const mode = closedMode(input.mode);
|
|
113
|
+
const residualRaw = input.residual;
|
|
114
|
+
let residual = null;
|
|
115
|
+
if (typeof residualRaw === 'number' && Number.isFinite(residualRaw) && residualRaw >= 0) {
|
|
116
|
+
residual = Math.floor(residualRaw);
|
|
117
|
+
}
|
|
118
|
+
if (!present)
|
|
119
|
+
residual = residual == null ? 0 : residual;
|
|
120
|
+
return {
|
|
121
|
+
notAScore: true,
|
|
122
|
+
present,
|
|
123
|
+
mode: present ? mode : null,
|
|
124
|
+
extraMergeTeeth: present && mode === 'enforced' && input.extraMergeTeeth === true,
|
|
125
|
+
residual,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export function formatArkOrderDoctorLines(section) {
|
|
129
|
+
if (!section || section.notAScore !== true)
|
|
130
|
+
return [];
|
|
131
|
+
if (section.active !== true) {
|
|
132
|
+
return ['ArkOrder extra is off — silent on Layers (not a score).'];
|
|
133
|
+
}
|
|
134
|
+
const mode = section.mode ?? 'unknown';
|
|
135
|
+
const teeth = section.extraMergeTeeth === true ? 'armed' : 'not armed';
|
|
136
|
+
const keys = section.xiKeys.length > 0 ? section.xiKeys.join(', ') : '(none named — field-write sensor silent)';
|
|
137
|
+
const lines = [
|
|
138
|
+
ARKORDER_ONE_BREATH,
|
|
139
|
+
`mode: ${mode} · xiKeys: ${keys} · extra merge teeth ${teeth} · not a score`,
|
|
140
|
+
];
|
|
141
|
+
if (section.residual.count > 0) {
|
|
142
|
+
const shown = section.residual.ruleIds.join(', ');
|
|
143
|
+
const more = section.residual.count > section.residual.ruleIds.length
|
|
144
|
+
? ` (+${section.residual.count - section.residual.ruleIds.length} more)`
|
|
145
|
+
: '';
|
|
146
|
+
lines.push(`Residual: ${shown}${more}`);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
lines.push('Residual: none on this scan (not a score — green extras ≠ a frozen billing plan).');
|
|
150
|
+
}
|
|
151
|
+
if (section.failMergeWhen)
|
|
152
|
+
lines.push(section.failMergeWhen);
|
|
153
|
+
return lines;
|
|
154
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML for the doctor ArkOrder advisory (report parity: data-advisory="arkOrder").
|
|
3
|
+
*/
|
|
4
|
+
import { ARKORDER_ONE_BREATH } from './ark-order-doctor.mjs';
|
|
5
|
+
|
|
6
|
+
export function formatArkOrderHtml(section, esc) {
|
|
7
|
+
if (!section || typeof section !== 'object' || section.notAScore !== true) return '';
|
|
8
|
+
const escape = typeof esc === 'function' ? esc : (v) => String(v);
|
|
9
|
+
const note = section.note ? `<p class="muted">${escape(section.note)}</p>` : '';
|
|
10
|
+
if (section.active !== true) {
|
|
11
|
+
return `
|
|
12
|
+
<section class="section card" data-advisory="arkOrder">
|
|
13
|
+
<h2>ArkOrder <span class="muted">(opt-in extra — not a score)</span></h2>
|
|
14
|
+
<p class="dim" style="margin:.15rem 0 .55rem;font-size:.88rem">
|
|
15
|
+
${ARKORDER_ONE_BREATH}
|
|
16
|
+
Off until you turn it on — Layers stay the same.
|
|
17
|
+
</p>
|
|
18
|
+
${note}
|
|
19
|
+
</section>`;
|
|
20
|
+
}
|
|
21
|
+
const residual = section.residual && typeof section.residual === 'object' ? section.residual : { count: 0, ruleIds: [] };
|
|
22
|
+
const ids = Array.isArray(residual.ruleIds) ? residual.ruleIds : [];
|
|
23
|
+
const residualHtml =
|
|
24
|
+
residual.count > 0
|
|
25
|
+
? `<p><span class="tag warn">residual</span> ${ids
|
|
26
|
+
.map((id) => `<code>${escape(id)}</code>`)
|
|
27
|
+
.join(' · ')}${
|
|
28
|
+
residual.count > ids.length ? ` <span class="muted">(+${residual.count - ids.length} more)</span>` : ''
|
|
29
|
+
}</p>`
|
|
30
|
+
: '<p class="muted">Residual: none on this scan (not a score — green extras ≠ a frozen billing plan).</p>';
|
|
31
|
+
const teeth = section.extraMergeTeeth === true
|
|
32
|
+
? '<span class="tag">extra merge teeth armed</span>'
|
|
33
|
+
: '<span class="tag warn">extra merge teeth not armed</span>';
|
|
34
|
+
const mergeSentence =
|
|
35
|
+
section.mergePlanes && typeof section.mergePlanes.failMergeWhen === 'string'
|
|
36
|
+
? section.mergePlanes.failMergeWhen
|
|
37
|
+
: section.failMergeWhen;
|
|
38
|
+
const merge =
|
|
39
|
+
mergeSentence
|
|
40
|
+
? `<p class="muted" style="margin:.35rem 0 .55rem;font-size:.86rem"><b>Merge planes:</b> ${escape(mergeSentence)}</p>`
|
|
41
|
+
: '';
|
|
42
|
+
const keys = Array.isArray(section.xiKeys) && section.xiKeys.length > 0
|
|
43
|
+
? section.xiKeys.map((key) => `<code>${escape(key)}</code>`).join(' · ')
|
|
44
|
+
: '<span class="muted">(none named — field-write sensor silent)</span>';
|
|
45
|
+
return `
|
|
46
|
+
<section class="section card" data-advisory="arkOrder">
|
|
47
|
+
<h2>ArkOrder <span class="muted">(not a score)</span></h2>
|
|
48
|
+
<p class="dim" style="margin:.15rem 0 .55rem;font-size:.88rem">
|
|
49
|
+
<b>[ArkOrder]</b> ${ARKORDER_ONE_BREATH}
|
|
50
|
+
Separate from <b>[Layer]</b> imports, <b>[ArkRules]</b> shape, and <b>[ArkRun]</b> travel.
|
|
51
|
+
</p>
|
|
52
|
+
${merge}
|
|
53
|
+
<div class="kpis" style="margin-bottom:.55rem">
|
|
54
|
+
<div class="kpi"><b>${escape(section.mode || '—')}</b><span>Mode</span></div>
|
|
55
|
+
<div class="kpi"><b>${Number(residual.count) || 0}</b><span>Residual ids</span></div>
|
|
56
|
+
<div class="kpi"><b>${Number(section.planeRoots) || 0}</b><span>Plane roots</span></div>
|
|
57
|
+
<div class="kpi"><b>${Number(section.managedLayers) || 0}</b><span>Managed layers</span></div>
|
|
58
|
+
</div>
|
|
59
|
+
<p>${teeth} · <code>notAScore</code></p>
|
|
60
|
+
<p class="dim" style="margin:.35rem 0 .55rem;font-size:.86rem">xiKeys: ${keys}</p>
|
|
61
|
+
${residualHtml}
|
|
62
|
+
${note}
|
|
63
|
+
</section>`;
|
|
64
|
+
}
|
|
@@ -219,7 +219,7 @@ export function evaluateArkOrderSensors(input) {
|
|
|
219
219
|
continue;
|
|
220
220
|
if (!matchesArkOrderAppliesTo(write.file, extra.appliesTo))
|
|
221
221
|
continue;
|
|
222
|
-
findings.push(finding(extra, 'arkorder-xi-field-write', write.file, write.line, `
|
|
222
|
+
findings.push(finding(extra, 'arkorder-xi-field-write', write.file, write.line, `This file writes ${JSON.stringify(write.key)} the same way it would write a seat count. Take the event in, or change that choice through the valve (propose, then apply).`, { fromLayer, target: write.key }, teethAllowed));
|
|
223
223
|
}
|
|
224
224
|
findings.sort((left, right) => left.file.localeCompare(right.file) ||
|
|
225
225
|
left.ruleId.localeCompare(right.ruleId) ||
|
|
@@ -68,10 +68,10 @@ export const DIAGNOSTIC_CATALOG = Object.freeze([
|
|
|
68
68
|
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.'),
|
|
69
69
|
entry('ARKORDER_MISSING_PLANE', 'arkorder', 'No createOrderPlane in plane roots', 'The ArkOrder extra is on but no createOrderPlane factory was found in arkOrder.planeRoots, so agents can skip the pattern plane while the write gate stays green.', 'Import createOrderPlane from arkgate/order and call it in a plane root listed in arkOrder.planeRoots, then preflight again. Never mechanical-safe — factory placement is a design decision.'),
|
|
70
70
|
entry('ARKORDER_KERNEL_IN_DOMAIN', 'arkorder', 'Domain-role layer imports the order plane', 'A Domain-role layer imports arkgate/order. Domain stays plane-free; planeRoots own the factory.', 'Move the arkgate/order import out of the Domain-role layer into a plane root or adapter, then preflight again. Never mechanical-safe.'),
|
|
71
|
-
entry('ARKORDER_GENERIC_UPDATE', 'arkorder', 'Generic update of
|
|
71
|
+
entry('ARKORDER_GENERIC_UPDATE', 'arkorder', 'Generic update of a big product choice', 'A call to update/patch/set rewrites a named product choice (like billing plan) as if it were a seat count.', 'Don\'t use a generic update. First freeze with release(). Later, propose the change, then apply it.'),
|
|
72
72
|
entry('ARKORDER_TOO_MANY_PARAMS', 'arkorder', 'Too many slow keys', 'ξ has more keys than arkOrder.maxXiKeys. Haken requires a few slow modes, not a dump of microstate.', 'Cut ξ to the slow keys that actually slave the rest, then preflight again. Never mechanical-safe.'),
|
|
73
73
|
entry('ARKORDER_INGEST_WRITES_XI', 'arkorder', 'ingest assigned into ξ', 'An ingest() result is written into a Release or ξ store. ingest may absorb, escalate_up, or hold; it never mints a pattern.', 'Keep ingest results as absorb/escalate_up/hold only. Change ξ with proposeRelease then apply(ProposeResult). Never mechanical-safe.'),
|
|
74
|
-
entry('ARKORDER_XI_FIELD_WRITE', 'arkorder', '
|
|
74
|
+
entry('ARKORDER_XI_FIELD_WRITE', 'arkorder', 'Big product choice written like a seat count', 'A use-case writes a named product choice (like billing plan) through a database update. Invoices and seats can flow. That choice cannot.', 'Keep invoices and seats as events. Change the choice through the valve (proposeRelease then apply), not a generic update.'),
|
|
75
75
|
entry('ARKORDER_INFORMATION_BUDGET', 'arkorder', 'Projection observes a forbidden kind', 'h(ξ) allowedKinds includes a kind listed in informationBudget.cannotObserve. A scale may not look at what it was told not to see.', 'Cut that kind from the projector or from cannotObserve, then preflight again. Never mechanical-safe.'),
|
|
76
76
|
entry('ARKORDER_XI_TTL', 'arkorder', 'Slow key carries a freshness field', 'ξ named ttl/freshUntil/maxAge. Freshness belongs on σ. A slow parameter that expires per transaction is not slow.', 'Move freshness onto σ (freshUntil) and keep ξ stable, then preflight again. Never mechanical-safe.'),
|
|
77
77
|
entry('ARKORDER_STALE_SIGMA', 'arkorder', 'σ is stale', 'ingest ran after σ.freshUntil (or sigmaMaxAgeMs). ξ does not TTL.', 'Call refreshSigma and ingest again, or proposeRelease then apply(ProposeResult) if the pattern changed. Never mechanical-safe.'),
|
|
@@ -21,6 +21,82 @@ import { detectGraphBlindSpots, printGraphBlindSection } from './graph-blind.mjs
|
|
|
21
21
|
import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
|
|
22
22
|
import { collectStewardNudge } from './team-parliament-io.mjs';
|
|
23
23
|
import { formatArkRunDoctorLines, summarizeArkRunSection } from './ark-run-doctor.mjs';
|
|
24
|
+
import {
|
|
25
|
+
ARKORDER_ONE_BREATH,
|
|
26
|
+
formatArkOrderDoctorLines,
|
|
27
|
+
summarizeArkOrderSection,
|
|
28
|
+
} from './ark-order-doctor.mjs';
|
|
29
|
+
import { composeMergePlanesHonesty } from './extra-merge-teeth.mjs';
|
|
30
|
+
|
|
31
|
+
export function attachExtraDoctorSections(rulesUnderContract, config, classification, findings) {
|
|
32
|
+
const arkRulesMerge = {
|
|
33
|
+
active: rulesUnderContract?.active === true,
|
|
34
|
+
structureEnforced: rulesUnderContract?.mergePlanes?.structureSensors?.enforced,
|
|
35
|
+
structureTotal: rulesUnderContract?.mergePlanes?.structureSensors?.total,
|
|
36
|
+
structureAdvisory: rulesUnderContract?.mergePlanes?.structureSensors?.advisory,
|
|
37
|
+
invariantEnforced: rulesUnderContract?.mergePlanes?.invariants?.enforced,
|
|
38
|
+
invariantTotal: rulesUnderContract?.mergePlanes?.invariants?.total,
|
|
39
|
+
invariantAdvisory: rulesUnderContract?.mergePlanes?.invariants?.advisory,
|
|
40
|
+
covered: rulesUnderContract?.mergePlanes?.invariants?.covered,
|
|
41
|
+
uncovered: rulesUnderContract?.mergePlanes?.invariants?.uncovered,
|
|
42
|
+
};
|
|
43
|
+
const arkRun = summarizeArkRunSection({
|
|
44
|
+
arkRun: config?.arkRun,
|
|
45
|
+
findings,
|
|
46
|
+
classification,
|
|
47
|
+
arkRules: arkRulesMerge,
|
|
48
|
+
});
|
|
49
|
+
const arkOrder = summarizeArkOrderSection({
|
|
50
|
+
arkOrder: config?.arkOrder,
|
|
51
|
+
findings,
|
|
52
|
+
classification,
|
|
53
|
+
arkRules: arkRulesMerge,
|
|
54
|
+
arkRun: {
|
|
55
|
+
present: arkRun.active === true,
|
|
56
|
+
mode: arkRun.mode,
|
|
57
|
+
residualCount: arkRun.residual?.count,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const mergePlanes = composeMergePlanesHonesty({
|
|
61
|
+
classification,
|
|
62
|
+
arkRules: arkRulesMerge,
|
|
63
|
+
arkRun: {
|
|
64
|
+
present: arkRun.active === true,
|
|
65
|
+
mode: arkRun.mode,
|
|
66
|
+
residualCount: arkRun.residual?.count,
|
|
67
|
+
},
|
|
68
|
+
arkOrder: {
|
|
69
|
+
present: arkOrder.active === true,
|
|
70
|
+
mode: arkOrder.mode,
|
|
71
|
+
residualCount: arkOrder.residual?.count,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (rulesUnderContract?.mergePlanes) rulesUnderContract.mergePlanes = mergePlanes;
|
|
75
|
+
arkRun.mergePlanes = mergePlanes;
|
|
76
|
+
arkRun.failMergeWhen = mergePlanes.failMergeWhen;
|
|
77
|
+
arkOrder.mergePlanes = mergePlanes;
|
|
78
|
+
arkOrder.failMergeWhen = mergePlanes.failMergeWhen;
|
|
79
|
+
return { arkRun, arkOrder, mergePlanes };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function printCompactExtraDoctorLines(advisories, io) {
|
|
83
|
+
const arkRun = advisories?.arkRun;
|
|
84
|
+
if (arkRun?.active === true && arkRun.notAScore === true) {
|
|
85
|
+
console.log('');
|
|
86
|
+
const residual = Number(arkRun.residual?.count) || 0;
|
|
87
|
+
io.line(residual > 0 ? io.warn : ' ', `ArkRun: ${arkRun.mode || 'on'} · residual=${residual} · not a score`);
|
|
88
|
+
}
|
|
89
|
+
const arkOrder = advisories?.arkOrder;
|
|
90
|
+
if (arkOrder?.active === true && arkOrder.notAScore === true) {
|
|
91
|
+
console.log('');
|
|
92
|
+
const residual = Number(arkOrder.residual?.count) || 0;
|
|
93
|
+
const keys =
|
|
94
|
+
Array.isArray(arkOrder.xiKeys) && arkOrder.xiKeys.length > 0 ? arkOrder.xiKeys.join(', ') : 'unnamed';
|
|
95
|
+
const mark = residual > 0 ? io.warn : ' ';
|
|
96
|
+
io.line(mark, ARKORDER_ONE_BREATH);
|
|
97
|
+
io.line(mark, `ArkOrder: ${arkOrder.mode || 'on'} · xiKeys=${keys} · residual=${residual} · not a score`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
24
100
|
|
|
25
101
|
function classificationFromCoverage(cov) {
|
|
26
102
|
return {
|
|
@@ -55,25 +131,12 @@ export function computeDoctorAdvisories(root, config, cov, rules, files, ts, par
|
|
|
55
131
|
: undefined);
|
|
56
132
|
const classification = classificationFromCoverage(cov);
|
|
57
133
|
const rulesUnderContract = summarizeRulesUnderContract(root, config, factPaths, classification);
|
|
58
|
-
const arkRun =
|
|
59
|
-
|
|
60
|
-
|
|
134
|
+
const { arkRun, arkOrder } = attachExtraDoctorSections(
|
|
135
|
+
rulesUnderContract,
|
|
136
|
+
config,
|
|
61
137
|
classification,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
structureEnforced: rulesUnderContract?.mergePlanes?.structureSensors?.enforced,
|
|
65
|
-
structureTotal: rulesUnderContract?.mergePlanes?.structureSensors?.total,
|
|
66
|
-
structureAdvisory: rulesUnderContract?.mergePlanes?.structureSensors?.advisory,
|
|
67
|
-
invariantEnforced: rulesUnderContract?.mergePlanes?.invariants?.enforced,
|
|
68
|
-
invariantTotal: rulesUnderContract?.mergePlanes?.invariants?.total,
|
|
69
|
-
invariantAdvisory: rulesUnderContract?.mergePlanes?.invariants?.advisory,
|
|
70
|
-
covered: rulesUnderContract?.mergePlanes?.invariants?.covered,
|
|
71
|
-
uncovered: rulesUnderContract?.mergePlanes?.invariants?.uncovered,
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
if (rulesUnderContract?.mergePlanes) {
|
|
75
|
-
rulesUnderContract.mergePlanes = arkRun.mergePlanes;
|
|
76
|
-
}
|
|
138
|
+
activeViolations
|
|
139
|
+
);
|
|
77
140
|
return {
|
|
78
141
|
contractHealth: computeContractHealth(root, config, cov, rules),
|
|
79
142
|
ambientState: computeAmbientState(ts, root, config, files),
|
|
@@ -86,6 +149,7 @@ export function computeDoctorAdvisories(root, config, cov, rules, files, ts, par
|
|
|
86
149
|
stewardNudge: collectStewardNudge(root, config),
|
|
87
150
|
rulesUnderContract,
|
|
88
151
|
arkRun,
|
|
152
|
+
arkOrder,
|
|
89
153
|
};
|
|
90
154
|
}
|
|
91
155
|
|
|
@@ -116,4 +180,13 @@ export function printDoctorAdvisories(advisories, io) {
|
|
|
116
180
|
io.line(mark, text);
|
|
117
181
|
}
|
|
118
182
|
}
|
|
183
|
+
const arkOrder = advisories.arkOrder;
|
|
184
|
+
if (arkOrder && arkOrder.notAScore === true) {
|
|
185
|
+
console.log('');
|
|
186
|
+
console.log(io.color.bold('ArkOrder (not a score)'));
|
|
187
|
+
const mark = arkOrder.active && arkOrder.residual?.count > 0 ? io.warn : ' ';
|
|
188
|
+
for (const text of formatArkOrderDoctorLines(arkOrder)) {
|
|
189
|
+
io.line(mark, text);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
119
192
|
}
|
package/bin/lib/doctor-human.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { arkCommand } from '../ark-shared.mjs';
|
|
|
7
7
|
import { operatingModeTitle } from './product-copy.mjs';
|
|
8
8
|
import { isDoctorHealthyNothingToDo } from './post-green-path.mjs';
|
|
9
9
|
import { printParseHealthSection } from './parse-health.mjs';
|
|
10
|
-
import { printDoctorAdvisories } from './doctor-advisories.mjs';
|
|
10
|
+
import { printDoctorAdvisories, printCompactExtraDoctorLines } from './doctor-advisories.mjs';
|
|
11
11
|
import { designDeltaDoctorLines } from './design-delta.mjs';
|
|
12
12
|
import { enforcementDoctorLines } from './enforcement-state.mjs';
|
|
13
13
|
import { analysisIncompleteStatement } from './analysis-completeness.mjs';
|
|
@@ -164,15 +164,7 @@ export function printDoctorCompactHuman(view) {
|
|
|
164
164
|
line(warn, nudge.ask);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
if (arkRun?.active === true && arkRun.notAScore === true) {
|
|
169
|
-
console.log('');
|
|
170
|
-
const residual = Number(arkRun.residual?.count) || 0;
|
|
171
|
-
line(
|
|
172
|
-
residual > 0 ? warn : ' ',
|
|
173
|
-
`ArkRun: ${arkRun.mode || 'on'} · residual=${residual} · not a score`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
167
|
+
printCompactExtraDoctorLines(doctorAdvisories, { line, warn });
|
|
176
168
|
|
|
177
169
|
if (violations.length === 0) {
|
|
178
170
|
if (!analysisComplete) {
|
package/bin/lib/doctor-plan.mjs
CHANGED
|
@@ -658,11 +658,11 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
658
658
|
pilotTarget: residualPilot?.pilotTarget ?? residualPilot?.pilot ?? null,
|
|
659
659
|
arkRulesMergeHonesty: rulesUnderContract?.mergePlanes
|
|
660
660
|
? {
|
|
661
|
-
active: rulesUnderContract.active === true || arkRun?.active === true,
|
|
661
|
+
active: rulesUnderContract.active === true || arkRun?.active === true || doctorAdvisories.arkOrder?.active === true,
|
|
662
662
|
...rulesUnderContract.mergePlanes,
|
|
663
663
|
}
|
|
664
|
-
: rulesUnderContract?.active === true || arkRun?.active === true
|
|
665
|
-
? { active: true, extraMergeTeeth: arkRun?.extraMergeTeeth === true }
|
|
664
|
+
: rulesUnderContract?.active === true || arkRun?.active === true || doctorAdvisories.arkOrder?.active === true
|
|
665
|
+
? { active: true, extraMergeTeeth: arkRun?.extraMergeTeeth === true || doctorAdvisories.arkOrder?.extraMergeTeeth === true }
|
|
666
666
|
: null,
|
|
667
667
|
primaryNextAction:
|
|
668
668
|
adopted === 'not-adopted' ? NOT_ADOPTED_NEXT_ACTION : postGreenPath?.action ?? dualTruthNext,
|
|
@@ -757,6 +757,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
757
757
|
...doctorAdvisories,
|
|
758
758
|
rulesUnderContract,
|
|
759
759
|
arkRun,
|
|
760
|
+
arkOrder: doctorAdvisories.arkOrder,
|
|
760
761
|
// P0-B — single anti-false-green honesty surface (never a score).
|
|
761
762
|
productHonesty,
|
|
762
763
|
governed: cov.governed,
|
|
@@ -80,7 +80,7 @@ export function demoteExtraPlaneTeethUnderClassificationFloor(violations, classi
|
|
|
80
80
|
return violations;
|
|
81
81
|
}
|
|
82
82
|
/** Stamp for extra-plane honesty: never one architecture score. */
|
|
83
|
-
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score); ArkOrder =
|
|
83
|
+
export const MERGE_PLANES_DUAL_STAMP = 'Structure = heuristics; invariants = catalog+coverage evidence (not business runtime); ArkRun = kernel usage + declarations (not a score); ArkOrder = the few big product choices (not a score). Extra planes never merge into one architecture score. Advisory ArkRules ≠ merge teeth. Advisory ArkRun ≠ merge teeth. Advisory ArkOrder ≠ merge teeth.';
|
|
84
84
|
function countOrZero(value) {
|
|
85
85
|
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
86
86
|
}
|
|
@@ -112,7 +112,14 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
112
112
|
const arkRunResidual = countOrZero(input.arkRun?.residualCount);
|
|
113
113
|
const arkRunHasEnforced = arkRunPresent && arkRunMode === 'enforced';
|
|
114
114
|
const arkRunTeeth = arkRunHasEnforced && classificationAllowsTeeth;
|
|
115
|
-
const
|
|
115
|
+
const arkOrderPresent = input.arkOrder?.present === true;
|
|
116
|
+
const arkOrderMode = input.arkOrder?.mode === 'enforced' || input.arkOrder?.mode === 'advisory'
|
|
117
|
+
? input.arkOrder.mode
|
|
118
|
+
: null;
|
|
119
|
+
const arkOrderResidual = countOrZero(input.arkOrder?.residualCount);
|
|
120
|
+
const arkOrderHasEnforced = arkOrderPresent && arkOrderMode === 'enforced';
|
|
121
|
+
const arkOrderTeeth = arkOrderHasEnforced && classificationAllowsTeeth;
|
|
122
|
+
const hasEnforcedTeeth = arkRulesHasEnforced || arkRunHasEnforced || arkOrderHasEnforced;
|
|
116
123
|
const extraMergeTeeth = hasEnforcedTeeth && classificationAllowsTeeth;
|
|
117
124
|
const teethDeferredForClassification = hasEnforcedTeeth && classificationKnown && !classificationAllowsTeeth;
|
|
118
125
|
let failMergeWhen;
|
|
@@ -122,12 +129,15 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
122
129
|
extras.push('enforced structure/invariant findings');
|
|
123
130
|
if (arkRunHasEnforced)
|
|
124
131
|
extras.push('enforced ArkRun skip findings');
|
|
132
|
+
if (arkOrderHasEnforced)
|
|
133
|
+
extras.push('enforced ArkOrder skip findings');
|
|
125
134
|
failMergeWhen = `Layer graph failures plus ${extras.join(' and ')} (advisory extras never fail merge alone).`;
|
|
126
135
|
}
|
|
127
136
|
else if (teethDeferredForClassification) {
|
|
128
137
|
const which = [
|
|
129
138
|
arkRulesHasEnforced ? 'ArkRules structure/invariant' : null,
|
|
130
139
|
arkRunHasEnforced ? 'ArkRun' : null,
|
|
140
|
+
arkOrderHasEnforced ? 'ArkOrder' : null,
|
|
131
141
|
]
|
|
132
142
|
.filter((part) => Boolean(part))
|
|
133
143
|
.join(' and ');
|
|
@@ -139,15 +149,21 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
139
149
|
: arkRunMode === 'advisory'
|
|
140
150
|
? ' Advisory ArkRun never merge-blocks.'
|
|
141
151
|
: ' ArkRun extra is present but does not arm merge teeth.';
|
|
152
|
+
const arkOrderBit = !arkOrderPresent
|
|
153
|
+
? ' Absence of arkOrder is silent.'
|
|
154
|
+
: arkOrderMode === 'advisory'
|
|
155
|
+
? ' Advisory ArkOrder never merge-blocks.'
|
|
156
|
+
: ' ArkOrder extra is present but does not arm merge teeth.';
|
|
142
157
|
failMergeWhen =
|
|
143
158
|
'Layer graph only — no enforced ArkRules structure/invariant teeth on this tree. Advisory packs do not arm merge teeth.' +
|
|
144
|
-
arkRunBit
|
|
159
|
+
arkRunBit +
|
|
160
|
+
arkOrderBit;
|
|
145
161
|
}
|
|
146
162
|
const out = {
|
|
147
163
|
layers: {
|
|
148
164
|
role: 'inter-layer-edges',
|
|
149
165
|
alwaysOnGate: true,
|
|
150
|
-
note: 'Import/export layer graph — the default merge plane. Absent
|
|
166
|
+
note: 'Import/export layer graph — the default merge plane. Absent extras change nothing here.',
|
|
151
167
|
},
|
|
152
168
|
structureSensors: {
|
|
153
169
|
role: 'intra-layer-heuristics',
|
|
@@ -177,6 +193,18 @@ export function composeMergePlanesHonesty(input = {}) {
|
|
|
177
193
|
: 'Advisory ArkRun never adds merge teeth and never flips valid. Residual is a count, never a score.'
|
|
178
194
|
: 'Absence of arkRun is silent — Layers and ArkRules verdicts unchanged. The extra never becomes a score.',
|
|
179
195
|
},
|
|
196
|
+
arkOrder: {
|
|
197
|
+
role: 'pattern-slaving',
|
|
198
|
+
present: arkOrderPresent,
|
|
199
|
+
mode: arkOrderMode,
|
|
200
|
+
residualCount: arkOrderResidual,
|
|
201
|
+
extraMergeTeeth: arkOrderTeeth,
|
|
202
|
+
note: arkOrderPresent
|
|
203
|
+
? arkOrderMode === 'enforced'
|
|
204
|
+
? 'Enforced ArkOrder arms extra merge teeth only when the layer plane is classified. Residual is a count, never a score.'
|
|
205
|
+
: 'Advisory ArkOrder never adds merge teeth and never flips valid. Residual is a count, never a score.'
|
|
206
|
+
: 'Absence of arkOrder is silent — Layers verdicts unchanged. The extra never becomes a score.',
|
|
207
|
+
},
|
|
180
208
|
extraMergeTeeth,
|
|
181
209
|
dualPlaneStamp: MERGE_PLANES_DUAL_STAMP,
|
|
182
210
|
failMergeWhen,
|
|
@@ -11,6 +11,7 @@ import { effectiveCapabilityDeny } from './analysis-engine.mjs';
|
|
|
11
11
|
import { graphBlindSpotsHtml } from './graph-blind.mjs';
|
|
12
12
|
import { formatRulesUnderContractHtml } from './rules-under-contract.mjs';
|
|
13
13
|
import { formatArkRunHtml } from './ark-run-report.mjs';
|
|
14
|
+
import { formatArkOrderHtml } from './ark-order-report.mjs';
|
|
14
15
|
import { primaryImprovementCompassNextAction } from './improvement-compass.mjs';
|
|
15
16
|
|
|
16
17
|
// htmlEscape is injected by the caller (html-report.mjs) — importing it back
|
|
@@ -353,6 +354,7 @@ export function renderAdvisorySections(advisories, escape) {
|
|
|
353
354
|
graphBlindSpotsHtml(advisories.graphBlindSpots, esc),
|
|
354
355
|
rulesUnderContractHtml(advisories.rulesUnderContract),
|
|
355
356
|
formatArkRunHtml(advisories.arkRun, esc),
|
|
357
|
+
formatArkOrderHtml(advisories.arkOrder, esc),
|
|
356
358
|
]
|
|
357
359
|
.filter(Boolean)
|
|
358
360
|
.join('\n');
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
buildProductHonesty,
|
|
20
20
|
} from './enforcement-honesty.mjs';
|
|
21
21
|
import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import { attachExtraDoctorSections } from './doctor-advisories.mjs';
|
|
23
23
|
import { readBaseline, baselineOccurrenceKeys } from './violations.mjs';
|
|
24
24
|
import { describePackageVersionDualTruth } from './field-install.mjs';
|
|
25
25
|
import { buildDoctorImprovementCompass } from './improvement-compass-doctor.mjs';
|
|
@@ -136,23 +136,12 @@ export function buildReportDepthPayload(
|
|
|
136
136
|
classifiedFiles: coverage?.governed?.classifiedFiles ?? null,
|
|
137
137
|
};
|
|
138
138
|
const rulesUnderContract = summarizeRulesUnderContract(root, config, undefined, classification);
|
|
139
|
-
const arkRun =
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const { arkRun, arkOrder } = attachExtraDoctorSections(
|
|
140
|
+
rulesUnderContract,
|
|
141
|
+
config,
|
|
142
142
|
classification,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
structureEnforced: rulesUnderContract?.mergePlanes?.structureSensors?.enforced,
|
|
146
|
-
structureTotal: rulesUnderContract?.mergePlanes?.structureSensors?.total,
|
|
147
|
-
structureAdvisory: rulesUnderContract?.mergePlanes?.structureSensors?.advisory,
|
|
148
|
-
invariantEnforced: rulesUnderContract?.mergePlanes?.invariants?.enforced,
|
|
149
|
-
invariantTotal: rulesUnderContract?.mergePlanes?.invariants?.total,
|
|
150
|
-
invariantAdvisory: rulesUnderContract?.mergePlanes?.invariants?.advisory,
|
|
151
|
-
covered: rulesUnderContract?.mergePlanes?.invariants?.covered,
|
|
152
|
-
uncovered: rulesUnderContract?.mergePlanes?.invariants?.uncovered,
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
if (rulesUnderContract?.mergePlanes) rulesUnderContract.mergePlanes = arkRun.mergePlanes;
|
|
143
|
+
activeViolations
|
|
144
|
+
);
|
|
156
145
|
// Single residual expression (parity with doctor): nextPilot || extractionCard.
|
|
157
146
|
const residualPilot =
|
|
158
147
|
pilotLoop?.nextPilot || pilotLoop?.extractionCard || null;
|
|
@@ -174,7 +163,7 @@ export function buildReportDepthPayload(
|
|
|
174
163
|
residualPilots: Boolean(residualPilot) && designFitness.designWeak === true,
|
|
175
164
|
pilotTarget: residualPilot?.pilotTarget ?? residualPilot?.pilot ?? null,
|
|
176
165
|
arkRulesMergeHonesty: rulesUnderContract?.mergePlanes
|
|
177
|
-
? { active: rulesUnderContract.active === true || arkRun?.active === true, ...rulesUnderContract.mergePlanes }
|
|
166
|
+
? { active: rulesUnderContract.active === true || arkRun?.active === true || arkOrder?.active === true, ...rulesUnderContract.mergePlanes }
|
|
178
167
|
: null,
|
|
179
168
|
primaryNextAction: postGreenPath?.action ?? dualTruthNext,
|
|
180
169
|
activeBlockingViolations: activeBlockingCount,
|
|
@@ -218,6 +207,7 @@ export function buildReportDepthPayload(
|
|
|
218
207
|
productHonesty,
|
|
219
208
|
mergePlanes: rulesUnderContract?.mergePlanes ?? null,
|
|
220
209
|
arkRun,
|
|
210
|
+
arkOrder,
|
|
221
211
|
improvementCompass,
|
|
222
212
|
deepModuleCoach,
|
|
223
213
|
},
|
package/bin/lib/html-report.mjs
CHANGED
|
@@ -152,6 +152,8 @@ export function buildReportSnapshot({
|
|
|
152
152
|
improvementCompass = null,
|
|
153
153
|
/** RN08 — thin status ArkRun slice (notAScore; residual count, never a score). */
|
|
154
154
|
arkRun = null,
|
|
155
|
+
/** Thin status ArkOrder slice (notAScore; residual count, never a score). */
|
|
156
|
+
arkOrder = null,
|
|
155
157
|
}) {
|
|
156
158
|
const layers = Array.isArray(config?.layers) ? config.layers : [];
|
|
157
159
|
const rules = Array.isArray(config?.rules) ? config.rules : [];
|
|
@@ -213,6 +215,20 @@ export function buildReportSnapshot({
|
|
|
213
215
|
: null,
|
|
214
216
|
};
|
|
215
217
|
}
|
|
218
|
+
if (arkOrder && typeof arkOrder === 'object' && arkOrder.notAScore === true) {
|
|
219
|
+
snapshot.arkOrder = {
|
|
220
|
+
notAScore: true,
|
|
221
|
+
present: arkOrder.active === true || arkOrder.present === true,
|
|
222
|
+
mode: arkOrder.mode === 'enforced' || arkOrder.mode === 'advisory' ? arkOrder.mode : null,
|
|
223
|
+
extraMergeTeeth: arkOrder.extraMergeTeeth === true,
|
|
224
|
+
residual:
|
|
225
|
+
typeof arkOrder.residual === 'number'
|
|
226
|
+
? arkOrder.residual
|
|
227
|
+
: typeof arkOrder.residual?.count === 'number'
|
|
228
|
+
? arkOrder.residual.count
|
|
229
|
+
: null,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
216
232
|
return snapshot;
|
|
217
233
|
}
|
|
218
234
|
|