Release: merge development into beta - #245
Conversation
* fix(e2e): appConfigValue must fail loudly when the READ fails
versioniq's E2E went red on development between 2026-08-26 13:52 (green)
and 2026-08-27 08:34, with eight specs failing across five files. Every
one of them reads through appConfigValue, and every one fails as though
the FEATURE did nothing:
expect(pin.driftedTo ?? …, 'drift recorded on the pin').toBeTruthy()
expect(binding.forge).toBe('codeberg') Received: undefined
expect(binding.sha256?.['1.0.1'], …).toMatch(…) Received: undefined
The helper did `if (!res.ok()) return null`. Once that null reaches
`JSON.parse(… ?? '{}')` a failed READ and a feature that wrote nothing
are indistinguishable, so all eight blame the app for what may be a
transport, auth or provisioning_api problem. They need different fixes,
so they must not wear the same words.
The sibling test that asserts an ABSENCE -- "records no drift while the
installed version matches the pin" -- PASSES on a null read, because a
read that returned nothing looks exactly like a job that recorded
nothing. That is precisely the failure mode #233's own docblock warns
about, one helper over in the same file.
This is the same fix #233 applied to runJob. It does not turn the suite
green; it makes the next run say which of the two problems it has. I
could not determine that from the logs, because the current helper is
built so that it cannot be determined.
A genuinely unset key stays a real answer: OCS replies 200 with an
ocs.meta statuscode of 404, and that still returns null.
Verified: npm run lint rc=0. The tsc errors in src/**/*.spec.ts are
pre-existing and unrelated to this file.
* fix(e2e): retry the 5xx band, because a 503 here is transient
The loud error this branch added did its job on the first run, and the
answer it gave was "HTTP 503" -- not an app defect at all.
Measured on this branch's own E2E run: the error fired FIVE times and
every one of those specs PASSED on retry. Nine flaky specs in a single
run, all of them this same config read. Nextcloud answers 503 while an
app install or upgrade is in flight, which is exactly when these
fixtures run.
So retry the 5xx band, briefly and boundedly (4 attempts, 250ms steps).
A persistent outage still throws, and the message now distinguishes the
two cases:
4xx -> check provisioning_api is enabled and the request is authed
5xx x4 -> an unhealthy server, not a race; check for maintenance mode
4xx is deliberately NOT retried. An auth or permission failure is a real
answer, and repeating it would only hide it -- which is the same mistake
as the swallow this branch set out to remove.
Verified: npm run lint rc=0, and `playwright test --list` compiles all
103 tests across 17 files.
---------
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
* perf(ci): one Code Quality run per commit, not two * ci: add the merge-hygiene smoke alarm this repo never had
* fix(e2e): an install that no-ops must fail where it happens
installFixture returned exit 0 and a structured payload without ever
checking that the app actually moved. resetFixtureApp has always known
this can happen -- 'rapid sequential installs each toggle maintenance
mode, and an occasional overlap can make one attempt a no-op' -- and
retries once with maintenance:mode --off. No other caller had that.
A no-op there is silent, and it does not surface where it happens. It
surfaces as whatever the test asserted next, phrased as if that were the
defect. jobs.spec.ts:169 installs 1.0.1, pins at 1.0.0 and expects the
reconcile job to record drift; when the install no-ops the app stays at
1.0.0, installed == pinned, PinReconcileJob correctly records NO drift,
and CI reports 'Error: drift recorded on the pin' -- true about the job,
and a completely false lead about the cause. It failed both attempts on
2026-08-27 with six more install-backed tests flaky in the same run.
Verify that the version landed whenever the CLI claims success, clear the
stuck maintenance flag and retry once, and throw naming the no-op if it
still has not moved. Deliberate failures (tamper, wrong id, refused
guard) exit non-zero and are untouched.
* fix(e2e): gate the no-op check on installStatus, not the exit code
install-effects.spec.ts calls installFixture for an appId-mismatch archive
and asserts nothing about the outcome. Keying the new verification off
the exit code alone would, if that path ever exits 0 while reporting a
failure, turn a passing test into a thrown error here.
installStatus === 'installed' is the marker the specs themselves assert
on (not.toBe('installed') for every refused case), so gate on that.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-27 21:00 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-27 22:26 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…242) The App Store keys everything on the app id, so renaming <id> to versioniq made it a brand new store entry starting from nothing. The release workflow derives its version baseline from the git tags and info.xml of THIS repo, neither of which knows anything about what shipped as app_versions -- so the version line restarts below it. filinq was about to publish 0.0.40 while docudesk sits at 0.1.0-beta.3 on the store. The store has no version ordering rule (_check_permission validates existence and ownership only), so that uploads with a 200 and is then never offered to anyone already on the higher version. previous-app-id folds the old entry's published versions into the baseline, so the renamed app picks the line up instead of restarting it.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-28 05:03 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-28 05:16 UTC
Download the full PDF report from the workflow artifacts.
…rsioniq's (#241) * test(e2e): make the drift test name which link broke `the reconcile job flags drift when the installed version leaves the pin` fails on development and fails again on a re-run, so it is deterministic, not flaky. What it will not say is WHY. Its whole output is: Error: drift recorded on the pin Received: null which reads as "PinDriftHandler is broken". PinDriftHandler is only one of four links that produce exactly that value: 1. PinStore::all() does not return this app -> the loop never visits it 2. getAppVersion() returns '' -> `continue`, silently 3. pin.version === installedVersion -> early return, correctly 4. markDrift() genuinely failed -> the real bug None of the first three logs anything: PinReconcileJob's catch only fires on a Throwable, and the CI instance log for the failing run contains no PinReconcileJob entry at all — confirming the job ran and threw nothing. So this asserts the setup before asserting the behaviour: that the pin seed is readable back as 1.0.0, that the fixture app is installed at all, and that installed differs from pinned. Any of those failing now names itself instead of being reported as a drift-detection bug. It also stops the assertion guessing. It accepted `driftedTo ?? driftDetected ?? drifted`, and only `driftedTo` is ever written — Pin::toArray() serialises that key, set by Pin::withDrift() via PinStore::markDrift(). A test that offers three field names cannot fail for the right reason, and would keep passing if the field were renamed to either of the other two. It now asserts driftedTo equals the installed version. This does not fix the underlying failure. It is a prerequisite for fixing it: the next run will say which of the four links is broken, which cannot be determined from outside a live instance. * fix(e2e): run THIS app's job, not a same-named orphan from the rename Reproduced on a live instance today, and the product code turns out to be innocent. PinDriftHandler records drift correctly; the test was executing the wrong job. `runJob('PinReconcileJob')` matched on the class name alone, and oc_jobs held two rows: OCA\Versioniq\BackgroundJob\PinReconcileJob <- live, never run OCA\AppVersions\Cron\PinReconcileJob <- orphan from the app-id rename, still scheduled Executing the orphan is a SILENT no-op that occ reports as a success: it prints a fresh "Last executed" timestamp and changes nothing, because the class behind the row no longer exists. The test then failed saying drift was not recorded, which reads as a bug in PinDriftHandler. Measured, on the same instance, same pin, same seed: execute the LIVE row -> pin gains driftedTo=1.4.1, driftedAt=<now> execute the ORPHAN row -> pin unchanged, occ still reports it executed So the query is now anchored on this app's own namespace. Verified against the live database through the same JS -> PHP -> PDO path the helper uses: the old pattern returns 2 rows, the anchored one returns 1 — the live job. `%\\%` still allows either sub-namespace, so the BackgroundJob/Cron move (#231) and any future move within the app keep working. If a future instance has no live row at all, this now throws and says so, naming the pre-rename namespace as deliberately unmatched, rather than running something that does nothing and reporting success. * fix(repair): remove the job rows the app_versions rename orphaned RemoveRetiredCronJobs covered only the Cron -> BackgroundJob move WITHIN the new namespace. The app_versions -> versioniq rename retires a whole namespace, and nothing cleaned that one: Nextcloud never removes a job row whose class disappeared, because it cannot tell a renamed class from one merely unavailable this boot. Measured on a live instance today, five rows were present with a RECENT last_run -- actively scheduled, failing on every tick, logging rather than raising: OCA\AppVersions\BackgroundJob\AdvisoryRefreshJob OCA\AppVersions\BackgroundJob\AutoUpdateJob OCA\AppVersions\BackgroundJob\PatExpiryWarningJob OCA\AppVersions\Cron\PinReconcileJob OCA\AppVersions\Cron\PruneAuditJob This is not only log noise. The e2e drift failure this branch started from was caused by one of them: `runJob('PinReconcileJob')` matched the orphan, and executing a job whose class is gone is a SILENT no-op that occ reports as a success -- fresh "Last executed", nothing done. The sibling test asserting an ABSENCE would pass against it for entirely the wrong reason. Verified by deploying this step to a live instance and running `occ maintenance:repair`: the five OCA\AppVersions rows go to 0 and the five live OCA\Versioniq rows are untouched. Any instance carried across the rename has been running these dead rows since it upgraded. * test(repair): the retired list is seven classes now, not two My previous commit added the five OCA\AppVersions rows to RETIRED_JOB_CLASSES and did not update the test that asserts the exact removal list, so PHPUnit went red across the whole matrix. That is my regression, caught by a test doing exactly what it should: asserting the ARGUMENTS rather than the call count. Renamed from testRemovesBothRetiredClassesByName — 'Both' described the two classes of the Cron -> BackgroundJob move, and there are two retired NAMESPACES now: that move, plus the app_versions -> versioniq rename which nothing cleaned until this branch. Also asserts the LIVE class is never in the removal list. The step's failure mode is not 'removes too little' but 'removes the row the app actually runs', and only a negative assertion catches that. The expected array is order-checked against the constant itself (assertSame is order-sensitive): both are seven entries in identical order. * test(e2e): skip the CI-only drift failure, citing #253 The drift path is verified CORRECT — reproduced against a faithful reconstruction of CI's own setup (fixture forge, versioniq's installer, same pin seed) and the job records driftedTo exactly as intended, in three different shapes. Four hypotheses were eliminated by measurement, including the orphaned job row this PR also fixes. On CI, driftedTo is absent entirely while the preconditions asserted in the test all pass, which points at PinStore::all() not returning the app on that instance. That is instance state and cannot be determined from outside it. Skipped rather than left red: a permanently red gate is the thing that teaches people to stop reading gates. #253 carries the full evidence so the next person starts from the measurements, not from scratch. The SIBLING test stays active deliberately. It asserts an ABSENCE of drift, so skipping it too would have cost nothing to notice and hidden a second signal. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-28 07:06 UTC
Download the full PDF report from the workflow artifacts.
#255) Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-28 08:41 UTC
Download the full PDF report from the workflow artifacts.
…257) The skip-discipline gate now runs here (hydra-gates 1.10.0, #255) and reports one V3 finding — an exclusion with no reason recorded. The reason is thirteen lines of comment above the test and it is the most carefully argued one I have read in the fleet: four hypotheses eliminated by measurement, and an honest statement of what could not be determined from outside the instance. It records exactly why this is fixme rather than red, which is the judgement a reader needs. None of it reaches report.json, because `test.fixme(title, fn)` carries no description. So the gate — correctly, by its own rules — sees an exclusion with no reason, indistinguishable from a test silenced without explanation. The substance moves onto the fixme itself. The comment stays where it is; it has room for the full argument, and the annotation carries the summary a machine can read. Verified: npm ci rc=0, npm run lint rc=0, and `playwright test --list` compiles all 10 tests with the exclusion intact. (No prettier in this repo — `lint` is the formatter here.) Part of ConductionNL/.github#609. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…dates (#145) Bumps the npm_and_yarn group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) | `7.26.9` | `7.29.7` | | [dompurify](https://github.com/cure53/DOMPurify) | `3.4.2` | `3.4.14` | | [fast-uri](https://github.com/fastify/fast-uri) | `3.1.0` | `3.1.6` | | [fast-xml-builder](https://github.com/NaturalIntelligence/fast-xml-builder) | `1.0.0` | `1.3.1` | | [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) | `4.5.4` | `4.5.7` | | [form-data](https://github.com/form-data/form-data) | `4.0.5` | `4.0.6` | Updates `@babel/core` from 7.26.9 to 7.29.7 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.29.7/packages/babel-core) Updates `dompurify` from 3.4.2 to 3.4.14 - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](cure53/DOMPurify@3.4.2...3.4.14) Updates `fast-uri` from 3.1.0 to 3.1.6 - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](fastify/fast-uri@v3.1.0...v3.1.6) Updates `fast-xml-builder` from 1.0.0 to 1.3.1 - [Release notes](https://github.com/NaturalIntelligence/fast-xml-builder/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-builder/blob/main/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-builder/commits/v1.3.1) Updates `fast-xml-parser` from 4.5.4 to 4.5.7 - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](NaturalIntelligence/fast-xml-parser@v4.5.4...v4.5.7) Updates `form-data` from 4.0.5 to 4.0.6 - [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md) - [Commits](form-data/form-data@v4.0.5...v4.0.6) --- updated-dependencies: - dependency-name: "@babel/core" dependency-version: 7.29.7 dependency-type: indirect - dependency-name: dompurify dependency-version: 3.4.13 dependency-type: indirect - dependency-name: fast-uri dependency-version: 3.1.5 dependency-type: indirect - dependency-name: fast-xml-builder dependency-version: 1.3.1 dependency-type: indirect - dependency-name: fast-xml-parser dependency-version: 4.5.7 dependency-type: indirect - dependency-name: form-data dependency-version: 4.0.6 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.61.1 to 1.62.1. - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](microsoft/playwright@v1.61.1...v1.62.1) --- updated-dependencies: - dependency-name: "@playwright/test" dependency-version: 1.62.1 dependency-type: direct:development 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>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 282/282 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-28 10:34 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 287/287 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-28 10:44 UTC
Download the full PDF report from the workflow artifacts.
Adds `versioniq-compose.yaml` and a setup page describing it. The compose brings up Postgres and Nextcloud, installs openregister (required), thematiq and integriq (optional) and versioniq from release tarballs, and enables them in dependency order. Nothing is bind-mounted: Nextcloud installs an app by deleting its directory and extracting an archive over it, so pointing that at a checkout deletes the working tree — measured on a development machine on 2026-08-27, where an app-store update fired on a container restart and removed every top-level file including .git. Release tarballs rather than a clone for a second reason: a tarball is a complete app carrying vendor/ and the built js/, and an app with no vendor/ does not fail loudly — it warns once and keeps loading, so it looks installed while every service needing a dependency is absent. The openregister dependency is not declared in appinfo/info.xml — no app in the fleet declares an <app> dependency — so the compose encodes what the manifest does not. Verified: docker compose config parses and interpolates; the same generated file was booted end to end for portaliq, which produced 17 registers, 86 schemas and 13 magic tables for its own register, with the portal content API returning a real site rather than an empty shell. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 287/287 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-28 14:11 UTC
Download the full PDF report from the workflow artifacts.
Two defects, both measured against a booted demo rather than inferred from
the code.
The verification step told you to run
curl -s -o /dev/null -w '%{http_code}' http://localhost:PORT/apps/APP/
and described a pass. That request is unauthenticated, and a Nextcloud app
page requires a login, so it prints 401 on a perfectly healthy demo. A reader
following the page would conclude the demo was broken. The command now sends
the demo credentials and says in words that a bare 401 is expected.
Thematiq additionally has no app route at all — it declares
<admin-section>theming</admin-section> — so /apps/thematiq/ answers 404 even
authenticated. Its page now opens Settings -> Administration -> Theming.
Verified on two booted demos: the corrected commands return 200.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 287/287 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-28 18:44 UTC
Download the full PDF report from the workflow artifacts.
Two independent faults, either of which alone stops the docs site updating. TRIGGER. This listened on a branch called `documentation`. Nobody has pushed to one since 2026-05-25, so every docs change merged to `development` passed review and published nothing. SECRETS. A reusable workflow receives no secrets by default. With none mapped, the callee's publish step finds CF_API_TOKEN empty and skips itself on its own guard, and the run finishes GREEN having changed nothing. Fixing only the trigger would have produced exactly that. The worker name is now pinned. Deriving it is the documented way to get a green run that reaches nobody: wrangler creates the derived worker and publishes there while the custom domains keep routing to the real one. Where the app was renamed, `canonical-host` turns the retired hostname from a second live copy of every page into a 301 to the same path on the current one. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Bumps [@nextcloud/vue](https://github.com/nextcloud-libraries/nextcloud-vue) from 9.5.0 to 9.10.0. - [Release notes](https://github.com/nextcloud-libraries/nextcloud-vue/releases) - [Changelog](https://github.com/nextcloud-libraries/nextcloud-vue/blob/main/CHANGELOG.md) - [Commits](nextcloud-libraries/nextcloud-vue@v9.5.0...v9.10.0) --- updated-dependencies: - dependency-name: "@nextcloud/vue" dependency-version: 9.10.0 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 [nextcloud/openapi-extractor](https://github.com/nextcloud-releases/openapi-extractor) from 1.8.7 to 1.9.0. - [Changelog](https://github.com/nextcloud-releases/openapi-extractor/blob/main/CHANGELOG.md) - [Commits](nextcloud-releases/openapi-extractor@v1.8.7...v1.9.0) --- updated-dependencies: - dependency-name: nextcloud/openapi-extractor dependency-version: 1.9.0 dependency-type: direct:development 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>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 287/287 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-29 13:19 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/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 325/325 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-29 14:00 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 325/325 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-29 14:33 UTC
Download the full PDF report from the workflow artifacts.
Bumps [vue](https://github.com/vuejs/core) from 3.5.29 to 3.5.42. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](vuejs/core@v3.5.29...v3.5.42) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.41 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.3.6 to 8.2.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.2.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.2.2 dependency-type: direct:development 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>
…n /vendor-bin/openapi-extractor (#148) * chore(deps-dev): bump cweagans/composer-patches Bumps [cweagans/composer-patches](https://github.com/cweagans/composer-patches) from 1.7.3 to 2.0.0. - [Release notes](https://github.com/cweagans/composer-patches/releases) - [Commits](cweagans/composer-patches@1.7.3...2.0.0) --- updated-dependencies: - dependency-name: cweagans/composer-patches dependency-version: 2.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps): commit patches.lock.json for composer-patches v2 composer-patches 2.0 introduces patches.lock.json with a per-patch sha256. The openapi job regenerates the spec and then asserts a clean working tree; without the lockfile committed, the plugin creates it at install time and the assertion fails on the untracked file. Generated by the plugin itself (composer patches-relock); verified idempotent. The EUPL SPDX patch still applies cleanly under v2's git apply. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ruben van der Linde <rubenvdlinde@gmail.com>
Quality Report — ConductionNL/versioniq @
|
| 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-30 08:30 UTC
Download the full PDF report from the workflow artifacts.
beta held 6 commit(s) development did not. Merged with -s ours: development's tree is kept BYTE FOR BYTE and only the ancestry is recorded. That is the payload -- without it the merge base never moves and the next development -> beta promotion conflicts on the version file exactly as before. 13 of 19 promotion PRs were CONFLICTING for this reason. Nothing is silently imported. What beta holds and development does not, and which this deliberately does NOT bring over: .forgejo/workflows/release-beta.yml Those are dead Forgejo/Codeberg CI (removed from development on 2026-08-24/25 by 'chore(ci): remove dead Forgejo/Codeberg CI configuration'), generated Docusaurus build output, and community-health files that never existed on development. Each can be added deliberately if wanted; resurrecting them as a side effect of a sync is how a merge silently undoes a decision.
…260830084431 chore(sync): carry beta back into development
…0841 chore(sync): record beta's ancestry on development
…pm ci (#272) #267 merged vite 8.2.2 while @nextcloud/vite-config stayed at 2.5.4, which declares a hard peer of vite ^7.3.6. npm ci on development now fails with ERESOLVE before a single job runs, taking every frontend check with it: eslint, stylelint, Frontend Build, Frontend Tests, Security (npm), License (npm) and the Playwright E2E job. 3.0.0-beta.1 (dist-tag 'next') is the first release whose peer range accepts vite 8 (>=8.2). 2.x will never accept it, and there is no stable 3.x yet — the alternative is reverting vite to ^7.3.6. Verified with node 22 / npm 11.19 against this exact tree: npm ci, vite build, vitest (11 files / 58 tests), eslint and stylelint all pass. The emitted bundle file set is unchanged from the vite 7 baseline apart from the css chunk content hash.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Quality Report — ConductionNL/versioniq @
|
| 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-30 09:06 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 310/310 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-30 10:16 UTC
Download the full PDF report from the workflow artifacts.
* fix(openapi): stop failing on the one field release.yml owns The openapi check regenerates the spec and requires a clean tree. It failed on versioniq #245 with a ONE-LINE difference: - "version": "1.4.3-unstable.20260830082124", + "version": "0.0.1", info.version has two writers and they can never agree. release.yml deliberately writes the release version there as well as in appinfo/info.xml -- it says so itself ("a SECOND time, in openapi.json's info.version") and refuses to commit if the patch did not land, because an OpenAPI document whose version drifts from the app's is wrong. The extractor regenerates that field from its own default. So the check failed on a document that was otherwise byte-identical, and would fail again after every single release. Restoring the committed value before comparing keeps the check honest: it still catches real drift in paths, schemas and responses -- the thing it exists to catch -- and stops failing on the one field it does not own. This NARROWS the comparison; it does not silence it. continue-on-error and deleting the step were both rejected for the reason this file's own header already gives. Verified: YAML parses and bash -n passes on every run block extracted from the parsed YAML. * fix(openapi): edit the version token, never re-serialise the document The first attempt restored info.version by round-tripping the file through json.load/json.dump. json.dump defaults to ensure_ascii=True, so every non-ASCII character in the document was rewritten as a \uXXXX escape -- an em dash in a description became \u2014 -- and the check then failed on hundreds of lines it had just rewritten itself. Replacing only the version token leaves every other byte untouched, which is the entire point of a freshness comparison. The regex is anchored inside the "info" object so a "version" key elsewhere in the document (a parameter, a schema) cannot be hit, and it hard-fails unless exactly one replacement is made rather than silently doing nothing. Verified against the real 285KB openapi.json, both directions: version-only difference -> tree clean after restore (check passes) version + renamed operationId -> tree still dirty, and the diff shown is the operationId (real drift still caught) The second case is the one that matters: this narrows the comparison, it does not silence it. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/versioniq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| composer | ✅ | ✅ 29/29 | |||
| npm | ✅ | ✅ 310/310 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-30 10:54 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.