@plainconceptsplatform/workflows 1.14.0 → 1.15.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 (36) hide show
  1. package/dist/workflow-catalog.d.ts +1 -1
  2. package/dist/workflow-catalog.js +0 -2
  3. package/loops/actions/add-issue-labels/action.yml +50 -50
  4. package/loops/actions/agent-output.cjs +17 -17
  5. package/loops/actions/apply-agent-bundle/action.yml +24 -24
  6. package/loops/actions/apply-agent-comments/action.yml +42 -42
  7. package/loops/actions/apply-agent-labels/action.yml +55 -55
  8. package/loops/actions/cleanup-artifacts/action.yml +91 -91
  9. package/loops/actions/close-agent-issues/action.yml +43 -43
  10. package/loops/actions/create-issue-comment/action.yml +29 -29
  11. package/loops/actions/download-agent-output/action.yml +53 -53
  12. package/loops/actions/link-pr-to-issue/action.yml +40 -40
  13. package/loops/actions/list-open-issues/action.yml +33 -33
  14. package/loops/actions/load-issue-context/action.yml +45 -45
  15. package/loops/actions/merge-agent-pr/action.yml +49 -49
  16. package/loops/actions/remove-issue-labels/action.yml +37 -37
  17. package/loops/actions/update-agent-issues/action.yml +58 -58
  18. package/loops/actions/validate-refine-output/validate-refine-output.sh +28 -4
  19. package/loops/actions/validate-review-output/action.yml +35 -35
  20. package/loops/actions/validate-review-output/validate-review-output.sh +4 -1
  21. package/loops/actions/validate-triage-output/action.yml +36 -36
  22. package/loops/actions/validate-triage-output/validate-triage-output.sh +5 -2
  23. package/loops/actions/verify-composite-actions/action.yml +9 -9
  24. package/loops/actions/verify-refine-output/action.yml +9 -9
  25. package/loops/actions/verify-refine-output/verify-refine-output.sh +14 -0
  26. package/loops/actions/verify-route-matrix/action.yml +9 -9
  27. package/loops/actions/verify-route-matrix/verify-route-matrix.sh +32 -46
  28. package/loops/templates/agentics/agentics-maintenance.yml +121 -121
  29. package/loops/templates/issues/bug_report.yml +109 -109
  30. package/loops/templates/issues/feature_request.yml +75 -75
  31. package/loops/workflows/agent-refine.md +43 -119
  32. package/loops/workflows/shared/platform-defaults.md +53 -53
  33. package/package.json +1 -1
  34. package/loops/actions/report-workflow-errors/action.yml +0 -538
  35. package/loops/actions/report-workflow-errors/report-policy.cjs +0 -194
  36. package/loops/templates/agentics/agentics-error-report.yml +0 -101
