Closes the gap between what the guide documents and what the tooling actually enforces.
Two documented failure modes were described but never checked. tbl@rowCnt disagreeing with the real row count collapses the document onto one page; a stale secCnt after pulling a chapter out of a merged report opens to a single blank page. hwpxlib kept both correct when you went through its helpers, but a document that arrived already wrong passed every check. Both are now gated, and exposed as rowcnt_mismatches() / seccnt_mismatch().
The checks only ran if the agent chose to run them. hwpx_guard.py registers as a PostToolUse hook: after each Bash command it takes the .hwpx files named in it that were just modified, runs the structural checks, and hands any failure back to the agent to fix on the spot. Silent on success, and harness-executed — its model-context cost is zero.
Nothing pinned the helpers' output. corpus/ runs five real edits — row deletion, column widening, a cell edit, two endnotes at one anchor, section extraction — against a document generated in code, and compares the result to committed expectations. Comparison is structural rather than byte-exact, since a re-deflated entry varies with the zlib version and CI runs on a different platform than development.
Fixed
table_width_ok()raisedAttributeErroron a table missing its geometry, aborting the wholeverify.pyrun instead of reporting. It now returns "no verdict".- Both new gates treat an absent attribute as stating nothing rather than as a failure, and the
secCntlookup no longer assumes thehh:prefix. - The 0.1.0 changelog listed
rowCntandsecCntamong its hard checks. They were not checked; corrected in place.
Full detail in CHANGELOG.md.