devflow-kit 2.5.0 → 3.0.0

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 (158) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +44 -19
  3. package/dist/agents/git.md +13 -15
  4. package/dist/cli/commands/ambient.js +160 -145
  5. package/dist/cli/commands/capture.js +29 -55
  6. package/dist/cli/commands/compliance.js +32 -61
  7. package/dist/cli/commands/context.js +17 -32
  8. package/dist/cli/commands/debug.js +65 -26
  9. package/dist/cli/commands/flags.js +3 -3
  10. package/dist/cli/commands/hud.js +34 -10
  11. package/dist/cli/commands/init-seed.js +40 -4
  12. package/dist/cli/commands/init.js +249 -271
  13. package/dist/cli/commands/install-report.js +10 -15
  14. package/dist/cli/commands/knowledge/index.js +1 -1
  15. package/dist/cli/commands/knowledge/toggle.js +11 -3
  16. package/dist/cli/commands/learning.js +52 -37
  17. package/dist/cli/commands/legacy-hooks.js +11 -14
  18. package/dist/cli/commands/memory.js +67 -78
  19. package/dist/cli/commands/proxy.js +23 -41
  20. package/dist/cli/commands/security.js +5 -13
  21. package/dist/cli/commands/skills.js +21 -3
  22. package/dist/cli/commands/tracker.js +100 -228
  23. package/dist/cli/commands/uninstall.js +343 -138
  24. package/dist/commands/bug-analysis.md +38 -12
  25. package/dist/commands/code-review.md +70 -21
  26. package/dist/commands/debug.md +37 -7
  27. package/dist/commands/dynamic-build.md +66 -17
  28. package/dist/commands/dynamic-plan.md +19 -8
  29. package/dist/commands/dynamic-profile.md +24 -10
  30. package/dist/commands/dynamic-tickets.md +22 -11
  31. package/dist/commands/explore.md +37 -7
  32. package/dist/commands/implement.md +96 -32
  33. package/dist/commands/plan.md +62 -19
  34. package/dist/commands/release.md +2 -2
  35. package/dist/commands/research.md +34 -8
  36. package/dist/commands/resolve.md +65 -17
  37. package/dist/commands/self-review.md +45 -9
  38. package/dist/core/compliance-compose.js +27 -27
  39. package/dist/core/evidence-policy.js +240 -24
  40. package/dist/core/feature-config.js +94 -25
  41. package/dist/core/feature-switch.js +1 -1
  42. package/dist/core/flags.js +30 -2
  43. package/dist/core/fs-atomic.js +27 -0
  44. package/dist/core/hook-log-dirs.js +104 -0
  45. package/dist/core/learning-tuning-config.js +5 -3
  46. package/dist/core/ledger-root.js +102 -0
  47. package/dist/core/manifest.js +6 -4
  48. package/dist/core/mds-variants.js +34 -97
  49. package/dist/core/migrations.js +49 -23
  50. package/dist/core/plugins.js +5 -4
  51. package/dist/core/project-paths.js +0 -17
  52. package/dist/core/same-location.js +25 -0
  53. package/dist/core/tracker.js +226 -139
  54. package/dist/hud/components/config-counts.js +15 -4
  55. package/dist/hud/components/learning-counts.js +14 -0
  56. package/dist/hud/config.js +2 -1
  57. package/dist/hud/cost-history.js +2 -4
  58. package/dist/hud/git.js +52 -7
  59. package/dist/hud/index.js +7 -9
  60. package/dist/skills/git/references/pr/check-merge-readiness.md +1 -1
  61. package/dist/skills/git/references/pr/ensure-pr-ready.md +1 -1
  62. package/dist/skills/git/references/pr/update-pr-evidence.md +1 -1
  63. package/dist/skills/git/references/tracker/_mcp.md +1 -1
  64. package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +1 -1
  65. package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +1 -1
  66. package/dist/skills/git/references/tracker/github/gather-release-evidence.md +2 -2
  67. package/dist/skills/git/references/tracker/github/manage-debt.md +3 -3
  68. package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +1 -1
  69. package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +1 -1
  70. package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +2 -2
  71. package/dist/skills/git/references/tracker/jira/manage-debt.md +1 -1
  72. package/dist/skills/git/references/tracker/jira/post-wave-report.md +1 -1
  73. package/dist/skills/git/references/tracker/jira/setup-task.md +1 -1
  74. package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +1 -1
  75. package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +1 -1
  76. package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +2 -2
  77. package/dist/skills/git/references/tracker/linear/manage-debt.md +1 -1
  78. package/dist/skills/git/references/tracker/linear/post-wave-report.md +1 -1
  79. package/dist/skills/git/references/tracker/linear/setup-task.md +1 -1
  80. package/dist/targets/claude-code/claude-paths.js +59 -57
  81. package/dist/targets/claude-code/compliance-install.js +49 -65
  82. package/dist/targets/claude-code/hooks.js +108 -3
  83. package/dist/targets/claude-code/installer.js +30 -57
  84. package/dist/targets/claude-code/post-install.js +232 -139
  85. package/dist/targets/claude-code/tracker-install.js +38 -65
  86. package/package.json +5 -4
  87. package/src/assets/agents/code.md +4 -3
  88. package/src/assets/agents/design.md +1 -0
  89. package/src/assets/agents/git.mds +55 -57
  90. package/src/assets/agents/knowledge.md +2 -2
  91. package/src/assets/agents/review.md +3 -1
  92. package/src/assets/agents/tracker.md +37 -30
  93. package/src/assets/commands/_partials/_compliance.mds +19 -1
  94. package/src/assets/commands/_partials/_decisions.mds +15 -3
  95. package/src/assets/commands/_partials/_docs_root.mds +35 -0
  96. package/src/assets/commands/_partials/_engine.mds +2 -2
  97. package/src/assets/commands/_partials/_evidence_policy.mds +3 -3
  98. package/src/assets/commands/_partials/_factory.mds +1 -1
  99. package/src/assets/commands/_partials/_knowledge.mds +27 -9
  100. package/src/assets/commands/_partials/_plan_contract.mds +2 -2
  101. package/src/assets/commands/_partials/_preamble.mds +1 -1
  102. package/src/assets/commands/_partials/_publication.mds +6 -2
  103. package/src/assets/commands/_partials/_settings.mds +28 -0
  104. package/src/assets/commands/_partials/_ticket_template.mds +3 -3
  105. package/src/assets/commands/_partials/_tracker.mds +4 -4
  106. package/src/assets/commands/_partials/_wave.mds +4 -4
  107. package/src/assets/commands/bug-analysis.mds +19 -17
  108. package/src/assets/commands/code-review.mds +39 -33
  109. package/src/assets/commands/debug.mds +4 -5
  110. package/src/assets/commands/dynamic-build.mds +75 -53
  111. package/src/assets/commands/dynamic-plan.mds +20 -15
  112. package/src/assets/commands/dynamic-profile.mds +24 -11
  113. package/src/assets/commands/dynamic-tickets.mds +25 -20
  114. package/src/assets/commands/explore.mds +4 -5
  115. package/src/assets/commands/implement.mds +58 -45
  116. package/src/assets/commands/plan.mds +34 -29
  117. package/src/assets/commands/release.md +2 -2
  118. package/src/assets/commands/research.mds +11 -9
  119. package/src/assets/commands/resolve.mds +41 -39
  120. package/src/assets/commands/self-review.mds +24 -25
  121. package/src/assets/mds/git/_pr.mds +61 -61
  122. package/src/assets/mds/git/_references.mds +19 -19
  123. package/src/assets/mds/tracker/_common.mds +8 -8
  124. package/src/assets/mds/tracker/_github.mds +71 -71
  125. package/src/assets/mds/tracker/_jira.mds +74 -74
  126. package/src/assets/mds/tracker/_linear.mds +75 -75
  127. package/src/assets/mds/tracker/_mcp.mds +23 -17
  128. package/src/assets/scripts/hooks/background-memory-update +35 -19
  129. package/src/assets/scripts/hooks/capture-prompt +18 -12
  130. package/src/assets/scripts/hooks/capture-question +18 -12
  131. package/src/assets/scripts/hooks/capture-turn +27 -17
  132. package/src/assets/scripts/hooks/debug-trace +11 -6
  133. package/src/assets/scripts/hooks/ensure-devflow-init +33 -6
  134. package/src/assets/scripts/hooks/ensure-proxy +9 -8
  135. package/src/assets/scripts/hooks/ensure-root-gitignore +111 -36
  136. package/src/assets/scripts/hooks/git-marker +48 -0
  137. package/src/assets/scripts/hooks/json-helper.cjs +6 -1
  138. package/src/assets/scripts/hooks/lib/project-paths.cjs +0 -19
  139. package/src/assets/scripts/hooks/log-paths +80 -0
  140. package/src/assets/scripts/hooks/memory-worker +17 -15
  141. package/src/assets/scripts/hooks/pre-compact-memory +41 -16
  142. package/src/assets/scripts/hooks/queue-append +104 -30
  143. package/src/assets/scripts/hooks/resolve-project-root +101 -7
  144. package/src/assets/scripts/hooks/session-start-context +289 -122
  145. package/src/assets/scripts/hooks/session-start-memory +35 -16
  146. package/src/assets/scripts/lib/project-config.cjs +633 -0
  147. package/src/assets/scripts/resolve-evidence-policy.cjs +300 -220
  148. package/src/assets/scripts/resolve-settings.cjs +1054 -0
  149. package/src/assets/scripts/verify-evidence.cjs +1 -1
  150. package/src/assets/skills/compliance/SKILL.md +2 -2
  151. package/src/assets/skills/docs-framework/SKILL.md +6 -7
  152. package/src/assets/skills/docs-framework/references/patterns.md +10 -17
  153. package/src/assets/skills/gap-analysis/SKILL.md +2 -2
  154. package/src/assets/skills/git/references/github-api.md +9 -9
  155. package/src/assets/skills/git/references/patterns.md +1 -1
  156. package/src/assets/skills/worktree-support/SKILL.md +1 -1
  157. package/src/assets/skills/worktree-support/references/roots.md +29 -0
  158. package/src/targets/claude-code/templates/managed-settings.json +25 -9
@@ -43,23 +43,23 @@ Load when the resolved tracker provider is `github` and the operation is `setup-
43
43
 
44
44
  ### Process
45
45
 
46
- 1. **`ISSUE_INPUT` pre-flight**, when provided: it must satisfy `^#?[1-9][0-9]\{0,8\}$`, anchored at both ends; strip one leading `#` — the digits are the issue number steps 1c and 3 use. Anything else ⇒ `TRACEABILITY: DEGRADED (issue reference "\{ref\}" does not match github reference grammar)`, and the task proceeds with no issue.
47
- {common.conventions_step()}
46
+ 1. **`ISSUE_INPUT` pre-flight**, when provided: it must satisfy `^#?[1-9][0-9]{0,8}$`, anchored at both ends; strip one leading `#` — the digits are the issue number steps 1c and 3 use. Anything else ⇒ `TRACEABILITY: DEGRADED (issue reference "{ref}" does not match github reference grammar)`, and the task proceeds with no issue.
47
+ {{common.conventions_step()}}
48
48
  1c. Issue-first, only when `ISSUE_REQUIRED` is `true`: before branch derivation, ensure a GitHub issue exists for this task:
49
- - Preconditions: remote reachable AND `gh` authenticated. If either fails → emit `TRACEABILITY: DEGRADED (\{reason\})` and continue to step 2 (convention still applies; no issue number is set).
49
+ - Preconditions: remote reachable AND `gh` authenticated. If either fails → emit `TRACEABILITY: DEGRADED ({reason})` and continue to step 2 (convention still applies; no issue number is set).
50
50
  - If `ISSUE_INPUT` was provided, step 1 alone decides the number.
51
51
  - Otherwise: invoke `ensure-traceable-issue` with `TASK_DESCRIPTION` (and `PLAN_ARTIFACT_PATH` if provided) to create or find an issue. Capture the returned issue number.
