Release note · August 1, 2026
A relationship is not a Word hyperlink
Package relationships are a useful review surface, but their count is not a count of Word links. A hyperlink relationship can remain in a package after its visible markup is gone. Conversely, a direct WordprocessingML w:hyperlink can point to an in-document anchor—or the start of the document—without a relationship at all.
That distinction matters in CI and controlled handoffs. A reviewer needs evidence about the stored element that a Word client can interpret, not an accidental proxy from an unrelated or residual package record. The right report says that direct hyperlink markup exists and changed, while keeping its target material out of logs.
DocFence 0.18 adds that review boundary.
Three stored target forms
The OOXML w:hyperlink definition separates a relationship ID from a local anchor. With r:id, the relationship specifies the target. With no ID, w:anchor can name a local destination. With neither, the documented form navigates to the start of the current document.
When both r:id and w:anchor are stored, the relationship wins. That is a precedence rule, not two destinations. The anchor remains useful review evidence, but copying its value into a build log would defeat a privacy-safe review boundary.
A recognized hyperlink relationship can have either an internal or external target mode. DocFence preserves that stored mode distinction, but never guesses whether a target is a web URL, reachable, permitted, safe, or rendered by a particular client.
Count direct markup, not guesses
The new inventory reports aggregate direct-element and story counts; relationship-backed totals; external, internal, and unsupported relationship classes; anchor-only and current-document-start forms; and anchors shadowed by a relationship-backed element. A hyperlink relationship with no direct w:hyperlink reference does not inflate this inventory.
Targets, anchors, locations, tooltips, frame names, history, display text, relationship IDs, story paths, and fingerprints remain private. The private signature still notices a same-count target or markup rewrite. Relationship-ID renumbering with otherwise identical semantics stays quiet.
DocFence does not resolve, retrieve, follow, validate, evaluate, or render a link. This is stored-package evidence for review—not a link scanner, URL validator, or safety verdict.
Two policy choices
For a handoff that must contain no direct Word hyperlink markup:
rules:
require_no_word_hyperlink_markup: true
This produces DFP049. For a governed template that intentionally retains direct links:
rules:
no_word_hyperlink_markup_changes: true
DFP050 protects the private direct-markup baseline. These policies complement—not replace—the generic relationship policy and the separate HYPERLINK field policies. Each representation carries different evidence.
Release evidence
The 0.18 suite has 44 tests. It covers external and internal relationship modes, a resolved unsupported relationship, anchor-only and current-document-start forms, r:id precedence over an anchor, body/header stories, Transitional and Strict namespaces, orphaned relationship exclusion, same-count target and anchor changes, relationship-ID renumbering stability, policy/SARIF output, and redaction.
For an independent smoke test, the released wheel profiles python-docx’s public par-hyperlinks.docx fixture. It contains four direct relationship-backed hyperlink elements. DocFence reports four direct elements and four external relationship-backed elements without emitting their targets or display text.
Hosted CI passed on Python 3.11 and 3.13, including distribution validation. The wheel and source archive were independently rebuilt from the tagged 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.18.0/docfence-0.18.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 exact contract in the policy reference and threat model.