@plainconceptsplatform/workflows 1.5.0 → 1.6.10

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.
@@ -2,7 +2,7 @@
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-merge-gate.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
4
  VERIFY_COMMANDS: ""
5
- REPO_RULES: "Review the selected bot pull request for defects and report what you verified. Do not decide the outcome: the workflow computes it from your report and from facts it measured before you ran."
5
+ REPO_RULES: "Review the selected pull request for defects and report what you verified. Do not decide the outcome: the workflow computes it from your report and from facts it measured before you ran."
6
6
  # Where to look first, not what to escalate on. This list used to be the check that decided
7
7
  # whether a machine merged without a human, and it decided by category: the prompt told the
8
8
  # agent that a match "is not a defect, it is a reason this pull request needs a person". In a
@@ -13,34 +13,36 @@ env:
13
13
  # One line: gh-aw joins a multi-line env value onto a single line when it compiles the lock.
14
14
  RISK_INDICATORS: "Any diff touching authentication, authorization or session handling. Any change to a calculation or pricing engine, or to code handling money. Any database migration, or a change to an entity or schema. Any change to an audit or event log, or anything that could break its continuity. Any change to a public API contract or a shared library other repositories consume."
15
15
  # Paths a bot may change but never merge on its own: an extended regular expression matched
16
- # against every changed path in the pull request. The default names this stack's dependency
17
- # and toolchain manifests plus everything under a dotted directory, and is wrong for a
18
- # repository built on anything else, which is the failure worth knowing about: an unmatched
19
- # list protects nothing and reports nothing. A match holds the merge for a human; it does not
20
- # stop the agent repairing failed CI on the same files.
21
- PROTECTED_PATHS: '^(\.|AGENTS\.md$|ARCHITECTURE\.md$|opencode\.jsonc$|package\.json$|pnpm-lock\.yaml$|Directory\.Packages\.props$|global\.json$)'
16
+ # against every changed path in the pull request. A match holds the merge for a human; it does
17
+ # not stop the agent repairing failed CI on the same files.
18
+ #
19
+ # Only the automation itself. This list used to hold every dependency manifest, lockfile and
20
+ # dotted directory as well, and with a size threshold and an owner list as wide it parked most
21
+ # of a night's pull requests for a person who then merged them by hand, unread, on Monday:
22
+ # in Pliny-Bot 32 of 40 bot pull requests in two days. What stops a merge now is what is
23
+ # genuinely dangerous to merge unseen: the workflows, the secrets, and a change too big to
24
+ # review in one pass.
25
+ PROTECTED_PATHS: '^\.github/'
22
26
  # Paths whose change needs the person who owns them. A match forces OWNER REVIEW REQUIRED and
23
27
  # sets blast radius high on its own, whatever the diff's size. CODEOWNERS names who is asked
24
- # when the repository has that file; it is never a prerequisite, because a repository without
25
- # one must still be able to protect its auth and its infrastructure.
28
+ # when the repository has that file; it is never a prerequisite.
26
29
  #
27
- # Matches a path segment or a file stem, in both spellings, because the same default has to
28
- # work for `src/auth/`, `src/Api/Identity/` and `AuthEndpoints.cs`. The lowercase-only,
29
- # directory-only version this replaced matched nothing at all in a .NET consumer: replayed
30
- # against that repository's last eighteen gated pull requests it caught none of them, while
31
- # this one catches exactly three and they are the three that deserved an owner (a database
32
- # migration, a change to the platform role definitions, and a downstream token service).
33
- OWNER_PATHS: '(^|/)([Aa]uth|[Aa]uthn|[Aa]uthz|[Aa]uthentication|[Aa]uthorization|[Ii]dentity|[Ss]ecurity|[Ss]ecrets?|[Mm]igrations|[Ii]nfra|terraform|helm|k8s|deploy)(/|[A-Z][A-Za-z]*\.[a-z]+$)'
30
+ # Secrets: a `secrets` directory or file, an environment file, a key or a certificate. Code
31
+ # that handles secrets (a SecretMasker.cs) is not a secret; the review pass reads it like any
32
+ # other change.
33
+ OWNER_PATHS: '(^|/)([Ss]ecrets?(/|\.[A-Za-z0-9]+$)|\.env(\.[A-Za-z0-9_-]+)?$|[^/]+\.(pem|pfx|p12|key)$)'
34
34
  # Paths worth a second look that do not, alone, need a person. A match raises the floor to
