Kevin Crutt commited on
Commit
7cbb7e2
·
1 Parent(s): d69e83e

liris: add frontend parity matrix

Browse files
docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ LIRISFEPMHDR|host=liris|date=2026-06-14|topic=frontend-parity-matrix|responds_to=fabric-council-q-1781432025196-musksw-CONVERGE-157of251+NOTYETBUILTQUEUE-frontend-parity-matrix+C015-frontend-parity-gap|tag=PROVEN-HELD-SAFE|json=0
2
+ LIRISFEPMVERDICT|fabric=CONVERGE-157of251|dominant_domains=daemons154+audit29+language_glyph24|named_frontend_voters=hermes-dashboard+behcs1024-root|live_daemon_contract=NONE_RETURNED|action=build-held-safe-matrix-not-cutover|json=0
3
+ LIRISFEPMTOOL|tool=tools/behcs/frontend-parity-matrix.mjs|matrices=M-model_selector+T-tool_skill+P-project_guide+C-council_vote+Q-swarm_queue+R-memory_index+E-local_engine+A-route_api+D-dashboard_parity+G-gate_state|rule=each-cell-has-route-or-file-or-sha-or-explicit-CANNOT_SEE|tag=PROVEN-CODE|json=0
4
+ LIRISFEPMSUM|green=4|partial=4|red=2|gated=0|red_cells=M-model_selector+P-project_guide|partial_cells=T-tool_skill+Q-swarm_queue+E-local_engine+D-dashboard_parity|cutover_ready=0|json=0
5
+ LIRISFEPMLEDGER|catch_C015=OPEN-to-PARTIAL|reason=matrix-now-exists-but-M/P-red-and-T/Q/E/D-partial-so-front-end-cutover-still-HOLD|md_final_ready=0|tag=HONEST-PARTIAL|json=0
6
+ LIRISFEPMVERIFY|selftest=7of7|unit=8of8|lattice=9of9|suite=291of291|no_spawn=1|no_fetch=1|no_write=1|no_mint=1|no_cutover=1|process_launch=0|tag=PROVEN-LOCAL|json=0
7
+ LIRISFEPMFTR|state=FRONTEND-PARITY-MATRIX-BUILT-CUTOVER-HELD|next=ask-fabric-for-M-model-selector-or-T-tool-skill-or-P-project-guide-artifact-or-cosign-submit-schema-proof|old_dashboards_deleted=0|json=0
docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 4F187E63141190DA8F5664DCFA685E58A6A2AB8D0B108160A5454BA0A456E57E LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp
tests/fabric-agent-preload-catalog.unit.test.mjs CHANGED
@@ -25,6 +25,7 @@ test('preload catalog includes the laws, tools, roles, and cadence agents need',
25
  assert.ok(TOOLS.some((t) => t.id === 'github-live-pid-reconcile'));
26
  assert.ok(TOOLS.some((t) => t.id === 'catch-count-ledger' && t.gate.includes('md-final-release-claims-held')));
27
  assert.ok(TOOLS.some((t) => t.id === 'mlc-engine-wiring-increment' && t.gate.includes('process_launch-0')));
 
28
  assert.ok(ROLES.some((r) => r.id === 'flywheel' && r.must_do.includes('compare-to-acer-local-truth')));
29
  assert.ok(WORKFLOW.join('-').includes('memory-index-plan'));
30
  assert.equal(toolById('token-cube-catalog-binder').gate, 'mint-write-live-DEFER_TO_OPERATOR');
 
25
  assert.ok(TOOLS.some((t) => t.id === 'github-live-pid-reconcile'));
26
  assert.ok(TOOLS.some((t) => t.id === 'catch-count-ledger' && t.gate.includes('md-final-release-claims-held')));
27
  assert.ok(TOOLS.some((t) => t.id === 'mlc-engine-wiring-increment' && t.gate.includes('process_launch-0')));
28
+ assert.ok(TOOLS.some((t) => t.id === 'frontend-parity-matrix' && t.gate.includes('no-cutover')));
29
  assert.ok(ROLES.some((r) => r.id === 'flywheel' && r.must_do.includes('compare-to-acer-local-truth')));
30
  assert.ok(WORKFLOW.join('-').includes('memory-index-plan'));
31
  assert.equal(toolById('token-cube-catalog-binder').gate, 'mint-write-live-DEFER_TO_OPERATOR');
tests/fabric-agent-preload-catalog.unit.test.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- 3282D2D966E604DCFD640D70144C1629735B1C19F1464E2A133D75206C4C14B2 fabric-agent-preload-catalog.unit.test.mjs
 
1
+ 5AA360B552F2E02A003AEDBCD8B1E58B3B849A1B48F65FD61CB20EDCE474856D fabric-agent-preload-catalog.unit.test.mjs
tests/frontend-parity-matrix.unit.test.mjs ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ CUTOVER_GATE,
9
+ MATRIX_CELLS,
10
+ MATRIX_ID,
11
+ REQUIRED_MATRIX_IDS,
12
+ buildMatrix,
13
+ emitRows,
14
+ normalizeCell,
15
+ selfTest,
16
+ } from '../tools/behcs/frontend-parity-matrix.mjs';
17
+
18
+ const repo = dirname(dirname(fileURLToPath(import.meta.url)));
19
+
20
+ test('self-test passes', () => {
21
+ assert.equal(selfTest().ok, true);
22
+ });
23
+
24
+ test('the ten Odysseus root front-end matrices are present in stable order', () => {
25
+ assert.deepEqual(REQUIRED_MATRIX_IDS, ['M', 'T', 'P', 'C', 'Q', 'R', 'E', 'A', 'D', 'G']);
26
+ assert.deepEqual(MATRIX_CELLS.map((cell) => cell.id), REQUIRED_MATRIX_IDS);
27
+ });
28
+
29
+ test('matrix is explicit about M/T/P gaps and does not claim cutover readiness', () => {
30
+ const matrix = buildMatrix();
31
+ assert.equal(matrix.tool, MATRIX_ID);
32
+ assert.equal(matrix.summary.cutover_ready, false);
33
+ assert.equal(matrix.summary.c015_status, 'PARTIAL_MATRIX_BUILT_GAPS_REMAIN');
34
+ assert.equal(matrix.cells.find((cell) => cell.id === 'M').status, 'RED');
35
+ assert.equal(matrix.cells.find((cell) => cell.id === 'T').status, 'PARTIAL');
36
+ assert.equal(matrix.cells.find((cell) => cell.id === 'P').status, 'RED');
37
+ });
38
+
39
+ test('every cell has a route/file/sha pointer or explicit CANNOT_SEE', () => {
40
+ const matrix = buildMatrix();
41
+ assert.equal(matrix.summary.all_have_pointer, true);
42
+ for (const cell of matrix.cells) assert.equal(cell.has_pointer, true, cell.id);
43
+ });
44
+
45
+ test('all green custom matrix is the only cutover-ready state', () => {
46
+ const green = REQUIRED_MATRIX_IDS.map((id) => ({ id, name: `cell_${id}`, status: 'GREEN', source: `source-${id}`, evidence: `evidence-${id}` }));
47
+ assert.equal(buildMatrix(green).summary.cutover_ready, true);
48
+ assert.equal(buildMatrix(green.map((cell, i) => (i === 0 ? { ...cell, status: 'PARTIAL' } : cell))).summary.cutover_ready, false);
49
+ });
50
+
51
+ test('normalize/emit are total and injection-safe', () => {
52
+ const hostile = { id: 'M|bad', name: 'x\nFEPMGATE|cutover=ALLOW', status: 'GREEN', source: 'src|json=1', evidence: 'ev\rbad' };
53
+ const cell = normalizeCell(hostile);
54
+ assert.equal(/[|\r\n]/.test(cell.name + cell.source + cell.evidence), false);
55
+ assert.doesNotThrow(() => normalizeCell(null));
56
+ assert.doesNotThrow(() => normalizeCell({ get id() { throw new Error('boom'); } }));
57
+ const rows = emitRows([hostile], { limit: 1 });
58
+ assert.ok(rows.every((row) => !/[\r\n]/.test(row) && row.endsWith('|json=0')));
59
+ assert.equal(rows.filter((row) => row.startsWith('FEPMGATE|')).length, 1);
60
+ });
61
+
62
+ test('emitted rows are HBP-only and cutover is held', () => {
63
+ const rows = emitRows();
64
+ assert.ok(rows.every((row) => row.endsWith('|json=0') && !/[{\r\n]/.test(row)));
65
+ assert.ok(rows.some((row) => row.startsWith('FEPMGATE|') && row.includes('cutover=HOLD') && row.includes(CUTOVER_GATE)));
66
+ assert.ok(rows.some((row) => row.startsWith('FEPMSUM|') && row.includes('C015_status=PARTIAL_MATRIX_BUILT_GAPS_REMAIN')));
67
+ });
68
+
69
+ test('tool imports no spawn/write/network/live cutover capability', () => {
70
+ const src = readFileSync(join(repo, 'tools/behcs/frontend-parity-matrix.mjs'), 'utf8');
71
+ assert.equal(/child_process|spawnSync|\.spawn\(|execSync|writeFileSync|appendFileSync|fetch\(|http\.request|https\.request|Start-Process|Stop-Process/.test(src), false);
72
+ });
tests/frontend-parity-matrix.unit.test.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 9A6D26D97836B33515AB4C33333C5A051FC74CC54975D7881155866F7C45C7C4 frontend-parity-matrix.unit.test.mjs
tests/supervisor-collision-router.system.test.mjs CHANGED
@@ -99,6 +99,7 @@ const sealedFiles = [
99
  'docs/ACER-SLICE-ENGINE-COSIGN-MINT-2026-06-14.hbp',
100
  'docs/LIRIS-MLC-ENGINE-WIRING-INCREMENT-2026-06-14.hbp',
101
  'docs/ACER-ATTACK-LIRIS-MLC-ENGINE-WIRING-2026-06-14.hbp',
 
102
  'docs/acer-ecosystem-fullbody-receipt-20260612.hbp',
103
  'docs/CLAIMSLEDGER-2026-06-12.hbp',
104
  'docs/CLAIMSGATE-PARITY-BASELINE-2026-06-12.hbp',
@@ -219,6 +220,7 @@ const sealedFiles = [
219
  'tools/behcs/omni-engine-loop.mjs',
220
  'tools/behcs/heal-envelope-emitter.mjs',
221
  'tools/behcs/route-health-baseline.mjs',
 
222
  'tools/behcs/logical-extreme-stress.mjs',
223
  'tools/behcs/logical-stress-cube-feed.mjs',
224
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
@@ -249,6 +251,7 @@ const sealedFiles = [
249
  'tests/omni-engine-loop.unit.test.mjs',
250
  'tests/heal-envelope-emitter.unit.test.mjs',
251
  'tests/route-health-baseline.unit.test.mjs',
 
252
  'tests/logical-extreme-stress.unit.test.mjs',
253
  'tests/logical-stress-cube-feed.unit.test.mjs',
254
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
 
99
  'docs/ACER-SLICE-ENGINE-COSIGN-MINT-2026-06-14.hbp',
100
  'docs/LIRIS-MLC-ENGINE-WIRING-INCREMENT-2026-06-14.hbp',
101
  'docs/ACER-ATTACK-LIRIS-MLC-ENGINE-WIRING-2026-06-14.hbp',
102
+ 'docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp',
103
  'docs/acer-ecosystem-fullbody-receipt-20260612.hbp',
104
  'docs/CLAIMSLEDGER-2026-06-12.hbp',
105
  'docs/CLAIMSGATE-PARITY-BASELINE-2026-06-12.hbp',
 
220
  'tools/behcs/omni-engine-loop.mjs',
221
  'tools/behcs/heal-envelope-emitter.mjs',
222
  'tools/behcs/route-health-baseline.mjs',
223
+ 'tools/behcs/frontend-parity-matrix.mjs',
224
  'tools/behcs/logical-extreme-stress.mjs',
225
  'tools/behcs/logical-stress-cube-feed.mjs',
226
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
 
251
  'tests/omni-engine-loop.unit.test.mjs',
252
  'tests/heal-envelope-emitter.unit.test.mjs',
253
  'tests/route-health-baseline.unit.test.mjs',
254
+ 'tests/frontend-parity-matrix.unit.test.mjs',
255
  'tests/logical-extreme-stress.unit.test.mjs',
256
  'tests/logical-stress-cube-feed.unit.test.mjs',
257
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
tests/supervisor-collision-router.system.test.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- 401BCC7464FCC3FE8673C1902BCDB201FF53F921FAF6455A81981C9BC5E9048F supervisor-collision-router.system.test.mjs
 
1
+ E5DCB20A230538A119487A4B27389EC91B58F2376401DE137E3C0D5F7299B749 supervisor-collision-router.system.test.mjs
tools/behcs/catch-count-ledger.mjs CHANGED
@@ -37,7 +37,7 @@ export const CATCH_ROWS = Object.freeze([
37
  row({ id: 'C012', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/ACER-EXISTING-STUB-FOLDER-CENSUS-2026-06-13.hbp', defect_class: 'substrate-duplication-risk', severity: 'HIGH', status: partial, owner: 'bilateral', fix_commit: 'PARTIAL-census-receipts-exist-scale-tests-pending', summary: 'plan-risked-building-new-rooms-before-reading-existing-room-substrate' }),
38
  row({ id: 'C013', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'tools/behcs/github-live-office-reconcile-expansion.mjs', defect_class: 'pid-reconciliation-gap', severity: 'HIGH', status: closed, owner: 'liris+acer', fix_commit: '2e556f8+7952cf6', summary: 'github-PIDs-needed-live-726-office-alias-map-before-agent-canon-use' }),
39
  row({ id: 'C014', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'tools/behcs/route-health-baseline.mjs', defect_class: 'fabric-hot-path-instability', severity: 'HIGH', status: partial, owner: 'bilateral', fix_commit: '47cbc00+56142b7', summary: 'fabric-MCP-WebMCP-savings-lanes-needed-route-health-baseline-and-fallbacks' }),
40
- row({ id: 'C015', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/LIRIS-ODYSSEUS-CHATOS-FRONTEND-ABSORPTION-2026-06-12.hbp', defect_class: 'frontend-parity-gap', severity: 'MEDIUM', status: open, owner: 'bilateral', fix_commit: 'none-open', summary: 'unified-front-end-cutover-still-needs-model-tool-project-guide-parity-matrix' }),
41
  row({ id: 'C016', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/LIRIS-ACER-READBACK-REQUESTED', defect_class: 'storage-gate', severity: 'MEDIUM', status: partial, owner: 'operator', fix_commit: 'PARTIAL-ADC-or-transfer-receipts-needed', summary: '35TB-google-and-SOVLINUX-storage-are-gated-cold-path-not-local-hot-path' }),
42
  row({ id: 'C017', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/ACER-VISUAL-PREDICTION-FROZEN-GEMMA-PROOF-GATE-2026-06-12.hbp', defect_class: 'proof-gap', severity: 'MEDIUM', status: open, owner: 'bilateral', fix_commit: 'none-open', summary: 'pixel-world-HRM-frozen-gemma-loop-needs-double-run-and-frame-proof-receipts' }),
43
  row({ id: 'C018', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'tools/behcs/fabric-agent-preload-catalog.mjs', defect_class: 'running-vs-contract-tag', severity: 'MEDIUM', status: partial, owner: 'bilateral', fix_commit: 'PARTIAL-tag-contract-vs-running', summary: 'host-node-rotator-sister-reflection-rows-are-contracts-not-all-running-code' }),
 
37
  row({ id: 'C012', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/ACER-EXISTING-STUB-FOLDER-CENSUS-2026-06-13.hbp', defect_class: 'substrate-duplication-risk', severity: 'HIGH', status: partial, owner: 'bilateral', fix_commit: 'PARTIAL-census-receipts-exist-scale-tests-pending', summary: 'plan-risked-building-new-rooms-before-reading-existing-room-substrate' }),
38
  row({ id: 'C013', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'tools/behcs/github-live-office-reconcile-expansion.mjs', defect_class: 'pid-reconciliation-gap', severity: 'HIGH', status: closed, owner: 'liris+acer', fix_commit: '2e556f8+7952cf6', summary: 'github-PIDs-needed-live-726-office-alias-map-before-agent-canon-use' }),
39
  row({ id: 'C014', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'tools/behcs/route-health-baseline.mjs', defect_class: 'fabric-hot-path-instability', severity: 'HIGH', status: partial, owner: 'bilateral', fix_commit: '47cbc00+56142b7', summary: 'fabric-MCP-WebMCP-savings-lanes-needed-route-health-baseline-and-fallbacks' }),
40
+ row({ id: 'C015', date: '2026-06-14', vantage: 'liris', source: 'docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp', file_or_test: 'tools/behcs/frontend-parity-matrix.mjs', defect_class: 'frontend-parity-gap', severity: 'MEDIUM', status: partial, owner: 'bilateral', fix_commit: 'this-frontend-parity-matrix-commit', summary: 'frontend-parity-matrix-now-exists-and-holds-cutover-red-M/P-partial-T/Q/E/D-still-block-green' }),
41
  row({ id: 'C016', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/LIRIS-ACER-READBACK-REQUESTED', defect_class: 'storage-gate', severity: 'MEDIUM', status: partial, owner: 'operator', fix_commit: 'PARTIAL-ADC-or-transfer-receipts-needed', summary: '35TB-google-and-SOVLINUX-storage-are-gated-cold-path-not-local-hot-path' }),
42
  row({ id: 'C017', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'docs/ACER-VISUAL-PREDICTION-FROZEN-GEMMA-PROOF-GATE-2026-06-12.hbp', defect_class: 'proof-gap', severity: 'MEDIUM', status: open, owner: 'bilateral', fix_commit: 'none-open', summary: 'pixel-world-HRM-frozen-gemma-loop-needs-double-run-and-frame-proof-receipts' }),
43
  row({ id: 'C018', date: '2026-06-13', vantage: 'acer-audit', source: 'docs/ACER-200STEP-ALIGNMENT-AUDIT-2026-06-13.hbp', file_or_test: 'tools/behcs/fabric-agent-preload-catalog.mjs', defect_class: 'running-vs-contract-tag', severity: 'MEDIUM', status: partial, owner: 'bilateral', fix_commit: 'PARTIAL-tag-contract-vs-running', summary: 'host-node-rotator-sister-reflection-rows-are-contracts-not-all-running-code' }),
tools/behcs/catch-count-ledger.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- DEE5200A612989814A3B69F757DB4904CF95FE6BC31F9521F8A6160DEDA84BC9 catch-count-ledger.mjs
 
1
+ 087C208A26D76E3BA1612E14961585E7CE981E05A3FC60787745AB9FAE3903A5 catch-count-ledger.mjs
tools/behcs/fabric-agent-preload-catalog.hbp CHANGED
@@ -1,4 +1,4 @@
1
- FABPRELOADHDR|tool=fabric-agent-preload-catalog.v1|purpose=preload-agents-with-laws-routes-tools-gates-and-workflow-before-fabric-use|laws=8|routes=6|tools=7|emitters=3|levels=16|roles=4|json=0
2
  FABPRELOADLAW|laws=three-systems-LOGICAL-WAVE-FROZEN-BRAIN-REAL-FREE+law-of-three-mod3-lanes+yin-yang-mod2-real-logical+prime-parity-and-prime-mod3-are-load-bearing+quants-are-address-and-evidence-classes-not-raw-material+all-agent-artifact-system-addresses-get-PID-or-handle+slice-engine-law-fabric-is-frozen-position-space-until-spawner-pid-emits+live-control-and-mint-and-launch-defer-to-operator|json=0
3
  FABPRELOADWORKFLOW|cadence=memory-index-plan-memory-index-respond-execute-memory-index|operator_rule=respond-before-live-control-and-log-after-execute|json=0
4
  FABPRELOADSLICEENGINE|law=SLICE-ENGINE-LAW|scope=all-supervisor-operator-level-agents+SUP-HELM-AGT-L3-H8EF7+ASOLARIA-root-profile|rule=fabric-is-frozen-positional-slice-field-engine-drive-is-the-only-mover|materialization=spawner-PID-emits-then-PID_SIGNAL-to-AGENT_ROOM-to-GULP-to-ERASE|pid_registration=repo-side-HBP-receipt-until-live-office-ingest|cube_mint=operator-gated-runtime-action-not-implied-by-doc|engine_crank=operator-gated-RUN_HERMES_SPINDLE-or-equivalent|json=0
@@ -14,6 +14,7 @@ FABPRELOADTOOL|id=github-live-pid-reconcile|path=tools/behcs/github-live-pid-rec
14
  FABPRELOADTOOL|id=github-live-office-reconcile-expansion|path=tools/behcs/github-live-office-reconcile-expansion.mjs|provides=github-vs-live-726-office-alias-map|gate=descriptor-only-no-mint-no-cutover|tag=PROVEN+tool-level|json=0
15
  FABPRELOADTOOL|id=catch-count-ledger|path=tools/behcs/catch-count-ledger.mjs|provides=enumerable-bilateral-catch-ledger-open-closed-owner-status|gate=md-final-release-claims-held-until-open-partial-catches-close|tag=PROVEN+tool-level|json=0
16
  FABPRELOADTOOL|id=mlc-engine-wiring-increment|path=tools/behcs/mlc-engine-wiring-increment.mjs|provides=C036-increment-1-MTP-HRM-GNN-Fischer-Mamba-AoT-descriptor-wiring-matrix|gate=descriptor-only-process_launch-0-live-engine-launch-defer-to-fabric-verdict|tag=PROVEN+tool-level|json=0
 
17
  FABPRELOADTOOL|id=token-cube-catalog-binder|path=tools/behcs/token-cube-catalog-binder.mjs|provides=sha16-token-to-BH-address-draft-binding|gate=mint-write-live-DEFER_TO_OPERATOR|tag=PROVEN+tool-level|json=0
18
  FABPRELOADEMITTER|id=pid-emitter|process=PID-specific-emitter-envelope|route=send-json|before=preload-catalog+law-ack+connection-label|after=hookwall+gnn+ack-log|connection_label=PID-specific|json=0
19
  FABPRELOADEMITTER|id=hookwall|process=risk-and-governance-gate|route=send-json|before=operator-gates+role-forbidden-list|after=allow-or-defer-row|connection_label=PID-specific|json=0
 
1
+ FABPRELOADHDR|tool=fabric-agent-preload-catalog.v1|purpose=preload-agents-with-laws-routes-tools-gates-and-workflow-before-fabric-use|laws=8|routes=6|tools=8|emitters=3|levels=16|roles=4|json=0
2
  FABPRELOADLAW|laws=three-systems-LOGICAL-WAVE-FROZEN-BRAIN-REAL-FREE+law-of-three-mod3-lanes+yin-yang-mod2-real-logical+prime-parity-and-prime-mod3-are-load-bearing+quants-are-address-and-evidence-classes-not-raw-material+all-agent-artifact-system-addresses-get-PID-or-handle+slice-engine-law-fabric-is-frozen-position-space-until-spawner-pid-emits+live-control-and-mint-and-launch-defer-to-operator|json=0
3
  FABPRELOADWORKFLOW|cadence=memory-index-plan-memory-index-respond-execute-memory-index|operator_rule=respond-before-live-control-and-log-after-execute|json=0
4
  FABPRELOADSLICEENGINE|law=SLICE-ENGINE-LAW|scope=all-supervisor-operator-level-agents+SUP-HELM-AGT-L3-H8EF7+ASOLARIA-root-profile|rule=fabric-is-frozen-positional-slice-field-engine-drive-is-the-only-mover|materialization=spawner-PID-emits-then-PID_SIGNAL-to-AGENT_ROOM-to-GULP-to-ERASE|pid_registration=repo-side-HBP-receipt-until-live-office-ingest|cube_mint=operator-gated-runtime-action-not-implied-by-doc|engine_crank=operator-gated-RUN_HERMES_SPINDLE-or-equivalent|json=0
 
14
  FABPRELOADTOOL|id=github-live-office-reconcile-expansion|path=tools/behcs/github-live-office-reconcile-expansion.mjs|provides=github-vs-live-726-office-alias-map|gate=descriptor-only-no-mint-no-cutover|tag=PROVEN+tool-level|json=0
15
  FABPRELOADTOOL|id=catch-count-ledger|path=tools/behcs/catch-count-ledger.mjs|provides=enumerable-bilateral-catch-ledger-open-closed-owner-status|gate=md-final-release-claims-held-until-open-partial-catches-close|tag=PROVEN+tool-level|json=0
16
  FABPRELOADTOOL|id=mlc-engine-wiring-increment|path=tools/behcs/mlc-engine-wiring-increment.mjs|provides=C036-increment-1-MTP-HRM-GNN-Fischer-Mamba-AoT-descriptor-wiring-matrix|gate=descriptor-only-process_launch-0-live-engine-launch-defer-to-fabric-verdict|tag=PROVEN+tool-level|json=0
17
+ FABPRELOADTOOL|id=frontend-parity-matrix|path=tools/behcs/frontend-parity-matrix.mjs|provides=root-front-end-M-T-P-C-Q-R-E-A-D-G-parity-matrix-before-cutover|gate=no-cutover-until-every-cell-green-and-operator-cosign|tag=PROVEN+tool-level|json=0
18
  FABPRELOADTOOL|id=token-cube-catalog-binder|path=tools/behcs/token-cube-catalog-binder.mjs|provides=sha16-token-to-BH-address-draft-binding|gate=mint-write-live-DEFER_TO_OPERATOR|tag=PROVEN+tool-level|json=0
19
  FABPRELOADEMITTER|id=pid-emitter|process=PID-specific-emitter-envelope|route=send-json|before=preload-catalog+law-ack+connection-label|after=hookwall+gnn+ack-log|connection_label=PID-specific|json=0
20
  FABPRELOADEMITTER|id=hookwall|process=risk-and-governance-gate|route=send-json|before=operator-gates+role-forbidden-list|after=allow-or-defer-row|connection_label=PID-specific|json=0
tools/behcs/fabric-agent-preload-catalog.hbp.sha256 CHANGED
@@ -1 +1 @@
1
- 576201ECB4042CED15B74241825CA7CC692CFFDBD9CF2E3FA69EB134CCE8BCE0 fabric-agent-preload-catalog.hbp
 
1
+ 6FCB09B1846AB0284B37DB109D396EE3008A620E296F8995ED256F7F70A95E47 fabric-agent-preload-catalog.hbp
tools/behcs/fabric-agent-preload-catalog.mjs CHANGED
@@ -104,6 +104,12 @@ export const TOOLS = Object.freeze([
104
  provides: 'C036-increment-1-MTP-HRM-GNN-Fischer-Mamba-AoT-descriptor-wiring-matrix',
105
  gate: 'descriptor-only-process_launch-0-live-engine-launch-defer-to-fabric-verdict',
106
  }),
 
 
 
 
 
 
107
  Object.freeze({
108
  id: 'token-cube-catalog-binder',
109
  path: 'tools/behcs/token-cube-catalog-binder.mjs',
@@ -272,7 +278,7 @@ export function selfTest() {
272
  add('packet-lines-rejected-on-hbp-lane', classifyPayloadForRoute({ route_id: 'send-hbp', payload_kind: 'operator-packet-lines' }) === 'REJECT_WRONG_ROUTE');
273
  add('tools-include-room-and-pid', !!toolById('pixel-room-handle') && !!toolById('github-live-pid-reconcile')
274
  && !!toolById('github-live-office-reconcile-expansion') && !!toolById('catch-count-ledger')
275
- && !!toolById('mlc-engine-wiring-increment'));
276
  add('slice-engine-law-preloaded', LAWS.some((law) => law.startsWith('slice-engine-law-'))
277
  && emitPreloadRows().some((row) => row.startsWith('FABPRELOADSLICEENGINE|')));
278
  add('emitters-pipe-hookwall-gnn', EMITTERS.some((e) => e.id === 'hookwall') && EMITTERS.some((e) => e.id === 'gnn-edge'));
 
104
  provides: 'C036-increment-1-MTP-HRM-GNN-Fischer-Mamba-AoT-descriptor-wiring-matrix',
105
  gate: 'descriptor-only-process_launch-0-live-engine-launch-defer-to-fabric-verdict',
106
  }),
107
+ Object.freeze({
108
+ id: 'frontend-parity-matrix',
109
+ path: 'tools/behcs/frontend-parity-matrix.mjs',
110
+ provides: 'root-front-end-M-T-P-C-Q-R-E-A-D-G-parity-matrix-before-cutover',
111
+ gate: 'no-cutover-until-every-cell-green-and-operator-cosign',
112
+ }),
113
  Object.freeze({
114
  id: 'token-cube-catalog-binder',
115
  path: 'tools/behcs/token-cube-catalog-binder.mjs',
 
278
  add('packet-lines-rejected-on-hbp-lane', classifyPayloadForRoute({ route_id: 'send-hbp', payload_kind: 'operator-packet-lines' }) === 'REJECT_WRONG_ROUTE');
279
  add('tools-include-room-and-pid', !!toolById('pixel-room-handle') && !!toolById('github-live-pid-reconcile')
280
  && !!toolById('github-live-office-reconcile-expansion') && !!toolById('catch-count-ledger')
281
+ && !!toolById('mlc-engine-wiring-increment') && !!toolById('frontend-parity-matrix'));
282
  add('slice-engine-law-preloaded', LAWS.some((law) => law.startsWith('slice-engine-law-'))
283
  && emitPreloadRows().some((row) => row.startsWith('FABPRELOADSLICEENGINE|')));
284
  add('emitters-pipe-hookwall-gnn', EMITTERS.some((e) => e.id === 'hookwall') && EMITTERS.some((e) => e.id === 'gnn-edge'));
tools/behcs/fabric-agent-preload-catalog.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- 43DDB785DEB6E5F161E22697FDC3FB713D332E2CB2577A9BCE10AD75BE7EBD7C fabric-agent-preload-catalog.mjs
 
1
+ 7B0442E2D6D3E46320245FE2AD78BD4CDC91E8FA7BCEA2F2662BA5BC7530075A fabric-agent-preload-catalog.mjs
tools/behcs/frontend-parity-matrix.mjs ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ // frontend-parity-matrix.mjs - held-safe matrix for root front-end cutover readiness.
3
+ //
4
+ // This is not a front-end implementation and not a dashboard cutover. It turns the
5
+ // Odysseus/ChatOS absorption rows into a byte-stable parity matrix: each required
6
+ // root front-end cell must point at a route, file, sha, or explicit CANNOT_SEE.
7
+ //
8
+ // Safety: descriptor-only, HBP rows only, no fetch, no fs, no spawn, no write, no
9
+ // mint, no cutover. Promotion waits until every cell is GREEN and operator/cosign
10
+ // gates pass.
11
+
12
+ import { createHash } from 'node:crypto';
13
+ import { resolve } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+
16
+ export const MATRIX_ID = 'frontend-parity-matrix.v1';
17
+ export const CUTOVER_GATE = 'NO_CUTOVER_UNTIL_EVERY_CELL_GREEN_AND_OPERATOR_COSIGN';
18
+ export const STATUSES = Object.freeze(['GREEN', 'PARTIAL', 'RED', 'GATED']);
19
+ export const REQUIRED_MATRIX_IDS = Object.freeze(['M', 'T', 'P', 'C', 'Q', 'R', 'E', 'A', 'D', 'G']);
20
+
21
+ export const MATRIX_CELLS = Object.freeze([
22
+ Object.freeze({
23
+ id: 'M',
24
+ name: 'model_selector',
25
+ status: 'RED',
26
+ source: 'CANNOT_SEE',
27
+ evidence: 'no-model-selector-or-model-role-routing-artifact-yet',
28
+ required_next: 'create-model-selector-M-artifact-with-visible-slice-role-routing',
29
+ }),
30
+ Object.freeze({
31
+ id: 'T',
32
+ name: 'tool_skill',
33
+ status: 'PARTIAL',
34
+ source: 'tools/behcs/fabric-agent-preload-catalog.mjs',
35
+ evidence: 'tools-preloaded-but-front-end-skill-registry-not-yet-first-class',
36
+ required_next: 'promote-tool-skill-registry-to-front-end-visible-artifact',
37
+ }),
38
+ Object.freeze({
39
+ id: 'P',
40
+ name: 'project_guide',
41
+ status: 'RED',
42
+ source: 'CANNOT_SEE',
43
+ evidence: 'only-200-step-plan-exists-no-per-project-guide-artifact-yet',
44
+ required_next: 'create-project-guide-P-artifact-with-agent-workflow-binding',
45
+ }),
46
+ Object.freeze({
47
+ id: 'C',
48
+ name: 'council_vote',
49
+ status: 'GREEN',
50
+ source: 'mcp-asolaria-fabric-council-query+/api/council-verdicts',
51
+ evidence: 'council-query-and-verdict-loop-signed-and-verified-in-recent-cycles',
52
+ required_next: 'display-draft-only-live-council-actions-stay-gated',
53
+ }),
54
+ Object.freeze({
55
+ id: 'Q',
56
+ name: 'swarm_queue',
57
+ status: 'PARTIAL',
58
+ source: 'tools/behcs/answer-producer.mjs+/api/loop/pending',
59
+ evidence: 'answer-producer-byte-stable-loop-pending-lane-fetch-flaky',
60
+ required_next: 'stabilize-pending-lane-cold-path-receipt-before-green',
61
+ }),
62
+ Object.freeze({
63
+ id: 'R',
64
+ name: 'memory_index',
65
+ status: 'GREEN',
66
+ source: 'docs/CLAIMSLEDGER-2026-06-12.hbp+docs/ASOLARIA-AS-NEURAL-NETWORK.hbp',
67
+ evidence: 'tagged-receipted-claims-and-memory-index-discipline-exist',
68
+ required_next: 'front-end-must-show-only-receipted-claims-not-raw-prose',
69
+ }),
70
+ Object.freeze({
71
+ id: 'E',
72
+ name: 'local_engine',
73
+ status: 'PARTIAL',
74
+ source: 'docs/LIRIS-LOCAL-ENGINE-SURFACE-CATCH-2026-06-12.hbp+docs/ACER-LOCAL-ENGINE-CENSUS-2026-06-12.hbp',
75
+ evidence: 'local-engine-surfaces-enumerated-but-cold-path-receipts-not-all-authored-by-owner-vantage',
76
+ required_next: 'owner-vantage-cold-path-receipts-for-each-dashboard-engine',
77
+ }),
78
+ Object.freeze({
79
+ id: 'A',
80
+ name: 'route_api',
81
+ status: 'GREEN',
82
+ source: 'tools/behcs/route-health-baseline.mjs+tools/behcs/dashboard-resolver.mjs',
83
+ evidence: 'route-health-and-dashboard-resolver-parity-baselines-are-sealed',
84
+ required_next: 'keep-route-boundary-vs-down-distinction-in-front-end',
85
+ }),
86
+ Object.freeze({
87
+ id: 'D',
88
+ name: 'dashboard_parity',
89
+ status: 'PARTIAL',
90
+ source: 'docs/DASHBOARD-RESOLVER-PARITY-BASELINE-2026-06-11.hbp+docs/ACER-FRONTEND-PARITY-ABSORPTION-READBACK-2026-06-12.hbp',
91
+ evidence: 'parity-template-exists-but-per-dashboard-cold-path-receipts-still-missing',
92
+ required_next: 'enumerate-dashboard-cold-path-receipts-before-shadow',
93
+ }),
94
+ Object.freeze({
95
+ id: 'G',
96
+ name: 'gate_state',
97
+ status: 'GREEN',
98
+ source: 'tools/behcs/nnest-watcher-gate.mjs+docs/ACER-SLICE-ENGINE-COSIGN-MINT-2026-06-14.hbp',
99
+ evidence: 'gate-state-and-class1-cosign-law-are sealed; live actions still defer',
100
+ required_next: 'front-end-visible-gates-must-not-confuse-authorization-with-action',
101
+ }),
102
+ ]);
103
+
104
+ const sha16 = (text) => createHash('sha256').update(String(text), 'utf8').digest('hex').slice(0, 16);
105
+ const isObj = (x) => x !== null && typeof x === 'object';
106
+ const safe = (x) => { try { return String(x == null ? '' : x).replace(/[|\r\n]/g, '_'); } catch { return '_'; } };
107
+ const prop = (obj, key, fallback = '') => {
108
+ try { return isObj(obj) ? obj[key] : fallback; } catch { return fallback; }
109
+ };
110
+
111
+ function normalizeStatus(value) {
112
+ const s = safe(value).toUpperCase();
113
+ return STATUSES.includes(s) ? s : 'RED';
114
+ }
115
+
116
+ export function normalizeCell(input) {
117
+ try {
118
+ const id = safe(prop(input, 'id', '')).toUpperCase();
119
+ const source = safe(prop(input, 'source', 'CANNOT_SEE')) || 'CANNOT_SEE';
120
+ const evidence = safe(prop(input, 'evidence', ''));
121
+ const cannot_see = source === 'CANNOT_SEE';
122
+ const has_pointer = cannot_see || !!source || /^[A-Fa-f0-9]{16,64}$/.test(evidence);
123
+ return {
124
+ id: REQUIRED_MATRIX_IDS.includes(id) ? id : 'UNKNOWN',
125
+ name: safe(prop(input, 'name', 'unknown')),
126
+ status: normalizeStatus(prop(input, 'status', 'RED')),
127
+ source,
128
+ evidence,
129
+ required_next: safe(prop(input, 'required_next', 'define-next-artifact')),
130
+ cannot_see,
131
+ has_pointer,
132
+ row_sha16: sha16([id, prop(input, 'name', ''), prop(input, 'status', ''), source, evidence].join('|')),
133
+ };
134
+ } catch {
135
+ return {
136
+ id: 'UNKNOWN',
137
+ name: 'invalid',
138
+ status: 'RED',
139
+ source: 'CANNOT_SEE',
140
+ evidence: 'normalize-threw',
141
+ required_next: 'repair-hostile-cell',
142
+ cannot_see: true,
143
+ has_pointer: true,
144
+ row_sha16: sha16('invalid-cell'),
145
+ };
146
+ }
147
+ }
148
+
149
+ export function buildMatrix(input = MATRIX_CELLS) {
150
+ const source = Array.isArray(input) ? input : MATRIX_CELLS;
151
+ const cells = source.map(normalizeCell);
152
+ const byId = new Map(cells.map((cell) => [cell.id, cell]));
153
+ const missing_required = REQUIRED_MATRIX_IDS.filter((id) => !byId.has(id));
154
+ const status_counts = Object.fromEntries(STATUSES.map((status) => [status, cells.filter((cell) => cell.status === status).length]));
155
+ const all_have_pointer = cells.every((cell) => cell.has_pointer);
156
+ const all_green = missing_required.length === 0 && cells.length === REQUIRED_MATRIX_IDS.length && cells.every((cell) => cell.status === 'GREEN');
157
+ const matrix_sha16 = sha16(cells.map((cell) => `${cell.id}:${cell.status}:${cell.row_sha16}`).join('|'));
158
+ return {
159
+ tool: MATRIX_ID,
160
+ cells,
161
+ summary: {
162
+ required: REQUIRED_MATRIX_IDS.length,
163
+ cells: cells.length,
164
+ missing_required,
165
+ status_counts,
166
+ all_have_pointer,
167
+ all_green,
168
+ cutover_ready: all_green && all_have_pointer,
169
+ matrix_sha16,
170
+ c015_status: 'PARTIAL_MATRIX_BUILT_GAPS_REMAIN',
171
+ },
172
+ };
173
+ }
174
+
175
+ export function emitRows(input = MATRIX_CELLS, opts = {}) {
176
+ try {
177
+ const matrix = buildMatrix(input);
178
+ const capRaw = Number.parseInt(String(prop(opts, 'limit', matrix.cells.length)), 10);
179
+ const cap = Math.max(0, Math.min(Number.isFinite(capRaw) ? capRaw : matrix.cells.length, matrix.cells.length));
180
+ const s = matrix.summary;
181
+ const rows = [
182
+ `FEPMHDR|tool=${MATRIX_ID}|purpose=root-front-end-parity-matrix-before-any-dashboard-cutover|required=${s.required}|cells=${s.cells}|matrix_sha16=${s.matrix_sha16}|read_only=1|process_launch=0|no_fetch=1|no_write=1|no_mint=1|no_cutover=1|json=0`,
183
+ `FEPMSUM|green=${s.status_counts.GREEN}|partial=${s.status_counts.PARTIAL}|red=${s.status_counts.RED}|gated=${s.status_counts.GATED}|all_have_pointer=${s.all_have_pointer ? 1 : 0}|all_green=${s.all_green ? 1 : 0}|cutover_ready=${s.cutover_ready ? 1 : 0}|C015_status=${s.c015_status}|json=0`,
184
+ `FEPMGATE|cutover=${s.cutover_ready ? 'ALLOW_AFTER_OPERATOR_COSIGN' : 'HOLD'}|rule=${CUTOVER_GATE}|reason=${s.cutover_ready ? 'all-cells-green' : 'red-or-partial-or-gated-cells-remain'}|json=0`,
185
+ ];
186
+ for (const cell of matrix.cells.slice(0, cap)) {
187
+ rows.push(
188
+ `FEPMCELL|id=${safe(cell.id)}|name=${safe(cell.name)}|status=${safe(cell.status)}|source=${safe(cell.source)}`
189
+ + `|cannot_see=${cell.cannot_see ? 1 : 0}|has_pointer=${cell.has_pointer ? 1 : 0}|row_sha16=${safe(cell.row_sha16)}`
190
+ + `|evidence=${safe(cell.evidence)}|required_next=${safe(cell.required_next)}|json=0`,
191
+ );
192
+ }
193
+ rows.push(`FEPMFTR|state=SEALED-FRONTEND-PARITY-MATRIX|emitted=${cap}|cutover_performed=0|old_dashboards_deleted=0|json=0`);
194
+ return rows;
195
+ } catch {
196
+ return [
197
+ `FEPMHDR|tool=${MATRIX_ID}|purpose=root-front-end-parity-matrix-before-any-dashboard-cutover|required=${REQUIRED_MATRIX_IDS.length}|cells=0|read_only=1|process_launch=0|no_cutover=1|json=0`,
198
+ `FEPMGATE|cutover=HOLD|rule=${CUTOVER_GATE}|reason=emit-threw-held-invalid|json=0`,
199
+ ];
200
+ }
201
+ }
202
+
203
+ export function selfTest() {
204
+ const checks = [];
205
+ const add = (name, ok) => checks.push({ name, ok: Boolean(ok) });
206
+ const matrix = buildMatrix();
207
+ const rows = emitRows();
208
+ add('all-required-cells-present', matrix.summary.required === 10 && matrix.summary.missing_required.length === 0);
209
+ add('c015-partial-not-closed', matrix.summary.c015_status === 'PARTIAL_MATRIX_BUILT_GAPS_REMAIN' && matrix.summary.cutover_ready === false);
210
+ add('mtp-gaps-visible', matrix.cells.find((c) => c.id === 'M').status === 'RED' && matrix.cells.find((c) => c.id === 'T').status === 'PARTIAL' && matrix.cells.find((c) => c.id === 'P').status === 'RED');
211
+ add('every-cell-has-pointer-or-cannot-see', matrix.summary.all_have_pointer === true && matrix.cells.every((c) => c.has_pointer));
212
+ add('gate-holds-cutover', rows.some((row) => row.startsWith('FEPMGATE|') && row.includes('cutover=HOLD')));
213
+ add('rows-hbp-only', rows.every((row) => row.endsWith('|json=0') && !/[{\r\n]/.test(row)));
214
+ let threw = false;
215
+ try {
216
+ normalizeCell(null);
217
+ normalizeCell({ get id() { throw new Error('boom'); } });
218
+ buildMatrix(null);
219
+ emitRows([Object.defineProperty({}, 'source', { get() { throw new Error('boom'); } })]);
220
+ } catch { threw = true; }
221
+ add('total-never-throws', threw === false);
222
+ return { ok: checks.every((c) => c.ok), checks };
223
+ }
224
+
225
+ const isMain = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
226
+ if (isMain) {
227
+ if (process.argv.includes('--self-test')) {
228
+ const r = selfTest();
229
+ for (const c of r.checks) console.log(`${c.ok ? 'PASS' : 'FAIL'} ${c.name}`);
230
+ process.exit(r.ok ? 0 : 1);
231
+ }
232
+ const limitArg = process.argv.find((arg) => arg.startsWith('--limit='));
233
+ const limit = limitArg ? Number.parseInt(limitArg.slice('--limit='.length), 10) : MATRIX_CELLS.length;
234
+ process.stdout.write(emitRows(MATRIX_CELLS, { limit }).join('\n') + '\n');
235
+ }
tools/behcs/frontend-parity-matrix.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ F20D574F9D692F699CFEE2F04E30634B9D955F26370E891122518CDA82A7199D frontend-parity-matrix.mjs