Files
digital-drosophila/models/male-cns-lif/normal-conditioning-v1/append_ledger.py
T
2026-09-30 21:00:33 +08:00

443 lines
28 KiB
Python

"""Serial, immutable artifact accounting; not a process runner or science gate.
The long-lived parent hashes this cycle's declared inputs/outputs and the known
ledger tail. It does NOT rehash all old artifacts per cycle. Reopening, inspect
and final_verify perform full historical verification. Never infer a process's
terminal state from a PID, missing file, elapsed time, or a live handle.
"""
from __future__ import annotations
from contextlib import contextmanager
import hashlib
import json
import os
from pathlib import Path, PurePosixPath
import re
import shutil
import uuid
SCHEMA = 'normal-append-ledger-v1'
CONTROL = '.append-ledger'
REGISTRATION = 'protocol/preregistered.json'
SHA = re.compile('[0-9a-f]{64}')
ID = re.compile('[A-Za-z0-9][A-Za-z0-9_-]{0,127}')
def require(ok, message):
if not ok:
raise ValueError(message)
def raw_json(value):
return (json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=False, allow_nan=False)+'\n').encode('utf-8')
def read_json(path):
def unique(items):
result = {}
for key, value in items:
require(key not in result, 'Duplicate JSON key'); result[key] = value
return result
return json.loads(Path(path).read_bytes().decode('utf-8'), object_pairs_hook=unique,
parse_constant=lambda _: (_ for _ in ()).throw(ValueError('Nonfinite JSON')))
def digest(path):
h = hashlib.sha256()
with Path(path).open('rb') as stream:
for block in iter(lambda: stream.read(8 << 20), b''): h.update(block)
return h.hexdigest()
def relative_name(value):
require(type(value) is str and bool(value) and '\\' not in value and '\x00' not in value and
'\n' not in value and '\r' not in value, 'Invalid relative path')
path = PurePosixPath(value)
require(not path.is_absolute() and str(path) == value and
all(p not in ('.', '..', '') and ':' not in p for p in path.parts), 'Escaping/noncanonical path')
return value
def unlinked(path):
p = Path(path)
require(p.is_absolute() and '..' not in p.parts, 'Absolute nonescaping path required')
require(not any(q.is_symlink() or (hasattr(q, 'is_junction') and q.is_junction()) for q in (p, *p.parents)),
'Linked path forbidden')
return p
def identity(path):
p = unlinked(path)
require(p.is_file(), 'Missing regular file: '+str(p))
size = p.stat().st_size; sha = digest(p)
require(p.stat().st_size == size, 'File changed while hashing')
return dict(bytes=size, sha256=sha)
def validate_identity(value):
require(type(value) is dict and set(value) == {'bytes', 'sha256'} and type(value['bytes']) is int and
value['bytes'] >= 0 and type(value['sha256']) is str and SHA.fullmatch(value['sha256']), 'Invalid SHA/byte identity')
def _sync_directory(directory):
# Windows has no portable directory fsync. File bytes are fsynced there.
if os.name != 'nt':
descriptor = os.open(directory, os.O_RDONLY)
try: os.fsync(descriptor)
finally: os.close(descriptor)
def publish_exclusive(path, value):
"""Atomic no-replace publication on filesystems supporting hard links.
No unsafe rename/replace fallback. An interrupted temporary is preserved;
inspect/final audit rejects it. A failed destination collision also never
deletes or replaces the pre-existing destination.
"""
path = unlinked(path); require(path.parent.is_dir(), 'Missing publication parent')
require(not path.exists(), 'Immutable destination already exists; no retry')
raw = raw_json(value); temporary = path.parent / ('.publishing-'+uuid.uuid4().hex)
descriptor = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(descriptor, 'wb') as stream:
stream.write(raw); stream.flush(); os.fsync(stream.fileno())
os.link(temporary, path) # Exclusive destination, same bytes/inode; never overwrite.
_sync_directory(path.parent)
require(path.read_bytes() == raw, 'Published bytes changed')
temporary.unlink() # Only this function's exact, newly created temporary.
_sync_directory(path.parent)
return dict(bytes=len(raw), sha256=hashlib.sha256(raw).hexdigest())
class Ledger:
"""One long-lived instance per serial parent, never parallel scheduling.
Inventories map absolute or root-relative paths to {bytes, sha256}; initial
inventory is root-relative and must contain the exact registration file.
Call begin BEFORE spawn, then append only after the parent has observed
actual exit 0 and saved its independent process receipt. Existing starts
are never reissued. An interrupted append may be independently inspected,
but automatic resume/rerun is not provided.
"""
def __init__(self, root, registration_sha, initial_inventory, max_output_bytes, reserve_bytes,
shared_build_relative='extension-build'):
self.root = unlinked(Path(root)).resolve(strict=True)
require(self.root.is_dir(), 'Existing experiment root required')
require(type(registration_sha) is str and SHA.fullmatch(registration_sha), 'External registration SHA required')
require(type(max_output_bytes) is int and max_output_bytes > 0 and type(reserve_bytes) is int and reserve_bytes >= 0,
'Explicit nonnegative reserve and positive output cap required')
self.registration_sha = registration_sha; self.max_output_bytes = max_output_bytes; self.reserve_bytes = reserve_bytes
self.build_name = relative_name(shared_build_relative)
require(self.build_name != CONTROL and not self.build_name.startswith(CONTROL+'/'), 'Build overlaps ledger controls')
self.control = self.root / CONTROL; self.header_path = self.control / 'header.json'
self.starts = self.control / 'started'; self.entries = self.control / 'entries'
require(type(initial_inventory) is dict and initial_inventory, 'Explicit initial inventory required')
initial = {}
for name, expected in initial_inventory.items():
relative_name(name); self._payload_path(name); validate_identity(expected)
require(identity(self.root/name) == expected, 'Initial file identity differs: '+name)
initial[name] = dict(expected)
require(initial.get(REGISTRATION, {}).get('sha256') == registration_sha, 'Initial registration binding missing')
header = dict(schema=SCHEMA, root=str(self.root), registration_sha256=registration_sha,
initial_inventory=initial, max_output_bytes=max_output_bytes, reserve_bytes=reserve_bytes,
shared_mutable_build=self.build_name, initial_inventory_scope='caller supplied; entire tree checked only by final_verify',
scientific_gate_claimed=False)
if self.header_path.exists():
require(read_json(self.header_path) == header, 'Existing ledger authority/options differ')
else:
require(not self.control.exists(), 'Partial ledger initialization; no automatic retry')
self.control.mkdir(); self.starts.mkdir(); self.entries.mkdir()
publish_exclusive(self.header_path, header)
self.header_identity = identity(self.header_path); self.initial = initial
self._tracked = dict(initial); self._controls = {CONTROL+'/header.json': self.header_identity}
self._completed = []; self._completed_set = set(); self._pending = {}; self._tail = None
self._immutable_bytes = sum(v['bytes'] for v in initial.values())
self._control_bytes = self.header_identity['bytes']
self._write_failed = False
self._replay()
self._budget()
def _payload_path(self, value):
path = Path(value)
if not path.is_absolute(): path = self.root / relative_name(str(value))
path = unlinked(path)
require(path.is_relative_to(self.root), 'Output escapes experiment')
rel = path.relative_to(self.root).as_posix(); relative_name(rel)
require(rel != CONTROL and not rel.startswith(CONTROL+'/') and rel != self.build_name and
not rel.startswith(self.build_name+'/'), 'Immutable payload overlaps controls/shared build')
return path, rel
def _rows(self, mapping, *, output, verified=None):
require(type(mapping) is dict, 'Explicit inventory dictionary required')
result = []; used = set()
for text, expected in mapping.items():
validate_identity(expected); p = Path(text)
if output: p, rel = self._payload_path(text)
else:
if not p.is_absolute(): p = self.root / relative_name(str(text))
p = unlinked(p); rel = p.relative_to(self.root).as_posix() if p.is_relative_to(self.root) else None
p = p.resolve(strict=True)
rel = p.relative_to(self.root).as_posix() if p.is_relative_to(self.root) else None
require(str(p) not in used, 'Duplicate path aliases'); used.add(str(p))
if not output and rel in self._tracked:
require(expected == self._tracked[rel], 'Consumed immutable input differs from committed identity')
observed = self._identity_once(p, verified)
require(observed == expected, 'Actual file SHA/bytes differ: '+str(p))
result.append(dict(path=str(p), relative_path=rel, **expected))
return sorted(result, key=lambda row: row['path'])
@staticmethod
def _identity_once(path, verified):
"""One *invocation-local* actual SHA read per unique file, no stat cache."""
if verified is None: return identity(path)
key = str(path)
if key not in verified: verified[key] = identity(path)
return verified[key]
def _check_tail(self):
require(not self._write_failed, 'Previous publication failed; independent inspection required, no automatic retry')
require(identity(self.header_path) == self.header_identity, 'Ledger header changed')
if self._completed:
p = self.entries / f'{len(self._completed):016d}.json'
require(identity(p)['sha256'] == self._tail, 'Known ledger tail changed')
require(not (self.entries / f'{len(self._completed)+1:016d}.json').exists(), 'Unobserved appended entry; independently reopen/inspect')
@contextmanager
def _writer(self):
lock = self.control/'writer.lock'; token = uuid.uuid4().hex.encode()
unlinked(lock)
descriptor = os.open(lock, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
try:
with os.fdopen(descriptor, 'wb') as stream: stream.write(token); stream.flush(); os.fsync(stream.fileno())
self._check_tail()
yield
finally:
# Do not remove another actor's/stale lock or broadly delete a tree.
if lock.is_file() and lock.read_bytes() == token: lock.unlink()
def _build_inventory(self):
root = unlinked(self.root/self.build_name); result = {}
if root.exists():
require(root.is_dir(), 'Shared build must be a directory')
for p in sorted(root.rglob('*')):
unlinked(p)
if p.is_file(): result[p.relative_to(self.root).as_posix()] = identity(p)
else: require(p.is_dir(), 'Nonregular shared build file')
return result
def _budget(self, *, outputs=(), extra_control=0):
# O(new outputs), not O(all previous payload rows), for the serial path.
added = {row['relative_path']:row['bytes'] for row in outputs}
provisional = {}
for attempt in self._pending.values():
job = attempt['job']; rel = job['relative_path']
if rel is not None and rel not in self._tracked and rel not in added: provisional[rel] = job['bytes']
build = self._build_inventory()
immutable = self._immutable_bytes+sum(added.values())
control = self._control_bytes+extra_control
build_bytes = sum(row['bytes'] for row in build.values())
total = immutable+control+build_bytes+sum(provisional.values())
require(total <= self.max_output_bytes, 'Tracked outputs/control/shared build exceed cap')
require(shutil.disk_usage(self.root).free >= self.reserve_bytes+extra_control, 'Free-space reserve would be crossed')
return dict(immutable_payload_bytes=immutable, ledger_control_bytes=control, shared_mutable_build_bytes=build_bytes,
provisional_job_bytes=sum(provisional.values()), total_accounted_bytes=total,
shared_mutable_build_inventory=build, unlisted_files_included=False,
scope='tracked immutable payload + ledger controls + pending job files + current shared mutable build; unlisted files checked at final audit')
def begin(self, entry_id, job_file, metadata=None):
"""Persist BEFORE spawning; success does not authorize automatic retry."""
require(type(entry_id) is str and ID.fullmatch(entry_id), 'Unsafe entry ID')
require(metadata is None or type(metadata) is dict, 'Begin metadata must be a JSON dictionary')
with self._writer():
require(not self._pending, 'Serial ledger has an uncommitted start; do not rerun it')
require(entry_id not in self._completed_set and not (self.starts/(entry_id+'.json')).exists(), 'Entry already started/committed; no retry')
path = Path(job_file)
if not path.is_absolute(): path = self.root / relative_name(str(job_file))
rows = self._rows({str(path):identity(path)}, output=False)
value = dict(schema=SCHEMA+'-start', entry_id=entry_id, registration_sha256=self.registration_sha,
next_sequence=len(self._completed)+1, prev_entry_sha256=self._tail, job=rows[0], metadata=metadata or {},
terminal_state='unknown', retry_authorized=False)
raw_json(value); self._pending[entry_id] = value
try:
self._budget(extra_control=len(raw_json(value)))
info = publish_exclusive(self.starts/(entry_id+'.json'),value)
except BaseException:
self._write_failed = True
self._pending.pop(entry_id, None); raise
self._controls[f'{CONTROL}/started/{entry_id}.json'] = info
self._control_bytes += info['bytes']
return dict(entry_id=entry_id,start_sha256=info['sha256'],sequence=value['next_sequence'],terminal_state='unknown',retry_authorized=False)
def append(self, entry_id, inputs, outputs, metadata):
"""Commit exactly one observed-successful serial parent job.
metadata requires job_file/process_receipt_file/scope/observed_returncode.
The independent parent process JSON must declare entry_id, registration
SHA, job SHA, complete=true, exit_code integer 0, timed_out=false,
exit_observed_by_parent=true. These are authenticated recorded facts,
not a new OS observation by this ledger.
"""
require(type(metadata) is dict and all(k in metadata for k in
('job_file','process_receipt_file','scope','observed_returncode')), 'Complete parent metadata required')
require(type(metadata['scope']) is str and bool(metadata['scope'].strip()) and
type(metadata['observed_returncode']) is int and metadata['observed_returncode'] == 0,
'Live/failed process cannot be committed as successful')
raw_json(metadata)
with self._writer():
require(entry_id in self._pending and entry_id not in self._completed_set, 'No unique uncommitted start; no retry')
start = self._pending[entry_id]; startfile = self.starts/(entry_id+'.json')
require(identity(startfile) == self._controls[f'{CONTROL}/started/{entry_id}.json'] and read_json(startfile) == start,
'Start authority changed')
incoming = self._rows(inputs, output=False); outgoing = self._rows(outputs, output=True)
require(outgoing, 'Empty completed output inventory')
require(all(row['relative_path'] not in self._tracked for row in outgoing), 'Output overwrites previously tracked file')
self._receipt(entry_id,start,incoming,outgoing,metadata)
cumulative = self._immutable_bytes+sum(row['bytes'] for row in outgoing)
budget = self._budget(outputs=outgoing)
value = dict(schema=SCHEMA+'-entry', sequence=len(self._completed)+1, entry_id=entry_id,
registration_sha256=self.registration_sha, prev_entry_sha256=self._tail,
start_sha256=identity(startfile)['sha256'], consumed_inputs=incoming, new_outputs=outgoing,
metadata=metadata, cumulative_immutable_bytes=cumulative, shared_mutable_build=budget['shared_mutable_build_inventory'],
hash_scope='actual declared files and current head; historical payload is rehashed at inspect/reopen/final_verify',
scientific_gate_claimed=False, OS_exit_independently_observed_here=False)
budget = self._budget(outputs=outgoing,extra_control=len(raw_json(value)))
require(budget['shared_mutable_build_inventory'] == value['shared_mutable_build'], 'Shared build changed during append accounting')
try: info = publish_exclusive(self.entries/f'{value["sequence"]:016d}.json',value)
except BaseException:
self._write_failed = True; raise
self._controls[f'{CONTROL}/entries/{value["sequence"]:016d}.json'] = info
self._control_bytes += info['bytes']; self._immutable_bytes = cumulative
self._tracked.update({r['relative_path']:{k:r[k] for k in ('bytes','sha256')} for r in outgoing})
self._completed.append(entry_id); self._completed_set.add(entry_id); self._pending.pop(entry_id); self._tail = info['sha256']
return dict(sequence=value['sequence'],entry_id=entry_id,entry_sha256=self._tail,
cumulative_immutable_bytes=cumulative,budget=budget,scientific_gate_claimed=False)
def _receipt(self,entry_id,start,inputs,outputs,metadata):
def path(value):
p=Path(value)
return str(unlinked(p if p.is_absolute() else self.root/relative_name(str(value))))
jobpath=path(metadata['job_file']);receiptpath=path(metadata['process_receipt_file'])
supplied={r['path']:r for r in inputs+outputs}
require(jobpath == start['job']['path'] and jobpath in supplied and
all(supplied[jobpath][k] == start['job'][k] for k in ('bytes','sha256')), 'Job not bound to original start')
require(type(metadata.get('observed_returncode')) is int and metadata['observed_returncode'] == 0 and
type(metadata.get('scope')) is str and bool(metadata['scope'].strip()), 'Invalid parent observation/scope')
require(receiptpath in {r['path'] for r in outputs}, 'Parent process receipt must be a new output')
receipt=read_json(receiptpath)
require(receipt.get('entry_id') == entry_id and receipt.get('registration_sha256') == self.registration_sha and
receipt.get('job_sha256') == start['job']['sha256'] and receipt.get('complete') is True and
type(receipt.get('exit_code')) is int and receipt['exit_code'] == 0 and receipt.get('timed_out') is False and
receipt.get('exit_observed_by_parent') is True, 'Missing bound observed-successful parent process receipt')
def _replay(self, verified=None):
verified = {} if verified is None else verified
header_observed = identity(self.header_path)
require(header_observed == self.header_identity, 'Ledger header changed')
verified[str(self.header_path)] = header_observed
if self._completed:
require(identity(self.entries/f'{len(self._completed):016d}.json')['sha256'] == self._tail,
'Previously observed ledger head changed')
require(not (self.control/'writer.lock').exists(), 'Writer/stale lock present; state unknown, never clear automatically')
tracked=dict(self.initial);controls={CONTROL+'/header.json':self.header_identity};completed=[];completed_set=set();tail=None
cumulative=sum(v['bytes'] for v in tracked.values())
starts={}
require(self.starts.is_dir() and self.entries.is_dir(), 'Missing ledger directories')
for p in sorted(self.starts.iterdir()):
unlinked(p);require(p.is_file() and p.suffix=='.json' and ID.fullmatch(p.stem), 'Unknown/partial start artifact')
row=read_json(p);require(row.get('schema')==SCHEMA+'-start' and row.get('entry_id')==p.stem and
row.get('registration_sha256')==self.registration_sha and row.get('retry_authorized') is False,
'Invalid start schema/authority')
require(row['job']==self._rows({row['job']['path']:{k:row['job'][k] for k in ('bytes','sha256')}},output=False,verified=verified)[0], 'Start job bytes changed')
starts[p.stem]=row;controls[p.relative_to(self.root).as_posix()]=self._identity_once(p,verified)
for index,p in enumerate(sorted(self.entries.iterdir()),1):
unlinked(p);require(p.is_file() and p.name==f'{index:016d}.json','Missing/out-of-order/temporary ledger entry')
row=read_json(p);entry_id=row.get('entry_id');require(entry_id in starts and entry_id not in completed_set,'Missing/duplicate start binding')
start=starts[entry_id]
require(row.get('schema')==SCHEMA+'-entry' and type(row.get('sequence')) is int and row['sequence']==index and
row.get('registration_sha256')==self.registration_sha and row.get('prev_entry_sha256')==tail and
start['next_sequence']==index and start['prev_entry_sha256']==tail and
row['start_sha256']==controls[f'{CONTROL}/started/{entry_id}.json']['sha256'] and
row.get('scientific_gate_claimed') is False,'Entry chain/start identity differs')
for field,output in (('consumed_inputs',False),('new_outputs',True)):
items=row[field];require(type(items) is list and len({r['path'] for r in items})==len(items),'Invalid stored file rows')
observed=self._rows({r['path']:{k:r[k] for k in ('bytes','sha256')} for r in items},output=output,verified=verified)
require(items==observed,'Stored absolute/relative/hash identity differs')
require(row['new_outputs'] and all(r['relative_path'] not in tracked for r in row['new_outputs']), 'Immutable output repeated')
self._receipt(entry_id,start,row['consumed_inputs'],row['new_outputs'],row['metadata'])
tracked.update({r['relative_path']:{k:r[k] for k in ('bytes','sha256')} for r in row['new_outputs']})
cumulative+=sum(r['bytes'] for r in row['new_outputs'])
require(type(row['cumulative_immutable_bytes']) is int and row['cumulative_immutable_bytes']==cumulative,'Cumulative byte accounting differs')
completed.append(entry_id);completed_set.add(entry_id);info=self._identity_once(p,verified);controls[p.relative_to(self.root).as_posix()]=info;tail=info['sha256']
pending={k:v for k,v in starts.items() if k not in completed_set}
require(len(pending)<=1 and all(v['next_sequence']==len(completed)+1 and v['prev_entry_sha256']==tail for v in pending.values()),
'Uncommitted start does not follow actual head')
for name,info in tracked.items():require(self._identity_once(self.root/name,verified)==info,'Historical payload changed: '+name)
allowed=set(controls)
for p in self.control.rglob('*'):
unlinked(p)
require(p.is_dir() or (p.is_file() and p.relative_to(self.root).as_posix() in allowed),'Unlisted/partial ledger control artifact')
# Fresh head reads bracket this audit. This is not an atomic FS snapshot.
require(identity(self.header_path)==self.header_identity,'Ledger header changed during audit')
require(not (self.control/'writer.lock').exists() and not (self.entries/f'{len(completed)+1:016d}.json').exists(),
'Concurrent writer/append detected; audit not terminal')
if completed:require(identity(self.entries/f'{len(completed):016d}.json')['sha256']==tail,'Ledger head changed during audit')
self._tracked=tracked;self._controls=controls;self._completed=completed;self._completed_set=completed_set;self._pending=pending;self._tail=tail
self._immutable_bytes=cumulative
self._control_bytes=sum(v['bytes'] for v in controls.values())
def inspect(self):
"""Full historical read verification; no restart or retry authorization."""
self._replay()
return dict(schema=SCHEMA+'-inspection',registration_sha256=self.registration_sha,entries=len(self._completed),
entry_ids=list(self._completed),head_sha256=self._tail,uncommitted_entry_ids=sorted(self._pending),
uncommitted_state='STARTED-UNCOMMITTED-STATE-UNKNOWN' if self._pending else None,
retry_authorized=False,all_tracked_history_rehashed=True,entire_experiment_tree_checked=False,
SHA_scope='each unique payload path read during this invocation; no cross-invocation cache; not an atomic snapshot',
budget=self._budget(),scientific_gate_claimed=False)
def final_verify(self,expected_entry_ids):
"""Full tree at this instant, before caller writes any future final report.
expected IDs must be derived by caller from the externally pinned
registration. Shared build is mutable and separately hashed/accounted,
never silently accepted as an immutable payload.
"""
require(type(expected_entry_ids) is list and all(type(x) is str and ID.fullmatch(x) for x in expected_entry_ids) and
len(set(expected_entry_ids))==len(expected_entry_ids),'Exact registered expected entry order required')
errors=[];verified={}
try:self._replay(verified)
except (ValueError,OSError,KeyError,TypeError) as exc:errors.append(type(exc).__name__+': '+str(exc))
expected={**self._tracked,**self._controls};actual={};links=[]
for p in sorted(self.root.rglob('*')):
rel=p.relative_to(self.root).as_posix()
try:
unlinked(p)
if p.is_file():actual[rel]=self._identity_once(p,verified)
else:require(p.is_dir(),'Nonregular artifact')
except (ValueError,OSError) as exc:links.append(rel);errors.append(str(exc))
build={k:v for k,v in actual.items() if k.startswith(self.build_name+'/')}
immutable={k:v for k,v in actual.items() if k not in build}
extra=sorted(set(immutable)-set(expected));missing=sorted(set(expected)-set(immutable))
changed=sorted(k for k in set(expected)&set(immutable) if expected[k]!=immutable[k])
exact_order=self._completed==expected_entry_ids
actual_bytes=sum(v['bytes'] for v in actual.values());within_cap=actual_bytes<=self.max_output_bytes
free_reserve=shutil.disk_usage(self.root).free>=self.reserve_bytes
# Bracket the *entire* tree walk as well as replay. These fresh small
# authority reads deliberately bypass the per-invocation payload cache.
# They detect changed/appended heads, not an atomic filesystem snapshot.
try:
self._check_tail()
require(not (self.control/'writer.lock').exists(), 'Concurrent writer detected at final audit end')
except (ValueError,OSError) as exc:errors.append(type(exc).__name__+': '+str(exc))
passed=not(errors or extra or missing or changed or self._pending) and exact_order and within_cap and free_reserve
return dict(schema=SCHEMA+'-final-audit',pass_all=passed,registration_sha256=self.registration_sha,
entry_ids=list(self._completed),expected_entry_ids=expected_entry_ids,expected_order_exact=exact_order,
head_sha256=self._tail,extra_files=extra,missing_files=missing,changed_files=changed,unsafe_files=links,errors=errors,
uncommitted_entry_ids=sorted(self._pending),uncommitted_state_unknown=bool(self._pending),retry_authorized=False,
actual_total_bytes=actual_bytes,immutable_and_ledger_bytes=actual_bytes-sum(v['bytes'] for v in build.values()),
shared_mutable_build_bytes=sum(v['bytes'] for v in build.values()),shared_mutable_build_inventory=build,
output_cap_respected=within_cap,free_reserve_respected=free_reserve,
all_current_files_rehashed=True,checked_before_future_final_report=True,
SHA_scope='each unique path read during this invocation; fresh header/head checks bracket full audit; no cross-invocation cache; not an atomic snapshot',
expected_inventory_authority='caller derives IDs from pinned registration; ledger does not interpret scientific plan',
scientific_gate_claimed=False)