P08-03: 配置の通常操作受入

This commit is contained in:
Agent Control Runner
2026-10-14 04:21:06 +09:00
parent c2b59f04f9
commit 8e3d79d5f2
12 changed files with 543 additions and 54 deletions
+109
View File
@@ -135,6 +135,115 @@ class EvidenceTests(unittest.TestCase):
self.edit('pair/reader-save-result-0001.json', lambda d: d.update(result=F.typed({'ok':True,'operation':'load'}), requested_path='/outside/formal'))
self.reject('save outside private user profile')
def test_notification_payload_is_recomputed_from_returned_dict(self):
path = 'pair/reader-checkpoint.json'
original = (self.out/path).read_bytes()
fields = ('ok','code','message','operation','save_path','reason','request_id',
'checkpoint_absolute_minute','duration_us','runtime_duration_us',
'selected_candidate_id','selected_candidate_kind','selected_generation',
'save_id','saved_absolute_minute')
for field in fields:
with self.subTest(field=field):
data = json.loads(original)
event = C.typed_member(data,'systems','runtime','domain_events','recent_events')['items'][-1]
value = C.typed_member(event,'payload',field)
decoded = C.decode(value)
changed = not decoded if isinstance(decoded,bool) else decoded+1 if isinstance(decoded,int) else decoded+'-drift'
value.update(C.scalar(changed,value['type']))
F.put(self.out/path,data); F.repin(self.out)
self.reject('source-defined operation drift')
(self.out/path).write_bytes(original); F.repin(self.out)
def test_notification_envelope_cannot_drift(self):
path = 'pair/writer-checkpoint.json'
original = (self.out/path).read_bytes()
for field in ('event_id','event_type','source_service','absolute_minute','causation_command_id','entity_ids'):
with self.subTest(field=field):
data = json.loads(original)
event = C.typed_member(data,'systems','runtime','domain_events','recent_events')['items'][-1]
value = C.typed_member(event,field)
if field == 'entity_ids': value['items'].append(C.scalar('unexpected-entity'))
else:
old = C.decode(value)
value.update(C.scalar(old+1 if isinstance(old,int) else old+'-drift',value['type']))
F.put(self.out/path,data); F.repin(self.out)
self.reject('source-defined operation drift')
(self.out/path).write_bytes(original); F.repin(self.out)
def test_notification_counter_must_increment_exactly_once(self):
def corrupt(data):
C.typed_member(data,'systems','runtime','id_generator','counters','domain_event')['text'] = '9'
self.edit('pair/reader-checkpoint.json',corrupt)
self.reject('source-defined operation drift')
def test_notification_published_ids_cannot_be_omitted(self):
self.edit('pair/writer-checkpoint.json',lambda d: C.typed_member(d,'systems','runtime','domain_events','published_ids')['items'].clear())
self.reject('source-defined operation drift')
def test_extra_notification_is_rejected(self):
def corrupt(data):
events = C.typed_member(data,'systems','runtime','domain_events','recent_events')['items']
events.append(copy.deepcopy(events[-1]))
self.edit('pair/reader-checkpoint.json',corrupt)
self.reject('source-defined operation drift')
def test_existing_event_history_cannot_be_rewritten(self):
def corrupt(data):
event = C.typed_member(data,'systems','runtime','domain_events','recent_events')['items'][0]
C.typed_member(event,'event_type').update(text='"REWRITTEN_HISTORY"')
self.edit('pair/reader-checkpoint.json',corrupt)
self.reject('source-defined operation drift')
def test_postsave_unrelated_resource_drift_is_rejected(self):
self.edit('pair/writer-checkpoint.json',lambda d: C.typed_member(d,'game_state','resources','gold').update(text='9999'))
self.reject('source-defined operation drift')
def test_postload_unknown_field_drift_is_rejected(self):
self.edit('pair/reader-checkpoint.json',lambda d: C.typed_member(d,'systems','runtime','inventory')['entries'].append([C.scalar('unknown'),C.scalar(1)]))
self.reject('source-defined operation drift')
def test_presave_must_match_read_only_formal_model(self):
self.edit('pair/writer-presave.json',lambda d: C.typed_member(d,'clock','absolute_minute').update(text='361'))
self.reject('wrong presave formal model')
def test_read_only_inspection_must_match_complete_formal_model(self):
self.edit('pair/reader-save-result-0002.json',lambda d: C.typed_member(d['result'],'snapshot','clock','absolute_minute').update(text='361'))
self.reject('wrong read-only formal model')
def test_inspection_cannot_lose_read_only_attribution(self):
self.edit('pair/writer-save-result-0002.json',lambda d: C.typed_member(d['result'],'read_only').update(text='false'))
self.reject('missing read-only formal model')
def test_returned_result_payload_tampering_is_rejected(self):
self.edit('pair/reader-save-result-0001.json',lambda d: C.typed_member(d['result'],'duration_us').update(text='999'))
self.reject('source-defined operation drift')
def test_notification_payload_type_drift_is_rejected(self):
def corrupt(data):
event = C.typed_member(data,'systems','runtime','domain_events','recent_events')['items'][-1]
C.typed_member(event,'payload','operation')['type'] = 'String'
C.typed_member(event,'payload','operation')['text'] = '"recovery"'
self.edit('pair/reader-checkpoint.json',corrupt)
self.reject('source-defined operation drift')
def test_operation_count_is_source_derived_with_recent_limit(self):
model = C.decode(json.loads((self.out/'pair/writer-formal-model.json').read_text()))
runtime = model['systems']['runtime']
runtime['id_generator']['counters']['domain_event'] = 900
stream = runtime['domain_events']
stream['published_ids'] = ['domain_event.%012d' % n for n in range(1,901)]
stream['recent_events'] = [{'ordinal':n} for n in range(645,901)]
expected = C.decode(C.expected_operation(F.typed(model),{'ok':True},'SAVE_CHECKPOINT_SUCCEEDED'))
new = expected['systems']['runtime']
self.assertEqual(901,new['id_generator']['counters']['domain_event'])
self.assertEqual(901,len(new['domain_events']['published_ids']))
self.assertEqual(256,len(new['domain_events']['recent_events']))
self.assertEqual(stream['recent_events'][1:],new['domain_events']['recent_events'][:-1])
self.assertEqual('domain_event.000000000901',new['domain_events']['recent_events'][-1]['event_id'])
del runtime['id_generator']['counters']
with self.assertRaisesRegex(ValueError,'missing/duplicate typed model member'):
C.expected_operation(F.typed(model),{'ok':True},'SAVE_CHECKPOINT_SUCCEEDED')
def test_missing_formal_member(self):
for name in ('formal','formal.bak'):
with self.subTest(package=name):