feat(tasks): AC identity + child->parent AC linkage (guardrails spec 1/4)

Foundation for the decomposition-coverage and roll-up AC-verification gates.
Acceptance criteria were a flat list[str] with no per-criterion identity, so
nothing could relate a child task's criteria to the parent's — letting a PM drop
half a parent's ACs unnoticed (PR #175).

- migration 036: additive acceptance_criteria_ids + parent_ac_refs array columns;
  backfills stable md5(task_id:index) ids for existing rows.
- Task model + TaskCreateRequest + db table: the two fields.
- TaskService.create generates one stable id per criterion (1:1) when absent.
- DelegateInputs.covers_parent_criteria -> child.parent_ac_refs (the linkage),
  propagated through create_subtask.
- regression-safe (53 task tests green) + 1 new test.

Coverage gate (spec 2), roll-up AC gate (spec 4), per-dev sequenced queues
(spec 3) build on this. Design: docs/SPEC_AC_GUARDRAILS_2026-06-16.md.
This commit is contained in:
Renn F
2026-06-16 03:02:54 +02:00
parent 55ff05e6ec
commit 87ca142f4e
6 changed files with 141 additions and 1 deletions
@@ -313,6 +313,9 @@ class DelegateInputs:
acceptance_criteria: list[str] | None = None
estimated_complexity: str = "medium"
project_id: UUID | None = None
# Parent AC ids this subtask is responsible for — the decomposition coverage
# link. Empty/None means the child covers no specific parent criteria yet.
covers_parent_criteria: list[str] | None = None
class Choreographer:
@@ -4093,6 +4096,7 @@ class Choreographer:
title=inputs.title,
description=inputs.description,
acceptance_criteria=inputs.acceptance_criteria,
parent_ac_refs=inputs.covers_parent_criteria or [],
team=team_enum,
created_by=pm_agent_id,
project_id=resolved_project_id,