@@ -1,75 +1,75 @@
1
- name: Feature request
2
- description: Propose a small improvement or new capability
3
- labels: ["enhancement"]
4
- body:
5
- - type: markdown
6
- attributes:
7
- value: |
8
- This template is for small, well-scoped improvements a focused
9
- enhancement, a missing convenience, a quality-of-life fix.
10
-
11
- For large features, architecture changes, or cross-cutting work,
12
- open a planning issue or an ADR instead.
13
-
14
- Do **not** include real secrets or production data use placeholders.
15
- - type: dropdown
16
- id: scope
17
- attributes:
18
- label: Scope
19
- description: How big is this change? If it doesn't fit Small or Medium, use a planning issue instead.
20
- options:
21
- - Small a single file or component, no refactoring
22
- - Medium touches a few files or a feature area, may need minor refactoring
23
- validations:
24
- required: true
25
- - type: textarea
26
- id: current-behavior
27
- attributes:
28
- label: Current behavior
29
- description: How does it work today? Describe the existing behavior or limitation.
30
- validations:
31
- required: true
32
- - type: textarea
33
- id: problem
34
- attributes:
35
- label: Problem / motivation
36
- description: What user or business need does this address? Why is the current behavior a problem?
37
- validations:
38
- required: true
39
- - type: textarea
40
- id: proposal
41
- attributes:
42
- label: Proposed solution
43
- description: What would you like to happen?
44
- validations:
45
- required: true
46
- - type: textarea
47
- id: alternatives
48
- attributes:
49
- label: Alternatives considered
50
- validations:
51
- required: false
52
- - type: textarea
53
- id: acceptance
54
- attributes:
55
- label: Acceptance criteria
56
- description: A checklist a reviewer can verify when this is done (include the tests).
57
- placeholder: |
58
- - [ ] ...
59
- - [ ] Tests
60
- validations:
61
- required: false
62
- - type: textarea
63
- id: open-questions
64
- attributes:
65
- label: Open questions
66
- description: Decisions a maintainer must make before this can be planned. Leave blank if none.
67
- validations:
68
- required: false
69
- - type: textarea
70
- id: related
71
- attributes:
72
- label: Related links
73
- description: Links to related issues, PRs, discussions, or docs. Leave blank if none.
74
- validations:
75
- required: false
1
+ name: Feature request
2
+ description: Propose a small improvement or new capability
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ This template is for small, well-scoped improvements a focused
9
+ enhancement, a missing convenience, a quality-of-life fix.
10
+
11
+ For large features, architecture changes, or cross-cutting work,
12
+ open a planning issue or an ADR instead.
13
+
14
+ Do **not** include real secrets or production data use placeholders.
15
+ - type: dropdown
16
+ id: scope
17
+ attributes:
18
+ label: Scope
19
+ description: How big is this change? If it doesn't fit Small or Medium, use a planning issue instead.
20
+ options:
21
+ - Small a single file or component, no refactoring
22
+ - Medium touches a few files or a feature area, may need minor refactoring
23
+ validations:
24
+ required: true
25
+ - type: textarea
26
+ id: current-behavior
27
+ attributes:
28
+ label: Current behavior
29
+ description: How does it work today? Describe the existing behavior or limitation.
30
+ validations:
31
+ required: true
32
+ - type: textarea
33
+ id: problem
34
+ attributes:
35
+ label: Problem / motivation
36
+ description: What user or business need does this address? Why is the current behavior a problem?
37
+ validations:
38
+ required: true
39
+ - type: textarea
40
+ id: proposal
41
+ attributes:
42
+ label: Proposed solution
43
+ description: What would you like to happen?
44
+ validations:
45
+ required: true
46
+ - type: textarea
47
+ id: alternatives
48
+ attributes:
49
+ label: Alternatives considered
50
+ validations:
51
+ required: false
52
+ - type: textarea
53
+ id: acceptance
54
+ attributes:
55
+ label: Acceptance criteria
56
+ description: A checklist a reviewer can verify when this is done (include the tests).
57
+ placeholder: |
58
+ - [ ] ...
59
+ - [ ] Tests
60
+ validations:
61
+ required: false
62
+ - type: textarea
63
+ id: open-questions
64
+ attributes:
65
+ label: Open questions
66
+ description: Decisions a maintainer must make before this can be planned. Leave blank if none.
67
+ validations:
68
+ required: false
69
+ - type: textarea
70
+ id: related
71
+ attributes:
72
+ label: Related links
73
+ description: Links to related issues, PRs, discussions, or docs. Leave blank if none.
74
+ validations:
75
+ required: false
@@ -43,15 +43,18 @@ env:
43
43
  REFINE_ATTEMPT_MARKER: "<!-- agent-refine-attempt -->"
44
44
  MAX_ATTEMPTS: "5"
45
45
  PARK_AT_ATTEMPT: "4"
