iOfficeAI / iOfficeAI/OfficeCLI

[BUG] pptx: targeted edit re-serializes every untouched slide XML part

Open
#267 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.