Skip to content

fix: real insert/remove_watermark, honest image-watermark error, sectPr hydration - #171

Open
ebolamerican wants to merge 1 commit into
PsychQuant:mainfrom
ebolamerican:fix/watermark-remove-and-sectpr-hydration
Open

fix: real insert/remove_watermark, honest image-watermark error, sectPr hydration#171
ebolamerican wants to merge 1 commit into
PsychQuant:mainfrom
ebolamerican:fix/watermark-remove-and-sectpr-hydration

Conversation

@ebolamerican

@ebolamerican ebolamerican commented Jul 17, 2026

Copy link
Copy Markdown

Summary

The watermark tools were stubs that reported success without touching the document, and open_document never populated sectionProperties from the source sectPr — so any typed re-emission of word/document.xml collapsed margins, page geometry, and header/footer references to defaults.

This PR makes those tools do what they claim, and works around the DocxReader sectPr gap server-side.

Changes

  • insert_watermark actually inserts a watermark. Writes Word's own VML WordArt watermark (PowerPlusWaterMarkObject textpath shape, o:spt="136") into the default page header, honoring font / color / size / semitransparent / rotation. Three paths:
    • Existing default header — append the watermark paragraph to the header's typed bodyChildren.
    • Scratch-built document (no archiveTempDir) — pure typed path via addHeader; the writer emits every part from the typed model.
    • Source-loaded document with no header part (the reported repro: an engine-built .docx with footer1.xml only) — wire the new header surgically into the preserved archive (relationship in word/_rels/document.xml.rels, Override in [Content_Types].xml, <w:headerReference> inserted into the existing body-level <w:sectPr>) before registering the typed Header, so DocxWriter's overlay gates stay closed and the source rels / [Content_Types].xml are preserved verbatim. A second insert errors instead of stacking duplicate shapes.
  • remove_watermark actually removes. Strips watermark paragraphs from every header (typed raw blocks and source-parsed w:pict runs) and errors honestly when no watermark exists.
  • insert_image_watermark returns an honest error. Image watermarks need media-part plumbing that isn't implemented; the tool now returns a not-implemented error instead of the prior false success that wrote nothing.
  • open_document hydrates sectionProperties (header/footer refs incl. first/even, page size + orientation, margins, columns, titlePg, section break type, pgNumType, vAlign, line numbers, docGrid) from the source body-level <w:sectPr>. This works around DocxReader leaving sectionProperties at defaults (see filed upstream issue), which otherwise caused every typed re-emission of word/document.xml to silently drop the source's footer reference, custom margins, and page geometry.

Tests

  • Tests/CheWordMCPTests/WatermarkInsertRegressionTests.swift — append-to-existing-header, create-header-when-none-exists, remove actually removes, second insert errors.
  • Tests/CheWordMCPTests/SectPrPreservationProbeTests.swiftinsert_paragraph preserves the source footer reference.

swift build clean; swift test green (5/5 on the new suites).

Related upstream issues

These fixes work around, but do not fix, three root-cause bugs filed separately:

🤖 Generated with Claude Code

@ebolamerican
ebolamerican force-pushed the fix/watermark-remove-and-sectpr-hydration branch from 6fb4509 to 7fb031e Compare July 17, 2026 21:26
…Pr hydration

The watermark tools were stubs that reported success without touching the
document, and open_document never populated sectionProperties from the
source sectPr — so any typed re-emission of word/document.xml collapsed
margins, page geometry, and header/footer references to defaults.

- insert_watermark now writes Word's VML WordArt watermark
  (PowerPlusWaterMarkObject textpath, o:spt="136") into the default page
  header, honoring font/color/size/semitransparent/rotation. Three paths:
  append to an existing default header; pure-typed for scratch-built docs;
  and, for source-loaded docs with no header part, surgically wire the new
  header (relationship + Content_Types Override + sectPr headerReference)
  into the preserved archive BEFORE registering the typed Header, so
  DocxWriter's overlay gates stay closed and source rels/[Content_Types]
  are preserved verbatim. A second insert errors instead of stacking shapes.
- remove_watermark strips watermark paragraphs from every header (typed
  raw blocks and source-parsed w:pict runs) and errors when none exists.
- insert_image_watermark returns an honest not-implemented error instead
  of the prior false success that wrote nothing.
- open_document hydrates sectionProperties (header/footer refs incl.
  first/even, page size + orientation, margins, columns, titlePg, section
  break type, pgNumType, vAlign, line numbers, docGrid) from the source
  body-level <w:sectPr>, working around DocxReader's sectPr stub.

Regression tests: WatermarkInsertRegressionTests, SectPrPreservationProbeTests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ebolamerican
ebolamerican force-pushed the fix/watermark-remove-and-sectpr-hydration branch from 7fb031e to cf2e0d5 Compare July 17, 2026 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant