@plainconceptsplatform/workflows 1.14.1 → 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 (34) 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 +13 -1
  19. package/loops/actions/validate-review-output/action.yml +35 -35
  20. package/loops/actions/validate-triage-output/action.yml +36 -36
  21. package/loops/actions/verify-composite-actions/action.yml +9 -9
  22. package/loops/actions/verify-refine-output/action.yml +9 -9
  23. package/loops/actions/verify-refine-output/verify-refine-output.sh +4 -0
  24. package/loops/actions/verify-route-matrix/action.yml +9 -9
  25. package/loops/actions/verify-route-matrix/verify-route-matrix.sh +32 -46
  26. package/loops/templates/agentics/agentics-maintenance.yml +121 -121
  27. package/loops/templates/issues/bug_report.yml +109 -109
  28. package/loops/templates/issues/feature_request.yml +75 -75
  29. package/loops/workflows/agent-refine.md +29 -118
  30. package/loops/workflows/shared/platform-defaults.md +53 -53
  31. package/package.json +1 -1
  32. package/loops/actions/report-workflow-errors/action.yml +0 -538
  33. package/loops/actions/report-workflow-errors/report-policy.cjs +0 -194
  34. package/loops/templates/agentics/agentics-error-report.yml +0 -101
@@ -1,37 +1,37 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/remove-issue-labels/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Remove issue labels
3
- description: Remove one or more labels from an issue or pull request.
4
- inputs:
5
- token:
6
- description: GitHub token used by github-script.
7
- required: true
8
- issue-number:
9
- description: Issue or pull request number.
10
- required: true
11
- labels:
12
- description: Labels to remove, one per line. A comma-separated list is accepted as well.
13
- required: true
14
- runs:
15
- using: composite
16
- steps:
17
- - name: Remove labels
18
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
19
- env:
20
- ISSUE_NUMBER: ${{ inputs.issue-number }}
21
- LABELS: ${{ inputs.labels }}
22
- with:
23
- github-token: ${{ inputs.token }}
24
- script: |
25
- // Callers wrote `labels: a,b` while this split on newlines, so one label named "a,b"
26
- // was removed: a 404, swallowed below, and neither label ever came off.
27
- for (const label of process.env.LABELS.split(/\r?\n|,/).map((label) => label.trim()).filter(Boolean)) {
28
- try {
29
- await github.rest.issues.removeLabel({
30
- ...context.repo,
31
- issue_number: Number(process.env.ISSUE_NUMBER),
32
- name: label,
33
- });
34
- } catch (error) {
35
- if (error.status !== 404) throw error;
36
- }
37
- }
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/remove-issue-labels/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Remove issue labels
3
+ description: Remove one or more labels from an issue or pull request.
4
+ inputs:
5
+ token:
6
+ description: GitHub token used by github-script.
7
+ required: true
8
+ issue-number:
9
+ description: Issue or pull request number.
10
+ required: true
11
+ labels:
12
+ description: Labels to remove, one per line. A comma-separated list is accepted as well.
13
+ required: true
14
+ runs:
15
+ using: composite
16
+ steps:
17
+ - name: Remove labels
18
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
19
+ env:
20
+ ISSUE_NUMBER: ${{ inputs.issue-number }}
21
+ LABELS: ${{ inputs.labels }}
22
+ with:
23
+ github-token: ${{ inputs.token }}
24
+ script: |
25
+ // Callers wrote `labels: a,b` while this split on newlines, so one label named "a,b"
26
+ // was removed: a 404, swallowed below, and neither label ever came off.
27
+ for (const label of process.env.LABELS.split(/\r?\n|,/).map((label) => label.trim()).filter(Boolean)) {
28
+ try {
29
+ await github.rest.issues.removeLabel({
30
+ ...context.repo,
31
+ issue_number: Number(process.env.ISSUE_NUMBER),
32
+ name: label,
33
+ });
34
+ } catch (error) {
35
+ if (error.status !== 404) throw error;
36
+ }
37
+ }
@@ -1,58 +1,58 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/update-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Update agent issues
3
- description: Apply every update_issue item from agent_output.json.
4
- inputs:
5
- output-file:
6
- description: Path to agent_output.json.
7
- required: true
8
- token:
9
- description: GitHub token with issues:write.
10
- required: true
11
- fallback-issue-number:
12
- description: Issue an item targets when it names none.
13
- required: false
14
- default: ''
15
- runs:
16
- using: composite
17
- steps:
18
- - name: Update issues
19
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
20
- env:
21
- AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
22
- OUTPUT_FILE: ${{ inputs.output-file }}
23
- FALLBACK_ISSUE_NUMBER: ${{ inputs.fallback-issue-number }}
24
- with:
25
- github-token: ${{ inputs.token }}
26
- script: |
27
- const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
28
- const items = readAgentItems(process.env.OUTPUT_FILE, 'update_issue');
29
-
30
- let updated = 0;
31
-
32
- for (const item of items) {
33
- const target = item.item_number ?? process.env.FALLBACK_ISSUE_NUMBER;
34
-
35
- if (!target) {
36
- core.warning(`update_issue item has no item_number and no fallback, skipping: ${JSON.stringify(item)}`);
37
- continue;
38
- }
39
-
40
- const changes = {};
41
- if (item.title) changes.title = item.title;
42
- if (item.body) changes.body = item.body;
43
-
44
- if (Object.keys(changes).length === 0) {
45
- core.warning(`update_issue item changes nothing, skipping: ${JSON.stringify(item)}`);
46
- continue;
47
- }
48
-
49
- await github.rest.issues.update({
50
- ...context.repo,
51
- issue_number: Number(target),
52
- ...changes,
53
- });
54
-
55
- updated += 1;
56
- }
57
-
58
- core.info(`Updated ${updated} issue(s).`);
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/update-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Update agent issues
3
+ description: Apply every update_issue item from agent_output.json.
4
+ inputs:
5
+ output-file:
6
+ description: Path to agent_output.json.
7
+ required: true
8
+ token:
9
+ description: GitHub token with issues:write.
10
+ required: true
11
+ fallback-issue-number:
12
+ description: Issue an item targets when it names none.
13
+ required: false
14
+ default: ''
15
+ runs:
16
+ using: composite
17
+ steps:
18
+ - name: Update issues
19
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
20
+ env:
21
+ AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
22
+ OUTPUT_FILE: ${{ inputs.output-file }}
23
+ FALLBACK_ISSUE_NUMBER: ${{ inputs.fallback-issue-number }}
24
+ with:
25
+ github-token: ${{ inputs.token }}
26
+ script: |
27
+ const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
28
+ const items = readAgentItems(process.env.OUTPUT_FILE, 'update_issue');
29
+
30
+ let updated = 0;
31
+
32
+ for (const item of items) {
33
+ const target = item.item_number ?? process.env.FALLBACK_ISSUE_NUMBER;
34
+
35
+ if (!target) {
36
+ core.warning(`update_issue item has no item_number and no fallback, skipping: ${JSON.stringify(item)}`);
37
+ continue;
38
+ }
39
+
40
+ const changes = {};
41
+ if (item.title) changes.title = item.title;
42
+ if (item.body) changes.body = item.body;
43
+
44
+ if (Object.keys(changes).length === 0) {
45
+ core.warning(`update_issue item changes nothing, skipping: ${JSON.stringify(item)}`);
46
+ continue;
47
+ }
48
+
49
+ await github.rest.issues.update({
50
+ ...context.repo,
51
+ issue_number: Number(target),
52
+ ...changes,
53
+ });
54
+
55
+ updated += 1;
56
+ }
57
+
58
+ core.info(`Updated ${updated} issue(s).`);
@@ -121,6 +121,18 @@ jq -r --arg marker "$marker" --arg prefix "$comment_prefix" --arg issue "$issue_
121
121
  (.body | split($marker) | join("") | split($prefix) | join("") |
122
122
  gsub("<[^>]*>"; "") | test("[[:alnum:]]")));
