feat(launchpad): add the feature issue type — form, label, body-check schema - #509
Conversation
… schema (#507) Milestone > PRD > Feature > Task: features are one demonstrable capability under a PRD, decomposed into agent-executable tasks. Task template now routes would-be parents to the Feature form. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>
serina-mcfall
left a comment
There was a problem hiding this comment.
Changes requested — 1 blocker
Agent-authored under @serinamcfall's instruction. Per launchpad/AGENTS.md:165 — "Draft
everything. Approve nothing." — this raises the concern and clears none.
Note on method: the deterministic pre-pass my process asks for
(launchpad/scripts/pr_review_batch.py) does not exist. I used
launchpad/scripts/pr-preflight.py and ran the content checks by hand. Flagging the
substitution rather than implying the named script ran.
Pre-pass clean: all 6 applicable checks SUCCESS, Closes #507 resolves and agrees with the body
text, one expected org_rulesets skip.
I owe this PR an acknowledgement first. Reviewing buzz-infrastructure#129 I wrote that I
could not find a counterpart PR in this repo and raised its absence as a blocker. This is it —
opened 2026-08-24T00:06, well inside the range I searched. My search was gh pr list --search "feature issue type", which returned unrelated results, and I did not fall back to listing by
author. That blocker was withdrawn on #129 for a different reason; it should have been withdrawn
for this one. Apologies for the noise on your other PR.
And credit where it is due: type:feature already exists as a live label on this repo but is
not in launchpad/labels.yml, which means it was hand-created in the UI — exactly what that
file's own header warns against ("do not hand-create labels in the UI, or this file stops being
true"). This PR repairs that drift as a side effect. Worth stating because it is invisible from
the diff alone.
Blocker — launchpad/AGENTS.md still says there are five types, and now contradicts the form
launchpad/AGENTS.md is not in this diff. After merge it says the opposite of the templates, in
four places:
:104 Five types. **Exactly one `type:` label per issue** — a type never modifies another type.
:145 4. **A Task never has children.** If a Task grows children, it was a PRD — relabel it.
:182 There is one specialised form beyond the five types: **Agent workflow proposal**
Line 145 is directly contradicted by this PR's own 02-task.yml edit:
2. A Task has NO children. If this needs sub-issues, it is a Feature - use 07-feature.yml.
Plus two structural gaps in §4 "Choosing an issue type":
-
The decision table has no Feature row. Five rows, worked in order, "first yes wins", and
row 4 is "Does it need child issues to finish? → PRD". An agent following the documented
algorithm still lands on PRD for every would-be Feature, so the new type is unreachable by the
process meant to select it. -
The hierarchy tree has no Feature level:
Milestone (M0, M1) └── PRD the approvable unit; holds acceptance criteria ├── Task executable child: one branch, one PR ├── Bug ├── Enhancement └── ADRIt also annotates PRD as "holds acceptance criteria", which this PR moves to Feature in
labels.yml.
In fairness, #507 under-scoped this. Its Definition of Done lists four items — form, label,
checker schema, task-template routing — and never mentions AGENTS.md. So this is a faithfully
executed incomplete brief, not an author oversight. The same gap exists in
buzz-infrastructure#128/#129, and the fix is the same: add the §4 Feature row, the tree level,
and correct rule 4 and the line-182 count, in this PR.
Note line 182 is a fourth occurrence I did not flag on #129. It applies there too.
High 1 — a Task still cannot record a Feature as its parent
This PR updates the instructions about children and leaves the field about parents untouched.
02-task.yml's parent input is immediately below the edited intro and unchanged, and
launchpad-issue-check.yml's type:task entry still requires the heading Parent PRD.
So from the first Feature onward, every Task under one has a real parent it cannot name — it
either skips the new level in its body, or writes a Feature number under a heading that says PRD.
This is the finding most likely to leave a mess that is expensive to unpick, because it corrupts
data rather than documentation: every Task filed between merge and the fix carries a wrong parent,
and re-deriving the right one later means reading each Task to work out which Feature it belonged
to. Tracked for the companion repo as buzz-infrastructure#131; this repo needs its own.
High 2 — the two new fields are the two the checker cannot actually enforce
The REQUIRED entry this PR adds is correct and matches the form. But the check tests only that
a heading exists and that the text under it is non-empty after .strip(), and 07-feature.yml
prefills both new textareas with checkbox skeletons. A skeleton is non-empty, so it passes.
Simulated against this PR's own REQUIRED entry and the form's own prefilled defaults — a filer
who typed nothing into either textarea:
### Acceptance criteria ### Child issues ### Milestone
- [ ] - [ ] # banana
- [ ]
- [ ]
-> problems: NONE — this body PASSES the check
So a type:feature issue passes CI with no acceptance criteria, no child issues, and a milestone
title that is not a milestone. Those three are the entire substance of the type — the form's own
instructions call the child list "the feature's progress bar".
The Milestone field is the sharpest case: instruction 7 says it "makes the intent checkable",
and nothing checks it.
This weakness is inherited, not introduced here — 02-task.yml's "Definition of done" has
the same hole on launchpad today. Flagging it on this PR because this PR adds two more
instances. Tracked as buzz-infrastructure#130, which is the same defect in the shared checker
logic; worth fixing in both repos together since the two workflows share the pattern.
Medium — the new PRD description makes 48 existing child issues read as malformed
labels.yml rewrites type:prd to "Problem, evidence and success criteria — delivered through
child features". No PRD in this repo has a single Feature child:
PRD #289 → {"type:task": 30}
PRD #109 → {"type:task": 11, "type:bug": 5, "type:adr": 1, "type:enhancement": 1}
48 issues across two PRDs, all filed correctly under the rules in force at the time. A label
description is the shortest and most-read statement of a convention, so someone will reasonably
conclude these are mis-structured and start re-parenting them through newly-invented Features.
That would also break AGENTS.md's deliberate ADR relationship — "A PRD's open questions are
raised as ADR issues, parented to that PRD" — which puts ADRs on the PRD, not on a Feature.
Either say "features and tasks", or state that direct PRD→Task parenting stays valid.
#507 rightly scopes retro-typing out; the label text is what will drive it anyway.
Low — Feature sorts last in the New Issue chooser
Templates order by filename, so 07-feature.yml lands after 06-agent-workflow.yml: PRD, Task,
Enhancement, Bug, ADR, Agent workflow, Feature. A level-2 concept appears below the
specialised form, while §4's decision list is explicit that order carries meaning. Cosmetic, and
the numbering is the only thing conveying hierarchy at the chooser.
This PR closes a bug I filed against this repo
#511 — "type:feature has a label but no form or validation schema, so the issue-body check
passes anything" — is fixed by this PR. It adds both missing pieces, and the schema entry is
exactly the six sections #511 said were absent. I have commented there pointing at this PR; it
should close on merge rather than stand as separate work. The residual validation weakness
described in High 2 survives this PR and is the part that still needs its own fix.
Assessment
The change is well-shaped and the reasoning behind it is sound — a Feature level between PRD and
Task is a real gap, and doing form + label + schema in one commit is the right unit, which is
precisely what made #511 findable as a defect in the pre-existing state.
Two things I would keep as-is: the 07-feature.yml instruction that Outcome names the
capability, not the implementation (with the Redis-cache counterexample), and the "if you need
more than ~7 lines, split the feature" bound on acceptance criteria. Both are the kind of
guidance that stops a template degrading into a form people fill in without thinking.
Nothing here questions the Feature type itself. The blocker is four lines of AGENTS.md that
this PR's brief forgot to ask for. Happy to re-review on push.
…keeps tasks valid (#507) Review fixes for #509: decision table gains the Feature row, hierarchy tree gains the Feature level with a no-re-parenting note for pre-Feature tasks, rule 4 relabels task-with-children to Feature, specialised-form count fixed, and the type:prd description says 'features and tasks' so the 48 existing direct task children stay well-formed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>
|
Re-review requested — pushed ae756e3 addressing the review. Disposition per finding: Blocker (AGENTS.md contradictions) — fixed in this PR. All four sites: §4 now says six types; the decision table gains a PRD row sharpened to problem-plus-evidence and a Feature row (needs-children → Feature), so the documented algorithm reaches the new type; the hierarchy tree carries the Feature level (with ADR placement at both feature and PRD level — a decision only one feature depends on sits under that feature, one that several depend on sits at PRD level); rule 4 now relabels a task-with-children to Feature; the specialised-form count on the old line 182 reads six. Medium (48 existing children read as malformed) — fixed in this PR. High 1 (Task cannot name a Feature parent) — agreed, tracked as #512 (mirror of buzz-infrastructure#131), scoped to land without failing the back-catalogue on edit. High 2 (checker passes prefilled skeletons) — agreed it's inherited; deferring to buzz-infrastructure#130's shared-checker fix, applied to both repos together rather than forking the pattern here. Low (chooser ordering) — acknowledged, not taking in this PR: renumbering the six existing forms churns every filename reference in AGENTS.md and muscle memory for a cosmetic gain; if the numbering bites in practice it can ride along with #512's template touch. #511 — this PR now carries Also appreciated the search-method transparency in the acknowledgement — the withdrawn-blocker loop closes cleanly here. |
serina-mcfall
left a comment
There was a problem hiding this comment.
Re-review — the blocker is addressed at all four sites. No blocker remains.
Agent-authored under @serina-mcfall's instruction. I do not approve; this records what I verified.
Blocker (AGENTS.md contradicted the templates) — fixed. All four flagged sites, plus both structural gaps:
$ git show origin/task/feature-issue-type-507:launchpad/AGENTS.md | grep -n "Six types\|A Task never has children\|specialised form beyond"
104:Six types. **Exactly one `type:` label per issue** — a type never modifies another
152:4. **A Task never has children.** If a Task grows children, it was a Feature — relabel it.
189:There is one specialised form beyond the six types: **Agent workflow proposal**
$ ... | grep -n "Feature"
115:| 5 | Does it need **child issues** to finish? | **Feature** | One demonstrable capability; holds acceptance criteria and decomposes into tasks |
126: ├── Feature one demonstrable capability; holds acceptance criteria
The decision table now reaches Feature (:115), so the documented algorithm can select the new type — that was the substantive half of the blocker, not just the count.
Medium (48 existing children read as malformed) — fixed, and better than asked.
$ git show origin/task/feature-issue-type-507:launchpad/labels.yml | grep -A2 "type:prd"
description: "Problem, evidence and success criteria — delivered through child features and tasks"
$ ... AGENTS.md | sed -n '137p'
Tasks filed before the Feature level existed parent directly to their PRD; that
The explicit migration note in the tree is the part that stops someone re-parenting the back catalogue. Good addition.
High 1 (a Task cannot name a Feature parent) — accepted as tracked. #512 exists and is OPEN: "task: let a Task record a Feature as its parent — field, checker heading, and migration note". Scoping it separately so it does not fail the back-catalogue on edit is the right call.
High 2 (checker passes prefilled skeletons) — accepted as deferred to buzz-infrastructure#130's shared-checker fix. Fixing the pattern once across both repos beats forking it here.
Low (chooser ordering) — declined, and the reasoning holds. Renumbering six forms churns every filename reference in AGENTS.md for a cosmetic gain.
Nothing new found. Two Highs are deferred to filed issues rather than fixed here, which is a judgement call for @serina-mcfall rather than mine — but neither is a blocker under this repo's rubric, and both are findable.
Reviewed at head ae756e326. Every grep above was run by me at that ref.
🤖 Review drafted by Claude Code (claude-opus-5) for @serina-mcfall.
Summary
Adds the
type:featureissue type: a new issue form (07-feature.yml), the label in launchpad/labels.yml, and the six required body sections in launchpad-issue-check.yml. This makes the agreed hierarchy Milestone > PRD > Feature > Task expressible — features are one demonstrable capability under a PRD, decomposed into agent-executable tasks, with checkable acceptance criteria and a child task-list as the progress bar. The task template now routes would-be parents to the Feature form instead of PRD.Related issue
Closes #507
Closes #511
Issue type
Task
Agent provenance
Objective
A
type:featureissue type this repo can validate: form, label, and CI body-check schema.Impacted components
.github/ISSUE_TEMPLATE/07-feature.yml (new)
.github/ISSUE_TEMPLATE/02-task.yml
.github/workflows/launchpad-issue-check.yml
launchpad/labels.yml
Approach and rejected alternatives
Design follows researched practice (GitHub issue-forms docs; Vite/Angular/GitLab exemplar templates; Atlassian/AltexSoft on testable acceptance criteria): field labels become the
### HeadingsCI validates; form-siderequireddoes not bind agents filing viagh, so the workflow check carries the real contract. Rejected: GitHub sub-issues for the child list (they live outside the issue body, invisible to the body checker; task-list checkboxes render a progress bar and are editable by agents with a plain issue edit); Given/When/Then acceptance criteria (a checklist of independently verifiable statements fits mixed human+agent verification better); a dropdown Milestone field (open milestones change; free text validated by convention avoids template rot). Mirrors buzz-infrastructure PR #129 minus that repo's Routing gate, keeping the type identical in both repos as launchpad/labels.yml requires.Verification
Command run:
Raw output (run against the identical infra variant of the template; the buzz file differs only by the absent Routing checkbox block):
Not verified
Security implications
None — issue-tracking metadata only. No workflow permissions change; the checker edit is data in the existing validation dict.
Escalations