@plainconceptsplatform/workflows 1.6.16 → 1.6.21

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.
@@ -1788,6 +1788,46 @@ fi
1788
1788
  # leaving a verdict or an attempt is a loop: the train cannot tell a gate that declined from a gate
1789
1789
  # that has not run. Refusals are for what the train never hands over (a fork, a stranger, a pull
1790
1790
  # request that is not open), and the train filters those itself.
1791
+ # The implement run is mostly model turns and repeated verification: Pliny-Bot #694 reached its
1792
+ # full verification at minute forty-one after six scoped runs, and #751 spent fifteen of twenty-two
1793
+ # minutes in twelve tiny worker tasks. These sentences are what keep a run near twenty minutes.
1794
+ if worker_installed implement; then
1795
+ if grep -qF 'Run them once, on the final tree.' "$IMPLEMENT_WORKER_MD" && grep -qF 'on both paths, before the commands above.' "$IMPLEMENT_WORKER_MD" && grep -qF 'Ask it for few, coarse tasks' "$IMPLEMENT_WORKER_MD" && grep -qF 'WORK IN FEW TURNS' "$IMPLEMENT_WORKER_MD"; then
1796
+ PASS=$((PASS + 1))
1797
+ else
1798
+ FAIL=$((FAIL + 1))
1799
+ echo "FAIL: the implement prompt must verify once on the final tree, ask for coarse tasks and work in few turns" >&2
1800
+ fi
1801
+ fi
1802
+ # gh-aw leaves OPENCODE_MODEL empty, so every lead ran on opencode.ci.json's one model. Each worker
1803
+ # names its own in AGENT_LEAD_MODEL, the merge step writes it onto ci-workflow-agent, and the model
1804
+ # it names, like every tier model in harness.json, has to be declared in opencode.ci.json or the
1805
+ # run dies at its first turn on "model not found".
1806
+ LEAD_OK=1
1807
+ # A consumer has it at its root; this package keeps the template beside the workflows.
1808
+ CI_JSON="${HERE}/../../../opencode.ci.json"
1809
+ [ -f "$CI_JSON" ] || CI_JSON="${HERE}/../../templates/opencode/opencode.ci.json"
1810
+ for route in refine implement triage apply-review merge-gate audit release; do
1811
+ worker_md="${WORKFLOWS_DIR}/agent-${route}.md"
1812
+ [ -f "$worker_md" ] || continue
1813
+ lead=$(sed -n 's/^ AGENT_LEAD_MODEL: "\(.*\)"$/\1/p' "$worker_md")
1814
+ if [ -z "$lead" ]; then
1815
+ LEAD_OK=0; echo "FAIL: agent-${route} names no AGENT_LEAD_MODEL, so its session runs on the cheap default" >&2; continue
1816
+ fi
1817
+ if [ -f "$CI_JSON" ] && ! jq -e --arg p "${lead%%/*}" --arg m "${lead#*/}" '.providers[$p].models[$m]' "$CI_JSON" > /dev/null; then
1818
+ LEAD_OK=0; echo "FAIL: agent-${route} leads on ${lead}, which opencode.ci.json does not declare" >&2
1819
+ fi
1820
+ done
1821
+ if [ -f "${WORKFLOWS_DIR}/agent-refine.md" ] && grep -q '^ AGENT_LEAD_MODEL: "forge/carina' "${WORKFLOWS_DIR}/agent-refine.md"; then
1822
+ LEAD_OK=0; echo "FAIL: refine must never lead on carina" >&2
1823
+ fi
1824
+ if ! grep -qF 'jq --arg model "$AGENT_LEAD_MODEL"' "${WORKFLOWS_DIR}/shared/opencode-ci.md"; then
1825
+ LEAD_OK=0; echo "FAIL: the CI config merge must write AGENT_LEAD_MODEL onto ci-workflow-agent" >&2
1826
+ fi
1827
+ if worker_installed implement && ! grep -qF 'subagent_type: planner' "$IMPLEMENT_WORKER_MD"; then
1828
+ LEAD_OK=0; echo "FAIL: the implement prompt must run propose and archive in the planner agent" >&2
1829
+ fi
1830
+ if [ "$LEAD_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
1791
1831
  # The shape of the tests reaches the agent only through these two prompts (check-diff measures size,
1792
1832
  # never shape), so losing the sentence silently brings the pyramid back.
1793
1833
  if worker_installed implement; then
@@ -2695,6 +2735,52 @@ if [ -f "$HK_YML" ] && [ -f "$TRAIN_SH_HB" ]; then
2695
2735
  echo "FAIL: the merge train has no heartbeat from housekeeping, or does not cancel a repair gate whose CI turned green" >&2
2696
2736
  fi
2697
2737
  fi
2738
+ # The implement queue was the issue's key modulo the number of queues, so three independent issues whose
2739
+ # numbers were multiples of three (Pliny-Bot #726, #750 and #694 under #690) shared queue zero and ran in
2740
+ # series behind a three-hour run. The queue is now the key's place among the keys of the issues waiting for
2741
+ # an implement, and the children of one refine still share a key.
2742
+ if grep -qF "implement-queue-" "$ROUTER_YML" 2>/dev/null; then
2743
+ if grep -qF 'place=$index' "$ROUTER_YML" && grep -qF 'queue=$(( place % queues ))' "$ROUTER_YML" && ! grep -qF 'queue=$(( key % queues ))' "$ROUTER_YML"; then
2744
+ PASS=$((PASS + 1))
2745
+ else
2746
+ FAIL=$((FAIL + 1))
2747
+ echo "FAIL: the implement queue is chosen by the issue number modulo the queue count, which puts independent issues in one queue" >&2
2748
+ fi
2749
+ fi
2750
+ # The runner VM kills any job that outlives RUNNER_JOB_TIMEOUT, whatever the workflow allows. The default
2751
+ # of 90 minutes killed three Pliny-Bot implements that the workflow had given 180: no log, no pull request.
2752
+ # The cap in cloud-init has to stay above the longest agent job, or the workflow's own timeout is decoration.
2753
+ CLOUD_INIT_YML="${HERE}/../../../runners/cloud-init.yaml"
2754
+ if [ -f "$CLOUD_INIT_YML" ] && [ -f "${WORKFLOWS_DIR}/agent-implement.md" ]; then
2755
+ cap="$(sed -n 's/^ *RUNNER_JOB_TIMEOUT=\([0-9][0-9]*\)$/\1/p' "$CLOUD_INIT_YML" | tail -1)"
2756
+ longest="$(grep -hoE '^timeout-minutes: [0-9]+' "${WORKFLOWS_DIR}"/agent-*.md | grep -oE '[0-9]+' | sort -n | tail -1)"
2757
+ if [ -n "$cap" ] && [ -n "$longest" ] && [ "$cap" -gt $((longest * 60)) ]; then
2758
+ PASS=$((PASS + 1))
2759
+ else
2760
+ FAIL=$((FAIL + 1))
2761
+ echo "FAIL: the runner job cap (${cap:-unset} s in cloud-init.yaml) is not above the longest agent timeout (${longest:-?} min); a long agent job would be killed by the VM" >&2
2762
+ fi
2763
+ fi
2764
+ # decide-agent-retry reads why an agent job died from the job's annotations, and the annotations API needs
2765
+ # `checks: read`. Without it the read fails quietly (`2>/dev/null || true`), a runner shut down mid-job
2766
+ # (exit code 143) reads as no cause, and the issue is parked for a person instead of being run again:
2767
+ # Pliny-Bot #750 died at 44 minutes with exactly that annotation and was flagged for review.
2768
+ RETRY_PERM_OK=1
2769
+ for worker in "${WORKFLOWS_DIR}"/agent-*.md; do
2770
+ [ -f "$worker" ] || continue
2771
+ grep -q "decide-agent-retry" "$worker" || continue
2772
+ missing="$(awk '
2773
+ function flush() { if (job != "" && uses && !checks) printf "%s ", job }
2774
+ /^ [a-z_]+:$/ { flush(); job = $1; uses = 0; checks = 0; next }
2775
+ /decide-agent-retry/ { uses = 1 }
2776
+ /^ checks: read$/ { checks = 1 }
2777
+ END { flush() }' "$worker")"
2778
+ if [ -n "${missing// /}" ]; then
2779
+ RETRY_PERM_OK=0
2780
+ echo "FAIL: ${worker##*/}: job(s) ${missing}use decide-agent-retry without checks: read, so a runner shutdown reads as no cause" >&2
2781
+ fi
2782
+ done
2783
+ if [ "$RETRY_PERM_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2698
2784
  # The implement prompt tells the agent it is already on its branch and to skip the pc-plan-goal
2699
2785
  # branching phase. That is only true if a step before the agent made the branch, and nothing in the
2700
2786
  # sandbox can do it later: no git credentials, and the prompt forbids the commands. Without the
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://opencode.ai/config.json",
3
- "model": "forge/glm-5-2",
3
+ "model": "forge/carina-60b",
4
4
  "default_agent": "ci-workflow-agent",
5
5
  "agents": {
6
6
  "ci-workflow-agent": {
@@ -44,7 +44,61 @@
44
44
  "apiKey": "{env:OPENAI_API_KEY}"
45
45
  },
46
46
  "models": {
47
+ "carina-60b": {
48
+ "name": "Carina 60B",
49
+ "capabilities": {
50
+ "tools": true,
51
+ "input": [
52
+ "text",
53
+ "image"
54
+ ],
55
+ "output": [
56
+ "text"
57
+ ]
58
+ },
59
+ "limit": {
60
+ "context": 1048576,
61
+ "input": 1048576,
62
+ "output": 131072
63
+ }
64
+ },
65
+ "quasar-438b": {
66
+ "name": "Quasar 438B",
67
+ "capabilities": {
68
+ "tools": true,
69
+ "input": [
70
+ "text",
71
+ "image"
72
+ ],
73
+ "output": [
74
+ "text"
75
+ ]
76
+ },
77
+ "limit": {
78
+ "context": 1048576,
79
+ "input": 1048576,
80
+ "output": 131072
81
+ }
82
+ },
47
83
  "glm-5-2": {
84
+ "name": "GLM 5.2",
85
+ "capabilities": {
86
+ "tools": true,
87
+ "input": [
88
+ "text",
89
+ "image"
90
+ ],
91
+ "output": [
92
+ "text"
93
+ ]
94
+ },
95
+ "limit": {
96
+ "context": 1048576,
97
+ "input": 1048576,
98
+ "output": 131072
99
+ }
100
+ },
101
+ "glm-5-3": {
48
102
  "name": "GLM 5.3",
49
103
  "capabilities": {
50
104
  "tools": true,
@@ -61,8 +115,53 @@
61
115
  "input": 1048576,
62
116
  "output": 131072
63
117
  }
118
+ }
119
+ }
120
+ },
121
+ "plainconcepts": {
122
+ "package": "aisdk:@ai-sdk/openai-compatible",
123
+ "settings": {
124
+ "baseURL": "{env:OPENAI_BASE_URL}",
125
+ "apiKey": "{env:OPENAI_API_KEY}"
126
+ },
127
+ "models": {
128
+ "carina-60b": {
129
+ "name": "Carina 60B",
130
+ "capabilities": {
131
+ "tools": true,
132
+ "input": [
133
+ "text",
134
+ "image"
135
+ ],
136
+ "output": [
137
+ "text"
138
+ ]
139
+ },
140
+ "limit": {
141
+ "context": 1048576,
142
+ "input": 1048576,
143
+ "output": 131072
144
+ }
64
145
  },
65
146
  "quasar-438b": {
147
+ "name": "Quasar 438B",
148
+ "capabilities": {
149
+ "tools": true,
150
+ "input": [
151
+ "text",
152
+ "image"
153
+ ],
154
+ "output": [
155
+ "text"
156
+ ]
157
+ },
158
+ "limit": {
159
+ "context": 1048576,
160
+ "input": 1048576,
161
+ "output": 131072
162
+ }
163
+ },
164
+ "glm-5-2": {
66
165
  "name": "GLM 5.2",
67
166
  "capabilities": {
68
167
  "tools": true,
@@ -79,6 +178,24 @@
79
178
  "input": 1048576,
80
179
  "output": 131072
81
180
  }
181
+ },
182
+ "glm-5-3": {
183
+ "name": "GLM 5.3",
184
+ "capabilities": {
185
+ "tools": true,
186
+ "input": [
187
+ "text",
188
+ "image"
189
+ ],
190
+ "output": [
191
+ "text"
192
+ ]
193
+ },
194
+ "limit": {
195
+ "context": 1048576,
196
+ "input": 1048576,
197
+ "output": 131072
198
+ }
82
199
  }
83
200
  }
84
201
  }
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-apply-review.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/quasar-438b"
4
9
  # Printed by the prompt as the verification block. Consumers set their own commands.
5
10
  VERIFY_COMMANDS: ""
6
11
  REPO_RULES: "Apply only actionable outstanding reviewer feedback to the selected bot pull request. Make minimal changes that address each comment. Preserve architecture and do not weaken tests. Run full verification after changes."
@@ -307,6 +312,10 @@ jobs:
307
312
  issues: write
308
313
  # the retry re-enters through the router, which is a workflow_dispatch
309
314
  actions: write
315
+ # decide-agent-retry reads why the agent job died from its annotations, and the annotations API needs this scope.
316
+ # Without it the read fails quietly, a runner shut down mid-job (exit code 143) reads as no cause,
317
+ # and the issue is parked for a person instead of being run again (Pliny-Bot #750).
318
+ checks: read
310
319
  steps:
311
320
  - name: Checkout workflow actions
312
321
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -402,7 +411,7 @@ engine:
402
411
  env:
403
412
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
404
413
 
405
- model: openai/glm-5-2
414
+ model: openai/quasar-438b
406
415
 
407
416
  max-turns: 300
408
417
  max-turn-cache-misses: 3000
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-audit.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/quasar-438b"
4
9
  REPO_RULES: "Read-only repository audit. Report only reproducible, actionable defects with evidence. Do not modify files, commit, push, or run write operations."
5
10
  # Split out of REPO_RULES, which carried both the read-only discipline above and the list
6
11
  # below. All four consuming repositories had customised the list and none could touch it
@@ -67,7 +72,7 @@ engine:
67
72
  env:
68
73
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
69
74
 
70
- model: openai/glm-5-2
75
+ model: openai/quasar-438b
71
76
 
72
77
  max-turns: 300
73
78
  max-turn-cache-misses: 3000
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-implement.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/quasar-438b"
4
9
  VERIFY_COMMANDS: ""
5
10
  REPO_RULES: "Implement only the selected issue. Follow repository documentation and existing conventions. Do not weaken tests, lower coverage thresholds, or bypass checks."
6
11
  # Split out of REPO_RULES because one field asked to carry architecture, testing, coverage and
@@ -247,6 +252,10 @@ jobs:
247
252
  pull-requests: write
248
253
  # reads the agent job's log and annotations, and re-enters through the router on a retry
249
254
  actions: write
255
+ # decide-agent-retry reads why the agent job died from its annotations, and the annotations API needs this scope.
256
+ # Without it the read fails quietly, a runner shut down mid-job (exit code 143) reads as no cause,
257
+ # and the issue is parked for a person instead of being run again (Pliny-Bot #750).
258
+ checks: read
250
259
  steps:
251
260
  - name: Checkout workflow actions
252
261
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -509,6 +518,10 @@ jobs:
509
518
  issues: write
510
519
  # the retry re-enters through the router, which is a workflow_dispatch
511
520
  actions: write
521
+ # decide-agent-retry reads why the agent job died from its annotations, and the annotations API needs this scope.
522
+ # Without it the read fails quietly, a runner shut down mid-job (exit code 143) reads as no cause,
523
+ # and the issue is parked for a person instead of being run again (Pliny-Bot #750).
524
+ checks: read
512
525
  steps:
513
526
  - name: Checkout workflow actions
514
527
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -614,7 +627,7 @@ engine:
614
627
  env:
615
628
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
616
629
 
617
- model: openai/glm-5-2
630
+ model: openai/quasar-438b
618
631
 
619
632
  max-turns: 300
620
633
  max-turn-cache-misses: 3000
@@ -732,18 +745,33 @@ timeout-minutes: 180
732
745
  wrote instead:
733
746
 
734
747
  1. `pc-plan-goal`, then Phase 0 as it describes.
748
+
749
+ **Propose and archive run in the `planner` agent, not in this session.** Spawn it with the
750
+ task tool (`subagent_type: planner`) and a prompt that names the skill to load
751
+ (`pc-plan-propose` or `pc-plan-archive`), the issue context path above, the branch, and that it
752
+ runs in autonomous mode with no one to ask. `planner` runs on the repository's plan model, which
753
+ is stronger than this session's, and these two steps decide the whole change. Wait for it in the
754
+ same turn, then continue with the next phase yourself. Only when no `planner` agent exists
755
+ (agent-harness older than 3.4.0) load the skill here instead.
756
+
735
757
  2. `pc-plan-propose`, even when the issue is refined. It is what turns the issue into
736
758
  `openspec/changes/<id>/tasks.md` with every task annotated
737
759
  `<!-- agent: <engineer>.<tier>, depends_on: [...], touches: [...] -->`. **You never write
738
760
  `proposal.md` or `tasks.md` yourself.** A hand-written `tasks.md` carries no annotations,
739
761
  and without them `pc-plan-apply` has no workers to spawn, so the whole change is done by
740
762
  you alone, in sequence, on one model. That is the failure this step exists to prevent.
763
+ Ask it for few, coarse tasks: one task per area of files, the tests for that code in the
764
+ same task, and no task whose only job is to repair what an earlier task broke. Five tasks
765
+ in three waves cover most issues. Every task is a fresh worker that rereads the code it
766
+ needs before it edits anything, one to three minutes each: Pliny-Bot #751 split a small
767
+ web feature into twelve tasks and spent fifteen of its twenty-two minutes in them, and
768
+ #696 ended with a twelve-minute task that fixed the test doubles the earlier tasks broke.
741
769
  3. `pc-plan-apply`. The tasks are implemented by the subagents it spawns, in waves, each on
742
770
  the model tier its annotation names. **In this phase you do not edit source files
743
771
  yourself.** If it stops because a worker cannot be resolved, report that with
744
772
  `report_incomplete`, naming the task and the missing worker; do not do the task yourself
745
773
  to get past it.
746
- 4. `pc-repo-verify`, then `pc-plan-archive`, as `pc-plan-goal` directs.
774
+ 4. `pc-repo-verify`, then `pc-plan-archive` in `planner`, as `pc-plan-goal` directs.
747
775
 
748
776
  Before the first edit to a source file, check that
749
777
  `openspec/changes/<id>/tasks.md` exists and that its tasks carry the annotation above. If it
@@ -767,6 +795,12 @@ timeout-minutes: 180
767
795
  Adhere to ${{ env.REPO_RULES }}, ${{ env.ARCHITECTURE_RULES }} and
768
796
  ${{ env.TESTING_RULES }}.
769
797
 
798
+ **WORK IN FEW TURNS**, on both paths. Every turn is a model call of three to twenty
799
+ seconds, and the turns, not the commands, are most of a run. Read a file whole, or in
800
+ ranges of a few hundred lines, once; never eight or fifteen lines at a time. Put
801
+ independent reads and searches in the same turn. Leave whitespace and line endings to the
802
+ formatter instead of inspecting them with `hexdump` or `cat -A`.
803
+
770
804
  **DECISIVE IMPLEMENTATION**, on both paths. When a design choice is ambiguous, pick the most
771
805
  standard interpretation and implement it immediately. Do not deliberate between options for
772
806
  more than one turn. Do not ask clarifying questions the issue author expects you to use good
@@ -781,6 +815,21 @@ timeout-minutes: 180
781
815
 
782
816
  Never open a pull request that does not pass them.
783
817
 
818
+ **Run them once, on the final tree.** They are slow: Pliny-Bot's `pnpm verify` is about
819
+ twenty minutes of work on this runner. `pc-plan-apply` runs them in its verify step, and
820
+ that run is this one: do not run them again when nothing changed since. Order the end of
821
+ the run so the last run is the only one: first `check-diff` below, which takes seconds, and
822
+ fix what it lists; then these commands. While you work, check with the narrowest command
823
+ that covers what you changed (build the project you edited, run the test files you
824
+ edited, typecheck the web app), not with these. Pliny-Bot #694 ran three typechecks and
825
+ three test runs of its own before it reached the full verification at minute forty-one.
826
+
827
+ A test that cannot start in this sandbox (it needs Docker, a database or a host the
828
+ firewall blocks) and fails the same way on the default branch is not yours to fix: say so
829
+ in the pull request and move on, CI runs it with the service. Pliny-Bot #696 spent its
830
+ turns on 365 integration tests that could not start here because Testcontainers found an
831
+ empty Docker configuration.
832
+
784
833
  **Run every command in the foreground and wait for it in the same turn. Never move a command
785
834
  to the background and never end a turn to wait for it.** This run is not interactive: nothing
786
835
  resumes you. A turn that ends with text and no tool call ends the whole run, and the work is
@@ -803,7 +852,7 @@ timeout-minutes: 180
803
852
 
804
853
  When `.opencode/scripts/check-diff.mjs` exists, also run
805
854
  `node .opencode/scripts/check-diff.mjs`
806
- on both paths. It must exit 0. It holds the comments and tests you add to the size of the
855
+ on both paths, before the commands above. It must exit 0. It holds the comments and tests you add to the size of the
807
856
  change and makes you clean the files you touched; fix every line it lists. The merge gate
808
857
  runs it again and does not merge while it fails.
809
858
 
@@ -812,8 +861,9 @@ timeout-minutes: 180
812
861
  unit test only for logic with real branching. A bug fix gets one regression test. Do not
813
862
  write tests of constants, configured defaults, mocks of your own code or markup attributes.
814
863
 
815
- Anything you change to satisfy `check-diff` is a change: run the verification commands
816
- again afterwards, and open the pull request only from a tree where both pass. Do not delete
864
+ Anything you change to satisfy `check-diff` is a change: run it again, and run the
865
+ verification commands only after it passes, so they run on the tree you ship. Open the
866
+ pull request only from a tree where both pass. Do not delete
817
867
  a test that covers a branch you added to fit the budget; the complexity gate in CI measures
818
868
  that coverage.
819
869
 
@@ -1,6 +1,11 @@
1
1
  ---
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
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/quasar-438b"
4
9
  VERIFY_COMMANDS: ""
5
10
  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
11
  # Where to look first, not what to escalate on. This list used to be the check that decided
@@ -870,7 +875,7 @@ engine:
870
875
  env:
871
876
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
872
877
 
873
- model: openai/glm-5-2
878
+ model: openai/quasar-438b
874
879
 
875
880
  max-turns: 300
876
881
  max-turn-cache-misses: 3000
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-refine.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/glm-5-3"
4
9
  REPO_RULES: "Refine only the selected issue into a grounded, implementation-ready user story. Read repository documentation for domain context. Write acceptance criteria that match existing patterns. Where a story or its open questions decide how business data (named people, roles, addresses) is stored, resolve it toward the repository's convention for that data -- a database entity or a settings entry -- and record that choice in the acceptance criteria; do not carry a person's name or email address into the story as something the code reads from a constant. Do not implement code. Do not use web search or web fetch tools. The issue body already contains the research that motivated it; derive your domain context from the repository's own code and documentation only."
5
10
  # The estimate decides whether a story gets split, and the prompt tells the agent these bands
6
11
  # come from this repository's own merged pull requests. They have to actually come from it, or
@@ -672,6 +677,10 @@ jobs:
672
677
  issues: write
673
678
  # the retry re-enters through the router, which is a workflow_dispatch
674
679
  actions: write
680
+ # decide-agent-retry reads why the agent job died from its annotations, and the annotations API needs this scope.
681
+ # Without it the read fails quietly, a runner shut down mid-job (exit code 143) reads as no cause,
682
+ # and the issue is parked for a person instead of being run again (Pliny-Bot #750).
683
+ checks: read
675
684
  steps:
676
685
  - name: Checkout workflow actions
677
686
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -803,7 +812,7 @@ engine:
803
812
  env:
804
813
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
805
814
 
806
- model: openai/glm-5-2
815
+ model: openai/glm-5-3
807
816
  # 150 rather than 500. With a four-hour clock this is the loop guard, and the worst
808
817
  # observed run used 44 turns, so this leaves better than three times the worst case.
809
818
  max-turns: 150
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-release.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/quasar-438b"
4
9
  GIT_AUTHOR_NAME: "github-actions[bot]"
5
10
  GIT_AUTHOR_EMAIL: "github-actions[bot]@users.noreply.github.com"
6
11
  GIT_COMMITTER_NAME: "github-actions[bot]"
@@ -42,7 +47,7 @@ engine:
42
47
  env:
43
48
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
44
49
 
45
- model: openai/glm-5-2
50
+ model: openai/quasar-438b
46
51
 
47
52
  max-turns: 100
48
53
  max-turn-cache-misses: 3000
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  # Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-triage.md. Update with `workflows update --force`; consumer edits may be overwritten.
3
3
  env:
4
+ # The model this worker's own session runs on. opencode.ci.json's `model` is the cheap default
5
+ # every agent without its own model falls back to; the lead is where a wrong call costs a run,
6
+ # so it names its model here. `model:` below only satisfies the compiler. A repository may
7
+ # change it to any model its opencode.ci.json declares.
8
+ AGENT_LEAD_MODEL: "forge/quasar-438b"
4
9
  REPO_RULES: "Triage issues opened by outside collaborators. Assess template completeness, security risk, change size, danger level, duplicates, clarity, reproducibility, acceptance criteria, and cross-cutting impact. When the request names specific people, email addresses, or business entities as the thing the code acts on, judge where that data is meant to live: business data that belongs in the database or a settings page is a design decision, not a wording detail, and it must not be left for the implementer to decide by hardcoding it. Do not implement code. Do not modify the issue body."
5
10
  # What a product owner may ask for, and what has to become a maintainer-owned technical
6
11
  # proposal instead. This is business policy, so it belongs to the repository rather than to
@@ -314,6 +319,10 @@ jobs:
314
319
  issues: write
315
320
  # the retry re-enters through the router, which is a workflow_dispatch
316
321
  actions: write
322
+ # decide-agent-retry reads why the agent job died from its annotations, and the annotations API needs this scope.
323
+ # Without it the read fails quietly, a runner shut down mid-job (exit code 143) reads as no cause,
324
+ # and the issue is parked for a person instead of being run again (Pliny-Bot #750).
325
+ checks: read
317
326
  steps:
318
327
  - name: Checkout workflow actions
319
328
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -408,7 +417,7 @@ engine:
408
417
  env:
409
418
  OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
410
419
 
411
- model: openai/glm-5-2
420
+ model: openai/quasar-438b
412
421
  max-turns: 120
413
422
  max-turn-cache-misses: 3000
414
423
  max-ai-credits: 5000
@@ -195,6 +195,12 @@ pre-agent-steps:
195
195
  merged=$(jq -S . "$FRAGMENT")
196
196
  fi
197
197
 
198
+ # The worker's lead model, from its env. gh-aw leaves OPENCODE_MODEL empty, so without this
199
+ # every worker's session would run on opencode.ci.json's default.
200
+ if [ -n "${AGENT_LEAD_MODEL:-}" ]; then
201
+ merged=$(printf '%s' "$merged" | jq --arg model "$AGENT_LEAD_MODEL" '.agents["ci-workflow-agent"].model = $model')
202
+ fi
203
+
198
204
  printf '%s\n' "$merged" > "$CONFIG"
199
205
 
200
206
  # A tracked config now differs from HEAD, so the agent sees it in `git diff`, takes it for
@@ -210,5 +216,5 @@ pre-agent-steps:
210
216
  # `$existing * $base`. Base wins on conflicting keys, but it defines neither `model`
211
217
  # nor this provider, so both survive and `awf-proxy` is added alongside.
212
218
  echo "Wrote $CONFIG from $FRAGMENT:"
213
- jq -r '" model: \(.model // "unset")", " plugins: \(.plugins // [] | join(", "))", " providers: \(.providers // {} | keys | join(", "))"' "$CONFIG"
219
+ jq -r '" model: \(.model // "unset")", " lead: \(.agents["ci-workflow-agent"].model // "the default")", " plugins: \(.plugins // [] | join(", "))", " providers: \(.providers // {} | keys | join(", "))"' "$CONFIG"
214
220
  ---
@@ -551,9 +551,29 @@ jobs:
551
551
  body=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json body --jq '.body // ""' 2>/dev/null || echo '')
552
552
  parent=$(printf '%s' "$body" | grep -oE '<!-- split-parent: [0-9]+ -->' | head -1 | grep -oE '[0-9]+' || true)
553
553
  key="${parent:-$ISSUE_NUMBER}"
554
- queue=$(( key % queues ))
554
+
555
+ # The queue is the key's place among the keys of every issue waiting for an implement, not
556
+ # the key modulo the number of queues. Three independent issues whose numbers were all
557
+ # multiples of three (Pliny-Bot #726, #750 and #694, whose parent is #690) landed in queue
558
+ # zero together and ran one after another behind a three-hour run while two queues sat
559
+ # empty. A place among the waiting keys puts independent issues in different queues, and
560
+ # the children of one refine, which share a key, still share one.
561
+ waiting=$(
562
+ { printf '%s\n' "$key"
563
+ gh issue list --repo "$REPO" --label "implement" --state open --limit 100 --json number,body \
564
+ --jq '.[] | ((.body // "") | capture("<!-- split-parent: (?<p>[0-9]+) -->").p) // (.number | tostring)' \
565
+ 2>/dev/null || true
566
+ } | grep -E '^[0-9]+$' | sort -un
567
+ )
568
+ place=0
569
+ index=0
570
+ for candidate in $waiting; do
571
+ [ "$candidate" = "$key" ] && place=$index
572
+ index=$((index + 1))
573
+ done
574
+ queue=$(( place % queues ))
555
575
  echo "queue=$queue" >> "$GITHUB_OUTPUT"
556
- echo "#$ISSUE_NUMBER waits in implement queue $queue of $queues (keyed on #$key)."
576
+ echo "#$ISSUE_NUMBER waits in implement queue $queue of $queues (keyed on #$key, place $place among $index waiting)."
557
577
  - name: Resolve the feature branch from the stack markers
558
578
  id: stack
559
579
  env:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/workflows",
3
- "version": "1.6.16",
3
+ "version": "1.6.21",
4
4
  "description": "Install and update Platform GitHub agentic workflows.",
5
5
  "keywords": [
6
6
  "github-actions",