Skip to main content

ADR-0122: Retire the reasoning-registry package export

Date: 2026-07-23 Status: Accepted Deciders: Adrian (Soft4U BV), Claude (Opus 4.8) Amends: ADR-0037 (Shared Python Packages for Atlas Integration)

Context

ADR-0037 extracted portable Workflow code into standalone packages/ so a second codebase, Atlas, could pip install and consume it. One of those exports was the reasoning red-flag rule registry, at packages/trustrelay-compliance/src/trustrelay_compliance/reasoning/registry.py.

Two things changed since.

  1. It drifted. The backend keeps its own authoritative registry (app/services/reasoning_template_registry.py, 96 rules). The package copy was never wired back as the source of truth, and diverged to 79 rules. During the 2026-07-23 citation-correctness work it became clear the divergence was actively harmful: a legal-basis citation fixed in the backend silently kept its wrong value in the package copy, so anything importing the package would serve wrong law. The copy was hand-synced three times in one session before the cost of maintaining a second, drifting source was judged not worth paying.

  2. Atlas consumption is no longer a goal. ADR-0037's entire rationale for exporting this API was Atlas. That is no longer pursued (decision recorded by Adrian, 2026-07-23), so the API has no intended consumer — and the only consumer it could have would receive the drifted, wrong-law copy.

A code reviewer (Codex, PR #489) correctly noted that a repo-wide absence of imports proves only that the local backend does not consume the module, not that no external deployment does — and that deleting an ADR-0037-established public API without recording the decision leaves the ADR register asserting an API the code no longer has. This ADR is that record.

Decision

Delete the trustrelay_compliance.reasoning subpackage (its registry.py and __init__.py). Do not retain a compatibility shim.

The dependency direction forecloses the usual alternative. Consumers import trustrelay_compliance → the backend; the package cannot re-export from the backend without inverting that direction. So a shim could only re-export the drifted copy — which is precisely the wrong-law hazard being removed. Deletion is the only reconciliation that does not perpetuate the defect.

The backend registry remains authoritative and unchanged. If Atlas integration is ever revived, the registry can be re-extracted from the authoritative backend version at that time, under a new ADR — starting from correct law rather than a years-stale copy.

The package's own descriptions (pyproject.toml, README.md, __init__ docstring) are updated to drop the "reasoning templates" capability, because advertising a removed export is the same over-claim in prose that the drifted registry was in code.

Consequences

Positive

  • One authoritative registry. A citation fixed in the backend can no longer be silently wrong in a second copy — the "unreconciled copies" defect class is removed for this surface.
  • The ADR register and the code agree again: no API is claimed that does not exist.

Negative

  • import trustrelay_compliance.reasoning.registry now raises ModuleNotFoundError. This is a breaking change to the package's public surface. It is acceptable only because the API has no intended consumer (Atlas dropped) and zero external installs are known; under a different consumer story this would require a deprecation path, not a deletion.
  • If Atlas integration returns, the registry export must be re-created — but from the authoritative source, which is the correct starting point anyway.

Neutral

  • The package's other exports (conclusion, GoAML, evidence bundles, workflow schemas) are untouched and continue to be consumed.

Alternatives Considered

Alternative 1: Retain a compatibility shim re-exporting the registry

Rejected. The dependency direction means the shim would have to re-export the package's own drifted copy (the backend cannot be imported from the package), so it would keep serving wrong law — perpetuating the exact defect the deletion removes. A shim is only honest when it forwards to a correct source; here there is none reachable.

Alternative 2: Reconcile the package copy with the backend and keep it

Rejected. This re-establishes two sources that must be hand-synced forever — the drift that caused the problem. With no consumer, the maintenance cost buys nothing. If a consumer reappears, extraction-on-demand from the authoritative source is strictly better than a standing duplicate.

Alternative 3: Leave it in place, unused

Rejected. A drifted copy that asserts law is a latent liability, not inert: the next citation fix silently diverges it further, and any future import gets wrong law with no warning. "Unused" is not "safe" for a copy of legal citations.

References

  • ADR-0037 (Shared Python Packages for Atlas Integration) — the export this retires
  • ADR-0119 (structured citation binding) / ADR-0121 (semantic citation verification) — the citation-correctness work that surfaced the drift