python-hwpx product boundary
python-hwpx is the primary product: an independently useful HWPX document
library comparable in role to python-docx.
Core owns
the document object model and public facade;
OPC package and OXML part ownership;
generic reading, traversal, editing, formatting, and table primitives;
serialization, byte/story preservation, validation, rollback, and recovery;
renderer-neutral quality contracts such as
RenderBackend,EditMask, andVisualReport.
Companion layers own
python-hwpx-automation owns office workflows, genre/profile/policy decisions, agent
plans, Hancom discovery, and renderer binding. hwpx-skill owns task judgment,
routing, and prompt guidance.
Core must not import either companion package. A new core module that was not
present at the 4.2.0 baseline requires an explicit entry in
module-ownership.json; falling through the generic
core rule is not enough.
Mixed-module decisions
qualityandtable_patchstay core.renderer-neutral protocols are core; Hancom/backend binding and visual execution belong to
python-hwpx-automation.document diff keeps a generic diff model in core; task-plan composition moves.
mail merge keeps generic HWPX binding in core; sanitization/policy is injected.
tracked-change format primitives stay core; oracle verification moves.
benchmark and conformance campaign runners are repository QA, not product API.
The 5.0 boundary is closed: every non-core disposition (mcp-migrate, split,
dev-only, and undecided) must remain exactly zero. A non-core file fails the
ownership gate even if it would have fit beneath the historical baseline or
carried a self-consistent ledger exception.
The 4.2 path baseline is the repository fixture
module-ownership-baseline-4.2.json, pinned independently by path count and
SHA-256 in the checker, ledger, and tests. The gate never reads Git history, so
the same result is required in full, shallow, single-commit, and gitless source
copies.
Removal is a second, independent invariant. The exact 77 paths removed in 5.0
are recorded in module-ownership-removed-5.0.json at SHA-256
4b8b4da35b3cf44503eb0dba05e335de1894ca5dd0b2fb668692a69e21ae6172.
Every one must remain absent even if an empty file, a new implementation, or a
new ledger exception would otherwise classify as core. Public-artifact hygiene
normalizes both wheel members (hwpx/...) and sdist members
(<archive-root>/src/hwpx/...) back to repository paths and applies the same
zero-resurrection inventory.
Closed import capability
The gate AST-inspects every core Python module. Absolute imports are fail-closed:
the allowed roots are the running Python’s standard library, hwpx, and the
three declared runtime dependencies lxml, openpyxl, and latex2mathml.
Everything else—including the companion products, MCP SDK, PDF/rendering,
numerical, COM, and macOS GUI bindings—is rejected without maintaining a
guessable denylist.
Dynamic loading is capability-gated, not inferred from literal target strings.
Core cannot acquire importlib loaders, importlib.util, find_spec, builtin
__import__, eval, or exec. subprocess and ctypes imports and
os.system/os.popen (including the covered alias and reflective forms) are
also forbidden. The only exceptions are:
one exact
from importlib import resourcesimport used by packaged templates;PackageNotFoundErrorandversionimported directly fromimportlib.metadata, inside_resolve_version()rather than at module scope — a module-level binding leakshwpx.PackageNotFoundErroronto the top-level surface even though it is not in__all__, so keep the import in the function;the two code-pinned
importlib.import_module(module_name)calls insrc/hwpx/__init__.py.
The two lazy calls, their line/version-neutral AST fingerprint, and their
12-entry literal-map inventory are pinned. Each call also performs a runtime
fail-closed check that the selected module is exactly hwpx or below hwpx.*;
mutating the private map cannot turn it into an external import.
This is an architectural dependency ratchet, not a Python security sandbox. Arbitrary standard-library laundering, native extensions, generated bytecode, and intentionally obfuscated runtime code are outside its threat model. The gate covers normal source imports and the explicitly tested acquisition, aliasing, assignment, and reflection forms; release review and package tests remain responsible for hostile-code scenarios.