oracle7-chameleon / scripts /build_input_discovery.py
psiloceyeben's picture
Upload folder using huggingface_hub
09aeaeb verified
Raw History Blame Contribute Delete
6.67 kB
"""Bounded staged input discovery from pinned inventory and inert build declarations."""
import json
import posixpath
from build_module_overlay import parse_module_source
from chameleon_core.adaptation_contracts import Intake, Residual
from chameleon_core.contracts import digest
from chameleon_core.entry_capture import capture_entry
from chameleon_core.module_resolution import resolve_relative_import
from chameleon_core.repository_capture import fetch_bytes, tree_files, verify_package
from plan_saved_build import plan_saved_build
def capture_build_inputs(source, entry, importer, *, additional_paths=(), fetch=fetch_bytes):
"""Runs in isolated capture worker; cache frozen GETs and cap the entire chain."""
cache, trees, plans = {}, {}, []
wire = reads = 0
def bounded_fetch(url, limit):
nonlocal wire, reads
if url not in cache:
if reads >= 64:
raise Residual('BUILD_DISCOVERY_REQUEST_BUDGET')
reads += 1
body = fetch(url, limit)
wire += len(body)
if len(body) > limit or wire > 6*1024*1024:
raise Residual('BUILD_DISCOVERY_WIRE_BUDGET')
cache[url] = body
if '?recursive=1' in url:
tree = json.loads(body)
trees[tree['sha']] = tree
if len(cache[url]) > limit:
raise Residual('BUILD_DISCOVERY_WIRE_BUDGET')
return cache[url]
paths = sorted(set(additional_paths) | {importer})
previous = None
for _ in range(8):
package = capture_entry(source, entry, bounded_fetch, additional_paths=paths)
repo = package['repository']
if previous and (any(repo[k] != previous[k] for k in ('source', 'commit_sha', 'tree_sha', 'entry'))
or any(repo['files'].get(p) != r for p, r in previous['files'].items())):
raise Residual('BUILD_DISCOVERY_RECAPTURE_MISMATCH')
tree = trees.get(repo['tree_sha'])
if tree is None:
raise Residual('BUILD_COMPLETE_INVENTORY_REQUIRED')
try:
plan = discover_build_inputs(package, importer, tree)
except ValueError as exc:
raise Residual(str(exc)) from exc
plans.append(plan)
if plan['status'] == 'READY':
repo['projection'].update(additional_local_paths=list(additional_paths),
build_importer=importer, build_discovered_paths=paths, build_discovery=plans)
repo['acquisition'].update(external_reads=reads, wire_bytes=wire)
package['digest'] = digest(repo)
verify_package(package)
return package
new_paths = sorted(set(paths) | set(plan['missing_paths']))
if new_paths == paths:
raise Residual('BUILD_DISCOVERY_STALLED')
paths, previous = new_paths, repo
raise Residual('BUILD_DISCOVERY_PASS_BUDGET')
def discover_build_inputs(package, importer, tree):
files = verify_package(package)
repo = package['repository']
if tree.get('sha') != repo['tree_sha']:
raise ValueError('BUILD_TREE_BINDING_MISMATCH')
inventory = tree_files(tree, metadata_only=True)
for name, record in repo['files'].items():
if (name not in inventory or inventory[name]['sha'] != record['git_blob_sha']
or inventory[name]['size'] != record['bytes']):
raise ValueError('BUILD_HELD_TREE_MISMATCH')
if importer not in files or not importer.endswith(('.js', '.mjs')):
raise ValueError('BUILD_CAPTURED_IMPORTER_REQUIRED')
metadata = {'package.json', 'rollup.config.js'}
if not metadata <= inventory.keys():
raise ValueError('BUILD_DECLARATION_FILES_ABSENT')
missing = metadata - files.keys()
visited, edges = set(), []
if not missing:
plan = plan_saved_build(package)['plan']
aliases = {}
for row in plan['mappings']:
if row['format'] != 'es':
continue
destination = row.get('destination', row['output'])
if destination in aliases or destination in inventory:
raise ValueError('BUILD_ALIAS_AMBIGUOUS')
aliases[destination] = row['input']
if not aliases:
raise ValueError('BUILD_ES_MAPPING_REQUIRED')
pending = [importer]
while pending:
current = pending.pop()
if current in visited:
continue
visited.add(current)
if len(visited) > 64:
raise ValueError('BUILD_GRAPH_BUDGET')
if current not in inventory:
raise ValueError('BUILD_DECLARED_INPUT_ABSENT')
if current not in files:
missing.add(current)
continue
syntax = parse_module_source(files[current])
if syntax['dynamic_imports']:
raise ValueError('BUILD_DYNAMIC_IMPORT_UNSUPPORTED')
for ref in syntax['references']:
# Resolver enforces relative-only paths and ambiguity refusal.
virtual = {**inventory, **{p: {'sha': '0'*40, 'size': 0} for p in aliases if p not in inventory}}
resolution = resolve_relative_import(current, ref['specifier'], virtual)
if resolution['status'] != 'RESOLVED':
raise ValueError('BUILD_MODULE_' + resolution['status'])
destination = resolution['matches'][0]['path']
source = destination if destination in inventory else aliases[destination]
if not posixpath.splitext(source)[1] in ('.js', '.mjs'):
raise ValueError('BUILD_SOURCE_TYPE_UNSUPPORTED')
edges.append({'importer': current, 'specifier': ref['specifier'],
'destination': destination, 'source': source})
pending.append(source)
paths = sorted(set(repo.get('projection', {}).get('additional_local_paths', [])) | missing)
if len(paths) > 16:
raise ValueError('BUILD_CAPTURE_PATH_BUDGET')
intake = Intake(source=repo['source']+'/tree/'+repo['commit_sha'], source_type='repository',
repository_scope='entry', repository_entry=repo['entry'],
repository_assets=paths, build_counterpart=True)
return {'version': 'build-input-discovery-v1', 'source_digest': package['digest'],
'inventory_digest': digest(tree), 'status': 'CAPTURE_REQUIRED' if missing else 'READY',
'missing_paths': sorted(missing), 'visited': sorted(visited), 'edges': edges,
'intake': intake.model_dump(mode='json'), 'verified_application': False}