123
123
 
124
+ # A completion announcement. Branch 5 (has_clarification -> questions) treats any comment
125
+ # with content as a question the agent asked, but a "Refinement complete" comment is not a
126
+ # question: paired with a draft body (which is how branch 5 is reached, via has_draft_body)
127
+ # it is a self-contradiction -- the agent said complete over a body still pending -- and the
128
+ # right outcome is invalid, not questions. Seen as a regression after has_draft_body started
129
+ # matching the pending mark when the HTML draft marker was stripped (1.15.0): the test "a body
130
+ # still pending with no questions asked is not complete" flipped from invalid to questions.
131
+ def has_completion_comment:
132
+ any(.items[]; .type == "add_comment" and (.item_number | tostring) == $issue and
133
+ (.body | type == "string") and
134
+ (.body | test("Refinement complete"; "i")));
135
+
124
136
  # Order matters: a run that wrote children is a split even though it also replaced the
125
137
  # parent body, and a lone child with no parent update is an incomplete split, not a
126
138
  # complete refinement. A body carrying the draft marker is a temporal draft, not a
@@ -140,7 +152,7 @@ jq -r --arg marker "$marker" --arg prefix "$comment_prefix" --arg issue "$issue_
140
152
  and (reported_incomplete | not) then "questions"
141
153
  elif has_replacement_body and (has_draft_body | not) and (has_pending_marks | not) and has_only_source_items then "complete"
