Extension Checklist¶
An executor implementation is considered Lace Extension Compatible when it satisfies all items in this checklist. Partial compatibility must be documented -- an executor may declare which sections it supports.
Spec version: 0.9.0
1. Extension Loading¶
- [ ] Reads
.laceextfiles listed inlace.configat startup - [ ] Fails with a clear error if a listed extension file is not found
- [ ] Loads extensions in the order listed in config
- [ ] Parses the TOML structure and validates it against the
.laceextschema - [ ] Rejects
.laceextfiles with unknown top-level sections (warning, not error)
2. Schema Additions¶
- [ ] Registers extension fields with the validator at the declared targets
- [ ] Accepts registered fields without error when extension is active
- [ ] Emits unknown-field warnings (not errors) for extension fields when extension is inactive
- [ ] Does not emit errors for unknown fields in
options {}blocks regardless of extension state
3. Rule Body Language¶
- [ ] Parses rule bodies and function bodies using the grammar in
lace-extensions.mdsection 5.1 - [ ] Executes
foriteration with named binding; skips body when collection is null - [ ] Executes inline
when expras a guard that exits current scope on false/null - [ ] Executes block
when expr:as a conditional block skip - [ ] Executes
let $name = expras an immutable local binding within current scope - [ ] Rejects rebinding the same
$namein the same scope - [ ] Executes
set $name = expras reassignment of an existing binding (walks up scope chain) - [ ] Rejects
setin rule bodies -- parse error - [ ] Rejects
seton an unbound name -- runtime error - [ ] Executes
emit target <- { fields }as an append to the target array - [ ] Rejects
emitto paths not declared in[result]orresult.runVars - [ ] Executes
exitas immediate exit from rule body - [ ] Rejects
exitinside function bodies -- parse error - [ ] Rejects
returninside rule bodies -- parse error - [ ] Executes
return exprinside function bodies only
4. Expressions¶
- [ ] Evaluates all arithmetic operators with correct type rules (
lace-extensions.mdsection 5.3, 5.4) - [ ] Evaluates all comparison operators with correct type rules
- [ ] Evaluates
and,or,notwith short-circuit evaluation - [ ] Null propagation: field access, array index, array filter on null returns null (
lace-extensions.mdsection 5.5) - [ ]
null eq nullevaluates totrue - [ ]
not nullevaluates totrue - [ ] Array filter
[? condition]returns first matching element or null - [ ] Ternary
a ? b : cevaluates correctly; falsya(false or null) takes thecbranch - [ ] String concatenation with
+ - [ ] No implicit type coercion -- incompatible types return null
5. Primitives¶
- [ ]
compare(a, b)returns correct op key for all comparable type pairs; null for null/incomparable inputs - [ ]
map_get(map, key)returns correct value; falls back to"default"; null for absent/null - [ ]
map_match(map, actual, expected, op)tries literal key, then op key, then"default"in order - [ ]
is_null(v)returns bool correctly - [ ]
type_of(v)returns correct type string for all value types - [ ]
to_string(v)returns string representation for all value types - [ ]
replace(str, pattern, replacement)performs string substitution; null-safe
6. Functions¶
- [ ] Parses function definitions from
[functions]section - [ ] Calls extension functions by name from rule bodies and other functions
- [ ] Parameters bound as
$param_name - [ ]
return exprexits function and produces value - [ ] Function reaching end without
returnreturns null - [ ] Rejects recursive calls (cycle detection at load time)
- [ ] Functions cannot
emitor accessresultdirectly
7. Hook Points¶
- [ ]
on before callfires before any chain method on a call executes - [ ]
on callfires after all chain methods on a call complete - [ ]
on before expectfires before each.expect()scope is evaluated - [ ]
on expectfires after each.expect()scope is evaluated (once per scope, not once per method) - [ ]
on before check/on check-- same as expect for.check() - [ ]
on before assert/on assertfires per condition in.assert() - [ ]
on before store/on storefires per entry in.store() - [ ] Rules from multiple extensions at the same hook are ordered per
lace-extensions.mdsection 8.1.1 -- by explicitafter/beforequalifiers and implicitafteredges fromrequire, topo-sorted with ties broken deterministically (declaration order within a file, then extension name alphabetically). Executors must not rely onlace.configload order for determinism. - [ ] Rules within a single extension run in declaration order (unless explicit ordering qualifiers say otherwise)
8. Extension Variables¶
- [ ]
emit result.runVars <- { key: value }merges intorunVars - [ ] Rejects keys not prefixed with
{extension_name}.-- records warning, continues - [ ] Extension variables appear in final
runVarsmap - [ ] Extension variables are not injected into the script's
$varnamespace - [ ] Values may be any JSON-serialisable shape (scalar, object, or array)
9. Configuration¶
- [ ] Loads sibling
{extName}.configfile when present (lace-extensions.mdsection 2.3); absence is not an error - [ ] Reads
[extensions.{name}]config section fromlace.config - [ ] Merges
.configdefaults withlace.configoverrides perlace-extensions.mdsection 11.1 (overrides win, defaults preserved for absent keys) - [ ] Provides merged
configobject to rule bodies containing the extension's config values - [ ] Resolves
env:VARNAMEandenv:VARNAME:defaultinlace.configvalues at startup (not in.configdefaults)
10. Result Conformance¶
- [ ]
emit result.actions.{key}initialises to[]if not yet present - [ ] Final result contains all emitted extension fields under
actions - [ ] Extension variables appear in
runVarswith correct prefixes - [ ] Core result fields (
calls,outcome,runVarsscript entries,startedAt,endedAt) are never mutated by extension rules