feat(decision-types): make the decisionType vocabulary configuration, not code - #1099
Merged
Merged
Conversation
… not code The vocabulary lived in four homes: the ALLOWED_TYPES constant, the Decision enum in both registers, and the DecisionTemplate narrowing in fragment 68, pinned together by a parity test. Adding a type cost a release in four places, which is how dossiq's advice and the pending woo-decision need each stalled. One authority now: the decision_types app setting. SeedDecisionTypes writes today's vocabulary (woo-decision included) once and never overwrites an admin's edits. DecisionTypeRegistry validates referentially, falling back to the seed only while no row is stored. The integration hub fails closed on an unknown type and its refusal names the fix: an administrator adds the type, no release. The schema declarations drop their enums on purpose: a declared enum drifts from the store and recreates the four-homes problem. The parity test inverts, proving no second authority exists and that the seed covers every type a fleet caller sends (dossiq, stackiq). Also bumps conduction/hydra-gates to v1.11.0.
rubenvdlinde
requested review from
Rem-Dam,
SudoThijn,
WilcoLouwerse,
bbrands02,
remko48 and
rjzondervan
as code owners
September 2, 2026 10:40
Contributor
Quality Report — ConductionNL/decidiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-nav-ceiling | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 537/537 | |||
| 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-02 10:45 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.
Why
A decision type is configuration on the existing decision abstraction, not code. Today the vocabulary is a closed list mirrored in four homes: the
DecisionIntegrationService::ALLOWED_TYPESconstant, the Decision enum indecidesk_register.json, its copy indecidiq_mock_register.json, and the DecisionTemplate narrowing inregister.d/68. A parity test pins the four together. Adding one type costs a release in four places. That is how dossiq'sadvicestalled, and how the pendingwoo-decisionneed stalls now.What changes
decision_typesapp setting.DecisionTypeRegistryreads it; the integration hub validates against it and fails closed on an unknown type. The refusal message names the fix: an administrator adds the type, no release.SeedDecisionTypes(registered ininfo.xmlunder install and post-migration) writes today's vocabulary once,woo-decisionincluded. It never overwrites a stored row, so admin edits survive every upgrade. Until it runs, the registry falls back to the same shipped list, so nothing fails closed in the gap.decisionTypedeclarations become free-text strings with referential validation. No enum is generated either: a copy that drifts from the store recreates the four-homes problem. The trade-off (raw OpenRegister object writes lose enum checking) is documented on the schema; that path already bypasses the chair, quorum and terminal-completeness gates.ALLOWED_TYPESconstant exists, no schema home carries an enum, and the seed covers every type a fleet caller sends (dossiq:contract-renewal,report-adoption,advice,bezwaar-decision,woo-decision; stackiq:contract,contract-renewal).woo-decisionenters as seed data.decision-types-as-configurationwith spec delta ondecidesk-contract-decision-hub(new REQ-DCDH-009, modified REQ-DCDH-001).conduction/hydra-gatesbumped to v1.11.0.Adding a type after this PR
Follow-up (named in design.md)
Per-type behavioural configuration (motion and amendment branching, kind grouping in
decisionLink.js, lifecycle domain defaults) belongs to the ADR-037 consumer rewrite. The string registry stays the validity authority.Verification
lint,phpcs,phpmd(per subdir, both rulesets),psalm,phpstan: all clean, run individually in the foreground.test:l10n,check:l10n-js,check:manifest,check:nav-ceiling,formatall pass; the schema-l10n ratchet baseline drops 1632 to 1613 (removed enum strings).Note:
test:l10n:parityfails on a missingl10n/rm.json. Pre-existing, not run in CI (per the workflow comment), and this PR adds no translatable strings.