our_knp/cats-dogs/save_handoff.py
int 979aa90bb4 Add 2026-10-14 handoff materials, verify accelerated runs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:29:08 +03:00

133 lines
6.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Explicitly resume the user-requested backup and verified workstation transfer.
This script connects to the permanent test stand. Run only at the user's request.
Does not launch training, alter drivers, remove runs, or overwrite original KNP code.
"""
from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import subprocess
import sys
import tarfile
ROOT = Path(__file__).resolve().parent
STATE = ROOT / 'handoff-state'
HOST = 'int@10.9.8.230'
KEY = str(Path.home() / '.ssh/id_ed25519_snw')
SSH = ['ssh', '-i', KEY, '-o', 'IdentitiesOnly=yes', '-o', 'BatchMode=yes',
'-o', 'ConnectTimeout=10', '-o', 'ServerAliveInterval=15',
'-o', 'ServerAliveCountMax=2', HOST]
def manifest():
excluded = {'SHA256SUMS', 'preservation-manifest.json', 'preservation-status.json'}
rows = []
for path in sorted(ROOT.rglob('*')):
if not path.is_file() or '__pycache__' in path.parts or path.name.endswith('.part'):
continue
relative = path.relative_to(ROOT).as_posix()
if relative in excluded:
continue
digest = hashlib.sha256()
with path.open('rb') as stream:
for block in iter(lambda: stream.read(1024 * 1024), b''):
digest.update(block)
rows.append({'path': relative, 'bytes': path.stat().st_size, 'sha256': digest.hexdigest()})
(ROOT / 'preservation-manifest.json').write_text(json.dumps({'files': rows}, indent=2) + '\n')
(ROOT / 'SHA256SUMS').write_text(''.join(f"{r['sha256']} {r['path']}\n" for r in rows))
return len(rows)
def status(success, detail):
(ROOT / 'preservation-status.json').write_text(json.dumps({
'updated_utc': datetime.now(timezone.utc).isoformat(),
'remote_verified': success, 'detail': detail,
'destination': HOST + ':/mnt/c/KNP/cats-dogs',
}, ensure_ascii=False, indent=2) + '\n')
def capture(name, command):
result = subprocess.run(SSH + [command], capture_output=True, check=True)
(STATE / name).write_bytes(result.stdout)
def archive(name, command):
path = STATE / name
temporary = path.with_suffix(path.suffix + '.part')
try:
with temporary.open('wb') as output:
subprocess.run(SSH + [command], stdout=output, check=True)
with tarfile.open(temporary, 'r:gz') as saved:
for _ in saved:
pass
temporary.replace(path)
finally:
temporary.unlink(missing_ok=True)
def main():
STATE.mkdir(exist_ok=True)
if '--local-manifest-only' in sys.argv:
print('Local files hashed:', manifest())
return
status(False, 'Backup/transfer in progress; no success claimed yet')
try:
subprocess.run(SSH + ['true'], check=True)
commands = {
'remote-inventory.txt': 'date -u; uname -a; ls -la /mnt/c/KNP; ls -la /mnt/c/KNP/cats-dogs; find /home/int/run/cats-dogs -maxdepth 2 -type f; ps -eo pid,etime,args | grep -E "cats_dogs|http.server|nvcc|build_fast|build_tuned" | grep -v grep || true',
'original-knp-status.txt': 'git -C /mnt/c/KNP/examples rev-parse HEAD; git -C /mnt/c/KNP/examples status --short',
'original-knp-changes.patch': 'git -C /mnt/c/KNP/examples diff --binary',
'visualizer-status.txt': 'git -C /mnt/c/KNP/viz rev-parse HEAD; git -C /mnt/c/KNP/viz status --short',
'visualizer-changes.patch': 'git -C /mnt/c/KNP/viz diff --binary',
'compiler-flags.txt': 'cat /home/int/knp-build/knp/backends/cpu/cpu-single-threaded-backend/CMakeFiles/knp-cpu-single-threaded-backend.dir/flags.make /home/int/knp-build/knp/backends/cpu/cpu-single-threaded-backend/CMakeFiles/knp-cpu-single-threaded-backend.dir/link.txt; /usr/bin/c++ --version; /home/int/cuda-12.9/bin/nvcc --version; /usr/lib/wsl/lib/nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader',
}
for name, command in commands.items():
capture(name, command)
print('Captured state', flush=True)
# First deliver the existing local context, even if a later full backup fails.
manifest()
transport = 'ssh -i ' + KEY + ' -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=10'
def upload():
available = subprocess.run(SSH + ['command -v rsync'], capture_output=True)
if available.returncode == 0:
subprocess.run(['rsync', '-a', '--exclude=__pycache__', '--exclude=*.part',
'-e', transport, str(ROOT) + '/', HOST + ':/mnt/c/KNP/cats-dogs/'], check=True)
else:
pack = subprocess.Popen(['tar', '--exclude=__pycache__', '--exclude=*.part',
'-cf', '-', '-C', str(ROOT), '.'], stdout=subprocess.PIPE)
try:
subprocess.run(SSH + ['mkdir -p /mnt/c/KNP/cats-dogs && tar -xf - -C /mnt/c/KNP/cats-dogs'],
stdin=pack.stdout, check=True)
finally:
pack.stdout.close()
result = pack.wait()
if result:
raise RuntimeError(f'Upload tar exited {result}')
subprocess.run(SSH + ['cp /mnt/c/KNP/cats-dogs/HANDOFF.md /mnt/c/KNP/HANDOFF-2026-10-14.md && '
'cd /mnt/c/KNP/cats-dogs && sha256sum -c SHA256SUMS >/tmp/knp-handoff-check.log'], check=True)
upload()
print('Existing local context delivered and verified', flush=True)
archive('remote-runtime.tar.gz', 'tar -czf - -C /home/int/run cats-dogs')
archive('prior-context-and-source.tar.gz',
'tar -czf - -C / mnt/c/KNP/cats-dogs/source mnt/c/KNP/viz/altai_viz.html '
'mnt/c/KNP/viz/app.html mnt/c/KNP/Отчёт_MNIST_точность.md '
'mnt/c/KNP/Отчёт_altai.md mnt/c/KNP/Отчёт_колонки_altai.md '
'mnt/c/KNP/Отчёт_размер_колонки_и_одежда.md '
'home/int/.claude/projects/-mnt-c-knp/memory '
'home/int/.claude/projects/-mnt-c-KNP/memory')
print('Archives validated; local files hashed:', manifest(), flush=True)
upload()
status(True, 'Runtime/context archives validated, files transferred, remote SHA256SUMS passed')
subprocess.run(['scp', '-i', KEY, '-o', 'IdentitiesOnly=yes', '-o', 'BatchMode=yes',
'-o', 'ConnectTimeout=10', str(ROOT / 'preservation-status.json'),
HOST + ':/mnt/c/KNP/cats-dogs/preservation-status.json'], check=True)
print('Verified workstation copy: /mnt/c/KNP/HANDOFF-2026-10-14.md')
except Exception as error:
status(False, str(error))
manifest()
raise
if __name__ == '__main__':
main()