{"record":{"id":"2ae31f694eb21d63","repo":"ruvnet/RuView","slug":"brain-corpus-exceeds-1-mib","errorCode":null,"errorMessage":"brain corpus exceeds 1 MiB","messagePattern":"brain corpus exceeds 1 MiB","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"harness/homecore/src/brain.js","lineNumber":73,"sourceCode":"    if (!/^[a-f0-9]{64}$/.test(record.source?.digest || '')) {\n      errors.push('source.digest must be a lowercase SHA-256 digest');\n    }\n  }\n  if (!Array.isArray(record.tags) || record.tags.some((tag) => typeof tag !== 'string')) {\n    errors.push('tags must be strings');\n  }\n  if ((record.content || '').length > 8192) errors.push('content exceeds 8192 characters');\n  if ((record.title || '').length > 200) errors.push('title exceeds 200 characters');\n  if (canonical && record.reviewed !== true) errors.push('canonical records must be reviewed');\n  const combined = `${record.title || ''}\\n${record.content || ''}`;\n  if (SECRET.test(combined)) errors.push('record appears to contain a secret');\n  if (INJECTION.test(combined)) errors.push('record contains instruction-like prompt injection');\n  return errors;\n}\n\nexport function loadBrain(path = CORPUS_PATH) {\n  const raw = readFileSync(path, 'utf8').replace(/\\r\\n/g, '\\n');\n  if (Buffer.byteLength(raw) > 1_048_576) throw new Error('brain corpus exceeds 1 MiB');\n  const records = raw.split('\\n').filter(Boolean).map((line, index) => {\n    if (Buffer.byteLength(line) > 16_384) {\n      throw new Error(`brain line ${index + 1}: exceeds 16 KiB`);\n    }\n    let record;\n    try {\n      record = JSON.parse(line);\n    } catch (error) {\n      throw new Error(`brain line ${index + 1}: ${error.message}`);\n    }\n    const errors = validateBrainRecord(record, { canonical: true });\n    if (errors.length) throw new Error(`brain line ${index + 1}: ${errors.join('; ')}`);\n    return Object.freeze(record);\n  });\n  if (records.length > 1000) throw new Error('brain corpus exceeds 1000 records');\n  const ids = new Set();\n  for (const record of records) {\n    if (ids.has(record.id)) throw new Error(`duplicate brain id: ${record.id}`);","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/harness/homecore/src/brain.js#L55-L91","documentation":"This is the firmware/privshield copy of the same daemon (byte-identical to wifi-veil/firmware/openwrt/veil_shieldd.c); the error is the event loop at lines 284-290 logging a negative return from nl_recvmsgs_default(). That libnl3 call receives and parses generic-netlink traffic on the nl80211 'mlme' group and runs the NL_CB_VALID callback veil_event_cb; any failure inside recv, parse, or callback dispatch yields a -NLE_* code. The loop whitelists only -NLE_AGAIN, so every other error (notably -NLE_INTR on signal shutdown, -NLE_SEQ_MISMATCH, -NLE_PARSE_ERR, -NLE_BAD_SOCK) aborts the daemon. Logging the raw integer and then returning exit status 0 hides both the cause and the failure from supervisors.","triggerScenarios":"Concrete producers on this code path: (1) SIGINT/SIGTERM during the blocking receive - the handler sets g_ctx.running=0 but recvmsg returns EINTR, mapped by libnl to -NLE_INTR, which the loop treats as fatal and logs; (2) veil_event_cb returning negative after failing to parse an mlme notification - callback errors are propagated by nl_recvmsgs_default; (3) kernel ENOBUFS when mlme multicast bursts exceed the default rcvbuf, killing the loop mid-run; (4) -NLE_BAD_SOCK when the socket was closed/freed elsewhere or used from a second thread; (5) -NLE_SEQ_MISMATCH if this duplicated file drifts from the original and loses nl_socket_disable_seq_check() at line 268, which multicast events require; (6) an error ACK left on the socket by the veil_set_tx_antenna_mask() path when the driver rejects NL80211_CMD_SET_WIPHY.","commonSituations":"This duplicate lives in firmware/privshield/openwrt while the original sits in wifi-veil/firmware/openwrt - the classic vendored-copy failure is the two files diverging (one gets a fix, the other keeps the bug), so always patch both; running the scaffold (self-declared SYNTHETIC/L0, untested on silicon) against a real AP's mlme group; Ctrl-C or procd stop producing a scary error line on an otherwise clean shutdown; older OpenWrt libnl3 builds mapping unexpected errnos to -NLE_FAILURE, leaving the logged number ambiguous.","solutions":["Decode the logged integer with the libnl3 NLE_* table (1=FAILURE, 2=INTR, 3=BAD_SOCK, 5=MSGSIZE, 14=SEQ_MISMATCH, 15=DUMP_INTR, 16=PARSE_ERR, 18=NOMEM) or switch the fprintf to nl_geterror(r) so the string name appears in the log.","If it fires at shutdown (-NLE_INTR after SIGINT/SIGTERM), add -NLE_INTR to the tolerated codes or test g_ctx.running before breaking - it is not a real fault.","Verify veil_event_cb returns only NL_OK/NL_SKIP and never a negative errno; guard every nla_find/nla_parse result before dereferencing.","Confirm nl_socket_disable_seq_check(g_ctx.sock) (line 268) is still present in this copy - it is mandatory once the mlme multicast membership at line 86-89 is active.","For ENOBUFS under event storms, call nl_socket_set_buffer_size(g_ctx.sock, 1<<20, 1<<20) before entering the loop, and confirm with strace.","Keep all libnl use of g_ctx.sock on one thread; no other code path may nl_socket_free or recv on it.","Change the tail to return non-zero when the loop exited while still running, so init scripts detect and restart the daemon; apply any fix to BOTH veil_shieldd.c copies (wifi-veil and privshield)."],"exampleFix":"// before (firmware/privshield/openwrt/veil_shieldd.c:284-293)\nwhile (g_ctx.running) {\n    int r = nl_recvmsgs_default(g_ctx.sock);\n    if (r < 0 && r != -NLE_AGAIN) {\n        fprintf(stderr, \"veil: nl_recvmsgs_default: %d\\n\", r);\n        break;\n    }\n}\nnl_socket_free(g_ctx.sock);\nreturn 0;\n\n// after\nwhile (g_ctx.running) {\n    int r = nl_recvmsgs_default(g_ctx.sock);\n    if (r < 0 && r != -NLE_AGAIN && r != -NLE_INTR) {\n        fprintf(stderr, \"veil: nl_recvmsgs_default: %d (%s)\\n\",\n                r, nl_geterror(r));\n        break;\n    }\n}\nnl_socket_free(g_ctx.sock);\nreturn g_ctx.running ? 1 : 0; /* supervisors see the failure */","handlingStrategy":"try-catch","validationCode":"/* Before the loop: cheap invariants that prevent the common fatal codes */\nif (nl_socket_get_fd(g_ctx.sock) < 0) return 1;               /* -NLE_BAD_SOCK */\nif (g_ctx.family < 0)             return 1;                   /* nl80211 unresolved */\nnl_socket_set_buffer_size(g_ctx.sock, 1 << 20, 1 << 20);      /* ENOBUFS on mlme */\n/* line 268 must remain: nl_socket_disable_seq_check(g_ctx.sock); */","typeGuard":"/* C predicate: which receive errors are safe to survive */\nstatic int nl_recv_transient(int r) {\n    return r == -NLE_AGAIN || r == -NLE_INTR || r == -NLE_DUMP_INTR;\n}","tryCatchPattern":"/* Wrap each receive in an explicit error branch; classify before acting */\nint r = nl_recvmsgs_default(g_ctx.sock);\nif (r < 0) {\n    if (nl_recv_transient(r)) continue;                /* benign: next iteration */\n    fprintf(stderr, \"veil: nl_recvmsgs_default: %s\\n\", nl_geterror(r));\n    exit_code = 1;                                     /* do not mask as 0 */\n    break;\n}","preventionTips":["Print nl_geterror(r), not just %d - the raw negative number is undebuggable on-target.","Treat -NLE_INTR as expected on SIGINT/SIGTERM shutdown instead of a fatal event.","Re-check this vendored copy after any change to the wifi-veil original: diff the two veil_shieldd.c files so one does not silently lose seq-check-disable or buffer sizing fixes.","Keep veil_event_cb defensive: validate NLA lengths, return NL_SKIP for unrecognized mlme commands.","Enlarge rcvbuf before subscribing to multicast groups; default buffers overflow during association storms.","Return a non-zero exit status when the loop exits with g_ctx.running still set, so the OpenWrt init system restarts the daemon."],"tags":["libnl","netlink","nl80211","c","openwrt","privshield","duplicate-code"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}