Skip to content

fix(mailings): header and footer fields stay unresolved after merge #430

Closed

Description

@coygeek

Summary

A recipient field inserted in an attached header stays as «Name» during Preview Results and after Finish & Merge. The same field in the body resolves correctly. The erroneous header result persists in the saved DOCX and after reopening. A footer inserted through the analogous public command has the same failure.

Steps to reproduce

Use the CLI runtime described below. Run the following in a disposable directory with wordcraft-cli on PATH. This one-recipient fixture was executed locally; it needs no recipient file or existing document.

wordcraft-cli run --template blank --print \
  --cmd 'mailings.recipients={"rows":[{"Name":"Alpha"}]}' \
  --cmd 'insert.header={"text":"Recipient: "}' \
  --cmd caret.docEnd \
  --cmd 'mailings.insertField={"field":"Name"}' \
  --cmd insert.closeHeader \
  --cmd 'text.insert={"text":"Body: "}' \
  --cmd 'mailings.insertField={"field":"Name"}' \
  --cmd 'mailings.preview={"value":true}' \
  --cmd document.inspect \
  --cmd 'mailings.preview={"value":false}' \
  --cmd document.inspect \
  --cmd 'mailings.finish={"from":1,"to":1}' \
  --cmd document.inspect \
  --save merged.docx
wordcraft-cli inspect merged.docx

Compare the body and part texts in each inspection. Repeat the same commands in a fresh session with insert.footer in place of insert.header to reproduce the footer variant. Both variants were run, saved, and reopened successfully.

To inspect the stored field independently, run this comparison after the header fixture:

python3 - <<'PY'
import zipfile
import xml.etree.ElementTree as ET
ns = {'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'}
with zipfile.ZipFile('merged.docx') as z:
    for name in ('word/document.xml', 'word/header1.xml'):
        root = ET.fromstring(z.read(name))
        text = ''.join(e.text or '' for e in root.findall('.//w:t', ns))
        fields = [e.text for e in root.findall('.//w:instrText', ns)]
        print(name, repr(text), fields)
PY

Expected behavior

Preview Results should show Recipient: Alpha in the attached header and Body: Alpha in the body. Turning preview off should restore the merge-field placeholders. Finishing the selected recipient should produce Recipient: Alpha and Body: Alpha in the saved document, with the recipient fields resolved to text. The same contract applies to the accepted footer field.

Actual behavior

Every fixture command exited successfully. With preview enabled, inspection showed Body: Alpha and the attached header as Recipient: «Name». With preview disabled, the body correctly returned to Body: «Name»; the header did not change. Finish returned {"records":1} and resolved the body to Body: Alpha, while the attached header still read Recipient: «Name».

The saved DOCX contained body text Body: Alpha with no body field instructions. Its header contained Recipient: «Name» and the instruction MERGEFIELD Name. A fresh CLI inspection of the saved file showed the same incorrect header text. The footer variant gave the corresponding unresolved footer result in memory, in its stored XML, and after reopening.

Evidence

Source locators below refer to the current recheck source. Original execution identity is retained under Runtime or environment.

  • Expected source: README.md:119 documents mail merge fields, preview and finish to a document. The public command declarations in crates/engine/src/cmd/insert.rs:45 and crates/engine/src/cmd/mailings.rs:60 support creating header/footer parts and inserting a merge field at the active selection, without a body-only restriction. The preview contract at crates/engine/src/cmd/mailings.rs:377 specifies recipient values during preview, and the finish contract at line 420 specifies that fields become plain text.
  • Failure source: The executed inline fixture's inspections, independently read word/document.xml and word/header1.xml, and fresh CLI inspection of the saved DOCX all show the unresolved attached header alongside the resolved body. The footer variant reproduces the same result. Source checks at crates/engine/src/cmd/mailings.rs:378 and line 421 confirm that preview evaluates body paragraphs and finish merges body blocks while retaining the document parts.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The primary violation evidence is execution through the public CLI and inspection of the stored output. Source inspection separately supports reachability and scope. Both header and footer cases were executed, saved, independently inspected as DOCX XML, and reopened.

The fixture uses a fresh unprotected document, a known field name, one recipient, and the same field-insertion command in both stories. Its body control demonstrates that recipient loading and ordinary merge evaluation work. The accepted selection remains in the attached header or footer until Close Header and Footer returns it to the body.

The current recheck independently searched all 170 listed issue bodies and read the relevant live comments and fixing patches. No matching open or closed report was found for this failure; routing remains a separate new bug report.

Restoration check

Run the header fixture and its footer variant. With preview enabled, both the body and attached part must show Alpha. With preview disabled, both must show the Name placeholder, which prevents replacing the template field permanently just to satisfy preview. After finish, independently inspect and reopen the saved DOCX: the body and attached part must retain Alpha and no unresolved Name merge field. Keep the attached part and the Recipient: prefix; deleting the part or moving its content into the body does not restore the contract.

Runtime or environment

  • Original verification source baseline: 4615cef8784b6fc23a6cd356070802ccba21098f. The supplied read-only checkout was directly verified at this revision with a clean working tree.
  • Original runtime: the supplied native macOS build, reporting wordcraft-cli 0.4.0; independently measured binary SHA-256 0424c3df03f1e565a5c862f5cef3158342d3726a18d1a40181e088b4df4f0f6b. Its source association comes from the supplied build provenance.
  • All runtime checks used synthetic content and a 60-second timeout per invocation. GUI behavior, external Word rendering, first/even header variants, and automated multi-recipient header results were not tested.
  • Current recheck source: e4b7d155f15a7784197ba34eeea0b54490d70eb2, directly confirmed as clean checkout HEAD. Current supplied native runtime reports wordcraft-cli 0.5.0 on macOS; measured executable SHA-256: 6292c6e5b24074eed6193529e3003d0d9a987e13db803ad99cb14e4b0f201651. Source association follows the supplied build provenance; this reviewer did not rebuild it.
  • Current verification: Every executable reproduction in this report was rerun, followed by the meaningful comparison and workaround controls. The attached header and footer remain unresolved in preview, finish, stored XML and reopened output. The body resolves to Alpha, and manual replacement works for the single-record fixture. All CLI fixture invocations completed with exit 0; no GUI execution is claimed.

Additional context

For the single-record case, replacing the header field with the known recipient text before finishing is a verified workaround. After inserting the body field, insert.header={"text":"Recipient: Alpha"} followed by insert.closeHeader and the same finish command produced correct body and header text in the saved and reopened DOCX. This requires manual recipient substitution and does not establish an automated multi-recipient workaround.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Accepted header/footer merge fields remain unresolved in generated output, including the saved document. The demonstrated defect affects a bounded document-part combination; the same body fields work, and no crash or source-document loss was observed.
  • Workaround status: available
  • Workaround basis: Manual replacement with the recipient's text was demonstrated to preserve the requested header and correct body output for the single-record case. It requires extra editing; automated multi-recipient output was not evaluated.

Activity

  1. vangel76 commented on Oct 11, 2026

    @vangel76
    Contributor

    I'll take this together with #427–#430 (mail merge rules bundle). Fix + regression test, PR follows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions