make boundary crossings attributable to the construct that caused them
The beat reported which function crossed a boundary, never which decorator
put the beat there. So the graph accumulated boundary events with no
attribution, and no construct could be measured — "is this decorator
earning its keep" stayed an argument instead of a traversal.
engram_boundary_beat now takes the construct and carries it on the bus as
{"construct":"..."}. The injection point, the beat, and the accumulation
already existed; only the attribution was missing.
Also pins a known defect as a test: codegen calls fn_has_decorator for
exactly three names (manager, accessor, route). Twelve others parse, attach,
and compile to nothing — including @authenticate (6 uses), @authorize (3),
@rate_limit (3) and @validate (2), which look like protection and are not.
decorator-authenticate-compiles-to-nothing asserts that @authenticate emits
byte-identical C to no decorator at all, so fixing it will be a visible flip.
Verified: compiler self-hosts byte-identically, 86/86 native compiler tests
pass, emitted C carries the construct for both @manager and @accessor.
This commit is contained in:
@@ -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