Skip to content

Release: merge development into beta - #197

Open
github-actions[bot] wants to merge 800 commits into
betafrom
development
Open

Release: merge development into beta#197
github-actions[bot] wants to merge 800 commits into
betafrom
development

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automated PR to sync development changes to beta for beta release.

Merging this PR will trigger the beta release workflow.

Reminder: Add a major, minor, or patch label to this PR to control the version bump. Default is patch.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit ebbb0dc
Branch 197/merge
Event pull_request
Generated 2026-03-19 16:38 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23305755039

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit baec00a
Branch 197/merge
Event pull_request
Generated 2026-03-19 16:46 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23306099824

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit d71ef19
Branch 197/merge
Event pull_request
Generated 2026-03-19 18:55 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23311644661

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit 99124f4
Branch 197/merge
Event pull_request
Generated 2026-03-19 18:58 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23311788331

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit bedba4b
Branch 197/merge
Event pull_request
Generated 2026-03-19 19:04 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23312029118

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit 985de13
Branch 197/merge
Event pull_request
Generated 2026-03-19 21:37 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23318049540

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit cac4c4b
Branch 197/merge
Event pull_request
Generated 2026-03-23 16:15 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/23447563193

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit 2d92441
Branch 197/merge
Event pull_request
Generated 2026-04-09 09:48 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/24183667745

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP
Playwright SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.

E2E Tests (Playwright)

Playwright E2E tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/softwarecatalog
Commit c176ba1
Branch 197/merge
Event pull_request
Generated 2026-04-09 10:00 UTC
Workflow Run https://github.com/ConductionNL/softwarecatalog/actions/runs/24184203950

Summary

Group Result
PHP Quality FAIL
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP
Playwright SKIP

PHP Quality

Tool Result
lint PASS
phpcs FAIL
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint FAIL

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (120 total)

Metric Count
Approved (allowlist) 120
Approved (override) 0
Denied 0

npm dependencies (582 total)

Metric Count
Approved (allowlist) 581
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.

E2E Tests (Playwright)

Playwright E2E tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 6c8d08c

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 582/582
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-03 15:17 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ bc9432a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-03 17:47 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 62280a4

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-03 18:04 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 954821d

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-05 09:14 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 533d8dc

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-07 20:53 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ ec04faa

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-07 21:24 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ b849b29

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-10 07:09 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 7176811

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-10 08:33 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 75b1d84

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-10 19:20 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 612957d

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-10 19:31 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ d94e250

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 622/622
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-10 21:09 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 1a1e9c7

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 622/622
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-11 20:20 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 919e14b

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-12 21:00 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 05b95eb

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-12 21:43 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 33b6854

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-12 22:08 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 4f950b5

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-12 22:31 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 4f950b5

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-13 04:37 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 364fcb3

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-13 04:45 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 364fcb3

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/282 statements)


Quality workflow — 2026-05-13 04:52 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 364fcb3

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-13 04:56 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 3b21d4c

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 120/120
npm ✅ 623/623
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-13 05:14 UTC

Download the full PDF report from the workflow artifacts.

…527)

Adopts the canonical script from ConductionNL/.github (quality-config/coverage-guard.php).

The whole-project comparison fires on measurement noise. doriath#240 was a PR
whose entire diff was `webpack.config.js` — no PHP at all — and the guard failed
it: identical denominator (13723), both runs reporting exactly
`Tests: 948, Assertions: 3051, Skipped: 1`, and six covered statements of
run-to-run xdebug variance between them.

The measured `--against` floor cancels driver variance (xdebug vs pcov), as its
header says. It does not cancel run-to-run variance within one driver, and the
ratchet has no tolerance. Scoping the comparison to the PHP a change actually
touches keeps full strength where a regression matters and makes the noise
unreachable by construction — a diff with no PHP cannot fail.

New `changed-files` capability; the shared workflow PROBES for it rather than
assuming, so an un-updated copy keeps the previous behaviour instead of silently
accepting and ignoring the flag.

Script only — no behaviour change until the workflow passes `--changed-files`.
Byte-identical to the canonical copy (md5 5be122aad209da030c79b22a133232fb).
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 0c4b12c

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-16 11:09 UTC

Download the full PDF report from the workflow artifacts.

…-the-contract

fix(tests): the ObjectEntity stub declared return types wider than the contract
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 73c43de

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-16 11:30 UTC

Download the full PDF report from the workflow artifacts.

…ying (#531)

* fix(me): pass the two ADR-084 arguments the /me factory stopped supplying

`GET /api/softwarecatalog/api/me` returns 500 for every user on
`development` right now:

    Too few arguments to function
    OCA\SoftwareCatalog\Controller\ContactpersonenController::__construct(),
    11 passed in .../lib/AppInfo/Application.php on line 730
    and exactly 13 expected

ADR-084 (#519) added `$objectService` and `$organisationService` to
`ContactpersonenController::__construct()`. That controller is not
autowired: `Application.php` registers it with a hand-written factory
closure, added deliberately "for /me endpoint", and a hand-written
factory does not gain a constructor argument automatically.

Nothing we run catches that. `php -l` passes, phpcs/phpmd/psalm/phpstan
pass, and the controller's own unit tests pass because they construct the
controller themselves and never go through the factory. The first thing
that notices is a request. It was found by an end-to-end run, as the only
5xx URL in 176 requests — and it accounts for 42 of that suite's 47
failures.

The fix supplies both arguments from the same container entries the file
already uses twice (`ObjectServiceInterface::class` via the alias
registered at the top of `register()`, and OpenRegister's
`OrganisationService`).

`tests/Unit/AppInfo/CompositionRootArgumentsTest.php` closes the hole for
every hand-written factory in the composition root, not just this one. It
reads `Application.php`'s own source with PHP's tokeniser, extracts every
`new <Class>(...)`, and reflects the target constructor. It refuses to
report a vacuous pass: it asserts a floor on the number of call sites
parsed and on the number of classes reflected, and it keeps the set of
targets it cannot reflect explicit, because unreflectable is "unchecked",
not "clean".

* test(composition-root): resolve an unqualified class name against the file's own namespace

The first version of the parser resolved `use ... as Alias` after taking
the short name, and did not resolve an unqualified name against the
file's own namespace at all. Both mistakes push a call site into the
"could not reflect" bucket, and unreflectable reads as unchecked, which
reads as clean.

With both fixed, the set of factory targets this test cannot reflect in
softwarecatalog is EMPTY — all 40 call sites in the composition root are
actually checked — so the declaration is now asserted exactly rather than
as a subset.

* test(stubs): give the ObjectEntity stub the return types its contract declares

The unit suite does not run on `development`. It dies with

    Fatal error: Declaration of OCA\OpenRegister\Db\ObjectEntity::getUuid()
    must be compatible with
    OCA\OpenRegister\Contract\ObjectEntityInterface::getUuid(): ?string
    in tests/Stubs/Db/ObjectEntity.php on line 151

ADR-084 made the stub `implements ObjectEntityInterface`, but its five
abstract declarations kept their untyped, docblock-only signatures. PHP
refuses to declare a class whose abstract method is less specific than
the interface it satisfies, so the failure is a class-declaration fatal,
not a test failure: it aborts the run rather than reporting anything.
Under `tests/bootstrap.php` — the config CI uses — every stub is
`require_once`d at bootstrap, so the suite dies before test one and the
job reports zero tests.

One anonymous subclass (MergeOrganisatieServiceTest) needed the same four
return types for the same reason.

`getId()` and `setObject()` are deliberately left untyped: neither is on
the contract, so nothing constrains them.

This does not fix a single test. It makes the suite measurable:

    before: 50 tests, then a fatal (0 under tests/bootstrap.php)
    after:  Tests: 702, Assertions: 2656, Errors: 50, Failures: 12,
            Warnings: 3, Deprecations: 1, Skipped: 25

The 62 problems now visible are the rest of the ADR-084 fallout and are
NOT addressed here — 38 are test helpers still declaring a return type of
the concrete `OCA\OpenRegister\Service\ObjectService` while the code they
feed now takes `ObjectServiceInterface`, and 8 are the deleted
`$container` constructor parameter shifting every positional argument
after it. They need their own change.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ b348bf5

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-16 12:25 UTC

Download the full PDF report from the workflow artifacts.

…e whole voorzieningen register (#529)

The E2E (Playwright) job on `development` has not run a single test since
2026-08-14 19:29Z. It fails in the seed step, before Playwright starts, on
softwarecatalog's own honest gate:

    softwarecatalog has no register/schema mapping for:
      ['organisatie_schema', 'contactpersoon_schema', 'module_schema', 'contract_schema']

That gate is correct and the register really is unusable. The chain, read
from the failing job's own Nextcloud log (run 31937311499):

1. `view` and `bioMeasure` declare `objectDescriptionField: "summary"` while
   neither schema has a `summary` property. OpenRegister's
   `SchemaMapper::validateConfigField()` throws for exactly this, and
   `ImportHandler` logs
   `Failed to import schema: The value for objectDescriptionField ('summary')
   does not exist as a property in the schema.`
2. Both schemas are therefore absent from the import's `schemasMap`, so the
   `voorzieningen` and `vng-gemma` registers are imported without them —
   OpenRegister logs 18 `not found in schemasMap` warnings.
3. `SettingsService::configureVoorzieningen()` iterates the register's
   schemas to build the app-config map. With the links gone it writes
   `register` and nothing else, leaving every `*_schema` key empty.
4. `tests/e2e/ci-seed.sh` refuses to run Playwright against that. Correctly —
   the alternative is ~20 spec failures blaming the fixtures.

Where the two values came from: commit 386771d (#513, "translate 12
pre-existing Dutch property names") renamed the `view` schema's `summary`
property KEY to `omschrijving` and left `objectDescriptionField` pointing at
the old key, and separately rewrote `bioMeasure`'s `objectDescriptionField`
VALUE from `omschrijving` to `summary` while its property key stayed
`omschrijving`. Two dangling references, opposite directions, one commit.

This points both at the property each schema actually declares. It does not
rename anything: a property rename here is a data migration and belongs with
the vocabulary programme, not with an E2E fix.

Evidence, same instrument both sides — OpenRegister's own three acceptance
forms applied to the shipped register file, 20 schemas / 38 configuration
fields measured:

  before: 2 failures (view.objectDescriptionField, bioMeasure.objectDescriptionField)
  after:  0 failures

The new test reproduces that measurement in PHPUnit and carries a positive
control asserting the check can fail, so a future rename cannot silently
detach the register again. Run in a php:8.3-cli container (the host is 8.2):

  before fix: Tests: 4, Assertions: 21, Failures: 1  (naming both schemas)
  after fix:  OK (4 tests, 21 assertions)
  phpcs --standard=phpcs.xml on the new file: exit 0, 1 file measured

The test also records the two `objectSummaryField` values that dangle today
(`element`, `relation`). OpenRegister does not validate that key, so they are
inert — asserted as a known set rather than zero, so adding a new one fails
while the existing debt stays visible.
* fix(gate-57): delete six orphaned write capabilities

gate-57 orphaned-write-capability reported 6 findings over 55 lib/Service
files. All six had zero callers; all six are deleted.

- AangebodenGebruik\GebruikStatusHandler::updateStatus — the whole class is
  unreferenced. Its docblock says "AangebodenGebruikService delegates all
  updateStatus() logic here"; AangebodenGebruikService has no such method and
  never constructs the handler, so the method-decomposition extraction landed
  without its caller ever being updated. Deleted with the class, and with
  StatusTransitionValidator, whose only consumer it was.
- SoftwareCatalogContactSyncService::importContact — validated a UID and
  returned it unchanged. The two live consumers (OrganizationContactSyncJob,
  Repair\MigrateContactsToNc) use isAvailable/findContactByUid/
  findContactForRecord/syncToContacts, which already serve resolve-or-create.
  Spec REQ-SCNC-003 updated: the service no longer names importContact.
- SoftwareCatalogue\ContactPersonHandler::updateUserGroupsFromRoles — already
  @deprecated, logged "deprecated - role assignment now based on organization
  type" on every call, ignored both role arguments and forwarded to
  updateUserGroupsFromContactData(). No caller, so its backward compatibility
  had no consumer. Group membership is a permission fact; a second entry point
  into it is a surface, not a convenience.
- SoftwareCatalogueService::sendGebruikerWelcomeEmail,
  ::syncUserWithRevertedContact and ::updateUserFromRevertedGebruiker — each
  was a single logger->info() and nothing else. They named capabilities
  (send a welcome mail, reconcile a user after an object revert) that have
  never been implemented; wiring a log line in would have hidden the gap.

⚠️ SoftwareCatalogEventListenerTest asserted that the listener calls
sendGebruikerWelcomeEmail, syncUserWithRevertedContact and
updateUserFromRevertedGebruiker exactly once each. It does not, and there is no
code path in SoftwareCatalogEventListener that ever did — the tests described a
wiring that does not exist. They are corrected here rather than deleted: the
revert case now asserts the true invariant (the revert path runs without
reaching a capability the app does not implement).

Before: 6 findings over 55 files. After: 0 findings over 53 files (two service
files fewer because the dead handler pair was deleted).

* style(catalogue): capitalise two inline comments

Two pre-existing phpcs errors ('Inline comments must start with a capital
letter') in a file this branch already touches, per the fix-what-you-touch
rule. lib/Service/SoftwareCatalogueService.php is now phpcs-clean (0 errors).
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ eb6dd79

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-16 13:18 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 3700abc

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-16 13:47 UTC

Download the full PDF report from the workflow artifacts.

`PHP Quality (phpcs)` reported 19 errors across 8 files. All are documentation
or formatting; none change behaviour. `./vendor/bin/phpcs --standard=phpcs.xml`
now exits 0 (was 2, then 1).

  * 9x "Doc comment for parameter missing" — constructors that grew injected
    collaborators (ObjectServiceInterface, OrganisationService,
    OrganisationMapper, SchemaMapper, RegisterMapper, MetadataHydrationHandler,
    RenameDutchCatalogDecisions) without their `@param` lines following.
    Documented what each one is for rather than restating its type.
  * 2x parameter-comment alignment in OrganisationMembersController — caused by
    two orphaned continuation lines hanging off `$userManager`, describing a
    parameter that no longer exists. Removed rather than realigned.
  * 4x line-length — a `@return array{...}` shape in FederationMerger wrapped
    onto three lines with its prose moved above it, and a `@spec` URL in
    InitializeSettings split across three comment lines.
  * 1x inline comment capitalisation.
  * 1x "You must use /** style comments for a function comment" in
    ReviewController: a prose note sat BETWEEN the attribute list and the
    signature, where PHPCS reads any comment as the function's doc comment.
    Moved into the docblock — nothing should sit between an attribute list and
    the thing it annotates.

⚠️ I broke the file once while fixing that last one: the explanation I wrote
contained a literal `*/` inside backticks, which CLOSED the docblock early and
turned it into a parse error. `php -l` caught it immediately; rephrased. Worth
recording because the comment was ABOUT comment syntax, which is exactly when
this is easy to do.

## Verification, and its limit

Every touched file passes `php -l`, and the changes are comments only, so
parse-level is the relevant risk and it is covered. I could NOT run the test
suite: softwarecatalog's `tests/bootstrap.php` requires a Nextcloud server tree
and my container has none — it fatals in the bootstrap, before any test. Saying
so rather than implying a green suite.

THIS DOES NOT GREEN THE APP. phpstan, psalm, phpmd, all six PHPUnit cells, E2E
and Hydra Gates are still failing on this branch and are untouched here.
fix(phpcs): clear all 19 errors — phpcs exits 0
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 9eab803

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-16 18:37 UTC

Download the full PDF report from the workflow artifacts.

…44 static findings

PHPUnit was red in all six matrix cells with an IDENTICAL count
(Tests 705, Errors 7, Failures 12, Warnings 3, Skipped 20), which looked
like a class-load fatal. It was not: the suite ran to completion in every
cell. The shared cause is that this app's consumption of OpenRegister
drifted from the contract OpenRegister now publishes
(OCA\OpenRegister\Contract\ObjectServiceInterface / ObjectEntityInterface),
and both the production code and its doubles were pinned to the older
surface.

Measured, in-container on PHP 8.4 against the same openregister:
  PHPUnit  705 tests: 19 red -> 1 red -> 0 red
  phpstan  37 errors -> 0
  psalm     4 errors -> 0
  phpmd     3 findings -> 0
  phpcs     exit 0 before and after (warnings only, pre-existing)

Six distinct defects, not one:

1. The saveObject() double omitted the contract's second parameter.
   ObjectServiceInterface::saveObject() is
   (object, extend, register, schema, uuid, ...). MergeOrganisatieServiceTest's
   willReturnCallback declared (object, register, schema, uuid). PHPUnit
   resolves the subject's NAMED arguments against the generated mock's own
   signature and then invokes the callback POSITIONALLY, so the capture
   silently recorded extend-as-register and register-as-schema. Nothing threw;
   every assertion that looked a save up by (schema, uuid) reported "no such
   save". Six failures. The callback now mirrors the contract position for
   position.

2. Three controller tests wired their fixture into a ContainerInterface
   double while the subject holds an INJECTED contract. The subject was
   left holding a different, unconfigured mock: reads returned empty, and
   the organisation guard refused a caller reading their OWN organisation.
   Five failures, one of them a cross-tenant test passing straight through
   the check it exists to prove.

3. getObjectService() asked the container for the CONCRETE class and gated
   on `instanceof ObjectService`. Anything that satisfies the published
   interface without being that exact class - i.e. every double a leaf app
   can build - fell to the fail-closed arm and refused an owner. Fixed in
   ContractApprovalService, ContractStatusService and SbomImportService:
   ask for the contract, narrow on the contract.

4. Two tests referenced RegisterMapper / MetadataHydrationHandler with no
   import, so they resolved inside the test's own namespace. Four errors.
   The listener's dependency on both is gone (see 6), so the imports went
   with it.

5. QueryLimitBoundingTest seeded only `container` and `logger` by
   reflection on a newInstanceWithoutConstructor() instance. Reading an
   uninitialised typed property is an Error, not a null, so the test died
   before observing the query it exists to observe. It now seeds
   `objectService` too.

6. UserProfileUpdatedEventListener reached past the contract into
   SchemaMapper, RegisterMapper and Service\Object\SaveObject\
   MetadataHydrationHandler to regenerate `_name` before saving. That was
   redundant - ObjectService::saveObject() calls hydrateObjectMetadata() on
   both its create and its update path - and it is what psalm reported as
   two UndefinedClass errors and phpmd as a LongVariable plus an unused
   $registerEntity. All three dependencies removed.

Production defects found on the way, each fixed at the call site:

- ContactpersonenController passed `silent: true` TWICE in one saveObject()
  call (a merge artefact); psalm InvalidNamedArgument, phpstan duplicate.
- GebruikSyncService passed `id:` where the contract's parameter is `uuid:`.
  The name was corrected, not dropped.
- ContactpersoonService tested `findSilent(...) === null`. findSilent()
  declares a NON-nullable ObjectEntityInterface and lets the mapper's
  DoesNotExistException out, so the distinct "not found" entry was
  unreachable and every miss came back carrying an `error` key instead. Now
  caught explicitly.
- ContactPersonHandler::findContactPersonByUsername() was private, had no
  caller, and called findAll($filters, $registerId, $schemaId) POSITIONALLY
  against findAll(array $config, bool $_rbac, bool $_multitenancy) - the
  register id would have landed in $_rbac and the search run unscoped.
  Deleted with the reasoning recorded in place.
- OrganizationHandler had one saveObject() with no register/schema at all,
  leaving the write to whatever scope the service happened to carry. It now
  falls back to the entity's own coordinates.

Six call sites pushed a payload into the entity with setObject() and read
it straight back out. setObject(), setOrganisation() and getId() are
implementation-only accessors reached through Entity::__call() and are not
on ObjectEntityInterface; the payload is now threaded through explicitly.
saveObject() is PUT-semantic, so every unchanged field is still carried
forward.

Two constructors dropped an unused ContainerInterface (phpstan: "never
read, only written") - ADR-084 replaced the lazy lookup with the injected
contract. lib/AppInfo/Application.php's hand-written factories updated to
match; tests/Unit/AppInfo/CompositionRootArgumentsTest.php covers that.

tests/Stubs/Db/ObjectEntity.php's header documented the OPPOSITE of the
current truth. It said getOrganisation() is magic on the real entity, so
declaring it here inverts method_exists(). ADR-084 changed that: the real
ObjectEntity implements ObjectEntityInterface, and an interface method
cannot be served by __call(), so the real class declares all six
concretely. The stub mirrors it, keeps the backing `organisation` property
(that is what Entity::getter() and readOwningOrganisation() key on), and
the header now says so. testTheMagicEntityDoubleMatchesTheRealObjectEntity
AccessorShape was asserting the pre-ADR-084 shape and is re-pointed at the
current one, pinning BOTH halves so the softwarecatalog#490 data-loss path
cannot come back.

No named argument was removed anywhere in this change. `id:` -> `uuid:` is
a NAME correction to match the published signature.

E2E Tests, Hydra Gates and Quality Report are NOT addressed here and remain
red; they were not diagnosed.
fix: close the ADR-084 contract drift behind 19 PHPUnit failures and 44 static findings
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 6ca58fa

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-16 21:11 UTC

Download the full PDF report from the workflow artifacts.

`development` (run 31971663303, sha 8fd9130) failed exactly three jobs:
Hydra Gates, E2E Tests (Playwright), and the Quality Report downstream of
them. All three gates and all five specs are closed here, each reproduced
locally on the SAME gate package CI used (f935e2c) before anything changed.

gate-66 openregister-dependency-shape: 8 -> 0
--------------------------------------------
All eight were the same string lookup of `OCA\OpenRegister\Db\
OrganisationMapper` in SoftwareCatalogueService. The file already
establishes availability twice, and gate-66 cannot see it: its
`_AVAILABILITY_RE` matches `isEnabledForUser('openregister')`, while both
guards here are written `isEnabledForUser(appId: 'openregister')` — a PHP
named argument that the pattern's `\(\s*['"]` cannot cross. Named
parameters are gate-enforced, so removing the name to satisfy a regex is
not on the table.

Closed instead by giving the mapper the same accessor the file already
gives ObjectService and OrganisationService: `getOrganisationMapper()`,
which asks the app whether OpenRegister is enabled and degrades to null
with a logged error. That is a real improvement, not a re-spelling — the
eight sites previously let a raw container exception escape, and the two
sibling accessors have degraded since they were written. Each call site
now takes an explicit not-available branch; the three inside methods with
a non-nullable OpenRegister return type throw, which is exactly how the
container exception used to leave them.

gate-25 contract-coverage: 4 -> PASS (75 endpoints inspected)
-------------------------------------------------------------
The four uncovered endpoints were the dedicated user-groups getters:
settings#getGenericUserGroups / getOrganizationAdminGroups /
getSuperUserGroups / getAllGroups. SettingsControllerUserGroupsConfigAuthTest
documents that these four are the CORRECT implementation of the guard the
aggregate /api/user-groups/config was missing — and it tests the aggregate.
The four that carry the guard had no test of their own.

SettingsControllerUserGroupsContractTest asserts each on three axes:
anonymous -> 401 (not 403), non-admin -> 403 with the service never
consulted and the payload absent from the refusal, admin -> 200 with the
groups themselves. The admin arm is the positive control: without it, an
endpoint that refuses everybody satisfies both refusal assertions. Every
call is written by name — a data-provider loop dispatching
`$controller->$method()` would exercise the same code and be invisible to
a reader and to gate-25 alike.

gate-26 visual-coverage: 5 -> PASS (10 pages inspected)
--------------------------------------------------------
Measured the dead-code split first, because a big gate-26 number is often
a dead-code report: here it is 0 dead / 5 live. All five are referenced by
manifest.json, registry.js or customComponents.js, and four already had a
spec driving them. Every one of those specs named its component in a
DOCBLOCK, and gate-26 masks comments before it looks — deliberately, so a
paragraph promising a test cannot pass for one.

tests/e2e/spec-coverage/page-components.ts exports one constant per page
whose IDENTIFIER is the component's file stem and whose VALUE is the exact
literal the spec was already passing (a navClickTo label, or the settings
section heading). Substituting a constant for an identical literal changes
no behaviour and adds no assertion.

E2E: five failures, three distinct causes, two of them product defects
-----------------------------------------------------------------------
1. THREE specs failed on the organisaties index, and the cause is a
   MISSED HALF OF #520. The Organisaties page filters
   `config.filter.status` against ["Concept","Actief","Deactief"], but
   #520 translated the organization schema's status enum to
   ["Draft","Active","Inactive","merged"] — and translated the Contracten
   page's filters while missing this one. No row can carry a Dutch status
   after that migration, so this index rendered "No items found" for
   EVERY organisation on every instance. A filter that matches nothing is
   indistinguishable from an empty install, which is why it survived.

   Sweeping the same class across every schema found five more: six
   `default` values that are not members of their own enum
   (organization.status 'Concept', usage.status 'In productie',
   connection.status 'in gebruik', connection.integrationType's template
   emitting extern/intern, module.type 'Applicatie',
   moduleVersion.status 'in gebruik'). Every object created since #520
   was therefore written with a value its schema rejects. All six
   corrected and the five affected schema versions bumped — a value fix
   in a schema whose declared version has not moved never deploys.

   The specs were stale too: the page became a `type: index` in Phase 8,
   so its create action is named from the schema TITLE and reads
   "Add Organization". `/Add organisation/i` differs by one letter and
   matched nothing. And `expect(getByText('No organisations')).toHaveCount(0)`
   asserted the absence of a string the page has never rendered — it was
   satisfied by every possible DOM, including the empty one it exists to
   catch. Re-pointed at the real empty state.

2. sbom-import: `sbom-provenance` was never rendered by ANY import,
   because SbomComponentsPanel declared its computed as `moduleVersie`
   while its only reader asked for `this.moduleVersion`. Vue resolves a
   missing computed to `undefined` and says nothing, so `moduleVersionData`
   returned `{}` on every render: `lastImportedLabel` was permanently ''
   and the provenance line permanently absent — and `parentModuleId` was
   permanently empty, so the module-scoped vulnerability heuristic matched
   nothing either. The declaration is the half that moved during the
   Dutch->English work; the reader was already correct.

3. gemma-faceted-search expected the 400 body to name `dienst`.
   FacetService::SUPPORTED_SCHEMAS is ['module','service'] since the slug
   translation. Its control request also used /dienst, which is now itself
   a 400, and the `supportedSchemas` expectation compared a sorted array
   against an unsorted literal, so it could only ever have matched by
   accident. All three corrected.

Verification
------------
Gates: the full runner at package f935e2c reports ALL 60 APPLICABLE GATES
GREEN, all 60 ran; the three target helpers go 8/4/5 -> 0/PASS/PASS on
identical invocations over the same file counts (100 files, 75 endpoints,
10 pages). gate-53's single WARN is byte-identical to the base.

Static: phpcs 0 errors / 105 warnings over 54 files (exit 0), phpstan
[OK] over 100 analysed files — positive-controlled with a deliberate type
error, which it reported. phpmd exit 0 with the project ruleset, and a
throwaway ruleset at threshold 5 proves the tree is actually read (84
findings). prettier --check passes on every changed .ts/.vue and was
positive-controlled against a misformatted file. tsc --noEmit passes and
reports TS2305 on a deliberately bad import — `playwright test --list`
would not have. eslint clean on the changed component. vitest 226/226.

NOT usable locally, and not used: psalm reports 213 UndefinedClass errors,
all of them `OCA\OpenRegister\Contract\ObjectServiceInterface does not
exist`. It is green in CI, which installs the real openregister.
…t as untested

CI on 583f538 was green everywhere except one cell: `PHPUnit (PHP 8.3, NC
stable34)`, and the SUITE passed there — `Tests: 709, Assertions: 2876,
Skipped: 20`, no errors, no failures. The job failed on a later step, the
Coverage Baseline Protection ratchet, which runs in exactly one matrix cell:

    Changed files, head:     0.54%  (12/2233 statements)
    Changed files, base:     0.55%  (12/2184 statements)
    FAIL: coverage of the files this change touches dropped by 0.01%.

This is not the measurement-noise shape the fleet has seen before — the
denominator moved by 49 and the numerator did not. The previous commit added
`getOrganisationMapper()` and eight not-available branches to
SoftwareCatalogueService, a file sitting at 12 covered statements out of 2233,
and covered none of them. The ratchet is right.

The accessor is worth pinning on its own terms rather than for the ratio.
Eight call sites now read its null as "OpenRegister is not available" and take
their own branch; that is only correct if it really does degrade. Three arms:

  - OpenRegister disabled      -> null, and the container is NEVER asked
                                  (asking it is the unguarded lookup the
                                  accessor exists to replace)
  - enabled and resolvable     -> the mapper itself, asserted with assertSame
  - resolution throws          -> null plus a logged error carrying the cause

The middle arm is the positive control: without it an accessor that returned
null unconditionally would satisfy both null assertions while silently
disabling every organisation-membership path in the app.

Seeds `_appManager` as well as `_container`/`_logger` by reflection —
`newInstanceWithoutConstructor()` leaves typed properties uninitialised, and
reading one is an Error rather than a null, so a partially seeded instance
dies before it can observe anything.

Verified standalone against `phpunit-unit.xml` on PHP 8.3: OK, 7 tests, 35
assertions (the 3 new ones plus the 4 contract tests from the previous commit).
…d the SBOM provenance line read a name that no longer existed (#536)

* fix(softwarecatalog): the Organisations index filtered on values #520 deleted, and the SBOM provenance line read a name that no longer existed

Five of the six E2E failures on `development` came from two renames that moved
one half of a pair and left the other behind. Neither raised an error, which is
why both survived: one produced an empty list, the other produced an element
that never rendered.

1. THE ORGANISATIONS INDEX WAS EMPTY FOR EVERY USER.
   `src/manifest.json`'s Organisaties page filtered on
   `status: ["Concept", "Actief", "Deactief"]`. #520 translated that enum to
   Draft/Active/Inactive/merged and migrated the stored rows, but not this
   filter — so the page filtered on three values no row can hold. OpenRegister
   answers such a filter `200 {"total": 0}`, so the index rendered
   "No items found" and read as an empty catalogue: no console error, no failed
   request, nothing in the log.

   Measured on a running instance, positive and negative control:
     ?status[]=Draft&status[]=Active          -> total 1 (the seeded row)
     ?status[]=Concept&status[]=Actief&...    -> total 0
   and reproduced in the browser: one organisation exists, the index shows
   "No items found".

   The same commit missed `organization.status`'s `default` ("Concept", not a
   member of its own enum, so every newly created organisation lands outside
   this filter) and the whole `x-openregister-lifecycle` block, whose
   `initial`, `final` and every `from`/`to` still named the Dutch values — a
   lifecycle whose transitions match no row simply offers nothing. Both are
   fixed here, with the schema version bumped: a deployed version >= the
   declared one makes the import SKIP, and OpenRegister's
   schemaContentDiffers() escape hatch compares only properties/required/
   authorization — never `configuration` — so a lifecycle-only edit would never
   have deployed.

2. THE SBOM PROVENANCE LINE COULD NEVER RENDER.
   `SbomComponentsPanel`'s producer computed is `moduleVersie()`; when the
   schema slug was translated the CONSUMER was renamed to `this.moduleVersion`
   and the producer was not. Vue resolves the unknown property to `undefined`,
   `moduleVersionData` returned `{}`, and every derived value went empty:
   `lastImportedLabel` returned '' so the `v-if`-gated
   `data-testid="sbom-provenance"` never mounted, and `parentModuleId` returned
   '' so the vulnerability-match heuristic ran with an empty scope. "No import
   yet" is a legitimate state, so the broken build was indistinguishable from an
   unimported module version.

3. Three e2e tests asserted a surface the product stopped rendering. Organisations
   was decomposed from a bespoke `type: custom` OrganisatieIndexView to a
   standard `type: index` page; the tests still looked for that view's
   "Add organisation" button and its "No organisations" empty state. The empty-
   state assertion was the worse half: `toHaveCount(0)` against a string nothing
   renders passes unconditionally, so the guard meant to catch an empty list said
   nothing while the list really was empty. They now assert the CnIndexPage
   surface — heading, Cards/Table toggle, create action, list body — which is
   strictly more than before.

4. `gemma-faceted-search` still named the pre-#518 Dutch slug `dienst` in three
   places: the message assertion, the 200 control, and a
   `supportedSchemas.sort()` compared against an UNSORTED literal, which could
   not have held for any naming.

5. `index-pages`' "index standards" test.fixme claimed "blocked: missing
   `standaard` schema". The page is bound to `"schema": "element"`, which the CI
   seed enumerates among the 36 schemas present, and a running instance renders
   the index with an "Add Element" action and no app-origin error. A skip whose
   reason has stopped being true reads exactly like a passing test, so it is put
   back to work rather than re-worded.

BEFORE / AFTER (local, same command both sides)

  tests/vitest/sbomProvenanceLabel.spec.js  (new, 4 tests)
    on HEAD: 2 failed / 2 passed   (both failures are the defect; both passes
                                    are the negative controls, so the
                                    assertions discriminate)
    after:   4 passed / 0 failed

  tests/vitest/manifestFilterEnumParity.spec.js  (new, 3 tests)
    on HEAD: 1 failed / 2 passed — reporting exactly the three stale filter
             values, with its positive control passing on both sides
    after:   3 passed / 0 failed

  full vitest suite, run from `git archive HEAD` with the same node_modules:
    HEAD:   22 files, 21 passed / 1 failed, 226 tests passed
    branch: 23 files, 22 passed / 1 failed, 230 tests passed
  The one failing file is `adminApi.spec.js` (`ReferenceError: window is not
  defined`); it fails identically on pristine HEAD and this change does not
  touch it or anything it imports.

  eslint on the changed component: clean.
  `node tests/validate-manifest.js`: PASS (0 errors), 29 pages, schema 2.22.0.

FILES MEASURED: 11 changed (2 config/JSON, 1 component, 5 e2e specs + 1 e2e
helper, 2 new vitest specs + 1 stub).

NOT DONE, DELIBERATELY — recorded on the fleet board:
  - Five more schemas carry the same #520 miss: `usage.status` default
    'In productie', `connection.status` and `moduleVersion.status` default
    'in gebruik', `module.type` default 'Applicatie',
    `connection.integrationType` default template emitting 'extern'/'intern' —
    every one outside its own enum — plus four more Dutch
    `x-openregister-lifecycle` blocks (usage 'Verwerving', contract
    'In onderhandeling', connection and moduleVersion 'in ontwikkeling'). They
    are the same class of bug on surfaces this change does not measure, so they
    belong to whoever owns #520 rather than to an E2E repair.
  - The schema title is authored "Organization" while every other string in the
    app is British, and a deployed instance can still serve the older
    "Organisation" because a title change never redeploys. Rather than rename a
    schema title from an E2E fix, the affected assertions accept either spelling
    of that one word.
  - `organisatie-crud`'s UI-create test.fixme is NOT re-enabled. Its stated
    reason (an ObjectModal Catalogus cascade) describes a removed surface, so
    the reason is corrected to "unverified" rather than restated — the body has
    never been re-authored against the dialog that replaced it, and guessing
    which fields that dialog exposes is exactly the kind of assertion that
    passes without testing anything.

* docs(e2e): record the measured cause of the standards index failure

Un-skipping `index standards` exposed a real defect, and this records what it
is so the next reader does not re-derive it — and so nobody "fixes" it the
wrong way.

The surface assertions pass (chrome, "Add Element", list body). The failure is
`expectNoAppErrors`: `Error fetching 14-element collection`. The page config is
`register: "@resolve:voorzieningen_register"` + `schema: "element"`, but
`element` is bound to the OTHER register declared in the same register file —
`components.registers.vng-gemma.schemas`, not `.voorzieningen.schemas`. Same
family as openconnector#1275's `synchronization_run`: declaring a schema does
not attach it, and only an attached schema is fetchable.

⚠️ Adding `element` to the voorzieningen register would make the request
succeed and return NOTHING, because objects live per register and the GEMMA
elements were imported under vng-gemma — a visible error turned into an empty
list, which is an invisible pass and worse than the red.

The honest fix needs a second `@resolve:` sentinel for the gemma register.
`voorzieningen_register` is currently the only one (34 uses), provisioned in
Application.php::boot() from the `voorzieningen_config` blob; no app-config key
holds a vng-gemma register id, and tests/e2e/ci-seed.sh does not provision that
register at all. Where that id lives is a config-ownership decision, so it is
escalated on the board rather than guessed.

No behaviour change: comment only.

* style(e2e): satisfy prettier and eslint on the files this branch touched

`quality / Frontend Check (format)` was the one check this branch INTRODUCED
against `development` — prettier disagreed with two of my line breaks. Fixed by
running the repo's own `prettier --write` on exactly those two files, plus the
two eslint errors on files this branch added:

  - perfectionist/sort-imports — the register import must precede the manifest
    import in the new manifest/enum parity spec;
  - prefer-object-has-own — `Object.hasOwn()` in the l10n stub.

Re-verified after the change: `prettier --check "**/*.{js,ts,vue,css,scss}"`
reports "All matched files use Prettier code style!", eslint on the four
touched/added files is silent, and both new vitest specs still pass 7/7 —
including the manifest guard's positive control, so the reformat did not turn
the instrument off.
…ve defaults it did not reach

#536 landed the same two diagnoses independently: the Organisations index
filtering on values #520 translated away, and the SBOM provenance computed
whose declaration and reader disagreed. Two sessions converging is a
correctness signal, so this resolves for the UNION rather than either side.

TOOK THEIRS, because each is strictly stronger:

- `SbomComponentsPanel.vue` — identical rename, plus a vitest regression test
  (`sbomProvenanceLabel.spec.js`) that fails if the producer/consumer pair
  drifts again. Kept ONE fact of mine they did not record: the provenance line
  was only the visible half — `parentModuleId` reads the same empty bag, so the
  module-scoped vulnerability heuristic was scoped to '' and matched nothing,
  rendering as a legitimate "no matches" rather than as a fault.
- `src/manifest.json` `_note` — theirs carries the live measurement
  (`?status[]=Draft&status[]=Active` returns the seeded row;
  `?status[]=Concept&...` returns total=0). Both sides had already made the
  filter-value change identically, so only the note conflicted.
- `dashboard.spec.ts` / `index-pages.spec.ts` / `organisatie-crud.spec.ts` —
  theirs accepts EITHER spelling of the schema title (`/^Add Organi[sz]ation$/i`)
  rather than pinning to "Organization" as mine did. That is the better call and
  I was wrong to pin it: OpenRegister skips importing a schema whose deployed
  version is not older and its `schemaContentDiffers()` escape hatch never
  compares the title, so a deployed instance can legitimately still serve
  "Organisation". Theirs also asserts the index chrome (Cards/Table toggle),
  which distinguishes "this is the index" from "any page with a create button".
- `gemma-faceted-search.spec.ts` — theirs copies before sorting
  (`[...(body?.supportedSchemas ?? [])].sort()`), so the assertion does not
  mutate the response body. Mine sorted in place. Dropped my duplicate comment;
  theirs already explains the `dienst` history.

KEPT MINE, because #536 does not contain it:

- **Five of the six schema `default`s that sit outside their own enum.** #536
  fixed `organization.status` only. `usage.status` ('In productie'),
  `connection.status` ('in gebruik'), `connection.integrationType` (a template
  emitting extern/intern), `module.type` ('Applicatie') and
  `moduleVersion.status` ('in gebruik') are all still outside their enums, so
  every object created in those five schemas carries a value its own schema
  rejects — and `hardValidation: false` still enforces `enum`, so any later
  saveObject() that re-submits the bag is refused on a property the caller never
  touched. Their four version bumps came with it; #536's covers organization.
  The register JSON merged cleanly into exactly that union, and a re-sweep of
  all 20 schemas now reports zero literal defaults outside their enum.
- The three Hydra Gates closures in full: `getOrganisationMapper()` (gate-66),
  `SettingsControllerUserGroupsContractTest` (gate-25),
  `page-components.ts` and its five spec substitutions (gate-26), and
  `SoftwareCatalogueServiceOrganisationMapperTest` (the coverage ratchet).
  #536 touches none of these.

Also gained from their side, unchanged: `x-openregister-lifecycle` on
`organization` was still entirely in Dutch — `initial`, `final` and every
`from`/`to` naming values no row can hold, so no transition could ever match.
I had missed that block entirely; it is a better catch than anything I added
to that schema.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 679b87f

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-17 00:02 UTC

Download the full PDF report from the workflow artifacts.

fix: close the last three Hydra Gates and the five E2E failures
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ bb12898

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-17 00:43 UTC

Download the full PDF report from the workflow artifacts.

…t does not carry it

`src/manifest.json` binds Standaarden + StandaardDetail to
`register: "@resolve:voorzieningen_register"` with `schema: "element"`, but
`lib/Settings/softwarecatalogus_register.json` attaches `element` to the SECOND
register it declares — `vng-gemma` (title "AMEF") — and not to `voorzieningen`.

Declaring a schema is not attaching it. Only an attached schema is fetchable
through `/api/objects/{register}/{schema}`, and OpenRegister's 2026-08-16 change
to `ObjectService::setSchema()` turned a register-scoped slug miss from a silent
fallback into a throw. Measured from the CI Playwright trace of run 31981873526:

    GET /api/objects/14/element?_limit=20&_page=1&gemmaType=standaard&_facets=extend
      -> 404 {"message":"Schema not found: 'element'"}

Attaching `element` to `voorzieningen` was considered and rejected: the request
would then succeed and return an EMPTY list, because objects live per register
and AMEF elements are written to the AMEF one. That trades a visible error for
an invisible pass.

The fix points the pages at the register that carries the schema, through a
second `@resolve:` sentinel. `amef_register` is provisioned in
`Application::boot()` from the `amef_config` blob written by
`SettingsService::configureAmef()`, exactly as `voorzieningen_register` is from
`voorzieningen_config`. configureAmef() detects its register by the PRESENCE of
the AMEF core schemas rather than by slug, which is the property this sentinel
needs: whatever it selects carries `element` by construction.

The nested `st-compliance` object-list on StandaardDetail deliberately keeps
`@resolve:voorzieningen_register` — `compliancy` really does live there.
… rows

Repointing the page removes the console error. It does not prove the page works
— a repointed page with no rows is quiet, renders "No items found", and passes
every surface assertion in the suite. That is the invisible pass the register
fix was chosen to avoid, so the test has to go past "the error is gone".

ci-seed.sh:
  * requires `vng-gemma` alongside `voorzieningen`. It was unchecked, so an
    import producing only one register reported a clean seed.
  * resolves the AMEF register from the app's own `/api/amef/config`, i.e. the
    same value the `@resolve:amef_register` sentinel resolves to, and fails
    loudly when it or `element_schema` is unset.
  * probes `/api/objects/<amef>/element` — the request the PAGE makes. Verifying
    a slug is present in /api/schemas is a different question from whether it is
    attached to the register you are addressing, and only the second one decides
    whether the endpoint answers. This is the check whose absence let the defect
    ship.
  * seeds two `element` objects, idempotent by `identifier`: `Digikoppeling`
    (gemmaType `standaard`) and `Zaakregistratiecomponent` (gemmaType
    `referentiecomponent`). GEMMA elements normally arrive via the ArchiMate
    import of GEMMA_release.xml, which no CI job runs.
  * verifies them with a FRESH read (never the save response, which echoes back
    properties OpenRegister discarded) under three guards: at least one
    standaard; a nonsense gemmaType matching zero; and strictly fewer standaards
    than elements, so the page's filter has something to exclude.

All three guards were demonstrated able to fail against a live instance:
deleting the referentiecomponent trips the third, deleting both trips the first,
and the nonsense-value control was measured at 0 with the positive control at 1
of 2.

index-pages.spec.ts now asserts a POPULATED list ("Showing N of M", which
CnIndexPage renders only for a non-empty collection), the seeded standard by
name, and the ABSENCE of the seeded referentiecomponent. The absence assertion
has a real subject: that row exists in the same register and schema, is listed
by an unfiltered page, and the seed fails the job if it is missing — so a zero
means the filter worked, not that the string never existed.
…es the schema

The defect this PR fixes was invisible to every static check in the repo. The
manifest validator checks the value's SHAPE; the gate package's manifest
cross-reference deliberately skips sentinels (its `isLiteralSlug()` excludes any
value containing `@`); and nothing at all compares a page's `(register, schema)`
pair against `lib/Settings/softwarecatalogus_register.json`. It took an E2E run
and a Playwright network trace to see a 404.

This closes both holes from the repository's own files:

  1. every `@resolve:<key>` register sentinel in the manifest is provisioned by
     `Application::boot()` — an unprovisioned one substitutes null and the page
     fetches `/api/objects/null/<schema>`;
  2. every `(sentinel, schema)` pair names a register that ATTACHES that schema.

The sentinel -> register-slug map is declared in the test on purpose: nothing in
the app declares it (the ids are discovered at runtime by configureVoorzieningen
/ configureAmef), so an unmapped sentinel FAILS rather than being skipped. A new
sentinel has to be a decision, not a silent gap.

Both checks were shown able to fail before being committed: reverting the
manifest to `@resolve:voorzieningen_register` fails check 2 with the register's
actual schema list quoted in the message, and renaming the provisioned
initial-state key fails check 1. A third test is a standing positive control on
the fixture itself — it asserts `element` is declared, is NOT attached to
voorzieningen, and IS attached to vng-gemma, so check 2 passing cannot be
explained by every register listing every schema.
fix(e2e): the Standards pages read `element` from a register that does not carry it
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 1c8a5b6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-17 08:11 UTC

Download the full PDF report from the workflow artifacts.

…duction/* exclude (#541)

This app's composer entry already had a cooldown block, but with
default-days: 1 (below the fleet floor of 2) and no exclude at all — a
fresh conduction/* release would have waited the same as any third-party
package instead of being exempt. Brings it in line with the fleet-wide
floor gate-93 (composer-cooldown-config) enforces, and with this file's own
npm entry which already excludes @conduction/*.

See ConductionNL/hydra openspec/changes/composer-dependency-cooldown and
ADR-093 (proposed, ConductionNL/hydra#591).
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/softwarecatalog @ 560310e

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
composer ✅ 130/130
npm ✅ 704/704
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-17 11:08 UTC

Download the full PDF report from the workflow artifacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants