morphtree 2.1.0__py3-none-win_amd64.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.
- morphtree/__init__.py +28 -0
- morphtree/__main__.py +3 -0
- morphtree/_experimental/__init__.py +1 -0
- morphtree/_experimental/admission.py +364 -0
- morphtree/_experimental/base.py +215 -0
- morphtree/_experimental/component_cache_v2.py +263 -0
- morphtree/_experimental/evolution_report.py +307 -0
- morphtree/_experimental/execution_v2.py +697 -0
- morphtree/_experimental/facade.py +289 -0
- morphtree/_experimental/integrated.py +748 -0
- morphtree/_experimental/learning.py +418 -0
- morphtree/_experimental/manifest.json +204 -0
- morphtree/_experimental/numeric_fixture.py +21 -0
- morphtree/_experimental/parameter_contract.py +38 -0
- morphtree/_experimental/postfit.py +51 -0
- morphtree/_experimental/preprocessing.py +133 -0
- morphtree/_experimental/processes.py +191 -0
- morphtree/_experimental/producer.py +542 -0
- morphtree/_experimental/product.py +156 -0
- morphtree/_experimental/product_cli.py +43 -0
- morphtree/_experimental/roundtrip_v3.py +311 -0
- morphtree/_experimental/runtime_io.py +65 -0
- morphtree/_experimental/sampling.py +26 -0
- morphtree/_experimental/support.py +281 -0
- morphtree/_experimental/target.py +59 -0
- morphtree/_experimental/training.py +53 -0
- morphtree/_experimental/worker.py +682 -0
- morphtree/_installed.py +17 -0
- morphtree/_native/__init__.py +1 -0
- morphtree/_native/bin/win_amd64/morphtree_kernels.dll +0 -0
- morphtree/_native/buffers.py +82 -0
- morphtree/_native/loader.py +39 -0
- morphtree/_native/manifest.json +29 -0
- morphtree/_native/runtime.py +48 -0
- morphtree/_native/src/histogram.c +61 -0
- morphtree/_native/src/traversal.c +51 -0
- morphtree/api.py +388 -0
- morphtree/api_compat.py +65 -0
- morphtree/backend.py +162 -0
- morphtree/booster.py +252 -0
- morphtree/cli.py +52 -0
- morphtree/config.py +262 -0
- morphtree/control.py +20 -0
- morphtree/data.py +300 -0
- morphtree/diagnostics.py +158 -0
- morphtree/estimators.py +156 -0
- morphtree/examples.py +25 -0
- morphtree/exporting.py +224 -0
- morphtree/legacy_artifacts.py +32 -0
- morphtree/metrics.py +156 -0
- morphtree/model.py +1010 -0
- morphtree/mutations.py +205 -0
- morphtree/native_lab_backend.py +79 -0
- morphtree/numpy_backend.py +180 -0
- morphtree/optuna_tuner.py +154 -0
- morphtree/persistence.py +414 -0
- morphtree/prediction_output.py +35 -0
- morphtree/prepared_bins.py +82 -0
- morphtree/public.py +106 -0
- morphtree/resource_plan.py +170 -0
- morphtree/scalable.py +781 -0
- morphtree/scalable_backend.py +74 -0
- morphtree/scalable_checkpoint.py +129 -0
- morphtree/scalable_data.py +255 -0
- morphtree/scalable_receipts.py +92 -0
- morphtree/scalable_target.py +68 -0
- morphtree/scalable_variants.py +133 -0
- morphtree/sklearn_view.py +79 -0
- morphtree/source_markers.py +25 -0
- morphtree/species.py +47 -0
- morphtree/temporary.py +65 -0
- morphtree/training_fragment.py +130 -0
- morphtree/tree.py +231 -0
- morphtree/tuning.py +150 -0
- morphtree-2.1.0.dist-info/METADATA +212 -0
- morphtree-2.1.0.dist-info/RECORD +79 -0
- morphtree-2.1.0.dist-info/WHEEL +4 -0
- morphtree-2.1.0.dist-info/entry_points.txt +2 -0
- morphtree-2.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
"""COMP003 profile adapter to the existing installed worker and Session.
|
|
2
|
+
|
|
3
|
+
Not an authorization framework: owner claim/permit, pipe handoff, OS leases,
|
|
4
|
+
component cache, native execution and finalizers are the existing components.
|
|
5
|
+
The exact finite profile below is the only newly qualified campaign scope.
|
|
6
|
+
"""
|
|
7
|
+
import copy
|
|
8
|
+
import importlib
|
|
9
|
+
import importlib.util
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
import time
|
|
13
|
+
from contextvars import ContextVar
|
|
14
|
+
from contextlib import contextmanager
|
|
15
|
+
from dataclasses import asdict, replace
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from morphtree.config import AlgorithmGenome, HyperParams
|
|
18
|
+
from .admission import AdmissionError, digest, sha, read, safe_path, installed_identity
|
|
19
|
+
from .runtime_io import configure, artifact_path, publish, reference, WORKDIR
|
|
20
|
+
from .execution_v2 import Session as ExistingSession, PreFitBoundary
|
|
21
|
+
from .target import _NamedRows, _split, detect_target
|
|
22
|
+
from .preprocessing import TrainEncoder, _m26_rows
|
|
23
|
+
from .sampling import bootstrap
|
|
24
|
+
from .processes import exclusive_lock
|
|
25
|
+
from . import component_cache_v2 as cache
|
|
26
|
+
|
|
27
|
+
PROFILE={'id':'COMP009_NATIVE_EVOLUTION_V1','calls':13,'scalar_trees':14,'trials':0,
|
|
28
|
+
'global_seconds':600,'worker_seconds':540,'component_seconds':60,
|
|
29
|
+
'workers':1,'artifact_bytes':32*1024**2,'OOF':8,'GUARD':0,'refits':0,'retries':0}
|
|
30
|
+
PHASES=('FAMILY','OOF','STRUCTURE','NUMERIC','FINALIZATION')
|
|
31
|
+
CAPS={'FAMILY':{'calls':3,'trees':4,'trials':0},
|
|
32
|
+
'OOF':{'calls':8,'trees':8,'trials':0},
|
|
33
|
+
'STRUCTURE':{'calls':2,'trees':2,'trials':0},
|
|
34
|
+
'NUMERIC':{'calls':0,'trees':0,'trials':0}}
|
|
35
|
+
PIPE_CURRENT=ContextVar('comp009-owned-evolution-pipe',default=None)
|
|
36
|
+
WORKFLOWS=[('binary','auto','auto','none')]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def evolution_profile():
|
|
40
|
+
return PROFILE.get('id')=='COMP009_NATIVE_EVOLUTION_V1'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def oof_profiles(case,params,seed):
|
|
44
|
+
"""Four exact fixed-program declarations, not four independent sources.
|
|
45
|
+
|
|
46
|
+
Stored by the existing AdmissionEngine as explicit TRAIN-fold sources.
|
|
47
|
+
Nothing is inferred from a role name or mutable caller-supplied indices.
|
|
48
|
+
"""
|
|
49
|
+
from .sampling import oof_folds
|
|
50
|
+
from .integrated import learning_program
|
|
51
|
+
raw=case['raw'];_,y,_=detect_target(raw['y'],'binary')
|
|
52
|
+
ty=[y[i] for i in case['TRAIN']];ids=case['source']['partitions']['TRAIN']
|
|
53
|
+
held=oof_folds(ty,'binary',seed);result={}
|
|
54
|
+
for family in ('boost','bag'):
|
|
55
|
+
for genome in (AlgorithmGenome(),AlgorithmGenome(growth_policy='depthwise')):
|
|
56
|
+
program=learning_program({'task':'binary','family':family,'recipe':{'genome':genome.to_dict()}})
|
|
57
|
+
frozen=digest({'program':program,'params':params,'seed':seed})
|
|
58
|
+
source=copy.deepcopy(case['source'])
|
|
59
|
+
source['OOF']=[{'fit':[ids[i] for i in range(len(ids)) if i not in set(h)],
|
|
60
|
+
'held':[ids[i] for i in h],'recipe_sha256':frozen} for h in held]
|
|
61
|
+
result[digest(program)]={'program':program,'params':copy.deepcopy(params),'seed':seed,'source':source}
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def bound_reference(root, ref):
|
|
66
|
+
if type(ref) is not dict or set(ref)!={'path','bytes','sha256'}:raise ValueError('Exact supplied reference')
|
|
67
|
+
p=safe_path(root,ref['path'])
|
|
68
|
+
if p.stat().st_size!=ref['bytes']:raise ValueError('Changed bound size')
|
|
69
|
+
return read(p,expected_sha256=ref['sha256'])
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def prepare(engine,plan):
|
|
73
|
+
evo=evolution_profile()
|
|
74
|
+
keys={'schema','id','protocol','profile','params','seed','cases','max_requests'}|({'oof_profiles','max_mutations'} if evo else set())
|
|
75
|
+
if set(plan)!=keys or plan['schema']!=('comp009-evolution-v1' if evo else 'comp003-multiphase-v2'):
|
|
76
|
+
raise ValueError('Exact multiphase profile required')
|
|
77
|
+
if plan['id']!=('COMP009-LIVE-001' if evo else 'COMP009-LIVE-001') or plan['profile']!=PROFILE or plan['protocol']!=engine.q['protocol'] or plan['max_requests']!=32:
|
|
78
|
+
raise ValueError('Unqualified campaign/profile/protocol')
|
|
79
|
+
wanted=asdict(HyperParams(n_estimators=2,max_leaves=8,max_depth=4,max_bins=15,min_samples_leaf=2,row_fraction=1.))
|
|
80
|
+
if plan['params']!=wanted or plan['seed']!=42 or set(plan['cases'])!=({'binary'} if evo else {'binary','multiclass','regression'}):
|
|
81
|
+
raise ValueError('Frozen INT002 technical recipes/seed only')
|
|
82
|
+
result={}
|
|
83
|
+
for task,c in plan['cases'].items():
|
|
84
|
+
if set(c)!={'dataset','source'}:raise ValueError('Explicit data/source')
|
|
85
|
+
raw=bound_reference(engine.q['input_root'],c['dataset'])
|
|
86
|
+
rows,names=_m26_rows(_NamedRows(raw['X'],raw['names']));actual,y,classes=detect_target(raw['y'],task)
|
|
87
|
+
if actual!=task or len(rows)!=48 or len(rows[0])!=3:raise ValueError('Exact small exposed technical source')
|
|
88
|
+
source=c['source']
|
|
89
|
+
if source['origin']['original_sha256']!=c['dataset']['sha256'] or source['exposure']!='DEV_EXPOSED' or source['sealed'] or source['OOF']:
|
|
90
|
+
raise ValueError('Not the admitted exposed source')
|
|
91
|
+
if source['rows']!=[{'id':'ROW:'+str(i),'X':row,'y':raw['y'][i]} for i,row in enumerate(rows)]:raise ValueError('Changed source content')
|
|
92
|
+
ti,si=_split(y,task,plan['seed'])
|
|
93
|
+
if source['partitions']!={'TRAIN':['ROW:'+str(i) for i in ti],'SEARCH':['ROW:'+str(i) for i in si],'GUARD_FINAL':[]}:
|
|
94
|
+
raise ValueError('Changed actual frozen split')
|
|
95
|
+
if engine.q['sources'].get(digest(source))!=source:raise ValueError('Unknown source')
|
|
96
|
+
encoder=TrainEncoder().fit([rows[i] for i in ti]);encoder.state_['names']=names
|
|
97
|
+
if encoder.width_!=7:raise ValueError('Expected exact retained encoder width')
|
|
98
|
+
result[task]={'raw':raw,'source':source,'classes':classes,'TRAIN':ti,'SEARCH':si,'encoder':encoder.to_dict()}
|
|
99
|
+
if evo:
|
|
100
|
+
from .admission import validate_roles
|
|
101
|
+
if plan['max_mutations']!=2 or plan['oof_profiles']!=oof_profiles(result['binary'],wanted,42):
|
|
102
|
+
raise ValueError('Exact fixed-parent program/fold declarations required')
|
|
103
|
+
for profile in plan['oof_profiles'].values():
|
|
104
|
+
s=profile['source'];validate_roles(s,engine.q['sources'].get(digest(s)))
|
|
105
|
+
key=digest({'runtime':engine.identity,'plan':plan,'actual_cases':result})
|
|
106
|
+
return {'plan':copy.deepcopy(plan),'key':key,'task':'multiphase','cases':result,
|
|
107
|
+
'request':{'learning_budget':{k:PROFILE[k] for k in ('calls','scalar_trees','trials')}}}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def optional_module(engine, *, load):
|
|
111
|
+
lock=engine.q.get('optional_dependency')
|
|
112
|
+
if lock is None:return None
|
|
113
|
+
if set(lock)!={'root','files','version'} or lock['version']!='5.0.0' or not lock['files']:raise ValueError('Exact optional source lock')
|
|
114
|
+
root=Path(lock['root']).resolve()
|
|
115
|
+
if root!=engine.package.parent:raise ValueError('Optional dependency must be installed beside this wheel, no checkout path')
|
|
116
|
+
for name,h in lock['files'].items():
|
|
117
|
+
if Path(name).parts[0]=='morphtree' or sha(safe_path(root,name))!=h:raise ValueError('Changed/shadowing optional dependency')
|
|
118
|
+
spec=importlib.util.find_spec('optuna')
|
|
119
|
+
if spec is None:return None
|
|
120
|
+
if Path(spec.origin).resolve()!=root/'optuna/__init__.py':raise ValueError('Unqualified optional origin')
|
|
121
|
+
if not load:return lock
|
|
122
|
+
module=importlib.import_module('optuna')
|
|
123
|
+
if module.__version__!=lock['version']:raise ValueError('Wrong optional version')
|
|
124
|
+
return module
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class NumericBinding:
|
|
128
|
+
"""Account before ask; reuse real Optuna only in the owner-admitted worker."""
|
|
129
|
+
def __init__(self, session, module):
|
|
130
|
+
self.session=session;self.module=module;self.samplers=module.samplers
|
|
131
|
+
self.trial=module.trial
|
|
132
|
+
self.actual_driver=getattr(module,'__name__',None)=='optuna'
|
|
133
|
+
def create_study(self, **kwargs):
|
|
134
|
+
s=self.session;s.check()
|
|
135
|
+
if s.frozen is None:raise ValueError('No study before structural freeze')
|
|
136
|
+
study=self.module.create_study(**kwargs)
|
|
137
|
+
class Study:
|
|
138
|
+
def ask(self):
|
|
139
|
+
if s.mode=='PUBLIC_USER':s.reserve_trial(real_driver=self_outer.actual_driver)
|
|
140
|
+
else:s.reserve_trial()
|
|
141
|
+
result=study.ask()
|
|
142
|
+
if s.mode=='PUBLIC_USER':s.event('NUMERIC_TRIAL_ASKED',number=result.number,real=self_outer.actual_driver)
|
|
143
|
+
return result
|
|
144
|
+
def tell(self,trial,*args,**kw):
|
|
145
|
+
# Failed/interrupted trials remain charged even if tell fails.
|
|
146
|
+
s.check();value=study.tell(trial,*args,**kw)
|
|
147
|
+
s.event('NUMERIC_TRIAL_COMPLETED',number=trial.number,
|
|
148
|
+
real=(self_outer.actual_driver if s.mode=='PUBLIC_USER' else s.mode=='LIVE'),state='FAIL' if kw else 'COMPLETE')
|
|
149
|
+
return value
|
|
150
|
+
self_outer=self
|
|
151
|
+
return Study()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class Session(ExistingSession):
|
|
155
|
+
"""Specific M031 pipe-owned multiphase adapter, one shared canonical store."""
|
|
156
|
+
def admission_recipe(self, estimator, form):
|
|
157
|
+
# This is the actual additional native form that this workflow can
|
|
158
|
+
# acquire, not an arbitrary tag used to mint another capability.
|
|
159
|
+
if evolution_profile():
|
|
160
|
+
return {'schema':'comp009-evolution-capacity-v1','initial':form,
|
|
161
|
+
'OOF':{'calls':8,'scalar_trees':8,'folds':2,'max_contexts':2},
|
|
162
|
+
'child_genome':AlgorithmGenome(growth_policy='depthwise').to_dict()}
|
|
163
|
+
if estimator._research_growth and self.structural:
|
|
164
|
+
if set(form)!={'candidates'} or self.prepared['task']!='binary':
|
|
165
|
+
raise ValueError('Explicit binary two-family research scope required')
|
|
166
|
+
return {**form,'research_genome':AlgorithmGenome(growth_policy='depthwise').to_dict()}
|
|
167
|
+
return form
|
|
168
|
+
|
|
169
|
+
def __init__(self,engine,plan,policy,root,*,owner_permit=None,owner_text_sha=None):
|
|
170
|
+
configure(root);self.root=artifact_path(root);self.engine=engine
|
|
171
|
+
if self.root!=engine.workdir or self.root!=Path(engine.q['input_root']).resolve():raise ValueError('Exact supplied scope')
|
|
172
|
+
self.policy=copy.deepcopy(policy);self.policy_pin=digest(policy)
|
|
173
|
+
if PIPE_CURRENT.get()!=self.policy_pin:raise PermissionError('No actual pre-operation pipe release')
|
|
174
|
+
self.policy_file_pin=sha(self.root/'RUN-POLICY.json')
|
|
175
|
+
self.plan=copy.deepcopy(plan);self.pin=digest(plan);self.campaign=prepare(engine,plan)
|
|
176
|
+
self.mode=policy['mode'];self.owner=owner_permit;self.owner_text_sha=owner_text_sha
|
|
177
|
+
if self.mode not in ('LIVE','PREFIT','FIXTURE'):raise ValueError('Known finite mode')
|
|
178
|
+
self.fixture=self.fixture_payload if self.mode=='FIXTURE' else None
|
|
179
|
+
self.started=time.monotonic();self.prepared=None;self.physical=0;self.prefit=0;self.fixture_calls=0
|
|
180
|
+
self.logical=0;self.component=None;self.structural=False;self.cursor=0;self.phase=None;self.frozen=None;self.native_started=None
|
|
181
|
+
self._oof_capture=None;self._fold_scope=None;self._diagnostic_proofs={};self._oof_parent=None
|
|
182
|
+
self._pending_program=None;self._oof_context_intents=0
|
|
183
|
+
if (self.root/'SESSION.json').exists():raise RuntimeError('Consumed session; no new deadline/attempt')
|
|
184
|
+
cache.configure(self.root,engine.package)
|
|
185
|
+
cache._write(self.root/'SESSION.json',{'plan':self.plan,'policy':self.policy,'runtime':engine.identity})
|
|
186
|
+
self.policy_sha=sha(self.root/'SESSION.json')
|
|
187
|
+
self.store=cache.MultitaskStore(self.root/'store',max_compute_jobs=PROFILE['calls'],seconds=PROFILE['worker_seconds'])
|
|
188
|
+
self.check()
|
|
189
|
+
if self.mode=='LIVE':self.permit()
|
|
190
|
+
|
|
191
|
+
def check(self):
|
|
192
|
+
configure(self.root);cache.configure(self.root,self.engine.package)
|
|
193
|
+
if PIPE_CURRENT.get()!=self.policy_pin or digest(self.policy)!=self.policy_pin or digest(self.plan)!=self.pin:
|
|
194
|
+
raise ValueError('Mutated plan/policy/pipe')
|
|
195
|
+
if sha(self.root/'RUN-POLICY.json')!=self.policy_file_pin or sha(self.root/'SESSION.json')!=self.policy_sha:raise ValueError('Changed durable policy')
|
|
196
|
+
if digest(self.engine.q)!=self.engine._q_pin or installed_identity(self.engine.package,self.engine.q)!=self.engine.identity:raise ValueError('Changed qualification/runtime')
|
|
197
|
+
if self.engine.stop.exists() or (self.root/'STOP').exists() or (self.store.root/'STOP').exists():raise RuntimeError('STOP permanent')
|
|
198
|
+
self.store.events() # Original chained journal rejects partial/corrupt tails.
|
|
199
|
+
if sum(p.stat().st_size for p in self.root.rglob('*') if p.is_file())>PROFILE['artifact_bytes']:
|
|
200
|
+
raise RuntimeError('Global artifact cap exceeded')
|
|
201
|
+
if time.time()>=self.policy['deadline_utc'] or time.monotonic_ns()>=self.policy['deadline_ns']:raise TimeoutError('Global immutable deadline')
|
|
202
|
+
if self.native_started is not None and time.monotonic()-self.native_started>=PROFILE['component_seconds']:raise TimeoutError('Cooperative component deadline')
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def source(self):return self.prepared['source']
|
|
206
|
+
|
|
207
|
+
def bind_input(self, estimator,X,y):
|
|
208
|
+
self.check()
|
|
209
|
+
if self.cursor>=len(WORKFLOWS):raise RuntimeError('All planned workflows consumed')
|
|
210
|
+
task,family,morph,tuning=WORKFLOWS[self.cursor]
|
|
211
|
+
c=self.campaign['cases'][task];raw=c['raw'];rows,names=_m26_rows(X)
|
|
212
|
+
if rows!=raw['X'] or names!=raw['names'] or y!=raw['y'] or estimator.task not in ('auto',task):raise ValueError('Wrong ordered actual input/task')
|
|
213
|
+
if (estimator.families,estimator.morphing,estimator.tuning)!=(family,morph,tuning) or estimator.random_state!=42 or estimator.capacity is not None:
|
|
214
|
+
raise ValueError('Not the next frozen workflow')
|
|
215
|
+
if tuning=='optuna' and estimator.n_trials!=2:raise ValueError('Two startup trials only')
|
|
216
|
+
if evolution_profile() and (not estimator._evolving_program or estimator._research_growth or estimator._max_mutations!=2):
|
|
217
|
+
raise ValueError('Exact automatic evolutionary API and finite two-decision scope required')
|
|
218
|
+
_,targets,classes=detect_target(y,task)
|
|
219
|
+
self.prepared={'task':task,'source':c['source'],'rows':rows,'y':targets,'classes':classes,'names':names,
|
|
220
|
+
'ti':c['TRAIN'],'si':c['SEARCH']}
|
|
221
|
+
self.workflow_physical_start=self.store.counts()['NATIVE_FIT_STARTED']
|
|
222
|
+
self.phase='FAMILY' if evolution_profile() else 'BASELINE' if self.cursor<3 else 'FAMILY'
|
|
223
|
+
self.structural=morph=='auto';self.frozen=None;self.lineage={}
|
|
224
|
+
self.cursor+=1
|
|
225
|
+
|
|
226
|
+
def event(self,kind,**values):
|
|
227
|
+
if kind=='ORCHESTRATION':
|
|
228
|
+
e=values['value']
|
|
229
|
+
if evolution_profile() and e['operation']=='evolution_intent':
|
|
230
|
+
from .integrated import program_dispatch
|
|
231
|
+
program=e['child_program'];family,genome=program_dispatch(program)
|
|
232
|
+
if self.frozen is not None or e['gene']!='growth_policy' or genome!=AlgorithmGenome(growth_policy='depthwise'):
|
|
233
|
+
raise ValueError('Only the declared operative growth transformation before freeze')
|
|
234
|
+
self.phase='STRUCTURE';self._pending_program=copy.deepcopy(program)
|
|
235
|
+
self.lineage={'gene':e['gene'],'parent_packet_sha256':e['parent_packet_sha256'],
|
|
236
|
+
'from':AlgorithmGenome().to_dict(),'to':genome.to_dict(),
|
|
237
|
+
'reason':'OOF_HEURISTIC_HYPOTHESIS_NOT_CAUSAL_UTILITY'}
|
|
238
|
+
if e['operation']=='structural_proposal':
|
|
239
|
+
if self.frozen is not None:raise ValueError('No mutation after freeze')
|
|
240
|
+
self.phase='STRUCTURE'
|
|
241
|
+
self.lineage={'gene':e['gene'], 'parent_packet_sha256':digest(e['parent_packet']),
|
|
242
|
+
'from':copy.deepcopy(e['parent_packet']['recipe']['genome']), 'to':copy.deepcopy(e['genome']),
|
|
243
|
+
'reason':'STATIC_TECHNICAL_NOMINATION_NOT_DIAGNOSTIC_UTILITY'}
|
|
244
|
+
if e['operation']=='structure_frozen':
|
|
245
|
+
if 'packet' in e:
|
|
246
|
+
if self.frozen is not None and self.frozen!=e['packet']:raise ValueError('Changed frozen structure')
|
|
247
|
+
self.frozen=copy.deepcopy(e['packet'])
|
|
248
|
+
self.phase='NUMERIC' if self.cursor==6 else 'FINALIZATION'
|
|
249
|
+
self.store.event(kind,phase=self.phase,**values)
|
|
250
|
+
if kind=='ORCHESTRATION' and values['value']['operation']=='structural_rollback':
|
|
251
|
+
# A verified worse candidate is a normal ROLLBACK decision. This
|
|
252
|
+
# event means an exception: keep the anchor, stop the campaign,
|
|
253
|
+
# and never spend the subsequent stage's unused budget.
|
|
254
|
+
raise RuntimeError('STRUCTURAL_PHASE_FAILED_TERMINAL_NO_NUMERIC_CONTINUATION')
|
|
255
|
+
if kind=='ORCHESTRATION' and evolution_profile() and values['value']['operation']=='evolution_failure':
|
|
256
|
+
raise RuntimeError('EVOLUTION_COMPONENT_FAILED_TERMINAL_ANCHOR_PRESERVED')
|
|
257
|
+
|
|
258
|
+
@contextmanager
|
|
259
|
+
def oof_operation(self,selected,program):
|
|
260
|
+
self.check()
|
|
261
|
+
if not evolution_profile() or not self.structural or self.frozen is not None:
|
|
262
|
+
yield None;return
|
|
263
|
+
if self.mode not in ('LIVE','FIXTURE','PREFIT'):raise PermissionError('No OOF mode')
|
|
264
|
+
if self.mode=='LIVE':self.permit()
|
|
265
|
+
profile=self.plan['oof_profiles'].get(digest(program))
|
|
266
|
+
if profile is None or profile['program']!=program or selected['params']!=profile['params']:
|
|
267
|
+
raise ValueError('Current program has no exact declared fold profile')
|
|
268
|
+
if self._oof_context_intents>=2:raise RuntimeError('Two-context OOF opportunity budget exhausted')
|
|
269
|
+
form={'family':selected['family'],'members':1 if selected['family']=='boost' else profile['params']['n_estimators'],
|
|
270
|
+
'stages':profile['params']['n_estimators'] if selected['family']=='boost' else 1,
|
|
271
|
+
'classes':2,'genome_sha256':digest(program['genome'])}
|
|
272
|
+
r=self.engine.request(operation='inspect',task='binary',recipe=form,source=profile['source'],role='OOF',
|
|
273
|
+
protocol=self.engine.q['protocol'],authorization=self.engine.q['authorization']['id'],components=[])
|
|
274
|
+
previous=self.phase;self.phase='OOF';self._oof_parent=copy.deepcopy(selected)
|
|
275
|
+
try:
|
|
276
|
+
with self.engine.fold_operation(r):
|
|
277
|
+
self._oof_context_intents+=1
|
|
278
|
+
self.event('OOF_CONTEXT_INTENT',parent=digest(selected),program=digest(program),
|
|
279
|
+
fold_source=digest(profile['source']),role='TRAIN_FOLDS')
|
|
280
|
+
yield ('AUTHENTIC_FIXED_PROGRAM_TRAIN_FOLDS_ADAPTIVE_UTILITY_UNPROVED' if self.mode=='LIVE'
|
|
281
|
+
else 'SOFTWARE_FOLD_FIXTURE_NOT_TRAINED_OOF' if self.mode=='FIXTURE' else 'PREFIT_NO_TRAINED_OOF')
|
|
282
|
+
finally:self.phase=previous;self._oof_parent=None;self._fold_scope=None
|
|
283
|
+
|
|
284
|
+
def _validate_evolution_input(self,model,identity):
|
|
285
|
+
"""Reconstruct raw complements; reject a superficial role/ID rewrite."""
|
|
286
|
+
from .sampling import oof_folds
|
|
287
|
+
c=self.campaign['cases']['binary'];raw=c['raw'];_,y,_=detect_target(raw['y'],'binary')
|
|
288
|
+
ids=['ROW:'+str(i) for i in c['TRAIN']];rows=[raw['X'][i] for i in c['TRAIN']];ty=[y[i] for i in c['TRAIN']]
|
|
289
|
+
if self.phase=='OOF':
|
|
290
|
+
scope=self._fold_scope
|
|
291
|
+
if scope is None or self._oof_parent is None:raise ValueError('Missing owned current fold')
|
|
292
|
+
if scope['held'] not in oof_folds(ty,'binary',42) or scope['fit']!=[i for i in range(len(ty)) if i not in set(scope['held'])]:
|
|
293
|
+
raise ValueError('Changed raw fold complement')
|
|
294
|
+
fit=scope['fit'];rows=[rows[i] for i in fit];ty=[ty[i] for i in fit];ids=[ids[i] for i in fit]
|
|
295
|
+
wanted=self._oof_parent['recipe']['genome'];family=self._oof_parent['family']
|
|
296
|
+
elif self.phase=='STRUCTURE':
|
|
297
|
+
if self._pending_program is None:raise ValueError('Missing typed child program')
|
|
298
|
+
wanted=self._pending_program['genome'];family=self._pending_program['family']
|
|
299
|
+
elif self.phase=='FAMILY':wanted=AlgorithmGenome().to_dict();family=identity['family']
|
|
300
|
+
else:raise ValueError('No native learning outside family/OOF/structure phases')
|
|
301
|
+
encoder=TrainEncoder().fit(rows);encoder.state_['names']=raw['names']
|
|
302
|
+
encoded=encoder.transform(_NamedRows(rows,raw['names']))
|
|
303
|
+
if identity['family']!=family or identity['TRAIN_ids']!=ids or identity['actual_TRAIN_y']!=ty or identity['actual_TRAIN_X']!=encoded or identity['preprocessing']!=encoder.to_dict():
|
|
304
|
+
raise ValueError('Actual native TRAIN differs from owned raw complement/preprocessing')
|
|
305
|
+
if model.base_genome.to_dict()!=wanted:raise ValueError('Actual native learning program mismatch')
|
|
306
|
+
params=HyperParams(**self.plan['params'])
|
|
307
|
+
if family=='bag':params=replace(params,n_estimators=1,learning_rate=1.,row_fraction=1.)
|
|
308
|
+
if asdict(model.base_params)!=asdict(params):raise ValueError('Current fixed-parent numerical recipe mismatch')
|
|
309
|
+
|
|
310
|
+
def packet_lineage(self, genome):
|
|
311
|
+
if self.phase=='NUMERIC' and self.frozen is not None:
|
|
312
|
+
return copy.deepcopy(self.frozen['recipe']['lineage'])
|
|
313
|
+
return copy.deepcopy(self.lineage) if genome!=AlgorithmGenome() else {}
|
|
314
|
+
|
|
315
|
+
def _used(self):
|
|
316
|
+
rows=self.store.events()
|
|
317
|
+
used={p:{'calls':0,'trees':0,'trials':0} for p in CAPS}
|
|
318
|
+
for r in rows:
|
|
319
|
+
if r['event'] in ('NATIVE_FIT_STARTED','FIXTURE_FIT_INTENT'):
|
|
320
|
+
used[r['phase']]['calls']+=1;used[r['phase']]['trees']+=r['scalar_trees']
|
|
321
|
+
if r['event']=='NUMERIC_TRIAL_INTENT':used['NUMERIC']['trials']+=1
|
|
322
|
+
return used
|
|
323
|
+
|
|
324
|
+
def reserve(self,*,calls=0,trees=0,trials=0):
|
|
325
|
+
self.check();used=self._used()
|
|
326
|
+
if self.phase not in CAPS:raise ValueError('No learning in this phase')
|
|
327
|
+
add={'calls':calls,'trees':trees,'trials':trials}
|
|
328
|
+
if any(used[self.phase][k]+v>CAPS[self.phase][k] for k,v in add.items()):raise RuntimeError('Subbudget exhausted')
|
|
329
|
+
total={k:sum(r[k] for r in used.values()) for k in add}
|
|
330
|
+
if total['calls']+calls>PROFILE['calls'] or total['trees']+trees>PROFILE['scalar_trees'] or total['trials']+trials>PROFILE['trials']:raise RuntimeError('Global budget exhausted')
|
|
331
|
+
|
|
332
|
+
def reserve_trial(self):
|
|
333
|
+
if self.frozen is None or self.phase!='NUMERIC':raise ValueError('No trial before freeze')
|
|
334
|
+
if not self.engine.q.get('numeric_authorized') or self.engine.q.get('trial_cap',0)<=0:
|
|
335
|
+
raise PermissionError('Zero/unapproved numeric budget')
|
|
336
|
+
if self._used()['NUMERIC']['trials']>=self.engine.q['trial_cap']:raise RuntimeError('Numeric budget exhausted')
|
|
337
|
+
if self.mode=='LIVE':self.permit()
|
|
338
|
+
elif self.mode!='FIXTURE':raise PermissionError('No numeric work in PREFIT')
|
|
339
|
+
self.reserve(trials=1)
|
|
340
|
+
self.event('NUMERIC_TRIAL_INTENT',real=self.mode=='LIVE',frozen_sha256=digest(self.frozen))
|
|
341
|
+
|
|
342
|
+
def optional_optuna(self):
|
|
343
|
+
return optional_module(self.engine,load=False) is not None
|
|
344
|
+
def numeric_admitted(self, executor):
|
|
345
|
+
if not self.engine.q.get('numeric_authorized',False) or self.engine.q.get('trial_cap',0)<=0:return False
|
|
346
|
+
if self.mode=='LIVE':self.permit()
|
|
347
|
+
return self.mode in ('LIVE','FIXTURE')
|
|
348
|
+
def load_optuna(self):
|
|
349
|
+
if not self.numeric_admitted(None):raise PermissionError('No exact numeric admission')
|
|
350
|
+
if self.mode=='FIXTURE':
|
|
351
|
+
from .numeric_fixture import module
|
|
352
|
+
return NumericBinding(self,module(self.engine.q.get('numeric_fault')))
|
|
353
|
+
return NumericBinding(self,optional_module(self.engine,load=True))
|
|
354
|
+
|
|
355
|
+
def fixture_payload(self,v,X,y):
|
|
356
|
+
from morphtree.species import AlgorithmSpecies
|
|
357
|
+
payload=copy.deepcopy(bound_reference(self.engine.q['input_root'],self.engine.q['software_templates'][v['task']]))
|
|
358
|
+
p=v['params'];k=len(v['preprocessing']['encoded_classes']) if v['task']=='multiclass' else 1
|
|
359
|
+
payload['booster']['trees']=payload['booster']['trees'][:p['n_estimators']*k]
|
|
360
|
+
payload['booster']['steps']=[p['learning_rate']]*(p['n_estimators']*k)
|
|
361
|
+
payload['report']={'backend':'python-stdlib','config':{'seed':v['seed']}}
|
|
362
|
+
if v['task']=='binary':payload['algorithm']=AlgorithmSpecies(AlgorithmGenome(**v['structure']),HyperParams(**p),{'learning_recipe':payload['algorithm']['learning_recipe']|{'seed':v['seed']}}).to_dict()
|
|
363
|
+
else:payload['parameters']=p
|
|
364
|
+
scalar=p['n_estimators']*k;self.reserve(calls=1,trees=scalar)
|
|
365
|
+
self.event('FIXTURE_FIT_INTENT',scalar_trees=scalar,key=digest(v),physical_fits=0)
|
|
366
|
+
return payload
|
|
367
|
+
|
|
368
|
+
def execute_native(self,model,X,y,*,identity,cancel):
|
|
369
|
+
if evolution_profile():self._validate_evolution_input(model,identity)
|
|
370
|
+
c=asdict(model.config);p=asdict(model.base_params);task=self.prepared['task'];family=identity['family'];i=identity['member']
|
|
371
|
+
if c['seed']!=42+i:raise ValueError('Wrong member seed')
|
|
372
|
+
ids=list(range(len(identity['actual_TRAIN_y']))) if family=='boost' else bootstrap(identity['actual_TRAIN_y'],task,42+i+1)
|
|
373
|
+
if ids!=identity['ordered_sample']:raise ValueError('Changed actual bootstrap')
|
|
374
|
+
if self.phase=='NUMERIC':
|
|
375
|
+
if self.frozen is None or family!=self.frozen['family']:raise ValueError('Changed numeric family')
|
|
376
|
+
g=model.base_genome.to_dict() if task=='binary' else AlgorithmGenome().to_dict()
|
|
377
|
+
if g!=self.frozen['recipe']['genome']:raise ValueError('Changed frozen genome')
|
|
378
|
+
base=HyperParams(**self.frozen['params']);base=base if family=='boost' else replace(base,n_estimators=1,learning_rate=1.,row_fraction=1.)
|
|
379
|
+
allowed={'l2','min_samples_leaf'}|({'learning_rate'} if family=='boost' else set())
|
|
380
|
+
if any(p[k]!=v for k,v in asdict(base).items() if k not in allowed):raise ValueError('Changed structural/fixed numeric field')
|
|
381
|
+
return super().execute_native(model,X,y,identity=identity,cancel=cancel)
|
|
382
|
+
|
|
383
|
+
def native_boundary(self,original,model,X,y,kwargs):
|
|
384
|
+
self.check()
|
|
385
|
+
if self.component is None:raise PermissionError('No active component lease')
|
|
386
|
+
want,xx,yy,request=self.component;v=request.value()
|
|
387
|
+
if model is not want or X!=xx or y!=yy or set(kwargs)!={'cancel'} or not callable(kwargs['cancel']):raise ValueError('Actual native invocation changed')
|
|
388
|
+
if asdict(model.base_params)!=v['params'] or asdict(model.config)!=v['config']:raise ValueError('Actual native recipe changed')
|
|
389
|
+
g=model.base_genome.to_dict() if v['task']=='binary' else AlgorithmGenome().to_dict()
|
|
390
|
+
if g!=v['structure']:raise ValueError('Actual native structure changed')
|
|
391
|
+
self.prepared.update(request=v,key=request.key)
|
|
392
|
+
self.prefit+=1;self.event('NATIVE_PREFIT_BOUNDARY',key=request.key,physical_fits=0)
|
|
393
|
+
if self.mode=='PREFIT':raise PreFitBoundary('STOP_BEFORE_ORIGINAL_NATIVE_FIT')
|
|
394
|
+
if self.mode!='LIVE':raise PermissionError('Software cannot invoke original native function')
|
|
395
|
+
self.permit();k=len(self.prepared['classes']) if v['task']=='multiclass' else 1
|
|
396
|
+
scalar=v['params']['n_estimators']*k;self.reserve(calls=1,trees=scalar)
|
|
397
|
+
self.event('NATIVE_FIT_STARTED',key=request.key,scalar_trees=scalar)
|
|
398
|
+
self.physical+=1;self.native_started=time.monotonic()
|
|
399
|
+
try:result=original(model,X,y,**kwargs);self.check()
|
|
400
|
+
finally:self.native_started=None
|
|
401
|
+
self.event('NATIVE_FIT_COMPLETED',key=request.key,scalar_trees=scalar)
|
|
402
|
+
return result
|
|
403
|
+
|
|
404
|
+
def permit(self):
|
|
405
|
+
return validate_permit(self.owner,expected_owner_text_sha=self.owner_text_sha,engine=self.engine,
|
|
406
|
+
prepared=self.campaign,policy=self.policy,workdir=self.root)
|
|
407
|
+
|
|
408
|
+
def execute(self):
|
|
409
|
+
if evolution_profile():
|
|
410
|
+
if self.mode=='PREFIT' and self.policy['scenario']=='oof':
|
|
411
|
+
from morphtree import MorphTree
|
|
412
|
+
from .integrated import learning_program
|
|
413
|
+
from .base import _payloads
|
|
414
|
+
c=self.campaign['cases']['binary'];raw=c['raw']
|
|
415
|
+
estimator=MorphTree(task='binary',random_state=42,verbosity=0,use_optuna=False,max_mutations=2,time_budget=300)
|
|
416
|
+
self.bind_input(estimator,_NamedRows(raw['X'],raw['names']),raw['y'])
|
|
417
|
+
r=self.engine.q['oof_parent'];bound_reference(self.root,r)
|
|
418
|
+
retained=MorphTree.load(self.root/r['path'],workdir=self.root)
|
|
419
|
+
p={'id':'retained-prefit-parent','task':'binary','family':retained.best_family_,
|
|
420
|
+
'recipe':retained.recipe()['structure'],'learning_identity':retained.recipe()['training_identity'],
|
|
421
|
+
'params':retained.recipe()['params'],'artifact_sha256':digest(_payloads(retained.model_))}
|
|
422
|
+
with self.activate(),self.orchestration_operation(estimator):
|
|
423
|
+
self.evolution_context(p,learning_program(p))
|
|
424
|
+
raise AssertionError('OOF PREFIT did not stop before original native learning')
|
|
425
|
+
return live_pipeline(self)
|
|
426
|
+
if self.mode!='PREFIT':return live_pipeline(self)
|
|
427
|
+
from .integrated import MorphTree
|
|
428
|
+
seen=[]
|
|
429
|
+
for task,_,_,_ in WORKFLOWS[:3]:
|
|
430
|
+
raw=self.campaign['cases'][task]['raw']
|
|
431
|
+
model=MorphTree(task=task,families='boost',morphing='none',tuning='none',random_state=42,time_budget=300)
|
|
432
|
+
try:
|
|
433
|
+
with self.activate():model.fit(_NamedRows(raw['X'],raw['names']),raw['y'])
|
|
434
|
+
except PreFitBoundary:seen.append(task)
|
|
435
|
+
else:raise AssertionError('Original native fit reached in PREFIT')
|
|
436
|
+
self.event('ALL_TASK_PREFIT_QUALIFIED',tasks=seen,physical_fits=0)
|
|
437
|
+
raise PreFitBoundary('ALL_THREE_TASKS_BEFORE_ORIGINAL_NATIVE_FIT')
|
|
438
|
+
|
|
439
|
+
def counters(self):
|
|
440
|
+
counts=super().counters();used=self._used()
|
|
441
|
+
rows=[json.loads(x) for x in (self.store.root/'EVENTS.jsonl').read_text('utf8').splitlines()] if (self.store.root/'EVENTS.jsonl').exists() else []
|
|
442
|
+
counts.update(physical_fits_started=sum(r['event']=='NATIVE_FIT_STARTED' for r in rows),
|
|
443
|
+
physical_fits_completed=sum(r['event']=='NATIVE_FIT_COMPLETED' for r in rows),
|
|
444
|
+
Optuna_trials=sum(r['event']=='NUMERIC_TRIAL_INTENT' and r['real'] for r in rows),
|
|
445
|
+
simulated_trials=sum(r['event']=='NUMERIC_TRIAL_INTENT' and not r['real'] for r in rows),
|
|
446
|
+
stages=used,scalar_trees_started=sum(r.get('scalar_trees',0) for r in rows if r['event']=='NATIVE_FIT_STARTED'))
|
|
447
|
+
counts['trials']=counts['Optuna_trials'];return counts
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def live_pipeline(session):
|
|
451
|
+
"""Same installed API for every stage; no fit outside that API."""
|
|
452
|
+
from .integrated import MorphTree
|
|
453
|
+
if evolution_profile():
|
|
454
|
+
from morphtree import MorphTree
|
|
455
|
+
results=[]
|
|
456
|
+
for index,(task,family,morph,tuning) in enumerate(WORKFLOWS):
|
|
457
|
+
session.check();c=session.campaign['cases'][task];raw=c['raw']
|
|
458
|
+
options=dict(task=task,tuning=tuning,n_trials=2,random_state=42,time_budget=300)
|
|
459
|
+
model=(MorphTree(task=task,random_state=42,verbosity=0,use_optuna=False,max_mutations=2,time_budget=300)
|
|
460
|
+
if evolution_profile() else MorphTree.research(operators=('growth_policy:depthwise',),**options) if morph=='auto'
|
|
461
|
+
else MorphTree(families=family,morphing=morph,**options))
|
|
462
|
+
with session.activate():model.fit(_NamedRows(raw['X'],raw['names']),raw['y'])
|
|
463
|
+
folder=artifact_path(session.root/('result-'+str(index)));folder.mkdir()
|
|
464
|
+
from .postfit import finish
|
|
465
|
+
result=finish(session,model,folder,c['raw']);results.append(result)
|
|
466
|
+
session.event('WORKFLOW_COMPLETED',index=index,task=task,model=result['model'],counts=session.counters())
|
|
467
|
+
if hasattr(model,'program_history_'):
|
|
468
|
+
from .base import _payloads
|
|
469
|
+
def finalized(packet):
|
|
470
|
+
if digest(_payloads(model.model_))!=packet['artifact_sha256']:
|
|
471
|
+
raise ValueError('Postfit weights differ from verified frozen packet')
|
|
472
|
+
return {'packet_sha256':digest(packet),'weights_sha256':packet['artifact_sha256'],
|
|
473
|
+
'model':result['model'],'V3':result['V3'],'standalone':result['standalone'],
|
|
474
|
+
'predictor':result['program']}
|
|
475
|
+
with session.activate():model._verify_evolution_report(finalization=finalized)
|
|
476
|
+
result['report']=model.report()
|
|
477
|
+
if session.cursor!=len(WORKFLOWS):raise ValueError('Missing planned workflows')
|
|
478
|
+
return {**results[-1],'kind':'LIVE_NATIVE_MULTIPHASE' if session.mode=='LIVE' else 'SOFTWARE_MULTIPHASE_NOT_TRAINING',
|
|
479
|
+
'workflows':results,'counts':session.counters(),'pipeline_status':'ALL_PLANNED_STAGES_COMPLETE',
|
|
480
|
+
'recipe':model.recipe(),'report':model.report()}
|
|
481
|
+
|
|
482
|
+
def _original_claim_once(input_root, token, value):
|
|
483
|
+
"""Nonrenewable cooperative consumption across all output directories.
|
|
484
|
+
|
|
485
|
+
A token is not permission. The separate trusted owner/protocol/identity
|
|
486
|
+
checks are still mandatory before any LIVE operation.
|
|
487
|
+
"""
|
|
488
|
+
if type(token) is not str or len(token) != 64 or any((c not in '0123456789abcdef' for c in token)):
|
|
489
|
+
raise ValueError('Canonical consumption token')
|
|
490
|
+
directory = safe_path(input_root, Path(input_root) / '.native-authorities' / token)
|
|
491
|
+
with exclusive_lock(directory):
|
|
492
|
+
if (directory / 'CLAIM.json').exists() or (directory / 'CLAIM.json.pending').exists():
|
|
493
|
+
raise RuntimeError('Authority already consumed, across output roots')
|
|
494
|
+
return atomic_result(directory, 'CLAIM.json', value, lambda: None)
|
|
495
|
+
|
|
496
|
+
def validate_permit(permit, *, expected_owner_text_sha, engine, prepared, policy, workdir):
|
|
497
|
+
"""A trusted caller supplies the owner's newly recorded message hash.
|
|
498
|
+
|
|
499
|
+
A fixture, old receipt or request metadata is never itself permission.
|
|
500
|
+
This cooperative trust boundary does not sandbox hostile Python callers.
|
|
501
|
+
"""
|
|
502
|
+
if not expected_owner_text_sha:
|
|
503
|
+
raise PermissionError('Separate explicit owner consent absent')
|
|
504
|
+
if type(permit) is not dict or set(permit) != {'schema', 'scope', 'owner_text', 'runtime', 'protocol', 'plan_id', 'native_key', 'profile', 'output_root', 'phases', 'deadline_utc', 'policy_sha256'}:
|
|
505
|
+
raise ValueError('Exact owner permit schema')
|
|
506
|
+
if permit['schema'] != 'morph031-owner-fit-permit-v1' or permit['scope'] != 'EXPLICIT_OWNER_APPROVED_COMP009_EVOLUTION':
|
|
507
|
+
raise PermissionError('Not a new executable owner permit')
|
|
508
|
+
owner = bound_reference(engine.q['input_root'], permit['owner_text'])
|
|
509
|
+
if permit['owner_text']['sha256'] != expected_owner_text_sha or owner.get('authority') != 'EXPLICIT_HUMAN_MESSAGE' or owner.get('campaign') != 'COMP009-LIVE-001':
|
|
510
|
+
raise PermissionError('Unknown/consumed consent origin')
|
|
511
|
+
p = prepared['plan']
|
|
512
|
+
if owner.get('approved_profile')!=PROFILE or owner.get('approved_runtime')!=engine.identity or owner.get('approved_protocol')!=p['protocol'] or owner.get('authority_root')!=engine.q['authority_root']:raise PermissionError('Owner identity/profile/protocol mismatch')
|
|
513
|
+
if p['protocol'].get('id') != 'COMP-009-LIVE-001' or not engine.q.get('training_protocol'):
|
|
514
|
+
raise PermissionError('Zero-fit INT010 cannot authorize physical training')
|
|
515
|
+
protocol = bound_reference(engine.q['input_root'], engine.q['training_protocol'])
|
|
516
|
+
if protocol.get('id') != 'COMP-009-LIVE-001' or protocol.get('frozen_before_execution') is not True or p['protocol']['sha256'] != engine.q['training_protocol']['sha256'] or (protocol.get('planned_profile') != PROFILE):
|
|
517
|
+
raise PermissionError('Not the separately frozen physical pilot protocol')
|
|
518
|
+
if permit['runtime'] != engine.identity or permit['protocol'] != p['protocol'] or permit['plan_id'] != p['id'] or (permit['native_key'] != prepared['key']):
|
|
519
|
+
raise ValueError('Consent bound to another runtime/request')
|
|
520
|
+
if permit['profile'] != PROFILE or prepared['task'] != 'multiphase' or prepared['request']['learning_budget'] != {'calls': 13, 'scalar_trees': 14, 'trials': 0}:
|
|
521
|
+
raise ValueError('Pilot exact fit/tree/task budget')
|
|
522
|
+
if permit['output_root'] != str(Path(workdir).resolve()) or permit['phases'] != list(PHASES):
|
|
523
|
+
raise ValueError('Wrong output/operation scope')
|
|
524
|
+
activation = {k: v for k, v in policy.items() if k not in ('owner_permit', 'owner_text_sha256')}
|
|
525
|
+
if permit['policy_sha256'] != digest(activation) or permit['deadline_utc'] != policy['deadline_utc'] or time.time() >= permit['deadline_utc']:
|
|
526
|
+
raise PermissionError('Expired or different activation policy')
|
|
527
|
+
claim = read(safe_path(engine.q['authority_root'], Path(engine.q['authority_root']) / '.native-authorities' / expected_owner_text_sha / 'CLAIM.json'))
|
|
528
|
+
expected = {'owner_text_sha256': expected_owner_text_sha, 'native_key': prepared['key'], 'output_root': str(Path(workdir).resolve()), 'policy_sha256': digest(activation)}
|
|
529
|
+
if claim != expected:
|
|
530
|
+
raise PermissionError('Missing/different globally consumed authority')
|
|
531
|
+
return True
|
|
532
|
+
|
|
533
|
+
def atomic_result(root, name, value, check):
|
|
534
|
+
root = Path(root)
|
|
535
|
+
target = safe_path(root, name)
|
|
536
|
+
publish(target, json.dumps(value, sort_keys=True, allow_nan=False) + '\n', check)
|
|
537
|
+
return {'path': target.relative_to(root).as_posix(), 'bytes': target.stat().st_size, 'sha256': sha(target)}
|
|
538
|
+
|
|
539
|
+
def claim_once(root,token,value):
|
|
540
|
+
previous=WORKDIR.get();configure(root)
|
|
541
|
+
try:return _original_claim_once(root,token,value)
|
|
542
|
+
finally:WORKDIR.set(previous)
|