@plainconceptsplatform/workflows 0.4.15 → 0.4.20
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.
- package/loops/actions/classify-route/action.yml +1 -0
- package/loops/actions/classify-route/classify-route.sh +15 -3
- package/loops/templates/agentics/agentics-checks.yml +2 -2
- package/loops/templates/agentics/agentics-maintenance.yml +4 -4
- package/loops/templates/ci/app-ci-dotnet-next.yml +6 -6
- package/loops/templates/ci/app-ci-node-monorepo.yml +9 -9
- package/loops/templates/release/github-release.yml +1 -1
- package/loops/workflows/agent-apply-review.md +6 -6
- package/loops/workflows/agent-audit.md +3 -3
- package/loops/workflows/agent-direct.md +6 -6
- package/loops/workflows/agent-implement.md +20 -14
- package/loops/workflows/agent-merge-gate.md +9 -23
- package/loops/workflows/agent-propose.md +5 -5
- package/loops/workflows/agent-refine.md +6 -6
- package/loops/workflows/authorize-bot-work.yml +8 -10
- package/loops/workflows/work-router.yml +22 -9
- package/package.json +1 -1
|
@@ -48,6 +48,7 @@ runs:
|
|
|
48
48
|
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
49
49
|
COMMENT_ON_PR: ${{ github.event.issue.pull_request != '' }}
|
|
50
50
|
COMMENT_SENDER_TYPE: ${{ github.event.comment.user.type }}
|
|
51
|
+
ACTOR: ${{ github.actor }}
|
|
51
52
|
RUN_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
52
53
|
RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
53
54
|
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
@@ -53,9 +53,19 @@ classify_route() {
|
|
|
53
53
|
fi
|
|
54
54
|
;;
|
|
55
55
|
refine | implement | direct)
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
|
|
56
|
+
# If the actor is a bot (e.g. refine→implement transition), route directly.
|
|
57
|
+
# If the actor is a human, authorize-bot-work.yml will add bot-working which triggers the workflow.
|
|
58
|
+
if [ "${ACTOR:-}" != "" ] && echo "${ACTOR:-}" | grep -q '\[bot\]$'; then
|
|
59
|
+
route="${LABEL:-}"
|
|
60
|
+
issue_number="${EVENT_ISSUE_NUMBER:-}"
|
|
61
|
+
if [ "${LABEL:-}" = "refine" ]; then
|
|
62
|
+
refine_mode="first"
|
|
63
|
+
elif [ "${LABEL:-}" = "direct" ]; then
|
|
64
|
+
direct_mode="first"
|
|
65
|
+
fi
|
|
66
|
+
else
|
|
67
|
+
error="waiting for bot to add bot-working label"
|
|
68
|
+
fi
|
|
59
69
|
;;
|
|
60
70
|
esac
|
|
61
71
|
fi
|
|
@@ -67,6 +77,8 @@ classify_route() {
|
|
|
67
77
|
pr_number="${EVENT_ISSUE_NUMBER:-}"
|
|
68
78
|
elif [ "${COMMENT_SENDER_TYPE:-}" = "Bot" ]; then
|
|
69
79
|
error="comment authored by a bot"
|
|
80
|
+
elif has_label implement; then
|
|
81
|
+
error="issue has implement label; comments do not re-trigger implement"
|
|
70
82
|
elif has_label direct; then
|
|
71
83
|
route="direct"
|
|
72
84
|
direct_mode="continue"
|
|
@@ -26,7 +26,7 @@ concurrency:
|
|
|
26
26
|
jobs:
|
|
27
27
|
verify-lockfiles:
|
|
28
28
|
name: Verify generated agent lockfiles
|
|
29
|
-
runs-on:
|
|
29
|
+
runs-on: RunnerLandingZone
|
|
30
30
|
timeout-minutes: 10
|
|
31
31
|
steps:
|
|
32
32
|
- name: Checkout repository
|
|
@@ -56,7 +56,7 @@ jobs:
|
|
|
56
56
|
|
|
57
57
|
lint-workflows:
|
|
58
58
|
name: Lint authored workflows and shell
|
|
59
|
-
runs-on:
|
|
59
|
+
runs-on: RunnerLandingZone
|
|
60
60
|
timeout-minutes: 10
|
|
61
61
|
steps:
|
|
62
62
|
- name: Checkout repository
|
|
@@ -48,7 +48,7 @@ permissions: {}
|
|
|
48
48
|
jobs:
|
|
49
49
|
close-expired-discussions:
|
|
50
50
|
if: ${{ !(github.event.repository.fork) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '') }}
|
|
51
|
-
runs-on:
|
|
51
|
+
runs-on: RunnerLandingZone
|
|
52
52
|
permissions:
|
|
53
53
|
discussions: write
|
|
54
54
|
steps:
|
|
@@ -66,7 +66,7 @@ jobs:
|
|
|
66
66
|
await main();
|
|
67
67
|
close-expired-issues:
|
|
68
68
|
if: ${{ !(github.event.repository.fork) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '') }}
|
|
69
|
-
runs-on:
|
|
69
|
+
runs-on: RunnerLandingZone
|
|
70
70
|
permissions:
|
|
71
71
|
issues: write
|
|
72
72
|
steps:
|
|
@@ -84,7 +84,7 @@ jobs:
|
|
|
84
84
|
await main();
|
|
85
85
|
close-expired-pull-requests:
|
|
86
86
|
if: ${{ !(github.event.repository.fork) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '') }}
|
|
87
|
-
runs-on:
|
|
87
|
+
runs-on: RunnerLandingZone
|
|
88
88
|
permissions:
|
|
89
89
|
pull-requests: write
|
|
90
90
|
steps:
|
|
@@ -102,7 +102,7 @@ jobs:
|
|
|
102
102
|
await main();
|
|
103
103
|
cleanup-cache-memory:
|
|
104
104
|
if: ${{ !(github.event.repository.fork) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '' || inputs.operation == 'clean_cache_memories') }}
|
|
105
|
-
runs-on:
|
|
105
|
+
runs-on: RunnerLandingZone
|
|
106
106
|
permissions:
|
|
107
107
|
actions: write
|
|
108
108
|
steps:
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
api:
|
|
48
48
|
name: API (.NET)
|
|
49
49
|
if: github.event_name != 'schedule'
|
|
50
|
-
runs-on:
|
|
50
|
+
runs-on: RunnerLandingZone
|
|
51
51
|
timeout-minutes: 30
|
|
52
52
|
services:
|
|
53
53
|
sqlserver:
|
|
@@ -104,7 +104,7 @@ jobs:
|
|
|
104
104
|
web:
|
|
105
105
|
name: Web (Next.js)
|
|
106
106
|
if: github.event_name != 'schedule'
|
|
107
|
-
runs-on:
|
|
107
|
+
runs-on: RunnerLandingZone
|
|
108
108
|
timeout-minutes: 15
|
|
109
109
|
steps:
|
|
110
110
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
@@ -134,14 +134,14 @@ jobs:
|
|
|
134
134
|
|
|
135
135
|
secret-scan:
|
|
136
136
|
name: Secret scan (TruffleHog)
|
|
137
|
-
runs-on:
|
|
137
|
+
runs-on: RunnerLandingZone
|
|
138
138
|
steps:
|
|
139
139
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
140
140
|
- run: docker run --rm -v "${{ github.workspace }}:/repo" "$TRUFFLEHOG_IMAGE" filesystem /repo --only-verified --fail --no-update
|
|
141
141
|
|
|
142
142
|
deps-and-iac-scan:
|
|
143
143
|
name: Dependencies and IaC (Trivy)
|
|
144
|
-
runs-on:
|
|
144
|
+
runs-on: RunnerLandingZone
|
|
145
145
|
steps:
|
|
146
146
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
147
147
|
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
|
@@ -155,14 +155,14 @@ jobs:
|
|
|
155
155
|
|
|
156
156
|
sast-scan:
|
|
157
157
|
name: SAST (Semgrep)
|
|
158
|
-
runs-on:
|
|
158
|
+
runs-on: RunnerLandingZone
|
|
159
159
|
steps:
|
|
160
160
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
161
161
|
- run: docker run --rm -v "${{ github.workspace }}:/src" -w /src "$SEMGREP_IMAGE" semgrep scan --error --metrics=off --oss-only --disable-version-check --config p/default --config p/security-audit --config p/secrets --config p/csharp --config p/typescript --config p/react --exclude-rule yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag
|
|
162
162
|
|
|
163
163
|
sbom:
|
|
164
164
|
name: SBOM (CycloneDX)
|
|
165
|
-
runs-on:
|
|
165
|
+
runs-on: RunnerLandingZone
|
|
166
166
|
steps:
|
|
167
167
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
168
168
|
- uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
|
|
@@ -37,7 +37,7 @@ jobs:
|
|
|
37
37
|
lint:
|
|
38
38
|
name: Lint (Biome)
|
|
39
39
|
if: github.event_name != 'schedule'
|
|
40
|
-
runs-on:
|
|
40
|
+
runs-on: RunnerLandingZone
|
|
41
41
|
steps:
|
|
42
42
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
43
43
|
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
|
|
@@ -50,7 +50,7 @@ jobs:
|
|
|
50
50
|
web:
|
|
51
51
|
name: Web (Next.js static export)
|
|
52
52
|
if: github.event_name != 'schedule'
|
|
53
|
-
runs-on:
|
|
53
|
+
runs-on: RunnerLandingZone
|
|
54
54
|
steps:
|
|
55
55
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
56
56
|
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
|
|
@@ -73,7 +73,7 @@ jobs:
|
|
|
73
73
|
name: E2E (Playwright)
|
|
74
74
|
if: github.event_name != 'schedule'
|
|
75
75
|
needs: web
|
|
76
|
-
runs-on:
|
|
76
|
+
runs-on: RunnerLandingZone
|
|
77
77
|
steps:
|
|
78
78
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
79
79
|
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
|
|
@@ -98,7 +98,7 @@ jobs:
|
|
|
98
98
|
name: Desktop (Electron)
|
|
99
99
|
if: github.event_name != 'schedule'
|
|
100
100
|
needs: web
|
|
101
|
-
runs-on:
|
|
101
|
+
runs-on: RunnerLandingZone
|
|
102
102
|
steps:
|
|
103
103
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
104
104
|
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
|
|
@@ -122,7 +122,7 @@ jobs:
|
|
|
122
122
|
mobile:
|
|
123
123
|
name: Mobile (Capacitor)
|
|
124
124
|
if: github.event_name != 'schedule'
|
|
125
|
-
runs-on:
|
|
125
|
+
runs-on: RunnerLandingZone
|
|
126
126
|
steps:
|
|
127
127
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
128
128
|
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
|
|
@@ -141,14 +141,14 @@ jobs:
|
|
|
141
141
|
|
|
142
142
|
secret-scan:
|
|
143
143
|
name: Secret scan (TruffleHog)
|
|
144
|
-
runs-on:
|
|
144
|
+
runs-on: RunnerLandingZone
|
|
145
145
|
steps:
|
|
146
146
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
147
147
|
- run: docker run --rm -v "${{ github.workspace }}:/repo" "$TRUFFLEHOG_IMAGE" filesystem /repo --only-verified --fail --no-update
|
|
148
148
|
|
|
149
149
|
deps-and-iac-scan:
|
|
150
150
|
name: Dependencies and IaC (Trivy)
|
|
151
|
-
runs-on:
|
|
151
|
+
runs-on: RunnerLandingZone
|
|
152
152
|
steps:
|
|
153
153
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
154
154
|
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
|
@@ -162,14 +162,14 @@ jobs:
|
|
|
162
162
|
|
|
163
163
|
sast-scan:
|
|
164
164
|
name: SAST (Semgrep)
|
|
165
|
-
runs-on:
|
|
165
|
+
runs-on: RunnerLandingZone
|
|
166
166
|
steps:
|
|
167
167
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
168
168
|
- run: docker run --rm -v "${{ github.workspace }}:/src" -w /src "$SEMGREP_IMAGE" semgrep scan --error --metrics=off --oss-only --disable-version-check --config p/default --config p/security-audit --config p/secrets --config p/typescript --config p/react --exclude-rule yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag
|
|
169
169
|
|
|
170
170
|
sbom:
|
|
171
171
|
name: SBOM (CycloneDX)
|
|
172
|
-
runs-on:
|
|
172
|
+
runs-on: RunnerLandingZone
|
|
173
173
|
steps:
|
|
174
174
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
175
175
|
- uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
|
|
@@ -44,7 +44,7 @@ on:
|
|
|
44
44
|
# substantive feedback. A custom job, not `on.steps`, because the prompt needs these values.
|
|
45
45
|
jobs:
|
|
46
46
|
subject:
|
|
47
|
-
runs-on:
|
|
47
|
+
runs-on: RunnerLandingZone
|
|
48
48
|
permissions:
|
|
49
49
|
contents: read
|
|
50
50
|
issues: read
|
|
@@ -113,7 +113,7 @@ jobs:
|
|
|
113
113
|
reserve:
|
|
114
114
|
needs: subject
|
|
115
115
|
if: needs.subject.outputs.found == 'true' && needs.subject.outputs.issue != ''
|
|
116
|
-
runs-on:
|
|
116
|
+
runs-on: RunnerLandingZone
|
|
117
117
|
permissions:
|
|
118
118
|
contents: read
|
|
119
119
|
issues: write
|
|
@@ -145,7 +145,7 @@ jobs:
|
|
|
145
145
|
if: >
|
|
146
146
|
needs.agent.result == 'success' &&
|
|
147
147
|
needs.safe_outputs.result == 'success'
|
|
148
|
-
runs-on:
|
|
148
|
+
runs-on: RunnerLandingZone
|
|
149
149
|
permissions:
|
|
150
150
|
contents: write
|
|
151
151
|
issues: write
|
|
@@ -174,7 +174,7 @@ jobs:
|
|
|
174
174
|
always() &&
|
|
175
175
|
needs.subject.outputs.found == 'true' &&
|
|
176
176
|
needs.agent.result != 'success'
|
|
177
|
-
runs-on:
|
|
177
|
+
runs-on: RunnerLandingZone
|
|
178
178
|
permissions:
|
|
179
179
|
contents: read
|
|
180
180
|
issues: write
|
|
@@ -213,8 +213,8 @@ jobs:
|
|
|
213
213
|
|
|
214
214
|
if: needs.subject.outputs.found == 'true'
|
|
215
215
|
|
|
216
|
-
runs-on:
|
|
217
|
-
runs-on-slim:
|
|
216
|
+
runs-on: RunnerLandingZone
|
|
217
|
+
runs-on-slim: RunnerLandingZone
|
|
218
218
|
|
|
219
219
|
secrets:
|
|
220
220
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -42,8 +42,8 @@ on:
|
|
|
42
42
|
query: "is:issue is:open label:audit"
|
|
43
43
|
max: 3
|
|
44
44
|
|
|
45
|
-
runs-on:
|
|
46
|
-
runs-on-slim:
|
|
45
|
+
runs-on: RunnerLandingZone
|
|
46
|
+
runs-on-slim: RunnerLandingZone
|
|
47
47
|
|
|
48
48
|
secrets:
|
|
49
49
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -76,7 +76,7 @@ jobs:
|
|
|
76
76
|
needs.agent.result == 'success' &&
|
|
77
77
|
needs.safe_outputs.result == 'success' &&
|
|
78
78
|
needs.safe_outputs.outputs.process_safe_outputs_processed_count != '0'
|
|
79
|
-
runs-on:
|
|
79
|
+
runs-on: RunnerLandingZone
|
|
80
80
|
permissions:
|
|
81
81
|
contents: read
|
|
82
82
|
issues: write
|
|
@@ -45,7 +45,7 @@ on:
|
|
|
45
45
|
|
|
46
46
|
jobs:
|
|
47
47
|
eligibility:
|
|
48
|
-
runs-on:
|
|
48
|
+
runs-on: RunnerLandingZone
|
|
49
49
|
permissions:
|
|
50
50
|
issues: read
|
|
51
51
|
outputs:
|
|
@@ -72,7 +72,7 @@ jobs:
|
|
|
72
72
|
reserve:
|
|
73
73
|
needs: eligibility
|
|
74
74
|
if: needs.eligibility.outputs.eligible == 'true'
|
|
75
|
-
runs-on:
|
|
75
|
+
runs-on: RunnerLandingZone
|
|
76
76
|
permissions:
|
|
77
77
|
contents: read
|
|
78
78
|
issues: write
|
|
@@ -104,7 +104,7 @@ jobs:
|
|
|
104
104
|
if: >
|
|
105
105
|
needs.agent.result == 'success' &&
|
|
106
106
|
needs.safe_outputs.result == 'success'
|
|
107
|
-
runs-on:
|
|
107
|
+
runs-on: RunnerLandingZone
|
|
108
108
|
permissions:
|
|
109
109
|
contents: read
|
|
110
110
|
issues: write
|
|
@@ -140,7 +140,7 @@ jobs:
|
|
|
140
140
|
always() &&
|
|
141
141
|
needs.eligibility.outputs.eligible == 'true' &&
|
|
142
142
|
needs.agent.result != 'success'
|
|
143
|
-
runs-on:
|
|
143
|
+
runs-on: RunnerLandingZone
|
|
144
144
|
permissions:
|
|
145
145
|
contents: read
|
|
146
146
|
issues: write
|
|
@@ -179,8 +179,8 @@ jobs:
|
|
|
179
179
|
|
|
180
180
|
if: inputs.issue-number != '' && needs.eligibility.outputs.eligible == 'true'
|
|
181
181
|
|
|
182
|
-
runs-on:
|
|
183
|
-
runs-on-slim:
|
|
182
|
+
runs-on: RunnerLandingZone
|
|
183
|
+
runs-on-slim: RunnerLandingZone
|
|
184
184
|
|
|
185
185
|
secrets:
|
|
186
186
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -43,7 +43,7 @@ on:
|
|
|
43
43
|
|
|
44
44
|
jobs:
|
|
45
45
|
eligibility:
|
|
46
|
-
runs-on:
|
|
46
|
+
runs-on: RunnerLandingZone
|
|
47
47
|
permissions:
|
|
48
48
|
issues: read
|
|
49
49
|
outputs:
|
|
@@ -70,7 +70,7 @@ jobs:
|
|
|
70
70
|
reserve:
|
|
71
71
|
needs: eligibility
|
|
72
72
|
if: needs.eligibility.outputs.eligible == 'true'
|
|
73
|
-
runs-on:
|
|
73
|
+
runs-on: RunnerLandingZone
|
|
74
74
|
permissions:
|
|
75
75
|
contents: read
|
|
76
76
|
issues: write
|
|
@@ -108,7 +108,7 @@ jobs:
|
|
|
108
108
|
if: >
|
|
109
109
|
needs.agent.result == 'success' &&
|
|
110
110
|
needs.safe_outputs.result == 'success'
|
|
111
|
-
runs-on:
|
|
111
|
+
runs-on: RunnerLandingZone
|
|
112
112
|
permissions:
|
|
113
113
|
contents: read
|
|
114
114
|
issues: write
|
|
@@ -144,7 +144,7 @@ jobs:
|
|
|
144
144
|
always() &&
|
|
145
145
|
needs.eligibility.outputs.eligible == 'true' &&
|
|
146
146
|
needs.agent.result != 'success'
|
|
147
|
-
runs-on:
|
|
147
|
+
runs-on: RunnerLandingZone
|
|
148
148
|
permissions:
|
|
149
149
|
contents: read
|
|
150
150
|
issues: write
|
|
@@ -183,8 +183,8 @@ jobs:
|
|
|
183
183
|
|
|
184
184
|
if: inputs.issue-number != '' && needs.eligibility.outputs.eligible == 'true'
|
|
185
185
|
|
|
186
|
-
runs-on:
|
|
187
|
-
runs-on-slim:
|
|
186
|
+
runs-on: RunnerLandingZone
|
|
187
|
+
runs-on-slim: RunnerLandingZone
|
|
188
188
|
|
|
189
189
|
secrets:
|
|
190
190
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -239,23 +239,29 @@ timeout-minutes: 90
|
|
|
239
239
|
a. Load the `ob-plan-goal` skill. It defines a mandatory, gate-sequenced pipeline:
|
|
240
240
|
`explore · propose · apply · verify · archive · evidence · output · report`
|
|
241
241
|
|
|
242
|
-
b.
|
|
242
|
+
b. **Refined-issue fast path:** If the issue context at `${{ env.ISSUE_CONTEXT_PATH }}`
|
|
243
|
+
already contains structured acceptance criteria (e.g. "## Acceptance criteria",
|
|
244
|
+
"### Scenario:", Gherkin blocks), affected artifacts, and design decisions, the
|
|
245
|
+
`ob-plan-goal` skill will skip the explore and propose phases and go directly to
|
|
246
|
+
apply. Do not override this: re-exploring a pre-refined issue wastes tokens.
|
|
247
|
+
|
|
248
|
+
c. Execute every phase in order. Each phase loads its own sub-skill (`ob-plan-explore`,
|
|
243
249
|
`ob-plan-propose`, `ob-plan-apply`, `ob-repo-verify`, `ob-plan-archive`,
|
|
244
|
-
`ob-ops-evidence`) and owns its procedure. You must not skip a phase
|
|
245
|
-
|
|
250
|
+
`ob-ops-evidence`) and owns its procedure. You must not skip a phase unless the
|
|
251
|
+
pipeline's refined-issue detection says to.
|
|
246
252
|
|
|
247
|
-
|
|
253
|
+
d. The `apply` phase uses `ob-plan-apply` which delegates implementation to specialist
|
|
248
254
|
subagent waves. Let it own worker resolution, concurrency, and retry , do not
|
|
249
255
|
implement the tasks yourself unless `ob-plan-apply` instructs you to.
|
|
250
256
|
|
|
251
|
-
|
|
257
|
+
e. Implement only what the issue asks for: a vague sentence is not licence to redesign
|
|
252
258
|
a module. Never read outside this repository root. The issue context at
|
|
253
259
|
`${{ env.ISSUE_CONTEXT_PATH }}` defines acceptance criteria that the pipeline must
|
|
254
260
|
satisfy.
|
|
255
261
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
262
|
+
f. Follow repository documentation and established conventions. Keep changes focused,
|
|
263
|
+
protect secrets, do not bypass checks, and do not modify generated files unless the issue requires it.
|
|
264
|
+
Adhere to ${{ env.REPO_RULES }}.
|
|
259
265
|
|
|
260
266
|
4. Verify before you conclude. From the repository root:
|
|
261
267
|
|
|
@@ -57,7 +57,7 @@ on:
|
|
|
57
57
|
# values and `on.steps` outputs do not reach the agent job.
|
|
58
58
|
jobs:
|
|
59
59
|
subject:
|
|
60
|
-
runs-on:
|
|
60
|
+
runs-on: RunnerLandingZone
|
|
61
61
|
permissions:
|
|
62
62
|
contents: read
|
|
63
63
|
issues: read
|
|
@@ -86,7 +86,7 @@ jobs:
|
|
|
86
86
|
protected_changes:
|
|
87
87
|
needs: subject
|
|
88
88
|
if: needs.subject.outputs.found == 'true'
|
|
89
|
-
runs-on:
|
|
89
|
+
runs-on: RunnerLandingZone
|
|
90
90
|
permissions:
|
|
91
91
|
pull-requests: read
|
|
92
92
|
outputs:
|
|
@@ -119,7 +119,7 @@ jobs:
|
|
|
119
119
|
review_required:
|
|
120
120
|
needs: [subject, protected_changes]
|
|
121
121
|
if: needs.subject.outputs.found == 'true' && needs.protected_changes.outputs.requires_review == 'true'
|
|
122
|
-
runs-on:
|
|
122
|
+
runs-on: RunnerLandingZone
|
|
123
123
|
permissions:
|
|
124
124
|
contents: read
|
|
125
125
|
issues: write
|
|
@@ -162,7 +162,7 @@ jobs:
|
|
|
162
162
|
reserve:
|
|
163
163
|
needs: subject
|
|
164
164
|
if: needs.subject.outputs.found == 'true'
|
|
165
|
-
runs-on:
|
|
165
|
+
runs-on: RunnerLandingZone
|
|
166
166
|
permissions:
|
|
167
167
|
contents: read
|
|
168
168
|
issues: write
|
|
@@ -195,20 +195,6 @@ jobs:
|
|
|
195
195
|
else
|
|
196
196
|
echo "has_conflicts=false" >> "$GITHUB_OUTPUT"
|
|
197
197
|
fi
|
|
198
|
-
- name: Mark the issue as in progress
|
|
199
|
-
if: needs.subject.outputs.conclusion == 'failure'
|
|
200
|
-
uses: ./.github/actions/add-issue-labels
|
|
201
|
-
with:
|
|
202
|
-
token: ${{ steps.app-token.outputs.token }}
|
|
203
|
-
issue-number: ${{ needs.subject.outputs.issue }}
|
|
204
|
-
labels: ${{ env.WORKING_LABEL }}
|
|
205
|
-
- name: Clear the human-needed flag
|
|
206
|
-
if: needs.subject.outputs.conclusion == 'failure'
|
|
207
|
-
uses: ./.github/actions/remove-issue-labels
|
|
208
|
-
with:
|
|
209
|
-
token: ${{ steps.app-token.outputs.token }}
|
|
210
|
-
issue-number: ${{ needs.subject.outputs.issue }}
|
|
211
|
-
labels: ${{ env.REVIEW_LABEL }}
|
|
212
198
|
- name: Comment on issue - problems found, solving them
|
|
213
199
|
if: needs.subject.outputs.conclusion == 'failure'
|
|
214
200
|
uses: ./.github/actions/create-issue-comment
|
|
@@ -217,7 +203,7 @@ jobs:
|
|
|
217
203
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
218
204
|
body: |
|
|
219
205
|
${{ env.GATE_MARKER }}
|
|
220
|
-
Problems found in PR #${{ needs.subject.outputs.pr }}. ${{ steps.conflicts.outputs.has_conflicts == 'true' && 'Merge conflicts detected.' || '
|
|
206
|
+
Problems found in PR #${{ needs.subject.outputs.pr }}. ${{ steps.conflicts.outputs.has_conflicts == 'true' && 'Merge conflicts detected.' || 'CI failed.' }}
|
|
221
207
|
Bot is working on fixing it.
|
|
222
208
|
conclude:
|
|
223
209
|
needs: [activation, subject, protected_changes, agent, safe_outputs]
|
|
@@ -225,7 +211,7 @@ jobs:
|
|
|
225
211
|
needs.agent.result == 'success' &&
|
|
226
212
|
needs.safe_outputs.result == 'success' &&
|
|
227
213
|
needs.protected_changes.outputs.requires_review != 'true'
|
|
228
|
-
runs-on:
|
|
214
|
+
runs-on: RunnerLandingZone
|
|
229
215
|
permissions:
|
|
230
216
|
contents: write
|
|
231
217
|
issues: write
|
|
@@ -264,7 +250,7 @@ jobs:
|
|
|
264
250
|
needs.subject.outputs.found == 'true' &&
|
|
265
251
|
needs.protected_changes.outputs.requires_review != 'true' &&
|
|
266
252
|
needs.agent.result != 'success'
|
|
267
|
-
runs-on:
|
|
253
|
+
runs-on: RunnerLandingZone
|
|
268
254
|
permissions:
|
|
269
255
|
contents: read
|
|
270
256
|
issues: write
|
|
@@ -308,8 +294,8 @@ jobs:
|
|
|
308
294
|
|
|
309
295
|
if: needs.subject.outputs.found == 'true' && needs.protected_changes.outputs.requires_review != 'true'
|
|
310
296
|
|
|
311
|
-
runs-on:
|
|
312
|
-
runs-on-slim:
|
|
297
|
+
runs-on: RunnerLandingZone
|
|
298
|
+
runs-on-slim: RunnerLandingZone
|
|
313
299
|
|
|
314
300
|
secrets:
|
|
315
301
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -56,8 +56,8 @@ on:
|
|
|
56
56
|
query: "is:issue is:open label:proposed -label:refine -label:implement"
|
|
57
57
|
max: 1
|
|
58
58
|
|
|
59
|
-
runs-on:
|
|
60
|
-
runs-on-slim:
|
|
59
|
+
runs-on: RunnerLandingZone
|
|
60
|
+
runs-on-slim: RunnerLandingZone
|
|
61
61
|
|
|
62
62
|
secrets:
|
|
63
63
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -156,7 +156,7 @@ jobs:
|
|
|
156
156
|
# Circuit breaker. A guard job that only reports; the agent's own `if:` is what stops the
|
|
157
157
|
# run, because a `needs` job succeeding with a false output does not gate its dependents.
|
|
158
158
|
capacity:
|
|
159
|
-
runs-on:
|
|
159
|
+
runs-on: RunnerLandingZone
|
|
160
160
|
permissions:
|
|
161
161
|
issues: read
|
|
162
162
|
outputs:
|
|
@@ -185,7 +185,7 @@ jobs:
|
|
|
185
185
|
needs.agent.result == 'success' &&
|
|
186
186
|
needs.safe_outputs.result == 'success' &&
|
|
187
187
|
needs.safe_outputs.outputs.process_safe_outputs_processed_count != '0'
|
|
188
|
-
runs-on:
|
|
188
|
+
runs-on: RunnerLandingZone
|
|
189
189
|
permissions:
|
|
190
190
|
contents: read
|
|
191
191
|
issues: write
|
|
@@ -225,7 +225,7 @@ safe-outputs:
|
|
|
225
225
|
# (release notes) and then files an issue, so it is the only one where a prompt-injection
|
|
226
226
|
# attempt has somewhere to go.
|
|
227
227
|
threat-detection:
|
|
228
|
-
runs-on:
|
|
228
|
+
runs-on: RunnerLandingZone
|
|
229
229
|
create-issue:
|
|
230
230
|
max: 1
|
|
231
231
|
|
|
@@ -53,7 +53,7 @@ on:
|
|
|
53
53
|
|
|
54
54
|
jobs:
|
|
55
55
|
reserve:
|
|
56
|
-
runs-on:
|
|
56
|
+
runs-on: RunnerLandingZone
|
|
57
57
|
permissions:
|
|
58
58
|
contents: read
|
|
59
59
|
issues: write
|
|
@@ -86,7 +86,7 @@ jobs:
|
|
|
86
86
|
always() &&
|
|
87
87
|
needs.agent.result == 'success' &&
|
|
88
88
|
needs.safe_outputs.result == 'success'
|
|
89
|
-
runs-on:
|
|
89
|
+
runs-on: RunnerLandingZone
|
|
90
90
|
permissions:
|
|
91
91
|
contents: read
|
|
92
92
|
outputs:
|
|
@@ -116,7 +116,7 @@ jobs:
|
|
|
116
116
|
needs.agent.result == 'success' &&
|
|
117
117
|
needs.safe_outputs.result == 'success' &&
|
|
118
118
|
needs.validate_output.outputs.valid == 'true'
|
|
119
|
-
runs-on:
|
|
119
|
+
runs-on: RunnerLandingZone
|
|
120
120
|
permissions:
|
|
121
121
|
contents: read
|
|
122
122
|
issues: write
|
|
@@ -181,7 +181,7 @@ jobs:
|
|
|
181
181
|
needs.safe_outputs.result != 'success' ||
|
|
182
182
|
needs.validate_output.outputs.valid != 'true'
|
|
183
183
|
)
|
|
184
|
-
runs-on:
|
|
184
|
+
runs-on: RunnerLandingZone
|
|
185
185
|
permissions:
|
|
186
186
|
contents: read
|
|
187
187
|
issues: write
|
|
@@ -218,8 +218,8 @@ jobs:
|
|
|
218
218
|
|
|
219
219
|
if: inputs.issue-number != ''
|
|
220
220
|
|
|
221
|
-
runs-on:
|
|
222
|
-
runs-on-slim:
|
|
221
|
+
runs-on: RunnerLandingZone
|
|
222
|
+
runs-on-slim: RunnerLandingZone
|
|
223
223
|
|
|
224
224
|
secrets:
|
|
225
225
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Human adds implement/refine/direct label → validates permission → bot adds bot-working
|
|
2
2
|
# This ensures the bot is the actor for all agentic workflows.
|
|
3
|
+
#
|
|
4
|
+
# IMPORTANT: Only triggers for HUMAN actors. When the bot transitions refine→implement,
|
|
5
|
+
# it adds bot-working itself, so authorize-bot-work must not fire again.
|
|
3
6
|
name: "Authorize Bot Work"
|
|
4
7
|
|
|
5
8
|
on:
|
|
@@ -11,13 +14,15 @@ permissions:
|
|
|
11
14
|
|
|
12
15
|
jobs:
|
|
13
16
|
authorize:
|
|
14
|
-
# Only trigger for implement/refine/direct labels
|
|
17
|
+
# Only trigger for implement/refine/direct labels from HUMANS (not bots),
|
|
18
|
+
# and only if bot-working is NOT already present
|
|
15
19
|
if: >
|
|
16
20
|
(github.event.label.name == 'implement' ||
|
|
17
21
|
github.event.label.name == 'refine' ||
|
|
18
22
|
github.event.label.name == 'direct') &&
|
|
19
|
-
!contains(github.event.issue.labels.*.name, 'bot-working')
|
|
20
|
-
|
|
23
|
+
!contains(github.event.issue.labels.*.name, 'bot-working') &&
|
|
24
|
+
!endsWith(github.actor, '[bot]')
|
|
25
|
+
runs-on: RunnerLandingZone
|
|
21
26
|
timeout-minutes: 5
|
|
22
27
|
permissions:
|
|
23
28
|
contents: read
|
|
@@ -31,13 +36,6 @@ jobs:
|
|
|
31
36
|
run: |
|
|
32
37
|
set -euo pipefail
|
|
33
38
|
|
|
34
|
-
# Bots don't need validation - they're already authorized
|
|
35
|
-
if [[ "$ACTOR" == *"[bot]"* ]]; then
|
|
36
|
-
echo "authorized=true" >> "$GITHUB_OUTPUT"
|
|
37
|
-
echo "::notice::Bot actor ($ACTOR) - skipping permission check"
|
|
38
|
-
exit 0
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
39
|
permission=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$ACTOR/permission" \
|
|
42
40
|
--jq '.permission' 2>/dev/null || echo "none")
|
|
43
41
|
|
|
@@ -118,7 +118,7 @@ permissions:
|
|
|
118
118
|
jobs:
|
|
119
119
|
# Public repositories must check repository permission before an event can start a model.
|
|
120
120
|
authorize:
|
|
121
|
-
runs-on:
|
|
121
|
+
runs-on: RunnerLandingZone
|
|
122
122
|
timeout-minutes: 5
|
|
123
123
|
permissions:
|
|
124
124
|
contents: read
|
|
@@ -167,7 +167,7 @@ jobs:
|
|
|
167
167
|
esac
|
|
168
168
|
|
|
169
169
|
classify:
|
|
170
|
-
runs-on:
|
|
170
|
+
runs-on: RunnerLandingZone
|
|
171
171
|
timeout-minutes: 5
|
|
172
172
|
permissions:
|
|
173
173
|
contents: read
|
|
@@ -322,7 +322,7 @@ jobs:
|
|
|
322
322
|
if: >
|
|
323
323
|
needs.classify.outputs.route == 'bot-approve' &&
|
|
324
324
|
(github.actor == 'app/github-actions' || github.actor == 'platform-devbox[bot]')
|
|
325
|
-
runs-on:
|
|
325
|
+
runs-on: RunnerLandingZone
|
|
326
326
|
timeout-minutes: 5
|
|
327
327
|
permissions:
|
|
328
328
|
actions: write
|
|
@@ -353,7 +353,7 @@ jobs:
|
|
|
353
353
|
reconcile-bot-pr-runs:
|
|
354
354
|
needs: classify
|
|
355
355
|
if: needs.classify.outputs.route == 'reconcile-bot-pr-runs'
|
|
356
|
-
runs-on:
|
|
356
|
+
runs-on: RunnerLandingZone
|
|
357
357
|
timeout-minutes: 5
|
|
358
358
|
permissions:
|
|
359
359
|
contents: read
|
|
@@ -387,7 +387,7 @@ jobs:
|
|
|
387
387
|
jq -r --arg repo "$REPO" '
|
|
388
388
|
.[]
|
|
389
389
|
| select(
|
|
390
|
-
.user.login == "github-actions[bot]"
|
|
390
|
+
(.user.login == "github-actions[bot]" or .user.login == "app/github-actions" or .user.login == "platform-devbox[bot]")
|
|
391
391
|
and .head.repo.full_name == $repo
|
|
392
392
|
and .mergeable_state != "dirty"
|
|
393
393
|
)
|
|
@@ -406,12 +406,25 @@ jobs:
|
|
|
406
406
|
gh api "repos/$REPO/actions/runs/$run_id/approve" --method POST
|
|
407
407
|
done
|
|
408
408
|
|
|
409
|
+
# Check if merge-gate already ran for this PR (comment on PR or linked issue)
|
|
409
410
|
gate_recorded=$(gh api "repos/$REPO/issues/$pr_number/comments?per_page=100" \
|
|
410
411
|
--jq 'any(.[]; .body | contains("<!-- agent-merge-gate -->"))')
|
|
411
412
|
if [ "$gate_recorded" = "true" ]; then
|
|
413
|
+
echo "Merge gate already recorded for PR #$pr_number, skipping"
|
|
412
414
|
continue
|
|
413
415
|
fi
|
|
414
416
|
|
|
417
|
+
# Also check the linked issue comments if the PR closes an issue
|
|
418
|
+
linked_issue=$(gh pr view "$pr_number" --repo "$REPO" --json closingIssuesReferences --jq '.closingIssuesReferences[0].number // empty' 2>/dev/null || true)
|
|
419
|
+
if [ -n "$linked_issue" ]; then
|
|
420
|
+
gate_recorded=$(gh api "repos/$REPO/issues/$linked_issue/comments?per_page=100" \
|
|
421
|
+
--jq 'any(.[]; .body | contains("<!-- agent-merge-gate -->"))')
|
|
422
|
+
if [ "$gate_recorded" = "true" ]; then
|
|
423
|
+
echo "Merge gate already recorded on issue #$linked_issue for PR #$pr_number, skipping"
|
|
424
|
+
continue
|
|
425
|
+
fi
|
|
426
|
+
fi
|
|
427
|
+
|
|
415
428
|
ci=$(gh api "repos/$REPO/actions/runs?branch=$branch&per_page=100" \
|
|
416
429
|
--jq '[.workflow_runs[]
|
|
417
430
|
| select(
|
|
@@ -439,7 +452,7 @@ jobs:
|
|
|
439
452
|
audit-close:
|
|
440
453
|
needs: classify
|
|
441
454
|
if: needs.classify.outputs.route == 'audit-close'
|
|
442
|
-
runs-on:
|
|
455
|
+
runs-on: RunnerLandingZone
|
|
443
456
|
timeout-minutes: 15
|
|
444
457
|
concurrency:
|
|
445
458
|
group: audit-close
|
|
@@ -459,7 +472,7 @@ jobs:
|
|
|
459
472
|
cleanup-artifacts:
|
|
460
473
|
needs: classify
|
|
461
474
|
if: needs.classify.outputs.route == 'cleanup-artifacts' && !github.event.repository.fork
|
|
462
|
-
runs-on:
|
|
475
|
+
runs-on: RunnerLandingZone
|
|
463
476
|
timeout-minutes: 15
|
|
464
477
|
concurrency:
|
|
465
478
|
group: cleanup-artifacts
|
|
@@ -480,7 +493,7 @@ jobs:
|
|
|
480
493
|
stale-recovery:
|
|
481
494
|
needs: classify
|
|
482
495
|
if: needs.classify.outputs.route == 'stale-recovery'
|
|
483
|
-
runs-on:
|
|
496
|
+
runs-on: RunnerLandingZone
|
|
484
497
|
timeout-minutes: 15
|
|
485
498
|
concurrency:
|
|
486
499
|
group: stale-recovery
|
|
@@ -503,7 +516,7 @@ jobs:
|
|
|
503
516
|
validate:
|
|
504
517
|
needs: classify
|
|
505
518
|
if: needs.classify.outputs.route == 'validate'
|
|
506
|
-
runs-on:
|
|
519
|
+
runs-on: RunnerLandingZone
|
|
507
520
|
timeout-minutes: 10
|
|
508
521
|
permissions:
|
|
509
522
|
contents: read
|