142
154
  elif has_clarification and ((has_update | not) or has_draft_body) and has_only_source_items
143
- and (reported_incomplete | not) then "questions"
155
+ and (reported_incomplete | not) and (has_completion_comment | not) then "questions"
144
156
  else "invalid"
145
157
  end
146
158
  ' "$output_file"
@@ -1,35 +1,35 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/validate-review-output/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Validate review output
3
- description: Verify an apply-review outcome accounts for every unresolved review thread.
4
- inputs:
5
- output-file:
6
- description: Path to agent_output.json.
7
- required: true
8
- pr-number:
9
- description: Pull request receiving the review feedback.
10
- required: true
11
- review-threads-file:
12
- description: JSON file containing unresolved review threads.
13
- required: true
14
- outputs:
15
- valid:
16
- description: Whether the agent output is a valid review outcome.
17
- value: ${{ steps.validate.outputs.valid }}
18
- outcome:
19
- description: "Deterministic review outcome: implemented, already-satisfied, needs-human, or invalid."
20
- value: ${{ steps.validate.outputs.outcome }}
21
- runs:
22
- using: composite
23
- steps:
24
- - name: Validate review outcome
25
- id: validate
26
- shell: bash
27
- env:
28
- OUTPUT_FILE: ${{ inputs.output-file }}
29
- PR_NUMBER: ${{ inputs.pr-number }}
30
- REVIEW_THREADS_FILE: ${{ inputs.review-threads-file }}
31
- run: |
32
- set -euo pipefail
33
- outcome="$(bash "${{ github.action_path }}/validate-review-output.sh" "$OUTPUT_FILE" "$PR_NUMBER" "$REVIEW_THREADS_FILE")"
34
- echo "outcome=$outcome" >> "$GITHUB_OUTPUT"
35
- echo "valid=$([ "$outcome" != 'invalid' ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/validate-review-output/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Validate review output
3
+ description: Verify an apply-review outcome accounts for every unresolved review thread.
4
+ inputs:
5
+ output-file:
6
+ description: Path to agent_output.json.
7
+ required: true
8
+ pr-number:
9
+ description: Pull request receiving the review feedback.
10
+ required: true
11
+ review-threads-file:
12
+ description: JSON file containing unresolved review threads.
13
+ required: true
14
+ outputs:
15
+ valid:
16
+ description: Whether the agent output is a valid review outcome.
17
+ value: ${{ steps.validate.outputs.valid }}
18
+ outcome:
19
+ description: "Deterministic review outcome: implemented, already-satisfied, needs-human, or invalid."
20
+ value: ${{ steps.validate.outputs.outcome }}
21
+ runs:
22
+ using: composite
23
+ steps:
24
+ - name: Validate review outcome
25
+ id: validate
26
+ shell: bash
27
+ env:
28
+ OUTPUT_FILE: ${{ inputs.output-file }}
29
+ PR_NUMBER: ${{ inputs.pr-number }}
30
+ REVIEW_THREADS_FILE: ${{ inputs.review-threads-file }}
31
+ run: |
32
+ set -euo pipefail
33
+ outcome="$(bash "${{ github.action_path }}/validate-review-output.sh" "$OUTPUT_FILE" "$PR_NUMBER" "$REVIEW_THREADS_FILE")"
34
+ echo "outcome=$outcome" >> "$GITHUB_OUTPUT"
35
+ echo "valid=$([ "$outcome" != 'invalid' ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
@@ -1,36 +1,36 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/validate-triage-output/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Validate triage output
3
- description: Verify agent_output.json contains a usable triage verdict before any GitHub writes.
4
- inputs:
5
- output-file:
6
- description: Path to agent_output.json.
7
- required: true
8
- issue-number:
9
- description: Issue number that every triage outcome must target.
10
- required: true
11
- outputs:
12
- valid:
13
- description: Whether the output contains a usable triage comment with a verdict.
14
- value: ${{ steps.validate.outputs.valid }}
15
- outcome:
16
- description: "Deterministic triage outcome: pass, needs-info, needs-maintainer, block, or invalid."
17
- value: ${{ steps.validate.outputs.outcome }}
18
- runs:
19
- using: composite
20
- steps:
21
- - name: Validate triage outcome
22
- id: validate
23
- shell: bash
24
- env:
25
- ISSUE_NUMBER: ${{ inputs.issue-number }}
26
- OUTPUT_FILE: ${{ inputs.output-file }}
27
- run: |
28
- set -euo pipefail
29
-
30
- outcome="$(bash "${{ github.action_path }}/validate-triage-output.sh" "$OUTPUT_FILE" "$ISSUE_NUMBER")"
31
- echo "outcome=$outcome" >> "$GITHUB_OUTPUT"
32
- echo "valid=$([ "$outcome" != 'invalid' ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
33
-
34
- if [ "$outcome" = 'invalid' ]; then
35
- echo "::warning::Agent output has no usable triage outcome. It will not be applied."
36
- fi
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/validate-triage-output/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Validate triage output
3
+ description: Verify agent_output.json contains a usable triage verdict before any GitHub writes.
4
+ inputs:
5
+ output-file:
6
+ description: Path to agent_output.json.
7
+ required: true
8
+ issue-number:
9
+ description: Issue number that every triage outcome must target.
10
+ required: true
11
+ outputs:
12
+ valid:
13
+ description: Whether the output contains a usable triage comment with a verdict.
14
+ value: ${{ steps.validate.outputs.valid }}
15
+ outcome:
16
+ description: "Deterministic triage outcome: pass, needs-info, needs-maintainer, block, or invalid."
17
+ value: ${{ steps.validate.outputs.outcome }}
18
+ runs:
19
+ using: composite
20
+ steps:
21
+ - name: Validate triage outcome
22
+ id: validate
23
+ shell: bash
24
+ env:
25
+ ISSUE_NUMBER: ${{ inputs.issue-number }}
26
+ OUTPUT_FILE: ${{ inputs.output-file }}
27
+ run: |
28
+ set -euo pipefail
29
+
30
+ outcome="$(bash "${{ github.action_path }}/validate-triage-output.sh" "$OUTPUT_FILE" "$ISSUE_NUMBER")"
31
+ echo "outcome=$outcome" >> "$GITHUB_OUTPUT"
32
+ echo "valid=$([ "$outcome" != 'invalid' ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
33
+
34
+ if [ "$outcome" = 'invalid' ]; then
35
+ echo "::warning::Agent output has no usable triage outcome. It will not be applied."
36
+ fi
@@ -1,9 +1,9 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/verify-composite-actions/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Verify composite actions
3
- description: Check every local composite action manifest parses and uses only contexts a composite action actually has.
4
- runs:
5
- using: composite
6
- steps:
7
- - name: Validate composite action manifests
8
- shell: bash
9
- run: bash "${GITHUB_ACTION_PATH}/verify-composite-actions.sh"
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/verify-composite-actions/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Verify composite actions
3
+ description: Check every local composite action manifest parses and uses only contexts a composite action actually has.
4
+ runs:
5
+ using: composite
6
+ steps:
7
+ - name: Validate composite action manifests
8
+ shell: bash
9
+ run: bash "${GITHUB_ACTION_PATH}/verify-composite-actions.sh"
@@ -1,9 +1,9 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/verify-refine-output/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Verify refine output validation
3
- description: Exercise deterministic Refine output validation regressions.
4
- runs:
5
- using: composite
6
- steps:
7
- - name: Verify refinement outcomes
8
- shell: bash
9
- run: bash "${{ github.action_path }}/verify-refine-output.sh"
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/verify-refine-output/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Verify refine output validation
3
+ description: Exercise deterministic Refine output validation regressions.
4
+ runs:
5
+ using: composite
6
+ steps:
7
+ - name: Verify refinement outcomes
8
+ shell: bash
9
+ run: bash "${{ github.action_path }}/verify-refine-output.sh"
@@ -82,6 +82,10 @@ assert_output 'draft update with questions comment is questions' questions \
82
82
  # cannot settle on its own" instead of the exact sentence. The pending mark
