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,85 @@
|
|
|
1
|
+
# Canonical Jira automation rule definitions for methodology-framework projects.
|
|
2
|
+
#
|
|
3
|
+
# These rules are provisioned by the bootstrap CLI on project adoption.
|
|
4
|
+
# All references to a specific project key use {{PROJECT_KEY}} for substitution.
|
|
5
|
+
#
|
|
6
|
+
# JSON-schema: each rule has name, description, trigger, conditions[], and
|
|
7
|
+
# actions[].
|
|
8
|
+
|
|
9
|
+
schema_version: "1.0"
|
|
10
|
+
|
|
11
|
+
automation_rules:
|
|
12
|
+
- name: "PR merged → transition to Done"
|
|
13
|
+
key: "pr_merged_to_done"
|
|
14
|
+
description: >-
|
|
15
|
+
When a pull request is merged and its title contains the issue key,
|
|
16
|
+
transition the linked issue to Done. Gated by a path filter: only fires
|
|
17
|
+
if the PR changes files outside docs/stories/** (docs-only PRs like
|
|
18
|
+
story-file post-exec-notes updates do not auto-close the ticket).
|
|
19
|
+
trigger:
|
|
20
|
+
type: "pull_request_merged"
|
|
21
|
+
repository: "{{PROJECT_KEY}}"
|
|
22
|
+
conditions:
|
|
23
|
+
- type: "pr_title_contains_issue_key"
|
|
24
|
+
description: >-
|
|
25
|
+
pullRequest.title contains issue.key — ensures only the primary
|
|
26
|
+
ticket auto-transitions. PR titles must contain exactly one Jira key.
|
|
27
|
+
- type: "changed_files_outside_path"
|
|
28
|
+
path_filter: "docs/stories/**"
|
|
29
|
+
description: >-
|
|
30
|
+
At least one file changed by the PR is outside docs/stories/**.
|
|
31
|
+
Prevents docs-only PRs (e.g. post-execution notes updates) from
|
|
32
|
+
prematurely closing the ticket.
|
|
33
|
+
actions:
|
|
34
|
+
- type: "transition_issue"
|
|
35
|
+
target_status: "Done"
|
|
36
|
+
transition_id: 41
|
|
37
|
+
|
|
38
|
+
- name: "Dependency resolution → Waiting to Ready for Agent"
|
|
39
|
+
key: "dependency_resolution"
|
|
40
|
+
description: >-
|
|
41
|
+
When all blocking issues of a Waiting ticket reach Done status,
|
|
42
|
+
automatically transition the ticket from Waiting to Ready for Agent.
|
|
43
|
+
This is the sync-driven dependency resolution mechanism.
|
|
44
|
+
trigger:
|
|
45
|
+
type: "issue_transitioned"
|
|
46
|
+
target_status: "Done"
|
|
47
|
+
conditions:
|
|
48
|
+
- type: "all_linked_blocking_issues_done"
|
|
49
|
+
link_type: "is blocked by"
|
|
50
|
+
description: >-
|
|
51
|
+
Every issue linked via 'is blocked by' relationship is in Done status.
|
|
52
|
+
- type: "issue_in_status"
|
|
53
|
+
status: "Waiting"
|
|
54
|
+
description: >-
|
|
55
|
+
The dependent issue is currently in Waiting status.
|
|
56
|
+
actions:
|
|
57
|
+
- type: "transition_issue"
|
|
58
|
+
target_status: "Ready for AI agent"
|
|
59
|
+
transition_id: 2
|
|
60
|
+
|
|
61
|
+
- name: "BLOCKED protection"
|
|
62
|
+
key: "blocked_protection"
|
|
63
|
+
description: >-
|
|
64
|
+
Prevents automated workflows from transitioning a ticket OUT of Blocked
|
|
65
|
+
status. Only human operators may unblock a ticket. This enforces the
|
|
66
|
+
methodology's distinction: Blocked = human intervention required;
|
|
67
|
+
Waiting = auto-resolves when deps merge.
|
|
68
|
+
trigger:
|
|
69
|
+
type: "issue_transitioned"
|
|
70
|
+
source_status: "Blocked"
|
|
71
|
+
conditions:
|
|
72
|
+
- type: "actor_is_automation"
|
|
73
|
+
description: >-
|
|
74
|
+
The transition was triggered by an automation rule or sync workflow,
|
|
75
|
+
not a human operator.
|
|
76
|
+
actions:
|
|
77
|
+
- type: "revert_transition"
|
|
78
|
+
description: >-
|
|
79
|
+
Transition the issue back to Blocked. Log a warning comment noting
|
|
80
|
+
the attempted automated un-block was prevented.
|
|
81
|
+
- type: "add_comment"
|
|
82
|
+
body: >-
|
|
83
|
+
Automated transition out of Blocked was prevented by the BLOCKED
|
|
84
|
+
protection rule. Only human operators may transition tickets out
|
|
85
|
+
of Blocked status.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Canonical Jira custom field definitions for methodology-framework projects.
|
|
2
|
+
#
|
|
3
|
+
# Mirrors the three required custom fields from the SCRUM project.
|
|
4
|
+
# These fields are provisioned by the bootstrap CLI on project adoption.
|
|
5
|
+
#
|
|
6
|
+
# JSON-schema: each field has name, key, type, description, required_at_create,
|
|
7
|
+
# and optional constraints.
|
|
8
|
+
|
|
9
|
+
schema_version: "1.0"
|
|
10
|
+
|
|
11
|
+
custom_fields:
|
|
12
|
+
- name: "Story File"
|
|
13
|
+
key: "story_file"
|
|
14
|
+
type: "url"
|
|
15
|
+
description: >-
|
|
16
|
+
URL to the canonical story file in the repo. Set by the outbound sync
|
|
17
|
+
workflow on story creation. Format:
|
|
18
|
+
https://github.com/<owner>/<repo>/blob/main/docs/stories/<phase>/<slug>.md
|
|
19
|
+
required_at_create: false
|
|
20
|
+
constraints:
|
|
21
|
+
pattern: "^https://.+"
|
|
22
|
+
|
|
23
|
+
- name: "Requirement IDs"
|
|
24
|
+
key: "requirement_ids"
|
|
25
|
+
type: "labels"
|
|
26
|
+
description: >-
|
|
27
|
+
Multi-value field containing the REQ-id(s) this story implements.
|
|
28
|
+
Values come from the project's use-case registry (e.g. REQ-VIZ-12,
|
|
29
|
+
REQ-MET-PORT). Set by the outbound sync workflow from story frontmatter.
|
|
30
|
+
required_at_create: false
|
|
31
|
+
constraints:
|
|
32
|
+
allow_custom_values: true
|
|
33
|
+
|
|
34
|
+
- name: "Agent Estimate"
|
|
35
|
+
key: "agent_estimate"
|
|
36
|
+
type: "number"
|
|
37
|
+
description: >-
|
|
38
|
+
Estimated agent-hours for the story. Populated from the story frontmatter
|
|
39
|
+
estimate field (converted to numeric hours). Used for capacity planning
|
|
40
|
+
and estimate_overrun drift-trigger thresholds.
|
|
41
|
+
required_at_create: false
|
|
42
|
+
constraints:
|
|
43
|
+
min: 0
|
|
44
|
+
precision: 1
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Canonical Jira workflow shape definition for methodology-framework projects.
|
|
2
|
+
#
|
|
3
|
+
# Mirrors the SCRUM project workflow as the reference shape.
|
|
4
|
+
# All references to a specific project key use {{PROJECT_KEY}} for substitution.
|
|
5
|
+
#
|
|
6
|
+
# JSON-schema: each status has name, description, status_id, and transitions[].
|
|
7
|
+
# Each transition has name, transition_id, target, and allowed_actors[].
|
|
8
|
+
|
|
9
|
+
schema_version: "1.0"
|
|
10
|
+
|
|
11
|
+
statuses:
|
|
12
|
+
- name: "To Do"
|
|
13
|
+
description: >-
|
|
14
|
+
Backlog state. Stories with manual-gate label sit here.
|
|
15
|
+
Initial state for stories that are not yet ready for agent pickup.
|
|
16
|
+
status_id: 10000
|
|
17
|
+
transitions:
|
|
18
|
+
- name: "Ready for AI agent"
|
|
19
|
+
transition_id: 2
|
|
20
|
+
target: "Ready for AI agent"
|
|
21
|
+
allowed_actors: ["sync-workflow", "operator"]
|
|
22
|
+
- name: "Won't do"
|
|
23
|
+
transition_id: 4
|
|
24
|
+
target: "Won't do"
|
|
25
|
+
allowed_actors: ["sync-workflow", "operator"]
|
|
26
|
+
|
|
27
|
+
- name: "Ready for AI agent"
|
|
28
|
+
description: >-
|
|
29
|
+
Trigger-firing state. Devin picks up tickets from this status via the
|
|
30
|
+
automation trigger. Stories land here when all depends_on are resolved.
|
|
31
|
+
status_id: 10070
|
|
32
|
+
transitions:
|
|
33
|
+
- name: "In Progress"
|
|
34
|
+
transition_id: 21
|
|
35
|
+
target: "In Progress"
|
|
36
|
+
allowed_actors: ["agent", "operator"]
|
|
37
|
+
- name: "Blocked"
|
|
38
|
+
transition_id: 3
|
|
39
|
+
target: "Blocked"
|
|
40
|
+
allowed_actors: ["agent", "operator"]
|
|
41
|
+
- name: "To Do"
|
|
42
|
+
transition_id: 11
|
|
43
|
+
target: "To Do"
|
|
44
|
+
allowed_actors: ["operator"]
|
|
45
|
+
|
|
46
|
+
- name: "In Progress"
|
|
47
|
+
description: >-
|
|
48
|
+
Agent is actively implementing. Read-only for humans during this state.
|
|
49
|
+
Agent transitions here on session start.
|
|
50
|
+
status_id: 10001
|
|
51
|
+
transitions:
|
|
52
|
+
- name: "In Review"
|
|
53
|
+
transition_id: 31
|
|
54
|
+
target: "In Review"
|
|
55
|
+
allowed_actors: ["agent", "operator"]
|
|
56
|
+
- name: "Blocked"
|
|
57
|
+
transition_id: 3
|
|
58
|
+
target: "Blocked"
|
|
59
|
+
allowed_actors: ["agent", "operator"]
|
|
60
|
+
- name: "Waiting"
|
|
61
|
+
transition_id: 5
|
|
62
|
+
target: "Waiting"
|
|
63
|
+
allowed_actors: ["sync-workflow", "operator"]
|
|
64
|
+
|
|
65
|
+
- name: "In Review"
|
|
66
|
+
description: >-
|
|
67
|
+
PR is open and awaiting human review. Agent transitions here on PR open.
|
|
68
|
+
PR link is posted as a remote link by the GitHub-Jira integration.
|
|
69
|
+
status_id: 10002
|
|
70
|
+
transitions:
|
|
71
|
+
- name: "Done"
|
|
72
|
+
transition_id: 41
|
|
73
|
+
target: "Done"
|
|
74
|
+
allowed_actors: ["jira-automation", "operator"]
|
|
75
|
+
- name: "In Progress"
|
|
76
|
+
transition_id: 21
|
|
77
|
+
target: "In Progress"
|
|
78
|
+
allowed_actors: ["operator"]
|
|
79
|
+
- name: "Blocked"
|
|
80
|
+
transition_id: 3
|
|
81
|
+
target: "Blocked"
|
|
82
|
+
allowed_actors: ["operator"]
|
|
83
|
+
|
|
84
|
+
- name: "Waiting"
|
|
85
|
+
description: >-
|
|
86
|
+
Dependency not yet resolved. Auto-resolves when blocking issues reach Done.
|
|
87
|
+
Sync-driven; distinct from Blocked (which requires human intervention).
|
|
88
|
+
status_id: 10137
|
|
89
|
+
transitions:
|
|
90
|
+
- name: "Ready for AI agent"
|
|
91
|
+
transition_id: 2
|
|
92
|
+
target: "Ready for AI agent"
|
|
93
|
+
allowed_actors: ["sync-workflow", "operator"]
|
|
94
|
+
- name: "Blocked"
|
|
95
|
+
transition_id: 3
|
|
96
|
+
target: "Blocked"
|
|
97
|
+
allowed_actors: ["operator"]
|
|
98
|
+
- name: "To Do"
|
|
99
|
+
transition_id: 11
|
|
100
|
+
target: "To Do"
|
|
101
|
+
allowed_actors: ["operator"]
|
|
102
|
+
|
|
103
|
+
- name: "Blocked"
|
|
104
|
+
description: >-
|
|
105
|
+
Human attention required. Reserved for drift-trigger escalations:
|
|
106
|
+
ambiguity_escalation, ac_verification_fail, ci_repeat_fail,
|
|
107
|
+
estimate_overrun (3x), file_overlap_with_open_story.
|
|
108
|
+
status_id: 10103
|
|
109
|
+
transitions:
|
|
110
|
+
- name: "Ready for AI agent"
|
|
111
|
+
transition_id: 2
|
|
112
|
+
target: "Ready for AI agent"
|
|
113
|
+
allowed_actors: ["operator"]
|
|
114
|
+
- name: "To Do"
|
|
115
|
+
transition_id: 11
|
|
116
|
+
target: "To Do"
|
|
117
|
+
allowed_actors: ["operator"]
|
|
118
|
+
- name: "Won't do"
|
|
119
|
+
transition_id: 4
|
|
120
|
+
target: "Won't do"
|
|
121
|
+
allowed_actors: ["operator"]
|
|
122
|
+
|
|
123
|
+
- name: "Done"
|
|
124
|
+
description: >-
|
|
125
|
+
Terminal success state. Reached via Jira automation rule on PR merge
|
|
126
|
+
(gated by pullRequest.title contains issue.key).
|
|
127
|
+
status_id: 10003
|
|
128
|
+
transitions: []
|
|
129
|
+
|
|
130
|
+
- name: "Won't do"
|
|
131
|
+
description: >-
|
|
132
|
+
Terminal rejected state. Reached via sync workflow on story file rename
|
|
133
|
+
(prefixed with underscore) or by operator decision.
|
|
134
|
+
status_id: 10104
|
|
135
|
+
transitions: []
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
---
|
|
2
|
+
playbook_id: scrum-router
|
|
3
|
+
version: 1.2.0
|
|
4
|
+
changelog:
|
|
5
|
+
- "1.2.0 (2026-05-27): New convention — agent writes pre-execution scoping into the story file's new ## Scoping notes (pre-execution) section as the first commit of the implementation branch. New convention — agent populates the ## Post-execution notes block before opening PR; empty-default stubs are forbidden. MINOR bump per SemVer (additive new conventions)."
|
|
6
|
+
- "1.1.1 (2026-05-25): Bug fixes in the build + register pipeline — (1) preserve Variables-required section from substitution; (2) substitute version literal from frontmatter into the audit-echo line via {{VERSION}}; (3) look up existing Devin playbook by playbook_id slug, not rendered H1 title. No body content changes; PATCH-level bump."
|
|
7
|
+
- "1.1.0 (2026-05-24): Add PR-title-single-key convention (step 13 sub-section + Forbidden Action). The 1.0.0 changelog claimed this was included but the text was missing — uncommitted edits to the pre-relocation file at .devin/playbooks/ never landed in main before the relocation ran. This port brings the convention into the canonical body and corrects the changelog."
|
|
8
|
+
- "1.0.0 (2026-05-24): Initial extraction from project-specific to methodology-central. Encodes drift triggers, file-overlap rule, lifecycle status hygiene (Waiting vs Blocked). Parameterized via {{PROJECT_KEY}}, {{REPO}}, {{REQ_DOC_PATH}}, {{CONFIG_DOC_PATH}}, {{STORY_PATH_PATTERN}}. (Note: this entry originally also claimed the PR-title-single-key convention; that text was ported separately in 1.1.0.)"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Versioning
|
|
12
|
+
|
|
13
|
+
This playbook follows [Semantic Versioning](https://semver.org/):
|
|
14
|
+
|
|
15
|
+
- **MAJOR** — breaking changes to required reading or step numbering (consumers must re-read and possibly adjust their bindings or workflows).
|
|
16
|
+
- **MINOR** — new conventions, new drift triggers, new steps (additive; consumers inherit new behavior on next pin bump).
|
|
17
|
+
- **PATCH** — clarifications and language tightenings (no behavioral change; safe to adopt without review).
|
|
18
|
+
|
|
19
|
+
When bumping the version: update the `version:` field in the frontmatter above, add a changelog entry, and update the consuming project's `playbook_version` pin in their config doc.
|
|
20
|
+
|
|
21
|
+
## Variables required
|
|
22
|
+
|
|
23
|
+
Consuming projects must provide bindings for the following placeholders. The build-time concatenation script (`scripts/build_playbook.py`) or equivalent registration mechanism substitutes these before the playbook is registered in Devin's webapp.
|
|
24
|
+
|
|
25
|
+
| Placeholder | Description | Example (this project) |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `{{PROJECT_KEY}}` | Jira project key for the consuming project. | `SCRUM` |
|
|
28
|
+
| `{{REPO}}` | GitHub repository identifier (`owner/repo`). | `whiteout59/centralized-pipeline-ui` |
|
|
29
|
+
| `{{REQ_DOC_PATH}}` | Path to the project's requirements / use-case registry doc. | `docs/use-cases.md` |
|
|
30
|
+
| `{{CONFIG_DOC_PATH}}` | Path to the project's Jira pickup config doc. | `docs/jira-pickup-config.md` |
|
|
31
|
+
| `{{STORY_PATH_PATTERN}}` | Glob-style base path to the story directories (include trailing `/`). | `docs/stories/{phase1,phase2}/` |
|
|
32
|
+
| `{{VERSION}}` | Playbook version from frontmatter; injected automatically by the build script. | `1.2.0` |
|
|
33
|
+
|
|
34
|
+
# {{PROJECT_KEY}} ticket pickup (router)
|
|
35
|
+
|
|
36
|
+
## Overview
|
|
37
|
+
|
|
38
|
+
You have been spawned by Devin's Jira pickup automation on the `{{REPO}}` repository (Jira project key `{{PROJECT_KEY}}`). Your job is to route the work from the ticket to the matching story file in this repo and execute the per-story instructions found there. You are **not** authoring per-story procedure — that's in the story file. You **are** the stable agent shell that finds, validates, scopes, and (in direct mode) executes that procedure under the project's universal rules.
|
|
39
|
+
|
|
40
|
+
The Jira integration is configured in **scoping-only** mode for the POC. That means: when this playbook is triggered by a state transition, you produce *only* the scoping comment (step 9 of the Procedure) and stop. A human then clicks "Start session" to spawn the implementation run, which runs this same playbook past step 9.
|
|
41
|
+
|
|
42
|
+
**Required reading before you start, in order:**
|
|
43
|
+
|
|
44
|
+
1. `CLAUDE.md` — project context; locked decisions; conventions; "Where things live."
|
|
45
|
+
2. `methodology/devin-jira-pickup.md` — the inbound-side methodology (what this playbook implements).
|
|
46
|
+
3. `methodology/devin-story-format.md` — the 8-section story schema, the `Execution recipe` section, and frontmatter spec.
|
|
47
|
+
4. `methodology/runbook-net-new-via-agents.md` — full SDLC runbook. Pay special attention to § 4.3 (drift triggers) and § 7 (synthesis pass).
|
|
48
|
+
5. `{{CONFIG_DOC_PATH}}` — this project's instantiation: state names, bootstrap mechanism, smoke-test plan.
|
|
49
|
+
|
|
50
|
+
## What's Needed From User
|
|
51
|
+
|
|
52
|
+
The Jira ticket must give you enough information to locate the corresponding story file in the repo. Try the lookup mechanisms below in order, stopping at the first one that resolves to exactly one story file:
|
|
53
|
+
|
|
54
|
+
1. **Frontmatter `jira_key:`** — story file's frontmatter has `jira_key: {{PROJECT_KEY}}-XXX` matching the ticket key. *(Canonical going forward; not yet present on existing stories — see the note in Advice and Pointers about the maturity gradient.)*
|
|
55
|
+
2. **Exact title match** — the Jira ticket's summary matches the story file's frontmatter `title:` field verbatim. This is the outbound-sync convention (`methodology/devin-story-format.md`), so any story filed via that sync should match here.
|
|
56
|
+
3. **Explicit path in description** — the ticket description references a specific story-file path under `{{STORY_PATH_PATTERN}}`.
|
|
57
|
+
|
|
58
|
+
If none of these resolve to exactly one story file (or multiple stories match ambiguously), raise an `ambiguity_escalation` per runbook § 4.3 in the scoping comment and stop.
|
|
59
|
+
|
|
60
|
+
The matched story file ideally contains an `Execution recipe` section (now specified as the 8th body section in `methodology/devin-story-format.md` § "Body structure"; mandatory for Phase-2 forward stories, optional for Phase-1 `manual-gate`-labeled backfill stories). If the recipe is **present**, follow it. If it's **absent** (Phase-1 backfill, or any pre-spec story not yet retrofitted), fall back to inferring the procedure from the story's `Acceptance criteria`, `Files`, and `Validation` sections — and cap your scoping-comment confidence at MEDIUM. If those three sections are themselves missing or vague, raise an `ambiguity_escalation`.
|
|
61
|
+
|
|
62
|
+
## Procedure
|
|
63
|
+
|
|
64
|
+
1. Clone the repo and check out `main`. First line of your substantive output (scoping comment OR implementation log) MUST be: `Playbook: scrum-router@{{VERSION}} (binding: {{PROJECT_KEY}})`. This makes the active playbook version unambiguous in audit logs.
|
|
65
|
+
2. Read `CLAUDE.md`, then the four files listed in Overview, in order.
|
|
66
|
+
3. Identify the Jira ticket key from the trigger context.
|
|
67
|
+
4. Locate the story file under `{{STORY_PATH_PATTERN}}` using the lookup chain from "What's Needed From User":
|
|
68
|
+
- Try `jira_key:` frontmatter match. If exactly one match, use it.
|
|
69
|
+
- Else try exact `title:` frontmatter match against the Jira ticket summary. If exactly one match, use it.
|
|
70
|
+
- Else check the ticket description for an explicit story-file path under `{{STORY_PATH_PATTERN}}...`. Validate the file exists.
|
|
71
|
+
- If still no match, or multiple ambiguous matches → post an `ambiguity_escalation` comment naming the failure mode and stop.
|
|
72
|
+
5. Read the matched story file in full. Confirm it has the canonical body sections per `methodology/devin-story-format.md` § "Body structure" — `Context`, `Goal`, `Acceptance criteria`, `Files`, `Validation`, `Out of scope`, `Dependencies` are required at scoping time on every story. `Execution recipe` is required on Phase-2 forward stories but may be absent on Phase-1 `manual-gate` backfill stories. `Post-execution notes` is appended by the agent at PR-open time, so may be a stub or absent at scoping. If any required section is missing or empty, raise an `ambiguity_escalation` and stop. Note whether the `Execution recipe` section is present — this drives step 11's behavior.
|
|
73
|
+
6. Write your scoping output into the story file's `## Scoping notes (pre-execution)` section. Commit this as the first commit on the implementation branch with message `docs(stories): scope <story-slug>` (or `[skip ci]` equivalent if your project's CI shape requires). Only then proceed to implementation work. **This step executes during the implementation phase only** — in scoping-only mode, the scoping output is captured in the Jira comment (step 9) but the in-repo commit waits for the implementation session.
|
|
74
|
+
7. Verify the story's acceptance criteria are concrete (per the story-format rules — each AC must be mechanically verifiable). If any AC is vague, flag in the scoping comment and lower confidence.
|
|
75
|
+
8. Verify the story's `Files:` section enumerates actual file paths and the `Validation:` block has runnable commands. If anything is TBD or ambiguous, flag and lower confidence.
|
|
76
|
+
9. Compose the scoping comment using the template below, then **post it to the Jira ticket via the Jira REST API**. The native Devin ↔ Jira integration only posts a stub acknowledgement comment with a session link — it does **not** post substantive content. You must post via REST using OAuth 2.0 client credentials, with secrets configured in Devin's organization settings (`JIRA_OAUTH_CLIENT_ID`, `JIRA_OAUTH_CLIENT_SECRET`).
|
|
77
|
+
|
|
78
|
+
**Authentication — OAuth 2.0 client credentials flow:**
|
|
79
|
+
|
|
80
|
+
1. **Token exchange.** `POST https://auth.atlassian.com/oauth/token` with JSON body `{"grant_type": "client_credentials", "client_id": "$JIRA_OAUTH_CLIENT_ID", "client_secret": "$JIRA_OAUTH_CLIENT_SECRET"}`. Extract the `access_token` from the response. Tokens are short-lived (~1 hour); obtain a fresh one at the start of each session.
|
|
81
|
+
2. **Discover cloud ID.** `GET https://api.atlassian.com/oauth/token/accessible-resources` with `Authorization: Bearer <token>`. Find the entry whose `url` matches `https://icpipeline.atlassian.net` and extract its `id` (the cloud ID).
|
|
82
|
+
3. **All subsequent Jira REST calls** use base URL `https://api.atlassian.com/ex/jira/<CLOUD-ID>` with header `Authorization: Bearer <token>`.
|
|
83
|
+
|
|
84
|
+
**Posting the comment:**
|
|
85
|
+
|
|
86
|
+
- **Endpoint:** `POST https://api.atlassian.com/ex/jira/<CLOUD-ID>/rest/api/3/issue/<TICKET-KEY>/comment`
|
|
87
|
+
- **Auth:** `Authorization: Bearer <token>` (from step 1 above)
|
|
88
|
+
- **Body:** Atlassian Document Format (ADF). For a multi-section comment, build a `doc` node containing `heading`, `paragraph`, and `bulletList` children. ADF spec: https://developer.atlassian.com/cloud/jira/platform/apidocs/#api-rest-api-3-issue-issueIdOrKey-comment-post
|
|
89
|
+
- **Verify:** GET the same endpoint after posting and confirm the new comment appears in the response.
|
|
90
|
+
- **If the comment is long or includes structured detail (a full report, large file list, etc.):** post a short ADF-formatted summary comment via the endpoint above, then upload the full report as an attachment via `POST https://api.atlassian.com/ex/jira/<CLOUD-ID>/rest/api/3/issue/<TICKET-KEY>/attachments` with header `X-Atlassian-Token: no-check` and multipart-form field `file=@<path>`. Reference the attachment in the summary comment.
|
|
91
|
+
|
|
92
|
+
**Fallback.** If the OAuth token exchange fails (e.g. 401 from `auth.atlassian.com`), the client credentials have been rotated or revoked — raise `ambiguity_escalation` immediately; the human owner must re-provision the OAuth app credentials in the Devin org vault.
|
|
93
|
+
|
|
94
|
+
Comment template (rendered into ADF):
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Playbook: scrum-router@{{VERSION}} (binding: {{PROJECT_KEY}})
|
|
98
|
+
|
|
99
|
+
### Scoping for <TICKET-KEY> — <story title>
|
|
100
|
+
|
|
101
|
+
**Story file:** `{{STORY_PATH_PATTERN}}<slug>.md`
|
|
102
|
+
|
|
103
|
+
**My understanding of the goal (1–2 sentences):** …
|
|
104
|
+
|
|
105
|
+
**Implementation plan:**
|
|
106
|
+
1. …
|
|
107
|
+
2. …
|
|
108
|
+
|
|
109
|
+
**Files I expect to touch:**
|
|
110
|
+
- `path/to/file.ext` — what changes
|
|
111
|
+
- …
|
|
112
|
+
|
|
113
|
+
**Acceptance-criteria verification approach:**
|
|
114
|
+
- AC 1: <restate> — verified by <method from Validation>
|
|
115
|
+
- AC 2: <restate> — verified by <method from Validation>
|
|
116
|
+
- …
|
|
117
|
+
|
|
118
|
+
**Confidence:** HIGH | MEDIUM | LOW
|
|
119
|
+
**Reasoning:** <one line — what would lower this to MEDIUM/LOW>
|
|
120
|
+
|
|
121
|
+
**Concerns / ambiguities:** (only include if non-empty)
|
|
122
|
+
- …
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Confidence calibration anchors.** Pick the level deterministically:
|
|
126
|
+
|
|
127
|
+
- **LOW** if *any* of the following are true (a single hard blocker is enough — do not soften LOW into MEDIUM because the rest of the scope is clear):
|
|
128
|
+
- An unmet `depends_on:` exists in `main` (the referenced story is not yet `Done` in Jira AND/OR its produced artifact is not yet on `main`).
|
|
129
|
+
- A story-referenced file (`Files:` entry, `Validation:` command, recipe `Procedure` step) does not exist on `main` and is not authored to be created by this story.
|
|
130
|
+
- An AC bullet is mechanically unverifiable — it cannot be checked by a `pytest`, `mypy`, `ruff`, shell command, or specific file/state assertion.
|
|
131
|
+
- The `Execution recipe` references a precondition (e.g., "confirm X is merged") that is not currently met.
|
|
132
|
+
- Two or more independent ambiguities that each would have been a MEDIUM on their own.
|
|
133
|
+
- **MEDIUM** if the scope is workable but a discrete assumption or judgment call could turn out to be wrong — a vague AC bullet, an architecture choice not pinned by the story, a TBD that the recipe says to resolve mid-flight. The work CAN proceed; the reviewer's job is to read the reasoning and confirm.
|
|
134
|
+
- **HIGH** if all AC are concrete and mechanically verifiable, all referenced files exist on `main`, all `depends_on:` resolve to `Done` tickets on `main`, and the recipe procedure is mechanical. Reviewer's job is light.
|
|
135
|
+
|
|
136
|
+
10. **End-of-scoping gates** (evaluate in order; stop at the first that fires):
|
|
137
|
+
|
|
138
|
+
a. **If `Confidence` is `LOW`**, fire the `ambiguity_escalation` drift trigger: transition the ticket to `BLOCKED`, reassign to the ticket owner (assignee at time of pickup; fall back to reporter if no assignee), and post a comment naming the trigger and what specifically is blocking (e.g., "ambiguity_escalation: depends_on `simulator-payments-api-happy-pair-scenario` not on main"). Stop the session. *This applies in scoping-only mode too — do not wait for the implementation phase to escalate a scoping-time blocker.*
|
|
139
|
+
|
|
140
|
+
b. **If the Jira integration is in scoping-only mode**, stop the session here without further action. The scoping comment is posted; a human will click "Start session" to spawn implementation when ready. **Source of truth for the mode is the webapp's automation-trigger settings (`app.devin.ai > Settings > Integrations > Jira > Automation triggers > scrum-router > Session mode`), not any in-repo document** — check the webapp setting if the mode is ambiguous from context. The consuming project's `{{CONFIG_DOC_PATH}}` § 5 may describe the intended mode but is best-effort, not authoritative.
|
|
141
|
+
|
|
142
|
+
c. **If the Jira integration is in direct mode, or a human has started the session from a scoping comment**, proceed to step 11 (implementation).
|
|
143
|
+
|
|
144
|
+
11. **Implementation phase — runs only in Direct mode, or when a human has started a session from a scoping comment.** Transition the ticket to `In Progress` (transition id `21`) before beginning implementation work. Skip this if the ticket is already in `In Progress` (e.g., from a prior in-flight session). Execute step 6 now (write scoping notes to the story file and commit as the first implementation-branch commit). Then, if the story has an `Execution recipe` section, follow its `Procedure` step-by-step. If not, follow the implementation plan you posted in step 9 (which was inferred from the story's `Acceptance criteria`, `Files`, and `Validation` sections). In both cases, treat `Acceptance criteria`, `Files`, and `Validation` as the contract for what "done" means.
|
|
145
|
+
|
|
146
|
+
12. While implementing, apply the **universal drift-trigger rules** from runbook § 4.3. All Jira comments named below are posted via the same REST API mechanism documented in step 9 (`POST https://api.atlassian.com/ex/jira/<CLOUD-ID>/rest/api/3/issue/<TICKET-KEY>/comment` with OAuth Bearer auth and ADF body).
|
|
147
|
+
|
|
148
|
+
| Drift trigger | Action |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `ambiguity_escalation` | Transition the ticket to `BLOCKED`, reassign to the ticket owner (assignee at time of pickup; fall back to reporter if no assignee), post a comment naming the trigger and what's ambiguous. Stop. |
|
|
151
|
+
| `ac_verification_fail` | Same as above. |
|
|
152
|
+
| `ci_repeat_fail` (3+ consecutive failures of the same job after good-faith fix attempts) | Same as above. |
|
|
153
|
+
| `file_scope_drift` (you're modifying files not in the story's `Files:` list) | Post a notify-only comment naming the trigger, list the unplanned files, request confirmation. Continue if the additions are clearly required by the AC. |
|
|
154
|
+
| `estimate_overrun` at 2× story estimate | Post a notify-only comment with current progress and confidence in remaining work. Continue. |
|
|
155
|
+
| `estimate_overrun` at 3× story estimate | Transition to `BLOCKED` + reassign + comment naming the trigger. Stop. |
|
|
156
|
+
| `file_overlap_with_open_story` | Transition the ticket to `BLOCKED`, reassign to the ticket owner, post a comment naming the overlapping story's slug and the files in common. Stop. Do NOT proceed to PR-open; do NOT attempt to merge the inline fix. |
|
|
157
|
+
|
|
158
|
+
> **Note:** `Blocked` is reserved for these human-attention cases (`ambiguity_escalation`, `ac_verification_fail`, `ci_repeat_fail`, `estimate_overrun (3×)`, `file_overlap_with_open_story`). Sync-driven dep-resolution writes to `Waiting` (status id `10137`, transition id `5`), not Blocked. The distinction: Waiting auto-resolves when the dep merges; Blocked requires human intervention.
|
|
159
|
+
|
|
160
|
+
13. **Pre-PR file-overlap check.** Enumerate every file you modified outside the story's declared `Files:` list (every `file_scope_drift` event). For each such file, search `{{STORY_PATH_PATTERN}}*.md` for any story whose `Files:` block includes that file. If a match is found AND that story is not the current ticket AND its post-execution notes show `actual_hours: 0` (not yet executed), fire the `file_overlap_with_open_story` drift trigger from step 12 and stop.
|
|
161
|
+
|
|
162
|
+
14. Populate the story file's `## Post-execution notes` block with concrete values. The unmodified template default (`surprises: []`, `actual_hours: 0`, all fields at default) is forbidden in a merged PR. If a field has no content, write `# none observed` inline instead of leaving the template default. See step 16 for the required field list and step 17 for the verification gate.
|
|
163
|
+
|
|
164
|
+
15. Open a PR following the repo's PR template (under `.github/`). Conventional-commit title (`feat:`, `fix:`, `docs:`, etc.). The PR description must follow the project's template (typically the file at `.github/pull_request_template.md`) and link back to the Jira ticket. The Jira integration will automatically post the PR link as a remote link on the ticket; do not duplicate that as a comment. After PR creation succeeds, transition the ticket to `In Review` (transition id `31`). This is explicit and idempotent — do not rely on the Jira ↔ GitHub integration's auto-transition behavior.
|
|
165
|
+
|
|
166
|
+
**PR title convention — exactly one Jira ticket key, the primary one.** The consuming project's Jira automation rule for "PR merged → transition to Done" is gated by `{{pullRequest.title}} contains {{issue.key}}`. So **every** Jira ticket whose key appears in the PR title will auto-transition to Done on merge. To make this deterministic:
|
|
167
|
+
- The PR title MUST contain the current story's Jira ticket key — the **primary** ticket the PR is being opened for. Format: append ` ({{PROJECT_KEY}}-XXX)` to the conventional-commit title. Example: `feat(api): add pair_history to candidate detail ({{PROJECT_KEY}}-115)`.
|
|
168
|
+
- The PR title MUST NOT contain any **other** Jira ticket key. Even if the implementation work touches files or unblocks behavior tracked by a sibling/prereq ticket, do not put that ticket's key in the title. The branch-name and PR-body references via DVCS integration are sufficient to surface the linkage; the title is reserved for the auto-transition trigger.
|
|
169
|
+
- If the PR body needs to reference a related/prereq story for context, use the **slug** (e.g., `simulator-poster-previous-pair-tracking`) rather than the Jira key (e.g., `{{PROJECT_KEY}}-116`). The slug carries the same human-readable meaning without arming the auto-transition rule.
|
|
170
|
+
- Background: 2026-05-24 — a PR for one ticket included a prereq ticket's key in its title/body. The auto-transition rule fired against both tickets on merge, silently closing the prereq before its dedicated implementation PR existed. The condition `pullRequest.title contains issue.key` was added to the automation rule to enforce this convention; the playbook now codifies the author-side contract that matches it.
|
|
171
|
+
|
|
172
|
+
16. **Populate** the story file's existing `## Post-execution notes` YAML block. The block is **pre-existing** in the template with placeholder values (`actual_hours: 0`, `surprises: []`, etc.); your job is to **overwrite the placeholders with real data**, not to add a new section. Required minimum:
|
|
173
|
+
- `actual_hours` — real session time
|
|
174
|
+
- `estimated_hours` — carry through from the story's `estimate:` frontmatter
|
|
175
|
+
- `estimate_delta_pct` — compute: `(actual − estimated) / estimated × 100`
|
|
176
|
+
- `drift_events` — list of drift triggers fired during the session, or `[]`
|
|
177
|
+
- `surprises` — one or more free-text bullets capturing non-obvious findings. **Single most important field for compounding lessons across stories.** If you genuinely encountered nothing surprising, write that explicitly as a bullet rather than leaving `[]`.
|
|
178
|
+
- `recommended_runbook_updates` — concrete methodology / runbook / story-format edits these findings imply, or `[]` with an explicit comment if you genuinely have none.
|
|
179
|
+
|
|
180
|
+
17. **Verification gate before PR-open.** Confirm the `## Post-execution notes` block has non-placeholder values:
|
|
181
|
+
- `actual_hours != 0`
|
|
182
|
+
- `surprises` either has at least one bullet OR an explicit "nothing notable" comment
|
|
183
|
+
- `estimate_delta_pct` matches your computed value
|
|
184
|
+
If any of these still show the template placeholders, **you have not completed step 16** — go back and populate before opening the PR. This is a hard requirement of the methodology (per `methodology/devin-story-format.md` § "Feedback loop and post-execution notes"); reviewers will reject PRs that fail this gate.
|
|
185
|
+
|
|
186
|
+
## Specifications
|
|
187
|
+
|
|
188
|
+
- **Scoping phase end-state:** a Jira comment matching the template in step 9 is posted to the ticket. No other writes (no state transition, no PR, no in-repo changes).
|
|
189
|
+
- **Ambiguity / format-violation end-state:** a single Jira comment naming the drift trigger from runbook § 4.3 is posted. No other writes.
|
|
190
|
+
- **Implementation phase end-state:** a PR is open against `main`. PR title and body conform to the templates. The Jira ticket has been transitioned through `In Progress` → `In Review` → (eventually) `Done`. The pre-PR file-overlap check (step 13) has passed. The integration has posted the PR link as a remote link. The story file's `Post-execution notes` section has been populated.
|
|
191
|
+
|
|
192
|
+
## Advice and Pointers
|
|
193
|
+
|
|
194
|
+
- **Maturity gradient.** This router is the starting point of a model that matures over time. Two conventions in this router have a gradient:
|
|
195
|
+
- **Frontmatter `jira_key:`** — not yet in the format spec, not yet on any story. The router uses it as the preferred lookup mechanism so the convention can land later without changing the router.
|
|
196
|
+
- **In-story `Execution recipe` section** — now in the format spec as Phase-2 mandatory, Phase-1 backfill optional (`methodology/devin-story-format.md` § "Body structure"). Not yet retrofitted to existing stories. The router degrades gracefully to AC + Files + Validation inference during the transition period.
|
|
197
|
+
As stories migrate to the conventions, this router will be tightened to require them and drop the fallbacks.
|
|
198
|
+
- `CLAUDE.md` is canonical for **locked decisions** (under "Decisions locked"). Anything that contradicts a locked decision is `ambiguity_escalation`, not a license to deviate.
|
|
199
|
+
- Stories under `{{STORY_PATH_PATTERN}}` are already implemented on `main` — if a ticket points at a phase1 story, suspect it's a smoke-test fixture and confirm with the ticket reporter before doing destructive work.
|
|
200
|
+
- Resist producing more than the scoping comment when the integration is in scoping-only mode. The implementation phase only runs when a human has explicitly started the session post-scoping or when the integration is set to direct mode.
|
|
201
|
+
- Confidence calibration: pick the level (HIGH / MEDIUM / LOW) deterministically per step 8's anchors — not by gut feel. The most common miscalibration is softening a real blocker into MEDIUM because "the rest of the scope is clear." It's not — one hard blocker is enough to make confidence LOW, and LOW triggers step 9a's automatic `ambiguity_escalation` (transition to BLOCKED). Hedging into MEDIUM bypasses that gate and leaves the operator to manually catch the blocker; that's a worse outcome than the system was designed to produce.
|
|
202
|
+
- **Jira identity model during the POC.** The native Devin ↔ Jira integration runs as `icpipeline` (admin OAuth). Its stub acknowledgement comment posts under whoever transitioned the ticket. Your substantive REST-API comments (step 8 / step 11) post under the Devin integration service account (`DevinInt`) because the OAuth client credentials belong to that service account. Don't be surprised if author attribution varies between the automated stub and your substantive output — this is expected.
|
|
203
|
+
- **Secret rotation.** `JIRA_OAUTH_CLIENT_ID` and `JIRA_OAUTH_CLIENT_SECRET` are the org-vault secrets for Jira REST access. Unlike API tokens, OAuth client secrets do not auto-expire on a fixed cadence, but they can be rotated or revoked in the Atlassian Developer Console. If the token exchange returns a 401, raise `ambiguity_escalation` immediately rather than retrying; the human owner must re-provision the credentials at https://developer.atlassian.com/console/myapps/ and update the Devin org vault.
|
|
204
|
+
|
|
205
|
+
## Forbidden Actions
|
|
206
|
+
|
|
207
|
+
- Do NOT modify the repo's locked decisions (`CLAUDE.md` § "Decisions locked").
|
|
208
|
+
- Do NOT merge to `main`.
|
|
209
|
+
- Do NOT push directly to `main`; always open a PR via the project's branch convention.
|
|
210
|
+
- Do NOT modify tests to make them pass unless the story's `Execution recipe` or `Acceptance criteria` explicitly asks for test changes.
|
|
211
|
+
- Do NOT proceed past scoping if your confidence is LOW. Step 10a is the procedure for this — fire `ambiguity_escalation` (transition to BLOCKED + reassign + comment), don't just stop silently and don't soften the rating into MEDIUM to keep the ticket in `READY FOR AI AGENT`.
|
|
212
|
+
- Do NOT transition the ticket out of `READY FOR AI AGENT` during the scoping phase. State transitions happen during implementation per the runbook's rules, or via the integration on PR open.
|
|
213
|
+
- Do NOT use admin-level Jira APIs beyond posting comments and transitioning the ticket per the rules in step 11. No bulk operations, no workflow edits, no project-config changes.
|
|
214
|
+
- Do NOT author finished business logic, React components, or route handlers without first checking `CLAUDE.md` § "How to work on this project" — Bryan writes implementation himself in VS Code for some surfaces; respect that boundary unless the story's recipe explicitly says otherwise.
|
|
215
|
+
- Do NOT skip the scoping-notes commit. The Jira comment is a duplicate; the story file is the canonical record.
|
|
216
|
+
- Do NOT open a PR while the post-exec block is identical to the template default. The block exists to capture findings the next agent session needs to read; an empty block is silently lying about what happened.
|
|
217
|
+
- Do NOT put more than one Jira ticket key in a PR title. The consuming project's "PR merged → transition to Done" automation is gated by `pullRequest.title contains issue.key`, so any ticket whose key appears in the title auto-transitions on merge. Step 15 codifies the rule; for context on the prior failure mode that prompted it, see the 2026-05-24 episode noted there.
|