35
35
  # medium, and medium with acceptable recoverability still auto-merges. This is the line that
36
- # separates "look here" from "stop here", which the old RISK_INDICATORS list could not.
37
- SENSITIVE_PATHS: '(^|/)([Dd]omain|entities|[Cc]ontracts)/'
38
- # Diff shape. Size and spread are the honest deterministic signal for a change that touches no
39
- # path a regex would name: the one pull request in the measured sample that genuinely wanted an
40
- # owner matched no sensitive path and was identified by 29 files and ~1600 lines across five
41
- # architectural layers.
42
- BLAST_HIGH_FILES: "20"
43
- BLAST_HIGH_LINES: "800"
36
+ # separates "look here" from "stop here". Auth, identity, security, migrations and
37
+ # infrastructure used to stop a merge from here; they are the review pass's to look at now, and
38
+ # a migration that rewrites data still parks through a `low` recoverability the agent evidences.
39
+ SENSITIVE_PATHS: '(^|/)([Dd]omain|entities|[Cc]ontracts)/|(^|/)([Aa]uth|[Aa]uthn|[Aa]uthz|[Aa]uthentication|[Aa]uthorization|[Ii]dentity|[Ss]ecurity|[Mm]igrations|[Ii]nfra|terraform|helm|k8s|deploy)(/|[A-Z][A-Za-z]*\.[a-z]+$)'
40
+ # Diff shape. Lines decide high: a change over ten thousand counted lines (tests, docs,
41
+ # translations and generated code excluded) is too big to merge unseen. It was a thousand, which
42
+ # is a normal feature once the tests are left out. A file count alone never decides, so the high
43
+ # file threshold is set out of reach; spread still raises medium.
44
+ BLAST_HIGH_FILES: "100000"
45
+ BLAST_HIGH_LINES: "10000"
44
46
  BLAST_MEDIUM_FILES: "5"
45
47
  BLAST_MEDIUM_LINES: "200"
46
48
  # Paths that change no runtime behaviour: tests, docs, specs, translations and generated
@@ -80,14 +82,18 @@ env:
80
82
  PARK_AT_UNUSABLE_OUTPUT: "2"
81
83
  ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
82
84
  GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
85
+ # The bots whose pull requests the gate takes, in every spelling GitHub uses for one account.
86
+ # Any other author needs write access to the repository, as they would to push the branch.
87
+ TRUSTED_BOTS: "github-actions[bot] app/github-actions platform-devbox[bot]"
83
88
  GIT_AUTHOR_NAME: "github-actions[bot]"
84
89
  GIT_AUTHOR_EMAIL: "github-actions[bot]@users.noreply.github.com"
85
90
  GIT_COMMITTER_NAME: "github-actions[bot]"
86
91
  GIT_COMMITTER_EMAIL: "github-actions[bot]@users.noreply.github.com"
87
92
  description: |
88
- Decides what happens to a bot-authored pull request once CI has reported: merge when the
89
- risk assessment is clean, hand to a human when it is not, fix CI when it failed. Called by
90
- the Work Router; does not trigger on public events.
93
+ Decides what happens to a pull request once CI has reported, whether the bot or a person with
94
+ write access opened it: merge when the risk assessment is clean, hand to a human when it is
95
+ genuinely dangerous, fix CI or a conflict when there is one. Called by the Work Router, one
96
+ pull request at a time by its merge train; does not trigger on public events.
91
97
 
92
98
  In a stack, a child pull request (its base is the feature branch) merges into that feature
93
99
  branch and its child issue closes with it; the root pull request is held for a person. The
@@ -154,6 +160,10 @@ jobs:
154
160
  found: ${{ steps.subject.outputs.found }}
155
161
  pr: ${{ steps.subject.outputs.pr }}
156
162
  issue: ${{ steps.subject.outputs.issue }}
163
+ # Where verdicts, attempts and labels go: the issue, or the pull request when it closes none.
164
+ record: ${{ steps.subject.outputs.record }}
165
+ head_ref: ${{ steps.subject.outputs.head-ref }}
166
+ closes: ${{ steps.subject.outputs.closes }}
157
167
  conclusion: ${{ steps.subject.outputs.conclusion }}
