nx_sitesweep.nx
buildroot/runtime/nx_sitesweep.nx
about
nx_sitesweep.nx -- THE STANDING ANSWER TO "HOW MANY PAGES ON OUR PUBLIC SITE SERVE BROKEN ASSETS?"
WHY THIS EXISTS. nx_page_verify answers that question for ONE page, browser-grade (fetch, extract
every asset ref, refuse a relative ref by law, fetch each asset, deep-decode PNGs). It was BLIND to
unquoted HTML attributes until 2026-08-25; the instant it could see, /world/foundation turned out to
have had 15 images broken in every browser while reporting GREEN-PARTIAL. NOBODY KNEW HOW MANY OTHER
PAGES WERE LIKE THAT, because there was no instrument over the POPULATION -- only over a page a human
happened to name. A RULER WITH NO SWEEP MEASURES WHATEVER SOMEONE REMEMBERED TO POINT IT AT, AND ITS
SILENCE ON EVERYTHING ELSE READS AS HEALTH.
ONE RULER, NEVER TWO. This organ does NOT extract refs, does NOT decode PNGs and does NOT re-state the
relative-ref law. It FORKS nx_page_verify per page and reads its verdict. Every judgement about a page
is that organ's judgement; this organ enumerates, budgets, classifies and reconciles. The two pieces
of judgement it DOES add -- the ref prefilter and the verdict parser -- live in nx_sitesweep_lib.nx,
which its gate imports, so the tested copy and the shipped copy cannot differ.
COVERAGE IS A BUDGET PROBLEM AND THE BUDGET IS DECLARED. The docroot holds tens of thousands of
servable pages (33,243 entries in the generated organ-card tree alone, measured 2026-08-25).
Live-verifying all of them every beat would make this sweep the dominant load source on the box, which
the operator standing order names a BUG, not thoroughness. So: the ENUMERATION is complete every run
(cheap, local), and the LIVE CHECK is a deadline-bounded, cursor-advancing slice that rotates across
beats. That is a DECLARED PREFIX WITH A CURSOR, NOT A SAMPLE -- the run prints how many it examined,
how many it deferred and where the cursor now sits, and corpus_complete drops to 0 the moment
anything is deferred.
THE LEDGER IS THE ANSWER, NOT THE RUN. One row per enumerated page, rewritten whole (TRUNCATE) every
run: this run's slice gets a fresh result, every other page carries its previous row forward with its
own at= epoch so staleness is visible per row. So "how many pages serve broken assets" is answered
from the accumulated ledger, and the partition SUMS to the enumeration by construction.
THE THIRD STATE IS PLUMBED THROUGH. nx_page_verify already separates "I could not reach it"
(UNOBSERVABLE) and "our domain with an unusable registry endpoint" (UNMEASURED) from RED. This organ
keeps them as their own buckets and NEVER folds them into broken. A sweep that convicts a page it
never reached is reporting on its own environment. A ruler run that yields no readable verdict at all
(fork failure, per-page timeout, a capture cut so the tail carrying VERDICT was destroyed) is
UNREADABLE -- also never RED.
usage: nx_sitesweep [root=<subpath>] [deadline=<secs>] [max=<pages>] [cursor=<n>] [probe=1]
root= sweep only docroot/<subpath>. FORCES PROBE: a different population must never write the
beat's ledger or cursor, or the coverage claim silently becomes about a subtree.
dependencies 5 imports · 0 importers
imports: nx_syscalls.nxnx_dir.nxnx_tool_run.nxnx_lineconf_lib.nxnx_sitesweep_lib.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
| 54 | const SS_CONF: *u8 = "knowledge/sitesweep.conf" |
| 55 | const SS_LOG: *u8 = "knowledge/status/sitesweep.log" |
| 56 | const SS_LEDGER: *u8 = "knowledge/status/sitesweep.ledger" |
| 57 | const SS_CURSOR: *u8 = "knowledge/status/sitesweep.cursor" |
| 63 | const SS_LOG_PROBE: *u8 = "knowledge/status/sitesweep.probe.log" |
| 67 | const SS_EXIT_GREEN: i64 = 0 |
| 68 | const SS_EXIT_RED: i64 = 1 |
| 69 | const SS_EXIT_USAGE: i64 = 2 |
| 70 | const SS_EXIT_NOEVIDENCE: i64 = 3 |
| 71 | const SS_EXIT_UNMEASURED: i64 = 4 |
| 77 | const SS_DIR_ENTRIES_CAP: i64 = 65536 |
| 78 | const SS_DIR_NAME_ARENA: i64 = 8388608 |
| 79 | const SS_MAX_PAGES: i64 = 131072 |
| 80 | const SS_MAX_DIRS: i64 = 16384 |
| 81 | const SS_PATH_CAP: i64 = 1024 |
| 82 | const SS_PAGE_ARENA: i64 = 16777216 |
| 83 | const SS_DIR_ARENA: i64 = 4194304 |
| 87 | const SS_CAPTURE_CAP: i64 = 1048576 |
| 88 | const SS_LEDGER_LINE: i64 = 1024 |
| 91 | const SS_LEDGER_ARENA: i64 = 50331648 |
| 92 | const SS_ARGV_MAX: i64 = 64 |
| 93 | const SS_MS_PER_S: i64 = 1000 |
| 94 | const SS_STAT_SLOTS: i64 = 16 |
| 95 | const SS_SEP_BYTES: i64 = 2 |
| 103 | const SS_DEADLINE_DEFAULT_S: i64 = 1440 |
| 104 | const SS_PAGE_TIMEOUT_DEF_MS: i64 = 120000 |
| 105 | const SS_MAX_LIVE_DEFAULT: i64 = 100000 |
| 114 | const SS_K_DOCROOT: *u8 = "docroot" |
| 115 | const SS_K_ORIGIN: *u8 = "origin" |
| 116 | const SS_K_RULER: *u8 = "ruler_elf" |
| 117 | const SS_K_VANTAGE: *u8 = "vantage" |
| 118 | const SS_K_DEADL: *u8 = "deadline_s" |
| 119 | const SS_K_PTMO: *u8 = "page_timeout_ms" |
| 120 | const SS_K_MAXLIVE: *u8 = "max_live" |
| 121 | const SS_K_BEAT: *u8 = "beat_secs" |
| 242 | const SS_LIST_COMMENT: i64 = 35 |
functions
| 123 | func ow(s: *u8) -> i64 { sys_write(1, s, ss_len(s)); return 0 } |
| 124 | func on(v: i64) -> i64 |
| 142 | func ss_verify(ruler: *u8, url: *u8, vantage: *u8, cap_buf: *u8, timeout_ms: i64, outv: *i64) -> i64 |
| 170 | func ss_walk(root: *u8, pg_off: *i64, pg_arena: *u8, st: *i64) -> i64 |
| 253 | func ss_from_list(listpath: *u8, pg_off: *i64, pg_arena: *u8, st: *i64) -> i64 |
| 290 | func main(argc: i64, argv: *i64) -> i64 |