code wiki / _hdl_build / nx_seat_meter_beat.nx

nx_seat_meter_beat.nx

buildroot/runtime/_hdl_build/nx_seat_meter_beat.nx

56340 B1109 linesdepth 5pulls 6 transitivereach 0 importersview sourcekind tooltopic seat
docsdependenciesstructsconstsfunctions

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

nx_syscalls.nx nx_memplane_lib.nx nx_tool_run.nx nx_seat_meter_beat.nx

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

main sys_exit mb_usage mp_write_all sys_write mp_len mp_streq sys_mmap nxa_die sys_write ↻ sys_exit ↻ nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sys_read_file sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_munmap sys_close mp_write_all ↻ mp_len ↻ mb_daykey_at mb_int_at mb_remote_has sys_mmap ↻ mp_cat mb_cat_key mp_catn sys_mmap ↻ mb_find

structs

none

consts

39const MB_DAYS_DEFAULT: i64 = 3 // a hook run owes yesterday and the day before; older days were owed earlier
40const MB_DAYS_MAX: i64 = 400 // distinct days one run can hold; reaching it announces days_floor=1
41const MB_FAM_MAX: i64 = 8 // model families per run (fable, opus, sonnet, haiku, ...)
42const MB_FAM_CAP: i64 = 32 // one family token cell
43const MB_SLOT: i64 = 256 // one transcript name cell (names measured 42 B)
44const MB_FILES_MAX: i64 = 4096 // 220 transcripts on 2026-09-02; reaching the cap announces files_floor=1
45const MB_PATH: i64 = 4096 // PATH_MAX
46const MB_DENTBUF: i64 = 262144 // getdents64 batch buffer, LOOPED to completion
47const MB_STATBUF: i64 = 256 // struct stat is 144 B on x86_64
48const MB_STAT_MTIME_SLOT: i64 = 11 // st_mtim.tv_sec at byte 88 = i64[11]
49const MB_DOT: i64 = 46
50const MB_QUOTE: i64 = 34
51const MB_NL: i64 = 10
52const MB_DASH: i64 = 45
53const MB_ID_CAP: i64 = 64 // msg_ ids measured 30 B
54const MB_ID_RING: i64 = 8 // blocks of one message are consecutive; a ring of 8 absorbs interleaving
55const MB_OUT: i64 = 262144 // report buffer (400 days x 8 families x ~120 B fits 4x over)
56const MB_DAY_LEN: i64 = 10 // YYYY-MM-DD
57const MB_SEC_PER_DAY: i64 = 86400
58const MB_EXIT_OK: i64 = 0
59const MB_EXIT_RED: i64 = 1
60const MB_EXIT_USAGE: i64 = 2
61const MB_EXIT_UNOBS: i64 = 3
62const MB_FORK_TIMEOUT_MS: i64 = 60000 // the estate appends one row; 60 s covers a saturated box
63const MB_RESP_CAP: i64 = 65536
64const MB_READ_SLACK: i64 = 16 // sys_read_file maps size+16; released with the same arithmetic
65const MB_MARK_CAP: i64 = 1048576 // marker file window; 400 days x 8 families x ~64 B is 200 KB
66const MB_ARGV_MAX: i64 = 8
67const MB_FRAG_CAP: i64 = 1024
68const MB_NOTE_CAP: i64 = 256
69const MB_DIGITS_MAX: i64 = 18 // an i64 holds 18 full decimal digits; longer runs are malformed
70const MB_HINNANT_OFFSET: i64 = 719468 // days_from_civil: 1970-01-01 is day 719468 of the proleptic era count
71const MB_ERA_DAYS: i64 = 146097
72const MB_ERA_YEARS: i64 = 400
73const MB_DOY_MUL: i64 = 153
74const MB_DOY_ADD: i64 = 2
75const MB_DOY_DIV: i64 = 5
76const MB_YEAR_DAYS: i64 = 365
77const MB_KEY_YEAR_MUL: i64 = 10000 // day key = y*10000 + m*100 + d, printable back with dashes
78const MB_KEY_MON_MUL: i64 = 100
79const MB_CELLS: i64 = 3200 // MB_DAYS_MAX * MB_FAM_MAX
80const MB_I64: i64 = 8
248const MB_C_FILES: i64 = 0
249const MB_C_READ: i64 = 1
250const MB_C_SKIPPED: i64 = 2
251const MB_C_LINES: i64 = 3
252const MB_C_ASSIST: i64 = 4
253const MB_C_MSGS: i64 = 5
254const MB_C_DUP: i64 = 6
255const MB_C_MALFORMED: i64 = 7
256const MB_C_PARTIAL: i64 = 8
257const MB_C_DAYS: i64 = 9
258const MB_C_FAMS: i64 = 10
259const MB_C_DAYSFLOOR: i64 = 11
260const MB_C_FILESFLOOR: i64 = 12
261const MB_C_STATFAIL: i64 = 13
262const MB_C_OUTSIDE: i64 = 14
263const MB_C_SYNTH: i64 = 15 // harness-written API-error lines: model "<synthetic>", no msg_ id, nothing to meter
264const MB_C_RECOVERED: i64 = 16 // rows the estate log already held that the local marker had lost (a dropped receipt)
265const MB_C_DEFERRED: i64 = 17 // rows NOT pushed because the estate log could not be read first
266const MB_C_SLOTS: i64 = 24
267const MB_LOG_CAP: i64 = 262144 // one meterlog fetch: 400 rows x ~120 B escaped fits 5x over
268const MB_LOG_ROWS: *u8 = "400" // tail rows to read back; 40 days x 2 families x 2 retries is 160
269const 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
470const MB_R_REASON: i64 = 0
471const MB_R_AUTHORED: i64 = 1
472const MB_R_MECH: i64 = 2
473const MB_R_PROMPT: i64 = 3
474const MB_R_OTHER: i64 = 4
475const MB_R_LINES: i64 = 5
476const MB_R_SLOTS: i64 = 8
477const MB_LBRACE: i64 = 123
478const MB_RBRACE: i64 = 125
479const MB_LBRACK: i64 = 91
480const MB_RBRACK: i64 = 93
481const MB_COMMA: i64 = 44
482const MB_PERMIL: i64 = 1000
827const SM_PUSHED: i64 = 0
828const SM_ALREADY: i64 = 1
829const SM_WOULD: i64 = 2
830const SM_TRANSPORT: i64 = 3
831const SM_REFUSED: i64 = 4
832const SM_UNMARKED: i64 = 5
833const SM_RECOVERED: i64 = 6
834const SM_DEFERRED: i64 = 7

