Skip to content

Commit 347bc0b

Browse files
committed
docs(delivery): GitHub Issues as spec and queue — kind:state labels, issue forms, spec templates, DELIVERY.md, handoffs
1 parent b9d1221 commit 347bc0b

11 files changed

Lines changed: 601 additions & 0 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Bug report
2+
description: Something Simlock does that it should not, or does not do that it should.
3+
labels: ["bug:new"]
4+
body:
5+
- type: textarea
6+
id: observed
7+
attributes:
8+
label: What happened
9+
description: What Simlock did, as precisely as you can. Paste the exact command and its output where there is one.
10+
validations:
11+
required: true
12+
- type: textarea
13+
id: expected
14+
attributes:
15+
label: What you expected
16+
validations:
17+
required: true
18+
- type: textarea
19+
id: steps
20+
attributes:
21+
label: How to reproduce
22+
description: Steps from a fresh state. If it only happens sometimes, say how often.
23+
placeholder: |
24+
1. simlock daemon start
25+
2. simlock lease --platform ios
26+
3. ...
27+
validations:
28+
required: true
29+
- type: textarea
30+
id: environment
31+
attributes:
32+
label: Environment
33+
description: Simlock version, platform (iOS, Android, or both), OS version, and the output of `simlock doctor` if it runs.
34+
validations:
35+
required: true
36+
- type: textarea
37+
id: evidence
38+
attributes:
39+
label: Logs and evidence
40+
description: Daemon logs, screenshots, or anything else that shows the problem.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Blank issues stay enabled: feature and task specs are authored by the
2+
# maintainer from docs/internal/templates/, not through a form.
3+
blank_issues_enabled: true
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Feature request
2+
description: Something you want Simlock to do that it does not do today.
3+
labels: ["request:new"]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
Describe the problem, not the solution. If the request is taken up, a maintainer writes a separate spec issue and links it here; this issue stays yours and stays open until that feature ships.
9+
- type: textarea
10+
id: problem
11+
attributes:
12+
label: The problem
13+
description: What you are trying to do and what gets in the way.
14+
validations:
15+
required: true
16+
- type: textarea
17+
id: who
18+
attributes:
19+
label: Who runs into this
20+
description: You, a team, a coding agent, a CI job? What does that situation look like?
21+
validations:
22+
required: true
23+
- type: textarea
24+
id: proposal
25+
attributes:
26+
label: What you would like to happen
27+
description: The behaviour you would want, from the outside. Implementation ideas are welcome but optional.
28+
- type: textarea
29+
id: context
30+
attributes:
31+
label: Anything else
32+
description: Workarounds you use today, related issues, links.

.github/labels.json

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
[
2+
{
3+
"name": "request:new",
4+
"color": "bfdadc",
5+
"description": "Inbox. Never picked up, body never edited."
6+
},
7+
{ "name": "bug:new", "color": "d73a4a", "description": "Reported. Nobody has looked yet." },
8+
{
9+
"name": "bug:triage",
10+
"color": "d73a4a",
11+
"description": "An agent may reproduce it and write the triage report."
12+
},
13+
{
14+
"name": "bug:needs-info",
15+
"color": "d73a4a",
16+
"description": "Could not reproduce. Waiting on the reporter."
17+
},
18+
{ "name": "bug:ready", "color": "d73a4a", "description": "An agent may fix it." },
19+
{
20+
"name": "feature:spec",
21+
"color": "0e8a16",
22+
"description": "Business or technical spec in progress."
23+
},
24+
{
25+
"name": "feature:ready",
26+
"color": "0e8a16",
27+
"description": "No sub-issues; one PR delivers the whole feature."
28+
},
29+
{
30+
"name": "feature:planned",
31+
"color": "0e8a16",
32+
"description": "Split into tasks. Never picked up itself."
33+
},
34+
{
35+
"name": "task:draft",
36+
"color": "5319e7",
37+
"description": "Scope written; technical spec, approval, or deps missing."
38+
},
39+
{ "name": "task:ready", "color": "5319e7", "description": "An agent may implement it." },
40+
{
41+
"name": "documentation",
42+
"color": "0075ca",
43+
"description": "Improvements or additions to documentation"
44+
},
45+
{
46+
"name": "dependencies",
47+
"color": "0366d6",
48+
"description": "Pull requests that update a dependency file"
49+
},
50+
{
51+
"name": "github_actions",
52+
"color": "000000",
53+
"description": "Pull requests that update GitHub Actions code"
54+
}
55+
]

