Add 17 reviewed original HD terrain and ship pictures
This commit is contained in:
1 parent
2d95e145a5
commit
ff4ebf35eb
214 files changed
+1427108
-72
No files matched your search
@@ -0,0 +1,138 @@
|
||||
"""Narrow reviewed-math dispatcher: full genuine RGB with Original Scale4 support.
|
||||
|
||||
No generation, engine, acceptance or canonical writes. Dependencies and artwork
|
||||
are read once as authenticated bytes before geometry; outputs use a fresh folder.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import argparse,builtins,hashlib,io,json,os,re,shutil,stat,sys,types
|
||||
from pathlib import Path
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
PINS={'hd_frame_policy':'66184a4758027dadbadb5e20fe90b2add2b9fc218b7810304b1a1ea2de74f58e','hd_dshp20_cleanup':'c6123e9591f0a169846677019ddcb944bf9c2b4c9184a7d8ab02a08546de409b','hd_other_functional_cleanup':'f8078284e300947aec4d2c9e70cbc7198fa3cb5d34de6b36c07cacc5f3820a84'}
|
||||
SPEC={'102fc':([40,32],'f0357eded395029e0740c49d408a3475a9831cadcfd9dd626633bdff03e574fb','d65014c2023a3004067b3fdb8708d219de92355bd4663358b5b9984aca754791',[57,28,1377,1084],[[27,12],[28,12]]),'2009a':([48,32],'8408802c346c81ecb2062d8f4b0ef580a646a7547cb963f1b8e76d8d934305c2','50190a5588a581300232fd0bb11b98955fce30c50e35ea7e59be95d66904ad60',[132,124,894,632],[[x,y]for x in range(22,27)for y in range(13,16)]),'2009b':([48,32],'6888dd1bd06dd176b5450b431ff422220bf32541f2a2fed097ee3604c36fe725','50190a5588a581300232fd0bb11b98955fce30c50e35ea7e59be95d66904ad60',[132,891,894,1399],[[x,y]for x in range(22,27)for y in range(13,16)])}
|
||||
PALETTE='1cf6adb926d1dee1888b3e3d33b51a7049b3e5eb5f90a3067ef71c8970547204'
|
||||
METHOD='derived-existing-generated-RGB-SHIP05-singleton-SHIP03-rotor2-SourceScale4-v1'
|
||||
def sha(b):return hashlib.sha256(b).hexdigest()
|
||||
def read(binding,base=None,limit=32*1024*1024):
|
||||
if type(binding)is not dict or set(binding)!={'path','sha256'} or re.fullmatch('[0-9a-f]{64}',binding['sha256'])is None:raise ValueError('exact binding required')
|
||||
p=Path(binding['path'])
|
||||
if p.is_absolute()or '..'in p.parts or '\\'in str(p)or str(p)!=binding['path']or not p.parts:raise ValueError('canonical project-relative input required')
|
||||
base=Path.cwd()if base is None else Path(base)
|
||||
directory=os.open(base,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW)
|
||||
try:
|
||||
for part in p.parts[:-1]:
|
||||
nxt=os.open(part,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=directory);os.close(directory);directory=nxt
|
||||
fd=os.open(p.name,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK,dir_fd=directory)
|
||||
try:
|
||||
before=os.fstat(fd)
|
||||
if not stat.S_ISREG(before.st_mode) or before.st_size>limit:raise ValueError('bounded regular input required')
|
||||
chunks=[];count=0
|
||||
while True:
|
||||
b=os.read(fd,min(65536,limit+1-count))
|
||||
if not b:break
|
||||
chunks.append(b);count+=len(b)
|
||||
if count>limit:raise ValueError('input too large')
|
||||
payload=b''.join(chunks);after=os.fstat(fd)
|
||||
if (before.st_dev,before.st_ino,before.st_size,before.st_mtime_ns)!=(after.st_dev,after.st_ino,after.st_size,after.st_mtime_ns):raise ValueError('input changed')
|
||||
finally:os.close(fd)
|
||||
finally:os.close(directory)
|
||||
if sha(payload)!=binding['sha256']:raise ValueError('input hash mismatch')
|
||||
return payload
|
||||
|
||||
def modules(payloads):
|
||||
if set(payloads)!=set(PINS)or any(sha(payloads[k])!=v for k,v in PINS.items()):raise ValueError('dependency bytes differ')
|
||||
loaded={};real_import=builtins.__import__;proxy=types.SimpleNamespace(path=list(sys.path),version=sys.version)
|
||||
def importer(name,globals=None,locals=None,fromlist=(),level=0):
|
||||
if name in loaded:return loaded[name]
|
||||
if name=='sys':return proxy
|
||||
return real_import(name,globals,locals,fromlist,level)
|
||||
for name in PINS:
|
||||
m=types.ModuleType(name);m.__file__='/authenticated-buffered/'+name+'.py';m.__dict__['__builtins__']={**vars(builtins),'__import__':importer}
|
||||
exec(compile(payloads[name],m.__file__,'exec'),m.__dict__);loaded[name]=m
|
||||
return loaded
|
||||
|
||||
def validate_recipe(recipe):
|
||||
if type(recipe)is not dict or set(recipe)!={'format_version','family','palette','frames','dependencies'}or type(recipe['format_version'])is not int or recipe['format_version']!=1:raise ValueError('exact recipe fields/version required')
|
||||
ids={'SHIP05-singleton':['102fc'],'SHIP03-rotor2':['2009a','2009b']}.get(recipe['family'])
|
||||
if ids is None or type(recipe['frames'])is not list or [f.get('asset')for f in recipe['frames']]!=ids:raise ValueError('complete family required')
|
||||
if recipe['palette'].get('sha256')!=PALETTE:raise ValueError('Original palette differs')
|
||||
if set(recipe['dependencies'])!=set(PINS)or any(recipe['dependencies'][k].get('sha256')!=v for k,v in PINS.items()):raise ValueError('dependency binding differs')
|
||||
for f in recipe['frames']:
|
||||
if set(f)!={'asset','source','raw_png','viewport','origin','functional_original_cells'}:raise ValueError('exact frame fields required')
|
||||
canvas,source,raw,viewport,cells=SPEC[f['asset']]
|
||||
if any(type(x)is not int for x in f['origin']+f['viewport'])or any(type(x)is not int for xy in f['functional_original_cells']for x in xy):raise ValueError('literal integer geometry/functional cells required')
|
||||
if f['source'].get('sha256')!=source or f['raw_png'].get('sha256')!=raw or f['viewport']!=viewport or f['origin']!=[0,0] or f['functional_original_cells']!=cells:raise ValueError('Source/raw/geometry/functional declaration differs')
|
||||
return ids
|
||||
|
||||
def derive(recipe,base=None,shared_cache=None):
|
||||
ids=validate_recipe(recipe)
|
||||
base=Path.cwd()if base is None else Path(base)
|
||||
shared_cache={}if shared_cache is None else shared_cache
|
||||
def load(binding,limit=32*1024*1024):
|
||||
key=(binding['path'],binding['sha256'])
|
||||
if key not in shared_cache:shared_cache[key]=read(binding,base,limit)
|
||||
return shared_cache[key]
|
||||
dep={k:load(v,1024*1024)for k,v in recipe['dependencies'].items()};mods=modules(dep)
|
||||
decoder,g,functional=(mods[n]for n in PINS)
|
||||
# The pinned geometry dependency records its decoder's source identity at the
|
||||
# end. Supply that receipt from the already authenticated buffer as well.
|
||||
decoder.__file__=recipe['dependencies']['hd_frame_policy']['path']
|
||||
class BufferedDecoderReceiptPath:
|
||||
def __init__(self,value):
|
||||
if value!=decoder.__file__:raise ValueError('unbuffered dependency receipt path refused')
|
||||
def resolve(self):return self
|
||||
def read_bytes(self):return dep['hd_frame_policy']
|
||||
def __str__(self):return decoder.__file__
|
||||
g.Path=BufferedDecoderReceiptPath
|
||||
bindings=[recipe['palette']]+[f[k]for f in recipe['frames']for k in ('source','raw_png')]
|
||||
cache={}
|
||||
for b in bindings:
|
||||
key=(b['path'],b['sha256'])
|
||||
if key not in cache:cache[key]=load(b)
|
||||
def checked(binding,base):
|
||||
key=(binding['path'],binding['sha256'])
|
||||
if key not in cache:raise ValueError('unbuffered input refused')
|
||||
return Path(binding['path']),cache[key]
|
||||
g.checked=checked
|
||||
geom=dict(format_version=1,label=METHOD,palette=recipe['palette'],output_scale=4,max_fill_distance_pixels=12,shared_backing_anchor=0,frames=[{k:f[k]for k in ('asset','source','raw_png','viewport','origin')}|{'sampling_offset_native':[0,0]}for f in recipe['frames']])
|
||||
arrays,geometry=g.render_family(geom,Path('/'))
|
||||
pb=cache[(recipe['palette']['path'],PALETTE)];p6=np.frombuffer(pb,np.uint8).reshape(256,3).astype(np.uint16);palette=((p6<<2)|(p6>>4)).astype(np.uint8)
|
||||
outputs=[];records=[]
|
||||
for f,rgba in zip(recipe['frames'],arrays):
|
||||
w,h,cells=decoder._indices(cache[(f['source']['path'],f['source']['sha256'])]);s=np.asarray(cells,np.uint16).reshape(h,w)
|
||||
if [w,h]!=SPEC[f['asset']][0]:raise ValueError('Source canvas differs')
|
||||
out,retention=functional.retain_functional_original(rgba,s,palette,f['functional_original_cells'])
|
||||
outputs.append(out);records.append(dict(asset=f['asset'],functional_original=retention))
|
||||
return outputs,dict(method=METHOD,geometry=geometry,functional=records,limits=['Derived material, never untouched generation.','Functional Original2/15 cells are not generated HD.','Whole native material and context acceptance remain separate.'])
|
||||
|
||||
def derive_bundle(bundle,base):
|
||||
if type(bundle)is not dict or set(bundle)!={'format_version','families'}or type(bundle['format_version'])is not int or bundle['format_version']!=1:raise ValueError('exact bundle fields/version required')
|
||||
if type(bundle['families'])is not list or len(bundle['families'])!=2 or [f.get('family')for f in bundle['families']]!=['SHIP05-singleton','SHIP03-rotor2']:raise ValueError('exact complete singleton plus rotor2 bundle required')
|
||||
for family in bundle['families']:validate_recipe(family)
|
||||
cache={};outputs={};reports=[]
|
||||
for family in bundle['families']:
|
||||
arrays,report=derive(family,base,cache)
|
||||
for f,a in zip(family['frames'],arrays):outputs[f['asset']]=a
|
||||
reports.append(report)
|
||||
return outputs,dict(method=METHOD,family_reports=reports,unique_buffered_inputs=len(cache),scope='One portable bundled execution of unchanged two complete-family pixel computations; no engine or artistic authority.')
|
||||
|
||||
def main(recipe_path,output,project_root=None):
|
||||
base=Path(__file__).resolve().parent.parent if project_root is None else Path(project_root).resolve(strict=True)
|
||||
recipe_path=Path(recipe_path);recipe_path=recipe_path if recipe_path.is_absolute()else base/recipe_path
|
||||
if not recipe_path.resolve().is_relative_to(base):raise ValueError('recipe must be contained in supplied project root')
|
||||
output=Path(output);output=output if output.is_absolute()else base/output
|
||||
if output.exists()or output.is_symlink():raise ValueError('fresh output required')
|
||||
if not output.parent.is_dir()or output.parent.resolve()!=output.parent.absolute():raise ValueError('existing non-symlink output parent required')
|
||||
if shutil.disk_usage(output.parent).free<2_208_000_000:raise ValueError('2.2-billion-byte free floor plus bounded output reserve required')
|
||||
rb=recipe_path.read_bytes();bundle=json.loads(rb);arrays,report=derive_bundle(bundle,base)
|
||||
encoded={}
|
||||
for asset,a in arrays.items():
|
||||
b=io.BytesIO();Image.fromarray(a).save(b,format='PNG',compress_level=9);encoded[asset]=b.getvalue()
|
||||
output.mkdir()
|
||||
for asset,b in encoded.items():(output/(asset+'-derived.png')).write_bytes(b)
|
||||
frames=[f for family in bundle['families']for f in family['frames']]
|
||||
report['execution']=dict(status='success',method=METHOD,tool_sha256=sha(Path(__file__).read_bytes()),recipe_sha256=sha(rb),source_sha256={f['asset']:f['source']['sha256']for f in frames},parent_raw_sha256=sorted(set(f['raw_png']['sha256']for f in frames)),output_sha256={a:sha(b)for a,b in encoded.items()})
|
||||
(output/'derived-provenance.json').write_text(json.dumps(report,indent=2)+'\n');(output/'normalized-execution.json').write_text(json.dumps(report['execution'],indent=2)+'\n')
|
||||
print(json.dumps(report['execution']))
|
||||
if __name__=='__main__':
|
||||
p=argparse.ArgumentParser();p.add_argument('recipe');p.add_argument('output');p.add_argument('--project-root');a=p.parse_args();main(a.recipe,a.output,a.project_root)
|
||||
@@ -0,0 +1,317 @@
|
||||
"""Reproduce complete PLATOON1 art from genuine per-body/material RGB and Source support.
|
||||
|
||||
A narrowly fixed six-frame renderer, never artistic approval. Decoder, Source,
|
||||
palette and PNG bytes are verified once and consumed in memory. Source supplies
|
||||
alpha and six declared face cells; other painted RGB comes unchanged from the
|
||||
same generated phase/body/material. No gains, texture synthesis or cascading fills.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import argparse
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path, PurePosixPath
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image, __version__ as PILLOW_VERSION
|
||||
|
||||
METHOD = 'derived-PLATOON1-complete6-generated-component-material-SourceScale4-face6-v1'
|
||||
DECODER_SHA = '66184a4758027dadbadb5e20fe90b2add2b9fc218b7810304b1a1ea2de74f58e'
|
||||
ASSETS = [f'{0x200ec+i:05x}' for i in range(6)]
|
||||
WINDOWS = [('top', [0, 0, 24, 7]), ('middle_left', [0, 7, 12, 13]),
|
||||
('middle_right', [12, 7, 24, 13]), ('lower_middle', [6, 13, 13, 19]),
|
||||
('lower_left', [0, 19, 12, 24]), ('lower_right', [13, 13, 24, 24])]
|
||||
CAPS = {0: (.92, .70, 1.5), 1: (.36, .25, .65), 2: (.42, .30, .35)}
|
||||
NAMES = {0: 'near_black', 1: 'green', 2: 'tan'}
|
||||
|
||||
|
||||
def sha(payload):
|
||||
return hashlib.sha256(payload).hexdigest()
|
||||
|
||||
|
||||
def keys(value, expected, label):
|
||||
if type(value) is not dict or set(value) != set(expected):
|
||||
raise ValueError(f'{label}: exact fields required')
|
||||
|
||||
|
||||
def hash_string(value):
|
||||
return type(value) is str and len(value) == 64 and all(c in '0123456789abcdef' for c in value)
|
||||
|
||||
|
||||
def regular_bytes(path):
|
||||
"""Read one regular nonsymlink once; consume this buffer, never reopen it."""
|
||||
path = Path(path)
|
||||
for parent in [path, *path.parents]:
|
||||
if parent.is_symlink():
|
||||
raise ValueError('symlink input path')
|
||||
before = path.lstat()
|
||||
if not stat.S_ISREG(before.st_mode):
|
||||
raise ValueError('regular input required')
|
||||
descriptor = os.open(path, os.O_RDONLY | getattr(os, 'O_NOFOLLOW', 0))
|
||||
with os.fdopen(descriptor, 'rb') as stream:
|
||||
opened = os.fstat(stream.fileno())
|
||||
payload = stream.read()
|
||||
after = os.fstat(stream.fileno())
|
||||
def identity(s):
|
||||
return s.st_dev, s.st_ino, s.st_size, s.st_mtime_ns, s.st_mode
|
||||
if identity(before) != identity(opened) or identity(opened) != identity(after) or identity(path.lstat()) != identity(before):
|
||||
raise ValueError('input changed during buffered read')
|
||||
return payload
|
||||
|
||||
|
||||
def checked(binding, root):
|
||||
keys(binding, {'path', 'sha256'}, 'binding')
|
||||
name = binding['path']
|
||||
if type(name) is not str or not name or '\\' in name or ':' in name:
|
||||
raise ValueError('portable relative path required')
|
||||
relative = PurePosixPath(name)
|
||||
if relative.is_absolute() or any(part in ('', '.', '..') for part in name.split('/')):
|
||||
raise ValueError('unsafe relative path')
|
||||
if not hash_string(binding['sha256']):
|
||||
raise ValueError('sha256 required')
|
||||
root = Path(root).resolve()
|
||||
path = root.joinpath(*relative.parts)
|
||||
if not path.resolve().is_relative_to(root):
|
||||
raise ValueError('input escapes root')
|
||||
payload = regular_bytes(path)
|
||||
if sha(payload) != binding['sha256']:
|
||||
raise ValueError(f'input hash mismatch: {name}')
|
||||
return payload
|
||||
|
||||
|
||||
def verified_decoder(project_root):
|
||||
payload = checked({'path': 'tools/hd_frame_policy.py', 'sha256': DECODER_SHA}, project_root)
|
||||
namespace = {'__name__': '_verified_hd_frame_policy', '__file__': '<verified-hd-frame-policy-buffer>'}
|
||||
exec(compile(payload, '<verified-hd-frame-policy-buffer>', 'exec'), namespace)
|
||||
return namespace['_indices']
|
||||
|
||||
|
||||
def scale2(source):
|
||||
"""Published Scale2x, identical label comparisons including transparent256."""
|
||||
h, w = source.shape
|
||||
b = np.concatenate([source[:1], source[:-1]], axis=0)
|
||||
d = np.concatenate([source[:, :1], source[:, :-1]], axis=1)
|
||||
f = np.concatenate([source[:, 1:], source[:, -1:]], axis=1)
|
||||
g = np.concatenate([source[1:], source[-1:]], axis=0)
|
||||
condition = (b != g) & (d != f)
|
||||
out = np.empty((h*2, w*2), np.uint16)
|
||||
out[0::2, 0::2] = np.where(condition & (d == b), d, source)
|
||||
out[0::2, 1::2] = np.where(condition & (b == f), f, source)
|
||||
out[1::2, 0::2] = np.where(condition & (d == g), d, source)
|
||||
out[1::2, 1::2] = np.where(condition & (g == f), f, source)
|
||||
return out
|
||||
|
||||
|
||||
def materials(rgb):
|
||||
r, g, b = rgb.astype(np.int32).transpose(2, 0, 1)
|
||||
result = np.full(r.shape, 255, np.uint8)
|
||||
result[(np.maximum(np.maximum(r, g), b) <= 64) & (g-r < 5)] = 0
|
||||
result[(g >= r+5) & (g >= b+5) & (g >= 24)] = 1
|
||||
result[(r >= g+5) & (g >= b+5) & (r >= 64)] = 2
|
||||
return result
|
||||
|
||||
|
||||
def box(value, maximum, label):
|
||||
if (type(value) is not list or len(value) != 4 or any(type(v) is not int for v in value)
|
||||
or not 0 <= value[0] < value[2] <= maximum or not 0 <= value[1] < value[3] <= maximum):
|
||||
raise ValueError(f'{label}: bounded integer rectangle required')
|
||||
return value
|
||||
|
||||
|
||||
def bounds(mask):
|
||||
y, x = np.where(mask)
|
||||
if len(x) == 0:
|
||||
raise ValueError('empty anatomical body')
|
||||
return [int(x.min()), int(y.min()), int(x.max()+1), int(y.max()+1)]
|
||||
|
||||
|
||||
def render_frame(frame, source, palette, raw_cell):
|
||||
"""Pure buffered renderer. No file access and no writable input aliases."""
|
||||
source4 = scale2(scale2(source))
|
||||
source_colors = np.zeros((257, 3), np.uint8)
|
||||
source_colors[:256] = palette
|
||||
source_classes = materials(source_colors.reshape(1, 257, 3))[0]
|
||||
source_classes[256] = 255
|
||||
classes4 = source_classes[source4]
|
||||
if np.any((source4 < 256) & (classes4 == 255)):
|
||||
raise ValueError('Original contains unsupported material')
|
||||
raw_classes = materials(raw_cell[:, :, :3])
|
||||
visible = raw_cell[:, :, 3] >= 128
|
||||
rgba = np.zeros((96, 96, 4), np.uint8)
|
||||
rgba[:, :, 3] = np.where(source4 < 256, 255, 0)
|
||||
owned = np.zeros((96, 96), bool)
|
||||
raw_owned = np.zeros((512, 512), bool)
|
||||
reports = []
|
||||
expected_faces = []
|
||||
for component, (expected_name, window) in zip(frame['components'], WINDOWS):
|
||||
keys(component, {'name', 'source_bbox', 'raw_bbox'}, 'component')
|
||||
if component['name'] != expected_name:
|
||||
raise ValueError('fixed Source body order required')
|
||||
x0, y0, x1, y1 = window
|
||||
logical_ownership = np.zeros((24, 24), bool)
|
||||
logical_ownership[y0:y1, x0:x1] = True
|
||||
original_body = logical_ownership & (source < 256)
|
||||
sb = box(component['source_bbox'], 24, 'Source bbox')
|
||||
if bounds(original_body) != sb:
|
||||
raise ValueError('Source body bbox does not match authenticated Source')
|
||||
face_y = sb[1]+1
|
||||
face_x = [x for x in range(sb[0], sb[2]) if source_classes[source[face_y, x]] == 2]
|
||||
if len(face_x) != 1:
|
||||
raise ValueError('exact central Original face cell required')
|
||||
expected_faces.append([face_x[0], face_y])
|
||||
l, t, r, b = box(component['raw_bbox'], 512, 'raw bbox')
|
||||
if raw_owned[t:b, l:r].any():
|
||||
raise ValueError('raw body boxes overlap')
|
||||
raw_owned[t:b, l:r] = True
|
||||
if bounds(visible[t:b, l:r]) != [0, 0, r-l, b-t]:
|
||||
raise ValueError('raw body bbox differs from genuine alpha>=128 bounds')
|
||||
owner = np.repeat(np.repeat(logical_ownership, 4, axis=0), 4, axis=1) & (source4 < 256)
|
||||
if np.any(owned & owner):
|
||||
raise ValueError('Source ownership overlaps')
|
||||
owned |= owner
|
||||
sx = (r-l)/(sb[2]-sb[0])
|
||||
sy = (b-t)/(sb[3]-sb[1])
|
||||
for cls in (0, 1, 2):
|
||||
yy, xx = np.where(owner & (classes4 == cls))
|
||||
if len(xx) == 0:
|
||||
continue
|
||||
donor_y, donor_x = np.where(visible[t:b, l:r] & (raw_classes[t:b, l:r] == cls))
|
||||
donor_x, donor_y = donor_x+l, donor_y+t
|
||||
if not len(donor_x):
|
||||
raise ValueError('missing genuine same-body/material donors')
|
||||
u = l+((xx+.5)/4-sb[0])*sx
|
||||
v = t+((yy+.5)/4-sb[1])*sy
|
||||
px, py = np.floor(u).astype(int), np.floor(v).astype(int)
|
||||
if np.any(px < l) or np.any(px >= r) or np.any(py < t) or np.any(py >= b):
|
||||
raise ValueError('SourceScale4 sample escapes raw body')
|
||||
direct = visible[py, px] & (raw_classes[py, px] == cls)
|
||||
missing = float(np.mean(~direct))
|
||||
per_cap, _, distance_cap = CAPS[cls]
|
||||
if missing > per_cap+1e-12:
|
||||
raise ValueError(f'{expected_name}/{NAMES[cls]}: fixed missing fraction exceeded')
|
||||
maximum_distance = 0.0
|
||||
for point in np.where(~direct)[0]:
|
||||
# np.where returns donors in y/x order; argmin fixes equal-distance ties.
|
||||
distances = ((donor_x+.5-u[point])/sx)**2 + ((donor_y+.5-v[point])/sy)**2
|
||||
nearest = int(np.argmin(distances))
|
||||
distance = math.sqrt(float(distances[nearest]))
|
||||
if distance > distance_cap+1e-12:
|
||||
raise ValueError(f'{expected_name}/{NAMES[cls]}: fixed donor distance exceeded')
|
||||
px[point], py[point] = donor_x[nearest], donor_y[nearest]
|
||||
maximum_distance = max(maximum_distance, distance)
|
||||
rgba[yy, xx, :3] = raw_cell[py, px, :3]
|
||||
reports.append(dict(body=expected_name, material=NAMES[cls], material_class=cls,
|
||||
samples=len(xx), repaired=int((~direct).sum()),
|
||||
missing_fraction=missing, maximum_donor_logical_distance=maximum_distance,
|
||||
raw_donors=len(donor_x)))
|
||||
if not np.array_equal(owned, source4 < 256):
|
||||
raise ValueError('fixed windows do not exhaust all SourceScale4 support')
|
||||
if np.any(visible & ~raw_owned):
|
||||
raise ValueError('unbound generated body alpha>=128 outside six declared bodies')
|
||||
faces = frame['functional_original_cells']
|
||||
if (type(faces) is not list or any(type(xy) is not list or len(xy) != 2 or any(type(v) is not int for v in xy) for xy in faces) or faces != sorted(expected_faces) or len(faces) != 6
|
||||
or 4*len(faces) > int((source < 256).sum())):
|
||||
raise ValueError('exact six functional Original cells within quarter-painted limit required')
|
||||
before_retention = rgba.copy()
|
||||
for x, y in faces:
|
||||
region = source4[y*4:(y+1)*4, x*4:(x+1)*4]
|
||||
target = rgba[y*4:(y+1)*4, x*4:(x+1)*4]
|
||||
target[:, :, :3] = source_colors[region]
|
||||
target[:, :, 3] = np.where(region < 256, 255, 0)
|
||||
if not np.array_equal(rgba[:, :, 3], np.where(source4 < 256, 255, 0)):
|
||||
raise ValueError('functional Original retention changed support')
|
||||
return rgba, dict(components=reports, functional_Original_cells=faces,
|
||||
functional_Original_master_samples=96,
|
||||
SourceScale4_alpha_exact=True,
|
||||
restored_black_is_functional_support_not_generated_detail=True,
|
||||
Original_RGBA_changed_samples=int(np.any(before_retention != rgba, axis=2).sum()))
|
||||
|
||||
|
||||
def run_recipe(recipe_path, output, project_root=None):
|
||||
recipe_path, output = Path(recipe_path).absolute(), Path(output).absolute()
|
||||
if output.exists() or output.is_symlink():
|
||||
raise ValueError('fresh absent output directory required')
|
||||
for parent in output.parents:
|
||||
if parent.is_symlink():
|
||||
raise ValueError('symlink output parent')
|
||||
tool_sha = sha(regular_bytes(Path(__file__)))
|
||||
rb = regular_bytes(recipe_path)
|
||||
recipe = json.loads(rb)
|
||||
keys(recipe, {'format_version', 'method', 'raw_png', 'palette', 'frames'}, 'recipe')
|
||||
if type(recipe['format_version']) is not int or recipe['format_version'] != 1 or recipe['method'] != METHOD:
|
||||
raise ValueError('fixed recipe method/version required')
|
||||
frames = recipe['frames']
|
||||
if type(frames) is not list or len(frames) != 6 or [f.get('asset') for f in frames if type(f) is dict] != ASSETS:
|
||||
raise ValueError('complete ordered six-frame PLATOON1 required')
|
||||
decoder = verified_decoder(Path(project_root) if project_root else Path(__file__).resolve().parents[1])
|
||||
raw_payload = checked(recipe['raw_png'], recipe_path.parent)
|
||||
with Image.open(io.BytesIO(raw_payload)) as opened:
|
||||
if opened.format != 'PNG' or opened.size != (1536, 1024) or opened.mode != 'RGBA':
|
||||
raise ValueError('exact1536x1024 RGBA three-by-two parent required')
|
||||
raw = np.asarray(opened).copy()
|
||||
pb = checked(recipe['palette'], recipe_path.parent)
|
||||
if len(pb) != 768 or max(pb) > 63:
|
||||
raise ValueError('genuine VGA palette required')
|
||||
sixbit = np.frombuffer(pb, np.uint8).reshape(256, 3).astype(np.uint16)
|
||||
palette = ((sixbit << 2) | (sixbit >> 4)).astype(np.uint8)
|
||||
sources = []
|
||||
for frame in frames:
|
||||
keys(frame, {'asset', 'source', 'components', 'functional_original_cells'}, 'frame')
|
||||
if type(frame['components']) is not list or len(frame['components']) != 6:
|
||||
raise ValueError('six exact bodies per frame required')
|
||||
payload = checked(frame['source'], recipe_path.parent)
|
||||
width, height, indices = decoder(payload)
|
||||
if (width, height) != (24, 24):
|
||||
raise ValueError('exact24x24 Source canvas required')
|
||||
source = np.array(indices, np.uint16).reshape(24, 24)
|
||||
sources.append(source)
|
||||
# All outputs stay buffered until the entire complete6 validates.
|
||||
payloads, reports = [], []
|
||||
for i, (frame, source) in enumerate(zip(frames, sources)):
|
||||
rgba, report = render_frame(frame, source, palette,
|
||||
raw[i//3*512:(i//3+1)*512, i%3*512:(i%3+1)*512])
|
||||
stream = io.BytesIO()
|
||||
Image.fromarray(rgba).save(stream, format='PNG', compress_level=9)
|
||||
payloads.append((frame['asset'], stream.getvalue()))
|
||||
reports.append({'asset': frame['asset'], **report, 'RGBA_sha256': sha(rgba.tobytes())})
|
||||
for cls in (0, 1, 2):
|
||||
rows = [r for report in reports for r in report['components'] if r['material_class'] == cls]
|
||||
aggregate = sum(r['repaired'] for r in rows)/sum(r['samples'] for r in rows)
|
||||
if aggregate > CAPS[cls][1]+1e-12:
|
||||
raise ValueError('fixed complete6 aggregate material cap exceeded')
|
||||
if sha(regular_bytes(Path(__file__))) != tool_sha:
|
||||
raise ValueError('executing helper changed during render')
|
||||
execution = dict(status='success', method=METHOD, recipe_sha256=sha(rb),
|
||||
tool_sha256=tool_sha,
|
||||
source_sha256={f['asset']: f['source']['sha256'] for f in frames},
|
||||
parent_raw_sha256=[sha(raw_payload)],
|
||||
output_sha256={asset: sha(png) for asset, png in payloads})
|
||||
receipt = dict(execution=execution, decoder_sha256=DECODER_SHA,
|
||||
dependencies_consumed_from_verified_buffers=True, reports=reports,
|
||||
Python=sys.version.split()[0], NumPy=np.__version__, Pillow=PILLOW_VERSION,
|
||||
limits=['Original support and six faces are not new generated detail.',
|
||||
'Black completion is substantial functional Source-shape restoration.',
|
||||
'Reproduction and numerical caps do not confer artistic approval.'])
|
||||
output.mkdir(parents=True)
|
||||
for asset, payload in payloads:
|
||||
(output/f'{asset}.png').write_bytes(payload)
|
||||
(output/'execution-receipt.json').write_text(json.dumps(receipt, indent=2, sort_keys=True)+'\n')
|
||||
return receipt
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('recipe', type=Path)
|
||||
parser.add_argument('output', type=Path)
|
||||
parser.add_argument('--project-root', type=Path)
|
||||
args = parser.parse_args()
|
||||
result = run_recipe(args.recipe, args.output, args.project_root)
|
||||
print(json.dumps(result['execution'], sort_keys=True))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -12,6 +12,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
import struct
|
||||
import tempfile
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
@@ -550,6 +551,11 @@ def approved_catalog_only_retained_evidence(root, project, declaration, rows, qa
|
||||
payload = Path(source["path"]).read_bytes()
|
||||
if hashlib.sha256(payload).hexdigest() != source.get("sha256") or pattern.search(payload.decode()):
|
||||
raise ValueError("catalog-only native caller Source changed")
|
||||
_approved_catalog_intrinsic_material(root, declaration, rows, qa)
|
||||
|
||||
|
||||
def _approved_catalog_intrinsic_material(root, declaration, rows, qa):
|
||||
asset, frame = next(iter(rows.items()))
|
||||
peer = receipt_json(root, declaration.get("catalog_only_independent_material"))
|
||||
contract = declaration.get("catalog_only_material_contract", {})
|
||||
artist = peer.get("actual_artist", peer.get("original_generated_artist"))
|
||||
@@ -608,6 +614,150 @@ def approved_catalog_only_retained_evidence(root, project, declaration, rows, qa
|
||||
raise ValueError("catalog-only actual all-scale evidence differs")
|
||||
|
||||
|
||||
UNUSED_TERRAIN_TRACE_V1 = "original-unused-terrain-source-trace-v1"
|
||||
|
||||
|
||||
def approved_unused_terrain_retained_evidence(root, project, declaration, rows, qa, job):
|
||||
"""Unused catalog Terrain has no scene to invent: prove absence in all base maps."""
|
||||
if len(rows) != 1 or job.get("category") != "Terrain":
|
||||
raise ValueError("unused Terrain review needs one complete original Terrain picture")
|
||||
asset, frame = next(iter(rows.items()))
|
||||
if (type(frame.get("frame")) is not int or frame["frame"] != 0 or
|
||||
frame.get("logical_width") != 32 or frame.get("logical_height") != 32):
|
||||
raise ValueError("unused Terrain needs the complete native 32 by 32 frame")
|
||||
pictures, payloads = authentic_terrain_inventory(root, job)
|
||||
if set(pictures) != {asset}:
|
||||
raise ValueError("unused Terrain inventory membership differs")
|
||||
validate_hd_frame(root, frame, payloads[asset], pictures[asset])
|
||||
data = root.parent.resolve()
|
||||
trace = receipt_json(root, declaration.get("catalog_only_source_trace"))
|
||||
if (trace.get("contract_version") != UNUSED_TERRAIN_TRACE_V1 or
|
||||
trace.get("status") != "CLOSED_UNUSED_ORIGINAL_TERRAIN_ALL27_MAPS" or
|
||||
trace.get("asset") != asset or
|
||||
trace.get("direct_callers") != [] or trace.get("destroyed_callers") != [] or
|
||||
trace.get("no_genuine_original_gameplay_context_claimed") is not True):
|
||||
raise ValueError("unused Terrain needs its explicit complete no-caller trace")
|
||||
|
||||
def source_bytes(record, route):
|
||||
if (not isinstance(record, dict) or record.get("path") != route or
|
||||
type(record.get("bytes")) is not int or record["bytes"] < 0 or
|
||||
re.fullmatch(r"[0-9a-f]{64}", str(record.get("sha256", ""))) is None):
|
||||
raise ValueError("unused Terrain Source pin path or fields differ")
|
||||
relative = PurePosixPath(route)
|
||||
if relative.is_absolute() or ".." in relative.parts or relative.as_posix() != route:
|
||||
raise ValueError("unused Terrain Source pin escapes catalog")
|
||||
local = data / Path(*relative.parts)
|
||||
path = contained(data, Path(*relative.parts))
|
||||
if local != path or local.is_symlink() or not stat.S_ISREG(path.lstat().st_mode):
|
||||
raise ValueError("unused Terrain Source must be a regular nonsymlink file")
|
||||
payload = path.read_bytes()
|
||||
if len(payload) != record["bytes"] or hashlib.sha256(payload).hexdigest() != record["sha256"]:
|
||||
raise ValueError("unused Terrain Source bytes changed")
|
||||
return payload
|
||||
|
||||
index = source_bytes(trace.get("catalogue"), "INDEX")
|
||||
names, ids = {}, set()
|
||||
for line in index.decode().splitlines():
|
||||
if not line.strip():
|
||||
continue
|
||||
parts = line.split()
|
||||
if (len(parts) != 3 or re.fullmatch(r"[0-9a-fA-F]{1,8}", parts[0]) is None or
|
||||
not parts[1].isdigit() or int(parts[0], 16) in ids):
|
||||
raise ValueError("unused Terrain invalid original INDEX")
|
||||
identity = int(parts[0], 16)
|
||||
ids.add(identity)
|
||||
route = PurePosixPath(parts[2])
|
||||
if route.is_absolute() or ".." in route.parts or route.as_posix() != parts[2]:
|
||||
raise ValueError("unused Terrain invalid original INDEX route")
|
||||
names.setdefault(route.name.upper(), []).append((identity, int(parts[1]), parts[2]))
|
||||
|
||||
def named(name):
|
||||
entries = names.get(name, [])
|
||||
if len(entries) != 1:
|
||||
raise ValueError("unused Terrain named Source is missing or ambiguous")
|
||||
return entries[0]
|
||||
|
||||
target = next(target for target in job["targets"] if target["asset"] == asset)
|
||||
payload = source_bytes(trace.get("Source"), target["source_path"])
|
||||
if payload != payloads[asset] or len(payload) < 20:
|
||||
raise ValueError("unused Terrain target Source differs")
|
||||
header = list(struct.unpack_from("<5i", payload))
|
||||
claimed_header = trace.get("source_header_le_i32")
|
||||
if (not isinstance(claimed_header, list) or len(claimed_header) != 5 or
|
||||
any(type(value) is not int for value in claimed_header) or claimed_header != header or
|
||||
header[0] != 1 or header[3:] != [32, 32]):
|
||||
raise ValueError("unused Terrain target header differs")
|
||||
|
||||
maps = trace.get("maps", [])
|
||||
libraries = trace.get("flat_libraries", [])
|
||||
expected_names = {f"MAP{wave}G{sector}_MAP" for sector in range(1, 4) for wave in range(1, 10)}
|
||||
expected_routes = {named(name)[2] for name in expected_names}
|
||||
library_routes = [named(f"FLATSG{game}_ITM")[2] for game in range(1, 5)]
|
||||
if (not isinstance(maps, list) or len(maps) != 27 or
|
||||
any(not isinstance(row, dict) for row in maps) or
|
||||
{row.get("path") for row in maps} != expected_routes or
|
||||
not isinstance(libraries, list) or len(libraries) != 4 or
|
||||
any(not isinstance(row, dict) for row in libraries) or
|
||||
[row.get("path") for row in libraries] != library_routes):
|
||||
raise ValueError("unused Terrain trace omits or duplicates Original maps or libraries")
|
||||
flat_data, starts = [], []
|
||||
for game, record in enumerate(libraries, 1):
|
||||
identity, size, route = named(f"FLATSG{game}_ITM")
|
||||
lib = source_bytes(record, route)
|
||||
if not lib or len(lib) != size or len(lib) % 8:
|
||||
raise ValueError("unused Terrain truncated original FLATS library")
|
||||
start = named(f"STARTG{game}TILES")[0] + 1
|
||||
end = named(f"ENDG{game}TILES")[0]
|
||||
if start + len(lib) // 8 != end:
|
||||
raise ValueError("unused Terrain library span differs from original tile catalog")
|
||||
starts.append(start)
|
||||
flat_data.append(lib)
|
||||
direct, destroyed, total_spawns = [], [], 0
|
||||
for record in maps:
|
||||
route = record["path"]
|
||||
name = PurePosixPath(route).name.upper()
|
||||
identity, size, expected_route = named(name)
|
||||
payload = source_bytes(record, expected_route)
|
||||
if len(payload) < 5412:
|
||||
raise ValueError("unused Terrain truncated original MAP")
|
||||
declared, offset, count = struct.unpack_from("<iii", payload)
|
||||
if (declared != size or declared != len(payload) or offset != 5412 or
|
||||
not 0 <= count < 65536 or 5412 + count * 24 > len(payload)):
|
||||
raise ValueError("unused Terrain invalid original MAP header")
|
||||
total_spawns += count
|
||||
for position in range(1350):
|
||||
flat, game = struct.unpack_from("<hh", payload, 12 + position * 4)
|
||||
if flat < 0 or not 0 <= game < 4 or flat * 8 + 8 > len(flat_data[game]):
|
||||
raise ValueError("unused Terrain invalid original MAP tile reference")
|
||||
replacement, health, reward = struct.unpack_from("<ihh", flat_data[game], flat * 8)
|
||||
if not 0 <= replacement < len(flat_data[game]) // 8:
|
||||
raise ValueError("unused Terrain invalid original FLATS destruction reference")
|
||||
if starts[game] + flat == int(asset, 16):
|
||||
direct.append((route, position))
|
||||
if replacement != flat and starts[game] + replacement == int(asset, 16):
|
||||
destroyed.append((route, position))
|
||||
counts = trace.get("counts", {})
|
||||
expected_counts = dict(maps=27, layout_cells=36450, flat_libraries=4,
|
||||
spawn_records=total_spawns, direct_callers=0, destroyed_callers=0)
|
||||
if (any(type(counts.get(key)) is not int for key in expected_counts) or
|
||||
counts != expected_counts or direct or destroyed):
|
||||
raise ValueError("unused Terrain has an original caller or false Source census")
|
||||
_approved_catalog_intrinsic_material(root, declaration, rows, qa)
|
||||
approval = receipt_json(root, declaration.get("catalog_only_root_approval"))
|
||||
if (approval.get("status") != "approved" or approval.get("authority_role") != "project_root" or
|
||||
not isinstance(approval.get("reviewer"), str) or not approval["reviewer"] or
|
||||
approval.get("scope") != "unused_original_terrain_intrinsic_all_scales" or
|
||||
approval.get("asset") != asset or
|
||||
approval.get("frame_bindings_sha256") != binding_digest(rows) or
|
||||
approval.get("source_sha256") != frame["source_sha256"] or
|
||||
approval.get("raw_sha256") != qa["artwork_sha256"][frame["file"]] or
|
||||
not same_json(approval.get("retained_cells"), frame["original_detail_cells"]) or
|
||||
not same_json(approval.get("native_scales"), [1, 2, 3, 4]) or
|
||||
approval.get("whole_picture_personally_viewed") is not True or
|
||||
approval.get("no_genuine_original_gameplay_context_claimed") is not True):
|
||||
raise ValueError("unused Terrain needs explicit Root whole-intrinsic approval")
|
||||
|
||||
|
||||
def validate_extended_retained_sources(project, rows):
|
||||
"""Longer lists require authentic catalog bytes, not claimed QA pixel counts.
|
||||
|
||||
@@ -738,10 +888,11 @@ def approved_job(root, identity, project):
|
||||
if retained_details:
|
||||
declaration = review.get("retained_original_detail_review", {})
|
||||
catalog_only = declaration.get("hybrid_review_scope") == "catalog_only_no_known_original_runtime_caller"
|
||||
if catalog_only and selection is not None:
|
||||
unused_terrain = declaration.get("hybrid_review_scope") == "catalog_only_unused_original_terrain"
|
||||
if (catalog_only or unused_terrain) and selection is not None:
|
||||
raise ValueError("catalog-only scope cannot replace contextual Terrain approval")
|
||||
qualified_scope = declaration.get("hybrid_allscale_and_genuine_context_independent_review") is True
|
||||
if catalog_only:
|
||||
if catalog_only or unused_terrain:
|
||||
qualified_scope = (declaration.get("hybrid_allscale_and_genuine_context_independent_review") is False
|
||||
and declaration.get("catalog_only_no_original_runtime_caller") is True
|
||||
and declaration.get("catalog_only_independent_whole_material_and_allscale_review") is True)
|
||||
@@ -806,6 +957,8 @@ def approved_job(root, identity, project):
|
||||
approved_standalone_evidence(root, selection, review, rows, qa)
|
||||
elif retained_details and catalog_only:
|
||||
approved_catalog_only_retained_evidence(root, project, declaration, rows, qa)
|
||||
elif retained_details and unused_terrain:
|
||||
approved_unused_terrain_retained_evidence(root, project, declaration, rows, qa, job)
|
||||
validate_extended_retained_sources(project, rows)
|
||||
validate_palette_constraint_approval(project, rows, review, qa)
|
||||
return candidate, review, rows
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import hashlib,io,json,os,struct,subprocess,sys,tempfile,types,unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
import hd_darkship_cleanup as m
|
||||
class Contract(unittest.TestCase):
|
||||
def family(self,name):
|
||||
ids=['102fc']if name=='SHIP05-singleton'else['2009a','2009b']
|
||||
return dict(format_version=1,family=name,palette={'path':'data/misc/PALETTE_DAT','sha256':m.PALETTE},dependencies={k:{'path':'tools/'+k+'.py','sha256':v}for k,v in m.PINS.items()},frames=[dict(asset=a,source={'path':'data/source'+a,'sha256':m.SPEC[a][1]},raw_png={'path':'data/raw-singleton.png'if a=='102fc'else'data/raw-rotor.png','sha256':m.SPEC[a][2]},viewport=m.SPEC[a][3],origin=[0,0],functional_original_cells=m.SPEC[a][4])for a in ids])
|
||||
def bundle(self):return dict(format_version=1,families=[self.family(n)for n in ('SHIP05-singleton','SHIP03-rotor2')])
|
||||
def test_exact_two_families(self):
|
||||
for f in self.bundle()['families']:self.assertEqual(m.validate_recipe(f),[x['asset']for x in f['frames']])
|
||||
def test_partial_rotor_rejected(self):
|
||||
r=self.family('SHIP03-rotor2');r['frames'].pop()
|
||||
with self.assertRaises(ValueError):m.validate_recipe(r)
|
||||
def test_bundle_wrong_order_before_reads(self):
|
||||
b=self.bundle();b['families'].reverse()
|
||||
with patch.object(m,'read',side_effect=AssertionError('not read')):
|
||||
with self.assertRaises(ValueError):m.derive_bundle(b,Path('/'))
|
||||
def test_origin_crop_selectors_fixed(self):
|
||||
for key,value in [('origin',[1,0]),('viewport',[57,29,1377,1084]),('functional_original_cells',[[27,12]])]:
|
||||
r=self.family('SHIP05-singleton');r['frames'][0][key]=value
|
||||
with self.assertRaises(ValueError):m.validate_recipe(r)
|
||||
def test_bool_geometry_rejected(self):
|
||||
r=self.family('SHIP05-singleton');r['frames'][0]['origin']=[False,0]
|
||||
with self.assertRaises(ValueError):m.validate_recipe(r)
|
||||
def test_wrong_dependency_hash(self):
|
||||
r=self.family('SHIP05-singleton');r['dependencies']['hd_frame_policy']['sha256']='0'*64
|
||||
with self.assertRaises(ValueError):m.validate_recipe(r)
|
||||
def test_read_relative_sha_bound(self):
|
||||
with tempfile.TemporaryDirectory()as d:
|
||||
p=Path(d)/'source';p.write_bytes(b'abc');b={'path':'source','sha256':m.sha(b'abc')};self.assertEqual(m.read(b,d),b'abc')
|
||||
with self.assertRaises(ValueError):m.read(b,d,2)
|
||||
with self.assertRaises(ValueError):m.read(b|{'sha256':'0'*64},d)
|
||||
def test_bad_routes_rejected(self):
|
||||
for route in ('/tmp/a','../a','a/../b','a\\b','a//b','a/./b',''):
|
||||
with self.subTest(route=route),self.assertRaises(ValueError):m.read({'path':route,'sha256':'0'*64},'/')
|
||||
def test_symlinks_rejected(self):
|
||||
with tempfile.TemporaryDirectory()as d:
|
||||
p=Path(d);(p/'actual').mkdir();(p/'actual/f').write_bytes(b'x');(p/'alias').symlink_to('actual',target_is_directory=True);(p/'last').symlink_to('actual/f')
|
||||
for route in ('alias/f','last'):
|
||||
with self.assertRaises(OSError):m.read({'path':route,'sha256':m.sha(b'x')},p)
|
||||
def test_fifo_rejected_without_blocking(self):
|
||||
with tempfile.TemporaryDirectory()as d:
|
||||
os.mkfifo(Path(d)/'fifo')
|
||||
code="import sys;sys.path.insert(0,sys.argv[1]);import hd_darkship_cleanup as m\ntry:m.read({'path':'fifo','sha256':'0'*64},sys.argv[2])\nexcept ValueError:print('REJECTED');sys.exit(0)\nraise SystemExit('FIFO unexpectedly accepted')"
|
||||
z=subprocess.run([sys.executable,'-c',code,str(Path(m.__file__).parent),d],capture_output=True,text=True,timeout=2)
|
||||
self.assertEqual(z.returncode,0,z.stderr);self.assertEqual(z.stdout.strip(),'REJECTED')
|
||||
def test_existing_output_before_recipe_read(self):
|
||||
with tempfile.TemporaryDirectory()as d:
|
||||
with self.assertRaises(ValueError):m.main('absent',d,d)
|
||||
def test_outside_recipe_rejected(self):
|
||||
with tempfile.TemporaryDirectory()as d:
|
||||
with self.assertRaises(ValueError):m.main('/outside/recipe',str(Path(d)/'new'),d)
|
||||
def test_disk_floor_before_recipe_read(self):
|
||||
with tempfile.TemporaryDirectory()as d,patch.object(m.shutil,'disk_usage',return_value=types.SimpleNamespace(free=2_207_999_999)):
|
||||
with self.assertRaises(ValueError):m.main('absent',str(Path(d)/'new'),d)
|
||||
def test_actual_reviewed_dependencies_bundle_synthetic_assets_no_reopen(self):
|
||||
toolroot=Path(m.__file__).resolve().parent;payloads={n:(toolroot/(n+'.py')).read_bytes()for n in m.PINS};self.assertTrue(all(m.sha(payloads[n])==h for n,h in m.PINS.items()))
|
||||
def source(w):return struct.pack('<iiiii',0,0,0,w,32)+b''.join(struct.pack('<iiii',0,y,y*w,w)+bytes([10])*w for y in range(32))+struct.pack('<iiii',0,0,-1,0)
|
||||
def raw(w,h):
|
||||
a=np.zeros((h,w,4),np.uint8);a[:,:,0]=120;a[:,:,1]=80;a[:,:,2]=150;a[:,:,3]=255;b=io.BytesIO();Image.fromarray(a).save(b,format='PNG');return b.getvalue()
|
||||
data={'data/misc/PALETTE_DAT':bytes(768),'data/source102fc':source(40),'data/source2009a':source(48),'data/source2009b':source(48),'data/raw-singleton.png':raw(1402,1122),'data/raw-rotor.png':raw(1024,1536)}|{'tools/'+n+'.py':b for n,b in payloads.items()};calls=[]
|
||||
def read(binding,*args):calls.append(binding['path']);return data[binding['path']]
|
||||
with patch.object(m,'read',side_effect=read),patch.object(Path,'read_bytes',side_effect=AssertionError('no path reopen')):
|
||||
out,report=m.derive_bundle(self.bundle(),Path('/synthetic'))
|
||||
self.assertEqual(set(out),{'102fc','2009a','2009b'});self.assertEqual(len(calls),9);self.assertEqual(len(set(calls)),9);self.assertEqual(report['unique_buffered_inputs'],9)
|
||||
self.assertEqual(report['family_reports'][0]['geometry']['decoder_module']['sha256'],m.PINS['hd_frame_policy']);self.assertEqual(report['family_reports'][1]['geometry']['decoder_module']['path'],'tools/hd_frame_policy.py')
|
||||
def test_dependency_bytes_rejected(self):
|
||||
with self.assertRaises(ValueError):m.modules({k:b'wrong'for k in m.PINS})
|
||||
if __name__=='__main__':unittest.main()
|
||||
@@ -0,0 +1,263 @@
|
||||
"""Synthetic RLE complete6 exercises actual buffered recipe and receipt path."""
|
||||
import copy
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import struct
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
spec = importlib.util.spec_from_file_location('infantry_under_test', HERE/'hd_infantry_cleanup.py')
|
||||
tool = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(tool)
|
||||
R = HERE.parents[1] if HERE.parent.name == '.reference' else HERE.parent
|
||||
if not (R/'tools/hd_frame_policy.py').exists():
|
||||
R = next(p for p in HERE.parents if (p/'tools/hd_frame_policy.py').exists())
|
||||
|
||||
|
||||
def rle(source):
|
||||
height, width = source.shape
|
||||
result = bytearray(struct.pack('<5i', 0, 0, 0, width, height))
|
||||
for y in range(height):
|
||||
x = 0
|
||||
while x < width:
|
||||
if source[y, x] == 256:
|
||||
x += 1
|
||||
continue
|
||||
start = x
|
||||
while x < width and source[y, x] < 256:
|
||||
x += 1
|
||||
result.extend(struct.pack('<4i', start, y, y*width+start, x-start))
|
||||
result.extend(bytes(int(v) for v in source[y, start:x]))
|
||||
result.extend(struct.pack('<4i', 0, 0, -1, 0))
|
||||
return bytes(result)
|
||||
|
||||
|
||||
class CompleteRecipeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.root = Path(self.tmp.name)
|
||||
self.project = self.root/'project'
|
||||
(self.project/'tools').mkdir(parents=True)
|
||||
shutil.copyfile(R/'tools/hd_frame_policy.py', self.project/'tools/hd_frame_policy.py')
|
||||
self.base = self.root/'inputs'
|
||||
self.base.mkdir()
|
||||
palette = np.zeros((256, 3), np.uint8)
|
||||
palette[16], palette[17], palette[18] = [10, 23, 8], [48, 39, 33], [1, 1, 1]
|
||||
(self.base/'palette.bin').write_bytes(palette.tobytes())
|
||||
p8 = ((palette.astype(np.uint16) << 2) | (palette.astype(np.uint16) >> 4)).astype(np.uint8)
|
||||
raw = np.zeros((1024, 1536, 4), np.uint8)
|
||||
frames = []
|
||||
self.sources = []
|
||||
self.palette = p8
|
||||
positions = [(7, 2), (4, 8), (15, 7), (7, 15), (3, 19), (17, 18)]
|
||||
pattern = np.array([[16, 16, 17], [256, 17, 256], [16, 16, 18], [18, 256, 256]], np.uint16)
|
||||
for i, asset in enumerate(tool.ASSETS):
|
||||
source = np.full((24, 24), 256, np.uint16)
|
||||
components, faces = [], []
|
||||
for (name, _), (x, y) in zip(tool.WINDOWS, positions):
|
||||
source[y:y+4, x:x+3] = pattern
|
||||
l, t, rr, b = x*20+16, y*20+16, (x+3)*20+16, (y+4)*20+16
|
||||
block = np.repeat(np.repeat(pattern, 20, axis=0), 20, axis=1)
|
||||
visible = block < 256
|
||||
rgba = np.zeros((80, 60, 4), np.uint8)
|
||||
rgba[:, :, :3][visible] = p8[block[visible]]
|
||||
rgba[:, :, 3][visible] = 255
|
||||
# Genuine synthetic material variation, preserved byte-for-byte by donors.
|
||||
gy, gx = np.where(block == 16)
|
||||
rgba[gy, gx, 1] += (gx % 5).astype(np.uint8)
|
||||
raw[i//3*512+t:i//3*512+b, i%3*512+l:i%3*512+rr] = rgba
|
||||
components.append(dict(name=name, source_bbox=[x, y, x+3, y+4], raw_bbox=[l, t, rr, b]))
|
||||
faces.append([x+1, y+1])
|
||||
path = self.base/f'{asset}.bin'
|
||||
path.write_bytes(rle(source))
|
||||
self.sources.append(source)
|
||||
frames.append(dict(asset=asset, source=self.bind(path), components=components,
|
||||
functional_original_cells=sorted(faces)))
|
||||
Image.fromarray(raw).save(self.base/'raw.png')
|
||||
self.recipe = dict(format_version=1, method=tool.METHOD, palette=self.bind(self.base/'palette.bin'),
|
||||
raw_png=self.bind(self.base/'raw.png'), frames=frames)
|
||||
self.path = self.base/'recipe.json'
|
||||
self.output = self.root/'output'
|
||||
self.write()
|
||||
|
||||
def tearDown(self):
|
||||
self.tmp.cleanup()
|
||||
|
||||
def bind(self, path):
|
||||
return dict(path=path.name, sha256=tool.sha(path.read_bytes()))
|
||||
|
||||
def write(self):
|
||||
self.path.write_text(json.dumps(self.recipe))
|
||||
|
||||
def run_real(self):
|
||||
self.write()
|
||||
return tool.run_recipe(self.path, self.output, self.project)
|
||||
|
||||
def reject(self):
|
||||
self.write()
|
||||
with self.assertRaises((ValueError, FileNotFoundError)):
|
||||
tool.run_recipe(self.path, self.output, self.project)
|
||||
self.assertFalse(self.output.exists())
|
||||
|
||||
def test_real_RLE_six_outputs_and_unmocked_execution_receipt(self):
|
||||
receipt = self.run_real()
|
||||
self.assertEqual(set(receipt['execution']), {'status', 'method', 'recipe_sha256', 'tool_sha256',
|
||||
'source_sha256', 'parent_raw_sha256', 'output_sha256'})
|
||||
self.assertEqual(receipt, json.loads((self.output/'execution-receipt.json').read_text()))
|
||||
self.assertEqual(len(list(self.output.glob('*.png'))), 6)
|
||||
self.assertEqual(receipt['execution']['recipe_sha256'], tool.sha(self.path.read_bytes()))
|
||||
for i, frame in enumerate(self.recipe['frames']):
|
||||
path = self.output/(frame['asset']+'.png')
|
||||
self.assertEqual(tool.sha(path.read_bytes()), receipt['execution']['output_sha256'][frame['asset']])
|
||||
a = np.asarray(Image.open(path))
|
||||
s4 = tool.scale2(tool.scale2(self.sources[i]))
|
||||
self.assertTrue(np.array_equal(a[:, :, 3], np.where(s4 < 256, 255, 0)))
|
||||
for x, y in frame['functional_original_cells']:
|
||||
self.assertTrue(np.array_equal(a[y*4:(y+1)*4, x*4:(x+1)*4, :3],
|
||||
self.palette[s4[y*4:(y+1)*4, x*4:(x+1)*4]]))
|
||||
|
||||
def test_replay_is_byte_identical(self):
|
||||
first = self.run_real()
|
||||
self.output = self.root/'second'
|
||||
second = self.run_real()
|
||||
self.assertEqual(first['execution'], second['execution'])
|
||||
|
||||
def test_missing_last_frame_has_no_output(self):
|
||||
self.recipe['frames'].pop()
|
||||
self.reject()
|
||||
|
||||
def test_duplicate_or_reordered_frame_has_no_output(self):
|
||||
self.recipe['frames'][5]['asset'] = '200ec'
|
||||
self.reject()
|
||||
|
||||
def test_late_Source_hash_mismatch_has_no_output(self):
|
||||
self.recipe['frames'][5]['source']['sha256'] = '0'*64
|
||||
self.reject()
|
||||
|
||||
def test_raw_hash_mismatch_has_no_output(self):
|
||||
self.recipe['raw_png']['sha256'] = '0'*64
|
||||
self.reject()
|
||||
|
||||
def test_traversal_and_absolute_paths_rejected(self):
|
||||
for path in ['../raw.png', '/raw.png', 'x/../raw.png', 'x\\raw.png', 'C:/raw.png', './raw.png']:
|
||||
self.recipe['raw_png']['path'] = path
|
||||
self.reject()
|
||||
|
||||
def test_symlink_parent_rejected(self):
|
||||
(self.base/'link').symlink_to(self.base, target_is_directory=True)
|
||||
self.recipe['raw_png']['path'] = 'link/raw.png'
|
||||
self.reject()
|
||||
|
||||
def test_Source_bbox_cannot_move_or_enlarge(self):
|
||||
self.recipe['frames'][5]['components'][0]['source_bbox'][0] -= 1
|
||||
self.reject()
|
||||
|
||||
def test_raw_body_cannot_include_another_body(self):
|
||||
self.recipe['frames'][5]['components'][0]['raw_bbox'] = [0, 0, 512, 512]
|
||||
self.reject()
|
||||
|
||||
def test_wrong_face_or_extra_Original_selection_rejected(self):
|
||||
self.recipe['frames'][5]['functional_original_cells'].append([0, 0])
|
||||
self.reject()
|
||||
|
||||
def test_no_user_caps_or_unknown_fields(self):
|
||||
self.recipe['caps'] = {'distance': 1000}
|
||||
self.reject()
|
||||
|
||||
def test_missing_green_donors_rejects_complete_family(self):
|
||||
raw = np.asarray(Image.open(self.base/'raw.png')).copy()
|
||||
g = tool.materials(raw[:, :, :3]) == 1
|
||||
raw[g, :3] = [4, 4, 4]
|
||||
Image.fromarray(raw).save(self.base/'raw.png')
|
||||
self.recipe['raw_png'] = self.bind(self.base/'raw.png')
|
||||
self.reject()
|
||||
|
||||
def test_existing_output_never_overwritten(self):
|
||||
self.output.mkdir()
|
||||
(self.output/'sentinel').write_text('keep')
|
||||
self.write()
|
||||
with self.assertRaises(ValueError):
|
||||
tool.run_recipe(self.path, self.output, self.project)
|
||||
self.assertEqual((self.output/'sentinel').read_text(), 'keep')
|
||||
|
||||
def test_decoder_hash_mismatch_before_any_output(self):
|
||||
(self.project/'tools/hd_frame_policy.py').write_text('raise RuntimeError("must not execute")')
|
||||
self.reject()
|
||||
|
||||
def test_decoder_consumes_verified_buffer_without_path_reopen(self):
|
||||
original = tool.checked
|
||||
def changed_after_verified_read(binding, root):
|
||||
result = original(binding, root)
|
||||
if binding['path'] == 'tools/hd_frame_policy.py':
|
||||
(self.project/'tools/hd_frame_policy.py').write_text('raise RuntimeError("reopened path")')
|
||||
return result
|
||||
with patch.object(tool, 'checked', changed_after_verified_read):
|
||||
receipt = self.run_real()
|
||||
self.assertTrue(receipt['dependencies_consumed_from_verified_buffers'])
|
||||
self.assertEqual(receipt['execution']['status'], 'success')
|
||||
|
||||
def test_raw_decode_consumes_verified_buffer_without_reopen(self):
|
||||
original = tool.checked
|
||||
def changed_after_verified_read(binding, root):
|
||||
result = original(binding, root)
|
||||
if binding['path'] == 'raw.png':
|
||||
(self.base/'raw.png').write_bytes(b'not a PNG')
|
||||
return result
|
||||
with patch.object(tool, 'checked', changed_after_verified_read):
|
||||
receipt = self.run_real()
|
||||
self.assertEqual(receipt['execution']['status'], 'success')
|
||||
|
||||
def test_fixed_missing_fraction_cap_rejects_without_Original_fallback(self):
|
||||
raw = np.asarray(Image.open(self.base/'raw.png')).copy()
|
||||
c = self.recipe['frames'][5]['components'][0]
|
||||
l, t, r, b = c['raw_bbox']
|
||||
# Leave a small genuine green donor region, so absence of donors cannot
|
||||
# be the rejection reason. Most projected green samples become black.
|
||||
block = raw[512+t:512+b, 1024+l:1024+r]
|
||||
green = tool.materials(block[:, :, :3]) == 1
|
||||
yy, xx = np.where(green)
|
||||
block[yy[1:], xx[1:], :3] = [4, 4, 4]
|
||||
Image.fromarray(raw).save(self.base/'raw.png')
|
||||
self.recipe['raw_png'] = self.bind(self.base/'raw.png')
|
||||
self.write()
|
||||
with self.assertRaisesRegex(ValueError, 'fixed missing fraction exceeded'):
|
||||
tool.run_recipe(self.path, self.output, self.project)
|
||||
self.assertFalse(self.output.exists())
|
||||
|
||||
def test_fixed_distance_cap_rejects_even_when_missing_fraction_is_small(self):
|
||||
raw = np.asarray(Image.open(self.base/'raw.png')).copy()
|
||||
l, t, r, b = self.recipe['frames'][5]['components'][0]['raw_bbox']
|
||||
# One of four green logical cells is blackened. Other genuine green
|
||||
# donors remain, but the deep corner is over the fixed .65-cell cap.
|
||||
raw[512+t:512+t+20, 1024+l:1024+l+20, :3] = [4, 4, 4]
|
||||
Image.fromarray(raw).save(self.base/'raw.png')
|
||||
self.recipe['raw_png'] = self.bind(self.base/'raw.png')
|
||||
self.write()
|
||||
with self.assertRaisesRegex(ValueError, 'fixed donor distance exceeded'):
|
||||
tool.run_recipe(self.path, self.output, self.project)
|
||||
self.assertFalse(self.output.exists())
|
||||
|
||||
def test_scale2_preserves_label_identity_and_transparent_sentinel(self):
|
||||
source = np.array([[1, 256, 2], [256, 256, 256], [3, 256, 4]], np.uint16)
|
||||
output = tool.scale2(tool.scale2(source))
|
||||
self.assertEqual(output.shape, (12, 12))
|
||||
self.assertEqual(set(np.unique(output)), {1, 2, 3, 4, 256})
|
||||
self.assertEqual(int(output[0, 0]), 1)
|
||||
self.assertEqual(int(output[-1, -1]), 4)
|
||||
|
||||
def test_Source_RLE_truncation_rejected(self):
|
||||
source = self.base/'200f1.bin'
|
||||
source.write_bytes(source.read_bytes()[:-8])
|
||||
self.recipe['frames'][5]['source'] = self.bind(source)
|
||||
self.reject()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,231 @@
|
||||
"""Unused Terrain approval proves Source absence; it cannot invent a gameplay scene."""
|
||||
from pathlib import Path
|
||||
import copy, hashlib, json, struct, tempfile, unittest
|
||||
from PIL import Image
|
||||
import hd_register_reviewed as m
|
||||
|
||||
|
||||
class UnusedTerrainRetained(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory(prefix='unused-terrain-')
|
||||
self.project = Path(self.temp.name) / 'Renamed 游戏 bundle'
|
||||
self.data = self.project / 'data'
|
||||
self.root = self.data / 'hd'
|
||||
for folder in ('misc', 'maps', 'tiles', 'hd/proof', 'hd/raws'):
|
||||
(self.data / folder).mkdir(parents=True, exist_ok=True)
|
||||
self.asset = '00103'
|
||||
self.source = self.data / 'misc/unused.pic'
|
||||
self.source.write_bytes(struct.pack('<5i', 1, 0, 0, 32, 32) + bytes(1024))
|
||||
palette = self.data / 'misc/PALETTE_DAT'
|
||||
palette.write_bytes(bytes(768))
|
||||
self.index = []
|
||||
self.add(1, 'misc/PALETTE_DAT')
|
||||
self.add(0x103, 'misc/unused.pic')
|
||||
for game in range(1, 5):
|
||||
base = game * 0x100
|
||||
for name, identity in [(f'STARTG{game}TILES', base), (f'ENDG{game}TILES', base + 4)]:
|
||||
(self.data / 'tiles' / name).write_bytes(b'')
|
||||
self.add(identity, f'tiles/{name}')
|
||||
lib = self.data / f'misc/FLATSG{game}_ITM'
|
||||
lib.write_bytes(b''.join(struct.pack('<ihh', i, 0, 0) for i in range(3)))
|
||||
self.add(0x500 + game, f'misc/FLATSG{game}_ITM')
|
||||
for sector in range(1, 4):
|
||||
for wave in range(1, 10):
|
||||
route = f'maps/MAP{wave}G{sector}_MAP'
|
||||
(self.data / route).write_bytes(struct.pack('<iii', 5412, 5412, 0) + bytes(5400))
|
||||
self.add(0x600 + sector * 16 + wave, route)
|
||||
self.write_index()
|
||||
raw = self.root / 'raws/test.png'
|
||||
Image.new('RGBA', (64, 64), (0, 0, 0, 255)).save(raw)
|
||||
frame = dict(frame=0, file='raws/test.png', logical_width=32, logical_height=32,
|
||||
origin=[0, 0], source_sha256=self.sha(self.source),
|
||||
original_detail_cells=[[x, 31] for x in range(32)])
|
||||
self.rows = {self.asset: frame}
|
||||
self.job = dict(category='Terrain', targets=[dict(asset=self.asset,
|
||||
source_path='misc/unused.pic', source_sha256=self.sha(self.source),
|
||||
logical_canvas=[32, 32], origin=[0, 0], source_palette='PALETTE_DAT',
|
||||
source_palette_sha256=self.sha(palette))])
|
||||
self.candidate = dict(sequences=[dict(base_asset=0x103, frame_count=1, frames=[frame])])
|
||||
masks = [dict(scale=i, mask={}) for i in range(1, 5)]
|
||||
self.qa = dict(diagnostics=[], validated_frames=1,
|
||||
frames=[dict(asset=self.asset, hd_masks=masks)],
|
||||
artwork_sha256={'raws/test.png': self.sha(raw)})
|
||||
self.peer = dict(status='QUALIFIED', asset=self.asset, qualified_complete1=True,
|
||||
all4_scales_qualified=True, complete_native_frames=1, native_scales=[1, 2, 3, 4],
|
||||
actual_artist='artist', hybrid_trial_preparer='preparer', reviewer='different',
|
||||
different_from_artist_and_preparer=True, held_frames=0,
|
||||
raw={'sha256': self.sha(raw)}, exact_original_detail_cells=frame['original_detail_cells'])
|
||||
self.contract = dict(status='qualified', scope='complete_native_picture_intrinsic_all_scales',
|
||||
asset=self.asset, reviewer='different', artist='artist', preparer='preparer',
|
||||
qualified_frames=1, held_frames=0, retained_cell_count=32,
|
||||
native_frame=frame, retained_cells=frame['original_detail_cells'], native_scales=[1, 2, 3, 4])
|
||||
self.approval = dict(status='approved', authority_role='project_root', reviewer='root',
|
||||
scope='unused_original_terrain_intrinsic_all_scales', asset=self.asset,
|
||||
frame_bindings_sha256=m.binding_digest(self.rows), source_sha256=frame['source_sha256'],
|
||||
raw_sha256=self.sha(raw), retained_cells=frame['original_detail_cells'],
|
||||
native_scales=[1, 2, 3, 4], whole_picture_personally_viewed=True,
|
||||
no_genuine_original_gameplay_context_claimed=True)
|
||||
self.trace = dict(contract_version=m.UNUSED_TERRAIN_TRACE_V1,
|
||||
status='CLOSED_UNUSED_ORIGINAL_TERRAIN_ALL27_MAPS', asset=self.asset,
|
||||
direct_callers=[], destroyed_callers=[], no_genuine_original_gameplay_context_claimed=True,
|
||||
source_header_le_i32=[1, 0, 0, 32, 32],
|
||||
counts=dict(maps=27, layout_cells=36450, flat_libraries=4, spawn_records=0,
|
||||
direct_callers=0, destroyed_callers=0))
|
||||
|
||||
def tearDown(self):
|
||||
self.temp.cleanup()
|
||||
|
||||
@staticmethod
|
||||
def sha(path):
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
def add(self, identity, route):
|
||||
self.index.append([identity, (self.data / route).stat().st_size, route])
|
||||
|
||||
def write_index(self):
|
||||
(self.data / 'INDEX').write_text(''.join(f'{i:x} {s} {p}\n' for i, s, p in self.index))
|
||||
|
||||
def pin(self, route):
|
||||
path = self.data / route
|
||||
return dict(path=route, sha256=self.sha(path), bytes=path.stat().st_size)
|
||||
|
||||
def receipt(self, route, value):
|
||||
path = self.root / route
|
||||
path.write_text(json.dumps(value, indent=2) + '\n')
|
||||
return dict(path=route, sha256=self.sha(path))
|
||||
|
||||
def declaration(self):
|
||||
self.trace.setdefault('catalogue', self.pin('INDEX'))
|
||||
self.trace.setdefault('Source', self.pin('misc/unused.pic'))
|
||||
self.trace.setdefault('maps', [self.pin(f'maps/MAP{w}G{s}_MAP') for s in range(1, 4) for w in range(1, 10)])
|
||||
self.trace.setdefault('flat_libraries', [self.pin(f'misc/FLATSG{g}_ITM') for g in range(1, 5)])
|
||||
peer = copy.deepcopy(self.peer)
|
||||
peer['candidate'] = self.receipt('proof/candidate.json', self.candidate)
|
||||
return dict(catalog_only_source_trace=self.receipt('proof/trace.json', self.trace),
|
||||
catalog_only_independent_material=self.receipt('proof/peer.json', peer),
|
||||
catalog_only_material_contract=self.contract,
|
||||
catalog_only_actual_allscale_QA=self.receipt('proof/qa.json', self.qa),
|
||||
catalog_only_root_approval=self.receipt('proof/root.json', self.approval))
|
||||
|
||||
def check(self, declaration=None):
|
||||
return m.approved_unused_terrain_retained_evidence(self.root, self.project,
|
||||
self.declaration() if declaration is None else declaration, self.rows, self.qa, self.job)
|
||||
|
||||
def mutate(self, route, offset, fmt, value):
|
||||
path = self.data / route
|
||||
b = bytearray(path.read_bytes())
|
||||
struct.pack_into(fmt, b, offset, value)
|
||||
path.write_bytes(b)
|
||||
|
||||
def test_real_checked_synthetic_bundle_all27_unused_accepts_relocated_unicode(self):
|
||||
self.check()
|
||||
|
||||
def test_actual_direct_map_use_rejects_even_when_receipt_claims_zero(self):
|
||||
self.mutate('maps/MAP1G1_MAP', 12, '<h', 2)
|
||||
with self.assertRaisesRegex(ValueError, 'original caller'): self.check()
|
||||
|
||||
def test_actual_destroyed_map_use_rejects_even_when_receipt_claims_zero(self):
|
||||
self.mutate('misc/FLATSG1_ITM', 0, '<i', 2)
|
||||
with self.assertRaisesRegex(ValueError, 'original caller'): self.check()
|
||||
|
||||
def test_missing_trace_rejects(self):
|
||||
d = self.declaration(); d.pop('catalog_only_source_trace')
|
||||
with self.assertRaisesRegex(ValueError, 'hash-bound'): self.check(d)
|
||||
|
||||
def test_false_census_or_boolean_count_rejects(self):
|
||||
for value in [26, True]:
|
||||
with self.subTest(value=value):
|
||||
self.trace['counts']['maps'] = value
|
||||
with self.assertRaisesRegex(ValueError, 'false Source census'): self.check()
|
||||
|
||||
def test_missing_map_rejects(self):
|
||||
self.declaration(); self.trace['maps'].pop()
|
||||
with self.assertRaisesRegex(ValueError, 'omits or duplicates'): self.check()
|
||||
|
||||
def test_duplicate_map_cannot_cover_missing_twentyseventh(self):
|
||||
self.declaration(); self.trace['maps'][-1] = self.trace['maps'][0]
|
||||
with self.assertRaisesRegex(ValueError, 'omits or duplicates'): self.check()
|
||||
|
||||
def test_fourth_flat_library_required(self):
|
||||
self.declaration(); self.trace['flat_libraries'].pop()
|
||||
with self.assertRaisesRegex(ValueError, 'omits or duplicates'): self.check()
|
||||
|
||||
def test_bad_hash_rejects(self):
|
||||
self.declaration(); self.trace['maps'][0]['sha256'] = '0' * 64
|
||||
with self.assertRaisesRegex(ValueError, 'Source bytes changed'): self.check()
|
||||
|
||||
def test_wrong_pin_path_rejects(self):
|
||||
self.declaration(); self.trace['Source']['path'] = '../outside.pic'
|
||||
with self.assertRaisesRegex(ValueError, 'pin path'): self.check()
|
||||
|
||||
def test_header_claim_or_boolean_header_rejects(self):
|
||||
for value in [2, True]:
|
||||
with self.subTest(value=value):
|
||||
self.trace['source_header_le_i32'][0] = value
|
||||
with self.assertRaisesRegex(ValueError, 'header differs'): self.check()
|
||||
|
||||
def test_bad_MAP_header_offset_rejects(self):
|
||||
self.mutate('maps/MAP9G3_MAP', 4, '<i', 5411)
|
||||
with self.assertRaisesRegex(ValueError, 'MAP header'): self.check()
|
||||
|
||||
def test_negative_spawn_count_rejects(self):
|
||||
self.mutate('maps/MAP9G3_MAP', 8, '<i', -1)
|
||||
with self.assertRaisesRegex(ValueError, 'MAP header'): self.check()
|
||||
|
||||
def test_bad_tile_library_rejects(self):
|
||||
self.mutate('maps/MAP9G3_MAP', 14, '<h', 4)
|
||||
with self.assertRaisesRegex(ValueError, 'MAP tile reference'): self.check()
|
||||
|
||||
def test_out_of_range_flat_rejects(self):
|
||||
self.mutate('maps/MAP9G3_MAP', 12, '<h', 3)
|
||||
with self.assertRaisesRegex(ValueError, 'MAP tile reference'): self.check()
|
||||
|
||||
def test_out_of_range_destroyed_reference_rejects(self):
|
||||
self.mutate('misc/FLATSG1_ITM', 0, '<i', 3)
|
||||
with self.assertRaisesRegex(ValueError, 'destruction reference'): self.check()
|
||||
|
||||
def test_missing_root_approval_rejects(self):
|
||||
d = self.declaration(); d.pop('catalog_only_root_approval')
|
||||
with self.assertRaisesRegex(ValueError, 'hash-bound'): self.check(d)
|
||||
|
||||
def test_root_approval_requires_actual_whole_picture_view(self):
|
||||
self.approval['whole_picture_personally_viewed'] = False
|
||||
with self.assertRaisesRegex(ValueError, 'Root whole-intrinsic'): self.check()
|
||||
|
||||
def test_root_approval_cannot_claim_fabricated_context(self):
|
||||
self.approval['no_genuine_original_gameplay_context_claimed'] = False
|
||||
with self.assertRaisesRegex(ValueError, 'Root whole-intrinsic'): self.check()
|
||||
|
||||
def test_root_approval_frame_hash_cannot_change(self):
|
||||
self.approval['frame_bindings_sha256'] = '0' * 64
|
||||
with self.assertRaisesRegex(ValueError, 'Root whole-intrinsic'): self.check()
|
||||
|
||||
def test_peer_must_be_independent_from_preparer(self):
|
||||
self.peer['reviewer'] = 'preparer'
|
||||
with self.assertRaisesRegex(ValueError, 'independent qualified'): self.check()
|
||||
|
||||
def test_peer_pending_is_not_qualification(self):
|
||||
self.peer['status'] = 'QUALIFIED_PENDING'
|
||||
with self.assertRaisesRegex(ValueError, 'independent qualified'): self.check()
|
||||
|
||||
def test_peer_cannot_approve_different_raw(self):
|
||||
self.peer['raw']['sha256'] = '0' * 64
|
||||
with self.assertRaisesRegex(ValueError, 'source, raw'): self.check()
|
||||
|
||||
def test_peer_cannot_skip_native_scale(self):
|
||||
self.peer['native_scales'] = [1, 2, 4]
|
||||
with self.assertRaisesRegex(ValueError, 'independent qualified'): self.check()
|
||||
|
||||
def test_two_asset_scope_rejects(self):
|
||||
self.rows['00102'] = self.rows['00103']
|
||||
with self.assertRaisesRegex(ValueError, 'one complete'): self.check()
|
||||
|
||||
def test_original_nonterrain_catalog_branch_still_rejects_terrain(self):
|
||||
# New opt-in cannot weaken the separate existing non-Terrain policy.
|
||||
d = self.declaration()
|
||||
with self.assertRaises(ValueError):
|
||||
m.approved_catalog_only_retained_evidence(self.root, self.project, d, self.rows, self.qa)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user