Skip to content

Commit 2f48003

Browse files
feat: enhance workflow for implementation generation
- Add pending label before dispatching workflow - Implement retry mechanism for dispatching with exponential backoff - Ensure implementations directory exists for new specifications - Improve failure handling with automatic retries and comments
1 parent 8183965 commit 2f48003

3 files changed

Lines changed: 151 additions & 66 deletions

File tree

.github/workflows/bulk-generate.yml

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,26 +169,71 @@ jobs:
169169
echo "::warning::$SPEC_YAML not found"
170170
fi
171171
172+
- name: Add pending label before dispatch
173+
if: steps.spec.outputs.issue_number != ''
174+
env:
175+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
176+
ISSUE: ${{ steps.spec.outputs.issue_number }}
177+
LIBRARY: ${{ matrix.library }}
178+
run: |
179+
# Add pending label BEFORE dispatch so we can track what was attempted
180+
gh issue edit "$ISSUE" --add-label "impl:${LIBRARY}:pending" 2>/dev/null || true
181+
172182
- name: Trigger impl-generate for ${{ matrix.specification_id }} / ${{ matrix.library }}
173183
env:
174184
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
175185
ISSUE: ${{ steps.spec.outputs.issue_number }}
186+
SPEC_ID: ${{ matrix.specification_id }}
187+
LIBRARY: ${{ matrix.library }}
176188
run: |
177-
echo "Triggering impl-generate.yml for ${{ matrix.specification_id }} / ${{ matrix.library }}"
178-
179-
# Run workflow with optional issue_number (avoid eval for security)
180-
if [ -n "$ISSUE" ]; then
181-
gh workflow run impl-generate.yml --repo ${{ github.repository }} \
182-
-f specification_id="${{ matrix.specification_id }}" \
183-
-f library="${{ matrix.library }}" \
184-
-f issue_number="$ISSUE"
185-
else
186-
gh workflow run impl-generate.yml --repo ${{ github.repository }} \
187-
-f specification_id="${{ matrix.specification_id }}" \
188-
-f library="${{ matrix.library }}"
189-
fi
189+
echo "Triggering impl-generate.yml for ${SPEC_ID} / ${LIBRARY}"
190+
191+
# Retry dispatch up to 3 times with exponential backoff
192+
MAX_RETRIES=3
193+
RETRY_DELAY=5
194+
195+
for attempt in $(seq 1 $MAX_RETRIES); do
196+
echo "Dispatch attempt $attempt/$MAX_RETRIES..."
197+
198+
# Run workflow with optional issue_number
199+
if [ -n "$ISSUE" ]; then
200+
gh workflow run impl-generate.yml --repo ${{ github.repository }} \
201+
-f specification_id="${SPEC_ID}" \
202+
-f library="${LIBRARY}" \
203+
-f issue_number="$ISSUE" && DISPATCHED=true || DISPATCHED=false
204+
else
205+
gh workflow run impl-generate.yml --repo ${{ github.repository }} \
206+
-f specification_id="${SPEC_ID}" \
207+
-f library="${LIBRARY}" && DISPATCHED=true || DISPATCHED=false
208+
fi
209+
210+
if [ "$DISPATCHED" = true ]; then
211+
echo "::notice::Dispatched impl-generate for ${SPEC_ID} / ${LIBRARY} (issue: ${ISSUE:-none})"
212+
213+
# Wait and verify workflow appears in run list
214+
sleep 5
215+
FOUND=$(gh run list --workflow=impl-generate.yml --limit 10 --json displayTitle,createdAt \
216+
--jq "[.[] | select(.displayTitle | test(\"${LIBRARY}\"))] | length")
190217
191-
echo "::notice::Dispatched impl-generate for ${{ matrix.specification_id }} / ${{ matrix.library }} (issue: ${ISSUE:-none})"
218+
if [ "$FOUND" -gt 0 ]; then
219+
echo "::notice::Verified workflow run started"
220+
break
221+
else
222+
echo "::warning::Workflow dispatched but not found in run list, retrying..."
223+
fi
224+
fi
225+
226+
if [ "$attempt" -lt "$MAX_RETRIES" ]; then
227+
echo "Waiting ${RETRY_DELAY}s before retry..."
228+
sleep $RETRY_DELAY
229+
RETRY_DELAY=$((RETRY_DELAY * 2))
230+
fi
231+
done
232+
233+
if [ "$DISPATCHED" != true ]; then
234+
echo "::error::Failed to dispatch workflow after $MAX_RETRIES attempts"
235+
exit 1
236+
fi
192237
193238
# ============================================================================
194239
# Summary

