methodology-framework 0.4.2__tar.gz → 0.4.3__tar.gz

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.
Files changed (36) hide show
  1. {methodology_framework-0.4.2/src/methodology_framework.egg-info → methodology_framework-0.4.3}/PKG-INFO +2 -2
  2. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/README.md +1 -1
  3. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/pyproject.toml +1 -1
  4. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/build_playbook.py +3 -3
  5. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/jira_discovery.py +86 -21
  6. methodology_framework-0.4.2/src/methodology_framework/playbooks/scrum-router.body.md → methodology_framework-0.4.3/src/methodology_framework/playbooks/router-base.body.md +2 -1
  7. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/register_playbook_with_devin.py +1 -3
  8. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/sync_stories_to_jira.py +6 -3
  9. {methodology_framework-0.4.2 → methodology_framework-0.4.3/src/methodology_framework.egg-info}/PKG-INFO +2 -2
  10. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework.egg-info/SOURCES.txt +1 -1
  11. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/LICENSE +0 -0
  12. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/setup.cfg +0 -0
  13. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/__init__.py +0 -0
  14. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/__main__.py +0 -0
  15. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/bootstrap_jira.py +0 -0
  16. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/jira_shapes/__init__.py +0 -0
  17. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/jira_shapes/automation_rules.yaml +0 -0
  18. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/jira_shapes/custom_fields.yaml +0 -0
  19. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/jira_shapes/workflow.yaml +0 -0
  20. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/playbooks/bindings/meth.yaml +0 -0
  21. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/playbooks/bindings/scrum.yaml +0 -0
  22. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/populate_acus.py +0 -0
  23. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/specs/devin-story-format.md +0 -0
  24. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/templates/github_workflows/populate-story-acus-caller.yml +0 -0
  25. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework/templates/story.md +0 -0
  26. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework.egg-info/dependency_links.txt +0 -0
  27. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework.egg-info/requires.txt +0 -0
  28. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/src/methodology_framework.egg-info/top_level.txt +0 -0
  29. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_bootstrap_jira.py +0 -0
  30. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_build_playbook.py +0 -0
  31. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_jira_discovery.py +0 -0
  32. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_populate_acus.py +0 -0
  33. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_populate_acus_integration.py +0 -0
  34. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_register_playbook_with_devin.py +0 -0
  35. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_sync_stories_to_jira.py +0 -0
  36. {methodology_framework-0.4.2 → methodology_framework-0.4.3}/tests/test_workflows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: methodology-framework
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Portable process tooling for agent-driven delivery — scripts, playbooks, templates, and specs.
5
5
  Author: whiteout59
6
6
  License-Expression: Apache-2.0
@@ -316,7 +316,7 @@ jobs:
316
316
  build-and-register:
317
317
  uses: whiteout59/methodology-framework/.github/workflows/build-and-register.yml@v0.1.0
318
318
  with:
319
- playbook_body_path: "methodology/playbooks/scrum-router.body.md"
319
+ playbook_body_path: "methodology/playbooks/router-base.body.md"
320
320
  bindings_path: "docs/jira-pickup-config.md"
321
321
  secrets:
322
322
  DEVIN_API_TOKEN: ${{ secrets.DEVIN_API_TOKEN }}
@@ -292,7 +292,7 @@ jobs:
292
292
  build-and-register:
293
293
  uses: whiteout59/methodology-framework/.github/workflows/build-and-register.yml@v0.1.0
294
294
  with:
295
- playbook_body_path: "methodology/playbooks/scrum-router.body.md"
295
+ playbook_body_path: "methodology/playbooks/router-base.body.md"
296
296
  bindings_path: "docs/jira-pickup-config.md"
297
297
  secrets:
