Compare commits

...

20 Commits

Author SHA1 Message Date
Tim Lingo c2afcbddf5 fix(engram): allow SessionSummary node_type in validation allowlist
El SDK CI - dev / build-and-test (pull_request) Successful in 3m47s
handle_api_consolidate writes a "SessionSummary" node, but engram_valid_node_type
omitted it — so once this validation ships, every consolidate() would be silently
REJECTED at the engram boundary. Add SessionSummary to the allowlist.

Found in Will's PR review of neuron #1 / el #52.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 06:26:25 -05:00
Tim Lingo dfe4e83ed1 Fix engram_node_full wrapper field corruption + add node_type/tier validation
El SDK Release / build-and-release (pull_request) Failing after 9s
The wrapper signature was stale and didn't match the C primitive
__engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags).
Because el_val_t is an untyped machine word, the compiler coerced caller args to the
wrong declared param types and forwarded them BY POSITION — so tier received an int,
importance/confidence received strings, label received a float, etc. (~100 corrupt nodes).

- Correct the wrapper to match the C contract 1:1 (no coercion, no reorder).
- Add engram_valid_node_type / engram_valid_tier allowlists; engram_node and
  engram_node_full now reject invalid values with __println + return "" (fail loud,
  no silent malformed write).

See neuron repo: HANDOFF-engram-write-corruption.md for the full write-up + deploy runbook.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 16:13:43 -05:00
will.anderson 2ed6b26dde Merge pull request 'promote: stage → main (all elb linker fixes + ci-base rebuild)' (#42) from stage into main
El SDK Release / build-and-release (push) Successful in 6m28s
promote: stage → main (all elb linker fixes + ci-base rebuild)
2026-05-07 14:25:37 +00:00
will.anderson d8e9fd12f4 Merge pull request 'promote: dev → stage (all elb linker fixes)' (#41) from dev into stage
El SDK Release / build-and-release (pull_request) Successful in 3m51s
El SDK CI - stage / build-and-test (push) Successful in 4m11s
promote: dev → stage (all elb linker fixes)
2026-05-07 14:20:53 +00:00
will.anderson 8ef3eb6bec Merge pull request 'fix(elb): all linker fixes — gcc compat, OpenSSL, runtime import conflict' (#40) from fix/elb-gcc-bracket-depth into dev
El SDK CI - stage / build-and-test (pull_request) Successful in 4m8s
El SDK CI - dev / build-and-test (push) Successful in 4m34s
fix(elb): all linker fixes — gcc compat, OpenSSL, runtime import conflict
2026-05-07 14:16:17 +00:00
will.anderson 027ad82db2 fix elb linker: remove runtime imports from el-install, add --clean, catch in dev/stage CI
El SDK CI - dev / build-and-test (pull_request) Successful in 3m35s
el-install.el explicitly imported runtime/*.el modules (string, env, fs, exec,
json, http), which elb compiled to .c files in the shared dist/bin out_dir.
Linking those alongside el_runtime.c caused multiple definition errors for
every runtime function (http_get, http_patch, etc.). The runtime .el files are
thin wrappers over seed primitives already compiled into el_runtime.c — no
import needed.

Fixes:
- Remove all explicit runtime imports from el-install.el (root cause)
- Add --clean to every elb invocation in sdk-release.yaml so each build
  starts with a clean out_dir (defense-in-depth against stale .c files)
- Add elb build + epm/el-install build steps to ci-dev.yaml and ci-stage.yaml
  so linker errors are caught on every PR, not just stage->main
2026-05-07 03:20:44 -05:00
will.anderson 8fa9c4ba20 Merge pull request 'promote: dev → stage (elb linker fixes)' (#38) from dev into stage
El SDK Release / build-and-release (pull_request) Failing after 1m2s
El SDK CI - stage / build-and-test (push) Successful in 3m56s
promote: dev → stage (elb linker fixes)
2026-05-07 08:11:38 +00:00
will.anderson 8ab8e3fd31 Merge pull request 'fix(elb): add -lssl -lcrypto to link_binary flags' (#37) from fix/elb-gcc-bracket-depth into dev
El SDK CI - stage / build-and-test (pull_request) Successful in 3m22s
El SDK CI - dev / build-and-test (push) Successful in 3m56s
fix(elb): add -lssl -lcrypto to link_binary flags
2026-05-07 08:07:27 +00:00
will.anderson 05d717744b fix(elb): add -lssl -lcrypto to link_binary flags
El SDK CI - dev / build-and-test (pull_request) Successful in 3m24s
el_runtime.c uses OpenSSL (EVP_*, RAND_bytes) for AEAD encrypt/decrypt.
elb was only linking -lcurl -lpthread -lm, missing the SSL libs.
Matches the explicit flags used in ci-dev.yaml and ci-stage.yaml.
2026-05-07 03:03:21 -05:00
will.anderson 9c7bde47dc Merge pull request 'promote: dev → stage (elb gcc fix)' (#35) from dev into stage
El SDK Release / build-and-release (pull_request) Failing after 40s
El SDK CI - stage / build-and-test (push) Successful in 3m45s
promote: dev → stage (elb gcc fix)
2026-05-07 08:01:22 +00:00
will.anderson b0d0975f05 Merge pull request 'fix(elb): use clang-only -fbracket-depth flag conditionally' (#34) from fix/elb-gcc-bracket-depth into dev
El SDK CI - stage / build-and-test (pull_request) Successful in 3m21s
El SDK CI - dev / build-and-test (push) Successful in 3m53s
fix(elb): use clang-only -fbracket-depth flag conditionally
2026-05-07 07:57:34 +00:00
will.anderson 6f634ae432 fix(elb): use clang-only -fbracket-depth flag conditionally
El SDK CI - dev / build-and-test (pull_request) Successful in 3m26s
gcc rejects -fbracket-depth=1024 with 'unrecognized command-line option'.
Use shell subshell to probe cc --version and only pass the flag when
the compiler is clang.
2026-05-07 02:53:42 -05:00
will.anderson c0553459e1 Merge pull request 'promote: dev → stage (CI rebuild fix + ci-base refresh)' (#32) from dev into stage
El SDK Release / build-and-release (pull_request) Failing after 35s
El SDK CI - stage / build-and-test (push) Successful in 3m47s
promote: dev → stage (CI rebuild fix + ci-base refresh)
2026-05-07 07:50:27 +00:00
will.anderson 908ce303f3 Merge pull request 'ci: rebuild ci-base on SDK release; publish elb + el_runtime.js to Artifact Registry' (#31) from fix/ci-openssl-linker into dev
El SDK CI - stage / build-and-test (pull_request) Successful in 3m21s
El SDK CI - dev / build-and-test (push) Successful in 3m51s
ci: rebuild ci-base on SDK release; publish elb + el_runtime.js to Artifact Registry
2026-05-07 07:46:22 +00:00
will.anderson fd208583fe Merge pull request 'promote: dev → stage (elb build fix)' (#28) from dev into stage
El SDK CI - stage / build-and-test (push) Successful in 3m51s
El SDK Release / build-and-release (pull_request) Failing after 38s
promote: dev → stage (elb build fix)
2026-05-07 02:46:27 +00:00
will.anderson 3e29fc43ab Merge pull request 'promote: dev → stage (__http_do_map_to_file)' (#25) from dev into stage
El SDK CI - stage / build-and-test (push) Successful in 3m44s
El SDK Release / build-and-release (pull_request) Failing after 47s
2026-05-07 02:14:30 +00:00
will.anderson 979a5677d5 Merge pull request 'promote: dev → stage (__-prefixed runtime fix)' (#22) from dev into stage
El SDK CI - stage / build-and-test (push) Successful in 3m48s
El SDK Release / build-and-release (pull_request) Failing after 1m4s
2026-05-07 01:48:32 +00:00
will.anderson 17b1aa0736 Merge pull request 'promote: dev → stage (return type fix)' (#19) from dev into stage
El SDK CI - stage / build-and-test (push) Failing after 4m1s
El SDK Release / build-and-release (pull_request) Failing after 42s
2026-05-07 01:12:18 +00:00
will.anderson f0c731d2db Merge pull request 'promote: dev → stage (runtime fix)' (#16) from dev into stage
El SDK CI - stage / build-and-test (push) Successful in 3m43s
El SDK Release / build-and-release (pull_request) Failing after 45s
2026-05-07 00:43:52 +00:00
will.anderson e7e0f7d3e5 Merge pull request 'promote: dev → stage' (#12) from dev into stage
El SDK CI - stage / build-and-test (push) Successful in 4m3s
El SDK Release / build-and-release (pull_request) Failing after 37s
2026-05-07 00:23:46 +00:00
6 changed files with 108 additions and 16 deletions
+22
View File
@@ -174,6 +174,28 @@ jobs:
-lcurl -lssl -lcrypto -lpthread -lm -o /tmp/el_native_fs
/tmp/el_native_fs
# Build epm binary using elb (epm lives at repo root, not inside lang/)
- name: Build epm
run: |
ABS_ELB="$(pwd)/dist/bin/elb"
ABS_ELC="$(pwd)/dist/platform/elc"
ABS_RUNTIME="$(pwd)/el-compiler/runtime"
ABS_OUT="$(pwd)/dist/bin"
(cd ../epm && "$ABS_ELB" --clean --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
chmod +x dist/bin/epm
echo "epm built"
# Build el-install binary using elb
- name: Build el-install
run: |
ABS_ELB="$(pwd)/dist/bin/elb"
ABS_ELC="$(pwd)/dist/platform/elc"
ABS_RUNTIME="$(pwd)/el-compiler/runtime"
ABS_OUT="$(pwd)/dist/bin"
(cd tools/install && "$ABS_ELB" --clean --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
chmod +x dist/bin/el-install
echo "el-install built"
# Publish only after merge (push event), not on PR validation runs
- name: Publish El SDK to Artifact Registry (dev)
if: github.event_name == 'push'
+36
View File
@@ -170,6 +170,42 @@ jobs:
-lcurl -lssl -lcrypto -lpthread -lm -o /tmp/el_native_fs
/tmp/el_native_fs
# Build elb (needed for epm and el-install builds below)
- name: Build elb
run: |
mkdir -p dist/bin
dist/platform/elc elb.el > dist/elb.c
gcc -O2 \
-I el-compiler/runtime \
dist/elb.c \
el-compiler/runtime/el_runtime.c \
-lcurl -lssl -lcrypto -lpthread -lm \
-o dist/bin/elb
chmod +x dist/bin/elb
echo "elb built"
# Build epm binary using elb (epm lives at repo root, not inside lang/)
- name: Build epm
run: |
ABS_ELB="$(pwd)/dist/bin/elb"
ABS_ELC="$(pwd)/dist/platform/elc"
ABS_RUNTIME="$(pwd)/el-compiler/runtime"
ABS_OUT="$(pwd)/dist/bin"
(cd ../epm && "$ABS_ELB" --clean --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
chmod +x dist/bin/epm
echo "epm built"
# Build el-install binary using elb
- name: Build el-install
run: |
ABS_ELB="$(pwd)/dist/bin/elb"
ABS_ELC="$(pwd)/dist/platform/elc"
ABS_RUNTIME="$(pwd)/el-compiler/runtime"
ABS_OUT="$(pwd)/dist/bin"
(cd tools/install && "$ABS_ELB" --clean --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
chmod +x dist/bin/el-install
echo "el-install built"
# Publish only after merge (push event), not on PR validation runs
- name: Publish El SDK to Artifact Registry (stage)
if: github.event_name == 'push'
+2 -2
View File
@@ -77,7 +77,7 @@ jobs:
ABS_ELC="$(pwd)/dist/platform/elc"
ABS_RUNTIME="$(pwd)/el-compiler/runtime"
ABS_OUT="$(pwd)/dist/bin"
(cd ../epm && "$ABS_ELB" --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
(cd ../epm && "$ABS_ELB" --clean --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
chmod +x dist/bin/epm
echo "epm built"
@@ -88,7 +88,7 @@ jobs:
ABS_ELC="$(pwd)/dist/platform/elc"
ABS_RUNTIME="$(pwd)/el-compiler/runtime"
ABS_OUT="$(pwd)/dist/bin"
(cd tools/install && "$ABS_ELB" --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
(cd tools/install && "$ABS_ELB" --clean --elc="$ABS_ELC" --runtime="$ABS_RUNTIME" --out="$ABS_OUT")
chmod +x dist/bin/el-install
echo "el-install built"
+5 -2
View File
@@ -271,7 +271,10 @@ fn link_binary(c_files: [String], out_bin: String, runtime_path: String, out_dir
let parts: [String] = native_list_empty()
// Include both the runtime dir (for el_runtime.h) and the output dir
// (for module.elh cross-module forward declarations).
let parts = native_list_append(parts, "cc -O2 -fbracket-depth=1024 -I " + dirname_of(runtime_path) + " -I " + out_dir)
// Detect clang vs gcc: -fbracket-depth is clang-only; silently ignored
// if unsupported but gcc rejects it with an error.
let bracket_flag: String = "$(cc --version 2>&1 | grep -q clang && printf -- '-fbracket-depth=1024' || true)"
let parts = native_list_append(parts, "cc -O2 " + bracket_flag + " -I " + dirname_of(runtime_path) + " -I " + out_dir)
let i = 0
while i < n {
let f: String = native_list_get(c_files, i)
@@ -279,7 +282,7 @@ fn link_binary(c_files: [String], out_bin: String, runtime_path: String, out_dir
let i = i + 1
}
let parts = native_list_append(parts, runtime_path)
let parts = native_list_append(parts, "-lcurl -lpthread -lm")
let parts = native_list_append(parts, "-lcurl -lssl -lcrypto -lpthread -lm")
let parts = native_list_append(parts, "-o " + out_bin)
let cmd: String = str_join(parts, " ")
println(" link " + out_bin)
+43 -3
View File
@@ -6,15 +6,55 @@
//
// Dependencies: runtime/string.el, runtime/json.el
// --- Validation (defense in depth) ---
// el_val_t is an untyped machine word, so a wrong TYPE can't be caught here but a
// wrong VALUE can (a tier in the node_type slot, an empty/garbage string, an int, a
// path, a model name, a cgi id). Reject loudly instead of silently writing junk.
fn engram_valid_node_type(t: String) -> Bool {
return str_eq(t, "Memory") || str_eq(t, "Knowledge") || str_eq(t, "Belief")
|| str_eq(t, "Project") || str_eq(t, "Tag") || str_eq(t, "BacklogItem")
|| str_eq(t, "Artifact") || str_eq(t, "Conversation") || str_eq(t, "ExecutionContext")
|| str_eq(t, "InternalStateEvent") || str_eq(t, "Self") || str_eq(t, "Entity")
|| str_eq(t, "Process") || str_eq(t, "ConfigEntry") || str_eq(t, "Concept") || str_eq(t, "Imprint")
|| str_eq(t, "SessionSummary")
}
fn engram_valid_tier(t: String) -> Bool {
return str_eq(t, "Semantic") || str_eq(t, "Episodic") || str_eq(t, "Working")
|| str_eq(t, "Procedural") || str_eq(t, "Canonical") || str_eq(t, "Note") || str_eq(t, "Lesson")
}
// --- Node creation ---
fn engram_node(content: String, node_type: String, salience: Float) -> String {
if !engram_valid_node_type(node_type) {
__println("[engram] REJECTED node write — invalid node_type '" + node_type + "'")
return ""
}
return __engram_node(content, node_type, salience)
}
fn engram_node_full(content: String, nt: String, sal: Float, imp: Float,
source: String, lang: String, ts: Int, tags: String) -> String {
return __engram_node_full(content, nt, sal, imp, source, lang, ts, tags)
// Signature MUST match the C primitive __engram_node_full exactly (el_seed.h):
// (content, node_type, label, salience, importance, confidence, tier, tags)
// The previous wrapper declared a stale 8-arg schema with wrong names AND types
// (sal:Float at the label slot, ts:Int at the tier slot). Because el_val_t is an
// untyped machine word, the EL compiler coerced caller args to those wrong param
// types and then forwarded them BY POSITION into the C function so tier received
// an int, importance/confidence received strings, label received a float, etc.
// That is the field-corruption bug. Match the contract 1:1 no coercion, no reorder.
fn engram_node_full(content: String, node_type: String, label: String,
salience: Float, importance: Float, confidence: Float,
tier: String, tags: String) -> String {
if !engram_valid_node_type(node_type) {
__println("[engram] REJECTED node write — invalid node_type '" + node_type + "' (label=" + label + ")")
return ""
}
if !engram_valid_tier(tier) {
__println("[engram] REJECTED node write — invalid tier '" + tier + "' (node_type=" + node_type + ", label=" + label + ")")
return ""
}
return __engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags)
}
// --- Node retrieval ---
-9
View File
@@ -10,15 +10,6 @@
// export PATH="$HOME/.el/bin:$PATH"
// export EL_HOME="$HOME/.el"
// Imports
import "../../runtime/string.el"
import "../../runtime/env.el"
import "../../runtime/fs.el"
import "../../runtime/exec.el"
import "../../runtime/json.el"
import "../../runtime/http.el"
// Constants
fn gitea_releases_url() -> String {