Kevin Crutt commited on
Commit
72a39f8
·
1 Parent(s): f56e334

liris: add project guide matrix for frontend P cell

Browse files
docs/LIRIS-PROJECT-GUIDE-MATRIX-2026-06-14.hbp ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ LIRISPROJGUIDEHDR|date=2026-06-14|topic=project-guide-P-matrix|responds_to=fabric-verdict-guide-signal-after-council-q-1781433637756-m3ha4z+frontend-parity-P-red-cell|role=liris-held-safe-frontier-build-after-model-selector-M|tag=PROVEN-DESCRIPTOR|json=0
2
+ LIRISPROJGUIDETOOL|tool=tools/behcs/project-guide-matrix.mjs|frontend_cell=P|purpose=project-guide-table-to-sealed-artifacts-before-any-workflow-execution|sections=8|safety=read-only+process_launch=0+no_fetch+no_write+no_spawn+no_cutover|tag=PROVEN-HELD-SAFE|json=0
3
+ LIRISPROJGUIDESECTIONS|green=3|partial=4|gated=1|red=0|sections=law-spine+frontier-queue+frontend-parity+model-selector+engine-wiring+route-health+cosign-submit+memory-index|meaning=front-end-can-see-where-to-go-and-what-gate-remains-but-cannot-execute-workflow|tag=PROVEN|json=0
4
+ LIRISPROJGUIDEGATE|P_cell_status=PARTIAL_GUIDE_ARTIFACT_BUILT_WORKFLOW_BINDING_GATED|frontend_matrix_change=P-RED-to-PARTIAL|not_green_because=workflow-binding-not-live+cosign-submit-schema-proof-not-built+C036-live-daemon-contract-not-returned|cutover_ready=0|tag=HONEST-PARTIAL|json=0
5
+ LIRISPROJGUIDEPARITY|updates=tools/behcs/frontend-parity-matrix.mjs|matrix_after=green3-partial7-red0|remaining_red=none|remaining_partial=M+T+P+C+Q+E+D|C015_status=PARTIAL_MATRIX_BUILT_GAPS_REMAIN|tag=PROVEN-NO-CUTOVER|json=0
6
+ LIRISPROJGUIDEVERIFY|tests=tests/project-guide-matrix.unit.test.mjs+tests/frontend-parity-matrix.unit.test.mjs+tests/fabric-agent-preload-catalog.unit.test.mjs+lattice+full-suite|regressions=totality+HBP-injection+no-live-capability+P-partial-not-green|tag=SEALED-BY-TESTS|json=0
7
+ LIRISPROJGUIDEFTR|state=PROJECT-GUIDE-P-ARTIFACT-BUILT|next=ask-fabric-again-rank-cosign-submit-schema-proof-or-tool-skill-registry-or-live-daemon-contract|no_workflow_executed=1|no_process_launched=1|json=0
docs/LIRIS-PROJECT-GUIDE-MATRIX-2026-06-14.hbp.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 190162523B3D70B849FD99EB1575E781F56E407A42E440B5E6EEFFB67DBC6FF2 LIRIS-PROJECT-GUIDE-MATRIX-2026-06-14.hbp
tests/fabric-agent-preload-catalog.unit.test.mjs CHANGED
@@ -27,6 +27,7 @@ test('preload catalog includes the laws, tools, roles, and cadence agents need',
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(TOOLS.some((t) => t.id === 'model-selector-matrix' && t.gate.includes('live-model-invocation-0')));
 
30
  assert.ok(ROLES.some((r) => r.id === 'flywheel' && r.must_do.includes('compare-to-acer-local-truth')));
31
  assert.ok(WORKFLOW.join('-').includes('memory-index-plan'));
32
  assert.equal(toolById('token-cube-catalog-binder').gate, 'mint-write-live-DEFER_TO_OPERATOR');
 
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(TOOLS.some((t) => t.id === 'model-selector-matrix' && t.gate.includes('live-model-invocation-0')));
30
+ assert.ok(TOOLS.some((t) => t.id === 'project-guide-matrix' && t.gate.includes('no-cutover')));
31
  assert.ok(ROLES.some((r) => r.id === 'flywheel' && r.must_do.includes('compare-to-acer-local-truth')));
32
  assert.ok(WORKFLOW.join('-').includes('memory-index-plan'));
33
  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
- C62F449EB7DB49C369D791E4A0D3E4077869BD717B670236C815F8B7AD00E88A fabric-agent-preload-catalog.unit.test.mjs
 
1
+ B647604A270185837EDD4448A851C0AA5F13675853D02A07835B61CBFCB7C039 fabric-agent-preload-catalog.unit.test.mjs
tests/frontend-parity-matrix.unit.test.mjs CHANGED
@@ -33,7 +33,7 @@ test('matrix is explicit about M/T/P gaps and does not claim cutover readiness',
33
  assert.equal(matrix.summary.c015_status, 'PARTIAL_MATRIX_BUILT_GAPS_REMAIN');
34
  assert.equal(matrix.cells.find((cell) => cell.id === 'M').status, 'PARTIAL');
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('model_selector cell M is PARTIAL after selector artifact, not GREEN live model readiness', () => {
@@ -45,6 +45,15 @@ test('model_selector cell M is PARTIAL after selector artifact, not GREEN live m
45
  assert.equal(matrix.summary.cutover_ready, false);
46
  });
47
 
 
 
 
 
 
 
 
 
 
48
  test('every cell has a route/file/sha pointer or explicit CANNOT_SEE', () => {
49
  const matrix = buildMatrix();
50
  assert.equal(matrix.summary.all_have_pointer, true);
 
33
  assert.equal(matrix.summary.c015_status, 'PARTIAL_MATRIX_BUILT_GAPS_REMAIN');
34
  assert.equal(matrix.cells.find((cell) => cell.id === 'M').status, 'PARTIAL');
35
  assert.equal(matrix.cells.find((cell) => cell.id === 'T').status, 'PARTIAL');
36
+ assert.equal(matrix.cells.find((cell) => cell.id === 'P').status, 'PARTIAL');
37
  });
38
 
39
  test('model_selector cell M is PARTIAL after selector artifact, not GREEN live model readiness', () => {
 
45
  assert.equal(matrix.summary.cutover_ready, false);
46
  });
47
 
48
+ test('project_guide cell P is PARTIAL after guide artifact, not GREEN workflow readiness', () => {
49
+ const matrix = buildMatrix();
50
+ const p = matrix.cells.find((cell) => cell.id === 'P');
51
+ assert.equal(p.status, 'PARTIAL');
52
+ assert.equal(p.source, 'tools/behcs/project-guide-matrix.mjs');
53
+ assert.match(p.evidence, /submit-schema-remain-gated/);
54
+ assert.equal(matrix.summary.cutover_ready, false);
55
+ });
56
+
57
  test('every cell has a route/file/sha pointer or explicit CANNOT_SEE', () => {
58
  const matrix = buildMatrix();
59
  assert.equal(matrix.summary.all_have_pointer, true);
tests/frontend-parity-matrix.unit.test.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- 8AB94225498F261212EA9233CF367F1F84C1C09D63E9DE6937577D29563D6BF1 frontend-parity-matrix.unit.test.mjs
 
1
+ 15CD15DE6DC16D40788DE5D285FCA316950B8EE8221B6756F883C5550CCAE1EC frontend-parity-matrix.unit.test.mjs
tests/project-guide-matrix.unit.test.mjs ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ FRONTEND_CELL,
9
+ GUIDE_ID,
10
+ GUIDE_SECTIONS,
11
+ P_CELL_STATUS,
12
+ buildGuide,
13
+ emitRows,
14
+ guideSection,
15
+ normalizeSection,
16
+ selfTest,
17
+ } from '../tools/behcs/project-guide-matrix.mjs';
18
+
19
+ const repo = dirname(dirname(fileURLToPath(import.meta.url)));
20
+
21
+ test('self-test passes', () => {
22
+ assert.equal(selfTest().ok, true);
23
+ });
24
+
25
+ test('guide materializes the P cell as PARTIAL, not cutover-ready GREEN', () => {
26
+ const guide = buildGuide();
27
+ assert.equal(guide.tool, GUIDE_ID);
28
+ assert.equal(guide.frontend_cell, FRONTEND_CELL);
29
+ assert.equal(guide.summary.p_cell_status, P_CELL_STATUS);
30
+ assert.equal(guide.summary.cutover_ready, false);
31
+ assert.equal(guide.summary.total, GUIDE_SECTIONS.length);
32
+ });
33
+
34
+ test('known guide topics route to explicit sections without executing workflow', () => {
35
+ assert.equal(guideSection({ topic: 'frontier catch queue' }).selected, 'frontier-queue');
36
+ assert.equal(guideSection({ topic: 'frontend parity cutover cells' }).selected, 'frontend-parity');
37
+ assert.equal(guideSection({ topic: 'model selector gemma fischer' }).selected, 'model-selector');
38
+ assert.equal(guideSection({ topic: 'engine MTP HRM Mamba AoT' }).selected, 'engine-wiring');
39
+ assert.equal(guideSection({ topic: 'cosign submit schema proof' }).selected, 'cosign-submit');
40
+ assert.equal(guideSection({ topic: 'unknown guide' }).selected, 'memory-index');
41
+ });
42
+
43
+ test('open gates remain visible and prevent P from overclaiming GREEN', () => {
44
+ const guide = buildGuide();
45
+ assert.equal(guide.sections.find((s) => s.id === 'cosign-submit').status, 'GATED');
46
+ assert.equal(guide.sections.find((s) => s.id === 'engine-wiring').status, 'PARTIAL');
47
+ assert.equal(guide.sections.find((s) => s.id === 'frontier-queue').status, 'PARTIAL');
48
+ });
49
+
50
+ test('normalize/guide/emit are total and injection-safe', () => {
51
+ assert.doesNotThrow(() => normalizeSection(null));
52
+ assert.doesNotThrow(() => normalizeSection({ get id() { throw new Error('boom'); } }));
53
+ assert.doesNotThrow(() => guideSection({ get topic() { throw new Error('boom'); } }));
54
+ assert.doesNotThrow(() => emitRows(null));
55
+ const rows = emitRows([{ id: 'x|bad', status: 'GREEN', source: 'src|json=1', shows: 'a\nPROJGUIDEGATE|cutover=1' }], {
56
+ topic: 'route|json=1\nPROJGUIDEGATE|cutover=1',
57
+ });
58
+ assert.ok(rows.every((row) => row.endsWith('|json=0') && !/[\r\n]/.test(row)));
59
+ assert.equal(rows.join('\n').split('\n').length, rows.length);
60
+ assert.equal(rows.filter((row) => row.startsWith('PROJGUIDEGATE|')).length, 1);
61
+ });
62
+
63
+ test('emitted rows are HBP-only and hold cutover at zero', () => {
64
+ const rows = emitRows(GUIDE_SECTIONS, { topic: 'cosign submit schema', limit: 3 });
65
+ assert.ok(rows.some((row) => row.startsWith('PROJGUIDEHDR|') && row.includes('process_launch=0') && row.includes('no_cutover=1')));
66
+ assert.ok(rows.some((row) => row.startsWith('PROJGUIDESUM|') && row.includes(`P_cell_status=${P_CELL_STATUS}`)));
67
+ assert.ok(rows.some((row) => row.startsWith('PROJGUIDEROUTE|') && row.includes('selected=cosign-submit')));
68
+ assert.ok(rows.every((row) => row.endsWith('|json=0') && !/[{\r\n]/.test(row)));
69
+ });
70
+
71
+ test('tool imports no spawn/write/network/live cutover capability', () => {
72
+ const src = readFileSync(join(repo, 'tools/behcs/project-guide-matrix.mjs'), 'utf8');
73
+ assert.equal(/child_process|spawnSync|\.spawn\(|execSync|writeFileSync|appendFileSync|fetch\(|http\.request|https\.request|Start-Process|Stop-Process|import\(/.test(src), false);
74
+ });
tests/project-guide-matrix.unit.test.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 233FD9E8ED6C41559AAAF8346CE118EC29DFFA80E124591E3153476ACD2089EF project-guide-matrix.unit.test.mjs
tests/supervisor-collision-router.system.test.mjs CHANGED
@@ -102,6 +102,7 @@ const sealedFiles = [
102
  'docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp',
103
  'docs/ACER-ATTACK-LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp',
104
  'docs/LIRIS-MODEL-SELECTOR-MATRIX-2026-06-14.hbp',
 
105
  'docs/acer-ecosystem-fullbody-receipt-20260612.hbp',
106
  'docs/CLAIMSLEDGER-2026-06-12.hbp',
107
  'docs/CLAIMSGATE-PARITY-BASELINE-2026-06-12.hbp',
@@ -224,6 +225,7 @@ const sealedFiles = [
224
  'tools/behcs/route-health-baseline.mjs',
225
  'tools/behcs/frontend-parity-matrix.mjs',
226
  'tools/behcs/model-selector-matrix.mjs',
 
227
  'tools/behcs/logical-extreme-stress.mjs',
228
  'tools/behcs/logical-stress-cube-feed.mjs',
229
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
@@ -256,6 +258,7 @@ const sealedFiles = [
256
  'tests/route-health-baseline.unit.test.mjs',
257
  'tests/frontend-parity-matrix.unit.test.mjs',
258
  'tests/model-selector-matrix.unit.test.mjs',
 
259
  'tests/logical-extreme-stress.unit.test.mjs',
260
  'tests/logical-stress-cube-feed.unit.test.mjs',
261
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
 
102
  'docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp',
103
  'docs/ACER-ATTACK-LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp',
104
  'docs/LIRIS-MODEL-SELECTOR-MATRIX-2026-06-14.hbp',
105
+ 'docs/LIRIS-PROJECT-GUIDE-MATRIX-2026-06-14.hbp',
106
  'docs/acer-ecosystem-fullbody-receipt-20260612.hbp',
107
  'docs/CLAIMSLEDGER-2026-06-12.hbp',
108
  'docs/CLAIMSGATE-PARITY-BASELINE-2026-06-12.hbp',
 
225
  'tools/behcs/route-health-baseline.mjs',
226
  'tools/behcs/frontend-parity-matrix.mjs',
227
  'tools/behcs/model-selector-matrix.mjs',
228
+ 'tools/behcs/project-guide-matrix.mjs',
229
  'tools/behcs/logical-extreme-stress.mjs',
230
  'tools/behcs/logical-stress-cube-feed.mjs',
231
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
 
258
  'tests/route-health-baseline.unit.test.mjs',
259
  'tests/frontend-parity-matrix.unit.test.mjs',
260
  'tests/model-selector-matrix.unit.test.mjs',
261
+ 'tests/project-guide-matrix.unit.test.mjs',
262
  'tests/logical-extreme-stress.unit.test.mjs',
263
  'tests/logical-stress-cube-feed.unit.test.mjs',
264
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
tests/supervisor-collision-router.system.test.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- B3B7F5D8BF3D1C30C5271CFD3F87532185DF592EEFBEC4E5C70BD08971DFF3BE supervisor-collision-router.system.test.mjs
 
1
+ 8E6E02DF1CF1EC718BF1CD7578F347950EBC246DA41E817795FA49A2398A9571 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-14', vantage: 'liris', source: 'docs/LIRIS-FRONTEND-PARITY-MATRIX-2026-06-14.hbp+docs/LIRIS-MODEL-SELECTOR-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: 'frontend-parity-matrix+model-selector-M', summary: 'frontend-parity-matrix-now-exists-and-M-selector-is-PARTIAL; P-red-and-T/C/Q/E/D-partial-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' }),
 
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+docs/LIRIS-MODEL-SELECTOR-MATRIX-2026-06-14.hbp+docs/LIRIS-PROJECT-GUIDE-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: 'frontend-parity+model-selector-M+project-guide-P', summary: 'frontend-parity-matrix-now-has-M-and-P-descriptor-artifacts-PARTIAL; T/C/Q/E/D/M/P partial 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
- E179A74F85141CC4FCE143CB1A64567713F182EE95421E9051579AD1192F668F catch-count-ledger.mjs
 
1
+ 8CDB696CBD5B98CB0FCD92611F71C4562EF7FE9A579FD5ECE70A06FC8EEC1CCB 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=9|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
@@ -16,6 +16,7 @@ FABPRELOADTOOL|id=catch-count-ledger|path=tools/behcs/catch-count-ledger.mjs|pro
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=model-selector-matrix|path=tools/behcs/model-selector-matrix.mjs|provides=front-end-M-cell-visible-model-role-selector-no-live-invocation|gate=descriptor-only-process_launch-0-live-model-invocation-0|tag=PROVEN+tool-level|json=0
 
19
  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
20
  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
21
  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=10|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
 
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=model-selector-matrix|path=tools/behcs/model-selector-matrix.mjs|provides=front-end-M-cell-visible-model-role-selector-no-live-invocation|gate=descriptor-only-process_launch-0-live-model-invocation-0|tag=PROVEN+tool-level|json=0
19
+ FABPRELOADTOOL|id=project-guide-matrix|path=tools/behcs/project-guide-matrix.mjs|provides=front-end-P-cell-project-guide-to-sealed-artifacts-no-workflow-execution|gate=descriptor-only-process_launch-0-no-cutover|tag=PROVEN+tool-level|json=0
20
  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
21
  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
22
  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
- EA39618D0EB886A1C5241E5760728A59A139A099BAC226FD71E7BC05438B2814 fabric-agent-preload-catalog.hbp
 
1
+ 74DEE56FD84DB6C03ADB3DA409C026F87E166ABBF175E1534BCA2F5B9B5CEF59 fabric-agent-preload-catalog.hbp
tools/behcs/fabric-agent-preload-catalog.mjs CHANGED
@@ -116,6 +116,12 @@ export const TOOLS = Object.freeze([
116
  provides: 'front-end-M-cell-visible-model-role-selector-no-live-invocation',
117
  gate: 'descriptor-only-process_launch-0-live-model-invocation-0',
118
  }),
 
 
 
 
 
 
119
  Object.freeze({
120
  id: 'token-cube-catalog-binder',
121
  path: 'tools/behcs/token-cube-catalog-binder.mjs',
@@ -285,7 +291,7 @@ export function selfTest() {
285
  add('tools-include-room-and-pid', !!toolById('pixel-room-handle') && !!toolById('github-live-pid-reconcile')
286
  && !!toolById('github-live-office-reconcile-expansion') && !!toolById('catch-count-ledger')
287
  && !!toolById('mlc-engine-wiring-increment') && !!toolById('frontend-parity-matrix')
288
- && !!toolById('model-selector-matrix'));
289
  add('slice-engine-law-preloaded', LAWS.some((law) => law.startsWith('slice-engine-law-'))
290
  && emitPreloadRows().some((row) => row.startsWith('FABPRELOADSLICEENGINE|')));
291
  add('emitters-pipe-hookwall-gnn', EMITTERS.some((e) => e.id === 'hookwall') && EMITTERS.some((e) => e.id === 'gnn-edge'));
 
116
  provides: 'front-end-M-cell-visible-model-role-selector-no-live-invocation',
117
  gate: 'descriptor-only-process_launch-0-live-model-invocation-0',
118
  }),
119
+ Object.freeze({
120
+ id: 'project-guide-matrix',
121
+ path: 'tools/behcs/project-guide-matrix.mjs',
122
+ provides: 'front-end-P-cell-project-guide-to-sealed-artifacts-no-workflow-execution',
123
+ gate: 'descriptor-only-process_launch-0-no-cutover',
124
+ }),
125
  Object.freeze({
126
  id: 'token-cube-catalog-binder',
127
  path: 'tools/behcs/token-cube-catalog-binder.mjs',
 
291
  add('tools-include-room-and-pid', !!toolById('pixel-room-handle') && !!toolById('github-live-pid-reconcile')
292
  && !!toolById('github-live-office-reconcile-expansion') && !!toolById('catch-count-ledger')
293
  && !!toolById('mlc-engine-wiring-increment') && !!toolById('frontend-parity-matrix')
294
+ && !!toolById('model-selector-matrix') && !!toolById('project-guide-matrix'));
295
  add('slice-engine-law-preloaded', LAWS.some((law) => law.startsWith('slice-engine-law-'))
296
  && emitPreloadRows().some((row) => row.startsWith('FABPRELOADSLICEENGINE|')));
297
  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
- 93CC457012ADFDA1C5A3CDD632812BB7A812261141C03FAAC946B0C3EC55492D fabric-agent-preload-catalog.mjs
 
1
+ 13377B2CF1A25099437A4BA19EE286AE8A3B379EFBD7BCC0087901420D4411A8 fabric-agent-preload-catalog.mjs
tools/behcs/frontend-parity-matrix.mjs CHANGED
@@ -38,10 +38,10 @@ export const MATRIX_CELLS = Object.freeze([
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',
@@ -207,7 +207,7 @@ export function selfTest() {
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 === 'PARTIAL' && 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)));
 
38
  Object.freeze({
39
  id: 'P',
40
  name: 'project_guide',
41
+ status: 'PARTIAL',
42
+ source: 'tools/behcs/project-guide-matrix.mjs',
43
+ evidence: 'project-guide-P-artifact-now-points-front-end-sections-at-sealed-artifacts-but-workflow-binding-and-submit-schema-remain-gated',
44
+ required_next: 'bind-guide-into-front-end-view-and-build-cosign-submit-schema-proof-before-green',
45
  }),
46
  Object.freeze({
47
  id: 'C',
 
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 === 'PARTIAL' && matrix.cells.find((c) => c.id === 'T').status === 'PARTIAL' && matrix.cells.find((c) => c.id === 'P').status === 'PARTIAL');
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)));
tools/behcs/frontend-parity-matrix.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- 9C34637EFBF85515F902E46E04514EDE55AEA4340B0E2142F5D7BFDE3FE57D01 frontend-parity-matrix.mjs
 
1
+ A7EDD325E40E857E21D9DD4182F8BF38B31EDD05BAD2DC9C524306D78032DF56 frontend-parity-matrix.mjs
tools/behcs/project-guide-matrix.mjs ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ // project-guide-matrix.mjs - held-safe P-cell guide for root front-end parity.
3
+ //
4
+ // This is not a UI and not a workflow executor. It gives the front end a stable
5
+ // project-guide table: each guide section points to sealed repo artifacts and
6
+ // names the remaining gate. No spawn, no fetch, no write, no cutover.
7
+
8
+ import { createHash } from 'node:crypto';
9
+ import { resolve } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+
12
+ export const GUIDE_ID = 'project-guide-matrix.v1';
13
+ export const FRONTEND_CELL = 'P';
14
+ export const P_CELL_STATUS = 'PARTIAL_GUIDE_ARTIFACT_BUILT_WORKFLOW_BINDING_GATED';
15
+ export const STATUSES = Object.freeze(['GREEN', 'PARTIAL', 'GATED', 'RED']);
16
+
17
+ export const GUIDE_SECTIONS = Object.freeze([
18
+ Object.freeze({
19
+ id: 'law-spine',
20
+ status: 'GREEN',
21
+ source: 'canon/laws/LAW-SLICE-ENGINE.md+docs/ACER-SLICE-ENGINE-COSIGN-MINT-2026-06-14.hbp',
22
+ shows: 'canonical-law+class1-cosign-seal+authorization-vs-action-boundary',
23
+ next: 'display-as-gate-context-not-action-button',
24
+ }),
25
+ Object.freeze({
26
+ id: 'frontier-queue',
27
+ status: 'PARTIAL',
28
+ source: 'docs/TARGET-ARCHITECTURE-200-STEP-DELTA-2026-06-11.hbp+tools/behcs/catch-count-ledger.mjs',
29
+ shows: 'self-extending-frontier-queue+open-partial-catch-state',
30
+ next: 'continue-ask-fabric-loop-until-open-gates-close',
31
+ }),
32
+ Object.freeze({
33
+ id: 'frontend-parity',
34
+ status: 'PARTIAL',
35
+ source: 'tools/behcs/frontend-parity-matrix.mjs',
36
+ shows: 'M-T-P-C-Q-R-E-A-D-G-cell-state-before-cutover',
37
+ next: 'all-cells-green-plus-operator-cosign-before-any-cutover',
38
+ }),
39
+ Object.freeze({
40
+ id: 'model-selector',
41
+ status: 'PARTIAL',
42
+ source: 'tools/behcs/model-selector-matrix.mjs',
43
+ shows: 'model-role-routing-with-live-invocation-held-at-zero',
44
+ next: 'runtime-proof-and-live-model-contract-before-green',
45
+ }),
46
+ Object.freeze({
47
+ id: 'engine-wiring',
48
+ status: 'PARTIAL',
49
+ source: 'tools/behcs/mlc-engine-wiring-increment.mjs',
50
+ shows: 'C036-descriptor-wiring-MTP-HRM-GNN-Fischer-Mamba-AoT',
51
+ next: 'fabric-ranked-daemon-contract-before-process-launch',
52
+ }),
53
+ Object.freeze({
54
+ id: 'route-health',
55
+ status: 'GREEN',
56
+ source: 'tools/behcs/route-health-baseline.mjs+docs/ACER-BUS-HEALTH-CONTRACT-FIX-2026-06-13.hbp',
57
+ shows: 'route-boundary-vs-down-and-canonical-4947-behcs-health-contract',
58
+ next: 'keep-vantage-relative-labels-visible',
59
+ }),
60
+ Object.freeze({
61
+ id: 'cosign-submit',
62
+ status: 'GATED',
63
+ source: 'docs/ACER-SLICE-ENGINE-COSIGN-MINT-2026-06-14.hbp',
64
+ shows: 'single-writer-cosign-submit-route-known-from-seal-receipt-but-schema-proof-not-yet-front-end-artifact',
65
+ next: 'build-cosign-submit-schema-proof-before-exposing-submit-form',
66
+ }),
67
+ Object.freeze({
68
+ id: 'memory-index',
69
+ status: 'GREEN',
70
+ source: 'docs/CLAIMSLEDGER-2026-06-12.hbp+docs/ASOLARIA-AS-NEURAL-NETWORK.hbp',
71
+ shows: 'receipted-claims-and-memory-index-discipline',
72
+ next: 'show-only-tagged-receipted-claims',
73
+ }),
74
+ ]);
75
+
76
+ const sha16 = (text) => createHash('sha256').update(String(text), 'utf8').digest('hex').slice(0, 16);
77
+ const isObj = (x) => x !== null && typeof x === 'object';
78
+ const safe = (x) => { try { return String(x == null ? '' : x).replace(/[|\r\n]/g, '_'); } catch { return '_'; } };
79
+ const prop = (obj, key, fallback = '') => {
80
+ try { return isObj(obj) ? obj[key] : fallback; } catch { return fallback; }
81
+ };
82
+
83
+ function normalizeStatus(value) {
84
+ const status = safe(value).toUpperCase();
85
+ return STATUSES.includes(status) ? status : 'RED';
86
+ }
87
+
88
+ export function normalizeSection(input) {
89
+ try {
90
+ const id = safe(prop(input, 'id', 'unknown')) || 'unknown';
91
+ const source = safe(prop(input, 'source', 'CANNOT_SEE')) || 'CANNOT_SEE';
92
+ const status = normalizeStatus(prop(input, 'status', 'RED'));
93
+ const shows = safe(prop(input, 'shows', 'define-visible-guide'));
94
+ return {
95
+ id,
96
+ status,
97
+ source,
98
+ shows,
99
+ next: safe(prop(input, 'next', 'define-next-proof')),
100
+ process_launch: 0,
101
+ cutover: 0,
102
+ row_sha16: sha16([id, status, source, shows].join('|')),
103
+ };
104
+ } catch {
105
+ return {
106
+ id: 'invalid',
107
+ status: 'RED',
108
+ source: 'CANNOT_SEE',
109
+ shows: 'normalize-threw',
110
+ next: 'fix-invalid-guide-row',
111
+ process_launch: 0,
112
+ cutover: 0,
113
+ row_sha16: sha16('invalid'),
114
+ };
115
+ }
116
+ }
117
+
118
+ export function guideSection(input = {}) {
119
+ try {
120
+ const topic = safe(prop(input, 'topic', input)).toLowerCase();
121
+ const sections = GUIDE_SECTIONS.map(normalizeSection);
122
+ const pick = (id, reason) => ({ topic: safe(topic || 'default'), selected: id, reason, section: sections.find((s) => s.id === id) });
123
+ if (/submit|schema|chain/.test(topic)) return pick('cosign-submit', 'cosign-submit-remains-schema-gated');
124
+ if (/law|gate|cosign|authorization/.test(topic)) return pick('law-spine', 'law-and-gate-context');
125
+ if (/queue|frontier|catch|open|partial/.test(topic)) return pick('frontier-queue', 'frontier-and-catch-state');
126
+ if (/front|parity|cutover|cell/.test(topic)) return pick('frontend-parity', 'frontend-cell-state');
127
+ if (/model|selector|gemma|fischer/.test(topic)) return pick('model-selector', 'model-role-routing');
128
+ if (/engine|mlc|mtp|hrm|mamba|aot/.test(topic)) return pick('engine-wiring', 'engine-wiring-descriptor');
129
+ if (/route|health|api|dashboard/.test(topic)) return pick('route-health', 'route-health-guide');
130
+ return pick('memory-index', 'default-to-receipted-memory-index');
131
+ } catch {
132
+ return { topic: 'invalid', selected: 'memory-index', reason: 'guide-threw-default-held', section: normalizeSection(GUIDE_SECTIONS[7]) };
133
+ }
134
+ }
135
+
136
+ export function buildGuide(input = GUIDE_SECTIONS) {
137
+ const sections = (Array.isArray(input) ? input : GUIDE_SECTIONS).map(normalizeSection);
138
+ const count = (status) => sections.filter((section) => section.status === status).length;
139
+ return {
140
+ tool: GUIDE_ID,
141
+ frontend_cell: FRONTEND_CELL,
142
+ sections,
143
+ summary: {
144
+ total: sections.length,
145
+ green: count('GREEN'),
146
+ partial: count('PARTIAL'),
147
+ gated: count('GATED'),
148
+ red: count('RED'),
149
+ p_cell_status: P_CELL_STATUS,
150
+ cutover_ready: false,
151
+ },
152
+ };
153
+ }
154
+
155
+ export function emitRows(input = GUIDE_SECTIONS, opts = {}) {
156
+ try {
157
+ const built = buildGuide(input);
158
+ const s = built.summary;
159
+ const limitRaw = Number.parseInt(safe(prop(opts, 'limit', built.sections.length)), 10);
160
+ const limit = Math.max(0, Math.min(Number.isFinite(limitRaw) ? limitRaw : built.sections.length, built.sections.length));
161
+ const rows = [
162
+ `PROJGUIDEHDR|tool=${GUIDE_ID}|frontend_cell=P|purpose=project-guide-before-any-front-end-cutover|sections=${s.total}|read_only=1|process_launch=0|no_fetch=1|no_write=1|no_spawn=1|no_cutover=1|json=0`,
163
+ `PROJGUIDESUM|green=${s.green}|partial=${s.partial}|gated=${s.gated}|red=${s.red}|P_cell_status=${s.p_cell_status}|cutover_ready=0|json=0`,
164
+ ];
165
+ for (const section of built.sections.slice(0, limit)) {
166
+ rows.push(`PROJGUIDE|id=${safe(section.id)}|status=${safe(section.status)}|source=${safe(section.source)}|shows=${safe(section.shows)}|next=${safe(section.next)}|row_sha16=${safe(section.row_sha16)}|process_launch=0|cutover=0|json=0`);
167
+ }
168
+ const topic = prop(opts, 'topic', '');
169
+ if (topic) {
170
+ const selected = guideSection({ topic });
171
+ rows.push(`PROJGUIDEROUTE|topic=${safe(selected.topic)}|selected=${safe(selected.selected)}|reason=${safe(selected.reason)}|selected_status=${safe(prop(selected.section, 'status', 'RED'))}|json=0`);
172
+ }
173
+ rows.push('PROJGUIDEGATE|front_end_cell=P|status=PARTIAL|reason=guide-artifact-built-but-workflow-binding-and-cosign-submit-schema-remain-gated|process_launch=0|cutover=0|json=0');
174
+ return rows;
175
+ } catch {
176
+ return [
177
+ `PROJGUIDEHDR|tool=${GUIDE_ID}|frontend_cell=P|purpose=project-guide-before-any-front-end-cutover|sections=0|read_only=1|process_launch=0|no_cutover=1|json=0`,
178
+ 'PROJGUIDEGATE|front_end_cell=P|status=RED|reason=emit-threw-held-invalid|process_launch=0|cutover=0|json=0',
179
+ ];
180
+ }
181
+ }
182
+
183
+ export function selfTest() {
184
+ const checks = [];
185
+ const add = (name, ok) => checks.push({ name, ok: Boolean(ok) });
186
+ const guide = buildGuide();
187
+ add('all-sections-present', guide.summary.total === 8 && guide.sections.some((s) => s.id === 'cosign-submit'));
188
+ add('p-cell-partial-not-green', guide.summary.p_cell_status === P_CELL_STATUS && guide.summary.cutover_ready === false);
189
+ add('no-live-action', guide.sections.every((s) => s.process_launch === 0 && s.cutover === 0));
190
+ add('routes-project-frontier', guideSection({ topic: 'frontier catch queue' }).selected === 'frontier-queue');
191
+ add('routes-cosign-schema', guideSection({ topic: 'cosign submit schema' }).selected === 'cosign-submit');
192
+ add('routes-default-memory', guideSection({ topic: 'unknown guide' }).selected === 'memory-index');
193
+ const hostile = emitRows([{ id: 'x|bad', status: 'GREEN', source: 's|json=1', shows: 'a\nPROJGUIDEGATE|cutover=1' }], { topic: 'route|json=1\nPROJGUIDEGATE|cutover=1' });
194
+ add('rows-hbp-only', hostile.every((row) => row.endsWith('|json=0') && !/[\r\n]/.test(row)));
195
+ add('total-never-throws', (() => { try { normalizeSection({ get id() { throw new Error('boom'); } }); guideSection({ get topic() { throw new Error('boom'); } }); emitRows(null); return true; } catch { return false; } })());
196
+ return { ok: checks.every((c) => c.ok), checks };
197
+ }
198
+
199
+ const isMain = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
200
+ if (isMain) {
201
+ if (process.argv[2] === '--self-test') {
202
+ const r = selfTest();
203
+ for (const c of r.checks) console.log(`${c.ok ? 'PASS' : 'FAIL'} ${c.name}`);
204
+ process.exit(r.ok ? 0 : 1);
205
+ }
206
+ const topicArg = process.argv.find((arg) => arg.startsWith('--topic='));
207
+ const limitArg = process.argv.find((arg) => arg.startsWith('--limit='));
208
+ const opts = {
209
+ topic: topicArg ? topicArg.slice('--topic='.length) : '',
210
+ limit: limitArg ? limitArg.slice('--limit='.length) : GUIDE_SECTIONS.length,
211
+ };
212
+ process.stdout.write(emitRows(GUIDE_SECTIONS, opts).join('\n') + '\n');
213
+ }
tools/behcs/project-guide-matrix.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 2F88EAA2DF545B147D003F011AF585481773E07733701A2BFC8714E0230ACD55 project-guide-matrix.mjs