46
- # The size gate. An issue over either limit is refused before any model runs: a real
47
- # one, Pliny-Bot #305 (13,398 chars, 92 work units), burned a full agent -- 17 minutes,
48
- # 2.4M tokens -- and died at the provider's 32K output cap with zero outcome, twice.
49
- # Both numbers are measured before the agent starts, so refusal is deterministic and
50
- # costs ten seconds instead of half an hour. The audit files under its own AUDIT_MAX_*,
51
- # which must stay below these or refine refuses what it files.
52
- REFINE_MAX_BODY_CHARS: "8000"
53
- REFINE_MAX_WORK_UNITS: "24"
54
- REFUSE_MARKER: "<!-- agent-refine-refused -->"
46
+ # No size gate. Refine and implement consume the issue identically (load-issue-context ->
47
+ # ISSUE_CONTEXT_PATH JSON, read in the prompt), so there is no reason to gate one on the
48
+ # issue's size and not the other. The failure the gate once existed for -- Pliny-Bot #305,
49
+ # 13,398 chars, the model writing one giant refined body and dying at the provider's 32K
50
+ # single-response cap -- is bounded on the OUTPUT side by the split mechanism
51
+ # (estimate >= 8 -> write <= MAX_SPLIT_CHILDREN small child bodies, one per turn), the
52
+ # prompt's "tighten the body" rule, and max-turns + max-ai-credits. None of that depends
53
+ # on the INPUT size. Keeping a finite limit just re-created the asymmetry that mis-routed
54
+ # Bots #1357 (a 23,388-char UX contract) to implement, which read it as nothing-to-do:
55
+ # refine refused it, so the router sent it where large issues were accepted. Removed
56
+ # entirely at 1.15.0; the measure-issue-size action stays for the audit workers, whose
57
+ # own AUDIT_MAX_* limits are about how they file, not about how refine reads.
55
58
  # Ten rather than six: the failure that prompted this took three minutes, and a slower one on a
56
59
  # worse day would fall outside a six-minute window and park for a fault that clears by itself.
57
60
  RETRY_UNDER_MINUTES: "10"
@@ -131,7 +134,7 @@ on:
131
134
  required: false
132
135
  type: string
133
136
  default: first
134
- needs: [still_open, size_guard, eligibility]
137
+ needs: [still_open, eligibility]
135
138
 
136
139
  jobs:
137
140
  # A route dispatched while the issue was open must not execute after it has been closed. The
@@ -205,99 +208,11 @@ jobs:
205
208
  exit 0
206
209
  fi
207
210
  echo "eligible=true" >> "$GITHUB_OUTPUT"
208
- # The size gate, rung 4. Measures the issue before any model starts, because an oversized
209
- # body does not fail fast on its own: it produces an agent that explores for seventeen
210
- # minutes and then dies mid-generation at the provider's response cap having written
211
- # nothing, which reads as a green run with no outcome (Pliny-Bot #305, twice). No
212
- # model, one issue read; over either limit it is a refusal, not a smaller attempt.
213
- size_guard:
211
+ reserve:
214
212
  needs: [still_open, eligibility]
215
213
  if: needs.still_open.outputs.open == 'true' && needs.eligibility.outputs.eligible == 'true'
216
214
  runs-on: agents-arc
217
215
  timeout-minutes: 5
