Jessedbrown Claude Opus 4.8 (1M context) commited on
Commit
e352bcb
·
1 Parent(s): f8bf0f2

acer: heal-envelope-emitter — held-safe producer for the heal-pipeline-v1 self-heal

Browse files

The fabric's self-heal is the 10-step heal-pipeline (point->...->onboarding-update);
nothing produced a valid envelope. This emits schema-valid proposals ONLY — proposal_only,
process_launch=0, no heal/mint/spawn/write/network. The heal advances only when the
registrar/cosign/feeder daemons crank under operator gate (SLICE-ENGINE-LAW).

HARDENED by adversarial verification before push (acer builds, the gate attacks):
- wf_f227d321 (3-lens) found 12 real defects incl 2 HIGH HBP row-injection (numeric/array
fields interpolated without safe() could forge the load-bearing HEALENVGATE row).
- re-attack a3de3ec0 refuted the TOTAL claim (threw on throwing-getters/BigInt/circular).
All 13 fixed + encoded as permanent regressions: every field safe()'d, validate/heal/emit
are total (never throw), strict validation (NaN/Infinity, non-ISO ts, non-int step/rank/voted,
delimiter-bearing cosigners rejected), full-body envelope_sha16. self-test 19/19, unit 15/15,
suite 245/245, lattice green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

