Skip to content

Release: merge development into beta - #770

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

Release: merge development into beta#770
github-actions[bot] wants to merge 14 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 Bot and others added 4 commits August 31, 2026 10:29
The 0.2.6-beta.20260831102721 release bumped the version on beta. Without this,
development stays behind beta and the next development -> beta promotion
conflicts on the version file.

Version files resolve to development's side, which is the higher line,
so this never moves a version backwards.
Dependabot cannot propose composer updates for this app. Its updater fails
with:

  Your requirements could not be resolved to an installable set of packages.
    - edgedesign/phpqa[v1.27.0, ..., v1.27.2] require ext-xsl * ->
      it is missing from your system.

config.platform pins php 8.3 so composer resolves against a known PHP version,
but says nothing about extensions. edgedesign/phpqa requires ext-xsl and the
resolving environment does not have it, so the resolve fails before any bump
can be computed.

CI is unaffected, which is why this went unnoticed: composer install replays
the committed lock and never re-resolves, so the pipeline stays green while
dependabot -- which does re-resolve -- fails every time. The shared quality.yml
installs no xsl extension anywhere and never invokes phpqa.

Declaring ext-xsl beside the php pin makes resolution assume exactly what the
committed lockfile already assumes. Verified in a clean composer:2 container
without --ignore-platform-reqs: the same file fails without this line and
resolves (103 installs, lock written) with it.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…2.6-beta.20260831102721

chore(release): sync beta back into development
Levels this app with the fleet. 2.27.2 adds two fixes the earlier 2.27.0 pin does
not carry:

  * headerless is no longer chromeless — a flat KPI card in a borderless wrapper
    had no card, border or background at all;
  * a stat `variant` paints from the `-text` tokens rather than the fill tokens,
    which failed WCAG AA at 1.08:1 as a foreground colour. The KPI colour
    cleanup converted hardcoded values to `variant`, so this is what makes those
    conversions contrast-safe.

Lockfile only, and npm pruned nothing.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ a05f93d

Check PHP Vue Security License Tests
lint ⏭️
phpcs ⏭️
phpmd ⏭️
psalm ⏭️
phpstan ⏭️
phpmetrics ⏭️
eslint ⏭️
stylelint ⏭️
build ⏭️
composer ⏭️ ⏭️
npm ⏭️ ⏭️
app:check-code ⏭️
info.xml ⏭️
REUSE ⏭️
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-31 11:45 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 10e52a2

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-31 12:49 UTC

Download the full PDF report from the workflow artifacts.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 13e3f84

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-31 14:46 UTC

Download the full PDF report from the workflow artifacts.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rubenvdlinde <rubenvdlinde@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 40bc275

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-08-31 21:15 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 2 commits September 1, 2026 07:18
gate-60 reported 6 Tier B warnings, three concepts duplicated across the
real and mock register. Four adopted, two refused. 6 -> 2.

  Competency  TargetVariant  -> MedalOutline
  Course      FolderOutline  -> BookOpenPageVariantOutline

Course was the clear one: a course drawn as a plain folder said nothing
about what it is. A book does.

REFUSED: Order, which the gate wants on ClipboardListOutline. Its own
description settles it:

  "The payer-facing request for payment: payer (guardian/learner/employer),
   beneficiary learner, total, currency, due date, and a lifecycle
   draft -> open -> partially-paid | paid"

That is a payment request, not a task list. CartOutline reads as a purchase,
which is what enrolling in a paid course is; a clipboard checklist would
read as work to be done. It stays, as a non-blocking WARN.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ f1cac33

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 05:36 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 151fc2f

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 06:19 UTC

Download the full PDF report from the workflow artifacts.

…am (#777)

* chore(register): rename application to admission and assessment to exam

Two slug collisions.

`application` was claimed by three apps meaning three different things: an
app built with buildiq, a job application in humaniq, and this one, an
aanmelding, the pre-enrolment intake path. Stackiq means it a fourth time
under the slug `module`. `admission` says which one this is.

`assessment` was claimed by stackiq too, where it rates software. This one
is a toets, tentamen or examen composed of items from an ItemBank, with a
scoring scheme and an attempt policy. The two share NO properties at all.
`exam` says which one this is.

Eight sites beyond the two registers: AssessmentGradeGuard,
AssessmentScoringHandler, CoursePackageExportService,
LearniqJsonCourseImporter, and four manifest bindings.

* fix(register): follow the admission and exam slugs in every constant

The first pass matched the literal `schema:` and `$ref` shapes and missed
the constants, which is where most of this slug actually lives: ten
private/public *_SCHEMA constants across guards, listeners, loaders and
services each held the bare old slug.

A constant that still names a retired slug fails the way slugs always fail
here, by resolving to nothing rather than by throwing.

RenameDutchColumns::COLUMN_MAP maps a database COLUMN (beoordeling to
assessment), not a schema slug, and is untouched.

* test(admissions): pin the guard to the admission slug

* fix(manifest): follow the exam slug in its capitalised bindings

gate-53 crossref named three widgets binding schema 'Assessment'. The
manifest used the schema's PascalCase dict key while the register declared
the lowercase slug, and case-insensitive resolution had been quietly
covering the difference. Renaming the slug to `exam` removed that cover and
the three widgets stopped resolving.

Also moves the AssessmentDrawResolver and LessonReleaseController test seeds
to the new slug: seed() keys its fake db by schema.

* test(register): follow admission and exam through every fake keyed by schema

Twelve unit tests failed on the stable34 cell because their fakes index by
schema slug: OrEntityFactory::make(..., $schema), seed($schema, ...),
$fixtures[$schema], and the getSchema() stubs the listeners read. All of
them still named the retired slugs, so the listeners under test resolved
nothing and the assertions saw empty sets.

tests/e2e/seed-example-data.mjs seeds the Playwright fixtures through the
object API, which resolves by slug, so it moves too.

* test(release): pass the exam slug as itemSchema, and undo one bad rename

LessonReleaseEvaluator compares its itemSchema argument against
ASSESSMENT_SCHEMA, so the two callers in the test had to move with the
constant. The export test's row map is keyed by schema and moves too.

Reverts one line the shape-based sweep got wrong: 'assessment' in
PortalContributionProviderTest's whitelisted FIELDS list is a property name
on the werkproces record, not a schema. That is what
testPraktijkopleiderActionsAreDirectScopeStampedAndWhitelisted was telling
me.

* docs(release): the itemSchema docblock still named the old slug

---------

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 89c006d

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 07:50 UTC

Download the full PDF report from the workflow artifacts.

…se slug (#781)

Development E2E caught this, which is what it is for:

  admissions review board page renders without a fatal error
  Error: unexpected fatal errors: [AdmissionsReviewBoard] loadData error
         Error: Application fetch failed: 404

AdmissionsReviewBoard fetched objects/learniq/Application and
TakeAssessmentView fetched objects/learniq/Assessment. Both name the schema
in the URL with the register's PascalCase DICT KEY rather than the slug, and
the resolution had been case-insensitive enough to cover the difference
until the slugs became admission and exam.

Every earlier sweep for these URLs was anchored on a lowercase slug, so
neither was ever in scope. The audit is now case-insensitive.

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ b43ba15

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 08:46 UTC

Download the full PDF report from the workflow artifacts.

`npm run lint` was `eslint src`, so two whole trees were never linted. Across
the fleet that hid roughly 3,900 errors, none of which any CI leg had shown.

Most of it was the config, not the code, and the same two defects were in
every app.

**scripts/ had no config block at all.** These are CommonJS Node CLI checkers,
and flat config defaults every `.js` to ESM with browser-ish globals, so eslint
read the CommonJS wrapper itself as undefined identifiers: `require`,
`process`, `__dirname`, `__filename`, `module`. A `scripts/**` block now
declares the environment. Declaring beats suppressing here: `no-undef` is the
rule that catches a genuinely misspelled identifier, and dozens of fake
findings would bury a real one. A second block covers `scripts/**/*.mjs`, which
is ESM and needs Node's globals without the CommonJS wrapper.

**The tests block applied a non-TypeScript-aware rule to TypeScript.** It named
`tests/**/*.ts` while setting the CORE `no-unused-vars`, which v9 deliberately
turns off for `.ts` in favour of the `@typescript-eslint` version. The core
rule reads the parameter names inside a function TYPE as bindings, so

    t?: (app: string, key: string) => string

reports `app` and `key` as unused variables, and every unused `catch (e)` in a
`.ts` spec reports twice. The block is split now: `.js`/`.mjs` on the core
rule, `.ts`/`.tsx` on the TypeScript one, same patterns on both.

Also: stale `eslint-disable` comments naming plugins eslint 10 no longer
registers, which are themselves errors ("Definition for rule ... was not
found"), and a rule that must not parse shell scripts.

The genuinely real findings were the useful part: dead locals, unused imports,
dead helper functions, unused `catch` bindings, extensionless relative imports,
and a handful of `== null` comparisons spelled out so they still match null AND
undefined.

Verified per app: `npm run lint` 0 errors over src + tests + scripts,
`prettier --check` clean, and the unit suite still green.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ ece045d

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 10:57 UTC

Download the full PDF report from the workflow artifacts.

#786)

The signing-key rotation test died at:

  TypeError: expect(...).toBeVisible(...).waitForRequest is not a function

page.waitForRequest had been chained onto the assertion:

  await expect(rotateBtn)
      .toBeVisible()
      .waitForRequest(...)

expect().toBeVisible() resolves to undefined, not to the page, so the chain
threw and the test died before ever clicking Rotate. It was never testing the
rotation it is named for.

waitForRequest also has to be armed BEFORE the action that triggers the
request, or it waits for one that has already gone. So the promise is created
first, the click follows, and the promise is awaited after.

Verified by running it against a live instance rather than by reading:
`playwright test -g rotating-the-signing-key` now reports 1 passed. Before,
`playwright test --list` could not even collect the file.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 9d69429

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 13:27 UTC

Download the full PDF report from the workflow artifacts.

Nextcloud serves an app under both /apps/learniq/... and
/index.php/apps/learniq/..., but generateUrl() returns only the form the
instance is configured for. Used as the vue-router base, that means a visitor
arriving on the other form has a pathname the router cannot strip its base
from. No route matches, the catch-all takes over, and they land on the
dashboard with no error at all.

Measured on a live instance, across all 282 routes: /apps/learniq/courses
resolves to Courses, /index.php/apps/learniq/courses resolved to the dashboard.
Not one broken page, every deep link in that URL form.

routerBase() derives the base from the pathname, so it always matches the URL
the visitor actually arrived on. openregister, opencatalogi, stackiq, larpinq,
zaakafhandelapp, pipelinq and keepiq already do exactly this.

pages.spec.ts could not have caught it. Its route table addressed every page as
'#/courses', a fragment the history router never reads, so all 24 cases loaded
the dashboard and asserted the dashboard was fine. Both of its assertions, a
non-blank body and no console errors, hold there. The paths lose the '#' and
the test now asserts the URL is the route it asked for, which is the check that
keeps this fixed. /settings was in that table and is not a route; it is dropped.

Verified live: 23 passed, against 1 passed and 23 failed before the router fix.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ adf1462

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-01 17:33 UTC

Download the full PDF report from the workflow artifacts.

… inside (#790)

its own card.

⚠️ THE CAUSE IS AN INSET, NOT A COMPONENT. A card widget renders `flush` and
then has its padding put BACK by the card-fit rule (`padding: 8px 14px`), so
the KPI sits inside the wrapper while the WRAPPER draws the border, radius
and background the user reads as "the card". The library's
`--clickable:hover` rule then drew a 2px border and a drop shadow on the KPI
itself, 8-14px in from the edge being hovered.

Measured live on dossiq, while genuinely hovered: the tile carried a 2px
rgb(0,103,158) border and its own shadow, inset 9px from the wrapper's top
and 15px from its left. A non-card-fit tile sits at 1px, so its border lands
on the wrapper's own edge and reads as one card. That inset is the whole
difference, which is why it looked app-specific and was not.

nextcloud-vue#932 moves the affordance to the wrapper. No layout change:
nothing moves, one card outlines. Verified in the browser with a real pointer
hover:

  before   inner 2px rgb(0,103,158) + shadow   wrapper grey, no shadow
  after    inner transparent, no shadow        wrapper rgb(0,103,158) + shadow

Every app with clickable stat, gauge or delta tiles had this. This bump is
one of the fleet sweep that clears it.

Dependency change only: package.json and the nextcloud-vue entry in
package-lock.json.

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

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/learniq @ 0dc140c

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
format
check-l10n-js
check-schema-l10n
composer ✅ 104/104
npm ✅ 637/637
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright
Hydra gates

Quality workflow — 2026-09-02 19:14 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.

1 participant