2026-08-15 19:30:02 +07:00
from __future__ import annotations
import hashlib
import json
import subprocess
from pathlib import Path
from typing import Any
from django . core . exceptions import ValidationError
from django . db import transaction
from django . utils import timezone
from control_plane . agents . models import ProgenySignal
from control_plane . events . bus import EventBus
from control_plane . projects . models import (
CommitRecord ,
Decision ,
ExtensionCandidate ,
ExtensionPlan ,
Exploration ,
ExplorationOpportunity ,
EvolutionCandidate ,
EvolutionPlan ,
Feature ,
Finding ,
Milestone ,
Project ,
ProjectPlan ,
RoadmapItem ,
StewardFinding ,
Task ,
TaskDependency ,
TaskStatus ,
)
from control_plane . verification . models import Review , TestRun , Verification , VerificationLevel , VerificationResult
from graph . langgraph_runtime import LangGraphRuntime
from graph . models import GraphRun
from graph . task_nodes import TaskExecutionServices , task_execution_registry
from model_router . router import ModelCapability , ModelRequestContract , ModelRouter
from project_brain . planning import ProjectPlanContract , parse_project_plan_response
class LifecyclePlanningError ( ValueError ) :
pass
class ProjectContextMixin :
def project_context ( self , project : Project ) - > dict [ str , object ] :
files : dict [ str , str ] = { }
tests : dict [ str , str ] = { }
if project . repository_path :
root = Path ( project . repository_path )
for path in sorted ( root . rglob ( " *.py " ) ) [ : 40 ] :
if any ( part in path . parts for part in [ " .git " , " __pycache__ " , " migrations " , " .venv " , " venv " , " node_modules " , " .pytest_cache " ] ) :
continue
relative = path . relative_to ( root ) . as_posix ( )
content = path . read_text ( encoding = " utf-8 " , errors = " ignore " ) [ : 3000 ]
if relative . startswith ( " tests " ) or " test " in path . name :
tests [ relative ] = content
else :
files [ relative ] = content
return {
" project " : { " id " : str ( project . id ) , " name " : project . name , " goal " : project . goal , " architecture_summary " : project . architecture_summary } ,
" decisions " : list ( project . decisions . order_by ( " -created_at " ) . values ( " decision_type " , " decision " , " reason " ) [ : 20 ] ) ,
" roadmap_items " : list ( project . roadmap_items . order_by ( " -created_at " ) . values ( " title " , " description " , " status " , " source " ) [ : 20 ] ) ,
" findings " : list ( project . findings . order_by ( " -created_at " ) . values ( " finding_type " , " severity " , " title " , " status " ) [ : 20 ] ) ,
" steward_findings " : list ( project . steward_findings . order_by ( " -created_at " ) . values ( " finding_type " , " severity " , " title " , " status " , " recommended_action " ) [ : 20 ] ) ,
" features " : list ( project . features . order_by ( " created_at " ) . values ( " title " , " description " , " status " , " acceptance_criteria " ) [ : 50 ] ) ,
" tasks " : list ( project . tasks . order_by ( " -created_at " ) . values ( " task_type " , " status " , " goal " , " acceptance_criteria " ) [ : 50 ] ) ,
" files " : files ,
" tests " : tests ,
}
def _json_from_sol ( self , router : ModelRouter | None , prompt : str , * , fallback : dict [ str , object ] , project : Project | None = None ) - > dict [ str , object ] :
if router is None :
return fallback
2026-08-16 15:35:55 +07:00
response = router . complete ( ModelRequestContract ( purpose = ModelCapability . PLANNING , prompt = prompt , project = project ) )
2026-08-15 19:30:02 +07:00
try :
payload = json . loads ( response . content )
except json . JSONDecodeError as exc :
raise LifecyclePlanningError ( " Sol lifecycle planning response must be JSON " ) from exc
if not isinstance ( payload , dict ) :
raise LifecyclePlanningError ( " Sol lifecycle planning response must be a JSON object " )
return payload
def _json_from_project_brain ( self , router : ModelRouter | None , prompt : str , * , fallback : dict [ str , object ] , project : Project , category : str ) - > dict [ str , object ] :
try :
return self . _json_from_sol ( router , prompt , fallback = fallback , project = project )
except Exception as exc :
create_project_planning_signal ( project , f " Sol { category } planning response invalid; using bounded fallback plan. " , { " error " : str ( exc ) , " category " : category } )
return fallback
class ExtensionService ( ProjectContextMixin ) :
def __init__ ( self , router : ModelRouter | None = None , bus : EventBus | None = None ) - > None :
self . router = router
self . bus = bus or EventBus ( )
def create_candidate (
self ,
project : Project ,
* ,
title : str ,
description : str ,
rationale : str = " " ,
source : str = " user " ,
expected_value : str = " " ,
affected_areas : list [ str ] | None = None ,
estimated_complexity : str = " MEDIUM " ,
risk : str = " MEDIUM " ,
confidence : float = 0.5 ,
evidence : dict [ str , object ] | None = None ,
source_steward_finding : StewardFinding | None = None ,
source_opportunity : ExplorationOpportunity | None = None ,
2026-08-15 19:46:07 +07:00
source_roadmap_item : RoadmapItem | None = None ,
2026-08-15 19:30:02 +07:00
) - > ExtensionCandidate :
return ExtensionCandidate . objects . create (
project = project ,
title = title ,
description = description ,
rationale = rationale ,
source = source ,
expected_value = expected_value ,
affected_areas = affected_areas or [ ] ,
estimated_complexity = estimated_complexity ,
risk = risk ,
confidence = confidence ,
evidence = evidence or { } ,
source_steward_finding = source_steward_finding ,
source_opportunity = source_opportunity ,
2026-08-15 19:46:07 +07:00
source_roadmap_item = source_roadmap_item ,
2026-08-15 19:30:02 +07:00
)
def plan_with_project_brain ( self , candidate : ExtensionCandidate ) - > ExtensionPlan :
context = self . project_context ( candidate . project )
fallback = self . _fallback_extension_plan ( candidate , context )
payload = self . _json_from_project_brain (
self . router ,
" Plan an EXTENSION for an existing project. Return JSON with extension_plan and project_plan. Do not treat this as greenfield. \n "
+ json . dumps ( { " candidate " : self . _candidate_payload ( candidate ) , " context " : context } , default = str ) ,
fallback = fallback ,
project = candidate . project ,
category = " extension " ,
)
raw_plan = payload . get ( " extension_plan " , payload )
if not isinstance ( raw_plan , dict ) :
raise LifecyclePlanningError ( " extension_plan must be an object " )
project_plan_payload = raw_plan . get ( " project_plan " ) or payload . get ( " project_plan " )
if not isinstance ( project_plan_payload , dict ) :
create_project_planning_signal ( candidate . project , " Sol extension plan omitted project_plan; using bounded fallback plan. " , { " candidate_id " : str ( candidate . id ) } )
raw_plan = dict ( fallback [ " extension_plan " ] )
project_plan_payload = dict ( raw_plan [ " project_plan " ] )
try :
parse_project_plan_response ( json . dumps ( project_plan_payload ) )
except Exception as exc :
create_project_planning_signal ( candidate . project , " Sol extension project_plan failed validation; using bounded fallback plan. " , { " candidate_id " : str ( candidate . id ) , " error " : str ( exc ) } )
raw_plan = dict ( fallback [ " extension_plan " ] )
project_plan_payload = dict ( raw_plan [ " project_plan " ] )
parse_project_plan_response ( json . dumps ( project_plan_payload ) )
plan = ExtensionPlan . objects . create (
candidate = candidate ,
project = candidate . project ,
status = " PLANNED " ,
strategy = str ( raw_plan . get ( " strategy " , candidate . description ) ) ,
plan = raw_plan ,
acceptance_criteria = [ str ( item ) for item in raw_plan . get ( " acceptance_criteria " , project_plan_payload . get ( " acceptance_criteria " , [ ] ) ) ] ,
context_snapshot = context ,
)
candidate . status = " PLANNING "
candidate . save ( update_fields = [ " status " , " updated_at " ] )
self . bus . publish ( " EXTENSION_PLAN_CREATED " , project = candidate . project , payload = { " candidate_id " : str ( candidate . id ) , " plan_id " : str ( plan . id ) } )
return plan
def approve_plan ( self , plan : ExtensionPlan ) - > ExtensionPlan :
plan . status = " APPROVED "
plan . approved_at = timezone . now ( )
plan . save ( update_fields = [ " status " , " approved_at " , " updated_at " ] )
plan . candidate . status = " READY "
plan . candidate . save ( update_fields = [ " status " , " updated_at " ] )
return plan
def materialize_project_dag ( self , plan : ExtensionPlan ) - > ProjectPlan :
if plan . project_plan_id :
return plan . project_plan
contract = parse_project_plan_response ( json . dumps ( plan . plan . get ( " project_plan " , { } ) ) )
project_plan = self . _materialize_contract ( plan . project , contract , prefix = f " EXT- { str ( plan . id ) [ : 8 ] } " )
plan . project_plan = project_plan
plan . status = " MATERIALIZED "
plan . save ( update_fields = [ " project_plan " , " status " , " updated_at " ] )
plan . candidate . status = " BUILDING "
plan . candidate . save ( update_fields = [ " status " , " updated_at " ] )
return project_plan
def execute ( self , plan : ExtensionPlan , router : ModelRouter , * , test_command : list [ str ] | None = None ) - > list [ GraphRun ] :
from graph . bootstrap import champion_task_execution_graph_v1
project_plan = self . materialize_project_dag ( plan )
runs : list [ GraphRun ] = [ ]
for task in Task . objects . filter ( milestone__plan = project_plan ) . exclude ( status = TaskStatus . COMPLETE ) . order_by ( " priority " , " created_at " ) :
graph_version = champion_task_execution_graph_v1 ( )
graph_run = GraphRun . objects . create ( execution_graph_version = graph_version , project = task . project , milestone = task . milestone , feature = task . feature , task = task , current_node = graph_version . graph_spec [ " entry " ] , metadata = { " extension_plan_id " : str ( plan . id ) , " extension_candidate_id " : str ( plan . candidate_id ) } )
LangGraphRuntime ( task_execution_registry ( TaskExecutionServices ( router , bus = self . bus , test_command = test_command or [ " python " , " -m " , " pytest " ] ) ) , bus = self . bus ) . run_until_terminal_or_paused ( graph_run )
for commit in task . commits . all ( ) :
commit . extension_candidate = plan . candidate
commit . save ( update_fields = [ " extension_candidate " , " updated_at " ] )
runs . append ( graph_run )
return runs
def verify_extension ( self , plan : ExtensionPlan ) - > Verification :
project_plan = plan . project_plan
tasks = Task . objects . filter ( milestone__plan = project_plan ) if project_plan else Task . objects . none ( )
task_count = tasks . count ( )
completed = task_count > 0 and not tasks . exclude ( status = TaskStatus . COMPLETE ) . exists ( )
tests_pass = not TestRun . objects . filter ( task__in = tasks ) . exclude ( status = " PASS " ) . exists ( )
review_failures = Review . objects . filter ( task__in = tasks ) . exclude ( status = " PASS " )
judge_failures = Verification . objects . filter ( task__in = tasks , level = VerificationLevel . TASK ) . exclude ( result = VerificationResult . PASS )
criteria = plan . acceptance_criteria or plan . plan . get ( " acceptance_criteria " , [ ] )
criteria_present = bool ( criteria )
passed = completed and tests_pass and not review_failures . exists ( ) and not judge_failures . exists ( ) and criteria_present
verification = Verification . objects . create (
project = plan . project ,
milestone = tasks . first ( ) . milestone if tasks . exists ( ) else None ,
level = VerificationLevel . MILESTONE ,
result = VerificationResult . PASS if passed else VerificationResult . FAIL ,
contract = { " extension_plan_id " : str ( plan . id ) , " acceptance_criteria " : criteria } ,
evidence = [ { " task_count " : task_count , " all_tasks_complete " : completed , " tests_pass " : tests_pass , " review_failures " : review_failures . count ( ) , " judge_failures " : judge_failures . count ( ) } ] ,
summary = " Extension acceptance contract satisfied " if passed else " Extension acceptance contract failed " ,
)
plan . verification = verification
plan . status = " COMPLETE " if passed else " FAILED "
plan . completed_at = timezone . now ( )
plan . save ( update_fields = [ " verification " , " status " , " completed_at " , " updated_at " ] )
plan . candidate . status = " COMPLETE " if passed else " BUILDING "
plan . candidate . save ( update_fields = [ " status " , " updated_at " ] )
return verification
def _fallback_extension_plan ( self , candidate : ExtensionCandidate , context : dict [ str , object ] ) - > dict [ str , object ] :
task_goal = candidate . metadata . get ( " task_goal " ) or candidate . description or candidate . title
acceptance = candidate . metadata . get ( " acceptance_criteria " ) or [ f " { candidate . title } capability is present " , " Deterministic tests pass " ]
return {
" extension_plan " : {
" strategy " : f " Add bounded scope to existing project: { candidate . title } " ,
" acceptance_criteria " : acceptance ,
" project_plan " : {
" goal " : candidate . project . goal ,
" scope " : candidate . description ,
" acceptance_criteria " : acceptance ,
" milestones " : [
{
" key " : " EXTEND " ,
" title " : candidate . title ,
" goal " : candidate . description or candidate . title ,
" verification_contract " : { " extension_candidate_id " : str ( candidate . id ) } ,
" features " : [ { " key " : " F1 " , " title " : candidate . title , " description " : candidate . description , " acceptance_criteria " : acceptance , " tasks " : [ { " id " : " T1 " , " goal " : str ( task_goal ) , " type " : " implementation " , " acceptance_criteria " : acceptance , " priority " : 50 , " dependencies " : [ ] } ] } ] ,
}
] ,
} ,
}
}
def _candidate_payload ( self , candidate : ExtensionCandidate ) - > dict [ str , object ] :
return { " id " : str ( candidate . id ) , " title " : candidate . title , " description " : candidate . description , " rationale " : candidate . rationale , " expected_value " : candidate . expected_value , " affected_areas " : candidate . affected_areas , " evidence " : candidate . evidence }
def _materialize_contract ( self , project : Project , contract : ProjectPlanContract , * , prefix : str ) - > ProjectPlan :
with transaction . atomic ( ) :
version = project . current_plan_version + 1
project_plan = ProjectPlan . objects . create ( project = project , version = version , goal = project . goal , scope = contract . scope , stack = contract . stack , architecture = contract . architecture , constraints = contract . constraints , acceptance_criteria = contract . acceptance_criteria , permissions = contract . permissions , budget = contract . budget , open_decisions = contract . open_decisions , approved_at = timezone . now ( ) )
project . current_plan_version = version
project . save ( update_fields = [ " current_plan_version " , " updated_at " ] )
task_by_external_id : dict [ str , Task ] = { }
dependency_specs : list [ tuple [ Task , list [ str ] ] ] = [ ]
for order , milestone_contract in enumerate ( contract . milestones ) :
milestone = Milestone . objects . create ( project = project , plan = project_plan , key = f " { prefix } - { milestone_contract . key } " [ : 50 ] , title = milestone_contract . title , goal = milestone_contract . goal , verification_contract = milestone_contract . verification_contract , order = order )
for feature_contract in milestone_contract . features :
feature = Feature . objects . create ( project = project , milestone = milestone , title = feature_contract . title , description = feature_contract . description , acceptance_criteria = feature_contract . acceptance_criteria )
for task_contract in feature_contract . tasks :
task = Task . objects . create ( project = project , milestone = milestone , feature = feature , task_type = task_contract . task_type , status = TaskStatus . READY , priority = task_contract . priority , goal = task_contract . goal , acceptance_criteria = task_contract . acceptance_criteria )
task_by_external_id [ task_contract . task_id ] = task
dependency_specs . append ( ( task , task_contract . dependencies ) )
for task , deps in dependency_specs :
for dep in deps :
TaskDependency . objects . create ( task = task , depends_on = task_by_external_id [ dep ] )
return project_plan
class EvolutionService ( ProjectContextMixin ) :
def __init__ ( self , router : ModelRouter | None = None , bus : EventBus | None = None ) - > None :
self . router = router
self . bus = bus or EventBus ( )
2026-08-15 19:46:07 +07:00
def create_candidate ( self , project : Project , * , target : str , objective : str , baseline_measurement : dict [ str , object ] , desired_direction : str , target_measurement : dict [ str , object ] | None = None , rationale : str = " " , source : str = " user " , evidence : dict [ str , object ] | None = None , risk : str = " MEDIUM " , confidence : float = 0.5 , source_steward_finding : StewardFinding | None = None , source_opportunity : ExplorationOpportunity | None = None , source_roadmap_item : RoadmapItem | None = None ) - > EvolutionCandidate :
2026-08-15 19:30:02 +07:00
if not baseline_measurement :
raise ValidationError ( " EVOLVE requires a measurable baseline; route to INVESTIGATE or EXPLORE instead. " )
2026-08-15 19:46:07 +07:00
return EvolutionCandidate . objects . create ( project = project , target = target , objective = objective , baseline_measurement = baseline_measurement , desired_direction = desired_direction , target_measurement = target_measurement or { } , rationale = rationale , source = source , evidence = evidence or { } , risk = risk , confidence = confidence , source_steward_finding = source_steward_finding , source_opportunity = source_opportunity , source_roadmap_item = source_roadmap_item )
2026-08-15 19:30:02 +07:00
def plan_with_project_brain ( self , candidate : EvolutionCandidate ) - > EvolutionPlan :
if not candidate . baseline_measurement :
raise ValidationError ( " EvolutionCandidate has no baseline measurement. " )
context = self . project_context ( candidate . project )
fallback = self . _fallback_evolution_plan ( candidate )
payload = self . _json_from_project_brain ( self . router , " Plan an EVOLUTION for an existing project. Return JSON with evolution_plan and project_plan. Must preserve measurable baseline and threshold. \n " + json . dumps ( { " candidate " : self . _candidate_payload ( candidate ) , " context " : context } , default = str ) , fallback = fallback , project = candidate . project , category = " evolution " )
raw_plan = payload . get ( " evolution_plan " , payload )
if not isinstance ( raw_plan , dict ) :
raise LifecyclePlanningError ( " evolution_plan must be an object " )
project_plan_payload = raw_plan . get ( " project_plan " ) or payload . get ( " project_plan " )
if not isinstance ( project_plan_payload , dict ) :
create_project_planning_signal ( candidate . project , " Sol evolution plan omitted project_plan; using bounded fallback plan. " , { " candidate_id " : str ( candidate . id ) } )
raw_plan = dict ( fallback [ " evolution_plan " ] )
project_plan_payload = dict ( raw_plan [ " project_plan " ] )
try :
parse_project_plan_response ( json . dumps ( project_plan_payload ) )
except Exception as exc :
create_project_planning_signal ( candidate . project , " Sol evolution project_plan failed validation; using bounded fallback plan. " , { " candidate_id " : str ( candidate . id ) , " error " : str ( exc ) } )
raw_plan = dict ( fallback [ " evolution_plan " ] )
project_plan_payload = dict ( raw_plan [ " project_plan " ] )
parse_project_plan_response ( json . dumps ( project_plan_payload ) )
plan = EvolutionPlan . objects . create ( candidate = candidate , project = candidate . project , status = " PLANNED " , baseline = dict ( raw_plan . get ( " baseline " , candidate . baseline_measurement ) ) , hypothesis = str ( raw_plan . get ( " hypothesis " , candidate . objective ) ) , intervention = str ( raw_plan . get ( " intervention " , " Implement targeted project improvement " ) ) , measurement_method = dict ( raw_plan . get ( " measurement_method " , { " type " : " metadata " } ) ) , success_threshold = dict ( raw_plan . get ( " success_threshold " , { " minimum_improvement_percent " : 10 } ) ) , regression_constraints = list ( raw_plan . get ( " regression_constraints " , [ " Deterministic tests pass " ] ) ) , affected_components = list ( raw_plan . get ( " affected_components " , [ candidate . target ] ) ) , task_plan = project_plan_payload , experiment_requirements = dict ( raw_plan . get ( " experiment_requirements " , { } ) ) , context_snapshot = context )
candidate . status = " PLANNING "
candidate . save ( update_fields = [ " status " , " updated_at " ] )
return plan
def approve_plan ( self , plan : EvolutionPlan ) - > EvolutionPlan :
plan . status = " APPROVED "
plan . approved_at = timezone . now ( )
plan . save ( update_fields = [ " status " , " approved_at " , " updated_at " ] )
plan . candidate . status = " READY "
plan . candidate . save ( update_fields = [ " status " , " updated_at " ] )
return plan
def materialize_work ( self , plan : EvolutionPlan ) - > ProjectPlan :
if plan . project_plan_id :
return plan . project_plan
contract = parse_project_plan_response ( json . dumps ( plan . task_plan ) )
project_plan = ExtensionService ( bus = self . bus ) . _materialize_contract ( plan . project , contract , prefix = f " EVO- { str ( plan . id ) [ : 8 ] } " )
plan . project_plan = project_plan
plan . status = " MATERIALIZED "
plan . save ( update_fields = [ " project_plan " , " status " , " updated_at " ] )
plan . candidate . status = " BUILDING "
plan . candidate . save ( update_fields = [ " status " , " updated_at " ] )
return project_plan
def execute ( self , plan : EvolutionPlan , router : ModelRouter , * , test_command : list [ str ] | None = None ) - > list [ GraphRun ] :
from graph . bootstrap import champion_task_execution_graph_v1
project_plan = self . materialize_work ( plan )
runs : list [ GraphRun ] = [ ]
for task in Task . objects . filter ( milestone__plan = project_plan ) . exclude ( status = TaskStatus . COMPLETE ) . order_by ( " priority " , " created_at " ) :
graph_version = champion_task_execution_graph_v1 ( )
graph_run = GraphRun . objects . create ( execution_graph_version = graph_version , project = task . project , milestone = task . milestone , feature = task . feature , task = task , current_node = graph_version . graph_spec [ " entry " ] , metadata = { " evolution_plan_id " : str ( plan . id ) , " evolution_candidate_id " : str ( plan . candidate_id ) } )
LangGraphRuntime ( task_execution_registry ( TaskExecutionServices ( router , bus = self . bus , test_command = test_command or [ " python " , " -m " , " pytest " ] ) ) , bus = self . bus ) . run_until_terminal_or_paused ( graph_run )
for commit in task . commits . all ( ) :
commit . evolution_candidate = plan . candidate
commit . save ( update_fields = [ " evolution_candidate " , " updated_at " ] )
runs . append ( graph_run )
return runs
def measure_candidate ( self , plan : EvolutionPlan ) - > dict [ str , object ] :
method = plan . measurement_method or { }
if " candidate_measurement " in plan . metadata :
measurement = dict ( plan . metadata [ " candidate_measurement " ] )
elif method . get ( " type " ) == " command " and plan . project . repository_path :
completed = subprocess . run ( [ str ( part ) for part in method . get ( " command " , [ ] ) ] , cwd = plan . project . repository_path , capture_output = True , text = True , check = False , timeout = 120 )
measurement = { " returncode " : completed . returncode , " stdout " : completed . stdout [ - 4000 : ] , " stderr " : completed . stderr [ - 2000 : ] }
else :
measurement = dict ( plan . candidate . target_measurement or plan . baseline )
plan . candidate_measurement = measurement
plan . save ( update_fields = [ " candidate_measurement " , " updated_at " ] )
return measurement
def compare_baseline ( self , plan : EvolutionPlan ) - > dict [ str , object ] :
metric = str ( plan . success_threshold . get ( " metric " , plan . baseline . get ( " metric " , " value " ) ) )
baseline_value = float ( plan . baseline . get ( metric , plan . baseline . get ( " value " , 0 ) ) or 0 )
candidate_value = float ( plan . candidate_measurement . get ( metric , plan . candidate_measurement . get ( " value " , baseline_value ) ) or 0 )
direction = plan . candidate . desired_direction
if baseline_value == 0 :
improvement_percent = 0.0
elif direction == " DECREASE " :
improvement_percent = ( ( baseline_value - candidate_value ) / baseline_value ) * 100
else :
improvement_percent = ( ( candidate_value - baseline_value ) / baseline_value ) * 100
threshold = float ( plan . success_threshold . get ( " minimum_improvement_percent " , 0 ) )
delta = { " metric " : metric , " baseline " : baseline_value , " candidate " : candidate_value , " improvement_percent " : improvement_percent , " threshold " : threshold }
plan . delta = delta
plan . save ( update_fields = [ " delta " , " updated_at " ] )
return delta
def judge_evolution ( self , plan : EvolutionPlan ) - > Verification :
if not plan . candidate_measurement :
self . measure_candidate ( plan )
delta = self . compare_baseline ( plan )
project_plan = plan . project_plan
tasks = Task . objects . filter ( milestone__plan = project_plan ) if project_plan else Task . objects . none ( )
tests_pass = not TestRun . objects . filter ( task__in = tasks ) . exclude ( status = " PASS " ) . exists ( )
implementation_complete = not tasks . exclude ( status = TaskStatus . COMPLETE ) . exists ( ) if tasks . exists ( ) else True
improved = float ( delta [ " improvement_percent " ] ) > = float ( delta [ " threshold " ] )
verdict = " PASS " if implementation_complete and tests_pass and improved else " NOT_IMPROVED "
verification = Verification . objects . create ( project = plan . project , milestone = tasks . first ( ) . milestone if tasks . exists ( ) else None , level = VerificationLevel . MILESTONE , result = VerificationResult . PASS if verdict == " PASS " else VerificationResult . FAIL , contract = { " evolution_plan_id " : str ( plan . id ) , " success_threshold " : plan . success_threshold , " regression_constraints " : plan . regression_constraints } , evidence = [ { " implementation_complete " : implementation_complete , " tests_pass " : tests_pass , " delta " : delta , " verdict " : verdict } ] , summary = " Evolution objective improved " if verdict == " PASS " else " Evolution implementation did not improve objective " )
plan . verification = verification
plan . verdict = verdict
plan . status = " COMPLETE " if verdict == " PASS " else " NOT_IMPROVED "
plan . completed_at = timezone . now ( )
plan . save ( update_fields = [ " verification " , " verdict " , " status " , " completed_at " , " updated_at " ] )
plan . candidate . status = " COMPLETE " if verdict == " PASS " else " PROPOSED "
plan . candidate . save ( update_fields = [ " status " , " updated_at " ] )
return verification
def _fallback_evolution_plan ( self , candidate : EvolutionCandidate ) - > dict [ str , object ] :
acceptance = [ " Deterministic tests pass " , f " Objective improves: { candidate . objective } " ]
task_goal = candidate . metadata . get ( " task_goal " ) or f " Improve { candidate . target } : { candidate . objective } "
return { " evolution_plan " : { " baseline " : candidate . baseline_measurement , " hypothesis " : candidate . objective , " intervention " : str ( task_goal ) , " measurement_method " : { " type " : " metadata " } , " success_threshold " : { " metric " : candidate . baseline_measurement . get ( " metric " , " value " ) , " minimum_improvement_percent " : 10 } , " regression_constraints " : [ " Deterministic tests pass " ] , " affected_components " : [ candidate . target ] , " project_plan " : { " goal " : candidate . project . goal , " scope " : candidate . objective , " acceptance_criteria " : acceptance , " milestones " : [ { " key " : " EVOLVE " , " title " : candidate . target , " goal " : candidate . objective , " verification_contract " : { " evolution_candidate_id " : str ( candidate . id ) } , " features " : [ { " key " : " F1 " , " title " : candidate . target , " description " : candidate . objective , " acceptance_criteria " : acceptance , " tasks " : [ { " id " : " T1 " , " goal " : str ( task_goal ) , " type " : " implementation " , " acceptance_criteria " : acceptance , " priority " : 50 , " dependencies " : [ ] } ] } ] } ] } } }
def _candidate_payload ( self , candidate : EvolutionCandidate ) - > dict [ str , object ] :
return { " id " : str ( candidate . id ) , " target " : candidate . target , " objective " : candidate . objective , " baseline_measurement " : candidate . baseline_measurement , " desired_direction " : candidate . desired_direction , " target_measurement " : candidate . target_measurement , " evidence " : candidate . evidence }
class ExplorerService ( ProjectContextMixin ) :
def __init__ ( self , router : ModelRouter | None = None , bus : EventBus | None = None ) - > None :
self . router = router
self . bus = bus or EventBus ( )
def start_exploration ( self , project : Project , * , prompt : str = " " ) - > Exploration :
exploration = Exploration . objects . create ( project = project , prompt = prompt , context_snapshot = self . project_context ( project ) )
return exploration
def generate_opportunities ( self , exploration : Exploration ) - > list [ ExplorationOpportunity ] :
fallback = { " opportunities " : self . _fallback_opportunities ( exploration ) }
payload = self . _json_from_project_brain ( self . router , " Explore an existing project for valuable changes. Return JSON opportunities only; do not create build work. \n " + json . dumps ( exploration . context_snapshot , default = str ) , fallback = fallback , project = exploration . project , category = " exploration " )
raw_items = payload . get ( " opportunities " , [ ] )
if not isinstance ( raw_items , list ) :
raise LifecyclePlanningError ( " Explorer response opportunities must be a list " )
opportunities : list [ ExplorationOpportunity ] = [ ]
for raw in raw_items :
if not isinstance ( raw , dict ) :
continue
opportunity = self . upsert_opportunity ( exploration , raw )
opportunities . append ( opportunity )
exploration . status = " COMPLETE "
exploration . completed_at = timezone . now ( )
exploration . save ( update_fields = [ " status " , " completed_at " , " updated_at " ] )
return sorted ( opportunities , key = lambda item : item . composite_score , reverse = True )
def upsert_opportunity ( self , exploration : Exploration , raw : dict [ str , object ] ) - > ExplorationOpportunity :
title = str ( raw . get ( " title " , " Untitled opportunity " ) )
grouping_key = self . _grouping_key ( exploration . project , title , str ( raw . get ( " opportunity_type " , " FEATURE " ) ) )
existing = self . _known_duplicate ( exploration . project , grouping_key , title )
scores = self . score ( raw )
raw_evidence = raw . get ( " evidence " , { } )
evidence = raw_evidence if isinstance ( raw_evidence , dict ) else { " raw " : raw_evidence }
if existing is not None :
existing . metadata = { * * existing . metadata , " rediscovered_by " : str ( exploration . id ) }
existing . save ( update_fields = [ " metadata " , " updated_at " ] )
return existing
return ExplorationOpportunity . objects . create ( exploration = exploration , project = exploration . project , title = title , description = str ( raw . get ( " description " , " " ) ) , opportunity_type = str ( raw . get ( " opportunity_type " , " FEATURE " ) ) , evidence = evidence , rationale = str ( raw . get ( " rationale " , " " ) ) , expected_value = str ( raw . get ( " expected_value " , " " ) ) , effort_estimate = str ( raw . get ( " effort_estimate " , " MEDIUM " ) ) , risk = str ( raw . get ( " risk " , " MEDIUM " ) ) , confidence = scores [ " confidence " ] , technical_fit = scores [ " technical_fit " ] , strategic_fit = scores [ " strategic_fit " ] , value_score = scores [ " value " ] , effort_score = scores [ " effort " ] , risk_score = scores [ " risk " ] , composite_score = scores [ " composite " ] , recommended_action = str ( raw . get ( " recommended_action " , " DEFER " ) ) , grouping_key = grouping_key )
def score ( self , raw : dict [ str , object ] ) - > dict [ str , float ] :
value = self . _score_value ( raw . get ( " value " , raw . get ( " value_score " , 0.5 ) ) )
effort = self . _score_value ( raw . get ( " effort " , raw . get ( " effort_score " , 0.5 ) ) )
risk = self . _score_value ( raw . get ( " risk_score " , 0.5 ) )
confidence = self . _score_value ( raw . get ( " confidence " , 0.5 ) )
technical_fit = self . _score_value ( raw . get ( " technical_fit " , 0.5 ) )
strategic_fit = self . _score_value ( raw . get ( " strategic_fit " , 0.5 ) )
composite = ( value * 0.35 ) + ( ( 1 - effort ) * 0.15 ) + ( ( 1 - risk ) * 0.15 ) + ( confidence * 0.15 ) + ( technical_fit * 0.1 ) + ( strategic_fit * 0.1 )
return { " value " : value , " effort " : effort , " risk " : risk , " confidence " : confidence , " technical_fit " : technical_fit , " strategic_fit " : strategic_fit , " composite " : composite }
def _score_value ( self , value : object ) - > float :
try :
score = float ( value )
except ( TypeError , ValueError ) :
return 0.5
return max ( 0.0 , min ( 1.0 , score ) )
def convert_to_extension ( self , opportunity : ExplorationOpportunity ) - > ExtensionCandidate :
candidate = ExtensionService ( bus = self . bus ) . create_candidate ( opportunity . project , title = opportunity . title , description = opportunity . description , rationale = opportunity . rationale , source = " Explorer " , expected_value = opportunity . expected_value , affected_areas = [ opportunity . opportunity_type ] , estimated_complexity = opportunity . effort_estimate , risk = opportunity . risk , confidence = opportunity . confidence , evidence = opportunity . evidence , source_opportunity = opportunity )
opportunity . converted_extension = candidate
opportunity . status = " CONVERTED "
opportunity . save ( update_fields = [ " converted_extension " , " status " , " updated_at " ] )
return candidate
def convert_to_evolution ( self , opportunity : ExplorationOpportunity , * , baseline_measurement : dict [ str , object ] , desired_direction : str = " DECREASE " ) - > EvolutionCandidate :
candidate = EvolutionService ( bus = self . bus ) . create_candidate ( opportunity . project , target = opportunity . opportunity_type , objective = opportunity . description or opportunity . title , baseline_measurement = baseline_measurement , desired_direction = desired_direction , rationale = opportunity . rationale , source = " Explorer " , evidence = opportunity . evidence , risk = opportunity . risk , confidence = opportunity . confidence , source_opportunity = opportunity )
opportunity . converted_evolution = candidate
opportunity . status = " CONVERTED "
opportunity . save ( update_fields = [ " converted_evolution " , " status " , " updated_at " ] )
return candidate
def defer ( self , opportunity : ExplorationOpportunity ) - > ExplorationOpportunity :
opportunity . status = " DEFERRED "
opportunity . save ( update_fields = [ " status " , " updated_at " ] )
return opportunity
def reject ( self , opportunity : ExplorationOpportunity ) - > ExplorationOpportunity :
opportunity . status = " REJECTED "
opportunity . save ( update_fields = [ " status " , " updated_at " ] )
return opportunity
def _fallback_opportunities ( self , exploration : Exploration ) - > list [ dict [ str , object ] ] :
context = exploration . context_snapshot
features = str ( context . get ( " features " , " " ) ) . lower ( )
opportunities : list [ dict [ str , object ] ] = [ ]
if " dashboard " not in features :
opportunities . append ( { " title " : " Add project health dashboard " , " description " : " Expose recent runs, findings, and lifecycle status in a project dashboard. " , " opportunity_type " : " FEATURE " , " evidence " : { " missing_feature " : " dashboard " } , " rationale " : " Operators need a fast project health view. " , " expected_value " : " Improves observability " , " effort_estimate " : " MEDIUM " , " value " : 0.8 , " effort " : 0.45 , " risk_score " : 0.3 , " confidence " : 0.7 , " technical_fit " : 0.8 , " strategic_fit " : 0.8 , " recommended_action " : " EXTEND " } )
opportunities . append ( { " title " : " Measure repository analysis latency " , " description " : " Establish and improve latency for repeated project inspection. " , " opportunity_type " : " PERFORMANCE " , " evidence " : { " source " : " Explorer fallback " } , " rationale " : " Faster analysis improves iteration speed. " , " expected_value " : " Reduces operational latency " , " effort_estimate " : " LOW " , " value " : 0.6 , " effort " : 0.25 , " risk_score " : 0.2 , " confidence " : 0.65 , " technical_fit " : 0.75 , " strategic_fit " : 0.65 , " recommended_action " : " EVOLVE " } )
return opportunities
def _known_duplicate ( self , project : Project , grouping_key : str , title : str ) - > ExplorationOpportunity | None :
existing = ExplorationOpportunity . objects . filter ( project = project , grouping_key = grouping_key ) . first ( )
if existing :
return existing
lowered = title . lower ( )
if ExtensionCandidate . objects . filter ( project = project , title__iexact = title ) . exists ( ) or RoadmapItem . objects . filter ( project = project , title__iexact = title ) . exists ( ) :
return ExplorationOpportunity . objects . filter ( project = project , title__iexact = title ) . first ( )
if any ( item in lowered for item in [ " authentication " , " auth " ] ) and Decision . objects . filter ( project = project , decision__icontains = " authentication " ) . exists ( ) :
return ExplorationOpportunity . objects . filter ( project = project , title__icontains = " auth " ) . first ( )
return None
def _grouping_key ( self , project : Project , title : str , opportunity_type : str ) - > str :
fingerprint = hashlib . sha256 ( f " { title . lower ( ) } : { opportunity_type . lower ( ) } " . encode ( " utf-8 " ) ) . hexdigest ( ) [ : 16 ]
return f " { project . id } : { opportunity_type } : { fingerprint } " [ : 240 ]
class LifecycleInspectionService :
def project_lifecycle_view ( self , project : Project ) - > dict [ str , object ] :
return {
" project_id " : str ( project . id ) ,
" repairs " : list ( project . steward_findings . filter ( recommended_action = " REPAIR " ) . values ( " id " , " title " , " status " , " severity " ) ) ,
" extensions " : [ self . _extension ( candidate ) for candidate in project . extension_candidates . order_by ( " -created_at " ) ] ,
" evolutions " : [ self . _evolution ( candidate ) for candidate in project . evolution_candidates . order_by ( " -created_at " ) ] ,
" explorations " : [ self . _exploration ( exploration ) for exploration in project . explorations . order_by ( " -created_at " ) ] ,
}
def _extension ( self , candidate : ExtensionCandidate ) - > dict [ str , object ] :
plan = candidate . plans . order_by ( " -created_at " ) . first ( )
tasks = Task . objects . filter ( milestone__plan = plan . project_plan ) if plan and plan . project_plan_id else Task . objects . none ( )
return { " candidate " : { " id " : str ( candidate . id ) , " title " : candidate . title , " status " : candidate . status } , " plan " : str ( plan . id ) if plan else None , " tasks " : list ( tasks . values ( " id " , " status " , " goal " ) ) , " verification " : str ( plan . verification_id ) if plan and plan . verification_id else None , " commits " : list ( candidate . commits . values ( " id " , " sha " , " task_id " ) ) }
def _evolution ( self , candidate : EvolutionCandidate ) - > dict [ str , object ] :
plan = candidate . plans . order_by ( " -created_at " ) . first ( )
return { " candidate " : { " id " : str ( candidate . id ) , " target " : candidate . target , " objective " : candidate . objective , " status " : candidate . status } , " baseline " : candidate . baseline_measurement , " target " : candidate . target_measurement , " measurement " : plan . candidate_measurement if plan else { } , " delta " : plan . delta if plan else { } , " verdict " : plan . verdict if plan else " " }
def _exploration ( self , exploration : Exploration ) - > dict [ str , object ] :
return { " id " : str ( exploration . id ) , " status " : exploration . status , " opportunities " : list ( exploration . opportunities . order_by ( " -composite_score " ) . values ( " id " , " title " , " opportunity_type " , " status " , " recommended_action " , " value_score " , " effort_score " , " risk_score " , " confidence " , " technical_fit " , " strategic_fit " , " composite_score " ) ) }
def create_project_planning_signal ( project : Project , summary : str , evidence : dict [ str , object ] ) - > ProgenySignal :
return ProgenySignal . objects . create ( project = project , source = " project_lifecycle " , severity = " MEDIUM " , failure_category = " PROJECT_PLANNING " , summary = summary , evidence = evidence , grouping_key = f " project_lifecycle: { project . id } :planning " [ : 120 ] )