.github/workflows/impl-generate.yml

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ jobs:
244244
echo "is_regeneration=false" >> $GITHUB_OUTPUT
245245
fi
246246
247+
- name: Ensure implementations directory exists
248+
env:
249+
SPEC_ID: ${{ steps.inputs.outputs.specification_id }}
250+
run: |
251+
# Create implementations directory if it doesn't exist (for new specs)
252+
mkdir -p "plots/${SPEC_ID}/implementations"
253+
echo "::notice::Ensured implementations directory exists"
254+
247255
- name: Run Claude Code to generate implementation
248256
id: claude
249257
continue-on-error: true
@@ -615,7 +623,7 @@ jobs:
615623
fi
616624
617625
# ========================================================================
618-
# Failure handling: Track failures and clean up labels
626+
# Failure handling: Track failures via comments and auto-retry
619627
# ========================================================================
620628
- name: Handle generation failure
621629
if: failure() && steps.issue.outputs.number != ''
@@ -627,43 +635,60 @@ jobs:
627635
run: |
628636
echo "::notice::Handling generation failure for $LIBRARY/$SPEC_ID"
629637
630-
# Count previous failed generation runs for this spec/library
631-
# Filter by both library AND spec ID to avoid counting unrelated failures
632-
FAILURE_COUNT=$(gh run list \
633-
--workflow=impl-generate.yml \
634-
--limit 20 \
635-
--json conclusion,displayTitle,createdAt \
636-
-q "[.[] | select(.conclusion == \"failure\") | select(.displayTitle | (contains(\"$LIBRARY\") and contains(\"$SPEC_ID\")))] | length" \
637-
2>/dev/null || echo "0")
638+
# Count previous failures via hidden marker comments (more reliable than workflow runs)
639+
MARKER="<!-- impl-fail:${SPEC_ID}:${LIBRARY} -->"
640+
FAILURE_COUNT=$(gh api "repos/${{ github.repository }}/issues/${ISSUE}/comments" \
641+
--jq "[.[] | select(.body | contains(\"$MARKER\"))] | length" 2>/dev/null || echo "0")
638642
639-
echo "::notice::Previous failures: $FAILURE_COUNT"
643+
echo "::notice::Previous failures for ${LIBRARY}/${SPEC_ID}: $FAILURE_COUNT"
640644
641-
# After 3 failures, mark as failed (current run is the 3rd)
642-
if [ "$FAILURE_COUNT" -ge 2 ]; then
643-
echo "::warning::Marking $LIBRARY as failed after multiple generation failures"
645+
# After 1 previous failure (= this is attempt 2) → mark as failed
646+
if [ "$FAILURE_COUNT" -ge 1 ]; then
647+
echo "::warning::Marking $LIBRARY as failed after 2 generation attempts"
644648
645649
# Create failed label if needed
646650
gh label create "impl:${LIBRARY}:failed" --color "d73a4a" \
647651
--description "${LIBRARY} implementation failed" 2>/dev/null || true
648652
649-
# Remove stale labels and add failed (Fix #2: clean up duplicates)
653+
# Remove stale labels and add failed
650654
gh issue edit "$ISSUE" \
651655
--remove-label "generate:${LIBRARY},impl:${LIBRARY}:pending" \
652656
--add-label "impl:${LIBRARY}:failed" 2>/dev/null || true
653657
654-
# Post failure comment
655-
gh issue comment "$ISSUE" --body "## :x: ${LIBRARY} Failed
658+
# Post final failure comment with marker
659+
gh issue comment "$ISSUE" --body "${MARKER}
660+
## :x: ${LIBRARY} Failed (Attempt 2/2)
661+
662+
The **${LIBRARY}** implementation for \`${SPEC_ID}\` failed after 2 attempts.
656663
657-
The **${LIBRARY}** implementation for \`${SPEC_ID}\` failed after multiple attempts.
664+
**Reason:** Claude Code failed to create the implementation file.
658665
659-
This may indicate that the library cannot implement this plot type natively.
666+
To retry manually:
667+
\`\`\`
668+
gh workflow run impl-generate.yml -f specification_id=${SPEC_ID} -f library=${LIBRARY} -f issue_number=${ISSUE}
669+
\`\`\`
660670
661671
---
662672
:robot: *[impl-generate](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*"
663673
664674
else
665-
# Not enough failures yet - just clean up stale generate label
666-
# Keep pending label for retry
675+
# First failure → post comment with marker and auto-retry
676+
gh issue comment "$ISSUE" --body "${MARKER}
677+
## :warning: ${LIBRARY} Generation Failed (Attempt 1/2)
678+
679+
First attempt failed. Automatically retrying...
680+
681+
---
682+
:robot: *[impl-generate](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*"
683+
684+
# Clean up generate label before retry
667685
gh issue edit "$ISSUE" --remove-label "generate:${LIBRARY}" 2>/dev/null || true
668-
echo "::notice::Cleaned up generate label, keeping pending for retry"
686+
687+
# Automatic retry via workflow_dispatch
688+
gh workflow run impl-generate.yml \
689+
-f specification_id="${SPEC_ID}" \
690+
-f library="${LIBRARY}" \
691+
-f issue_number="${ISSUE}"
692+
693+
echo "::notice::Triggered automatic retry for ${LIBRARY}/${SPEC_ID}"
669694
fi
Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,45 @@
11
# Generate Implementation
22

3-
You are generating the **{LIBRARY}** implementation for **{SPEC_ID}**.
3+
**YOUR PRIMARY TASK: Create a working Python plot implementation file.**
44

5-
**Regeneration:** {IS_REGENERATION}
5+
You MUST create: `plots/{SPEC_ID}/implementations/{LIBRARY}.py`
66

7-
## Step 1: Read required files
7+
This is NOT optional. The workflow will FAIL if this file does not exist after you finish.
88

9-
1. `prompts/plot-generator.md` - Base generation rules (IMPORTANT: Read the "Regeneration" section!)
10-
2. `prompts/default-style-guide.md` - Visual style requirements
11-
3. `prompts/quality-criteria.md` - Quality requirements
12-
4. `prompts/library/{LIBRARY}.md` - Library-specific rules
13-
5. `plots/{SPEC_ID}/specification.md` - The specification
9+
---
1410

15-
## Step 1b: If Regeneration, read previous feedback
11+
**Variables:**
12+
- LIBRARY: {LIBRARY}
13+
- SPEC_ID: {SPEC_ID}
14+
- Regeneration: {IS_REGENERATION}
1615

17-
If this is a regeneration ({IS_REGENERATION} == true):
16+
## Step 1: Read the rules (quickly)
1817

19-
1. Read `plots/{SPEC_ID}/metadata/{LIBRARY}.yaml`
20-
- Look at `review.strengths` (keep these aspects!)
21-
- Look at `review.weaknesses` (fix these problems - decide HOW yourself)
22-
- Look at `review.image_description` (understand what was generated visually)
23-
- Look at `review.criteria_checklist` (see exactly which criteria failed)
24-
- Focus on categories with low scores (e.g., visual_quality.score < visual_quality.max)
25-
- Check items with `passed: false` - these need fixing
26-
- VQ-XX items for visual issues
27-
- SC-XX items for spec compliance
28-
- CQ-XX items for code quality
29-
2. Read `plots/{SPEC_ID}/implementations/{LIBRARY}.py`
30-
- Understand what was done before
31-
- Keep what worked, fix what didn't
18+
Read these files to understand the requirements:
3219

33-
## Step 2: Generate implementation
20+
1. `prompts/plot-generator.md` - Base generation rules
21+
2. `prompts/library/{LIBRARY}.md` - Library-specific rules (CRITICAL!)
22+
3. `plots/{SPEC_ID}/specification.md` - What to visualize
3423

35-
Create: `plots/{SPEC_ID}/implementations/{LIBRARY}.py`
24+
Optional (if regenerating):
25+
- `plots/{SPEC_ID}/metadata/{LIBRARY}.yaml` - Previous review feedback
26+
- `plots/{SPEC_ID}/implementations/{LIBRARY}.py` - Previous implementation
27+
28+
## Step 2: CREATE THE FILE (MANDATORY)
29+
30+
**You MUST use the Write tool to create:**
31+
32+
```
33+
plots/{SPEC_ID}/implementations/{LIBRARY}.py
34+
```
3635

3736
The script MUST:
38-
- Save as `plot.png` in the current directory
37+
- Follow the KISS structure: imports → data → plot → save
38+
- Save output as `plot.png` in current directory
3939
- For interactive libraries (plotly, bokeh, altair, highcharts, pygal, letsplot): also save `plot.html`
4040

41+
**DO NOT SKIP THIS STEP. The file MUST be created.**
42+
4143
## Step 3: Test and fix (up to 3 attempts)
4244

4345
Run the implementation:
@@ -64,7 +66,17 @@ ruff format plots/{SPEC_ID}/implementations/{LIBRARY}.py
6466
ruff check --fix plots/{SPEC_ID}/implementations/{LIBRARY}.py
6567
```
6668

67-
## Step 6: Commit
69+
## Step 6: Verify file exists (CRITICAL)
70+
71+
Before committing, verify the implementation file exists:
72+
73+
```bash
74+
ls -la plots/{SPEC_ID}/implementations/{LIBRARY}.py
75+
```
76+
77+
**If the file does NOT exist, you MUST go back to Step 2 and create it!**
78+
79+
## Step 7: Commit
6880

6981
```bash
7082
git config user.name "github-actions[bot]"
@@ -74,8 +86,11 @@ git commit -m "feat({LIBRARY}): implement {SPEC_ID}"
7486
git push -u origin implementation/{SPEC_ID}/{LIBRARY}
7587
```
7688

77-
## Report result
89+
## Final Check
90+
91+
Before finishing, confirm:
92+
1.`plots/{SPEC_ID}/implementations/{LIBRARY}.py` exists
93+
2.`plot.png` was generated successfully
94+
3. ✅ Changes were committed and pushed
7895

79-
Print exactly one line:
80-
- `GENERATION_SUCCESS` - if everything worked
81-
- `GENERATION_FAILED: <reason>` - if it failed
96+
If any of these failed, DO NOT report success.

0 commit comments

Comments
 (0)