Publish verified Windows authoring prerelease evidence

This commit is contained in:
2026-09-11 05:43:28 -07:00
parent 01b76a1e89
commit 6a610616e7
26 changed files with 9273 additions and 0 deletions
@@ -0,0 +1,18 @@
# Authoring prerelease evidence
Exact preserved producer, independent reviewer and root native evidence for
Windows preview `v0.2.0-preview.authoring.20260911`. `hashes.json` records each
copied artifact's original private path, length and SHA256. Git must retain these
measured bytes. The executable ZIP and validation notes are release assets.
The preserved Python files are the original host-specific harnesses. Their
relative paths and source/toolchain prerequisites refer to the recorded original
`.local` layout; they are not portable standalone tests when run from this archive.
To reproduce them, restore that layout in a disposable checkout and use fresh
output directories. They never contain Gitea credentials. The GUI launch script
only launches the application; native actions were performed using Computer Use.
See the three `harness/release-authoring-prerelease-*-20260911.md` reports for
methods, initial GUI harness failure, passed checks, source provenance and limits.
`published-verified.json` records the final release readback; upload records bind
the exact downloaded assets. Publication does not complete the wider OA/SA goal.
@@ -0,0 +1,9 @@
{
"pid": 10800,
"exe": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\authoring-prerelease-gui-20260911-v2\\extracted\\ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm\\arcadia-studio.exe",
"archive_sha256": "664f30b6217689aca1492eb263b3d15777067d732fa890eeb028f435209dadfa",
"files": 559,
"path": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\authoring-prerelease-gui-20260911-v2\\extracted\\ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm;C:\\Windows\\System32;C:\\Windows",
"local_appdata": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\authoring-prerelease-gui-20260911-v2\\profile\\local",
"appdata": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\authoring-prerelease-gui-20260911-v2\\profile\\roaming"
}
@@ -0,0 +1,37 @@
from pathlib import Path
import hashlib
import json
import os
import subprocess
import zipfile
root = Path.cwd()
name = 'ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm'
archive = root / '.local/authoring-prerelease-20260911/packages' / (name + '.zip')
assert hashlib.sha256(archive.read_bytes()).hexdigest() == '664f30b6217689aca1492eb263b3d15777067d732fa890eeb028f435209dadfa'
trial = root / '.local/authoring-prerelease-gui-20260911-v2'
trial.mkdir(exist_ok=False)
extract = trial / 'extracted'
extract.mkdir()
with zipfile.ZipFile(archive) as z:
names = z.namelist()
assert len(names) == len(set(n.casefold() for n in names)) == 559
assert all(n.startswith(name + '/') and '..' not in Path(n).parts for n in names)
z.extractall(extract)
package = extract / name
for line in (package / 'SHA256SUMS.txt').read_text().splitlines():
digest, path = line.split(' ', 1)
assert hashlib.sha256((package / path).read_bytes()).hexdigest() == digest, path
for folder in ['profile/local', 'profile/roaming']:
(trial / folder).mkdir(parents=True)
env = os.environ.copy()
env['LOCALAPPDATA'] = str(trial / 'profile/local')
env['APPDATA'] = str(trial / 'profile/roaming')
env['PATH'] = os.pathsep.join([str(package), str(Path(env['SYSTEMROOT']) / 'System32'), env['SYSTEMROOT']])
exe = package / 'arcadia-studio.exe'
assert hashlib.sha256(exe.read_bytes()).hexdigest() == 'd4d9c2bd937e301ff1009d7cb93a34ee5aa6dfc837ff7e87d468c85371b20c31'
with (trial / 'stdout.log').open('wb') as out, (trial / 'stderr.log').open('wb') as err:
process = subprocess.Popen([str(exe)], cwd=package, env=env, stdout=out, stderr=err)
result = {'pid': process.pid, 'exe': str(exe), 'archive_sha256': hashlib.sha256(archive.read_bytes()).hexdigest(), 'files': len(names), 'path': env['PATH'], 'local_appdata': env['LOCALAPPDATA'], 'appdata': env['APPDATA']}
(trial / 'launch.json').write_text(json.dumps(result, indent=2), encoding='utf-8')
print(json.dumps(result, indent=2))
@@ -0,0 +1,64 @@
[
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\authoring-prerelease-gui-20260911-v2\\extracted\\ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm\\arcadia-studio.exe",
"C:\\Windows\\SYSTEM32\\ntdll.dll",
"C:\\Windows\\System32\\KERNEL32.DLL",
"C:\\Windows\\System32\\KERNELBASE.dll",
"C:\\Windows\\SYSTEM32\\apphelp.dll",
"C:\\Windows\\System32\\user32.dll",
"C:\\Windows\\System32\\win32u.dll",
"C:\\Windows\\System32\\GDI32.dll",
"C:\\Windows\\System32\\gdi32full.dll",
"C:\\Windows\\System32\\msvcp_win.dll",
"C:\\Windows\\System32\\ucrtbase.dll",
"C:\\Windows\\System32\\ole32.dll",
"C:\\Windows\\System32\\combase.dll",
"C:\\Windows\\System32\\RPCRT4.dll",
"C:\\Windows\\System32\\advapi32.dll",
"C:\\Windows\\System32\\msvcrt.dll",
"C:\\Windows\\System32\\sechost.dll",
"C:\\Windows\\System32\\bcryptprimitives.dll",
"C:\\Windows\\System32\\shell32.dll",
"C:\\Windows\\System32\\imm32.dll",
"C:\\Windows\\System32\\ws2_32.dll",
"C:\\Windows\\System32\\oleaut32.dll",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\authoring-prerelease-gui-20260911-v2\\extracted\\ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm\\libunwind.dll",
"C:\\Windows\\SYSTEM32\\bcrypt.dll",
"C:\\Windows\\SYSTEM32\\dwmapi.dll",
"C:\\Windows\\SYSTEM32\\uxtheme.dll",
"C:\\Windows\\SYSTEM32\\opengl32.dll",
"C:\\Windows\\SYSTEM32\\GLU32.dll",
"C:\\Windows\\SYSTEM32\\CRYPTBASE.DLL",
"C:\\Windows\\SYSTEM32\\dxcore.dll",
"C:\\Windows\\System32\\MSCTF.dll",
"C:\\Windows\\SYSTEM32\\kernel.appcore.dll",
"C:\\Windows\\System32\\clbcatq.dll",
"C:\\Windows\\system32\\dataexchange.dll",
"C:\\Windows\\system32\\twinapi.appcore.dll",
"C:\\Windows\\system32\\explorerframe.dll",
"C:\\Windows\\System32\\SHCORE.dll",
"C:\\Windows\\System32\\SHLWAPI.dll",
"C:\\Windows\\System32\\Windows.Storage.dll",
"C:\\Windows\\SYSTEM32\\powrprof.dll",
"C:\\Windows\\SYSTEM32\\UMPDC.dll",
"C:\\Windows\\SYSTEM32\\CFGMGR32.dll",
"C:\\Windows\\system32\\dxgi.dll",
"C:\\Windows\\SYSTEM32\\windows.staterepositorycore.dll",
"C:\\Windows\\SYSTEM32\\directxdatabasehelper.dll",
"C:\\Windows\\SYSTEM32\\d3d12.dll",
"C:\\Windows\\SYSTEM32\\d3dcompiler_47.dll",
"C:\\Windows\\SYSTEM32\\cryptsp.dll",
"C:\\Windows\\System32\\DriverStore\\FileRepository\\vm3d.inf_amd64_39d3dfd189710365\\vm3dgl64.dll",
"C:\\Windows\\System32\\DriverStore\\FileRepository\\vm3d.inf_amd64_39d3dfd189710365\\vm3dglhelper64.dll",
"C:\\Windows\\SYSTEM32\\WINMM.dll",
"C:\\Windows\\SYSTEM32\\D3D12Core.dll",
"C:\\Windows\\SYSTEM32\\d3d10warp.dll",
"C:\\Windows\\SYSTEM32\\D3DSCache.dll",
"C:\\Windows\\SYSTEM32\\USERENV.dll",
"C:\\Windows\\SYSTEM32\\dxilconv.dll",
"C:\\Windows\\SYSTEM32\\dcomp.dll",
"C:\\Windows\\SYSTEM32\\Microsoft.Internal.WarpPal.dll",
"C:\\Windows\\SYSTEM32\\textinputframework.dll",
"C:\\Windows\\SYSTEM32\\uiautomationcore.dll",
"C:\\Windows\\SYSTEM32\\OLEACC.dll",
"C:\\Windows\\System32\\threadpoolwinrt.dll"
]
@@ -0,0 +1,5 @@
{
"matched_files": 558,
"exact_physical_inventory": 559,
"result": "PASS after native packaged walkthrough open and Save"
}
@@ -0,0 +1,116 @@
[
{
"path": "producer-inventory.json",
"original": ".local/authoring-prerelease-20260911/inventory.json",
"bytes": 66465,
"sha256": "3c78dea4e93dae186fd24ab826c6680178a2c7849c270a22deae2ff732f1857b"
},
{
"path": "producer-build-evidence.json",
"original": ".local/authoring-prerelease-20260911/build-evidence.json",
"bytes": 1230,
"sha256": "ccc1ccd087f1de9605ba23a4680e1cb6d37ce5ccf0f8db03c03c4797ae32db25"
},
{
"path": "producer-package-result.json",
"original": ".local/authoring-prerelease-20260911/package-initial-result.json",
"bytes": 216,
"sha256": "45f372960931fa34ca75086df5d346eab9127a7ae70b53aed86751e372c24bae"
},
{
"path": "producer-roundtrip.json",
"original": ".local/authoring-prerelease-20260911/committed-roundtrip.json",
"bytes": 40443,
"sha256": "27e4cd2d6130a9ced76560cee130b5d363478ee0da62925e785691c63fadb098"
},
{
"path": "reviewer-artifact-result.json",
"original": ".local/authoring-prerelease-review-20260911/artifact-result.json",
"bytes": 338784,
"sha256": "8b20e9d294338754ddc9b3320b59f55fc19ab979b8da18819fb47a8036db0bba"
},
{
"path": "reviewer-server-result.json",
"original": ".local/authoring-prerelease-review-20260911/server-result.json",
"bytes": 128779,
"sha256": "086bf21e79f3bc7deddfd3278c8ade9b470b11031f7fb278ca0ead3a75b6cfb1"
},
{
"path": "reviewer.py",
"original": ".local/authoring-prerelease-review-20260911/review.py",
"bytes": 21434,
"sha256": "af9eb20946dfcec78bf8959f1d5dc175e82ebb9fabba9f94cefe590fea516b92"
},
{
"path": "gui-launch.json",
"original": ".local/authoring-prerelease-gui-20260911-v2/launch.json",
"bytes": 827,
"sha256": "ade93cb1abea623f1cc63b8124857cad822e4f75e8d1c389f75fd8a9089b2c39"
},
{
"path": "gui-loaded-modules.json",
"original": ".local/authoring-prerelease-gui-20260911-v2/loaded-modules.json",
"bytes": 3123,
"sha256": "ccae3d91310644e171bf35028f1c0758ef330ebb051983e0524b8cd714652b6b"
},
{
"path": "gui-post-save-exact.json",
"original": ".local/authoring-prerelease-gui-20260911-v2/post-save-package-exact.json",
"bytes": 133,
"sha256": "e340289a2c09058c539e63de33a361326b146fc181a8bd1349a88bfc813f2420"
},
{
"path": "upload-binaries-verified.json",
"original": ".local/authoring-prerelease-20260911/upload-binaries-verified.json",
"bytes": 685,
"sha256": "16799aa759e7287f4c50af1068d311f6f916f97e0cfbd7aaddf7432770d281f3"
},
{
"path": "gui-launch.py",
"original": ".local/authoring-prerelease-gui-20260911.py",
"bytes": 2001,
"sha256": "db256498e44cbb67cd84738a1a37f0e9ab0931d130a3b8c830af2c02cff0924c"
},
{
"path": "home.png",
"original": ".local/authoring-prerelease-gui-20260911-v2/home.png",
"bytes": 97695,
"sha256": "e9c24489e949096347b11234d8d2d343716fd5895903c4978d139107a70e3e5a"
},
{
"path": "oa-walkthrough-save.png",
"original": ".local/authoring-prerelease-gui-20260911-v2/oa-walkthrough-save.png",
"bytes": 131037,
"sha256": "61b2cbdd2dddb6fa176000198ae845554147cbc80abe52fa992211157f6297b5"
},
{
"path": "sa-walkthrough.png",
"original": ".local/authoring-prerelease-gui-20260911-v2/sa-walkthrough.png",
"bytes": 132180,
"sha256": "7f3a2bbed9fa69f9d5d844f9a52f81fbc3928244f49d7a9ff1e475c3f2411dbf"
},
{
"path": "state-workspace.png",
"original": ".local/authoring-prerelease-gui-20260911-v2/state-workspace.png",
"bytes": 135827,
"sha256": "79010527e5e1bb8ccf428788a00dea80e6d8253f3d7c249089218e2df9edd6da"
},
{
"path": "offline-guide.png",
"original": ".local/authoring-prerelease-gui-20260911-v2/offline-guide.png",
"bytes": 185496,
"sha256": "58812d2bd0d6e73daa5187f2dd87564189960387ac4bb1e399af4b8d114c05df"
},
{
"path": "published-verified.json",
"original": ".local/authoring-prerelease-20260911/published-verified.json",
"bytes": 374,
"sha256": "668f28c4d8cf753386085271eb181513b0127940f324f423a2b87614ec8cc85a"
},
{
"path": "upload-validation-verified.json",
"original": ".local/authoring-prerelease-20260911/upload-validation-verified.json",
"bytes": 277,
"sha256": "f39859baea544662fc4bdd1fe14dbcb9bdab5639b173754a34b58b853f0d47a7"
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

@@ -0,0 +1,10 @@
{
"source_identity": "Exact-byte reconstructed input snapshot 234e01e27d6935d213097b345d91d369f808af82, derived from release base 2ec72d4241fa8971fa6fe9f626937de9dfd7c7eb by seven documented LF-to-CRLF restorations and preservation attributes. All 253 GUI manifest inputs and 120 preserved server source files matched. This derived commit is not claimed as the original build commit; GUI and server original build records are retained separately.",
"profile": "Prebuilt Windows debug/development artifacts: GUI cargo build --locked -p oa-desktop --bin arcadia-studio, September 11 2026; preserved server from September 7 workspace bins build. Not a release-profile or reproducible-build claim.",
"compiler": "rustc 1.98.1, commit 48a229ceaefd4985c50990b14116b6d856af0985, x86_64-pc-windows-gnullvm, LLVM 22.1.8. Current rustc -vV, all 58 prior-notice target-library hashes and both embedded compiler paths matched; original recorded build evidence retained.",
"target": "x86_64-pc-windows-gnullvm",
"binary_sha256": {
"arcadia-studio.exe": "d4d9c2bd937e301ff1009d7cb93a34ee5aa6dfc837ff7e87d468c85371b20c31",
"arcadia-server.exe": "efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665"
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
{
"started": "2026-09-11T12:17:30.7730570Z",
"source_commit": "234e01e27d6935d213097b345d91d369f808af82",
"success": true,
"finished": "2026-09-11T12:21:23.0302800Z",
"elapsed_seconds": 232.2812442
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
{
"id": 1,
"tag": "v0.2.0-preview.authoring.20260911",
"url": "http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/releases/tag/v0.2.0-preview.authoring.20260911",
"draft": false,
"prerelease": true,
"asset_count": 3,
"notes_sha256": "e48399db78b18c6bd779412f7aeccf13fe78bf8c9bac22a4c418755acfab175c",
"published_at": "2026-09-11T12:40:51Z"
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,335 @@
"""Independent frozen archive and packaged-server checks; never runs Cargo or GUI."""
from pathlib import Path, PurePosixPath
import hashlib
import json
import os
import re
import socket
import stat
import struct
import subprocess
import sys
import tarfile
import time
import tomllib
import traceback
import urllib.request
import uuid
import zipfile
OUT = Path(__file__).resolve().parent
ROOT = OUT.parents[1]
PREP = ROOT / '.local/authoring-prerelease-20260911'
NAME = 'ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm'
ZIP = PREP / 'packages' / (NAME + '.zip')
EXTRACT = OUT / 'extracted'
PACKAGE = EXTRACT / NAME
SOURCE = PREP / 'source'
SOURCE_COMMIT = '234e01e27d6935d213097b345d91d369f808af82'
BASE_COMMIT = '2ec72d4241fa8971fa6fe9f626937de9dfd7c7eb'
EXPECTED_ZIP = '664f30b6217689aca1492eb263b3d15777067d732fa890eeb028f435209dadfa'
BINARIES = {
'arcadia-studio.exe': 'd4d9c2bd937e301ff1009d7cb93a34ee5aa6dfc837ff7e87d468c85371b20c31',
'arcadia-server.exe': 'efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665',
'libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4',
}
RESULT = {'checks': [], 'scope': sys.argv[1], 'started_utc': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
def check(condition, label):
if not condition:
raise AssertionError(label)
RESULT['checks'].append(label)
def sha(data):
return hashlib.sha256(data).hexdigest()
def read_json(path):
return json.loads(path.read_text(encoding='utf-8-sig'))
def write_json(path, value):
with path.open('x', encoding='utf-8', newline='\n') as f:
json.dump(value, f, indent=2, ensure_ascii=False)
f.write('\n')
def file_map(directory):
result = {}
for p in directory.rglob('*'):
check(not p.is_symlink() and not (getattr(p.lstat(), 'st_file_attributes', 0) & 0x400), 'ordinary path: ' + p.relative_to(directory).as_posix())
if p.is_file():
result[p.relative_to(directory).as_posix()] = sha(p.read_bytes())
return result
def safe_name(name):
p = PurePosixPath(name)
return not p.is_absolute() and p.as_posix() == name and '\\' not in name and ':' not in name and all(c not in ('', '.', '..') and not c.endswith(('.', ' ')) and not re.match(r'(?i)^(con|nul|prn|aux|com[1-9]|lpt[1-9])(\.|$)', c) for c in p.parts)
def git_blobs(ref, paths):
raw = subprocess.run(['git', 'cat-file', '--batch'], input=''.join(ref + ':' + p + '\n' for p in paths).encode(), cwd=ROOT, capture_output=True, check=True).stdout
result, cursor = {}, 0
for p in paths:
end = raw.index(b'\n', cursor)
header = raw[cursor:end].split()
check(len(header) == 3 and header[1] == b'blob', 'Git blob exists: ' + ref[:7] + ':' + p)
size = int(header[2])
result[p] = raw[end + 1:end + 1 + size]
cursor = end + 2 + size
check(cursor == len(raw), 'Git batch framing complete: ' + ref[:7])
return result
def artifact():
check(not EXTRACT.exists(), 'clean extraction destination absent')
check(ZIP.stat().st_size == 32618262 and sha(ZIP.read_bytes()) == EXPECTED_ZIP, 'frozen ZIP size and SHA256')
with zipfile.ZipFile(ZIP) as archive:
infos = archive.infolist()
names = [i.filename for i in infos]
check(len(infos) == 559, '559 ZIP members')
check(len({n.casefold() for n in names}) == len(names), 'no duplicate or case-colliding ZIP names')
check(all(safe_name(n) and n.startswith(NAME + '/') for n in names), 'one safe ZIP root without traversal or Windows special paths')
check(all(not i.is_dir() and stat.S_IFMT(i.external_attr >> 16) in (0, stat.S_IFREG) for i in infos), 'ordinary file-only ZIP entries')
check(all(i.date_time == (2000, 1, 1, 0, 0, 0) and i.flag_bits & 1 == 0 for i in infos), 'fixed timestamps and no encrypted entries')
check(archive.testzip() is None, 'all ZIP CRCs')
EXTRACT.mkdir()
archive.extractall(EXTRACT)
archive_hashes = {i.filename[len(NAME) + 1:]: sha(archive.read(i)) for i in infos}
actual = file_map(PACKAGE)
check(actual == archive_hashes, 'complete extracted file set and bytes equal ZIP')
sums = {}
for line in (PACKAGE / 'SHA256SUMS.txt').read_text().splitlines():
match = re.fullmatch(r'([0-9a-f]{64}) (.+)', line)
check(match is not None and safe_name(match[2]) and match[2] not in sums, 'well-formed unique checksum row')
sums[match[2]] = match[1]
check(sums == {p: h for p, h in actual.items() if p != 'SHA256SUMS.txt'}, 'checksum inventory covers every other file exactly')
package = read_json(PACKAGE / 'package.json')
inputs = package['input_sha256']
generated = {'SHA256SUMS.txt', 'START-HERE.txt', 'THIRD-PARTY-NOTICES.txt', 'dependency-notices.json', 'documentation-check.json', 'package.json'}
check(set(actual) - set(inputs) == generated and all(actual[p] == h.lower() for p, h in inputs.items()), '553 package input hashes plus exactly six generated files')
check(package['version'] == '0.2.0-preview.authoring.20260911' and package['target'] == 'x86_64-pc-windows-gnullvm', 'version and target')
check(all(actual[p] == h for p, h in BINARIES.items()), 'exact GUI, server and runtime hashes')
for p in BINARIES:
data = (PACKAGE / p).read_bytes()
offset = struct.unpack_from('<I', data, 0x3c)[0]
check(data[:2] == b'MZ' and data[offset:offset + 4] == b'PE\0\0' and struct.unpack_from('<H', data, offset + 4)[0] == 0x8664, 'ordinary PE x86_64: ' + p)
check({p for p in actual if '/' not in p} == {'arcadia-server.exe', 'arcadia-studio.exe', 'libunwind.dll', 'LICENSE', 'README.md'} | generated, 'only declared portable top-level files')
check({p.split('/')[0] for p in actual if '/' in p} == {'deployment', 'docs', 'examples', 'licenses'}, 'no harness, private profile, source checkout or credential-directory payload')
for p in actual:
if p.startswith(('docs/', 'examples/', 'deployment/')) or p == 'LICENSE':
check((SOURCE / p).is_file() and sha((SOURCE / p).read_bytes()) == actual[p], 'public source document/example bytes: ' + p)
RESULT['archive'] = {'path': str(ZIP), 'sha256': EXPECTED_ZIP, 'bytes': ZIP.stat().st_size, 'file_count': len(actual), 'files': actual}
RESULT['package_claims'] = {k: package[k] for k in ('version', 'target', 'acceptance', 'build', 'build_evidence')}
provenance()
notices(actual)
def provenance():
gui_path = ROOT / '.local/behavior-creation-20260911/gui-verified/manifest.json'
gui = read_json(gui_path)
expected = {i['path']: i['sha256'].lower() for i in gui['inputs']}
check(len(expected) == 253, 'original GUI manifest has 253 unique inputs')
derived = git_blobs(SOURCE_COMMIT, list(expected))
base = git_blobs(BASE_COMMIT, list(expected))
differences = []
for p, h in expected.items():
check(sha(derived[p]) == h == sha((SOURCE / p).read_bytes()), 'original GUI input equals derived Git blob and checkout: ' + p)
if sha(base[p]) != h:
check(sha(base[p].replace(b'\r\n', b'\n').replace(b'\n', b'\r\n')) == h, 'exact LF-to-CRLF-only restoration: ' + p)
differences.append(p)
check(set(differences) == {'docs/openapi.json'} | {'crates/oa-desktop/src/semantic_review/' + p + '.rs' for p in ('artifacts_view', 'attachments_view', 'keyed_rows', 'keyed_tests', 'keyed', 'ordered')}, 'exact seven documented CRLF restorations')
delta = subprocess.run(['git', 'diff', '--name-only', '--ignore-space-at-eol', BASE_COMMIT, SOURCE_COMMIT], cwd=ROOT, check=True, capture_output=True).stdout.decode().splitlines()
check(delta == ['.gitattributes'], 'derived commit changes only preservation attributes beyond EOL bytes')
origin = read_json(ROOT / 'harness/experiments/textual-authoring-20260911-local/provenance.json')
tar_path = ROOT / '.local/linux-qa/runtime/source7-20260907T082753190288Z.tar.gz'
check(sha(tar_path.read_bytes()) == 'cbb371a93a562e1e641d7629fe351e016d63e66fc9112499b3fed6d5cd171f78', 'original server source tar identity')
server_expected = {i['path']: i['snapshot_sha256'].lower() for i in origin['source_comparisons']}
check(len(server_expected) == 120, '120 independently recorded server source files')
server_base = git_blobs(BASE_COMMIT, list(server_expected))
tar_manifest = read_json(tar_path.with_suffix('').with_suffix('.tar.manifest.json'))
with tarfile.open(tar_path) as tar:
members = {m.name.removeprefix('./'): m for m in tar.getmembers() if m.isfile()}
for p, h in server_expected.items():
check(sha(tar.extractfile(members[p]).read()) == h == sha(server_base[p]) == sha((SOURCE / p).read_bytes()), 'server recorded tar equals base Git and staged input: ' + p)
shared = [p for p in members if p in ('Cargo.toml', 'Cargo.lock', 'docs/openapi.json') or p.startswith('build/')]
for p in shared:
check(sha(tar.extractfile(members[p]).read()) == expected[p] == tar_manifest['files'][p].lower(), 'original server/GUI shared manifest or build input: ' + p)
evidence = read_json(PACKAGE / 'package.json')['build_evidence']['evidence']
check(evidence['binary_sha256'] == {k: v for k, v in BINARIES.items() if k.endswith('.exe')}, 'packaged build evidence binds both exact executables')
check(SOURCE_COMMIT in evidence['source_identity'] and BASE_COMMIT in evidence['source_identity'], 'evidence identifies auxiliary and base sources distinctly')
check('not claimed as the original build commit' in evidence['source_identity'] and 'Not a release-profile or reproducible-build claim' in evidence['profile'], 'packaged provenance retains explicit limitations')
RESULT['provenance'] = {'gui_manifest_sha256': sha(gui_path.read_bytes()), 'gui_build_record': gui['build'], 'historical_gui_head': gui['head'], 'gui_inputs': 253, 'source_commit': SOURCE_COMMIT, 'base_commit': BASE_COMMIT, 'eol_restorations': differences, 'server_source_files': 120, 'shared_input_files': shared, 'tar_sha256': sha(tar_path.read_bytes())}
def notices(actual):
notice = read_json(PACKAGE / 'dependency-notices.json')
check(notice['root_packages'] == ['oa-desktop', 'oa-server'] and len(notice['packages']) == 266, '266 notice packages and exact desktop/server roots')
check(notice['cargo_lock_sha256'].lower() == sha((SOURCE / 'Cargo.lock').read_bytes()), 'notice lock equals exact historical source lock')
for p, h in notice['workspace_build_inputs_sha256'].items():
check(sha((SOURCE / p).read_bytes()) == h, 'notice common build input: ' + p)
lock = tomllib.loads((SOURCE / 'Cargo.lock').read_text())
locked = {(p['name'], p['version'], p.get('source')): p for p in lock['package']}
referenced = set()
def refs(items):
for i in items:
p = i['path']
check(safe_name(p) and p.startswith('licenses/') and actual.get(p) == i['sha256'].lower(), 'bundled exact notice reference: ' + p)
referenced.add(p)
fonts = []
for p in notice['packages']:
key = (p['name'], p['version'], p['source'])
check(key in locked and p['registry_checksum'] == locked[key].get('checksum'), 'notice identity/checksum occurs in historical lock: ' + p['name'] + '@' + p['version'])
check(len(p['notices']) > 0, 'package has notice text: ' + p['name'])
refs(p['notices'])
for f in p['embedded_fonts']:
check(len(f['notices']) > 0, 'embedded font notice present: ' + p['name'] + '/' + f['path'])
refs(f['notices'])
fonts.append({'package': p['name'], 'path': f['path'], 'sha256': f['sha256'], 'license': f['license']})
if p['source'] is None:
directory = SOURCE / 'crates' / p['name']
files = {f.relative_to(directory).as_posix(): sha(f.read_bytes()) for f in directory.rglob('*') if f.is_file() and 'target' not in f.relative_to(directory).parts and f.name != '.cargo-ok'}
check(files == p['local_source_sha256'], 'complete ordinary local-crate inventory: ' + p['name'])
refs(notice['rust']['notices'])
refs(notice['runtime']['notices'])
check(notice['runtime']['sha256'] == BINARIES['libunwind.dll'], 'runtime notice is bound to shipped DLL')
library_dir = ROOT / '.local/toolchain/rustup/toolchains/stable-x86_64-pc-windows-gnullvm/lib/rustlib/x86_64-pc-windows-gnullvm/lib'
check(len(notice['rust']['target_libraries_sha256']) == 58, '58 compiler target libraries recorded')
for name, h in notice['rust']['target_libraries_sha256'].items():
check(sha((library_dir / name).read_bytes()) == h, 'retained compiler target-library bytes: ' + name)
RESULT['notices'] = {'packages': len(notice['packages']), 'roots': notice['root_packages'], 'lock_sha256': notice['cargo_lock_sha256'], 'notice_reference_files': len(referenced), 'additional_license_files': sorted({p for p in actual if p.startswith('licenses/')} - referenced), 'embedded_fonts': fonts, 'rust_version': notice['rust']['version'], 'runtime_provenance': notice['runtime']['provenance'], 'scope': notice['scope']}
def server():
prior = read_json(OUT / 'artifact-result.json')
check(prior['status'] == 'PASS' and file_map(PACKAGE) == prior['archive']['files'], 'previously verified extracted package is unchanged')
runtime = OUT / 'server-run'
runtime.mkdir()
data_dir = runtime / 'data'
temp = runtime / 'temp'
temp.mkdir()
windows = Path(os.environ['SystemRoot'])
env = {'SystemRoot': str(windows), 'WINDIR': str(windows), 'PATH': str(windows / 'System32') + ';' + str(windows), 'TEMP': str(temp), 'TMP': str(temp)}
exe = PACKAGE / 'arcadia-server.exe'
RESULT['environment'] = env
RESULT['processes'] = []
for arg in ('--version', '--help'):
output = subprocess.run([str(exe), arg], cwd=PACKAGE, env=env, capture_output=True, timeout=15, creationflags=subprocess.CREATE_NO_WINDOW)
(runtime / (arg[2:] + '.stdout')).write_bytes(output.stdout)
(runtime / (arg[2:] + '.stderr')).write_bytes(output.stderr)
check(output.returncode == 0 and not output.stderr, arg + ' succeeds under clean runtime PATH')
if arg == '--version':
check(output.stdout.decode().strip() == 'arcadia-server 0.2.0', 'server reports underlying application version 0.2.0')
check(not data_dir.exists(), 'help/version do not create explicit test data directory')
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
request_number = 0
def request(port, method, path, payload=None):
nonlocal request_number
request_number += 1
body = None if payload is None else json.dumps(payload, ensure_ascii=False).encode()
req = urllib.request.Request(f'http://127.0.0.1:{port}' + path, data=body, method=method, headers={} if body is None else {'Content-Type': 'application/json'})
with opener.open(req, timeout=10) as response:
raw = response.read()
meta = {'method': method, 'path': path, 'status': response.status, 'headers': dict(response.headers), 'body_sha256': sha(raw)}
prefix = runtime / f'http-{request_number:02d}'
prefix.with_suffix('.body').write_bytes(raw)
write_json(prefix.with_suffix('.json'), meta)
return meta, raw
def start(index):
with socket.socket() as s:
s.bind(('127.0.0.1', 0))
port = s.getsockname()[1]
out = (runtime / f'server-{index}.stdout').open('xb')
err = (runtime / f'server-{index}.stderr').open('xb')
args = [str(exe), '--bind', f'127.0.0.1:{port}', '--data-dir', str(data_dir)]
process = subprocess.Popen(args, cwd=PACKAGE, env=env, stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW)
out.close()
err.close()
RESULT['processes'].append({'pid': process.pid, 'port': port, 'arguments': args})
deadline = time.monotonic() + 15
while True:
if process.poll() is not None:
raise AssertionError('packaged server exited before listening')
try:
with socket.create_connection(('127.0.0.1', port), timeout=.2):
break
except OSError:
if time.monotonic() > deadline:
process.terminate()
process.wait(timeout=5)
raise AssertionError('packaged server did not listen within 15s')
time.sleep(.05)
return process, port
def stop(process):
process.terminate()
code = process.wait(timeout=10)
RESULT['processes'][-1]['exit_after_explicit_terminate'] = code
process = None
try:
process, port = start(1)
for path in ('/health', '/health/ready'):
meta, raw = request(port, 'GET', path)
check(meta['status'] == 200 and json.loads(raw) == {'status': 'ok'}, path + ' contract')
meta, raw = request(port, 'GET', '/api/v1/openapi.json')
check(meta['status'] == 200 and raw == (PACKAGE / 'docs/openapi.json').read_bytes(), 'served OpenAPI equals complete packaged source bytes')
name = 'Independent package persistence — 救助 20260911'
meta, raw = request(port, 'POST', '/api/v1/projects', {'name': name})
created = json.loads(raw)
check(meta['status'] == 201, 'one create returns 201')
resource = str(uuid.UUID(created['resource_id']))
model_id = str(uuid.UUID(created['model_id']))
expected_summary = {'resource_id': resource, 'revision': 1, 'model_id': model_id, 'schema_version': 7, 'name': name, 'elements': 0, 'relations': 0, 'migration': None}
check(created == expected_summary and resource != model_id, 'complete create summary with distinct fresh resource/model IDs')
etag = f'"p-{resource}-r1"'
headers = {k.lower(): v for k, v in meta['headers'].items()}
path = '/api/v1/projects/' + resource
check(headers.get('etag') == etag and headers.get('location') == path, 'create ETag and resource Location')
meta, raw = request(port, 'GET', path)
stored = json.loads(raw)
model = {'schema_version': 7, 'id': model_id, 'alias': 'mission', 'name': name, 'description': '', 'elements': {}, 'relations': {}, 'diagrams': {}, 'artifact_links': {}, 'traces': {}}
source = f'arcadia 7;\nproject mission {json.dumps(name, ensure_ascii=False)} id "{model_id}" {{\n description "";\n}}\n'
expected = {'resource_id': resource, 'revision': 1, 'model': model, 'source_project': {'entry': 'project.arcadia', 'files': {'project.arcadia': source}}}
check(meta['status'] == 200 and stored == expected, 'GET equals independently predicted complete Project and SourceBundle')
check({k.lower(): v for k, v in meta['headers'].items()}.get('etag') == etag, 'GET ETag equals created revision')
disk = data_dir / (resource + '.json')
disk_bytes = disk.read_bytes()
check(json.loads(disk_bytes) == expected, 'durable disk envelope equals complete expected GET')
check({p.name for p in data_dir.iterdir()} == {'.arcadia.lock', disk.name}, 'private store contains only one project and lock')
stop(process)
process = None
process, port = start(2)
meta, raw = request(port, 'GET', '/health/ready')
check(meta['status'] == 200 and json.loads(raw) == {'status': 'ok'}, 'restarted packaged server ready')
meta, raw = request(port, 'GET', path)
check(meta['status'] == 200 and json.loads(raw) == expected, 'restart retains exact complete Project and SourceBundle')
check({k.lower(): v for k, v in meta['headers'].items()}.get('etag') == etag and disk.read_bytes() == disk_bytes, 'restart retains revision, ETag and every durable envelope byte')
RESULT['persistence'] = {'resource_id': resource, 'model_id': model_id, 'revision': 1, 'etag': etag, 'disk_sha256': sha(disk_bytes), 'expected': expected, 'stop_kind': 'explicit process termination after acknowledged durable create; not a graceful-drain claim'}
finally:
if process is not None and process.poll() is None:
stop(process)
check(file_map(PACKAGE) == prior['archive']['files'], 'server execution leaves complete extracted package unchanged')
check(sha(ZIP.read_bytes()) == EXPECTED_ZIP, 'frozen ZIP unchanged after independent runtime checks')
if __name__ == '__main__':
result_path = OUT / (sys.argv[1] + '-result.json')
if result_path.exists():
raise SystemExit('Refusing to overwrite prior evidence: ' + str(result_path))
try:
{'artifact': artifact, 'server': server}[sys.argv[1]]()
RESULT['status'] = 'PASS'
except Exception as error:
RESULT['status'] = 'FAIL'
RESULT['error'] = repr(error)
RESULT['traceback'] = traceback.format_exc()
RESULT['finished_utc'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
RESULT['script_sha256'] = sha(Path(__file__).read_bytes())
write_json(result_path, RESULT)
print(json.dumps({k: RESULT[k] for k in ('scope', 'status', 'started_utc', 'finished_utc')}, indent=2))
print('checks:', len(RESULT['checks']))
if RESULT['status'] == 'FAIL':
print(RESULT['traceback'])
sys.exit(1)
Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

@@ -0,0 +1,18 @@
[
{
"id": 1,
"name": "ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm.zip",
"bytes": 32618262,
"sha256": "664f30b6217689aca1492eb263b3d15777067d732fa890eeb028f435209dadfa",
"url": "http://217.177.34.108:3000/attachments/48a283b7-5391-4677-9427-02a772e5e7e4",
"readback": "PASS"
},
{
"id": 2,
"name": "ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm.zip.sha256",
"bytes": 143,
"sha256": "ea553a85f35d2d48f229dd4cd00ac0c3d4a6e9dafa58273004b2c49d1279f856",
"url": "http://217.177.34.108:3000/attachments/08164a39-9292-4b2d-9856-c6ec41d9b8e2",
"readback": "PASS"
}
]
@@ -0,0 +1,10 @@
[
{
"id": 3,
"name": "VALIDATION.md",
"bytes": 29308,
"sha256": "c2a70be735c780d3e468d5f12643fb00be75673434211366739926536bbbe9b9",
"url": "http://217.177.34.108:3000/attachments/9ff53361-eedf-46a0-aa4e-34f11bb0f302",
"readback": "PASS"
}
]