83
83
  # (_pending see questions below_) survives in the body and the comment is still on
84
84
  # the source issue, so the outcome is questions, not invalid.
85
+ # The JSON fixture below carries literal markdown backticks from the real Bots #1336 output.
86
+ # The checker reads them as command substitution inside single quotes (SC2016), a false
87
+ # positive because the whole argument is data, not shell.
88
+ # shellcheck disable=SC2016
85
89
  assert_output 'stripped draft marker with paraphrased questions is questions' questions \
86
90
  '{"items":[{"type":"update_issue","item_number":42,"body":"**Complexity:** standard path\n\n> Refinement draft. Three open questions are in a separate comment. The parts they leave open are marked `_pending see questions below_`."},{"type":"add_comment","item_number":42,"body":"## Refinement update\n\nI have some questions that the code cannot settle on its own. Reply in one comment to change any of them.\n1. Does the conductor bot stay local only too?"}]}'
87
91
 
@@ -1,9 +1,9 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/actions/verify-route-matrix/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
- name: Verify route matrix
3
- description: Exercise the router's classifier against every supported event, and check that each route and dispatch operation has a job in work-router.yml.
4
- runs:
5
- using: composite
6
- steps:
7
- - name: Run route matrix verification
8
- shell: bash
9
- run: bash "${GITHUB_ACTION_PATH}/verify-route-matrix.sh"
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/actions/verify-route-matrix/action.yml. Update with workflows update --force; consumer edits may be overwritten.
2
+ name: Verify route matrix
3
+ description: Exercise the router's classifier against every supported event, and check that each route and dispatch operation has a job in work-router.yml.
4
+ runs:
5
+ using: composite
6
+ steps:
7
+ - name: Run route matrix verification
8
+ shell: bash
9
+ run: bash "${GITHUB_ACTION_PATH}/verify-route-matrix.sh"
@@ -2645,17 +2645,11 @@ if worker_installed audit; then
2645
2645
  printf '%s\n' "$story_labels" | grep -qx refine || af "stories are not labelled refine, so nothing refines them"