218
- permissions:
219
- contents: read
220
- issues: read
221
- outputs:
222
- too_big: ${{ steps.measure.outputs.too-big }}
223
- reason: ${{ steps.measure.outputs.reason }}
224
- steps:
225
- - name: Checkout workflow actions
226
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
227
- with:
228
- persist-credentials: false
229
- # The rule lives in issue-size.cjs, which the audit also runs before it files, so the two
230
- # cannot drift: every audit report from 2026-09-21 on was refused here for want of it.
231
- - name: Measure the issue against the size limits
232
- id: measure
233
- uses: ./.github/actions/measure-issue-size
234
- with:
235
- token: ${{ github.token }}
236
- issue-number: ${{ inputs.issue-number }}
237
- max-body-chars: ${{ env.REFINE_MAX_BODY_CHARS }}
238
- max-work-units: ${{ env.REFINE_MAX_WORK_UNITS }}
239
- # The deterministic refusal. Runs only when the size gate tripped, so it costs one
240
- # comment and no model. The refine label stays: a human who shrinks the body and
241
- # replies re-enters rerefine through the comment route, and the classifier ignores
242
- # bot comments, so this comment cannot re-trigger the worker.
243
- refuse_big_issue:
244
- needs: [still_open, size_guard, eligibility]
245
- if: needs.still_open.outputs.open == 'true' && needs.eligibility.outputs.eligible == 'true' && needs.size_guard.outputs.too_big == 'true'
246
- runs-on: agents-arc
247
- timeout-minutes: 5
248
- permissions:
249
- contents: read
250
- issues: write
251
- steps:
252
- - name: Checkout workflow actions
253
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
254
- with:
255
- persist-credentials: false
256
- - name: Create bot token
257
- id: app-token
258
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
259
- with:
260
- client-id: ${{ secrets.BOT_APP_ID }}
261
- private-key: ${{ secrets.BOT_PRIVATE_KEY }}
262
- - name: Refuse the oversized issue
263
- uses: ./.github/actions/create-issue-comment
264
- with:
265
- token: ${{ steps.app-token.outputs.token }}
266
- issue-number: ${{ inputs.issue-number }}
267
- body: |
268
- ${{ env.REFUSE_MARKER }}
269
- This issue is too large to refine automatically: ${{ needs.size_guard.outputs.reason }}.
270
- A story this size does not fail fast; it burns a full agent run and dies mid-generation at the provider's response cap, producing nothing.
271
-
272
- Split it into smaller issues, each describing one story, or edit this body down under the limits (at most ${{ env.REFINE_MAX_BODY_CHARS }} characters and ${{ env.REFINE_MAX_WORK_UNITS }} work-unit bullets), then reply here and refinement will run again.
273
- - name: Flag the issue for a person
274
- uses: ./.github/actions/add-issue-labels
275
- with:
276
- token: ${{ steps.app-token.outputs.token }}
277
- issue-number: ${{ inputs.issue-number }}
278
- labels: review
279
- - name: Clear a stale stalled flag
280
- uses: ./.github/actions/remove-issue-labels
281
- with:
282
- token: ${{ steps.app-token.outputs.token }}
283
- issue-number: ${{ inputs.issue-number }}
284
- labels: stalled
285
- # A refusal must also release the reservation. authorize-bot-work adds bot-working
286
- # before the router dispatches, and this job is the refused run's only terminal path:
287
- # incomplete is gated off it (see there), so without this removal a refused issue
288
- # stays reserved with no run behind it -- parked, invisible, not re-triggerable until
289
- # the hourly reconcile sweep clears it hours later.
290
- - name: Release the reservation
291
- uses: ./.github/actions/remove-issue-labels
292
- with:
293
- token: ${{ steps.app-token.outputs.token }}
294
- issue-number: ${{ inputs.issue-number }}
295
- labels: ${{ env.WORKING_LABEL }}
296
- reserve:
297
- needs: [still_open, size_guard, eligibility]
298
- if: needs.still_open.outputs.open == 'true' && needs.eligibility.outputs.eligible == 'true' && needs.size_guard.outputs.too_big != 'true'
299
- runs-on: agents-arc
300
- timeout-minutes: 5
301
216
  permissions:
302
217
  contents: read
303
218
  issues: write
@@ -369,9 +284,10 @@ jobs:
369
284
  conclude:
370
285
  needs: [activation, agent, safe_outputs, validate_output]
371
286
  # `always()` is load-bearing: without it GitHub prepends `success()`, which returns false
