fix(flow): the ask that named nobody, and three templates left behind by a rename - #1804
Merged
rubenvdlinde merged 1 commit intoSep 4, 2026
Conversation
… by a rename
Three defects, from a fresh-rig acceptance proof. Two of the three reported
were already gone (see below); what shipped here is the third, plus what
sweeping for the first one's SHAPE actually turned up.
ask-indiener could not name anybody, so the run died
----------------------------------------------------
The supplement step declared `assignee: "{{ case.assignee }}"`, and `assignee`
is NOT in the case schema's `required`. A case filed from the New case dialog
with only a title and a case type therefore has none, the template resolved to
nothing, the node threw `could not resolve the assignee "{{ case.assignee }}"`,
and the run FAILED. The case then sat in `Wacht op aanvulling` with no task for
anybody and nothing waiting on it. Reproduced twice on independent clean
installs. The e2e never saw it because every case it files names an assignee.
The node is named for the indiener and addresses the behandelaar, and the
behandelaar is right. An indiener has NO Nextcloud identity in this app: the
case carries them as `initiatorSourceId` (a BSN, a KvK number or a contact URI)
or as the pseudonymous `portalSubject`, while a task's `assignee` is a uid or a
group id and the completion gate resolves it as one. The ask cannot go to the
applicant. It goes to the handler, who asks the applicant and records the
supplement, which is also the only way `description` gets filled and the loop
back to `check-complete` ever takes its `compleet` exit. So the node is
`ask-aanvulling` now, and its Dutch copy addresses the person who holds it.
The no-assignee behaviour is a DECLARED fallback, not a silent one:
`assigneeFallback: "behandelaars"`, the same group `task-behandelaar` already
uses and ProvisionAssignedGroups already creates. Unclaimed work reaches the
handlers' queue instead of killing the case. Failing closed stays the last
word: no fallback, or a fallback that resolves to nobody, still refuses, since
OpenRegister's resume guard lets ANYONE answer a step that names no assignee.
The same sweep found the bezwaar-advice flow dead
-------------------------------------------------
`register.d/72-committees-to-decidiq.json` ships two `dossiq.askPerson` nodes
that declared no assignee AT ALL. validateConfig refuses that outright, so
every bacAdviceRequest ever created failed its run at the first human step.
CaseFlowDeclarationTest could not see it: it read the case flow alone. It now
walks every declaration file, the way its edge-condition test already did.
Both steps go to `bezwaarcommissie`, a group kept separate from `behandelaars`
on purpose: Awb art. 7:13 requires the advisory committee to be independent of
the officials who handled the case. The flow's own description names the
secretary and the chair, and both uids exist, on the bezwaaradviescommissie.
They are not reachable from here: the item json is the bacAdviceRequest, whose
`committee` is a bare reference the trigger does not expand, so
`{{ committee.secretary }}` would resolve to nothing on every single run and
quietly mean the fallback. The group is the honest principal until that
reference is expanded into the run.
Three templates a rename left behind
------------------------------------
The reported VoorstelDetail defect retired with the whole voorstel model in
af1ff19 (#1796). Its SHAPE had not: a `vue/no-undef-properties` sweep of
`src/**` found three live components where a Dutch name was replaced by an
English one in the script and left standing in the template. Vue resolves an
unknown root identifier to `undefined` and says nothing.
- DsoCaseDetail renamed its prop to `case` and its id computed to `zaakId`,
while the template still read `zaak.*` and `caseId`. Every field rendered
blank and the three sub-dialogs got an empty id. `case` is a JS RESERVED
WORD, so a template cannot name that prop at all: the `zaak` computed is
the only way in, not a nicety.
- SamenwerkverzoekDialog renamed its field to `requestedCompetentAuthority`
and left `aangezochtBevoegdGezag` in the submit button's `:disabled`. The
button was pinned disabled; the dialog could not be submitted at all.
- BeschikkingComposerDialog renamed its field to `rationale` and left the
textarea writing to `motivering`, so typing a motivering did nothing and
the composed decision went out without one.
tests/vitest/dialogTemplateBindings.spec.js MOUNTS all three with a realistic
object. A shallow mount never evaluates the template, which is the only place
these defects exist. All seven assertions red on the unfixed components.
What was already gone
---------------------
The voorstel detail page and `concludeParafering` both retired in af1ff19
(#1796, "a voorstel is a case, not a record of its own"), which deleted 68
files: the proposal/parafeerroute/parafeeractie/paraferingAuditEntry schemas,
the /voorstellen pages and the parafering runtime across 21 PHP classes. The
acceptance rig ran against a build from before it. No surviving transition in
the tree has concludeParafering's shape: of 80 declared lifecycle transitions,
the 76 without a `requires` are ordinary steps a person is meant to click.
rubenvdlinde
requested review from
SudoThijn,
WilcoLouwerse,
bbrands02,
remko48 and
rjzondervan
as code owners
September 4, 2026 14:46
rubenvdlinde
deleted the
fix/askperson-assignee-fallback-and-template-renames
branch
September 4, 2026 14:51
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 | ✅ | ✅ 541/541 | |||
| 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-04 14:51 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 this fixes
Three defects from a fresh-rig acceptance proof. Two of the three reported were
already gone; what ships here is the third, plus what sweeping for the first
one's shape actually turned up.
1.
ask-indienercould not name anybody, so the run diedThe supplement step declared
assignee: "{{ case.assignee }}", andassigneeis not in the case schema's
required. A case filed from the New casedialog with only a title and a case type therefore has none, the template
resolved to nothing, the node threw
could not resolve the assignee "{{ case.assignee }}", and the run failed.The case then sat in
Wacht op aanvullingwith no task for anybody and nothingwaiting on it. Reproduced twice on independent clean installs. The e2e never
caught it because every case it files names an assignee.
Who it should address: the behandelaar, and it already did. An indiener has
no Nextcloud identity in this app at all. The case carries them as
initiatorSourceId(a BSN, a KvK number or a contact URI) or as thepseudonymous
portalSubject, while a task'sassigneeis a uid or a group idand the completion gate resolves it as one. The ask cannot go to the applicant.
It goes to the handler, who asks the applicant and records the supplement,
which is also the only way
descriptiongets filled and the loop back tocheck-completeever takes itscompleetexit. The node isask-aanvullingnow, and its Dutch copy addresses the person who holds it.
Behaviour when there is none: a declared fallback, not a silent one.
assigneeFallback: "behandelaars", the same grouptask-behandelaaralreadyuses and
ProvisionAssignedGroupsalready creates, so unclaimed work reachesthe handlers' queue instead of killing the case. Failing closed stays the last
word: no fallback, or a fallback that resolves to nobody, still refuses, since
OpenRegister's resume guard lets anyone answer a step that names no
assignee.
2. The same sweep found the bezwaar-advice flow dead
register.d/72-committees-to-decidiq.jsonships twodossiq.askPersonnodesthat declared no assignee at all.
validateConfigrefuses that outright, soevery
bacAdviceRequestever created failed its run at the first human step.CaseFlowDeclarationTestcould not see it: it read the case flow alone. It nowwalks every declaration file, the way its edge-condition test already did.
Both steps go to
bezwaarcommissie, kept separate frombehandelaarsonpurpose: Awb art. 7:13 requires the advisory committee to be independent of the
officials who handled the case. The flow's description names the secretary and
the chair, and both uids exist, on the
bezwaaradviescommissie. They are notreachable from here: the item json is the
bacAdviceRequest, whosecommitteeis a bare reference the trigger does not expand, so
{{ committee.secretary }}would resolve to nothing on every run and quietly mean the fallback. The group
is the honest principal until that reference is expanded into the run.
3. Three templates a rename left behind
The reported
VoorstelDetaildefect retired with the whole voorstel model inaf1ff19 (#1796). Its shape had not. A
vue/no-undef-propertiessweep ofsrc/**found three live components where a Dutch name was replaced by anEnglish one in the script and left standing in the template. Vue resolves an
unknown root identifier to
undefinedand says nothing.DsoCaseDetailcase, id computed tozaakId; template still readzaak.*andcaseId. Every field rendered blank and the three sub-dialogs got an empty id.caseis a JS reserved word, so a template cannot name that prop at all: thezaakcomputed is the only way in, not a nicety.SamenwerkverzoekDialogrequestedCompetentAuthority,aangezochtBevoegdGezagleft in the submit button's:disabled. The button was pinned disabled; the dialog could not be submitted at all.BeschikkingComposerDialogrationale, textarea left writing tomotivering. Typing a motivering did nothing and the composed decision went out without one.tests/vitest/dialogTemplateBindings.spec.jsmounts all three with arealistic object. A shallow mount never evaluates the template, which is the
only place these defects exist. All seven assertions red on the unfixed
components and green on the fixed ones, proven by stashing the fix.
What was already gone
The voorstel detail page and
concludeParaferingboth retired in af1ff19(#1796, "a voorstel is a case, not a record of its own"), which deleted 68
files: the
proposal/parafeerroute/parafeeractie/paraferingAuditEntryschemas, the/voorstellenpages and the paraferingruntime across 21 PHP classes. The acceptance rig ran against a build from
before it.
No surviving transition has
concludeParafering's shape: of 80 declaredlifecycle transitions, the 76 without a
requiresare ordinary steps a personis meant to click.
Verified locally
CI is bottlenecked, so this was verified locally and individually. Exit codes,
not summary lines.
Failures: 1— see belowdevelopment's baselinelib/Flow,lib/Repair,lib/Settings), both rulesetsdevelopment's baseline--scope-to-diffThe one PHPUnit failure is environmental, not dossiq's.
StubApiDriftTestcompares dossiq's stubs against a siblingopenregistercheckout at
../openregister, which on this machine is stale. It reportedStoreDescriptor::__construct() takes 5 arguments … the real class takes 4.Asking the remote settles it:
origin/developmentof openregister has the5-argument constructor, so dossiq's stub is correct and CI, which clones
openregister fresh, is green. The same failure reproduces on a clean checkout
of
development, so it is not introduced here.Not run locally: the e2e suite (needs a live rig).
case-flow-live-journeyswas updated for the renamed node and the new task title.
🤖 Generated with Claude Code