forked from Ikalus1988/MisakaNet
-
Notifications
You must be signed in to change notification settings - Fork 0
203 lines (174 loc) · 8.96 KB
/
Copy pathintake-auto-review.yml
File metadata and controls
203 lines (174 loc) · 8.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
name: Intake Auto Review
on:
issues:
# Review once per intake. 'labeled' is deliberately excluded: this
# workflow itself applies labels, so listening to it re-triggered the
# review (and posted duplicate comments) on every label change. Manual
# re-review stays available via workflow_dispatch.
types: [opened, reopened]
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to review"
required: true
type: string
jobs:
auto-review:
if: >-
github.event_name == 'workflow_dispatch' ||
contains(github.event.issue.labels.*.name, 'intake') ||
contains(github.event.issue.labels.*.name, 'mcp-intake') ||
startsWith(github.event.issue.title, '[Intake]')
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
env:
ISSUE_NUMBER: ${{ github.event.inputs.issue_number || github.event.issue.number }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: "3.10"
- name: Install dependencies
run: pip install pyyaml jsonschema
- name: Run auto-review
id: review
run: |
# Get issue details
ISSUE_BODY=$(gh issue view $ISSUE_NUMBER --repo ${{ github.repository }} --json body --jq '.body')
ISSUE_TITLE=$(gh issue view $ISSUE_NUMBER --repo ${{ github.repository }} --json title --jq '.title')
# Save body to temp file
echo "$ISSUE_BODY" > /tmp/issue_body.txt
# Structured Kind wins: question/knowledge-gap intakes are NOT lesson
# candidates — skip lesson scoring + badcase archiving entirely and
# route them as questions. (Observed on #1396: a Portuguese question
# got scored 16.9/100, auto-rejected and archived as if it were a
# malformed lesson, with no answer channel.)
KIND=$(sed -n 's/^\*\*Kind:\*\*[[:space:]]*//p' /tmp/issue_body.txt | head -1 | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')
echo "kind=$KIND" >> "$GITHUB_OUTPUT"
if [ "$KIND" = "question" ]; then
echo "Question intake (#$ISSUE_NUMBER) — skipping lesson auto-review."
echo "decision=question" >> "$GITHUB_OUTPUT"
echo "final_score=-1" >> "$GITHUB_OUTPUT"
echo "lesson_title=" >> "$GITHUB_OUTPUT"
echo "lesson_domain=" >> "$GITHUB_OUTPUT"
echo "lesson_tags=" >> "$GITHUB_OUTPUT"
echo "archive_path=" >> "$GITHUB_OUTPUT"
exit 0
fi
# Run auto-review with archiving (exit code 1 = reject, not an error)
RESULT=$(python3 scripts/intake_auto_review.py \
--issue $ISSUE_NUMBER \
--title "$ISSUE_TITLE" \
--file /tmp/issue_body.txt \
--archive \
--json 2>&1) || true
# Parse result
DECISION=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['decision'])")
FINAL_SCORE=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['final_score'])")
LESSON_TITLE=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['lesson_title'])")
LESSON_DOMAIN=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['lesson_domain'])")
LESSON_TAGS=$(echo "$RESULT" | python3 -c "import sys,json; print(','.join(json.load(sys.stdin)['lesson_tags']))")
ARCHIVE_PATH=$(echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('archive',{}).get('archive_path',''))" 2>/dev/null || echo "")
echo "decision=$DECISION" >> "$GITHUB_OUTPUT"
echo "final_score=$FINAL_SCORE" >> "$GITHUB_OUTPUT"
echo "lesson_title=$LESSON_TITLE" >> "$GITHUB_OUTPUT"
echo "lesson_domain=$LESSON_DOMAIN" >> "$GITHUB_OUTPUT"
echo "lesson_tags=$LESSON_TAGS" >> "$GITHUB_OUTPUT"
echo "archive_path=$ARCHIVE_PATH" >> "$GITHUB_OUTPUT"
# Generate comment (exit code 1 = reject, not an error)
COMMENT=$(python3 scripts/intake_auto_review.py \
--issue $ISSUE_NUMBER \
--title "$ISSUE_TITLE" \
--file /tmp/issue_body.txt 2>&1) || true
# Save comment to file
echo "$COMMENT" > /tmp/review_comment.txt
- name: Post review comment
env:
# Static markdown for the question-routing comment (no heredoc:
# column-0 content would break the YAML block scalar).
QUESTION_COMMENT: |
<!-- misakanet-intake-question -->
## [QUESTION] Treated as a Question, Not a Lesson
This intake carries Kind: `question` (knowledge gap / how-to), so it was **not** run through the lesson auto-review and **not** archived as a badcase.
To turn it into an actionable lesson — or to get a precise answer — please reply with:
- `## Error` — the concrete error/symptom, or a short snippet of the failing interaction
- `## What was tried` — approaches already attempted
- `## Expected` — the outcome you were hoping for
- Context — which agent/tool/harness produced the problem
If it is not a failure case, it stays an open question for maintainer / FAQ handling.
_Automated routing only — no lesson was published or closed._
run: |
DECISION="${{ steps.review.outputs.decision }}"
ARCHIVE_PATH="${{ steps.review.outputs.archive_path }}"
# Question intakes get a routing comment instead of a review verdict.
if [ "$DECISION" = "question" ]; then
if gh issue view $ISSUE_NUMBER --repo ${{ github.repository }} --json comments --jq '.comments[].body' \
| grep -q "## \[QUESTION\]"; then
echo "Question comment already exists — skipping."
exit 0
fi
gh issue comment $ISSUE_NUMBER --repo ${{ github.repository }} --body "$QUESTION_COMMENT"
exit 0
fi
COMMENT=$(cat /tmp/review_comment.txt)
ARCHIVE_PATH="${{ steps.review.outputs.archive_path }}"
# Idempotency guard: if a review comment already exists on this
# issue, skip posting (prevents duplicates on re-runs).
if gh issue view $ISSUE_NUMBER --repo ${{ github.repository }} --json comments --jq '.comments[].body' \
| grep -q "## \[REVIEW\]"; then
echo "Review comment already exists — skipping."
exit 0
fi
# Add archive info to comment if applicable
if [ -n "$ARCHIVE_PATH" ]; then
COMMENT="$COMMENT
📁 **Archived to:** \`$ARCHIVE_PATH\`"
fi
gh issue comment $ISSUE_NUMBER --repo ${{ github.repository }} --body "$COMMENT"
- name: Apply labels
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
DECISION="${{ steps.review.outputs.decision }}"
# Question routing labels — never auto-approved/auto-rejected/salvage.
if [ "$DECISION" = "question" ]; then
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} \
--remove-label "auto-approved" \
--remove-label "auto-rejected" \
--remove-label "needs-salvage" \
--remove-label "type:feature" \
--remove-label "type:bug" 2>/dev/null || true
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} \
--add-label "question" \
--add-label "type:question" \
--add-label "needs-human-review"
exit 0
fi
# Remove existing review labels
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} \
--remove-label "auto-approved" \
--remove-label "auto-rejected" \
--remove-label "needs-human-review" \
--remove-label "pending-review" 2>/dev/null || true
# Apply new label based on decision.
# NOTE: auto-review NEVER auto-creates a lesson PR anymore (removed
# 2026-08-30). Approve only signals a machine recommendation; a
# maintainer must still review the issue body and merge any lesson
# PR manually. This closes the anonymous issue → published-lesson
# poisoning chain (issue body is attacker-controlled).
if [ "$DECISION" = "approve" ]; then
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} \
--add-label "auto-approved" \
--add-label "needs-human-review"
elif [ "$DECISION" = "reject" ]; then
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} \
--add-label "auto-rejected" \
--add-label "needs-salvage"
else
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} \
--add-label "needs-human-review"
fi