diff --git a/worker_plan/worker_plan_internal/extract_dag.py b/worker_plan/worker_plan_internal/extract_dag.py new file mode 100644 index 00000000..62ac55a6 --- /dev/null +++ b/worker_plan/worker_plan_internal/extract_dag.py @@ -0,0 +1,244 @@ +"""Extract the pipeline DAG from Luigi task introspection. + +Walks the FullPlanPipeline task graph via requires()/output() and produces +a JSON description of every stage: name, output files, upstream stages, +and source code files. This replaces the hand-maintained registry with a +generated artifact that stays in sync with the actual pipeline code. + +Usage: + cd worker_plan + python -m worker_plan_internal.extract_dag + python -m worker_plan_internal.extract_dag --output pipeline_dag.json +""" +import inspect +import json +import re +import sys +from pathlib import Path +from typing import Any + +import luigi + +_WORKER_PLAN_DIR = Path(__file__).resolve().parent.parent # worker_plan/ + +# Module prefixes that are infrastructure/utilities, not implementation logic. +# Imports from these are excluded from source_files auto-detection. +_INFRASTRUCTURE_PREFIXES = ( + "worker_plan_internal.plan.stages.", + "worker_plan_internal.plan.run_plan_pipeline", + "worker_plan_internal.plan.pipeline_environment", + "worker_plan_internal.plan.ping_llm", + "worker_plan_internal.llm_util.", + "worker_plan_internal.llm_factory", + "worker_plan_internal.luigi_util.", + "worker_plan_internal.utils.", + "worker_plan_internal.format_", + "worker_plan_api.", +) + + +def _class_name_to_stage_name(class_name: str) -> str: + """Convert CamelCase task class name to snake_case stage name. + + Removes the 'Task' suffix, then converts CamelCase → snake_case. + + Examples: + PotentialLeversTask → potential_levers + SWOTAnalysisTask → swot_analysis + WBSProjectLevel1AndLevel2Task → wbs_project_level1_and_level2 + GovernancePhase1AuditTask → governance_phase1_audit + """ + name = class_name.removesuffix("Task") + # Insert underscore between lowercase/digit and uppercase + name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name) + # Insert underscore between consecutive uppercase run and uppercase+lowercase + name = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", name) + return name.lower() + + +def _extract_output_filenames(task: luigi.Task) -> list[str]: + """Extract output filenames (basenames) from a task's output() method.""" + try: + outputs = task.output() + except Exception: + return [] + + targets: list[Any] = [] + if isinstance(outputs, dict): + targets = list(outputs.values()) + elif isinstance(outputs, (list, tuple)): + targets = list(outputs) + else: + targets = [outputs] + + filenames: list[str] = [] + for target in targets: + if hasattr(target, "path"): + filenames.append(Path(target.path).name) + return filenames + + +def _extract_upstream_tasks(task: luigi.Task) -> list[luigi.Task]: + """Extract upstream task instances from a task's requires() method.""" + try: + deps = task.requires() + except Exception: + return [] + + if deps is None: + return [] + if isinstance(deps, dict): + return list(deps.values()) + if isinstance(deps, (list, tuple)): + return list(deps) + if isinstance(deps, luigi.Task): + return [deps] + return [] + + +def _detect_implementation_files(cls: type) -> list[str]: + """Auto-detect implementation source files from module-level imports. + + Scans the module that defines *cls* for classes and functions imported + from ``worker_plan_internal.*`` that are NOT infrastructure (stages, + LLM utilities, API types, etc.). Returns paths relative to worker_plan/. + """ + module = inspect.getmodule(cls) + if module is None: + return [] + + files: list[str] = [] + seen_modules: set[str] = set() + + for attr_name in dir(module): + obj = getattr(module, attr_name, None) + if obj is None or not (inspect.isclass(obj) or inspect.isfunction(obj)): + continue + + obj_module_name = getattr(obj, "__module__", "") or "" + if not obj_module_name.startswith("worker_plan_internal."): + continue + if any(obj_module_name.startswith(p) for p in _INFRASTRUCTURE_PREFIXES): + continue + if obj_module_name in seen_modules: + continue + seen_modules.add(obj_module_name) + + try: + obj_file = Path(inspect.getfile(obj)).resolve() + rel = str(obj_file.relative_to(_WORKER_PLAN_DIR)) + if rel not in files: + files.append(rel) + except (TypeError, ValueError, OSError): + continue + + return files + + +def _extract_source_files(task: luigi.Task) -> list[str]: + """Get source files: task's own file + auto-detected implementation files.""" + cls = type(task) + + # The task's own file + result: list[str] = [] + try: + task_file = Path(inspect.getfile(cls)).resolve() + result.append(str(task_file.relative_to(_WORKER_PLAN_DIR))) + except (TypeError, ValueError, OSError): + pass + + # Supplement with auto-detected implementation files + for f in _detect_implementation_files(cls): + if f not in result: + result.append(f) + + return result + + +def _output_sort_key(stage: dict[str, Any]) -> tuple[int, int, str]: + """Sort key: numeric prefix from the first output filename, then name.""" + filename = stage["output_files"][0] if stage.get("output_files") else "" + match = re.match(r"(\d+)-?(\d+)?", filename) + if match: + major = int(match.group(1)) + minor = int(match.group(2)) if match.group(2) else 0 + return (major, minor, stage["id"]) + return (9999, 0, stage["id"]) + + +def extract_dag() -> dict[str, Any]: + """Walk the FullPlanPipeline task graph and extract DAG info. + + Returns a top-level schema object with stages sorted by pipeline order. + """ + from worker_plan_internal.plan.stages.full_plan_pipeline import FullPlanPipeline + + root = FullPlanPipeline(run_id_dir=Path("/tmp/_dag_extract_dummy")) + + stages: list[dict[str, Any]] = [] + visited: set[str] = set() + + def _walk(task: luigi.Task) -> None: + class_name = task.__class__.__name__ + if class_name in visited: + return + visited.add(class_name) + + upstream_tasks = _extract_upstream_tasks(task) + + # Recurse into dependencies first (depth-first) + for dep in upstream_tasks: + _walk(dep) + + # Skip the orchestrator itself + if class_name == "FullPlanPipeline": + return + + cls = type(task) + stage_name = _class_name_to_stage_name(class_name) + description = cls.description() if hasattr(cls, "description") else "" + output_files = _extract_output_filenames(task) + source_files = _extract_source_files(task) + depends_on_names = sorted(set( + _class_name_to_stage_name(dep.__class__.__name__) + for dep in upstream_tasks + )) + + stages.append({ + "id": stage_name, + "description": description, + "output_files": output_files, + "depends_on": depends_on_names, + "source_files": source_files, + }) + + _walk(root) + + stages.sort(key=_output_sort_key) + + return { + "schema_version": "1.0", + "pipeline_name": "planning_pipeline", + "description": "DAG for PlanExe, an AI-driven project planning system.", + "stages": stages, + } + + +def main() -> None: + output_path = None + args = sys.argv[1:] + if len(args) >= 2 and args[0] == "--output": + output_path = args[1] + + dag = extract_dag() + dag_json = json.dumps(dag, indent=2, ensure_ascii=False) + + if output_path: + Path(output_path).write_text(dag_json + "\n", encoding="utf-8") + print(f"Wrote {len(dag['stages'])} stages to {output_path}", file=sys.stderr) + else: + print(dag_json) + + +if __name__ == "__main__": + main() diff --git a/worker_plan/worker_plan_internal/plan/run_plan_pipeline.py b/worker_plan/worker_plan_internal/plan/run_plan_pipeline.py index 93861faf..56b5f1a7 100644 --- a/worker_plan/worker_plan_internal/plan/run_plan_pipeline.py +++ b/worker_plan/worker_plan_internal/plan/run_plan_pipeline.py @@ -78,6 +78,18 @@ class PlanTask(luigi.Task): # If the callback is not provided, the pipeline will run until completion. _pipeline_executor_callback = luigi.Parameter(default=None, significant=False, visibility=luigi.parameter.ParameterVisibility.PRIVATE) + @classmethod + def description(cls) -> str: + """Brief description of what this task does. + + Default returns the first line of the class docstring. + Override in subclasses for a custom description. + """ + doc = cls.__doc__ + if doc: + return doc.strip().split("\n")[0].strip() + return "" + def file_path(self, filename: FilenameEnum) -> Path: return self.run_id_dir / filename.value diff --git a/worker_plan/worker_plan_internal/plan/stages/candidate_scenarios.py b/worker_plan/worker_plan_internal/plan/stages/candidate_scenarios.py index 958f7a48..d48b70f8 100644 --- a/worker_plan/worker_plan_internal/plan/stages/candidate_scenarios.py +++ b/worker_plan/worker_plan_internal/plan/stages/candidate_scenarios.py @@ -11,9 +11,7 @@ class CandidateScenariosTask(PlanTask): - """ - Combinations of the vital few levers. - """ + """Generate aggressive, moderate, and conservative scenarios from the vital few levers.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/consolidate_assumptions_markdown.py b/worker_plan/worker_plan_internal/plan/stages/consolidate_assumptions_markdown.py index f150618b..e7b873b5 100644 --- a/worker_plan/worker_plan_internal/plan/stages/consolidate_assumptions_markdown.py +++ b/worker_plan/worker_plan_internal/plan/stages/consolidate_assumptions_markdown.py @@ -18,9 +18,7 @@ class ConsolidateAssumptionsMarkdownTask(PlanTask): - """ - Combines multiple small markdown documents into a single big document. - """ + """Merge locations, currency, risks, and assumption stages into one reference document.""" def requires(self): return { 'identify_purpose': self.clone(IdentifyPurposeTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/consolidate_governance.py b/worker_plan/worker_plan_internal/plan/stages/consolidate_governance.py index 424ae8c4..7971ccc0 100644 --- a/worker_plan/worker_plan_internal/plan/stages/consolidate_governance.py +++ b/worker_plan/worker_plan_internal/plan/stages/consolidate_governance.py @@ -10,6 +10,8 @@ class ConsolidateGovernanceTask(PlanTask): + """Consolidate all governance phases into a single markdown document.""" + def requires(self): return { 'governance_phase1_audit': self.clone(GovernancePhase1AuditTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/constraint_checker_stages.py b/worker_plan/worker_plan_internal/plan/stages/constraint_checker_stages.py index 74c08c28..b0ab8468 100644 --- a/worker_plan/worker_plan_internal/plan/stages/constraint_checker_stages.py +++ b/worker_plan/worker_plan_internal/plan/stages/constraint_checker_stages.py @@ -30,7 +30,7 @@ def _read_constraints_json(task: PlanTask) -> str: class PotentialLeversConstraintTask(PlanTask): - """Check potential levers output for constraint violations.""" + """Guardrail: verify brainstormed levers respect the user's constraints.""" def requires(self): return { 'extract_constraints': self.clone(ExtractConstraintsTask), @@ -49,7 +49,7 @@ def run_with_llm(self, llm: LLM) -> None: class DeduplicatedLeversConstraintTask(PlanTask): - """Check deduplicated levers output for constraint violations.""" + """Guardrail: verify triaged levers still respect the user's constraints.""" def requires(self): return { 'extract_constraints': self.clone(ExtractConstraintsTask), @@ -68,7 +68,7 @@ def run_with_llm(self, llm: LLM) -> None: class EnrichedLeversConstraintTask(PlanTask): - """Check enriched levers output for constraint violations.""" + """Guardrail: verify enriched levers still respect the user's constraints.""" def requires(self): return { 'extract_constraints': self.clone(ExtractConstraintsTask), @@ -87,7 +87,7 @@ def run_with_llm(self, llm: LLM) -> None: class VitalFewLeversConstraintTask(PlanTask): - """Check vital few levers output for constraint violations.""" + """Guardrail: verify the selected vital levers respect the user's constraints.""" def requires(self): return { 'extract_constraints': self.clone(ExtractConstraintsTask), @@ -106,7 +106,7 @@ def run_with_llm(self, llm: LLM) -> None: class CandidateScenariosConstraintTask(PlanTask): - """Check candidate scenarios output for constraint violations.""" + """Guardrail: verify generated scenarios respect the user's constraints.""" def requires(self): return { 'extract_constraints': self.clone(ExtractConstraintsTask), @@ -125,7 +125,7 @@ def run_with_llm(self, llm: LLM) -> None: class SelectedScenarioConstraintTask(PlanTask): - """Check selected scenario output for constraint violations.""" + """Guardrail: verify the chosen scenario respects the user's constraints before planning begins.""" def requires(self): return { 'extract_constraints': self.clone(ExtractConstraintsTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/convert_pitch_to_markdown.py b/worker_plan/worker_plan_internal/plan/stages/convert_pitch_to_markdown.py index 43856006..2928b5bb 100644 --- a/worker_plan/worker_plan_internal/plan/stages/convert_pitch_to_markdown.py +++ b/worker_plan/worker_plan_internal/plan/stages/convert_pitch_to_markdown.py @@ -9,12 +9,7 @@ class ConvertPitchToMarkdownTask(PlanTask): - """ - Human readable version of the pitch. - - This task depends on: - - CreatePitchTask: Creates the pitch JSON. - """ + """Convert the raw pitch JSON into a polished, scannable markdown document.""" def output(self): return { 'raw': self.local_target(FilenameEnum.PITCH_CONVERT_TO_MARKDOWN_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/create_pitch.py b/worker_plan/worker_plan_internal/plan/stages/create_pitch.py index 6a759430..397dc67b 100644 --- a/worker_plan/worker_plan_internal/plan/stages/create_pitch.py +++ b/worker_plan/worker_plan_internal/plan/stages/create_pitch.py @@ -17,15 +17,7 @@ class CreatePitchTask(PlanTask): - """ - Create a the pitch that explains the project plan, from multiple perspectives. - - This task depends on: - - ProjectPlanTask: provides the project plan JSON. - - WBSProjectLevel1AndLevel2Task: containing the top level of the project plan. - - The resulting pitch JSON is written to the file specified by FilenameEnum.PITCH. - """ + """Create a compelling project pitch with target audience, call to action, and risk mitigation.""" def output(self): return self.local_target(FilenameEnum.PITCH_RAW) diff --git a/worker_plan/worker_plan_internal/plan/stages/create_schedule.py b/worker_plan/worker_plan_internal/plan/stages/create_schedule.py index 82077822..e920ae2a 100644 --- a/worker_plan/worker_plan_internal/plan/stages/create_schedule.py +++ b/worker_plan/worker_plan_internal/plan/stages/create_schedule.py @@ -19,6 +19,8 @@ class CreateScheduleTask(PlanTask): + """Build the project schedule and generate Gantt charts.""" + def output(self): return { 'dhtmlx_html': self.local_target(FilenameEnum.SCHEDULE_GANTT_DHTMLX_HTML), diff --git a/worker_plan/worker_plan_internal/plan/stages/create_wbs_level1.py b/worker_plan/worker_plan_internal/plan/stages/create_wbs_level1.py index 5755d8ed..e8f08fa3 100644 --- a/worker_plan/worker_plan_internal/plan/stages/create_wbs_level1.py +++ b/worker_plan/worker_plan_internal/plan/stages/create_wbs_level1.py @@ -12,14 +12,7 @@ class CreateWBSLevel1Task(PlanTask): - """ - Creates the Work Breakdown Structure (WBS) Level 1. - Depends on: - - ProjectPlanTask: provides the project plan as JSON. - Produces: - - Raw WBS Level 1 output file (xxx-wbs_level1_raw.json) - - Cleaned up WBS Level 1 file (xxx-wbs_level1.json) - """ + """Extract the project title and top-level phases (WBS Level 1) from the project plan.""" def requires(self): return { 'project_plan': self.clone(ProjectPlanTask) diff --git a/worker_plan/worker_plan_internal/plan/stages/create_wbs_level2.py b/worker_plan/worker_plan_internal/plan/stages/create_wbs_level2.py index 6ae31ff5..74e900cc 100644 --- a/worker_plan/worker_plan_internal/plan/stages/create_wbs_level2.py +++ b/worker_plan/worker_plan_internal/plan/stages/create_wbs_level2.py @@ -16,15 +16,7 @@ class CreateWBSLevel2Task(PlanTask): - """ - Creates the Work Breakdown Structure (WBS) Level 2. - Depends on: - - ProjectPlanTask: provides the project plan as JSON. - - CreateWBSLevel1Task: provides the cleaned WBS Level 1 result. - Produces: - - Raw WBS Level 2 output (007-wbs_level2_raw.json) - - Cleaned WBS Level 2 output (008-wbs_level2.json) - """ + """Decompose top-level phases into major tasks (WBS Level 2).""" def requires(self): return { 'strategic_decisions_markdown': self.clone(StrategicDecisionsMarkdownTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/create_wbs_level3.py b/worker_plan/worker_plan_internal/plan/stages/create_wbs_level3.py index 282e94cc..7e854827 100644 --- a/worker_plan/worker_plan_internal/plan/stages/create_wbs_level3.py +++ b/worker_plan/worker_plan_internal/plan/stages/create_wbs_level3.py @@ -19,18 +19,7 @@ class CreateWBSLevel3Task(PlanTask): - """ - This task creates the Work Breakdown Structure (WBS) Level 3, by decomposing tasks from Level 2 into subtasks. - - It depends on: - - ProjectPlanTask: provides the project plan JSON. - - WBSProjectLevel1AndLevel2Task: provides the major phases with subtasks and the task UUIDs. - - EstimateTaskDurationsTask: provides the aggregated task durations (task_duration_list). - - For each task without any subtasks, a query is built and executed using the LLM. - The raw JSON result for each task is written to a file using the template from FilenameEnum. - Finally, all individual results are accumulated and written as an aggregated JSON file. - """ + """Break Level 2 tasks into detailed subtasks (WBS Level 3).""" def output(self): return self.local_target(FilenameEnum.WBS_LEVEL3) diff --git a/worker_plan/worker_plan_internal/plan/stages/currency_strategy.py b/worker_plan/worker_plan_internal/plan/stages/currency_strategy.py index 87992af0..22f735c9 100644 --- a/worker_plan/worker_plan_internal/plan/stages/currency_strategy.py +++ b/worker_plan/worker_plan_internal/plan/stages/currency_strategy.py @@ -12,9 +12,7 @@ class CurrencyStrategyTask(PlanTask): - """ - Identify/suggest what currency to use for the plan, depending on the physical locations. - """ + """Choose the project currency based on physical locations and cross-border needs.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/data_collection.py b/worker_plan/worker_plan_internal/plan/stages/data_collection.py index 86de18c4..bab62fe0 100644 --- a/worker_plan/worker_plan_internal/plan/stages/data_collection.py +++ b/worker_plan/worker_plan_internal/plan/stages/data_collection.py @@ -14,9 +14,7 @@ class DataCollectionTask(PlanTask): - """ - Determine what kind of data is to be collected. - """ + """Specify data-gathering actions needed to validate the plan: market, financial, regulatory, etc.""" def output(self): return { 'raw': self.local_target(FilenameEnum.DATA_COLLECTION_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/deduplicate_levers.py b/worker_plan/worker_plan_internal/plan/stages/deduplicate_levers.py index 82f6b645..1142d058 100644 --- a/worker_plan/worker_plan_internal/plan/stages/deduplicate_levers.py +++ b/worker_plan/worker_plan_internal/plan/stages/deduplicate_levers.py @@ -11,9 +11,7 @@ class DeduplicateLeversTask(PlanTask): - """ - The potential levers usually have some redundant levers. - """ + """Triage levers into primary, secondary, or remove.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/distill_assumptions.py b/worker_plan/worker_plan_internal/plan/stages/distill_assumptions.py index c645d54f..eee50a78 100644 --- a/worker_plan/worker_plan_internal/plan/stages/distill_assumptions.py +++ b/worker_plan/worker_plan_internal/plan/stages/distill_assumptions.py @@ -13,9 +13,7 @@ class DistillAssumptionsTask(PlanTask): - """ - Distill raw assumption data. - """ + """Condense verbose assumptions into concise, strategically important ones.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_create.py b/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_create.py index 47a6e7d2..a5a64cfe 100644 --- a/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_create.py +++ b/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_create.py @@ -18,9 +18,7 @@ class DraftDocumentsToCreateTask(PlanTask): - """ - The "documents to create". Write bullet points to what each document roughly should contain. - """ + """Draft content specs for each document to create: essential info, risks, and scenarios.""" def output(self): return self.local_target(FilenameEnum.DRAFT_DOCUMENTS_TO_CREATE_CONSOLIDATED) diff --git a/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_find.py b/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_find.py index 65842998..e4e0bd8e 100644 --- a/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_find.py +++ b/worker_plan/worker_plan_internal/plan/stages/draft_documents_to_find.py @@ -18,9 +18,7 @@ class DraftDocumentsToFindTask(PlanTask): - """ - The "documents to find". Write bullet points to what each document roughly should contain. - """ + """Draft content specs for each document to find: essential info, risks, and scenarios.""" def output(self): return self.local_target(FilenameEnum.DRAFT_DOCUMENTS_TO_FIND_CONSOLIDATED) diff --git a/worker_plan/worker_plan_internal/plan/stages/enrich_levers.py b/worker_plan/worker_plan_internal/plan/stages/enrich_levers.py index 179b66a8..059ee1b9 100644 --- a/worker_plan/worker_plan_internal/plan/stages/enrich_levers.py +++ b/worker_plan/worker_plan_internal/plan/stages/enrich_levers.py @@ -11,9 +11,7 @@ class EnrichLeversTask(PlanTask): - """ - Enrich potential levers with more information. - """ + """Add description, synergy, and conflict text to each lever.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/enrich_team_background_story.py b/worker_plan/worker_plan_internal/plan/stages/enrich_team_background_story.py index 7ebcb848..4512d2ff 100644 --- a/worker_plan/worker_plan_internal/plan/stages/enrich_team_background_story.py +++ b/worker_plan/worker_plan_internal/plan/stages/enrich_team_background_story.py @@ -20,6 +20,8 @@ class EnrichTeamMembersWithBackgroundStoryTask(PlanTask): + """Develop background story for each team member.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/enrich_team_contract_type.py b/worker_plan/worker_plan_internal/plan/stages/enrich_team_contract_type.py index a6b52292..c5faf3c4 100644 --- a/worker_plan/worker_plan_internal/plan/stages/enrich_team_contract_type.py +++ b/worker_plan/worker_plan_internal/plan/stages/enrich_team_contract_type.py @@ -19,6 +19,8 @@ class EnrichTeamMembersWithContractTypeTask(PlanTask): + """Determine contract type for each team member.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/enrich_team_environment_info.py b/worker_plan/worker_plan_internal/plan/stages/enrich_team_environment_info.py index 6791fe51..e3217c6c 100644 --- a/worker_plan/worker_plan_internal/plan/stages/enrich_team_environment_info.py +++ b/worker_plan/worker_plan_internal/plan/stages/enrich_team_environment_info.py @@ -19,6 +19,8 @@ class EnrichTeamMembersWithEnvironmentInfoTask(PlanTask): + """Add equipment needs and facility requirements for each team member's role.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/estimate_task_durations.py b/worker_plan/worker_plan_internal/plan/stages/estimate_task_durations.py index c6cd991f..55d4e3ea 100644 --- a/worker_plan/worker_plan_internal/plan/stages/estimate_task_durations.py +++ b/worker_plan/worker_plan_internal/plan/stages/estimate_task_durations.py @@ -15,20 +15,7 @@ class EstimateTaskDurationsTask(PlanTask): - """ - This task estimates durations for WBS tasks in chunks. - - It depends on: - - ProjectPlanTask: providing the project plan JSON. - - WBSProjectLevel1AndLevel2Task: providing the major phases with subtasks and the task UUIDs. - - For each chunk of 3 task IDs, a raw JSON file (e.g. "011-1-task_durations_raw.json") is written, - and an aggregated JSON file (defined by FilenameEnum.TASK_DURATIONS) is produced. - - IDEA: 1st estimate the Tasks that have zero children. - 2nd estimate tasks that have children where all children have been estimated. - repeat until all tasks have been estimated. - """ + """Estimate realistic, minimum, and maximum durations for each WBS task bottom-up.""" def output(self): return self.local_target(FilenameEnum.TASK_DURATIONS) diff --git a/worker_plan/worker_plan_internal/plan/stages/executive_summary.py b/worker_plan/worker_plan_internal/plan/stages/executive_summary.py index 0c7ba83b..33b14a35 100644 --- a/worker_plan/worker_plan_internal/plan/stages/executive_summary.py +++ b/worker_plan/worker_plan_internal/plan/stages/executive_summary.py @@ -18,9 +18,7 @@ class ExecutiveSummaryTask(PlanTask): - """ - Create an executive summary of the plan. - """ + """Produce a concise one-pager for decision-makers with key findings and recommendations.""" def output(self): return { 'raw': self.local_target(FilenameEnum.EXECUTIVE_SUMMARY_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/expert_review.py b/worker_plan/worker_plan_internal/plan/stages/expert_review.py index 05b8635f..bb3fd4c5 100644 --- a/worker_plan/worker_plan_internal/plan/stages/expert_review.py +++ b/worker_plan/worker_plan_internal/plan/stages/expert_review.py @@ -19,9 +19,7 @@ class ExpertReviewTask(PlanTask): - """ - Finds experts to review the SWOT analysis and have them provide criticism. - """ + """Assemble a panel of domain experts and have them critique the plan.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/extract_constraints.py b/worker_plan/worker_plan_internal/plan/stages/extract_constraints.py index e7a37fa5..63db8da6 100644 --- a/worker_plan/worker_plan_internal/plan/stages/extract_constraints.py +++ b/worker_plan/worker_plan_internal/plan/stages/extract_constraints.py @@ -7,10 +7,7 @@ class ExtractConstraintsTask(PlanTask): - """ - Extract and classify constraints from the user's prompt. - Produces a list of positive/negative constraint items. - """ + """Extract positive/negative constraints from the user's prompt.""" def requires(self): return self.clone(SetupTask) diff --git a/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_create.py b/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_create.py index 179b4c25..3af2f826 100644 --- a/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_create.py +++ b/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_create.py @@ -13,10 +13,7 @@ class FilterDocumentsToCreateTask(PlanTask): - """ - The "documents to create" may be a long list of documents, some duplicates, irrelevant, not needed at an early stage of the project. - This task narrows down to a handful of relevant documents. - """ + """Narrow the documents-to-create list to the most relevant ones for the current plan.""" def output(self): return { "raw": self.local_target(FilenameEnum.FILTER_DOCUMENTS_TO_CREATE_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_find.py b/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_find.py index 6b7f81ab..90fec0fe 100644 --- a/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_find.py +++ b/worker_plan/worker_plan_internal/plan/stages/filter_documents_to_find.py @@ -13,10 +13,7 @@ class FilterDocumentsToFindTask(PlanTask): - """ - The "documents to find" may be a long list of documents, some duplicates, irrelevant, not needed at an early stage of the project. - This task narrows down to a handful of relevant documents. - """ + """Narrow the documents-to-find list to the most relevant ones for the current plan.""" def output(self): return { "raw": self.local_target(FilenameEnum.FILTER_DOCUMENTS_TO_FIND_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/find_team_members.py b/worker_plan/worker_plan_internal/plan/stages/find_team_members.py index c5cefb60..1c0f32f1 100644 --- a/worker_plan/worker_plan_internal/plan/stages/find_team_members.py +++ b/worker_plan/worker_plan_internal/plan/stages/find_team_members.py @@ -18,6 +18,8 @@ class FindTeamMembersTask(PlanTask): + """Identify team members required for project execution.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/focus_on_vital_few_levers.py b/worker_plan/worker_plan_internal/plan/stages/focus_on_vital_few_levers.py index 83ed59cf..dd8dff05 100644 --- a/worker_plan/worker_plan_internal/plan/stages/focus_on_vital_few_levers.py +++ b/worker_plan/worker_plan_internal/plan/stages/focus_on_vital_few_levers.py @@ -11,9 +11,7 @@ class FocusOnVitalFewLeversTask(PlanTask): - """ - Apply the 80/20 principle to the levers. - """ + """Select the ~5 highest-impact levers by rating each as critical, high, or medium.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/governance_phase1_audit.py b/worker_plan/worker_plan_internal/plan/stages/governance_phase1_audit.py index 46d239c5..7939372f 100644 --- a/worker_plan/worker_plan_internal/plan/stages/governance_phase1_audit.py +++ b/worker_plan/worker_plan_internal/plan/stages/governance_phase1_audit.py @@ -14,6 +14,8 @@ class GovernancePhase1AuditTask(PlanTask): + """Design the governance structure and compliance requirements for the plan.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/governance_phase2_bodies.py b/worker_plan/worker_plan_internal/plan/stages/governance_phase2_bodies.py index 708c2a24..2633a712 100644 --- a/worker_plan/worker_plan_internal/plan/stages/governance_phase2_bodies.py +++ b/worker_plan/worker_plan_internal/plan/stages/governance_phase2_bodies.py @@ -15,6 +15,8 @@ class GovernancePhase2BodiesTask(PlanTask): + """Define governance bodies and organizational hierarchy.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/governance_phase3_impl_plan.py b/worker_plan/worker_plan_internal/plan/stages/governance_phase3_impl_plan.py index 55bcc12f..c46e3c6b 100644 --- a/worker_plan/worker_plan_internal/plan/stages/governance_phase3_impl_plan.py +++ b/worker_plan/worker_plan_internal/plan/stages/governance_phase3_impl_plan.py @@ -17,6 +17,8 @@ class GovernancePhase3ImplPlanTask(PlanTask): + """Create implementation plan for the governance structure.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/governance_phase4_decision_escalation_matrix.py b/worker_plan/worker_plan_internal/plan/stages/governance_phase4_decision_escalation_matrix.py index cd54ba3c..1e1f1b85 100644 --- a/worker_plan/worker_plan_internal/plan/stages/governance_phase4_decision_escalation_matrix.py +++ b/worker_plan/worker_plan_internal/plan/stages/governance_phase4_decision_escalation_matrix.py @@ -18,6 +18,8 @@ class GovernancePhase4DecisionEscalationMatrixTask(PlanTask): + """Establish decision-making authority and escalation pathways.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/governance_phase5_monitoring_progress.py b/worker_plan/worker_plan_internal/plan/stages/governance_phase5_monitoring_progress.py index 16b29515..52458ad3 100644 --- a/worker_plan/worker_plan_internal/plan/stages/governance_phase5_monitoring_progress.py +++ b/worker_plan/worker_plan_internal/plan/stages/governance_phase5_monitoring_progress.py @@ -19,6 +19,8 @@ class GovernancePhase5MonitoringProgressTask(PlanTask): + """Define monitoring mechanisms and progress tracking.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/governance_phase6_extra.py b/worker_plan/worker_plan_internal/plan/stages/governance_phase6_extra.py index e772622d..83ece1a5 100644 --- a/worker_plan/worker_plan_internal/plan/stages/governance_phase6_extra.py +++ b/worker_plan/worker_plan_internal/plan/stages/governance_phase6_extra.py @@ -21,6 +21,8 @@ class GovernancePhase6ExtraTask(PlanTask): + """Validate prior governance phases with tough questions and a high-level summary.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/identify_documents.py b/worker_plan/worker_plan_internal/plan/stages/identify_documents.py index b0970696..51d765c3 100644 --- a/worker_plan/worker_plan_internal/plan/stages/identify_documents.py +++ b/worker_plan/worker_plan_internal/plan/stages/identify_documents.py @@ -16,9 +16,7 @@ class IdentifyDocumentsTask(PlanTask): - """ - Identify documents that need to be created or found for the project. - """ + """List documents the project needs — permits, contracts, specs, research, etc.""" def output(self): return { "raw": self.local_target(FilenameEnum.IDENTIFIED_DOCUMENTS_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/identify_purpose.py b/worker_plan/worker_plan_internal/plan/stages/identify_purpose.py index 6f7bdd67..40fd1b02 100644 --- a/worker_plan/worker_plan_internal/plan/stages/identify_purpose.py +++ b/worker_plan/worker_plan_internal/plan/stages/identify_purpose.py @@ -7,9 +7,7 @@ class IdentifyPurposeTask(PlanTask): - """ - Determine if this is this going to be a business/personal/other plan. - """ + """Classify the plan as business, personal, or other to tailor downstream prompts.""" def requires(self): return self.clone(SetupTask) diff --git a/worker_plan/worker_plan_internal/plan/stages/identify_risks.py b/worker_plan/worker_plan_internal/plan/stages/identify_risks.py index df662f0e..9977dc9b 100644 --- a/worker_plan/worker_plan_internal/plan/stages/identify_risks.py +++ b/worker_plan/worker_plan_internal/plan/stages/identify_risks.py @@ -13,9 +13,7 @@ class IdentifyRisksTask(PlanTask): - """ - Identify risks for the plan, depending on the physical locations. - """ + """Build a risk register covering strategic, operational, financial, and location-specific risks.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/identify_task_dependencies.py b/worker_plan/worker_plan_internal/plan/stages/identify_task_dependencies.py index a2268f1b..948371cb 100644 --- a/worker_plan/worker_plan_internal/plan/stages/identify_task_dependencies.py +++ b/worker_plan/worker_plan_internal/plan/stages/identify_task_dependencies.py @@ -16,9 +16,7 @@ class IdentifyTaskDependenciesTask(PlanTask): - """ - This task identifies the dependencies between WBS tasks. - """ + """Identify prerequisite relationships between WBS tasks for scheduling.""" def output(self): return self.local_target(FilenameEnum.TASK_DEPENDENCIES_RAW) diff --git a/worker_plan/worker_plan_internal/plan/stages/make_assumptions.py b/worker_plan/worker_plan_internal/plan/stages/make_assumptions.py index 282f2764..3b7e1e15 100644 --- a/worker_plan/worker_plan_internal/plan/stages/make_assumptions.py +++ b/worker_plan/worker_plan_internal/plan/stages/make_assumptions.py @@ -14,9 +14,7 @@ class MakeAssumptionsTask(PlanTask): - """ - Make assumptions about the plan. - """ + """Fill information gaps with grounded assumptions about costs, timelines, and resources.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/markdown_documents.py b/worker_plan/worker_plan_internal/plan/stages/markdown_documents.py index 066c84ac..22f67876 100644 --- a/worker_plan/worker_plan_internal/plan/stages/markdown_documents.py +++ b/worker_plan/worker_plan_internal/plan/stages/markdown_documents.py @@ -8,9 +8,7 @@ class MarkdownWithDocumentsToCreateAndFindTask(PlanTask): - """ - Create markdown with the "documents to create and find" - """ + """Format drafted documents into a structured markdown with roles, templates, and approval steps.""" def output(self): return self.local_target(FilenameEnum.DOCUMENTS_TO_CREATE_AND_FIND_MARKDOWN) diff --git a/worker_plan/worker_plan_internal/plan/stages/physical_locations.py b/worker_plan/worker_plan_internal/plan/stages/physical_locations.py index 85f74a68..4d8b9c06 100644 --- a/worker_plan/worker_plan_internal/plan/stages/physical_locations.py +++ b/worker_plan/worker_plan_internal/plan/stages/physical_locations.py @@ -15,9 +15,7 @@ class PhysicalLocationsTask(PlanTask): - """ - Identify/suggest physical locations for the plan. - """ + """Determine where the project operates — extract or suggest physical locations.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/potential_levers.py b/worker_plan/worker_plan_internal/plan/stages/potential_levers.py index c43fdfc7..b065f2c8 100644 --- a/worker_plan/worker_plan_internal/plan/stages/potential_levers.py +++ b/worker_plan/worker_plan_internal/plan/stages/potential_levers.py @@ -10,9 +10,7 @@ class PotentialLeversTask(PlanTask): - """ - Identify potential levers that can be adjusted. - """ + """Brainstorm actionable levers — knobs the plan can turn to change outcomes.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/pre_project_assessment.py b/worker_plan/worker_plan_internal/plan/stages/pre_project_assessment.py index a026861c..79c300bd 100644 --- a/worker_plan/worker_plan_internal/plan/stages/pre_project_assessment.py +++ b/worker_plan/worker_plan_internal/plan/stages/pre_project_assessment.py @@ -13,6 +13,7 @@ class PreProjectAssessmentTask(PlanTask): + """Evaluate project viability and readiness before detailed planning.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/premise_attack.py b/worker_plan/worker_plan_internal/plan/stages/premise_attack.py index 7f42939b..396aee67 100644 --- a/worker_plan/worker_plan_internal/plan/stages/premise_attack.py +++ b/worker_plan/worker_plan_internal/plan/stages/premise_attack.py @@ -7,6 +7,8 @@ class PremiseAttackTask(PlanTask): + """Stress-test the plan's premise through five independent lenses to kill bad ideas early.""" + def requires(self): return self.clone(SetupTask) diff --git a/worker_plan/worker_plan_internal/plan/stages/premortem.py b/worker_plan/worker_plan_internal/plan/stages/premortem.py index cc9d9bfe..49d42c00 100644 --- a/worker_plan/worker_plan_internal/plan/stages/premortem.py +++ b/worker_plan/worker_plan_internal/plan/stages/premortem.py @@ -21,6 +21,8 @@ class PremortemTask(PlanTask): + """Imagine the project has already failed — identify how and why it would happen.""" + def output(self): return { 'raw': self.local_target(FilenameEnum.PREMORTEM_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/project_plan.py b/worker_plan/worker_plan_internal/plan/stages/project_plan.py index f63fa3c8..f91ac204 100644 --- a/worker_plan/worker_plan_internal/plan/stages/project_plan.py +++ b/worker_plan/worker_plan_internal/plan/stages/project_plan.py @@ -14,8 +14,9 @@ logger = logging.getLogger(__name__) - class ProjectPlanTask(PlanTask): + """Generate the project plan with goals, milestones, deliverables, and success criteria.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/questions_and_answers.py b/worker_plan/worker_plan_internal/plan/stages/questions_and_answers.py index 0c7d6dfa..66a0a261 100644 --- a/worker_plan/worker_plan_internal/plan/stages/questions_and_answers.py +++ b/worker_plan/worker_plan_internal/plan/stages/questions_and_answers.py @@ -20,6 +20,8 @@ class QuestionsAndAnswersTask(PlanTask): + """Anticipate stakeholder questions and provide clear answers from the plan.""" + def output(self): return { 'raw': self.local_target(FilenameEnum.QUESTIONS_AND_ANSWERS_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/redline_gate.py b/worker_plan/worker_plan_internal/plan/stages/redline_gate.py index 40108651..b74aa046 100644 --- a/worker_plan/worker_plan_internal/plan/stages/redline_gate.py +++ b/worker_plan/worker_plan_internal/plan/stages/redline_gate.py @@ -7,6 +7,8 @@ class RedlineGateTask(PlanTask): + """Block prompts that cross policy, legal, or ethical red lines.""" + def requires(self): return self.clone(SetupTask) diff --git a/worker_plan/worker_plan_internal/plan/stages/related_resources.py b/worker_plan/worker_plan_internal/plan/stages/related_resources.py index 66a6cad8..ae0b2584 100644 --- a/worker_plan/worker_plan_internal/plan/stages/related_resources.py +++ b/worker_plan/worker_plan_internal/plan/stages/related_resources.py @@ -16,6 +16,8 @@ class RelatedResourcesTask(PlanTask): + """Identify external resources needed: software, APIs, datasets, services, etc.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/report.py b/worker_plan/worker_plan_internal/plan/stages/report.py index da7e4034..5f41bdbd 100644 --- a/worker_plan/worker_plan_internal/plan/stages/report.py +++ b/worker_plan/worker_plan_internal/plan/stages/report.py @@ -29,9 +29,7 @@ class ReportTask(PlanTask): - """ - Generate a report html document. - """ + """Assemble all pipeline outputs into the final HTML report.""" def output(self): return self.local_target(FilenameEnum.REPORT) diff --git a/worker_plan/worker_plan_internal/plan/stages/review_assumptions.py b/worker_plan/worker_plan_internal/plan/stages/review_assumptions.py index 17db2648..600b3125 100644 --- a/worker_plan/worker_plan_internal/plan/stages/review_assumptions.py +++ b/worker_plan/worker_plan_internal/plan/stages/review_assumptions.py @@ -18,9 +18,7 @@ class ReviewAssumptionsTask(PlanTask): - """ - Find issues with the assumptions. - """ + """Flag unreasonable, missing, or contradictory assumptions with recommendations.""" def requires(self): return { 'identify_purpose': self.clone(IdentifyPurposeTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/review_plan.py b/worker_plan/worker_plan_internal/plan/stages/review_plan.py index 66bd44b1..f64309f3 100644 --- a/worker_plan/worker_plan_internal/plan/stages/review_plan.py +++ b/worker_plan/worker_plan_internal/plan/stages/review_plan.py @@ -17,9 +17,7 @@ class ReviewPlanTask(PlanTask): - """ - Ask questions about the almost finished plan. - """ + """Critically review the near-final plan with targeted questions and SMART recommendations.""" def output(self): return { 'raw': self.local_target(FilenameEnum.REVIEW_PLAN_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/review_team.py b/worker_plan/worker_plan_internal/plan/stages/review_team.py index 2567d315..5f2c44a2 100644 --- a/worker_plan/worker_plan_internal/plan/stages/review_team.py +++ b/worker_plan/worker_plan_internal/plan/stages/review_team.py @@ -20,6 +20,8 @@ class ReviewTeamTask(PlanTask): + """Review and validate the assembled team composition.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/scenarios_markdown.py b/worker_plan/worker_plan_internal/plan/stages/scenarios_markdown.py index fa707435..6051b09a 100644 --- a/worker_plan/worker_plan_internal/plan/stages/scenarios_markdown.py +++ b/worker_plan/worker_plan_internal/plan/stages/scenarios_markdown.py @@ -8,9 +8,7 @@ class ScenariosMarkdownTask(PlanTask): - """ - Present the scenarios in a human readable format. - """ + """Format the selected scenario and rejected alternatives into a readable document.""" def requires(self): return { 'candidate_scenarios': self.clone(CandidateScenariosTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/screen_planning_prompt.py b/worker_plan/worker_plan_internal/plan/stages/screen_planning_prompt.py index 5a72c723..33b4d730 100644 --- a/worker_plan/worker_plan_internal/plan/stages/screen_planning_prompt.py +++ b/worker_plan/worker_plan_internal/plan/stages/screen_planning_prompt.py @@ -7,10 +7,7 @@ class ScreenPlanningPromptTask(PlanTask): - """ - Screen the user's prompt for quality before plan generation. - Classifies the prompt as USABLE or UNUSABLE. - """ + """Flag prompts as UNUSABLE when there is high confidence the prompt is garbage.""" def requires(self): return self.clone(SetupTask) diff --git a/worker_plan/worker_plan_internal/plan/stages/select_scenario.py b/worker_plan/worker_plan_internal/plan/stages/select_scenario.py index ef5a9bac..faabde29 100644 --- a/worker_plan/worker_plan_internal/plan/stages/select_scenario.py +++ b/worker_plan/worker_plan_internal/plan/stages/select_scenario.py @@ -13,9 +13,7 @@ class SelectScenarioTask(PlanTask): - """ - Pick the best fitting scenario to make a plan for. - """ + """Evaluate trade-offs and select the best scenario with a rationale.""" def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/self_audit.py b/worker_plan/worker_plan_internal/plan/stages/self_audit.py index 9e2d3252..cbe70036 100644 --- a/worker_plan/worker_plan_internal/plan/stages/self_audit.py +++ b/worker_plan/worker_plan_internal/plan/stages/self_audit.py @@ -27,6 +27,8 @@ class SelfAuditTask(PlanTask): + """Checklist-based diagnostic: find gaps, contradictions, and unsupported claims across all stages.""" + def output(self): return { 'raw': self.local_target(FilenameEnum.SELF_AUDIT_RAW), diff --git a/worker_plan/worker_plan_internal/plan/stages/setup.py b/worker_plan/worker_plan_internal/plan/stages/setup.py index bd0ba06d..af60ff95 100644 --- a/worker_plan/worker_plan_internal/plan/stages/setup.py +++ b/worker_plan/worker_plan_internal/plan/stages/setup.py @@ -4,7 +4,7 @@ class SetupTask(PlanTask): - """The plan prompt text provided by the user.""" + """Load the user's plan prompt as the pipeline input.""" def output(self): return self.local_target(FilenameEnum.INITIAL_PLAN) diff --git a/worker_plan/worker_plan_internal/plan/stages/start_time.py b/worker_plan/worker_plan_internal/plan/stages/start_time.py index c655d279..c7e2a32b 100644 --- a/worker_plan/worker_plan_internal/plan/stages/start_time.py +++ b/worker_plan/worker_plan_internal/plan/stages/start_time.py @@ -4,7 +4,7 @@ class StartTimeTask(PlanTask): - """The timestamp when the pipeline was started.""" + """Record the pipeline start time.""" def output(self): return self.local_target(FilenameEnum.START_TIME) diff --git a/worker_plan/worker_plan_internal/plan/stages/strategic_decisions_markdown.py b/worker_plan/worker_plan_internal/plan/stages/strategic_decisions_markdown.py index 123de49a..f7bd8097 100644 --- a/worker_plan/worker_plan_internal/plan/stages/strategic_decisions_markdown.py +++ b/worker_plan/worker_plan_internal/plan/stages/strategic_decisions_markdown.py @@ -8,9 +8,7 @@ class StrategicDecisionsMarkdownTask(PlanTask): - """ - Human readable markdown with the levers. - """ + """Summarize the lever exploration pipeline into a readable strategic-decisions document.""" def requires(self): return { 'enriched_levers': self.clone(EnrichLeversTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/swot_analysis.py b/worker_plan/worker_plan_internal/plan/stages/swot_analysis.py index 34bb2bb5..b488c69b 100644 --- a/worker_plan/worker_plan_internal/plan/stages/swot_analysis.py +++ b/worker_plan/worker_plan_internal/plan/stages/swot_analysis.py @@ -19,6 +19,8 @@ class SWOTAnalysisTask(PlanTask): + """Identify strengths, weaknesses, opportunities, and threats tailored to the plan's purpose.""" + def requires(self): return { 'setup': self.clone(SetupTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/team_markdown.py b/worker_plan/worker_plan_internal/plan/stages/team_markdown.py index ffd7150a..c7ff9313 100644 --- a/worker_plan/worker_plan_internal/plan/stages/team_markdown.py +++ b/worker_plan/worker_plan_internal/plan/stages/team_markdown.py @@ -11,6 +11,8 @@ class TeamMarkdownTask(PlanTask): + """Compile team roles, contracts, backgrounds, and equipment into one team document.""" + def requires(self): return { 'enrich_team_members_with_environment_info': self.clone(EnrichTeamMembersWithEnvironmentInfoTask), diff --git a/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_and_level2.py b/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_and_level2.py index e9a60463..03b4c37b 100644 --- a/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_and_level2.py +++ b/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_and_level2.py @@ -8,13 +8,7 @@ class WBSProjectLevel1AndLevel2Task(PlanTask): - """ - Create a WBS project from the WBS Level 1 and Level 2 JSON files. - - It depends on: - - CreateWBSLevel1Task: providing the cleaned WBS Level 1 JSON. - - CreateWBSLevel2Task: providing the major phases with subtasks and the task UUIDs. - """ + """Merge Level 1 and Level 2 into a unified WBS project tree.""" def output(self): return self.local_target(FilenameEnum.WBS_PROJECT_LEVEL1_AND_LEVEL2) diff --git a/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_level2_level3.py b/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_level2_level3.py index 033075ed..901a197c 100644 --- a/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_level2_level3.py +++ b/worker_plan/worker_plan_internal/plan/stages/wbs_project_level1_level2_level3.py @@ -9,13 +9,7 @@ class WBSProjectLevel1AndLevel2AndLevel3Task(PlanTask): - """ - Create a WBS project from the WBS Level 1 and Level 2 and Level 3 JSON files. - - It depends on: - - WBSProjectLevel1AndLevel2Task: providing the major phases with subtasks and the task UUIDs. - - CreateWBSLevel3Task: providing the decomposed tasks. - """ + """Merge all three WBS levels into the complete project hierarchy (JSON + CSV).""" def output(self): return { 'full': self.local_target(FilenameEnum.WBS_PROJECT_LEVEL1_AND_LEVEL2_AND_LEVEL3_FULL),