Skip to content

release: publish a stable NLDesign release with downloadable assets - #419

Merged
rubenvdlinde merged 607 commits into
mainfrom
beta
Aug 30, 2026
Merged

rubenvdlinde merged 607 commits into
mainfrom
beta

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Promotes beta to main so a stable release with tarball assets is published.

Why now

The demo composes for the Connext ecosystem install apps from GitHub release tarballs. NLDesign has stable tags (v1.0.0, v0.1.3) but no releases attached to them — GET /releases/tags/v1.0.0 returns 404 — so there is nothing to download and a demo compose cannot install it.

NLDesign is required for the OpenCatalogi demo: the seeded demo portal declares theme: opencatalogi, which NLDesign resolves. Without it the portal renders unthemed.

Scope

beta is 553 commits ahead of main and 12 behind, so unlike the Portaliq promotion this is a genuine merge rather than a fast-forward. Flagging that explicitly for review.

rubenvdlinde and others added 30 commits July 24, 2026 08:11
docs(openspec): archive icons-from-ncvue
…wave

The whole e2e suite has been non-functional: global-setup filled the login
form immediately after goto(), but Nextcloud's login is client-rendered
(Vue), so the inputs did not exist yet and EVERY run died in setup. One
waitFor() brings all 31 existing specs back to life (admin-settings: 17/17).

Adds browser coverage for the wave's features, which shipped with
'@e2e exclude covered by <PHPUnit>' annotations only:
- dark-mode: dark layer injected after the light one, dual-scoped so an
  explicit light choice is never darkened, toggle matches persisted state
- icon-assets-ncvue: the three nc-vue packs serve as valid SVG, a mapped
  legacy name still resolves, an unmapped Amsterdam-only name is 404, logos
  survive
- render-context-injection: logged-in / login (guest) / error renders are all
  themed in cascade order; the OCS capability publishes the huisstijl
  pre-login with a strict key allowlist
- admin-feature-panels: every wave feature has a REACHABLE admin panel
  (guards the orphaned-capability defect class), audit table headers,
  freshness opt-in default-off + egress host disclosed, font licence notice

Settings endpoints are CSRF-protected, so the specs fetch in-page with
OC.requestToken rather than through the raw request context (412 otherwise).
The instance-mutating toggle test is deliberately @e2e exclude'd with a
reason, matching the hide-slogan spec's existing convention for shared-env
mutation.

22/22 new specs green.
…ver break a flow

Found by the newly-revived e2e suite: uploading a custom token set succeeded
server-side, but the list never refreshed. Root cause is not the upload —
'OC.Notification' is undefined on Nextcloud 34 (toasts moved to OCP.Toast /
@nextcloud/dialogs), so every one of the 56 OC.Notification.showTemporary()
calls throws a TypeError. Sitting inside .then() handlers, the throw aborted
the REST of the handler, so loadCustomTokenSets() after a successful upload
never ran.

Adds a notify() guard (OCP.Toast → legacy OC.Notification → console) and
routes all 56 call sites through it; same guard in preview-banner.js. A purely
cosmetic notification can no longer break the functional flow it annotates.

Verified by direct browser probe: before, PAGEERROR + list stale; after, no
page error and the uploaded set appears. 453 PHPUnit, 36 vitest green.
test(e2e): revive the dead Playwright harness, cover the wave, and fix the NC34 toast bug it found
…anne, switchable icons

Deep-dive into La Suite's live Cunningham CSS produced hard numbers: our
shipped lasuite set transcribed only 37 of the 799 effective deployed tokens
(4.6%), though accurately (34/37 exact, 3 notation-only). Three ff changes:

- lasuite-token-completeness: generate all 1167 Cunningham tokens from
  @openfun/cunningham-tokens (MIT), reproduce the deployed VIOLET override
  (brand-600 #534fc2 / logo #4844ad — app-level only, sourced from the live
  bundle) as a separate layer, complete the NC --color-* bridge, prove
  per-component parity via computed-style e2e, and guard against drift.
