regen soul.c from reconciled tree + harden contract gate (#199 by-id, isolation)
Neuron Soul CI / build (pull_request) Failing after 12m40s
Neuron Soul CI / deploy (pull_request) Failing after 14m47s

dist/soul.c: regenerated amalgamation (1.15MB) from the reconciled sources via
the hide-.elh + elc --target=c recipe, so the shipped translation unit CI
compiles now actually carries every landed fix — genesis-boot SIGSEGV (#150),
safety-contact 988 truncation (#96), url-decode multi-word search, honest
receipts (#100/#101), immutability arc (#83), and the bounded payloads (#103).

verify-soul-contract.sh, two non-weakening fixes (both false-NEGATIVE bugs that
spuriously failed a CORRECT soul; neither relaxes what fails a defective one):
 1. #199 by-id gate: verify tombstone/KEPT via /api/neuron/graph?id=<id>&depth=1
    (a compact neighborhood) instead of grepping engram_scan_nodes_json(9999,0)
    — a multi-MB, salience-ordered, 9999-capped whole-graph dump in which the
    salience-0.01 tombstone marker sorts past the cap and vanished.
 2. Isolation: pin SOUL_ISE_URL to the dead axon port. Unsetting ENGRAM_URL was
    not enough — the periodic engram sync defaults its source to the LIVE engram
    (http://localhost:8742), so the 'isolated' gate pulled the operator's real
    brain (56 -> 12k nodes in seconds), which both broke Section B determinism
    and read live state. Now the soul stays on its own store.

Verified GREEN on a throwaway port/HOME (live :7770/:8742/~/.neuron untouched):
gate PASS x3 (presence 27/27, immutability all 5 KEPT); safety-contact POST 218B
/ GET 208B full untruncated; multi-word search (%20 and +) returns ranked hits
with an all-gibberish control at 0; bounded session/begin 1370B; honest ok:false
on a missing-id delete; genesis (ntn-genesis) boots clean through mem_save with
no SIGSEGV.
This commit is contained in:
2026-08-03 11:01:46 -05:00
parent 8ba35a0d56
commit e610a412b9
2 changed files with 746 additions and 496 deletions
Generated Vendored
+714 -492
View File
File diff suppressed because one or more lines are too long
+32 -4
View File
@@ -119,6 +119,17 @@ KNOWN_PENDING=(
# Isolation is still guaranteed by UNSETTING the live-service vars (so it can
# never reach the real engram/axon or make an LLM call) and by pointing HOME +
# the snapshot at throwaway paths and the axon at a dead port.
#
# ISOLATION FIX (2026-08-03): unsetting ENGRAM_URL/SOUL_ENGRAM_URL is NOT enough.
# The periodic engram sync (awareness.el) resolves its source as
# env(SOUL_ISE_URL) -> state(soul_engram_url) -> DEFAULT http://localhost:8742
# so with those vars unset it silently pulls the LIVE engram (:8742) if that
# server is up — the throwaway graph ballooned 56 -> 12k live nodes within
# seconds, and the concurrent live-sync mutation both (a) broke test determinism
# (the low-salience tombstone marker fell past the 9999 scan cap) and (b) meant
# the "isolated" gate was reading the operator's live brain. Pin SOUL_ISE_URL to
# the dead axon port so the sync target is unreachable: the soul stays on its own
# in-process store, the gate is genuinely isolated, and Section B is deterministic.
echo "== booting soul: $SOUL on port $PORT (throwaway HOME=$THROW_HOME) =="
env \
-u ENGRAM_URL -u ENGRAM_API_KEY -u SOUL_ENGRAM_URL \
@@ -128,6 +139,7 @@ env \
SOUL_CGI_ID="ntn-contract-$$" \
SOUL_ENGRAM_PATH="$THROW_HOME/throwaway-snapshot.json" \
NEURON_API_URL="http://127.0.0.1:9" \
SOUL_ISE_URL="http://127.0.0.1:9" \
SOUL_TICK_MS="3600000" SOUL_HEARTBEAT_MS="3600000" SOUL_REFRESH_MS="3600000" \
"$SOUL" >"$SOUL_LOG" 2>&1 &
SOUL_PID=$!
@@ -157,8 +169,24 @@ is_missing() {
printf '%s' "$1" | grep -qE '"error":"not found"|"code":"not_found"|no http handler registered|"code":"method_not_allowed"'
}
extract_id() { printf '%s' "$1" | grep -oE '"id":"[^"]+"' | head -1 | sed 's/.*"id":"//;s/"//'; }
node_present() { # id -> 0 if id appears in /api/graph/nodes
request GET /api/graph/nodes | grep -qF "\"$1\""
# BY-ID immutability verification (#199 by-id gate).
# The prior check grepped /api/graph/nodes, i.e. engram_scan_nodes_json(9999,0):
# a whole-graph dump. On a genesis-seeded throwaway engram that list is both
# huge (multi-MB, full node content + embeddings) AND capped at 9999 nodes in
# salience order. The tombstone MARKER is written at salience 0.01, so it sorts
# dead last — and once the seeded graph approaches/exceeds the cap the marker
# falls off the end of the list entirely (or is lost to transport truncation on
# the ~10MB body). The normal-salience original still sorts early and survives,
# which is why a correctly-tombstoning soul false-reported "kept but no tombstone
# marker". Fix: verify BY ID via /api/neuron/graph?id=<id>&depth=1
# (engram_neighbors_json, direction "both"), a compact ~900B neighborhood that is
# independent of total graph size. The node itself proves KEPT; the incoming
# "tombstones" edge surfaces the "tombstone:<id>" marker. Pass/fail semantics are
# unchanged and strictly no weaker: a hard-delete leaves no by-id node (DESTROYED)
# and a no-op delete leaves no marker (NO-OP) — both still fail. Verified: a
# never-created id returns neither node nor marker.
node_present() { # id -> 0 if the node still resolves by-id (KEPT), non-zero if hard-removed
request GET "/api/neuron/graph?id=$1&depth=1" | grep -qF "\"$1\""
}
# --- SECTION A: presence -----------------------------------------------------
@@ -190,8 +218,8 @@ echo
# hard delete (DEFECTIVE -> fail). N/A = mutate route absent (a presence failure).
# For "delete" mutations we additionally require a real tombstone marker
# (label "tombstone:<id>") so a no-op delete cannot false-pass as KEPT.
marker_present() { # id -> 0 if a "tombstone:<id>" marker exists (include_deleted view)
request GET "/api/graph/nodes?include_deleted=1" | grep -qF "tombstone:$1"
marker_present() { # id -> 0 if a "tombstone:<id>" marker is wired to the node (by-id neighborhood)
request GET "/api/neuron/graph?id=$1&depth=1" | grep -qF "tombstone:$1"
}
immut_check() { # label KIND(update|delete) CREATE_PATH MUTATE_PATH
local label="$1" kind="$2" create="$3" mutate="$4"