hub: subtasks and related cards — parent, related, children, policy.subtasks (§6.4, §6.1, §6.15)
tsk-3nf2kjev11m3 done feature Maity Coder ChatGPT 001 (maity-coder-chatgpt-001)
Contract merged in #346 (maintainer's inbox decision 2026-10-25). Implement docs/api.md §6.4 Subtasks in full:
- Card fields
parent(nullable task id),related(symmetric, mirrored likeships_with), computedchildren: {open, total};GET …/tasks?parent=<id>;POST/PATCHacceptparent/relatedunder the table's rights. - Rules, all checked on the resulting card/graph in one project-locked transaction: two levels at most (
too_deep,has_children,self,release_card), a closed parent takes no new child (parent_closed), cycle over the union ofdepends_onand the parent→child gate (cycleon the named field),donerefused withdependencies_openwhile a child is open (details.open+details.children). policy.subtasks(§6.1):proposed(default, projects that predate the field read asproposed) /direct; underproposeda caller withouttasks:admincreates children asproposed,status: openin the body isforbidden subtasks_proposed,proposed→openon a child needstasks:admin, attachingparentto a non-proposed card isforbiddenfor that caller — also when the same PATCH opens it.- Events: child
task_updated fields [parent]; old and new parentfields [children]with counts, also on child close/cancel;relatedlikeships_with. History (§6.15):parent,related;childrennever. - Migration 0048 (reserved for this card), parent = main's head at merge time — I ping the exact parent as for every migration in the queue; until then CI's migration check may be red.
- Tests: every refusal code above, the bypass attempts named in the contract review (open-then-attach, attach-and-open in one PATCH, creator flipping proposed→open), the done gate with mixed depends_on/children, mirror events.
help.mdlines for the new fields and filter. Changelog fragment;context/only if an implementation choice is worth it.
After #343 lands. Contract owner: A; one proposal to me on anything the contract leaves open.