- marianne-font-restricted: bundle the real Marianne woff2 (DSFR, Etalab-2.0)
  self-hosted, behind an admin acknowledgement gate (default OFF, Inter used)
  since Marianne is reserved for French state agencies — with a repo user
  agreement + licence + unmissable notice.
- theme-switchable-iconography: icon_pack per design system so a served
  government's icons swap with the theme (DSFR French gov icons, existing NL
  packs), NC stock when none.

Shell/chrome geometry deferred to #182.
…7-24

docs(openspec): La Suite pixel-parity wave (3 ff changes)
…et override, complete bridge coverage

Replaces the 4.6%-complete hand-transcribed lasuite defaults.css with a
re-runnable generator (scripts/generate-lasuite-tokens.mjs) that reads
@openfun/cunningham-tokens and emits all 1167 --lasuite--* tokens (584 light +
583 dark, mirroring the source's own two-block structure) plus a closed
compatibility-alias block for the existing bridge/element-overrides consumers.

The deployed La Suite violet theme (no npm package ships it) is now a
separate, sourced css/systems/lasuite/brand-override.css layered after
defaults, with provenance citing the docs.numerique.gouv.fr bundle observed
2026-07-24. css/systems/lasuite/bridge.css now covers all 68 audited
Nextcloud --color-* variables (up from ~30), and its --nldesign-color-*-rgb
literals are recomputed against the regenerated (correct) hex values.

Adds an optional cunningham (blue-base) sibling design system/token set,
correcting a discovered inconsistency along the way: the shared bridge
derives --color-primary from brand-650 (not brand-600), so cunningham's
swatch/rendered primary is #1A509F, not #0659C5 — fixed consistently across
token-sets.json, css/tokens/cunningham.css, the PHPUnit regression, and the
change's own spec deltas.

Adds a drift guard (npm run test:lasuite-tokens), a bridge-coverage checker
(npm run test:lasuite-bridge-coverage, mirrored in PHPUnit), and the
component-parity e2e spec (tests/e2e/spec-coverage/lasuite-parity.spec.ts).

Tests: 19 new vitest unit tests (generator), 21 PHPUnit tests in
LasuiteDesignStackTest (was 12), full non-Mail Unit suite 457/457 green,
composer check:strict all green. Live 8080 verification (tasks 7.4-7.6)
deferred per builder-brief ground rules — done post-merge on the main
checkout.
feat(lasuite): generate full Cunningham token base, sourced violet override, complete bridge coverage
Built (#184), merged, live-verified: full 5-layer lasuite cascade injects in
order (fonts→defaults→brand-override→bridge→element-overrides); the deployed
violet (brand-650 #4844ad) resolves. 1167 generated tokens + sourced violet
override + 68-var bridge + drift/coverage guards. 462 PHPUnit, 74 vitest.
…-completeness

docs(openspec): archive lasuite-token-completeness
…dpoints

Adds nldesign's side of the app-token-set-selection contract: a read-only,
non-admin token-set catalogue for a leaf app's own picker, a shared WCAG
contrast-evaluation endpoint generalising ContrastService beyond its two
fixed pairs, and the published (not implemented) scoped-application contract
a shared nextcloud-vue applier will target.

- GET /api/token-sets (#[NoAdminRequired]) - TokenSetService::getPublicCatalogue()
  projects getAvailableTokenSets() to a closed 5-field shape; wcagLevel reuses
  ShippedTokenSetAuditService::auditSet() via a new computeCachedWcagLevel()
  helper, sharing Capabilities' own nldesign_wcag_level ICache namespace.
- POST /api/contrast/evaluate (#[NoAdminRequired]) - ContrastService::evaluate()
  generalises check() to arbitrary candidate/role pairs against a caller
  background; never returns a blocked/allowed/verdict field.
- Regression test (TokenCssShapeTest) proving every shipped css/tokens/*.css
  (excluding dark/) is flat :root-only - the invariant the scoped applier
  contract depends on.
- Cross-referenced the resulting warn-only selection policy from
  custom-token-sets and token-set-contrast-audit specs.
- Docs: docs/reference/app-token-scope-contract.md.

Capabilities.php is unchanged; TokenSetService/ContrastService gain new
methods only, existing behaviour (check(), getAvailableTokenSets()) is
untouched.
…set-selection

# Conflicts:
#	openspec/specs/app-token-set-selection/spec.md
feat(token-sets): non-admin catalogue + shared contrast evaluation endpoints
…cknowledgement

Marianne is the official typeface of the French State, reserved for French
State administrations. This bundles the 8 DSFR Marianne woff2 weights
self-hosted under css/systems/lasuite/fonts/marianne/ (Etalab-2.0), but
keeps them inert by default: the real @font-face declarations live in a
separate css/systems/lasuite/marianne.css, emitted by CssInjectionService
only when the lasuite design system is active AND an admin has ticked the
"our organisation is a French State agency" acknowledgement gate
(marianne_enabled app config, default '0'). With the gate off, no Marianne
byte is ever requested and the lasuite set renders Inter.

Adds the admin settings toggle + unmissable restriction notice (translated
en/nl/fr), MARIANNE-LICENCE.md, AGREEMENT-MARIANNE.md, LICENSES/Etalab-2.0.txt,
and .license-overrides.json attribution, and updates the lasuite-stack and
claim-accuracy specs/tests that previously asserted Marianne was never
bundled.

Tests: 475 PHPUnit (via nextcloud:34 container, excl. pre-existing
OC\Mail\EMailTemplate harness gap), 60 vitest, composer check:strict green.
feat(lasuite): bundle Marianne font gated behind admin French-state acknowledgement
Built (#187), merged, live-verified: gate default-OFF injects no marianne.css
(zero Marianne bytes fetched, Inter renders); enabling it (admin affirming
French-state eligibility) + lasuite injects the self-hosted woff2. 8 DSFR
Marianne woff2 (Etalab-2.0), repo user agreement + licence + unmissable
notice. 505 PHPUnit green, check:strict green.
docs(openspec): archive marianne-font-restricted
…ack resolver

Adds an optional icon_pack field to design-systems.json (nldesign -> the
existing rvo/open-gemeenten/den-haag packs, lasuite -> dsfr), materializes
the French-government DSFR icon set (1038 SVGs, Etalab-2.0, via
@gouvfr/dsfr) into img/icons/dsfr/, and adds a DesignSystemService
resolver (getIconPacks/resolveActiveIconPacks/resolveIconPath) so the
bundled icon pack an app resolves through nldesign travels with the
active design system instead of being hardcoded. Resolution honors an
appconfig icon_pack admin override and is exposed on the public
capability as iconPacks; a read-only admin indicator surfaces the
active pack and its source. Existing Dutch icon URLs and the
imagePath('nldesign', 'icons/{set}/{key}.svg') contract are unchanged
(purely additive).

Tests: 478 PHPUnit tests / 3546 assertions green (in-container run,
excluding the pre-existing OC\Mail\EMailTemplate harness limitation);
55 vitest tests green; composer check:strict green.
…chable-iconography

# Conflicts:
#	.license-overrides.json
#	README.md
#	js/admin.js
#	l10n/be.json
#	l10n/bg.json
#	l10n/bs.json
#	l10n/ca.json
#	l10n/cs.json
#	l10n/da.json
#	l10n/de.json
#	l10n/el.json
#	l10n/en.json
#	l10n/es.json
#	l10n/et.json
#	l10n/fi.json
#	l10n/fr.json
#	l10n/ga.json
#	l10n/hr.json
#	l10n/hu.json
#	l10n/is.json
#	l10n/it.json
#	l10n/lb.json
#	l10n/lt.json
#	l10n/lv.json
#	l10n/mk.json
#	l10n/mt.json
#	l10n/nb.json
#	l10n/nl.json
#	l10n/pl.json
#	l10n/pt.json
#	l10n/rm.json
#	l10n/ro.json
#	l10n/ru.json
#	l10n/sk.json
#	l10n/sl.json
#	l10n/sq.json
#	l10n/sr.json
#	l10n/sv.json
#	l10n/tr.json
#	l10n/uk.json
#	templates/settings/admin.php
…raphy

feat: theme-switchable iconography — DSFR pack + design-system icon-pack resolver
Live verification caught it: rijkshuisstijl (and the ~33 Dutch municipality
sets) omit design_system in token-sets.json — they carry id/name/description/
theming and rely on the app-wide 'nldesign' default that
getAvailableTokenSets()/Capabilities apply. resolveActiveIconPacks() did NOT
apply that default, so every Dutch-government set resolved to NO icon pack —
silently breaking the 'Dutch government → Dutch icons' promise this wave is
about.

Fix distinguishes a KNOWN set that omits the field (→ nldesign default →
Dutch packs) from an UNKNOWN token set id (empty meta → no pack). The
existing 'NldesignDefault' test set design_system explicitly so it never
exercised the real omitted-field case; added a regression test with a set
that omits it.

Verified live: rijkshuisstijl→[rvo,open-gemeenten,den-haag], lasuite→[dsfr],
summer-breeze→[], unknown→[]. 527 PHPUnit, check:strict green.
…n-system

fix(icons): Dutch-government sets resolve Dutch icons (default missing design_system)
Built (#189), merged, live-verified per-government icon resolution:
lasuite→[dsfr] (French gov icons), rijkshuisstijl→[rvo,open-gemeenten,
den-haag] (Dutch), summer-breeze→[] (non-gov), unknown→[]. 1038 DSFR icons
(Etalab-2.0) materialized; capability exposes iconPacks. Includes the
missing-design_system default fix (#190). Archive header aligned to the
canonical 'nc-vue Icon Packs' name (broadened to cover the DSFR pack).
docs(openspec): archive theme-switchable-iconography
… hover, brand-050 text

A local computed-style comparison of the lasuite theme against La Suite's own
shipped Cunningham CSS (the authentic violet :root build) exposed that our
primary button filled brand-650 (#4844ad) at rest — which is La Suite's HOVER
step, one shade too dark. La Suite's .c__button--brand--primary fills brand-550
(#5e5cd0) at REST and brand-650 on hover, with brand-050 (#eef1fa) text, not
pure white.

- element-overrides.css: primary fill/border brand-650→brand-550 (rest),
  hover brand-750→brand-650, text gray-000→brand-050; color selector made
  symmetric with the fill selector (button[class*="primary"]).
- bridge.css: --color-primary-element→brand-550, -hover→brand-650,
  -element-text→brand-050.
- generate-lasuite-tokens.mjs: emit the --lasuite-color-brand-550 short alias
  the bridge now consumes; defaults.css regenerated (drift guard green).
- lasuite-parity.spec.ts: assert the corrected button reference values.

Verified: primary button now an exact match (bg #5e5cd0, text #eef1fa,
radius 4px) on both La Suite and the nldesign lasuite theme.
…onfig) (#192)

* feat(config): NL Design theme as a shareable config type (federated-config)

Contributes NL Design's theme configuration to OpenRegister's federated-config
engine, so a theme can be published to and installed from GitHub over the fleet's
one sharing mechanism — the proof that the standard is storage-agnostic, since NL
Design config lives in Nextcloud's IConfig, not in OpenRegister objects.

- NlDesignThemeShareableConfigType implements OCA\OpenRegister\Service\Config\
  IShareableConfigType, wrapping the existing ConfigBundleService export()/import()
  as the (de)serialiser. serialise() ignores its selection (a theme is the
  instance's one theme config); no secrets (theming carries none).
- ShareableConfigTypeListener registers it on RegisterShareableConfigTypesEvent,
  guarded on the event class existing (boots fine without OpenRegister).
- Application::register() now include_once's the app's composer autoloader so the
  cross-app listener is resolvable process-wide — the same mechanism hermiq uses
  to contribute flow nodes to OpenRegister.

Follows the identical cross-app contribution pattern hermiq uses (guarded event
listener + vendor-autoload include). OpenRegister-side, the federated-config
standard and its first two consumers (flows, registers/schemas) are merged and
e2e-verified (openregister#2134, #2135). Live round-trip verification of this
theme type on the shared dev instance is pending a clean deploy — the listener is
correct but its cross-app autoload did not activate on that instance; opened for
review rather than merged unverified.

* fix(config): correct namespace case + lazy bundle service — theme type now registers

The shareable theme type was written under OCA\NlDesign\ but this app's PSR-4
prefix is OCA\NLDesign\ (capital NL). PHP namespaces are case-sensitive, so the
server container's PSR-4 autoloader could not find the listener/type when
OpenRegister's dispatcher constructed them cross-app — the classmap could (why a
manual require worked), which masked it. Corrected the namespace to OCA\NLDesign\
throughout and regenerated the autoloader.

Also resolve ConfigBundleService lazily (via the container) instead of injecting
it: the type is constructed on every shareable-type catalogue read, but the
bundle service's deep theming chain is only needed when a theme is actually
serialised/installed.

Live-verified on 8080 end to end: nldesign.theme now appears in OpenRegister's
/api/federated-config/types cross-app over HTTP; bundling exports the real theme
config (token set, footer, overrides); installing it back returns
installed=["nldesign-theme"]. The storage-agnostic claim holds — theme config
lives in IConfig, shared over the same mechanism as flows and registers.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
The lasuite theme matched La Suite only on the brand ramp. A computed-style
comparison against La Suite's own deployed Cunningham build showed the whole
rest of the colour system was off: our neutrals were the plain npm base greys
while La Suite tints its gray/white/black ramps violet, and our semantic
palettes were the npm defaults while La Suite ships its own vivid hues
(success true-green, warning orange, info brighter blue). 539 of 593 :root
tokens differed.

Rather than change defaults.css — which is SHARED with the `cunningham` design
system and must stay on the published blue base — this expands the lasuite-only
brand-override.css from a hand-authored brand+logo layer into the full deployed
colour delta, generated reproducibly:

- Vendor La Suite's deployed violet Cunningham build (suitenumerique/docs
  @61c2183, MIT) as scripts/sources/lasuite-deployed-cunningham-tokens.css.
- generate-lasuite-tokens.mjs --override diffs that deployed :root against the
  blue npm base and emits brand-override.css: 331 colour tokens (brand ramp +
  violet-tinted neutrals + La Suite's semantic palettes + logo). Scope is
  globals--colors + text-differing contextuals; structural globals
  (spacing/font/breakpoints) and unconsumed Cunningham components--* are
  excluded so the delta never moves layout. New drift guard:
  npm run test:lasuite-override.
- element-overrides.css: style NC secondary buttons from La Suite's
  brand-secondary contextuals (pale brand-100 fill, brand-600 text, no border),
  which our theme previously left as NC's default grey.

defaults.css is byte-unchanged except its header (regenerated); the cunningham
theme stays blue. Verified: a local computed-style comparison now matches La
Suite exactly on heading text, brand, logo, primary + secondary buttons, input
border and the tinted neutrals (only the Inter-Variable font-stack notation
differs — same rendered face). La Suite's deployed semantic -550 fills all meet
WCAG AA on white (5.35–5.38:1).

Guards: test:lasuite-tokens + test:lasuite-override drift, bridge-coverage,
stylelint, 73 vitest (incl 32 generator unit tests), phpcs, and
LasuiteDesignStackTest (22 tests) all green.
…ntract stubs

The NL Design theme shareable-config type (#192) references OpenRegister's
IShareableConfigType interface and RegisterShareableConfigTypesEvent — a SOFT
runtime dependency (registered behind a class_exists guard, so the instance
boots without OpenRegister). During static analysis OpenRegister is absent, so
phpstan and psalm could not resolve the contract, producing 4 phpstan + 3 psalm
errors (implements/extends unknown interface, unknown class, InvalidTemplateParam
on the listener's IEventListener<Event> generic, and a knock-on registerEventListener
type error in Application.php). "implements unknown interface" is a category
phpstan refuses to ignoreErrors, so a baseline entry was rejected outright.

Fix at the root with declaration-only analysis stubs of the two contract
classes (stubs/openregister-config.php, signatures mirrored verbatim from
openregister/lib/Service/Config/), wired into phpstan.neon `scanDirectories`
and psalm.xml `<stubs>`. Never autoloaded at runtime (PSR-4 maps only
OCA\NLDesign\ → lib/, and the file sits outside the test suite), so the real
OpenRegister classes are used whenever it is enabled — the "share the contract"
pattern, not a blanket excludePaths. Also drops the now-dead, non-ignorable
`implements unknown interface` ignoreErrors line, and suppresses the
interface-mandated unused $selection param (PHPMD, same convention as
UpstreamFreshnessJob).

In-container (PHP 8.4): phpstan/psalm/phpmd/phpcs all clean, phpunit 527/527.
…multi-line tokens

Comparing the lasuite theme against the LIVE La Suite app (running locally,
localhost:3000) instead of a synthetic showcase surfaced three defects that
colour-token parity could not see.

- Button labels: Nextcloud's .button-vue ships font-weight 700; La Suite sets
  --c--components--button--font-weight to 500. Every button read noticeably
  bolder than La Suite's. Now 500.
- Tertiary buttons: La Suite's .c__button--brand--tertiary is transparent with
  BRAND text (brand-550 #5e5cd0); ours fell back to near-black gray-900, so
  tertiary actions read as plain body text. Now brand-tinted, scoped to
  text-bearing tertiary buttons OUTSIDE #header so the header's icon buttons
  keep their white-on-brand contrast and icon-only row actions stay neutral.
- generate-lasuite-tokens.mjs: parseDeclarations was line-anchored, but La
  Suite's deployed build is prettier-formatted and wraps long values across
  lines. It silently skipped 157 of that source's 593 declarations — mostly the
  semantic `contextuals` — so the generated override lost them, including the
  tertiary colour being repointed brand-500 -> brand-550. The parser is now
  multi-line tolerant and strips comments; the override grew 333 -> 343
  declarations. defaults.css is byte-unchanged (the npm base is single-line),
  so the `cunningham` blue set is unaffected.

Verified live in Nextcloud Files under a per-user theme preview: buttons now
render weight 500, tertiary text #5e5cd0, secondary unchanged (#534fc2 on
#dde2f5), and header buttons still white. Guards: both drift guards,
bridge-coverage, stylelint, 76 vitest (35 generator), phpcs, 22 PHPUnit.
Measured against La Suite running locally (authenticated, localhost:3000), the
theme's neutral steps were each one off:

- Primary text: La Suite's nav items and document-row titles are gray-850
  (#25252f); the bridge used gray-900 (#1b1b23). --color-main-text -> gray-850.
- Muted text: La Suite's column headers/labels are gray-600 (#5d5d70); the
  bridge used gray-500 (#75758a). --color-text-maxcontrast -> gray-600, which
  also raises contrast on white from 4.50:1 to 6.43:1.
- Structural hairlines: La Suite's sidebar border-right is gray-100 (#e2e2ea);
  we used gray-200 (#c5c6d5). --color-border, the #header bottom rule and the
  app-navigation border-right all -> gray-100.

Adds the --lasuite-color-gray-600 / -850 short aliases the bridge now reads
(COMPAT_ALIASES, so defaults.css and brand-override.css regenerate in step) and
updates the parity spec's hairline constant GRAY_200 -> GRAY_100.

Verified live in Nextcloud Files under a per-user theme preview: --color-main-text
#25252f, --color-text-maxcontrast #5d5d70, --color-border #e2e2ea, sidebar
border-right and header rule both rgb(226,226,234), and the nav link colour now
equals La Suite's own rgb(37,37,47) exactly. Guards: both drift guards,
bridge-coverage, stylelint, 76 vitest, phpcs, 22 PHPUnit.
Clears the 19 conflicts blocking the beta -> main promotion (#419). Each is
taken from beta, which is strictly the newer side on all of them:

  appinfo/info.xml   beta 1.1.0, NC max-version 34; main 0.1.2, max 33. Both
                     already carry the PHP 8.3 / NC 32 floors main raised in
                     #249, so nothing from it is lost.
  css/tokens/*.css   beta 2026-08-18, main 2026-05-26.
  token-sets.json    47 token sets on beta against 32 on main.
  workflows          beta runs the shared reusable pipeline; main still has
                     the old inline php-checks job. The five workflows beta
                     deleted stay deleted — the legacy DEPLOY_KEY ones main
                     also set out to drop (#279).

main's remaining unique commits are the Codeberg-era migration banner and
token sync, which this fleet does not want, and dependabot bumps beta passed
long ago. The merge contributes main's history, not its content.

Proof, not intent: the merged tree is byte-identical to origin/beta.
…motion

chore: absorb main's history into beta so the promotion can merge
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/thematiq @ 188db6f

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

Quality workflow — 2026-08-29 10:39 UTC

Download the full PDF report from the workflow artifacts.

github-actions Bot and others added 22 commits August 29, 2026 14:00
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
)

Bumps [@cyclonedx/cyclonedx-npm](https://github.com/CycloneDX/cyclonedx-node-npm) from 5.0.0 to 6.0.1.
- [Release notes](https://github.com/CycloneDX/cyclonedx-node-npm/releases)
- [Changelog](https://github.com/CycloneDX/cyclonedx-node-npm/blob/main/HISTORY.md)
- [Commits](CycloneDX/cyclonedx-node-npm@v5.0.0...v6.0.1)

---
updated-dependencies:
- dependency-name: "@cyclonedx/cyclonedx-npm"
  dependency-version: 6.0.1
  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>
Bumps [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) from 3.2.7 to 4.1.11.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/coverage-v8)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.11
  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>
)

* chore(deps): clear the critical and all nine high audit findings

npm audit: 15 findings (1 critical, 9 high) -> 3, all moderate.

  vitest 1 -> 3                     the critical: the Vitest UI server let an
                                    arbitrary file be read while listening
  @cyclonedx/cyclonedx-npm 4 -> 5   shell injection via an unsanitised argument
  npm audit fix                     the remaining eight highs (@gouvfr/dsfr*,
                                    browser-sync*, immutable, nanoid, sharp),
                                    all non-breaking

@vitest/ui and @vitest/coverage-v8 move with vitest: @vitest/ui peers it at an
EXACT version, so bumping vitest alone silently fails to resolve and the audit
numbers come back unchanged.

cyclonedx goes to 5, not 6. The advisory range is >=2.1.0 <5.0.0, so 5 closes
it, while 6 treats a non-clean `npm ls` as fatal and this fleet cannot produce
one (stylelint-config-recommended-vue@1.6.1 peers postcss-html@^1 while its own
stylelint-config-html@2 requires ^2).

* chore(tokens): regenerate the opencatalogi dark palette provenance

The GENERATED header recorded the sha256 of an older
tokens/opencatalogi.css. No token value changes; the header now matches
the source it was actually generated from.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](microsoft/TypeScript@v6.0.3...v7.0.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 7.0.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>
…452)

Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.13.6 to 4.0.4.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/4.x/CHANGELOG-3.x.md)
- [Commits](PHPCSStandards/PHP_CodeSniffer@3.13.6...4.0.4)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 4.0.4
  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>
…451)

Bumps [phpcsstandards/phpcsextra](https://github.com/PHPCSStandards/PHPCSExtra) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/PHPCSStandards/PHPCSExtra/releases)
- [Changelog](https://github.com/PHPCSStandards/PHPCSExtra/blob/develop/CHANGELOG.md)
- [Commits](PHPCSStandards/PHPCSExtra@1.5.0...1.5.1)

---
updated-dependencies:
- dependency-name: phpcsstandards/phpcsextra
  dependency-version: 1.5.1
  dependency-type: direct:development
  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>
… feat/docs-host-to-thematiq (#435)

* feat(docs): move the docs host to the new name, and stop linking to Codeberg

The `<new>.conduction.nl` docs hosts did not exist until 2026-08-23, which is
why every documentationUrl, CNAME and docusaurus `url:` in this repo was
deliberately frozen on the old host. They exist now: each new hostname was
attached as a SECOND custom domain on the SAME `<old>-docs` worker, so both
hosts answer and nothing goes dark in either direction.

`docs-hosts` lists BOTH hosts on purpose. wrangler reconciles a worker's
triggers against the config it is handed, so a hostname omitted there is REMOVED
from the worker — which would take that site down. (Observed the same day: a
deploy without `workers_dev` in the file silently disabled the workers.dev URL,
404 where it had been 200, while reporting success.)

Codeberg links in docs/ now point at GitHub. GitHub is the only host, including
for issues, and the navbar on the published site was offering Codeberg.

The docs will only actually change once ConductionNL/.github#555 lands: the
reusable documentation workflow writes gh-pages and never touches the worker
that serves the host, so every fleet docs site has been serving a May/June build
while reporting success on each run.

* docs: point the remaining repo links at the renamed repository

The merge conflict this branch just resolved was one GitHub link development had
already moved from ConductionNL/nldesign to ConductionNL/thematiq. Sweeping for
the rest found four more the branch had left behind: the docusaurus editUrl and
navbar href, the icon-documentation link, and llms.txt's source-code entry.

They are not broken today — GitHub redirects a renamed repository — but a
redirect is a grace period, not a contract, and llms.txt in particular exists to
tell a machine where the source lives. Leaving them also puts the docs in the
state the conflict was about: the same fact spelled two ways in one site, which
is what made the conflict rather than a clean merge.

Verified ConductionNL/thematiq resolves (default branch `main`) before pointing
anything at it, rather than assuming the rename landed. Config still parses.

* fix(docs): point the GitHub links at the CURRENT repo name

The Codeberg->GitHub conversion swapped the HOST and kept the repo slug, so the
links landed on `github.com/ConductionNL/<old-app-name>`. Those resolve —
GitHub redirects a renamed repository — which is exactly why this is worth
fixing rather than leaving: a working URL is not evidence of the current name,
and the `editUrl`, the navbar and llms.txt all showed the retired one to
readers.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Bumps [jsdom](https://github.com/jsdom/jsdom) from 29.1.1 to 30.0.1.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Commits](jsdom/jsdom@v29.1.1...v30.0.1)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-version: 30.0.1
  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>
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan-phar-composer-source) from 2.2.8 to 2.2.9.
- [Commits](https://github.com/phpstan/phpstan-phar-composer-source/commits)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-version: 2.2.9
  dependency-type: direct:development
  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 [nextcloud/ocp](https://github.com/nextcloud-deps/ocp) from 34.0.2 to 34.0.3.
- [Commits](nextcloud-deps/ocp@v34.0.2...v34.0.3)

---
updated-dependencies:
- dependency-name: nextcloud/ocp
  dependency-version: 34.0.3
  dependency-type: direct:development
  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 [phpmetrics/phpmetrics](https://github.com/phpmetrics/PhpMetrics) from 2.9.1 to 2.11.0.
- [Release notes](https://github.com/phpmetrics/PhpMetrics/releases)
- [Changelog](https://github.com/phpmetrics/PhpMetrics/blob/master/CHANGELOG.md)
- [Commits](phpmetrics/PhpMetrics@v2.9.1...v2.11.0)

---
updated-dependencies:
- dependency-name: phpmetrics/phpmetrics
  dependency-version: 2.11.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>
Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.27.0 to 3.28.0.
- [Release notes](https://github.com/twigphp/Twig/releases)
- [Changelog](https://github.com/twigphp/Twig/blob/3.x/CHANGELOG)
- [Commits](twigphp/Twig@v3.27.0...v3.28.0)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-version: 3.28.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>
…83900

chore(sync): carry main back into beta
beta held 18 commit(s) development did not. Version files were
resolved to development's side so the version never moves backwards --
the same rule release.yml applies to its own post-release sync.

Recording the ancestry is the payload: without it the merge base never
moves and the next development -> beta promotion conflicts on the version
file exactly as before.
…260830083911

chore(sync): carry beta back into development
…2608300839

chore(sync): record beta's ancestry on development
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/thematiq @ 208f35b

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-manifest ✅
test-l10n ✅
format ✅
composer ✅ ✅ 104/104
npm ✅ ✅ 2/2
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.

Release: merge development into beta
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/thematiq @ ce13dd8

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

Quality workflow — 2026-08-30 10:47 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit d080263 into main Aug 30, 2026
47 of 48 checks passed
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.

4 participants