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.
Files changed (252) hide show
  1. tgi/__init__.py +7 -0
  2. tgi/__main__.py +194 -0
  3. tgi/acquisition_history.py +45 -0
  4. tgi/acquisition_history_check.py +51 -0
  5. tgi/acquisition_monitor.py +66 -0
  6. tgi/acquisition_monitor_check.py +78 -0
  7. tgi/acquisition_projection.py +70 -0
  8. tgi/acquisition_projection_check.py +93 -0
  9. tgi/acquisition_role_cells.py +53 -0
  10. tgi/acquisition_role_constraints.py +13 -0
  11. tgi/acquisition_role_constraints_check.py +66 -0
  12. tgi/acquisition_snapshot.py +35 -0
  13. tgi/acquisition_stream.py +21 -0
  14. tgi/acquisition_witness.py +117 -0
  15. tgi/actuation_goal_frontier.py +117 -0
  16. tgi/actuation_goal_frontier_check.py +147 -0
  17. tgi/actuation_goal_workflow.py +159 -0
  18. tgi/actuation_sequence_feedback.py +41 -0
  19. tgi/actuation_sequence_feedback_check.py +43 -0
  20. tgi/ask_certificate.py +74 -0
  21. tgi/bands.py +59 -0
  22. tgi/capacity_graph.py +70 -0
  23. tgi/closed_actuation_goal_frontier.py +13 -0
  24. tgi/closed_actuation_goal_frontier_check.py +19 -0
  25. tgi/closed_actuation_goal_workflow.py +159 -0
  26. tgi/closure.py +202 -0
  27. tgi/compact_acquisition_map.py +68 -0
  28. tgi/compact_acquisition_map_check.py +91 -0
  29. tgi/compact_complete_role_core.py +36 -0
  30. tgi/compact_complete_role_core_check.py +62 -0
  31. tgi/compact_measured_path.py +84 -0
  32. tgi/compact_role_observation.py +13 -0
  33. tgi/compact_role_observation_check.py +66 -0
  34. tgi/compatible_joins.py +33 -0
  35. tgi/complete_role_core.py +53 -0
  36. tgi/complete_role_core_check.py +54 -0
  37. tgi/context_family_selection.py +45 -0
  38. tgi/context_family_selection_check.py +32 -0
  39. tgi/context_family_separation.py +43 -0
  40. tgi/context_family_separation_check.py +47 -0
  41. tgi/contextual_isometry.py +62 -0
  42. tgi/contextual_isometry_check.py +54 -0
  43. tgi/continuation_checkpoint.py +75 -0
  44. tgi/continuation_cycle.py +102 -0
  45. tgi/continuation_goal_frontier.py +13 -0
  46. tgi/continuation_goal_frontier_check.py +19 -0
  47. tgi/continuation_goal_workflow.py +159 -0
  48. tgi/continuation_learning.py +36 -0
  49. tgi/continuation_learning_check.py +53 -0
  50. tgi/correspondence.py +76 -0
  51. tgi/cross_action_correspondence.py +182 -0
  52. tgi/cross_action_correspondence_check.py +92 -0
  53. tgi/cross_view_identity_map.py +41 -0
  54. tgi/cross_view_identity_map_check.py +48 -0
  55. tgi/derivation.py +74 -0
  56. tgi/empirical_transport.py +74 -0
  57. tgi/empirical_transport_check.py +78 -0
  58. tgi/events.py +36 -0
  59. tgi/evidence_response.py +24 -0
  60. tgi/evidence_response_check.py +33 -0
  61. tgi/exact_field.py +101 -0
  62. tgi/experience.py +68 -0
  63. tgi/experience_cli.py +44 -0
  64. tgi/feedback_update.py +32 -0
  65. tgi/feedback_update_check.py +38 -0
  66. tgi/formation.py +74 -0
  67. tgi/frame_cli.py +26 -0
  68. tgi/frame_engine.py +214 -0
  69. tgi/functional_capacity.py +74 -0
  70. tgi/functional_capacity_check.py +110 -0
  71. tgi/functional_transition.py +40 -0
  72. tgi/functional_transition_check.py +58 -0
  73. tgi/geometry.py +143 -0
  74. tgi/grounding.py +285 -0
  75. tgi/guarded_word_closure.py +148 -0
  76. tgi/guarded_word_closure_check.py +171 -0
  77. tgi/guarded_word_goal_frontier.py +13 -0
  78. tgi/guarded_word_goal_frontier_check.py +19 -0
  79. tgi/guarded_word_goal_workflow.py +160 -0
  80. tgi/identity.py +32 -0
  81. tgi/incidence.py +155 -0
  82. tgi/incremental.py +134 -0
  83. tgi/intervention_composition.py +63 -0
  84. tgi/intervention_composition_check.py +84 -0
  85. tgi/intervention_continuity.py +43 -0
  86. tgi/intervention_continuity_check.py +56 -0
  87. tgi/intervention_correspondence.py +156 -0
  88. tgi/intervention_correspondence_check.py +80 -0
  89. tgi/intervention_edit_contrast.py +27 -0
  90. tgi/intervention_edit_contrast_check.py +41 -0
  91. tgi/intervention_experiment.py +62 -0
  92. tgi/intervention_experiment_check.py +78 -0
  93. tgi/intervention_resolution.py +45 -0
  94. tgi/intervention_resolution_check.py +70 -0
  95. tgi/intervention_roles.py +83 -0
  96. tgi/intervention_roles_check.py +91 -0
  97. tgi/intervention_scope.py +34 -0
  98. tgi/intervention_sequence_experiment.py +71 -0
  99. tgi/intervention_sequence_experiment_check.py +97 -0
  100. tgi/interventions.py +240 -0
  101. tgi/joint_correspondence.py +73 -0
  102. tgi/joint_frontier_acquisition.py +114 -0
  103. tgi/joint_frontier_acquisition_check.py +116 -0
  104. tgi/joint_goal_observation.py +49 -0
  105. tgi/joint_goal_observation_check.py +55 -0
  106. tgi/joint_goal_traversal.py +101 -0
  107. tgi/joint_goal_traversal_check.py +114 -0
  108. tgi/joint_observed_laws.py +40 -0
  109. tgi/joint_observed_laws_check.py +63 -0
  110. tgi/joint_temporal_candidates.py +40 -0
  111. tgi/joint_temporal_candidates_check.py +68 -0
  112. tgi/lineage_knowledge.py +29 -0
  113. tgi/lineage_knowledge_check.py +41 -0
  114. tgi/lineage_state.py +39 -0
  115. tgi/lineage_state_check.py +47 -0
  116. tgi/local_acquisition_ownership.py +65 -0
  117. tgi/local_acquisition_runtime.py +119 -0
  118. tgi/local_acquisition_selection.py +41 -0
  119. tgi/local_acquisition_transition.py +50 -0
  120. tgi/local_acquisition_transition_check.py +80 -0
  121. tgi/local_edit_transport_classes.py +220 -0
  122. tgi/local_edit_transport_classes_check.py +128 -0
  123. tgi/local_evidence_persistence.py +67 -0
  124. tgi/measured_actuation_transition.py +56 -0
  125. tgi/measured_actuation_transition_check.py +81 -0
  126. tgi/measured_capacity.py +61 -0
  127. tgi/measured_context.py +52 -0
  128. tgi/measured_context_check.py +65 -0
  129. tgi/measured_context_laws.py +75 -0
  130. tgi/measured_context_laws_check.py +91 -0
  131. tgi/measured_context_layout.py +49 -0
  132. tgi/measured_occurrence_path.py +70 -0
  133. tgi/momentum.py +43 -0
  134. tgi/observation_context_laws.py +32 -0
  135. tgi/observation_context_laws_check.py +40 -0
  136. tgi/observation_epochs.py +35 -0
  137. tgi/observation_epochs_check.py +51 -0
  138. tgi/observation_point.py +92 -0
  139. tgi/observation_projection.py +45 -0
  140. tgi/observation_projection_check.py +48 -0
  141. tgi/observed_actuation_cycle.py +114 -0
  142. tgi/observed_actuation_discovery.py +41 -0
  143. tgi/observed_actuation_discovery_check.py +54 -0
  144. tgi/observed_actuation_learning.py +71 -0
  145. tgi/observed_actuation_learning_check.py +73 -0
  146. tgi/observed_actuation_runtime.py +114 -0
  147. tgi/observed_context_actions.py +66 -0
  148. tgi/observed_context_actions_check.py +81 -0
  149. tgi/observed_joint_state.py +52 -0
  150. tgi/observed_joint_state_check.py +55 -0
  151. tgi/observed_refinement.py +43 -0
  152. tgi/observed_response.py +20 -0
  153. tgi/observed_response_check.py +27 -0
  154. tgi/observed_role_core.py +41 -0
  155. tgi/observed_role_core_check.py +54 -0
  156. tgi/occurrence_route.py +56 -0
  157. tgi/operator_windows.py +84 -0
  158. tgi/operator_windows_check.py +111 -0
  159. tgi/organization.py +484 -0
  160. tgi/organization_check.py +143 -0
  161. tgi/organization_cli.py +77 -0
  162. tgi/organization_inventory_check.py +82 -0
  163. tgi/organization_snapshot.py +50 -0
  164. tgi/path_isometry.py +82 -0
  165. tgi/path_temporal_feasibility.py +69 -0
  166. tgi/phase_evidence.py +100 -0
  167. tgi/port_distinction_exploration.py +37 -0
  168. tgi/port_distinction_exploration_check.py +40 -0
  169. tgi/proofcheck.py +117 -0
  170. tgi/provenance.py +19 -0
  171. tgi/recent_observation.py +145 -0
  172. tgi/relational.py +222 -0
  173. tgi/resonance.py +114 -0
  174. tgi/response_eligibility.py +46 -0
  175. tgi/response_eligibility_check.py +55 -0
  176. tgi/response_interval_order.py +59 -0
  177. tgi/response_interval_order_check.py +92 -0
  178. tgi/response_readout.py +53 -0
  179. tgi/response_readout_check.py +73 -0
  180. tgi/role_bundle.py +31 -0
  181. tgi/role_bundle_check.py +20 -0
  182. tgi/role_candidates.py +47 -0
  183. tgi/role_candidates_check.py +57 -0
  184. tgi/role_eligibility.py +34 -0
  185. tgi/role_eligibility_check.py +46 -0
  186. tgi/role_feedback.py +15 -0
  187. tgi/role_feedback_check.py +23 -0
  188. tgi/role_history.py +37 -0
  189. tgi/role_history_check.py +51 -0
  190. tgi/role_projection.py +16 -0
  191. tgi/role_projection_check.py +85 -0
  192. tgi/role_proposal.py +39 -0
  193. tgi/role_proposal_check.py +51 -0
  194. tgi/role_readout.py +31 -0
  195. tgi/role_readout_check.py +51 -0
  196. tgi/role_response.py +34 -0
  197. tgi/role_response_check.py +40 -0
  198. tgi/role_work.py +54 -0
  199. tgi/scoped_sequence_experiment.py +20 -0
  200. tgi/scoped_sequence_experiment_check.py +33 -0
  201. tgi/separation.py +74 -0
  202. tgi/separation_check.py +87 -0
  203. tgi/sequence_prefix_feedback.py +57 -0
  204. tgi/sequence_prefix_feedback_check.py +79 -0
  205. tgi/source_intervals.py +85 -0
  206. tgi/source_intervals_check.py +97 -0
  207. tgi/spatial.py +109 -0
  208. tgi/spatial_action_observation.py +88 -0
  209. tgi/spatial_action_relation.py +53 -0
  210. tgi/spatial_action_relation_check.py +45 -0
  211. tgi/spatial_action_relation_cycle.py +84 -0
  212. tgi/spatial_action_relation_migration.py +41 -0
  213. tgi/spatial_action_relation_migration_bundle.py +60 -0
  214. tgi/spatial_contextual_action_cycle.py +130 -0
  215. tgi/spatial_contextual_action_local.py +79 -0
  216. tgi/spatial_contextual_action_phase.py +81 -0
  217. tgi/spatial_contextual_action_phase_check.py +81 -0
  218. tgi/spatial_direct_action_cycle.py +98 -0
  219. tgi/spatial_direct_action_relation.py +60 -0
  220. tgi/spatial_direct_action_relation_check.py +67 -0
  221. tgi/spatial_local_action_cycle.py +62 -0
  222. tgi/spatial_local_action_relation.py +66 -0
  223. tgi/spatial_temporal_action_cycle.py +116 -0
  224. tgi/spatial_temporal_action_local.py +77 -0
  225. tgi/spatial_temporal_action_phase.py +89 -0
  226. tgi/spatial_temporal_action_phase_check.py +94 -0
  227. tgi/structural_append_closure.py +99 -0
  228. tgi/structural_append_closure_check.py +106 -0
  229. tgi/structural_continuation_closure.py +93 -0
  230. tgi/structural_continuation_closure_check.py +108 -0
  231. tgi/temporal_candidate_spectrum.py +57 -0
  232. tgi/temporal_candidate_spectrum_check.py +94 -0
  233. tgi/temporal_correspondence.py +41 -0
  234. tgi/temporal_correspondence_check.py +56 -0
  235. tgi/temporal_projection.py +41 -0
  236. tgi/temporal_projection_check.py +56 -0
  237. tgi/transport.py +294 -0
  238. tgi/transport_cli.py +27 -0
  239. tgi/unlabeled_port_classes.py +199 -0
  240. tgi/unlabeled_port_classes_check.py +113 -0
  241. tgi/unobserved_action_selection.py +47 -0
  242. tgi/unobserved_action_selection_check.py +40 -0
  243. tgi/verification.py +98 -0
  244. tgi/witness_function.py +62 -0
  245. tgi/witness_probe.py +50 -0
  246. tgi/witness_probe_feedback.py +106 -0
  247. tgi/witness_response.py +67 -0
  248. tgi_foundation-0.2.0.dev0.dist-info/METADATA +30 -0
  249. tgi_foundation-0.2.0.dev0.dist-info/RECORD +252 -0
  250. tgi_foundation-0.2.0.dev0.dist-info/WHEEL +5 -0
  251. tgi_foundation-0.2.0.dev0.dist-info/licenses/LICENSE +3 -0
  252. tgi_foundation-0.2.0.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,159 @@
