Commit Graph

84 Commits

Author SHA1 Message Date
will.anderson 8ba35a0d56 reconcile: merge Will's self-review WIP (456267a) into main
Union of all ship-critical soul fixes for the Mac beta:
- Keeps main's honest receipts (#100/#101), immutability arc + #199 by-id
  gate (#83), Track B threat routing (#76), bounded beginSession (#103),
  CI hardening (#85/#86), elc typo hotfix (#77), neuron-dev-setup (#84).
- Brings WIP's genesis-boot SIGSEGV fix (#150/#95), safety-contact 988
  truncation fix (#96), bounded-persona floor (#93), and 10 self-review
  commits (importance flattening, curiosity DF gating, WM/heartbeat
  observability, boot-counter telemetry).
- Folds the multi-word ranked-search fix: api_query_param now url_decode()s
  the extracted value so q=foo%20bar / foo+bar tokenize as two words.

Conflicts (neuron-api.el payload-bound comments, mcp-wrapper tool_forget)
resolved toward the correct end state: main's verified honest-receipt
read-back is kept; WIP's improved forget description is kept. Generated
dist/*.c taken from main and will be regenerated from this reconciled
source in the following commit.
2026-08-03 10:35:01 -05:00
will.anderson 9bbb4f2af8 Bound beginSession/compileCtx payloads to a compact digest
Neuron Soul CI / build (pull_request) Successful in 4m19s
Neuron Soul CI / deploy (pull_request) Has been skipped
Port the payload-bounding fix (PR #102, commit 872120c) onto main. The
session-init endpoints projected unbounded engram nodes (~900KB), closing
the MCP client socket on every beginSession. Cap the lists (8 activated /
10 recent for begin_session, 10/20 for compile_ctx) and project each node
to a light identity + a bounded, UTF-8-safe content snippet via
api_compact_node / api_compact_activated / api_utf8_trunc. Response drops
~900KB -> ~12KB; full content stays available via recall/fetch/inspectGraph.

Regenerate dist/soul.c (the CI-built amalgamation) and dist/neuron-api.c
from source. The soul.c regen also compiles in already-merged source the
previously-committed soul.c was stale against (agent write/edit receipt
fixes, #100/#101); verified via scripts/verify-soul-contract.sh
(PRESENCE + IMMUTABILITY PASS) and a clean CI-style cc build.
2026-08-01 11:37:04 -05:00
will.anderson 456267a771 self-review 2026-08-01: fix importance flattening in remember/evolve/cultivate paths
Four sites passed the Float local 'sal' through el_from_float() a second
time. el_val_t is the bit-pattern of the double, so re-wrapping performs
an int64->double VALUE conversion of the bits before re-bitcasting —
garbage that fails engram_decode_score's range check and clamps to
defaults. Net effect: importance="critical" stored 0.5/0.5 — importance
levels were cosmetic on the MCP memory path. Verified fixed live:
critical now stores salience/importance 0.95/0.95. Same bug fixed today
in engram server.el route_create_node (foundation/el 7f03876). Literal
wraps (el_from_float(0.9)) are safe — elc passes numeric literals raw.
2026-08-01 08:42:44 -05:00
will.anderson edb0670670 self-review 2026-08-01: emit discrete wm_saturation_transition ISE
wm_saturated was a sampled boolean — the 0->1 onset and 1->0 release
moments were only recoverable by hand-diffing consecutive heartbeats.
Emit a low-rate transition ISE at each edge carrying the WM top-5 at
that instant, so the composition that caused the regime change is
captured rather than the composition up to 59s later. First beat of a
boot never fires (restart is not a transition).
2026-08-01 08:38:53 -05:00
will.anderson 872120c757 Bound beginSession/compileCtx payloads to a compact digest
The session-init endpoints concatenated unbounded engram activate/scan
results as FULL node objects (content up to ~90KB per node), producing a
~900KB response. After the MCP wrapper re-escapes that into a stringified
text block the client dropped the socket ('connection closed unexpectedly')
on every beginSession call. Cap each list (8-10 activated, 10-20 recent)
and project every node to a light identity plus a bounded, UTF-8-safe
content snippet. Response drops from ~900KB to ~12KB; full content stays
available on demand via recall/fetch/inspectGraph.
2026-07-31 14:59:09 -05:00
will.anderson f3660e92a1 self-review 2026-07-31: heartbeat deltas for cumulative counters, embed_eligible; fix stale semantic-seeding comment
Runtime activation counters are now cumulative, so the heartbeat emits
wm_evicted/breakthroughs as totals plus wm_evicted_delta/
breakthroughs_delta (state-tracked change since the previous beat) —
events between beats are no longer lost. Adds embed_eligible from
/api/stats so coverage reads as embed_count/embed_eligible instead of
the misleading absolute count, and surfaces auto_term_streak in the
heartbeat stream. Replaces the false 'semantic seeding NOT implemented'
comment: engram_activate embeds the query, seeds semantic top-K, gates
propagation on cosine, and scores WM promotion semantically.
2026-07-31 08:41:41 -05:00
will.anderson b0f4d6c493 self-review 2026-07-30: auto_term stopword filter, real idle_ms, bounded beginSession
- awareness.el: curiosity auto_term was the raw first word of a WM
  label with no term-quality scoring — observed seeds included What,
  Colon, Prose, Context. Replaced the 7-word genre blocklist whack-a-
  mole with a delimited stopword membership test (function words +
  document-structure words); topical terms pass untouched. Verified
  live: seeds now ReasonEdit, Reasoning-model, Self-review.
- routes.el + awareness.el: idle counter only reset on rare inbox
  synthesis-requests, so idle==pulse always (zero information).
  handle_request now stamps soul.last_activity_ts on every inbound
  HTTP request; heartbeat emits idle_ms = ms since last request
  (-1 until first request of a boot).
- neuron-api.el: beginSession concatenated a depth-2 spread plus the
  unbounded self-hub neighbor dump — multi-MB response, doubled by
  wrapper re-escaping, socket died on every call. Now depth-1 and
  the hub dump dropped (identity loading has its own tool). Verified:
  beginSession returns instead of closing the socket.
2026-07-30 08:45:21 -05:00
will.anderson 627eb534a2 self-review 2026-07-28: close ISE lifecycle observability gaps
- session_start now also posted to the HTTP Engram via ise_post: the
  local engram_node_full write never crossed to the observable stream
  (sync flows HTTP->soul only), so boots 5+ were invisible — last
  visible session_start was boot 4, two weeks ago
- graceful shutdown emits a final ISE with boot/pulse/uptime; a boot
  with no shutdown event now reliably signals a crash/SIGKILL
- empty /api/sync responses emit a sync_empty warn ISE instead of
  being silently skipped — unreachable engram no longer looks
  identical to quiet-but-healthy
- sync backflow prune reads ENGRAM_ISE_RETENTION_MS instead of
  duplicating the 48h magic number server.el already honors
2026-07-28 08:37:39 -05:00
will.anderson 2b612ed5d4 self-review 2026-07-27: heartbeat carries activation observability
Fold engram_act_stats_json() into the heartbeat ISE: wm_evicted and
breakthroughs (per curiosity-scan activate call) plus embed_breaker_open —
the failure mode embed_ok structurally cannot see (it pings the Ollama
root, not the embed pipeline). WM-cap eviction, breakthrough-floor
flooding, and silent lexical degradation are now one-glance diagnosable
from telemetry.
2026-07-27 08:38:54 -05:00
will.anderson 8392f44c45 self-review 2026-07-26: heartbeat wm_churn + wm_top0_wm; fix streak counting on empty id
- wm_churn: count of top-5 WM ids absent from previous beat — separates
  'one stuck node' from 'whole WM frozen' without hand-correlating ISEs.
- wm_top0_wm: leader's weight; a frozen anchor reads as a constant here.
- Streak guard: before the runtime emitted id in wm_top JSON,
  json_get(...,"id") was always empty and the streak incremented on
  ""=="" every beat — wm_top0_streak measured uptime, not fixation.
  Empty id now resets the streak to 0.
2026-07-26 08:40:56 -05:00
will.anderson 58a9eda311 self-review 2026-07-25: break curiosity positive-feedback loop; observability for WM regime
proactive_curiosity strengthened its top result unconditionally every
scan — a positive-feedback fixed point that pinned auto_term on the same
node's first word for hours ('Fast-slow' era). Strengthen now fires only
when the top node changed since the last scan, and a 4-deep finst-style
tabu ring (ACT-R declarative finsts) hard-excludes recently used auto
terms (~2 min at the 30s cadence). Quoted-title guard stops '"The'
leaking through the >3-char stopword check and seeding lexical floods.

Heartbeat now pumps /api/embed-backfill?n=32 on the authoritative store
(its lazy backfill had no production trigger; coverage stalled at
93/12175) and emits wm_saturated, wm_top0_streak, embed_backfilled,
embed_count. Curiosity ISE emits auto_term_streak. The stuck-WM failure
mode is now a one-glance signal instead of manual ISE cross-referencing.
2026-07-25 08:45:22 -05:00
will.anderson fb0bb553f3 self-review 2026-07-24: boot counter — demote to telemetry weight, restore persistence via HTTP write-back
Three stale soul:boot_count copies (salience .9, importance .9, Canonical:
+0.2 tier bias, 0.15 threshold) held the top WM slots for 23h — a boot
counter outcompeting real context. Demoted to salience .55 / importance .2 /
tier Working: plumbing, not memory.

Persistence was also broken: in HTTP-engram mode the server owns state and
nothing wrote the counter back — the log shows boot #5 on three consecutive
boots. mem_boot_count_inc now mirrors the persona write-back: delete stale
server copies (matched by content prefix — route_create_node sets
label=content), create the replacement server-side. Working tier is in the
boot seed (/api/nodes) but excluded from periodic /api/sync, so the count
survives restarts without re-importing mid-session. Verified: restart
incremented 1->2 with exactly one server-side counter node.
2026-07-24 08:53:02 -05:00
will.anderson 9e59c51f3c self-review 2026-07-23: title-derived Knowledge labels + Knowledge admitted to curiosity auto-term
Sentinel labels (knowledge:captured/evolved/canonical) made every capture
anonymous in WM telemetry — 35 identical wm_top entries — and starved the
curiosity auto-term seeder, which derives scan seeds from WM top-10 labels
and had returned empty on every scan since boot 6 because WM became
Knowledge-dominated while Knowledge was excluded from seeding.

- capture/evolve/promote now pass title (or empty → engram_node_full's
  content[:60] derivation) instead of sentinels
- auto_term_try_slot admits Knowledge slots; sentinel-shaped labels
  (colon, no space) are skipped so legacy nodes cannot seed 'knowledge'
- verified: probe capture labeled 'Label derivation probe 2026-07-23'
2026-07-23 08:39:16 -05:00
will.anderson 3ae07cc7b0 harden(neuron-dev-setup): fix 7 fresh-Mac onboarding installer bugs (#99)
Neuron Soul CI / build (pull_request) Has been cancelled
Neuron Soul CI / deploy (pull_request) Has been cancelled
Co-authored-by: Neuron <will.anderson@neurontechnologies.ai>
Co-committed-by: Neuron <will.anderson@neurontechnologies.ai>
2026-07-22 21:49:30 +00:00
will.anderson a45a3ca379 Fix truncated POST/GET /api/safety-contact response
Saving the 988 crisis-line contact returned truncated, unparseable JSON —
cut mid-"set_at" at the file's byte length (e.g. 178 of a 218-byte
response). The contact written to disk was complete; only the HTTP response
was clipped, so a real customer's crisis-contact save came back corrupt.

Root cause is in the el runtime's response writer, not a handler buffer:
fs_read stores the file's byte count in a thread-local (_tl_fs_read_len)
for binary-safe file serving, and the response writer uses that length when
non-zero instead of strlen(body) (el_runtime.c:1409). Both safety-contact
handlers call fs_read (the POST read-back verify; the GET file read) and
then return a LONGER wrapped JSON string, so the response is capped to the
file size.

Soul-source fix (no runtime change needed):
- POST: verify persistence via fs_write's return (1 = all bytes written)
  instead of an fs_read read-back — removes the fs_read, so nothing caps the
  response.
- GET: fs_read is required, so reset the thread-local after it with a no-op
  fs_read("") (fs_read zeroes the length before it opens a path) so the
  wrapped response is sent in full.

Verified: POST (crisis-line + custom) and GET now return complete, valid
JSON (parses cleanly, full contact incl. set_at). Regenerated dist/soul.c +
dist/safety.c (3GB RSS watchdog, release el_runtime v1.0.0-20260501).
Full suite still green: verify-soul-contract GATE PASS (PRESENCE +
IMMUTABILITY), genesis boot survives (/health 200, no segfault), bounded-
persona floor still compiled in.

NOTE: the underlying runtime leak (any handler that fs_reads then returns a
longer string) is worth a proper fix in el_runtime.c (use the max of
strlen and _tl_fs_read_len) so this class can't recur.
2026-07-21 12:13:58 -05:00
will.anderson 091cc1fc0e Fix issue #150: fresh-install genesis boot SIGSEGV in mem_save
A fresh-install (SOUL_CGI_ID=ntn-genesis) boot crashed with
"Segmentation fault: 11" right after the http server came up — a real
customer's very first boot. Backtrace:

  strcmp(0x1) <- str_eq (el_runtime.c:219) <- mem_save <- awareness_run

Root cause: the el runtime's engram_save returns an Int (1 = ok, 0 =
failure), but mem_save did `str_eq(engram_save(path), "")`, treating the
return as a String. str_eq runs EL_CSTR on it, which is a raw cast:
EL_CSTR(1) = (char*)0x1. On a SUCCESSFUL save (return 1) strcmp then
dereferences 0x1 and segfaults. Genesis is the first path that both seeds
the brain AND saves it successfully on the very first awareness pass, so it
crashes there; non-genesis boots (contract gate, refusal test) don't hit a
successful early mem_save, which is why they passed. handle_api_consolidate
had the identical latent bug.

Fix: read engram_save's Int result and compare `== 0` instead of str_eq'ing
it — in mem_save (memory.el) and handle_api_consolidate (neuron-api.el).

Regression: pre-existing, NOT introduced by the immutability/floor rebuild.
The pre-immutability build (1442ce2) genesis-crashes identically in the same
unchanged mem_save; #159 never actually fixed #150 for a release-runtime
build.

Regenerated dist/soul.c + per-module dist/{memory,neuron-api}.c (3GB RSS
watchdog, built against release el_runtime v1.0.0-20260501). Verified:
genesis boot survives (/health 200, no segfault), verify-soul-contract.sh
GATE PASS (PRESENCE + IMMUTABILITY), and the bounded-persona floor is still
compiled in (BOUNDED PERSONA / SOUL_PERSONA_NAME strings present).
2026-07-21 11:50:59 -05:00
will.anderson 6527988eb9 Make engram deletes/updates/forgets immutable on the launch branch
The ship-soul builds from this branch, which has the bounded-persona floor
(#93) but never received the tombstone/supersede immutability fix (that
went to main; hotfix diverged before it). So the launch soul failed
verify-soul-contract IMMUTABILITY on the delete/update/forget routes —
they hard-removed engram nodes via engram_forget/mem_forget.

Apply the same fix, mirroring the knowledge routes' supersede pattern:
- node/update -> create new node + "supersedes" edge to the original, KEEP
  the original (no engram_forget).
- node/delete, memory/delete, memory/forget, cultivate forget, and the
  autonomous awareness forget -> TOMBSTONE via the canonical mem_tombstone
  (memory.el): keep the node + its edges, record a Tombstone marker, hide
  from default bounded list reads (?include_deleted recovers). Never
  engram_forget. The MCP forget tool now routes to the tombstoning delete
  instead of faking a delete.
Internal GC that genuinely removes transient nodes (awareness inbox-trigger
consume, consolidation dedup, session-summary replace, telemetry pruning)
still calls engram_forget directly and is unchanged.

Regenerated dist/soul.c (single-TU) + per-module dist/{memory,awareness,
neuron-api}.c from THIS branch's sources under a 3GB physical-RSS watchdog
(peak ~32MB), built against the release el_runtime (v1.0.0-20260501). The
bounded-persona floor is preserved — verified in the emitted C and the
linked binary (BOUNDED PERSONA / SOUL_PERSONA_NAME strings present).

verify-soul-contract.sh: GATE PASS — PRESENCE all 27 routes, IMMUTABILITY
5/5 KEPT (memory-update, memory-delete, node-update, node-delete,
memory-forget).
2026-07-21 10:55:46 -05:00
will.anderson c63e3d1a68 self-review 2026-07-21: break perceive→respond→store feedback loop in awareness
The soul daemon leaked ~104 orphan in-memory nodes/min (17.6GB RSS,
OOM-killed) because the perceive gate substring-matched 'soul-inbox'
against the loop's own verbatim-copy output, the trigger node was
strengthened but never consumed, and record() persisted a Memory node
per cycle. Fixes: perceive gates and activates only on the dedicated
soul-inbox-pending tag; one_cycle requires the tag on the node's tags
field before attending (makes consumption safe); processed triggers
are consumed via engram_forget; loop outcomes route through ISE
telemetry (48h prune) instead of permanent Memory nodes.

Verified post-restart: node_delta 104→~0, curiosity scans resumed,
WM average unfrozen (0.120833→0.0676), RSS 17.6GB→184MB.
2026-07-21 08:50:47 -05:00
will.anderson 50cf67bd66 self-review 2026-07-19: close silent sync-starvation hole + heartbeat deltas
- engram refresh URL now resolves env -> state -> localhost:8742, same
  hardening ise_post got after the boot-4 blackout. Previously a corrupted/
  empty soul_engram_url state key silently disabled sync forever while
  heartbeats kept flowing — WM starves of Knowledge nodes with no outward
  sign.
- heartbeat ISE: node_delta, edge_delta (growth vs stall vs flood is now
  one field, not cross-ISE forensics), sync_age_ms from a new
  soul.last_sync_ok_ts stamp (-1 = never; >> SOUL_REFRESH_MS = refresh
  path broken). Verified live: pulse 1 sync_age_ms=-1, sync fired +1.6s,
  age counts up between syncs.
2026-07-19 08:47:00 -05:00
will.anderson 40d800195a Tombstone the remaining forget paths (close the immutability arc)
Phase 1 tombstoned memory/delete + node/delete, but the generic forget
path was still destructive. This routes every forget through the same
tombstone semantics so nothing in the daemon can hard-delete an engram
node anymore.

Canonical helper: mem_tombstone (memory.el, imported first so every module
can call it) — keep the node + its edges, record a Tombstone marker, never
engram_forget. neuron-api's tombstone_node now delegates to it (single
source of truth).

Per-path before -> after:
- memory.el `mem_forget`      hard delete (engram_forget) -> tombstone. This
  alone fixes both callers: the /api/neuron/memory/forget route
  (handle_api_forget) and the cultivate op=="forget".
- awareness.el autonomous `forget` action  engram_forget -> mem_tombstone.
  The soul can no longer autonomously hard-delete a memory.
- mcp-wrapper tool_forget  was a FAKE no-op that returned {"ok","deleted"}
  without deleting OR tombstoning -> now routes to the soul's tombstoning
  /api/neuron/memory/delete; tool description fixed to say it
  supersedes/tombstones (recoverable), not "Remove a node".

Left intentionally as hard deletes (internal GC / lifecycle, not user
memory, all call engram_forget directly): session-summary replace
(chat.el), mem_consolidate dedup (memory.el), session-start telemetry
pruning (soul.el), session lifecycle (sessions.el).

Regenerated both ship paths under a 3GB physical-RSS watchdog (peak ~32MB):
dist/soul.c (single-TU amalgamation, macOS/Linux) and the per-module
dist/{memory,awareness,neuron-api}.c (Windows/Linux build). Verified: no
forget handler calls engram_forget; a forget leaves the node present +
tombstone marker. Gate (neuron-ui verify-soul-contract.sh, new memory-forget
row): PRESENCE + IMMUTABILITY PASS.
2026-07-18 13:22:43 -05:00
will.anderson f3034d23f7 Regenerate per-module dist/neuron-api.c for the immutability fix
soul.c (the macOS single-TU amalgamation) already carries the
tombstone/supersede change, but the Windows/Linux build path compiles
the per-module dist/*.c instead (build-soul-windows.sh excludes soul.c).
That path was still pulling the stale, destructive dist/neuron-api.c —
so without this the cross-compiled neuron.exe would keep hard-deleting
engram nodes even though the source is fixed.

Regenerated with `elc --emit-header neuron-api.el`: no engram_forget in
memory_delete/node_delete (tombstone), supersedes edge in node_update.
Portable C — identical for macOS/Windows/Linux; only the runtime it links
against differs.
2026-07-17 16:57:55 -05:00
will.anderson d337fcb265 Make engram deletes/updates immutable (tombstone + supersede)
The soul was hard-deleting engram nodes: memory/delete and node/delete
called engram_forget (frees the node and drops its incident edges), and
node/update created a replacement then forgot the original with no link
back. That violates the day-one rule that engram nodes are immutable —
memory could be silently, irrecoverably destroyed via the API.

Convert the three destructive handlers to Will's immutability semantics,
mirroring the pattern memory/update and knowledge evolve/promote already
use:

- node/update  -> create the new node, wire a "supersedes" edge new->old,
  KEEP the original. No engram_forget. (Was: create + forget old, no edge.)
- memory/delete and node/delete -> TOMBSTONE: keep the node AND its edges,
  create a Tombstone marker node (content = target id, label
  "tombstone:<id>") wired with a "tombstones" edge. Never engram_forget.
  Default bounded list reads (handle_api_list_typed / the memory list) hide
  tombstoned nodes and the markers; ?include_deleted=1 returns them, and
  internal cognition + /api/graph/nodes still traverse them. memory/update
  was already correct and is unchanged.

Full-graph hiding on /api/graph/nodes is deliberately NOT done at the el
layer: json_array_get is O(index), so filtering that endpoint (called with
limit up to 999999) would be O(n^2). That hide needs a runtime scan filter
and is a separate follow-up; nodes there remain traversable, tagged
status:deleted via the marker edge.

Regenerated dist/soul.c from these sources (flat single-TU amalgamation,
compiled under a 3GB physical-RSS watchdog, peak ~32MB). Verified with
scripts/verify-soul-contract.sh in neuron-ui: PRESENCE passes (all 27
routes) and IMMUTABILITY passes (all four mutation routes KEPT; deletes
produce a real tombstone marker and hide from the default list).
2026-07-17 16:42:30 -05:00
will.anderson 1011d8e5be regen dist: rebuild soul.c from corrected sources (OOM gone, Track B compiled in)
Neuron Soul CI / build (pull_request) Successful in 4m12s
Neuron Soul CI / deploy (pull_request) Has been skipped
Regenerates the combined dist/soul.c and per-module dist/*.c from the current
El sources, on top of the elc-source-typo fixes (PR #77) and the Track B
threat-to-others routing (PR #76), both already on this branch.

Validated end to end under a physical-RSS watchdog (macOS silently ignores
ulimit -v / RLIMIT_AS, so every elc/elb run was RSS-polled and kill -9'd at a
3GB ceiling, one module at a time):

- OOM is GONE. The stale dist/soul-with-nlg.el (which still carries the
  malformed string literals) explodes to 3.3GB+ and is watchdog-killed at ~90%.
  With the typos fixed, every one of the 48 modules compiles at <=18MB peak RSS,
  and the full flat amalgamation compiles as a single translation unit at ~68MB.
  The 700GB pathology was purely the unbounded-parser-on-malformed-literal loop;
  no malformed construct means no loop.
- The regenerated soul.c contains Track B: safety_classify_hard_bell ->
  threat_other -> safety_hard_directive routes credible threat-to-others to 911
  and explicitly NOT to 988 / the safety contact. Verified in source, in the
  emitted C, and in the linked binary's strings. Track A (abuse / self_harm)
  is unchanged and still checked first.
- The regenerated soul links to a working native arm64 binary and boots: serves
  on a throwaway port, /health returns 200, awareness loop runs.

Also fixes one source blocker discovered during regen (unrelated to the typos
or Track B): chat.el handle_chat_agentic left a void `if { println(...) }` in
value position, which the current elc lowers to `_if_result = (println(...))`
(assigning void) -> invalid C. Bound an explicit Bool so the branch is
non-void; behavior unchanged (still only logs on persist failure).

NOTE (runtime dependency, for controlled deploy): this branch's chat.el calls
engram_get_node_by_label, which the canonical el-compiler/runtime does not yet
declare/define (the release runtime v1.0.0-20260501 has it; the newest runtime
has arena + http_serve_async but not this). Building the soul requires a runtime
that has all three. Land engram_get_node_by_label into the runtime package
before this soul.c can be built in CI.

Do not merge — regen + Track B going live is a controlled-deploy call.
2026-07-14 18:45:14 -05:00
will.anderson c8cb425412 soul: per-tick arena bracketing in awareness_run + hand-patched dist/soul.c
Neuron Soul CI / build (push) Successful in 5m14s
Neuron Soul CI / deploy (push) Failing after 10m9s
awareness_run's while-loop ran outside any request arena, so every
allocation in every 1s tick (search JSON, heartbeat payloads, curiosity
activations) was treated as permanent by the runtime — 7.5GB RSS in
under a minute. Bracket each iteration with el_arena_push/el_arena_pop
(same pattern the compiler emits for scoped blocks; state_set/state_get
persist separately via el_strdup_persist and are unaffected).

dist/soul.c carries the same change hand-patched at the compiled
awareness_run site — elc is currently unsafe to run locally (pathological
memory on sessions.el), so the generated C was patched to match the
source, verified line-for-line against the compiler's own conventions.

MUST be paired with el repo PR #64 (el_strdup_persist for stored engram
fields): per-tick arena reclamation widens the write-corruption window
without it. Verified together: 5h live soak on the recovered production
snapshot, flat RSS, write-field-integrity clean.

Note: dist/soul.c still needs a full elc regen to pick up PR #73's
source changes (consent tiers) — tracked separately; this patch does not
regress that (those changes were never in dist).
2026-07-13 16:24:15 -05:00
will.anderson 2688cb722a chore(dist): update soul.c with PR #63/#65/#66 + Task 1 chat.el changes
Neuron Soul CI / build (push) Successful in 5m57s
Neuron Soul CI / deploy (push) Failing after 5m15s
Manually adds compiled C equivalents for:
- distill_transcript() — last-3-messages extractor; wires into
  handle_dharma_room_turn and handle_dharma_room_turn_agentic
- current_engine_note() — appended to system prompt in handle_chat
  so Neuron can answer 'what model am I running on?' truthfully (PR #66)
- llm_base_url / llm_wire_format / json_escape / openai_chat_complete —
  OpenAI-compatible provider path in handle_chat_agentic (PR #65)
- flag_true() — tolerant agentic flag check (PR #63)

Compile verified: 6 pre-existing warnings, 0 errors.
2026-07-01 11:42:56 -05:00
will.anderson c586ea5ef1 chore(dist): recompile neuron.c and elp-c-decls.h
Neuron Soul CI / build (push) Has been cancelled
Neuron Soul CI / deploy (push) Has been cancelled
Reflects session-start event pruning in emit_session_start_event
(keep_n=10, prunes oldest beyond that) and updated forward declarations
for connector routing (connectd_get, connectd_post, handle_connectors,
rate_limit_check, handle_chat_plan) replacing the removed route_sessions
helpers and flag_true.
2026-07-01 11:26:00 -05:00
will.anderson 6819729429 fix(awareness): correct stale comment; add wm_top to curiosity_scan ISE
The hops=1 comment incorrectly claimed a semantic seed supplement
(cosine-sim scan) was active — it was planned but never implemented.
Corrected to accurately describe what the runtime does (istr_contains
only). Also adds wm_top (top-3 WM nodes by weight) to the curiosity_scan
ISE payload so activation patterns are visible without relying solely on
the heartbeat's wm_active count.
2026-07-01 11:25:54 -05:00
will.anderson 31dd93d5f4 fix(chat): add distill_transcript (was called but never defined)
handle_dharma_room_turn and handle_dharma_chat both called
distill_transcript since June 30 but the function was never declared,
causing a build failure. Implements last-3-messages extraction for JSON
array transcripts and last-500-char truncation for plain text.
2026-07-01 11:25:48 -05:00
will.anderson 9d266aac4c fix(sessions): extract session_search_entry to fix ELC OOM in session_search
The while loop in session_search had too many let bindings in scope;
the ELC compiler's exponential rebinding accumulation caused OOM and
truncation of dist/sessions.c since June 30. Moving the per-node logic
into session_search_entry gives the compiler a clean scope boundary per
call, restoring O(N) compile behaviour.
2026-07-01 11:25:45 -05:00
will.anderson 76bd3afdf8 feat(dist): Win32 POSIX shim for el_runtime.c cross-compilation 2026-06-29 12:38:27 -05:00
will.anderson 51bea5507b prevent engram corruption: idempotent boot seeding, session-start event cap
Fix 1: mem_boot_count_inc prunes all existing soul:boot_count nodes before
        inserting the new one — keeps exactly one boot counter node instead
        of accumulating a new node per boot. Also fixes a latent ordering
        bug where engram_search_json oldest-first results caused the counter
        to read stale (low) values once >3 copies accumulated.

Fix 3: handle_api_node_delete comment clarified — the no-verify exception
        is correct for deletes (not a write path); read-back-verify is for
        writes only.

Fix 4: emit_session_start_event prunes old session-start InternalStateEvent
        nodes after each boot, keeping the 10 most recent and forgetting
        older ones. Prevents unbounded accumulation of ~120+ copies.
2026-06-29 11:09:01 -05:00
will.anderson 933547265e chore(dist): compile PRs #60/#61 into soul.c
Neuron Soul CI / build (push) Successful in 4m3s
Neuron Soul CI / deploy (push) Failing after 5m12s
- PR #60: inject operator home dir into system prompt (#30)
  Adds OPERATOR IDENTITY section so the LLM correctly resolves
  'my files/notes/desktop' to the actual running user's $HOME.
  Prevents identity confusion between imprint author and operator.

- PR #61: plan-mode endpoint POST /api/chat {mode:'plan'} (#27)
  Adds handle_chat_plan — returns {steps:[{id,title,detail}]} JSON.
  Wired into all three /api/chat route handlers. Grounds the plan
  via engram_compile (same as agentic path) for context awareness.

dist changes:
  - soul.c: both PRs compiled in; build_system_prompt updated to
    2-param signature (ctx, chat_mode); handle_chat_plan added
  - chat.c/routes.c/chat.elh: individual module outputs updated
  - elp-c-decls.h: remove stale 1-param build_system_prompt decl,
    add handle_chat_plan declaration
  - soul.elh.c: new soul header declarations file (from PR #60)

Compile verified: cc -O2 -DHAVE_CURL soul.c el_runtime.c -lcurl
Binary: 805K arm64, smoke test passes (port in use = expected).
2026-06-29 08:17:45 -05:00
will.anderson a77578e243 chore(dist): compile PRs #56/#57/#58 into soul.c
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
- PR #56: vision in agentic chat path (image content block)
- PR #57: /api/connectors/call route — proxy connector tool calls
- PR #58: /api/neuron/list/<type> off-by-one fix (str_slice 16->17)

Live-verified: list/BacklogItem returns 50 nodes (was 0 before #58 fix).
Binary size: 3.8MB.
2026-06-28 12:29:52 -05:00
will.anderson af594a9162 Add .gitignore, untrack compiled binary from dist/ 2026-06-27 11:50:18 -05:00
will.anderson 2589183775 Expose node/create endpoint and respect label field in memory writes 2026-06-27 11:49:09 -05:00
will.anderson dcc0bf550a Add Ollama provider, portable memory, cultivation digest, refugee importer, GLM-OCR spike
- P0: unified soul binary with engram_node_full fix, read-back-verify, search fix
- P0: move API keys from plaintext plists to macOS Keychain
- P0: fix MCP backend URL (port 8742 → 7770)
- P1.6: memory-export/import scripts (AES-256-CBC, versioned .neuronmem format)
- P1.7: nightly cultivation digest with sharpness metric (launchd at 23:55)
- P2.10: Ollama provider in agentic loop (SOUL_LLM_PROVIDER=ollama)
- P3.12: refugee importer for ChatGPT/Screenpipe/generic formats
- P3.13: GLM-OCR spike — SHIP IT (mlx-vlm, 1.59GB, photo-to-memory.sh)
2026-06-27 11:46:30 -05:00
will.anderson d4609c7baa chore(dist): update neuron.c and routes.c to 2-arg build_system_prompt
Deploy Soul to GKE / deploy (push) Failing after 7m15s
Neuron Soul CI / build (push) Failing after 21m49s
neuron.c and routes.c were compiled against the old 1-arg soul interface.
chat.c already uses the 2-arg signature. The Windows cross-compile build
generates elp-c-decls.h from all dist/*.c files, causing a conflicting-types
error when both signatures appear. Recompile these modules against the
current soul API to eliminate the conflict.
2026-06-25 13:10:20 -05:00
will.anderson 98603f5ae8 self-review 2026-06-24: rebuild with goal_bias fix (Knowledge type boost)
Linked against dev runtime with is_knowledge fix that adds Knowledge
node type. Engram goal_bias now gives Knowledge nodes +0.3 boost on
technical queries, consistent with how Belief/DharmaSelf/Safety nodes
are already treated. Same el_runtime source as concurrent foundation/el
commit 16d62bd.
2026-06-24 08:48:21 -05:00
will.anderson bdc07be344 chore(dist): compile EL recall/dedup/session-continuity fixes to C
Neuron Soul CI / build (push) Failing after 12m40s
Deploy Soul to GKE / deploy (push) Failing after 6m0s
Updates soul.c and all per-module .c files with:
- parse_float_x100() engram score fix
- id_in_seen dedup wiring across session_preload
- session-end summary hook + session-start recall
- Emergency structural repair (no duplicate fns, all callsites wired)
2026-06-23 13:04:06 -05:00
will.anderson f33cdaf793 feat(recall): activation-seed improvements
- Issue 2: replace raw 50-char threshold with is_genuine_continuation() that
  checks for explicit follow-up phrases and mid-sentence capitalization (proper
  nouns signal a new topic, not a continuation)
- Issue 3/8: build_activation_seed() scans back to find the prior USER turn as
  the topic anchor instead of using the last assistant reply (hist_len-1)
- Issue 4: engram_compile_multi() fans out across three seeds — enriched primary,
  raw message (entity queries), and emotion query — merging non-redundant results
- Issue 5: agent workspace_root appended to ag_seed so agentic activation is
  workspace-aware; previously ignored despite being available in state
- Issue 6: distill_transcript() extracts salient tail+question content from full
  transcripts before passing to engram_compile in dharma room handlers
- Issue 7: dist/soul-with-nlg.el handle_chat and handle_chat_agentic now load
  history and use build_activation_seed() — the raw message path is eliminated
- Issue 9: topic_snip_from_entry() takes the TAIL 200 chars of a long reply and
  finds the last sentence boundary — captures end-of-reply named concepts
- Issue 10: multi_turn_topic() pulls up to 3 prior user turns into the non-
  continuation seed so earlier thread context re-activates high-salience nodes
2026-06-22 12:55:33 -05:00
Tim Lingo f6c4ea70a0 fix(chat): forbid fake tool calls in tool-less (Just chat) mode
Neuron Soul CI / build (pull_request) Successful in 4m47s
REPRODUCED: in the non-agentic path (Tools off / 'Just chat'), asking for
tool-work makes the model role-play tool use — it emits a fake ```json {...}```
'tool call' and says 'let me search/query/pull your sessions' while NOTHING
runs. Reads as a broken/lying app. (The agentic path is fine: verified it
calls search_memory and reports honestly.)

Root cause: build_system_prompt (handle_chat, the tool-less path) never told
the model it has no tools this turn, so it fabricated.

Fix: add a NO-TOOLS directive to the non-agentic system prompt — never emit
tool calls / JSON tool blocks / 'let me pull...' narration; answer from context
only; if a tool is truly needed, say so in one sentence and tell the user to
turn Tools on. Applied to chat.el (source) AND dist/soul.c (the curated TU the
CI compiles), so the CI-built binary carries it.

Verified the FABRICATION repro on the live local soul; could not verify the
patched binary locally (no matching el-runtime version on this machine — a
hand-link against origin/main runtime 404s on all routes). Builds correctly via
CI, which links soul.c against the pinned runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:57:24 -05:00
will.anderson 6f4adf7640 self-review 2026-06-19: filter auto_term to Memory/BacklogItem/Entity only
Knowledge nodes dominated the WM-autobiographical auto_term slot:
'Numeric tier strings...' (a Knowledge node) always scored highest
in WM and its first word 'Numeric' became the curiosity seed every
scan — activating more Numeric nodes, keeping that node in WM,
repeating indefinitely.

Fix: only derive auto_term from Memory, BacklogItem, or Entity nodes.
Knowledge nodes are reference material, not live context. Dynamic/
personal nodes carry the salience worth radiating from.

Also patches proactive_curiosity directly in dist/neuron.c (ELC
cannot compile soul.el within timeout — fallback build pattern).
2026-06-19 08:49:42 -05:00
will.anderson ceef82464a chore(dist): update pre-compiled soul.c to patched4
Deploy Soul to GKE / deploy (push) Failing after 6m20s
Neuron Soul CI / build (push) Failing after 6m56s
Incorporates PRs #22/#23/#24:
- agentic_tools_all dedup fix (no duplicate web_search tool)
- workspace scope functions (agent_workspace_root, path_within_root, resolve_in_root)
- updated dispatch_tool with workspace confinement
- canonical-self bridge (ensure_self_canonical_bridge)

Also incorporates CI link fix from PR #26 (soul.c is self-contained, no
other dist/*.c needed). Fixes the CI build step which was compiling the
old June-16 soul.c that predated all these changes.
2026-06-18 12:19:54 -05:00
Tim Lingo 5ddb860201 fix(soul): ratio guard against genesis seeding over a populated engram
Genesis boot previously seeded a fresh identity and saved it over snapshot.json
whenever the in-memory graph looked empty. Replace the fixed node-count threshold
with a ratio guard: refuse to seed when the on-disk snapshot is large
(>200KB) but the loaded graph is sparse (< disk/16000 nodes).

KNOWN LIMITATION: this gates only the seed/pre-serve-save path. The deeper cause
is a non-atomic engram_save (fopen wb truncates to 0 before writing 47MB), which
creates a window where a concurrent load reads an empty file -> genesis -> and if
guard_disk is read in that same window the guard passes. The real fix is an
atomic engram_save (temp + fsync + rename) in el_runtime.c, tracked separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:18:35 -05:00
Tim Lingo 6d8a992716 feat(soul): add safety module, expand connectors API, memory-recall bug notes
- safety.el/.elh: new safety module
- neuron-api.el, routes.el, soul.el, chat.el: connectors API expansion
- regenerated dist/ C artifacts
- MEMORY_RECALL_BUG.md: investigation notes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:18:35 -05:00
will.anderson e22cb31b85 chore: remove stale Linux CI binary (dist/neuron)
Deploy Soul to GKE / deploy (push) Failing after 6m28s
Neuron Soul CI / build (push) Failing after 7m31s
Neuron Soul CI / build (pull_request) Failing after 10m28s
2026-06-15 12:41:35 -05:00
will.anderson 00f15b094b feat(soul): add sessions layer, MCP connectors, conversation continuity fix
Deploy Soul to GKE / deploy (push) Failing after 12m39s
Neuron Soul CI / build (push) Failing after 12m49s
- sessions.el: new sessions module with session management and approval gate
- routes.el: wire /api/sessions routes (list, get, create, approve, tool_result)
- chat.el: thread-aware activation — short messages anchor to last reply
  before engram compilation so follow-ups stay on-topic
- chat.el: agentic path tracks per-session history (session_hist_{id})
  instead of shared conv_history, seeding each turn with prior context
- chat.el: add call_neuron_mcp, dispatch_tool, is_builtin_tool, next_bridge_id
  agentic_loop, bridge_save, agentic_resume, handle_tool_result
- dist/soul: rebuild with all of the above
2026-06-15 12:40:47 -05:00
will.anderson 3a5d38ea45 Merge branch 'main' of git.neuralplatform.ai:neuron-technologies/neuron 2026-06-15 11:51:26 -05:00
will.anderson a0470acc45 Merge PR #9: feat(soul): wire consciousness layers — L0->L1->L2->L3->L1 cycle
Deploy Soul to GKE / deploy (push) Failing after 14m11s
Neuron Soul CI / build (push) Failing after 14m23s
Resolves conflicts by keeping main's full safety/stewardship/imprint implementations.
PR #9 uniquely contributes: layered_cycle() in soul.el, route wiring in routes.el,
soul.elh export, and the layer composition test suite.
2026-06-15 11:32:32 -05:00
will.anderson 4aa79e85cd self-review 2026-06-13: rebuild soul daemon with Knowledge WM threshold fix 2026-06-13 08:42:40 -05:00