Problem
DocxReader.parseRunProperties treats <w:b>, <w:i>, <w:strike>, and <w:noProof> as true whenever the element exists, ignoring explicit off values such as w:val="0", false, or off. RunProperties.toXML() can then emit only the on form. A read → unrelated mutation → write round-trip therefore turns an untouched <w:b w:val="0"/> into <w:b/>.
Type
bug
Expected
- Typed on/off run properties preserve three states: absent, explicitly on, explicitly off.
- An untouched explicit-off property remains semantically off after save.
- Existing source-compatible reads such as
properties.bold still return false for absent and explicit-off states.
- Merge/formatting APIs can intentionally apply
false, rather than treating it as “unspecified”.
Actual
RunProperties.bold, italic, strikethrough, and noProof are plain Bool values.
- The reader sets them to true on element presence.
- The emitter omits false and emits naked elements for true.
merge(with:) applies only true, so callers cannot remove an existing boolean property.
Scope / Acceptance
- Add RED→GREEN read/write tests for
<w:b w:val="0"/>, including an unrelated paragraph mutation before save.
- Cover accepted ST_OnOff spellings (
0/false/off and omitted/1/true/on).
- Preserve source compatibility for callers reading/writing the existing Bool properties.
- Make merge distinguish an unspecified patch from an explicit false patch.
- Cover italic, strikethrough, and noProof through the same typed mechanism; untyped raw run-property children remain outside this issue.
- Run focused reader/writer/model tests and the full package suite.
Cross-repo tracking
Current Status
Phase: verified
Last updated: 2026-08-31 by idd-verify
Key Decisions
- Preserve public Bool access while storing absent/on/off assignment presence internally.
- Merge and copy by presence, not truthiness; explicit false and underline
none survive parser, writer, RunPayload, reducer, reverse extractor, and revision paths.
rPrChange delegates to the single canonical RunProperties.toXML() emitter.
Blocking
Follow-up
Commits
563039c — final program behavior.
a3fab8b — frozen consumer proof.
Verification
Pull Request
Problem
DocxReader.parseRunPropertiestreats<w:b>,<w:i>,<w:strike>, and<w:noProof>as true whenever the element exists, ignoring explicit off values such asw:val="0",false, oroff.RunProperties.toXML()can then emit only the on form. A read → unrelated mutation → write round-trip therefore turns an untouched<w:b w:val="0"/>into<w:b/>.Type
bug
Expected
properties.boldstill returnfalsefor absent and explicit-off states.false, rather than treating it as “unspecified”.Actual
RunProperties.bold,italic,strikethrough, andnoProofare plainBoolvalues.merge(with:)applies only true, so callers cannot remove an existing boolean property.Scope / Acceptance
<w:b w:val="0"/>, including an unrelated paragraph mutation before save.0/false/offand omitted/1/true/on).Cross-repo tracking
Current Status
Phase: verified
Last updated: 2026-08-31 by idd-verify
Key Decisions
nonesurvive parser, writer, RunPayload, reducer, reverse extractor, and revision paths.rPrChangedelegates to the single canonicalRunProperties.toXML()emitter.Blocking
Follow-up
Commits
563039c— final program behavior.a3fab8b— frozen consumer proof.Verification
idd-115-verified; still awaiting human merge.Pull Request