Skip to content

fix(debug): preserve language in plot links so R/ggplot2 deep-links work#7066

Merged
MarkusNeusinger merged 3 commits into
mainfrom
claude/fix-r-plot-links-aHhKX
May 17, 2026
Merged

fix(debug): preserve language in plot links so R/ggplot2 deep-links work#7066
MarkusNeusinger merged 3 commits into
mainfrom
claude/fix-r-plot-links-aHhKX

Conversation

@MarkusNeusinger
Copy link
Copy Markdown
Owner

Summary

Clicking an R/ggplot2 implementation from /debug landed on the cross-language hub filtered to ?language=python (without the plot), instead of opening the implementation detail page. Root cause: DebugPage.tsx hardcoded 'python' as the language when building plot deep links — for ggplot2 this produced /spec/python/ggplot2, which SpecPage then validates against the impl set, fails to match (the impl is in language r), and redirects to the Python-filtered hub.

Audited all other pages — only DebugPage had the hardcoded-'python' bug. Every other deep link (PlotOfTheDay, SpecOverview, StatsPage, PlotsPage, RelatedSpecs, SpecPage) reads language from the API response.

What changed

Bug fix (DebugPage):

  • Recent activity, desktop spec matrix, and mobile card list now use the real implementation language (via act.language_id from the API, and via a new LIB_TO_LANG constant for the matrix where only a library_id is in scope).

Companion fixes triggered by the R/ggplot2 rollout that the debug pipe never picked up:

  • RecentActivity payload (/debug/status) now includes language_id.
  • SpecStatusItem gains the ggplot2 column — the matrix column was always empty before.
  • library_names map and coverage formula (was specs * 9, now specs * len(SUPPORTED_LIBRARIES)).
  • Hardcoded 9s in DebugPage replaced with LIBRARIES.length (filter button, {implCount}/9 cell, repeat(9, 40px) grid template — both desktop and mobile).
  • /specs/{id}/images and /libraries/{id}/images now also expose language so external API consumers (MCP / docs) can build the same deep links. Docs updated.

Tests:

  • _make_impl helper accepts language_id (defaults to "python").
  • test_debug_status_recent_activity now exercises an R/ggplot2 impl and asserts language_id survives the round-trip — the regression that just shipped.
  • Coverage assertion updated to use len(SUPPORTED_LIBRARIES) rather than the magic 9.

Test plan

  • uv run --extra test --extra plotting pytest tests/unit/ — 1437 passed
  • yarn test --run — 459 passed
  • yarn tsc --noEmit — clean
  • Manual: open /debug, click a ggplot2 cell in the matrix → lands on /{spec}/r/ggplot2 with the plot visible
  • Manual: click a Python library cell → still goes to /{spec}/python/{lib} as before
  • Manual: click an entry in "recent activity" for an R impl → lands on the R detail page

https://claude.ai/code/session_01YKrNgGApdLy6LBfRQbL7qf


Generated by Claude Code

DebugPage hardcoded 'python' when building plot-detail URLs (recent
activity + spec matrix, desktop and mobile). For ggplot2 (R) this
produced /spec/python/ggplot2; SpecPage then validated that an impl
exists with language=python AND library=ggplot2, found none, and
redirected to the Python-filtered hub overview — exactly the symptom
reported (lands on overview, plot missing).

Fixes alongside, all triggered by the same R-language rollout:
- /debug/status RecentActivity now carries language_id so the frontend
  doesn't have to guess
- SpecStatusItem gains a ggplot2 column (was silently missing — the
  matrix column was always empty)
- coverage = total / (specs * len(SUPPORTED_LIBRARIES)) instead of *9
- library_names map includes ggplot2
- Hardcoded 9s in DebugPage replaced with LIBRARIES.length
  (filter, count display, grid template)
- /specs/{id}/images and /libraries/{id}/images now expose language too,
  so external API consumers can build the same deep links

Frontend constants gain LIB_TO_LANG (mirror of LIB_ABBREV) so the matrix
grid can resolve a column's language without waiting for /libraries to
load.
Copilot AI review requested due to automatic review settings May 17, 2026 11:19
@codecov
Copy link
Copy Markdown

codecov Bot commented May 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes broken deep-links for non-Python implementations (notably R/ggplot2) by preserving the correct implementation language when building links from the debug dashboard, and extends a couple of image-list API responses to include language so external consumers can build the same links.

Changes:

  • Debug dashboard now uses the real implementation language (language_id) for recent-activity links, and uses a library→language map for the spec matrix where only library_id is available.
  • /debug/status recent-activity payload now includes language_id, and ggplot2 is added to the spec status matrix model/column set; coverage calculation is no longer hardcoded to 9 libraries.
  • /specs/{id}/images and /libraries/{id}/images now include language in each image entry; API docs updated accordingly; unit tests updated for the new debug payload and dynamic library count.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/unit/api/test_debug.py Updates debug endpoint unit tests for language_id in recent activity and for dynamic coverage computation.