1
+ """Owned catalogue-aware selection, retained actual sessions and atomic recovery."""
2
+ from copy import deepcopy
3
+ from hashlib import sha256
4
+ import json,os,re,tempfile
5
+ from pathlib import Path
6
+ from .observed_actuation_runtime import ObservedActuationRuntime,raw
7
+ from .closed_actuation_goal_frontier import certify_closed_actuation_goal_frontier as certify_actuation_goal_frontier
8
+ from .closed_actuation_goal_frontier_check import verify_closed_actuation_goal_frontier as verify_actuation_goal_frontier
9
+ from .actuation_sequence_feedback import certify_actuation_sequence_feedback
10
+ from .actuation_sequence_feedback_check import verify_actuation_sequence_feedback,same_state_context
11
+ from .organization import RawOrganization
12
+ from .organization_snapshot import snapshot
13
+ from .organization_inventory_check import verify_organization_inventory
14
+ from .identity import REGISTRY_ID
15
+ from .frame_engine import canonical,unique_object
16
+ from .role_work import RoleSearchBudget
17
+ from .incremental import FormationSearchLimit
18
+ REVISION='TGI-CLOSED-ACTUATION-GOAL-WORKFLOW-V1'
19
+ FIELDS={'origin','frontier','selection_index','records','current','current_plan','current_frontier','feedback'}
20
+
21
+ def verify_session(s,goal,max_depth,budget):
22
+ budget.consume()
23
+ if type(s) is not dict or set(s)!=FIELDS or len(s['origin'])!=9 or len(s['current'])!=9 or type(s['records']) is not list:return False
24
+ for args in (s['origin'],s['current']):
25
+ if not verify_organization_inventory(snapshot(args[0])):return False
26
+ if not verify_actuation_goal_frontier(*s['origin'],goal=goal,certificate=s['frontier'],max_depth=max_depth) or not verify_actuation_goal_frontier(*s['current'],goal=goal,certificate=s['current_frontier'],max_depth=max_depth):return False
27
+ if canonical(s['current_frontier']['discovery'])!=canonical(s['current_plan']):return False
28
+ if s['selection_index'] is None:return not s['records'] and s['feedback'] is None and same_state_context(s['origin'],s['current'],budget)
29
+ return verify_actuation_sequence_feedback(s['origin'],goal,s['frontier']['frontier'],s['selection_index'],s['records'],s['current'],s['current_plan'],s['feedback'],max_depth=s['frontier']['effective_depth'])
30
+
31
+ def verify_sessions(archived,active,goal,max_depth,budget):
32
+ if type(archived) is not list:return False
33
+ previous=None
34
+ for s in [*archived,active]:
35
+ if not verify_session(s,goal,max_depth,budget) or (previous is not None and not same_state_context(previous,s['origin'],budget)):return False
36
+ previous=s['current']
37
+ return True
38
+
39
+ class ClosedActuationGoalWorkflow:
40
+ def __init__(self,runtime,goal,*,max_depth=None,max_search_steps=None):
41
+ b=RoleSearchBudget(max_search_steps)
42
+ with b.scope():
43
+ b.consume();self._runtime=deepcopy(runtime);self._goal=deepcopy(goal);self._depth=max_depth;args=self._runtime.context();frontier=certify_actuation_goal_frontier(*args,goal=goal,max_depth=max_depth)
44
+ self._active={'origin':args,'frontier':frontier,'selection_index':None,'records':[],'current':deepcopy(args),'current_plan':self._runtime.plan(),'current_frontier':deepcopy(frontier),'feedback':None};self._archived=[]
45
+ if not verify_sessions(self._archived,self._active,self._goal,self._depth,b):raise ValueError('Verified complete native goal workflow required')
46
+ def frontier(self):return deepcopy(self._active['current_frontier'])
47
+ def feedback(self):return deepcopy(self._active['feedback'])
48
+ def runtime(self):return deepcopy(self._runtime)
49
+ def sessions(self):return deepcopy([*self._archived,self._active])
50
+ def select(self,index,*,max_search_steps=None):
51
+ b=RoleSearchBudget(max_search_steps)
52
+ with b.scope():
53
+ b.consume()
54
+ if self._active['selection_index'] is not None or self._active['records']:raise ValueError('Replan before selecting another complete sequence')
55
+ obj=self.replan() if canonical(self._active['frontier'])!=canonical(self._active['current_frontier']) else deepcopy(self);obj._active['selection_index']=index;obj._active['feedback']=certify_actuation_sequence_feedback(obj._active['origin'],obj._goal,obj._active['frontier']['frontier'],index,[],obj._active['current'],obj._active['current_plan'],max_depth=obj._active['frontier']['effective_depth'])
56
+ if not verify_sessions(obj._archived,obj._active,obj._goal,obj._depth,b):raise ValueError('Independent selected workflow verification failed')
57
+ return obj
58
+ def pending(self):
59
+ s=self._active
60
+ if s['selection_index'] is None:return {'status':'SELECTION_REQUIRED','action':None,'position':0}
61
+ f=s['feedback']['result'];position=f['consumed_steps']
62
+ if f['terminal']:return {'status':f['status'],'action':None,'position':position}
63
+ choice=s['frontier']['choices'][s['selection_index']];action=choice['actions'][position];p=s['current_plan']
64
+ status='FRESH_CATALOGUE_REQUIRED' if not p['result']['catalogue_current'] else 'PLANNED_ACTION_UNAVAILABLE' if action not in p['available_actions'] else 'ACTUAL_TRANSITION_READY'
65
+ return {'status':status,'action':action,'position':position}
66
+ def _renew(self,runtime):
67
+ obj=deepcopy(self);obj._runtime=runtime;obj._active['current']=runtime.context();obj._active['current_plan']=runtime.plan();obj._active['current_frontier']=certify_actuation_goal_frontier(*obj._active['current'],goal=obj._goal,max_depth=obj._depth)
68
+ if obj._active['selection_index'] is not None:obj._active['feedback']=certify_actuation_sequence_feedback(obj._active['origin'],obj._goal,obj._active['frontier']['frontier'],obj._active['selection_index'],obj._active['records'],obj._active['current'],obj._active['current_plan'],max_depth=obj._active['frontier']['effective_depth'])
69
+ return obj
70
+ def advance(self,acquired,groups,measurements,group_index,*,catalogue=None,catalogue_measurements=None,max_search_steps=None):
71
+ b=RoleSearchBudget(max_search_steps)
72
+ with b.scope():
73
+ b.consume();pending=self.pending()
74
+ if pending['status']!='ACTUAL_TRANSITION_READY':raise ValueError('Selected, available, current nonterminal action required')
75
+ args=self._runtime.context();p=self._runtime.plan();index=p['available_actions'].index(pending['action']);context=(*args,p,index,acquired,groups,measurements,group_index);next,c=self._runtime.advance(index,acquired,groups,measurements,group_index,catalogue=catalogue,catalogue_measurements=catalogue_measurements)
76
+ if next is None:return None,c
77
+ obj=deepcopy(self);obj._active['records'].append(deepcopy({'context':context,'after':next.context()[0],'certificate':c}));obj=obj._renew(next)
78
+ if not verify_sessions(obj._archived,obj._active,obj._goal,obj._depth,b):raise ValueError('Independent actual workflow verification failed')
79
+ return obj,c
80
+ def refresh_catalogue(self,catalogue,measurements,*,max_search_steps=None):
81
+ b=RoleSearchBudget(max_search_steps)
82
+ with b.scope():
83
+ b.consume();obj=self._renew(self._runtime.refresh_catalogue(catalogue,measurements))
84
+ if not verify_sessions(obj._archived,obj._active,obj._goal,obj._depth,b):raise ValueError('Independent catalogue refresh verification failed')
85
+ return obj
86
+ def replan(self,*,max_search_steps=None):
87
+ b=RoleSearchBudget(max_search_steps)
88
+ with b.scope():
89
+ b.consume();obj=type(self)(self._runtime,self._goal,max_depth=self._depth);obj._archived=deepcopy([*self._archived,self._active])
90
+ if not verify_sessions(obj._archived,obj._active,obj._goal,obj._depth,b):raise ValueError('Independent retained session verification failed')
91
+ return obj
92
+ def commit(self,path,*,max_search_steps=None):
93
+ b=RoleSearchBudget(max_search_steps)
94
+ with b.scope():
95
+ b.consume();archived,active=deepcopy((self._archived,self._active))
96
+ if not verify_sessions(archived,active,self._goal,self._depth,b):raise ValueError('Complete independently verified workflow required')
97
+ models=[];known={}
98
+ def model_id(m):
99
+ rows=raw(m);key=canonical(rows);b.consume_many(sum(len(f) for row in rows for f in row['frames'])+1)
100
+ if key not in known:known[key]=len(models);models.append(rows)
101
+ return {'model':known[key]}
102
+ def context(args):return [model_id(v) if i in ((0,3,7) if len(args)==9 else (0,3,7,11)) else v for i,v in enumerate(args)]
103
+ def session(s):return {**s,'origin':context(s['origin']),'current':context(s['current']),'records':[{'context':context(r['context']),'after':model_id(r['after']),'certificate':r['certificate']} for r in s['records']]}
104
+ saved_archived=[session(s) for s in archived];saved_active=session(active);payload={'revision':REVISION,'registry':REGISTRY_ID,'goal':deepcopy(self._goal),'max_depth':self._depth,'root_origin':context((archived[0] if archived else active)['origin']),'models':models,'archived':saved_archived,'active':saved_active};data=canonical({'payload':payload,'sha256':sha256(canonical(payload).encode()).hexdigest()}).encode('utf8');path=Path(path);temporary=None
105
+ try:
106
+ with tempfile.NamedTemporaryFile(mode='wb',prefix='tgi-goal-',dir=path.parent,delete=False) as f:temporary=Path(f.name);f.write(data);f.flush();os.fsync(f.fileno())
107
+ os.replace(temporary,path);temporary=None
108
+ finally:
109
+ if temporary is not None and temporary.exists():temporary.unlink()
110
+ return {'path':str(path),'sha256':sha256(data).hexdigest(),'bytes':len(data),'revision':REVISION,'raw_inventory_models':len(models),'archived_sessions':len(archived),'actual_records':sum(len(s['records']) for s in [*archived,active])}
111
+ @classmethod
112
+ def recover(cls,path,expected_sha256,*,max_search_steps=None):
113
+ b=RoleSearchBudget(max_search_steps)
114
+ with b.scope():
115
+ b.consume();data=Path(path).read_bytes()
116
+ if not isinstance(expected_sha256,str) or re.fullmatch('[0-9a-f]{64}',expected_sha256) is None or sha256(data).hexdigest()!=expected_sha256:raise ValueError('Original external workflow byte digest required')
117
+ envelope=json.loads(data.decode('utf8'),object_pairs_hook=unique_object)
118
+ if type(envelope) is not dict or set(envelope)!={'payload','sha256'}:raise ValueError('Invalid workflow envelope')
119
+ p=envelope['payload']
120
+ if type(p) is not dict or set(p)!={'revision','registry','goal','max_depth','root_origin','models','archived','active'} or p['revision']!=REVISION or p['registry']!=REGISTRY_ID or sha256(canonical(p).encode()).hexdigest()!=envelope['sha256']:raise ValueError('Invalid complete workflow payload')
121
+ if type(p['models']) is not list or not p['models']:raise ValueError('Original raw inventory pool required')
122
+ models=[];unique=set()
123
+ for rows in p['models']:
124
+ if type(rows) is not list or canonical(rows) in unique:raise ValueError('Unique complete raw inventory pool required')
125
+ unique.add(canonical(rows));m=RawOrganization()
126
+ for row in rows:
127
+ if type(row) is not dict or set(row)!={'source','frames'} or type(row['frames']) is not list:raise ValueError('Original raw episode required')
128
+ b.consume_many(sum(len(f) for f in row['frames'])+1);m.observe(row['source'],row['frames'])
129
+ limits=[];parent=b
130
+ while parent is not None:
131
+ if parent.limit is not None:limits.append(max(0,parent.limit-parent.used))
132
+ parent=getattr(parent,'parent',None)
133
+ try:m.form(max_search_steps=min(limits) if limits else None)
134
+ except FormationSearchLimit as error:b.consume_many(error.used);b.consume();raise
135
+ b.consume_many(m.formation_work['search_steps']);models.append(m)
136
+ used=set()
137
+ def model(marker):
138
+ if type(marker) is not dict or set(marker)!={'model'} or type(marker['model']) is not int or not 0<=marker['model']<len(models):raise ValueError('Exact original model slot required')
139
+ used.add(marker['model']);return models[marker['model']]
140
+ def context(args,size):
141
+ if type(args) is not list or len(args)!=size:raise ValueError('Complete original model context required')
142
+ for i in ((0,3,7) if size==9 else (0,3,7,11)):args[i]=model(args[i])
143
+ return tuple(args)
144
+ def session(s):
145
+ if type(s) is not dict or set(s)!=FIELDS or type(s['records']) is not list:raise ValueError('Complete original session required')
146
+ s['origin']=context(s['origin'],9);s['current']=context(s['current'],9)
147
+ for r in s['records']:
148
+ if type(r) is not dict or set(r)!={'context','after','certificate'}:raise ValueError('Complete original actual transition required')
149
+ r['context']=context(r['context'],15);r['after']=model(r['after'])
150
+ return s
151
+ if type(p['archived']) is not list:raise ValueError('Ordered retained sessions required')
152
+ archived=[session(s) for s in p['archived']];active=session(p['active']);root_origin=context(p['root_origin'],9)
153
+ first=(archived[0] if archived else active)['origin']
154
+ if not same_state_context(root_origin,first,b) or canonical(root_origin[8])!=canonical(first[8]) or canonical(raw(root_origin[7]))!=canonical(raw(first[7])):raise ValueError('Original root session binding required')
155
+ if used!=set(range(len(models))) or not verify_sessions(archived,active,p['goal'],p['max_depth'],b):raise ValueError('Independent full workflow recovery verification failed')
156
+ obj=cls.__new__(cls);obj._goal=p['goal'];obj._depth=p['max_depth'];obj._archived=archived;obj._active=active;runtime=ObservedActuationRuntime.__new__(ObservedActuationRuntime);runtime._args=tuple(active['current']);runtime._plan=active['current_plan'];runtime._transaction=None
157
+ for s in [*archived,active]:
158
+ for r in s['records']:runtime._transaction=(tuple(r['context']),r['after'],r['certificate'])
159
+ obj._runtime=runtime;return obj
tgi/closure.py ADDED
@@ -0,0 +1,202 @@
1
+ """Certified finite closure of organizations formed from raw episodes.
2
+
3
+ Derived frames are transient consequences, never new formation exposures.
4
+ See contracts/RAW_CLOSURE_V2.md for terminal and resource semantics.
5
+ """
6
+ from dataclasses import dataclass
7
+ from .identity import encode, decode
8
+ from .organization import _match
9
+
10
+
11
+ class BudgetExhausted(Exception):
12
+ pass
13
+
14
+
15
+ @dataclass
16
+ class Work:
17
+ limit: int
18
+ used: int = 0
19
+
20
+ def tick(self):
21
+ self.used += 1
22
+ if self.used > self.limit:
23
+ raise BudgetExhausted
24
+
25
+
26
+ def observations(engine):
27
+ records = []
28
+ for source, (frames, _) in sorted(engine.episodes.items()):
29
+ if not engine._alive(source):
30
+ raise ValueError("Broken observed crystal")
31
+ records.extend({"source": source, "frame": fi, "text": decode(ids)}
32
+ for fi, ids in enumerate(frames))
33
+ return records
34
+
35
+
36
+ def prefixes(engine, nodes, work):
37
+ """Join ordered input paths only when their repeated axes agree."""
38
+ encoded = {text: encode(text) for text in sorted(nodes)}
39
+ yielded = set()
40
+ input_patterns = set()
41
+ frame_matches = {}
42
+ candidates = dict(engine.organizations)
43
+ candidates.update({a: h for a, (h, _) in engine.rejected_organizations.items()})
44
+ for _, h in sorted(candidates.items()):
45
+ if len(h.pattern) < 2 or h.pattern[:-1] in input_patterns:
46
+ continue
47
+ input_patterns.add(h.pattern[:-1])
48
+ states = [()]
49
+ for part in h.pattern[:-1]:
50
+ candidates = []
51
+ for text, ids in encoded.items():
52
+ work.tick()
53
+ key = (part, ids)
54
+ if key not in frame_matches:
55
+ frame_matches[key] = bool(_match((part,), (ids,)))
56
+ if frame_matches[key]:
57
+ candidates.append(text)
58
+ next_states = []
59
+ for state in states:
60
+ for text in candidates:
61
+ work.tick()
62
+ proposal = state+(text,)
63
+ if _match(h.pattern, tuple(encoded[t] for t in proposal)):
64
+ next_states.append(proposal)
65
+ states = next_states
66
+ for state in states:
67
+ if state not in yielded:
68
+ yielded.add(state)
69
+ yield state
70
+
71
+
72
+ def terminal(engine, text):
73
+ ids = encode(text)
74
+ known = list(engine.organizations.values())+[h for h, _ in engine.rejected_organizations.values()]
75
+ return not any(_match((part,), (ids,)) for h in known
76
+ for part in h.pattern[:-1] if any(k == "lit" and v for k, v in part))
77
+
78
+
79
+ def query_consequences(query, steps):
80
+ dependent = {query}
81
+ produced = set()
82
+ changed = True
83
+ while changed:
84
+ changed = False
85
+ for step in steps:
86
+ if any(text in dependent for text in step["prefix"]):
87
+ output = step["result"]["output"][0]
88
+ produced.add(output)
89
+ if output not in dependent:
90
+ dependent.add(output); changed = True
91
+ return produced
92
+
93
+
94
+ def resolve_closure(engine, query, *, max_nodes=1024, max_work=1000000, max_formation_steps=None):
95
+ encode(query)
96
+ if not query:
97
+ raise ValueError("Nonempty query required")
98
+ if type(max_nodes) is not int or type(max_work) is not int or min(max_nodes, max_work) < 1:
99
+ raise ValueError("Resource ceilings must be positive integers")
100
+ from .incremental import SearchBudget, FormationSearchLimit
101
+ SearchBudget(max_formation_steps)
102
+ work = Work(max_work)
103
+ steps, blocked, obs, nodes, fired = [], [], [], set(), set()
104
+ def result(status, reason=None, answers=()):
105
+ return {"status": status, "output": list(answers) if status == "RESOLVED" else [],
106
+ "query": query, "observations": obs, "steps": steps, "blocked": blocked, "node_count": len(nodes),
107
+ "work": work.used, "reason": reason}
108
+ try:
109
+ if engine._dirty:
110
+ if max_formation_steps is None:
111
+ engine.form()
112
+ else:
113
+ engine.form(max_search_steps=max_formation_steps)
114
+ from .organization_snapshot import snapshot
115
+ engine = snapshot(engine)
116
+ obs = observations(engine)
117
+ nodes = {r["text"] for r in obs} | {query}
118
+ if len(nodes) > max_nodes:
119
+ return result("INCOMPLETE", "node_budget")
120
+ while True:
121
+ added = False
122
+ for prefix in prefixes(engine, nodes, work):
123
+ if prefix in fired:
124
+ continue
125
+ fired.add(prefix)
126
+ resolution = engine.resolve(prefix, terminal_only=True)
127
+ if resolution["status"] in ("AMBIGUOUS", "CONFLICT"):
128
+ blocked.append({"prefix": list(prefix), "status": resolution["status"]})
129
+ continue
130
+ if resolution["status"] == "INCOMPLETE":
131
+ return result("INCOMPLETE", "incomplete_step")
132
+ if resolution["status"] != "RESOLVED" or len(resolution["output"]) != 1:
133
+ raise ValueError("Matched organization has no unique terminal frame")
134
+ steps.append({"prefix": list(prefix), "result": resolution})
135
+ text = resolution["output"][0]
136
+ if text not in nodes:
137
+ if len(nodes) == max_nodes:
138
+ return result("INCOMPLETE", "node_budget")
139
+ nodes.add(text); added = True
140
+ if not added:
141
+ break
142
+ dependent = {query} | query_consequences(query, steps)
143
+ if any(any(t in dependent for t in b["prefix"]) for b in blocked):
144
+ return result("AMBIGUOUS", "query_dependent_blocked_step")
145
+ consumed = {t for step in steps for t in step["prefix"]}
146
+ ends = sorted(text for text in query_consequences(query, steps)
147
+ if text not in consumed and terminal(engine, text))
148
+ if len(ends) > 1:
149
+ return result("CONFLICT", "multiple_terminal_consequences")
150
+ return result("RESOLVED", answers=ends) if ends else result("NO_PATH", "no_terminal_consequence")
151
+ except FormationSearchLimit:
152
+ return result("INCOMPLETE", "formation_search_limit")
153
+ except BudgetExhausted:
154
+ return result("INCOMPLETE", "work_budget")
155
+ except ValueError as error:
156
+ return result("INCOMPLETE", str(error))
157
+
158
+
159
+ def verify_closure(engine, query, certificate, *, max_work=1000000):
160
+ """Replay proof and independently require closure; never invoke a resolver."""
161
+ from .organization_check import verify_resolution
162
+ try:
163
+ if engine._dirty or certificate["status"] != "RESOLVED" or certificate["query"] != query:
164
+ return False
165
+ from .organization_snapshot import snapshot
166
+ engine = snapshot(engine)
167
+ obs = observations(engine)
168
+ if certificate["observations"] != obs:
169
+ return False
170
+ available = {r["text"] for r in obs} | {query}
171
+ checked = set()
172
+ for step in certificate["steps"]:
173
+ prefix = tuple(step["prefix"])
174
+ if prefix in checked or not all(t in available for t in prefix):
175
+ return False
176
+ resolution = step["result"]
177
+ if len(resolution["output"]) != 1 or not verify_resolution(engine, prefix, resolution, terminal_only=True):
178
+ return False
179
+ checked.add(prefix)
180
+ available.add(resolution["output"][0])
181
+ # A valid path alone does not certify that conflicting paths were absent.
182
+ # Every applicable ordered prefix in the final state needs a checked step.
183
+ from .phase_evidence import blocked_prefix
184
+ blocked = set()
185
+ for item in certificate["blocked"]:
186
+ prefix = tuple(item["prefix"])
187
+ if (prefix in checked or prefix in blocked or not all(t in available for t in prefix)
188
+ or item["status"] not in ("AMBIGUOUS", "CONFLICT") or not blocked_prefix(engine, prefix)):
189
+ return False
190
+ blocked.add(prefix)
191
+ expected = set(prefixes(engine, available, Work(max_work)))
192
+ if checked | blocked != expected:
193
+ return False
194
+ dependent = {query} | query_consequences(query, certificate["steps"])
195
+ if any(any(t in dependent for t in prefix) for prefix in blocked):
196
+ return False
197
+ consumed = {t for step in certificate["steps"] for t in step["prefix"]}
198
+ ends = sorted(t for t in query_consequences(query, certificate["steps"])
199
+ if t not in consumed and terminal(engine, t))
200
+ return len(ends) == 1 and certificate["output"] == ends and certificate["node_count"] == len(available)
201
+ except (ValueError, KeyError, TypeError, IndexError, BudgetExhausted):
202
+ return False
@@ -0,0 +1,68 @@
1
+ from tgi.compact_measured_path import _read_count
2
+ from tgi.identity import encode,decode
3
+ from tgi.acquisition_witness import certify_acquisition_witness
4
+ from tgi.organization import OMEGA_CRIT
5
+ from tgi.frame_engine import canonical
6
+ from tgi.compact_measured_path import _decimal_count
7
+
8
+ def build(left,right,alignments,direction,budget):
9
+ index={(a['left'],a['right'],a['direction']):k for k,a in enumerate(alignments)}
10
+ states=[(0,())];lookup={(0,()):0};ways=[1];edges=[];cursor=0
11
+ while cursor<len(states):
12
+ budget.consume()
13
+ mask,items=states[cursor];i=mask.bit_count()
14
+ if i<len(left):
15
+ for j in range(len(right)):
16
+ budget.consume()
17
+ if mask&(1<<j):continue
18
+ aid=index.get((i,j,direction))
19
+ if aid is None:continue
20
+ a=alignments[aid];mapping=dict(items);inverse={v:u for u,v in items};valid=True
21
+ for u,v,_,_ in a['positions']:
22
+ budget.consume()
23
+ if (u in mapping and mapping[u]!=v) or (v in inverse and inverse[v]!=u):valid=False;break
24
+ mapping[u]=v;inverse[v]=u
25
+ if not valid:continue
26
+ state=(mask|(1<<j),tuple(sorted(mapping.items())))
27
+ if state not in lookup:lookup[state]=len(states);states.append(state);ways.append(0)
28
+ target=lookup[state];ways[target]+=ways[cursor];edges.append([cursor,target,aid])
29
+ cursor+=1
30
+ return dict(direction=direction,nodes=[dict(mask=mask,mapping=[list(p) for p in items],count=_decimal_count(ways[i])) for i,(mask,items) in enumerate(states)],edges=edges,terminals=[i for i,(mask,_) in enumerate(states) if mask.bit_count()==len(left)])
31
+
32
+ def _produce(m,measurements,left,right,query,budget):
33
+ q=encode(query)
34
+ if not q or not isinstance(left,list) or not isinstance(right,list) or len(set(left))!=len(left) or len(set(right))!=len(right) or set(left)&set(right) or set(left)|set(right)!=set(m.episodes):raise ValueError('Complete disjoint channels required')
35
+ witness=certify_acquisition_witness(m,measurements);records={r['source']:r for r in witness['measurements']}
36
+ if len(records)!=len(measurements) or set(records)!=set(m.episodes):raise ValueError('Full measurements required')
37
+ for s,(frames,_) in m.episodes.items():
38
+ budget.consume()
39
+ r=records[s]
40
+ if len(frames)!=1 or r['frame']!=0 or r['start']!=0 or r['stop']!=len(frames[0]):raise ValueError('Full single-frame scope required')
41
+ left=sorted(left);right=sorted(right);clocks=sorted({r['clock'] for r in records.values()});enabled=len(left)==len(right) and len(clocks)==1;alignments=[];graphs=[];outcomes=[]
42
+ if enabled:
43
+ for i,a in enumerate(left):
44
+ for j,b in enumerate(right):
45
+ budget.consume()
46
+ if max(records[a]['lower'],records[b]['lower'])>min(records[a]['upper'],records[b]['upper']):continue
47
+ alignments.append(dict(left=i,right=j,direction=0,positions=[]));x=m.episodes[a][0][0];y=m.episodes[b][0][0]
48
+ if len(x)!=len(y):continue
49
+ for _ in x:budget.consume()
50
+ for direction in (-1,1):alignments.append(dict(left=i,right=j,direction=direction,positions=[[u,y[k if direction==1 else len(x)-1-k],k,k if direction==1 else len(x)-1-k] for k,u in enumerate(x)]))
51
+ for direction in (0,-1,1):
52
+ graph=build(left,right,alignments,direction,budget);graphs.append(graph)
53
+ if direction:
54
+ for terminal in graph['terminals']:
55
+ for _ in q:budget.consume()
56
+ node=graph['nodes'][terminal];mapping=dict(node['mapping']);missing=sorted(set(q)-set(mapping));ids=q if direction==1 else q[::-1]
57
+ outcomes.append(dict(direction=direction,terminal=terminal,count=node['count'],missing=missing,output=None if missing else decode(tuple(mapping[u] for u in ids))))
58
+ count=sum(_read_count(o['count']) for o in outcomes);outputs=sorted({o['output'] for o in outcomes if o['output'] is not None});distinct=len({m.episodes[s][0][0] for s in left})
59
+ status='INCOMPLETE' if len(left)!=len(right) else 'CLOCK_UNDETERMINED' if len(clocks)!=1 else 'CONFLICT' if not count else 'INCOMPLETE' if distinct<OMEGA_CRIT else 'UNKNOWN_ID' if any(o['missing'] for o in outcomes) else 'AMBIGUOUS_OUTPUT' if len(outputs)!=1 else 'CONDITIONAL_OUTPUT'
60
+ return dict(query=query,left=left,right=right,witness=witness,alignments=alignments,graphs=graphs,outcomes=outcomes,alternative_count=_decimal_count(count),diversity=distinct,status=status,outputs=outputs,output=outputs[0] if status=='CONDITIONAL_OUTPUT' else None)
61
+
62
+
63
+ def certify_compact_acquisition_map(model,measurements,left,right,query,*,max_search_steps=None):
64
+ from .organization_snapshot import snapshot
65
+ from .role_work import RoleSearchBudget
66
+ budget=RoleSearchBudget(max_search_steps)
67
+ with budget.scope():
68
+ return dict(policy='compact_acquisition_assignment_v1',threshold=OMEGA_CRIT,**_produce(snapshot(model),measurements,left,right,query,budget))
@@ -0,0 +1,91 @@
1
+ from tgi.compact_measured_path import _read_count
2
+ """Verify complete reachable assignment closure, not a producer rerun."""
3
+ from .identity import encode,decode
4
+ from .organization import OMEGA_CRIT
5
+ from .organization_snapshot import snapshot
6
+ from .acquisition_witness import verify_acquisition_witness
7
+ from .role_work import RoleSearchBudget
8
+ from .frame_engine import canonical
9
+ from .compact_measured_path import _decimal_count
10
+
11
+ def _graph(g,left,right,alignments,direction,budget):
12
+ if set(g)!={'direction','nodes','edges','terminals'} or type(g['direction']) is not int or g['direction']!=direction:raise ValueError('Graph schema')
13
+ nodes=g['nodes'];keys=[];lookup={}
14
+ for i,node in enumerate(nodes):
15
+ budget.consume()
16
+ if set(node)!={'mask','mapping','count'} or type(node['mask']) is not int or not 0<=node['mask']<(1<<len(right)):raise ValueError('State schema')
17
+ items=tuple(tuple(p) for p in node['mapping'])
18
+ if any(len(p)!=2 or any(type(x) is not int for x in p) for p in items) or items!=tuple(sorted(set(items))) or len({x for x,y in items})!=len(items) or len({y for x,y in items})!=len(items):raise ValueError('Invalid state relation')
19
+ key=(node['mask'],items)
20
+ if key in lookup:raise ValueError('Duplicate state')
21
+ lookup[key]=i;keys.append(key)
22
+ if not keys or keys[0]!=(0,()):raise ValueError('Missing root')
23
+ index={(a['left'],a['right'],a['direction']):k for k,a in enumerate(alignments)};edges=[]
24
+ for source,(mask,items) in enumerate(keys):
25
+ i=mask.bit_count()
26
+ if i==len(left):continue
27
+ for j in range(len(right)):
28
+ budget.consume()
29
+ aid=index.get((i,j,direction))
30
+ if mask&(1<<j) or aid is None:continue
31
+ pairs=set(items)
32
+ for u,v,_,_ in alignments[aid]['positions']:budget.consume();pairs.add((u,v))
33
+ if len({x for x,y in pairs})!=len(pairs) or len({y for x,y in pairs})!=len(pairs):continue
34
+ key=(mask|(1<<j),tuple(sorted(pairs)))
35
+ if key not in lookup:raise ValueError('Omitted continuation')
36
+ edges.append([source,lookup[key],aid])
37
+ if canonical(edges)!=canonical(g['edges']):raise ValueError('Incomplete transition inventory')
38
+ incoming=[[] for _ in nodes]
39
+ for a,b,_ in edges:incoming[b].append(a)
40
+ counts=[0]*len(nodes);counts[0]=1
41
+ for i in sorted(range(1,len(nodes)),key=lambda i:keys[i][0].bit_count()):
42
+ budget.consume();counts[i]=sum(counts[a] for a in incoming[i])
43
+ if any(v==0 for v in counts) or any(nodes[i]['count']!=_decimal_count(v) for i,v in enumerate(counts)):raise ValueError('Unreachable state or incorrect multiplicity')
44
+ terminals=[i for i,(mask,_) in enumerate(keys) if mask.bit_count()==len(left)]
45
+ if canonical(terminals)!=canonical(g['terminals']):raise ValueError('Terminal scope')
46
+ return terminals
47
+
48
+ def verify_compact_acquisition_map(model,measurements,left,right,query,c,*,max_search_steps=None):
49
+ budget=RoleSearchBudget(max_search_steps)
50
+ with budget.scope():
51
+ try:
52
+ if not isinstance(c,dict) or set(c)!={'policy','threshold','query','left','right','witness','alignments','graphs','outcomes','alternative_count','diversity','status','outputs','output'} or c['policy']!='compact_acquisition_assignment_v1' or type(c['threshold']) is not int or c['threshold']!=OMEGA_CRIT:return False
53
+ m=snapshot(model);q=encode(query)
54
+ if not q or not isinstance(left,list) or not isinstance(right,list) or len(set(left))!=len(left) or len(set(right))!=len(right) or set(left)&set(right) or set(left)|set(right)!=set(m.episodes):return False
55
+ if not verify_acquisition_witness(m,measurements,c['witness']):return False
56
+ records={r['source']:r for r in measurements}
57
+ if len(records)!=len(measurements) or set(records)!=set(m.episodes):return False
58
+ for s,(frames,_) in m.episodes.items():
59
+ budget.consume();r=records[s]
60
+ if len(frames)!=1 or (r['frame'],r['start'],r['stop'])!=(0,0,len(frames[0])):return False
61
+ left=sorted(left);right=sorted(right)
62
+ if c['query']!=query or canonical(c['left'])!=canonical(left) or canonical(c['right'])!=canonical(right):return False
63
+ clocks={r['clock'] for r in measurements};enabled=len(left)==len(right) and len(clocks)==1;alignments=[]
64
+ if enabled:
65
+ for i,a in enumerate(left):
66
+ for j,b in enumerate(right):
67
+ budget.consume()
68
+ if records[a]['upper']<records[b]['lower'] or records[b]['upper']<records[a]['lower']:continue
69
+ alignments.append(dict(left=i,right=j,direction=0,positions=[]));x=m.episodes[a][0][0];y=m.episodes[b][0][0]
70
+ if len(x)!=len(y):continue
71
+ for sign in (-1,1):
72
+ positions=[]
73
+ for k,u in enumerate(x):budget.consume();p=k if sign==1 else len(x)-1-k;positions.append([u,y[p],k,p])
74
+ alignments.append(dict(left=i,right=j,direction=sign,positions=positions))
75
+ if canonical(c['alignments'])!=canonical(alignments) or len(c['graphs'])!=(3 if enabled else 0):return False
76
+ outcomes=[]
77
+ for g,sign in zip(c['graphs'],(0,-1,1)):
78
+ terminals=_graph(g,left,right,alignments,sign,budget)
79
+ if not sign:continue
80
+ for terminal in terminals:
81
+ node=g['nodes'][terminal];mapping=dict(node['mapping']);missing=set();output=[]
82
+ for k in range(len(q)):
83
+ budget.consume();u=q[k if sign==1 else len(q)-1-k]
84
+ if u not in mapping:missing.add(u)
85
+ else:output.append(mapping[u])
86
+ outcomes.append(dict(direction=sign,terminal=terminal,count=node['count'],missing=sorted(missing),output=None if missing else decode(tuple(output))))
87
+ count=sum(_read_count(o['count']) for o in outcomes);outputs=sorted({o['output'] for o in outcomes if o['output'] is not None});distinct=len({m.episodes[s][0][0] for s in left})
88
+ status='INCOMPLETE' if len(left)!=len(right) else 'CLOCK_UNDETERMINED' if len(clocks)!=1 else 'CONFLICT' if not count else 'INCOMPLETE' if distinct<OMEGA_CRIT else 'UNKNOWN_ID' if any(o['missing'] for o in outcomes) else 'AMBIGUOUS_OUTPUT' if len(outputs)!=1 else 'CONDITIONAL_OUTPUT'
89
+ expected=dict(outcomes=outcomes,alternative_count=_decimal_count(count),diversity=distinct,status=status,outputs=outputs,output=outputs[0] if status=='CONDITIONAL_OUTPUT' else None)
90
+ return all(canonical(c[k])==canonical(v) for k,v in expected.items())
91
+ except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False
@@ -0,0 +1,36 @@
1
+ """Maximal complete original columns over the exact full symbolic role domain."""
2
+ from .organization_snapshot import snapshot
3
+ from .compact_role_observation import certify_compact_role_constraints
4
+ from .complete_role_core import projected_domain
5
+ from .intervention_roles import certify_intervention_roles
6
+ from .role_work import RoleSearchBudget
7
+
8
+
9
+ def certify_compact_complete_role_core(model,groups,measurements,*,max_search_steps=None):
10
+ budget=RoleSearchBudget(max_search_steps)
11
+ with budget.scope():
12
+ budget.consume();view=snapshot(model);parent=certify_compact_role_constraints(view,groups,measurements);columns=[]
13
+ for index in range(len(parent['ports'])):
14
+ budget.consume_many(len(parent['rows'])+1)
15
+ if all(r['cells'][index] is not None for r in parent['rows']):columns.append(index)
16
+ ports=[parent['ports'][i] for i in columns];local,gs,ms,sources=projected_domain(view,groups,measurements,ports);budget.consume_many(len(sources)+len(ms)+sum(map(len,gs))+len(gs));roles=certify_intervention_roles(local,gs,ms) if ports else None
17
+ return {'policy':'complete_measured_role_core_v2','parent':parent,'columns':columns,'ports':ports,'excluded':[p for p in parent['ports'] if p not in ports],'groups':gs,'sources':sources,'roles':roles,'result':{'status':'COMPLETE_ROLE_CORE' if ports else 'NO_COMPLETE_ROLE_CORE','rows_retained':len(parent['rows'])}}
18
+
19
+
20
+ def certify_compact_complete_core_resolution(model,groups,measurements,root_port,before,action,*,max_search_steps=None):
21
+ from copy import deepcopy
22
+ from .identity import encode
23
+ from .intervention_resolution import certify_intervention_resolution
24
+ budget=RoleSearchBudget(max_search_steps)
25
+ with budget.scope():
26
+ budget.consume();view=snapshot(model)
27
+ if not all(isinstance(x,str) and x for x in (root_port,before,action)):raise ValueError('Nonempty original query required')
28
+ for x in (root_port,before,action):encode(x)
29
+ core=certify_compact_complete_role_core(view,groups,measurements)
30
+ if root_port not in core['parent']['ports']:raise ValueError('Unknown root port')
31
+ child=None
32
+ if root_port in core['ports']:
33
+ local,gs,ms,_=projected_domain(view,groups,measurements,core['ports'])
34
+ child=certify_intervention_resolution(local,gs,ms,root_port,before,action)
35
+ result={'status':'ROOT_NOT_COMPLETE','output':[]} if child is None else deepcopy(child['result'])
36
+ return {'policy':'complete_role_core_resolution_v2','core':core,'root_port':root_port,'prefix':[before,action],'resolution':child,'result':result}
@@ -0,0 +1,62 @@
1
+ """Independent full parent, maximal columns and native resolution verification."""
2
+ from .organization_snapshot import snapshot
3
+ from .intervention_roles_check import verify_intervention_roles
4
+ from .compact_role_observation_check import verify_compact_role_constraints
5
+ from .complete_role_core_check import verify_complete_role_core
6
+ from .intervention_resolution_check import verify_intervention_resolution
7
+ from .complete_role_core import projected_domain
8
+ from .frame_engine import canonical
9
+ from .role_work import RoleSearchBudget
10
+ from .identity import encode
11
+
12
+
13
+ def verify_compact_complete_role_core(model,groups,measurements,certificate,*,max_search_steps=None):
14
+ budget=RoleSearchBudget(max_search_steps)
15
+ with budget.scope():
16
+ budget.consume()
17
+ try:
18
+ c=certificate;view=snapshot(model)
19
+ if c.get('policy')=='complete_measured_role_core_v1':return verify_complete_role_core(view,groups,measurements,c)
20
+ if set(c)!={'policy','parent','columns','ports','excluded','groups','sources','roles','result'} or c['policy']!='complete_measured_role_core_v2':return False
21
+ if not verify_compact_role_constraints(view,groups,measurements,c['parent']):return False
22
+ ports=c['parent']['ports'];columns=[]
23
+ for index in range(len(ports)):
24
+ budget.consume_many(len(c['parent']['rows'])+1)
25
+ missing=False
26
+ for row in c['parent']['rows']:
27
+ if row['cells'][index] is None:missing=True
28
+ if not missing:columns.append(index)
29
+ selected=[ports[i] for i in columns]
30
+ if canonical(c['columns'])!=canonical(columns) or c['ports']!=selected or c['excluded']!=[p for p in ports if p not in selected]:return False
31
+ local,gs,ms,sources=projected_domain(view,groups,measurements,selected)
32
+ budget.consume_many(len(sources)+len(ms)+sum(map(len,gs))+len(gs))
33
+ if canonical(c['groups'])!=canonical(gs) or c['sources']!=sources:return False
34
+ if selected:
35
+ if not verify_intervention_roles(local,gs,ms,c['roles']):return False
36
+ elif c['roles'] is not None:return False
37
+ expected={'status':'COMPLETE_ROLE_CORE' if selected else 'NO_COMPLETE_ROLE_CORE','rows_retained':len(groups)}
38
+ return canonical(c['result'])==canonical(expected)
39
+ except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False
40
+
41
+
42
+ def verify_compact_complete_core_resolution(model,groups,measurements,root_port,before,action,certificate,*,max_search_steps=None):
43
+ from .complete_role_core_check import verify_complete_core_resolution
44
+ budget=RoleSearchBudget(max_search_steps)
45
+ with budget.scope():
46
+ budget.consume()
47
+ try:
48
+ c=certificate;view=snapshot(model)
49
+ if not all(isinstance(x,str) and x for x in (root_port,before,action)):return False
50
+ for x in (root_port,before,action):encode(x)
51
+ if c.get('policy')=='observed_role_core_resolution_v1':
52
+ from .observed_role_core_check import verify_observed_role_core_resolution
53
+ return verify_observed_role_core_resolution(view,groups,measurements,root_port,before,action,c)
54
+ if c.get('policy')=='complete_role_core_resolution_v1':return verify_complete_core_resolution(view,groups,measurements,root_port,before,action,c)
55
+ if set(c)!={'policy','core','root_port','prefix','resolution','result'} or c['policy']!='complete_role_core_resolution_v2' or c['root_port']!=root_port or c['prefix']!=[before,action]:return False
56
+ if not verify_compact_complete_role_core(view,groups,measurements,c['core']) or root_port not in c['core']['parent']['ports']:return False
57
+ if root_port not in c['core']['ports']:
58
+ return c['resolution'] is None and canonical(c['result'])==canonical({'status':'ROOT_NOT_COMPLETE','output':[]})
59
+ local,gs,ms,_=projected_domain(view,groups,measurements,c['core']['ports'])
60
+ if not verify_intervention_resolution(local,gs,ms,root_port,before,action,c['resolution']):return False
61
+ return canonical(c['result'])==canonical(c['resolution']['result'])
62
+ except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False