iteration-1: the compiler stops adjudicating #164
@@ -3223,8 +3223,17 @@ fn cg_fn(stmt: Map<String, Any>) -> Void {
|
||||
// strengthen (self-activity) + a dharma bus event — so a decorated op
|
||||
// self-reports with ZERO hand-written instrumentation in its body. (VBD role
|
||||
// = the topmost decorator; write it topmost when stacking with @route.)
|
||||
if fn_has_decorator(stmt, "manager") || fn_has_decorator(stmt, "accessor") {
|
||||
emit_line(" engram_boundary_beat(EL_STR(" + c_str_lit(fn_name) + "));")
|
||||
// The beat carries the CONSTRUCT that caused it, not only the fn that beat.
|
||||
// Without it the graph accumulates boundary events with no way to attribute
|
||||
// them to the decorator responsible — so no construct can ever be measured,
|
||||
// and "is this decorator earning its keep" stays an argument instead of a
|
||||
// query. One parameter is the whole difference.
|
||||
if fn_has_decorator(stmt, "manager") {
|
||||
emit_line(" engram_boundary_beat(EL_STR(" + c_str_lit(fn_name) + "), EL_STR(" + c_str_lit("manager") + "));")
|
||||
} else {
|
||||
if fn_has_decorator(stmt, "accessor") {
|
||||
emit_line(" engram_boundary_beat(EL_STR(" + c_str_lit(fn_name) + "), EL_STR(" + c_str_lit("accessor") + "));")
|
||||
}
|
||||
}
|
||||
// Seed declared with parameter names so reassignment works
|
||||
let decl = native_list_empty()
|
||||
|
||||
@@ -16991,24 +16991,40 @@ void dharma_emit(el_val_t event_type, el_val_t payload) {
|
||||
free(b.buf);
|
||||
}
|
||||
|
||||
/* engram_boundary_beat(op_name) — the decorated-fn boundary AUTO-EMIT (VBD seam).
|
||||
* codegen injects a single call to this at the entry of every @manager/@accessor
|
||||
* decorated fn, so a decorated op self-reports with ZERO hand-written
|
||||
* instrumentation in its body:
|
||||
/* engram_boundary_beat(op_name, construct) — decorated-fn boundary AUTO-EMIT
|
||||
* (VBD seam). codegen injects a single call to this at the entry of every
|
||||
* @manager/@accessor decorated fn, so a decorated op self-reports with ZERO
|
||||
* hand-written instrumentation in its body:
|
||||
* (1) afferent counter++ — the boundary was crossed
|
||||
* (2) engram_chrono_tick() — interoception: the mind senses its own op firing
|
||||
* (3) engram_strengthen(self-anchor)— reinforce the self-activity anchor (an
|
||||
* activation-count/salience bump, NOT a content/edge write — identity
|
||||
* write-protection is untouched)
|
||||
* (4) dharma_emit(neuron.op.<name>) — provenance on the shared bus transport
|
||||
* (same bus the swarm peers field on); bumps _eg_dharma_emits. */
|
||||
el_val_t engram_boundary_beat(el_val_t op_name) {
|
||||
* (same bus the swarm peers field on); bumps _eg_dharma_emits.
|
||||
*
|
||||
* `construct` is the DECORATOR that caused the beat ("manager" / "accessor"),
|
||||
* carried in the payload. Before it, the beat reported which fn crossed a
|
||||
* boundary but never which construct put the beat there — so boundary events
|
||||
* accumulated in the graph with no attribution, and no decorator could ever be
|
||||
* measured. "Is this construct earning its keep" was an argument; with the
|
||||
* attribution it is a traversal. The payload is built here rather than at the
|
||||
* call site so the format has exactly one author.
|
||||
*
|
||||
* The construct name comes from a closed set codegen controls, so the
|
||||
* unescaped snprintf below cannot be injected through. That is NOT true of
|
||||
* dharma_emit generally — its payloads are hand-concatenated at 39 call sites
|
||||
* with no escaping, and a value containing a quote silently corrupts the
|
||||
* event. Fixing that is a separate change; this one does not add to it. */
|
||||
el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct) {
|
||||
_eg_aff_boundary_ops++;
|
||||
engram_chrono_tick();
|
||||
engram_strengthen(EL_STR("kn-efeb4a5b-5aff-4759-8a97-7233099be6ee"));
|
||||
const char* nm = EL_CSTR(op_name); if (!nm) nm = "";
|
||||
const char* nm = EL_CSTR(op_name); if (!nm) nm = "";
|
||||
const char* ct = EL_CSTR(construct); if (!ct) ct = "";
|
||||
char ev[160]; snprintf(ev, sizeof ev, "neuron.op.%s", nm);
|
||||
dharma_emit(el_wrap_str(el_strdup(ev)), EL_STR(""));
|
||||
char pl[192]; snprintf(pl, sizeof pl, "{\"construct\":\"%s\"}", ct);
|
||||
dharma_emit(el_wrap_str(el_strdup(ev)), el_wrap_str(el_strdup(pl)));
|
||||
return (el_val_t)0;
|
||||
}
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@ el_val_t engram_age_field(el_val_t delta_ms);
|
||||
el_val_t engram_age_field_catchup(void);
|
||||
el_val_t engram_chrono_persist_tick(void);
|
||||
el_val_t engram_chrono_tick(void);
|
||||
el_val_t engram_boundary_beat(el_val_t op_name); /* API-reshape decorator-seam auto-emit */
|
||||
el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct); /* API-reshape decorator-seam auto-emit; construct = the decorator that caused the beat */
|
||||
el_val_t engram_self_anchor_capture(void);
|
||||
el_val_t engram_self_drift_json(void);
|
||||
el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction);
|
||||
|
||||
@@ -460,7 +460,7 @@ The `@` token followed by an identifier attaches a decorator to the next `FnDef`
|
||||
| Decorator | Structural effect |
|
||||
|---|---|
|
||||
| `@manager` | Permits calls to `dharma_emit` / `dharma_field`. Calling either from a non-`@manager` fn emits a `#error` into the generated C — a compile-time failure, not a lint. |
|
||||
| `@manager`, `@accessor` | Codegen injects one call to `engram_boundary_beat(<fn name>)` at function entry. The decorated op self-reports (chrono tick, afferent counter, self-activity strengthen, dharma bus event) with **zero** hand-written instrumentation in its body. |
|
||||
| `@manager`, `@accessor` | Codegen injects one call to `engram_boundary_beat(<fn name>, <construct>)` at function entry, where `<construct>` is the decorator that caused the beat. The decorated op self-reports (chrono tick, afferent counter, self-activity strengthen, dharma bus event carrying `{"construct":"..."}`) with **zero** hand-written instrumentation in its body. Without the construct argument the graph accumulates boundary events with no attribution, so no construct can be measured. |
|
||||
| `@route(path, method, …)` | Records a route into a generated dispatch table. |
|
||||
|
||||
Decorators with no registered meaning are accepted and ignored.
|
||||
|
||||
@@ -726,3 +726,49 @@ test "compiler-stdint-include" {
|
||||
let out: String = compile_capture(src)
|
||||
assert str_contains(out, "stdint.h"), "output includes stdint.h"
|
||||
}
|
||||
|
||||
// ── Decorator seam: boundary-beat attribution ────────────────────────────────
|
||||
//
|
||||
// The beat carries the CONSTRUCT that caused it, not only the fn that beat.
|
||||
// Without the second argument the graph accumulates boundary events with no
|
||||
// way to attribute them to the decorator responsible, so no construct can ever
|
||||
// be measured and "is this decorator earning its keep" stays an argument
|
||||
// instead of a query.
|
||||
|
||||
test "decorator-manager-beat-carries-construct" {
|
||||
let src: String = "@manager\nfn f() -> Int { return 1 }"
|
||||
let out: String = compile_capture(src)
|
||||
assert str_contains(out, "engram_boundary_beat"), "@manager injects the beat"
|
||||
assert str_contains(out, "EL_STR(\"manager\")"), "beat carries the construct that caused it"
|
||||
}
|
||||
|
||||
test "decorator-accessor-beat-carries-construct" {
|
||||
let src: String = "@accessor\nfn f() -> Int { return 1 }"
|
||||
let out: String = compile_capture(src)
|
||||
assert str_contains(out, "engram_boundary_beat"), "@accessor injects the beat"
|
||||
assert str_contains(out, "EL_STR(\"accessor\")"), "beat carries the construct that caused it"
|
||||
}
|
||||
|
||||
test "decorator-undecorated-fn-has-no-beat" {
|
||||
let src: String = "fn f() -> Int { return 1 }"
|
||||
let out: String = compile_capture(src)
|
||||
assert !str_contains(out, "engram_boundary_beat"), "an undecorated fn does not beat"
|
||||
}
|
||||
|
||||
// ── Decorator seam: the twelve inert names ───────────────────────────────────
|
||||
//
|
||||
// PINS A KNOWN DEFECT. codegen calls fn_has_decorator for exactly three names
|
||||
// (manager, accessor, route). Twelve others parse, attach as {name,args}, and
|
||||
// compile to nothing — including four that look like protection:
|
||||
// @authenticate (6 uses), @authorize (3), @rate_limit (3), @validate (2).
|
||||
//
|
||||
// This test asserts the CURRENT behaviour so that fixing it is a visible
|
||||
// change rather than a silent one. When a pass wires or rejects these, this
|
||||
// test flips and that flip is the proof.
|
||||
|
||||
test "decorator-authenticate-compiles-to-nothing" {
|
||||
let src: String = "@authenticate\nfn f() -> Int { return 1 }"
|
||||
let out: String = compile_capture(src)
|
||||
let bare: String = compile_capture("fn f() -> Int { return 1 }")
|
||||
assert str_eq(out, bare), "KNOWN DEFECT: @authenticate emits identical C to no decorator at all"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user