.github/workflows/labels.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Labels
2+
3+
# Keeps the repo's labels equal to .github/labels.json. Creates and updates
4+
# only; a label that is no longer listed is deleted by hand, on purpose.
5+
6+
on:
7+
push:
8+
branches: [main]
9+
paths: [.github/labels.json]
10+
workflow_dispatch:
11+
12+
permissions: {}
13+
14+
jobs:
15+
sync:
16+
name: Sync labels
17+
runs-on: ubuntu-24.04
18+
permissions:
19+
issues: write
20+
timeout-minutes: 5
21+
steps:
22+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23+
with:
24+
persist-credentials: false
25+
- name: Create or update every listed label
26+
env:
27+
GH_TOKEN: ${{ github.token }}
28+
GH_REPO: ${{ github.repository }}
29+
run: |
30+
jq -c '.[]' .github/labels.json | while read -r label; do
31+
name=$(jq -r .name <<<"$label")
32+
color=$(jq -r .color <<<"$label")
33+
description=$(jq -r .description <<<"$label")
34+
gh label create "$name" --color "$color" --description "$description" --force
35+
done

AGENTS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ changes in this repo:
2525
docs (`docs/`) vs. maintainer/agent docs (`docs/internal/`); no ADR links
2626
or internal-doc links from end-user docs; nothing the tool prints names a
2727
file path in this repo.
28+
- [delivery.md](docs/internal/agent-rules/delivery.md) — GitHub Issues as
29+
spec and queue: one `<kind>:<state>` label per issue, agents act only on
30+
`*:ready` and `bug:triage`, the body is the spec and comments are
31+
discussion, reporters' issues are never rewritten, branches are
32+
`<kind>/<n>`, handoffs are one `## Handoff` comment per stop.
2833

2934
So are the accepted records in [docs/internal/adr/](docs/internal/adr/). An ADR marked
3035
_Accepted — not yet implemented_ means the documentation already describes the
@@ -49,6 +54,10 @@ End-user docs live directly under [docs/](docs/) and must stay self-contained
4954
Maintainer/agent docs live under [docs/internal/](docs/internal/):
5055

5156
- [ARCHITECTURE.md](docs/internal/ARCHITECTURE.md) — high-level architecture overview
57+
- [DELIVERY.md](docs/internal/DELIVERY.md) — how work flows through GitHub
58+
Issues: the three walkthroughs, handoffs, what is automated, where ADRs fit
59+
- [templates/](docs/internal/templates/) — the feature and task spec bodies a
60+
spec session writes
5261
- [EVENTS.md](docs/internal/EVENTS.md) — the same catalog with rationale and ADR references
5362
- [IDEAS.md](docs/internal/IDEAS.md) — post-v1 ideas; don't implement these unless asked
5463
- [KNOWN-PITFALLS.md](docs/internal/KNOWN-PITFALLS.md) — accepted gaps and their planned fixes

