Files
govoplan/docs/MODULE_CONTRACTS_AND_INSTALLS.md
Albrecht Degering 05ae81d641
Some checks failed
Dependency Audit / dependency-audit (push) Failing after 16s
Security Audit / security-audit (push) Failing after 11s
intermediate commit
2026-07-14 13:32:09 +02:00

4.4 KiB

Module Contracts and Install Boundaries

Why Some Changes Require pip install

GovOPlaN discovers runtime modules through Python package entry points in the govoplan.modules group. Core reads those entry points with importlib.metadata.entry_points(), imports the configured manifest factory, and then builds the module registry from the returned ModuleManifest.

That means the Python environment must know that a package exists before core can discover it.

In development, requirements-dev.txt installs modules with -e ../govoplan-module. With editable installs:

  • normal Python source changes are picked up after the process reloads;
  • manifest code changes are picked up after the process reloads;
  • new imports inside an already installed package are picked up after reload.

pip install is still needed when package metadata changes:

  • a repository was not installed in the environment before;
  • a pyproject.toml entry point is added, renamed, or removed;
  • package dependencies change;
  • optional extras change;
  • package names or import roots change;
  • console scripts or other installed metadata change;
  • release installs need a different tag, wheel, or source ref.

The same principle applies to WebUI packages: source changes are local during development, but package.json dependency or export changes require an install step so the consuming app sees the correct package metadata.

Current Contract Mechanism

Modules already announce contracts through ModuleManifest:

  • dependencies
  • optional_dependencies
  • required_capabilities
  • optional_capabilities
  • provides_interfaces
  • requires_interfaces
  • capability_factories
  • permissions and role templates
  • route factories, migrations, docs, lifecycle hooks, and frontend metadata

Core validates the active manifest graph when it builds the registry. Release tooling can inspect those manifests to calculate compatibility and migration impact.

What Core Can and Cannot Pick Up Automatically

Core can pick up contract changes automatically after reload when the changed module package is already installed and importable.

Core cannot discover a new module or new entry point that has not been installed into the environment, because there is no distribution metadata to enumerate.

Core also cannot notify every module about a contract change at edit time by itself. The runtime registry is built from installed/importable packages. The right place for cross-module announcement is the meta repo tooling and CI:

  • scan manifests across all repositories;
  • build an impact graph from provided/required interfaces and capabilities;
  • run affected module tests;
  • post Gitea issue/release notes for affected modules;
  • block releases when a required interface is missing or incompatible.

Mitigation Strategy

Use three layers:

  1. Editable development environment. Keep requirements-dev.txt in the meta repo as the one workspace installer. Source edits then need process reloads, not repeated full installs.

  2. Versioned runtime contracts. Keep adding and tightening provides_interfaces, requires_interfaces, and capability protocols. Treat interface names and versions as public module contracts.

  3. Meta-level contract audit. The meta repo statically reads src/**/backend/manifest.py files across all repositories and validates provided/required interface ranges without importing the packages. CI blocks missing or incompatible required interfaces before release installs are attempted.

Run the static graph check with:

./tools/checks/check-contracts.sh

Use --json when the release console or another automation needs structured provider/consumer impact data.

Practical Rule

Do not run pip install for every code edit. Run it when package metadata or the set of installed packages changes.

For normal development:

./.venv/bin/python tools/repo/sync-python-environment.py --requirements requirements-dev.txt --python ./.venv/bin/python

Then restart the server when Python code or manifests change. The development launcher runs this helper automatically by default; set GOVOPLAN_AUTO_SYNC_PYTHON=0 to disable that preflight.

For release validation:

./.venv/bin/python tools/repo/sync-python-environment.py --requirements requirements-release.txt --python ./.venv/bin/python

That install is necessary because the release environment intentionally resolves tagged package refs, not local editable source trees.