2646
2646
  printf '%s\n' "$story_labels" | grep -qx audit && af "stories are labelled audit; three of them fill the backpressure and audit-close treats each as a report"
2647
2647
  grep -qE '^ staged: true' "$AUDIT_WORKER_MD" || af "is not staged, so gh-aw files the issues before they are measured"
2648
- audit_env() { sed -n "s/^ $1: \"\([0-9]*\)\"$/\1/p" "$AUDIT_WORKER_MD" | head -1; }
2649
- if [ -f "$REFINE_WORKER_MD" ]; then
2650
- refine_chars=$(sed -n 's/^ REFINE_MAX_BODY_CHARS: "\([0-9]*\)"$/\1/p' "$REFINE_WORKER_MD" | head -1)
2651
- refine_units=$(sed -n 's/^ REFINE_MAX_WORK_UNITS: "\([0-9]*\)"$/\1/p' "$REFINE_WORKER_MD" | head -1)
2652
- [ "$(audit_env AUDIT_MAX_BODY_CHARS)" -lt "${refine_chars:-0}" ] 2>/dev/null ||
2653
- af "AUDIT_MAX_BODY_CHARS is not below refine's REFINE_MAX_BODY_CHARS (${refine_chars:-unset})"
2654
- [ "$(audit_env AUDIT_MAX_WORK_UNITS)" -lt "${refine_units:-0}" ] 2>/dev/null ||
2655
- af "AUDIT_MAX_WORK_UNITS is not below refine's REFINE_MAX_WORK_UNITS (${refine_units:-unset})"
2656
- grep -qF 'uses: ./.github/actions/measure-issue-size' "$REFINE_WORKER_MD" ||
2657
- af "and refine measure with different rules; refine's size_guard must use measure-issue-size"
2658
- fi
2648
+ # Refine no longer carries a size gate (1.15.0 removed it -- the split mechanism bounds
2649
+ # the output, and gating refine on input size while implement accepts any size just
2650
+ # mis-routed real specs). So there is no REFINE_MAX_* to keep AUDIT_MAX_* below: the
2651
+ # audit's own limits are about keeping its filed stories small and digestible, not about
2652
+ # staying under a gate refine will refuse.
2659
2653
  if [ "$AUDIT_FILE_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2660
2654
  fi
2661
2655
 
@@ -2676,12 +2670,9 @@ if worker_installed docs-audit; then
2676
2670
  printf '%s\n' "$docs_story_labels" | grep -qx docs-audit && dfa "stories are labelled docs-audit; one of them fills the backpressure"
2677
2671
  grep -qE '^ staged: true' "$DOCS_WORKER_MD" || dfa "is not staged, so gh-aw files the issues before they are measured"
2678
2672
  grep -q 'add-issue-labels' "$DOCS_WORKER_MD" && dfa "still labels a report gh-aw filed itself"
2679
- if [ -f "${WORKFLOWS_DIR}/agent-refine.md" ]; then
2680
- docs_chars=$(sed -n 's/^ DOCS_AUDIT_MAX_BODY_CHARS: "\([0-9]*\)"$/\1/p' "$DOCS_WORKER_MD" | head -1)
2681
- refine_chars=$(sed -n 's/^ REFINE_MAX_BODY_CHARS: "\([0-9]*\)"$/\1/p' "${WORKFLOWS_DIR}/agent-refine.md" | head -1)
2682
- [ "${docs_chars:-99999999}" -lt "${refine_chars:-0}" ] 2>/dev/null ||
2683
- dfa "DOCS_AUDIT_MAX_BODY_CHARS is not below refine's REFINE_MAX_BODY_CHARS (${refine_chars:-unset})"
2684
- fi
2673
+ # Refine has no size gate (1.15.0), so there is no REFINE_MAX_BODY_CHARS to keep
2674
+ # DOCS_AUDIT_MAX_BODY_CHARS below. The docs audit's own limit is about keeping its
2675
+ # filed stories small, measured before filing; it does not depend on refine.
2685
2676
  if [ "$DOCS_FILE_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2686
2677
  fi
2687
2678
 
@@ -2817,42 +2808,37 @@ fi
2817
2808
 
2818
2809
  echo "── Refine size gate ──────────────────────────────────────────────────────"
2819
2810
 
2820
- # The size gate added a job that skips in the happy path, and gh-aw adds every custom job to
2821
- # the agent's needs. Three claims about that shape are asserted, because each one broke in
2822
- # production in the same week (Pliny-Bot #320-322: sixteen runs, three parked issues, a
2823
- # refusal loop on an issue the author was shrinking live):
2811
+ # Refine had a size-gate + refusal job that skipped in the happy path, and gh-aw adds every
2812
+ # custom job to the agent's needs, so a skip-poisoned implicit success() killed the agent
2813
+ # in 0s (Pliny-Bot #320-322). The size gate was removed at 1.15.0 (the split mechanism
2814
+ # bounds the output, and gating refine on input size while implement accepts any size
2815
+ # mis-routed real specs like Bots #1357). Two claims from that era still hold and are
2816
+ # asserted below:
2824
2817
  #
2825
- # 1. the agent's gate carries !failure(), so a skipped refusal no longer poisons the
2826
- # implicit success() and kills the agent in 0s
2827
- # 2. the incomplete job excludes the refusal, so a refused issue is terminal: no attempt
2828
- # counter, no x/5, no re-dispatch, no stalled
2829
- # 3. the refusal itself releases bot-working, so a refused issue is not left reserved
2818
+ # 1. the agent's top-level gate still carries !failure(): still_open and eligibility skip
2819
+ # when refinement should not run (issue closed, parked for review), and without
2820
+ # !failure() a skipped need would poison the implicit success() and skip the agent
2821
+ # 2. the split floor: a split child carries a whole stack's machinery, so a 1- or 2-point
2822
+ # slice is a fragment and must be folded into a sibling
2830
2823
  if worker_installed refine; then
2831
- SIZE_GATE_OK=1
2824
+ REFINE_OK=1
2832
2825
  REFINE_WORKER_MD="${WORKFLOWS_DIR}/agent-refine.md"
2833
2826
 
2834
2827
  # The top-level if: starts at column 0 -- job-level ifs: are indented -- so anchor on that,
2835
- # not on the prose comment above it. It must end with !failure().
2828
+ # not on the prose comment above it. It must end with !failure(): still_open and eligibility
2829
+ # skip in the not-eligible case, and an implicit success() would short-circuit the agent.
2836
2830
  top_level_if="$(sed -n 's/^if: //p' "$REFINE_WORKER_MD" | head -1)"
2837
2831
  if [[ "$top_level_if" != *'!failure()' ]]; then
2838
- SIZE_GATE_OK=0
2839
- 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
2840
- fi
2841
-
2842
- # Extract the incomplete job's own block. A whole-file grep cannot make this claim: reserve,
2843
- # refuse_big_issue and the agent gate all read size_guard, so the exclusion clause could be
2844
- # deleted from incomplete while every grep still passes.
2845
- incomplete_block="$(awk '/^ incomplete:/{found=1; next} found && /^ [a-z_]+:/{exit} found{print}' "$REFINE_WORKER_MD")"
2846
- if ! printf '%s' "$incomplete_block" | grep -qE '^ needs: \[.*size_guard' \
2847
- || ! printf '%s' "$incomplete_block" | grep -qF "needs.size_guard.outputs.too_big != 'true'"; then
2848
- SIZE_GATE_OK=0
2849
- echo "FAIL: refine's incomplete does not exclude the refusal path; every refused issue also loops attempts" >&2
2832
+ REFINE_OK=0
2833
+ echo "FAIL: refine gates the agent without !failure(); a skipped still_open/eligibility poisons the implicit success() and skips the agent on every closed-or-reviewed issue" >&2
2850
2834
  fi
2851
2835
 
2852
- refuse_block="$(awk '/^ refuse_big_issue:/{found=1; next} found && /^ [a-z_]+:/{exit} found{print}' "$REFINE_WORKER_MD")"
2853
- if ! printf '%s' "$refuse_block" | grep -qF 'WORKING_LABEL'; then
2854
- SIZE_GATE_OK=0
2855
- echo "FAIL: the refine refusal never releases bot-working; a refused issue stays reserved with no run behind it" >&2
2836
+ # The size gate is gone, so there must be no size_guard job and no refuse_big_issue job
2837
+ # left behind (a leftover job compiles into the agent's needs and re-introduces the
2838
+ # skip-poison the removal was meant to end).
2839
+ if grep -qE '^ (size_guard|refuse_big_issue):' "$REFINE_WORKER_MD"; then
2840
+ REFINE_OK=0
2841
+ echo "FAIL: refine still carries a size_guard or refuse_big_issue job; the size gate was removed at 1.15.0" >&2
2856
2842
  fi
2857
2843
 
2858
2844
  # The split floor: a split child carries a whole stack's machinery (issue, feature branch,
@@ -2861,11 +2847,11 @@ if worker_installed refine; then
2861
2847
  # so a consumer cannot lower it below 3 without editing the worker.
2862
2848
  if ! grep -qF 'MIN_CHILD_POINTS: "3"' "$REFINE_WORKER_MD" \
2863
2849
  || ! grep -qF 'child estimated below ${{ env.MIN_CHILD_POINTS }}' "$REFINE_WORKER_MD"; then
2864
- SIZE_GATE_OK=0
2850
+ REFINE_OK=0
2865
2851
  echo "FAIL: refine allows split children below 3 points; the floor must stay interpolated from MIN_CHILD_POINTS" >&2
2866
2852
  fi
2867
2853
 
2868
- if [ "$SIZE_GATE_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2854
+ if [ "$REFINE_OK" -eq 1 ]; then PASS=$((PASS + 1)); else FAIL=$((FAIL + 1)); fi
2869
2855
  fi
2870
2856
 
2871
2857
  # The safeoutputs bridge reads its JSON from stdin only for `tool .`. Any --flag on the line makes