code wiki / _hdl_build / nx_seat_meter_beat.nx
nx_seat_meter_beat.nx
buildroot/runtime/_hdl_build/nx_seat_meter_beat.nx
about
nx_seat_meter_beat.nx -- ES1 of /compare/engineshift: THE SCOREBOARD'S PRODUCER (laptop-local, 2026-09-02).
nx_seat shift (F831) grades the engine shift from knowledge/status/token_efficiency.log, and every row that log
has ever held was appended BY HAND: 16 rows, the last dated 2026-08-05, no hook, clock row or organ names
`nx_seat meter`. A gauge whose rows are hand-appended is a diary, not a gauge -- it stops the day the hand
stops and reads as "no movement" forever (the local column read ZERO for 44 days and was quoted twice as a
finding about the estate). This organ is the producer. It rides the SessionStart hook beside nx_crashwin.
WHAT IT MEASURES. Every Claude Code transcript (<sessions>/*.jsonl) carries one line per assistant content
block, and EVERY block of one message repeats that message's usage object (measured 2026-09-02: 367 assistant
lines for 58 distinct message ids in one transcript). So usage is counted ONCE PER MESSAGE ID, never per line;
a naive sum overcounts about six-fold. Per complete UTC day and model family it sums output_tokens,
cache_read_input_tokens and cache_creation_input_tokens, counts messages, and counts the transcripts active
that day (the row's `sessions` column). A line is an assistant line when it carries a raw "type":"assistant"
(tool results are escaped strings and cannot); the message's OWN model, id and usage are the DEPTH-1 children of
"message":{ -- a tool_use input is raw JSON and may carry model and id fields of its own, so position on the line
decides nothing (neg-controls in the gate). Harness API-error lines (model "<synthetic>") are their own bucket.
nx_seat_meter_beat scan <sessions-dir> [--now <epoch>] [--days N]
prints one DAY row per (day, family) inside the window and a METERBEAT summary; writes nothing.
nx_seat_meter_beat beat <sessions-dir> <state-dir> <mcp-elf> <base-url> <cap-file> [--now <epoch>] [--days N]
[--dry] [--json]
for every COMPLETE day (strictly before today, UTC) in the window whose (day, family) is not yet in
<state-dir>/meterbeat.days, forks <mcp-elf> (nx_mcp_call) to run `nx_seat meter` on the estate and, on
the reply "METERED row appended", records the marker -- idempotent by day marker: a second run appends
nothing. --dry plans and prints, forks nothing, marks nothing. --json wraps the digest as a SessionStart
hook envelope and exits 0 (the hook framework parses stdout only on exit 0).
Today is NEVER pushed: an incomplete day would be re-summed tomorrow and the marker would make it final.
Window: --days N (default MB_DAYS_DEFAULT) complete days; transcripts whose mtime predates the window start
are not read (they cannot carry a newer day), so a session-start run touches only recent files.
A transcript whose last line has no newline is counted PARTIAL: its complete lines count, the tail does not,
and the summary says so -- a truncated file is never read as zero.
Exit: 0 GREEN | 1 RED (a push was refused or answered without the METERED receipt) | 2 usage |
3 UNOBSERVABLE (the sessions dir cannot be opened). verdict= is the LAST token of the last line.
license_tier: ORIGINAL. Writes only <state-dir>/meterbeat.days. No hw writes (Rule 26).
dependencies 3 imports · 0 importers
imports: nx_syscalls.nxnx_memplane_lib.nxnx_tool_run.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
| 39 | const MB_DAYS_DEFAULT: i64 = 3 // a hook run owes yesterday and the day before; older days were owed earlier |
| 40 | const MB_DAYS_MAX: i64 = 400 // distinct days one run can hold; reaching it announces days_floor=1 |
| 41 | const MB_FAM_MAX: i64 = 8 // model families per run (fable, opus, sonnet, haiku, ...) |
| 42 | const MB_FAM_CAP: i64 = 32 // one family token cell |
| 43 | const MB_SLOT: i64 = 256 // one transcript name cell (names measured 42 B) |
| 44 | const MB_FILES_MAX: i64 = 4096 // 220 transcripts on 2026-09-02; reaching the cap announces files_floor=1 |
| 45 | const MB_PATH: i64 = 4096 // PATH_MAX |
| 46 | const MB_DENTBUF: i64 = 262144 // getdents64 batch buffer, LOOPED to completion |
| 47 | const MB_STATBUF: i64 = 256 // struct stat is 144 B on x86_64 |
| 48 | const MB_STAT_MTIME_SLOT: i64 = 11 // st_mtim.tv_sec at byte 88 = i64[11] |
| 49 | const MB_DOT: i64 = 46 |
| 50 | const MB_QUOTE: i64 = 34 |
| 51 | const MB_NL: i64 = 10 |
| 52 | const MB_DASH: i64 = 45 |
| 53 | const MB_ID_CAP: i64 = 64 // msg_ ids measured 30 B |
| 54 | const MB_ID_RING: i64 = 8 // blocks of one message are consecutive; a ring of 8 absorbs interleaving |
| 55 | const MB_OUT: i64 = 262144 // report buffer (400 days x 8 families x ~120 B fits 4x over) |
| 56 | const MB_DAY_LEN: i64 = 10 // YYYY-MM-DD |
| 57 | const MB_SEC_PER_DAY: i64 = 86400 |
| 58 | const MB_EXIT_OK: i64 = 0 |
| 59 | const MB_EXIT_RED: i64 = 1 |
| 60 | const MB_EXIT_USAGE: i64 = 2 |
| 61 | const MB_EXIT_UNOBS: i64 = 3 |
| 62 | const MB_FORK_TIMEOUT_MS: i64 = 60000 // the estate appends one row; 60 s covers a saturated box |
| 63 | const MB_RESP_CAP: i64 = 65536 |
| 64 | const MB_READ_SLACK: i64 = 16 // sys_read_file maps size+16; released with the same arithmetic |
| 65 | const MB_MARK_CAP: i64 = 1048576 // marker file window; 400 days x 8 families x ~64 B is 200 KB |
| 66 | const MB_ARGV_MAX: i64 = 8 |
| 67 | const MB_FRAG_CAP: i64 = 1024 |
| 68 | const MB_NOTE_CAP: i64 = 256 |
| 69 | const MB_DIGITS_MAX: i64 = 18 // an i64 holds 18 full decimal digits; longer runs are malformed |
| 70 | const MB_HINNANT_OFFSET: i64 = 719468 // days_from_civil: 1970-01-01 is day 719468 of the proleptic era count |
| 71 | const MB_ERA_DAYS: i64 = 146097 |
| 72 | const MB_ERA_YEARS: i64 = 400 |
| 73 | const MB_DOY_MUL: i64 = 153 |
| 74 | const MB_DOY_ADD: i64 = 2 |
| 75 | const MB_DOY_DIV: i64 = 5 |
| 76 | const MB_YEAR_DAYS: i64 = 365 |
| 77 | const MB_KEY_YEAR_MUL: i64 = 10000 // day key = y*10000 + m*100 + d, printable back with dashes |
| 78 | const MB_KEY_MON_MUL: i64 = 100 |
| 79 | const MB_CELLS: i64 = 3200 // MB_DAYS_MAX * MB_FAM_MAX |
| 80 | const MB_I64: i64 = 8 |
| 248 | const MB_C_FILES: i64 = 0 |
| 249 | const MB_C_READ: i64 = 1 |
| 250 | const MB_C_SKIPPED: i64 = 2 |
| 251 | const MB_C_LINES: i64 = 3 |
| 252 | const MB_C_ASSIST: i64 = 4 |
| 253 | const MB_C_MSGS: i64 = 5 |
| 254 | const MB_C_DUP: i64 = 6 |
| 255 | const MB_C_MALFORMED: i64 = 7 |
| 256 | const MB_C_PARTIAL: i64 = 8 |
| 257 | const MB_C_DAYS: i64 = 9 |
| 258 | const MB_C_FAMS: i64 = 10 |
| 259 | const MB_C_DAYSFLOOR: i64 = 11 |
| 260 | const MB_C_FILESFLOOR: i64 = 12 |
| 261 | const MB_C_STATFAIL: i64 = 13 |
| 262 | const MB_C_OUTSIDE: i64 = 14 |
| 263 | const MB_C_SYNTH: i64 = 15 // harness-written API-error lines: model "<synthetic>", no msg_ id, nothing to meter |
| 264 | const MB_C_RECOVERED: i64 = 16 // rows the estate log already held that the local marker had lost (a dropped receipt) |
| 265 | const MB_C_DEFERRED: i64 = 17 // rows NOT pushed because the estate log could not be read first |
| 266 | const MB_C_SLOTS: i64 = 24 |
| 267 | const MB_LOG_CAP: i64 = 262144 // one meterlog fetch: 400 rows x ~120 B escaped fits 5x over |
| 268 | const MB_LOG_ROWS: *u8 = "400" // tail rows to read back; 40 days x 2 families x 2 retries is 160 |
| 269 | const MB_ROW_BACK: i64 = 200 // a log row is epoch TAB seat TAB 4 numbers TAB note: the seat sits within 200 B before its note |
| 470 | const MB_R_REASON: i64 = 0 |
| 471 | const MB_R_AUTHORED: i64 = 1 |
| 472 | const MB_R_MECH: i64 = 2 |
| 473 | const MB_R_PROMPT: i64 = 3 |
| 474 | const MB_R_OTHER: i64 = 4 |
| 475 | const MB_R_LINES: i64 = 5 |
| 476 | const MB_R_SLOTS: i64 = 8 |
| 477 | const MB_LBRACE: i64 = 123 |
| 478 | const MB_RBRACE: i64 = 125 |
| 479 | const MB_LBRACK: i64 = 91 |
| 480 | const MB_RBRACK: i64 = 93 |
| 481 | const MB_COMMA: i64 = 44 |
| 482 | const MB_PERMIL: i64 = 1000 |
| 827 | const SM_PUSHED: i64 = 0 |
| 828 | const SM_ALREADY: i64 = 1 |
| 829 | const SM_WOULD: i64 = 2 |
| 830 | const SM_TRANSPORT: i64 = 3 |
| 831 | const SM_REFUSED: i64 = 4 |
| 832 | const SM_UNMARKED: i64 = 5 |
| 833 | const SM_RECOVERED: i64 = 6 |
| 834 | const SM_DEFERRED: i64 = 7 |
functions
| 83 | func mb_slot(base: *u8, k: i64) -> *u8 { return ((base as i64) + k * MB_SLOT) as *u8 } |
| 84 | func mb_famslot(base: *u8, k: i64) -> *u8 { return ((base as i64) + k * MB_FAM_CAP) as *u8 } |
| 86 | func mb_copy(dst: *u8, src: *u8, cap: i64) -> i64 called by 1: mb_fam_index |
| 97 | func mb_ends_with(name: *u8, ext: *u8) -> i64 |
| 106 | func mb_atoi(s: *u8) -> i64 called by 1: main |
| 118 | func mb_find(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 called by 9: mb_int_aftermb_depth1_findmb_scan_filemb_residue_contentmb_residue_linemb_marked+3 calls 1: mp_len |
| 138 | func mb_rfind(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 |
| 158 | func mb_int_at(buf: *u8, i0: i64, e: i64) -> i64 |
| 177 | func mb_int_after(buf: *u8, s: i64, e: i64, key: *u8) -> i64 |
| 184 | func mb_days_from_civil(y0: i64, m: i64, d: i64) -> i64 called by 1: mb_key_daynum |
| 197 | func mb_daykey_at(buf: *u8, i: i64, e: i64) -> i64 |
| 212 | func mb_key_daynum(key: i64) -> i64 |
| 220 | func mb_cat_key(out: *u8, off: i64, key: i64) -> i64 |
| 234 | func mb_mtime(path: *u8) -> i64 |
| 271 | func mb_day_index(keys: *i64, ctr: *i64, key: i64) -> i64 called by 1: mb_scan_file |
| 285 | func mb_depth1_find(buf: *u8, s: i64, e: i64, key: *u8) -> i64 called by 5: mb_scan_filemb_strlen_ofmb_objlen_ofmb_residue_contentmb_residue_line calls 2: mp_lenmb_find |
| 312 | func mb_fam_index(fams: *u8, ctr: *i64, buf: *u8, p: i64, e: i64) -> i64 |
| 342 | func mb_scan_file(path: *u8, keys: *i64, fams: *u8, msgs: *i64, outt: *i64, cread: *i64, ccre: *i64, files: *i64, |
| 485 | func mb_str_end(buf: *u8, s: i64, e: i64) -> i64 |
| 494 | func mb_skip_value(buf: *u8, s: i64, e: i64) -> i64 |
| 524 | func mb_strlen_of(buf: *u8, s: i64, e: i64, key: *u8) -> i64 |
| 531 | func mb_objlen_of(buf: *u8, s: i64, e: i64, key: *u8) -> i64 |
| 538 | func mb_residue_content(buf: *u8, a: i64, e: i64, isasst: i64, acc: *i64) -> i64 called by 1: mb_residue_line calls 7: mb_skip_valuemb_depth1_findmp_lenmb_findmb_strlen_ofmb_objlen_of+1 |
| 574 | func mb_residue_line(buf: *u8, i: i64, e: i64, acc: *i64) -> i64 |
| 594 | func mb_residue_file(path: *u8, name: *u8, ob: *u8, op: *i64, win: *i64) -> i64 |
| 634 | func mb_scan_dir(dir: *u8, min_mtime: i64, keys: *i64, fams: *u8, msgs: *i64, outt: *i64, cread: *i64, ccre: *i64, called by 2: sm_residuemain calls 12: sys_openat_rdsys_mmapsys_getdents64dirent_reclendirent_namemb_ends_with+6 |
| 682 | func mb_marked(mark: *u8, mn: i64, key: i64, fam: *u8) -> i64 |
| 702 | func mb_mark_append(markpath: *u8, key: i64, fam: *u8, now: i64, sess: i64, ov: i64, cr: i64, cc: i64) -> i64 |
| 728 | func mb_push(mcp: *u8, base: *u8, cap: *u8, key: i64, fam: *u8, sess: i64, ov: i64, cr: i64, cc: i64, msgs: i64, resp: *u8) -> i64 |
| 766 | func mb_fetch_meterlog(mcp: *u8, base: *u8, capf: *u8, log: *u8) -> i64 |
| 791 | func mb_remote_has(log: *u8, n: i64, key: i64, fam: *u8) -> i64 |
| 840 | func sm_beat(mcp: *u8, base: *u8, capf: *u8, markpath: *u8, mark: *u8, mn: i64, log: *u8, ln: i64, key: i64, fam: *u8, sess: i64, ov: i64, cr: i64, cc: i64, nmsgs: i64, dry: i64, now: i64, resp: *u8) -> i64 |
| 855 | func mb_usage() -> i64 |
| 863 | func sm_residue(dir: *u8, now: i64, days: i64) -> i64 |
| 907 | func main(argc: i64, argv: *i64) -> i64 |