Visualize version deliveries and task dependency branches

This commit is contained in:
aiagent
2026-10-19 21:58:17 -07:00
parent 9ae803de23
commit bf53f011c9
10 changed files with 275 additions and 15 deletions
+17 -4
View File
@@ -43,6 +43,7 @@ TASK_REPORT_DEFAULTS = {'execution_status':'pending','last_report_at':None,'last
TASK_RELATION_DEFAULTS = {
'kind':'work', 'delivery_id':None,
'goal':'', 'scope':'', 'coupling_assessment':'', 'owner':'', 'integration_owner':'', 'version':'',
'parent_id':None, 'merged_into_id':None, 'depends_on':[], 'parallel_with':[], 'merge_sources':[],
'parallel_scope':'', 'acceptance_criteria':[], 'sync_points':[], 'integration_status':'not_started'}
@@ -327,7 +328,7 @@ class Store:
def _task_defaults(record):
return {**{k:list(v) if isinstance(v,list) else v for k,v in TASK_RELATION_DEFAULTS.items()},
**ETA_DEFAULTS, **TASK_REPORT_DEFAULTS, 'report_evidence':[],
'current_progress':'', 'progress_updated':None, **record}
'current_progress':'', 'progress_updated':None, 'created_at':None, **record}
@staticmethod
@@ -350,7 +351,11 @@ class Store:
if not isinstance(record[field],str):
raise Invalid('invalid '+field)
string(record[field],field,limit,True)
for field in ('parent_id','merged_into_id'):
if record['kind'] not in ('work','delivery'):
raise Invalid('invalid task kind')
if record['kind']=='delivery' and record['delivery_id'] is not None:
raise Invalid('delivery cannot belong to another delivery')
for field in ('parent_id','merged_into_id','delivery_id'):
value = record[field]
if value is not None:
identifier(value,field)
@@ -385,6 +390,13 @@ class Store:
@staticmethod
def _validate_task_graphs(tasks):
for task_id,task in tasks.items():
delivery = task.get('delivery_id')
if delivery is not None:
if delivery==task_id or delivery not in tasks:
raise Invalid('invalid delivery reference')
if task.get('kind','work')=='delivery' or tasks[delivery].get('kind','work')!='delivery':
raise Conflict('delivery reference requires a delivery task')
graphs = [
{key:([value['parent_id']] if value.get('parent_id') else []) for key,value in tasks.items()},
{key:value.get('depends_on',[]) for key,value in tasks.items()},
@@ -567,7 +579,7 @@ class Store:
def task(self, data, key=None):
if key is not None and 'id' in data and data['id'] != key:
raise Invalid('task id differs from target')
if 'progress_updated' in data or (ETA_MANAGED | set(TASK_REPORT_DEFAULTS)) & set(data):
if 'created_at' in data or 'progress_updated' in data or (ETA_MANAGED | set(TASK_REPORT_DEFAULTS)) & set(data):
raise Invalid('server managed task field')
key = identifier(key or data.get('id') or secrets.token_hex(12))
rejected = False
@@ -578,7 +590,7 @@ class Store:
record = dict(old, **data)
record['id'] = key
allowed = {'id','name','session_id','status','phase','eta_min_minutes','eta_max_minutes',
'eta_basis','decision','updated','current_progress','progress_updated'} | set(ETA_DEFAULTS) | set(TASK_RELATION_DEFAULTS) | set(TASK_REPORT_DEFAULTS)
'eta_basis','decision','updated','current_progress','progress_updated','created_at'} | set(ETA_DEFAULTS) | set(TASK_RELATION_DEFAULTS) | set(TASK_REPORT_DEFAULTS)
if set(record) - allowed:
raise Invalid('unknown task field')
record['name'] = string(record.get('name'), 'name', 200)
@@ -600,6 +612,7 @@ class Store:
record['current_progress'] = string(progress,'current_progress',1000,True)
record, related = self._stage_task_relations(db,record,old,set(data))
now = time.time()
record['created_at'] = old.get('created_at') if row else now
rejected = self._eta_change(record,old,data,now)
if rejected:
record = self._task_defaults(old)