372
- # if any needed job was skipped. If activation was skipped (Pliny-Bot #321: refuse_big_issue
373
- # skip-poisoned activation in v0.28.0), both conclude AND incomplete skipped and the refine
374
- # label never transitioned. The explicit conditions below are still the guard; `always()`
287
+ # if any needed job was skipped. The historical trigger was the size gate's refuse_big_issue
288
+ # skip-poisoning activation (Pliny-Bot #321) -- that gate is gone at 1.15.0, but a skip in
289
+ # any need still short-circuits, so `always()` plus the explicit conditions below remain
290
+ # the guard. The explicit conditions below are still the guard; `always()`
375
291
  # just prevents a skipped need from short-circuiting the whole expression.
376
292
  if: >
377
293
  always() &&
@@ -672,16 +588,10 @@ jobs:
672
588
  incomplete:
673
589
  # activation for the artifact prefix the usage read needs; validate_output for its
674
590
  # valid output, which decides whether the usage read should look for truncation at all.
675
- # size_guard because a refusal is terminal: when too_big is true, refuse_big_issue has
676
- # already spoken on the issue and no attempt, retry or park may follow. Without this
677
- # clause every refused issue also looped here -- one human-label visit produced eight
678
- # refusal comments and eight "Attempt N of 5" comments, none of which could succeed
679
- # (Pliny-Bot #322).
680
- needs: [activation, agent, safe_outputs, validate_output, size_guard, eligibility]
591
+ needs: [activation, agent, safe_outputs, validate_output, eligibility]
681
592
  if: >
682
593
  always() &&
683
594
  needs.eligibility.outputs.eligible == 'true' &&
