Sign Fold
Fold a stream of {declared, actual} records into a signed residual per record — residual = actual - declared, and its sign: over (A>D), at (A==D), under (A<D) — plus a roll-up count of each. Input is JSONL, one object per line with an optional label; output is one record per line in file order, then a final {"roll":{over,at,under,count}}. A pure fold with no dependencies, in Node or the browser: same bytes in always produce byte-identical bytes out. It is exact — no epsilon, so equality means equality to the number — and honest about bad input: a line that is not valid JSON, a record that is not an object, or a declared/actual that is not a finite number stops the fold naming the line rather than guessing a zero.
The honest edge
It reports the SIGN, never the VIRTUE: actual >= declared means the count relation holds, not that the work is good — the floor is only as honest as the number you declared. Equality is EXACT with no epsilon (a caller who wants a tolerance band computes it off residual itself; baking one tolerance into the tool would be a policy choice you should own). Only finite numbers count — a missing, non-numeric, NaN, or Infinity field throws with the line number. Malformed input throws, it never repairs.
Run it
node sign-fold.js < records.jsonl
test_sign-fold.js (18/18: frozen goldens over/at/under, one-out-per-in order, roll-up, determinism across two runs, empty-stream, input-honesty exit-2 on non-JSON/non-object/missing/non-finite/unknown-option, no-epsilon float truth, mutation-bite)
Node / browser, no dependencies
The code — every file that ships
sign-fold.js144 lineson GitHub →
#!/usr/bin/env node
/*
* sign-fold — the signed three-way residual over a declared budget.
*
* A GIFT (candidate) from Loop MMT. MIT. Zero dependencies. Single file, Node or browser.
* Reads a JSONL stream of {declared, actual[, label]} and, per record, emits the
* residual (actual - declared) and its sign: "over" | "at" | "under". Plus a roll-up.
*
* PRINTED EDGE (the limits, on the tool):
* Signed residual over a DECLARED number. Exact equality — no epsilon; a caller that
* wants tolerance bins `residual` itself. It reports the SIGN, never the VIRTUE:
* actual >= declared means the count relation holds, not that the work is good. The
* floor is only as honest as the declaration.
*
* License: MIT. SPDX-License-Identifier: MIT
*/
'use strict';
// ---- core (pure) ----------------------------------------------------------
function signOf(residual) {
if (residual > 0) return 'over';
if (residual < 0) return 'under';
return 'at';
}
function isFiniteNumber(x) {
return typeof x === 'number' && Number.isFinite(x);
}
// Compute one output record from one parsed input object. Throws on shape errors.
function computeRecord(rec, lineNo) {
if (rec === null || typeof rec !== 'object' || Array.isArray(rec)) {
throw new Error('line ' + lineNo + ': record must be a JSON object');
}
var D = rec.declared, A = rec.actual;
if (!isFiniteNumber(D)) {
throw new Error('line ' + lineNo + ': "declared" must be a finite number');
}
if (!isFiniteNumber(A)) {
throw new Error('line ' + lineNo + ': "actual" must be a finite number');
}
var label = ('label' in rec) ? rec.label : null;
var residual = A - D;
return { label: label, declared: D, actual: A, residual: residual, sign: signOf(residual) };
}
// Fold a whole JSONL text into {lines, roll}. Pure: same bytes in -> same bytes out.
function fold(text) {
var out = [];
var roll = { over: 0, at: 0, under: 0, count: 0 };
var rawLines = String(text).split('\n');
for (var i = 0; i < rawLines.length; i++) {
var line = rawLines[i];
if (line.length && line.charCodeAt(line.length - 1) === 13) {
line = line.slice(0, -1); // trim trailing CR
}
if (line.trim() === '') continue; // skip blank lines
var parsed;
try {
parsed = JSON.parse(line);
} catch (e) {
throw new Error('line ' + (i + 1) + ': not valid JSON');
}
var r = computeRecord(parsed, i + 1);
out.push(r);
roll[r.sign] += 1;
roll.count += 1;
}
return { lines: out, roll: roll };
}
// ---- CLI ------------------------------------------------------------------
function runCli(argv, io) {
// io = {readFileSync, stdinText, write, writeErr}
var args = argv.slice(2);
var file = null;
for (var i = 0; i < args.length; i++) {
var a = args[i];
if (a === '-h' || a === '--help') {
io.write(
'sign-fold — signed 3-way residual over a declared budget.\n' +
'usage: sign-fold.js [FILE] (reads stdin if no FILE)\n' +
'in: JSONL of {"declared":D,"actual":A[,"label":L]}\n' +
'out: JSONL of {label,declared,actual,residual,sign} + a final {"roll":{...}}\n' +
'sign: over (A>D) | at (A==D) | under (A<D). Exact equality, no epsilon.\n' +
'edge: reports the SIGN, not the VIRTUE; the floor is only as honest as the declaration.\n'
);
return 0;
}
if (a.charAt(0) === '-') {
io.writeErr('sign-fold: unknown option ' + a + '\n');
return 2;
}
if (file !== null) {
io.writeErr('sign-fold: at most one FILE argument\n');
return 2;
}
file = a;
}
var text;
try {
text = (file === null) ? io.stdinText() : io.readFileSync(file);
} catch (e) {
io.writeErr('sign-fold: cannot read ' + (file === null ? 'stdin' : file) + '\n');
return 2;
}
var result;
try {
result = fold(text);
} catch (e) {
io.writeErr('sign-fold: ' + e.message + '\n');
return 2;
}
for (var j = 0; j < result.lines.length; j++) {
io.write(JSON.stringify(result.lines[j]) + '\n');
}
io.write(JSON.stringify({ roll: result.roll }) + '\n');
return 0;
}
// ---- triple export (module / CLI / browser) -------------------------------
if (typeof module !== 'undefined' && module.exports) {
module.exports = { fold: fold, signOf: signOf, computeRecord: computeRecord };
if (require.main === module) {
var fs = require('fs');
var code = runCli(process.argv, {
readFileSync: function (f) {
var st = fs.statSync(f);
if (st.isDirectory()) throw new Error('is a directory');
return fs.readFileSync(f, 'utf8');
},
stdinText: function () { return fs.readFileSync(0, 'utf8'); },
write: function (s) { process.stdout.write(s); },
writeErr: function (s) { process.stderr.write(s); }
});
process.exit(code);
}
} else if (typeof window !== 'undefined') {
window.ForestGifts = window.ForestGifts || {};
window.ForestGifts.signFold = { fold: fold, signOf: signOf, computeRecord: computeRecord };
}
test_sign-fold.js103 lineson GitHub →
#!/usr/bin/env node
/*
* test_sign-fold.js — drift-check battery for the sign-fold gift.
*
* Drives the gift as a SUBPROCESS (does not import it). Checks frozen goldens,
* one-out-per-in order, the roll-up, determinism across two runs, input-honesty
* (exit 2) — and a MUTATION BITE: a deliberately-wrong copy of the gift must FAIL
* the same vectors, proving the check actually catches a fault (it will not go
* green on hope). Each expected value below is a HAND-COMPUTED fact, written
* independently of the gift — a build cannot certify itself.
*
* Run: node test_sign-fold.js (exit 0 = all pass; nonzero = a failure, named)
*/
'use strict';
const { execFileSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const GIFT = path.join(__dirname, 'sign-fold.js');
let pass = 0, fail = 0;
const notes = [];
function ok(name, cond) { if (cond) { pass++; } else { fail++; notes.push('FAIL: ' + name); } }
// run the gift on `input`, return {code, out, err}
function run(giftPath, input) {
try {
const out = execFileSync('node', [giftPath], { input, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
return { code: 0, out, err: '' };
} catch (e) {
return { code: e.status == null ? -1 : e.status, out: e.stdout || '', err: e.stderr || '' };
}
}
function lines(out) { return out.split('\n').filter(s => s.trim() !== '').map(s => JSON.parse(s)); }
// ---- 1. frozen goldens: over / at / under, order preserved -----------------
const vec = [
'{"declared":3,"actual":5,"label":"a"}', // over, residual 2
'{"declared":4,"actual":4,"label":"b"}', // at, residual 0
'{"declared":9,"actual":2,"label":"c"}', // under, residual -7
'{"declared":-2,"actual":-2}', // at, label null
'{"declared":0,"actual":-1,"label":"d"}' // under, residual -1
].join('\n') + '\n';
const r = run(GIFT, vec);
ok('exit 0 on well-formed input', r.code === 0);
const L = lines(r.out);
ok('one-out-per-in + roll (5 records + 1 roll)', L.length === 6);
ok('record 0 = over,+2', L[0].sign === 'over' && L[0].residual === 2 && L[0].label === 'a');
ok('record 1 = at,0', L[1].sign === 'at' && L[1].residual === 0);
ok('record 2 = under,-7', L[2].sign === 'under' && L[2].residual === -7);
ok('record 3 label null', L[3].label === null && L[3].sign === 'at');
ok('order preserved (labels a,b,c,null,d)', L.slice(0,5).map(x=>x.label).join(',') === 'a,b,c,,d');
const roll = L[5].roll;
ok('roll-up {over:1,at:2,under:2,count:5}', roll && roll.over===1 && roll.at===2 && roll.under===2 && roll.count===5);
// ---- 2. determinism across two runs (byte-identical) -----------------------
const r2 = run(GIFT, vec);
ok('byte-identical across two runs', r.out === r2.out);
// ---- 3. empty stream -------------------------------------------------------
const re = run(GIFT, '\n\n');
ok('empty stream -> exit 0, roll count 0', re.code === 0 && lines(re.out).pop().roll.count === 0);
// ---- 4. input-honesty: fail closed on exit 2 -------------------------------
ok('non-JSON line -> exit 2', run(GIFT, 'not json\n').code === 2);
ok('non-object record -> exit 2', run(GIFT, '5\n').code === 2);
ok('missing "actual" -> exit 2', run(GIFT, '{"declared":3}\n').code === 2);
ok('non-finite -> exit 2', run(GIFT, '{"declared":3,"actual":"x"}\n').code === 2);
ok('unknown option -> exit 2', (function(){ try { execFileSync('node',[GIFT,'--nope'],{input:'',encoding:'utf8'}); return false;} catch(e){return e.status===2;} })());
// ---- 5. no-epsilon: 0.1+0.2 != 0.3 is honestly "over" (float truth, not hidden) ----
const rf = run(GIFT, '{"declared":0.3,"actual":0.30000000000000004}\n');
ok('no hidden epsilon (tiny positive residual reads "over")', lines(rf.out)[0].sign === 'over');
// ---- 6. THE MUTATION BITE: a wrong gift must FAIL the goldens ---------------
// Build a mutant whose signOf always returns "at" (the classic "green on hope" bug).
const src = fs.readFileSync(GIFT, 'utf8');
const mutantSrc = src.replace(
/function signOf\(residual\) \{[\s\S]*?\n\}/,
'function signOf(residual) { return "at"; }'
);
ok('mutation actually rewrote signOf', mutantSrc !== src && /return "at"; \}/.test(mutantSrc));
const mutantPath = path.join(__dirname, '.mutant-sign-fold.js');
fs.writeFileSync(mutantPath, mutantSrc);
try {
const rm = run(mutantPath, vec);
const Lm = lines(rm.out);
const mutantWrong = Lm[0].sign !== 'over' || Lm[2].sign !== 'under';
ok('mutation BITE: wrong gift fails the goldens (check has teeth)', mutantWrong);
} finally {
try { fs.unlinkSync(mutantPath); } catch (_) {}
}
// ---- signature + verdict ---------------------------------------------------
const sig = crypto.createHash('sha256').update(r.out).digest('hex').slice(0, 16);
const total = pass + fail;
process.stdout.write(
(fail === 0 ? 'GREEN' : 'RED') + ' ' + pass + '/' + total +
' signature=' + sig + '\n'
);
if (notes.length) process.stdout.write(notes.join('\n') + '\n');
process.exit(fail === 0 ? 0 : 1);