Animate equipment artwork and publish optimized motion release, agent=codex

This commit is contained in:
german
2026-09-28 17:28:09 +03:00
parent 741c7935b6
commit c9ed6ec8e3
28 changed files with 1605 additions and 38 deletions
+58 -3
View File
@@ -118,7 +118,7 @@ def audit():
sftp.close(); ssh.close()
def put_atomic(sftp, local, remote, replace=False):
def put_atomic(sftp, local, remote, replace=False, backup_dir=REMOTE_BACKUP):
mkdirs(sftp, posixpath.dirname(remote))
temp = remote + '.codex-upload-' + uuid.uuid4().hex[:10]
sftp.put(str(local), temp, confirm=True)
@@ -128,7 +128,9 @@ def put_atomic(sftp, local, remote, replace=False):
try:
sftp.posix_rename(temp, remote)
except OSError:
shifted = REMOTE_BACKUP + '/' + posixpath.basename(remote) + '.shifted'
relative = posixpath.relpath(remote, WEBROOT)
shifted = backup_dir + '/' + relative + '.shifted'
mkdirs(sftp, posixpath.dirname(shifted))
sftp.rename(remote, shifted)
try:
sftp.rename(temp, remote)
@@ -198,6 +200,58 @@ def verify():
sftp.close(); ssh.close()
def update_motion():
"""Publish the illustration motion release only after an exact live baseline check."""
previous = ROOT.parent / 'site-servaki-online-git' / 'public'
if not previous.is_dir():
raise RuntimeError('Previous Gitea release is required for the baseline check')
old = {p.relative_to(previous).as_posix(): digest(p.read_bytes())
for p in previous.rglob('*') if p.is_file()}
new = manifest()
removed = set(old) - set(new)
changed = {rel for rel in new if new[rel] != old.get(rel)}
html = {p.relative_to(ROOT / 'public').as_posix()
for p in (ROOT / 'public').rglob('*.html')}
allowed = html | {'assets/editorial/motion.css', 'assets/editorial/motion.js'}
if removed or changed != allowed:
raise RuntimeError(f'Unexpected release scope: removed={sorted(removed)}, changed={sorted(changed ^ allowed)}')
local_backup = ROOT / 'release-backups' / '2026-09-28-before-motion'
remote_backup = SITE + '/backup-2026-09-28-before-motion'
ssh, sftp = connect()
try:
for rel, expected in old.items():
target = WEBROOT + '/' + rel
if not exists(sftp, target) or digest(remote_bytes(sftp, target)) != expected:
raise RuntimeError('Published baseline changed; stopped before writing: ' + rel)
for rel in changed - set(old):
if exists(sftp, WEBROOT + '/' + rel):
raise RuntimeError('New motion asset already exists: ' + rel)
mkdirs(sftp, remote_backup)
for rel in sorted(changed & set(old)):
data = remote_bytes(sftp, WEBROOT + '/' + rel)
destination = local_backup / rel
destination.parent.mkdir(parents=True, exist_ok=True)
if destination.exists() and destination.read_bytes() != data:
raise RuntimeError('Local backup conflict: ' + rel)
destination.write_bytes(data)
remote_copy = remote_backup + '/' + rel
if exists(sftp, remote_copy):
if digest(remote_bytes(sftp, remote_copy)) != old[rel]:
raise RuntimeError('Remote backup conflict: ' + rel)
else:
put_atomic(sftp, destination, remote_copy)
for rel in sorted(changed, key=lambda item: (item == 'index.html', not item.startswith('assets/'), item)):
put_atomic(sftp, ROOT / 'public' / rel, WEBROOT + '/' + rel,
replace=rel in old, backup_dir=remote_backup)
for rel in changed:
if digest(remote_bytes(sftp, WEBROOT + '/' + rel)) != new[rel]:
raise RuntimeError('Published motion file failed checksum: ' + rel)
print('Published animation update; changed files:', len(changed),
'verified previous files:', len(old), 'backup:', remote_backup)
finally:
sftp.close(); ssh.close()
def reprice():
"""Replace only the published homepage after verifying the six price tokens."""
before = json.loads((BACKUP / 'deployed.json').read_text(encoding='utf-8'))
@@ -249,4 +303,5 @@ def reprice():
if __name__ == '__main__':
{'audit': audit, 'deploy': deploy, 'verify': verify, 'reprice': reprice}[sys.argv[1]]()
{'audit': audit, 'deploy': deploy, 'verify': verify,
'reprice': reprice, 'update-motion': update_motion}[sys.argv[1]]()