CROSSWIRE / tests /test_adaptive.py
Kai9987kai's picture
Release crosswire-formal-synthesis-2026-11-03 from GitHub 91e7ac87c4e4
450ac2f verified
Raw History Blame Contribute Delete
4.17 kB
import copy
import pytest
from crosswire.core import CandidateSpace, Contract, Machine
def routing_space(temporal=False):
rows = (((1, 0), (1, 3), (1, 3)),
((2, 0), (2, 3), (2, 3)),
((3, 0), (3, 3), (3, 3)),
((4, 1), (5, 2), (5, 2)),
((4, 1), (4, 1), (4, 1)),
((5, 2), (5, 2), (5, 2)))
return CandidateSpace(Machine('routing', rows), Contract(horizon=4), temporal)
def test_contingent_policy_succeeds_where_no_fixed_word_exists():
from crosswire.adaptive import synthesize_policy, verify_policy
space = routing_space()
ids = space.survivors([])
assert not space.plan(ids)['admitted']
result = synthesize_policy(space, ids)
assert result['admitted'] and result['word'] is None
checked = verify_policy(space, ids, result['policy'])
assert checked['valid'] and checked['worst_case_steps'] == 4
# Independently execute the tree against every candidate, not just one seed.
for aid in ids:
node, word = result['policy'], ()
while 'action' in node:
word += (node['action'],)
assert space.contract.hazard not in space.semantic(aid, word)
node = node['branches'][str(space.predict(aid, word)[-1])]
assert node == {'stop': True}
assert space.contract.accepts(space.semantic(aid, word))
def test_certificate_rejects_missing_extra_unsafe_and_early_stop_branches():
from crosswire.adaptive import synthesize_policy, verify_policy
space = routing_space()
ids = space.survivors([])
tree = synthesize_policy(space, ids)['policy']
missing = copy.deepcopy(tree)
missing['branches'].pop(next(iter(missing['branches'])))
assert not verify_policy(space, ids, missing)['valid']
extra = copy.deepcopy(tree)
extra['branches']['99'] = {'stop': True}
assert not verify_policy(space, ids, extra)['valid']
assert not verify_policy(space, ids, {'stop': True})['valid']
assert not verify_policy(space, (), tree)['valid']
damaged = copy.deepcopy(tree)
node = damaged
while 'action' in node:
if all('stop' in child for child in node['branches'].values()):
node['action'] = (node['action'] + 1) % 3
break
node = next(iter(node['branches'].values()))
assert not verify_policy(space, ids, damaged)['valid']
def test_search_limit_and_empty_belief_never_admit():
from crosswire.adaptive import synthesize_policy
space = routing_space()
result = synthesize_policy(space, space.survivors([]), node_limit=1)
assert not result['admitted'] and result['status'] == 'SEARCH_LIMIT'
assert not result['search']['complete']
assert synthesize_policy(space, ())['status'] == 'FAMILY_CONTRADICTED'
with pytest.raises((ValueError, TypeError)):
synthesize_policy(space, (0,), node_limit=True)
def test_temporal_policy_checks_current_hazard_not_delayed_symbol():
from crosswire.adaptive import verify_policy
space = routing_space(True)
aid = next(a.id for a in space.adapters if a.delay == 1
and a.input_map == (0, 1, 2) and a.output_map == (0, 1, 2, 3)
and a.init_output == 0)
leaf = {'stop': True}
for raw, action in reversed(list(zip([0, 0, 0, 0], [0, 0, 0, 1]))):
leaf = {'action': action, 'branches': {str(raw): leaf}}
assert not verify_policy(space, (aid,), leaf)['valid']
def test_run_routing_adaptive_is_audited_and_replayed():
from crosswire.study import RunConfig, run
from crosswire.receipts import pack, replay
fixed = run(RunConfig(family='routing', budget=0))
result = run(RunConfig(family='routing', budget=0, admission='adaptive', execution_mode='shielded'))
assert not fixed['decision']['admitted']
assert result['decision']['admitted']
assert result['audit']['contract_satisfied'] is True
assert result['metrics']['target_calls'] == 0
assert result['deployment']['target_calls'] == 5
assert result['decision']['certificate']['valid']
assert replay(pack(result))['valid']