functions

83func mb_slot(base: *u8, k: i64) -> *u8 { return ((base as i64) + k * MB_SLOT) as *u8 }
84func mb_famslot(base: *u8, k: i64) -> *u8 { return ((base as i64) + k * MB_FAM_CAP) as *u8 }
called by 2: mb_fam_indexmain
86func mb_copy(dst: *u8, src: *u8, cap: i64) -> i64
called by 1: mb_fam_index
97func mb_ends_with(name: *u8, ext: *u8) -> i64
called by 1: mb_scan_dir calls 1: mp_len
106func mb_atoi(s: *u8) -> i64
called by 1: main
118func mb_find(buf: *u8, s: i64, e: i64, lit: *u8) -> i64
138func mb_rfind(buf: *u8, s: i64, e: i64, lit: *u8) -> i64
158func mb_int_at(buf: *u8, i0: i64, e: i64) -> i64
177func mb_int_after(buf: *u8, s: i64, e: i64, key: *u8) -> i64
called by 1: mb_scan_file calls 3: mb_findmb_int_atmp_len
184func mb_days_from_civil(y0: i64, m: i64, d: i64) -> i64
called by 1: mb_key_daynum
197func mb_daykey_at(buf: *u8, i: i64, e: i64) -> i64
called by 2: mb_scan_filemain calls 1: mb_int_at
212func mb_key_daynum(key: i64) -> i64
called by 1: mb_scan_file calls 1: mb_days_from_civil
220func mb_cat_key(out: *u8, off: i64, key: i64) -> i64
234func mb_mtime(path: *u8) -> i64
271func mb_day_index(keys: *i64, ctr: *i64, key: i64) -> i64
called by 1: mb_scan_file
285func mb_depth1_find(buf: *u8, s: i64, e: i64, key: *u8) -> i64
312func mb_fam_index(fams: *u8, ctr: *i64, buf: *u8, p: i64, e: i64) -> i64
342func mb_scan_file(path: *u8, keys: *i64, fams: *u8, msgs: *i64, outt: *i64, cread: *i64, ccre: *i64, files: *i64,
485func mb_str_end(buf: *u8, s: i64, e: i64) -> i64
494func mb_skip_value(buf: *u8, s: i64, e: i64) -> i64
524func mb_strlen_of(buf: *u8, s: i64, e: i64, key: *u8) -> i64
531func mb_objlen_of(buf: *u8, s: i64, e: i64, key: *u8) -> i64
538func mb_residue_content(buf: *u8, a: i64, e: i64, isasst: i64, acc: *i64) -> i64
574func mb_residue_line(buf: *u8, i: i64, e: i64, acc: *i64) -> i64
594func mb_residue_file(path: *u8, name: *u8, ob: *u8, op: *i64, win: *i64) -> i64
634func mb_scan_dir(dir: *u8, min_mtime: i64, keys: *i64, fams: *u8, msgs: *i64, outt: *i64, cread: *i64, ccre: *i64,
682func mb_marked(mark: *u8, mn: i64, key: i64, fam: *u8) -> i64
702func mb_mark_append(markpath: *u8, key: i64, fam: *u8, now: i64, sess: i64, ov: i64, cr: i64, cc: i64) -> i64
728func 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
766func mb_fetch_meterlog(mcp: *u8, base: *u8, capf: *u8, log: *u8) -> i64
791func mb_remote_has(log: *u8, n: i64, key: i64, fam: *u8) -> i64
840func 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
855func mb_usage() -> i64
called by 1: main calls 2: mp_write_allmp_len
863func sm_residue(dir: *u8, now: i64, days: i64) -> i64
907func main(argc: i64, argv: *i64) -> i64