feat(ori): dossiq stops owning the ORI register, safely - #1345
Merged
Conversation
Raadsinformatie is decidiq's domain (ADR-019/ADR-022): meetings, agenda items,
votes, council members and political groups are its core Popolo model, and
dossiq's `ori` register was a parallel, Dutch-named duplicate of it — schemas
named `vergadering`, `agendapunt`, `stemming`, `raadslid`, `fractie`, which also
breaks the English-identifier fleet contract structurally.
REMOVED OUTRIGHT — the declaration and both consumers:
- lib/Settings/ori_register.json and lib/Repair/RegisterOriRegister.php
- lib/Cron/OriDataQualityCheck.php and its <job> entry
- lib/Controller/RaadsinformatieFeedController.php and the three
/feed/ori/*.rss routes
- their tests
The feeds move to /apps/decidiq/feed/ori/*. Deliberately no proxy and no
redirect: a feed that silently answers from a different app is worse than one
that stops, because a subscriber cannot tell it has moved.
NOT REMOVED OUTRIGHT — the register itself, and this is the part worth reading.
Dropping the declaration stops the register being re-created. It does nothing
about the register already on an existing install, and that register holds real
objects: 115 on the reference instance, across all six schemas. Deleting them
without a migration destroys the record, and the paired decidiq importer
(`ori-adoption`) is not shipped yet — `decidiq:import-ori` does not exist in
that repo today. The change's own T0 gate says removal must not outrun
migration, and it is right.
So `RetireOriRegister` replaces `RegisterOriRegister` and retires the register
only once it is EMPTY, warning and keeping it otherwise, naming the object count
and what to run. Idempotent, so it simply retires on the first upgrade after the
migration finally happens. Declared in post-migration only: a fresh install never
had an ORI register to retire.
Two failure directions are deliberate, and tested:
- an unreadable object count KEEPS the register. An unreadable count must
never be able to authorise a deletion.
- the shard-table scan matches on the `openregister_table_` MARKER, not on a
computed table prefix. The prefix is configurable per install, and a guess
that misses returns zero tables — which would read as "empty" and authorise
exactly the deletion this step exists to prevent.
6 tests, including the one that matters most: seed a single unmigrated object
and assert the register survives. A guard that cannot say no is not a guard.
Full suite 2396 passed. PHPCS/PHPMD/Psalm/PHPStan clean, gate-16 count=0.
rubenvdlinde
requested review from
WilcoLouwerse,
bbrands02 and
rjzondervan
as code owners
August 24, 2026 07:57
Contributor
Quality Report — ConductionNL/dossiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 552/552 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-24 09:27 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
dossiq stops owning the ORI (Open Raadsinformatie) register.
Raadsinformatie is decidiq's domain (ADR-019/ADR-022) — meetings, agenda items,
votes, council members and political groups are its core Popolo model, and
dossiq's
oriregister was a parallel, Dutch-named duplicate of it. Its schemas(
vergadering,agendapunt,stemming,raadslid,fractie) also break theEnglish-identifier fleet contract structurally.
Implements
openspec/changes/ori-removalT2 and T3.Removed outright — the declaration and both consumers
lib/Settings/ori_register.json,lib/Repair/RegisterOriRegister.phplib/Cron/OriDataQualityCheck.php+ its<job>entrylib/Controller/RaadsinformatieFeedController.php+ the three/feed/ori/*.rssroutesThe feeds move to
/apps/decidiq/feed/ori/*. Deliberately no proxy and noredirect: a feed that silently answers from a different app is worse than one
that stops, because a subscriber cannot tell it has moved.
NOT removed outright — the register itself
This is the part worth reading, and it is a deliberate departure from "delete
it".
Dropping the declaration stops the register being re-created. It does nothing
about the register already on an existing install — and that register holds real
objects: 115 on the reference instance, across all six schemas.
Deleting them without a migration destroys the record, and the paired decidiq
importer is not shipped:
decidiq:import-oridoes not exist in that repotoday (checked, not assumed). The change's own T0 gate says removal must not
outrun migration, and it is right.
So
RetireOriRegisterreplacesRegisterOriRegisterand retires the registeronly once it is empty, warning and keeping it otherwise — naming the object
count and what to run. Idempotent, so it simply retires on the first upgrade
after the migration finally happens. Declared in post-migration only: a fresh
install never had an ORI register to retire.
Two failure directions are deliberate, and tested
An unreadable object count KEEPS the register. An unreadable count must never
be able to authorise a deletion.
The shard-table scan matches on the
openregister_table_MARKER, not on acomputed table prefix. The Nextcloud prefix is configurable per install, and a
guess that misses returns zero tables — which would read as "empty" and
authorise exactly the deletion this step exists to prevent.
6 tests, including the one that matters most: seed a single unmigrated object
and assert the register survives. A guard that cannot say no is not a guard.
Verification
Full suite 2396 passed. PHPCS 0 errors · PHPMD clean · Psalm 0 errors ·
PHPStan 0 errors · gate-16
count=0.Follow-up, not in this PR
T4/T5 of the change — the additive
case.meetingRefproperty and repointingVergaderingDetailViewat decidiq's meeting — are product changes rather thanremoval, and are left for their own PR.