158
168
  run-id: ${{ steps.subject.outputs.run-id }}
159
169
  review_blocked: ${{ steps.review.outputs.review_blocked }}
@@ -173,7 +183,7 @@ jobs:
173
183
  ci-conclusion: ${{ inputs.ci-conclusion }}
174
184
  ci-run-id: ${{ inputs.ci-run-id }}
175
185
  linked-issue: ${{ inputs.linked-issue }}
176
- require-label: ${{ env.IMPLEMENT_LABEL }}
186
+ trusted-bots: ${{ env.TRUSTED_BOTS }}
177
187
  - name: Block a pull request with requested changes
178
188
  id: review
179
189
  env:
@@ -310,8 +320,13 @@ jobs:
310
320
  echo "check-diff is not installed (agent-harness 3.2.0 or later ships it), so comments and tests were not checked." >> "$GITHUB_STEP_SUMMARY"
311
321
  exit 0
312
322
  fi
313
- report=$(node .opencode/scripts/check-diff.mjs --base "$BASE" 2>&1)
314
- code=$?
323
+ # `|| code=$?`, not a bare `code=$?` on the next line. GitHub runs this under `bash -e`,
324
+ # and `set -uo pipefail` above does not undo it, so a check-diff that exited 1 (the
325
+ # `fail` this step exists to report) ended the step there: the job failed, the agent
326
+ # was skipped, and the pull request burned its whole attempt budget on a verdict that
327
+ # was never recorded (Pliny-Bot #686, six attempts in twenty minutes).
328
+ code=0
329
+ report=$(node .opencode/scripts/check-diff.mjs --base "$BASE" 2>&1) || code=$?
315
330
  case "$code" in 0) result=pass ;; 1) result=fail ;; *) result=error ;; esac
316
331
  delimiter="EOF_$(openssl rand -hex 8)"
