Fix multi-database entity resolution capture validation

This commit is contained in:
Nico committed 2026-10-24 17:59:01 +02:00
1 parent 9c9d9d70d6
commit a9b49bbb13
2 files changed
+43 -2

No files matched your search

@@ -436,8 +436,16 @@ class EntityResolver:
captures=[]
for s,ref in zip(plan['searches'],search['capture_refs'],strict=True):
c=read_json(reader,ref,'project-capture',self.owner.limits.max_context_bytes)
if (ref != self.base(context)+'/captures/'+hashlib.sha256(reader.read_bytes(ref)).hexdigest()+'.json' or c['origin'] != initial['binding']
or c['query'] != query_for(s,initial['policy'])):
query=query_for(s,initial['policy'])
# Reconstruct the query-specific origin from the frozen binding, so
# completed cases remain verifiable without a live database provider.
binding=copy.deepcopy(initial['binding'])
if binding.get('kind') == 'mariadb' and (binding.get('additional_databases') or '.' in query['table']):
parts=query['table'].split('.')
database,table=(binding['database'],parts[0]) if len(parts)==1 else parts
binding.update(selected_database=database,selected_table=table)
if (ref != self.base(context)+'/captures/'+hashlib.sha256(reader.read_bytes(ref)).hexdigest()+'.json' or c['origin'] != binding
or c['query'] != query):
raise InterpretationError('ENTITY_RESOLUTION_CAPTURE_CHANGED')
captures.append(c)
if search['candidates'] != candidates_for(plan,captures,initial['policy']):
+33
View File
@@ -126,6 +126,39 @@ def context_of(store):
return build_context(json.loads(reader.read_bytes(ref)),ref,InterpretationLimits())
@pytest.mark.parametrize('qualified', [False, True])
@pytest.mark.parametrize('wrong_origin', [False, True])
def test_multidatabase_capture_origin_and_portable_replay(built_case, tmp_path, qualified, wrong_origin):
class MultiDatabase(Database):
def binding(self):
return {'kind':'mariadb', 'database':'world', 'snapshot_id':self.snapshot,
'tables':['components'], 'additional_databases':{'characters':['components']}}
def binding_for(self, query):
database, table = query['table'].split('.') if '.' in query['table'] else ('world', query['table'])
return {**self.binding(), 'selected_database':'wrong' if wrong_origin else database,
'selected_table':table}
def validate(self, query):
assert query['table'] in {'components','characters.components'}
store=built_case[0]
model=Model(); service=service_for(store,MultiDatabase())
if qualified:
service.entity_resolution['catalogs'][0]['table']='characters.components'
if wrong_origin:
with pytest.raises(InterpretationError, match='ENTITY_RESOLUTION_CAPTURE_CHANGED'):
run(store,model,service)
return
result=run(store,model,service)
assert result.status=='COMPLETED'
assert PackageValidator().validate(result.package).valid
receiving=CheckpointStore(type(store.workspace)(tmp_path/'portable-multidb'))
receiving.intake(result.package)
again=run(receiving,model)
assert again.reused and len(model.requests)==3
def test_resolves_unrecorded_subject_preserves_case_and_portable_replay(built_case, tmp_path):
store, _, built, _, _ = built_case
with PackageReader(built.package) as reader: