Release: merge development into beta - #3204
Conversation
The 2.0.6-beta.20260831102212 release bumped the version on beta. Without this, development stays behind beta and the next development -> beta promotion conflicts on the version file. Version files resolve to development's side, which is the higher line, so this never moves a version backwards.
Dependabot cannot propose composer updates for this app. Its updater fails
with:
Your requirements could not be resolved to an installable set of packages.
- edgedesign/phpqa[v1.27.0, ..., v1.27.2] require ext-xsl * ->
it is missing from your system.
config.platform pins php 8.3 so composer resolves against a known PHP version,
but says nothing about extensions. edgedesign/phpqa requires ext-xsl and the
resolving environment does not have it, so the resolve fails before any bump
can be computed.
CI is unaffected, which is why this went unnoticed: composer install replays
the committed lock and never re-resolves, so the pipeline stays green while
dependabot -- which does re-resolve -- fails every time. The shared quality.yml
installs no xsl extension anywhere and never invokes phpqa.
Declaring ext-xsl beside the php pin makes resolution assume exactly what the
committed lockfile already assumes. Verified in a clean composer:2 container
without --ignore-platform-reqs: the same file fails without this line and
resolves (103 installs, lock written) with it.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
The 2.0.7 release bumped the version on main. Without this, development stays behind main and the next development -> main promotion conflicts on the version file. Version files resolve to development's side, which is the higher line, so this never moves a version backwards.
….0.7 chore(release): sync main back into development
….0.6-beta.20260831102212 chore(release): sync beta back into development
Levels this app with the fleet. 2.27.2 adds two fixes the earlier 2.27.0 pin does
not carry:
* headerless is no longer chromeless — a flat KPI card in a borderless wrapper
had no card, border or background at all;
* a stat `variant` paints from the `-text` tokens rather than the fill tokens,
which failed WCAG AA at 1.08:1 as a foreground colour. The KPI colour
cleanup converted hardcoded values to `variant`, so this is what makes those
conversions contrast-safe.
Lockfile only, and npm pruned nothing.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 11:40 UTC
Download the full PDF report from the workflow artifacts.
Bumps [zod](https://github.com/colinhacks/zod) from 4.4.3 to 4.5.2. - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](colinhacks/zod@v4.4.3...v4.5.2) --- updated-dependencies: - dependency-name: zod dependency-version: 4.5.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [marked](https://github.com/markedjs/marked) from 12.0.2 to 18.0.11. - [Release notes](https://github.com/markedjs/marked/releases) - [Commits](markedjs/marked@v12.0.2...v18.0.11) --- updated-dependencies: - dependency-name: marked dependency-version: 18.0.11 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 12:14 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 12:46 UTC
Download the full PDF report from the workflow artifacts.
…0260831125107 chore(sync): carry beta back into development
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 13:15 UTC
Download the full PDF report from the workflow artifacts.
#3220) The override read: "apexcharts": "License is MIT - license-checker misreads logo URL as custom license" That was true once and is not true now. apexcharts stopped being MIT at 6.0.0: 4.7.0 and 5.0.0 are MIT, 6.0.0 and 7.0.0 are SEE LICENSE IN LICENSE. This app declares ^7.0.0 and locks 7.0.0, so the checker flagging it is CORRECT and the override was suppressing a true finding rather than correcting a false one -- the licence gate was reporting green on a dependency that is not open source. Nothing about the dependency changes here. apexcharts 7 stays. What changes is that the file now says what is actually true: - 6.0.0+ ship a dual-license: free under a Community License for organisations below USD 2M annual revenue, paid above it, and sublicensing under different terms is not permitted. - Conduction confirmed 2026-08-31 that it is below that threshold and so qualifies under the Community License. - The override is therefore a deliberate acceptance, dated and attributed, not a claim that the checker is wrong. The note also records the redistribution question, because the Community License binds the organisation USING the software rather than only the one shipping it, and this app is distributed through the Nextcloud App Store. An installing tenant above USD 2M would need its own commercial licence. That is flagged for a decision, not decided here. For reference: dossiq is on apexcharts 4.7.0 (MIT) with no override, and its bump to 7.0.0 was closed today on these grounds (dossiq#1527). apexcharts 5.x is the last MIT release if the fleet ever needs to return to one. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 13:48 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 14:34 UTC
Download the full PDF report from the workflow artifacts.
The 2.0.9 release bumped the version on main. Without this, development stays behind main and the next development -> main promotion conflicts on the version file. Version files resolve to development's side, which is the higher line, so this never moves a version backwards.
…0260831154312 chore(sync): carry beta back into development
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 16:06 UTC
Download the full PDF report from the workflow artifacts.
Dependabot cannot update these packages. Its npm updater fails with: npm error code EOVERRIDE npm error Override for <pkg> conflicts with direct dependency The package is listed BOTH as a direct dependency and as a literal overrides entry pinned to the same range. Dependabot bumps the direct dependency and does not move the override, npm rejects the mismatched pair, and the update is abandoned -- so these packages can never be updated, security advisories included. npm's self-reference is the idiom for exactly this: $<name> tells the override to follow whatever the direct dependency resolves to, instead of a range that has to be kept in lockstep by hand. This repo already uses it (see the vue entry under @vue/test-utils). Transitive consumers still get pinned to one version -- the direct dependency's -- which is what the override was there to do. What changes is that the pin tracks the dependency instead of duplicating it. Verified in a clean container: bumping the direct dependency with the literal override reproduces the EOVERRIDE above; with the self-reference the same bump resolves. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 16:45 UTC
Download the full PDF report from the workflow artifacts.
…SetupHandler (#3233) * fix(db): bind catch(Exception) to a class that exists, and drop dead SetupHandler Two findings that psalm-baseline.xml had been carrying as accepted noise. Neither is noise. 187 -> 184. lib/Db/Register.php caught `Exception` with no import, inside namespace OCA\OpenRegister\Db. PHP resolves an unqualified catch type against the CURRENT namespace, so that block was bound to OCA\OpenRegister\Db\Exception, which does not exist, and it could never catch anything. Verified rather than reasoned about: namespace Demo\Sub; try { throw new \RuntimeException("boom"); } catch (Exception $e) { ... } // no import -> NOT CAUGHT -> RuntimeException: boom Adding `use Exception;` binds it to the global class the code plainly meant. Checked the rest of lib/: ObjectsController and Repair/RenameDutchColumns also catch a bare `Exception`, but both import OCP\DB\Exception, so their catches bind to a real class and are deliberate. Psalm flagged exactly the one file that was broken. lib/Service/SettingsService.php declared a property, a constructor parameter and two docblocks for SetupHandler, a class that exists nowhere in the tree. It was written and never read, so it was dead API surface that would fatal the moment anything tried to supply it. Removed, along with the `setupHandler: null` argument in Application.php and the matching positional null in the two tests that build the service positionally. Verified with the repo own vendor/bin/psalm 5.26.1 on PHP 8.3: errors with the baseline emptied went 187 -> 184, and the regenerated baseline is green. PHPUnit was NOT run here: it needs the Nextcloud server bootstrap, which only exists inside a server checkout. * fix(tests): realign the five positional constructor calls I missed Removing the SetupHandler parameter shifted every later POSITIONAL argument, and I checked for that by reading the first line after each `new SettingsService(` and concluding the file used named arguments. It uses both. Five calls further down SettingsServiceTest.php are positional, and CI caught it as 13 TypeErrors, all the same one: Argument #14 ($appName) must be of type string, MockObject_IAppContainer given which is the shift saying exactly what it was. Verified by position this time rather than by sampling: with the parameter gone, appName is slot 14, and all seven positional call sites across the three test files now carry a string literal there. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 17:06 UTC
Download the full PDF report from the workflow artifacts.
….0.9 chore(release): sync main back into development
…etter (#3236) Two more entries the Psalm baseline was carrying. Both are real. 184 -> 180. PollLinkService had a fallback that could never run: $pollId = (int)$this->db->lastInsertId("oc_polls_polls_id_seq"); if ($pollId === 0) { // Fallback for drivers without sequence support. $pollId = (int)$this->db->lastInsertId(); } OCP\IDBConnection::lastInsertId(string $table): int takes a REQUIRED argument, so the no-arg call raises ArgumentCountError on exactly the drivers the fallback was written for. The surrounding catch (Throwable) turned that into "Failed to create poll", which blames the insert rather than the id retrieval. A zero now falls through to the explicit throw that was already there and says what actually happened. Checked the other four lastInsertId call sites. MagicMapper and DedupCollidedSchemasCommand pass a table. DbalObjectSourceProvider calls it with no argument, but on a DBAL Connection rather than IDBConnection, where the parameter is optional. Psalm flagged only the one that was wrong. CaseToken declared getToken TWICE: @method string|null getToken() @method void getToken(?string $token) <- copy-paste of the setter @method void setToken(?string $token) Psalm binds to the second, which is why two correct $row->getToken() calls read as "Too few arguments". Removed; setToken on the next line was already right. Swept lib/Db for the same slip: this was the only one of them. Verified with the repo own vendor/bin/psalm 5.26.1 on PHP 8.3: all four TooFewArguments are gone, errors with the baseline emptied went 184 -> 180, regenerated baseline is green. PHPUnit was NOT run here, it needs the Nextcloud server bootstrap that only exists inside a server checkout. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 17:13 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 17:28 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 17:58 UTC
Download the full PDF report from the workflow artifacts.
… it (#3243) * fix(chat): send temperature through modelOptions, where LLPhant reads it Four assignments of $config->temperature and one of $config->organizationId on LLPhant\OpenAIConfig. Neither is a property of that class, so each one created a DYNAMIC property that nothing ever read. An agent temperature configured in the UI never reached the model. The suppressions above them said so and were read the other way round: @psalm-suppress UndefinedPropertyAssignment LLPhant dynamic properties LLPhant does not use dynamic properties. It reads modelOptions: OpenAIChat.php:89 $this->modelOptions = $config->modelOptions; OpenAIChat.php:368 $openAiArgs = $this->modelOptions; and OpenAIConfig own docblock lists temperature inside the ModelOptions array shape, not among its properties. Nothing anywhere in the library reads a temperature property. Temperature now goes to $config->modelOptions["temperature"], which is what reaches the API. organizationId is removed rather than relocated: LLPhant has no organization support of any kind, so there is nowhere for it to go. That drops the pretence, not the behaviour, because there was none.⚠️ PHP 8.2 deprecated dynamic property creation, so this was also going to start emitting deprecations and then fail outright. Verified with the repo own vendor/bin/psalm 5.26.1 on PHP 8.3: errors with the baseline emptied went 173 -> 168, regenerated baseline is green. PHPUnit was NOT run here, it needs the Nextcloud server bootstrap that only exists inside a server checkout. * style(chat): start the new inline comments with a capital phpcs: "Inline comments must start with a capital letter". Five of the comments I added opened on an identifier (modelOptions, organizationId). --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 18:26 UTC
Download the full PDF report from the workflow artifacts.
…y holds (#3245) $this->stats was documented as eight int keys, and the name-cache warm-up stores a ninth, warmup_breakdown, holding an array. That mismatch is what Psalm was reporting as InvalidPropertyAssignmentValue, and it had been baselined rather than reconciled. The runtime behaviour was never wrong: PHP arrays take the key regardless. What was wrong is that the declaration described a narrower shape than the class keeps, so anything reading the annotation, a reader or an IDE or the analyser, was told the key cannot be there. Declared optional, because it is absent until the warm-up has run. Verified with the repo own vendor/bin/psalm 5.26.1 on PHP 8.3: 168 -> 167 with the baseline emptied, regenerated baseline green, phpcs clean on the touched file. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 18:56 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 20:42 UTC
Download the full PDF report from the workflow artifacts.
* feat(schemas): let an app retire a schema from its descriptor Removing a schema from an app's register descriptor never removed it from the instance. ImportHandler unions the freshly-imported schema ids into the register's existing list and prunes only the ids it has just shadowed by slug, so a retired schema kept its row, its magic table and its place in the register's schemas array forever. On a shared instance that is how a cross-app slug collision outlives the descriptor change meant to end it. Adds occ openregister:schemas:prune-retired --app <appId> --slug <slug>. Scoped by owning application, so it can never reach a same-slug schema another app owns: measured on the dev instance, filinq's product is id 21 and decidiq's is id 987. Dry-run by default, refuses a schema that still owns objects unless --force, and unlinks the id from every referencing register before the row goes. unlinkSchemaId() matches the integer and the string form of an id. The stored list holds either depending on which import era wrote it, so a strict comparison would leave "74" behind pointing at a deleted row. * docs(schemas): tag every prune-retired method with its @SPEC gate-16 named two changed methods with no @SPEC. Tagging all five so the class does not drift back over the line as it changes.
) * feat(organisation): carry the four chain-partner fields it lacked Version1Date20260831020000 made an organisation able to say it is a tenant somewhere ELSE. That settled WHERE a counterparty lives, not WHO it is. dossiq carries that separately in its own `partnerOrganization` schema, and folding partners into Organisation would drop whatever this table cannot hold. Measured against the live table rather than assumed, which corrected me: of that schema's nine properties, `name`, `slug`, `isActive` and `groupId` already map onto columns here, and `oin` ALREADY EXISTS alongside `tooi`. I had told the team OIN was the missing field that decided the question. It was not. Four properties genuinely had nowhere to go, and those four are what this adds: contactEmail, defaultPermissionLevel, qualityScore, qualityStatus. All four are nullable with NO default. A tenant of this installation has no chain-partner contact address and has never been scored, and a zero score reads as "scored badly" — a different claim from "never assessed", and one a partner dashboard cannot tell apart afterwards. There is a test for exactly that. 🔴 `defaultPermissionLevel` is a DEFAULT, never an authorization input. ADR-002 Rule 1 keeps the organisation UUID as the only tenant key; nothing may read this column to decide whether an actor may act, only what a NEW share is proposed at. That is the trap `type` was deliberately kept out of, and the docblock says so where someone would otherwise reach for it. The field types register under the PROPERTY name, not the column name: Entity resolves a setter to lcfirst(substr($method, 3)) and looks that up, so a snake_case registration matches nothing and the integer cast silently never runs. Tested. Note for reviewers: OrganisationTest reports 3 PHP warnings from inside Nextcloud's own Entity.php. They are pre-existing — 3 before this change and 3 after, with 67 tests becoming 70. * fix(quality): restore the copyright tag and group the suppression Two CI findings, both mine. gate-1 spdx-headers: the new migration carried @license but no @copyright. phpcs: the PHPMD.LongVariable suppression sat between the @method tags and the rest, separated by a blank line, which breaks "tags must be grouped together". It now joins the existing class-level suppressions, and the REASON it exists moves to the property's own docblock where it is actually read: Entity maps a property to its column BY NAME, so `defaultPermissionLevel` must be the camelCase of `default_permission_level`, and shortening it to satisfy the rule would stop the mapping silently rather than failing. A bare suppression tag with the reason deleted would have satisfied phpcs and told the next reader nothing.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 21:53 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 22:15 UTC
Download the full PDF report from the workflow artifacts.
…the instance (#3249) New change in the ADR-098 chain, depending on flow-task-entity and flow-user-task-node. A separate openregister.portal-task node (not an external mode of user-task: performer resolution, delivery channel and completion payload all differ, and a mode would make half of each node's config keys invalid per mode) that: - matches the party from the case object's initiator role, frozen at creation and audited - creates a task with the external performer type (ADR-098 D3 amendment 2026-08-31), delta on the flow-tasks capability - suspends heartbeat-safe with a non-null resumeAt (findAbandonedSignals matches resume_at IS NULL; the 14-day reaper must never see a hersteltermijn) - delivers through portaliq's contribution surface (ADR-046); rendering is portaliq's follow-up change, one task line only - accepts an upload completion stored as an OR file attachment on the case object (ADR-022, decision 2026-08-31) - refuses completion by anyone but the matched party, fail-closed - loops on re-ask with a mandatory reason - consumes flow-business-timers for reminder, escalation and expiry
The fleet is dropping n8n: OpenRegister flows become the only engine. The descriptor is the first piece to go and the only one this schema audit touches. It declared five schemas with no `slug` key at all, so their slugs derived from their titles, and two of those, `notification` and `schedule`, collided with decidiq and hermiq in the fleet-wide scan. It reports `absent` on the dev instance, so it shipped and was never imported: this clears a static collision, not a live one. testEveryDescriptorOpenRegisterShipsIsDiscovered counts declaring files by reading lib/Settings itself, so it follows the deletion rather than breaking. The comments that named this file as a live example are rewritten to name one that still exists: a comment asserting a file ships is a claim, and a stale one is worse than none. The server-side retirement (N8nSettingsController, WorkflowEngineController, WorkflowEngineRegistry and the n8n branches in FlowEngine) is its own change.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-09-01 04:58 UTC
Download the full PDF report from the workflow artifacts.
) New change, no dependencies beyond shipped code. Three requirements: - GET /api/flow-runs/active accepts an optional subject filter matching FlowRun.subject_uuid, applied in the datastore inside the caller's organisation scope; the filter can only narrow, and the total counts the filtered set - a completed-runs read for a required subject (FlowRun::TERMINAL, newest first, bounded, honest total) so a case page can show history without widening the flowRun#index surface, which or-flow-active-runs requires to stay unchanged - one row contract for both reads: run uuid, flow name, current step, status, started at and the subject block; never marking, items or the step log The nc-vue consumption (subject option + run deep link on CnFlowRunsWidget) is one follow-up task line pointing at an nc-vue change.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-09-01 05:02 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 05:24 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 06:00 UTC
Download the full PDF report from the workflow artifacts.
…3260) The live-runs read (GET /api/flow-runs/active) accepts an optional subject parameter (a subject object uuid). It narrows INSIDE the caller's organisation scope in the datastore: the organisation predicate stays unconditional and the subject is a second AND predicate on subject_uuid, so a guessed uuid from another tenant matches nothing. The total counts the filtered set. Without subject the read is bit-identical to before. A completed-runs read (GET /api/flow-runs/completed) answers the history half for the same subject: FlowRun::TERMINAL statuses, subject REQUIRED (400 naming the parameter, never an org-wide history dump), same organisation scope, newest first, capped limit, honest total. It reuses summarise(), so both reads share one row contract: uuid, flow name, current step (null when no marking), status, created, subject block, and never the marking, items or step log. flowRun#index is untouched. One composite index on (organisation, subject_uuid, status, id) makes both reads a range scan on one case rather than a walk over the tenant's runs. Tests: controller (subject reaches rows and total, no org means no query, blank subject is no filter, completed read refuses a missing or blank subject, capped limit, shared row shape without heavy fields) and mapper (predicate order with the organisation first, terminal set including failed, newest-first bound, fail-closed on a missing predicate). openspec: flow-runs-subject-scope, tasks 1.1, 1.2, 2.1, 2.2, 3.1, 5.1, 5.2 Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
… through the notification subsystem (#3257) * feat(flow): send-notification, send-email and send-talk-message nodes through the notification subsystem Three messaging step nodes, implemented as orchestration-time invokers of the ADR-031 channel machinery rather than a second messaging stack: - The per-channel send units (nc-notification + web-push ride-along, email composition/handoff, Talk post), the recipient resolver and the dialect's placeholder evaluator are extracted from AnnotationNotificationDispatcher into call-shared units under lib/Service/Notification/; the dispatcher is re-wired onto them with its existing tests green and unchanged. - FlowMessagingService applies the guards in order: per-channel subsystem kill switches (new, default-on, silencing BOTH callers), the recipient's own channel preference, a post-expansion recipient bound (app-config raisable), and the RateLimiter — whose buckets gain a caller-agnostic shared per-recipient budget so a flow cannot double a person's ceiling. - Sends are attributed to the run's acting user; no resolvable actor fails the step naming the missing actor. Talk posts as the acting user and treats "not a participant" as a step failure, never an auto-join. - Per-recipient/channel outcomes land on the run log through a new FlowStepReport context handle the engine drains per hop, bounded by the log's sampling rule; a send failure is a step failure through onError. - No send-webhook node: outbound HTTP stays with OpenConnector (ADR-094). @SPEC openspec/changes/flow-messaging-nodes/specs/flow-messaging-nodes/spec.md * chore(flow): satisfy the spec-coverage and spec-anchor gates on the messaging nodes The config-form floor is cited at its shipped home in the flow-engine spec (the flow-node-config-forms change carries no spec file under that name), and the resolver's shared helpers and the Talk app boundary carry the messaging spec anchors they implement. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ❌ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ❌ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-09-01 07:01 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 07:21 UTC
Download the full PDF report from the workflow artifacts.
…3263) 2.28.0 carries the canvas run animation (nextcloud-vue#896) and the subject-scoped runs widget (nextcloud-vue#898), the two surfaces the flow-runs-subject-scope read (#3260) exists for. The bump could not be installed at all: #3232 rewrote the overrides as $-references and `npm install` refuses `$postcss` with "Unable to resolve reference". The other references resolve; this one does not, so it is the one direct spec again, matching the devDependency. Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 08:12 UTC
Download the full PDF report from the workflow artifacts.
Every object sub-resource endpoint answered 404 "Object not found", in every
app on the instance: notes, tags, relations, emails, polls, talk, bookmarks,
deck, calendar, tasks, time-tracker and the rest. The object itself resolved
fine at /objects/{register}/{schema}/{id}, and the identical resolution chain
succeeded from occ, which is what made this hard to see.
Under HTTP it threw `Schema slug "case" is not carried by register "buildiq"`
on a request that named dossiq. ObjectService::setSchema() scopes its slug
lookup to whatever register is CURRENTLY set, and the service is reused across
many operations in one process, so setting the schema first resolves the slug
against a register left behind by an unrelated earlier call. Buildiq happens to
own a `case` schema too; the global lookup reached it first.
setRegister() already re-resolves a pending schema ref for exactly this reason,
and its own comment names this helper as the shape that inverted the two. That
repair cannot help here, because the throw happens inside setSchema() before
setRegister() is ever reached.
25 controllers carried the inverted order. FilesController did not, and its
docblock already described this bug, so the rule was known and simply never
applied to the others.
Worth naming what this cost: every one of those surfaces renders an EMPTY
STATE, not an error. A case with notes said "No notes yet". The page did not
report that it could not ask, so the failure was indistinguishable from the
data genuinely being absent.
The regression guard is a static scan over every controller rather than a
behavioural test. Reproducing the runtime symptom needs a second register that
happens to share a slug AND a prior operation that left its register set, which
is a state no unit test would reach naturally and one a live instance reaches
constantly. Verified the test fails when the order is put back.
Verified on the dev instance: notes, tags, relations, emails, files and
audit-trails all return 200 where they returned 404, including pipelinq, an app
untouched by this change. 3227 controller tests pass.
`npm run lint` was `eslint src`, so two whole trees were never linted. Across
the fleet that hid roughly 3,900 errors, none of which any CI leg had shown.
Most of it was the config, not the code, and the same two defects were in
every app.
**scripts/ had no config block at all.** These are CommonJS Node CLI checkers,
and flat config defaults every `.js` to ESM with browser-ish globals, so eslint
read the CommonJS wrapper itself as undefined identifiers: `require`,
`process`, `__dirname`, `__filename`, `module`. A `scripts/**` block now
declares the environment. Declaring beats suppressing here: `no-undef` is the
rule that catches a genuinely misspelled identifier, and dozens of fake
findings would bury a real one. A second block covers `scripts/**/*.mjs`, which
is ESM and needs Node's globals without the CommonJS wrapper.
**The tests block applied a non-TypeScript-aware rule to TypeScript.** It named
`tests/**/*.ts` while setting the CORE `no-unused-vars`, which v9 deliberately
turns off for `.ts` in favour of the `@typescript-eslint` version. The core
rule reads the parameter names inside a function TYPE as bindings, so
t?: (app: string, key: string) => string
reports `app` and `key` as unused variables, and every unused `catch (e)` in a
`.ts` spec reports twice. The block is split now: `.js`/`.mjs` on the core
rule, `.ts`/`.tsx` on the TypeScript one, same patterns on both.
Also: stale `eslint-disable` comments naming plugins eslint 10 no longer
registers, which are themselves errors ("Definition for rule ... was not
found"), and a rule that must not parse shell scripts.
The genuinely real findings were the useful part: dead locals, unused imports,
dead helper functions, unused `catch` bindings, extensionless relative imports,
and a handful of `== null` comparisons spelled out so they still match null AND
undefined.
Verified per app: `npm run lint` 0 errors over src + tests + scripts,
`prettier --check` clean, and the unit suite still green.
| ? [`pm.test('${c.key}: ${c.expect.status} rows are gone', () => pm.expect(matching.length).to.eql(${c.expect.exactly}))`] | ||
| : [`pm.test('${c.key}: wrote at least ${c.expect.atLeast} ${c.expect.status} object(s)', () => pm.expect(matching.length, 'the run was green but wrote nothing').to.be.at.least(${c.expect.atLeast}))`]), | ||
| ] | ||
| `const matching = objects.filter((o) => o.status === ${JSON.stringify(c.expect.status)})`, |
| ` pm.expect(other.length, 'only one branch produced anything — nothing was actually split').to.be.at.least(${c.expect.also.atLeast})`, | ||
| '})', | ||
| ] | ||
| `const other = objects.filter((o) => o.status === ${JSON.stringify(c.expect.also.status)})`, |
| ` pm.expect(Number(carrying[0][${JSON.stringify(c.expect.field.name)}])).to.eql(${c.expect.field.equals})`, | ||
| '})', | ||
| ] | ||
| `const carrying = objects.filter((o) => o.status === ${JSON.stringify(c.expect.status)})`, |
| ` pm.expect(String(bearing[0][${JSON.stringify(c.expect.text.name)}])).to.eql(${JSON.stringify(c.expect.text.equals)})`, | ||
| '})', | ||
| ] | ||
| `const bearing = objects.filter((o) => o.status === ${JSON.stringify(c.expect.status)})`, |
| ` pm.expect(String(named.status)).to.eql(${JSON.stringify(c.expect.step.status)})`, | ||
| '})', | ||
| ] | ||
| `const named = steps.filter((s) => s.transition === ${JSON.stringify(c.expect.step.node)})[0]`, |
| ` pm.expect(batchStep.itemsOut, 'batching did not reduce the item count').to.be.at.most(${c.expect.batched.maxOut})`, | ||
| '})', | ||
| ] | ||
| `const batchStep = steps.filter((s) => s.transition === ${JSON.stringify(c.expect.batched.node)})[0]`, |
…e-schema fix(controllers): name the register before the schema
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-09-01 10:30 UTC
Download the full PDF report from the workflow artifacts.
Automated PR to sync development changes to beta for beta release.
Merging this PR will trigger the beta release workflow.