52
- - Issue number drives the branch name in step 3: `\{type\}/\{number\}-\{slug\}`.
53
- {common.branch_detection_step()}
52
+ - Issue number drives the branch name in step 3: `{type}/{number}-{slug}`.
53
+ {{common.branch_detection_step()}}
54
54
  3. **Derive branch name** (using detected convention):
55
- - If issue number is known (from step 1 or 1c): fetch issue via GitHub API, then derive branch name as `\{type\}/\{number\}-\{slug\}` where:
55
+ - If issue number is known (from step 1 or 1c): fetch issue via GitHub API, then derive branch name as `{type}/{number}-{slug}` where:
56
56
  - `type` is inferred from issue labels: `bug` → `fix`, `documentation` or `docs` → `docs`, `refactor` → `refactor`, `chore` or `maintenance` → `chore`, default → `feature`
57
57
  - `slug` is the issue title: lowercased, non-alphanumeric replaced with hyphens, consecutive hyphens collapsed, trimmed, max 40 characters
58
58
  - Before placing fetched content in the output, neutralise any `</untrusted-issue-body>` in it (Principle 8 marker neutralisation).
59
- - If `TASK_DESCRIPTION` provided (no issue): infer type from description keywords (e.g., "fix login bug" → `fix`, "refactor auth" → `refactor`, "add JWT" → `feature`, "update docs" → `docs`, "chore: cleanup" → `chore`), then slugify description as `\{type\}/\{slug\}` (max 40 chars)
60
- - If neither: fallback to `task-\{YYYY-MM-DD_HHMM\}`
59
+ - If `TASK_DESCRIPTION` provided (no issue): infer type from description keywords (e.g., "fix login bug" → `fix`, "refactor auth" → `refactor`, "add JWT" → `feature`, "update docs" → `docs`, "chore: cleanup" → `chore`), then slugify description as `{type}/{slug}` (max 40 chars)
60
+ - If neither: fallback to `task-{YYYY-MM-DD_HHMM}`
61
61
 
62
- {common.handoff_values("`{n}` (bare, never `#{n}`)", "Closes #{n}")}
62
+ {{common.handoff_values("`{n}` (bare, never `#{n}`)", "Closes #{n}")}}
63
63
  @end
64
64
 
65
65
  @define fetch_issue():
@@ -71,11 +71,11 @@ Load when the resolved tracker provider is `github` and the operation is `fetch-
71
71
 
72
72
  ### Process
73
73
 
74
- 1b. **Ref pre-flight.** The numeric path is taken only when `ISSUE_INPUT` satisfies `^#?[1-9][0-9]\{0,8\}$` — this provider's anchored reference grammar, stated with its strip-one-leading-`#` normalisation and the shell-comment reason it exists for in this operation's sibling `backlink-shipped-issues` reference. Interpolate only the digits that survive the strip. Anything the grammar rejects is a SEARCH TERM and takes the text path, so it never reaches a command.
74
+ 1b. **Ref pre-flight.** The numeric path is taken only when `ISSUE_INPUT` satisfies `^#?[1-9][0-9]{0,8}$` — this provider's anchored reference grammar, stated with its strip-one-leading-`#` normalisation and the shell-comment reason it exists for in this operation's sibling `backlink-shipped-issues` reference. Interpolate only the digits that survive the strip. Anything the grammar rejects is a SEARCH TERM and takes the text path, so it never reaches a command.
75
75
  2. Fetch full issue data (title, body, labels, assignees, milestone, comments)
76
76
  3. Extract acceptance criteria and dependencies from body; neutralise any `</untrusted-issue-body>` in the body before wrapping (Principle 8 marker neutralisation).
77
77
 
78
- {common.handoff_values("`{n}` (bare, never `#{n}`)", "Closes #{n}")}
78
+ {{common.handoff_values("`{n}` (bare, never `#{n}`)", "Closes #{n}")}}
79
79
 
80
80
  ### Fetch Issue with All Details
81
81
 
@@ -108,13 +108,13 @@ Load when the resolved tracker provider is `github` and the operation is `fetch-
108
108
 
109
109
  2. Fetch all issues in a **single** GraphQL query using per-issue aliases (dynamically constructed for the resolved list); resolve owner/repo from the git remote context:
110
110
  ```
111
- gh api graphql -f query='query \{ repository(owner:"OWNER", name:"REPO") \{
112
- i1: issue(number:N1) \{ number title state body labels(first:10)\{nodes\{name\}\} assignees(first:5)\{nodes\{login\}\} milestone\{title\} \}
113
- i2: issue(number:N2) \{ number title state body labels(first:10)\{nodes\{name\}\} assignees(first:5)\{nodes\{login\}\} milestone\{title\} \}
111
+ gh api graphql -f query='query { repository(owner:"OWNER", name:"REPO") {
112
+ i1: issue(number:N1) { number title state body labels(first:10){nodes{name}} assignees(first:5){nodes{login}} milestone{title} }
113
+ i2: issue(number:N2) { number title state body labels(first:10){nodes{name}} assignees(first:5){nodes{login}} milestone{title} }
114
114
  ...
115
- \}\}'
115
+ }}'
116
116
  ```
117
- {common.state_batch_line("`state` (`OPEN` or `CLOSED`)", "`state`", "{ISSUE_REF}")}
117
+ {{common.state_batch_line("`state` (`OPEN` or `CLOSED`)", "`state`", "{ISSUE_REF}")}}
118
118
  @end
119
119
 
120
120
  @define manage_debt():
@@ -129,12 +129,12 @@ Load when the resolved tracker provider is `github` and the operation is `manage
129
129
  1. Find or create "Tech Debt Backlog" issue with `tech-debt` label
130
130
  2. Check issue body size; archive if > 60000 chars (per devflow:git)
131
131
  3. Extract items to add:
132
- - `## Fix Separately` entries from `\{REVIEW_DIR\}/resolution-summary.md` (FIX_SEPARATE from Triage agent)
133
- - `## Deferred to Tech Debt` entries from `\{REVIEW_DIR\}/resolution-summary.md` (TECH_DEBT from Triage agent)
132
+ - `## Fix Separately` entries from `{REVIEW_DIR}/resolution-summary.md` (FIX_SEPARATE from Triage agent)
133
+ - `## Deferred to Tech Debt` entries from `{REVIEW_DIR}/resolution-summary.md` (TECH_DEBT from Triage agent)
134
134
  - Pre-existing issues (Category 3) from review reports