docs/internal/DELIVERY.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# How work flows
2+
3+
GitHub Issues is the specification and the queue. An issue's body is what an
4+
agent builds against; its label is the only thing that tells an agent whether
5+
it may act. This page is the maintainer's manual for that model. The binding
6+
rules are in [agent-rules/delivery.md](agent-rules/delivery.md); this page
7+
explains how they fit together in practice.
8+
9+
## The model in five sentences
10+
11+
Every issue carries exactly one `<kind>:<state>` label, and the prefix is the
12+
kind. Agents act only on `bug:triage`, `bug:ready`, `feature:ready` and
13+
`task:ready`; everything else is either an unread claim from outside or an
14+
unfinished spec. The body is the spec and comments are discussion, so a
15+
comment changes nothing until a spec session folds it into the body. A
16+
reporter's issue is never rewritten: bugs are triaged in a comment, and a
17+
feature that came from a request is a new issue the maintainer owns. What
18+
happens after `ready` is read from GitHub itself — assignee, linked pull
19+
request, closed — not from a label.
20+
21+
| Label | Meaning |
22+
| ----------------- | -------------------------------------------------------- |
23+
| `request:new` | Inbox. Never picked up, body never edited. |
24+
| `bug:new` | Reported. Nobody has looked yet. |
25+
| `bug:triage` | An agent may reproduce it and write the triage report. |
26+
| `bug:needs-info` | Could not reproduce. Waiting on the reporter. |
27+
| `bug:ready` | An agent may fix it. |
28+
| `feature:spec` | Business or technical spec in progress. |
29+
| `feature:ready` | No sub-issues; one PR delivers the whole feature. |
30+
| `feature:planned` | Split into tasks. Never picked up itself. |
31+
| `task:draft` | Scope written; technical spec, approval or deps missing. |
32+
| `task:ready` | An agent may implement it. |
33+
34+
## A bug, from report to fix
35+
36+
1. Someone opens a bug through the form. It arrives as `bug:new`. Nothing
37+
happens.
38+
2. The maintainer reads it. If it sounds real, they add `bug:triage`. That is
39+
the whole delegation.
40+
3. An agent running `triage-bug` assigns itself, reproduces the bug as a
41+
failing test whose title states the claim, finds the root cause, pushes
42+
only the test to `bug/<n>-repro`, and posts one comment with five
43+
sections: Reproduction, Root cause, Simplest fix, Alternatives rejected,
44+
Risk. It opens no pull request, and it unassigns itself when done.
45+
4. If it could not reproduce, it swaps the label to `bug:needs-info` and says
46+
exactly what is missing. A reply from the reporter moves the issue back to
47+
`bug:triage` on its own; two weeks of silence closes it.
48+
5. The maintainer reads the report. Agree: add `bug:ready`. Disagree: reply
49+
with what is wrong and re-add `bug:triage`; the next agent starts from
50+
that reply.
51+
6. An agent running `deliver` claims the `bug:ready` issue, branches from the
52+
repro branch, and opens a PR that closes the issue. The triage test is now
53+
the regression test. Merge closes the bug.
54+
55+
## A feature, delivered as one PR
56+
57+
1. The maintainer creates a `feature:spec` issue, or an outside request
58+
arrives as `request:new` and the maintainer decides to take it up. Nothing
59+
happens to a request by default.
60+
2. First spec session. The agent interviews the maintainer and writes the
61+
business half of [templates/feature.md](templates/feature.md): Problem,
62+
Who it is for, Outcome, Non-goals, Completion conditions, Open questions.
63+
It says what a user can do afterwards, never how. If the feature came from
64+
a request, the session creates the feature issue, links it to the request,
65+
and comments on the request so the reporter knows where to look. The
66+
request stays open until the feature ships.
67+
3. Discussion happens, on the feature or on the request, in comments. Nobody
68+
edits the body by hand.
69+
4. Second spec session. The agent first lists every comment posted since the
70+
body was last edited, on both threads, as a set of proposed changes; the
71+
maintainer accepts or rejects each. Then it interviews for the Technical
72+
spec section. Any decision that constrains more than one future change or
73+
would be expensive to reverse becomes an ADR at _Proposed_, listed under
74+
Decisions. The session ends by editing the body and leaving a one-line
75+
"Spec updated" comment.
76+
5. Once Open questions is empty and every linked ADR is accepted, the
77+
maintainer adds `feature:ready`. The ADRs move to _Accepted — not yet
78+
implemented_.
79+
6. An agent running `deliver` claims it and opens a PR whose body walks every
80+
completion condition. Merge closes the feature, and its ADRs flip to
81+
_Accepted_.
82+
83+
## A feature, split into tasks
84+
85+
Steps 1 to 4 are the same, but the second session ends differently: instead
86+
of a Technical spec section on the feature, it produces sub-issues.
87+
88+
5. Each task is a native sub-issue of the feature, labelled `task:draft`, with
89+
a body from [templates/task.md](templates/task.md): Scope, Technical spec,
90+
Done when, Out of scope, Depends on, and an approval checkbox. The feature
91+
becomes `feature:planned` and keeps only its business spec, Decisions and
92+
the task list.
93+
6. The maintainer ticks the approval box on each task, once, at planning
94+
time. From then on the automation promotes a task to `task:ready` the
95+
moment its box is ticked, its Technical spec has content, and every issue
96+
under Depends on is closed. Nobody re-reads the dependency graph by hand.
97+
7. Agents claim `task:ready` issues one PR each. As tasks close, the ones they
98+
unblocked become ready on their own.
99+
8. When the last sub-issue closes, the automation comments on the feature
100+
that completion conditions are due. An agent proves them against `main`,
101+
usually with an end-to-end run, and reports in a comment. The maintainer
102+
closes the feature.
103+
104+
## Handoffs between agents
105+
106+
An agent that stops before its PR is merged — out of context, blocked, or
107+
told to stop — unassigns itself and leaves one comment headed `## Handoff`
108+
with four sections: Done, Not done, Findings, Blocked on. The branch is the
109+
other half of the handoff: because it is always `<kind>/<n>`, the next agent
110+
knows where the commits are without being told. A handoff records the state
111+
of the work, never a change to the spec; if the work showed the spec is
112+
wrong, the handoff says so and the maintainer runs a revise spec session.
113+
Agents do not post progress updates, only handoffs, so the one comment that
114+
matters is easy to find.
115+
116+
## What is automated and what is not
117+
118+
The workflow in `.github/workflows/issue-state.yml` handles the transitions
119+
that are mechanical: adding a state label removes the previous one, so every
120+
transition is a single add; `task:draft` becomes `task:ready` when approved,
121+
specified and unblocked; a reporter's reply moves `bug:needs-info` back to
122+
`bug:triage`; a silent `bug:needs-info` closes after two weeks; a feature
123+
whose last sub-issue closed gets the completion-conditions note. The repo's
124+
skills — `spec-session`, `triage-bug`, `deliver` — handle the transitions an
125+
agent makes as part of its own procedure.
126+
127+
Four transitions are judgments and stay manual on purpose: `bug:new` to
128+
`bug:triage`, `bug:triage` to `bug:ready`, `feature:spec` to
129+
`feature:ready`, and the approval box on each task. Each is one click.
130+
131+
## Where ADRs fit
132+
133+
A feature answers _what_ and _why_ in business terms. An ADR answers _how_,
134+
but only for choices that constrain more than one task or would be expensive
135+
to reverse. A task answers _how_ for exactly one PR. Most features never need
136+
an ADR; the ones that fix a protocol shape or an ownership model do. An ADR
137+
is born in a spec session, is _Proposed_ while the feature is `feature:spec`,
138+
_Accepted — not yet implemented_ while the feature is open, and _Accepted_
139+
when it closes. See [adr/README.md](adr/README.md).
140+
141+
## Pointers
142+
143+
- Rules: [agent-rules/delivery.md](agent-rules/delivery.md)
144+
- Templates: [templates/feature.md](templates/feature.md),
145+
[templates/task.md](templates/task.md)
146+
- Reporter forms: `.github/ISSUE_TEMPLATE/`
147+
- Labels: `.github/labels.json`, synced by `.github/workflows/labels.yml`
148+
- Automation: `.github/workflows/issue-state.yml`
149+
- Skills: `.claude/skills/spec-session`, `.claude/skills/triage-bug`,
150+
`.claude/skills/deliver`

docs/internal/adr/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ Status values:
1818
toward it should treat the documentation as the specification.
1919
- **Superseded by NNNN** — no longer binding; read the replacement.
2020

21+
An ADR's status follows the feature that produced it, per
22+
[agent-rules/delivery.md](../agent-rules/delivery.md): it is *Proposed*
23+
while the feature is still `feature:spec`, becomes *Accepted — not yet
24+
implemented* when the feature leaves that state, and becomes *Accepted*
25+
when the feature closes. An ADR that is *Accepted — not yet implemented*
26+
with no open feature behind it is a gap: either the feature is missing or
27+
the status is stale.
28+
2129
| ADR | Title | Status |
2230
|---|---|---|
2331
| [0001](0001-simlock-owned-device-roots.md) | Simlock-owned device roots | Accepted |

0 commit comments

Comments
 (0)