Files
DumiFlex ef2535548f feat(constraint): instance-only matrix cells — empty-cell overrides become new entries at resolve
The previous commit let users cycle empty matrix cells in the modal but
the engine only iterated `payload.matrix` — overrides for keys absent
from the library were silently ignored. Cycling produced dead UI: state
saved, engine ignored, runtime identical.

Engine extension: after the library-merge pass, do a second pass over
`cell_mode_overrides` ∪ `cell_factor_overrides` minus `covered_keys`.
Each leftover key becomes a new matrix entry with implicit baseline
mode "allow" + factor 1.0; whichever side(s) the user set populate the
rest. Disabled set still wins — entries in `disabled_matrix_cells` skip
both passes.

Added `decode_key` helper alongside `encode_key` for the second-pass
src/tgt extraction. Round-trip + malformed-input rejection covered by
new key tests. Malformed override keys in the resolve path are skipped
silently rather than crashing the run (defensive — instance JSON could
have rotted across schema migrations).

Updated the existing "unknown key silently ignored" test to assert the
new behavior (entry created from override). Added focused tests for:
factor-only override defaults to allow mode, disabled set still skips
empty-cell overrides, malformed key in override map doesn't crash.
2026-05-10 14:50:18 +03:00

59 lines
1.7 KiB
Python

"""Cross-language fitness test for composite-key encoding.
Reads the JSON fixture written by the Vitest fitness writer
(`src/components/context/editors/instance/keys.fitness.ts`) and asserts
Python `encode_key` produces byte-exact identical output for each input.
If JS encoding ever drifts from Python (e.g. someone changes the
separators or escape strategy), this test fails before the divergence
ships to users.
"""
import json
import pathlib
import pytest
from engine.modules._keys import decode_key, encode_key
FIXTURE = pathlib.Path(__file__).parent / "fixtures" / "encode_key_js_outputs.json"
def test_python_matches_js_outputs():
assert FIXTURE.exists(), (
"Fixture missing — regenerate via "
"`npx tsx src/components/context/editors/instance/keys.fitness.ts`"
)
cases = json.loads(FIXTURE.read_text(encoding="utf-8"))
for case in cases:
py_output = encode_key(case["input"])
assert py_output == case["output"], (
f"input={case['input']!r}: js={case['output']!r} py={py_output!r}"
)
def test_decode_key_round_trip():
cases = [
["red", "black"],
["", ""],
["ascii", "unicode-é"],
["with,comma", "with]bracket"],
]
for parts in cases:
encoded = encode_key(parts)
assert decode_key(encoded) == parts
def test_decode_key_rejects_non_array():
with pytest.raises(ValueError):
decode_key('"just-a-string"')
def test_decode_key_rejects_array_with_non_strings():
with pytest.raises(ValueError):
decode_key('["red",42]')
def test_decode_key_rejects_malformed_json():
with pytest.raises(ValueError):
decode_key("not-json")