Release note · August 1, 2026

A Word link can exist outside its relationship graph

By SybilGambleyyu · DocFence 0.17.0

Most Word-link review starts with package relationships. That is useful, but incomplete. Word can also store a HYPERLINK field code whose destination sits directly in the field instruction. There may be no corresponding relationship target to inspect.

That gap matters in CI and controlled handoffs. A document can gain a direct web, file, or bookmark destination without adding the package record a relationship-only check expects. The right evidence is that the field code exists and changed—not the destination copied into a build log.

DocFence 0.17 adds a separate, privacy-safe inventory for those stored field references.

A field code is not a relationship

Microsoft’s current Word field guidance describes a Hyperlink field as a link to a location in the document or an external location. The OOXML field definition makes the boundary concrete: the primary field argument identifies a bookmark or URL, while \l identifies a location in the current file.

That means a literal first argument is not enough to call a field external. It could be a URL, a file location, or a bookmark. DocFence deliberately does not guess. Its public inventory separates only three lexical cases: a literal leading destination, a literal \l internal-location-only target, and a dynamic or unparseable field code.

The report never prints the destination, bookmark, ScreenTip, frame target, field instruction, or story path. It also does not resolve, retrieve, follow, evaluate, or render a link.

Read stored code, not displayed results

Word can encode a field as a compact w:fldSimple instruction or as a complex begin/instruction/separate/end sequence. Complex instructions can be split across runs, retained in tracked-deletion markup, or contain nested fields. A displayed result can be stale and is not a safe substitute for the stored code.

DocFence therefore scans only complete simple instructions and complete complex pre-separator instructions across supported Word stories. Current and deleted field-code variants remain separately review-visible. Loose instruction text, post-separator result text, and unclosed complex fields do not create an inventory count.

Two policy choices

For a handoff that must contain no stored HYPERLINK field references:

rules:
  require_no_word_hyperlink_fields: true

This produces DFP047. For a governed template that intentionally retains the fields:

rules:
  no_word_hyperlink_field_changes: true

DFP048 protects the private inventory against a later mutation. These rules complement relationship and external-source-field policies rather than redefining them: each covers a different stored representation.

Release evidence

The 0.17 suite has 43 tests. It covers simple and split complex fields, quoted and plain arguments, \l internal locations, trailing switches, nested/dynamic and compound expressions, current/deleted variants, headers, Strict Word XML, same-count destination changes, policy/SARIF output, and redaction.

For an independent smoke test, the released wheel profiles the public doc.docx attachment from Pandoc issue #9246. It contains a complete complex HYPERLINK \l field in a real Word document. DocFence reports one literal internal-location-only reference without emitting its bookmark or result text.

Hosted CI passed on Python 3.11 and 3.13, including distribution validation. The wheel and source archive were independently rebuilt from the release commit and matched byte-for-byte; fresh GitHub release downloads passed the published SHA-256 manifest and package checks.

python -m pip install https://github.com/SybilGambleyyu/docfence/releases/download/v0.17.0/docfence-0.17.0-py3-none-any.whl

docfence profile candidate.docx --format markdown
docfence check approved.docx candidate.docx --policy docfence.yml --format sarif --output docfence.sarif

The public release includes the wheel, source archive, and SHA-256 manifest. Read the precise boundary in the policy reference and threat model.