fix(install): the parafering seam and termijn timers never armed on a fresh install - #1729
Merged
Merged
Conversation
… fresh install The "One engine" acceptance proof found seven fresh-install defects, each reproduced twice on a clean rig. They share a shape: the install reported success while the thing it installed did nothing. A. The shipped bvw templates declared besluitvormingActivate and besluitvormingPublish on the STEP. The engine's only action source is TransitionSpecReader::extractActions() over a TRANSITION, so "Start parafering" returned 200 with dispatchedActions: [] and no parafering was ever raised. The templates move, not the engine: the workflow-definition model spec gives steps and transitions each their own automaticActions, but the engine implements only the transition half, and widening it would have made "actions on step completion" mean "actions on status entry" for every app. besluitvormingActivate now sits on the transition INTO Parafering, besluitvormingPublish on the transition INTO Bekendmaking, in all three bundles. A template that still declares actions at an unread position now logs a warning at activation, so the no-op is loud. B. The shipped case flow assigns task-behandelaar to the group behandelaars, which nothing provisioned. The completion signal was refused fail-closed for every actor and the journey suite red 7/9. A new idempotent repair step creates the group at install; membership stays the administrator's. The flow is NOT reassigned to admin: that would hide a provisioning gap behind an over-privileged default. C. SeedDeadlineMonitoringData wrote as Anonymous, RBAC refused every row, and the failures were swallowed into "0 definities (0 overgeslagen)". It now runs under the system identity its sibling steps already use, and refused rows are COUNTED so a seed that seeded nothing cannot report success-shaped output. D. The bvw resultTypes wrote English archivalAction values into the register's Dutch enum, failing 9 objects at enable on every install. E. mandateArrangement declared a union type on to_amount, which makes OpenRegister drop the WHOLE schema on import, silently. F. The demo parafeerroutes were never held. The decision app's step schema accepts only person|body|role and refuses the route on anything else, so every route with a group actor came back "not handled". actorType is now translated rather than copied, and the schema's own `advice` spelling maps to advisory instead of falling back to a generic endorsement. G. The bvw caseTypes named no initial status, so an API-created case was born statusless; the verwerkingsactiviteit seeder called setters for columns OpenRegister has since renamed, failing all 7 rows with "naam is not a valid attribute"; and the ZGW-mapping repair threw on an empty schema context, which aborts an install. Tests. BvwTemplateConformanceTest drives the REAL TransitionSpecReader over the shipped JSON and asserts every declared action sits where the engine reads it, plus the enum and initial-status invariants. Proven red on all four axes before the fix. RegisterSchemaUnionTypeTest sweeps every shipped schema for union types; ProvisionAssignedGroupsTest sweeps the shipped flows so a new group assignment cannot ship without its provisioning; and ParaferingDelegationServiceTest now maps every SHIPPED route and asserts it lands inside the decision app's frozen vocabulary. The Verwerkingsactiviteit stub was a setter sink that accepted any attribute, so it could not fail; it now mirrors the real entity's declared properties and throws the way a QBMapper entity does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
rubenvdlinde
requested review from
Rem-Dam,
WilcoLouwerse,
bbrands02 and
rjzondervan
as code owners
September 3, 2026 09:44
…ma refuses Fixing mandateArrangement's union type left the mock register's copy of to_amount saying "null means unlimited". The mock already typed the property as a plain number, so that sentence described a value neither schema accepts. It also grew the untranslated-schema-string count by one and reddened the check:schema-l10n ratchet: the extractor dedupes by string VALUE across files, so the old wording survived here and the corrected wording landed as a genuinely new string. Syncing the two retires the old string instead of adding a second, which is why the count returns to its baseline rather than needing the baseline raised. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 | ❌ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 540/540 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-03 09:53 UTC
Download the full PDF report from the workflow artifacts.
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 | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 540/540 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-03 10:13 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 was broken
The "One engine" acceptance proof found seven fresh-install defects, each reproduced twice on a clean rig. They share a shape: the install reported success while the thing it installed did nothing.
A (HIGH) The parafering seam never armed
The shipped bvw templates declared
besluitvormingActivateandbesluitvormingPublishon the step. The engine's only action source isTransitionSpecReader::extractActions()over a transition, so "Start parafering" returned 200 withdispatchedActions: [], nothing was raised and nothing was logged.Decision: the templates move, not the engine. The workflow-definition model spec gives steps and transitions each their own
automaticActions, but the engine implements only the transition half. Teaching it to read step-level actions would silently redefine "actions on step completion" as "actions on status entry" for every app that ships a template, and no caller asked for that. SobesluitvormingActivatenow sits on the transition into Parafering andbesluitvormingPublishon the transition into Bekendmaking, in all three bundles. A template that still declares actions at an unread position now logs a warning at activation, so the no-op is loud instead of silent.B (HIGH) Nothing provisioned the group the shipped flow assigns to
dossiq_register.jsonassignstask-behandelaarto the groupbehandelaars. The completion gate resolves group membership, and membership of a group that does not exist is false for everyone, so the signal was refused fail-closed and the journey suite red 7/9.A new idempotent repair step creates the group at install and upgrade. Membership stays the administrator's: dossiq never adds users. The flow is deliberately not reassigned to
admin, which would hide a provisioning gap behind an over-privileged default. A backend that refuses group creation is reported loudly rather than swallowed. Documented indocs/admin/groups.md.C (HIGH) The termijn seed wrote as Anonymous and called it success
SeedDeadlineMonitoringDataran with no session, OpenRegister RBAC refused every row, and the per-row failures were logged but never counted, so the step reported0 definities (0 overgeslagen)as success. Zero TermijnDefinities existed on any fresh install, so no termijn timer could arm.It now runs under the same system identity its sibling steps already use, and refused rows are counted, so a seed that seeded nothing cannot produce success-shaped output.
Mediums and lows
keep/destroyinto the register's DutcharchivalActionenum, failing 9 objects at enable on every install.mandateArrangementdeclared a union type["number","null"]onto_amount, which makes OpenRegister drop the whole schema on import, silently. Nullability is now expressed by omitting the property.person|body|roleand refuses the route on anything else, so every route with agroupactor came back "not handled".actorTypeis now translated rather than copied, and the schema's ownadvicespelling maps toadvisoryinstead of falling back to a generic endorsement.The conformance test
BvwTemplateConformanceTestdrives the realTransitionSpecReaderover the shipped JSON, so it asserts what the engine actually sees rather than what the file looks like. It was proven red on all four axes before the fix. Three more sweeps close the same class:RegisterSchemaUnionTypeTestsweeps every shipped schema for union types.ProvisionAssignedGroupsTestsweeps the shipped flows, so a new group assignment cannot ship without its provisioning.ParaferingDelegationServiceTestnow maps every shipped route and asserts it lands inside the decision app's frozen vocabulary.Each sweep asserts it found something before asserting it found nothing wrong, so an empty query cannot read as clean.
The
Verwerkingsactiviteittest stub was a setter sink that accepted any attribute, so it could not fail. It now mirrors the real entity's declared properties and throws the way a QBMapper entity does, which is what makes G's seeder defect visible to the suite.Verification
lint,phpcs(0 errors),phpmd(per subdir, both configs, clean),psalm(no errors),phpstan(no errors),phpunit2849 tests green (3 skips, all pre-existing and verified on the unmodified tree).Known gate note.
gate-53 effective-manifest-crossreffails, and it is not from this change. Touching a register JSON makes the gate's scope indeterminate, so pre-existing findings start blocking. The finding isheaderActions[0]on the Dashboard page carryingincludeFields,fieldOverrides,sizeandcolumns, which the gate'sactionschema forbids. That block is byte-identical ondevelopmentand this branch does not touchsrc/manifest.json. Removing those properties would regress #1713, which restored the New case field narrowing on purpose, so the mismatch belongs in the hydra-gates schema rather than here.🤖 Generated with Claude Code