@plainconceptsplatform/workflows 0.5.1 → 0.6.1
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.
- package/dist/action-validation.test.d.ts +1 -0
- package/dist/action-validation.test.js +87 -0
- package/dist/catalog-installation.d.ts +30 -0
- package/dist/catalog-installation.js +422 -0
- package/dist/catalog-installation.test.d.ts +1 -0
- package/dist/catalog-installation.test.js +485 -0
- package/dist/catalog-listing.d.ts +13 -0
- package/dist/catalog-listing.js +70 -0
- package/dist/catalog-listing.test.d.ts +1 -0
- package/dist/catalog-listing.test.js +150 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +218 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +273 -0
- package/dist/repository-inspection.d.ts +23 -0
- package/dist/repository-inspection.js +113 -0
- package/dist/repository-inspection.test.d.ts +1 -0
- package/dist/repository-inspection.test.js +77 -0
- package/dist/route-processing.d.ts +6 -0
- package/dist/route-processing.js +149 -0
- package/dist/route-processing.test.d.ts +1 -0
- package/dist/route-processing.test.js +283 -0
- package/dist/stack-defaults.d.ts +11 -0
- package/dist/stack-defaults.js +104 -0
- package/dist/stack-defaults.test.d.ts +1 -0
- package/dist/stack-defaults.test.js +266 -0
- package/dist/tui.d.ts +25 -0
- package/dist/tui.js +287 -0
- package/dist/tui.test.d.ts +1 -0
- package/dist/tui.test.js +249 -0
- package/dist/workflow-catalog.d.ts +25 -0
- package/dist/workflow-catalog.js +55 -0
- package/dist/workflow-catalog.test.d.ts +1 -0
- package/dist/workflow-catalog.test.js +29 -0
- package/loops/actions/add-issue-labels/action.yml +2 -2
- package/loops/actions/apply-agent-bundle/apply-bundle.sh +14 -1
- package/loops/actions/classify-route/action.yml +7 -0
- package/loops/actions/classify-route/classify-route.sh +20 -5
- package/loops/actions/cleanup-artifacts/action.yml +38 -12
- package/loops/actions/identify-gate-subject/action.yml +3 -1
- package/loops/actions/remove-issue-labels/action.yml +4 -2
- package/loops/actions/validate-refine-output/validate-refine-output.sh +18 -2
- package/loops/actions/verify-refine-output/verify-refine-output.sh +20 -0
- package/loops/actions/verify-route-matrix/verify-route-matrix.sh +300 -16
- package/loops/scripts/compile-agent-workflows.mjs +96 -1
- package/loops/scripts/merge-changelog.mjs +76 -0
- package/loops/templates/agentics/actionlint.yaml +13 -0
- package/loops/templates/agentics/agentics-checks.yml +203 -86
- package/loops/templates/ci/app-ci-dotnet-next.yml +64 -2
- package/loops/templates/ci/app-ci-node-monorepo.yml +52 -0
- package/loops/templates/opencode/opencode.ci.json +2 -2
- package/loops/templates/opencode/opencode.ci.json.md +4 -1
- package/loops/workflows/agent-apply-review.md +5 -1
- package/loops/workflows/agent-implement.md +105 -3
- package/loops/workflows/agent-merge-gate.md +139 -25
- package/loops/workflows/agent-refine.md +26 -2
- package/loops/workflows/work-router.yml +227 -51
- package/package.json +1 -1
|
@@ -8,6 +8,9 @@ env:
|
|
|
8
8
|
REVIEW_LABEL: review
|
|
9
9
|
PR_PENDING_LABEL: pr-pending
|
|
10
10
|
GATE_MARKER: "<!-- agent-merge-gate -->"
|
|
11
|
+
ATTEMPT_MARKER: "<!-- agent-merge-gate-attempt -->"
|
|
12
|
+
MAX_ATTEMPTS: "6"
|
|
13
|
+
PARK_AT_ATTEMPT: "5"
|
|
11
14
|
INCOMPLETE_COMMENT: "Automated CI failure remediation ended without an outcome. The issue remains for a retry."
|
|
12
15
|
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
|
|
13
16
|
GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
|
|
@@ -51,6 +54,18 @@ on:
|
|
|
51
54
|
description: CI workflow run ID for fetching failing logs.
|
|
52
55
|
required: false
|
|
53
56
|
type: string
|
|
57
|
+
attempts_so_far:
|
|
58
|
+
description: Failed gate attempts already made against this CI verdict. Parked when it reaches the cap.
|
|
59
|
+
required: false
|
|
60
|
+
type: string
|
|
61
|
+
default: '0'
|
|
62
|
+
# gh-aw folds the top-level `if:` below into the generated activation job but does not carry
|
|
63
|
+
# the jobs that `if:` reads into activation's `needs`: only prompt-referenced custom jobs with
|
|
64
|
+
# no `needs:` of their own are hoisted (subject). protected_changes needs subject, so without
|
|
65
|
+
# this entry activation read needs.protected_changes.outputs.requires_review before
|
|
66
|
+
# protected_changes had started; the value was '' and the clause was always true
|
|
67
|
+
# (Pliny-Bot run 34042143350: activation finished 18 s before protected_changes began).
|
|
68
|
+
needs: [protected_changes]
|
|
54
69
|
|
|
55
70
|
# Rung 4. Router has classified the event; identify-gate-subject validates PR ownership,
|
|
56
71
|
# resolves the closing issue, and confirms the CI verdict.
|
|
@@ -160,13 +175,17 @@ jobs:
|
|
|
160
175
|
with:
|
|
161
176
|
client-id: ${{ secrets.BOT_APP_ID }}
|
|
162
177
|
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
178
|
+
# Only the reservation comes off. pr-pending says a pull request for this issue is open
|
|
179
|
+
# and waiting, which is still true when the gate hands it to a human, so taking it off
|
|
180
|
+
# here left a board where three issues with three open pull requests looked like they
|
|
181
|
+
# had none. The merge path is the one place the label stops being true.
|
|
163
182
|
- name: Release the issue
|
|
164
183
|
if: needs.protected_changes.outputs.requires_review == 'true' && needs.subject.outputs.conclusion != 'failure'
|
|
165
184
|
uses: ./.github/actions/remove-issue-labels
|
|
166
185
|
with:
|
|
167
186
|
token: ${{ steps.app-token.outputs.token }}
|
|
168
187
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
169
|
-
labels: ${{ env.WORKING_LABEL }}
|
|
188
|
+
labels: ${{ env.WORKING_LABEL }}
|
|
170
189
|
- name: Flag human review
|
|
171
190
|
if: needs.protected_changes.outputs.requires_review == 'true' && needs.subject.outputs.conclusion != 'failure'
|
|
172
191
|
uses: ./.github/actions/add-issue-labels
|
|
@@ -188,6 +207,8 @@ jobs:
|
|
|
188
207
|
Protected files:
|
|
189
208
|
${{ needs.protected_changes.outputs.files }}
|
|
190
209
|
|
|
210
|
+
**Verdict:** review
|
|
211
|
+
|
|
191
212
|
reserve:
|
|
192
213
|
needs: subject
|
|
193
214
|
if: needs.subject.outputs.found == 'true'
|
|
@@ -223,14 +244,15 @@ jobs:
|
|
|
223
244
|
else
|
|
224
245
|
echo "has_conflicts=false" >> "$GITHUB_OUTPUT"
|
|
225
246
|
fi
|
|
247
|
+
# First attempt only. Retries are recorded by the incomplete job's attempt comment, and
|
|
248
|
+
# every App comment is a router event: one issue collected sixteen of these in a day.
|
|
226
249
|
- name: Comment on issue - problems found, solving them
|
|
227
|
-
if: needs.subject.outputs.conclusion == 'failure'
|
|
250
|
+
if: needs.subject.outputs.conclusion == 'failure' && (inputs.attempts_so_far || '0') == '0'
|
|
228
251
|
uses: ./.github/actions/create-issue-comment
|
|
229
252
|
with:
|
|
230
253
|
token: ${{ steps.app-token.outputs.token }}
|
|
231
254
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
232
255
|
body: |
|
|
233
|
-
${{ env.GATE_MARKER }}
|
|
234
256
|
Problems found in PR #${{ needs.subject.outputs.pr }}. ${{ steps.conflicts.outputs.has_conflicts == 'true' && 'Merge conflicts detected.' || 'CI failed.' }}
|
|
235
257
|
Bot is working on fixing it.
|
|
236
258
|
validate_output:
|
|
@@ -300,6 +322,20 @@ jobs:
|
|
|
300
322
|
token: ${{ steps.app-token.outputs.token }}
|
|
301
323
|
push-to-branch: 'true'
|
|
302
324
|
apply-labels: 'false'
|
|
325
|
+
# GITHUB_TOKEN on purpose: an App-token comment on a pull request is an issue_comment
|
|
326
|
+
# event, and GITHUB_TOKEN raises none. The full assessment lives on the issue, where the
|
|
327
|
+
# lifecycle is; this is what a reviewer opening the pull request sees. Carrying the
|
|
328
|
+
# marker and the Verdict line makes the router's verdict detection independent of
|
|
329
|
+
# whether the model remembered the marker.
|
|
330
|
+
- name: Show the verdict on the pull request
|
|
331
|
+
uses: ./.github/actions/create-issue-comment
|
|
332
|
+
with:
|
|
333
|
+
token: ${{ github.token }}
|
|
334
|
+
issue-number: ${{ needs.subject.outputs.pr }}
|
|
335
|
+
body: |
|
|
336
|
+
${{ env.GATE_MARKER }}
|
|
337
|
+
**Verdict:** ${{ needs.validate_output.outputs.outcome }} (CI concluded ${{ needs.subject.outputs.conclusion }}).
|
|
338
|
+
Full assessment on the linked issue: #${{ needs.subject.outputs.issue }}. [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
303
339
|
- name: Merge approved pull request
|
|
304
340
|
if: needs.validate_output.outputs.outcome == 'merge'
|
|
305
341
|
env:
|
|
@@ -324,20 +360,26 @@ jobs:
|
|
|
324
360
|
token: ${{ steps.app-token.outputs.token }}
|
|
325
361
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
326
362
|
labels: ${{ env.REVIEW_LABEL }}
|
|
363
|
+
# The reservation only. The pull request is still open and still waiting, so pr-pending
|
|
364
|
+
# stays until the merge path below retires it.
|
|
327
365
|
- name: Release review outcome
|
|
328
366
|
if: needs.validate_output.outputs.outcome == 'review'
|
|
329
367
|
uses: ./.github/actions/remove-issue-labels
|
|
330
368
|
with:
|
|
331
369
|
token: ${{ steps.app-token.outputs.token }}
|
|
332
370
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
333
|
-
labels: ${{ env.WORKING_LABEL }}
|
|
371
|
+
labels: ${{ env.WORKING_LABEL }}
|
|
334
372
|
- name: Clear merged issue labels
|
|
335
373
|
if: needs.validate_output.outputs.outcome == 'merge'
|
|
336
374
|
uses: ./.github/actions/remove-issue-labels
|
|
337
375
|
with:
|
|
338
376
|
token: ${{ steps.app-token.outputs.token }}
|
|
339
377
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
340
|
-
labels:
|
|
378
|
+
labels: |
|
|
379
|
+
${{ env.IMPLEMENT_LABEL }}
|
|
380
|
+
${{ env.WORKING_LABEL }}
|
|
381
|
+
${{ env.REVIEW_LABEL }}
|
|
382
|
+
${{ env.PR_PENDING_LABEL }}
|
|
341
383
|
incomplete:
|
|
342
384
|
needs: [subject, protected_changes, agent, safe_outputs, validate_output]
|
|
343
385
|
if: >
|
|
@@ -364,28 +406,52 @@ jobs:
|
|
|
364
406
|
with:
|
|
365
407
|
client-id: ${{ secrets.BOT_APP_ID }}
|
|
366
408
|
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
367
|
-
|
|
368
|
-
|
|
409
|
+
# The attempt record comes first. The belt bounds its retries by counting attempt comments
|
|
410
|
+
# newer than the CI verdict, not by labels; releasing the labels before the record existed
|
|
411
|
+
# meant a failure in either step below un-reserved the issue with nothing to count, and the
|
|
412
|
+
# belt re-dispatched the same crash every cycle. The steps stay sequential on purpose: an
|
|
413
|
+
# always() release after a failed park would strip bot-working from an issue that was
|
|
414
|
+
# meant to be parked with review.
|
|
415
|
+
# attempts_so_far is a workflow_call input and arrives as '' when the caller passes an
|
|
416
|
+
# empty expression, declared default or not; fromJson('') is a hard failure, so the empty
|
|
417
|
+
# case reads as 0.
|
|
418
|
+
- name: Report the failed attempt
|
|
419
|
+
if: fromJson(inputs.attempts_so_far || '0') < fromJson(env.PARK_AT_ATTEMPT)
|
|
420
|
+
uses: ./.github/actions/create-issue-comment
|
|
421
|
+
with:
|
|
422
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
423
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
424
|
+
body: |
|
|
425
|
+
${{ env.ATTEMPT_MARKER }}
|
|
426
|
+
Attempt ${{ inputs.attempts_so_far || '0' }} of ${{ env.MAX_ATTEMPTS }} on PR #${{ needs.subject.outputs.pr }} ended without an outcome.
|
|
427
|
+
The issue keeps `implement`; the merge belt will retry.
|
|
428
|
+
[View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
429
|
+
- name: Report the exhausted attempt budget
|
|
430
|
+
if: fromJson(inputs.attempts_so_far || '0') >= fromJson(env.PARK_AT_ATTEMPT)
|
|
431
|
+
uses: ./.github/actions/create-issue-comment
|
|
369
432
|
with:
|
|
370
433
|
token: ${{ steps.app-token.outputs.token }}
|
|
371
434
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
372
|
-
|
|
373
|
-
|
|
435
|
+
body: |
|
|
436
|
+
${{ env.ATTEMPT_MARKER }}
|
|
437
|
+
Attempt ${{ inputs.attempts_so_far || '0' }} of ${{ env.MAX_ATTEMPTS }} on PR #${{ needs.subject.outputs.pr }} ended without an outcome.
|
|
438
|
+
The attempt budget for this CI verdict is exhausted. The review label is set: a human must take over.
|
|
439
|
+
[View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
440
|
+
- name: Park the issue for a human
|
|
441
|
+
if: fromJson(inputs.attempts_so_far || '0') >= fromJson(env.PARK_AT_ATTEMPT)
|
|
374
442
|
uses: ./.github/actions/add-issue-labels
|
|
375
443
|
with:
|
|
376
444
|
token: ${{ steps.app-token.outputs.token }}
|
|
377
445
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
378
446
|
labels: ${{ env.REVIEW_LABEL }}
|
|
379
|
-
|
|
380
|
-
|
|
447
|
+
# The reservation only. A failed attempt does not close the pull request, so pr-pending
|
|
448
|
+
# is still true and the board should keep saying so.
|
|
449
|
+
- name: Release the issue
|
|
450
|
+
uses: ./.github/actions/remove-issue-labels
|
|
381
451
|
with:
|
|
382
452
|
token: ${{ steps.app-token.outputs.token }}
|
|
383
453
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
384
|
-
|
|
385
|
-
${{ env.GATE_MARKER }}
|
|
386
|
-
Bot could not resolve PR #${{ needs.subject.outputs.pr }} automatically. The `review` label is set: a human must take over.
|
|
387
|
-
${{ env.INCOMPLETE_COMMENT }}
|
|
388
|
-
[View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
454
|
+
labels: ${{ env.WORKING_LABEL }}
|
|
389
455
|
|
|
390
456
|
agent:
|
|
391
457
|
# The top-level guard reads both outputs. GitHub Actions does not make a
|
|
@@ -424,6 +490,32 @@ checkout:
|
|
|
424
490
|
# Rung 3. The diff is what the risk assessment reads, and the failing logs are what a fix
|
|
425
491
|
# starts from. Both are known from the inputs, so neither costs the agent a turn.
|
|
426
492
|
steps:
|
|
493
|
+
# gh-aw checks out the router's ref. Its own "Checkout PR branch" step runs only when the event
|
|
494
|
+
# carries a pull request, which a router dispatch does not, so the agent would start on main.
|
|
495
|
+
# apply-agent-output fast-forwards origin/<branch> to the bundle tip and refuses anything else,
|
|
496
|
+
# and gh-aw builds that bundle from what the agent committed on top of the checkout; both need
|
|
497
|
+
# the agent to start on the branch it pushes to.
|
|
498
|
+
- name: Check out the pull request branch
|
|
499
|
+
env:
|
|
500
|
+
GH_TOKEN: ${{ github.token }}
|
|
501
|
+
REPO: ${{ github.repository }}
|
|
502
|
+
PR: ${{ needs.subject.outputs.pr }}
|
|
503
|
+
run: |
|
|
504
|
+
set -euo pipefail
|
|
505
|
+
branch=$(gh pr view "$PR" --repo "$REPO" --json headRefName --jq '.headRefName')
|
|
506
|
+
git switch --track "origin/$branch" 2>/dev/null || git switch "$branch"
|
|
507
|
+
echo "On $(git branch --show-current) at $(git rev-parse --short HEAD)"
|
|
508
|
+
# Every merge into the default branch invalidates every other open pull request that added a
|
|
509
|
+
# changelog entry, because they all insert at the top of the same list. The conflict is real
|
|
510
|
+
# and never interesting: both entries belong, newest first. Without a driver it costs a model
|
|
511
|
+
# run per sibling pull request, and it recurs on every merge while more than one is in flight.
|
|
512
|
+
# A consumer opts in by naming its own changelog in .gitattributes with `merge=changelog`;
|
|
513
|
+
# repositories that do not are unaffected, because git only calls a driver a path asks for.
|
|
514
|
+
- name: Teach git how to merge a changelog
|
|
515
|
+
run: |
|
|
516
|
+
set -euo pipefail
|
|
517
|
+
git config merge.changelog.name "newest-first changelog entries"
|
|
518
|
+
git config merge.changelog.driver "node $GITHUB_WORKSPACE/scripts/merge-changelog.mjs %O %A %B"
|
|
427
519
|
- name: Load the issue context
|
|
428
520
|
uses: ./.github/actions/load-issue-context
|
|
429
521
|
with:
|
|
@@ -456,6 +548,13 @@ steps:
|
|
|
456
548
|
fi
|
|
457
549
|
|
|
458
550
|
safe-outputs:
|
|
551
|
+
# Path B. Without this, gh-aw's own safe_outputs job writes as well as the conclude job, and
|
|
552
|
+
# it runs first: it pushed a flattened, single-parent commit with GITHUB_TOKEN while conclude
|
|
553
|
+
# was still waiting, so the agent's merge commit was lost, the pull request stayed
|
|
554
|
+
# conflicting, and GITHUB_TOKEN raises no events, so no CI ran on the new head and the belt
|
|
555
|
+
# stalled (Pliny-Bot run 34051821011). Staged runs everything and writes nothing; conclude
|
|
556
|
+
# applies the bundle and the comment with the App token, which does start CI.
|
|
557
|
+
staged: true
|
|
459
558
|
# A failed run is already a red run. An issue per failure buries the real backlog
|
|
460
559
|
# under noise nobody closes.
|
|
461
560
|
report-failure-as-issue: false
|
|
@@ -483,6 +582,12 @@ timeout-minutes: 60
|
|
|
483
582
|
an issue, and that the issue carries `implement`. Do not re-check any of that, and do not
|
|
484
583
|
poll for checks: the conclusion above is the answer.
|
|
485
584
|
|
|
585
|
+
You are on the pull request branch. Never rebase, reset, amend or otherwise rewrite
|
|
586
|
+
history: the workflow applies your commits as a bundle with a fast-forward-only push and
|
|
587
|
+
discards anything that is not a descendant of the branch tip. The
|
|
588
|
+
`push_to_pull_request_branch` tool's own description recommends rebasing; in this
|
|
589
|
+
repository that advice is wrong. Merge, commit, and let the workflow push.
|
|
590
|
+
|
|
486
591
|
2. Read `${{ env.ISSUE_CONTEXT_PATH }}`. It contains the issue body and its discussion. When
|
|
487
592
|
running `/repo-verify`, the acceptance criteria there define what the implementation must
|
|
488
593
|
satisfy.
|
|
@@ -521,13 +626,13 @@ timeout-minutes: 60
|
|
|
521
626
|
4b. **Merge conflict when CI is green.** If the conclusion is `success` and
|
|
522
627
|
`has_conflicts` is `true` (current value: `${{ needs.reserve.outputs.has_conflicts }}`),
|
|
523
628
|
resolve the conflict before assessing risk. You are already on the PR branch.
|
|
524
|
-
|
|
525
|
-
(`git
|
|
526
|
-
conflict deliberately, and run the verification commands below. Do not
|
|
527
|
-
`--theirs`, or a blanket conflict-marker deletion without reviewing the
|
|
528
|
-
behavior from both sides.
|
|
629
|
+
Merge `origin/${{ github.event.repository.default_branch }}` into it
|
|
630
|
+
(`git merge origin/${{ github.event.repository.default_branch }}`), resolve every
|
|
631
|
+
conflict deliberately, commit the merge, and run the verification commands below. Do not
|
|
632
|
+
use `--ours`, `--theirs`, or a blanket conflict-marker deletion without reviewing the
|
|
633
|
+
intended behavior from both sides, and never rebase: the push is fast-forward only.
|
|
529
634
|
|
|
530
|
-
Scope verification to the files the
|
|
635
|
+
Scope verification to the files the merge touched: pass changed file paths to
|
|
531
636
|
lint/format tools instead of running them repository-wide (see step 6's scoped
|
|
532
637
|
verification guidance).
|
|
533
638
|
|
|
@@ -535,13 +640,13 @@ timeout-minutes: 60
|
|
|
535
640
|
${{ env.VERIFY_COMMANDS }}
|
|
536
641
|
```
|
|
537
642
|
|
|
538
|
-
Push the
|
|
643
|
+
Push the merged branch using `push_to_pull_request_branch` (pr_number: ${{ needs.subject.outputs.pr }},
|
|
539
644
|
branch: the current PR branch), then emit the `add_comment` with
|
|
540
645
|
**Verdict:** remediated. CI will re-run on the updated branch and the merge gate
|
|
541
646
|
will be triggered again — the next cycle will see a clean, conflict-free PR and can
|
|
542
647
|
make a proper merge or review decision.
|
|
543
648
|
|
|
544
|
-
If the
|
|
649
|
+
If the merge cannot be completed or the conflicts are genuinely ambiguous, select the `review`
|
|
545
650
|
verdict instead and explain which conflicts could not be resolved safely.
|
|
546
651
|
|
|
547
652
|
If the conclusion is `success` and `has_conflicts` is `false`, skip this step and
|
|
@@ -595,6 +700,15 @@ timeout-minutes: 60
|
|
|
595
700
|
fix the actual cause. Run these verification commands before a push. Do not weaken a test,
|
|
596
701
|
disable a check, or push an unverified guess.
|
|
597
702
|
|
|
703
|
+
**Empty failure evidence is not a reason to ask for review.** If `failed-jobs.json` is `[]`
|
|
704
|
+
or the logs say they were unavailable, then no CI run judged this head. That is the normal
|
|
705
|
+
state of a conflicting pull request: GitHub cannot build `refs/pull/N/merge` while the
|
|
706
|
+
conflict lasts, so no `pull_request` CI can run on it and there is nothing to read. The
|
|
707
|
+
conflict is the failure to fix. Resolve it as described above, push, and select
|
|
708
|
+
`remediated`; CI runs on the result and the next cycle gets a real verdict. Select `review`
|
|
709
|
+
for missing evidence only when `has_conflicts` is `false`, because then there is genuinely
|
|
710
|
+
nothing to act on.
|
|
711
|
+
|
|
598
712
|
**Scoped verification.** The commands below are the full suite. This runner has limited
|
|
599
713
|
memory, and a whole-repo lint or build can be killed mid-run. Scope verification to the
|
|
600
714
|
files you actually changed first, and only escalate to the full suite when the scoped run
|
|
@@ -699,7 +813,7 @@ flowchart TD
|
|
|
699
813
|
gateConflict{"Merge conflicts?"}
|
|
700
814
|
gateConflict -->|yes| gateRebase
|
|
701
815
|
gateConflict -->|no| gateTrivial
|
|
702
|
-
gateRebase("
|
|
816
|
+
gateRebase("Merge main in<br/>Resolve conflicts, /repo-verify") -->|pushed| gateWait
|
|
703
817
|
gateRebase -.->|cannot resolve| gateHuman
|
|
704
818
|
gateTrivial{"Trivial marker?"}
|
|
705
819
|
gateTrivial -->|yes| gateMerge
|
|
@@ -382,8 +382,16 @@ safe-outputs:
|
|
|
382
382
|
# under noise nobody closes.
|
|
383
383
|
report-failure-as-issue: false
|
|
384
384
|
threat-detection: false
|
|
385
|
+
# The refined story replaces the issue body, which is one call carrying the whole
|
|
386
|
+
# thing. The allowance is three rather than one because a single malformed call the
|
|
387
|
+
# bridge accepts as spent would otherwise end the run with the body unwritten and a
|
|
388
|
+
# comment already claiming success: seen on a real run, "the first update_issue call
|
|
389
|
+
# was sent with an incorrect parameter shape (20 bytes, missing body) and was accepted
|
|
390
|
+
# with success by the bridge, consuming the 1-per-run quota". The prompt still says to
|
|
391
|
+
# send the body once.
|
|
385
392
|
update-issue:
|
|
386
393
|
target: "*"
|
|
394
|
+
max: 3
|
|
387
395
|
add-comment:
|
|
388
396
|
# Split children. An oversized story becomes several implementable ones rather than
|
|
389
397
|
# one issue nobody can land; the cap stops a runaway decomposition.
|
|
@@ -391,7 +399,12 @@ safe-outputs:
|
|
|
391
399
|
max: 6
|
|
392
400
|
|
|
393
401
|
|
|
394
|
-
|
|
402
|
+
# Sixty rather than forty. A real run wrote the whole refined story and was killed by the
|
|
403
|
+
# clock four short turns later, on its way to submitting it: 36 model turns, most of them
|
|
404
|
+
# under 110 output tokens and still over a minute each, so the budget buys about that many
|
|
405
|
+
# turns whatever the issue is. Not ninety, which is what implement gets for writing code
|
|
406
|
+
# and running a build; this reads a repository and rewrites one issue body.
|
|
407
|
+
timeout-minutes: 60
|
|
395
408
|
---
|
|
396
409
|
|
|
397
410
|
1. You are refining the triggering issue **#${{ inputs.issue-number }}**. Do not choose
|
|
@@ -553,7 +566,14 @@ timeout-minutes: 40
|
|
|
553
566
|
them is a domain expert, not an engineer.
|
|
554
567
|
|
|
555
568
|
**The story is complete.** You answered every exploration question yourself and none remain
|
|
556
|
-
for the author.
|
|
569
|
+
for the author.
|
|
570
|
+
|
|
571
|
+
Call `update_issue` first, with the replacement body, and wait for it to come back. Send
|
|
572
|
+
the whole body in that one call: it is the only thing this step has to get right, and a
|
|
573
|
+
call sent to see what the tool accepts still counts against your allowance even when it
|
|
574
|
+
fails. Do not send a partial payload, and do not probe.
|
|
575
|
+
|
|
576
|
+
Only once that call has succeeded, call `add_comment`
|
|
557
577
|
with `${{ env.REFINE_MARKER }}`, then `${{ env.SAFE_OUTPUT_COMMENT_PREFIX }}`,
|
|
558
578
|
then exactly one of these messages, based only on the `labels` array in the supplied issue
|
|
559
579
|
context:
|
|
@@ -561,6 +581,10 @@ timeout-minutes: 40
|
|
|
561
581
|
- If the array includes the exact label `future`: `Refinement complete. The implement label has been added. Implementation is paused until the future label is removed.`
|
|
562
582
|
- Otherwise: `Refinement complete. The implement label has been added and the implement workflow will start shortly.`
|
|
563
583
|
|
|
584
|
+
If `update_issue` did not succeed, do not post either message: an issue that reads as
|
|
585
|
+
refined with its body untouched is worse than one that says the run failed. Call
|
|
586
|
+
`report_incomplete` with what the tool told you, and let the run be retried.
|
|
587
|
+
|
|
564
588
|
**The story was split.** You estimated ${{ env.SPLIT_THRESHOLD }} or more and found real
|
|
565
589
|
seams. Call `create_issue` once per child, then `update_issue` on the parent with the
|
|
566
590
|
summary and the checklist, then `add_comment` with `${{ env.REFINE_MARKER }}`, then
|