Skip to content

feat(plotnine): implement treemap-basic - #9968

Closed
github-actions[bot] wants to merge 2 commits into
mainfrom
implementation/treemap-basic/plotnine
Closed

feat(plotnine): implement treemap-basic#9968
github-actions[bot] wants to merge 2 commits into
mainfrom
implementation/treemap-basic/plotnine

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Implementation: treemap-basic - python/plotnine

Implements the python/plotnine version of treemap-basic.

File: plots/treemap-basic/implementations/python/plotnine.py

Parent Issue: #766


🤖 impl-generate workflow

Regen from quality 80. Addressed:
- palette now uses Imprint colors (canonical order, first series #009E73) instead of custom hexes
- fixed title typo ('pyplots.ai' -> 'anyplot.ai') and added missing 'python' language token per mandated title format
- data-label and chrome text (title, legend) now theme-adaptive via ANYPLOT_THEME instead of hardcoded black
- output now saved as plot-{THEME}.png reading ANYPLOT_THEME, instead of a bare plot.png
- plot/panel background now theme-adaptive (#FAF8F1/#1A1A17) instead of theme_void()'s default
- canvas set to the canonical figure_size=(8, 4.5), dpi=400 -> 3200x1800
- smallest two rectangles left unlabeled per spec note ("smaller ones may omit labels for clarity")
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): Warm off-white background, pixel-confirmed at exactly #FAF8F1. Title reads "Budget Allocation by Department · treemap-basic · python · plotnine · anyplot.ai" in bold dark ink across the top; legend on the right ("Department": Engineering/Finance/HR/Marketing/Operations/Sales) uses an off-white elevated box with readable dark/soft-dark text. 12 rectangles form a squarified treemap colored by parent category (Engineering #009E73 green, Marketing #C475FD lavender, Sales #4467A3 blue, Operations #BD8233 ochre, HR #AE3030 red, Finance #2ABCCD cyan), each labeled with subcategory + dollar value. Not all text is readable: direct pixel sampling of the saved PNG shows solid title-ink pixels already present at row 0, the very first row of the 3200×1800 canvas — the tops of the title letters have been sliced off by the canvas edge. Separately, the "Recruiting $130K" label (dark ink on the red HR rectangle) computes to only 2.71:1 WCAG contrast, below even the large-text 3:1 floor.

Dark render (plot-dark.png): Warm near-black background, pixel-confirmed at exactly #1A1A17. Title and legend correctly flip to light ink (#F0EFE8) / soft-light ink (#B8B7B0) against the dark page and the dark-elevated legend box (#242420). Data colors are confirmed identical to the light render (only chrome flipped, as required). Not all text is readable: the same row-0 title-clipping signature is present here too (this is a hard layout bug, not theme-specific). Additionally, because label text color is tied to the page theme rather than to each rectangle's own fill, several labels become low-contrast here too: "Digital $200K" (light ink on lavender) = 2.49:1, "Accounting $170K" (light ink on cyan) = 1.99:1, "Logistics/Facilities" (light ink on ochre) = 2.84:1 — all fail the WCAG large-text 3:1 floor. This is effectively "dark-on-light-fill," the same failure class as dark-on-dark, just measured against the data color instead of the page background.

Score: 0/100

Category Score Max
Visual Quality 0 30
Design Excellence 0 20
Spec Compliance 0 15
Data Quality 0 15
Code Quality 0 10
Library Mastery 0 10
Total 0 100

Visual Quality (0/30)

  • VQ-01: Text Legibility (0/8) — title clipped at canvas top edge in both renders; multiple labels fail WCAG contrast against their own rectangle fill
  • VQ-02: No Overlap (0/6) — forced to 0 by AR-09 override (no overlap otherwise observed)
  • VQ-03: Element Visibility (0/6) — forced to 0 by AR-09 override (rectangles otherwise clearly visible)
  • VQ-04: Color Accessibility (0/2) — several label/fill pairings under 3:1 contrast
  • VQ-05: Layout & Canvas (0/4) — title clipped at top edge; legend right border sits at the absolute canvas edge with no margin
  • VQ-06: Axis Labels & Title (0/2) — forced to 0 by AR-09 override
  • VQ-07: Palette Compliance (0/2) — forced to 0 by AR-09 override (palette itself is compliant: Engineering #009E73 first, canonical order, theme-correct backgrounds)

Design Excellence (0/20)

  • DE-01: Aesthetic Sophistication (0/8) - forced to 0 by AR-09 override
  • DE-02: Visual Refinement (0/6) - forced to 0 by AR-09 override
  • DE-03: Data Storytelling (0/6) - forced to 0 by AR-09 override

Spec Compliance (0/15)

  • SC-01: Plot Type (0/5) — forced to 0 by AR-09 override (treemap correctly implemented otherwise)
  • SC-02: Required Features (0/4) — forced to 0 by AR-09 override
  • SC-03: Data Mapping (0/3) — forced to 0 by AR-09 override
  • SC-04: Title & Legend (0/3) — forced to 0 by AR-09 override

Data Quality (0/15)

  • DQ-01: Feature Coverage (0/6) — forced to 0 by AR-09 override
  • DQ-02: Realistic Context (0/5) — forced to 0 by AR-09 override
  • DQ-03: Appropriate Scale (0/4) — forced to 0 by AR-09 override

Code Quality (0/10)

  • CQ-01: KISS Structure (0/3) — forced to 0 by AR-09 override
  • CQ-02: Reproducibility (0/2) — forced to 0 by AR-09 override
  • CQ-03: Clean Imports (0/2) — forced to 0 by AR-09 override
  • CQ-04: Code Elegance (0/2) — forced to 0 by AR-09 override
  • CQ-05: Output & API (0/1) — forced to 0 by AR-09 override

Library Mastery (0/10)

  • LM-01: Idiomatic Usage (0/5) — forced to 0 by AR-09 override
  • LM-02: Distinctive Features (0/5) - forced to 0 by AR-09 override (hand-rolled squarified treemap via geom_rect is a genuinely distinctive workaround for plotnine's lack of a native treemap geom)

Score Caps Applied

  • AR-09 (Edge Clipping) — Score forced to 0 / REJECTED. Verified by direct pixel sampling, not visual impression alone: both plot-light.png and plot-dark.png have solid title-ink pixels at row 0 (the literal first row of the saved 3200×1800 PNG), with pixel counts rising steadily through rows 1-3 — the classic signature of a capital letter's top being sliced off by the canvas boundary. This is not "touching the border," it's missing pixels.

Strengths

  • Categorical colors follow the Imprint canonical order with Engineering (first series) correctly at #009E73
  • Plot backgrounds are exact theme tokens: #FAF8F1 light / #1A1A17 dark, verified by direct pixel sampling
  • Squarified treemap layout is a genuine, creative use of geom_rect + geom_text to implement a plot type plotnine has no native geom for
  • Legend background/text correctly use theme-adaptive ELEVATED_BG/INK_SOFT tokens
  • Value-based label thresholding (only rectangles ≥ $100K get a label) is a sensible, spec-aligned readability choice

Weaknesses

  • AR-09 title clipping (top edge, both renders) — pixel sampling shows solid title-ink pixels already at row 0 of the saved PNG, rising through rows 2-3 (63 → 108 → 125 matching pixels at strict tolerance), confirming the tops of the title letters were rendered outside the canvas and are gone for good, in both plot-light.png and plot-dark.png.
  • Label/rectangle contrast failuresgeom_text(color=INK, ...) ties label color to the page theme instead of each rectangle's own fill. Computed WCAG contrast: light-theme red rect (Recruiting) = 2.71:1; dark-theme lavender (Digital) = 2.49:1, cyan (Accounting) = 1.99:1, ochre (Logistics/Facilities) = 2.84:1 — all fail even the large-text 3:1 floor.
  • Legend's right border sits within ~2-3px of the canvas's absolute right edge — not clipped, but leaves no whitespace margin on that side.
  • White (color='white') cell borders are a fixed, non-theme-adaptive choice; works visually on both backgrounds here but is worth a deliberate look if repair touches this area.
  • The squarified layout algorithm (~80 lines of inline nested loops) makes the Imports→Data→Plot→Save flow harder to scan than most catalog implementations, though it's necessary since plotnine has no native treemap geom.

Issues Found

  1. AR-09 CRITICAL: Title clipped at top edge of canvas in both light and dark renders (pixel-verified)
    • Fix: Add real top padding so the title's ascenders clear row 0 — e.g. theme(plot_margin={'t': 0.04, ...}), or add a top value to plot_title's margin={'t': 10, 'b': 12}, and/or add general whitespace above the treemap area. theme_void() strips the default panel margins that would otherwise protect the title, so explicit top margin is required here.
  2. VQ-01/VQ-04 HIGH: Data label text color tied to page theme instead of rectangle fill, causing WCAG-failing contrast on several category/theme combinations
    • Fix: Choose each label's text color from its own rectangle's fill luminance (e.g. white text on the darker fills — blue/green/red — and near-black text on the lighter fills — lavender/cyan/ochre), independent of ANYPLOT_THEME, so labels always contrast their own box color rather than the page background.

AI Feedback for Next Attempt

Two concrete, pixel-verified defects to fix: (1) the title is clipped at the top of the canvas in both themes — give it real top padding/margin so no letter pixels touch row 0; theme_void() removes the default protective margin so this needs to be added explicitly. (2) data labels use a single page-theme-driven ink color for every rectangle, which fails WCAG contrast against several of the Imprint fill colors (red in light mode; lavender/cyan/ochre in dark mode) — pick the label color per-rectangle from that rectangle's own fill luminance instead of from the page theme. Everything else (palette assignment, legend, data mapping, treemap layout) is in good shape and can stay as-is.

Verdict: REJECTED

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

🔧 AI Review Produced No Score — Auto-Retrying

The Claude Code Action ran but didn't write quality_score.txt. Auto-retrying review once...


🤖 impl-review

@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): A squarified treemap on the #FAF8F1 warm off-white surface, showing budget allocation across six departments (Engineering, Marketing, Sales, HR, Operations, Finance) with twelve sub-category rectangles (R&D, Infrastructure, QA, Digital, Events, Direct, Channel, Support, Logistics, Facilities, Recruiting, Accounting). Rectangles are filled with the Imprint categorical palette (Engineering = #009E73 green, matching the required first-series color), separated by white borders, with bold dark-ink labels ("subcategory\n$valueK") centered in each rectangle large enough to hold text. A "Department" legend sits to the right with color swatches. The title reads "Budget Allocation by Department · treemap-basic · python · plotnine · anyplot.ai" in bold dark text at the top. However, the title is not fully readable — the tops of the capital letters ("B", "A", "D", etc.) are visibly chopped off at the very top edge of the canvas; this is a hard-border clipping issue, not just a tight margin.

Dark render (plot-dark.png): Same layout and data on the #1A1A17 warm near-black surface. Chrome correctly flips: title and rectangle labels render in light ink, legend swatches keep identical Imprint colors to the light render (confirmed: Engineering green, Marketing purple, Sales blue, HR red, Operations amber, Finance cyan are pixel-identical hues between the two renders — only chrome flipped, as required). Rectangle borders and legend box read clearly against the dark background. The same title clipping defect is present here too — the tops of the letters are cut off at the top canvas edge, identically to the light render.

Both paragraphs above required and provided. Text elsewhere (rectangle labels, axis-free legend, legend title/text) is fully legible in both themes — the only legibility failure is the top-clipped title.

Score: 0/100

Category Score Max
Visual Quality 0 30
Design Excellence 0 20
Spec Compliance 0 15
Data Quality 0 15
Code Quality 0 10
Library Mastery 0 10
Total 0 100

Auto-Reject: AR-09 (Edge Clipping)

Title clipped at top edge in BOTH light and dark renders — the tops of the capital letters in "Budget Allocation by Department · treemap-basic · python · plotnine · anyplot.ai" are visibly missing pixels at the canvas's top border (a zoomed crop of the top ~150 px confirms letters like "B", "A", "D" are shaved off, not just tight-to-the-edge). This is a hard auto-reject per AR-09 — pixels are actually missing, not merely close to the border.

Likely cause: the implementation uses theme_void() (which strips plotnine's default plot margins) combined with a plot_title that only sets a bottom margin (margin={"b": 12}) and no top margin / no explicit plot_margin. With no top breathing room reserved above the title, plotnine's matplotlib backend renders the title flush against — and partly outside — the top of the 3200×1800 canvas.

Fix direction for repair: add top margin so the title has room to render fully inside the canvas — either add theme(plot_margin=...) with a non-zero top value, or add a top margin to plot_title (e.g. margin={"t": 6, "b": 12}), or reduce the title's implicit top offset introduced by theme_void(). Verify by re-cropping the top 100–150 px of both renders after the fix — full ascenders of every capital letter must be visible with no missing pixels.

Visual Quality (0/30)

  • VQ-01: Text Legibility (0/8) — Title unreadable at the top: letters chopped mid-character. Rectangle labels and legend are otherwise legible in both themes.
  • VQ-02: No Overlap (5/6) — No collisions between rectangle labels, data, or legend.
  • VQ-03: Element Visibility (5/6) — Labels appropriately shown only on larger rectangles (≥$100K), smaller ones correctly left unlabeled per spec's "Notes" guidance.
  • VQ-04: Color Accessibility (2/2) — Imprint palette provides good hue separation; no red-green-only encoding.
  • VQ-05: Layout & Canvas (0/4) — Canvas border violation (title clipped) — forced to 0 alongside AR-09.
  • VQ-06: Axis Labels & Title (0/2) — Title present and descriptive but not fully rendered inside canvas.
  • VQ-07: Palette Compliance (2/2) — First series #009E73 (Engineering) confirmed; canonical Imprint order used for the 6 departments; identical data colors between light/dark; correct #FAF8F1/#1A1A17 backgrounds.

(Category total forced to 0 by AR-09 auto-reject regardless of the itemized sum above.)

Design Excellence (0/20)

  • DE-01: Aesthetic Sophistication (4/8) - Squarified layout, clean white rectangle borders, custom palette — solid baseline polish, but AR-09 caps the category.
  • DE-02: Visual Refinement (2/6) - theme_void() gives a clean chrome-free look; grid/spines correctly absent for a treemap.
  • DE-03: Data Storytelling (2/6) - Rectangle size clearly communicates part-to-whole magnitude; color groups sub-categories under departments effectively.

Spec Compliance (0/15)

  • SC-01: Plot Type (5/5) - Genuine treemap via geom_rect with a squarified layout algorithm — not a substitute chart type.
  • SC-02: Required Features (4/4) - Distinct department colors, borders between rectangles, labels on larger rectangles only, hierarchy shown via nesting + color — all "Notes" requirements met.
  • SC-03: Data Mapping (3/3) - Rectangle area proportional to value; category/subcategory hierarchy correctly reflected.
  • SC-04: Title & Legend (0/3) - Title text content and legend are correct, but the title is not fully visible (clipped) — 0 per AR-09.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) - 6 categories, 12 subcategories, realistic budget hierarchy — well within the 5–50 item spec range.
  • DQ-02: Realistic Context (5/5) - Plausible, neutral company budget-by-department example (R&D $450K, Direct sales $350K, etc.).
  • DQ-03: Appropriate Scale (4/4) - Dollar values ($80K–$450K) are sensible for a department budget context.

Code Quality (9/10)

  • CQ-01: KISS Structure (3/3) - No functions/classes; flat script.
  • CQ-02: Reproducibility (2/2) - Fully deterministic (no RNG; static data).
  • CQ-03: Clean Imports (2/2) - Only imports used plotnine symbols + pandas + os.
  • CQ-04: Code Elegance (2/2) - Inline squarified algorithm is verbose but reasonable given plotnine has no native treemap geom; no fake UI.
  • CQ-05: Output & API (0/1) - Saves as plot-{THEME}.png correctly, but the output is defective (clipped title) — see AR-09.

Library Mastery (4/10)

  • LM-01: Idiomatic Usage (3/5) - Correct ggplot() + geom_rect() + geom_text() + scale_fill_manual() + theme_void() composition; idiomatic grammar-of-graphics style despite treemap layout requiring a manual algorithm (plotnine has no native treemap geom).
  • LM-02: Distinctive Features (1/5) - Standard geom layering; no distinctive plotnine-only feature beyond the manual layout.

Score Caps Applied

  • AR-09 (Edge Clipping) triggered — Score forced to 0/100 regardless of itemized subscores above, per the mandatory Auto-Reject gate.

Strengths

  • Genuine squarified-treemap layout algorithm implemented natively in plotnine (no matplotlib fallback), correctly assigning rectangle area proportional to value.
  • Imprint palette applied correctly: first series #009E73, canonical department color order, and pixel-identical data colors between light and dark renders — only chrome flips.
  • Labels shown only on larger rectangles (≥$100K) per the spec's "Notes" guidance on avoiding clutter on small rectangles; smaller rectangles correctly left unlabeled.
  • Data is realistic, neutral, and appropriately scaled (department budget breakdown, $80K–$450K).

Weaknesses

  • Title clipped at the top edge of the canvas in BOTH renders (AR-09) — top of capital letters ("B", "A", "D", etc.) is visibly missing. Root cause is almost certainly theme_void() removing default plot margins combined with plot_title only specifying a bottom margin (margin={"b": 12}) and no top margin/plot_margin. Add top breathing room (e.g. plot_margin= with non-zero top, or margin={"t": 6, "b": 12} on plot_title) so the full title renders inside the 3200×1800 canvas with zero missing pixels.

Issues Found

  1. AR-09 CRITICAL: Title cropped at the top edge of the canvas in both light and dark renders — top of every capital letter is chopped off.
    • Fix: Reserve top margin space for the title (e.g. add plot_margin with a non-zero top value in the theme() call, or set margin={"t": 6, "b": 12} on plot_title) so the whole title, including ascenders, renders fully inside the canvas bounds in both themes.

AI Feedback for Next Attempt

The layout, palette, and data are solid — focus entirely on the AR-09 fix: the title is being clipped at the top of the canvas in both renders. theme_void() strips plotnine's default plot margins, and the current plot_title only reserves a bottom margin (margin={"b": 12}), leaving no room above the title. Add top margin via theme(plot_margin=...) or plot_title=element_text(..., margin={"t": 6, "b": 12}) and re-verify by visually inspecting the top ~100 px of both plot-light.png and plot-dark.png — every letter's ascender must be fully visible with zero missing pixels before resubmitting.

Verdict: REJECTED

@github-actions github-actions Bot added the ai-review-failed AI review action failed or timed out label Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

❌ AI Review Failed (auto-retry exhausted)

The AI review action completed but did not produce valid output files. Auto-retry already tried once.

What happened:

  • The Claude Code Action ran
  • No quality_score.txt file was created

Manual rerun:

gh workflow run impl-review.yml -f pr_number=9968

🤖 impl-review

@github-actions github-actions Bot added ai-review-rescued Review re-dispatched once after ai-review-failed and removed ai-review-failed AI review action failed or timed out labels Aug 4, 2026
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): Warm off-white background (#FAF8F1). A squarified treemap of 12 rectangles grouped by department (Engineering green #009E73, Marketing lavender #C475FD, Sales blue #4467A3, Operations ochre #BD8233, HR red #AE3030, Finance cyan #2ABCCD), each rectangle labeled with its subcategory name and dollar value in bold dark text, separated by white borders. A "Department" legend with color swatches sits at the right in an elevated cream box. Body text (rectangle labels, legend) is clearly readable against both the page background and the colored rectangle fills. However, the title "Budget Allocation by Department · treemap-basic · python · plotnine · anyplot.ai" is clipped at the very top of the canvas — the tops of the capital letters (B, A, D, etc.) are flatly cut off, pixels missing.

Dark render (plot-dark.png): Warm near-black background (#1A1A17). Data colors are identical to the light render (verified: green/purple/blue/ochre/red/cyan unchanged) — only chrome (background, title/legend text color) flipped to light tones. Rectangle labels remain readable (dark-ink text is now light-toned via the theme, sufficient contrast against the colored fills). No dark-on-dark background/label failures. The title suffers the identical clipping problem as the light render — top of the letters is cut off at the canvas's top edge.

Both renders otherwise look clean and well laid out, but the title clipping is a hard failure common to both.

Score: 0/100

Category Score Max
Visual Quality 0 30
Design Excellence 0 20
Spec Compliance 0 15
Data Quality 0 15
Code Quality 0 10
Library Mastery 0 10
Total 0 100

Visual Quality (0/30)

  • VQ-01: Text Legibility (0/8) - N/A, auto-reject overrides
  • VQ-02: No Overlap (0/6) - N/A, auto-reject overrides
  • VQ-03: Element Visibility (0/6) - N/A, auto-reject overrides
  • VQ-04: Color Accessibility (0/2) - N/A, auto-reject overrides
  • VQ-05: Layout & Canvas (0/4) - N/A, auto-reject overrides
  • VQ-06: Axis Labels & Title (0/2) - N/A, auto-reject overrides
  • VQ-07: Palette Compliance (0/2) - N/A, auto-reject overrides

Design Excellence (0/20)

  • DE-01: Aesthetic Sophistication (0/8) - N/A, auto-reject overrides
  • DE-02: Visual Refinement (0/6) - N/A, auto-reject overrides
  • DE-03: Data Storytelling (0/6) - N/A, auto-reject overrides

Spec Compliance (0/15)

  • SC-01: Plot Type (0/5) - N/A, auto-reject overrides
  • SC-02: Required Features (0/4) - N/A, auto-reject overrides
  • SC-03: Data Mapping (0/3) - N/A, auto-reject overrides
  • SC-04: Title & Legend (0/3) - N/A, auto-reject overrides

Data Quality (0/15)

  • DQ-01: Feature Coverage (0/6) - N/A, auto-reject overrides
  • DQ-02: Realistic Context (0/5) - N/A, auto-reject overrides
  • DQ-03: Appropriate Scale (0/4) - N/A, auto-reject overrides

Code Quality (0/10)

  • CQ-01: KISS Structure (0/3) - N/A, auto-reject overrides
  • CQ-02: Reproducibility (0/2) - N/A, auto-reject overrides
  • CQ-03: Clean Imports (0/2) - N/A, auto-reject overrides
  • CQ-04: Code Elegance (0/2) - N/A, auto-reject overrides
  • CQ-05: Output & API (0/1) - N/A, auto-reject overrides

Library Mastery (0/10)

  • LM-01: Idiomatic Usage (0/5) - N/A, auto-reject overrides
  • LM-02: Distinctive Features (0/5) - N/A, auto-reject overrides

Score Caps Applied

  • AR-09 (Edge Clipping) triggered — Score forced to 0/100 regardless of other quality, per the auto-reject rule in prompts/quality-criteria.md.

Strengths

  • Squarified treemap layout algorithm is correctly implemented and produces sensible rectangle proportions matching the underlying values
  • Imprint palette applied in canonical order with #009E73 for the first category (Engineering)
  • Rectangle labels conditionally omitted for the smallest items (< $100K), matching the spec's "smaller ones may omit labels for clarity" guidance
  • Theme-adaptive chrome (background, ink tokens) correctly threaded through for legend and body text
  • Data colors verified identical between light and dark renders — only chrome flipped

Weaknesses

  • AR-09 EDGE CLIPPING (critical, blocks approval): The plot title "Budget Allocation by Department · treemap-basic · python · plotnine · anyplot.ai" is clipped at the top edge of the canvas in both the light and dark renders — the tops of capital letters are visibly cut off (confirmed via pixel-level crop of the top-left 900×120 px region of both PNGs: text pixels are present starting at row 0, and the crop shows a flat cut across the ascenders of "B", "A", "D", etc.). This is caused by plot_title=element_text(size=10, ha="center", weight="bold", color=INK, margin={"b": 12}) only setting a bottom margin ("b": 12) with no top margin/padding, combined with the overall plot margin/theme_void() leaving no headroom above the title. Fix: add top margin/padding to the title (e.g. margin={"t": 10, "b": 12} in points, or increase overall plot margins via theme(plot_margin=...)) so the full glyph height — including ascenders on bold capital letters — renders inside the canvas bounds on both renders.

Issues Found

  1. AR-09 CRITICAL: Title clipped at top edge of canvas in both light and dark renders — tops of letters missing
    • Fix: Add top margin to plot_title (margin={"t": 10, "b": 12}) and/or increase theme(plot_margin=...) top inset so the bold 10pt title's full ascender height clears the canvas top edge with margin to spare.

AI Feedback for Next Attempt

The treemap layout, palette, and data mapping are solid — keep those. The blocking issue is purely a title-margin bug: the title is being clipped at the very top of the canvas in both renders (confirmed via pixel inspection, not just proximity). Add top padding/margin to plot_title and/or the overall plot_margin so the full glyph height clears the canvas edge. Re-verify by checking that the top few pixel rows of the saved PNG are pure background color before the title's first visible pixel.

Verdict: REJECTED

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

❌ AI Review Failed (auto-retry exhausted)

The AI review action completed but did not produce valid output files. Auto-retry already tried once.

What happened:

  • The Claude Code Action ran
  • No quality_score.txt file was created

Manual rerun:

gh workflow run impl-review.yml -f pr_number=9968

🤖 impl-review

@github-actions github-actions Bot added the ai-review-failed AI review action failed or timed out label Aug 4, 2026
MarkusNeusinger added a commit that referenced this pull request Aug 5, 2026
…review (#10179)

## The bug

`impl-review.yml` used quality score `0` as its sentinel for *"the AI
review produced no output"*. But `0` is also a score the review prompt
**mandates**: the Stage 1 auto-reject gates in
`prompts/workflow-prompts/ai-quality-review.md` require exactly `Score =
0, verdict = REJECTED` for **AR-08** (clipped element) and **AR-09**
(mandatory title not visible).

Prompt and workflow therefore contradicted each other, and the pipeline
was guaranteed to dead-end on exactly the plots it is designed to reject
hardest.

## The deadlock chain

1. Plot renders without a visible title → **AR-09** → reviewer returns
`Score: 0/100`, `Verdict: REJECTED` — **this is correct behaviour**
2. `Extract quality score` normalised it: `::warning::Invalid quality
score '0', defaulting to 0`
3. `Validate review output` fired on `score == '0'` → `::error::AI
Review did not produce valid output files` → `ai-review-failed` → `exit
1`
4. `exit 1` skipped **`Add verdict label and take action`** — which the
file itself documents as *"the pipeline's only hand-off point: every
downstream workflow (merge, repair) starts from a call made right here"*
5. So **`impl-repair` was never dispatched** and the missing title was
never fixed
6. `impl-review-retry.yml` rescued once → the re-review scored `0` again
(deterministically — the plot was unchanged) → `ai-review-failed`
re-applied
7. `ai-review-failed` + `ai-review-rescued` matches **no** watchdog case
(`watchdog-stuck-jobs.yml:116` only emits a `::warning::` and defers to
a human) → **PR stranded permanently**

## Evidence

Six open PRs sit in exactly that state, each with an AR-09 verdict
already in hand:

| PR | Library / spec | Reported score | Verdict | Gate |
|---|---|---|---|---|
| #10152 | seaborn windrose-basic | 0 | REJECTED | AR-09 |
| #10130 | muix streamgraph-basic | 0 | REJECTED | AR-09 |
| #10009 | matplotlib wireframe-3d-basic | 0 | REJECTED | AR-09 |
| #10003 | d3 ternary-basic | 0 | REJECTED | AR-09 |
| #9968 | plotnine treemap-basic | 0 | REJECTED | AR-09 |
| #9776 | matplotlib polar-basic | 0 | REJECTED | AR-09 |

This was never an infrastructure failure. In run
[31035492709](https://github.com/MarkusNeusinger/anyplot/actions/runs/31035492709)
the Claude action reported `"subtype": "success"`, `"is_error": false`,
15 turns, `permission_denials_count: 0` — and posted a complete review
ending in `### Score: 0/100` / `### Verdict: REJECTED`. 94 of the last
100 `impl-review` runs are green; the 6 failures are these gate-tripping
plots.

## The fix

Output presence becomes its own signal, decoupled from the score value:

- `Extract quality score` now emits **`has_output`** alongside `score`.
`0` is accepted as a valid score; only a non-numeric or out-of-range
value marks output as missing.
- The six gates that keyed off `score != '0'` / `score == '0'` now key
off `has_output`.
- A score of `0` therefore flows into the normal `ai-rejected` →
`impl-repair` path (threshold floor is 50, so `0 < 50` → rejected →
repair dispatched), and only genuinely absent output raises
`ai-review-failed`.

**Second, latent bug fixed in the same step:** the comment fallback read
`.comments[-1].body`, but on a retry the workflow's own
*"auto-retrying"* notice is posted **after** the review — so the
fallback searched the notice and found no score. It now selects the last
`claude[bot]` comment.

**Deliberately not changed:** `watchdog-stuck-jobs.yml`. With the root
cause fixed, "review produced no output twice in a row" (PRs
#9953/#9952/#9951, which have no `claude[bot]` comment at all) is a
genuine failure that *should* escalate to a human rather than loop
forever.

## Verification

GitHub Actions changes have no verification loop in this repo, so the
step's shell body was tested directly: a harness extracts the `Extract
quality score` `run:` block **verbatim from the YAML** and exercises it
with a stubbed `gh`.

```
--- the regression that caused the deadlock ---
PASS  file score 0 (AR-09 auto-reject)               score=0    has_output=true
PASS  comment fallback, score 0                      score=0    has_output=true
--- normal operation must be unchanged ---
PASS  file score 87 / 100 / 1 / trailing-newline 73  score=...  has_output=true
PASS  comment fallback, score 87                     score=87   has_output=true
--- genuine 'no output' must still be detected ---
PASS  no file, no review comment                     score=0    has_output=false
PASS  no file, comment without a score line          score=0    has_output=false
PASS  file with non-numeric garbage                  score=0    has_output=false
PASS  file with out-of-range score                   score=0    has_output=false
PASS  empty file                                     score=0    has_output=false

ALL CASES PASS
```

YAML validity re-checked after the edit (`yaml.safe_load`, 20 steps
parsed).

Residual risk: the `if:` expression rewrites and the `REPOSITORY` env
addition are only observable on a real pipeline run. Recovery path for
the six stranded PRs after merge: re-dispatch `impl-review.yml -f
pr_number=<n>`, which will now score them 0, label `ai-rejected`, and
hand them to `impl-repair` to fix the titles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@MarkusNeusinger

Copy link
Copy Markdown
Owner

Closing as superseded.

main already carries plots/treemap-basic/implementations/python/plotnine with quality_score: 80, which is at or above what this PR would land. impl-merge.yml has no regression guard against the score already on main, so resuming this PR would overwrite the better implementation with a worse one.

This PR stalled on the score-0 sentinel bug in impl-review.yml (a legitimate AR-08/AR-09 auto-reject was misreported as a crashed review, so impl-repair was never dispatched). That root cause is fixed in #10179, but the fix does not make this particular PR worth resuming — the coverage it would provide already exists at a higher score.

🤖 Closed during PR-queue cleanup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review-failed AI review action failed or timed out ai-review-rescued Review re-dispatched once after ai-review-failed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant