diff --git a/docs/tasks/INDEX.yaml b/docs/tasks/INDEX.yaml new file mode 100644 index 0000000..6b748ad --- /dev/null +++ b/docs/tasks/INDEX.yaml @@ -0,0 +1,34 @@ +# Task Dependency Index +# Generated by scripts/tasks.py index + +docs/tasks/features/FEATURES-20260305-085909-JDI-integrate-superpowers-workflows.md: + +docs/tasks/features/FEATURES-20260305-171241-FGU-implement-phase-1-planning-and-isolation-brainstorming.md: + +docs/tasks/features/FEATURES-20260305-171247-LAG-implement-phase-1-planning-and-isolation-workspace-setup.md: + +docs/tasks/features/FEATURES-20260305-171335-FJF-implement-phase-2-granular-execution-micro-planning.md: + +docs/tasks/features/FEATURES-20260305-171341-JOO-implement-phase-2-granular-execution-tdd-enforcer.md: + +docs/tasks/features/FEATURES-20260305-171348-HVS-implement-phase-3-subagent-orchestration-orchestrator.md: + +docs/tasks/features/FEATURES-20260305-171432-HBF-implement-phase-3-subagent-orchestration-local-code-review.md: + +docs/tasks/features/FEATURES-20260305-171438-HMD-update-agentsmd-and-docstasksguidemd-to-reflect-new-workflows.md: + +docs/tasks/foundation/FOUNDATION-20260203-004709-URI-test-create-v2.md: + +docs/tasks/foundation/FOUNDATION-20260203-EVAL-BEADS.md: + +docs/tasks/foundation/FOUNDATION-20260203-EVAL-MEMORY.md: + depends_on: + - docs/tasks/foundation/FOUNDATION-20260203-EVAL-BEADS.md + +docs/tasks/foundation/FOUNDATION-20260306-022244-SBP-implement-parent-and-related-fields-in-frontmatter.md: + +docs/tasks/foundation/FOUNDATION-20260306-022253-BHT-add-visualization-for-task-network.md: + +docs/tasks/foundation/TEST-GRAPH-V2.md: + depends_on: + - docs/tasks/foundation/FOUNDATION-20260203-EVAL-MEMORY.md diff --git a/docs/tasks/foundation/FOUNDATION-20260203-004709-URI-test-create-v2.md b/docs/tasks/foundation/FOUNDATION-20260203-004709-URI-test-create-v2.md index 026b322..74a70c2 100644 --- a/docs/tasks/foundation/FOUNDATION-20260203-004709-URI-test-create-v2.md +++ b/docs/tasks/foundation/FOUNDATION-20260203-004709-URI-test-create-v2.md @@ -9,8 +9,6 @@ created: 2026-02-03 00:47:09 category: foundation dependencies: type: task -part_of: [EPIC-TEST] -related_to: [REL-TEST] --- # Test Create V2 diff --git a/docs/tasks/foundation/FOUNDATION-20260306-022244-SBP-implement-parent-and-related-fields-in-frontmatter.md b/docs/tasks/foundation/FOUNDATION-20260306-022244-SBP-implement-parent-and-related-fields-in-frontmatter.md index 2ddcb71..8d6a069 100644 --- a/docs/tasks/foundation/FOUNDATION-20260306-022244-SBP-implement-parent-and-related-fields-in-frontmatter.md +++ b/docs/tasks/foundation/FOUNDATION-20260306-022244-SBP-implement-parent-and-related-fields-in-frontmatter.md @@ -1,6 +1,6 @@ --- id: FOUNDATION-20260306-022244-SBP -status: pending +status: completed title: Implement parent and related fields in Frontmatter priority: medium created: 2026-03-06 02:22:44 diff --git a/docs/tasks/foundation/FOUNDATION-20260309-111149-LVP-evaluate-testing-task.md b/docs/tasks/foundation/FOUNDATION-20260309-111149-LVP-evaluate-testing-task.md new file mode 100644 index 0000000..35bc831 --- /dev/null +++ b/docs/tasks/foundation/FOUNDATION-20260309-111149-LVP-evaluate-testing-task.md @@ -0,0 +1,13 @@ +--- +id: FOUNDATION-20260309-111149-LVP +status: pending +title: Evaluate Testing Task +priority: medium +created: 2026-03-09 11:11:49 +dependencies: +type: epic +--- + +# Evaluate Testing Task + +To be determined diff --git a/docs/tasks/foundation/TEST-GRAPH-V2.md b/docs/tasks/foundation/TEST-GRAPH-V2.md index 0214d21..d946c55 100644 --- a/docs/tasks/foundation/TEST-GRAPH-V2.md +++ b/docs/tasks/foundation/TEST-GRAPH-V2.md @@ -5,7 +5,7 @@ title: Test V2 Graph Features priority: low created: 2026-02-03 01:00:00 category: foundation -part_of: [FOUNDATION-20260203-EVAL] +part_of: [FOUNDATION-20260309-111149-LVP] dependencies: [FOUNDATION-20260203-EVAL-MEMORY] type: task estimate: 1 diff --git a/scripts/tasks.py b/scripts/tasks.py index a7b3d40..74ba906 100755 --- a/scripts/tasks.py +++ b/scripts/tasks.py @@ -922,25 +922,27 @@ def validate_all(output_format="text"): if "type" in frontmatter and frontmatter["type"] not in VALID_TYPES: errors.append(f"{file}: Invalid type '{frontmatter['type']}'") - # Parse dependencies - deps_str = frontmatter.get("dependencies") or "" - # Use shared parsing logic - deps = [] - if deps_str: - cleaned = deps_str.strip(" []") - if cleaned: - deps = [d.strip() for d in cleaned.split(",") if d.strip()] + # Parse dependencies, part_of, related_to + def parse_link_list(val): + if not val: return [] + val = str(val).strip(" []") + if not val: return [] + return [d.strip() for d in val.split(",") if d.strip()] + + deps = parse_link_list(frontmatter.get("dependencies")) + part_of = parse_link_list(frontmatter.get("part_of")) + related_to = parse_link_list(frontmatter.get("related_to")) # Check for Duplicate IDs if task_id in all_tasks: errors.append(f"{file}: Duplicate Task ID '{task_id}' (also in {all_tasks[task_id]['path']})") - all_tasks[task_id] = {"path": path, "deps": deps} + all_tasks[task_id] = {"path": path, "deps": deps, "part_of": part_of, "related_to": related_to} except Exception as e: errors.append(f"{file}: Error reading/parsing: {str(e)}") - # Pass 2: Dependency Validation & Cycle Detection + # Pass 2: Link Validation & Cycle Detection visited = set() recursion_stack = set() @@ -966,12 +968,14 @@ def detect_cycle(curr_id, path): return False for task_id, info in all_tasks.items(): - # Check dependencies exist - for dep_id in info["deps"]: - if dep_id not in all_tasks: - errors.append(f"{os.path.basename(info['path'])}: Invalid dependency '{dep_id}' (task not found)") - - # Check cycles + # Check links exist + for link_type in ["deps", "part_of", "related_to"]: + for linked_id in info[link_type]: + if linked_id not in all_tasks: + field_name = "dependency" if link_type == "deps" else link_type + errors.append(f"{os.path.basename(info['path'])}: Invalid {field_name} '{linked_id}' (task not found)") + + # Check cycles (only on dependencies) if task_id not in visited: cycle_path = [task_id] if detect_cycle(task_id, cycle_path): diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 94bb7d8..8f87bae 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -315,5 +315,42 @@ def test_breakdown_task(self): self.assertEqual(output['task_id'], task_id) self.assertEqual(output['action'], "breakdown") + def test_validate_links(self): + # Create a task with invalid links + tasks.create_task("foundation", "Task Invalid Links", "Desc", part_of=["INVALID-EPIC"], related_to=["INVALID-REL"]) + + # Verify validation fails + sys.stdout = StringIO() + tasks.validate_all(output_format="json") + output = json.loads(sys.stdout.getvalue()) + + self.assertFalse(output["valid"]) + error_msgs = "\n".join(output["errors"]) + self.assertIn("Invalid part_of 'INVALID-EPIC'", error_msgs) + self.assertIn("Invalid related_to 'INVALID-REL'", error_msgs) + + # Create valid tasks and link to them + tasks.create_task("foundation", "Valid Epic", "Desc", task_type="epic") + tasks.create_task("foundation", "Valid Rel", "Desc") + + sys.stdout = StringIO() + tasks.list_tasks(output_format="json") + data = json.loads(sys.stdout.getvalue()) + epic_id = [t for t in data if t['title'] == "Valid Epic"][0]['id'] + rel_id = [t for t in data if t['title'] == "Valid Rel"][0]['id'] + invalid_task_id = [t for t in data if t['title'] == "Task Invalid Links"][0]['id'] + + # Update the invalid task to valid links + filepath = tasks.find_task_file(invalid_task_id) + tasks.update_frontmatter_field(filepath, "part_of", [epic_id]) + tasks.update_frontmatter_field(filepath, "related_to", [rel_id]) + + # Verify validation succeeds + sys.stdout = StringIO() + tasks.validate_all(output_format="json") + output = json.loads(sys.stdout.getvalue()) + + self.assertTrue(output["valid"], f"Validation failed with errors: {output.get('errors')}") + if __name__ == "__main__": unittest.main()