@plainconceptsplatform/workflows 0.28.0 → 0.28.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.
@@ -2114,6 +2114,49 @@ if worker_installed implement; then
2114
2114
  if [ "$ENDINGS_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2115
2115
  fi
2116
2116
 
2117
+ echo "── Refine size gate ──────────────────────────────────────────────────────"
2118
+
2119
+ # The size gate added a job that skips in the happy path, and gh-aw adds every custom job to
2120
+ # the agent's needs. Three claims about that shape are asserted, because each one broke in
2121
+ # production in the same week (Pliny-Bot #320-322: sixteen runs, three parked issues, a
2122
+ # refusal loop on an issue the author was shrinking live):
2123
+ #
2124
+ # 1. the agent's gate carries !failure(), so a skipped refusal no longer poisons the
2125
+ # implicit success() and kills the agent in 0s
2126
+ # 2. the incomplete job excludes the refusal, so a refused issue is terminal: no attempt
2127
+ # counter, no x/5, no re-dispatch, no stalled
2128
+ # 3. the refusal itself releases bot-working, so a refused issue is not left reserved
2129
+ if worker_installed refine; then
2130
+ SIZE_GATE_OK=1
2131
+ REFINE_WORKER_MD="${WORKFLOWS_DIR}/agent-refine.md"
2132
+
2133
+ # The top-level if: starts at column 0 -- job-level ifs: are indented -- so anchor on that,
2134
+ # not on the prose comment above it. It must end with !failure().
2135
+ top_level_if="$(sed -n 's/^if: //p' "$REFINE_WORKER_MD" | head -1)"
2136
+ if [[ "$top_level_if" != *'!failure()' ]]; then
2137
+ SIZE_GATE_OK=0
2138
+ echo "FAIL: refine gates the agent without !failure(); a skipped refuse_big_issue poisons the implicit success() and skips the agent on every under-limit issue" >&2
2139
+ fi
2140
+
2141
+ # Extract the incomplete job's own block. A whole-file grep cannot make this claim: reserve,
2142
+ # refuse_big_issue and the agent gate all read size_guard, so the exclusion clause could be
2143
+ # deleted from incomplete while every grep still passes.
2144
+ incomplete_block="$(awk '/^ incomplete:/{found=1; next} found && /^ [a-z_]+:/{exit} found{print}' "$REFINE_WORKER_MD")"
2145
+ if ! printf '%s' "$incomplete_block" | grep -qE '^ needs: \[.*size_guard' \
2146
+ || ! printf '%s' "$incomplete_block" | grep -qF "needs.size_guard.outputs.too_big != 'true'"; then
2147
+ SIZE_GATE_OK=0
2148
+ echo "FAIL: refine's incomplete does not exclude the refusal path; every refused issue also loops attempts" >&2
2149
+ fi
2150
+
2151
+ refuse_block="$(awk '/^ refuse_big_issue:/{found=1; next} found && /^ [a-z_]+:/{exit} found{print}' "$REFINE_WORKER_MD")"
2152
+ if ! printf '%s' "$refuse_block" | grep -qF 'WORKING_LABEL'; then
2153
+ SIZE_GATE_OK=0
2154
+ echo "FAIL: the refine refusal never releases bot-working; a refused issue stays reserved with no run behind it" >&2
2155
+ fi
2156
+
2157
+ if [ "$SIZE_GATE_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2158
+ fi
2159
+
2117
2160
  echo "── Runner pools ──────────────────────────────────────────────────────────"
2118
2161
 
2119
2162
  # Where every job runs, stated once and asserted, because GitHub gives a wrong pool no error: a
@@ -229,6 +229,17 @@ jobs:
229
229
  token: ${{ steps.app-token.outputs.token }}
230
230
  issue-number: ${{ inputs.issue-number }}
231
231
  labels: stalled
232
+ # A refusal must also release the reservation. authorize-bot-work adds bot-working
233
+ # before the router dispatches, and this job is the refused run's only terminal path:
234
+ # incomplete is gated off it (see there), so without this removal a refused issue
235
+ # stays reserved with no run behind it -- parked, invisible, not re-triggerable until
236
+ # the hourly reconcile sweep clears it hours later.
237
+ - name: Release the reservation
238
+ uses: ./.github/actions/remove-issue-labels
239
+ with:
240
+ token: ${{ steps.app-token.outputs.token }}
241
+ issue-number: ${{ inputs.issue-number }}
242
+ labels: ${{ env.WORKING_LABEL }}
232
243
  reserve:
233
244
  needs: [still_open, size_guard]
234
245
  if: needs.still_open.outputs.open == 'true' && needs.size_guard.outputs.too_big != 'true'
@@ -475,9 +486,15 @@ jobs:
475
486
  incomplete:
476
487
  # activation for the artifact prefix the usage read needs; validate_output for its
477
488
  # valid output, which decides whether the usage read should look for truncation at all.
478
- needs: [activation, agent, safe_outputs, validate_output]
489
+ # size_guard because a refusal is terminal: when too_big is true, refuse_big_issue has
490
+ # already spoken on the issue and no attempt, retry or park may follow. Without this
491
+ # clause every refused issue also looped here -- one human-label visit produced eight
492
+ # refusal comments and eight "Attempt N of 5" comments, none of which could succeed
493
+ # (Pliny-Bot #322).
494
+ needs: [activation, agent, safe_outputs, validate_output, size_guard]
479
495
  if: >
480
496
  always() &&
497
+ needs.size_guard.outputs.too_big != 'true' &&
481
498
  (
482
499
  needs.agent.result != 'success' ||
483
500
  needs.safe_outputs.result != 'success' ||
@@ -598,7 +615,15 @@ jobs:
598
615
  ${{ steps.usage.outputs.truncated }}
599
616
  [View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
600
617
 
601
- if: inputs.issue-number != '' && needs.still_open.outputs.open == 'true' && needs.size_guard.outputs.too_big != 'true'
618
+ # `!failure()` is load-bearing, not decoration. gh-aw adds every custom job to the agent's
619
+ # `needs`, including refuse_big_issue -- a job that skips precisely when refinement should
620
+ # run. Without a status function in this `if:` GitHub prepends an implicit `success()`,
621
+ # and a skipped need fails it, so every under-limit issue skipped the agent in 0s and the
622
+ # incomplete loop parked the issue (Pliny-Bot #320-322, 16 runs). `!failure()` suppresses
623
+ # the implicit success(): a refused skip no longer poisons the agent, while any real
624
+ # failure -- size_guard erroring, the refusal job erroring mid-refuse, reserve failing --
625
+ # still blocks it and lands in incomplete.
626
+ if: inputs.issue-number != '' && needs.still_open.outputs.open == 'true' && needs.size_guard.outputs.too_big != 'true' && !failure()
602
627
 
603
628
  runs-on: agents-arc
604
629
  runs-on-slim: agents-arc
@@ -753,16 +778,16 @@ timeout-minutes: 90
753
778
  The visible line is for people and the marker is read by the workflow, which turns it into the
754
779
  `sp-N` label. A body without the marker gets no estimate label at all.
755
780
 
756
- 7. **One safe-output call per turn.** Never batch multiple safe-output calls into a single
757
- message: `update_issue`, `create_issue` and `add_comment` each go in their own turn, with
758
- nothing else in the message. The provider caps one response at a fixed size, and a batch of
759
- large calls is truncated mid-JSON before any of them executes, ending the run green with
760
- nothing written. On the split path, sequence `create_issue` → `create_issue` → … →
761
- `update_issue` → `add_comment`, one per turn. If a single body is so large it approaches the
762
- size of a very long message, tighten the body; a shorter call that lands beats a longer one
763
- that is cut off.
781
+ 7. **One safe-output call per turn.** Never batch multiple safe-output calls into a single
782
+ message: `update_issue`, `create_issue` and `add_comment` each go in their own turn, with
783
+ nothing else in the message. The provider caps one response at a fixed size, and a batch of
784
+ large calls is truncated mid-JSON before any of them executes, ending the run green with
785
+ nothing written. On the split path, sequence `create_issue` → `create_issue` → … →
786
+ `update_issue` → `add_comment`, one per turn. If a single body is so large it approaches the
787
+ size of a very long message, tighten the body; a shorter call that lands beats a longer one
788
+ that is cut off.
764
789
 
765
- 8. Decide exactly one outcome:
790
+ 8. Decide exactly one outcome:
766
791
 
767
792
  Labels are workflow-owned state. Do not call `add_labels` or `remove_labels`.
768
793
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/workflows",
3
- "version": "0.28.0",
3
+ "version": "0.28.1",
4
4
  "description": "Install and update Platform GitHub agentic workflows.",
5
5
  "keywords": [
6
6
  "github-actions",