Repository navigation
feat(agents): serve plotly and bokeh in the agent chat (PB-2a) - #12490
Merged
Merged
Conversation
plotly and bokeh join PYTHON_LIBRARIES and the admin deploy's _LIBRARIES,
rendered by PB-1's two-step figure mode: all 15 catalogue libraries are
served for the admin's live tests.
- code/figure.py: the pinned figure save the run form ends on
(plotly: fig.update_layout(width=, height=).write_json(f"plot-{THEME}.json");
bokeh: with open(...) as figure_file: json.dump(json_item(p), figure_file)),
the figure mode's device scale, and the export's swap back to the
library's normal save (question 10, decided by the owner).
- Normaliser: plotly's write_image/write_html block and bokeh's Selenium
screenshot block become the figure save; render_mode="svg" for plotly
express; "...".format(...) to an f-string for both. The 13 served
libraries' normalised code, findings and readiness are unchanged on all
4,213 catalogue files.
- Validator: plotly and bokeh profiles (subpackages only, JavaScript,
markup, URL fetchers and writers banned, HTML tooltip templates refused),
the pinned save lifted out of the scan in exactly its shape.
- Readiness: a plotly WebGL trace blocks as `webgl`; plotly and bokeh
coupling hints. render.mjs fails a WebGL trace as draw NoWebGL before
drawing (a 3D scene drew a blank plot that the host gates passed).
- Runtime: figure-mode argv and error grammar, export, local Docker mount
of render.mjs; adapter sections adapter_plotly.md and adapter_bokeh.md
after the unchanged Python prompt.
- 120 fixtures + 2 smoke cases, a plotly figure gate in the renderer's
candidate smoke, the agents image's CI scan, docs and plan.
Measured in the renderer image: 254 of 273 eligible plotly and 246 of 253
eligible bokeh catalogue files render on target in both themes (the rest
divide by the emptied title's length); model-free end to end passes R1-R3
in both themes for both libraries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
The owner's decisions on the survey's open questions, and the routes the
surface walk found:
- No private names in the plotly and bokeh profiles, as an attribute on
any receiver, a keyword or an unpacked dict key (`_validate=False`,
`fig._layout`); `bokeh.core.properties` leaves the surface.
- plotly: `plotly_relayout`, `plotly_update`, `plotly_restyle`, the geo
and map traces and `update_geos` banned; `trendline_options` banned as
a keyword (a getattr by string).
- bokeh: import by name and every route to a property object or a model
class by name (`instance_type`, `lookup`, `.property`, `descriptors`,
`parameters`, `model_class_reverse_map`, ...), `set_from_json`,
`apply_theme`, `Document`, and the `icon` properties banned.
- A string at a URL keyword (`URL_CONTEXTS`, plotly's image `source`) is
a `url-literal` whatever its scheme; the Python, R and Julia URL rules
refuse `//host`, `ws`, `wss`, `blob:` and `javascript:` as the
JavaScript one does. 0 of 4,213 served catalogue files change.
- bokeh tooltip templates pass as the catalogue writes them: every text
a tooltips value can take is read, text tags with quoted style or
class only, never `{safe}`; a pair's value is HTML too, so a Python
variable's text there is refused (2 catalogue files), and bokeh is
254 of 325 eligible.
- The CSP handler test asserts what ran and the directive, not
Chromium's wording.
- The plan records the MUI X eval matrix run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
Fable's review of PB-2a built bokeh tooltips the static rules did not see (a key built at run time, a dict filled by subscript, `chr(60)`, a SetValue callback) and had them run script in the exported HTML. - render.mjs reads the figure the plot wrote before a page opens and refuses what a browser would run, load or link, whatever built it, as `figure UnsafeMarkup`: bokeh's JavaScript, HTML, CSS and URL models, js_*_callbacks, CSS that loads or escapes, MathJax's HTML commands, a tooltip outside the template rule; plotly links to anything but http(s) (entities decoded), styles that load, image and geojson URLs. The export is the same code on the same data, so a refused figure is never downloaded. - Static bokeh rules: `**` only of literal options (a dict literal or a module-level dict read only by `**`), js_event_callbacks, js_property_callbacks, styles and stylesheets refused as keywords and dict keys, every callback model, set_select, stylesheet models, Styles and MathML banned, MathJax HTML commands refused in strings, the save's file handle named nowhere else. - URL contexts take only None or a bool (geojson a dict literal); flat update keys such as "images[0].source" are checked too. - The WebGL check guards a non-list `data` and compares without case. - plotly.js 4.1.1 drops entity-encoded javascript: links itself (measured); the check refuses them and relative links anyway. 0 of 4,213 served catalogue files change. bokeh: 252 of 325 eligible, 245 render on target; plotly unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
Fable's second review of PB-2a: - The renderer's markup check refuses a bokeh model outside the 97 the eligible catalogue's figures hold (BOKEH_CATALOGUE_MODELS, under the denylist), with a message that points the adapter to the catalogue's glyphs; tests/unit/automation/bokeh_catalogue_models.json holds the names, a test keeps the set equal to it, and an opt-in test (ANYPLOT_CATALOGUE_MODELS=1) recollects it from the catalogue. - No link at all in plotly text (an <a> tag or an href, https too), at run time and in the plotly profile (`url-literal`): no eligible catalogue file writes one. - The bokeh profile bans Tooltip, Pane, Panel, Drawer and Examiner, as the renderer refuses them. - The renderer image's CI asserts that a plotly link and a bokeh Div built with chr(60) fail as `figure UnsafeMarkup` through the image's own harness; the figure image test runs the markup cases with and without the checkout's render.mjs, so a stale image fails it. 0 eligible catalogue files are refused; 0 of 4,213 served catalogue files change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Critical validator gaps still allow protocol-relative URLs without dotted TLDs, and a Julia test fixture still incorrectly treats one such URL as valid.
4 open issues
What changed in this PR
This PR extends the agent chat’s Python runtime to serve Plotly and Bokeh through the renderer’s two-step figure mode. Catalogue code writes a guarded JSON figure, Chromium renders it at the canonical canvas size, and exported code restores each library’s normal PNG/HTML save workflow.
Changes:
- Adds Plotly and Bokeh normalisation, validation, readiness, export, runtime, prompt, and renderer support.
- Adds figure JSON markup/WebGL checks and deploy-time smoke coverage.
- Adds 120 generated evaluation fixtures plus associated counts, documentation, and tests.
| File | Description |
|---|---|
| tests/unit/agents/test_settings.py | Updated as part of this pull request. |
| tests/unit/agents/test_image.py | Updated as part of this pull request. |
| tests/unit/agents/runtime/test_render.py | Updated as part of this pull request. |
| tests/unit/agents/runtime/test_assess.py | Updated as part of this pull request. |
| tests/unit/agents/evals/test_cases.py | Updated as part of this pull request. |
| tests/unit/agents/code/test_readiness.py | Updated as part of this pull request. |
| tests/unit/agents/code/test_profile_r_validate.py | Updated as part of this pull request. |
| tests/unit/agents/code/test_profile_julia_validate.py | Updated as part of this pull request. |
| tests/unit/agents/code/test_normalise.py | Updated as part of this pull request. |
| agents/renderer/cloudbuild.yaml | Updated as part of this pull request. |
| agents/evals/matrix.py | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/violin-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/scatter-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-x10/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-decimal-comma/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-date/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-x10/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-decimal-comma/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-date/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/pie-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-timeseries-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-x10/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-decimal-comma/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-x10/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-decimal-comma/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/line-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/histogram-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/heatmap-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/box-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-x10/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-decimal-comma/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-date/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-x10/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-decimal-comma/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-date/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/bar-grouped-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-plotly-date/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-x10/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-renamed/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-renamed/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-n5000/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-n12/data.csv | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-n12/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-decimal-comma/case.json | Updated as part of this pull request. |
| agents/evals/fixtures/cases/area-basic-bokeh-date/case.json | Updated as part of this pull request. |
| agents/evals/eligibility.py | Updated as part of this pull request. |
| agents/evals/cases.py | Updated as part of this pull request. |
| agents/Dockerfile | Updated as part of this pull request. |
| agents/cloudbuild.yaml | Updated as part of this pull request. |
| agents/anyplot/settings.py | Updated as part of this pull request. |
| agents/anyplot/render/runtimes/__init__.py | Updated as part of this pull request. |
| agents/anyplot/render/contract.py | Updated as part of this pull request. |
| agents/anyplot/render/backends/local.py | Updated as part of this pull request. |
| agents/anyplot/prompts/root.md | Updated as part of this pull request. |
| agents/anyplot/code/profiles/r/validate.py | Updated as part of this pull request. |
| agents/anyplot/code/profiles/julia/validate.py | Updated as part of this pull request. |
Review effort: Lite
…e once Copilot's review of #12490: the protocol-relative branch of the URL rule matched only dotted names with an alphabetic TLD, so "//localhost/x", "//127.0.0.1/x" and "//host/x" passed. The Python, R, Julia and JavaScript profiles now share one rule: two or more slashes after the start, a space, a quote, `(`, `=` or `,`, then the first character of any host (a name, an IPv4 address, `[::1]`, a percent-encoded name, "///example.org"). A matplotlib hatch ("///"), "a // b" and Julia's 1//2 stay no URL; 0 of 4,863 catalogue files of the 15 libraries change. test_catalogue_summary ran over its CPU bound after plotly and bokeh joined the corpus. The scan now walks each tree once (it listed every node's children twice), `of()` returns its per-type list without a filter, and `_module_allowed` does one set lookup per dotted prefix: the six older libraries validate 17 % faster than on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
test_catalogue_summary bounded the whole corpus at 20 s of CPU, which plotly's and bokeh's 650 files pushed over in CI (26.1 s). The agent validates one file per request, so the bound is now main's own per-file budget, 20 s over its 1,946 files (CATALOGUE_CPU_PER_FILE_S), and the failure message reads in ms per file. With the single tree walk the branch takes 1.8 ms per file locally against the budget's 10.3 ms (CI runs about 4 times slower). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
3 of 4 tasks
MarkusNeusinger
added a commit
that referenced
this pull request
Nov 1, 2026
## Summary - Main is red since #12493: it added the `.claude/guardrails.md` section "Long-running work reports progress proactively" without registering it in `tests/unit/test_agent_instructions.py`, so `test_every_companion_section_is_registered` fails (seen on #12490's CI run). - #12493's CI never ran that test: "Run Tests" only starts for Python, config, workflow and prompt changes, and the PR changed only instruction files. `ci-tests.yml` now also runs the tests for `CLAUDE.md`, `AGENTS.md`, `.github/copilot-instructions.md`, `.claude/guardrails.md`, `.claude/skills/` and `agentic/commands/`, which `tests/unit/test_agent_instructions.py` and `tests/unit/skills` read. - Registers the new section with three CLAUDE.md anchors (never let the user ask, the 30-minute stall rule, the post-compaction re-check) and the classifier-denial rule under the external-writes section. ## Plan N/A (follow-up to #12493) ## Test plan - [x] `uv run --extra dev --extra test pytest tests/unit/test_agent_instructions.py tests/unit/skills tests/unit/workflows -n auto`: 1,319 passed - [x] The new filter matches `CLAUDE.md`, `.claude/guardrails.md`, a skill and a command, and not `docs/index.md` or `app/` (dry run of the grep) - [x] `tools.changelog check --base origin/main` passes - [ ] CI: this PR changes a workflow and a test, so "Run Tests" runs and must be green https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
4 of 5 tasks
MarkusNeusinger
added a commit
that referenced
this pull request
Nov 1, 2026
## Summary - Cloud Build refused the renderer deploy for PB-2a (#12490) before its first step ran: `invalid build: invalid .steps field: build step 7 arg 1 too long (max: 10000)` (build `dc1cf3ae`, 2026-11-01). The inline `smoke` step had reached 11,347 characters with the plotly probe; the agents service deployed (it now offers plotly and bokeh to the admin) while the renderer kept its PB-1 revision, without PB-2a's figure-markup checks. - The render probes (matplotlib, Makie, Chart.js, plotly, data run) move unchanged into `agents/renderer/deploy_smoke.sh`; only Cloud Build's `$$` escapes become `$` (a normalised line diff against the removed inline text is identical). The step keeps the candidate double read, the anonymous-403 check, the token mint and `/status`, and calls the script with the token in the environment. The step's argument is now 3,606 characters. - `tests/unit/test_cloudbuild_configs.py` keeps every step argument of every Cloud Build config at or under 10,000 characters (it fails on main's renderer config), and `ci-tests.yml` runs the unit tests when a Cloud Build config or the script changes. ## Plan N/A (incident fix after the PB-2a merge). ## Test plan - [x] `pytest tests/unit tests/integration -n 4`: 25,800 passed, 141 skipped. - [x] New tests: the step calls the script once, after `/status`, with the token through the environment; the script runs end to end against a fake `curl` (all five probes pass and send the token; a plotly render that fails twice exits non-zero and skips the data run); the plotly probe writes a valid `RenderRequest`. - [x] The limit test reports `step 7 (smoke) arg 1: 11347 characters` on main's config. - [x] Gemini 3.8 Flash pre-PR check: sound with changes, 3 low findings. Applied: the fake `curl` rejects unknown flags; the script is executable. Not applied: a 9,000-character margin, because `app/cloudbuild.yaml` already has a 9,895-character argument; moving that one is a separate follow-up. - [ ] After the merge: `deploy-renderer` passes its smoke on Cloud Run (Makie, Chart.js and plotly gates) and promotes; then the site smoke. No live loop exists for Cloud Build configs; the deploy after the merge is the first real run of the script. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
plotly and bokeh are served in "Use with my data" for the admin. They render through PB-1's two-step figure mode: the plot writes its figure as JSON under the plot guard, and the JavaScript harness draws it in Chromium at the catalogue's canvas. All 15 catalogue libraries are now served.
Validator profiles for both libraries, with the owner's decisions on the surface survey:
Nonewhere a URL is expected;//host;{safe};**only of literal options;The renderer checks the figure JSON before the page draws it.
render.mjs(figureMarkupProblem) refuses, asfigure UnsafeMarkup:The export is the same code on the same data, so what the render refuses never reaches the downloaded HTML. A plotly WebGL trace fails as
draw NoWebGLbefore it draws.Plan
agentic/specs/261024-agent-all-libraries.md, step 4: "What PB-2a built (2026-10-31)". That section has the table of deviations, the measurements and "Found for later". Question 10 is marked decided. The section "What JS-4c built" gains the MUI X eval matrix run.Measurements
origin/mainon all 4,213 catalogue files (0 changed).ZeroDivisionError(code that divides by the length of the emptied catalogue title; a follow-up is filed);+01:00timestamp and an integer past 2^53. It passes R1 to R3 in both themes at 3200 x 1800 for both libraries, and the export ends on the normal save.Reviews
**{"tool" + "tips": s}, a dict filled by subscript,chr(60),SetValueon a button) ran script in the exported bokeh HTML. Fixed in two layers:**only of literal options, callback, CSS and MathML models banned;Noneor a bool, plus flat update keys like"images[0].source".deploy-renderertrigger coversautomation/js-render/**.dataand compares case-insensitively; fixed.javascript:link in a plotly annotation: plotly.js 4.1.1 drops it itself, measured in Chromium; the markup check refuses it anyway.FuncTickFormatter: not in bokeh 3.10.1, a false positive.Test plan
uv run ruff check .,uv run ruff format --check .,mypy api core agents(193 files)pytest tests/unit tests/integration -n auto: 25,526 passed, 135 skippedtests/unit/automation/test_js_render_figure.pywith the lock'snode_modules: 67 passed, 1 skipped (the opt-in test below)tests/unit/agents/code/test_profile_python_figure_image.pyagainst an image built from this branch: 11 passed. The markup cases run with and without the checkout'srender.mjs, and a stale image fails them.ANYPLOT_CATALOGUE_MODELS=1recollection of the bokeh model allowlist from every eligible catalogue file: passed (35 s on 32 CPUs). It is opt-in and does not run per PR (about 8 CPU minutes).python -m agents.evals.make_fixtures --check,python -m tools.changelog check --base origin/main.github/workflowschange). I ran its script locally against the rebuilt image and both were refused.https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8