tests/heal-envelope-emitter.unit.test.mjs ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ COSIGNERS,
9
+ HEAL_STEPS,
10
+ VERDICTS,
11
+ emitRows,
12
+ healEnvelope,
13
+ selfTest,
14
+ validateEnvelope,
15
+ } from '../tools/behcs/heal-envelope-emitter.mjs';
16
+
17
+ const repo = dirname(dirname(fileURLToPath(import.meta.url)));
18
+ const VALID = {
19
+ step: 3,
20
+ target_pid: 'ACER-PID-H3CB8-A00-W1024-P00-N01630',
21
+ operator_witness: 'OP-JESSE-PID-G0000-A00-W000-P00-N00000',
22
+ ts: '2026-06-13T21:30:00.000Z',
23
+ };
24
+
25
+ test('self-test passes', () => {
26
+ assert.equal(selfTest().ok, true);
27
+ });
28
+
29
+ test('the 10 heal-pipeline-v1 steps and verdict enum are exact', () => {
30
+ assert.deepEqual(HEAL_STEPS, ['point', 'read', 'council-vote', 'gnn-rank', 'lazy-mint', 'auth', 'cell-cascade', 'bilateral-cosign', 'usb-sync', 'onboarding-update']);
31
+ assert.deepEqual(VERDICTS, ['MISSING', 'DRIFTED', 'OUTDATED', 'FRESH', 'NO-CHANGE']);
32
+ });
33
+
34
+ test('a complete envelope validates and is proposal-only / never heals', () => {
35
+ const env = healEnvelope({ ...VALID, council_verdict: { voted: 158, abstain: 93, verdict: 'DRIFTED' }, gnn_rank: { score: 0.42, rank: 1, mode: 'ranking' }, cosigners: COSIGNERS.slice() });
36
+ assert.equal(env.valid, true);
37
+ assert.equal(env.proposal_only, true);
38
+ assert.equal(env.process_launch, 0);
39
+ assert.equal(env.heal_action_performed, 0);
40
+ assert.equal(env.step_name, 'council-vote');
41
+ });
42
+
43
+ test('the minimal required envelope validates', () => {
44
+ assert.equal(validateEnvelope(VALID).ok, true);
45
+ });
46
+
47
+ test('schema violations are rejected (step, pid, witness, verdict, gnn, cosigners)', () => {
48
+ assert.equal(validateEnvelope({ ...VALID, step: 0 }).ok, false);
49
+ assert.equal(validateEnvelope({ ...VALID, step: 11 }).ok, false);
50
+ assert.equal(validateEnvelope({ ...VALID, target_pid: 'LIRIS-PID-xyz' }).ok, false);
51
+ assert.equal(validateEnvelope({ ...VALID, operator_witness: 'OP-MALLORY-PID-G0000-A00-W000-P00-N00000' }).ok, false);
52
+ assert.equal(validateEnvelope({ ...VALID, council_verdict: { verdict: 'MAYBE' } }).ok, false);
53
+ assert.equal(validateEnvelope({ ...VALID, gnn_rank: { mode: 'classify' } }).ok, false);
54
+ });
55
+
56
+ // --- adversarial regressions proven by wf_f227d321 (do NOT weaken) ---
57
+
58
+ test('NaN/Infinity gnn score is rejected (not silently accepted)', () => {
59
+ assert.equal(validateEnvelope({ ...VALID, gnn_rank: { score: NaN, mode: 'ranking' } }).ok, false);
60
+ assert.equal(validateEnvelope({ ...VALID, gnn_rank: { score: Infinity, mode: 'ranking' } }).ok, false);
61
+ assert.equal(validateEnvelope({ ...VALID, gnn_rank: { score: 0.5, mode: 'ranking' } }).ok, true);
62
+ });
63
+
64
+ test('non-integer voted/abstain/rank are rejected', () => {
65
+ assert.equal(validateEnvelope({ ...VALID, council_verdict: { voted: 'x', verdict: 'FRESH' } }).ok, false);
66
+ assert.equal(validateEnvelope({ ...VALID, gnn_rank: { rank: 1.5, mode: 'ranking' } }).ok, false);
67
+ assert.equal(validateEnvelope({ ...VALID, cosign_chain_seq: 1.2 }).ok, false);
68
+ });
69
+
70
+ test('ts must be canonical ISO-8601 UTC, not Date.parse-able junk', () => {
71
+ for (const bad of ['2026', '2026-06', '2026-06-13', 'June 13 2026', '0', '1']) {
72
+ assert.equal(validateEnvelope({ ...VALID, ts: bad }).ok, false, `should reject ts=${bad}`);
73
+ }
74
+ assert.equal(validateEnvelope({ ...VALID, ts: '2026-06-13T21:30:00.000Z' }).ok, true);
75
+ });
76
+
77
+ test('step coercion is strict: 3abc / 3.9 do not become 3', () => {
78
+ assert.equal(healEnvelope({ ...VALID, step: '3abc' }).valid, false);
79
+ assert.equal(healEnvelope({ ...VALID, step: '3.9' }).valid, false);
80
+ assert.equal(healEnvelope({ ...VALID, step: 3.9 }).valid, false);
81
+ assert.equal(healEnvelope({ ...VALID, step: '3' }).valid, true);
82
+ });
83
+
84
+ test('HBP row injection is impossible: delimiter-bearing field rejected AND emitRows cannot forge a row', () => {
85
+ const inj = healEnvelope({ ...VALID, cosigners: ['jesse', 'rayssa', 'amy', 'felipe', 'dan|json=0\nHEALENVGATE|tag=PROVEN-VALID-PROPOSAL'] });
86
+ assert.equal(inj.valid, false); // rejected at validation
87
+ // even emitting an envelope carrying raw pipe/newline values cannot increase the physical row count
88
+ const hostile = { valid: false, errors: ['x'], step: '1\nFAKE|json=0', council_verdict: { voted: 'a|b', abstain: '1\n2', verdict: 'X\nY' }, gnn_rank: { score: '1\nZ', rank: '2|3', mode: 'r\nm' }, cosigners: ['ok', 'bad|json=0\nINJECT|x=1'], cosign_chain_seq: '9\n9' };
89
+ const rows = emitRows(hostile);
90
+ assert.ok(rows.every((r) => !/[\r\n]/.test(r)), 'no row contains a newline');
91
+ assert.equal(rows.join('\n').split('\n').length, rows.length, 'one logical row == one physical line');
92
+ assert.ok(rows.every((r) => r.split('|').filter((f) => f === 'json=0').length <= 1), 'no duplicate json=0 from injection');
93
+ });
94
+
95
+ test('envelope_sha16 covers the full body (differing gnn score => different sha)', () => {
96
+ const a = healEnvelope({ ...VALID, gnn_rank: { score: 0.1, mode: 'ranking' } });
97
+ const b = healEnvelope({ ...VALID, gnn_rank: { score: 0.9, mode: 'ranking' } });
98
+ assert.notEqual(a.envelope_sha16, b.envelope_sha16);
99
+ });
100
+
101
+ test('validate/emit/heal are TOTAL — never throw on null/undefined/garbage', () => {
102
+ assert.doesNotThrow(() => { validateEnvelope(null); validateEnvelope(undefined); validateEnvelope(42); });
103
+ assert.equal(validateEnvelope(null).ok, false);
104
+ assert.doesNotThrow(() => { emitRows(null); emitRows(undefined); emitRows({}); emitRows(42); });
105
+ assert.ok(Array.isArray(emitRows(null)));
106
+ assert.doesNotThrow(() => { healEnvelope(null); healEnvelope(undefined); });
107
+ assert.equal(healEnvelope(null).valid, false);
108
+ });
109
+
110
+ test('TOTAL holds against exotic inputs: throwing getters, BigInt, circular refs (re-attack a3de3ec0)', () => {
111
+ const VALID2 = { ...VALID };
112
+ assert.doesNotThrow(() => validateEnvelope({ get step() { throw new Error('boom'); } }));
113
+ assert.equal(validateEnvelope({ get step() { throw new Error('boom'); } }).ok, false);
114
+ assert.doesNotThrow(() => emitRows({ valid: true, get council_verdict() { throw new Error('boom'); } }));
115
+ assert.doesNotThrow(() => emitRows({ valid: true, cosigners: [{ toString() { throw new Error('boom'); } }] }));
116
+ // BigInt body field: no throw, and correctly invalid
117
+ assert.doesNotThrow(() => healEnvelope({ ...VALID2, cosign_chain_seq: 10n }));
118
+ assert.equal(healEnvelope({ ...VALID2, cosign_chain_seq: 10n }).valid, false);
119
+ // circular body field: no throw, sha still computed (cycle handled in canonicalBody)
120
+ const c = {}; c.self = c;
121
+ assert.doesNotThrow(() => healEnvelope({ ...VALID2, council_verdict: c }));
122
+ assert.equal(typeof healEnvelope({ ...VALID2, council_verdict: c }).envelope_sha16, 'string');
123
+ });
124
+
125
+ test('emitted rows are HBP-only, single-line, with the held-safe gate row', () => {
126
+ const rows = emitRows(healEnvelope({ ...VALID, cosigners: COSIGNERS.slice() }));
127
+ assert.ok(rows.every((r) => r.endsWith('|json=0') && !r.includes('{"') && !/[\r\n]/.test(r)));
128
+ assert.ok(rows.some((r) => r.startsWith('HEALENVGATE|') && r.includes('this-tool-emits-proposal-never-heals')));
129
+ assert.ok(rows[0].includes('process_launch=0') && rows[0].includes('heal_action_performed=0'));
130
+ });
131
+
132
+ test('emitter has no spawn/exec/write/network/mint capability', () => {
133
+ const src = readFileSync(join(repo, 'tools/behcs/heal-envelope-emitter.mjs'), 'utf8');
134
+ assert.equal(/child_process|spawnSync|\.spawn\(|execSync|writeFileSync|appendFileSync|fetch\(|http\.request|mintPid/.test(src), false);
135
+ });
tests/heal-envelope-emitter.unit.test.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 2F637CBCE228BCF12DCA6FC9A916D232720E2F1A2C6966DE8A65A24B8A87135D heal-envelope-emitter.unit.test.mjs
tests/supervisor-collision-router.system.test.mjs CHANGED
@@ -207,6 +207,7 @@ const sealedFiles = [
207
  'tools/behcs/triad-nest-reference.mjs',
208
  'tools/behcs/mlc-line-watcher.mjs',
209
  'tools/behcs/omni-engine-loop.mjs',
 
210
  'tools/behcs/logical-extreme-stress.mjs',
211
  'tools/behcs/logical-stress-cube-feed.mjs',
212
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
@@ -232,6 +233,7 @@ const sealedFiles = [
232
  'tests/triad-nest-reference.unit.test.mjs',
233
  'tests/mlc-line-watcher.unit.test.mjs',
234
  'tests/omni-engine-loop.unit.test.mjs',
 
235
  'tests/logical-extreme-stress.unit.test.mjs',
236
  'tests/logical-stress-cube-feed.unit.test.mjs',
237
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
 
207
  'tools/behcs/triad-nest-reference.mjs',
208
  'tools/behcs/mlc-line-watcher.mjs',
209
  'tools/behcs/omni-engine-loop.mjs',
210
+ 'tools/behcs/heal-envelope-emitter.mjs',
211
  'tools/behcs/logical-extreme-stress.mjs',
212
  'tools/behcs/logical-stress-cube-feed.mjs',
213
  'tools/behcs/brown-hilbert-expansion-stress.mjs',
 
233
  'tests/triad-nest-reference.unit.test.mjs',
234
  'tests/mlc-line-watcher.unit.test.mjs',
235
  'tests/omni-engine-loop.unit.test.mjs',
236
+ 'tests/heal-envelope-emitter.unit.test.mjs',
237
  'tests/logical-extreme-stress.unit.test.mjs',
238
  'tests/logical-stress-cube-feed.unit.test.mjs',
239
  'tests/brown-hilbert-expansion-stress.unit.test.mjs',
tests/supervisor-collision-router.system.test.mjs.sha256 CHANGED
@@ -1 +1 @@
1
- 0B34F776438FC4567575ED5E79EC9EAEB3DE67F83C7E61209673CAF7242ED590 supervisor-collision-router.system.test.mjs
 
1
+ A4E6ACAC4E1705770C3C685D97B6ACE41731322418AA4811F68F670360E5B45C supervisor-collision-router.system.test.mjs
tools/behcs/heal-envelope-emitter.mjs ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ // heal-envelope-emitter.mjs — held-safe producer of schema-valid SELF-HEAL envelopes.
3
+ //
4
+ // The fabric's self-heal is the 10-step heal-pipeline (live schema behcs-256/heal-pipeline-v1
5
+ // at :4949/api/heal-pipeline-schema): point -> read -> council-vote -> gnn-rank -> lazy-mint ->
6
+ // auth -> cell-cascade -> bilateral-cosign -> usb-sync -> onboarding-update. Until now nothing
7
+ // PRODUCED a valid heal envelope. This emitter does — and ONLY that. It is the frozen-slice half
8
+ // of SLICE-ENGINE-LAW: it renders a proposal envelope; the heal only ADVANCES when the engine
9
+ // (registrar/cosign/feeder daemons) cranks it under operator gate.
10
+ //
11
+ // SAFETY: read-only, HBP-rows-only, no spawn/exec/write/network/mint, process_launch=0. It does
12
+ // NOT perform any heal step, lazy-mint a successor PID, cosign, usb-sync, or update onboarding.
13
+ // HARDENED (adversarial-verify wf_f227d321 + re-attack a3de3ec0, 2026-06-13): every interpolated
14
+ // field is run through safe() so no value can inject an HBP row; validate/heal/emit are TOTAL —
15
+ // they NEVER throw for ANY input (null, BigInt, circular refs, throwing getters), returning the
16
+ // invalid/safe result instead; validation is strict (NaN/Infinity, non-ISO ts, non-integer
17
+ // step/rank/voted, delimiter-bearing cosigners all rejected); envelope_sha16 covers the FULL
18
+ // canonical body so tamper is detectable.
19
+
20
+ import { createHash } from 'node:crypto';
21
+ import { resolve } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+
24
+ export const EMITTER_ID = 'heal-envelope-emitter.v1';
25
+ export const SCHEMA_ID = 'behcs-256/heal-pipeline-v1';
26
+
27
+ // 1=point .. 10=onboarding-update (exact order from the live heal-pipeline-v1 schema).
28
+ export const HEAL_STEPS = Object.freeze([
29
+ 'point', 'read', 'council-vote', 'gnn-rank', 'lazy-mint',
30
+ 'auth', 'cell-cascade', 'bilateral-cosign', 'usb-sync', 'onboarding-update',
31
+ ]);
32
+ export const VERDICTS = Object.freeze(['MISSING', 'DRIFTED', 'OUTDATED', 'FRESH', 'NO-CHANGE']);
33
+ export const COSIGNERS = Object.freeze(['jesse', 'rayssa', 'amy', 'felipe', 'dan']);
34
+ export const TARGET_PID_RE = /^ACER-PID-H[0-9A-F]{4,16}-A[0-9]{2}-W[0-9]+-P[0-9]{2}-N[0-9]{5}$/;
35
+ export const OPERATOR_WITNESS_RE = /^OP-(JESSE|RAYSSA|AMY|FELIPE|DAN)-PID-G0000-A00-W000-P00-N00000$/;
36
+ const ISO_UTC_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
37
+
38
+ const sha16 = (t) => createHash('sha256').update(String(t), 'utf8').digest('hex').slice(0, 16);
39
+ // safe(): strip every HBP delimiter from ANY value. Coerces non-strings; a throwing toString yields '_'.
40
+ const safe = (s) => { try { return String(s == null ? '' : s).replace(/[|\r\n]/g, '_'); } catch { return '_'; } };
41
+ const hasDelim = (s) => { try { return /[|\r\n]/.test(String(s)); } catch { return true; } };
42
+ const isObj = (x) => x !== null && typeof x === 'object';
43
+
44
+ function strictStep(raw) {
45
+ if (typeof raw === 'number') return Number.isInteger(raw) ? raw : NaN;
46
+ if (typeof raw === 'string' && /^\d+$/.test(raw)) return Number(raw);
47
+ return NaN;
48
+ }
49
+
50
+ function isCanonicalIso(ts) {
51
+ if (typeof ts !== 'string' || !ISO_UTC_RE.test(ts)) return false;
52
+ const t = Date.parse(ts);
53
+ if (Number.isNaN(t)) return false;
54
+ return new Date(t).toISOString() === ts; // round-trip rejects non-canonical
55
+ }
56
+
57
+ // canonical body serialization — BigInt-safe + cycle-safe + never throws. Covers the WHOLE proposal.
58
+ function canonicalBody(env) {
59
+ try {
60
+ const seen = new WeakSet();
61
+ return JSON.stringify({
62
+ step: env.step ?? null,
63
+ target_pid: env.target_pid ?? null,
64
+ operator_witness: env.operator_witness ?? null,
65
+ ts: env.ts ?? null,
66
+ predecessor_pid: env.predecessor_pid ?? null,
67
+ successor_pid: env.successor_pid ?? null,
68
+ council_verdict: env.council_verdict ?? null,
69
+ gnn_rank: env.gnn_rank ?? null,
70
+ cosigners: env.cosigners ?? null,
71
+ cosign_chain_seq: env.cosign_chain_seq ?? null,
72
+ }, (k, v) => {
73
+ if (typeof v === 'bigint') return `bigint:${v}`;
74
+ if (isObj(v)) { if (seen.has(v)) return '[circular]'; seen.add(v); }
75
+ return v;
76
+ });
77
+ } catch {
78
+ return 'UNCANONICALIZABLE';
79
+ }
80
+ }
81
+
82
+ function _validateEnvelope(input) {
83
+ const env = isObj(input) ? input : {};
84
+ const errors = [];
85
+ if (!Number.isInteger(env.step) || env.step < 1 || env.step > 10) errors.push('step-must-be-integer-1-to-10');
86
+ if (typeof env.target_pid !== 'string' || !TARGET_PID_RE.test(env.target_pid)) errors.push('target_pid-must-match-ACER-PID-pattern');
87
+ if (typeof env.operator_witness !== 'string' || !OPERATOR_WITNESS_RE.test(env.operator_witness)) errors.push('operator_witness-must-be-OP-pid');
88
+ if (!isCanonicalIso(env.ts)) errors.push('ts-must-be-canonical-iso-8601-utc');
89
+ if (env.predecessor_pid !== undefined && (typeof env.predecessor_pid !== 'string' || hasDelim(env.predecessor_pid))) errors.push('predecessor_pid-must-be-clean-string');
90
+ if (env.successor_pid !== undefined && (typeof env.successor_pid !== 'string' || hasDelim(env.successor_pid))) errors.push('successor_pid-must-be-clean-string');
91
+ if (env.council_verdict !== undefined) {
92
+ const v = env.council_verdict;
93
+ if (!isObj(v)) errors.push('council_verdict-must-be-object');
94
+ else {
95
+ if (v.verdict !== undefined && !VERDICTS.includes(v.verdict)) errors.push('council_verdict.verdict-must-be-enum');
96
+ if (v.voted !== undefined && !Number.isInteger(v.voted)) errors.push('council_verdict.voted-must-be-int');
97
+ if (v.abstain !== undefined && !Number.isInteger(v.abstain)) errors.push('council_verdict.abstain-must-be-int');
98
+ }
99
+ }
100
+ if (env.gnn_rank !== undefined) {
101
+ const g = env.gnn_rank;
102
+ if (!isObj(g)) errors.push('gnn_rank-must-be-object');
103
+ else {
104
+ if (g.score !== undefined && (typeof g.score !== 'number' || !Number.isFinite(g.score) || g.score < 0 || g.score > 1)) errors.push('gnn_rank.score-must-be-finite-0-to-1');
105
+ if (g.rank !== undefined && !Number.isInteger(g.rank)) errors.push('gnn_rank.rank-must-be-int');
106
+ if (g.mode !== undefined && g.mode !== 'ranking') errors.push('gnn_rank.mode-must-be-ranking');
107
+ }
108
+ }
109
+ if (env.cosigners !== undefined) {
110
+ if (!Array.isArray(env.cosigners) || env.cosigners.length < 5) errors.push('cosigners-must-be-array-min-5');
111
+ else if (!env.cosigners.every((c) => typeof c === 'string' && c.length > 0 && !hasDelim(c))) errors.push('cosigners-must-be-clean-non-empty-strings');
112
+ }
113
+ if (env.cosign_chain_seq !== undefined && !Number.isInteger(env.cosign_chain_seq)) errors.push('cosign_chain_seq-must-be-int');
114
+ return { ok: errors.length === 0, errors };
115
+ }
116
+
117
+ // TOTAL wrapper: never throws (throwing getters / exotic inputs -> invalid result).
118
+ export function validateEnvelope(input) {
119
+ try { return _validateEnvelope(input); }
120
+ catch { return { ok: false, errors: ['validation-threw-on-hostile-input'] }; }
121
+ }
122
+
123
+ function _healEnvelope(input) {
124
+ const opts = isObj(input) ? input : {};
125
+ const step = strictStep(opts.step);
126
+ const env = {
127
+ schema: SCHEMA_ID,
128
+ emitter: EMITTER_ID,
129
+ step,
130
+ step_name: (Number.isInteger(step) && step >= 1 && step <= 10) ? HEAL_STEPS[step - 1] : 'INVALID',
131
+ target_pid: opts.target_pid,
132
+ operator_witness: opts.operator_witness,
133
+ ts: opts.ts,
134
+ proposal_only: true,
135
+ process_launch: 0,
136
+ heal_action_performed: 0,
137
+ };
138
+ if (opts.predecessor_pid !== undefined) env.predecessor_pid = opts.predecessor_pid;
139
+ if (opts.successor_pid !== undefined) env.successor_pid = opts.successor_pid;
140
+ if (opts.council_verdict !== undefined) env.council_verdict = opts.council_verdict;
141
+ if (opts.gnn_rank !== undefined) env.gnn_rank = opts.gnn_rank;
142
+ if (opts.cosigners !== undefined) env.cosigners = opts.cosigners;
143
+ if (opts.cosign_chain_seq !== undefined) env.cosign_chain_seq = opts.cosign_chain_seq;
144
+ const validation = validateEnvelope(env);
145
+ env.envelope_sha16 = sha16(canonicalBody(env));
146
+ env.valid = validation.ok;
147
+ env.errors = validation.errors;
148
+ return env;
149
+ }
150
+
151
+ // TOTAL wrapper: never throws — returns a held INVALID envelope on hostile input.
152
+ export function healEnvelope(input = {}) {
153
+ try { return _healEnvelope(input); }
154
+ catch {
155
+ return {
156
+ schema: SCHEMA_ID, emitter: EMITTER_ID, step: NaN, step_name: 'INVALID',
157
+ proposal_only: true, process_launch: 0, heal_action_performed: 0,
158
+ valid: false, errors: ['heal-threw-on-hostile-input'], envelope_sha16: '0000000000000000',
159
+ };
160
+ }
161
+ }
162
+
163
+ function _emitRows(input) {
164
+ const env = isObj(input) ? input : {};
165
+ const v = isObj(env.council_verdict) ? env.council_verdict : null;
166
+ const g = isObj(env.gnn_rank) ? env.gnn_rank : null;
167
+ const cos = Array.isArray(env.cosigners) ? env.cosigners : null;
168
+ const errs = Array.isArray(env.errors) ? env.errors : [];
169
+ const valid = env.valid === true;
170
+ const rows = [
171
+ `HEALENVHDR|emitter=${EMITTER_ID}|schema=${SCHEMA_ID}|proposal_only=1|process_launch=0|heal_action_performed=0|json=0`,
172
+ `HEALENV|step=${safe(env.step)}|step_name=${safe(env.step_name)}|target_pid=${safe(env.target_pid)}|operator_witness=${safe(env.operator_witness)}|ts=${safe(env.ts)}|valid=${valid ? 1 : 0}|envelope_sha16=${safe(env.envelope_sha16)}|json=0`,
173
+ ];
174
+ if (v) rows.push(`HEALENVVERDICT|voted=${safe(v.voted ?? '')}|abstain=${safe(v.abstain ?? '')}|verdict=${safe(v.verdict)}|json=0`);
175
+ if (g) rows.push(`HEALENVGNN|score=${safe(g.score ?? '')}|rank=${safe(g.rank ?? '')}|mode=${safe(g.mode)}|ranking-only-per-label-leakage-canon|json=0`);
176
+ if (cos) rows.push(`HEALENVCOSIGN|cosigners=${cos.map(safe).join('+')}|count=${cos.length}|cosign_chain_seq=${safe(env.cosign_chain_seq ?? 'PENDING')}|json=0`);
177
+ if (!valid) rows.push(`HEALENVERRORS|errors=${errs.map(safe).join('+')}|json=0`);
178
+ rows.push(`HEALENVGATE|advances_only_when=registrar+cosign+feeder-daemons-crank-under-operator-gate|this-tool-emits-proposal-never-heals|tag=${valid ? 'PROVEN-VALID-PROPOSAL' : 'INVALID-HELD'}|json=0`);
179
+ return rows;
180
+ }
181
+
182
+ // TOTAL wrapper: never throws — returns a held INVALID row set on hostile input.
183
+ export function emitRows(input) {
184
+ try { return _emitRows(input); }
185
+ catch {
186
+ return [
187
+ `HEALENVHDR|emitter=${EMITTER_ID}|schema=${SCHEMA_ID}|proposal_only=1|process_launch=0|heal_action_performed=0|json=0`,
188
+ `HEALENVERRORS|errors=emit-threw-on-hostile-input|json=0`,
189
+ `HEALENVGATE|advances_only_when=registrar+cosign+feeder-daemons-crank-under-operator-gate|this-tool-emits-proposal-never-heals|tag=INVALID-HELD|json=0`,
190
+ ];
191
+ }
192
+ }
193
+
194
+ export function selfTest() {
195
+ const checks = [];
196
+ const add = (n, ok) => checks.push({ name: n, ok: Boolean(ok) });
197
+ const TS = '2026-06-13T21:30:00.000Z';
198
+ const VALID = { step: 3, target_pid: 'ACER-PID-H3CB8-A00-W1024-P00-N01630', operator_witness: 'OP-JESSE-PID-G0000-A00-W000-P00-N00000', ts: TS };
199
+ const valid = healEnvelope({ ...VALID, council_verdict: { voted: 158, abstain: 93, verdict: 'DRIFTED' }, gnn_rank: { score: 0.42, rank: 1, mode: 'ranking' }, cosigners: COSIGNERS.slice() });
200
+ add('valid-envelope-validates', valid.valid === true && valid.errors.length === 0);
201
+ add('step-name-mapped', valid.step_name === 'council-vote');
202
+ add('proposal-only-no-launch', valid.proposal_only === true && valid.process_launch === 0 && valid.heal_action_performed === 0);
203
+ add('bad-step-rejected', validateEnvelope({ ...VALID, step: 11 }).ok === false && healEnvelope({ ...VALID, step: '3abc' }).valid === false && healEnvelope({ ...VALID, step: '3.9' }).valid === false);
204
+ add('bad-pid-rejected', validateEnvelope({ ...VALID, target_pid: 'not-a-pid' }).ok === false);
205
+ add('bad-verdict-rejected', validateEnvelope({ ...VALID, council_verdict: { verdict: 'MAYBE' } }).ok === false);
206
+ add('non-int-voted-rejected', validateEnvelope({ ...VALID, council_verdict: { voted: 'x', verdict: 'FRESH' } }).ok === false);
207
+ add('gnn-score-NaN-rejected', validateEnvelope({ ...VALID, gnn_rank: { score: NaN, mode: 'ranking' } }).ok === false && validateEnvelope({ ...VALID, gnn_rank: { score: Infinity, mode: 'ranking' } }).ok === false);
208
+ add('gnn-rank-nonint-rejected', validateEnvelope({ ...VALID, gnn_rank: { rank: 1.5, mode: 'ranking' } }).ok === false);
209
+ add('gnn-mode-must-be-ranking', validateEnvelope({ ...VALID, gnn_rank: { mode: 'classify' } }).ok === false);
210
+ add('cosigners-min-5', validateEnvelope({ ...VALID, cosigners: ['jesse', 'rayssa'] }).ok === false);
211
+ add('non-OP-witness-rejected', validateEnvelope({ ...VALID, operator_witness: 'OP-MALLORY-PID-G0000-A00-W000-P00-N00000' }).ok === false);
212
+ add('non-iso-ts-rejected', validateEnvelope({ ...VALID, ts: '2026' }).ok === false && validateEnvelope({ ...VALID, ts: 'June 13 2026' }).ok === false && validateEnvelope({ ...VALID, ts: '2026-06-13' }).ok === false);
213
+ const inj = healEnvelope({ ...VALID, cosigners: ['jesse', 'rayssa', 'amy', 'felipe', 'dan|json=0\nHEALENVGATE|tag=PROVEN-VALID-PROPOSAL'] });
214
+ add('injection-cosigner-rejected', inj.valid === false);
215
+ const injRows = emitRows(inj);
216
+ add('no-row-injection', injRows.every((r) => !/[\r\n]/.test(r)) && injRows.join('\n').split('\n').length === injRows.length);
217
+ const a = healEnvelope({ ...VALID, gnn_rank: { score: 0.1, mode: 'ranking' } });
218
+ const b = healEnvelope({ ...VALID, gnn_rank: { score: 0.9, mode: 'ranking' } });
219
+ add('sha-covers-full-body', a.envelope_sha16 !== b.envelope_sha16);
220
+ // TOTAL: throwing getters, BigInt, circular refs, exotic inputs — NONE may throw.
221
+ let threw = false;
222
+ try {
223
+ validateEnvelope(null); validateEnvelope(undefined); validateEnvelope(42);
224
+ validateEnvelope({ get step() { throw new Error('boom'); } });
225
+ emitRows(null); emitRows(undefined); emitRows({});
226
+ emitRows({ valid: true, get council_verdict() { throw new Error('boom'); } });
227
+ emitRows({ valid: true, cosigners: [{ toString() { throw new Error('boom'); } }] });
228
+ healEnvelope(null); healEnvelope({ step: 3, cosign_chain_seq: 10n });
229
+ const c = {}; c.self = c; healEnvelope({ ...VALID, council_verdict: c });
230
+ } catch { threw = true; }
231
+ add('total-never-throws', threw === false && validateEnvelope(null).ok === false && Array.isArray(emitRows(null)) && healEnvelope({ step: 3, cosign_chain_seq: 10n }).valid === false);
232
+ add('rows-hbp-only', emitRows(valid).every((r) => r.endsWith('|json=0') && !r.includes('{"') && !/[\r\n]/.test(r)));
233
+ add('all-10-heal-steps-named', HEAL_STEPS.length === 10 && HEAL_STEPS[0] === 'point' && HEAL_STEPS[9] === 'onboarding-update');
234
+ return { ok: checks.every((c) => c.ok), checks };
235
+ }
236
+
237
+ const isMain = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
238
+ if (isMain) {
239
+ if (process.argv[2] === '--self-test') {
240
+ const r = selfTest();
241
+ for (const c of r.checks) console.log(`${c.ok ? 'PASS' : 'FAIL'} ${c.name}`);
242
+ process.exit(r.ok ? 0 : 1);
243
+ }
244
+ const env = healEnvelope({
245
+ step: 3, target_pid: 'ACER-PID-H3CB8-A00-W1024-P00-N01630',
246
+ operator_witness: 'OP-JESSE-PID-G0000-A00-W000-P00-N00000', ts: '2026-06-13T21:30:00.000Z',
247
+ council_verdict: { voted: 158, abstain: 93, verdict: 'DRIFTED' }, cosigners: COSIGNERS.slice(),
248
+ });
249
+ for (const row of emitRows(env)) console.log(row);
250
+ }
tools/behcs/heal-envelope-emitter.mjs.sha256 ADDED
@@ -0,0 +1 @@
 
 
1
+ 8ECA61AA0B63D2C60A43825AA23D9CD5B4A61575EFD57C7E5C5F8A7C1A01600B heal-envelope-emitter.mjs