Status: proposed only. Nothing in this repo has been changed. Ready to paste.
Why this repo
Across the platform, 4 of 7 packages carry import cycles: views-pipeline-core (7), views-hydranet (2), views-faoapi (1), views-crafdapi (1). views-postprocessing has none — along with views-frames and views-reporting. A contract here passes on day one and costs nothing.
Worth noting: this is also the only register on the platform that fully converges (78 concerns arrived, 78 resolved, open count flat at 22 over four months). Locking in the structure seems worth the two lines.
The measured structure
crafd -> contract, delivery
unfao -> contract, delivery
contract -> delivery
delivery -> (nothing)
Proposed contract
[tool.importlinter]
root_package = "views_postprocessing"
[[tool.importlinter.contracts]]
name = "Postprocessing layering"
type = "layers"
layers = [
"views_postprocessing.crafd | views_postprocessing.unfao",
"views_postprocessing.contract",
"views_postprocessing.delivery",
]
Plus import-linter = ">=2.0" in [tool.poetry.group.dev.dependencies], and one line after the Lint step in .github/workflows/run_pytest.yml (~line 118):
- name: Imports
run: poetry run lint-imports
| means the siblings are independent — crafd and unfao may not import each other, which is what prevents a cycle. Neither does today.
A concern that was raised and then disproved
views_postprocessing/ has no __init__.py, so it is an implicit namespace package, and I expected that to block import-linter — its graph builder has to import the root package. Tested in an isolated environment against this source tree, and it works: grimp built the graph successfully, finding 37 modules and all four top-level packages (contract, crafd, delivery, unfao).
So there is no packaging change needed and no __init__.py should be added on the linter's account. Recording it here because it looked like a blocker and is not.
To apply
- Paste the block into
pyproject.toml, add the dev dep and the CI step.
poetry install && poetry run lint-imports → expect Contracts: 1 kept, 0 broken.
- Mutation-test it — add
from views_postprocessing.crafd import ... to something under delivery/, confirm it breaks and names the chain, revert. A contract nobody has seen fail is not yet known to work.
poetry run pytest.
Precedent
Applied and mutation-tested in views-frames (views-platform/views-frames#238), where both contracts caught injected violations and named the exact offending import line.
Filed by Claude Opus 5 at Simon's request. Not applied here — this repo was deliberately left untouched.
Status: proposed only. Nothing in this repo has been changed. Ready to paste.
Why this repo
Across the platform, 4 of 7 packages carry import cycles:
views-pipeline-core(7),views-hydranet(2),views-faoapi(1),views-crafdapi(1).views-postprocessinghas none — along withviews-framesandviews-reporting. A contract here passes on day one and costs nothing.Worth noting: this is also the only register on the platform that fully converges (78 concerns arrived, 78 resolved, open count flat at 22 over four months). Locking in the structure seems worth the two lines.
The measured structure
Proposed contract
Plus
import-linter = ">=2.0"in[tool.poetry.group.dev.dependencies], and one line after theLintstep in.github/workflows/run_pytest.yml(~line 118):|means the siblings are independent —crafdandunfaomay not import each other, which is what prevents a cycle. Neither does today.A concern that was raised and then disproved
views_postprocessing/has no__init__.py, so it is an implicit namespace package, and I expected that to block import-linter — its graph builder has to import the root package. Tested in an isolated environment against this source tree, and it works: grimp built the graph successfully, finding 37 modules and all four top-level packages (contract,crafd,delivery,unfao).So there is no packaging change needed and no
__init__.pyshould be added on the linter's account. Recording it here because it looked like a blocker and is not.To apply
pyproject.toml, add the dev dep and the CI step.poetry install && poetry run lint-imports→ expectContracts: 1 kept, 0 broken.from views_postprocessing.crafd import ...to something underdelivery/, confirm it breaks and names the chain, revert. A contract nobody has seen fail is not yet known to work.poetry run pytest.Precedent
Applied and mutation-tested in
views-frames(views-platform/views-frames#238), where both contracts caught injected violations and named the exact offending import line.Filed by Claude Opus 5 at Simon's request. Not applied here — this repo was deliberately left untouched.