135
135
  4. Deduplicate against existing items using semantic matching
136
136
  5. Remove items that have been fixed (verify in codebase)
137
- 6. Compose updated issue body to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post via `gh issue edit \{number\} --body-file "$DEVFLOW_BODY"`
137
+ 6. Compose updated issue body to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post via `gh issue edit {number} --body-file "$DEVFLOW_BODY"`
138
138
  7. Return the backlog issue number for Tracked field backfill in resolution-summary.md
139
139
 
140
140
  ### Tech Debt Issue Management
@@ -154,7 +154,7 @@ post_scrubbed() {
154
154
  # scrubber scrub — and the chain publish — whatever the RAW file last held.
155
155
  # Never a pipeline: a pipeline's exit status hides a scrubber crash (fail-open).
156
156
  printf '%s\n' "$1" > "$DEVFLOW_BODY_RAW" \
157
- && node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/redact-secrets.cjs" \
157
+ && node "$HOME/.devflow/scripts/redact-secrets.cjs" \
158
158
  "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" \
159
159
  && gh issue comment "$2" --body-file "$DEVFLOW_BODY"
160
160
  }
@@ -181,7 +181,7 @@ add_tech_debt_item() {
181
181
  # edit` replaces the whole body, so what is composed is the body just read plus
182
182
  # the new item, under its trailing `## Items` heading.
183
183
  printf '%s\n%s\n' "$current_body" "$new_item" > "$DEVFLOW_BODY_RAW" \
184
- && node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/redact-secrets.cjs" \
184
+ && node "$HOME/.devflow/scripts/redact-secrets.cjs" \
185
185
  "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" \
186
186
  && gh issue edit "$TECH_DEBT_ISSUE" --body-file "$DEVFLOW_BODY"
187
187
  }
