acer: seed component 1 - dashboard resolver (pid,device,ts) -> tightest route
Browse files- tools/behcs/dashboard-resolver.mjs: pure deterministic table-driven
resolver; LAW = tightest possible, NEVER tighter than evidence; 8-rung
demotion ladder (dirty->INVALID, unknown device->GLOBAL_READONLY,
pid/device conflict->GLOBAL_READONLY never guess, bad pid->DEVICE,
malformed/future/stale ts->DEVICE, full proven tuple->AGENT_TIGHT)
- eyes/hands per GAP|1: eyes=route/hbp free read, hands=route/post gated
POST operator-cosign, global scope exposes NO hands
- injection-safe by construction: pipe/CR/LF rejected at rung 1, routes
built only from table keys + regex-validated PID + fixed literals
- room bands scout/review/write/test from PID P-field, declared as DRAFT
ASSUMPTION - bilateral contest welcome
- sealed parity baseline (12 cases, fixed clock, bundle_sha16=
eb3e518644a672e0) - liris pyramid run IS the byte-match, STEP|166 pattern
- pre-hardened against the assigned attack list: missing pid, unknown
device, stale/malformed/future ts, conflict, broad-vs-tight, host-path
leakage, HBP field injection - all encoded as unit tests + parity cases
- pyramid 63/63 on acer; no launch, no fabric call, apex-T0 untouched
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- README.md +2 -0
- README.md.sha256 +1 -1
- docs/DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp +14 -0
- docs/DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp.sha256 +1 -0
- docs/TARGET-ARCHITECTURE-VISION-2026-06-10.hbp +1 -0
- docs/TARGET-ARCHITECTURE-VISION-2026-06-10.hbp.sha256 +1 -1
- tests/dashboard-resolver.unit.test.mjs +121 -0
- tests/dashboard-resolver.unit.test.mjs.sha256 +1 -0
- tests/supervisor-collision-router.system.test.mjs +11 -0
- tests/supervisor-collision-router.system.test.mjs.sha256 +1 -1
- tools/behcs/dashboard-resolver.hbi +10 -0
- tools/behcs/dashboard-resolver.hbi.sha256 +1 -0
- tools/behcs/dashboard-resolver.hbp +9 -0
- tools/behcs/dashboard-resolver.hbp.sha256 +1 -0
- tools/behcs/dashboard-resolver.mjs +238 -0
- tools/behcs/dashboard-resolver.mjs.sha256 +1 -0
|
@@ -38,6 +38,7 @@ Every agent: (1) sees its **PID/device/timestamp-scoped dashboard**, (2) **trans
|
|
| 38 |
- `tools/omni-processor/omnitranslator-v0.js` — deterministic omnilanguage/json translator core.
|
| 39 |
- `tools/behcs/omnidirectional-translator-router.mjs` — component-2 router: implemented pairs execute, fabric endpoints stay draft-only.
|
| 40 |
- `tools/behcs/d22-verb-adapter.mjs` — thin D22 verb surface over the deterministic router/core.
|
|
|
|
| 41 |
- `tools/behcs/supervisor-collision-router.mjs` — Liris canonical implementation for Acer convergence.
|
| 42 |
- `tests/supervisor-collision-router.unit.test.mjs` — executable router contract tests.
|
| 43 |
|
|
@@ -47,6 +48,7 @@ The supervisor collision router converged in doctrine before it converged in byt
|
|
| 47 |
|
| 48 |
- component-2 translation router now exists in-repo: `omnilanguage<->json` executes deterministically through table/core logic; HBP/HBI/MCP/WebMCP/cube/whiteroom/Shannon/frozen-slice/geospatial/HRM endpoints return draft routes only until token bindings and required cosigns exist
|
| 49 |
- D22 verb adapter now exposes `tuple_to_english`, `english_to_tuple`, `ix_to_tuple`, `hilbert_to_human`, `crlt_merge`, `auto_transition_all_languages`, and `namespace_walk`; true natural-language and IX parsing remain explicit drafts
|
|
|
|
| 50 |
- input: `COLLISION|...|json=0` HBP rows, with JS-object input only as compatibility
|
| 51 |
- rule: a collision is only an error after classification
|
| 52 |
- head guard: non-`COLLISION` HBP rows are held, not routed as collisions
|
|
|
|
| 38 |
- `tools/omni-processor/omnitranslator-v0.js` — deterministic omnilanguage/json translator core.
|
| 39 |
- `tools/behcs/omnidirectional-translator-router.mjs` — component-2 router: implemented pairs execute, fabric endpoints stay draft-only.
|
| 40 |
- `tools/behcs/d22-verb-adapter.mjs` — thin D22 verb surface over the deterministic router/core.
|
| 41 |
+
- `tools/behcs/dashboard-resolver.mjs` — component-1 resolver: `(pid, device, ts)` → tightest-scoped dashboard route, 8-rung demotion ladder.
|
| 42 |
- `tools/behcs/supervisor-collision-router.mjs` — Liris canonical implementation for Acer convergence.
|
| 43 |
- `tests/supervisor-collision-router.unit.test.mjs` — executable router contract tests.
|
| 44 |
|
|
|
|
| 48 |
|
| 49 |
- component-2 translation router now exists in-repo: `omnilanguage<->json` executes deterministically through table/core logic; HBP/HBI/MCP/WebMCP/cube/whiteroom/Shannon/frozen-slice/geospatial/HRM endpoints return draft routes only until token bindings and required cosigns exist
|
| 50 |
- D22 verb adapter now exposes `tuple_to_english`, `english_to_tuple`, `ix_to_tuple`, `hilbert_to_human`, `crlt_merge`, `auto_transition_all_languages`, and `namespace_walk`; true natural-language and IX parsing remain explicit drafts
|
| 51 |
+
- component-1 dashboard resolver: tightest-possible-but-never-tighter-than-evidence — dirty input never routes, conflicts and unknown devices demote to global read-only, stale/malformed timestamps demote to device scope; routes are built only from table keys, regex-validated PIDs, and fixed literals
|
| 52 |
- input: `COLLISION|...|json=0` HBP rows, with JS-object input only as compatibility
|
| 53 |
- rule: a collision is only an error after classification
|
| 54 |
- head guard: non-`COLLISION` HBP rows are held, not routed as collisions
|
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
06D618A2184E67AC19FAA77488DAECCC4DB7C5A062A9986AADAA859D3DA917E8 README.md
|
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DASHRESPARITYHDR|component=1|cases=12|fixed_now=2026-06-11T12:00:00.000Z|rule=rows-byte-identical-on-every-machine|json=0
|
| 2 |
+
DASHRESPARITY|case=01|input_sha16=babeb95e1fee1431|state=AGENT_TIGHT|scope=AGENT|route=/dash/acer/pid/ACER-PID-H9E2A-A07-W104-P00-N00000/room/scout00|room_band=scout|gates=none|output_sha16=e216a1b288f9ead5|json=0
|
| 3 |
+
DASHRESPARITY|case=02|input_sha16=9fa6b3c0e5cfbcf9|state=AGENT_TIGHT|scope=AGENT|route=/dash/liris/pid/LIRIS-PID-H2BC1-A07-W110-P05-N00001/room/review05|room_band=review|gates=none|output_sha16=88a46bb1485a65de|json=0
|
| 4 |
+
DASHRESPARITY|case=03|input_sha16=f9e2656977ccf83e|state=AGENT_TIGHT|scope=AGENT|route=/dash/falcon/pid/OP-JESSE-PID-G0000-A00-W000-P00-N00000/room/scout00|room_band=scout|gates=none|output_sha16=c09ea561d9bd2f62|json=0
|
| 5 |
+
DASHRESPARITY|case=04|input_sha16=c9254593356a821e|state=DEVICE_SCOPE|scope=DEVICE|route=/dash/acer|room_band=none|gates=invalid-or-missing-pid|output_sha16=5e2d830cd3f2ebd1|json=0
|
| 6 |
+
DASHRESPARITY|case=05|input_sha16=efd7340405af9739|state=DEVICE_SCOPE|scope=DEVICE|route=/dash/liris|room_band=none|gates=invalid-or-missing-pid|output_sha16=571efcb3cfdde6e6|json=0
|
| 7 |
+
DASHRESPARITY|case=06|input_sha16=c353cd8e287b5b5b|state=GLOBAL_READONLY|scope=GLOBAL_READONLY|route=/dash/global/readonly|room_band=none|gates=unknown-or-missing-device|output_sha16=c7c19fc5d6250dd4|json=0
|
| 8 |
+
DASHRESPARITY|case=07|input_sha16=ccbc7eea0e9f511f|state=DEVICE_SCOPE|scope=DEVICE|route=/dash/acer|room_band=none|gates=stale-ts|output_sha16=2cf30c7684552b9c|json=0
|
| 9 |
+
DASHRESPARITY|case=08|input_sha16=65e42ccb088eae09|state=DEVICE_SCOPE|scope=DEVICE|route=/dash/acer|room_band=none|gates=malformed-ts|output_sha16=71a6aca813ac8ed2|json=0
|
| 10 |
+
DASHRESPARITY|case=09|input_sha16=55ee2ee0d2746b0c|state=DEVICE_SCOPE|scope=DEVICE|route=/dash/acer|room_band=none|gates=ts-in-future|output_sha16=295244f4dc713c15|json=0
|
| 11 |
+
DASHRESPARITY|case=10|input_sha16=ad813cd3f10287e3|state=GLOBAL_READONLY|scope=GLOBAL_READONLY|route=/dash/global/readonly|room_band=none|gates=pid-device-conflict:acer-vs-liris|output_sha16=1f79d130ab8a108f|json=0
|
| 12 |
+
DASHRESPARITY|case=11|input_sha16=49a82aa96fb49651|state=INVALID_INPUT|scope=NONE|route=none|room_band=none|gates=dirty-pid|output_sha16=ed59afe9f7400c91|json=0
|
| 13 |
+
DASHRESPARITY|case=12|input_sha16=0521e398e9c53d0c|state=AGENT_TIGHT|scope=AGENT|route=/dash/acer/pid/ACER-PID-H9E2A-A07-W104-P24-N00000|room_band=none|gates=none|output_sha16=43eeeda3dbf41c30|json=0
|
| 14 |
+
DASHRESPARITYFTR|cases=12|bundle_sha16=eb3e518644a672e0|exit=byte-match-when-regenerated-file-equals-sealed-baseline|json=0
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
A150D0FA84DA5DB209B5B9789C73E077BF15A6D6D7143C4077A278C5995F6BED DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp
|
|
@@ -4,6 +4,7 @@ TARGETARCHNOTE|each-component-HAS-a-proven-primitive|the-gap-is-INTEGRATION-not-
|
|
| 4 |
COMPONENT|1|name=LOCALIZED-PID-DEVICE-TIMESTAMP-SCOPED-DASHBOARDS|vision=every-agent-uses-the-RIGHT-dashboard-scoped-tightest-possible-to-ITS-PID+device+timestamp-tuple-NOT-one-global-dashboard
|
| 5 |
PROVEN|1|AgentTerms-:5054-already-scopes-by-EVENTRISK-PID-set+per-agent-guides+BH-room-scoping(scout00-03/review04-07/write08-15/test16-23)|each-URL-is-Brown-Hilbert-addressable-point(PID-first-doctrine)
|
| 6 |
GAP|1|agents-do-NOT-yet-auto-resolve-to-THEIR-scoped-dashboard-by-(PID,device,timestamp)-tuple|FIX=dashboard-resolver(pid,device,ts)->tightest-dashboard-route|each-agent-guide-points-eyes(hbp-reads)+hands(gated-POST)-scoped-to-its-tuple
|
|
|
|
| 7 |
|
| 8 |
COMPONENT|2|name=OMNIDIRECTIONAL-TRANSLATORS|vision=ANY-level-talks-to-ANY-type-of-thing-in-the-fabric(human<->AI<->subagent<->PID<->component<->kernel<->cube)
|
| 9 |
PROVEN|2|D22-TRANSLATION-dimension(7-verbs:tuple_to_english,english_to_tuple,ix_to_tuple,hilbert_to_human,crlt_merge,auto_transition_all_languages,namespace_walk)+7-layer-auto-translate(06-AUTO-TRANSLATE-LAYERS:L0-human..L6-cube,glyph-table-lookup-not-LLM)+BEHCS-1024-glyph
|
|
|
|
| 4 |
COMPONENT|1|name=LOCALIZED-PID-DEVICE-TIMESTAMP-SCOPED-DASHBOARDS|vision=every-agent-uses-the-RIGHT-dashboard-scoped-tightest-possible-to-ITS-PID+device+timestamp-tuple-NOT-one-global-dashboard
|
| 5 |
PROVEN|1|AgentTerms-:5054-already-scopes-by-EVENTRISK-PID-set+per-agent-guides+BH-room-scoping(scout00-03/review04-07/write08-15/test16-23)|each-URL-is-Brown-Hilbert-addressable-point(PID-first-doctrine)
|
| 6 |
GAP|1|agents-do-NOT-yet-auto-resolve-to-THEIR-scoped-dashboard-by-(PID,device,timestamp)-tuple|FIX=dashboard-resolver(pid,device,ts)->tightest-dashboard-route|each-agent-guide-points-eyes(hbp-reads)+hands(gated-POST)-scoped-to-its-tuple
|
| 7 |
+
PROGRESS|1|resolver_seed=tools/behcs/dashboard-resolver.mjs|law=tightest-possible-never-tighter-than-evidence|ladder=8-rungs(dirty-INVALID+unknown-device-GLOBAL+conflict-GLOBAL+bad-pid-DEVICE+bad-or-stale-ts-DEVICE+proven-AGENT_TIGHT)|eyes_hands=per-GAP-1|parity_baseline=DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp|draft_only=1|no_launch=1|no_fabric_call=1|json=0
|
| 8 |
|
| 9 |
COMPONENT|2|name=OMNIDIRECTIONAL-TRANSLATORS|vision=ANY-level-talks-to-ANY-type-of-thing-in-the-fabric(human<->AI<->subagent<->PID<->component<->kernel<->cube)
|
| 10 |
PROVEN|2|D22-TRANSLATION-dimension(7-verbs:tuple_to_english,english_to_tuple,ix_to_tuple,hilbert_to_human,crlt_merge,auto_transition_all_languages,namespace_walk)+7-layer-auto-translate(06-AUTO-TRANSLATE-LAYERS:L0-human..L6-cube,glyph-table-lookup-not-LLM)+BEHCS-1024-glyph
|
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
675607D3A73D5703BECB8A413AE1D931C39EA2FD3B07F0F32D059A82B11540CD TARGET-ARCHITECTURE-VISION-2026-06-10.hbp
|
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import assert from 'node:assert/strict';
|
| 2 |
+
import { readFileSync } from 'node:fs';
|
| 3 |
+
import test from 'node:test';
|
| 4 |
+
|
| 5 |
+
import {
|
| 6 |
+
DEVICES,
|
| 7 |
+
FRESH_WINDOW_S,
|
| 8 |
+
ROOM_BANDS,
|
| 9 |
+
emitParityRows,
|
| 10 |
+
resolveDashboard,
|
| 11 |
+
selfTest,
|
| 12 |
+
statusRows,
|
| 13 |
+
} from '../tools/behcs/dashboard-resolver.mjs';
|
| 14 |
+
|
| 15 |
+
const NOW = '2026-06-11T12:00:00.000Z';
|
| 16 |
+
const FRESH = '2026-06-11T11:59:00.000Z';
|
| 17 |
+
const GOOD_PID = 'ACER-PID-H9E2A-A07-W104-P00-N00000';
|
| 18 |
+
|
| 19 |
+
test('full proven tuple resolves AGENT_TIGHT with room band, eyes, and gated hands', () => {
|
| 20 |
+
const out = resolveDashboard(GOOD_PID, 'acer', FRESH, NOW);
|
| 21 |
+
assert.equal(out.state, 'AGENT_TIGHT');
|
| 22 |
+
assert.equal(out.scope, 'AGENT');
|
| 23 |
+
assert.equal(out.route, `/dash/acer/pid/${GOOD_PID}/room/scout00`);
|
| 24 |
+
assert.equal(out.eyes, `${out.route}/hbp`);
|
| 25 |
+
assert.equal(out.hands.gate, 'gated-POST-operator-cosign');
|
| 26 |
+
assert.deepEqual(out.gates, []);
|
| 27 |
+
});
|
| 28 |
+
|
| 29 |
+
test('demotion ladder: missing or invalid pid -> DEVICE_SCOPE, never AGENT', () => {
|
| 30 |
+
for (const pid of [null, undefined, '', 'NOT-A-REAL-PID', 'acer-pid-h9e2a-a07-w104-p00-n00000']) {
|
| 31 |
+
const out = resolveDashboard(pid, 'acer', FRESH, NOW);
|
| 32 |
+
assert.equal(out.state, 'DEVICE_SCOPE', `pid=${pid}`);
|
| 33 |
+
assert.equal(out.route, '/dash/acer');
|
| 34 |
+
assert.ok(out.gates.includes('invalid-or-missing-pid'));
|
| 35 |
+
}
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
test('demotion ladder: unknown device -> GLOBAL_READONLY with null hands', () => {
|
| 39 |
+
for (const device of ['toaster', null, '', 'ACER ']) {
|
| 40 |
+
const out = resolveDashboard(GOOD_PID, device, FRESH, NOW);
|
| 41 |
+
assert.equal(out.state, 'GLOBAL_READONLY', `device=${device}`);
|
| 42 |
+
assert.equal(out.route, '/dash/global/readonly');
|
| 43 |
+
assert.equal(out.hands, null, 'global scope must never expose hands');
|
| 44 |
+
}
|
| 45 |
+
});
|
| 46 |
+
|
| 47 |
+
test('demotion ladder: stale, malformed, and future timestamps -> DEVICE_SCOPE', () => {
|
| 48 |
+
const stale = resolveDashboard(GOOD_PID, 'acer', '2026-06-11T09:00:00.000Z', NOW);
|
| 49 |
+
assert.ok(stale.gates.includes('stale-ts'));
|
| 50 |
+
const boundary = resolveDashboard(GOOD_PID, 'acer', '2026-06-11T11:00:00.000Z', NOW);
|
| 51 |
+
assert.equal(boundary.state, 'AGENT_TIGHT', `exactly ${FRESH_WINDOW_S}s old is still fresh`);
|
| 52 |
+
for (const ts of ['yesterday-ish', '2026-06-11 11:59:00', '2026-06-11T11:59:00', '', null]) {
|
| 53 |
+
assert.equal(resolveDashboard(GOOD_PID, 'acer', ts, NOW).state, 'DEVICE_SCOPE', `ts=${ts}`);
|
| 54 |
+
}
|
| 55 |
+
const future = resolveDashboard(GOOD_PID, 'acer', '2026-06-11T13:00:00.000Z', NOW);
|
| 56 |
+
assert.ok(future.gates.includes('ts-in-future'));
|
| 57 |
+
const badNow = resolveDashboard(GOOD_PID, 'acer', FRESH, 'not-a-clock');
|
| 58 |
+
assert.ok(badNow.gates.includes('malformed-now'));
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
+
test('conflicting pid/device demotes to GLOBAL_READONLY, never guesses a side', () => {
|
| 62 |
+
const out = resolveDashboard(GOOD_PID, 'liris', FRESH, NOW);
|
| 63 |
+
assert.equal(out.state, 'GLOBAL_READONLY');
|
| 64 |
+
assert.ok(out.gates[0].startsWith('pid-device-conflict:acer-vs-liris'));
|
| 65 |
+
const op = resolveDashboard('OP-JESSE-PID-G0000-A00-W000-P00-N00000', 'falcon', FRESH, NOW);
|
| 66 |
+
assert.equal(op.state, 'AGENT_TIGHT', 'operator PIDs are apex: valid on any device');
|
| 67 |
+
});
|
| 68 |
+
|
| 69 |
+
test('broad vs tight: out-of-band plane stays AGENT but takes no room sub-route', () => {
|
| 70 |
+
const out = resolveDashboard('ACER-PID-H9E2A-A07-W104-P24-N00000', 'acer', FRESH, NOW);
|
| 71 |
+
assert.equal(out.state, 'AGENT_TIGHT');
|
| 72 |
+
assert.equal(out.room_band, 'none');
|
| 73 |
+
assert.ok(!out.route.includes('/room/'));
|
| 74 |
+
assert.ok(ROOM_BANDS.every((band) => 24 < band.lo || 24 > band.hi));
|
| 75 |
+
});
|
| 76 |
+
|
| 77 |
+
test('HBP injection: pipe/CR/LF in any input is rejected before routing', () => {
|
| 78 |
+
for (const args of [
|
| 79 |
+
['EVIL-PID|json=1', 'acer', FRESH],
|
| 80 |
+
[GOOD_PID, 'acer|liris', FRESH],
|
| 81 |
+
[GOOD_PID, 'acer', `${FRESH}|json=1`],
|
| 82 |
+
['EVIL\nPID', 'acer', FRESH],
|
| 83 |
+
]) {
|
| 84 |
+
const out = resolveDashboard(args[0], args[1], args[2], NOW);
|
| 85 |
+
assert.equal(out.state, 'INVALID_INPUT');
|
| 86 |
+
assert.equal(out.route, null, 'dirty input must never produce a route');
|
| 87 |
+
}
|
| 88 |
+
});
|
| 89 |
+
|
| 90 |
+
test('no host-specific path leakage in any route or parity row', () => {
|
| 91 |
+
const rows = emitParityRows();
|
| 92 |
+
for (const row of rows) {
|
| 93 |
+
assert.ok(!/[\\]|C:|Users|rayss|home\//.test(row), `host path leaked: ${row}`);
|
| 94 |
+
}
|
| 95 |
+
const out = resolveDashboard(GOOD_PID, 'acer', FRESH, NOW);
|
| 96 |
+
assert.match(out.route, /^\/dash\//);
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
+
test('status rows are HBP-only and device table is closed', () => {
|
| 100 |
+
const rows = statusRows();
|
| 101 |
+
assert.ok(rows.every((row) => row.endsWith('json=0') && !row.includes('{"')));
|
| 102 |
+
assert.deepEqual(Object.keys(DEVICES), ['acer', 'liris', 'falcon']);
|
| 103 |
+
assert.equal(selfTest().ok, true);
|
| 104 |
+
});
|
| 105 |
+
|
| 106 |
+
// Component-1 parity, STEP|166 pattern: regenerate locally, byte-compare to
|
| 107 |
+
// the acer-sealed baseline. A green run on liris IS the bilateral byte-match.
|
| 108 |
+
test('component-1 parity: regenerated rows byte-match the sealed baseline', () => {
|
| 109 |
+
const regenerated = emitParityRows().join('\n') + '\n';
|
| 110 |
+
const baseline = readFileSync(
|
| 111 |
+
new URL('../docs/DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp', import.meta.url),
|
| 112 |
+
'utf8',
|
| 113 |
+
);
|
| 114 |
+
assert.equal(regenerated, baseline, 'this machine produced different bytes than the sealed baseline');
|
| 115 |
+
});
|
| 116 |
+
|
| 117 |
+
test('parity rows stay HBP-only and carry no host or wall-clock fields', () => {
|
| 118 |
+
const rows = emitParityRows();
|
| 119 |
+
assert.ok(rows.every((row) => row.endsWith('json=0') && !row.includes('{"')));
|
| 120 |
+
assert.ok(rows.every((row) => !/host=/.test(row)));
|
| 121 |
+
});
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
0C67544C201380786F249DB4C1783EAE4F95E6A8E5729AC777CF40A66F65B589 dashboard-resolver.unit.test.mjs
|
|
@@ -23,6 +23,7 @@ const sealedFiles = [
|
|
| 23 |
'docs/LIRIS-D22-VERB-ADAPTER-2026-06-11.hbp',
|
| 24 |
'docs/ACER-READBACK-D22-2026-06-11.hbp',
|
| 25 |
'docs/D22-PARITY-BASELINE-2026-06-11.hbp',
|
|
|
|
| 26 |
'docs/LIRIS-STEP166-PARITY-CONFIRMED-2026-06-11.hbp',
|
| 27 |
'specs/SUPERVISOR-COLLISION-ROUTER-SPEC.hbp',
|
| 28 |
'tools/behcs/supervisor-collision-router.mjs',
|
|
@@ -35,9 +36,13 @@ const sealedFiles = [
|
|
| 35 |
'tools/behcs/d22-verb-adapter.hbp',
|
| 36 |
'tools/behcs/d22-verb-adapter.hbi',
|
| 37 |
'tools/behcs/d22-parity-probe.mjs',
|
|
|
|
|
|
|
|
|
|
| 38 |
'tools/omni-processor/omnitranslator-v0.js',
|
| 39 |
'tests/d22-verb-adapter.unit.test.mjs',
|
| 40 |
'tests/d22-parity-probe.unit.test.mjs',
|
|
|
|
| 41 |
'tests/supervisor-collision-router.unit.test.mjs',
|
| 42 |
'tests/supervisor-collision-router.integration.test.mjs',
|
| 43 |
'tests/supervisor-collision-router.suite.test.mjs',
|
|
@@ -73,6 +78,12 @@ test('D22 adapter descriptor records the current source and unit-test hashes', (
|
|
| 73 |
assert.match(hbp, new RegExp(`test_sha256=${sha256('tests/d22-verb-adapter.unit.test.mjs')}`));
|
| 74 |
});
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
test('sidecar filenames point at their target basenames', () => {
|
| 77 |
for (const rel of sealedFiles) {
|
| 78 |
const text = readFileSync(join(repo, `${rel}.sha256`), 'utf8').trim();
|
|
|
|
| 23 |
'docs/LIRIS-D22-VERB-ADAPTER-2026-06-11.hbp',
|
| 24 |
'docs/ACER-READBACK-D22-2026-06-11.hbp',
|
| 25 |
'docs/D22-PARITY-BASELINE-2026-06-11.hbp',
|
| 26 |
+
'docs/DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp',
|
| 27 |
'docs/LIRIS-STEP166-PARITY-CONFIRMED-2026-06-11.hbp',
|
| 28 |
'specs/SUPERVISOR-COLLISION-ROUTER-SPEC.hbp',
|
| 29 |
'tools/behcs/supervisor-collision-router.mjs',
|
|
|
|
| 36 |
'tools/behcs/d22-verb-adapter.hbp',
|
| 37 |
'tools/behcs/d22-verb-adapter.hbi',
|
| 38 |
'tools/behcs/d22-parity-probe.mjs',
|
| 39 |
+
'tools/behcs/dashboard-resolver.mjs',
|
| 40 |
+
'tools/behcs/dashboard-resolver.hbp',
|
| 41 |
+
'tools/behcs/dashboard-resolver.hbi',
|
| 42 |
'tools/omni-processor/omnitranslator-v0.js',
|
| 43 |
'tests/d22-verb-adapter.unit.test.mjs',
|
| 44 |
'tests/d22-parity-probe.unit.test.mjs',
|
| 45 |
+
'tests/dashboard-resolver.unit.test.mjs',
|
| 46 |
'tests/supervisor-collision-router.unit.test.mjs',
|
| 47 |
'tests/supervisor-collision-router.integration.test.mjs',
|
| 48 |
'tests/supervisor-collision-router.suite.test.mjs',
|
|
|
|
| 78 |
assert.match(hbp, new RegExp(`test_sha256=${sha256('tests/d22-verb-adapter.unit.test.mjs')}`));
|
| 79 |
});
|
| 80 |
|
| 81 |
+
test('dashboard resolver descriptor records the current source and unit-test hashes', () => {
|
| 82 |
+
const hbp = readFileSync(join(repo, 'tools/behcs/dashboard-resolver.hbp'), 'utf8');
|
| 83 |
+
assert.match(hbp, new RegExp(`resolver_sha256=${sha256('tools/behcs/dashboard-resolver.mjs')}`));
|
| 84 |
+
assert.match(hbp, new RegExp(`test_sha256=${sha256('tests/dashboard-resolver.unit.test.mjs')}`));
|
| 85 |
+
});
|
| 86 |
+
|
| 87 |
test('sidecar filenames point at their target basenames', () => {
|
| 88 |
for (const rel of sealedFiles) {
|
| 89 |
const text = readFileSync(join(repo, `${rel}.sha256`), 'utf8').trim();
|
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
8ADB2E0EDE3D459218AC20D158A941BA237A8B90FF8D0E2F0C0F5F69CB464E5B supervisor-collision-router.system.test.mjs
|
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DASHRESINDEX|host=acer|target=dashboard-resolver.hbp|tool=dashboard-resolver.mjs|rows=9|json=0
|
| 2 |
+
INDEXROW|row=1|kind=header|component=architecture-component-1|json=0
|
| 3 |
+
INDEXROW|row=2|kind=law|rule=tightest-possible-never-tighter-than-evidence|json=0
|
| 4 |
+
INDEXROW|row=3|kind=ladder|rungs=8|json=0
|
| 5 |
+
INDEXROW|row=4|kind=table|devices=3|bands=4|fresh_window_s=3600|json=0
|
| 6 |
+
INDEXROW|row=5|kind=routes|scopes=AGENT+DEVICE+GLOBAL_READONLY|injection_safe=table-keys-and-validated-pid-only|json=0
|
| 7 |
+
INDEXROW|row=6|kind=safety|mutates=0|pure_function=1|no_launch=1|no_fabric_call=1|json=0
|
| 8 |
+
INDEXROW|row=7|kind=verify|required=node-check+node-test+self-test+parity-byte-compare|json=0
|
| 9 |
+
INDEXROW|row=8|kind=sha|fields=resolver_sha256+test_sha256|json=0
|
| 10 |
+
INDEXROW|row=9|kind=footer|state=COMPONENT_1_SEED_READY_FOR_LIRIS_ADVERSARIAL_READBACK|json=0
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
B7DD7C833AC4616FFF2AE6D6384A5A90ED858B455E35A8D567847748B8BE4C52 dashboard-resolver.hbi
|
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DASHRESHDR|host=acer|component=architecture-component-1|tool=tools/behcs/dashboard-resolver.mjs|purpose=deterministic-(pid,device,ts)-to-tightest-scoped-dashboard-route|json=0
|
| 2 |
+
DASHRESLAW|rule=tightest-possible-but-NEVER-tighter-than-evidence|never=guess-on-dirty-conflicting-or-stale-input|composes=TARGET-ARCHITECTURE-VISION-2026-06-10(COMPONENT-1)+LAW-ASOLARIA-NEURAL-NETWORK|json=0
|
| 3 |
+
DASHRESLADDER|rungs=8|order=dirty-input-INVALID+unknown-device-GLOBAL_READONLY+pid-device-conflict-GLOBAL_READONLY+invalid-pid-DEVICE+malformed-ts-DEVICE+future-ts-DEVICE+stale-ts-DEVICE+full-tuple-proven-AGENT_TIGHT|json=0
|
| 4 |
+
DASHRESTABLE|devices=acer+liris+falcon|room_bands=scout00-03+review04-07+write08-15+test16-23|room_source=P-field-of-PID(DRAFT-ASSUMPTION-bilateral-contest-welcome)|fresh_window_s=3600|operator_pids=OP-prefix-valid-on-any-device|json=0
|
| 5 |
+
DASHRESROUTES|agent=/dash/DEVICE/pid/PID-with-room-suffix-when-band-known|device=/dash/DEVICE|global=/dash/global/readonly|eyes=route-plus-/hbp(free-read)|hands=route-plus-/post(gated-POST-operator-cosign)|global_hands=none|route_inputs=table-keys+regex-validated-pid+fixed-literals-only|json=0
|
| 6 |
+
DASHRESSAFETY|mutates=0|pure_function=1|no_live_dashboard_launch=1|no_fabric_call=1|no_disk_write=1|mints=0|launches=0|usb_writes=0|engine_edits=0|external_calls=0|json=0
|
| 7 |
+
DASHRESVERIFY|required=node-check+node-test+self-test+parity-byte-compare|parity_baseline=docs/DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp|bundle_sha16=eb3e518644a672e0|json=0
|
| 8 |
+
DASHRESSHA|resolver_sha256=2FD380B4A6353AB1A4E8682BD97510698755408785A7111E2C4F75168FF75D7D|test_sha256=0C67544C201380786F249DB4C1783EAE4F95E6A8E5729AC777CF40A66F65B589|json=0
|
| 9 |
+
DASHRESFTR|state=COMPONENT_1_SEED_READY_FOR_LIRIS_ADVERSARIAL_READBACK|json=0
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
BC8AAF0D8B8D546A7E3DD038AD59429199533885EF7026A86DDBE9B422D75284 dashboard-resolver.hbp
|
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
import { createHash } from 'node:crypto';
|
| 3 |
+
import { resolve } from 'node:path';
|
| 4 |
+
import { fileURLToPath } from 'node:url';
|
| 5 |
+
|
| 6 |
+
// COMPONENT|1 dashboard resolver: (pid, device, timestamp) -> tightest-scoped
|
| 7 |
+
// dashboard route. Pure deterministic table lookup -- no live dashboard
|
| 8 |
+
// launch, no fabric call, no disk write. The LAW of this resolver:
|
| 9 |
+
// tightest possible, but NEVER tighter than the evidence supports.
|
| 10 |
+
// Anything unproven demotes down the ladder with an explicit gate; the
|
| 11 |
+
// resolver never guesses a tight route from dirty or conflicting inputs.
|
| 12 |
+
|
| 13 |
+
export const RESOLVER_ID = 'dashboard-resolver.v1';
|
| 14 |
+
export const FRESH_WINDOW_S = 3600;
|
| 15 |
+
|
| 16 |
+
export const DEVICES = Object.freeze({
|
| 17 |
+
acer: { kind: 'desktop' },
|
| 18 |
+
liris: { kind: 'desktop' },
|
| 19 |
+
falcon: { kind: 'android' },
|
| 20 |
+
});
|
| 21 |
+
|
| 22 |
+
// BH-room scoping per PROVEN|1: scout00-03 / review04-07 / write08-15 / test16-23.
|
| 23 |
+
// room_source = P-field of the PID is a DRAFT ASSUMPTION -- bilateral contest welcome.
|
| 24 |
+
export const ROOM_BANDS = Object.freeze([
|
| 25 |
+
Object.freeze({ band: 'scout', lo: 0, hi: 3 }),
|
| 26 |
+
Object.freeze({ band: 'review', lo: 4, hi: 7 }),
|
| 27 |
+
Object.freeze({ band: 'write', lo: 8, hi: 15 }),
|
| 28 |
+
Object.freeze({ band: 'test', lo: 16, hi: 23 }),
|
| 29 |
+
]);
|
| 30 |
+
|
| 31 |
+
const PID_RE = /^([A-Z][A-Z0-9-]*)-PID-([A-Z][0-9A-F]{4})-A(\d{2})-W(\d{3})-P(\d{2})-N(\d{5})$/;
|
| 32 |
+
const TS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/;
|
| 33 |
+
const DIRTY_RE = /[|\r\n]/;
|
| 34 |
+
|
| 35 |
+
function hostHint(prefix) {
|
| 36 |
+
if (prefix.startsWith('OP-')) return 'operator';
|
| 37 |
+
if (prefix.includes('ACER')) return 'acer';
|
| 38 |
+
if (prefix.includes('LIRIS')) return 'liris';
|
| 39 |
+
if (prefix.includes('FALCON')) return 'falcon';
|
| 40 |
+
return null;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
function globalReadonly(gate) {
|
| 44 |
+
const route = '/dash/global/readonly';
|
| 45 |
+
return {
|
| 46 |
+
ok: true,
|
| 47 |
+
state: 'GLOBAL_READONLY',
|
| 48 |
+
scope: 'GLOBAL_READONLY',
|
| 49 |
+
route,
|
| 50 |
+
eyes: `${route}/hbp`,
|
| 51 |
+
hands: null,
|
| 52 |
+
room_band: 'none',
|
| 53 |
+
gates: [gate],
|
| 54 |
+
};
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
function deviceScope(dev, gate) {
|
| 58 |
+
const route = `/dash/${dev}`;
|
| 59 |
+
return {
|
| 60 |
+
ok: true,
|
| 61 |
+
state: 'DEVICE_SCOPE',
|
| 62 |
+
scope: 'DEVICE',
|
| 63 |
+
route,
|
| 64 |
+
eyes: `${route}/hbp`,
|
| 65 |
+
hands: { url: `${route}/post`, gate: 'gated-POST-operator-cosign' },
|
| 66 |
+
room_band: 'none',
|
| 67 |
+
gates: [gate],
|
| 68 |
+
};
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
export function resolveDashboard(pid, device, ts, nowIso) {
|
| 72 |
+
// Rung 1: dirty input never routes. Pipe/CR/LF or non-string (when present)
|
| 73 |
+
// is rejected outright so no caller input can reach a route or an HBP row.
|
| 74 |
+
for (const [label, value] of [['pid', pid], ['device', device], ['ts', ts], ['now', nowIso]]) {
|
| 75 |
+
if (value != null && (typeof value !== 'string' || DIRTY_RE.test(value))) {
|
| 76 |
+
return {
|
| 77 |
+
ok: false,
|
| 78 |
+
state: 'INVALID_INPUT',
|
| 79 |
+
scope: 'NONE',
|
| 80 |
+
route: null,
|
| 81 |
+
eyes: null,
|
| 82 |
+
hands: null,
|
| 83 |
+
room_band: 'none',
|
| 84 |
+
gates: [`dirty-${label}`],
|
| 85 |
+
};
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
// Rung 2: without a known device there is no device dashboard to scope to.
|
| 90 |
+
const dev = Object.hasOwn(DEVICES, String(device ?? '').toLowerCase())
|
| 91 |
+
? String(device).toLowerCase()
|
| 92 |
+
: null;
|
| 93 |
+
if (!dev) return globalReadonly('unknown-or-missing-device');
|
| 94 |
+
|
| 95 |
+
// Rung 3: a valid PID whose host prefix contradicts the device is a
|
| 96 |
+
// conflict -- the resolver never picks a side, it demotes to broadest.
|
| 97 |
+
const pidMatch = PID_RE.exec(String(pid ?? ''));
|
| 98 |
+
if (pidMatch) {
|
| 99 |
+
const hint = hostHint(pidMatch[1]);
|
| 100 |
+
if (hint && hint !== 'operator' && hint !== dev) {
|
| 101 |
+
return globalReadonly(`pid-device-conflict:${hint}-vs-${dev}`);
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
// Rung 4: no valid PID -> device scope only.
|
| 106 |
+
if (!pidMatch) return deviceScope(dev, 'invalid-or-missing-pid');
|
| 107 |
+
|
| 108 |
+
// Rungs 5-7: the timestamp must be strict ISO-8601 Zulu, not in the
|
| 109 |
+
// future, and inside the freshness window, or the tuple is not proven.
|
| 110 |
+
if (!TS_RE.test(String(nowIso ?? ''))) return deviceScope(dev, 'malformed-now');
|
| 111 |
+
if (!TS_RE.test(String(ts ?? ''))) return deviceScope(dev, 'malformed-ts');
|
| 112 |
+
const tsMs = Date.parse(ts);
|
| 113 |
+
const nowMs = Date.parse(nowIso);
|
| 114 |
+
if (Number.isNaN(tsMs) || Number.isNaN(nowMs)) return deviceScope(dev, 'unparseable-ts');
|
| 115 |
+
if (tsMs > nowMs) return deviceScope(dev, 'ts-in-future');
|
| 116 |
+
if ((nowMs - tsMs) / 1000 > FRESH_WINDOW_S) return deviceScope(dev, 'stale-ts');
|
| 117 |
+
|
| 118 |
+
// Rung 8: full tuple proven -> AGENT_TIGHT. Route is built only from the
|
| 119 |
+
// device table key, the regex-validated PID, and fixed literals.
|
| 120 |
+
const plane = Number(pidMatch[5]);
|
| 121 |
+
const band = ROOM_BANDS.find((b) => plane >= b.lo && plane <= b.hi) ?? null;
|
| 122 |
+
const route = `/dash/${dev}/pid/${pidMatch[0]}${band ? `/room/${band.band}${pidMatch[5]}` : ''}`;
|
| 123 |
+
return {
|
| 124 |
+
ok: true,
|
| 125 |
+
state: 'AGENT_TIGHT',
|
| 126 |
+
scope: 'AGENT',
|
| 127 |
+
route,
|
| 128 |
+
eyes: `${route}/hbp`,
|
| 129 |
+
hands: { url: `${route}/post`, gate: 'gated-POST-operator-cosign' },
|
| 130 |
+
room_band: band ? band.band : 'none',
|
| 131 |
+
gates: [],
|
| 132 |
+
};
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
function sha16(value) {
|
| 136 |
+
const text = typeof value === 'string' ? value : JSON.stringify(value);
|
| 137 |
+
return createHash('sha256').update(text).digest('hex').slice(0, 16);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
export function statusRows() {
|
| 141 |
+
const rows = [
|
| 142 |
+
`DASHRESHDR|ok=1|id=${RESOLVER_ID}|component=1|devices=${Object.keys(DEVICES).length}|bands=${ROOM_BANDS.length}|fresh_window_s=${FRESH_WINDOW_S}|state=RESOLVER_READY_NO_LAUNCH_NO_FABRIC_CALL|json=0`,
|
| 143 |
+
'DASHRESLADDER|rung=1|rule=dirty-input-never-routes|verdict=INVALID_INPUT|json=0',
|
| 144 |
+
'DASHRESLADDER|rung=2|rule=unknown-or-missing-device|verdict=GLOBAL_READONLY|json=0',
|
| 145 |
+
'DASHRESLADDER|rung=3|rule=pid-device-conflict-never-guess|verdict=GLOBAL_READONLY|json=0',
|
| 146 |
+
'DASHRESLADDER|rung=4|rule=invalid-or-missing-pid|verdict=DEVICE_SCOPE|json=0',
|
| 147 |
+
'DASHRESLADDER|rung=5|rule=malformed-ts-or-now|verdict=DEVICE_SCOPE|json=0',
|
| 148 |
+
'DASHRESLADDER|rung=6|rule=ts-in-future|verdict=DEVICE_SCOPE|json=0',
|
| 149 |
+
'DASHRESLADDER|rung=7|rule=stale-ts-beyond-window|verdict=DEVICE_SCOPE|json=0',
|
| 150 |
+
'DASHRESLADDER|rung=8|rule=full-tuple-proven|verdict=AGENT_TIGHT|json=0',
|
| 151 |
+
];
|
| 152 |
+
for (const [id, meta] of Object.entries(DEVICES)) {
|
| 153 |
+
rows.push(`DASHRESDEVICE|id=${id}|kind=${meta.kind}|route=/dash/${id}|json=0`);
|
| 154 |
+
}
|
| 155 |
+
for (const band of ROOM_BANDS) {
|
| 156 |
+
rows.push(`DASHRESBAND|band=${band.band}|lo=${String(band.lo).padStart(2, '0')}|hi=${String(band.hi).padStart(2, '0')}|source=P-field-DRAFT-ASSUMPTION|json=0`);
|
| 157 |
+
}
|
| 158 |
+
rows.push('DASHRESSAFETY|mutates=0|pure_function=1|no_live_dashboard_launch=1|no_fabric_call=1|json=0');
|
| 159 |
+
rows.push(`DASHRESEND|rungs=8|state=COMPONENT_1_SEED|json=0`);
|
| 160 |
+
return rows;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
// STEP|166-style parity: fixed clock, fixed cases, host- and time-free rows.
|
| 164 |
+
// Regenerated rows must byte-match the sealed baseline on every machine.
|
| 165 |
+
const PARITY_NOW = '2026-06-11T12:00:00.000Z';
|
| 166 |
+
const PARITY_CASES = Object.freeze([
|
| 167 |
+
{ id: '01', pid: 'ACER-PID-H9E2A-A07-W104-P00-N00000', device: 'acer', ts: '2026-06-11T11:59:00.000Z' },
|
| 168 |
+
{ id: '02', pid: 'LIRIS-PID-H2BC1-A07-W110-P05-N00001', device: 'liris', ts: '2026-06-11T11:30:00.000Z' },
|
| 169 |
+
{ id: '03', pid: 'OP-JESSE-PID-G0000-A00-W000-P00-N00000', device: 'falcon', ts: '2026-06-11T11:59:59.000Z' },
|
| 170 |
+
{ id: '04', pid: null, device: 'acer', ts: '2026-06-11T11:59:00.000Z' },
|
| 171 |
+
{ id: '05', pid: 'NOT-A-REAL-PID', device: 'liris', ts: '2026-06-11T11:59:00.000Z' },
|
| 172 |
+
{ id: '06', pid: 'ACER-PID-H9E2A-A07-W104-P00-N00000', device: 'toaster', ts: '2026-06-11T11:59:00.000Z' },
|
| 173 |
+
{ id: '07', pid: 'ACER-PID-H9E2A-A07-W104-P00-N00000', device: 'acer', ts: '2026-06-11T09:00:00.000Z' },
|
| 174 |
+
{ id: '08', pid: 'ACER-PID-H9E2A-A07-W104-P00-N00000', device: 'acer', ts: 'yesterday-ish' },
|
| 175 |
+
{ id: '09', pid: 'ACER-PID-H9E2A-A07-W104-P00-N00000', device: 'acer', ts: '2026-06-11T13:00:00.000Z' },
|
| 176 |
+
{ id: '10', pid: 'ACER-PID-H9E2A-A07-W104-P00-N00000', device: 'liris', ts: '2026-06-11T11:59:00.000Z' },
|
| 177 |
+
{ id: '11', pid: 'EVIL-PID|json=1', device: 'acer', ts: '2026-06-11T11:59:00.000Z' },
|
| 178 |
+
{ id: '12', pid: 'ACER-PID-H9E2A-A07-W104-P24-N00000', device: 'acer', ts: '2026-06-11T11:59:00.000Z' },
|
| 179 |
+
]);
|
| 180 |
+
|
| 181 |
+
export function emitParityRows() {
|
| 182 |
+
const rows = [
|
| 183 |
+
`DASHRESPARITYHDR|component=1|cases=${PARITY_CASES.length}|fixed_now=${PARITY_NOW}|rule=rows-byte-identical-on-every-machine|json=0`,
|
| 184 |
+
];
|
| 185 |
+
const outputs = [];
|
| 186 |
+
for (const probe of PARITY_CASES) {
|
| 187 |
+
const out = resolveDashboard(probe.pid, probe.device, probe.ts, PARITY_NOW);
|
| 188 |
+
const serialized = JSON.stringify(out);
|
| 189 |
+
outputs.push(serialized);
|
| 190 |
+
rows.push(
|
| 191 |
+
`DASHRESPARITY|case=${probe.id}|input_sha16=${sha16([probe.pid, probe.device, probe.ts])}|state=${out.state}|scope=${out.scope}|route=${out.route ?? 'none'}|room_band=${out.room_band}|gates=${out.gates.length ? out.gates.join('+') : 'none'}|output_sha16=${sha16(serialized)}|json=0`,
|
| 192 |
+
);
|
| 193 |
+
}
|
| 194 |
+
rows.push(
|
| 195 |
+
`DASHRESPARITYFTR|cases=${PARITY_CASES.length}|bundle_sha16=${sha16(outputs.join('\n'))}|exit=byte-match-when-regenerated-file-equals-sealed-baseline|json=0`,
|
| 196 |
+
);
|
| 197 |
+
return rows;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
export function selfTest() {
|
| 201 |
+
const checks = [];
|
| 202 |
+
const add = (name, ok) => checks.push({ name, ok });
|
| 203 |
+
const NOW = PARITY_NOW;
|
| 204 |
+
|
| 205 |
+
const tight = resolveDashboard('ACER-PID-H9E2A-A07-W104-P00-N00000', 'acer', '2026-06-11T11:59:00.000Z', NOW);
|
| 206 |
+
add('agent-tight-with-scout-band', tight.state === 'AGENT_TIGHT' && tight.room_band === 'scout' && tight.route.endsWith('/room/scout00'));
|
| 207 |
+
add('missing-pid-demotes-to-device', resolveDashboard(null, 'acer', '2026-06-11T11:59:00.000Z', NOW).state === 'DEVICE_SCOPE');
|
| 208 |
+
add('unknown-device-demotes-to-global', resolveDashboard('ACER-PID-H9E2A-A07-W104-P00-N00000', 'toaster', '2026-06-11T11:59:00.000Z', NOW).state === 'GLOBAL_READONLY');
|
| 209 |
+
add('stale-ts-demotes-to-device', resolveDashboard('ACER-PID-H9E2A-A07-W104-P00-N00000', 'acer', '2026-06-11T09:00:00.000Z', NOW).gates.includes('stale-ts'));
|
| 210 |
+
add('conflict-demotes-to-global', resolveDashboard('ACER-PID-H9E2A-A07-W104-P00-N00000', 'liris', '2026-06-11T11:59:00.000Z', NOW).gates[0].startsWith('pid-device-conflict'));
|
| 211 |
+
add('operator-pid-no-conflict', resolveDashboard('OP-JESSE-PID-G0000-A00-W000-P00-N00000', 'falcon', '2026-06-11T11:59:59.000Z', NOW).state === 'AGENT_TIGHT');
|
| 212 |
+
add('pipe-pid-rejected', resolveDashboard('EVIL-PID|json=1', 'acer', '2026-06-11T11:59:00.000Z', NOW).state === 'INVALID_INPUT');
|
| 213 |
+
add('global-hands-are-null', resolveDashboard('x', 'toaster', 'x', NOW).hands === null);
|
| 214 |
+
add('status-rows-hbp-only', statusRows().every((row) => row.endsWith('json=0') && !row.includes('{"')));
|
| 215 |
+
|
| 216 |
+
return { ok: checks.every((check) => check.ok), checks };
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
const isMain = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
|
| 220 |
+
|
| 221 |
+
if (isMain) {
|
| 222 |
+
const cmd = process.argv[2] || '--status';
|
| 223 |
+
if (cmd === '--status') {
|
| 224 |
+
console.log(statusRows().join('\n'));
|
| 225 |
+
} else if (cmd === '--self-test') {
|
| 226 |
+
const result = selfTest();
|
| 227 |
+
for (const check of result.checks) console.log(`${check.ok ? 'PASS' : 'FAIL'} ${check.name}`);
|
| 228 |
+
process.exit(result.ok ? 0 : 1);
|
| 229 |
+
} else if (cmd === '--parity') {
|
| 230 |
+
process.stdout.write(emitParityRows().join('\n') + '\n');
|
| 231 |
+
} else if (cmd === '--resolve') {
|
| 232 |
+
const [pid, device, ts, now] = process.argv.slice(3);
|
| 233 |
+
console.log(JSON.stringify(resolveDashboard(pid, device, ts, now ?? new Date().toISOString()), null, 2));
|
| 234 |
+
} else {
|
| 235 |
+
console.error('usage: dashboard-resolver.mjs --status | --self-test | --parity | --resolve <pid> <device> <ts> [now]');
|
| 236 |
+
process.exit(1);
|
| 237 |
+
}
|
| 238 |
+
}
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
2FD380B4A6353AB1A4E8682BD97510698755408785A7111E2C4F75168FF75D7D dashboard-resolver.mjs
|