@@ -585,6 +585,56 @@ def _build_worker_prompt_contracts(plan_bundle: dict[str, Any], payload: dict[st
585585 return contracts
586586
587587
588+ def _build_unblock_tasks_from_worker_contracts (worker_contracts : list [dict [str , Any ]]) -> list [dict [str , Any ]]:
589+ tasks : list [dict [str , Any ]] = []
590+ for contract in worker_contracts :
591+ if not isinstance (contract , dict ):
592+ continue
593+ continuation_policy = contract .get ("continuation_policy" ) if isinstance (contract .get ("continuation_policy" ), dict ) else {}
594+ on_blocked = str (continuation_policy .get ("on_blocked" ) or "" ).strip ()
595+ if on_blocked != "spawn_independent_temporary_unblock_task" :
596+ continue
597+ assigned_agent = contract .get ("assigned_agent" ) if isinstance (contract .get ("assigned_agent" ), dict ) else {}
598+ blocked_when = contract .get ("blocked_when" ) if isinstance (contract .get ("blocked_when" ), list ) else []
599+ reason = next (
600+ (
601+ str (item ).strip ()
602+ for item in blocked_when
603+ if str (item ).strip () and (
604+ "external blocker" in str (item ).lower ()
605+ or "unblock task" in str (item ).lower ()
606+ )
607+ ),
608+ "an external blocker requires an L0-managed unblock task" ,
609+ )
610+ prompt_contract_id = str (contract .get ("prompt_contract_id" ) or "" ).strip () or "worker-preview-1"
611+ tasks .append (
612+ {
613+ "version" : "v1" ,
614+ "unblock_task_id" : f"unblock-{ prompt_contract_id } " ,
615+ "source_prompt_contract_id" : prompt_contract_id ,
616+ "objective" : f"Unblock the scoped worker assignment for { contract .get ('objective' ) or 'the current wave' } " ,
617+ "scope_hint" : str (contract .get ("scope" ) or "" ).strip () or "No scope summary provided." ,
618+ "assigned_agent" : {
619+ "role" : str (assigned_agent .get ("role" ) or "WORKER" ).strip () or "WORKER" ,
620+ "agent_id" : str (assigned_agent .get ("agent_id" ) or "agent-1" ).strip () or "agent-1" ,
621+ },
622+ "owner" : "L0" ,
623+ "mode" : "independent_temporary_task" ,
624+ "status" : "proposed" ,
625+ "trigger" : on_blocked ,
626+ "reason" : reason ,
627+ "verification_requirements" : [
628+ str (item ).strip ()
629+ for item in contract .get ("verification_requirements" , [])
630+ if str (item ).strip ()
631+ ]
632+ or ["repo_hygiene" ],
633+ }
634+ )
635+ return tasks
636+
637+
588638def _apply_intake_contract_overrides (
589639 contract : dict [str , Any ],
590640 intake_payload : dict [str , Any ],
@@ -1127,6 +1177,10 @@ def preview(self, payload: dict[str, Any]) -> dict[str, Any]:
11271177 assigned_role = str (assigned_agent .get ("role" ) or "WORKER" ).strip () or "WORKER"
11281178 predicted_reports = _predicted_reports_for_task_template (task_template )
11291179 predicted_artifacts = _predicted_artifacts_for_payload (normalized_payload )
1180+ worker_prompt_contracts = _build_worker_prompt_contracts (plan_bundle , normalized_payload )
1181+ unblock_tasks = _build_unblock_tasks_from_worker_contracts (worker_prompt_contracts )
1182+ if unblock_tasks and "planning_unblock_tasks.json" not in predicted_artifacts :
1183+ predicted_artifacts .append ("planning_unblock_tasks.json" )
11301184 warnings : list [str ] = []
11311185 if requires_human_approval :
11321186 warnings .append ("Current policies suggest the run may require manual approval before execution can continue." )
@@ -1171,13 +1225,16 @@ def preview(self, payload: dict[str, Any]) -> dict[str, Any]:
11711225 "plan_bundle" : plan_bundle ,
11721226 "task_chain" : task_chain ,
11731227 "wave_plan" : _build_wave_plan (plan_bundle ),
1174- "worker_prompt_contracts" : _build_worker_prompt_contracts (plan_bundle , normalized_payload ),
1228+ "worker_prompt_contracts" : worker_prompt_contracts ,
1229+ "unblock_tasks" : unblock_tasks ,
11751230 "role_contract_summary" : contract_preview .get ("role_contract" ) if isinstance (contract_preview .get ("role_contract" ), dict ) else {},
11761231 "contract_preview" : contract_preview ,
11771232 }
11781233 self ._validator .validate_report (response ["wave_plan" ], "wave_plan.v1.json" )
1179- for contract in response [ " worker_prompt_contracts" ] :
1234+ for contract in worker_prompt_contracts :
11801235 self ._validator .validate_report (contract , "worker_prompt_contract.v1.json" )
1236+ for unblock_task in unblock_tasks :
1237+ self ._validator .validate_report (unblock_task , "unblock_task.v1.json" )
11811238 self ._validator .validate_report (response , "execution_plan_report.v1.json" )
11821239 return response
11831240
0 commit comments