fix(training): bind compact parent lineage to validated bytes

This commit is contained in:
rUv committed 2026-10-13 10:57:40 -07:00
1 parent 8282a6b21e
commit 56b0085b0b
4 files changed
+109 -9

No files matched your search

@@ -0,0 +1,52 @@
{
"decision": "INCONCLUSIVE",
"date": "2026-10-13",
"hypothesis": "Compact export lineage and retention metadata must remain bound to the exact baseline receipt and model bytes admitted by MotionBundle, even if the source paths change after validation.",
"baseline": {
"commit": "8282a6b21e83756f636d377c4fe5be4a1e489792",
"tree": "6a4e65ec1dc9d22e946c6a39978ee6e291543201",
"source_sha256": {
"scripts/csi_training/espfi_motion.py": "c6a8529ccf9d9f834383a2bdf5b14626764ec7ca2ade7ad5d4c1c14797d76054",
"scripts/csi_training/espfi_motion_compact.py": "8da946e1c575ae20b96dc3fdb229bb85cdc5054f6c2efb774aca506773770c2e",
"scripts/tests/test_espfi_motion_compact.py": "109031ec230bb0aeadd26acabe2f5c119d714b4c71f9fc28351cf801176c65c5"
},
"adversarial_result": "FAIL: a forged second receipt read changed emitted parent lineage"
},
"candidate_source_sha256": {
"scripts/csi_training/espfi_motion.py": "25d4f84e16c0b699654caef5c19614ef1d23c7ef0cc1e224e931cc5b95195b63",
"scripts/csi_training/espfi_motion_compact.py": "33886d88705410646787a73b05474e36e50be0d4a26535147a1a3bfaddd4b037",
"scripts/tests/test_espfi_motion_compact.py": "68b562b1e31ef21ce1db10457f0965d5a882e853e3d8aa40240e82fc47a798e3"
},
"data_and_split_policy": "No dataset, split, preprocessing, model weights, thresholds, predictions, or final-test payloads were read or changed.",
"acceptance": {
"adversarial_lineage_and_size_test": "PASS",
"focused_compact_tests": "4/4 PASS",
"motion_regression_tests": "40/40 PASS",
"broader_csi_tests": "72 PASS; collection stopped on missing local optional h5py dependency",
"diff_check": "PASS",
"independent_security_review": "NO BLOCK",
"hosted_ci": "PENDING"
},
"load_benchmark": {
"workload": "500 alternating loads after 20 warmups; 100 traced loads per arm",
"baseline": {
"p50_ms": 0.974565,
"p95_ms": 1.322553,
"peak_bytes": 16793369
},
"candidate": {
"p50_ms": 0.98026,
"p95_ms": 1.285652,
"peak_bytes": 16793409
},
"frozen_gate": "candidate p95 <= max(1.2 * baseline p95, baseline p95 + 0.1 ms) and peak <= baseline + 4096 bytes",
"result": "PASS"
},
"security_scope": {
"fixed": "Parent receipt hash, model hash, model byte count, and retention gate use the exact buffers validated by MotionBundle.",
"residual": "Initial multi-path intake is not an authenticated atomic directory snapshot; coherent pre-validation substitution remains outside this patch."
},
"cost": "Existing authorized ruOS CPU only; monetary cost unknown.",
"rollback": "Revert the containing commit.",
"next_action": "Require terminal hosted CI at the exact published head before accepting the candidate."
}
+12 -3
View File
@@ -4,6 +4,7 @@ Independent feature experiment, not a reproduction of an external model.
Only grouped training folds select a candidate; final test arrays are absent.
"""
import argparse
import hashlib
import json
from pathlib import Path
import time
@@ -88,7 +89,8 @@ class MotionBundle:
def __init__(self, directory):
root = Path(directory)
status = json.loads(_read(root/'status.json', 65536))
report = json.loads(_read(root/'metrics.json', 16*1024**2))
report_bytes = _read(root/'metrics.json', 16*1024**2)
report = json.loads(report_bytes)
if (not isinstance(status, dict) or not isinstance(report, dict)
or status.get('status') != 'complete' or status.get('promotionAuthorized') is not False
or report.get('status') != 'complete' or report.get('promotionAuthorized') is not False
@@ -99,8 +101,8 @@ class MotionBundle:
if self.candidate not in GRID:
raise ValueError('Unknown candidate')
data = _read(root/'model.safetensors', 1024**2)
import hashlib
if hashlib.sha256(data).hexdigest() != report.get('model_sha256'):
model_sha256 = hashlib.sha256(data).hexdigest()
if model_sha256 != report.get('model_sha256'):
raise ValueError('Model hash mismatch')
self.state = load(data)
width = WIDTHS[self.candidate['family']]
@@ -112,6 +114,13 @@ class MotionBundle:
for k, shape in expected.items()) or not (self.state['feature_scale'] > 0).all()):
raise ValueError('Invalid motion model state')
provenance = report.get('provenance', {})
self._verified_manifest_sha256 = (provenance.get('manifest_sha256')
if isinstance(provenance, dict) else None)
self._verified_model_sha256 = model_sha256
self._verified_model_bytes = len(data)
self._verified_receipt_sha256 = hashlib.sha256(report_bytes).hexdigest()
def predict(self, values):
return predict_features(self.state, motion_features(values, self.candidate['family']))
+4 -6
View File
@@ -89,10 +89,8 @@ def export(parts, provenance, baseline_directory, output, max_seconds=600):
raise ValueError('Invalid time budget')
_validate(parts)
baseline = MotionBundle(baseline_directory)
prior_bytes = _read(Path(baseline_directory)/'metrics.json',16*1024**2)
prior = json.loads(prior_bytes)
if (baseline.candidate != BASELINE or not provenance.get('manifest_sha256')
or prior.get('provenance',{}).get('manifest_sha256') != provenance['manifest_sha256']):
or baseline._verified_manifest_sha256 != provenance['manifest_sha256']):
raise ValueError('Baseline candidate or provenance mismatch')
root = Path(output)
root.mkdir(parents=True, exist_ok=False)
@@ -148,15 +146,15 @@ def export(parts, provenance, baseline_directory, output, max_seconds=600):
timings[name].append((time.perf_counter_ns()-before)/1e6)
latency = {k:{'p50_ms':float(np.percentile(v,50)),'p95_ms':float(np.percentile(v,95))} for k,v in timings.items()}
size = (root/'model.safetensors').stat().st_size
old_size = (Path(baseline_directory)/'model.safetensors').stat().st_size
old_size = baseline._verified_model_bytes
checks = {'model_below_10percent':size<.1*old_size,
'parity_all_admitted':True,
'p95_within_5percent':latency['candidate']['p95_ms']<=1.05*latency['incumbent']['p95_ms']}
metadata = {'status':'complete','promotionAuthorized':False,'spec':SPEC,
'model_sha256':digest(root/'model.safetensors'),
'random_map_sha256':{k:tensor_hash(v) for k,v in generated.items()},
'baseline_model_sha256':prior['model_sha256'],
'baseline_receipt_sha256':hashlib.sha256(prior_bytes).hexdigest(),
'baseline_model_sha256':baseline._verified_model_sha256,
'baseline_receipt_sha256':baseline._verified_receipt_sha256,
'provenance':{'manifest_sha256':provenance['manifest_sha256']}}
report = dict(metadata, provenance=provenance, evidence='SYNTHETIC' if provenance.get('evidence')=='SYNTHETIC' else 'MEASURED',
parity=parity,latency=latency,model_bytes=size,baseline_model_bytes=old_size,
@@ -1,9 +1,11 @@
"""Synthetic storage and numerical-parity contracts, not sensing evidence."""
import hashlib
import json
from pathlib import Path
import sys
import tempfile
import unittest
from unittest.mock import patch
import numpy as np
from safetensors.numpy import load, save_file
sys.path.insert(0,str(Path(__file__).resolve().parents[1]))
@@ -12,6 +14,7 @@ from csi_training.espfi_motion import MotionBundle
from csi_training.espfi_train import digest, write_json
from test_espfi_context import make_baseline
from test_espfi_generalize import fixture
import csi_training.espfi_motion_compact as compact_module
class CompactMotionTests(unittest.TestCase):
@@ -104,5 +107,43 @@ class CompactMotionTests(unittest.TestCase):
with self.assertRaisesRegex(ValueError,'Invalid compact'):
CompactMotionBundle(root/'compact')
def test_export_parent_lineage_uses_verified_baseline_generation(self):
parts,provenance=fixture()
with tempfile.TemporaryDirectory() as tmp:
root=Path(tmp)
baseline=root/'baseline'
make_baseline(parts,provenance,baseline)
expected_model=digest(baseline/'model.safetensors')
expected_receipt=digest(baseline/'metrics.json')
expected_model_bytes=(baseline/'model.safetensors').stat().st_size
forged=json.loads((baseline/'metrics.json').read_text())
forged['model_sha256']='f'*64
forged_bytes=json.dumps(forged,separators=(',',':'),sort_keys=True).encode()
forged_receipt=hashlib.sha256(forged_bytes).hexdigest()
real_read=compact_module._read
injected=[]
swapped=[]
def replace_second_receipt(path,limit):
if Path(path)==baseline/'metrics.json':
injected.append(Path(path))
return forged_bytes
result=real_read(path,limit)
if Path(path)==root/'compact'/'model.safetensors' and not swapped:
(baseline/'model.safetensors').write_bytes(b'x')
swapped.append(Path(path))
return result
with patch.object(compact_module,'_read',side_effect=replace_second_receipt):
report=export(parts,provenance,baseline,root/'compact')
metadata=json.loads((root/'compact'/'metadata.json').read_text())
self.assertEqual(injected,[])
self.assertEqual(len(swapped),1)
self.assertEqual(metadata['baseline_model_sha256'],expected_model)
self.assertEqual(metadata['baseline_receipt_sha256'],expected_receipt)
self.assertNotEqual(metadata['baseline_receipt_sha256'],forged_receipt)
self.assertEqual(report['baseline_model_bytes'],expected_model_bytes)
self.assertTrue(report['retention_checks']['model_below_10percent'])
if __name__=='__main__':
unittest.main()