docs/reference/api.md Documents the new language field in images responses.
app/src/pages/DebugPage.tsx Fixes debug-page deep-links to preserve language; replaces hardcoded 9 with LIBRARIES.length; adds ggplot2 support in the matrix type.
app/src/pages/DebugPage.test.tsx Adjusts mock debug payload shape to include the new ggplot2 column.
app/src/constants/index.ts Adds LIB_TO_LANG mapping to build correct links from library-only contexts.
api/routers/specs.py Adds language to /specs/{id}/images response entries.
api/routers/libraries.py Adds language to /libraries/{id}/images response entries.
api/routers/debug.py Adds language_id to recent activity items, adds ggplot2 column, and replaces hardcoded library-count coverage math.

Comment thread app/src/constants/index.ts Outdated
Comment on lines +31 to +32
// only know a library id (e.g. the debug-page spec matrix and recent-activity
// list, which would otherwise have to wait for /libraries to load).
Comment thread tests/unit/api/test_debug.py Outdated
"""recent_activity should return impls sorted by updated DESC, capped at 15."""
"""recent_activity should return impls sorted by updated DESC, capped at 15,
and surface each impl's language so the frontend can build correct deep links
(regression: Python + R impls were both linked as /spec/python/... before).
claude and others added 2 commits May 17, 2026 11:49
- ruff format collapsed two over-wrapped literals (api/routers/specs.py
  spec-images dict and the recent-activity test impl_r construction).
- Narrow the LIB_TO_LANG comment to the spec-matrix use case — once
  recent activity started carrying language_id from /debug/status it
  no longer relies on the static map.
- Update the recent-activity regression docstring so the URL shape
  matches the real specPath output ({specId}/{language}/{library},
  not /spec/python/...).
Copilot AI review requested due to automatic review settings May 17, 2026 14:58
@MarkusNeusinger MarkusNeusinger enabled auto-merge (squash) May 17, 2026 14:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@MarkusNeusinger MarkusNeusinger merged commit 3138048 into main May 17, 2026
13 checks passed
@MarkusNeusinger MarkusNeusinger deleted the claude/fix-r-plot-links-aHhKX branch May 17, 2026 15:03
MarkusNeusinger added a commit that referenced this pull request May 22, 2026
)

Closes #7612.

Adds **Julia** as anyplot's third language with **Makie.jl** (CairoMakie
backend) as its first library entry. Generalizes the multi-language
plumbing introduced for R/ggplot2 in #6944 + follow-ups (#6947, #6961,
#7066) so every `python | r` dispatch now handles `python | r | julia`
uniformly.

## Phase ordering — heads-up

This ships **Phase 5 (Julia) before Phases 1+2 (JavaScript family)**,
which the issue called out explicitly. The multi-language pipeline is
already proven on R; shipping Julia next provides a cheap second
non-Python validation that surfaces multi-language gaps the JS work
would otherwise hit cold. The JavaScript phases remain planned in
unchanged order. See `docs/concepts/library-expansion.md` §9.

## Why Makie over Plots.jl

Distinct scientific stack (not a wrapper), ~45 % share within Julia,
MIT-licensed. CairoMakie is the right backend for CI — pure-Cairo,
headless, no GPU / GLFW window. `PlotlyJS.jl` is a plotly.js wrapper
(already covered via Python Plotly). Plots.jl is the alternative;
revisit only if Plausible data flips. `GLMakie` / `WGLMakie` interactive
backends are out of scope; `INTERACTIVE_LIBRARIES` intentionally
excludes Makie.

## What's in the PR

### Constants + registry

- `core/constants.py`: add `julia` language, `makie` library
- `tests/unit/core/test_constants.py`: assert `julia` + `makie`

### CI runtime

- `.github/actions/setup-julia/action.yml`: install Julia 1.11, restore
from `Project.toml` / `Manifest.toml`, smoke-test a CairoMakie render
- `Project.toml`: pin CairoMakie + Makie + dataset packages (CSV,
Colors, ColorSchemes, DataFrames, PalmerPenguins, RDatasets, Random,
Statistics)

**`Manifest.toml` is intentionally not committed** — it gets resolved by
the first CI run; the action falls back to `Pkg.add(...)` when
`Manifest.toml` is absent so first-run doesn't hard-fail. (Same model as
`renv.lock` had pre-bump on the R rollout.)

### Workflows

Each workflow derives `LANGUAGE` + `EXT` from `LIBRARY` via a case
statement. Every case now has `matplotlib→python`, `ggplot2→r`,
`makie→julia`:

- `impl-generate.yml`, `impl-repair.yml`, `impl-review.yml`,
`impl-merge.yml`: add the `makie→julia` arm; install `setup-julia` when
`language==julia`; detect Julia version via `julia -e 'print(VERSION)'`;
detect Makie version via `Pkg.dependencies()`
- `impl-review.yml`:
- extend canvas-gate library-cause map with a Makie entry
(`Figure(resolution=(1600,900)) + px_per_unit=2` → 3200×1800;
`resolution=(1200,1200)` → 2400×2400)
- extend header-rewrite step to handle `#`-prefixed Julia comment
blocks, with prepend fallback when missing (same fix as #6947 did for
Python / R)
- `bulk-generate.yml`: add `makie` to `library` choices and
`ALL_LIBRARIES`
- `impl-merge.yml`: completion total now derives from the actual library
list rather than hardcoding 9

### Prompts

- **`prompts/library/makie.md`** (new): no-workarounds policy,
NOT_FEASIBLE for primary-interactivity specs, canvas hard rule,
`ANYPLOT_THEME` mapping, forbidden patterns (no `Plots.jl`, no
`display(fig)`, no `GLMakie`/`WGLMakie`), `# `-comment header style
- `plot-generator.md`: extend lead, available environment, forbidden
patterns with Julia/Makie section
- `quality-evaluator.md`, `workflow-prompts/ai-quality-review.md`:
extend the AR-08 static-libraries list with `makie`; extend the language
allow-list with `julia`
- `workflow-prompts/impl-generate-claude.md`, `impl-repair-claude.md`:
add the `julia | .jl | julia --project=.` row to the (language, ext,
runner) table; add Julia run + format sections
- `workflow-prompts/impl-similarity-claude.md`: third arm for `julia` in
the `{language}` mapping

### Frontend (avoids the two-follow-up-PR pattern from #6961 / #7066)

- `app/src/constants/index.ts`: add `makie` to `LIBRARIES`, `LIB_ABBREV:
'mk'`, `LIB_TO_LANG: 'julia'`, `LANG_DISPLAY: 'Julia'`, `LANG_EXT: 'jl'`
- `app/src/components/CodeHighlighter.tsx`: register `julia` Prism
grammar
- `app/src/types/react-syntax-highlighter.d.ts`: declare the
`prism/julia` module locally — **TS7016 fix in same PR, not deferred**
(the issue specifically called this out as a gap not to repeat)
- `app/src/components/LibraryCard.tsx`: description for makie
- `app/src/components/PlotOfTheDay.tsx`, `PlotOfTheDayTerminal.tsx`:
`julia --project=.` runner token + `.jl` extension when language is
julia
- `app/src/pages/LibrariesPage.tsx`, `AboutPage.tsx`, `PlotsPage.tsx`:
meta-description copy bumped to "Eleven libraries across Python, R, and
Julia"
- `app/src/pages/DebugPage.tsx`: `makie` column in `SpecStatus`
interface (the grid template uses `LIBRARIES.length` so the matrix grows
automatically)

### Backend

- `api/routers/debug.py`: `SpecStatusItem` and `library_names` entries
for makie
- `api/routers/specs.py`: doc comment updated to note `makie is Julia`

### Tests

- `app/src/components/CodeHighlighter.test.tsx`: julia-grammar case
- `app/src/hooks/useCodeFetch.test.ts`: julia `?language=` case +
three-language cache-key test
- `app/src/pages/DebugPage.test.tsx`: `makie` field on fixture

### Docs

- `docs/concepts/library-expansion.md`: §1 current-state table grows to
11 entries; §8 Phase 5 marked **shipped**; §9 records the phase-skip
rationale, Makie-over-Plots.jl decision, and CairoMakie-only scope
- `docs/reference/repository.md`: `implementations/` layout shows
`python/` + `r/` + `julia/` siblings
- `docs/concepts/vision.md`, `docs/reference/style-guide.md`:
pipeline-story copy ("eleven libraries in three languages")
- `docs/reference/plausible.md`: language slug list now includes `julia`
- `prompts/README.md`, `agentic/docs/project-guide.md`: Makie added

## Verified

- ✅ `core/constants.py` loads: `len(SUPPORTED_LIBRARIES)=11`,
`SUPPORTED_LANGUAGES={'python','r','julia'}`
- ✅ `pytest tests/unit/core tests/unit/api/test_routers.py
tests/unit/api/test_debug.py tests/unit/api/test_schemas.py` — **213
passed**, no regressions
- ✅ `Project.toml` valid TOML, deps load
- Frontend tests are wired but I couldn't run `yarn test` in this
environment (no node_modules). Code follows the existing patterns from
the R rollout.

## Post-merge follow-ups (called out in the issue)

1. Run `uv run python -m automation.scripts.label_manager sync` once so
`library:makie`, `generate:makie`, `impl:makie:{pending,done,failed}`
labels appear.
2. First CI run of `setup-julia` will resolve `Manifest.toml` — commit
that lockfile in a tiny follow-up so subsequent runs use
`Pkg.instantiate()` instead of the `Pkg.add` fallback.
3. Trigger `bulk-generate.yml -f library=makie` to fill the catalog
(separate from this infra PR — the issue called this out as "Out of
scope" / handled by the regular flow).
4. Optional `julia.anyplot.ai` marketing subdomain (mentioned in the
issue's "Out of scope" section; small follow-up modeled on
`python.anyplot.ai`).


---
_Generated by [Claude
Code](https://claude.ai/code/session_01AzjPDEE5aY2LYR5tcK3faj)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants