Backporting upstream VTK fixes into cvista
cvista is frozen on VTK 9.6.2 (upstream tag v9.6.2, project vtk/vtk id 13 on
gitlab.kitware.com). Upstream keeps moving — its master is on the 9.7.0 cycle. Real bug
fixes and useful features land upstream after the 9.6.2 cut, and cvista should pull in the ones
that affect the modules it ships. Each backport is one MR → one PR, linked to the MR.
cvista's root commit is a squash of 9.6.2, so there is no shared git history with upstream.
git cherry-pick does not work. A backport applies the MR's diff and adapts it to the 9.6.2
tree by hand where context has drifted.
The reusable details (API calls, diff fetch, triage heuristics) are in
references/upstream-api.md. The per-MR landing is delegated to the vtk-backport-engineer
agent. The ledger of what has been backported, skipped, or is pending is docs/upstream-backports.md.
The sweep
Read the ledger docs/upstream-backports.md. The watermark is the highest MR iid (or
the date) already triaged. If the ledger is absent, this is the first sweep: create it and
use the 9.6.2 tag date as the floor.
Pull merged MRs since the watermark from the GitLab API (read-only, public). See
references/upstream-api.md for the exact query. Collect iid, title, merge date, changed
file paths, and web_url for each.
Triage each MR (heuristics in the reference file; the short version):
- Skip if every changed file is absent from the cvista tree (
git ls-files <path> empty) —
that module was trimmed, so the fix is irrelevant. This is the strongest, cheapest filter.
- Skip infra, docs, CI, ThirdParty bumps, deprecation churn, and changes only to modules
cvista does not ship.
- Take crash / correctness / memory-safety fixes touching shipped modules (highest
value). Take user-visible feature or behavior fixes case by case.
- Defer performance MRs by default — cvista has its own perf line under the parity
contract, and an upstream perf change may conflict with it. Flag, do not auto-land.
- When unsure, mark pending in the ledger and surface it for a human call rather than
guessing.
Present the triage as a table (iid, title, decision, reason) and confirm scope before
landing anything. Landing N PRs is a high-volume, outward-facing action; get a go-ahead.
Landing the accepted backports
For each accepted MR, spawn a vtk-backport-engineer agent (run them in parallel for
independent MRs; use worktree isolation so concurrent branches do not collide). Give each agent:
- the MR iid, title, and web_url
- the changed-file list
- the standing instructions below
Each agent, for its one MR:
- Branch
backport/vtk-mr-<iid>-<short-slug> from main.
- Fetch the MR diff (
references/upstream-api.md) and apply it. Try git apply --3way first;
where context has drifted on the 9.6.2 tree, port the change by hand, reading the MR to
preserve its intent. Keep the change minimal and matched to surrounding VTK style.
- Handle parity: a behavioral fix diverges from stock 9.6.2 on purpose. Update the affected
tests/bitexact/ op to the corrected expectation and note the divergence (see the
parity-contract skill). A crash/guard fix on degenerate input usually leaves valid-input
output unchanged, so add a regression test for the degenerate case instead.
- Build (
PROFILE=fast ./build-cvista.sh) and run the relevant gate (bitexact / renderexact /
regression) to prove the fix and the parity story.
- Open the PR. The body must link the upstream MR
(
https://gitlab.kitware.com/vtk/vtk/-/merge_requests/<iid>), summarize the upstream defect
in cvista's own words, state the parity bucket, and attach the gate evidence. Commit and PR
prose follow .claude/CLAUDE.md (single-line conventional commit, no AI attribution,
prose-hygiene pass). Keep it framed around PyVista and VTK; no downstream-consumer rationale.
- Report back the PR number and the parity outcome.
Close the loop
Update docs/upstream-backports.md: for each MR, record iid, title, decision (backported #<PR> / skipped: <reason> / pending: <reason> / deferred: perf), and the date. Advance
the watermark. The next sweep starts from there, so triage is incremental and never repeats
work.
Ledger format
# Upstream VTK backports
Watermark: MR iid <N> (swept <YYYY-MM-DD>). Base: VTK 9.6.2 (gitlab.kitware.com/vtk/vtk).
| MR | Title | Decision | Date |
|----|-------|----------|------|
| !13353 | vtkPolyLine::Clip nullptr crash on degenerate polylines | backported #120 | 2026-06-21 |
| !13355 | Fix perf issues in marshalling | skipped: SerializationManager not shipped | 2026-06-21 |
1---2name: backport-vtk3description: Sweep recently merged upstream VTK merge requests, triage the bug fixes and features that matter to cvista's shipped modules, and land each as its own PR linked back to the original MR. Use when asked to check upstream VTK for backports, catch cvista up on upstream fixes, or port a specific VTK MR. Drives the vtk-backport-engineer agent for the per-MR landing work.4---56# Backporting upstream VTK fixes into cvista78cvista is frozen on VTK **9.6.2** (upstream tag `v9.6.2`, project `vtk/vtk` id `13` on9`gitlab.kitware.com`). Upstream keeps moving — its `master` is on the 9.7.0 cycle. Real bug10fixes and useful features land upstream after the 9.6.2 cut, and cvista should pull in the ones11that affect the modules it ships. Each backport is **one MR → one PR, linked to the MR**.1213cvista's root commit is a squash of 9.6.2, so there is **no shared git history with upstream**.14`git cherry-pick` does not work. A backport applies the MR's diff and adapts it to the 9.6.215tree by hand where context has drifted.1617The reusable details (API calls, diff fetch, triage heuristics) are in18`references/upstream-api.md`. The per-MR landing is delegated to the `vtk-backport-engineer`19agent. The ledger of what has been backported, skipped, or is pending is `docs/upstream-backports.md`.2021## The sweep22231. **Read the ledger** `docs/upstream-backports.md`. The watermark is the highest MR iid (or24 the date) already triaged. If the ledger is absent, this is the first sweep: create it and25 use the 9.6.2 tag date as the floor.26272. **Pull merged MRs since the watermark** from the GitLab API (read-only, public). See28 `references/upstream-api.md` for the exact query. Collect iid, title, merge date, changed29 file paths, and web_url for each.30313. **Triage each MR** (heuristics in the reference file; the short version):32 - **Skip** if every changed file is absent from the cvista tree (`git ls-files <path>` empty) —33 that module was trimmed, so the fix is irrelevant. This is the strongest, cheapest filter.34 - **Skip** infra, docs, CI, ThirdParty bumps, deprecation churn, and changes only to modules35 cvista does not ship.36 - **Take** crash / correctness / memory-safety fixes touching shipped modules (highest37 value). Take user-visible feature or behavior fixes case by case.38 - **Defer** performance MRs by default — cvista has its own perf line under the parity39 contract, and an upstream perf change may conflict with it. Flag, do not auto-land.40 - When unsure, mark **pending** in the ledger and surface it for a human call rather than41 guessing.42434. **Present the triage** as a table (iid, title, decision, reason) and confirm scope before44 landing anything. Landing N PRs is a high-volume, outward-facing action; get a go-ahead.4546## Landing the accepted backports4748For each accepted MR, spawn a `vtk-backport-engineer` agent (run them in parallel for49independent MRs; use worktree isolation so concurrent branches do not collide). Give each agent:5051- the MR iid, title, and web_url52- the changed-file list53- the standing instructions below5455Each agent, for its one MR:56571. Branch `backport/vtk-mr-<iid>-<short-slug>` from `main`.582. Fetch the MR diff (`references/upstream-api.md`) and apply it. Try `git apply --3way` first;59 where context has drifted on the 9.6.2 tree, port the change by hand, reading the MR to60 preserve its intent. Keep the change minimal and matched to surrounding VTK style.613. Handle parity: a behavioral fix diverges from stock 9.6.2 on purpose. Update the affected62 `tests/bitexact/` op to the corrected expectation and note the divergence (see the63 `parity-contract` skill). A crash/guard fix on degenerate input usually leaves valid-input64 output unchanged, so add a regression test for the degenerate case instead.654. Build (`PROFILE=fast ./build-cvista.sh`) and run the relevant gate (bitexact / renderexact /66 regression) to prove the fix and the parity story.675. Open the PR. The body **must** link the upstream MR68 (`https://gitlab.kitware.com/vtk/vtk/-/merge_requests/<iid>`), summarize the upstream defect69 in cvista's own words, state the parity bucket, and attach the gate evidence. Commit and PR70 prose follow `.claude/CLAUDE.md` (single-line conventional commit, no AI attribution,71 prose-hygiene pass). Keep it framed around PyVista and VTK; no downstream-consumer rationale.726. Report back the PR number and the parity outcome.7374## Close the loop7576Update `docs/upstream-backports.md`: for each MR, record iid, title, decision (`backported77#<PR>` / `skipped: <reason>` / `pending: <reason>` / `deferred: perf`), and the date. Advance78the watermark. The next sweep starts from there, so triage is incremental and never repeats79work.8081## Ledger format8283```markdown84# Upstream VTK backports8586Watermark: MR iid <N> (swept <YYYY-MM-DD>). Base: VTK 9.6.2 (gitlab.kitware.com/vtk/vtk).8788| MR | Title | Decision | Date |89|----|-------|----------|------|90| !13353 | vtkPolyLine::Clip nullptr crash on degenerate polylines | backported #120 | 2026-06-21 |91| !13355 | Fix perf issues in marshalling | skipped: SerializationManager not shipped | 2026-06-21 |92```