Files
DumiFlex 4ff45d2492 feat(toggles): every toggle can have a Value and a Negative, plus $name.bool (#367)
A toggle with a Value writes it to its variable while on and nothing while off; its Negative goes with the variable. $name.bool reads the switch (true/false) across nodes, in text and in conditions, through __wp_toggle_bools__. Payloads reading $name.bool stamp schema 12; bool is reserved as a tag group.
2026-11-12 02:12:08 +01:00

253 lines
9.4 KiB
Python

from engine.migrations import (
CURRENT_SCHEMA_VERSION,
MAX_KNOWN_SCHEMA_VERSION,
migrate_payload,
)
EMPTY_7 = {
"bundles": [], "wildcards": [], "fixed_values": [],
"combines": [], "derivations": [], "constraints": [], "categories": [],
}
def test_returns_payload_as_is_at_current_version():
payload = {"schema_version": CURRENT_SCHEMA_VERSION, **EMPTY_7}
result = migrate_payload(payload)
assert result["ok"] is True
assert result["migrated"] == payload
assert result["migrated_entity_count"] == 0
def test_rejects_future_version():
# The reject threshold is MAX_KNOWN (6), not CURRENT (2): only versions
# beyond what the runtime natively supports are rejected.
payload = {"schema_version": MAX_KNOWN_SCHEMA_VERSION + 1, **EMPTY_7}
result = migrate_payload(payload)
assert result["ok"] is False
assert "future" in result["reason"].lower()
def test_rejects_missing_version():
result = migrate_payload({**EMPTY_7})
assert result["ok"] is False
assert "schema_version" in result["reason"]
def test_walks_chain_to_current():
v0_payload = {
"schema_version": 0,
**EMPTY_7,
"wildcards": [{"uuid": "u", "name": "old"}],
}
result = migrate_payload(v0_payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == CURRENT_SCHEMA_VERSION
assert result["migrated"]["wildcards"][0]["migrated_from"] == 0
# 2 chain steps (v0->v1, v1->v2) each pass the 1 wildcard => count 2.
assert result["migrated_entity_count"] == 2
def test_walks_chain_on_empty_payload():
v0_empty = {"schema_version": 0, **EMPTY_7}
result = migrate_payload(v0_empty)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == CURRENT_SCHEMA_VERSION
assert result["migrated_entity_count"] == 0
def test_tags_fixed_values_combines_derivations_categories():
v0_payload = {
"schema_version": 0,
"bundles": [],
"wildcards": [],
"fixed_values": [{"uuid": "fv1", "name": "fv"}],
"combines": [{"uuid": "cb1", "name": "cb"}],
"derivations": [{"uuid": "dr1", "name": "dr"}],
"constraints": [],
"categories": [{"uuid": "cat1", "name": "cat"}],
}
result = migrate_payload(v0_payload)
assert result["ok"] is True
assert result["migrated"]["fixed_values"][0]["migrated_from"] == 0
assert result["migrated"]["combines"][0]["migrated_from"] == 0
assert result["migrated"]["derivations"][0]["migrated_from"] == 0
assert result["migrated"]["categories"][0]["migrated_from"] == 0
def test_sums_all_7_arrays_for_migrated_entity_count():
v0_payload = {
"schema_version": 0,
"bundles": [{"uuid": "b1"}],
"wildcards": [{"uuid": "w1"}],
"fixed_values": [{"uuid": "fv1"}],
"combines": [{"uuid": "cb1"}],
"derivations": [{"uuid": "dr1"}],
"constraints": [{"uuid": "c1"}],
"categories": [{"uuid": "cat1"}],
}
result = migrate_payload(v0_payload)
assert result["ok"] is True
# 7 entities x 2 chain steps (v0->v1, v1->v2) = 14.
assert result["migrated_entity_count"] == 14
def test_defaults_missing_arrays_to_empty():
# A partial payload (missing new buckets) should still succeed —
# migrate_payload fills them in via .get("key", []).
partial = {"schema_version": CURRENT_SCHEMA_VERSION, "wildcards": [{"uuid": "w1"}]}
result = migrate_payload(partial)
assert result["ok"] is True
assert result["migrated"]["fixed_values"] == []
assert result["migrated"]["combines"] == []
assert result["migrated"]["derivations"] == []
assert result["migrated"]["categories"] == []
# === Install-path fork: accept natively-supported future versions ==========
# Mirror of the TS `migrateImportEnvelope` fork. A payload at
# CURRENT < v <= MAX_KNOWN (v3 = text-grammar only; v4 = additive
# `target_select`; v5 = additive `accepts` tag axes; v6 = the constraint
# `only` rule; v7 = derivation AND / OR condition groups; v8 = send-to-negative
# `negative` text; v9 = the wildcard `fallback` option flag; v10 = NOT tests;
# v11 = `$name` terms in filters; v12 = `$name.bool`) is shape-compatible with
# v2 and natively handled at runtime, so the engine's commit-side re-validate must accept it AS-IS:
# not rejected, not migrated (the while-loop bound stays CURRENT so there is
# nothing to do), schema_version preserved. Only v > MAX_KNOWN rejects.
def test_max_known_schema_version_is_12():
assert MAX_KNOWN_SCHEMA_VERSION == 12
def test_v3_payload_passes_through_unchanged():
payload = {
"schema_version": 3,
**EMPTY_7,
"wildcards": [
{"id": "wcaaa", "payload": {"options": [
{"id": "o", "value": "{1-2$$a|b}", "weight": 1}]}}
],
}
result = migrate_payload(payload)
assert result["ok"] is True
# No migration ran — schema_version preserved, count zero.
assert result["migrated"]["schema_version"] == 3
assert result["migrated_entity_count"] == 0
def test_v4_target_select_payload_passes_through_unchanged():
payload = {
"schema_version": 4,
**EMPTY_7,
"constraints": [
{"id": "cn001", "type": "constraint", "name": "c", "payload": {
"source_wildcard_id": "wcaaa", "target_wildcard_id": "wcbbb",
"matrix": {}, "exceptions": [],
"target_select": {"mode": "next", "count": 2}}}
],
}
result = migrate_payload(payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == 4
assert result["migrated_entity_count"] == 0
# The additive target_select field survives verbatim.
cn = result["migrated"]["constraints"][0]
assert cn["payload"]["target_select"] == {"mode": "next", "count": 2}
def test_v5_accepts_axis_payload_passes_through_unchanged():
payload = {
"schema_version": 5,
**EMPTY_7,
"wildcards": [
{"id": "wcaxs", "type": "wildcard", "name": "outfit", "payload": {
"tag_groups": {"SHOES": ["boots"]},
"tag_group_kinds": {"SHOES": "accepts"},
"options": [{"id": "o", "value": "hiker", "weight": 1,
"sub_categories": ["boots"]}]}}
],
}
result = migrate_payload(payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == 5
assert result["migrated_entity_count"] == 0
wc = result["migrated"]["wildcards"][0]
assert wc["payload"]["tag_group_kinds"] == {"SHOES": "accepts"}
def test_v6_only_rule_payload_passes_through_unchanged():
only = {"source_value": "maid", "target_value": "apron", "mode": "only", "factor": 1.0}
payload = {
"schema_version": 6,
**EMPTY_7,
"constraints": [
{"id": "cnonly", "type": "constraint", "name": "link", "payload": {
"source_wildcard_id": "a", "target_wildcard_id": "b",
"matrix": {}, "exceptions": [only]}}
],
}
result = migrate_payload(payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == 6
assert result["migrated_entity_count"] == 0
assert result["migrated"]["constraints"][0]["payload"]["exceptions"] == [only]
def test_v7_condition_group_payload_passes_through_unchanged():
condition = {"match": "any", "conditions": [
{"var": "mood", "op": "equals", "value": "calm"},
{"var": "time", "op": "is_empty", "value": ""},
]}
payload = {
"schema_version": 7,
**EMPTY_7,
"derivations": [
{"id": "dvgroup", "type": "derivation", "name": "d", "payload": {"rules": [
{"id": "r1", "branches": [{
"condition": condition,
"action": {"target_var": "light", "mode": "replace", "value": "soft"},
}]},
]}}
],
}
result = migrate_payload(payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == 7
assert result["migrated_entity_count"] == 0
branch = result["migrated"]["derivations"][0]["payload"]["rules"][0]["branches"][0]
assert branch["condition"] == condition
def test_v8_negative_payload_passes_through_unchanged():
payload = {
"schema_version": 8,
**EMPTY_7,
"wildcards": [
{"id": "wcneg", "payload": {"options": [
{"id": "o", "value": "red hair", "weight": 1, "negative": "blonde"}]}}
],
}
result = migrate_payload(payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == 8
assert result["migrated_entity_count"] == 0
opt = result["migrated"]["wildcards"][0]["payload"]["options"][0]
assert opt["negative"] == "blonde"
def test_v2_still_migrates_from_older_version():
v0_payload = {"schema_version": 0, **EMPTY_7, "wildcards": [{"uuid": "u", "name": "old"}]}
result = migrate_payload(v0_payload)
assert result["ok"] is True
assert result["migrated"]["schema_version"] == CURRENT_SCHEMA_VERSION
assert result["migrated"]["wildcards"][0]["migrated_from"] == 0
def test_v5_payload_still_rejects_with_future_error():
payload = {"schema_version": MAX_KNOWN_SCHEMA_VERSION + 1, **EMPTY_7}
result = migrate_payload(payload)
assert result["ok"] is False
assert "future" in result["reason"].lower()
# The reject reason names the max-known ceiling, not the chain head.
assert str(MAX_KNOWN_SCHEMA_VERSION) in result["reason"]