298
298
  DEVIN_API_TOKEN: ${{ secrets.DEVIN_API_TOKEN }}
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "methodology-framework"
7
- version = "0.4.2"
7
+ version = "0.4.3"
8
8
  description = "Portable process tooling for agent-driven delivery — scripts, playbooks, templates, and specs."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  """Build a concrete, project-bound playbook from the parameterized body + bindings.
3
3
 
4
- Reads the parameterized playbook body from methodology/playbooks/scrum-router.body.md
4
+ Reads the parameterized playbook body from methodology/playbooks/router-base.body.md
5
5
  and substitutes {{PLACEHOLDER}} tokens with the project-specific bindings defined in
6
6
  docs/jira-pickup-config.md § 5.1 (the playbook_bindings YAML block).
7
7
 
@@ -23,7 +23,7 @@ Options:
23
23
  Does not write output.
24
24
 
25
25
  When --body and --bindings are omitted, the script falls back to the legacy
26
- hardcoded paths (methodology/playbooks/scrum-router.body.md and
26
+ hardcoded paths (methodology/playbooks/router-base.body.md and
27
27
  docs/jira-pickup-config.md relative to the repo root).
28
28
  """
29
29
 
@@ -35,7 +35,7 @@ import sys
35
35
  from pathlib import Path
36
36
 
37
37
  REPO_ROOT = Path(__file__).resolve().parent.parent
38
- BODY_PATH = REPO_ROOT / "methodology" / "playbooks" / "scrum-router.body.md"
38
+ BODY_PATH = REPO_ROOT / "methodology" / "playbooks" / "router-base.body.md"
39
39
  CONFIG_PATH = REPO_ROOT / "docs" / "jira-pickup-config.md"
40
40
 
41
41
  PLACEHOLDER_RE = re.compile(r"\{\{(\w+)\}\}")
