self-review 2026-05-17: fix heartbeat JSON validity for unset state keys

state_get() returns "" for unset keys. Both soul.pulse and soul_boot_count
could be empty on first heartbeat cycle, producing invalid JSON like
{"event":"heartbeat","pulse":,"boot":,...}. Add defensive guards:
if str_eq(raw, "") { "0" } else { raw } for both fields.
This commit is contained in:
2026-05-17 08:40:02 -05:00
parent e5364e7292
commit ffd17b2774
4 changed files with 90 additions and 60 deletions
+25 -1
View File
@@ -1,4 +1,3 @@
/* Auto-generated C forward declarations for all ELP modules */
#pragma once
#include "el_runtime.h"
@@ -82,6 +81,7 @@ el_val_t ang_willan_present(el_val_t slot);
el_val_t ang_witan_past(el_val_t slot);
el_val_t ang_witan_present(el_val_t slot);
el_val_t api_err(el_val_t msg);
el_val_t api_err_protected(el_val_t id);
el_val_t api_json_escape(el_val_t s);
el_val_t api_nonempty(el_val_t s);
el_val_t api_ok(el_val_t extra);
@@ -121,6 +121,7 @@ el_val_t awareness_run(void);
el_val_t axon_get(el_val_t path);
el_val_t axon_post(el_val_t path, el_val_t body);
el_val_t build_form_from_json(el_val_t semantic_form_json, el_val_t lang_code);
el_val_t build_identity_from_graph(void);
el_val_t build_np(el_val_t referent, el_val_t slots);
el_val_t build_pp(el_val_t loc);
el_val_t build_rules(void);
@@ -128,6 +129,7 @@ el_val_t build_system_prompt(el_val_t ctx);
el_val_t build_vocab(void);
el_val_t build_vp_body(el_val_t slots);
el_val_t build_vp_from_slots(el_val_t slots);
el_val_t call_neuron_mcp(el_val_t tool_name, el_val_t args_json);
el_val_t capitalize_first(el_val_t s);
el_val_t chat_default_model(void);
el_val_t clean_llm_response(el_val_t s);
@@ -219,9 +221,12 @@ el_val_t egy_slot_with_gender(el_val_t person, el_val_t gender, el_val_t number)
el_val_t egy_str_ends(el_val_t s, el_val_t suf);
el_val_t egy_str_len(el_val_t s);
el_val_t egy_suffix_pronoun(el_val_t slot);
el_val_t elapsed_human(void);
el_val_t elapsed_ms(void);
el_val_t elp_detect_predicate(el_val_t msg);
el_val_t elp_extract_topic(el_val_t msg);
el_val_t elp_parse(el_val_t msg);
el_val_t emit_heartbeat(void);
el_val_t emit_session_start_event(void);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
@@ -372,6 +377,7 @@ el_val_t fro_venir_past(el_val_t slot);
el_val_t fro_venir_present(el_val_t slot);
el_val_t fro_verb_class(el_val_t verb);
el_val_t fro_verb_stem(el_val_t verb, el_val_t vclass);
el_val_t gemini_api_key(void);
el_val_t generate(el_val_t semantic_form_json);
el_val_t generate_frame(el_val_t frame);
el_val_t generate_frame_lang(el_val_t frame, el_val_t lang_code);
@@ -527,8 +533,11 @@ el_val_t handle_api_browse_processes(el_val_t method, el_val_t path, el_val_t bo
el_val_t handle_api_capture_knowledge(el_val_t body);
el_val_t handle_api_compile_ctx(el_val_t body);
el_val_t handle_api_consolidate(el_val_t body);
el_val_t handle_api_cultivate(el_val_t body);
el_val_t handle_api_define_process(el_val_t body);
el_val_t handle_api_evolve_knowledge(el_val_t body);
el_val_t handle_api_evolve_memory(el_val_t body);
el_val_t handle_api_forget(el_val_t body);
el_val_t handle_api_inspect_config(el_val_t path, el_val_t body);
el_val_t handle_api_inspect_graph(el_val_t method, el_val_t path, el_val_t body);
el_val_t handle_api_link_entities(el_val_t body);
@@ -611,11 +620,16 @@ el_val_t hi_verb_stem(el_val_t infinitive);
el_val_t hi_verb_stem_clean(el_val_t infinitive);
el_val_t hist_append(el_val_t hist, el_val_t role, el_val_t content);
el_val_t hist_trim(el_val_t hist);
el_val_t idle_count(void);
el_val_t idle_inc(void);
el_val_t idle_reset(void);
el_val_t init_soul_edges(void);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t is_pronoun(el_val_t word);
el_val_t is_protected_node(el_val_t id);
el_val_t is_vowel(el_val_t c);
el_val_t ise_post(el_val_t content);
el_val_t ja_conjugate(el_val_t dict_form, el_val_t form);
el_val_t ja_godan_stem_change(el_val_t dict_form, el_val_t row);
el_val_t ja_ichidan_stem(el_val_t dict_form);
@@ -714,6 +728,8 @@ el_val_t lex_class(el_val_t entry);
el_val_t lex_form(el_val_t entry, el_val_t idx);
el_val_t lex_pos(el_val_t entry);
el_val_t lex_word(el_val_t entry);
el_val_t llm_call_gemini(el_val_t model, el_val_t system, el_val_t message);
el_val_t llm_call_grok(el_val_t model, el_val_t system, el_val_t message);
el_val_t load_identity_context(void);
el_val_t make_action(el_val_t kind, el_val_t payload);
el_val_t make_entry(el_val_t word, el_val_t pos, el_val_t f0, el_val_t f1, el_val_t f2, el_val_t f3, el_val_t f4, el_val_t cls);
@@ -905,6 +921,8 @@ el_val_t sa_vad_future(el_val_t slot);
el_val_t sa_vad_past(el_val_t slot);
el_val_t sa_vad_present(el_val_t slot);
el_val_t scan_token(el_val_t s, el_val_t start);
el_val_t security_research_authorized(void);
el_val_t seed_persona_from_env(void);
el_val_t sem_first_modifier(el_val_t mods);
el_val_t sem_frame(el_val_t intent, el_val_t subject, el_val_t obj, el_val_t modifiers);
el_val_t sem_frame_lang(el_val_t intent, el_val_t subject, el_val_t obj, el_val_t modifiers, el_val_t lang_code);
@@ -1006,6 +1024,11 @@ el_val_t sw_subj_prefix(el_val_t person, el_val_t number, el_val_t noun_class);
el_val_t sw_tense_marker(el_val_t tense);
el_val_t sw_verb_final(el_val_t tense, el_val_t negative);
el_val_t sw_verb_stem(el_val_t infinitive);
el_val_t threat_history_append(el_val_t text);
el_val_t threat_score_command(el_val_t cmd);
el_val_t threat_score_history(el_val_t history);
el_val_t threat_score_path(el_val_t path);
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input);
el_val_t tier_canonical(void);
el_val_t tier_episodic(void);
el_val_t tier_working(void);
@@ -1055,3 +1078,4 @@ el_val_t vocab_by_pos(el_val_t pos);
el_val_t vocab_lookup(el_val_t word, el_val_t lang_code);
el_val_t vocab_lookup_en(el_val_t word);
el_val_t vocab_synonym(el_val_t word, el_val_t lang_register, el_val_t lang_code);
el_val_t xai_api_key(void);