tgi-foundation 0.2.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tgi/__init__.py +7 -0
- tgi/__main__.py +194 -0
- tgi/acquisition_history.py +45 -0
- tgi/acquisition_history_check.py +51 -0
- tgi/acquisition_monitor.py +66 -0
- tgi/acquisition_monitor_check.py +78 -0
- tgi/acquisition_projection.py +70 -0
- tgi/acquisition_projection_check.py +93 -0
- tgi/acquisition_role_cells.py +53 -0
- tgi/acquisition_role_constraints.py +13 -0
- tgi/acquisition_role_constraints_check.py +66 -0
- tgi/acquisition_snapshot.py +35 -0
- tgi/acquisition_stream.py +21 -0
- tgi/acquisition_witness.py +117 -0
- tgi/actuation_goal_frontier.py +117 -0
- tgi/actuation_goal_frontier_check.py +147 -0
- tgi/actuation_goal_workflow.py +159 -0
- tgi/actuation_sequence_feedback.py +41 -0
- tgi/actuation_sequence_feedback_check.py +43 -0
- tgi/ask_certificate.py +74 -0
- tgi/bands.py +59 -0
- tgi/capacity_graph.py +70 -0
- tgi/closed_actuation_goal_frontier.py +13 -0
- tgi/closed_actuation_goal_frontier_check.py +19 -0
- tgi/closed_actuation_goal_workflow.py +159 -0
- tgi/closure.py +202 -0
- tgi/compact_acquisition_map.py +68 -0
- tgi/compact_acquisition_map_check.py +91 -0
- tgi/compact_complete_role_core.py +36 -0
- tgi/compact_complete_role_core_check.py +62 -0
- tgi/compact_measured_path.py +84 -0
- tgi/compact_role_observation.py +13 -0
- tgi/compact_role_observation_check.py +66 -0
- tgi/compatible_joins.py +33 -0
- tgi/complete_role_core.py +53 -0
- tgi/complete_role_core_check.py +54 -0
- tgi/context_family_selection.py +45 -0
- tgi/context_family_selection_check.py +32 -0
- tgi/context_family_separation.py +43 -0
- tgi/context_family_separation_check.py +47 -0
- tgi/contextual_isometry.py +62 -0
- tgi/contextual_isometry_check.py +54 -0
- tgi/continuation_checkpoint.py +75 -0
- tgi/continuation_cycle.py +102 -0
- tgi/continuation_goal_frontier.py +13 -0
- tgi/continuation_goal_frontier_check.py +19 -0
- tgi/continuation_goal_workflow.py +159 -0
- tgi/continuation_learning.py +36 -0
- tgi/continuation_learning_check.py +53 -0
- tgi/correspondence.py +76 -0
- tgi/cross_action_correspondence.py +182 -0
- tgi/cross_action_correspondence_check.py +92 -0
- tgi/cross_view_identity_map.py +41 -0
- tgi/cross_view_identity_map_check.py +48 -0
- tgi/derivation.py +74 -0
- tgi/empirical_transport.py +74 -0
- tgi/empirical_transport_check.py +78 -0
- tgi/events.py +36 -0
- tgi/evidence_response.py +24 -0
- tgi/evidence_response_check.py +33 -0
- tgi/exact_field.py +101 -0
- tgi/experience.py +68 -0
- tgi/experience_cli.py +44 -0
- tgi/feedback_update.py +32 -0
- tgi/feedback_update_check.py +38 -0
- tgi/formation.py +74 -0
- tgi/frame_cli.py +26 -0
- tgi/frame_engine.py +214 -0
- tgi/functional_capacity.py +74 -0
- tgi/functional_capacity_check.py +110 -0
- tgi/functional_transition.py +40 -0
- tgi/functional_transition_check.py +58 -0
- tgi/geometry.py +143 -0
- tgi/grounding.py +285 -0
- tgi/guarded_word_closure.py +148 -0
- tgi/guarded_word_closure_check.py +171 -0
- tgi/guarded_word_goal_frontier.py +13 -0
- tgi/guarded_word_goal_frontier_check.py +19 -0
- tgi/guarded_word_goal_workflow.py +160 -0
- tgi/identity.py +32 -0
- tgi/incidence.py +155 -0
- tgi/incremental.py +134 -0
- tgi/intervention_composition.py +63 -0
- tgi/intervention_composition_check.py +84 -0
- tgi/intervention_continuity.py +43 -0
- tgi/intervention_continuity_check.py +56 -0
- tgi/intervention_correspondence.py +156 -0
- tgi/intervention_correspondence_check.py +80 -0
- tgi/intervention_edit_contrast.py +27 -0
- tgi/intervention_edit_contrast_check.py +41 -0
- tgi/intervention_experiment.py +62 -0
- tgi/intervention_experiment_check.py +78 -0
- tgi/intervention_resolution.py +45 -0
- tgi/intervention_resolution_check.py +70 -0
- tgi/intervention_roles.py +83 -0
- tgi/intervention_roles_check.py +91 -0
- tgi/intervention_scope.py +34 -0
- tgi/intervention_sequence_experiment.py +71 -0
- tgi/intervention_sequence_experiment_check.py +97 -0
- tgi/interventions.py +240 -0
- tgi/joint_correspondence.py +73 -0
- tgi/joint_frontier_acquisition.py +114 -0
- tgi/joint_frontier_acquisition_check.py +116 -0
- tgi/joint_goal_observation.py +49 -0
- tgi/joint_goal_observation_check.py +55 -0
- tgi/joint_goal_traversal.py +101 -0
- tgi/joint_goal_traversal_check.py +114 -0
- tgi/joint_observed_laws.py +40 -0
- tgi/joint_observed_laws_check.py +63 -0
- tgi/joint_temporal_candidates.py +40 -0
- tgi/joint_temporal_candidates_check.py +68 -0
- tgi/lineage_knowledge.py +29 -0
- tgi/lineage_knowledge_check.py +41 -0
- tgi/lineage_state.py +39 -0
- tgi/lineage_state_check.py +47 -0
- tgi/local_acquisition_ownership.py +65 -0
- tgi/local_acquisition_runtime.py +119 -0
- tgi/local_acquisition_selection.py +41 -0
- tgi/local_acquisition_transition.py +50 -0
- tgi/local_acquisition_transition_check.py +80 -0
- tgi/local_edit_transport_classes.py +220 -0
- tgi/local_edit_transport_classes_check.py +128 -0
- tgi/local_evidence_persistence.py +67 -0
- tgi/measured_actuation_transition.py +56 -0
- tgi/measured_actuation_transition_check.py +81 -0
- tgi/measured_capacity.py +61 -0
- tgi/measured_context.py +52 -0
- tgi/measured_context_check.py +65 -0
- tgi/measured_context_laws.py +75 -0
- tgi/measured_context_laws_check.py +91 -0
- tgi/measured_context_layout.py +49 -0
- tgi/measured_occurrence_path.py +70 -0
- tgi/momentum.py +43 -0
- tgi/observation_context_laws.py +32 -0
- tgi/observation_context_laws_check.py +40 -0
- tgi/observation_epochs.py +35 -0
- tgi/observation_epochs_check.py +51 -0
- tgi/observation_point.py +92 -0
- tgi/observation_projection.py +45 -0
- tgi/observation_projection_check.py +48 -0
- tgi/observed_actuation_cycle.py +114 -0
- tgi/observed_actuation_discovery.py +41 -0
- tgi/observed_actuation_discovery_check.py +54 -0
- tgi/observed_actuation_learning.py +71 -0
- tgi/observed_actuation_learning_check.py +73 -0
- tgi/observed_actuation_runtime.py +114 -0
- tgi/observed_context_actions.py +66 -0
- tgi/observed_context_actions_check.py +81 -0
- tgi/observed_joint_state.py +52 -0
- tgi/observed_joint_state_check.py +55 -0
- tgi/observed_refinement.py +43 -0
- tgi/observed_response.py +20 -0
- tgi/observed_response_check.py +27 -0
- tgi/observed_role_core.py +41 -0
- tgi/observed_role_core_check.py +54 -0
- tgi/occurrence_route.py +56 -0
- tgi/operator_windows.py +84 -0
- tgi/operator_windows_check.py +111 -0
- tgi/organization.py +484 -0
- tgi/organization_check.py +143 -0
- tgi/organization_cli.py +77 -0
- tgi/organization_inventory_check.py +82 -0
- tgi/organization_snapshot.py +50 -0
- tgi/path_isometry.py +82 -0
- tgi/path_temporal_feasibility.py +69 -0
- tgi/phase_evidence.py +100 -0
- tgi/port_distinction_exploration.py +37 -0
- tgi/port_distinction_exploration_check.py +40 -0
- tgi/proofcheck.py +117 -0
- tgi/provenance.py +19 -0
- tgi/recent_observation.py +145 -0
- tgi/relational.py +222 -0
- tgi/resonance.py +114 -0
- tgi/response_eligibility.py +46 -0
- tgi/response_eligibility_check.py +55 -0
- tgi/response_interval_order.py +59 -0
- tgi/response_interval_order_check.py +92 -0
- tgi/response_readout.py +53 -0
- tgi/response_readout_check.py +73 -0
- tgi/role_bundle.py +31 -0
- tgi/role_bundle_check.py +20 -0
- tgi/role_candidates.py +47 -0
- tgi/role_candidates_check.py +57 -0
- tgi/role_eligibility.py +34 -0
- tgi/role_eligibility_check.py +46 -0
- tgi/role_feedback.py +15 -0
- tgi/role_feedback_check.py +23 -0
- tgi/role_history.py +37 -0
- tgi/role_history_check.py +51 -0
- tgi/role_projection.py +16 -0
- tgi/role_projection_check.py +85 -0
- tgi/role_proposal.py +39 -0
- tgi/role_proposal_check.py +51 -0
- tgi/role_readout.py +31 -0
- tgi/role_readout_check.py +51 -0
- tgi/role_response.py +34 -0
- tgi/role_response_check.py +40 -0
- tgi/role_work.py +54 -0
- tgi/scoped_sequence_experiment.py +20 -0
- tgi/scoped_sequence_experiment_check.py +33 -0
- tgi/separation.py +74 -0
- tgi/separation_check.py +87 -0
- tgi/sequence_prefix_feedback.py +57 -0
- tgi/sequence_prefix_feedback_check.py +79 -0
- tgi/source_intervals.py +85 -0
- tgi/source_intervals_check.py +97 -0
- tgi/spatial.py +109 -0
- tgi/spatial_action_observation.py +88 -0
- tgi/spatial_action_relation.py +53 -0
- tgi/spatial_action_relation_check.py +45 -0
- tgi/spatial_action_relation_cycle.py +84 -0
- tgi/spatial_action_relation_migration.py +41 -0
- tgi/spatial_action_relation_migration_bundle.py +60 -0
- tgi/spatial_contextual_action_cycle.py +130 -0
- tgi/spatial_contextual_action_local.py +79 -0
- tgi/spatial_contextual_action_phase.py +81 -0
- tgi/spatial_contextual_action_phase_check.py +81 -0
- tgi/spatial_direct_action_cycle.py +98 -0
- tgi/spatial_direct_action_relation.py +60 -0
- tgi/spatial_direct_action_relation_check.py +67 -0
- tgi/spatial_local_action_cycle.py +62 -0
- tgi/spatial_local_action_relation.py +66 -0
- tgi/spatial_temporal_action_cycle.py +116 -0
- tgi/spatial_temporal_action_local.py +77 -0
- tgi/spatial_temporal_action_phase.py +89 -0
- tgi/spatial_temporal_action_phase_check.py +94 -0
- tgi/structural_append_closure.py +99 -0
- tgi/structural_append_closure_check.py +106 -0
- tgi/structural_continuation_closure.py +93 -0
- tgi/structural_continuation_closure_check.py +108 -0
- tgi/temporal_candidate_spectrum.py +57 -0
- tgi/temporal_candidate_spectrum_check.py +94 -0
- tgi/temporal_correspondence.py +41 -0
- tgi/temporal_correspondence_check.py +56 -0
- tgi/temporal_projection.py +41 -0
- tgi/temporal_projection_check.py +56 -0
- tgi/transport.py +294 -0
- tgi/transport_cli.py +27 -0
- tgi/unlabeled_port_classes.py +199 -0
- tgi/unlabeled_port_classes_check.py +113 -0
- tgi/unobserved_action_selection.py +47 -0
- tgi/unobserved_action_selection_check.py +40 -0
- tgi/verification.py +98 -0
- tgi/witness_function.py +62 -0
- tgi/witness_probe.py +50 -0
- tgi/witness_probe_feedback.py +106 -0
- tgi/witness_response.py +67 -0
- tgi_foundation-0.2.0.dev0.dist-info/METADATA +30 -0
- tgi_foundation-0.2.0.dev0.dist-info/RECORD +252 -0
- tgi_foundation-0.2.0.dev0.dist-info/WHEEL +5 -0
- tgi_foundation-0.2.0.dev0.dist-info/licenses/LICENSE +3 -0
- tgi_foundation-0.2.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Native chronological formation of unlabeled sensor response classes."""
|
|
2
|
+
import copy
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from tgi.frame_engine import canonical, unique_object
|
|
11
|
+
from tgi.identity import REGISTRY_ID, encode
|
|
12
|
+
from tgi.organization import OMEGA_CRIT
|
|
13
|
+
from tgi.intervention_edit_contrast import contrast
|
|
14
|
+
|
|
15
|
+
REVISION = 'TGI-M1-UNLABELED-PORT-CLASSES-RESEARCH-V2'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _sha(data):
|
|
19
|
+
return hashlib.sha256(data).hexdigest()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _event(source, action, ports):
|
|
23
|
+
if type(source) is not str or not source or type(action) is not str or not action:
|
|
24
|
+
raise ValueError('Original source and action required')
|
|
25
|
+
if type(ports) is not dict or len(ports) < 3:
|
|
26
|
+
raise ValueError('At least three original port streams required')
|
|
27
|
+
rows = {}
|
|
28
|
+
for name, pair in sorted(ports.items()):
|
|
29
|
+
if (type(name) is not str or not name or type(pair) not in (tuple, list) or
|
|
30
|
+
len(pair) != 2):
|
|
31
|
+
raise ValueError('Raw port address and frame pair required')
|
|
32
|
+
rows[name] = contrast(*pair)
|
|
33
|
+
return {'source': source, 'action_nmu': list(encode(action)), 'ports': rows}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _apply(stats, members, event, names):
|
|
37
|
+
action = tuple(event['action_nmu'])
|
|
38
|
+
changed = all(event['ports'][name]['changed'] for name in members)
|
|
39
|
+
stable = all(not event['ports'][name]['changed'] for name in members)
|
|
40
|
+
if changed:
|
|
41
|
+
context = tuple(tuple(event['ports'][name]['before_nmu']) for name in members)
|
|
42
|
+
stats['support'].setdefault(action, set()).add(context)
|
|
43
|
+
elif stable:
|
|
44
|
+
stats['controls'][action] = stats['controls'].get(action, 0) + 1
|
|
45
|
+
if any(event['ports'][name]['changed'] for name in names if name not in members):
|
|
46
|
+
stats['comparator'].add(action)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def form(events):
|
|
50
|
+
if type(events) is not list:
|
|
51
|
+
raise ValueError('Original chronological event list required')
|
|
52
|
+
phases = []
|
|
53
|
+
seen = set()
|
|
54
|
+
names = None
|
|
55
|
+
previous_class = None
|
|
56
|
+
epoch_start = 0
|
|
57
|
+
traces = {}
|
|
58
|
+
previous_stats = {}
|
|
59
|
+
actions_seen = set()
|
|
60
|
+
for index, event in enumerate(events):
|
|
61
|
+
if (type(event) is not dict or set(event) != {'source', 'action_nmu', 'ports'} or
|
|
62
|
+
event['source'] in seen or type(event['ports']) is not dict):
|
|
63
|
+
raise ValueError('Unique original event required')
|
|
64
|
+
seen.add(event['source'])
|
|
65
|
+
current = list(event['ports'])
|
|
66
|
+
if names is None:
|
|
67
|
+
names = current
|
|
68
|
+
traces = {name: () for name in names}
|
|
69
|
+
if current != names:
|
|
70
|
+
raise ValueError('Fixed port inventory required')
|
|
71
|
+
for name in names:
|
|
72
|
+
row = event['ports'][name]
|
|
73
|
+
traces[name] += ((row['kind'], tuple(row['positions'])),)
|
|
74
|
+
grouped = {}
|
|
75
|
+
for name in names:
|
|
76
|
+
grouped.setdefault(traces[name], []).append(name)
|
|
77
|
+
classes = sorted(tuple(group) for group in grouped.values())
|
|
78
|
+
actions_seen.add(tuple(event['action_nmu']))
|
|
79
|
+
actions = sorted(actions_seen)
|
|
80
|
+
cells = []
|
|
81
|
+
eligible = []
|
|
82
|
+
current_stats = {}
|
|
83
|
+
for members in classes:
|
|
84
|
+
if members in previous_stats:
|
|
85
|
+
stats = previous_stats[members]
|
|
86
|
+
_apply(stats, members, event, names)
|
|
87
|
+
else:
|
|
88
|
+
stats = {'support': {}, 'controls': {}, 'comparator': set()}
|
|
89
|
+
for row in events[epoch_start:index + 1]:
|
|
90
|
+
_apply(stats, members, row, names)
|
|
91
|
+
current_stats[members] = stats
|
|
92
|
+
counts = []
|
|
93
|
+
for action in actions:
|
|
94
|
+
omega = len(stats['support'].get(action, ()))
|
|
95
|
+
controls = stats['controls'].get(action, 0)
|
|
96
|
+
comparator = any(other != action for other in stats['comparator'])
|
|
97
|
+
counts.append({'action_nmu': list(action), 'omega': omega,
|
|
98
|
+
'controls': controls, 'comparator': comparator})
|
|
99
|
+
if omega >= OMEGA_CRIT and controls and comparator:
|
|
100
|
+
eligible.append((action, members))
|
|
101
|
+
cells.append({'members': list(members), 'C_L_by_action': counts, 'xi': 0})
|
|
102
|
+
fractured = previous_class is not None and previous_class not in classes
|
|
103
|
+
if fractured:
|
|
104
|
+
result = {'status': 'REVOKED', 'action_nmu': None, 'members': None}
|
|
105
|
+
previous_class = None
|
|
106
|
+
epoch_start = index + 1
|
|
107
|
+
current_stats = {}
|
|
108
|
+
elif len(eligible) == 1:
|
|
109
|
+
action, members = eligible[0]
|
|
110
|
+
result = {'status': 'CRYSTAL', 'action_nmu': list(action), 'members': list(members)}
|
|
111
|
+
previous_class = members
|
|
112
|
+
for cell in cells:
|
|
113
|
+
cell['xi'] = int(tuple(cell['members']) == members)
|
|
114
|
+
elif previous_class is not None and not any(members == previous_class for _, members in eligible):
|
|
115
|
+
result = {'status': 'REVOKED', 'action_nmu': None, 'members': None}
|
|
116
|
+
else:
|
|
117
|
+
result = {'status': 'NO_PATH', 'action_nmu': None, 'members': None}
|
|
118
|
+
phases.append({'event_index': index, 'source': event['source'],
|
|
119
|
+
'epoch_start': epoch_start,
|
|
120
|
+
'classes': cells, 'result': result})
|
|
121
|
+
previous_stats = current_stats
|
|
122
|
+
result = phases[-1]['result'] if phases else {'status': 'NO_PATH', 'action_nmu': None, 'members': None}
|
|
123
|
+
return {'revision': REVISION, 'registry': REGISTRY_ID,
|
|
124
|
+
'events': list(events), 'phases': phases, 'result': result}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class OwnedPortClasses:
|
|
128
|
+
def __init__(self, events=None):
|
|
129
|
+
from tgi.unlabeled_port_classes_check import verify
|
|
130
|
+
self._events = copy.deepcopy([] if events is None else events)
|
|
131
|
+
self._certificate = form(self._events)
|
|
132
|
+
if not verify(self._events, self._certificate):
|
|
133
|
+
raise ValueError('Independent original port replay failed')
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def certificate(self):
|
|
137
|
+
return copy.deepcopy(self._certificate)
|
|
138
|
+
|
|
139
|
+
def observe(self, source, action, ports):
|
|
140
|
+
from tgi.unlabeled_port_classes_check import verify
|
|
141
|
+
if any(row['source'] == source for row in self._events):
|
|
142
|
+
raise ValueError('Duplicate original source')
|
|
143
|
+
event = _event(source, action, ports)
|
|
144
|
+
child = type(self).__new__(type(self))
|
|
145
|
+
child._events = self._events + [event]
|
|
146
|
+
child._certificate = form(child._events)
|
|
147
|
+
if not verify(child._events, child._certificate):
|
|
148
|
+
raise ValueError('Independent original port replay failed')
|
|
149
|
+
return child
|
|
150
|
+
|
|
151
|
+
def resolve(self, action):
|
|
152
|
+
result = self._certificate['result']
|
|
153
|
+
if type(action) is not str or not action:
|
|
154
|
+
raise ValueError('Original action trigger required')
|
|
155
|
+
if result['status'] != 'CRYSTAL' or result['action_nmu'] != list(encode(action)):
|
|
156
|
+
return None
|
|
157
|
+
return list(result['members'])
|
|
158
|
+
|
|
159
|
+
def commit(self, path):
|
|
160
|
+
from tgi.unlabeled_port_classes_check import verify
|
|
161
|
+
if not verify(self._events, self._certificate):
|
|
162
|
+
raise ValueError('Independent complete replay failed')
|
|
163
|
+
payload = {'revision': REVISION, 'registry': REGISTRY_ID,
|
|
164
|
+
'events': self._events, 'certificate': self._certificate}
|
|
165
|
+
envelope = {'payload': payload, 'sha256': _sha(canonical(payload).encode('utf8'))}
|
|
166
|
+
data = canonical(envelope).encode('utf8')
|
|
167
|
+
destination = Path(path)
|
|
168
|
+
temporary = None
|
|
169
|
+
try:
|
|
170
|
+
with tempfile.NamedTemporaryFile(mode='wb', dir=destination.parent, delete=False) as stream:
|
|
171
|
+
temporary = Path(stream.name)
|
|
172
|
+
stream.write(data)
|
|
173
|
+
stream.flush()
|
|
174
|
+
os.fsync(stream.fileno())
|
|
175
|
+
os.replace(temporary, destination)
|
|
176
|
+
temporary = None
|
|
177
|
+
finally:
|
|
178
|
+
if temporary is not None and temporary.exists():
|
|
179
|
+
temporary.unlink()
|
|
180
|
+
return {'path': str(destination), 'sha256': _sha(data), 'bytes': len(data)}
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def recover(cls, path, expected_sha256):
|
|
184
|
+
from tgi.unlabeled_port_classes_check import verify
|
|
185
|
+
if type(expected_sha256) is not str or re.fullmatch(r'[0-9a-f]{64}', expected_sha256) is None:
|
|
186
|
+
raise ValueError('External checkpoint digest required')
|
|
187
|
+
data = Path(path).read_bytes()
|
|
188
|
+
if _sha(data) != expected_sha256:
|
|
189
|
+
raise ValueError('Checkpoint digest mismatch')
|
|
190
|
+
envelope = json.loads(data.decode('utf8'), object_pairs_hook=unique_object)
|
|
191
|
+
if type(envelope) is not dict or set(envelope) != {'payload', 'sha256'}:
|
|
192
|
+
raise ValueError('Invalid checkpoint envelope')
|
|
193
|
+
payload = envelope['payload']
|
|
194
|
+
if (type(payload) is not dict or set(payload) != {'revision', 'registry', 'events', 'certificate'} or
|
|
195
|
+
payload['revision'] != REVISION or payload['registry'] != REGISTRY_ID or
|
|
196
|
+
_sha(canonical(payload).encode('utf8')) != envelope['sha256'] or
|
|
197
|
+
not verify(payload['events'], payload['certificate'])):
|
|
198
|
+
raise ValueError('Invalid original port checkpoint')
|
|
199
|
+
return cls(payload['events'])
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Independent complete chronological replay of class and epoch certificates."""
|
|
2
|
+
from tgi.frame_engine import canonical
|
|
3
|
+
from tgi.identity import REGISTRY_ID, decode
|
|
4
|
+
from tgi.organization import OMEGA_CRIT
|
|
5
|
+
from tgi.intervention_edit_contrast_check import verify as valid_contrast
|
|
6
|
+
|
|
7
|
+
REVISION = 'TGI-M1-UNLABELED-PORT-CLASSES-RESEARCH-V2'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _measure(data, members, row, names):
|
|
11
|
+
action = tuple(row['action_nmu'])
|
|
12
|
+
stable = all(row['ports'][port]['kind'] == 'STABLE' for port in members)
|
|
13
|
+
changed = all(row['ports'][port]['kind'] != 'STABLE' for port in members)
|
|
14
|
+
if changed:
|
|
15
|
+
key = tuple(tuple(row['ports'][port]['before_nmu']) for port in members)
|
|
16
|
+
data['contexts'].setdefault(action, set()).add(key)
|
|
17
|
+
if stable:
|
|
18
|
+
data['controls'][action] = data['controls'].get(action, 0) + 1
|
|
19
|
+
if any(row['ports'][port]['kind'] != 'STABLE' for port in names if port not in members):
|
|
20
|
+
data['separators'].add(action)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def verify(events, certificate):
|
|
24
|
+
try:
|
|
25
|
+
if (type(events) is not list or type(certificate) is not dict or
|
|
26
|
+
set(certificate) != {'revision', 'registry', 'events', 'phases', 'result'} or
|
|
27
|
+
certificate['revision'] != REVISION or certificate['registry'] != REGISTRY_ID or
|
|
28
|
+
canonical(certificate['events']) != canonical(events) or
|
|
29
|
+
type(certificate['phases']) is not list or len(certificate['phases']) != len(events)):
|
|
30
|
+
return False
|
|
31
|
+
names = None
|
|
32
|
+
seen = set()
|
|
33
|
+
traces = {}
|
|
34
|
+
actions = set()
|
|
35
|
+
epoch_rows = []
|
|
36
|
+
old_groups = {}
|
|
37
|
+
prior_crystal = None
|
|
38
|
+
epoch_start = 0
|
|
39
|
+
result = {'status': 'NO_PATH', 'action_nmu': None, 'members': None}
|
|
40
|
+
for index, event in enumerate(events):
|
|
41
|
+
if (type(event) is not dict or set(event) != {'source', 'action_nmu', 'ports'} or
|
|
42
|
+
type(event['source']) is not str or not event['source'] or event['source'] in seen or
|
|
43
|
+
type(event['action_nmu']) is not list or not event['action_nmu'] or
|
|
44
|
+
type(event['ports']) is not dict):
|
|
45
|
+
return False
|
|
46
|
+
seen.add(event['source'])
|
|
47
|
+
decode(event['action_nmu'])
|
|
48
|
+
current_names = list(event['ports'])
|
|
49
|
+
if (len(current_names) < 3 or current_names != sorted(current_names) or
|
|
50
|
+
any(type(name) is not str or not name for name in current_names)):
|
|
51
|
+
return False
|
|
52
|
+
if names is None:
|
|
53
|
+
names = current_names
|
|
54
|
+
traces = {name: [] for name in names}
|
|
55
|
+
elif current_names != names:
|
|
56
|
+
return False
|
|
57
|
+
for name in names:
|
|
58
|
+
contrast = event['ports'][name]
|
|
59
|
+
if not valid_contrast(contrast):
|
|
60
|
+
return False
|
|
61
|
+
traces[name].append((contrast['kind'], tuple(contrast['positions'])))
|
|
62
|
+
epoch_rows.append(event)
|
|
63
|
+
actions.add(tuple(event['action_nmu']))
|
|
64
|
+
partition = {}
|
|
65
|
+
for name in names:
|
|
66
|
+
partition.setdefault(tuple(traces[name]), []).append(name)
|
|
67
|
+
groups = sorted(tuple(members) for members in partition.values())
|
|
68
|
+
new_groups = {}
|
|
69
|
+
cells = []
|
|
70
|
+
winners = []
|
|
71
|
+
for members in groups:
|
|
72
|
+
if members in old_groups:
|
|
73
|
+
data = old_groups[members]
|
|
74
|
+
_measure(data, members, event, names)
|
|
75
|
+
else:
|
|
76
|
+
data = {'contexts': {}, 'controls': {}, 'separators': set()}
|
|
77
|
+
for row in epoch_rows:
|
|
78
|
+
_measure(data, members, row, names)
|
|
79
|
+
new_groups[members] = data
|
|
80
|
+
counts = []
|
|
81
|
+
for action in sorted(actions):
|
|
82
|
+
omega = len(data['contexts'].get(action, ()))
|
|
83
|
+
controls = data['controls'].get(action, 0)
|
|
84
|
+
comparison = any(other != action for other in data['separators'])
|
|
85
|
+
counts.append({'action_nmu': list(action), 'omega': omega,
|
|
86
|
+
'controls': controls, 'comparator': comparison})
|
|
87
|
+
if omega >= OMEGA_CRIT and controls and comparison:
|
|
88
|
+
winners.append((action, members))
|
|
89
|
+
cells.append({'members': list(members), 'C_L_by_action': counts, 'xi': 0})
|
|
90
|
+
if prior_crystal is not None and prior_crystal not in groups:
|
|
91
|
+
result = {'status': 'REVOKED', 'action_nmu': None, 'members': None}
|
|
92
|
+
prior_crystal = None
|
|
93
|
+
epoch_start = index + 1
|
|
94
|
+
epoch_rows = []
|
|
95
|
+
new_groups = {}
|
|
96
|
+
elif len(winners) == 1:
|
|
97
|
+
action, members = winners[0]
|
|
98
|
+
result = {'status': 'CRYSTAL', 'action_nmu': list(action), 'members': list(members)}
|
|
99
|
+
prior_crystal = members
|
|
100
|
+
for cell in cells:
|
|
101
|
+
cell['xi'] = int(tuple(cell['members']) == members)
|
|
102
|
+
elif prior_crystal is not None and not any(members == prior_crystal for _, members in winners):
|
|
103
|
+
result = {'status': 'REVOKED', 'action_nmu': None, 'members': None}
|
|
104
|
+
else:
|
|
105
|
+
result = {'status': 'NO_PATH', 'action_nmu': None, 'members': None}
|
|
106
|
+
expected = {'event_index': index, 'source': event['source'],
|
|
107
|
+
'epoch_start': epoch_start, 'classes': cells, 'result': result}
|
|
108
|
+
if canonical(certificate['phases'][index]) != canonical(expected):
|
|
109
|
+
return False
|
|
110
|
+
old_groups = new_groups
|
|
111
|
+
return canonical(certificate['result']) == canonical(result)
|
|
112
|
+
except (ValueError, TypeError, KeyError, IndexError, AttributeError):
|
|
113
|
+
return False
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Source-complete acquisition coverage choice before a separator is observable."""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from hashlib import sha256
|
|
4
|
+
from tgi.frame_engine import canonical
|
|
5
|
+
from tgi.identity import encode
|
|
6
|
+
from tgi.role_work import RoleSearchBudget
|
|
7
|
+
from tgi.guarded_word_goal_frontier_check import verify_guarded_word_goal_frontier
|
|
8
|
+
from tgi.guarded_word_goal_workflow import GuardedWordGoalWorkflow
|
|
9
|
+
|
|
10
|
+
def certify_unobserved_action_selection(*args,frontier,max_search_steps=None):
|
|
11
|
+
b=RoleSearchBudget(max_search_steps)
|
|
12
|
+
with b.scope():
|
|
13
|
+
b.consume();frontier=deepcopy(frontier)
|
|
14
|
+
if not verify_guarded_word_goal_frontier(*args,goal=frontier['goal'],certificate=frontier,max_depth=frontier['max_depth']):raise ValueError('Complete original current task frontier required')
|
|
15
|
+
d=frontier['discovery'];coverage=[];bindings=[]
|
|
16
|
+
for action in d['available_actions']:
|
|
17
|
+
witnesses=[]
|
|
18
|
+
for li,item in enumerate(d['laws']):
|
|
19
|
+
if item['action']!=action:continue
|
|
20
|
+
c=item['certificate'];c=c['law'] if c['policy']=='observation_context_laws_v1' else c;matching=[]
|
|
21
|
+
for ri,row in enumerate(c['rows']):
|
|
22
|
+
b.consume()
|
|
23
|
+
if row['cells'][item['port']]['frames'][1]==action:matching.append(ri)
|
|
24
|
+
witnesses.append({'law_index':li,'port':item['port'],'matching_original_rows':matching})
|
|
25
|
+
unobserved=bool(witnesses) and len(witnesses)==len(d['state_certificate']['ports']) and all(not w['matching_original_rows'] for w in witnesses)
|
|
26
|
+
coverage.append({'action':action,'action_ids':list(encode(action)),'source_coverage':witnesses,'unobserved':unobserved})
|
|
27
|
+
indexes=[]
|
|
28
|
+
for ci,choice in enumerate(frontier['choices']):
|
|
29
|
+
b.consume()
|
|
30
|
+
if unobserved and choice['kind']=='FRONTIER_EXPERIENCE' and choice['actions']==[action] and len(choice['edges'])==1 and frontier['frontier']['edges'][choice['edges'][0]]['source']==0:indexes.append(ci)
|
|
31
|
+
if unobserved:bindings.append({'action':action,'choice_indexes':indexes})
|
|
32
|
+
ready=d['result']['catalogue_current'] and d['state_certificate']['result']['status']=='JOINT_STATE_READY'
|
|
33
|
+
eligible=[row for row in bindings if len(row['choice_indexes'])==1];unique=ready and len(bindings)==1 and len(eligible)==1
|
|
34
|
+
status='UNIQUE_UNOBSERVED_ACTION_SELECTION_READY' if unique else 'UNOBSERVED_ACTION_ALTERNATIVES_RETAINED' if bindings else 'NO_CURRENT_UNOBSERVED_ACTION'
|
|
35
|
+
return {'policy':'unobserved_action_selection_v1','frontier_sha256':sha256(canonical(frontier).encode()).hexdigest(),'coverage':coverage,'bindings':bindings,'result':{'status':status,'selected_action':eligible[0]['action'] if unique else None,'selected_choice_index':eligible[0]['choice_indexes'][0] if unique else None,'effect_predicted':False,'separation_claimed':False}}
|
|
36
|
+
|
|
37
|
+
def select_unique_unobserved_action(workflow,*,max_search_steps=None):
|
|
38
|
+
from tgi.unobserved_action_selection_check import verify_unobserved_action_selection
|
|
39
|
+
b=RoleSearchBudget(max_search_steps)
|
|
40
|
+
with b.scope():
|
|
41
|
+
b.consume()
|
|
42
|
+
if type(workflow) is not GuardedWordGoalWorkflow or workflow.pending()['status']!='SELECTION_REQUIRED':raise ValueError('Owned unselected current workflow required')
|
|
43
|
+
args=workflow.context();f=workflow.frontier();c=certify_unobserved_action_selection(*args,frontier=f)
|
|
44
|
+
if not verify_unobserved_action_selection(*args,frontier=f,certificate=c) or c['result']['status']!='UNIQUE_UNOBSERVED_ACTION_SELECTION_READY':raise ValueError('Unique independently checked current acquisition obligation required')
|
|
45
|
+
result=workflow.select(c['result']['selected_choice_index'])
|
|
46
|
+
if result.pending()['action']!=c['result']['selected_action']:raise ValueError('Actual selection binding mismatch')
|
|
47
|
+
return result,c
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Independent complete original-row coverage and owned frontier selection verifier."""
|
|
2
|
+
from hashlib import sha256
|
|
3
|
+
from tgi.frame_engine import canonical
|
|
4
|
+
from tgi.identity import encode
|
|
5
|
+
from tgi.role_work import RoleSearchBudget
|
|
6
|
+
from tgi.guarded_word_goal_frontier_check import verify_guarded_word_goal_frontier
|
|
7
|
+
|
|
8
|
+
def verify_unobserved_action_selection(*args,frontier,certificate,max_search_steps=None):
|
|
9
|
+
b=RoleSearchBudget(max_search_steps)
|
|
10
|
+
with b.scope():
|
|
11
|
+
b.consume()
|
|
12
|
+
try:
|
|
13
|
+
if type(certificate) is not dict or set(certificate)!={'policy','frontier_sha256','coverage','bindings','result'} or certificate['policy']!='unobserved_action_selection_v1':return False
|
|
14
|
+
if not verify_guarded_word_goal_frontier(*args,goal=frontier['goal'],certificate=frontier,max_depth=frontier['max_depth']):return False
|
|
15
|
+
if certificate['frontier_sha256']!=sha256(canonical(frontier).encode()).hexdigest():return False
|
|
16
|
+
discovery=frontier['discovery'];coverage=[];bindings=[]
|
|
17
|
+
for action in discovery['available_actions']:
|
|
18
|
+
sources=[]
|
|
19
|
+
for li in range(len(discovery['laws'])):
|
|
20
|
+
law=discovery['laws'][li]
|
|
21
|
+
if law['action']!=action:continue
|
|
22
|
+
c=law['certificate'];c=c['law'] if c['policy']=='observation_context_laws_v1' else c;indexes=[]
|
|
23
|
+
for ri in range(len(c['rows'])):
|
|
24
|
+
b.consume()
|
|
25
|
+
if c['rows'][ri]['cells'][law['port']]['frames'][1]==action:indexes.append(ri)
|
|
26
|
+
sources.append({'law_index':li,'port':law['port'],'matching_original_rows':indexes})
|
|
27
|
+
missing=len(sources)==len(discovery['state_certificate']['ports']) and bool(sources) and not any(row['matching_original_rows'] for row in sources)
|
|
28
|
+
coverage.append({'action':action,'action_ids':list(encode(action)),'source_coverage':sources,'unobserved':missing})
|
|
29
|
+
choices=[]
|
|
30
|
+
for ci in range(len(frontier['choices'])):
|
|
31
|
+
b.consume();choice=frontier['choices'][ci]
|
|
32
|
+
if not missing or choice['kind']!='FRONTIER_EXPERIENCE' or choice['actions']!=[action] or len(choice['edges'])!=1:continue
|
|
33
|
+
if frontier['frontier']['edges'][choice['edges'][0]]['source']==0:choices.append(ci)
|
|
34
|
+
if missing:bindings.append({'action':action,'choice_indexes':choices})
|
|
35
|
+
eligible=[row for row in bindings if len(row['choice_indexes'])==1]
|
|
36
|
+
unique=discovery['result']['catalogue_current'] and discovery['state_certificate']['result']['status']=='JOINT_STATE_READY' and len(bindings)==1 and len(eligible)==1
|
|
37
|
+
status='UNIQUE_UNOBSERVED_ACTION_SELECTION_READY' if unique else 'UNOBSERVED_ACTION_ALTERNATIVES_RETAINED' if bindings else 'NO_CURRENT_UNOBSERVED_ACTION'
|
|
38
|
+
expected={'status':status,'selected_action':eligible[0]['action'] if unique else None,'selected_choice_index':eligible[0]['choice_indexes'][0] if unique else None,'effect_predicted':False,'separation_claimed':False}
|
|
39
|
+
return canonical(certificate['coverage'])==canonical(coverage) and canonical(certificate['bindings'])==canonical(bindings) and canonical(certificate['result'])==canonical(expected)
|
|
40
|
+
except (ValueError,KeyError,TypeError,IndexError,AttributeError):return False
|
tgi/verification.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Instrumented verification with complete-or-unverified matcher work."""
|
|
2
|
+
from .incremental import SearchBudget, FormationSearchLimit, ACTIVE_SEARCH_BUDGET
|
|
3
|
+
from .organization_check import verify_resolution, verify_refusal
|
|
4
|
+
from .organization_snapshot import snapshot
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class _VerificationBudget(SearchBudget):
|
|
8
|
+
def __init__(self,limit,parent):
|
|
9
|
+
super().__init__(limit);self.parent=parent
|
|
10
|
+
|
|
11
|
+
def match_step(self):
|
|
12
|
+
# Preflight the child before charging any ancestor. Ancestors perform
|
|
13
|
+
# the same preflight, so rejected work is charged nowhere in the chain.
|
|
14
|
+
if self.limit is not None and self.used>=self.limit:
|
|
15
|
+
raise FormationSearchLimit(self.limit,self.used)
|
|
16
|
+
if self.parent is not None:self.parent.match_step()
|
|
17
|
+
super().match_step()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def check_resolution(engine,prefix,result,*,terminal_only=False,max_match_steps=None):
|
|
21
|
+
budget=_VerificationBudget(max_match_steps,ACTIVE_SEARCH_BUDGET.get())
|
|
22
|
+
report={"status":"NOT_VERIFIED","verified":False,"match_steps":0,"max_match_steps":max_match_steps}
|
|
23
|
+
try:
|
|
24
|
+
with budget.scope():
|
|
25
|
+
if engine._dirty:return report
|
|
26
|
+
kind=result.get("status")
|
|
27
|
+
if kind not in ("RESOLVED","NO_PATH","AMBIGUOUS"):return report
|
|
28
|
+
frozen=snapshot(engine)
|
|
29
|
+
checker=verify_resolution if kind=="RESOLVED" else verify_refusal
|
|
30
|
+
verified=checker(frozen,prefix,result,terminal_only=terminal_only)
|
|
31
|
+
report.update(status="VERIFIED" if verified else "NOT_VERIFIED",verified=verified)
|
|
32
|
+
except FormationSearchLimit as error:
|
|
33
|
+
report.update(status="WORK_LIMIT",verified=False,exhausted_limit=error.limit)
|
|
34
|
+
except (KeyError,IndexError,TypeError,ValueError,AttributeError):
|
|
35
|
+
report.update(status="NOT_VERIFIED",verified=False)
|
|
36
|
+
finally:
|
|
37
|
+
report["match_steps"]=budget.matcher_used
|
|
38
|
+
return report
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def check_ask_certificate(engine, certificate, *, max_match_steps=None):
|
|
42
|
+
"""Check complete search scope; exhausted work never proves absence."""
|
|
43
|
+
from .ask_certificate import verify_ask_certificate
|
|
44
|
+
budget = _VerificationBudget(max_match_steps, ACTIVE_SEARCH_BUDGET.get())
|
|
45
|
+
report = {"status": "NOT_VERIFIED", "verified": False,
|
|
46
|
+
"match_steps": 0, "max_match_steps": max_match_steps}
|
|
47
|
+
try:
|
|
48
|
+
with budget.scope():
|
|
49
|
+
if engine._dirty:
|
|
50
|
+
return report
|
|
51
|
+
verified = verify_ask_certificate(engine, certificate)
|
|
52
|
+
report.update(status="VERIFIED" if verified else "NOT_VERIFIED",
|
|
53
|
+
verified=verified)
|
|
54
|
+
except FormationSearchLimit as error:
|
|
55
|
+
report.update(status="WORK_LIMIT", verified=False,
|
|
56
|
+
exhausted_limit=error.limit)
|
|
57
|
+
except (KeyError, IndexError, TypeError, ValueError, AttributeError):
|
|
58
|
+
report.update(status="NOT_VERIFIED", verified=False)
|
|
59
|
+
finally:
|
|
60
|
+
report["match_steps"] = budget.matcher_used
|
|
61
|
+
return report
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TemporalCandidateLimit(FormationSearchLimit):
|
|
65
|
+
"""Separate work unit: pool candidate or Cartesian tuple examination."""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class _TemporalCandidateBudget(SearchBudget):
|
|
69
|
+
def __init__(self,limit,parent):
|
|
70
|
+
super().__init__(limit);self.parent=parent
|
|
71
|
+
|
|
72
|
+
def consume(self):
|
|
73
|
+
if self.limit is not None and self.used>=self.limit:
|
|
74
|
+
raise TemporalCandidateLimit(self.limit,self.used)
|
|
75
|
+
if self.parent is not None:self.parent.consume()
|
|
76
|
+
super().consume()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def check_recent_certificate(engine,certificate,*,max_match_steps=None,max_candidates=None):
|
|
80
|
+
"""Verify temporal completeness under independent matcher/candidate ceilings."""
|
|
81
|
+
from .recent_observation import verify_recent_at,ACTIVE_TEMPORAL_CANDIDATES
|
|
82
|
+
matches=_VerificationBudget(max_match_steps,ACTIVE_SEARCH_BUDGET.get())
|
|
83
|
+
candidates=_TemporalCandidateBudget(max_candidates,ACTIVE_TEMPORAL_CANDIDATES.get())
|
|
84
|
+
report={'status':'NOT_VERIFIED','verified':False,'match_steps':0,'candidate_steps':0,
|
|
85
|
+
'max_match_steps':max_match_steps,'max_candidates':max_candidates}
|
|
86
|
+
token=ACTIVE_TEMPORAL_CANDIDATES.set(candidates)
|
|
87
|
+
try:
|
|
88
|
+
with matches.scope():
|
|
89
|
+
verified=verify_recent_at(engine,certificate)
|
|
90
|
+
report.update(status='VERIFIED' if verified else 'NOT_VERIFIED',verified=verified)
|
|
91
|
+
except TemporalCandidateLimit as error:
|
|
92
|
+
report.update(status='WORK_LIMIT',verified=False,exhausted_kind='candidates',exhausted_limit=error.limit)
|
|
93
|
+
except FormationSearchLimit as error:
|
|
94
|
+
report.update(status='WORK_LIMIT',verified=False,exhausted_kind='matcher',exhausted_limit=error.limit)
|
|
95
|
+
finally:
|
|
96
|
+
ACTIVE_TEMPORAL_CANDIDATES.reset(token)
|
|
97
|
+
report.update(match_steps=matches.matcher_used,candidate_steps=candidates.used)
|
|
98
|
+
return report
|
tgi/witness_function.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Conditional functional consensus over all measured candidate spans."""
|
|
2
|
+
from .identity import encode,decode
|
|
3
|
+
from .frame_engine import canonical
|
|
4
|
+
from .organization_snapshot import snapshot
|
|
5
|
+
from .role_work import RoleSearchBudget
|
|
6
|
+
from .acquisition_witness import certify_acquisition_witness,verify_acquisition_witness
|
|
7
|
+
from .response_eligibility import certify_response_eligibility
|
|
8
|
+
from .functional_transition import certify_functional_eligibility,certify_functional_readout
|
|
9
|
+
from .functional_transition_check import verify_functional_eligibility,_verify_functional_readout_contents
|
|
10
|
+
|
|
11
|
+
from .witness_response import _root_index
|
|
12
|
+
|
|
13
|
+
def certify_witness_function(model,measurements,root,query,*,max_search_steps=None):
|
|
14
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
15
|
+
with budget.scope():
|
|
16
|
+
view=snapshot(model);w=certify_acquisition_witness(view,measurements);i=_root_index(w['measurements'],root,query);neighbors=set()
|
|
17
|
+
for pair in w['pairs']:
|
|
18
|
+
budget.consume()
|
|
19
|
+
if i in (pair['left'],pair['right']):neighbors.add(pair['right'] if pair['left']==i else pair['left'])
|
|
20
|
+
eligibility=certify_functional_eligibility(view,certify_response_eligibility(view))
|
|
21
|
+
branches=[]
|
|
22
|
+
for j in sorted(neighbors):
|
|
23
|
+
budget.consume();r=w['measurements'][j];context=decode(tuple(w['occurrences'][j]['identities']))
|
|
24
|
+
branches.append({'measurement':dict(r),'response':certify_functional_readout(view,eligibility,[context,query])})
|
|
25
|
+
alternatives=sorted({x for b in branches for x in b['response']['result']['output']});complete=bool(branches) and all(b['response']['result']['status'] in ('OBSERVED_RESPONSE','CONDITIONAL_FUNCTION') for b in branches)
|
|
26
|
+
observed_conflict=any(b['response']['result']['basis']=='observed_conflict' for b in branches)
|
|
27
|
+
status='NO_CANDIDATES' if not branches else 'CONFLICT' if len(alternatives)>1 or observed_conflict else 'CONDITIONAL_FUNCTION_CONSENSUS' if complete and len(alternatives)==1 else 'UNRESOLVED'
|
|
28
|
+
return {'policy':'witness_function_response_v1','root':dict(root),'query':query,'witness':w,'branches':branches,'result':{'status':status,'output':alternatives if status=='CONDITIONAL_FUNCTION_CONSENSUS' else [],'alternatives':alternatives}}
|
|
29
|
+
|
|
30
|
+
def verify_witness_function(model,measurements,root,query,certificate,*,max_search_steps=None):
|
|
31
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
32
|
+
with budget.scope():
|
|
33
|
+
try:
|
|
34
|
+
view=snapshot(model)
|
|
35
|
+
if set(certificate)!={'policy','root','query','witness','branches','result'} or certificate['policy']!='witness_function_response_v1':return False
|
|
36
|
+
if canonical(certificate['root'])!=canonical(root) or certificate['query']!=query:return False
|
|
37
|
+
if not verify_acquisition_witness(view,measurements,certificate['witness']):return False
|
|
38
|
+
records=certificate['witness']['measurements'];i=_root_index(records,root,query);r=records[i];selected=[]
|
|
39
|
+
for j,other in enumerate(records):
|
|
40
|
+
budget.consume()
|
|
41
|
+
if other['source']!=r['source'] and other['clock']==r['clock'] and other['lower']<=r['upper'] and r['lower']<=other['upper']:selected.append(other)
|
|
42
|
+
branches=certificate['branches']
|
|
43
|
+
if not isinstance(branches,list) or len(branches)!=len(selected):return False
|
|
44
|
+
values=set();all_agree=True;conflict=False;verified_eligibility=None
|
|
45
|
+
for other,b in zip(selected,branches):
|
|
46
|
+
budget.consume()
|
|
47
|
+
if set(b)!={'measurement','response'} or canonical(b['measurement'])!=canonical(other):return False
|
|
48
|
+
raw=view.episodes[other['source']][0][other['frame']][other['start']:other['stop']]
|
|
49
|
+
eligibility=b['response']['eligibility']
|
|
50
|
+
if verified_eligibility is None:
|
|
51
|
+
if not verify_functional_eligibility(view,eligibility):return False
|
|
52
|
+
verified_eligibility=canonical(eligibility)
|
|
53
|
+
elif canonical(eligibility)!=verified_eligibility:return False
|
|
54
|
+
if b['response']['readout']['prefix']!=[decode(raw),query] or not _verify_functional_readout_contents(view,b['response']):return False
|
|
55
|
+
values.update(b['response']['result']['output']);all_agree &= b['response']['result']['status'] in ('OBSERVED_RESPONSE','CONDITIONAL_FUNCTION')
|
|
56
|
+
conflict |= b['response']['result']['basis']=='observed_conflict'
|
|
57
|
+
status='UNRESOLVED';output=[]
|
|
58
|
+
if not selected:status='NO_CANDIDATES'
|
|
59
|
+
elif len(values)>1 or conflict:status='CONFLICT'
|
|
60
|
+
elif all_agree and len(values)==1:status='CONDITIONAL_FUNCTION_CONSENSUS';output=sorted(values)
|
|
61
|
+
return canonical(certificate['result'])==canonical({'status':status,'output':output,'alternatives':sorted(values)})
|
|
62
|
+
except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False
|
tgi/witness_probe.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Complete conditional probe planning over measured candidate occurrences."""
|
|
2
|
+
from .identity import decode
|
|
3
|
+
from .frame_engine import canonical
|
|
4
|
+
from .organization_snapshot import snapshot
|
|
5
|
+
from .role_work import RoleSearchBudget
|
|
6
|
+
from .acquisition_witness import certify_acquisition_witness,verify_acquisition_witness
|
|
7
|
+
from .witness_response import _measured_root_index
|
|
8
|
+
from .witness_function import certify_witness_function,verify_witness_function
|
|
9
|
+
|
|
10
|
+
def certify_witness_probe(model,measurements,root,*,max_search_steps=None):
|
|
11
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
12
|
+
with budget.scope():
|
|
13
|
+
view=snapshot(model);w=certify_acquisition_witness(view,measurements);_measured_root_index(w['measurements'],root);rows=[];admitted=[]
|
|
14
|
+
queries=sorted({decode(frames[-2]) for frames,_ in view.episodes.values() if len(frames)>=3})
|
|
15
|
+
for query in queries:
|
|
16
|
+
budget.consume();c=certify_witness_function(view,measurements,root,query);groups={};complete=True
|
|
17
|
+
for i,b in enumerate(c['branches']):
|
|
18
|
+
r=b['response']['result'];complete &= r['status'] in ('CONDITIONAL_FUNCTION','OBSERVED_RESPONSE')
|
|
19
|
+
if r['output']:groups.setdefault(tuple(r['output']),[]).append(i)
|
|
20
|
+
count=len(c['branches']);separates=count>1 and complete and all(len(ids)<count for ids in groups.values())
|
|
21
|
+
rows.append({'query':query,'certificate':c,'groups':[{'response':list(v),'branches':ids} for v,ids in sorted(groups.items())],'separates':separates})
|
|
22
|
+
if separates:admitted.append(query)
|
|
23
|
+
return {'policy':'measured_probe_plan_v1','root':dict(root),'witness':w,'requests':rows,'result':{'status':'SEPARATING' if admitted else 'NO_SEPARATOR','requests':admitted}}
|
|
24
|
+
|
|
25
|
+
def verify_witness_probe(model,measurements,root,certificate,*,max_search_steps=None):
|
|
26
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
27
|
+
with budget.scope():
|
|
28
|
+
try:
|
|
29
|
+
view=snapshot(model)
|
|
30
|
+
if set(certificate)!={'policy','root','witness','requests','result'} or certificate['policy']!='measured_probe_plan_v1' or canonical(certificate['root'])!=canonical(root):return False
|
|
31
|
+
w=certificate['witness']
|
|
32
|
+
if not verify_acquisition_witness(view,measurements,w):return False
|
|
33
|
+
_measured_root_index(w['measurements'],root)
|
|
34
|
+
queries=sorted(set(decode(frames[-2]) for frames,_ in view.episodes.values() if len(frames)>=3));rows=certificate['requests']
|
|
35
|
+
if not isinstance(rows,list) or len(rows)!=len(queries):return False
|
|
36
|
+
admitted=[]
|
|
37
|
+
for query,row in zip(queries,rows):
|
|
38
|
+
budget.consume()
|
|
39
|
+
if set(row)!={'query','certificate','groups','separates'} or row['query']!=query:return False
|
|
40
|
+
c=row['certificate']
|
|
41
|
+
if canonical(c['witness'])!=canonical(w) or not verify_witness_function(view,measurements,root,query,c):return False
|
|
42
|
+
answers=[];complete=bool(c['branches'])
|
|
43
|
+
for b in c['branches']:
|
|
44
|
+
r=b['response']['result'];complete &= r['status'] in ('CONDITIONAL_FUNCTION','OBSERVED_RESPONSE');answers.append(r['output'])
|
|
45
|
+
values=sorted({tuple(a) for a in answers if a});groups=[{'response':list(v),'branches':[i for i,a in enumerate(answers) if tuple(a)==v]} for v in values]
|
|
46
|
+
separates=len(answers)>1 and complete and len(values)>1 and all(len(g['branches'])<len(answers) for g in groups)
|
|
47
|
+
if canonical(row['groups'])!=canonical(groups) or type(row['separates']) is not bool or row['separates']!=separates:return False
|
|
48
|
+
if separates:admitted.append(query)
|
|
49
|
+
return canonical(certificate['result'])==canonical({'status':'SEPARATING' if admitted else 'NO_SEPARATOR','requests':admitted})
|
|
50
|
+
except (KeyError,IndexError,TypeError,ValueError,AttributeError):return False
|