igneum/infra/build-server/capacity/summary.mjs
igneum-labs 6836115d65 Capacity layer: idle-core background workload on igneum-build-1 that yields to builds
infra/build-server/capacity: igneum-capacity.service (user build, Nice 19, SCHED_IDLE,
CPUQuota leaving 8 threads free) runs run.sh, a controller over a priority queue of jobs
that pauses (SIGSTOP) the instant a build slot or the measure hold is taken (5 s poll of
/srv/builds/_locks) and resumes after. Jobs, each with a dry-run and a 10-min smoke:
pow fuzz (continuous, seed base advances), sync-request fuzz against a throwaway pruned
node on loopback (the Horizon 28-unwrap gate, igneum-p2p-probe sync-fuzz), GHOSTDAG and
finality sweeps seeds 1 to 1,000, model.py sweeps cached, clippy+audit per recent branch.
Summaries to /srv/workers/capacity.json; the worker dashboard gains a Background lane
(collect.mjs doc.background, page renderBackground). Night battery stops and restarts the
layer. docs/plans/build-server.md section 8. igneum-pow fuzz tests and ghostdag_sim.py /
attacks.py gain a seed-base knob for the continuous sweeps.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:58:42 +00:00

72 lines
2.9 KiB
JavaScript
Executable file

#!/usr/bin/env node
// The capacity layer's summary writer. Atomically merges one JSON fragment into /srv/workers/capacity.json, the file
// the worker dashboard's collector (tools/workers/collect.mjs) reads for the "Background" lane. Never takes a build
// slot, never writes anywhere but IGNEUM_CAPACITY_JSON. Node 22, no deps.
//
// echo '{"state":"running","summary":"...","counters":{...}}' | summary.mjs job pow-fuzz
// merge the fragment into doc.jobs["pow-fuzz"], stamping updated_at; set doc.jobs[job].priority from CAP_PRIORITY if given
// echo '{"state":"running","current_job":"pow-fuzz","paused_reason":null}' | summary.mjs controller
// merge the fragment into the top-level controller fields (state, current_job, paused_reason, slice, host)
// summary.mjs init write an empty document if none exists
//
// The document:
// { v, generated_at, host, state, current_job, paused_reason, slice_s,
// jobs: { <job>: { priority, state, updated_at, summary, counters, panics, saved, ... } } }
import { readFileSync, writeFileSync, renameSync, mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
import { hostname } from 'node:os';
const OUT = process.env.IGNEUM_CAPACITY_JSON || '/srv/workers/capacity.json';
const iso = () => new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
function load() {
try {
const d = JSON.parse(readFileSync(OUT, 'utf8'));
if (d && typeof d === 'object') { d.jobs = d.jobs || {}; return d; }
} catch { /* fall through to a fresh document */ }
return { v: 1, host: hostname(), state: 'starting', current_job: null, paused_reason: null, slice_s: null, jobs: {} };
}
function save(d) {
d.v = 1; d.host = d.host || hostname(); d.generated_at = iso();
mkdirSync(dirname(OUT), { recursive: true });
const tmp = OUT + '.tmp';
writeFileSync(tmp, JSON.stringify(d));
renameSync(tmp, OUT);
}
function readStdin() {
try {
const t = readFileSync(0, 'utf8').trim();
if (!t) return {};
const o = JSON.parse(t);
return o && typeof o === 'object' ? o : {};
} catch (e) { process.stderr.write('summary.mjs: bad JSON on stdin: ' + (e.message || e) + '\n'); process.exit(1); }
}
const mode = process.argv[2];
const d = load();
if (mode === 'init') { save(d); process.exit(0); }
if (mode === 'controller') {
const frag = readStdin();
for (const k of ['state', 'current_job', 'paused_reason', 'slice_s', 'host']) if (k in frag) d[k] = frag[k];
save(d);
process.exit(0);
}
if (mode === 'job') {
const job = process.argv[3];
if (!job) { process.stderr.write('summary.mjs job <name>\n'); process.exit(1); }
const frag = readStdin();
const prev = d.jobs[job] || {};
const merged = { ...prev, ...frag, updated_at: iso() };
if (process.env.CAP_PRIORITY) merged.priority = Number(process.env.CAP_PRIORITY);
d.jobs[job] = merged;
save(d);
process.exit(0);
}
process.stderr.write('summary.mjs: mode is one of init | controller | job <name>\n');
process.exit(1);