@@ -203,7 +203,7 @@ archive_tech_debt_issue() {
203
203
 
204
204
  ## Items
205
205
  " > "$DEVFLOW_BODY_RAW" \
206
- && node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/redact-secrets.cjs" \
206
+ && node "$HOME/.devflow/scripts/redact-secrets.cjs" \
207
207
  "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" \
208
208
  && new_url=$(gh issue create \
209
209
  --title "Tech Debt Backlog" \
@@ -232,7 +232,7 @@ Load when the resolved tracker provider is `github` and the operation is `create
232
232
 
233
233
  Inside step 5 (compose release notes):
234
234
 
235
- - If `SHIPPED_ISSUES` provided: append a `## Closed Issues` section with issue references — **first ≤50 issues** (the same bound `backlink-shipped-issues` applies); if truncated, add a final `…and \{n\} more issues` line (D4 degrade if enrichment fails)
235
+ - If `SHIPPED_ISSUES` provided: append a `## Closed Issues` section with issue references — **first ≤50 issues** (the same bound `backlink-shipped-issues` applies); if truncated, add a final `…and {n} more issues` line (D4 degrade if enrichment fails)
236
236
  @end
237
237
 
238
238
  @define gather_release_evidence():
@@ -244,17 +244,17 @@ Load when the resolved tracker provider is `github` and the operation is `gather
244
244
 
245
245
  ### Process
246
246
 
247
- {common.last_release_tag_step()}
248
- {common.closing_keyword_rule()}
249
- 3b. **This provider's history grammar** is `^#[1-9][0-9]\{0,8\}$`. A bare number is not a reference here either: a keyword-anchored candidate must carry the `#`, and step 4 renders every number it reads from a merged PR as `#\{n\}` before step 5's gate.
247
+ {{common.last_release_tag_step()}}
248
+ {{common.closing_keyword_rule()}}
249
+ 3b. **This provider's history grammar** is `^#[1-9][0-9]{0,8}$`. A bare number is not a reference here either: a keyword-anchored candidate must carry the `#`, and step 4 renders every number it reads from a merged PR as `#{n}` before step 5's gate.
250
250
  4. If `gh` is authenticated and remote is reachable, resolve which issues the range's merged PRs close — **one listing, never one call per commit** — and merge the result with the commit-message set:
251
- - **Once, before the listing:** this repo's identity, `gh api 'repos/\{owner\}/\{repo\}' --jq '.owner.login + "/" + .name'`, and the tag's UTC date, `TAG_DATE=$(TZ=UTC git log -1 --date=format-local:%Y-%m-%d --format=%cd \{last_tag\})`, shape-gated `^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}$` — a local date can drop a PR merged just after the tag. If `TAG_DATE` fails this gate, treat it as **the listing fails** below: emit `TRACEABILITY: DEGRADED (\{reason\})` and go straight to that bullet's ≤25-PR fallback.
251
+ - **Once, before the listing:** this repo's identity, `gh api 'repos/{owner}/{repo}' --jq '.owner.login + "/" + .name'`, and the tag's UTC date, `TAG_DATE=$(TZ=UTC git log -1 --date=format-local:%Y-%m-%d --format=%cd {last_tag})`, shape-gated `^[0-9]{4}-[0-9]{2}-[0-9]{2}$` — a local date can drop a PR merged just after the tag. If `TAG_DATE` fails this gate, treat it as **the listing fails** below: emit `TRACEABILITY: DEGRADED ({reason})` and go straight to that bullet's ≤25-PR fallback.
252
252
  - **The listing:** `gh pr list --state merged --search "merged:>=$TAG_DATE" --limit 200 --json number,mergeCommit,closingIssuesReferences`; with no tag, omit `--search`.
253
- - **Map locally, with no further call:** keep a listed PR when its `mergeCommit.oid` is in `git rev-list \{last_tag\}..HEAD`, or when a range commit's subject ends `(#N)` naming it. Keep only references whose `repository.owner.login`/`name` equal this repo's identity — any other ⇒ `TRACEABILITY: DEGRADED (foreign issue reference \{ref\})`. Render each kept number `#\{n\}`.
253
+ - **Map locally, with no further call:** keep a listed PR when its `mergeCommit.oid` is in `git rev-list {last_tag}..HEAD`, or when a range commit's subject ends `(#N)` naming it. Keep only references whose `repository.owner.login`/`name` equal this repo's identity — any other ⇒ `TRACEABILITY: DEGRADED (foreign issue reference {ref})`. Render each kept number `#{n}`.
254
254
  - **Coverage:** a range subject carries a PR marker (`(#N)` or `Merge pull request #N`) but no listed PR maps into the range ⇒ `TRACEABILITY: DEGRADED (merged-PR listing did not cover the range)`. A listing of exactly 200 ⇒ status `INDETERMINATE (merged-PR listing hit its 200 cap)`, returning what was collected.
255
- - **The listing fails** (an older `gh` reports `Unknown JSON field`) ⇒ `TRACEABILITY: DEGRADED (\{reason\})`, then fall back to `gh pr view N --json closingIssuesReferences` over the PR numbers in `(#N)` / `Merge pull request #N` subjects — after a listing that succeeds, also over each range `(#N)` naming no listed PR — each N gated `^[1-9][0-9]\{0,8\}$`, filtered and rendered as above, bounded at ≤25 PRs; report the remainder as `THROTTLED (\{n\} not processed)` and never report the enrichment as complete while PRs went unresolved.
255
+ - **The listing fails** (an older `gh` reports `Unknown JSON field`) ⇒ `TRACEABILITY: DEGRADED ({reason})`, then fall back to `gh pr view N --json closingIssuesReferences` over the PR numbers in `(#N)` / `Merge pull request #N` subjects — after a listing that succeeds, also over each range `(#N)` naming no listed PR — each N gated `^[1-9][0-9]{0,8}$`, filtered and rendered as above, bounded at ≤25 PRs; report the remainder as `THROTTLED ({n} not processed)` and never report the enrichment as complete while PRs went unresolved.
256
256
  - On any 4xx → DEGRADED for that item, continue. On 5xx → 1 retry; still 5xx → DEGRADED for that item, continue. On the secondary rate limit of `### Provider signals (GitHub)` in this operation's `backlink-shipped-issues` reference → stop GitHub enrichment immediately, report remaining as `THROTTLED`.
257
- {common.trace_map_step("--grammar github --traced-file \"$T\"", "In one shell: `trap 'rm -- \"$T\"' EXIT; T=\"$(mktemp)\"`, then one 40-hex SHA per line into `$T` — each range commit step 4 tied to a PR with ≥1 kept reference (its `mergeCommit.oid`, or a subject naming it). ")}
257
+ {{common.trace_map_step("--grammar github --traced-file \"$T\"", "In one shell: `trap 'rm -- \"$T\"' EXIT; T=\"$(mktemp)\"`, then one 40-hex SHA per line into `$T` — each range commit step 4 tied to a PR with ≥1 kept reference (its `mergeCommit.oid`, or a subject naming it). ")}}
258
258
  @end
259
259
 
260
260
  @define backlink_shipped_issues():
@@ -276,27 +276,27 @@ The D4 degradation contract and the D11 comment-sink scrub state the rules; what
276
276
 
277
277
  ```bash
278
278
  trap 'GATE=$?; rm -- "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" 2>/dev/null; exit "$GATE"' EXIT INT TERM
279
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/redact-secrets.cjs" "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" \
279
+ node "$HOME/.devflow/scripts/redact-secrets.cjs" "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" \
280
280
  && gh issue comment {number} --body-file "$DEVFLOW_BODY"
281
281
  ```
282
282
 
283
283
  ### Process
284
284
 
285
- **Ref pre-flight (the always-loaded entry gate, instantiated for this provider).** Every entry of `SHIPPED_ISSUES` must satisfy `^#?[1-9][0-9]\{0,8\}$`, anchored at both ends of the STRING (a newline fails it) — this provider's reference grammar is what the entry gate's shape requirement means here, and the anchored form is what keeps a reference out of the commands below. **Then normalise once, before the loop, never inside it:** strip **exactly one** leading `#` from every admitted entry (`#42` ≡ `42`) and interpolate only the stripped digits. The grammar admits both spellings because both are how a reference is written here, but a `#` at word start opens a shell comment — an un-stripped `#42` would truncate `gh issue view`, `gh issue comment` and every other command below at the reference, so the stripped form is the only one that reaches a command. **Drop** every entry that fails and report it as `TRACEABILITY: DEGRADED (issue reference "\{ref\}" does not match github reference grammar)`. If every entry is dropped, emit `TRACEABILITY: DEGRADED (no parseable refs for provider \{p\})`, post nothing, and **never report the status as `COMPLETE`**.
285
+ **Ref pre-flight (the always-loaded entry gate, instantiated for this provider).** Every entry of `SHIPPED_ISSUES` must satisfy `^#?[1-9][0-9]{0,8}$`, anchored at both ends of the STRING (a newline fails it) — this provider's reference grammar is what the entry gate's shape requirement means here, and the anchored form is what keeps a reference out of the commands below. **Then normalise once, before the loop, never inside it:** strip **exactly one** leading `#` from every admitted entry (`#42` ≡ `42`) and interpolate only the stripped digits. The grammar admits both spellings because both are how a reference is written here, but a `#` at word start opens a shell comment — an un-stripped `#42` would truncate `gh issue view`, `gh issue comment` and every other command below at the reference, so the stripped form is the only one that reaches a command. **Drop** every entry that fails and report it as `TRACEABILITY: DEGRADED (issue reference "{ref}" does not match github reference grammar)`. If every entry is dropped, emit `TRACEABILITY: DEGRADED (no parseable refs for provider {p})`, post nothing, and **never report the status as `COMPLETE`**.
286
286
 
287
287
  **Setup (once, before the loop):** Fetch viewer login: `gh api user --jq '.login'` → store as VIEWER_LOGIN
288
288
 
289
289
  Then, per issue, within the operation's ≤50 bound:
290
290
 
291
- 1. Fetch existing comments authored by the viewer: `gh issue view \{number\} --json comments --jq '[.comments[] | select(.author.login == "'"$VIEWER_LOGIN"'")] | .[].body'`
292
- 2. Check if `<!-- devflow:shipped v\{BARE_VERSION\} -->` already present in viewer-authored comments. If yes: skip.
291
+ 1. Fetch existing comments authored by the viewer: `gh issue view {number} --json comments --jq '[.comments[] | select(.author.login == "'"$VIEWER_LOGIN"'")] | .[].body'`
292
+ 2. Check if `<!-- devflow:shipped v{BARE_VERSION} -->` already present in viewer-authored comments. If yes: skip.
293
293
  3. Write the two-line body to `$DEVFLOW_BODY_RAW` — a real newline, not a `\n` escape (bash does not
294
294
  expand `\n` inside double quotes, so an inline `--body` would post a single literal line):
295
295
  ```
296
- <!-- devflow:shipped v\{BARE_VERSION\} -->
297
- This was shipped in v\{BARE_VERSION\}.
296
+ <!-- devflow:shipped v{BARE_VERSION} -->
297
+ This was shipped in v{BARE_VERSION}.
298
298
  ```
299
- Apply the Comment-sink scrub (D11) and post via `gh issue comment \{number\} --body-file "$DEVFLOW_BODY"`.
299
+ Apply the Comment-sink scrub (D11) and post via `gh issue comment {number} --body-file "$DEVFLOW_BODY"`.
300
300
  4. Wait 1s between issues.
301
301
  @end
302
302
 
@@ -309,14 +309,14 @@ Load when the resolved tracker provider is `github` and the operation is `associ
309
309
 
310
310
  ### Process
311
311
 
312
- **Ref pre-flight (the always-loaded entry gate, instantiated for this provider).** Every entry of `SHIPPED_ISSUES` must satisfy `^#?[1-9][0-9]\{0,8\}$`, anchored at both ends of the STRING; strip exactly one leading `#` once, and interpolate only the digits. Drop each failure as `TRACEABILITY: DEGRADED (issue reference "\{ref\}" does not match github reference grammar)`. Every entry dropped ⇒ `TRACEABILITY: DEGRADED (no parseable refs for provider \{p\})`, no call, and **never report the status as `COMPLETE`**.
312
+ **Ref pre-flight (the always-loaded entry gate, instantiated for this provider).** Every entry of `SHIPPED_ISSUES` must satisfy `^#?[1-9][0-9]{0,8}$`, anchored at both ends of the STRING; strip exactly one leading `#` once, and interpolate only the digits. Drop each failure as `TRACEABILITY: DEGRADED (issue reference "{ref}" does not match github reference grammar)`. Every entry dropped ⇒ `TRACEABILITY: DEGRADED (no parseable refs for provider {p})`, no call, and **never report the status as `COMPLETE`**.
313
313
 
314
314
  Steps 1, 3 and 4 each run in ONE shell that opens with `trap 'rm -- "$F"' EXIT; F="$(mktemp)"`.
315
315
 
316
- 1. **Create first**, once: `gh api --method POST "repos/\{owner\}/\{repo\}/milestones" -f title="v\{BARE_VERSION\}" > "$F"; echo "exit=$?"`, then read `$F` raw — never `--jq` over an error body. `exit=0` ⇒ `created`; keep its `number` and `node_id`.
317
- 2. **HTTP 422 whose `errors[].code` includes `already_exists`** ⇒ `existing`: `gh api --method GET "repos/\{owner\}/\{repo\}/milestones" -f state=all -f per_page=100 -f page=N`, N = 1…10, stopping at the first page under 100 items; keep the one exact `title` match. None found ⇒ `TRACEABILITY: DEGRADED (release marker unavailable)`; its `state` `closed` ⇒ `TRACEABILITY: DEGRADED (release marker closed)`. Any other failure of step 1 or 2 ⇒ `TRACEABILITY: DEGRADED (release marker unavailable)`. Each of these makes no item call.
318
- 3. **Read**, one query: write `query($owner:String!, $name:String!)\{ repository(owner:$owner, name:$name)\{ … \} \}` to `$F`, one alias per item, `iN: issue(number:N)\{ id milestone\{ number \} \}`, and run `gh api graphql -F owner='\{owner\}' -F name='\{repo\}' -F query=@"$F"`. Read every alias even when `gh` exits 1: a null or absent alias ⇒ that item DEGRADED; this milestone's number ⇒ Already set; another ⇒ Kept other release, left untouched.
319
- 4. **Assign**, one mutation over the items with no milestone: gate every node ID, the milestone's too, against `^[A-Za-z0-9_=-]\{1,100\}$`; write one `mutation` to `$F` with `mN: updateIssue(input:\{id:"<id>", milestoneId:"<node_id>"\})\{ issue\{ number \} \}` per item, and run `gh api graphql -F query=@"$F"`. Parse every alias even when `gh` exits 1: `data.mN` non-null ⇒ Added, null ⇒ that item DEGRADED.
316
+ 1. **Create first**, once: `gh api --method POST "repos/{owner}/{repo}/milestones" -f title="v{BARE_VERSION}" > "$F"; echo "exit=$?"`, then read `$F` raw — never `--jq` over an error body. `exit=0` ⇒ `created`; keep its `number` and `node_id`.
317
+ 2. **HTTP 422 whose `errors[].code` includes `already_exists`** ⇒ `existing`: `gh api --method GET "repos/{owner}/{repo}/milestones" -f state=all -f per_page=100 -f page=N`, N = 1…10, stopping at the first page under 100 items; keep the one exact `title` match. None found ⇒ `TRACEABILITY: DEGRADED (release marker unavailable)`; its `state` `closed` ⇒ `TRACEABILITY: DEGRADED (release marker closed)`. Any other failure of step 1 or 2 ⇒ `TRACEABILITY: DEGRADED (release marker unavailable)`. Each of these makes no item call.
318
+ 3. **Read**, one query: write `query($owner:String!, $name:String!){ repository(owner:$owner, name:$name){ … } }` to `$F`, one alias per item, `iN: issue(number:N){ id milestone{ number } }`, and run `gh api graphql -F owner='{owner}' -F name='{repo}' -F query=@"$F"`. Read every alias even when `gh` exits 1: a null or absent alias ⇒ that item DEGRADED; this milestone's number ⇒ Already set; another ⇒ Kept other release, left untouched.
319
+ 4. **Assign**, one mutation over the items with no milestone: gate every node ID, the milestone's too, against `^[A-Za-z0-9_=-]{1,100}$`; write one `mutation` to `$F` with `mN: updateIssue(input:{id:"<id>", milestoneId:"<node_id>"}){ issue{ number } }` per item, and run `gh api graphql -F query=@"$F"`. Parse every alias even when `gh` exits 1: `data.mN` non-null ⇒ Added, null ⇒ that item DEGRADED.
320
320
 
321
321
  **Residual race, not closed:** a milestone set on an item between steps 3 and 4 is overwritten — GitHub has no conditional update. On backpressure, follow `### Provider signals (GitHub)` in this operation's `backlink-shipped-issues` reference.
322
322
  @end
@@ -328,25 +328,25 @@ Load when the resolved tracker provider is `github` and the operation is `ensure
328
328
 
329
329
  **Mechanics held here:** the `**Process:**` body — issue creation, and posting the design artifact as a collapsed comment; and the D3 issue template below, whose section headings are GitHub's Markdown, not every tracker's.
330
330
 
331
- {common.traceable_issue_rules()}
331
+ {{common.traceable_issue_rules()}}
332
332
 
333
333
  ### Process
334
334
 
335
335
  1. If `ISSUE_INPUT` is provided (numeric = existing issue; text = search for it):
336
- - Compose structured comment to `$DEVFLOW_BODY_RAW` (NEVER rewrite the issue body); apply the Comment-sink scrub (D11) and post via `gh issue comment \{number\} --body-file "$DEVFLOW_BODY"`. Comment template:
336
+ - Compose structured comment to `$DEVFLOW_BODY_RAW` (NEVER rewrite the issue body); apply the Comment-sink scrub (D11) and post via `gh issue comment {number} --body-file "$DEVFLOW_BODY"`. Comment template:
337
337
  ```markdown
338
338
  ## Devflow Traceability Update
339
- **Initial Request**: \{TASK_DESCRIPTION or "(see issue body)"\}
339
+ **Initial Request**: {TASK_DESCRIPTION or "(see issue body)"}
340
340
  **Status**: Linked to branch for implementation
341
341
  ```
342
- - If `PLAN_ARTIFACT_PATH` provided: read the design artifact, cap the body at 60000 characters (if larger, truncate and end with `…truncated — full report in the local plan artifact \{PLAN_ARTIFACT_PATH\} (not committed; ask the author)`), compose to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post as a collapsed `<details>` comment via `gh issue comment \{number\} --body-file "$DEVFLOW_BODY"`, then reference the comment URL from the `## Implementation Plan` section in a follow-up comment.
342
+ - If `PLAN_ARTIFACT_PATH` provided: read the design artifact, cap the body at 60000 characters (if larger, truncate and end with `…truncated — full report in the local plan artifact {PLAN_ARTIFACT_PATH} (not committed; ask the author)`), compose to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post as a collapsed `<details>` comment via `gh issue comment {number} --body-file "$DEVFLOW_BODY"`, then reference the comment URL from the `## Implementation Plan` section in a follow-up comment.
343
343
  - Return the issue number.
344
344
  2. If no `ISSUE_INPUT`: create a new issue using the D3 template:
345
345
  - Title: derived from `TASK_DESCRIPTION` (same slug logic as setup-task); bind to a shell variable: `DEVFLOW_ISSUE_TITLE="..."`.
346
346
  - Compose the issue body to `$DEVFLOW_BODY_RAW` using the D3 template in the `### Traceability Issue Template (D3)` section below. `TASK_DESCRIPTION`, `INITIAL_REQUEST`, and `REQUIREMENTS` are caller-supplied and untrusted — never interpolate them into the command string. Apply the Comment-sink scrub (D11) — non-zero exit → DEGRADED, do not create issue.
347
347
  - If `LABELS` provided: bind to a shell variable `DEVFLOW_LABELS`; create with `gh issue create --title "$DEVFLOW_ISSUE_TITLE" --body-file "$DEVFLOW_BODY" --label "$DEVFLOW_LABELS"`. Label values are third-party input — never interpolate them into the command string.
348
348
  - If `LABELS` not provided: create with `gh issue create --title "$DEVFLOW_ISSUE_TITLE" --body-file "$DEVFLOW_BODY"`.
349
- - If `PLAN_ARTIFACT_PATH` provided: read the design artifact, cap the body at 60000 characters (if larger, truncate and end with `…truncated — full report in the local plan artifact \{PLAN_ARTIFACT_PATH\} (not committed; ask the author)`), compose to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post as a collapsed `<details>` comment via `gh issue comment \{number\} --body-file "$DEVFLOW_BODY"`; then reference the comment URL in a follow-up comment to the issue.
349
+ - If `PLAN_ARTIFACT_PATH` provided: read the design artifact, cap the body at 60000 characters (if larger, truncate and end with `…truncated — full report in the local plan artifact {PLAN_ARTIFACT_PATH} (not committed; ask the author)`), compose to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post as a collapsed `<details>` comment via `gh issue comment {number} --body-file "$DEVFLOW_BODY"`; then reference the comment URL in a follow-up comment to the issue.
350
350
  3. Return the issue number.
351
351
 
352
352
  ### Create Issue with Labels and Assignees
@@ -364,7 +364,7 @@ Login fails when using SSO authentication.
364
364
  ## Expected Behavior
365
365
  User should be logged in successfully.
366
366
  EOF
367
- } && node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/redact-secrets.cjs" \
367
+ } && node "$HOME/.devflow/scripts/redact-secrets.cjs" \
368
368
  "$DEVFLOW_BODY_RAW" "$DEVFLOW_BODY" \
