| id | 154 |
|---|---|
| title | arch-fix: extract cross-rule helpers |
| status | ✅ |
| summary | Move shared fence-position and table-format helpers out of donor rule packages into sibling helper packages so no rule imports another rule. |
| model | sonnet |
| depends-on |
Stop rules importing other rules. The architecture hub forbids it. Keep the boundary at compile time.
Closes the first blocker in Audit 2026-05-13.
Five rules reach across the rule boundary for shared helpers today.
Four rules import
internal/rules/fencedcodestyle. Each
uses FenceCharAt, FenceOpenLine,
FenceOpenLineRange, FenceCloseLine,
and FenceCloseLineRange. The four
rules are:
internal/rules/fencedcodelanguageinternal/rules/orderedlistnumberinginternal/rules/unclosedcodeblockinternal/rules/blanklinearoundfencedcode
A fifth rule (internal/rules/catalog)
imports internal/rules/tableformat
for FormatString.
The donor rule packages still own
MDS010 and MDS035. The cross-rule
reach is into their exported helper
functions, not their rule.Rule
implementation. The structural fix is
the same for both. Lift the helpers
into a sibling helper package
consumed by donor and consumer.
- Create
internal/rules/fencepos/exportingCharAt,OpenLine,OpenLineRange,CloseLine, andCloseLineRange. Drop theFenceprefix; the package name carries the noun. Move the implementations out ofinternal/rules/fencedcodestyle/rule.go. - Update
internal/rules/fencedcodestyle/rule.goto import and consumefencepos. No exported helpers remain on the rule package. - Update the four consumer rules
(
fencedcodelanguage,orderedlistnumbering,unclosedcodeblock,blanklinearoundfencedcode) to importfenceposinstead offencedcodestyle. - Create
internal/rules/tablefmt/exportingFormatString. Move the implementation out ofinternal/rules/tableformat/rule.go. The donor rule also consumesViolationsandFormatLinesso the table parsing/formatting machinery lives in one place. - Update
internal/rules/tableformat/rule.goandinternal/rules/catalog/rule.goto importtablefmt. - Add a grep-based regression test
under
internal/integration/(TestRulesDoNotImportEachOtherinrule_boundaries_test.go). Make it fail if any non-test file underinternal/rules/imports anotherinternal/rules/<...>/package. Allow only the documented helpers (astutil,settings,fencepos,tablefmt) and same-rule sub-packages. The blank-import barrelall/is exempt.
-
internal/rules/fencepos/andinternal/rules/tablefmt/exist. Their package comments name the single question each answers. (SRP) - The regression search reports
only the allowed cross-package
imports under
internal/rules/. (DIP) - All tests pass:
go test ./.... -
go tool golangci-lint runreports no issues. -
mdsmith check .passes after the refactor. - The audit entry for this blocker moves to a "Resolved by plan/154" section in the audit log.