@@ -229,24 +229,14 @@ def discover_statuses(
229
229
  return result
230
230
 
231
231
 
232
- def discover_transitions(
233
- session: Any,
234
- base_url: str,
235
- project_key: str,
236
- ) -> dict[str, str]:
237
- """Discover transition name→ID map.
238
-
239
- Uses GET /rest/api/3/project/{key}/statuses to find a sample issue
240
- type, then queries the workflow scheme. Falls back to scanning
241
- transitions from each status via the workflow spec.
242
-
243
- For transitions, the approach is: use the statuses endpoint to get
244
- status names, then use GET /rest/api/3/status to get transitions.
245
- But Jira Cloud doesn't expose transitions without an issue context.
246
-
247
- Instead, we create a name→ID map from the workflow spec (which has
248
- transition_id values) and verify they're consistent with what's live.
249
- The verifier already checked these exist; we trust the spec IDs.
232
+ def _spec_transition_map() -> dict[str, str]:
233
+ """Return canonical transition name→ID map sourced from workflow.yaml.
234
+
235
+ Used only for dry-run sync invocations where no Jira credentials are
236
+ available. Returns the SCRUM-accidental IDs encoded in the spec —
237
+ these are stable for the SCRUM project but will NOT match a freshly-
238
+ provisioned team-managed project. Real sync uses :func:`discover_transitions`
239
+ which queries Jira directly.
250
240
  """
251
241
  shape = _load_shape(_WORKFLOW_YAML)
252
242
  result: dict[str, str] = {}
@@ -256,11 +246,86 @@ def discover_transitions(
256
246
  tid = str(t["transition_id"])
257
247
  if name not in result:
258
248
  result[name] = tid
249
+ return result
259
250
 
260
- if not result:
261
- raise _fail("transition", "(any)", project_key)
262
251
 
263
- return result
252
+ def discover_transitions(
253
+ session: Any,
254
+ base_url: str,
255
+ project_key: str,
256
+ ) -> dict[str, str]:
257
+ """Discover transition name→ID map by querying Jira directly.
258
+
259
+ Strategy: find any existing issue in the project via JQL search, then
260
+ call ``GET /rest/api/3/issue/{key}/transitions`` to read the live
261
+ transition map for the workflow. The framework's canonical workflow
262
+ uses global transitions (``isGlobal: true``), so any single issue
263
+ exposes the complete name→ID map.
264
+
265
+ Raises :class:`DiscoveryError` if:
266
+
267
+ - The project has no issues yet (operator must create at least one
268
+ issue before first sync — sync can't probe an empty project's
269
+ workflow because Jira Cloud only exposes transitions in an issue
270
+ context).
271
+ - Any canonical transition name is missing from the live workflow
272
+ (operator must fix the workflow per ``bootstrap-jira --verify``).
273
+
274
+ For SCRUM the discovered IDs match :func:`_spec_transition_map` by
275
+ historical accident. For freshly-provisioned projects they will not —
276
+ that's the point of querying instead of trusting the spec.
277
+ """
278
+ # Find any existing issue in the project via JQL.
279
+ resp = session.get(
280
+ f"{base_url}/rest/api/3/search/jql",
281
+ params={
282
+ "jql": f"project={project_key}",
283
+ "fields": "key",
284
+ "maxResults": 1,
285
+ },
286
+ )
287
+ resp.raise_for_status()
288
+ search_data: dict[str, Any] = resp.json()
289
+ issues = search_data.get("issues") or []
290
+
291
+ if not issues:
292
+ raise DiscoveryError(
293
+ f"Project {project_key} has no issues yet, so workflow transitions "
294
+ f"cannot be probed. Jira Cloud only exposes transition IDs in an "
295
+ f"issue context. Create at least one placeholder issue in "
296
+ f"{project_key} (any issue type, any state) and re-run sync. "
297
+ f"That issue is enough — discovery uses it as a probe to read the "
298
+ f"global transition map for the project's workflow."
299
+ )
300
+
301
+ probe_key: str = issues[0]["key"]
302
+ logger.info(
303
+ "Probing transitions on %s (any existing issue exposes the global "
304
+ "transition map for the project's workflow).",
305
+ probe_key,
306
+ )
307
+
308
+ resp = session.get(f"{base_url}/rest/api/3/issue/{probe_key}/transitions")
309
+ resp.raise_for_status()
310
+ transitions_data: dict[str, Any] = resp.json()
311
+
312
+ name_to_id: dict[str, str] = {}
313
+ for t in transitions_data.get("transitions", []):
314
+ name_to_id[t["name"]] = str(t["id"])
315
+
316
+ # Verify every canonical transition name resolved.
317
+ canonical = _canonical_transition_names()
318
+ missing = canonical - set(name_to_id.keys())
319
+ if missing:
320
+ raise DiscoveryError(
321
+ f"Project {project_key}'s workflow is missing required transition(s): "
322
+ f"{', '.join(sorted(missing))}. "
323
+ f"Run 'methodology-framework bootstrap-jira --verify "
324
+ f"--project-key={project_key}' to identify the gaps, then add the "
325
+ f"missing states/transitions in the Jira workflow editor."
326
+ )
327
+
328
+ return name_to_id
264
329
 
265
330
 
266
331
  def discover_link_types(
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  playbook_id: {{PLAYBOOK_ID}}
3
- version: 1.5.0
3
+ version: 1.6.0
4
4
  changelog:
5
+ - "1.6.0 (2026-06-07): Renamed body file from `scrum-router.body.md` to `router-base.body.md`. Canonical-template naming should be project-neutral; the SCRUM prefix was a legacy artifact from when the playbook had a single SCRUM binding. The rendered outputs continue to be named per-binding via `{{PLAYBOOK_ID}}` (scrum-router, meth-router, etc.). Code + workflow references updated to the new path. Closes #113. MINOR bump per SemVer (additive: file rename + reference updates, no body content change)."
5
6
  - "1.5.0 (2026-06-07): Parameterize all self-references via new {{PLAYBOOK_ID}} substitution token (previously hardcoded as `scrum-router` in 4 places — frontmatter, the audit-banner step, the comment template, and the webapp settings-path reference). Bindings (scrum.yaml, meth.yaml) now declare PLAYBOOK_ID. Rendered METH playbook now correctly emits `meth-router` in the audit banner instead of `scrum-router` (surfaced by the post-extraction smoke #71 / METH-5). MINOR bump per SemVer (new substitution token added; no breaking change since all bindings updated simultaneously). Closes #92."
6
7
  - "1.4.0 (2026-06-02): Added METH as a second bound project alongside SCRUM. Surface expansion only; no body changes. MINOR bump per SemVer (binding surface expands without breaking existing callers)."
7
8
  - "1.3.0 (2026-05-29): New convention — cross-repo writeback discipline (story file in repo A, implementation in repo B → two-PR pattern with writeback PR in repo A). New convention — agent populates agent_session_url field in post-execution notes block. New convention — agent_acus field added to post-exec block (default \"pending\"; populated asynchronously by post-merge automation since agents cannot self-report ACU consumption mid-session). MINOR bump per SemVer (three additive new conventions, no breaking changes for single-repo work)."
@@ -103,9 +103,7 @@ def list_playbooks(token: str, org_id: str) -> list[dict[str, Any]]:
103
103
  # forward-compat across API shape changes.
104
104
  if isinstance(resp, list):
105
105
  return resp
106
- items: list[dict[str, Any]] = resp.get(
107
- "items", resp.get("playbooks", resp.get("data", []))
108
- )
106
+ items: list[dict[str, Any]] = resp.get("items", resp.get("playbooks", resp.get("data", [])))
109
107
  return items
110
108
 
111
109
 
@@ -1070,10 +1070,13 @@ def main(argv: list[str] | None = None) -> int:
1070
1070
  logger.error("Jira shape discovery failed: %s", exc)
1071
1071
  return 1
1072
1072
  else:
1073
- # In dry-run mode, use a placeholder shape with spec-sourced IDs
1074
- from methodology_framework.jira_discovery import discover_transitions as _dt
1073
+ # In dry-run mode, use a placeholder shape with spec-sourced IDs.
1074
+ # _spec_transition_map() reads workflow.yaml and never calls Jira —
1075
+ # safe for dry-run where credentials may be absent. Real sync uses
1076
+ # discover_transitions() which probes a live issue.
1077
+ from methodology_framework.jira_discovery import _spec_transition_map
1075
1078
 
1076
- transitions = _dt(client.session, client.base_url, project_key)
1079
+ transitions = _spec_transition_map()
1077
1080
  shape = JiraShape(
1078
1081
  project_key=project_key,
1079
1082
  cf_story_file="DRY_RUN_CF",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: methodology-framework
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Portable process tooling for agent-driven delivery — scripts, playbooks, templates, and specs.
5
5
  Author: whiteout59
6
6
  License-Expression: Apache-2.0
@@ -316,7 +316,7 @@ jobs:
316
316
  build-and-register:
317
317
  uses: whiteout59/methodology-framework/.github/workflows/build-and-register.yml@v0.1.0
318
318
  with:
319
- playbook_body_path: "methodology/playbooks/scrum-router.body.md"
319
+ playbook_body_path: "methodology/playbooks/router-base.body.md"
320
320
  bindings_path: "docs/jira-pickup-config.md"
321
321
  secrets:
322
322
  DEVIN_API_TOKEN: ${{ secrets.DEVIN_API_TOKEN }}
@@ -18,7 +18,7 @@ src/methodology_framework/jira_shapes/__init__.py
18
18
  src/methodology_framework/jira_shapes/automation_rules.yaml
19
19
  src/methodology_framework/jira_shapes/custom_fields.yaml
20
20
  src/methodology_framework/jira_shapes/workflow.yaml
21
- src/methodology_framework/playbooks/scrum-router.body.md
21
+ src/methodology_framework/playbooks/router-base.body.md
22
22
  src/methodology_framework/playbooks/bindings/meth.yaml
23
23
  src/methodology_framework/playbooks/bindings/scrum.yaml
24
24
  src/methodology_framework/specs/devin-story-format.md