369
369
  && gh issue create \
370
370
  --title "Bug: Login fails for SSO users" \
@@ -400,23 +400,23 @@ Load when the resolved tracker provider is `github` and the operation is `post-w
400
400
 
401
401
  **Mechanics held here:** the `**Process:**` body — locating the wave's tracking item and posting or updating the report.
402
402
 
403
- {common.wave_report_inputs()}
403
+ {{common.wave_report_inputs()}}
404
404
 
405
405
  ### Process
406
406
 
407
407
  1. Check for existing marker (author-filtered — a third party posting the marker must not suppress the post):
408
408
  - Fetch viewer login: `gh api user --jq '.login'` → store as VIEWER_LOGIN
409
- - `gh issue view \{TRACKING_ISSUE\} --json comments --jq '[.comments[] | select(.author.login == "'"$VIEWER_LOGIN"'")] | .[].body'`
410
- - Search for `<!-- devflow:wave-report wave:\{WAVE_ID\} -->` in viewer-authored comment bodies only
411
- - If found: skip — report `Skipped: wave report for \{WAVE_ID\} already posted`
409
+ - `gh issue view {TRACKING_ISSUE} --json comments --jq '[.comments[] | select(.author.login == "'"$VIEWER_LOGIN"'")] | .[].body'`
410
+ - Search for `<!-- devflow:wave-report wave:{WAVE_ID} -->` in viewer-authored comment bodies only
411
+ - If found: skip — report `Skipped: wave report for {WAVE_ID} already posted`
412
412
  3. Compose the comment body:
413
413
  ```markdown
