Three separate places dropped an axis read on the floor:
- The producer map replaced a variable's record wholesale on every later
write, so a derivation or injector rebinding $outfit erased the wildcard's
axes. The engine keys __wp_axes__ by binding at pick time and a rebind
never clears it, so the axes must survive the override. Carried forward in
both the graph walk and the same-node sibling merge.
- The static preview resolver knew only the numeric .K accessor, so
"$outfit.SHOES" substituted $outfit and stranded ".SHOES" — the preview and
resolved lines both read "a white t-shirt and denim skirt.SHOES". It now
resolves an axis to its first tag, the same deterministic convention @{uuid}
expansion already uses, and leaves an accessor it cannot resolve verbatim
rather than deleting text.
- strip_internals runs at the prompt-render boundary and dropped every
__-prefixed key, __wp_axes__ and __wp_picks__ included. The assembler
therefore rendered "$outfit.SHOES" and "$outfit.0" as literal text while the
identical template resolved one node upstream. Those two tables are read by
key, never as variables, so keeping them cannot leak a $var.
48 lines
1.5 KiB
Python
48 lines
1.5 KiB
Python
"""The assembler must resolve the same accessor grammar a Combine does.
|
|
|
|
`$var.AXIS` and `$var.N` read tables the engine keeps under `__`-prefixed
|
|
keys. `strip_internals` runs at the prompt-render boundary and dropped every
|
|
such key, so the assembler rendered the accessor as literal text while the
|
|
identical template resolved correctly one node upstream.
|
|
"""
|
|
import random
|
|
|
|
from engine.context import strip_internals
|
|
from engine.template import resolve_variables
|
|
|
|
|
|
def _ctx() -> dict:
|
|
return {
|
|
"outfit": "a white t-shirt and denim skirt",
|
|
"__wp_rng__": random.Random(0),
|
|
"__wp_warnings__": [],
|
|
"__wp_axes__": {"outfit": {"SHOES": "sneakers"}},
|
|
"__wp_picks__": {},
|
|
}
|
|
|
|
|
|
def test_strip_internals_keeps_the_accessor_tables():
|
|
kept = strip_internals(_ctx())
|
|
assert kept["__wp_axes__"] == {"outfit": {"SHOES": "sneakers"}}
|
|
assert "__wp_picks__" in kept
|
|
|
|
|
|
def test_strip_internals_still_drops_bookkeeping_and_internal_vars():
|
|
ctx = _ctx()
|
|
ctx["__wp_trace__"] = ["noise"]
|
|
ctx["secret"] = "hidden"
|
|
ctx["__wp_internal_flags__"] = {"secret": True}
|
|
kept = strip_internals(ctx)
|
|
assert "__wp_trace__" not in kept
|
|
assert "secret" not in kept
|
|
|
|
|
|
def test_assembler_resolves_an_axis_read():
|
|
out = resolve_variables("wearing $outfit.SHOES", strip_internals(_ctx()))
|
|
assert out == "wearing sneakers"
|
|
|
|
|
|
def test_assembler_still_resolves_the_plain_var():
|
|
out = resolve_variables("wearing $outfit", strip_internals(_ctx()))
|
|
assert out == "wearing a white t-shirt and denim skirt"
|