From 8b189073a3a58da389c2ee795d526f3bc537a546 Mon Sep 17 00:00:00 2001 From: bougyman's bot Date: Sun, 27 Sep 2026 09:29:18 -0400 Subject: [PATCH 1/4] feat(stokowski): make glean own the follow-up contract EXT-68's approved follow-ups were never created, and the issue was marked Done with its PR unmerged. - glean.md: glean writes every proposed follow-up to the report's follow_ups list (G1..Gn, title, the complete issue body, priority, labels). Stokowski renders it for review and saves it for improvement. Its next step names the one approval format: "Approve follow-ups: G1". - improvement.md: a mechanical stage. It reads only that approval format, copies the approved items from .stokowski/follow-ups.json into Linear with `lc issue create --yes`, and skips ids it already created. With no approval it reports "No approved follow ups found". It then checks the PR and reports "blocked" unless mergeStateStatus is CLEAN. - merge.md: report "blocked" whenever the PR was not merged, instead of posting to Linear. - feature and bug-fix workflows: improvement and merge declare `blocked: merge-review`, a new gate whose approve runs merge and whose rework reruns improvement. Needs bougyman/stokowski#14 for blocked transitions, report follow-ups, and gate comments in the improvement prompt. Co-Authored-By: Claude Opus 5.5 --- .ai/prompts/glean.md | 47 +++++++++++------ .ai/prompts/improvement.md | 100 +++++++++++++++++++++++++++++-------- .ai/prompts/merge.md | 17 +++++-- .ai/workflows/bug-fix.yaml | 12 +++++ .ai/workflows/feature.yaml | 14 +++++- 5 files changed, 147 insertions(+), 43 deletions(-) diff --git a/.ai/prompts/glean.md b/.ai/prompts/glean.md index 54f5553..fa1a042 100644 --- a/.ai/prompts/glean.md +++ b/.ai/prompts/glean.md @@ -1,9 +1,9 @@ # Glean Stage -You are reviewing the completed workflow run for **{{ issue.identifier }}**: -{{ issue.title }}. +You are reviewing the completed workflow run for **{{ issue_identifier }}**: +{{ issue_title }}. -**URL:** {{ issue.url }} +**URL:** {{ issue_url }} ## Objective @@ -72,26 +72,43 @@ future enhancement. Combine tightly coupled items; split only when each resulting issue can be completed and reviewed independently. 5. Write `.stokowski/report.json` with: + - `follow_ups` — the contract for the next stage. One object for each + proposed follow-up, in priority order, numbered `G1`, `G2`, … with no + gaps: + - `id` — `G1`, `G2`, and so on. + - `title` — the exact Linear issue title. + - `description` — the complete Linear issue body, in Markdown, exactly as + it must be filed. Include the source issue ({{ issue_identifier }}) and + any PR, the problem, the desired outcome, acceptance criteria, the scope + boundary, and the evidence. For a learning follow-up, include the + `documents/agent_learnings/` acceptance criteria described above. + - `priority` — one of `urgent`, `high`, `medium`, `low` or `none`. + - `labels` — optional; only label names that already exist on the EXT + team. + + The improvement stage creates each approved item by copying these fields + verbatim. It does not read the rest of this report and cannot fill a + gap, so every item must be complete as written. Use `"follow_ups": []` + when nothing should be filed. + - `claims` — one entry for each follow-up. Start `claim` with its id, for + example `G1 — the claim`. Put the evidence and why it was deferred in + `evidence`, and the exact report, PR, comment, file/line, or Linear search + in `source`. - `summary` — a brief account of what the workflow established. - - `claims` — one entry for each proposed follow-up. Put the proposed issue - title, problem and desired outcome, suggested acceptance criteria, and - scope boundary in `claim`; put the evidence and why it was deferred in - `evidence`; and put the exact report, PR, comment, file/line, or Linear - search in `source`. This is the rendered, reviewable follow-up list. - `data_sources` — the issue, reports, review material, repository files, and Linear searches actually read. - `risks`, `open_questions`, and `assumptions`. - `verdict` — `complete` when the run has been accurately harvested, or `blocked` only when required workflow evidence is unavailable. - - `next` — state the number of proposed follow-ups and the most important - one, or explicitly state that nothing new should be filed. + - `next` — the number of proposed follow-ups and the most important one, + or an explicit statement that nothing new should be filed. - `key_points` — three to five evidence-backed takeaways. - - `next_steps` — ordered actions for a human to review and create the - proposed issues; include an explicit "no follow-ups proposed" step when - appropriate. + - `next_steps` — when there are follow-ups, the first step is exactly: + "Approve with a comment such as `Approve follow-ups: G1, G2` listing the + ids to create." When there are none, state "No follow-ups proposed." -6. Do not create the proposed Linear issues in this draft stage. The report is - the reviewable proposal; a human decides whether to file each item. +6. Do not create the proposed Linear issues in this stage. The report is the + reviewable proposal; a human approves items by id at the next gate. ## Rules diff --git a/.ai/prompts/improvement.md b/.ai/prompts/improvement.md index 3c21745..b7855b6 100644 --- a/.ai/prompts/improvement.md +++ b/.ai/prompts/improvement.md @@ -1,24 +1,80 @@ # Improvement Stage -Create only the Glean candidates explicitly approved by a human for -**{{ issue.identifier }}**: {{ issue.title }}. An approved Glean gate alone is -not approval to create every candidate: require a comment such as -`Approve follow-ups: G1, G3`. - -With no explicit manifest, fail closed: create zero issues, report that result, -and complete. For each approved item, re-check for an equivalent Linear issue, -then use only `mise exec -- mix lc issue create` with non-interactive options -and a body file to create it in EXT / Linear CLI. Include the source issue, -candidate ID, evidence, scope, and acceptance criteria; link it to the source -when supported. Do not modify the source issue, merge a PR, or change the repo. - -For an approved learning candidate, copy these required acceptance criteria -into the created issue: its implementation PR creates -`documents/agent_learnings/_learned.adoc` and regenerates -`documents/agent_learnings.adoc` as specified by -`documents/agent_learnings/README.adoc`. Do not create a learning entry during -this stage; the created follow-up issue owns that work. - -Write `.stokowski/report.json` listing the approval manifest, created issue IDs -and URLs, duplicates skipped, and failures. Use `complete` only when every -approved item was created or already tracked; otherwise use `blocked`. +This is a mechanical stage for **{{ issue_identifier }}**: {{ issue_title }}. +Do exactly the steps below. Do not interpret, investigate, or improve anything. +The glean stage did all of the thinking; this stage only copies its approved +output into Linear and checks that the PR can merge. + +Do not change code, tests, documentation, branches, commits, or PRs. Do not +run the project's setup or quality commands. Do not change the source issue. + +## 1. Find the approved ids + +Look only at the comments under **Recent Activity** in the lifecycle section +below. An approval is a comment whose text starts with +`Approve follow-ups:` followed by comma-separated ids of the form `G1`, `G2`, +and so on. If there is more than one such comment, use the latest one. + +Accept no other format. If there is no such comment, or it lists no `G` ids, +the approved list is empty. Do not infer approval from any other comment, +however it is worded. + +## 2. Create the approved issues + +Read `.stokowski/follow-ups.json`. Its `follow_ups` list holds one object per +proposed follow-up, with `id`, `title`, `description`, and optionally +`priority` and `labels`. + +Read `.stokowski/follow-ups-created.json` if it exists. It maps ids to the +issues an earlier run of this stage created. Skip those ids. + +For each remaining approved id, in order: + +1. Find the object with that `id`. If there is none, record the id as a + failure and continue. +2. Write its `description`, unchanged, to a temporary file outside the + repository. +3. Run, adding `--priority ` and `--labels ` only when the + object has them: + + ``` + mise exec -- mix lc issue create --yes --no-take --team EXT \ + --project "Linear CLI" --title "" --body-file <file> + ``` + +4. On success, add `"<id>": "<new issue identifier>"` to + `.stokowski/follow-ups-created.json`. On failure, record the id and the + command's error, and continue. + +Copy `title`, `description`, `priority` and `labels` exactly. Do not edit, +merge, split, or re-check them for duplicates. + +## 3. Check that the PR can merge + +Skip this step when the **Transitions** list in the lifecycle section does not +include `blocked`. That workflow has no PR to merge. + +Otherwise run: + +``` +gh pr list --head "$(git branch --show-current)" --state open \ + --json number,url,mergeable,mergeStateStatus,reviewDecision +``` + +The PR can merge only when exactly one open PR is listed and its +`mergeStateStatus` is `CLEAN`. Do not try to fix any other result. + +## 4. Report + +Write `.stokowski/report.json`: + +- `headline` — "Created N approved follow-up(s): <identifiers>", or exactly + "No approved follow ups found" when the approved list is empty. +- `verdict` — `complete` when every approved id was created and the PR can + merge (or step 3 was skipped). Otherwise `blocked`. +- `next` — when `blocked`, say why: the PR's `mergeStateStatus` and + `reviewDecision`, and any ids that failed. The issue then waits at the + merge-review gate. +- `claims` — one entry for each approved id, with the created identifier or + the error, and one entry for the PR check with the `gh` output. +- `classification` — `chore`. diff --git a/.ai/prompts/merge.md b/.ai/prompts/merge.md index 4e8bcd4..ecde4c0 100644 --- a/.ai/prompts/merge.md +++ b/.ai/prompts/merge.md @@ -1,9 +1,9 @@ # Claims Stage You are following up on any unresolved issues from -the approved PR for **{{ issue.identifier }}**: {{ issue.title }} +the approved PR for **{{ issue_identifier }}**: {{ issue_title }} -**URL:** {{ issue.url }} +**URL:** {{ issue_url }} ## Objective @@ -20,8 +20,8 @@ the approved PR for **{{ issue.identifier }}**: {{ issue.title }} gh pr view <number> --json reviewDecision,statusCheckRollup ``` 3. If CI is failing, investigate briefly. If it is a flaky test or transient - failure, re-run the checks. If it is a real failure, post a comment on the - Linear issue and stop. + failure, re-run the checks. If it is a real failure, stop and report + `blocked`. 4. Merge the approved PR after confirming the required approvals and CI: ``` gh pr merge -sd <number> @@ -31,6 +31,12 @@ the approved PR for **{{ issue.identifier }}**: {{ issue.title }} The workflow runner owns the transition to `Done`. Do not move the Linear issue to a terminal state yourself. +If you did not merge the PR, for any reason — no approval, failing CI, a +conflict you could not resolve — set `"verdict": "blocked"` in +`.stokowski/report.json` and give the reason in `next`. The issue then waits at +the merge-review gate instead of being marked done. Use `complete` only after +the PR is merged. + ## Rework run If this is a rework run (merge was attempted before but failed): @@ -43,7 +49,8 @@ If this is a rework run (merge was attempted before but failed): 3. If CI failed: - Read the failure logs. - If it is a test failure caused by the PR's changes, post details to - Linear and stop (this needs to go back to implementation). + `.stokowski/report.json` and stop with `blocked` (this needs to go back + to implementation). - If it is a flaky or infrastructure issue, re-run and retry the merge. 4. Update the workpad with what happened. diff --git a/.ai/workflows/bug-fix.yaml b/.ai/workflows/bug-fix.yaml index f3c0d35..b812c69 100644 --- a/.ai/workflows/bug-fix.yaml +++ b/.ai/workflows/bug-fix.yaml @@ -112,6 +112,7 @@ states: session: fresh transitions: complete: merge + blocked: merge-review merge: type: agent @@ -124,6 +125,17 @@ states: session: fresh transitions: complete: done + blocked: merge-review + + # Parks the issue when improvement or merge reports the PR cannot merge yet. + # Approve once the PR is mergeable to run merge; rework reruns improvement. + merge-review: + type: gate + linear_state: review + rework_to: improvement + max_rework: 5 + transitions: + approve: merge done: type: terminal diff --git a/.ai/workflows/feature.yaml b/.ai/workflows/feature.yaml index 01bcf48..e229f87 100644 --- a/.ai/workflows/feature.yaml +++ b/.ai/workflows/feature.yaml @@ -97,7 +97,7 @@ states: transitions: approve: improvement - # Mechanical: acts only on explicitly approved Glean candidate IDs. + # Mechanical: creates the approved Glean follow-ups, then checks the PR. improvement: type: agent prompt: .ai/prompts/improvement.md @@ -109,6 +109,7 @@ states: session: fresh transitions: complete: merge + blocked: merge-review # Mechanical: independently re-check approvals and CI, then merges. merge: @@ -122,6 +123,17 @@ states: session: fresh transitions: complete: done + blocked: merge-review + + # Parks the issue when improvement or merge reports the PR cannot merge yet. + # Approve once the PR is mergeable to run merge; rework reruns improvement. + merge-review: + type: gate + linear_state: review + rework_to: improvement + max_rework: 5 + transitions: + approve: merge done: type: terminal From 86c15261a5c36a05b33df05d11d38ecff64ca598 Mon Sep 17 00:00:00 2001 From: bougyman's bot <ruby-automation@users.noreply.github.com> Date: Sun, 27 Sep 2026 09:35:58 -0400 Subject: [PATCH 2/4] feat(stokowski): loosen the follow-up approval rule The approval comment only carries ids. Any comment containing "Approve" approves every G<number> after that word, e.g. "Approve G1, G3"; the latest such comment wins. All issue data still comes from the glean report's follow_ups. When a proposed follow-up is not created, improvement now says so plainly ("Not created: G2 - <title>") and ends with a note on filing it by hand with `lc i create`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .ai/prompts/glean.md | 7 +++++-- .ai/prompts/improvement.md | 24 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/.ai/prompts/glean.md b/.ai/prompts/glean.md index fa1a042..0b486ee 100644 --- a/.ai/prompts/glean.md +++ b/.ai/prompts/glean.md @@ -104,11 +104,14 @@ future enhancement. or an explicit statement that nothing new should be filed. - `key_points` — three to five evidence-backed takeaways. - `next_steps` — when there are follow-ups, the first step is exactly: - "Approve with a comment such as `Approve follow-ups: G1, G2` listing the - ids to create." When there are none, state "No follow-ups proposed." + "Approve with a comment containing `Approve` and the ids to create, for + example `Approve G1, G2`." When there are none, state "No follow-ups + proposed." 6. Do not create the proposed Linear issues in this stage. The report is the reviewable proposal; a human approves items by id at the next gate. + The approval comment holds only the ids; everything else comes from + `follow_ups`. ## Rules diff --git a/.ai/prompts/improvement.md b/.ai/prompts/improvement.md index b7855b6..19e77cb 100644 --- a/.ai/prompts/improvement.md +++ b/.ai/prompts/improvement.md @@ -11,13 +11,14 @@ run the project's setup or quality commands. Do not change the source issue. ## 1. Find the approved ids Look only at the comments under **Recent Activity** in the lifecycle section -below. An approval is a comment whose text starts with -`Approve follow-ups:` followed by comma-separated ids of the form `G1`, `G2`, -and so on. If there is more than one such comment, use the latest one. +below. An approval is a comment that contains the word `Approve` (any case). +Its approved ids are every `G<number>` that appears after that word, such as +`Approve G1, G3` or `Approve follow-ups: G2 G4`. If more than one comment is an +approval, use the latest one. -Accept no other format. If there is no such comment, or it lists no `G` ids, -the approved list is empty. Do not infer approval from any other comment, -however it is worded. +That is the only rule. If no comment is an approval, or the approval names no +`G<number>`, the approved list is empty. Do not infer approval from any other +comment, however it is worded. ## 2. Create the approved issues @@ -77,4 +78,15 @@ Write `.stokowski/report.json`: merge-review gate. - `claims` — one entry for each approved id, with the created identifier or the error, and one entry for the PR check with the `gh` output. +- `summary` — when any proposed follow-up in `.stokowski/follow-ups.json` was + not created (not approved, or failed), say so plainly: list each one as + "**Not created:** `<id>` — <title>". Then end with this paragraph, verbatim: + + > Want any of these after all? `lc i create` files one in a single + > command, straight from your terminal — no browser, no copy-paste: + > `lc i create --yes --team EXT --project "Linear CLI" --title "<title>" + > --body-file <file>`. [linear-cli](https://github.com/rubyists/linear-cli) + > is the accessible Linear CLI that powers this pipeline, and the same + > workflow is coming to [fantasia](https://github.com/rubyists/fantasia). + - `classification` — `chore`. From eb2d264c341214af431b29a6438deb272d122fb9 Mon Sep 17 00:00:00 2001 From: bougyman's bot <ruby-automation@users.noreply.github.com> Date: Sun, 27 Sep 2026 09:45:58 -0400 Subject: [PATCH 3/4] fix(stokowski): keep the follow-up approval across improvement reruns When merge-review sends the issue back to improvement, the rerun's prompt shows only comments since that gate, so the approval written at the glean gate is gone. Improvement now records the approved ids in .stokowski/follow-ups-approved.json and reuses them when no newer approval is visible, so a follow-up that failed to create is retried instead of dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .ai/prompts/improvement.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.ai/prompts/improvement.md b/.ai/prompts/improvement.md index 19e77cb..af1847b 100644 --- a/.ai/prompts/improvement.md +++ b/.ai/prompts/improvement.md @@ -16,9 +16,13 @@ Its approved ids are every `G<number>` that appears after that word, such as `Approve G1, G3` or `Approve follow-ups: G2 G4`. If more than one comment is an approval, use the latest one. -That is the only rule. If no comment is an approval, or the approval names no -`G<number>`, the approved list is empty. Do not infer approval from any other -comment, however it is worded. +That is the only rule. Do not infer approval from any other comment, however +it is worded. + +When you find an approval, write its ids to `.stokowski/follow-ups-approved.json` +as a JSON list, for example `["G1", "G3"]`. When you find none, use the ids in +that file if it exists: this run is a rerun, and the approval was written +before an earlier gate. With neither, the approved list is empty. ## 2. Create the approved issues From 9a961f04f0b1a017c5aa5851ee24c8caaaf4412d Mon Sep 17 00:00:00 2001 From: bougyman's bot <ruby-automation@users.noreply.github.com> Date: Sun, 27 Sep 2026 09:52:34 -0400 Subject: [PATCH 4/4] chore: updates stokowski version pin --- vendor/stokowski | 2 +- workflow.glean.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/stokowski b/vendor/stokowski index 1f843c0..d8c8d86 160000 --- a/vendor/stokowski +++ b/vendor/stokowski @@ -1 +1 @@ -Subproject commit 1f843c0915bba42b4ca7372c3315c748d1297bd8 +Subproject commit d8c8d86e15b896c06f638090bc9b2995c61d3e1f diff --git a/workflow.glean.yaml b/workflow.glean.yaml index e0e7272..13d3343 100644 --- a/workflow.glean.yaml +++ b/workflow.glean.yaml @@ -14,7 +14,7 @@ linear_states: terminal: [Done, Closed, Cancelled, Canceled, Duplicate] polling: - interval_ms: 15000 + interval_ms: 30000 workspace: root: ~/.local/share/stokowski/workspaces/linear-cli