414
- <!-- devflow:wave-report wave:\{WAVE_ID\} -->
415
- \{contents of WAVE_REPORT_PATH\}
414
+ <!-- devflow:wave-report wave:{WAVE_ID} -->
415
+ {contents of WAVE_REPORT_PATH}
416
416
  ```
417
417
  Cap the composed body at 60000 characters; if larger, truncate and end with
418
- `…truncated — full report in the local wave artifact \{WAVE_REPORT_PATH\} (not committed; ask the author)`.
419
- 4. Write composed body to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post via `gh issue comment \{TRACKING_ISSUE\} --body-file "$DEVFLOW_BODY"`.
418
+ `…truncated — full report in the local wave artifact {WAVE_REPORT_PATH} (not committed; ask the author)`.
419
+ 4. Write composed body to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) and post via `gh issue comment {TRACKING_ISSUE} --body-file "$DEVFLOW_BODY"`.
420
420
  @end
421
421
 
422
422
  @define ensure_pr_ready():
@@ -424,49 +424,49 @@ Load when the resolved tracker provider is `github` and the operation is `post-w
424
424
 
425
425
  Load when the resolved tracker provider is `github` and the operation is `ensure-pr-ready`.
426
426
 
427
- **Mechanics held here:** step 4b's TRACKER half only — the issue-number resolution and its `Closes #\{n\}` line; every other step is in `references/pr/ensure-pr-ready.md`.
427
+ **Mechanics held here:** step 4b's TRACKER half only — the issue-number resolution and its `Closes #{n}` line; every other step is in `references/pr/ensure-pr-ready.md`.
428
428
 
