Ground handoff map values through explicit canonical fact bindings

This commit is contained in:
Nico committed 2026-10-19 17:34:23 +02:00
1 parent 061f82e6f1
commit c6f4ea9877
10 files changed
+257 -5

No files matched your search

@@ -120,7 +120,11 @@ class ChangeRequestBuilder:
if hashlib.sha256(raw).hexdigest()!=entry['record']['content_sha256']:
raise ChangeRequestError('CHANGE_REQUEST_LOCAL_CONTEXT_CHANGED')
local[ref]={'kind':next(iter(kinds)),'source_ref':ref,'sha256':hashlib.sha256(raw).hexdigest(),'size':len(raw)}
if parameter_grounding:result['parameter_grounding']=1
if parameter_grounding:
result['parameter_grounding']=parameter_grounding
if parameter_grounding == 2:
from viano_bug_analysis.profiles.database_bindings import fact_bindings
result['database_fact_bindings'] = fact_bindings(result['case'])
validate(result, "change-request-context")
if len(json_bytes(result)) > self.limits.max_context_bytes:
raise ChangeRequestError("CHANGE_REQUEST_CONTEXT_LIMIT")
@@ -153,7 +157,7 @@ class ChangeRequestBuilder:
policy = old["max_invalid_responses"]
if self.config_explicit and policy != self.config.max_invalid_responses:
raise ChangeRequestError("CHANGE_REQUEST_POLICY_CHANGED")
context = self.context(reader, policy, protocol=old.get("handoff_protocol",1) if started else 2, parameter_grounding=old.get("parameter_grounding",0) if started else 1)
context = self.context(reader, policy, protocol=old.get("handoff_protocol",1) if started else 2, parameter_grounding=old.get("parameter_grounding",0) if started else 2)
if started and (old != context or started["details"]["context_sha256"] != digest(context)):
raise ChangeRequestError("CHANGE_REQUEST_CONTEXT_CHANGED")
if completed:
@@ -46,6 +46,11 @@ def compact_handoff_context(context):
view['case'] = {k: context['case'][k] for k in
('bug', 'human_observations', 'expected_behavior', 'data_quality')
if k in context['case']}
if context.get('parameter_grounding') == 2:
# Show only actual bound values, not the full runtime fact inventory.
view['database_fact_bindings'] = context['database_fact_bindings']
ids = {b['fact_id'] for b in context['database_fact_bindings']}
view['bound_case_facts'] = [f for f in context['case'].get('runtime_facts', {}).get('facts', []) if f.get('id') in ids]
view['evidence'] = {eid: {'content': entry['content'],
'content_ref': entry['record']['content_ref'],
'content_sha256': entry['record']['content_sha256']}
@@ -5,13 +5,15 @@ It never substitutes values or modifies model instructions.
"""
import re
from decimal import Decimal
from math import isfinite
def unsupported_assignments(payload,context):
observed={}
table_columns={}
def remember(column,value):
if (isinstance(column,str) and re.fullmatch(r'[A-Za-z_][A-Za-z0-9_]{0,127}',column)
and type(value) in (int,float)):
and type(value) in (int,float) and (type(value) is int or isfinite(value))):
observed.setdefault(column.lower(),set()).add(Decimal(str(value)))
for entry in context.get('evidence',{}).values():
for capture in entry['content'].get('items',[]):
@@ -19,6 +21,21 @@ def unsupported_assignments(payload,context):
query=capture.get('query');result=capture.get('result')
if not isinstance(query,dict) or not isinstance(result,dict):continue
kind=query.get('kind')
if context.get('parameter_grounding') == 2 and kind in {'database.rows','database.schema','database.relations'}:
for item in result.get('items', []):
if not isinstance(item, dict): continue
table = item.get('table') or query.get('table')
if not isinstance(table, str): continue
columns = table_columns.setdefault(table, set())
for col in item.get('columns', []) or []:
if (isinstance(col, dict) and isinstance(col.get('COLUMN_NAME'), str)
and isinstance(col.get('COLUMN_TYPE'), str)
and re.match(r'(?:tinyint|smallint|mediumint|int|bigint|decimal|numeric|float|double)\b', col.get('COLUMN_TYPE', ''), re.I)):
columns.add(col['COLUMN_NAME'])
rows = item.get('rows', []) if kind == 'database.relations' else [item.get('row', {})]
for row in rows:
if isinstance(row, dict):
columns.update(k for k, v in row.items() if type(v) in (int, float))
if kind=='database.relations':
for node in result.get('items',[]):
for row in node.get('rows',[]):
@@ -44,6 +61,27 @@ def unsupported_assignments(payload,context):
elif isinstance(v,list):
for item in v:case_values(item)
case_values(context.get('case',{}))
if context.get('parameter_grounding') == 2:
facts = context.get('case', {}).get('runtime_facts', {}).get('facts', [])
counts = {}
for fact in facts:
fid = fact.get('id')
if isinstance(fid, str): counts[fid] = counts.get(fid, 0) + 1
unique = {f['id']: f for f in facts if counts.get(f.get('id')) == 1}
for fact in unique.values():
# A named canonical fact is not a free-text model claim.
name = fact.get('name')
if isinstance(name, str) and name.lower() in observed:
remember(name, fact.get('value'))
from viano_bug_analysis.profiles.database_bindings import fact_bindings
# Re-derive adapter bindings; arbitrary descriptors cannot authorize values.
allowed = fact_bindings(context.get('case', {}))
for binding in context.get('database_fact_bindings', []):
if binding not in allowed: continue
fact = unique.get(binding['fact_id'])
if (fact and fact.get('name') == binding['fact_name']
and binding['column'] in table_columns.get(binding['table'], set())):
remember(binding['column'], fact.get('value'))
bad=[]
for text in payload.get('implementation_guidance',[]):
if not isinstance(text,str):continue
@@ -0,0 +1,9 @@
"""Explicit adapter-owned fact/column bindings; no inferred field aliases."""
def fact_bindings(case):
project = case.get('case', {}).get('project', {})
if project.get('type') == 'wow' and project.get('profile') == 'vcore':
from .vcore.database_bindings import reproduction_bindings_v1
return reproduction_bindings_v1(case)
return []
@@ -0,0 +1,12 @@
"""wowdiag reproduction location to Vcore creature schema, version 1."""
def reproduction_bindings_v1(case):
# Intentionally narrow: no suffix matching, coordinates, masks or entity IDs.
return [{'fact_id': fact['id'], 'fact_name': 'map_id',
'table': 'creature', 'column': 'map'}
for fact in case.get('runtime_facts', {}).get('facts', [])
if fact.get('name') == 'map_id'
and isinstance(fact.get('id'), str)
and fact.get('provenance', {}).get('kind') == 'reproduction_record'
and type(fact.get('value')) is int and fact['value'] >= 0]
@@ -77,7 +77,73 @@
"const": 2
},
"parameter_grounding": {
"const": 1
"type": "integer",
"enum": [
1,
2
]
},
"database_fact_bindings": {
"type": "array",
"maxItems": 10000,
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"fact_id",
"fact_name",
"table",
"column"
],
"properties": {
"fact_id": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"fact_name": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"table": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"column": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
}
}
}
}
},
"allOf": [
{
"if": {
"required": [
"parameter_grounding"
],
"properties": {
"parameter_grounding": {
"const": 2
}
}
},
"then": {
"required": [
"database_fact_bindings"
]
},
"else": {
"not": {
"required": [
"database_fact_bindings"
]
}
}
}
]
}