684
- needs.size_guard.outputs.too_big != 'true' &&
685
595
  (
686
596
  needs.agent.result != 'success' ||
687
597
  needs.safe_outputs.result != 'success' ||
@@ -738,7 +648,20 @@ jobs:
738
648
  output_tokens=$(jq -r '.output_tokens // empty' usage-read/agent_usage.json 2>/dev/null || echo "")
739
649
  fi
740
650
  if [ -n "$output_tokens" ] && [ "$output_tokens" -gt 20000 ]; then
741
- echo "truncated=This attempt consumed ${output_tokens} output tokens and still produced no outcome. That is what provider output truncation looks like, not an outage: the model hit the single-response cap mid-generation and every call it was writing was lost. If this repeats, split the issue or tighten its body." >> "$GITHUB_OUTPUT"
651
+ # A run that burned tokens and produced items the validator refused is not
652
+ # truncation: the agent finished, and the validator did not recognise the
653
+ # outcome shape (Bots #1336, run 42214146974: 50926 output tokens, 2 items,
654
+ # draft marker stripped by process_safe_outputs, questions line paraphrased).
655
+ # Only call it truncation when the agent spent tokens and produced nothing.
656
+ item_count=0
657
+ if [ -f usage-read/agent_output.json ]; then
658
+ item_count=$(jq '.items | length' usage-read/agent_output.json 2>/dev/null || echo 0)
659
+ fi
660
+ if [ "$item_count" -gt 0 ]; then
661
+ echo "truncated=This attempt consumed ${output_tokens} output tokens and produced ${item_count} item(s), but the validator could not recognise the outcome. The agent finished its work: check the run artifacts (agent_output.json, safeoutputs.jsonl) against the validator's expected shape before retrying." >> "$GITHUB_OUTPUT"
662
+ else
663
+ echo "truncated=This attempt consumed ${output_tokens} output tokens and still produced no outcome. That is what provider output truncation looks like, not an outage: the model hit the single-response cap mid-generation and every call it was writing was lost. If this repeats, split the issue or tighten its body." >> "$GITHUB_OUTPUT"
664
+ fi
742
665
  else
743
666
  echo "truncated=" >> "$GITHUB_OUTPUT"
744
667
  fi
@@ -806,15 +729,16 @@ jobs:
806
729
  ${{ steps.usage.outputs.truncated }}
807
730
  [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
808
731
 
809
- # `!failure()` is load-bearing, not decoration. gh-aw adds every custom job to the agent's
810
- # `needs`, including refuse_big_issue -- a job that skips precisely when refinement should
811
- # run. Without a status function in this `if:` GitHub prepends an implicit `success()`,
812
- # and a skipped need fails it, so every under-limit issue skipped the agent in 0s and the
813
- # incomplete loop parked the issue (Pliny-Bot #320-322, 16 runs). `!failure()` suppresses
814
- # the implicit success(): a refused skip no longer poisons the agent, while any real
815
- # failure -- size_guard erroring, the refusal job erroring mid-refuse, reserve failing --
816
- # still blocks it and lands in incomplete.
817
- if: inputs.issue-number != '' && needs.still_open.outputs.open == 'true' && needs.eligibility.outputs.eligible == 'true' && needs.size_guard.outputs.too_big != 'true' && !failure()
732
+ # `!failure()` is load-bearing, not decoration. `still_open` and `eligibility` skip
733
+ # precisely when refinement should not run (issue closed, parked for review). Without a
734
+ # status function in this `if:` GitHub prepends an implicit `success()`, and a skipped
735
+ # need fails it, so every closed-or-reviewed issue skipped the agent in 0s and the
736
+ # incomplete loop parked it. `!failure()` suppresses the implicit success(): a
737
+ # skipped gate no longer poisons the agent, while any real failure -- eligibility
738
+ # erroring, reserve failing -- still blocks it and lands in incomplete. (The original
739
+ # motivation was the size gate's refuse_big_issue skip; that gate is gone at 1.15.0,
740
+ # but the same skip shape applies to still_open and eligibility, so the guard stays.)
741
+ if: inputs.issue-number != '' && needs.still_open.outputs.open == 'true' && needs.eligibility.outputs.eligible == 'true' && !failure()
818
742
 
819
743
  runs-on: agents-arc
820
744
  runs-on-slim: agents-arc
@@ -1,53 +1,53 @@
1
- ---
2
- # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/shared/platform-defaults.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
- description: Shared network and safe-output defaults for catalog agent workflows, plus the verification rules every worker that builds or pushes has to follow. The body below is runtime-imported into each worker's prompt ahead of its own steps.
4
-
5
- network:
6
- allowed:
7
- - defaults
8
- - forge.plainconcepts.com
9
- # opencode fetches its model registry from models.opencode.ai at startup; without
10
- # this host on the allowlist the fetch blocks bootstrap and the run stalls after
11
- # "init" until the runner kills it. The apex "opencode.ai" is not enough.
12
- - models.opencode.ai
13
- - node
14
- - github
15
- - dotnet
16
- - fonts
17
- - login.microsoftonline.com
18
- # centralised AgentMemory (App Service); the MCP shim needs it through the egress proxy
19
- - agentmemory-pro-01.azurewebsites.net
20
-
21
- safe-outputs:
22
- threat-detection: false
23
- ---
24
-
25
- ## These runs are not interactive
26
-
27
- - Nothing resumes you. A turn that ends with text and no tool call ends the whole run, and the work
28
- is discarded, whatever the text promised. "I'll read the context files first." as a last message
29
- is a finished run: the Pliny-Bot merge gate did exactly that on #801, ended in twenty-three
30
- seconds with exit code 0 and no outcome, and was retried twice before the pull request was handed
31
- to a person for nothing.
32
- - So every message you write carries a tool call until the last one, which is the safe-output call
33
- the task names. Say what you are about to do and do it in the same message. Never announce a step
34
- and stop, never wait for a command, a reviewer or a "next turn".
35
- - A command the bash tool reports as moved to the background is still running: poll its output file
36
- with tool calls (`sleep 40; tail -n 15 <file>`) until it shows an exit status, then go on.
37
-
38
- ## Verification, for every worker that builds or pushes
39
-
40
- - Scope every check to the files you changed. This is the runner, not a preference: a
41
- whole-repository lint, build or test run exhausts its memory and gets killed mid-run, which
42
- fails the job with no useful output. Pass the changed paths to the linter (`pnpm exec biome
43
- check <files>`), build only the projects containing them, and run only the test project that
44
- covers them. Escalate to the full suite only after the scoped run passes and only when the
45
- change crosses a project boundary.
46
- - Run nothing at all for a change that touches only documentation. A cold Release build on a
47
- shared runner is minutes the run does not get back.
48
- - Never make a check pass by weakening it: not a deleted test, not a lowered threshold, not a
49
- skipped step. Fix the cause and run it again.
50
- - Once the checks pass, run the project's lint fix command over the files you changed
51
- (`pnpm lint:fix`, `pnpm exec biome check --write <changed-files>`, or its equivalent), or
52
- correct what lint reports where no fix command exists. A branch that arrives with lint errors
53
- gets sent back for them.
1
+ ---
2
+ # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/shared/platform-defaults.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
+ description: Shared network and safe-output defaults for catalog agent workflows, plus the verification rules every worker that builds or pushes has to follow. The body below is runtime-imported into each worker's prompt ahead of its own steps.
4
+
5
+ network:
6
+ allowed:
7
+ - defaults
8
+ - forge.plainconcepts.com
9
+ # opencode fetches its model registry from models.opencode.ai at startup; without
10
+ # this host on the allowlist the fetch blocks bootstrap and the run stalls after
11
+ # "init" until the runner kills it. The apex "opencode.ai" is not enough.
12
+ - models.opencode.ai
13
+ - node
14
+ - github
15
+ - dotnet
16
+ - fonts
17
+ - login.microsoftonline.com
18
+ # centralised AgentMemory (App Service); the MCP shim needs it through the egress proxy
19
+ - agentmemory-pro-01.azurewebsites.net
20
+
21
+ safe-outputs:
22
+ threat-detection: false
23
+ ---
24
+
25
+ ## These runs are not interactive
26
+
27
+ - Nothing resumes you. A turn that ends with text and no tool call ends the whole run, and the work
28
+ is discarded, whatever the text promised. "I'll read the context files first." as a last message
29
+ is a finished run: the Pliny-Bot merge gate did exactly that on #801, ended in twenty-three
30
+ seconds with exit code 0 and no outcome, and was retried twice before the pull request was handed
31
+ to a person for nothing.
32
+ - So every message you write carries a tool call until the last one, which is the safe-output call
33
+ the task names. Say what you are about to do and do it in the same message. Never announce a step
34
+ and stop, never wait for a command, a reviewer or a "next turn".
35
+ - A command the bash tool reports as moved to the background is still running: poll its output file
36
+ with tool calls (`sleep 40; tail -n 15 <file>`) until it shows an exit status, then go on.
37
+
38
+ ## Verification, for every worker that builds or pushes
39
+
40
+ - Scope every check to the files you changed. This is the runner, not a preference: a
41
+ whole-repository lint, build or test run exhausts its memory and gets killed mid-run, which
42
+ fails the job with no useful output. Pass the changed paths to the linter (`pnpm exec biome
43
+ check <files>`), build only the projects containing them, and run only the test project that
44
+ covers them. Escalate to the full suite only after the scoped run passes and only when the
45
+ change crosses a project boundary.
46
+ - Run nothing at all for a change that touches only documentation. A cold Release build on a
47
+ shared runner is minutes the run does not get back.
48
+ - Never make a check pass by weakening it: not a deleted test, not a lowered threshold, not a
49
+ skipped step. Fix the cause and run it again.
50
+ - Once the checks pass, run the project's lint fix command over the files you changed
51
+ (`pnpm lint:fix`, `pnpm exec biome check --write <changed-files>`, or its equivalent), or
52
+ correct what lint reports where no fix command exists. A branch that arrives with lint errors
53
+ gets sent back for them.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/workflows",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "description": "Install and update Platform GitHub agentic workflows.",
5
5
  "keywords": [
6
6
  "github-actions",