Repository navigation
fix(agents): restore protected theme statements after a drifting retry - #12209
Merged
Merged
Conversation
…k retry A plan whose only failure is drift of the protected THEME assignment, theme tokens or final savefig gets those statements restored from the code before the plan once the round's check retry is spent (owner decision 2026-10-16), and goes on through check, render and review instead of ending the round. A rebind is never restored. pipeline_check logs outcome drift_restored and pipeline_run telemetry gains a drift_restored flag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Restoration can copy unrelated statements from shared base lines and silently undo plot repairs.
1 open finding
What changed in this PR
Restores protected theme statements after an adapter exhausts its check retry, allowing plot repairs to continue through validation, rendering, and review.
Changes:
- Adds guarded restoration and pipeline integration.
- Adds restoration telemetry and a BigQuery view field.
- Adds regression coverage and updates documentation.
| File | Description |
|---|---|
| tests/unit/agents/runtime/test_service_flow.py | Tests restoration through the pipeline. |
| tests/unit/agents/code/test_edits.py | Tests restoration behavior and guards. |
| docs/reference/agent-telemetry.md | Documents the restoration flag. |
| docs/concepts/agent-network.md | Explains restoration and retry behavior. |
| changelog.d/agent-theme-drift-restore.md | Records the fix. |
| agents/telemetry/views/02_event_views.sql | Exposes the restoration flag. |
| agents/README.md | Updates retry documentation. |
| agents/anyplot/telemetry.py | Adds the telemetry field. |
| agents/anyplot/settings.py | Clarifies retry behavior in documentation. |
| agents/anyplot/pipeline.py | Integrates restoration and logging. |
| agents/anyplot/code/edits.py | Implements protected-statement restoration. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…lines Splicing the base's whole lines back would also restore another statement on the same line and undo a repair's change to it (Copilot review of #12209). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M
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
Oct 16, 2026
## Summary - Cut the 3.5.0 section with `uv run python -m tools.changelog release 3.5.0 --title "Bring your own data"`. It folds all 99 fragments in `changelog.d/` (agent network window: #12099 to #12209), deletes them, repoints the compare links, and bumps `pyproject.toml`, `uv.lock` and `app/package.json` to 3.5.0. - Add the hand-written parts: a section intro (precedent from 3.4.0) and the italic *Catalog* line. No catalogue PRs merged since v3.4.0, and coverage stays at 315 of 325 specs. No **Dependencies:** bullet, because no Dependabot PR merged in the window. The five grouped bumps #12160 to #12164 are still open. - Fix the fragment `api-agent-secret-binding.md`, which had no PR reference, by adding `(#12128)` before the fold. The release is the admin-only "Use with my data" agent chat. The section does not suggest that it is publicly available, because that is reserved for v4.0.0. ## Plan `agentic/commands/release.md`. Tag `v3.5.0` and the condensed GitHub release follow after the merge. ## Test plan - [x] `uv run python -m tools.changelog check --base origin/main` passes - [x] `uv lock --check` passes - [x] `tests/unit/test_version_sync.py` and `tests/unit/tools` pass - [x] The diff touches only `CHANGELOG.md`, `pyproject.toml`, `uv.lock`, `app/package.json` and the 99 deleted fragments - [ ] CI green 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M 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
drift:theme,drift:theme_token,drift:savefig), and the round's check retry is already spent,edits.restore_protectedsplices the base's statement text back over the drifted statements. The result then goes through the normal_check, render and review. Owner decision 2026-10-16, live case "heat3" (round 8): no third round, no new forced-repair ids.drift:rebind) is never restored. Nothing is restored when a protected statement was removed, when it shares its lines with another statement (x = 1; INK = ...), or when the splice does not parse or still drifts.AppliedPlan.driftedcarries the plan's result when drift alone refused it, andapply_planitself is unchanged in behavior.pipeline_checklogs outcomedrift_restoredwith the restored drift kinds (one line per attempt;rejectedif the restored code then fails the validator). Thepipeline_runtelemetry line gains adrift_restoredbool, which is added todocs/reference/agent-telemetry.mdand to thepipeline_runsview inagents/telemetry/views/02_event_views.sql. The view needs a reload in BigQuery (it selects fields explicitly).Decisions made in this PR
THEMEor of the token, the final module-level savefig), not by region detection. A full file that turnsPAGE_BGinto a plainPAGE_BG = "#FFFFFF"is no longer a theme token there, so the region finder would miss it.plt.close()after the savefig survives.AGENT_CHECK_RETRY=falsethere is no retry to spend, so a restorable drift is restored on the first miss. The restore also applies to round 1's retry (attempt 2 may send a full file) and does not require the first answer of the round to have drifted too. The rule is "no retry left and this answer is drift-only".Plan
N/A (owner decision 2026-10-16, relayed in the delegate brief)
Test plan
tests/unit/agents/code/test_edits.py::TestRestoreProtected: restore for each allowed kind (THEME value, THEME no longergetenv, token value, token no longer a theme conditional, savefig, all three at once), keeping a plot change; end-of-file savefig; no restore on rebind, removal, a shared line, an unparseable splice (monkeypatched_splice), no drift or an unparseable plan.tests/unit/agents/runtime/test_service_flow.py::test_a_repair_that_drifts_the_theme_twice_renders_with_the_theme_restored: round 1 is rejected, round 2's full-file answer and its check retry both drift THEME and PAGE_BG, and the restored code (with the repair's marker change) renders, passes review and ships.pipeline_checkoutcomes areok,edits_failedanddrift_restored;pipeline_run.drift_restoredis true. The shipped attempt is 3 (the retry), which is shipped round 2.ruff check,ruff format --check,mypy api core agents,pytest tests/unit(12,135 passed), changelog check.agents/telemetry/views/02_event_views.sqlin BigQuery sopipeline_runs.drift_restoredexists.🤖 Generated with Claude Code
https://claude.ai/code/session_01GdMSqLR5ww4ji74EUSmk9M