Commit 35f592e
committed
fix(oxml): scope CT_GroupShape.max_shape_id to spTree descendants
The xpath `//@id` in `CT_GroupShape.max_shape_id` is absolute — it
scopes to the whole document, not the spTree subtree. On slide masters,
that pulls in the sentinel ids on `<p:sldLayoutIdLst>/<p:sldLayoutId>`
which start at 2147483649 (PowerPoint's authoring convention for
layout-master pointer ids — a deliberately-segregated namespace).
The next-shape-id calculation `max_shape_id + 1` then returns a value
just above `xs:int` (2147483660). PowerPoint quarantines shapes with
ids in that range on open, surfacing as a 'Repair' dialog that removes
the offending shape and synthesizes replacement parts.
The latent bug was harmless until Phase 5 (#52) introduced
`MasterShapes.add_textbox` and `SlideMaster.add_text_watermark` — the
first public API that *writes* a shape to a slide master. Reads off
masters didn't exercise `_next_shape_id`.
Fix: change `self.xpath('//@id')` to `self.xpath('.//@id')`. `.//` is
the descendant-or-self axis relative to the context node — scopes the
search to the shape tree only, leaving sibling-element ids
(`p:sldLayoutId`, etc.) outside the max.
Tests:
- `it_returns_zero_for_max_shape_id_on_an_empty_spTree` — baseline.
- `it_finds_the_max_id_among_shape_descendants` — sanity, picks
max=42 across three sp ids.
- `but_it_ignores_sibling_ids_outside_the_shape_tree` — regression
pin: `<p:sldLayoutIdLst>` siblings with ids in the 2147483649+
range do NOT inflate the result. spTree.max_shape_id stays at 2.
Verification (local, CPython 3.14.4):
- python3 -m pytest tests/ -q → 3654 passed (+3 vs Phase 5 baseline)
- python3 -m ruff check src tests → All checks passed!
- python3 -m ruff format --check src tests → 216 files already formatted
- python3 -m behave features/ --no-color → 1048 scenarios, 0 failed
- python3 uat/uat_headers_footers_phase5.py → script runs clean;
watermark shape_id=7 (was 2147483660 pre-fix). UAT signoff is
maintainer-only per CLAUDE.md §6a — please re-open the regenerated
uat/out_headers_footers_phase5.pptx in PowerPoint to confirm.
Refs #52.1 parent dba6ca4 commit 35f592e
2 files changed
Lines changed: 52 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
160 | 164 | | |
161 | | - | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
162 | 170 | | |
163 | 171 | | |
164 | 172 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
91 | 126 | | |
92 | 127 | | |
93 | 128 | | |
| |||
0 commit comments