429
429
  ### Process
430
430
 
431
- 4b. (ALWAYS-ON) Ensure PR body contains a `## Related Issues` section with `Closes #\{n\}` link when a verified issue number is known. Resolution order:
431
+ 4b. (ALWAYS-ON) Ensure PR body contains a `## Related Issues` section with `Closes #{n}` link when a verified issue number is known. Resolution order:
432
432
  a. Prefer the issue number returned by `setup-task` / `ensure-traceable-issue` for this branch.
433
- b. If unavailable, fall back to the branch name pattern `\{type\}/\{number\}-\{slug\}`: extract the numeric segment and verify with `gh issue view \{n\} --json number,state`. If the call fails or `.state` is not `"open"`, skip silently — never add a `Closes` link for an unverified number. Branches like `chore/2026-cleanup` or `fix/2fa-login` may produce false matches; the existence check is the guard.
433
+ b. If unavailable, fall back to the branch name pattern `{type}/{number}-{slug}`: extract the numeric segment and verify with `gh issue view {n} --json number,state`. If the call fails or `.state` is not `"open"`, skip silently — never add a `Closes` link for an unverified number. Branches like `chore/2026-cleanup` or `fix/2fa-login` may produce false matches; the existence check is the guard.
434
434
 
435
435
  Publish the section through step 4b's PR-host half.
436
436
 
437
437
  If no verified issue number is discoverable, skip silently.
438
- On any 4xx/5xx from `gh pr edit` when updating the body: emit `TRACEABILITY: DEGRADED (\{reason\})` and continue — a failed Related Issues update never blocks the PR.
438
+ On any 4xx/5xx from `gh pr edit` when updating the body: emit `TRACEABILITY: DEGRADED ({reason})` and continue — a failed Related Issues update never blocks the PR.
439
439
  @end
440
440
 
441
441
  <!-- op: setup-task -->
442
- {setup_task()}
442
+ {{setup_task()}}
443
443
 
444
444
  <!-- op: fetch-issue -->
445
- {fetch_issue()}
445
+ {{fetch_issue()}}
446
446
 
447
447
  <!-- op: fetch-issues-batch -->
448
- {fetch_issues_batch()}
448
+ {{fetch_issues_batch()}}
449
449
 
450
450
  <!-- op: manage-debt -->
451
- {manage_debt()}
451
+ {{manage_debt()}}
452
452
 
453
453
  <!-- op: create-release -->
454
- {create_release()}
454
+ {{create_release()}}
455
455
 
456
456
  <!-- op: gather-release-evidence -->
457
- {gather_release_evidence()}
457
+ {{gather_release_evidence()}}
458
458
 
459
459
  <!-- op: backlink-shipped-issues -->
460
- {backlink_shipped_issues()}
460
+ {{backlink_shipped_issues()}}
461
461
 
462
462
  <!-- op: associate-release -->
463
- {associate_release()}
463
+ {{associate_release()}}
464
464
 
465
465
  <!-- op: ensure-traceable-issue -->
466
- {ensure_traceable_issue()}
466
+ {{ensure_traceable_issue()}}
467
467
 
468
468
  <!-- op: post-wave-report -->
469
- {post_wave_report()}
469
+ {{post_wave_report()}}
470
470
 
471
471
  <!-- op: ensure-pr-ready -->
472
- {ensure_pr_ready()}
472
+ {{ensure_pr_ready()}}