from pathlib import Path from types import SimpleNamespace import pytest from lightnest.bootstrap import Task, iterate, propose_and_validate from lightnest.rv32 import assemble def program(op): return assemble(f'lw t0, 0(a1)\nlw t1, 4(a1)\n{op} a0, t0, t1\nebreak') def test_two_accepted_generations_inherit_actual_bytes(tmp_path): source = tmp_path/'source.bin' source.write_bytes(program('add')) observed = [] class Policy: def propose(self, command, blob, base_offset=0): observed.append(blob) target = program('sub') if len(observed) == 1 else program('add') changes = [i for i,(a,b) in enumerate(zip(blob,target)) if a != b] assert len(changes) == 1 i=changes[0] return SimpleNamespace(relative_offset=i,old_byte=blob[i],new_byte=target[i],base_offset=base_offset) records = iterate(Policy(), source, tmp_path/'lineage', [ Task('subtract', (((7,2),5), ((-5,3),-8))), Task('add', (((7,2),9), ((-5,3),-2)))]) assert all(x['accepted'] for x in records) assert records[1]['parent_sha256'] == records[0]['candidate_sha256'] assert observed == [program('add'), program('sub')] assert source.read_bytes() == program('add') def test_wrong_proposal_rejected_without_file_or_repair(tmp_path): source=tmp_path/'source.bin';source.write_bytes(program('add')) class Wrong: def propose(self, command, blob, base_offset=0): return SimpleNamespace(relative_offset=0,old_byte=blob[0],new_byte=0,base_offset=0) candidate=tmp_path/'candidate.bin' result=propose_and_validate(Wrong(),source,candidate,Task('subtract',(((7,2),5),))) assert not result['accepted'] and not candidate.exists() assert source.read_bytes()==program('add') def test_bad_oracle_limits_rejected(tmp_path): with pytest.raises(ValueError): propose_and_validate(None,tmp_path/'missing',tmp_path/'candidate',Task('x',())) def test_existing_audit_rejected_before_policy_or_child(tmp_path): source=tmp_path/'source.bin';source.write_bytes(program('add')) folder=tmp_path/'lineage';folder.mkdir() audit=folder/'generation-001.json';audit.write_text('prior audit') class Never: def propose(self,*args,**kwargs): pytest.fail('existing audit must reject before model call') with pytest.raises(FileExistsError): iterate(Never(),source,folder,[Task('subtract',(((7,2),5),))]) assert audit.read_text()=='prior audit' assert not (folder/'generation-001.rv32').exists()