From a988142a1a7b5deac9cfb467b54db8fef1c6e533 Mon Sep 17 00:00:00 2001 From: ggttyy1 Date: Sat, 11 Jul 2026 19:37:12 +0800 Subject: [PATCH 1/2] fix: align blockedBy IDs with task filenames --- s12_task_system/code.py | 25 +++++++++++++++++++++---- s13_background_tasks/code.py | 25 +++++++++++++++++++++---- s14_cron_scheduler/code.py | 25 +++++++++++++++++++++---- s15_agent_teams/code.py | 25 +++++++++++++++++++++---- s16_team_protocols/code.py | 25 +++++++++++++++++++++---- s17_autonomous_agents/code.py | 29 ++++++++++++++++++++++++----- s18_worktree_isolation/code.py | 29 ++++++++++++++++++++++++----- s19_mcp_plugin/code.py | 29 ++++++++++++++++++++++++----- s20_comprehensive/code.py | 29 ++++++++++++++++++++++++----- 9 files changed, 201 insertions(+), 40 deletions(-) diff --git a/s12_task_system/code.py b/s12_task_system/code.py index 7f442ebf2..eb9d86a42 100644 --- a/s12_task_system/code.py +++ b/s12_task_system/code.py @@ -96,12 +96,25 @@ def get_task(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {id: id, subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: """Check if all blockedBy dependencies are completed. Missing dependencies are treated as blocked.""" task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -113,8 +126,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if not _task_path(d).exists() or load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s13_background_tasks/code.py b/s13_background_tasks/code.py index a96eabcac..2be9ab7d5 100644 --- a/s13_background_tasks/code.py +++ b/s13_background_tasks/code.py @@ -95,12 +95,25 @@ def get_task(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: """Check if all blockedBy dependencies are completed. Missing dependencies are treated as blocked.""" task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -112,8 +125,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if not _task_path(d).exists() or load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s14_cron_scheduler/code.py b/s14_cron_scheduler/code.py index 7fd36324c..01fc2efc8 100644 --- a/s14_cron_scheduler/code.py +++ b/s14_cron_scheduler/code.py @@ -97,12 +97,25 @@ def get_task(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: """Check if all blockedBy dependencies are completed. Missing dependencies are treated as blocked.""" task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -114,8 +127,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if not _task_path(d).exists() or load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s15_agent_teams/code.py b/s15_agent_teams/code.py index 143a73e82..25d504545 100644 --- a/s15_agent_teams/code.py +++ b/s15_agent_teams/code.py @@ -95,12 +95,25 @@ def get_task(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: """Check if all blockedBy dependencies are completed. Missing dependencies are treated as blocked.""" task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -112,8 +125,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if not _task_path(d).exists() or load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s16_team_protocols/code.py b/s16_team_protocols/code.py index d7993fb9e..650bf4c3a 100644 --- a/s16_team_protocols/code.py +++ b/s16_team_protocols/code.py @@ -99,12 +99,25 @@ def get_task(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: """Check if all blockedBy dependencies are completed. Missing dependencies are treated as blocked.""" task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -116,8 +129,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if not _task_path(d).exists() or load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s17_autonomous_agents/code.py b/s17_autonomous_agents/code.py index 71d97bebe..b04d8e09d 100644 --- a/s17_autonomous_agents/code.py +++ b/s17_autonomous_agents/code.py @@ -91,10 +91,23 @@ def get_task(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -108,9 +121,15 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.owner: return f"Task {task_id} already owned by {task.owner}" if not can_start(task_id): - deps = [d for d in task.blockedBy - if _task_path(d).exists() and load_task(d).status != "completed"] - missing = [d for d in task.blockedBy if not _task_path(d).exists()] + idx = _build_task_index() + deps = [] + missing = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None: + missing.append(d) + elif load_task(did).status != "completed": + deps.append(d) parts = [] if deps: parts.append(f"blocked by: {deps}") if missing: parts.append(f"missing deps: {missing}") diff --git a/s18_worktree_isolation/code.py b/s18_worktree_isolation/code.py index c00fcf449..660c670c5 100644 --- a/s18_worktree_isolation/code.py +++ b/s18_worktree_isolation/code.py @@ -99,10 +99,23 @@ def get_task_json(task_id: str) -> str: return json.dumps(asdict(task), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -116,9 +129,15 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.owner: return f"Task {task_id} already owned by {task.owner}" if not can_start(task_id): - deps = [d for d in task.blockedBy - if _task_path(d).exists() and load_task(d).status != "completed"] - missing = [d for d in task.blockedBy if not _task_path(d).exists()] + idx = _build_task_index() + deps = [] + missing = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None: + missing.append(d) + elif load_task(did).status != "completed": + deps.append(d) parts = [] if deps: parts.append(f"blocked by: {deps}") if missing: parts.append(f"missing deps: {missing}") diff --git a/s19_mcp_plugin/code.py b/s19_mcp_plugin/code.py index eed5acecb..69e6cf43e 100644 --- a/s19_mcp_plugin/code.py +++ b/s19_mcp_plugin/code.py @@ -93,10 +93,23 @@ def get_task_json(task_id: str) -> str: return json.dumps(asdict(load_task(task_id)), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -110,9 +123,15 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.owner: return f"Task {task_id} already owned by {task.owner}" if not can_start(task_id): - deps = [d for d in task.blockedBy - if _task_path(d).exists() and load_task(d).status != "completed"] - missing = [d for d in task.blockedBy if not _task_path(d).exists()] + idx = _build_task_index() + deps = [] + missing = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None: + missing.append(d) + elif load_task(did).status != "completed": + deps.append(d) parts = [] if deps: parts.append(f"blocked by: {deps}") if missing: parts.append(f"missing deps: {missing}") diff --git a/s20_comprehensive/code.py b/s20_comprehensive/code.py index 722aba153..e256d24f3 100644 --- a/s20_comprehensive/code.py +++ b/s20_comprehensive/code.py @@ -121,12 +121,25 @@ def get_task_json(task_id: str) -> str: return json.dumps(asdict(load_task(task_id)), indent=2) +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: # Dependencies are intentionally simple: every blocker must exist and be # completed before the task can be claimed. task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False if load_task(dep_id).status != "completed": return False @@ -140,9 +153,15 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.owner: return f"Task {task_id} already owned by {task.owner}" if not can_start(task_id): - deps = [d for d in task.blockedBy - if _task_path(d).exists() and load_task(d).status != "completed"] - missing = [d for d in task.blockedBy if not _task_path(d).exists()] + idx = _build_task_index() + deps = [] + missing = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None: + missing.append(d) + elif load_task(did).status != "completed": + deps.append(d) parts = [] if deps: parts.append(f"blocked by: {deps}") if missing: parts.append(f"missing deps: {missing}") From 6868aa18fe095220b3100c4ff6c057b49ea4442d Mon Sep 17 00:00:00 2001 From: ggttyy1 Date: Sat, 11 Jul 2026 21:16:58 +0800 Subject: [PATCH 2/2] update README with subject-based blockedBy resolution --- s12_task_system/README.en.md | 25 +++++++++++++++++++++---- s12_task_system/README.ja.md | 25 +++++++++++++++++++++---- s12_task_system/README.md | 25 +++++++++++++++++++++---- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/s12_task_system/README.en.md b/s12_task_system/README.en.md index 756aedb42..a10281f67 100644 --- a/s12_task_system/README.en.md +++ b/s12_task_system/README.en.md @@ -83,10 +83,23 @@ Automatically calls `save_task` on creation to write `.tasks/{id}.json`. `blocke A task can only start after all its `blockedBy` dependencies are **completed**: ```python +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False # missing dependency = blocked dep = load_task(dep_id) if dep.status != "completed": @@ -106,8 +119,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s12_task_system/README.ja.md b/s12_task_system/README.ja.md index ebc8c7e06..75a3aba71 100644 --- a/s12_task_system/README.ja.md +++ b/s12_task_system/README.ja.md @@ -83,10 +83,23 @@ def create_task(subject: str, description: str = "", タスクは `blockedBy` が**すべて completed** になってからでないと開始できない: ```python +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False # missing dependency = blocked dep = load_task(dep_id) if dep.status != "completed": @@ -106,8 +119,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress" diff --git a/s12_task_system/README.md b/s12_task_system/README.md index 03a925281..5d10cf697 100644 --- a/s12_task_system/README.md +++ b/s12_task_system/README.md @@ -83,10 +83,23 @@ def create_task(subject: str, description: str = "", 一个任务只能在它的 `blockedBy` **全部 completed** 之后才能开始: ```python +def _build_task_index() -> dict[str, str]: + """Build a {subject: id} lookup for resolving refs to task IDs.""" + lookup = {} + for f in TASKS_DIR.glob("task_*.json"): + t = json.loads(f.read_text()) + lookup[t["subject"]] = t["id"] + return lookup + + def can_start(task_id: str) -> bool: task = load_task(task_id) - for dep_id in task.blockedBy: - if not _task_path(dep_id).exists(): + if not task.blockedBy: + return True + idx = _build_task_index() + for dep_ref in task.blockedBy: + dep_id = idx.get(dep_ref) + if dep_id is None: return False # missing dependency = blocked dep = load_task(dep_id) if dep.status != "completed": @@ -106,8 +119,12 @@ def claim_task(task_id: str, owner: str = "agent") -> str: if task.status != "pending": return f"Task {task_id} is {task.status}, cannot claim" if not can_start(task_id): - deps = [d for d in task.blockedBy - if load_task(d).status != "completed"] + idx = _build_task_index() + deps = [] + for d in task.blockedBy: + did = idx.get(d) + if did is None or load_task(did).status != "completed": + deps.append(d) return f"Blocked by: {deps}" task.owner = owner task.status = "in_progress"