nx_compare_feed_lib.nx
buildroot/runtime/nx_compare_feed_lib.nx
about
nx_compare_feed_lib.nx -- THE COMPARE FEED (ecosystem EC47, 2026-09-16): every /compare board's daily place on the
four-quadrant map and the board rows journaled that day, emitted as ONE RSS 2.0 feed the regenerator publishes at
/compare/feed.xml on the same beat that republishes the pages. Operator (goal, 2026-09-15): "where we are and our
competitors and where we are moving as time goes on daily like the rss feed with more and more expansive reviews".
INPUTS -- all data the estate already writes, nothing typed here:
knowledge/compare/regen.list the boards
knowledge/status/cdmap/<dom>.spine cd|<epoch>|<day>|<player>|<C>|<D>|<breadth-points>|<rows>|<players>|<held>
one row per player per calendar day, written by the FIRST publish of the day
knowledge/compare/<dom>.plan log|<epoch>|<rung>|<kind>|<text> rows, the board's own worked ledger
OUTPUT: one <item> per board per spine day inside the window (CF_WINDOW_DAYS), board-major and newest day first inside a
board; every item carries its own pubDate (the spine row's epoch) so a reader orders them by time. The title carries
Nishi's centrality, distinctiveness and quadrant and the move since the previous spine day; the body lists every
player's position, quadrant and move, then the board rows journaled on that day -- so the review grows with the board.
THE QUADRANT IS THE MAP'S OWN RULE: cd_quadrant over the day's player means (nx_cdmap_lib), never a second cut.
Composes nx_rss_lib (the estate's RSS 2.0 builder), nx_timefmt (civil dates) and nx_cdmap_lib (the quadrant rule).
Pure over the root it is pointed at (root prefix + the relative paths above), so nx_compare_feed_gate drives it on a
fixture root. Every count it decides on is published in st[] (partition: items = distinct in-window (board, day) pairs).
A spine or plan larger than its index is announced as OVERFLOW and read as a prefix, never silently. A body that would
not fit its scratch is announced as SHORT and the board's item is not emitted (a truncated feed is not a feed).
license_tier: ORIGINAL. No hw writes (Rule 26).
dependencies 4 imports · 2 importers
imports: nx_syscalls.nxnx_rss_lib.nxnx_cdmap_lib.nxnx_timefmt.nx
imported by: nx_compare_feed_gate.nxnx_compare_regen.nx
structs
| none |
consts
| 26 | const CF_MAX_ROWS: i64 = 4096 // spine rows indexed per board (16 players x 256 days); beyond = OVERFLOW, prefix read |
| 27 | const CF_MAX_LOG: i64 = 8192 // plan log rows indexed per board; beyond = OVERFLOW, prefix read |
| 28 | const CF_MAX_DAYS: i64 = 512 // distinct spine days a board may carry in the index |
| 29 | const CF_WINDOW_DAYS: i64 = 14 // days of history the feed covers, newest first |
| 30 | const CF_TEXT_MAX: i64 = 480 // bytes of one board row quoted in an item (cut at a UTF-8 boundary, announced with ...) |
| 31 | const CF_DAY_S: i64 = 86400 |
| 32 | const CF_PATH_MAX: i64 = 1024 |
| 33 | const CF_LINE_MAX: i64 = 4096 // scratch for a title, a link, a guid or one list line |
| 34 | const CF_BODY_BASE: i64 = 65536 // body scratch base; grown by the rows a board can quote |
| 35 | const CF_ROW_QUOTE: i64 = 640 // scratch per quoted row: CF_TEXT_MAX escaped (worst case x6 for '&') is bounded by this x6 below |
| 36 | const CF_ESC_X: i64 = 6 // worst-case expansion of html escaping ('&' -> '&') |
| 37 | const CF_OUT_START: i64 = 262144 // the growable output's first capacity; doubled as needed, never a cap |
| 38 | const CF_OUT_HEAD: i64 = 8192 // headroom kept for the channel open and close |
| 39 | const CF_ST_SLOTS: i64 = 10 |
| 40 | const CF_ST_DOMAINS: i64 = 0 |
| 41 | const CF_ST_SPINES: i64 = 1 |
| 42 | const CF_ST_ITEMS: i64 = 2 |
| 43 | const CF_ST_ROWS: i64 = 3 |
| 44 | const CF_ST_MALFORMED: i64 = 4 |
| 45 | const CF_ST_OVERFLOW: i64 = 5 |
| 46 | const CF_ST_BYTES: i64 = 6 |
| 47 | const CF_ST_SHORT: i64 = 7 |
| 48 | const CF_ST_NEWEST: i64 = 8 |
| 49 | const CF_ST_WINDOW: i64 = 9 |
| 50 | const CF_ROW_W: i64 = 8 |
| 51 | const CF_R_EPOCH: i64 = 0 |
| 52 | const CF_R_DAY: i64 = 1 |
| 53 | const CF_R_NOFF: i64 = 2 |
| 54 | const CF_R_NLEN: i64 = 3 |
| 55 | const CF_R_C: i64 = 4 |
| 56 | const CF_R_D: i64 = 5 |
| 57 | const CF_R_HELD: i64 = 6 |
| 58 | const CF_LOG_W: i64 = 4 |
| 59 | const CF_L_EPOCH: i64 = 0 |
| 60 | const CF_L_DAY: i64 = 1 |
| 61 | const CF_L_OFF: i64 = 2 |
| 62 | const CF_L_LEN: i64 = 3 |
| 63 | const CF_PIPE: i64 = 124 |
| 64 | const CF_LF: i64 = 10 |
| 65 | const CF_HASHB: i64 = 35 |
| 66 | const CF_DOT: i64 = 46 |
| 67 | const CF_ZERO: i64 = 48 |
| 68 | const CF_NINE: i64 = 57 |
| 69 | const CF_MINUS: i64 = 45 |
| 70 | const CF_UTF8_CONT_LO: i64 = 128 // a UTF-8 continuation byte is 10xxxxxx: 128..191 (tested arithmetically, no bitwise op) |
| 71 | const CF_UTF8_CONT_HI: i64 = 192 |
| 72 | const CF_FEED_TITLE: *u8 = "Nishi /compare -- daily positions and reviews" as *u8 |
| 73 | const CF_FEED_LINK: *u8 = "https://nishifamily.com/compare/" as *u8 |
| 74 | const CF_FEED_DESC: *u8 = "Every /compare board's place on the four-quadrant centrality-distinctiveness map, its move since the previous day, and the board rows journaled that day. Emitted by nx_compare_regen on the compare beat; positions are measured from the boards, never typed." as *u8 |
| 75 | const CF_GUID_SEP: *u8 = "cd-" as *u8 // written after a CF_HASHB byte: the lexer keeps that byte out of literals |
| 76 | const CF_SPINE_DIR: *u8 = "knowledge/status/cdmap/" as *u8 |
| 77 | const CF_SPINE_EXT: *u8 = ".spine" as *u8 |
| 78 | const CF_PLAN_DIR: *u8 = "knowledge/compare/" as *u8 |
| 79 | const CF_PLAN_EXT: *u8 = ".plan" as *u8 |
| 80 | const CF_LIST_PATH: *u8 = "knowledge/compare/regen.list" as *u8 |
| 81 | const CF_NISHI: *u8 = "Nishi" as *u8 |
| 82 | const CF_ROW_TAG: *u8 = "cd|" as *u8 |
| 83 | const CF_LOG_TAG: *u8 = "log|" as *u8 |
| 84 | const CF_SPINE_F_EPOCH: i64 = 1 |
| 85 | const CF_SPINE_F_DAY: i64 = 2 |
| 86 | const CF_SPINE_F_NAME: i64 = 3 |
| 87 | const CF_SPINE_F_C: i64 = 4 |
| 88 | const CF_SPINE_F_D: i64 = 5 |
| 89 | const CF_SPINE_F_HELD: i64 = 9 |
| 90 | const CF_LOG_F_EPOCH: i64 = 1 |
| 91 | const CF_LOG_F_RUNG: i64 = 2 |
| 92 | const CF_LOG_F_KIND: i64 = 3 |
| 93 | const CF_LOG_F_TEXT: i64 = 4 |
functions
| 95 | func cf_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 96 | func cf_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } |
| 97 | func cf_catb(d: *u8, o: i64, s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { d[o + i] = s[i]; i = i + 1 } return o + n } |
| 98 | func cf_catn(d: *u8, o: i64, v: i64) -> i64 |
| 112 | func cf_catsigned(d: *u8, o: i64, v: i64) -> i64 |
| 118 | func cf_date(d: *u8, o: i64, day: i64) -> i64 |
| 133 | func cf_atoi(buf: *u8, off: i64, end: i64) -> i64 |
| 151 | func cf_field(buf: *u8, start: i64, end: i64, k: i64, out2: *i64) -> i64 |
| 167 | func cf_starts(buf: *u8, off: i64, end: i64, tag: *u8) -> i64 |
| 172 | func cf_name_eq(buf: *u8, off: i64, n: i64, s: *u8) -> i64 |
| 178 | func cf_names_eq(a: *u8, ao: i64, an: i64, b: *u8, bo: i64, bn: i64) -> i64 |
| 185 | func cf_eol(buf: *u8, n: i64, i: i64) -> i64 |
| 191 | func cf_path(dst: *u8, root: *u8, dir: *u8, dom: *u8, domlen: i64, ext: *u8) -> i64 |
| 200 | func cf_load_spine(buf: *u8, n: i64, rows: *i64, cap: i64, st: *i64) -> i64 |
| 241 | func cf_load_log(buf: *u8, n: i64, idx: *i64, cap: i64, st: *i64) -> i64 |
| 264 | func cf_row_of(buf: *u8, rows: *i64, nr: i64, day: i64, noff: i64, nlen: i64) -> i64 |
| 274 | func cf_quote_text(body: *u8, bcap: i64, bo: i64, buf: *u8, off: i64, len: i64) -> i64 |
| 293 | func cf_board(root: *u8, dom: *u8, domlen: i64, today: i64, outp: *i64, ocap: *i64, olen: i64, st: *i64) -> i64 |
| 499 | func cf_build(root: *u8, listpath: *u8, today: i64, st: *i64, outp: *i64) -> i64 |