317
332
  {
@@ -354,14 +369,14 @@ jobs:
354
369
  uses: ./.github/actions/remove-issue-labels
355
370
  with:
356
371
  token: ${{ steps.app-token.outputs.token }}
357
- issue-number: ${{ needs.subject.outputs.issue }}
372
+ issue-number: ${{ needs.subject.outputs.record }}
358
373
  labels: ${{ env.WORKING_LABEL }}
359
374
  - name: Flag owner review
360
375
  if: needs.protected_changes.outputs.holds_review == 'true'
361
376
  uses: ./.github/actions/add-issue-labels
362
377
  with:
363
378
  token: ${{ steps.app-token.outputs.token }}
364
- issue-number: ${{ needs.subject.outputs.issue }}
379
+ issue-number: ${{ needs.subject.outputs.record }}
365
380
  labels: |-
366
381
  ${{ env.REVIEW_LABEL }}
367
382
  ${{ env.OWNER_REVIEW_LABEL }}
@@ -370,7 +385,7 @@ jobs:
370
385
  uses: ./.github/actions/create-issue-comment
371
386
  with:
372
387
  token: ${{ steps.app-token.outputs.token }}
373
- issue-number: ${{ needs.subject.outputs.issue }}
388
+ issue-number: ${{ needs.subject.outputs.record }}
374
389
  body: |
375
390
  ${{ env.GATE_MARKER }}
376
391
  PR #${{ needs.subject.outputs.pr }} changes protected files and cannot be auto-merged.
@@ -439,7 +454,7 @@ jobs:
439
454
  uses: ./.github/actions/create-issue-comment
440
455
  with:
441
456
  token: ${{ steps.app-token.outputs.token }}
442
- issue-number: ${{ needs.subject.outputs.issue }}
457
+ issue-number: ${{ needs.subject.outputs.record }}
443
458
  body: |
444
459
  Problems found in PR #${{ needs.subject.outputs.pr }}. ${{ steps.conflicts.outputs.has_conflicts == 'true' && 'Merge conflicts detected.' || 'CI failed.' }}
445
460
  Bot is working on fixing it.
@@ -473,7 +488,7 @@ jobs:
473
488
  uses: ./.github/actions/validate-merge-gate-output
474
489
  with:
475
490
  output-file: ${{ steps.output.outputs.output-file }}
476
- issue-number: ${{ needs.subject.outputs.issue }}
491
+ issue-number: ${{ needs.subject.outputs.record }}
477
492
  ci-conclusion: ${{ needs.subject.outputs.conclusion }}
478
493
  blast-level: ${{ needs.protected_changes.outputs.level }}
479
494
  protected-hit: ${{ needs.protected_changes.outputs.requires_review }}
@@ -511,18 +526,23 @@ jobs:
511
526
  token: ${{ steps.app-token.outputs.token }}
512
527
  fetch-depth: 0
513
528
  - name: Verify pull request closes the source issue
529
+ if: needs.subject.outputs.issue != ''
514
530
  continue-on-error: true
515
531
  uses: ./.github/actions/link-pr-to-issue
516
532
  with:
517
533
  token: ${{ steps.app-token.outputs.token }}
518
534
  pr-number: ${{ needs.subject.outputs.pr }}
519
535
  issue-number: ${{ needs.subject.outputs.issue }}
536
+ # The push goes to this pull request's branch or nowhere. A `[bot] ` title prefix used to be
537
+ # the guard, which a person's pull request does not carry; the branch the subject job read
538
+ # is the exact one, whoever opened it.
520
539
  - name: Apply agent output
521
540
  uses: ./.github/actions/apply-agent-output
522
541
  with:
523
542
  artifact-name: ${{ needs.activation.outputs.artifact_prefix }}agent
524
543
  token: ${{ steps.app-token.outputs.token }}
525
544
  push-to-branch: 'true'
545
+ expected-branch: ${{ needs.subject.outputs.head_ref }}
526
546
  apply-labels: 'false'
527
547
  # GITHUB_TOKEN on purpose: an App-token comment on a pull request is an issue_comment
528
548
  # event, and GITHUB_TOKEN raises none. The full assessment lives on the issue, where the
@@ -558,7 +578,7 @@ jobs:
558
578
  ${{ needs.protected_changes.outputs.signals }}
559
579
  ```
560
580
 
561
- Findings and verification on the linked issue: #${{ needs.subject.outputs.issue }}. [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
581
+ ${{ needs.subject.outputs.issue != '' && format('Findings and verification on the linked issue: #{0}.', needs.subject.outputs.issue) || 'Findings and verification are in the review comment above.' }} [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
562
582
  ${{ env.EVIDENCE_BEFORE_REVIEW == 'true' && contains(fromJson('["human-review","owner-review"]'), needs.validate_output.outputs.outcome) && 'Screenshots of this head follow in their own comment if it carries a verification plan. Approving the pull request merges it.' || '' }}
563
583
  - name: Merge approved pull request
564
584
  if: needs.validate_output.outputs.outcome == 'auto-merge' && needs.subject.outputs.stack_root != 'true'
@@ -579,7 +599,7 @@ jobs:
579
599
  uses: ./.github/actions/create-issue-comment
580
600
  with:
581
601
  token: ${{ steps.app-token.outputs.token }}
582
- issue-number: ${{ needs.subject.outputs.issue }}
602
+ issue-number: ${{ needs.subject.outputs.record }}
583
603
  body: |
584
604
  **Stack root held.** This pull request is the root of a stack: its children merge
585
605
  into the feature branch, and it merges into ${{ github.event.repository.default_branch }} only when a person
@@ -589,7 +609,7 @@ jobs:
589
609
  uses: ./.github/actions/remove-issue-labels
590
610
  with:
591
611
  token: ${{ steps.app-token.outputs.token }}
592
- issue-number: ${{ needs.subject.outputs.issue }}
612
+ issue-number: ${{ needs.subject.outputs.record }}
593
613
  labels: ${{ env.WORKING_LABEL }}
594
614
  # `review` goes on for all three parked dispositions, so every board query and every
595
615
  # authorize-bot-work handoff that already reads it keeps working. The second label is what
@@ -599,7 +619,7 @@ jobs:
599
619
  uses: ./.github/actions/add-issue-labels
600
620
  with:
601
621
  token: ${{ steps.app-token.outputs.token }}
602
- issue-number: ${{ needs.subject.outputs.issue }}
622
+ issue-number: ${{ needs.subject.outputs.record }}
603
623
  labels: |-
604
624
  ${{ env.REVIEW_LABEL }}
605
625
  ${{ needs.validate_output.outputs.outcome == 'owner-review' && env.OWNER_REVIEW_LABEL || '' }}
@@ -631,7 +651,7 @@ jobs:
631
651
  uses: ./.github/actions/remove-issue-labels
632
652
  with:
633
653
  token: ${{ steps.app-token.outputs.token }}
634
- issue-number: ${{ needs.subject.outputs.issue }}
654
+ issue-number: ${{ needs.subject.outputs.record }}
635
655
  labels: ${{ env.WORKING_LABEL }}
636
656
  # GitHub's closing keywords never fire when a PR merges into a branch other than the
637
657
  # default, so a child PR landing on the feature branch leaves its issue open — and
@@ -641,7 +661,7 @@ jobs:
641
661
  # and `gh issue close` on an already-closed issue is a harmless no-op, making the
642
662
  # step safe to re-run.
643
663
  - name: Close the child issue when the pull request landed on a feature branch
644
- if: needs.validate_output.outputs.outcome == 'auto-merge' && needs.subject.outputs.pr_base != '' && needs.subject.outputs.pr_base != github.event.repository.default_branch
664
+ if: needs.validate_output.outputs.outcome == 'auto-merge' && needs.subject.outputs.issue != '' && needs.subject.outputs.pr_base != '' && needs.subject.outputs.pr_base != github.event.repository.default_branch
645
665
  env:
646
666
  GH_TOKEN: ${{ steps.app-token.outputs.token }}
647
667
  REPO: ${{ github.repository }}
@@ -668,7 +688,7 @@ jobs:
668
688
  uses: ./.github/actions/remove-issue-labels
669
689
  with:
670
690
  token: ${{ steps.app-token.outputs.token }}
671
- issue-number: ${{ needs.subject.outputs.issue }}
691
+ issue-number: ${{ needs.subject.outputs.record }}
672
692
  labels: |
673
693
  ${{ env.IMPLEMENT_LABEL }}
674
694
  ${{ env.WORKING_LABEL }}
@@ -676,8 +696,12 @@ jobs:
676
696
  ${{ env.OWNER_REVIEW_LABEL }}
677
697
  ${{ env.BLOCKED_LABEL }}
678
698
  ${{ env.PR_PENDING_LABEL }}
699
+ # A conclude that dies (a push refused, a token rejected) is a failed attempt too. Without it
700
+ # here the run left no verdict and no attempt comment, which the merge train reads as a gate that
701
+ # did nothing and never offers the pull request again: Pliny-Bot #716 sat stranded that way after
702
+ # its repair was computed and then lost to a rejected git fetch in conclude.
679
703
  incomplete:
680
- needs: [subject, protected_changes, agent, safe_outputs, validate_output]
704
+ needs: [subject, protected_changes, agent, safe_outputs, validate_output, conclude]
681
705
  if: >
682
706
  always() &&
683
707
  needs.subject.outputs.found == 'true' &&
@@ -685,7 +709,8 @@ jobs:
685
709
  (
686
710
  needs.agent.result != 'success' ||
687
711
  needs.safe_outputs.result != 'success' ||
688
- needs.validate_output.outputs.valid != 'true'
712
+ needs.validate_output.outputs.valid != 'true' ||
713
+ needs.conclude.result == 'failure'
689
714
  )
690
715
  runs-on: agents-arc
691
716
  permissions:
@@ -745,18 +770,18 @@ jobs:
745
770
  uses: ./.github/actions/create-issue-comment
746
771
  with:
747
772
  token: ${{ steps.app-token.outputs.token }}
748
- issue-number: ${{ needs.subject.outputs.issue }}
773
+ issue-number: ${{ needs.subject.outputs.record }}
749
774
  body: |
750
775
  ${{ env.ATTEMPT_MARKER }}
751
776
  Attempt ${{ inputs.attempts_so_far || '0' }} of ${{ env.MAX_ATTEMPTS }} on PR #${{ needs.subject.outputs.pr }} ended without an outcome.
752
- This failure parks at ${{ steps.budget.outputs.threshold }}. The issue keeps `implement`; the merge belt will retry.
777
+ This failure parks at ${{ steps.budget.outputs.threshold }}. The merge train will retry.
753
778
  [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
754
779
  - name: Report the exhausted attempt budget
755
780
  if: steps.budget.outputs.park == 'true' && steps.budget.outputs.kind == 'machine'
756
781
  uses: ./.github/actions/create-issue-comment
757
782
  with:
758
783
  token: ${{ steps.app-token.outputs.token }}
759
- issue-number: ${{ needs.subject.outputs.issue }}
784
+ issue-number: ${{ needs.subject.outputs.record }}
760
785
  body: |
761
786
  ${{ env.ATTEMPT_MARKER }}
762
787
  Attempt ${{ inputs.attempts_so_far || '0' }} of ${{ steps.budget.outputs.threshold }} on PR #${{ needs.subject.outputs.pr }} ended without an outcome.
@@ -774,7 +799,7 @@ jobs:
774
799
  uses: ./.github/actions/create-issue-comment
775
800
  with:
776
801
  token: ${{ steps.app-token.outputs.token }}
777
- issue-number: ${{ needs.subject.outputs.issue }}
802
+ issue-number: ${{ needs.subject.outputs.record }}
778
803
  body: |
779
804
  ${{ env.GATE_MARKER }}
780
805
  The agent finished on PR #${{ needs.subject.outputs.pr }} but its report could not be
@@ -794,7 +819,7 @@ jobs:
794
819
  token: ${{ steps.app-token.outputs.token }}
795
820
  issue-number: ${{ needs.subject.outputs.pr }}
796
821
  body: |
797
- The merge gate stopped on this pull request and handed it to a person (#${{ needs.subject.outputs.issue }}).
822
+ The merge gate stopped on this pull request and handed it to a person${{ needs.subject.outputs.issue != '' && format(' (#{0})', needs.subject.outputs.issue) || '' }}.
798
823
  ${{ needs.validate_output.outputs.pushed == 'true' && 'The agent pushed a repair that was not applied because its report could not be read. The patch and bundle are in the `agent` artifact of the run below.' || '' }}
799
824
  [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
800
825
  - name: Label the pull request for review
@@ -812,7 +837,7 @@ jobs:
812
837
  uses: ./.github/actions/add-issue-labels
813
838
  with:
814
839
  token: ${{ steps.app-token.outputs.token }}
815
- issue-number: ${{ needs.subject.outputs.issue }}
840
+ issue-number: ${{ needs.subject.outputs.record }}
816
841
  labels: |-
817
842
  ${{ env.REVIEW_LABEL }}
818
843
  ${{ steps.budget.outputs.kind == 'machine' && env.STALLED_LABEL || '' }}
@@ -822,7 +847,7 @@ jobs:
822
847
  uses: ./.github/actions/remove-issue-labels
823
848
  with:
824
849
  token: ${{ steps.app-token.outputs.token }}
825
- issue-number: ${{ needs.subject.outputs.issue }}
850
+ issue-number: ${{ needs.subject.outputs.record }}
826
851
  labels: ${{ env.WORKING_LABEL }}
827
852
 
828
853
  agent:
@@ -892,7 +917,7 @@ steps:
892
917
  uses: ./.github/actions/load-issue-context
893
918
  with:
894
919
  token: ${{ github.token }}
895
- issue-number: ${{ needs.subject.outputs.issue }}
920
+ issue-number: ${{ needs.subject.outputs.record }}
896
921
  output-path: ${{ env.ISSUE_CONTEXT_PATH }}
897
922
  - name: Fetch the diff and any failing job logs
898
923
  env:
@@ -934,9 +959,10 @@ safe-outputs:
934
959
  # target "*" because these workers are dispatched, not triggered by the pull request:
935
960
  # the default "triggering" target has no pull request in context and rejects the push
936
961
  # with "requires pull request context", so the agent's fix is computed and discarded.
962
+ # No title prefix: the gate repairs pull requests people opened as well, and conclude pushes
963
+ # only to the branch of the pull request the subject job validated.
937
964
  push-to-pull-request-branch:
938
965
  target: "*"
939
- required-title-prefix: "[bot] "
940
966
  max-patch-size: 10240
941
967
  # A failed bot PR may already contain protected files. Permit a verified repair push,
942
968
  # but protected_changes still prevents the later green-CI cycle from auto-merging it.
@@ -955,13 +981,13 @@ safe-outputs:
955
981
  timeout-minutes: 120
956
982
  ---
957
983
 
958
- 1. You are gating pull request **#${{ needs.subject.outputs.pr }}**, which closes issue
959
- **#${{ needs.subject.outputs.issue }}**. CI concluded
960
- **${{ needs.subject.outputs.conclusion }}**.
984
+ 1. You are gating pull request **#${{ needs.subject.outputs.pr }}**, which ${{ needs.subject.outputs.closes }}.
985
+ CI concluded **${{ needs.subject.outputs.conclusion }}**.
961
986
 
962
- It has already been confirmed that this is an open pull request we authored, that it closes
963
- an issue, and that the issue carries `implement`. Do not re-check any of that, and do not
964
- poll for checks: the conclusion above is the answer.
987
+ It has already been confirmed that this is an open pull request from this repository, opened
988
+ by the bot or by someone with write access. Do not re-check any of that, and do not poll for
989
+ checks: the conclusion above is the answer. Who opened it changes nothing below: a person's
990
+ pull request is repaired, reviewed and merged by the same rules as the bot's.
965
991
 
966
992
  You are on the pull request branch. Never rebase, reset, amend or otherwise rewrite
967
993
  history: the workflow applies your commits as a bundle with a fast-forward-only push and
@@ -969,9 +995,11 @@ timeout-minutes: 120
969
995
  `push_to_pull_request_branch` tool's own description recommends rebasing; in this
970
996
  repository that advice is wrong. Merge, commit, and let the workflow push.
971
997
 
972
- 2. Read `${{ env.ISSUE_CONTEXT_PATH }}`. It contains the issue body and its discussion. The
998
+ 2. Read `${{ env.ISSUE_CONTEXT_PATH }}`. It contains the issue body and its discussion, or, for
999
+ a pull request that closes no issue, the pull request's own description and discussion. The
973
1000
  acceptance criteria there define what this implementation had to satisfy, and step 5c asks
974
- you to check the diff against them.
1001
+ you to check the diff against them. A description with no stated criteria is checked against
1002
+ what it says the change does.
975
1003
 
976
1004
  3. Branch on the conclusion.
977
1005
 
@@ -1225,7 +1253,7 @@ timeout-minutes: 120
1225
1253
  your report and from the facts it measured, and a word it does not recognise parks the pull
1226
1254
  request. Never merge with administrator privileges and never bypass a required check.
1227
1255
 
1228
- 8. Emit exactly one `add_comment` targeting issue `${{ needs.subject.outputs.issue }}`,
1256
+ 8. Emit exactly one `add_comment` targeting item `${{ needs.subject.outputs.record }}`,
1229
1257
  containing, in this order:
1230
1258
 
1231
1259
  1. `${{ env.GATE_MARKER }}`
@@ -837,9 +837,11 @@ safe-outputs:
837
837
  # was sent with an incorrect parameter shape (20 bytes, missing body) and was accepted
838
838
  # with success by the bridge, consuming the 1-per-run quota". The prompt still says to
839
839
  # send the body once.
840
+ # `title:` lets refine set an English title when the issue was written in another language.
840
841
  update-issue:
841
842
  target: "*"
842
843
  max: 3
844
+ title:
843
845
  add-comment:
844
846
  # Split children. An oversized story becomes several implementable ones rather than
845
847
  # one issue nobody can land; the cap stops a runaway decomposition.
@@ -976,6 +978,13 @@ timeout-minutes: 90
976
978
  The visible line is for people and the marker is read by the workflow, which turns it into the
977
979
  `sp-N` label. A body without the marker gets no estimate label at all.
978
980
 
981
+ **Everything you write is in English, whatever language the issue was written in.** Bodies,
982
+ child issues, comments and questions are English. When the title of the issue you are refining
983
+ is not English, put an English title in the same `update_issue` call as the body, as
984
+ `{"issue_number":N,"title":"...","body":"..."}`: it carries the same meaning, short, with no
985
+ language tag. People write issues in their own language, and everything the workflow produces
986
+ from them (pull requests, commits, the run history) is read by everyone else in English.
987
+
979
988
  7. **One safe-output call per turn.** Never batch multiple safe-output calls into a single
980
989
  message: `update_issue`, `create_issue` and `add_comment` each go in their own turn, with
981
990
  nothing else in the message. The provider caps one response at a fixed size, and a batch of