"""Quiescence evidence must distinguish process exit from unavailable identity.""" import os import hashlib import json import sqlite3 import subprocess from pathlib import Path import unittest from unittest.mock import patch SOURCE = Path(__file__).resolve().parents[1] / 'crates/supervisor/src/runner_files.py' class FileProcessProof(unittest.TestCase): def setUp(self): self.boot = '00000000-0000-0000-0000-000000000000:123' self.module = {'process_info': lambda pid: {'start': '456', 'state': 'S'}, 'boot_identity': lambda: self.boot} exec(compile(SOURCE.read_text(), str(SOURCE), 'exec'), self.module) self.reference = {'pid': os.getpid(), 'start': '456', 'boot': self.boot} def test_live_reused_and_unavailable_identity(self): finished = self.module['file_process_finished'] self.assertFalse(finished(self.reference)) self.assertTrue(finished({**self.reference, 'start': '455'})) self.assertIsNone(finished({**self.reference, 'boot': self.boot[:-3] + '999'})) self.assertIsNone(finished({**self.reference, 'boot': 'invalid'})) with patch.object(os, 'stat', side_effect=PermissionError()): self.assertIsNone(finished(self.reference)) with patch.object(os, 'stat', side_effect=FileNotFoundError()): self.assertTrue(finished(self.reference)) self.module['boot_identity'] = lambda: (_ for _ in ()).throw(FileNotFoundError()) self.assertIsNone(finished(self.reference), 'missing boot data is not proof of exit') def test_legacy_and_controller_only_evidence(self): quiescent = self.module['file_quiescent'] self.assertIsNone(quiescent({})) self.assertFalse(quiescent({'handoff_required': True, 'controller': self.reference})) self.assertFalse(quiescent({'handoff_required': True, 'controller': {**self.reference, 'start': '455'}, 'execution': self.reference})) self.assertTrue(quiescent({'handoff_required': True, 'execution': {**self.reference, 'start': '455'}})) def test_controller_exit_refreshes_child_committed_after_first_read(self): identity = {'computer_id': 'fixture', 'bot_id': 'race', 'generation': 1} encoded = self.module['file_identity'](identity) key = hashlib.sha256((encoded + ':operation').encode()).hexdigest() metadata = {'action': 'write', 'path': 'file', 'desiredHash': 'a' * 64, 'handoff_required': True, 'controller': {**self.reference, 'start': '455'}} with sqlite3.connect(':memory:') as db: self.module['file_journal_schema'](db) db.execute('INSERT INTO file_operations VALUES (?,?,?,?,NULL,?,?)', (key, encoded, 'digest', 'accepted', json.dumps(metadata), 0)) db.commit() def observe_process(pid): # The status SELECT already returned controller-only metadata; # the controller commits its child and dies before /proc is read. db.execute('UPDATE file_operations SET metadata=? WHERE id=?', (json.dumps({**metadata, 'execution': self.reference}), key)) db.commit() return {'start': '456', 'state': 'S'} self.module['process_info'] = observe_process fingerprint = subprocess.CompletedProcess([], 0, json.dumps({'path': 'file', 'kind': 'file', 'sha256': 'a' * 64}), '') with patch.object(subprocess, 'run', return_value=fingerprint): result = self.module['file_journal_handle'](db, { 'action': 'file_status', 'identity': identity, 'input': json.dumps({'operation_id': 'operation', 'readback': True, 'resolve': True}) }, '', lambda *_: False) evidence = json.loads(result['stdout']) self.assertEqual(result['status'], 'unknown') self.assertTrue(evidence['desired_state_matches']) self.assertFalse(evidence['helper_quiescent'], 'committed child is still alive') stored = json.loads(db.execute('SELECT observation FROM file_observations').fetchone()[0]) self.assertFalse(stored['helper_quiescent']) self.module['process_info'] = lambda pid: {'start': '456', 'state': 'S'} db.execute('UPDATE file_operations SET metadata=? WHERE id=?', (json.dumps({**metadata, 'controller': self.reference, 'execution': {**self.reference, 'start': '455'}}), key)) db.commit() with patch.object(subprocess, 'run', return_value=fingerprint): result = self.module['file_journal_handle'](db, { 'action': 'file_status', 'identity': identity, 'input': json.dumps({'operation_id': 'operation', 'readback': True, 'resolve': True}) }, '', lambda *_: False) self.assertEqual(result['status'], 'unknown', 'live controller can still commit its original receipt') self.assertFalse(json.loads(result['stdout'])['controller_quiescent']) if __name__ == '__main__': unittest.main()