From 40653d2aa109e9ce2fc54295292e49898cfca7fb Mon Sep 17 00:00:00 2001 From: Neuron Date: Sun, 9 Aug 2026 13:36:51 -0500 Subject: [PATCH] =?UTF-8?q?fix(codegen):=20emit=20the=20declared=20cgi=20i?= =?UTF-8?q?dentity=20=E2=80=94=20it=20was=20searched=20for=20in=20a=20list?= =?UTF-8?q?=20that=20cannot=20contain=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A cgi block is a top-level declaration, so codegen_streaming classifies it via is_top_level_decl and releases it. The identity emission then searched toplevel_exec_stmts for that same block. Declarations are excluded from that list by construction, so the search could never succeed. A probe printed what it actually saw for a program whose first statement is a cgi block: [Let, Expr]. It emitted nothing, silently, with no diagnostic on any channel. The code documented its own assumption — 'Since cgi blocks are rare and small, they end up in toplevel_exec_stmts' — and that assumption was false. Capture the declared values before the release and emit from them. The search is deleted rather than repaired, so the failure mode is removed rather than relocated. Proven discriminating (old fails, new passes): minimal cgi program, old -> 0 el_cgi_init minimal cgi program, fixed -> el_cgi_init with all four declared values neuron soul, fixed -> principal present in the compiled binary (0 before), boots in 2s, interface 110 routes in / 110 out Consequence: a binary now carries its declared identity as a compiled constant, which is what the identity protocol requires. Whether the runtime surfaces it to state_get("soul_principal") is unverified and separate. Co-Authored-By: Claude Opus 5 (1M context) --- lang/el-compiler/src/codegen.el | 70 ++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/lang/el-compiler/src/codegen.el b/lang/el-compiler/src/codegen.el index 917fb31..f948872 100644 --- a/lang/el-compiler/src/codegen.el +++ b/lang/el-compiler/src/codegen.el @@ -3626,6 +3626,24 @@ fn codegen_streaming(tokens: [Any], sigs: [Map], source: String) -> let pos: Int = 0 let el_main_body: [Map] = native_list_empty() let toplevel_exec_stmts: [Map] = native_list_empty() + // CGI IDENTITY CAPTURE (2026-08-09). A cgi block is a top-level DECLARATION, so + // the classifier below correctly excludes it from toplevel_exec_stmts and calls + // el_release on it. The identity emission further down then searched + // toplevel_exec_stmts for it — a list that structurally can never contain it — + // found nothing, and emitted nothing, silently. Measured: that search sees only + // [Let, Expr] for a program whose first statement is a cgi block. + // Fix: copy the values out BEFORE the release (strings, so no dangling reference) + // and emit from these. No search, so the failure mode is removed rather than moved. + let cgi_have: Bool = false + let cgi_name_v: String = "" + let cgi_did_v: String = "" + let cgi_prin_v: String = "" + let cgi_net_v: String = "" + let cgi_eng_v: String = "" + let cgi_has_did: Bool = false + let cgi_has_prin: Bool = false + let cgi_has_net: Bool = false + let cgi_has_eng: Bool = false let has_toplevel_exec: Bool = false let stream_running: Bool = true @@ -3736,6 +3754,20 @@ fn codegen_streaming(tokens: [Any], sigs: [Map], source: String) -> if is_top_level_decl(stmt) { // Import, TypeDef, EnumDef, CgiBlock, ServiceBlock, ExternFn // These are no-ops in codegen (forward decls already emitted) + // — except a CgiBlock, whose declared identity must survive + // this release to be emitted as a compiled constant. + if str_eq(sk, "CgiBlock") { + let cgi_have = true + let cgi_name_v = stmt["name"] + let cgi_did_v = stmt["dharma_id"] + let cgi_prin_v = stmt["principal"] + let cgi_net_v = stmt["network"] + let cgi_eng_v = stmt["engram"] + let cgi_has_did = stmt["has_dharma_id"] + let cgi_has_prin = stmt["has_principal"] + let cgi_has_net = stmt["has_network"] + let cgi_has_eng = stmt["has_engram"] + } el_release(stmt) } else { if str_eq(sk, "Let") { @@ -3814,33 +3846,17 @@ fn codegen_streaming(tokens: [Any], sigs: [Map], source: String) -> let sig2 = native_list_get(sigs, si2) let sk3: String = sig2["kind"] if str_eq(sk3, "cgi_block") { - // We need the full cgi_block data — it was parsed by scan_fn_sigs - // but scan only stored the name. For cgi_init we need dharma_id etc. - // Since cgi blocks are rare and small, they end up in toplevel_exec_stmts. - // Find the CgiBlock in toplevel_exec_stmts. - let tes_n: Int = native_list_len(toplevel_exec_stmts) - let tes_i: Int = 0 - while tes_i < tes_n { - let tes = native_list_get(toplevel_exec_stmts, tes_i) - let tes_k: String = tes["stmt"] - if str_eq(tes_k, "CgiBlock") { - let cname2: String = tes["name"] - let cdid2: String = tes["dharma_id"] - let cprin2: String = tes["principal"] - let cnet2: String = tes["network"] - let ceng2: String = tes["engram"] - let has_did2: Bool = tes["has_dharma_id"] - let has_prin2: Bool = tes["has_principal"] - let has_net2: Bool = tes["has_network"] - let has_eng2: Bool = tes["has_engram"] - let arg_name2: String = "EL_STR(" + c_str_lit(cname2) + ")" - let arg_did2: String = cgi_arg(cdid2, has_did2) - let arg_prin2: String = cgi_arg(cprin2, has_prin2) - let arg_net2: String = cgi_arg(cnet2, has_net2) - let arg_eng2: String = cgi_arg(ceng2, has_eng2) - emit_line(" el_cgi_init(" + arg_name2 + ", " + arg_did2 + ", " + arg_prin2 + ", " + arg_net2 + ", " + arg_eng2 + ");") - } - let tes_i = tes_i + 1 + // Emit from the values captured before the declaration was released. + // The previous implementation searched toplevel_exec_stmts, which by + // construction never contains a declaration — so it emitted nothing and + // said nothing. See the capture block near toplevel_exec_stmts init. + if cgi_have { + let arg_name2: String = "EL_STR(" + c_str_lit(cgi_name_v) + ")" + let arg_did2: String = cgi_arg(cgi_did_v, cgi_has_did) + let arg_prin2: String = cgi_arg(cgi_prin_v, cgi_has_prin) + let arg_net2: String = cgi_arg(cgi_net_v, cgi_has_net) + let arg_eng2: String = cgi_arg(cgi_eng_v, cgi_has_eng) + emit_line(" el_cgi_init(" + arg_name2 + ", " + arg_did2 + ", " + arg_prin2 + ", " + arg_net2 + ", " + arg_eng2 + ");") } } let si2 = si2 + 1