nx_swarm_beat.nx
buildroot/runtime/nx_swarm_beat.nx
about
nx_swarm_beat.nx -- SWARM FABRIC fleet-beat store (SF-R1b): every worker reports its beacon NODE
row here; the hub reads back a fresh fleet snapshot. This is deliberately its OWN small organ per
[[feedback-no-risky-inplace-mgmt-api-deploy]] (NEVER bolt telemetry onto mgmt/hostctl) -- NAS-side
it runs via the pinned tools/call lane; nx_node_beacon (v2) emits the row, this organ stores it,
a later mgmt train may READ the snapshot (read-only swap of the hardcoded workers literal).
nx_swarm_beat put <log> <snap> "<NODE row>" -- validate row; flock'd append to <log> (fa_append,
the R0b torn-write floor); atomically replace-by-name
in <snap> (whole-file rewrite, tmp+renameat)
nx_swarm_beat put "<NODE row>" -- NAS tools/call form: default paths swarm_beats.log +
node_rows.snap in CWD (tools daemon CWD = nishihost)
nx_swarm_beat show <snap> <window_sec> -- print FRESH/STALE per row (ts vs wall clock; the
window comes from the CALLER/conf -- no baked
freshness constant, rule 11)
nx_swarm_beat show <window_sec> -- default snap node_rows.snap
PATH LAW (least-authority BY CONSTRUCTION -- a leaked cap must not clobber nishihost binaries):
CLI paths must end .log/.snap, contain no "..", and be either bare basenames (land in CWD) or
live under /tmp/ (local tests). Everything else -> REFUSED before any io.
nx_swarm_beat [gate] -- self-gate: put/replace/show + neg-controls + the
fabricated-liveness liar-killer (an ancient or
future-forged ts can NEVER read FRESH)
Row contract (v2 positional, additive -- emitted by nx_node_beacon):
NODE <name> <cpu> <load> <ncpu> <lpc> <memu> <mema> <memt> <conns> <ts_us> <temp_mc> <batt_pct>
v1 HONEST LIMIT: two DIFFERENT nodes putting at the same instant can lose one snap rewrite
(last-writer-wins whole-file); periodic beats self-heal next cycle and the LOG never loses a row
(flock'd). Serialize the rewrite under a lock file = v1.1 if beats ever collide in practice.
license_tier: ORIGINAL expect_exit:0
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_framed_append.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 31 | const SB_MAGIC_60000000: i64 = 60000000 |
| 32 | const SB_MAGIC_1000000: i64 = 1000000 |
| 33 | const SB_MAGIC_7200000000: i64 = 7200000000 |
| 34 | const SB_MAGIC_3600: i64 = 3600 |
| 35 | const SB_MAGIC_600000000: i64 = 600000000 |
| 37 | const SB_SNAP_CAP: i64 = 65536 |
| 38 | const SB_ROW_CAP: i64 = 512 |
functions
| 40 | func sb_puts(s: *u8) -> i64 { sys_write(1, s, fa_len(s)); return 0 } |
| 42 | func sb_eq(a: *u8, b: *u8) -> i64 called by 1: main |
| 50 | func sb_path_ok(p: *u8) -> i64 |
| 84 | func sb_read(path: *u8, buf: *u8, cap: i64) -> i64 |
| 98 | func sb_has(buf: *u8, n: i64, needle: *u8) -> i64 |
| 113 | func sb_pint(buf: *u8, n: i64, p: i64, vout: *i64, pend: *i64) -> i64 |
| 134 | func sb_validate(row: *u8, n: i64, nso: *i64, nlo: *i64, tso: *i64) -> i64 |
| 177 | func sb_fresh(ts: i64, now: i64, window_sec: i64) -> i64 |
| 185 | func sb_snap_replace(snap: *u8, row: *u8, rowlen: i64, ns: i64, nl: i64) -> i64 |
| 241 | func sb_put(log: *u8, snap: *u8, row: *u8) -> i64 |
| 259 | func sb_show(snap: *u8, window_sec: i64) -> i64 |
| 301 | func sb_mkrow(dst: *u8, name: *u8, cpu: i64, ts: i64) -> i64 |
| 313 | func sb_gate() -> i64 |
| 420 | func main(argc: i64, argv: *i64) -> i64 |