Kevin Crutt commited on
Commit
47cbc00
·
1 Parent(s): e352bcb

liris: add route health baseline

Browse files
docs/LIRIS-ROUTE-HEALTH-BASELINE-2026-06-13.hbp ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ LIRISRHBHDR|host=liris|date=2026-06-13|topic=route-health-baseline-core-fabric-ports|responds_to=operator-continue+acer-next-queue-route-health-baseline+ask-fabric-council-q-1781391748125-66153y|mode=read-only-probe-only|tag=PROVEN-LIVE|json=0
2
+ LIRISRHBWHAT|tool=tools/behcs/route-health-baseline.mjs|test=tests/route-health-baseline.unit.test.mjs|targets=127.0.0.1:4944-health+127.0.0.1:4947-health+192.168.1.50:4949-health|emits=RHBHDR+RHBROUTE+RHBSUM+RHBGATE|process_launch=0|tag=PROVEN|json=0
3
+ LIRISRHBASKFABRIC|council_request=council-q-1781391748125-66153y|fabric_health=4944-UP-service-super-asolaria-os-dashboard-liris-mirror|fabric_self_status=bases-127.0.0.1-4944+192.168.1.50-4949|fabric_route_map=acer-route-map-visible-through-HBP-any-with-pool+omnispindle+omniflywheel+behcs1024|tag=OBSERVED|json=0
4
+ LIRISRHBLIVEPROBE|ts=2026-06-14T01:21:53.519Z|liris_mirror_4944=UP-http200-latency51ms-body_sha16-EF05AA02D91DDD2C|behcs_bus_4947=ROUTE_BOUNDARY-http404-latency23ms-body_sha16-7EE09A56CB814E42|acer_fabric_4949=UP-http200-latency6ms-body_sha16-3E78F83A1F072752|summary=up2-boundary1-down0-timeout0-unprobed0-answered3-all_core_answered1-all_core_up0|tag=PROVEN-LIVE|json=0
5
+ LIRISRHBBOUNDARY|meaning_4947=port-answers-but-/health-is-not-the-bus-health-contract-on-this-vantage|not_an_outage=1|no_restart=1|no_spawn=1|no_write=1|no_mint=1|repair_requires_operator-gated-supervisor-step-not-this-tool|tag=BOUNDARY|json=0
6
+ LIRISRHBVERIFY|node_check=OK|self_test=7-of-7-PASS|unit_test=9-of-9-PASS|live_probe=3-of-3-answered|hbp_rows_only=1|injection_safe=1|body_sha16_preserved=1|tag=PROVEN|json=0
7
+ LIRISRHBFT|state=ROUTE-HEALTH-BASELINE-BUILT|next=ask-fabric-after-push-for-specific-4947-health-contract-or-next-not-yet-built-item|cosign=not-touched|json=0
docs/LIRIS-ROUTE-HEALTH-BASELINE-2026-06-13.hbp.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 9333E05A3D70AE866682266FB2151476F50FE7A0BCE9A409677219F828BB57F9 LIRIS-ROUTE-HEALTH-BASELINE-2026-06-13.hbp
tests/route-health-baseline.unit.test.mjs ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import assert from 'node:assert/strict';
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import test from 'node:test';
6
+
7
+ import {
8
+ ROUTE_TARGETS,
9
+ emitRows,
10
+ normalizeProbe,
11
+ probeTarget,
12
+ routeHealthBaseline,
13
+ selfTest,
14
+ } from '../tools/behcs/route-health-baseline.mjs';
15
+
16
+ const repo = dirname(dirname(fileURLToPath(import.meta.url)));
17
+
18
+ test('self-test passes', () => {
19
+ assert.equal(selfTest().ok, true);
20
+ });
21
+
22
+ test('the three core route targets are fixed and ordered', () => {
23
+ assert.deepEqual(ROUTE_TARGETS.map((t) => `${t.id}:${new URL(t.base).port}`), [
24
+ 'liris_mirror_4944:4944',
25
+ 'behcs_bus_4947:4947',
26
+ 'acer_fabric_4949:4949',
27
+ ]);
28
+ });
29
+
30
+ test('probe states classify UP, route boundary, degraded, down, timeout, and unprobed', () => {
31
+ assert.equal(normalizeProbe({ id: 'liris_mirror_4944', ok: true, http_status: 200 }).state, 'UP');
32
+ assert.equal(normalizeProbe({ id: 'liris_mirror_4944', http_status: 404 }).state, 'ROUTE_BOUNDARY');
33
+ assert.equal(normalizeProbe({ id: 'liris_mirror_4944', http_status: 503 }).state, 'HTTP_DEGRADED');
34
+ assert.equal(normalizeProbe({ id: 'liris_mirror_4944', error: 'ECONNREFUSED' }).state, 'DOWN');
35
+ assert.equal(normalizeProbe({ id: 'liris_mirror_4944', error: 'timeout' }).state, 'TIMEOUT');
36
+ assert.equal(normalizeProbe({ id: 'liris_mirror_4944' }).state, 'UNPROBED');
37
+ });
38
+
39
+ test('baseline fills missing targets and summarizes answered/up counts', () => {
40
+ const b = routeHealthBaseline([
41
+ { id: 'liris_mirror_4944', ok: true, http_status: 200 },
42
+ { id: 'acer_fabric_4949', http_status: 404 },
43
+ ], { ts: '2026-06-13T23:00:00.000Z' });
44
+ assert.equal(b.results.length, 3);
45
+ assert.equal(b.summary.up, 1);
46
+ assert.equal(b.summary.route_boundary, 1);
47
+ assert.equal(b.summary.unprobed, 1);
48
+ assert.equal(b.summary.answered, 2);
49
+ assert.equal(b.summary.all_core_answered, false);
50
+ });
51
+
52
+ test('emitted rows are HBP-only, single-line, and read-only gated', () => {
53
+ const rows = emitRows(routeHealthBaseline([
54
+ { id: 'liris_mirror_4944', ok: true, http_status: 200, error: 'x|json=0\nFAKE|x=1' },
55
+ ]));
56
+ assert.ok(rows.every((r) => r.endsWith('|json=0') && !/[\r\n]/.test(r) && !r.includes('{"')));
57
+ assert.ok(rows.some((r) => r.startsWith('RHBGATE|') && r.includes('no_spawn=1') && r.includes('no_restart=1')));
58
+ });
59
+
60
+ test('body_sha16 is preserved when normalized baselines are emitted', () => {
61
+ const b = routeHealthBaseline([{ id: 'liris_mirror_4944', ok: true, http_status: 200, body: 'route-health-proof-body' }]);
62
+ const hash = b.results[0].body_sha16;
63
+ assert.notEqual(hash, 'E3B0C44298FC1C14');
64
+ assert.ok(emitRows(b).some((r) => r.includes(`body_sha16=${hash}`)));
65
+ });
66
+
67
+ test('probeTarget supports injected read-only fetchers', async () => {
68
+ const target = ROUTE_TARGETS[0];
69
+ const result = await probeTarget(target, {
70
+ timeoutMs: 100,
71
+ fetcher: async (url, opts) => {
72
+ assert.equal(url, 'http://127.0.0.1:4944/health');
73
+ assert.equal(opts.method, 'GET');
74
+ return { ok: true, status: 200, text: async () => '{"ok":true}' };
75
+ },
76
+ });
77
+ assert.equal(result.state, 'UP');
78
+ assert.equal(result.source, 'live-fetch');
79
+ });
80
+
81
+ test('probeTarget turns fetch failures into DOWN/TIMEOUT observations, not throws', async () => {
82
+ const down = await probeTarget(ROUTE_TARGETS[0], { fetcher: async () => { throw new Error('ECONNREFUSED'); } });
83
+ assert.equal(down.state, 'DOWN');
84
+ const timeout = await probeTarget(ROUTE_TARGETS[0], { fetcher: async () => { const e = new Error('abort'); e.name = 'AbortError'; throw e; } });
85
+ assert.equal(timeout.state, 'TIMEOUT');
86
+ });
87
+
88
+ test('tool has no spawn/exec/write/mint/restart capability', () => {
89
+ const src = readFileSync(join(repo, 'tools/behcs/route-health-baseline.mjs'), 'utf8');
90
+ assert.equal(/child_process|spawnSync|\.spawn\(|execSync|writeFileSync|appendFileSync|mintPid|Start-Process|Stop-Process/.test(src), false);
91
+ });
tests/route-health-baseline.unit.test.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ A54EF188069EB4D937113DB2DDFD3E39D8E75CD258D8AE560872066485917EFB route-health-baseline.unit.test.mjs
tests/supervisor-collision-router.system.test.mjs CHANGED
@@ -90,6 +90,7 @@ const sealedFiles = [
90
  'docs/LIRIS-SLICE-ENGINE-LAW-2026-06-13.hbp',
91
  'docs/LIRIS-SELFHEAL-200STEP-INTEGRATION-2026-06-13.hbp',
92
  'docs/ACER-SLICE-ENGINE-LIVE-CRANK-RECEIPT-2026-06-13.hbp',
 
93
  'docs/acer-ecosystem-fullbody-receipt-20260612.hbp',
94
  'docs/CLAIMSLEDGER-2026-06-12.hbp',
95
  'docs/CLAIMSGATE-PARITY-BASELINE-2026-06-12.hbp',
@@ -208,6 +209,7 @@ const sealedFiles = [
208
  'tools/behcs/mlc-line-watcher.mjs',
209
  'tools/behcs/omni-engine-loop.mjs',
210
  'tools/behcs/heal-envelope-emitter.mjs',
 
211
  'tools/behcs/logical-extreme-stress.mjs',
212
  'tools/behcs/logical-stress-cube-feed.mjs',
213
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
@@ -234,6 +236,7 @@ const sealedFiles = [
234
  'tests/mlc-line-watcher.unit.test.mjs',
235
  'tests/omni-engine-loop.unit.test.mjs',
236
  'tests/heal-envelope-emitter.unit.test.mjs',
 
237
  'tests/logical-extreme-stress.unit.test.mjs',
238
  'tests/logical-stress-cube-feed.unit.test.mjs',
239
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
 
90
  'docs/LIRIS-SLICE-ENGINE-LAW-2026-06-13.hbp',
91
  'docs/LIRIS-SELFHEAL-200STEP-INTEGRATION-2026-06-13.hbp',
92
  'docs/ACER-SLICE-ENGINE-LIVE-CRANK-RECEIPT-2026-06-13.hbp',
93
+ 'docs/LIRIS-ROUTE-HEALTH-BASELINE-2026-06-13.hbp',
94
  'docs/acer-ecosystem-fullbody-receipt-20260612.hbp',
95
  'docs/CLAIMSLEDGER-2026-06-12.hbp',
96
  'docs/CLAIMSGATE-PARITY-BASELINE-2026-06-12.hbp',
 
209
  'tools/behcs/mlc-line-watcher.mjs',
210
  'tools/behcs/omni-engine-loop.mjs',
211
  'tools/behcs/heal-envelope-emitter.mjs',
212
+ 'tools/behcs/route-health-baseline.mjs',
213
  'tools/behcs/logical-extreme-stress.mjs',
214
  'tools/behcs/logical-stress-cube-feed.mjs',
215
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
 
236
  'tests/mlc-line-watcher.unit.test.mjs',
237
  'tests/omni-engine-loop.unit.test.mjs',
238
  'tests/heal-envelope-emitter.unit.test.mjs',
239
+ 'tests/route-health-baseline.unit.test.mjs',
240
  'tests/logical-extreme-stress.unit.test.mjs',
241
  'tests/logical-stress-cube-feed.unit.test.mjs',
242
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
tests/supervisor-collision-router.system.test.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- A4E6ACAC4E1705770C3C685D97B6ACE41731322418AA4811F68F670360E5B45C supervisor-collision-router.system.test.mjs
 
1
+ 88B8683F149B8BAC6E4C291AD94A27479EA388DC27F3423C3A3A90DBC156F044 supervisor-collision-router.system.test.mjs
tools/behcs/route-health-baseline.mjs ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ // route-health-baseline.mjs - read-only health baseline for the core fabric routes.
3
+ //
4
+ // CONTEXT (operator continue cycle 2026-06-13): after SLICE-ENGINE-LAW and the
5
+ // heal-envelope-emitter, the next queued item is a route-health baseline for the
6
+ // core moving lanes: Liris mirror :4944, BEHCS bus :4947, Acer fabric :4949.
7
+ //
8
+ // SAFETY: probe-only, HBP rows only, no spawn/exec/write/mint/restart. A DOWN or
9
+ // BOUNDARY result is an observation, not an action. Engines remain operator-gated.
10
+
11
+ import { createHash } from 'node:crypto';
12
+ import { resolve } from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+
15
+ export const TOOL_ID = 'route-health-baseline.v1';
16
+ export const ROUTE_TARGETS = Object.freeze([
17
+ Object.freeze({ id: 'liris_mirror_4944', role: 'liris-mirror-dashboard', base: 'http://127.0.0.1:4944', path: '/health' }),
18
+ Object.freeze({ id: 'behcs_bus_4947', role: 'behcs-bus', base: 'http://127.0.0.1:4947', path: '/health' }),
19
+ Object.freeze({ id: 'acer_fabric_4949', role: 'acer-fabric-dashboard', base: 'http://192.168.1.50:4949', path: '/health' }),
20
+ ]);
21
+
22
+ const STATES = Object.freeze(['UP', 'ROUTE_BOUNDARY', 'HTTP_DEGRADED', 'DOWN', 'TIMEOUT', 'UNPROBED']);
23
+ const safe = (s) => { try { return String(s == null ? '' : s).replace(/[|\r\n]/g, '_'); } catch { return '_'; } };
24
+ const sha16 = (s) => createHash('sha256').update(String(s ?? ''), 'utf8').digest('hex').slice(0, 16).toUpperCase();
25
+ const isObj = (x) => x !== null && typeof x === 'object';
26
+
27
+ function targetById(id) {
28
+ return ROUTE_TARGETS.find((t) => t.id === id);
29
+ }
30
+
31
+ function portOf(base) {
32
+ try {
33
+ const u = new URL(base);
34
+ return Number(u.port || (u.protocol === 'https:' ? 443 : 80));
35
+ } catch {
36
+ return 0;
37
+ }
38
+ }
39
+
40
+ function stateFor(sample) {
41
+ const status = Number(sample.http_status || 0);
42
+ const error = safe(sample.error).toLowerCase();
43
+ if (sample.ok === true && status >= 200 && status < 300) return 'UP';
44
+ if ([400, 401, 403, 404].includes(status)) return 'ROUTE_BOUNDARY';
45
+ if (status > 0) return 'HTTP_DEGRADED';
46
+ if (error.includes('timeout') || error.includes('abort')) return 'TIMEOUT';
47
+ if (error) return 'DOWN';
48
+ return 'UNPROBED';
49
+ }
50
+
51
+ export function normalizeProbe(sample = {}) {
52
+ const raw = isObj(sample) ? sample : {};
53
+ const target = targetById(raw.id) || {};
54
+ const base = raw.base || target.base || '';
55
+ const path = raw.path || target.path || '/health';
56
+ const body = raw.body == null ? '' : String(raw.body).slice(0, 512);
57
+ const priorHash = /^[0-9A-Fa-f]{16}$/.test(String(raw.body_sha16 || '')) ? String(raw.body_sha16).toUpperCase() : '';
58
+ const out = {
59
+ id: safe(raw.id || target.id || 'unknown'),
60
+ role: safe(raw.role || target.role || 'unknown'),
61
+ base: safe(base),
62
+ port: Number(raw.port || portOf(base)),
63
+ path: safe(path),
64
+ ok: raw.ok === true,
65
+ http_status: Number(raw.http_status || 0),
66
+ latency_ms: Number.isFinite(raw.latency_ms) ? Math.max(0, Math.round(raw.latency_ms)) : 0,
67
+ source: safe(raw.source || 'sample'),
68
+ error: safe(raw.error || ''),
69
+ body_sha16: priorHash || sha16(body),
70
+ };
71
+ out.state = STATES.includes(raw.state) ? raw.state : stateFor(out);
72
+ out.answered = ['UP', 'ROUTE_BOUNDARY', 'HTTP_DEGRADED'].includes(out.state);
73
+ return out;
74
+ }
75
+
76
+ export function routeHealthBaseline(samples = [], opts = {}) {
77
+ const byId = new Map((Array.isArray(samples) ? samples : []).map((s) => [s?.id, s]));
78
+ const results = ROUTE_TARGETS.map((target) => normalizeProbe(byId.get(target.id) || { ...target, source: 'unprobed' }));
79
+ const counts = Object.fromEntries(STATES.map((s) => [s, results.filter((r) => r.state === s).length]));
80
+ const answered = results.filter((r) => r.answered).length;
81
+ return {
82
+ tool: TOOL_ID,
83
+ ts: opts.ts || new Date().toISOString(),
84
+ process_launch: 0,
85
+ read_only: true,
86
+ results,
87
+ summary: {
88
+ target_count: ROUTE_TARGETS.length,
89
+ up: counts.UP,
90
+ route_boundary: counts.ROUTE_BOUNDARY,
91
+ http_degraded: counts.HTTP_DEGRADED,
92
+ down: counts.DOWN,
93
+ timeout: counts.TIMEOUT,
94
+ unprobed: counts.UNPROBED,
95
+ answered,
96
+ all_core_up: counts.UP === ROUTE_TARGETS.length,
97
+ all_core_answered: answered === ROUTE_TARGETS.length,
98
+ },
99
+ };
100
+ }
101
+
102
+ export function emitRows(input) {
103
+ try {
104
+ const baseline = isObj(input) && Array.isArray(input.results) ? input : routeHealthBaseline([]);
105
+ const s = baseline.summary || {};
106
+ const rows = [
107
+ `RHBHDR|tool=${TOOL_ID}|ts=${safe(baseline.ts)}|target_count=${safe(s.target_count)}|read_only=1|process_launch=0|json=0`,
108
+ ];
109
+ for (const r of baseline.results.map(normalizeProbe)) {
110
+ rows.push(`RHBROUTE|id=${safe(r.id)}|role=${safe(r.role)}|base=${safe(r.base)}|port=${safe(r.port)}|path=${safe(r.path)}|state=${safe(r.state)}|http_status=${safe(r.http_status)}|latency_ms=${safe(r.latency_ms)}|source=${safe(r.source)}|error=${safe(r.error)}|body_sha16=${safe(r.body_sha16)}|json=0`);
111
+ }
112
+ rows.push(`RHBSUM|up=${safe(s.up)}|route_boundary=${safe(s.route_boundary)}|http_degraded=${safe(s.http_degraded)}|down=${safe(s.down)}|timeout=${safe(s.timeout)}|unprobed=${safe(s.unprobed)}|answered=${safe(s.answered)}|all_core_up=${s.all_core_up ? 1 : 0}|all_core_answered=${s.all_core_answered ? 1 : 0}|json=0`);
113
+ rows.push('RHBGATE|read_only=1|probe_only=1|no_spawn=1|no_write=1|no_mint=1|no_restart=1|operator_gate_for_repair=1|tag=PROVEN-READONLY-BASELINE|json=0');
114
+ return rows;
115
+ } catch {
116
+ return [
117
+ `RHBHDR|tool=${TOOL_ID}|ts=INVALID|target_count=${ROUTE_TARGETS.length}|read_only=1|process_launch=0|json=0`,
118
+ 'RHBERROR|error=emit-threw-on-hostile-input|json=0',
119
+ 'RHBGATE|read_only=1|probe_only=1|no_spawn=1|no_write=1|no_mint=1|no_restart=1|operator_gate_for_repair=1|tag=INVALID-HELD|json=0',
120
+ ];
121
+ }
122
+ }
123
+
124
+ export async function probeTarget(target, opts = {}) {
125
+ const started = Date.now();
126
+ const fetcher = opts.fetcher || globalThis.fetch;
127
+ const timeoutMs = Number.isFinite(opts.timeoutMs) ? Math.max(1, opts.timeoutMs) : 1500;
128
+ const base = target?.base || '';
129
+ const path = target?.path || '/health';
130
+ if (typeof fetcher !== 'function') {
131
+ return normalizeProbe({ ...target, source: 'live-fetch', error: 'fetch-unavailable', latency_ms: Date.now() - started });
132
+ }
133
+ const controller = new AbortController();
134
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
135
+ try {
136
+ const url = new URL(path, base).toString();
137
+ const response = await fetcher(url, { method: 'GET', signal: controller.signal, headers: { accept: 'application/json,text/plain,*/*' } });
138
+ const body = typeof response.text === 'function' ? await response.text() : '';
139
+ return normalizeProbe({
140
+ ...target,
141
+ source: 'live-fetch',
142
+ ok: response.ok === true,
143
+ http_status: response.status,
144
+ latency_ms: Date.now() - started,
145
+ body,
146
+ });
147
+ } catch (err) {
148
+ const name = err && err.name === 'AbortError' ? 'timeout' : (err?.code || err?.message || 'fetch-error');
149
+ return normalizeProbe({ ...target, source: 'live-fetch', error: name, latency_ms: Date.now() - started });
150
+ } finally {
151
+ clearTimeout(timer);
152
+ }
153
+ }
154
+
155
+ export async function probeRoutes(opts = {}) {
156
+ const results = [];
157
+ for (const target of ROUTE_TARGETS) {
158
+ results.push(await probeTarget(target, opts));
159
+ }
160
+ return routeHealthBaseline(results, { ts: opts.ts });
161
+ }
162
+
163
+ export function selfTest() {
164
+ const samples = [
165
+ { id: 'liris_mirror_4944', ok: true, http_status: 200, latency_ms: 12, body: '{"ok":true}' },
166
+ { id: 'behcs_bus_4947', error: 'ECONNREFUSED', latency_ms: 4 },
167
+ { id: 'acer_fabric_4949', http_status: 404, latency_ms: 30, body: '{"routes":["/health"]}' },
168
+ ];
169
+ const b = routeHealthBaseline(samples, { ts: '2026-06-13T23:00:00.000Z' });
170
+ const rows = emitRows(b);
171
+ const checks = [
172
+ ['three-targets', b.results.length === 3],
173
+ ['state-classification', b.results[0].state === 'UP' && b.results[1].state === 'DOWN' && b.results[2].state === 'ROUTE_BOUNDARY'],
174
+ ['summary-counts', b.summary.up === 1 && b.summary.down === 1 && b.summary.route_boundary === 1 && b.summary.answered === 2],
175
+ ['hbp-only', rows.every((r) => r.endsWith('|json=0') && !/[\r\n]/.test(r) && !r.includes('{"'))],
176
+ ['gate-readonly', rows.some((r) => r.startsWith('RHBGATE|') && r.includes('no_restart=1'))],
177
+ ['injection-safe', emitRows(routeHealthBaseline([{ id: 'liris_mirror_4944', error: 'x|json=0\nFAKE|x=1' }])).every((r) => !/[\r\n]/.test(r))],
178
+ ['body-hash-preserved', rows.some((r) => r.includes(`body_sha16=${b.results[0].body_sha16}`)) && b.results[0].body_sha16 !== sha16('')],
179
+ ].map(([name, ok]) => ({ name, ok: Boolean(ok) }));
180
+ return { ok: checks.every((c) => c.ok), checks };
181
+ }
182
+
183
+ const isMain = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
184
+ if (isMain) {
185
+ if (process.argv.includes('--self-test')) {
186
+ const r = selfTest();
187
+ for (const c of r.checks) console.log(`${c.ok ? 'PASS' : 'FAIL'} ${c.name}`);
188
+ process.exit(r.ok ? 0 : 1);
189
+ }
190
+ const baseline = process.argv.includes('--probe')
191
+ ? await probeRoutes()
192
+ : routeHealthBaseline([
193
+ { id: 'liris_mirror_4944', ok: true, http_status: 200, latency_ms: 0, source: 'fabric-health-read', body: 'ok=true service=super-asolaria-os-dashboard-liris-mirror port=4944' },
194
+ { id: 'behcs_bus_4947', source: 'not-probed-in-demo' },
195
+ { id: 'acer_fabric_4949', http_status: 404, source: 'fabric-route-map-read', body: 'route-map-visible health-path-boundary' },
196
+ ], { ts: '2026-06-13T23:00:00.000Z' });
197
+ for (const row of emitRows(baseline)) console.log(row);
198
+ }
tools/behcs/route-health-baseline.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 9BA42D52CBED8603AFD7552AF7742BE23B93882E6B950BCBD97D52FC45399A2D route-health-baseline.mjs