iOfficeAI / iOfficeAI/OfficeCLI
[BUG] pptx: targeted edit re-serializes every untouched slide XML part
- Dominant language
- C#
- Stars
- 30.7k
- Forks
- 2.1k
- Avg merge
- 9d 8h
- Merged PRs (30d)
- 5
Description
## Summary
On a PPTX authored by Microsoft Macintosh PowerPoint, changing one paragraph on slide 1 with `officecli set` re-serializes every slide XML part in the package.
The untouched slides remain visually valid in my test, but they are no longer byte-preserved. This creates noisy package diffs and increases the round-trip risk for unsupported or extension XML on slides that the command did not target.
## Environment
- OfficeCLI: `1.0.142`
- OS: Linux x86_64
- Source PPTX producer (`docProps/app.xml`): `Microsoft Macintosh PowerPoint`
- Deck: 18 slides
## Reproduction
```bash
cp input.pptx before.pptx
cp input.pptx after.pptx
officecli set after.pptx \
'/slide[1]/shape[@id=4]/paragraph[1]' \
--prop 'text=OfficeCLI round-trip probe' \
--json
mkdir before after
unzip -qq before.pptx -d before
unzip -qq after.pptx -d after
for f in before/ppt/slides/slide*.xml; do
name=$(basename "$f")
cmp -s "$f" "after/ppt/slides/$name" || echo "$name"
done
```
Observed output:
```text
slide1.xml
slide2.xml
...
slide18.xml
```
Only slide 1 was targeted. For example, `slide2.xml` changed from 19,543 bytes to 19,944 bytes solely through serializer normalization (XML declaration/empty-element/whitespace formatting); its content was not intentionally edited.
The same command on a PPTX generated by OfficeCLI itself did not produce unrelated slide diffs, so this appears to be most visible when OfficeCLI first opens a package serialized by another producer.
## Expected behavior
A targeted edit to slide 1 should persist the modified slide and any package-level parts that genuinely require an update, while leaving unrelated slide parts byte-for-byte unchanged.
If whole-deck normalization is intentional, an explicit opt-in mode would be safer than making it the default for a targeted edit.
## Possible cause
`PowerPointHandler` calls `InitShapeIdCounter()` when an editable document is opened. That method walks `GetSlideParts()` and calls `GetSlide(slidePart)` for every slide, loading every slide root into the Open XML SDK DOM. A later package save may then serialize all loaded roots, including clean slides.
Relevant locations:
- `src/officecli/Handlers/PowerPointHandler.cs` (editable constructor)
- `src/officecli/Handlers/Pptx/PowerPointHandler.Helpers.ShapeId.cs` (`InitShapeIdCounter`)
A regression test could use a fixture with deliberately non-SDK lexical serialization, edit one paragraph on slide 1, then assert that the raw ZIP bytes for `ppt/slides/slide2.xml` and subsequent untouched slides remain identical.
If a shareable fixture is needed, I can build a synthetic PPTX that preserves the relevant producer/serialization characteristics. The original test deck contains private business material and will not be uploaded.
Contributor guide
Research direction
Start by reading the editable constructor in src/officecli/Handlers/PowerPointHandler.cs and InitShapeIdCounter in src/officecli/Handlers/Pptx/PowerPointHandler.Helpers.ShapeId.cs, then run the supplied officecli set and ZIP comparison. Add a regression fixture with non-SDK lexical serialization and verify that editing slide 1 leaves the raw bytes of untouched slide XML parts unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100