methodology-framework 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- methodology_framework/__init__.py +17 -0
- methodology_framework/__main__.py +28 -0
- methodology_framework/bootstrap_jira.py +427 -0
- methodology_framework/build_playbook.py +172 -0
- methodology_framework/jira_shapes/__init__.py +0 -0
- methodology_framework/jira_shapes/automation_rules.yaml +85 -0
- methodology_framework/jira_shapes/custom_fields.yaml +44 -0
- methodology_framework/jira_shapes/workflow.yaml +135 -0
- methodology_framework/playbooks/scrum-router.body.md +217 -0
- methodology_framework/populate_acus.py +210 -0
- methodology_framework/register_playbook_with_devin.py +294 -0
- methodology_framework/specs/devin-story-format.md +536 -0
- methodology_framework/sync_stories_to_jira.py +1087 -0
- methodology_framework/templates/github_workflows/populate-story-acus-caller.yml +29 -0
- methodology_framework/templates/story.md +152 -0
- methodology_framework-0.1.0.dist-info/METADATA +264 -0
- methodology_framework-0.1.0.dist-info/RECORD +20 -0
- methodology_framework-0.1.0.dist-info/WHEEL +5 -0
- methodology_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
- methodology_framework-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# Devin / Jira story format
|
|
2
|
+
|
|
3
|
+
> **Purpose.** A consistent, paste-friendly story format that lets an autonomous coding agent (Devin) reproduce the system from this repo. Each story is a small, testable unit of work tied to one or more REQ-ids in [`../docs/use-cases.md`](../docs/use-cases.md). Bryan pastes story bodies into Jira; Jira assigns its own keys; the repo files remain the canonical source.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## TL;DR
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
docs/stories/
|
|
11
|
+
├── _template.md # blank skeleton — copy when starting a new story
|
|
12
|
+
├── phase1/ # backfill of Phase-1 work so Devin can reproduce it
|
|
13
|
+
│ └── initial-database-schema.md
|
|
14
|
+
└── phase2/ # forward stories for the fully functional system
|
|
15
|
+
└── simulator-service-skeleton.md
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- One `.md` file per story. **Slug filenames only** — no `STORY-NNN`, no IDs (Jira assigns its own keys).
|
|
19
|
+
- Group by phase folder + a `labels:` frontmatter field. Bryan sorts epics in Jira after pasting.
|
|
20
|
+
- Body opens with a `**Requirement(s):**` line citing the REQ-id(s) the story implements.
|
|
21
|
+
- One story = one PR-sized unit of work, roughly half a day to two days for an autonomous agent.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Why this format
|
|
26
|
+
|
|
27
|
+
Three constraints shaped it:
|
|
28
|
+
|
|
29
|
+
1. **Devin reads the body verbatim.** Anything not in the body — frontmatter notes, repo conventions buried in CLAUDE.md, "obviously do X" tribal knowledge — is invisible to Devin. The body must be self-contained.
|
|
30
|
+
2. **Bryan pastes into Jira.** The body must render cleanly in Jira's Markdown subset (headings, lists, code blocks, links — yes; HTML, frontmatter, exotic syntax — no). The frontmatter stays in the repo file but is not pasted.
|
|
31
|
+
3. **Traceability matters.** Every story has to cite a `REQ-id` so we can answer "which requirement is this implementing?" without re-reading the source docs.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Filename and location
|
|
36
|
+
|
|
37
|
+
- Path: `docs/stories/{phase1|phase2}/<slug>.md`
|
|
38
|
+
- Slug: short, kebab-case, descriptive. **No numbering.** Examples:
|
|
39
|
+
- ✅ `initial-database-schema.md`
|
|
40
|
+
- ✅ `add-owner-team-filter-to-board.md`
|
|
41
|
+
- ✅ `simulator-service-skeleton.md`
|
|
42
|
+
- ❌ `STORY-042-...` — no story IDs (Jira assigns them)
|
|
43
|
+
- ❌ `001-...` — same
|
|
44
|
+
- If two stories collide on slug, narrow the slug (`add-board-filter-by-owner-team` and `add-board-filter-by-status`) rather than numbering.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Frontmatter spec
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
---
|
|
52
|
+
title: Initial database schema and SQLAlchemy ORM models
|
|
53
|
+
type: task
|
|
54
|
+
labels: [phase1-backfill, schema, db, foundation]
|
|
55
|
+
requirements: [REQ-VIZ-12, REQ-PIPE-4.15, REQ-PIPE-6.2, REQ-POL-2.3]
|
|
56
|
+
depends_on: []
|
|
57
|
+
parent: null
|
|
58
|
+
tasks: []
|
|
59
|
+
estimate: 24h
|
|
60
|
+
jira_key: null
|
|
61
|
+
---
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Field guide:**
|
|
65
|
+
|
|
66
|
+
| Field | Required | Notes |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `title` | yes | One-line title. Becomes the Jira summary. Don't restate the slug. |
|
|
69
|
+
| `type` | yes | `task` or `story`. Default is `task` (a leaf ticket — one PR). Use `story` only when the ticket aggregates child tasks (see "Story vs task — when to bundle" below). |
|
|
70
|
+
| `labels` | yes | Lowercase kebab-case. Used to group in Jira. Examples: `phase1-backfill`, `phase2`, `simulator`, `ui`, `api`, `db`, `schema`, `ingest`, `read-endpoints`, `auth`, `ci`, `docs`. Pick 2–4. |
|
|
71
|
+
| `requirements` | yes | One or more REQ-ids from `../docs/use-cases.md` Part B. The story body must justify how it covers each. |
|
|
72
|
+
| `depends_on` | no | Slug filenames (without `.md`) of other tickets that must be complete first. Empty list `[]` is fine. Distinct from `parent` — a leaf can depend on another leaf without being a child of it. |
|
|
73
|
+
| `parent` | no | Only on `type: task` tickets that belong to a parent story. The slug (without `.md`) of the parent. `null` if the task is flat. |
|
|
74
|
+
| `tasks` | no | Only on `type: story` tickets. List of slugs of the leaf tasks the parent collects. |
|
|
75
|
+
| `estimate` | yes | Agent-time estimate, **always in raw hours** (agents run continuously; there is no 8h workday assumption). **For `type: task`: hard cap of `24h`.** Tasks exceeding 24h must be split. For `type: story` (parents): the sum of child estimates; the parent body must include an "Estimate breakdown" table showing the leaf rollup. Express as `2h`, `8h`, `24h`, `48h` — no `d` unit. |
|
|
76
|
+
| `jira_key` | yes | Jira ticket key for this story (e.g. `SCRUM-123`). **Sync-managed, not author-managed.** Authors write `null` on initial draft; the Jira sync workflow writes the assigned key back to the frontmatter on first sync. The router playbook uses this field to resolve a Jira ticket back to its story file. Once set, leave it alone — renaming a story does not change its `jira_key`. |
|
|
77
|
+
|
|
78
|
+
The frontmatter is for repo-internal organization. **It is not part of what Bryan pastes into Jira.**
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Body structure
|
|
83
|
+
|
|
84
|
+
Ten sections, in this order, every time. Devin and humans both rely on the order — don't shuffle. Sections 1–8 are authored when the story PR is opened; section 9 (`## Scoping notes (pre-execution)`) is populated by the agent at implementation-session start as the first commit on the implementation branch; section 10 (`## Post-execution notes`) is populated by the agent before opening the implementation PR per the feedback-loop convention (see `## Feedback loop and post-execution notes` below).
|
|
85
|
+
|
|
86
|
+
```markdown
|
|
87
|
+
# {Title}
|
|
88
|
+
|
|
89
|
+
**Requirement(s):** REQ-VIZ-12, REQ-PIPE-4.15, REQ-PIPE-6.2, REQ-POL-2.3
|
|
90
|
+
|
|
91
|
+
## Context
|
|
92
|
+
…why this story exists, in 1–3 sentences. Cite related stories or docs by path.
|
|
93
|
+
|
|
94
|
+
## Goal
|
|
95
|
+
…the deliverable in one sentence. "Add X" / "Wire up Y" / "Replace Z with …".
|
|
96
|
+
|
|
97
|
+
## Acceptance criteria
|
|
98
|
+
- …testable bullet 1
|
|
99
|
+
- …testable bullet 2
|
|
100
|
+
- …
|
|
101
|
+
|
|
102
|
+
## Files
|
|
103
|
+
- `path/to/file.ext` — (new | modified) — short note on the change
|
|
104
|
+
- …
|
|
105
|
+
|
|
106
|
+
## Validation
|
|
107
|
+
```bash
|
|
108
|
+
# concrete commands the reviewer (or Devin) runs to confirm the story is done
|
|
109
|
+
docker compose up -d --build
|
|
110
|
+
docker compose exec api …
|
|
111
|
+
curl …
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Expected: …human-readable description of expected output.
|
|
115
|
+
|
|
116
|
+
## Out of scope
|
|
117
|
+
- …explicitly NOT this story (next story / followup / different concern)
|
|
118
|
+
|
|
119
|
+
## Dependencies
|
|
120
|
+
- `slug-of-prior-story` — short reason
|
|
121
|
+
- (or "None.")
|
|
122
|
+
|
|
123
|
+
## Execution recipe
|
|
124
|
+
|
|
125
|
+
### Procedure
|
|
126
|
+
1. …imperative step, action verb first
|
|
127
|
+
2. …
|
|
128
|
+
3. …Run the commands in `## Validation` and confirm green.
|
|
129
|
+
|
|
130
|
+
### Inputs needed from user
|
|
131
|
+
- …or "None."
|
|
132
|
+
|
|
133
|
+
### Story-specific advice
|
|
134
|
+
- …(optional; omit if empty)
|
|
135
|
+
|
|
136
|
+
### Story-specific forbidden actions
|
|
137
|
+
- …(optional; omit if empty)
|
|
138
|
+
|
|
139
|
+
## Scoping notes (pre-execution)
|
|
140
|
+
…written by the agent at session start, before any implementation work. See `## Pre- and post-execution discipline` below.
|
|
141
|
+
|
|
142
|
+
## Post-execution notes
|
|
143
|
+
…populated by the agent before opening the implementation PR. See `## Feedback loop and post-execution notes`.
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Section-by-section guide:**
|
|
147
|
+
|
|
148
|
+
- **`# {Title}`** — same string as the frontmatter `title`. Don't reformat (no leading emoji, no "TASK:" prefix).
|
|
149
|
+
- **`**Requirement(s):**` line** — REQ-ids verbatim, comma-separated. Repeats the frontmatter field on purpose: it's the first thing a reader sees and it's also the first thing Devin keys off when planning the change.
|
|
150
|
+
- **`## Context`** — short. Why this exists. Link to docs (`../docs/alignment.md §6`, `../docs/use-cases.md UC-04`) rather than re-explaining them.
|
|
151
|
+
- **`## Goal`** — one sentence. If you can't, the story is too big — split it.
|
|
152
|
+
- **`## Acceptance criteria`** — bullets, each testable. Avoid vague language ("works correctly", "looks good"). Prefer concrete checks ("`GET /api/v1/board?owner_team=PayFac` returns only rows where `service.owner_team == 'PayFac'`").
|
|
153
|
+
- **`## Files`** — every file Devin creates or modifies, with the path + new/modified flag + a short reason. This list is also the diff scope — anything not in this list is out of scope.
|
|
154
|
+
- **`## Validation`** — concrete commands a reviewer can run. Prefer `bash` blocks. Include expected output in plain prose underneath. The same commands serve Devin's self-check via the recipe's Procedure (next section).
|
|
155
|
+
- **`## Out of scope`** — name the things that look like this story but aren't. The cure for scope creep.
|
|
156
|
+
- **`## Dependencies`** — slugs (matching `depends_on` frontmatter) with one-line reasons. Or "None."
|
|
157
|
+
- **`## Execution recipe`** — strategy: how Devin goes from cold start to AC-satisfied state for THIS specific story. Sits between `Dependencies` (resolved) and `Scoping notes` (agent's pre-execution plan). Has four subsections — `Procedure` (required, 5–15 imperative steps; reference `## Validation` for verification rather than duplicating its commands), `Inputs needed from user` (required, default "None."), `Story-specific advice` (optional; omit if empty), `Story-specific forbidden actions` (optional; omit if empty). Universal forbidden actions and drift-trigger handling are **not** in the recipe — they live in the router playbook (`.devin/playbooks/scrum-router.devin.md`). Output specs / type signatures / API shapes are **not** in the recipe — they live in `Acceptance criteria` / `Files` / `Validation`. The recipe is purely additive: per-story imperative procedure that the existing 8 contract sections don't already carry. Length guideline: 10–30 lines typical; > 50 lines is a signal the story is too big or content belongs elsewhere. Canonical template: `methodology/templates/execution-recipe.template.md`.
|
|
158
|
+
- **`## Scoping notes (pre-execution)`** — structured YAML written by the agent at session start as the first commit on the implementation branch. Source of truth for the agent's pre-execution understanding. See `## Pre- and post-execution discipline` below.
|
|
159
|
+
- **`## Post-execution notes`** — structured YAML populated by the agent before opening the implementation PR. The unmodified template default is forbidden in a merged PR. See `## Feedback loop and post-execution notes` for the schema.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Pre- and post-execution discipline
|
|
164
|
+
|
|
165
|
+
Two agent-populated sections — `## Scoping notes (pre-execution)` and `## Post-execution notes` — turn the story file into the canonical in-git audit trail for what the agent planned and what actually happened. Together they serve four goals:
|
|
166
|
+
|
|
167
|
+
1. **Cross-surface continuity.** The same scoping output that appears in the Jira comment is committed to the story file, so operators working in Cowork, VS Code, or raw git all see the same pre-execution context without traversing Jira threads.
|
|
168
|
+
2. **Audit reconstructability.** A reviewer can reconstruct the agent's full session — plan, execution, and findings — from git history alone. No external system (Jira, Devin webapp) is required.
|
|
169
|
+
3. **Retrospective synthesis.** The synthesis pass (`runbook-net-new-via-agents.md` § 4.6) reads post-execution notes to draft structured retros and runbook updates. If findings live only in Jira comments, the synthesis pass can't consume them.
|
|
170
|
+
4. **Portability.** Adopting projects inherit the story template and playbook; both now require findings to be captured in git, not just a specific work-tracking tool.
|
|
171
|
+
|
|
172
|
+
### Scoping notes — purpose and rules
|
|
173
|
+
|
|
174
|
+
The `## Scoping notes (pre-execution)` section is the agent's response to the story's `Execution recipe`. Reading order: recipe (author → agent), then scoping (agent → reviewer), then post-exec (agent → next session).
|
|
175
|
+
|
|
176
|
+
**Rules:**
|
|
177
|
+
- The agent populates this section and commits it as the **first commit** on the implementation branch, with message `docs(stories): scope <story-slug>`.
|
|
178
|
+
- The commit happens during the **implementation phase only**. In scoping-only mode, the Jira comment captures the scoping output; the in-repo commit waits for the implementation session.
|
|
179
|
+
- The Jira scoping comment is a duplicate for operator convenience. The story file is the canonical record.
|
|
180
|
+
|
|
181
|
+
**Fields (YAML block):**
|
|
182
|
+
- `understanding_of_goal:` — free-form, 1–2 sentences
|
|
183
|
+
- `implementation_plan:` — list of steps
|
|
184
|
+
- `files_expected_to_touch:` — list of paths
|
|
185
|
+
- `ac_verification_approach:` — per-AC mapping
|
|
186
|
+
- `confidence:` — HIGH / MEDIUM / LOW (per the playbook's confidence-calibration anchors)
|
|
187
|
+
- `confidence_reasoning:` — free-form, 1–3 sentences
|
|
188
|
+
|
|
189
|
+
### Post-execution notes — purpose and rules
|
|
190
|
+
|
|
191
|
+
The `## Post-execution notes` section captures what actually happened during execution. Its YAML schema is documented in `## Feedback loop and post-execution notes` below.
|
|
192
|
+
|
|
193
|
+
**Rules:**
|
|
194
|
+
- The agent populates this section with concrete values **before opening the implementation PR**.
|
|
195
|
+
- The unmodified template default (`surprises: []`, `actual_hours: 0`, all fields at default) is **forbidden in a merged PR**. If a field genuinely has no content, write `# none observed` inline instead of leaving the template default.
|
|
196
|
+
- The `surprises` field is the single most important field for compounding lessons. If nothing was surprising, write that explicitly rather than leaving `[]`.
|
|
197
|
+
|
|
198
|
+
### Backfill discipline for in-flight stories
|
|
199
|
+
|
|
200
|
+
When this playbook version (1.2.0+) lands, in-flight stories (already started by an agent but not yet merged) should ideally be backfilled with scoping notes if a Jira scoping comment exists. Mechanical backfill is operator-driven; not enforced. Stories merged before 1.2.0 retain their empty post-execution-notes blocks as a historical fingerprint of the pre-discipline era.
|
|
201
|
+
|
|
202
|
+
### Worked example — populated scoping-notes block
|
|
203
|
+
|
|
204
|
+
From SCRUM-112 (UC-11 hotfix exception scenario):
|
|
205
|
+
|
|
206
|
+
```yaml
|
|
207
|
+
understanding_of_goal: >
|
|
208
|
+
Add a simulator scenario YAML and integration test for UC-11 (hotfix exception path).
|
|
209
|
+
The scenario drives a settlement-api candidate through full promotion (dev→prd),
|
|
210
|
+
then opens an exception_path with kind="hotfix" — verifying the exception opens,
|
|
211
|
+
PRD is deployed, and the exception remains open (close is deferred).
|
|
212
|
+
implementation_plan:
|
|
213
|
+
- "Read poster.py to confirm ExceptionPathOpenStep passes kind='hotfix' through."
|
|
214
|
+
- "Author simulator/scenarios/settlement-api-hotfix-exception.yaml with metadata, setup, and steps."
|
|
215
|
+
- "Add index row to simulator/scenarios/README.md."
|
|
216
|
+
- "Author integration test following the gateway-iat-blocked pattern."
|
|
217
|
+
- "Run validation: ruff check, ruff format, mypy --strict, pytest, integration test."
|
|
218
|
+
files_expected_to_touch:
|
|
219
|
+
- "simulator/scenarios/settlement-api-hotfix-exception.yaml"
|
|
220
|
+
- "simulator/scenarios/README.md"
|
|
221
|
+
- "simulator/tests/integration/test_settlement_api_hotfix_exception_e2e.py"
|
|
222
|
+
ac_verification_approach:
|
|
223
|
+
- "AC 1 (YAML validates): verified by load_scenario() + assertion on metadata fields and step count."
|
|
224
|
+
- "AC 2 (Integration test): GET /api/v1/candidates/... returns exception_paths[0].kind=hotfix, state=open."
|
|
225
|
+
confidence: HIGH
|
|
226
|
+
confidence_reasoning: >
|
|
227
|
+
All AC are concrete, all referenced files exist on main, the sole dependency
|
|
228
|
+
(simulator-poster-previous-pair-tracking) is merged, and the recipe procedure is mechanical.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Style notes for Devin-consumed stories
|
|
234
|
+
|
|
235
|
+
- **Acceptance criteria must be concrete — non-negotiable.** Every AC bullet must specify exact paths, exact commands, exact JSON shapes, or exact expected outputs. Bullets like "works correctly," "looks right," "behaves as expected," or "matches the spec" are **rejected on review**. A reviewer should be able to mechanically verify each bullet without judgment calls. Concreteness is the single biggest lever on agent output quality — it's worth re-writing AC bullets multiple times to eliminate ambiguity before the ticket goes to Jira.
|
|
236
|
+
- **Concrete > general everywhere.** "Add a Postgres `CHECK (started_at <= completed_at)` constraint on `pipeline_run`" is better than "validate timestamps". Same principle, applied to every section.
|
|
237
|
+
- **Show, don't tell.** Code snippets, exact SQL, exact JSON, exact curl commands. If you can't be concrete, you don't understand the work yet — go back to the REQ/UC registry and resolve the gap before drafting the ticket.
|
|
238
|
+
- **Reference, don't restate.** Don't paste DDL into a story that's about wiring an endpoint to existing DDL. Link to `db/migrations/0001_initial.sql` instead. Devin reads paths.
|
|
239
|
+
- **Validation must be runnable.** A reviewer should be able to copy the validation block, paste into a terminal, and see the expected output. If the validation depends on prior state (seeded DB, running services), say so under "Dependencies" or as a `# Setup` block before the assertion commands.
|
|
240
|
+
- **Don't list everything we hope is true.** List only the criteria you'd actually fail the PR for.
|
|
241
|
+
- **Out-of-scope is a feature, not an apology.** Listing "ai_summary rendering — separate story" prevents scope creep and tells the next story-author what to pick up.
|
|
242
|
+
- **Pin external API endpoints in the story body, not at execution time.** When a story integrates with a third-party API (Jira, GitHub, Slack, etc.), name the exact endpoint(s), HTTP methods, request shapes, and expected response shapes in the AC or Files section. Do NOT delegate "look up the current API" to the agent — vendor APIs deprecate, scope, and version-bump underneath you. Caching the pinned endpoint in the story gives reviewers a verifiable contract clause and prevents future similar stories from re-doing the research. *Driving example:* the SCRUM-8 sync story's AC referenced "the Jira REST API" generically; Devin used the obvious `/rest/api/3/search` endpoint, which Atlassian had deprecated effective May 2025 (returns `410 Gone`). The methodology-correct fix is to author the story with `/rest/api/3/search/jql` (POST + JSON body) pinned in the AC.
|
|
243
|
+
- **Unit-test setups that pre-populate state can hide bugs in state-transition code.** If an AC bullet specifies that "behavior X must hold when the system has just transitioned to state Y," the verifying unit test must actually exercise that transition (start from state Y-1, perform the action that produces state Y, then assert X). Tests that construct state Y up-front and just assert X pass even when the transition itself is broken. *Driving example:* the SCRUM-25 sync-fix story's AC required `build_jira_fields` to include `parent` when the parent has a `jira_key`. The test passed because the test fixture set `parent.jira_key = "SCRUM-100"` before calling `build_jira_fields`. In production, the parent's `jira_key` was assigned mid-run by a successful create — and the in-memory propagation of that assignment was broken, so the production lookup returned `None` and the test never caught it. The fix landed as a follow-up hotfix; the lesson is to write the test against the actual production transition shape.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## File-overlap sequencing rule
|
|
248
|
+
|
|
249
|
+
**No two open stories may list the same source file under their `Files:` sections without an explicit `depends_on` between them.**
|
|
250
|
+
|
|
251
|
+
When authoring a new story, the author checks against every story under `docs/stories/{phase1,phase2}/*.md` whose post-execution notes show `actual_hours: 0` (not yet executed). Any file in common must be reflected in a `depends_on` from the later story to the earlier one. This ensures the sync workflow routes the dependent story to `Waiting` until the earlier story merges, preventing the kind of silent overlap that occurred in the SCRUM-111 / SCRUM-107 (UC-16) incident: SCRUM-107 merged first and silently absorbed work that SCRUM-111 (the dedicated `rollback_policy` enum-sync fix) was queued to do, resulting in SCRUM-111 merging second as a partial/redundant change.
|
|
252
|
+
|
|
253
|
+
**Additive-index-file exemption.** Pure additive edits to index/README files (e.g., adding a row to `simulator/scenarios/README.md`) are exempt from this rule. These edits merge cleanly and don't require sequencing. The rule applies to source files where edits typically conflict — Python modules, TypeScript components, configuration files, schema migrations, etc.
|
|
254
|
+
|
|
255
|
+
**Authoring discipline + runtime safety net.** This rule is the authoring-discipline layer — it prevents the overlap at story-creation time. The runtime safety net is the `file_overlap_with_open_story` drift trigger in the router playbook (step 11 / step 12), which fires at PR-open time if an agent modified a file that belongs to another open story. Together, the two layers cover both anticipated overlaps (caught by the author) and unanticipated drift (caught by the runtime check).
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Story vs task — when to bundle
|
|
260
|
+
|
|
261
|
+
By default every `.md` file is a flat **task** (one Jira ticket = one PR ≤ 24h). Resist the urge to introduce hierarchy. Most tickets are flat.
|
|
262
|
+
|
|
263
|
+
A **parent story** is a `.md` with `type: story` whose body collects 2+ child tasks via the `tasks:` frontmatter list. Use a parent story when, and **only when**, the children together prove a capability that no child proves on its own — and the bundling makes review or delivery materially easier.
|
|
264
|
+
|
|
265
|
+
### When to introduce a parent story
|
|
266
|
+
|
|
267
|
+
Good candidates:
|
|
268
|
+
- **First vertical slice.** Simulator skeleton + first scenario + candidate-detail UI render — none of these alone proves "the system works end-to-end"; together they do.
|
|
269
|
+
- **A coherent UI feature.** "Candidate detail page" parent collecting children for header card / env timeline / pair lifecycle / approvals tab / rollbacks tab. Each child is independently shippable but the parent is the thing the stakeholder demos.
|
|
270
|
+
- **A schema migration plus the code that consumes it.** "Add `service_links` to `service`" parent collecting the migration child + the API-route child + the UI-rendering child. The schema alone is dead code; the parent gives the change a coherent story.
|
|
271
|
+
|
|
272
|
+
Bad candidates (keep flat):
|
|
273
|
+
- **A single concern that just happens to be larger than 24h.** Split it into smaller flat tasks instead. Don't fake a parent to dodge the cap.
|
|
274
|
+
- **A grab-bag of unrelated changes.** If the children don't share a theme, they shouldn't share a parent.
|
|
275
|
+
- **"Phase X work."** Phase tagging is what `labels:` is for, not a parent ticket.
|
|
276
|
+
|
|
277
|
+
### Frontmatter wiring
|
|
278
|
+
|
|
279
|
+
A leaf task with a parent:
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
---
|
|
283
|
+
title: Render the env timeline component on candidate detail
|
|
284
|
+
type: task
|
|
285
|
+
labels: [phase2, ui, candidate-detail]
|
|
286
|
+
requirements: [REQ-VIZ-10, REQ-VIZ-12]
|
|
287
|
+
parent: candidate-detail-page
|
|
288
|
+
estimate: 8h
|
|
289
|
+
---
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The parent story:
|
|
293
|
+
|
|
294
|
+
```yaml
|
|
295
|
+
---
|
|
296
|
+
title: Build the candidate detail page
|
|
297
|
+
type: story
|
|
298
|
+
labels: [phase2, ui, candidate-detail]
|
|
299
|
+
requirements: [REQ-VIZ-10, REQ-VIZ-12, REQ-VIZ-15, REQ-VIZ-17]
|
|
300
|
+
tasks:
|
|
301
|
+
- candidate-detail-skeleton
|
|
302
|
+
- candidate-detail-header-card
|
|
303
|
+
- candidate-detail-env-timeline
|
|
304
|
+
- candidate-detail-pair-lifecycle
|
|
305
|
+
- candidate-detail-approvals-tab
|
|
306
|
+
- candidate-detail-rollbacks-tab
|
|
307
|
+
estimate: 1w
|
|
308
|
+
---
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The parent's body is shorter than a task body — typically just `Context`, `Goal`, and a `Tasks` section listing the children with one-line descriptions. The parent's `Acceptance criteria` is the union of the children's plus any cross-cutting checks (e.g., "all six children merged; the page renders end-to-end against a seeded candidate").
|
|
312
|
+
|
|
313
|
+
### Jira mapping
|
|
314
|
+
|
|
315
|
+
- Parent `type: story` → Jira **Story**.
|
|
316
|
+
- Child `type: task` with a `parent:` value → Jira **Subtask** linked to the Story.
|
|
317
|
+
- Flat `type: task` (default, no parent) → Jira **Story** by itself (yes, "flat task" still maps to a Jira Story; the word "task" here is repo-vocabulary).
|
|
318
|
+
|
|
319
|
+
Two-level only. Don't go three deep — if a child needs sub-tasks, it should have been a parent itself.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Feedback loop and post-execution notes
|
|
324
|
+
|
|
325
|
+
The story format closes the loop by capturing what actually happened during execution back in the story file itself. After the implementation PR merges, the agent (Devin or similar) appends a `## Post-execution notes` section to the story `.md`. The notes are structured YAML for DB ingestion and cross-project comparison; the free-text fields carry the qualitative lessons.
|
|
326
|
+
|
|
327
|
+
### What gets captured
|
|
328
|
+
|
|
329
|
+
Every story carries the same shape (see `templates/story.md` for the canonical block):
|
|
330
|
+
|
|
331
|
+
- `actual_hours` vs `estimated_hours` and `estimate_delta_pct` — calibrates future estimates and the 24h cap. Aggregated at synthesis-pass time.
|
|
332
|
+
- `ac_bullets_clarified` + `ac_clarifications` — AC bullets that needed mid-flight clarification. Patterns drive AC-style improvements in this doc's "Style notes" section.
|
|
333
|
+
- `drift_events` — typed: `file_scope_drift`, `estimate_overrun`, `ambiguity_escalation`, `ci_repeat_fail`, `ac_verification_fail`. Hygiene rules per `runbook-net-new-via-agents.md` § 4.3.
|
|
334
|
+
- `rescoping_required` + `rescoping_reason` — surfaces stories that were too coarse, under-specified, or hit unforeseen complexity.
|
|
335
|
+
- `files_touched_outside_spec` — flags drift from the declared `Files` section. List of `{path, reason}`.
|
|
336
|
+
- `surprises` — free-text observations. **The single most important field** for compounding lessons across projects; an outside reader should learn something non-obvious from each entry.
|
|
337
|
+
- `recommended_runbook_updates` — candidate edits to feed the next synthesis pass.
|
|
338
|
+
|
|
339
|
+
Use empty list `[]` for "none" rather than deleting fields. Downstream tooling expects the keys.
|
|
340
|
+
|
|
341
|
+
### How the loop closes
|
|
342
|
+
|
|
343
|
+
1. Devin completes the implementation PR and appends the `## Post-execution notes` block to the story file.
|
|
344
|
+
2. Lead reviews the PR and may edit the notes for accuracy or clarity.
|
|
345
|
+
3. PR merges to `main`.
|
|
346
|
+
4. Periodically — every ~5 stories complete since the last pass, or at each phase-end gate, whichever comes first — the lead runs a **synthesis pass**.
|
|
347
|
+
5. The synthesis pass reads all post-execution notes since the last pass, drafts a structured retrospective in `../docs/retrospectives/`, and proposes specific runbook / format-doc edits as a PR titled `runbook: lessons from <phase> batch <n>`.
|
|
348
|
+
|
|
349
|
+
This is the active-consumption mechanism — capture without consumption is just data accumulation. The synthesis pass is documented in detail in `runbook-net-new-via-agents.md` § 4.6. AI-assisted synthesis (Claude or similar reading the raw notes and drafting the retro + runbook PR) keeps the loop fast enough to actually run on cadence.
|
|
350
|
+
|
|
351
|
+
### Done-gate policy
|
|
352
|
+
|
|
353
|
+
A story PR that doesn't include the post-execution notes block fails the "Done" Jira automation. Capture is non-optional.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Cross-cutting conventions Devin needs to know
|
|
358
|
+
|
|
359
|
+
These live in `CLAUDE.md` (root of the repo). Story bodies should not restate them — they should rely on Devin reading `CLAUDE.md` first. Highlights:
|
|
360
|
+
|
|
361
|
+
- **Stack:** React + TypeScript UI, FastAPI Python 3.12 API, Postgres 16 with JSONB, monorepo, docker-compose phase 1.
|
|
362
|
+
- **Env chain:** `dev → iat → qar → xat → prd`. `iat` (not `iac`).
|
|
363
|
+
- **Auth (Phase 1):** `X-Persona` header → mock persona; persona switcher in UI. Phase 2 swaps to OIDC.
|
|
364
|
+
- **Audit columns:** every audit-relevant DB row carries `actor`, `actor_persona`, `policy_version`. Story doesn't need to repeat this — but if a story creates a new audit-relevant table, it must call out compliance with this convention.
|
|
365
|
+
- **Idempotent ingest:** `(deploy_marker_id, source)` unique constraint on `deployment_event`. Don't break it.
|
|
366
|
+
- **GitHub best practice:** branch protection on `main`, PR-based, squash merges, conventional commit messages.
|
|
367
|
+
- **Bryan codes implementation himself in VS Code.** Stories are written for Devin or for Bryan to consume; both follow the same format.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Jira sync (automated)
|
|
372
|
+
|
|
373
|
+
The repo `.md` files are the **single source of truth** for story content. Jira tickets are a derived, work-tracking representation. A CI workflow keeps them in sync — no manual cut-and-paste, no human in the sync loop at all. The story PR review **is** the human gate; everything from "merge to main" through "ready for Devin pickup" is automated.
|
|
374
|
+
|
|
375
|
+
### Trigger and behavior
|
|
376
|
+
|
|
377
|
+
On every push to `main` that touches `docs/stories/**/*.md`, the workflow:
|
|
378
|
+
|
|
379
|
+
1. **Resolves each changed `.md`** to a Jira ticket — by reading the `jira_key:` frontmatter field if set, otherwise it creates a new ticket and writes the assigned key back to the file's frontmatter (committed back to `main` by the sync workflow).
|
|
380
|
+
2. **Maps frontmatter to Jira custom fields:**
|
|
381
|
+
- `title` → ticket summary
|
|
382
|
+
- `labels` → ticket labels
|
|
383
|
+
- `requirements` → `Requirement IDs` custom field
|
|
384
|
+
- `phase` (derived from the path: `phase1` / `phase2` / etc.) → `Phase` custom field
|
|
385
|
+
- `estimate` → `Agent estimate` custom field
|
|
386
|
+
- `depends_on` → Jira `is blocked by` links to the resolved keys (only when those tickets exist)
|
|
387
|
+
- `parent` (if set) → Jira `parent` link to the parent Story (this child becomes a Subtask)
|
|
388
|
+
- File path in the repo → `Story file` URL custom field
|
|
389
|
+
3. **Renders the body** by stripping the frontmatter and any `<!-- author notes -->` comments; the remaining markdown becomes the ticket description. The `## Acceptance criteria` section is also extracted and populated into the `Acceptance criteria` checklist field, one bullet per row.
|
|
390
|
+
4. **Transitions the ticket to `Ready for Agent`** if and only if:
|
|
391
|
+
- every `depends_on:` slug resolves to a Jira ticket in `Done` state, **and**
|
|
392
|
+
- the story does **not** carry a `manual-gate` label.
|
|
393
|
+
- Otherwise the ticket lands in `Blocked` (or `Backlog` for fresh tickets with no dependencies but a `manual-gate` label). The next merge that resolves a dependency re-runs the same check on dependent tickets and promotes them when they clear.
|
|
394
|
+
5. **Closes superseded tickets** if a story's filename is renamed with an underscore prefix (`_<slug>.md`, the canceled-story convention) — transitions the existing ticket to `Won't Do` with a comment.
|
|
395
|
+
|
|
396
|
+
The sync is **one-way**: repo → Jira. Jira-side state — comments, status transitions made by the lead or by automations, AC-checkbox progress, time-in-status — stays in Jira and is never pushed back into the repo.
|
|
397
|
+
|
|
398
|
+
> ⚠️ **Design constraint — sync needs write access to `main`.** Step 1 above requires the sync workflow to commit-and-push the assigned `jira_key:` back to the story file's frontmatter on first sync. This is the **only** path by which the sync writes to the repo, and it must be implemented carefully: use a bot identity (or a fine-scoped PAT / GitHub App token) with `contents: write` permission on the workflow, a commit message convention that's easy to filter from `git log` (e.g. `chore(sync): write jira_key for <slug>`), and a guard against re-triggering the sync on its own commit (skip-CI marker or path-ignore). Whoever implements `automated-story-sync-to-jira` (`../docs/stories/phase2/automated-story-sync-to-jira.md`) must cover this in the story's `Acceptance criteria` and `Validation`.
|
|
399
|
+
|
|
400
|
+
### The escape hatch — `manual-gate` label
|
|
401
|
+
|
|
402
|
+
Stories tagged with the `manual-gate` label sync to Jira but **don't** auto-transition to `Ready for Agent`, even when their dependencies clear. The ticket sits in `Backlog` until a human transitions it manually. Use cases are rare:
|
|
403
|
+
- A story you want merged for record-keeping but held from Devin pending an external decision.
|
|
404
|
+
- A story you want to demo at a stakeholder review before Devin picks it up.
|
|
405
|
+
- A story whose acceptance criteria depend on something the workflow can't verify (e.g., a vendor sign-off).
|
|
406
|
+
|
|
407
|
+
Most stories will not need this label. It exists as a deliberate hold mechanism, not a default.
|
|
408
|
+
|
|
409
|
+
### What this means for story authors
|
|
410
|
+
|
|
411
|
+
You don't open Jira tickets manually. You write the `.md`, open a PR, get it reviewed, merge. The workflow handles the rest. If a sync fails (Jira API down, frontmatter malformed), CI fails the merge — fix the issue, re-merge, sync runs again.
|
|
412
|
+
|
|
413
|
+
The implementation lives in `scripts/sync_stories_to_jira.py` + `.github/workflows/sync-stories-to-jira.yml`. It's its own Phase-2 story (`../docs/stories/phase2/automated-story-sync-to-jira.md`).
|
|
414
|
+
|
|
415
|
+
### Implementation gotchas for future projects
|
|
416
|
+
|
|
417
|
+
These are pitfalls observed on the first project that applied this methodology (Centralized Delivery Pipeline UI POC, May 2026). Re-deriving them on every adopting project is wasted cost — design around them from the start.
|
|
418
|
+
|
|
419
|
+
1. **`depends_on` link management must reconcile on UPDATE, not just CREATE.** The naïve implementation runs the `depends_on → "is blocked by"` link-creation loop only inside the CREATE branch (because at create time the dependency tickets are typically already in place). This produces two distinct failure modes:
|
|
420
|
+
- **Missing links never added.** If a story is created in the same sync batch as one of its dependencies, the dependency may not yet have a `jira_key:` at the moment its dependent's create runs. The link gets silently skipped. Subsequent UPDATEs on the dependent ticket — when the dependency now exists in Jira — never re-attempt the link.
|
|
421
|
+
- **Stale links never removed.** When a story's `depends_on:` is emptied (the prior blockage is no longer relevant) or a referenced story is renamed/canceled, the UPDATE writes the new field values but leaves the existing Jira "blocked by" link in place. The ticket can also remain in `BLOCKED` after the blockage is operationally resolved.
|
|
422
|
+
|
|
423
|
+
**Fix shape for the sync script:** on every UPDATE, fetch the current set of inward "blocked by" links from Jira, compute the set justified by current `depends_on:` (same `resolve_slug_to_key` walk), and reconcile both ways — DELETE links not justified, CREATE links justified-but-missing. Re-evaluate ticket status if the remaining "blocked by" set no longer justifies `BLOCKED`. **Pair this with terminal-state-preservation** (see gotcha 2 below) so the re-evaluation doesn't revert a `DONE` ticket.
|
|
424
|
+
|
|
425
|
+
2. **UPDATE's `determine_transition` must short-circuit on terminal states.** Without an explicit guard, the sync's `determine_transition` function on UPDATE recomputes the target status from the story's current frontmatter — and may transition a `DONE` ticket back to `Ready for Agent` (if all `depends_on:` resolve as Done), or a `Won't Do` ticket back to `BLOCKED` (if a `depends_on:` was added later). This was first observed on this project's SCRUM-8 (DONE → Ready) and SCRUM-25 (DONE → BLOCKED) on 2026-05-19. The fix landed in this project's PR #37. New projects should pre-stage the terminal-state guard in the initial sync-script implementation — it's a 4-line check at the top of `determine_transition`.
|
|
426
|
+
|
|
427
|
+
3. **Devin session creates a duplicate tracking ticket when the story already has a `jira_key:`.** The outbound sync writes `jira_key:` back to story frontmatter on first sync. When Devin then picks the story up, its session creates **its own** Jira tracking ticket independently — so you get one ticket from the sync and a second from Devin's session, both pointing at the same story file. Manual `Won't Do` on the orphan is the current workaround. Track in `methodology/devin-vendor-issues.md` issue #3; the methodology-level fix is to have Devin's session honor an existing `jira_key:` rather than creating fresh.
|
|
428
|
+
|
|
429
|
+
4. **`devin` label has double-duty as both manual-bootstrap mechanism and (optional) trigger condition.** If your automation trigger requires the `devin` label AND you use that same label as the manual-bootstrap path, **adding the label fires both** — the manual-bootstrap path triggers immediately on label-add (before any status condition is evaluated), bypassing the workflow you intended. Pick one role for the label per project. See `methodology/devin-jira-pickup.md` § 5 pitfall.
|
|
430
|
+
|
|
431
|
+
Each gotcha is mirrored in the consuming project's `docs/followups.md` with concrete ticket-level evidence. New projects should treat gotchas 1, 2, and 4 as **design-from-day-one constraints** on the sync-script implementation; gotcha 3 is a vendor-side gap to track and work around until Cognition fixes it.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Linking, dependencies, and the order of work
|
|
436
|
+
|
|
437
|
+
- **Within a phase folder:** stories should be self-contained but may depend on earlier stories listed in `depends_on`.
|
|
438
|
+
- **Across folders:** Phase-2 stories may depend on Phase-1 backfill stories (since the Phase-2 work logically rests on a foundation Devin needs to reproduce). That's expected.
|
|
439
|
+
- **Cycles forbidden.** A → B → A is a sign the stories aren't well-bounded; split them.
|
|
440
|
+
- **No transitive listing.** If A depends on B and B depends on C, A's `depends_on` only lists B. Devin walks the chain.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Maintenance
|
|
445
|
+
|
|
446
|
+
- When a story is **filed in Jira**, leave the repo file in place. The repo is the canonical version; Jira is the work-tracking surface.
|
|
447
|
+
- When a story is **completed**, the merged PR is the proof. Don't add a "completed" marker to the story file — the git history is the source of truth.
|
|
448
|
+
- When the **REQ-id list changes** (because `../docs/use-cases.md` was updated), update the story's `requirements:` frontmatter and the `**Requirement(s):**` body line.
|
|
449
|
+
- When a story is **superseded or canceled**, prefix its filename with `_` (e.g., `_canceled-old-feature.md`) and add a note explaining why. Don't delete — it preserves the trail for Devin's reproduction.
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Sample stories
|
|
454
|
+
|
|
455
|
+
Two samples ship alongside this format doc:
|
|
456
|
+
|
|
457
|
+
- [`../docs/stories/phase1/initial-database-schema.md`](../docs/stories/phase1/initial-database-schema.md) — moderately-sized backfill story. Shows the format for foundational work that's already done.
|
|
458
|
+
- [`../docs/stories/phase2/simulator-service-skeleton.md`](../docs/stories/phase2/simulator-service-skeleton.md) — small forward story. Shows the format for new work in a clean, narrow scope.
|
|
459
|
+
|
|
460
|
+
Compare them. They follow the same structure but differ in size and tone — both work because the format is the same.
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## Jira configuration — custom fields and automations
|
|
465
|
+
|
|
466
|
+
This format leans on Jira to stay tidy. The **interim** spec below covers what works today with native Jira (no marketplace plugins, no GH Actions to maintain). The **final-state** automation work (managed picklists, native checklist gating) is captured in `../docs/followups.md` and isn't blocking the methodology.
|
|
467
|
+
|
|
468
|
+
### Custom fields to add to the project's issue type (interim)
|
|
469
|
+
|
|
470
|
+
| Field | Type | Source / how it's filled |
|
|
471
|
+
|---|---|---|
|
|
472
|
+
| `Requirement IDs` | **Plain text** (interim — picklist later) | Comma-separated REQ-ids written by the sync workflow from the story's `requirements:` frontmatter (e.g. `REQ-VIZ-12, REQ-PIPE-4.20`). The final-state field is a multi-select picklist seeded from `../docs/use-cases.md` Part B via a GH Action; until that work lands, plain text is the working stand-in. |
|
|
473
|
+
| `Story file` | URL | Link back to the `.md` in the repo (e.g. `https://github.com/<org>/<repo>/blob/main/docs/stories/phase2/<slug>.md`). |
|
|
474
|
+
| `Agent estimate` | Number (hours) | The frontmatter `estimate` field. Always raw hours; no `d` unit. |
|
|
475
|
+
|
|
476
|
+
**Not custom fields — already surfaced by integrations:**
|
|
477
|
+
|
|
478
|
+
- **Devin session URL** — the native Devin ↔ Jira integration posts a stub acknowledgement comment containing the session link every time the trigger fires. That comment is the operational forensics path; a dedicated custom field would be redundant.
|
|
479
|
+
- **PR URL** — the GitHub ↔ Jira integration adds the PR as a *remote link* on the ticket (appears under "Linked issues") when a PR with a matching branch / smart-commit reference is opened. A dedicated custom field would also be redundant for the common case.
|
|
480
|
+
|
|
481
|
+
Both fields were originally specced and have been **dropped from the issue-type config**. Re-add them as custom fields only if a filterable, queryable view becomes operationally important (e.g., "show me all tickets where Devin opened a PR but the PR never merged"). At that point, the sync workflow would also need to populate them — neither integration writes custom-field values, only stub comments and remote links.
|
|
482
|
+
|
|
483
|
+
### Things that go in **labels** rather than custom fields
|
|
484
|
+
|
|
485
|
+
Native Jira labels handle these without picklist maintenance:
|
|
486
|
+
|
|
487
|
+
- **Phase** (`phase1-backfill`, `phase2`, `phase2b-ado`, `phase3`) — already in the story's `labels:` frontmatter; sync workflow writes them as Jira labels directly.
|
|
488
|
+
- **Manual-gate** (the escape-hatch label) — also in story `labels:`.
|
|
489
|
+
- **REQ-ids in label form** (e.g. `req-viz-12`) — *optional*, deferred to the picklist follow-up. Until then, the plain-text `Requirement IDs` field carries them.
|
|
490
|
+
|
|
491
|
+
Native Jira label search works for filtering ("issues with label `phase2`", "issues with label `manual-gate`").
|
|
492
|
+
|
|
493
|
+
### Acceptance criteria — markdown checkboxes, manual approval (interim)
|
|
494
|
+
|
|
495
|
+
Jira does not have a native checklist field, and a marketplace plugin is overhead we don't want yet. Interim approach:
|
|
496
|
+
|
|
497
|
+
- AC bullets render in the ticket description as markdown checkboxes (`- [ ] ...`). Visible to humans; Jira renders them; no programmatic gate.
|
|
498
|
+
- The lead engineer **manually verifies AC** during the implementation PR review and confirms the story is ready to close.
|
|
499
|
+
- No `AC verified` boolean field; no Done-gate automation. Lead's PR approval is the implicit AC pass.
|
|
500
|
+
|
|
501
|
+
Final state — either a marketplace checklist plugin (e.g. "Issue Checklist for Jira") or per-AC native sub-tasks with a Done-gate transition rule — is tracked in `../docs/followups.md`.
|
|
502
|
+
|
|
503
|
+
### Automations worth setting up early (interim subset)
|
|
504
|
+
|
|
505
|
+
1. **Branch ↔ ticket auto-link.** Convention: branch name `feat/<slug>` matches the ticket's `Story file` slug → Jira auto-links the PR. Standard Atlassian + GitHub integration handles this once the project is connected.
|
|
506
|
+
2. **PR-state → Jira-state.** PR opened → ticket transitions to "In Progress." PR merged → ticket transitions to "Done." PR closed without merge → ticket transitions back to "To Do" with an automated comment.
|
|
507
|
+
3. **`depends_on` enforcement.** A ticket with unresolved `Blocked by` links cannot transition out of Backlog. Forces the dependency chain in the frontmatter to be honored on the work-tracking side.
|
|
508
|
+
|
|
509
|
+
Three automations dropped from the early-setup list (deferred per follow-ups):
|
|
510
|
+
|
|
511
|
+
4. ~~Done gate that requires AC checklist fully checked~~ — replaced by manual lead verification on PR review.
|
|
512
|
+
5. ~~Drift alarm on PR commits outside the `Files` list~~ — nice-to-have once the loop is running; deferred.
|
|
513
|
+
6. ~~Estimate-overrun alarm~~ — deferred.
|
|
514
|
+
7. ~~Ready-for-Agent → Devin webhook~~ — deferred.
|
|
515
|
+
|
|
516
|
+
### What does **not** belong in custom fields
|
|
517
|
+
|
|
518
|
+
- **Filename** — the slug is already encoded in `Story file`. Don't duplicate.
|
|
519
|
+
- **REQ-id descriptions** — Jira shouldn't try to mirror `../docs/use-cases.md`. The repo doc owns the descriptions; Jira just carries the IDs.
|
|
520
|
+
- **Body sections** other than the interim ones above. Jira's full-text search covers Context / Goal / Files / Validation / Dependencies inside the description.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Open questions / future improvements
|
|
525
|
+
|
|
526
|
+
- **Helper script** to strip frontmatter and copy the rest to clipboard (`scripts/story-to-jira.sh` or a tiny `make` target). Not needed for the first batch; revisit when Bryan has 10+ stories to paste.
|
|
527
|
+
- **Linting** the format (required sections, valid REQ-ids that resolve to `../docs/use-cases.md`, no orphan `depends_on`). Could live as a pre-commit hook or CI step. Worth doing once the story library exceeds ~20 files.
|
|
528
|
+
- **Per-story PR template** that auto-fills the linked story. Possible via `.github/PULL_REQUEST_TEMPLATE/from-story.md` keyed off branch name.
|
|
529
|
+
- **Story → PR back-link.** When a story merges, append the merged PR URL to the story file. Manual for now; could be automated later.
|
|
530
|
+
- **Devin webhook relay.** A small service that forwards `Ready for Agent` Jira transitions to Devin's API. Defer until needed.
|
|
531
|
+
|
|
532
|
+
These are tracked in [`../docs/followups.md`](../docs/followups.md). None are blockers for using the format today.
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
See also: [`runbook-net-new-via-agents.md`](runbook-net-new-via-agents.md) — the methodology runbook for using this story format + use-case registry on a net-new product. The runbook is filled progressively as we live the model; the cadence and pause-points are observed empirically rather than prescribed upfront.
|