Add reliable execution reporting and coordinated dashboard views

This commit is contained in:
aiagent
2026-10-19 04:29:33 -07:00
parent 547f62fa53
commit c2dfe311f7
41 changed files with 3867 additions and 107 deletions
+222
View File
@@ -0,0 +1,222 @@
"""Atomic worker receipts and execution versus acceptance state."""
import concurrent.futures
import http.client
import json
from pathlib import Path
import tempfile
import threading
import unittest
from unittest.mock import patch
from agent_control.store import Store, Invalid, Conflict
from agent_control.server import Server
def report(**changes):
data=dict(report_id='report-1',task_id='task',session_id='worker',stage='execution_completed',
current_progress='Implementation tested',summary='Execution finished',
evidence=['Synthetic tests passed'],version='v1')
data.update(changes)
return data
class ReportTests(unittest.TestCase):
def setUp(self):
self.tmp=tempfile.TemporaryDirectory()
self.path=Path(self.tmp.name)/'reports.sqlite3'
self.store=Store(self.path)
for sid in ['worker','other']:
self.store.session(dict(id=sid,name=sid))
self.store.task(dict(id='task',name='Work',session_id='worker',status='running'))
self.store.task(dict(id='other-task',name='Other',session_id='other'))
def tearDown(self):
self.tmp.cleanup()
def task(self):
return next(t for t in self.store.state()['tasks'] if t['id']=='task')
def test_execution_completion_is_waiting_not_business_completion(self):
result=self.store.task_report(report())
self.assertFalse(result['duplicate'])
task=result['task']
self.assertEqual(task['execution_status'],'completed')
self.assertEqual(task['status'],'waiting')
self.assertEqual(task['phase'],'integration')
self.assertEqual(task['current_progress'],'Implementation tested')
self.assertEqual(task['report_evidence'],['Synthetic tests passed'])
self.assertEqual(task['last_report_id'],'report-1')
self.assertEqual(self.store.task_reports('task')['reports'],[result['report']])
self.assertEqual(self.store.state()['attention']['items'],[])
def test_duplicate_persistent_receipt_returns_current_task_without_reapplying(self):
first=self.store.task_report(report())
self.store.task(dict(status='completed',phase='done',current_progress='Accepted'),'task')
second=Store(self.path).task_report(report(needs_attention=False))
self.assertTrue(second['duplicate'])
self.assertEqual(second['report'],first['report'])
self.assertEqual(second['task']['status'],'completed')
self.assertEqual(second['task']['current_progress'],'Accepted')
self.assertEqual(len(self.store.task_reports('task')['reports']),1)
with self.assertRaises(Conflict): self.store.task_report(report(summary='Different'))
with self.assertRaises(Conflict): self.store.task_report(report(task_id='other-task',session_id='other'))
def test_new_late_report_does_not_roll_back_integrated_or_accepted_task(self):
self.store.task_report(report())
for status in ['integrated','verified']:
self.store.task(dict(integration_status=status,current_progress='Validated',version='accepted'),'task')
before=self.task()
result=self.store.task_report(report(report_id='late-'+status,stage='progress',
current_progress='Old work',version='old'))
self.assertEqual(result['task']['integration_status'],status)
self.assertEqual(result['task']['current_progress'],'Validated')
self.assertEqual(result['task']['execution_status'],'completed')
self.assertEqual(result['task']['version'],'accepted')
self.assertEqual(result['task']['progress_updated'],before['progress_updated'])
self.store.task(dict(status='completed',phase='done'),'task')
result=self.store.task_report(report(report_id='late-failure',stage='failed'))
self.assertEqual(result['task']['status'],'completed')
self.assertEqual(result['task']['phase'],'done')
self.assertEqual(len(self.store.task_reports('task')['reports']),4)
def test_concurrent_completion_and_late_progress_preserve_waiting_but_new_blocker_applies(self):
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as pool:
bodies=[report()]+[report(report_id='progress-'+str(i),stage='progress',
current_progress='Older progress') for i in range(12)]
list(pool.map(self.store.task_report,bodies))
task=self.task()
self.assertEqual(task['execution_status'],'completed')
self.assertEqual(task['status'],'waiting')
self.assertEqual(task['phase'],'integration')
self.assertEqual(task['current_progress'],'Implementation tested')
progress_updated=task['progress_updated']
self.store.task_report(report(report_id='latest-arrival',stage='progress',
current_progress='Still old progress'))
task=self.task()
self.assertEqual(task['current_progress'],'Implementation tested')
self.assertEqual(task['progress_updated'],progress_updated)
self.assertEqual(len(self.store.task_reports('task')['reports']),14)
for stage in ['blocked','failed']:
task=self.store.task_report(report(report_id='new-'+stage,stage=stage,
current_progress='New issue discovered'))['task']
self.assertEqual(task['status'],stage)
self.assertEqual(task['execution_status'],stage)
self.assertEqual(task['current_progress'],'New issue discovered')
def test_blocked_failed_progress_and_server_managed_defaults(self):
self.assertEqual(self.task()['execution_status'],'pending')
self.assertIsNone(self.task()['last_report_id'])
for stage,expected in [('blocked','blocked'),('failed','failed'),('progress','running')]:
task=self.store.task_report(report(report_id=stage,stage=stage))['task']
self.assertEqual(task['execution_status'],expected)
self.assertEqual(task['status'],expected)
for field,value in [('execution_status','completed'),('last_report_id','fake'),
('last_report_at',123),('report_evidence',['fake'])]:
with self.assertRaises(Invalid): self.store.task({field:value},'task')
self.store.task(dict(id='manual',name='Manual',status='completed',phase='done'))
task=next(t for t in self.store.state()['tasks'] if t['id']=='manual')
self.assertEqual(task['execution_status'],'pending')
def test_identity_and_schema_reject_without_mutation(self):
before=self.task()
cases=[dict(session_id='other'),dict(session_id='missing'),dict(task_id='other-task'),
dict(stage='completed'),dict(current_progress=None),dict(current_progress='x'*1001),
dict(summary='x'*2001),dict(evidence=['x']*21),dict(evidence=['x'*1001]),
dict(evidence=[{}]),dict(version=None),dict(needs_attention=1),
dict(needs_attention=True,summary=''),dict(source='admin')]
for change in cases:
with self.subTest(change=change):
with self.assertRaises(Invalid): self.store.task_report(report(**change))
self.assertEqual(self.task(),before)
self.assertEqual(self.store.task_reports('task')['reports'],[])
def test_attention_only_on_explicit_true_and_same_task_item_updated(self):
first=self.store.task_report(report(needs_attention=True))
items=self.store.state()['attention']['items']
self.assertEqual(len(items),1)
aid=items[0]['id']
self.store.task_report(report(report_id='r2',stage='blocked',needs_attention=True,summary='Need review'))
items=self.store.state()['attention']['items']
self.assertEqual(len(items),1)
self.assertEqual(items[0]['id'],aid)
self.assertEqual(items[0]['reason'],'Need review')
self.store.attention(dict(id=aid,page='tasks',required=False,reason=''))
self.store.task_report(report(needs_attention=True))
self.assertEqual(self.store.state()['attention']['items'],[])
self.assertEqual(self.store.hook_notifications()['pending_count'],0)
self.assertEqual(self.store.decision_notifications()['pending_count'],0)
def test_failure_rolls_back_task_and_report_and_attention(self):
before=self.task()
with self.store.db() as db:
db.execute("CREATE TRIGGER fail_report_attention BEFORE INSERT ON attention_history BEGIN SELECT RAISE(ABORT,'synthetic'); END")
with self.assertRaises(Exception): self.store.task_report(report(needs_attention=True))
self.assertEqual(self.task(),before)
self.assertEqual(self.store.task_reports('task')['reports'],[])
self.assertEqual(self.store.state()['attention']['items'],[])
def test_concurrent_receipt_only_one_record(self):
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as pool:
results=list(pool.map(lambda _:self.store.task_report(report()),range(12)))
self.assertEqual(sum(not r['duplicate'] for r in results),1)
self.assertEqual(len(self.store.task_reports('task')['reports']),1)
def test_recent_reports_are_bounded_and_task_scoped(self):
for i in range(53):
self.store.task_report(report(report_id='r-'+str(i),stage='progress'))
self.store.task_report(report(report_id='other',task_id='other-task',session_id='other'))
rows=self.store.task_reports('task')['reports']
self.assertEqual(len(rows),50)
self.assertEqual(rows[0]['report_id'],'r-52')
self.assertTrue(all(row['task_id']=='task' for row in rows))
self.assertEqual(len(self.store.task_reports('other-task')['reports']),1)
with self.assertRaises(Invalid): self.store.task_reports('missing')
class ReportHTTPTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
root = Path(self.tmp.name)
root.chmod(0o700)
token = root / 'token'
self.secret = 'h'*48
token.write_text(self.secret)
token.chmod(0o600)
self.metrics = patch('agent_control.server.MetricsCache')
mock = self.metrics.start()
mock.return_value.snapshot.return_value = {'status':'synthetic'}
self.server = Server(dict(bind='127.0.0.1',port=0,runtime_root=str(root),token_file=str(token)))
self.thread = threading.Thread(target=self.server.serve_forever, daemon=True)
self.thread.start()
def tearDown(self):
self.server.shutdown()
self.server.server_close()
self.thread.join()
self.metrics.stop()
self.tmp.cleanup()
def request(self,path,method='GET',payload=None,headers=None):
conn = http.client.HTTPConnection(*self.server.server_address,timeout=3)
merged = {'Authorization':'Bearer '+self.secret,'X-CSRF-Token':'1','Content-Type':'application/json'}
merged.update(headers or {})
conn.request(method,path,json.dumps(payload) if payload is not None else None,merged)
response = conn.getresponse()
status, body = response.status,json.loads(response.read())
conn.close()
return status, body
def test_security_query_and_roundtrip(self):
self.server.store.session(dict(id='worker',name='Worker'))
self.server.store.task(dict(id='task',name='Task',session_id='worker'))
path='/api/task-reports'
for headers,code in [({'Authorization':''},401),({'X-CSRF-Token':''},403),
({'Origin':'https://untrusted.example'},403)]:
self.assertEqual(self.request(path,'POST',report(),headers)[0],code)
self.assertEqual(self.request(path+'?task_id=task',headers={'Authorization':''})[0],401)
for query in ['', '?task_id=', '?task_id=task&task_id=other', '?session_id=worker']:
self.assertEqual(self.request(path+query)[0],400)
self.assertEqual(self.request(path,'POST',report())[0],200)
self.assertTrue(self.request(path,'POST',report())[1]['duplicate'])
self.assertEqual(self.request(path,'POST',report(summary='Changed'))[0],409)
self.assertEqual(len(self.request(path+'?task_id=task')[1]['reports']),1)