Release: merge beta into main - #727
Open
rubenvdlinde wants to merge 47 commits into
Open
Conversation
…260830191003 chore(sync): carry beta back into development
Bumps [css-loader](https://github.com/webpack/css-loader) from 7.1.4 to 7.1.5. - [Release notes](https://github.com/webpack/css-loader/releases) - [Changelog](https://github.com/webpack/css-loader/blob/main/CHANGELOG.md) - [Commits](webpack/css-loader@v7.1.4...v7.1.5) --- updated-dependencies: - dependency-name: css-loader dependency-version: 7.1.5 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>
vue-router 5 peers `vite: ^7.3.0 || ^8.0.0` and expects a Vite toolchain. These apps build with webpack, which cannot resolve it at all: the build dies on `Can't resolve 'vue-router'` from src and from @nextcloud/vue's own chunks. Adopting it is a Vite migration, not a version bump. Dependabot proposed it across 8 repositories in a single run, and merging any one of them takes that app's build from green to red with no code change that can fix it. versioniq already builds with Vite and is the natural pilot if the fleet does move. Lift this when an app's toolchain can actually take it.
#703) The comment claimed these apps "cannot resolve it at all". That is not what the evidence shows, and a comment that overstates its case is worse than none: the next person reads it, tries vue-router 5 somewhere it works, and stops trusting the file. Measured across four apps: integriq and zaakafhandelapp fail their build on `Can't resolve 'vue-router'`, while openregister and learniq build clean on 5.3.0. The holdback still stands, for the honest reason rather than the overstated one: a major that breaks some apps and not others cannot be merged unattended, and the difference between them is not yet understood. No behaviour change. The ignore rule is unchanged; only the reasoning is.
The 0.1.42 release bumped the version on main. Without this, development stays behind main and the next development -> main promotion conflicts on the version file. Version files resolve to development's side, which is the higher line, so this never moves a version backwards.
…ires (#709) npm ci failed with ERESOLVE, so every frontend job failed before running a single check. Two conflicts, one under the other: postcss-html 2.0.0 vs stylelint-config-recommended-vue peers ^1.0.0 @babel/core 8.0.1 vs @nextcloud/webpack-vue-config@7.0.4 peers ^7.22.9 The babel one cannot be solved by picking a version. This app had adopted the babel 8 generation -- @babel/preset-env ^8.0.2 alongside @babel/core ^8 -- while @nextcloud/webpack-vue-config@7.0.4 still peers @babel/core ^7.22.9. No single value satisfies both, and trying one oscillates between ^7.22.9 and ^8.0.0 forever. So the babel packages move back to 7 TOGETHER. babel-loader ^10.1.1 is left alone: it accepts either generation, so it is not part of the conflict. Babel 8 can be adopted here once webpack-vue-config peers it; until then the two are mutually exclusive and the build tool wins, because it is what actually compiles the app. Verified: the lockfile resolves from a clean tree, where it previously exited on ERESOLVE. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…11934 chore(sync): carry main back into beta
…260831011942 chore(sync): carry beta back into development
…715) 2.25.x makes the canonical KPI card flat and horizontal, so dashboards stop drawing a grey box inside the white card CnWidgetWrapper already draws, and 2.25.1 fixes the narrow-tile step-down that 2.25.0 shipped inert (a source-order bug left KPI values clipped on a three-column tile). The caret range already allowed both; only the lockfile pinned this app back. Lockfile only.
…1.42 chore(release): sync main back into development
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
hydra-gates v1.10.0 -> v1.10.0 nc-vue 2.25.1 -> 2.26.0 Lock-only: both packages are already declared with caret ranges that permit these versions, so nothing about what this app ACCEPTS changes - only what it currently resolves to. Opened by the weekly fleet shared-dependency bump, because a lock nobody re-resolves is a pin nobody chose. Merging is gated by this repository's own suite, deliberately: taking hydra-gates v1.8.1 added patchObject() to a published interface, which is a load-time fatal for any concrete double that implements it without the method. CI is the only thing that can tell a safe bump from that. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Carries the two KPI-card fixes this dashboard reads: the canonical card is flat and horizontal (no grey box inside the white card CnWidgetWrapper already draws), and a calendar-aligned date range follows the reader's calendar rather than UTC — "Current month" previously showed a To of 1 September in CEST on 31 August. The caret range already allowed it; only the lockfile pinned this app back. Lockfile only, and npm pruned nothing.
Release: merge development into beta
The 0.1.44-beta.20260831102716 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>
…1.44-beta.20260831102716 chore(release): sync beta back into development
rubenvdlinde
requested review from
Rem-Dam,
SudoThijn,
WilcoLouwerse,
bbrands02,
remko48 and
rjzondervan
as code owners
August 31, 2026 11:20
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.
Contributor
Quality Report — ConductionNL/hermiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 123/123 | |||
| npm | ✅ | ✅ 730/730 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 12:24 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Dependabot cannot update these packages. Its npm updater fails with: npm error code EOVERRIDE npm error Override for <pkg> conflicts with direct dependency The package is listed BOTH as a direct dependency and as a literal overrides entry pinned to the same range. Dependabot bumps the direct dependency and does not move the override, npm rejects the mismatched pair, and the update is abandoned -- so these packages can never be updated, security advisories included. npm's self-reference is the idiom for exactly this: $<name> tells the override to follow whatever the direct dependency resolves to, instead of a range that has to be kept in lockstep by hand. This repo already uses it (see the vue entry under @vue/test-utils). Transitive consumers still get pinned to one version -- the direct dependency's -- which is what the override was there to do. What changes is that the pin tracks the dependency instead of duplicating it. Verified in a clean container: bumping the direct dependency with the literal override reproduces the EOVERRIDE above; with the self-reference the same bump resolves. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
`a local-pinned agent does NOT fall back to the browser when the service is
down` failed intermittently with
Error: expect(locator).toContainText(expected) failed
Locator: locator('[data-testid="cn-ai-input-dictation-error"]')
Expected pattern: /private/i Timeout: 15000ms
Error: element(s) not found
The assertion outlived the thing it asserted on. CnAiInput's
`showDictationError()` arms `setTimeout(..., DICTATION_ERROR_TIMEOUT)` with
DICTATION_ERROR_TIMEOUT = 6000 -- the banner wipes itself after 6s,
deliberately, because "a banner with no lifetime becomes furniture". The test
allowed 15s to observe it. If the runner stalled between the click and the
first poll the banner had already cleared, and Playwright then waited out the
rest of the 15s for an element that no longer existed.
Measured on development 2026-08-31: 2 failures in 8 runs, and a `push` and a
`pull_request` run of the SAME commit disagreed -- the signature of a missed
window rather than of an app that failed to refuse.
So the observation now happens inside the banner's own lifetime, and the
trigger is repeated if the window was missed (bounded at 3). Re-clicking is
safe and changes nothing the test is about: the control is `aria-disabled`,
the app refuses the click either way, each call re-arms the banner's timer,
and the assertion that matters -- that NO browser recogniser was constructed
-- is checked over the whole test rather than per click.
Deliberately NOT a longer timeout and NOT a weakened matcher. The refusal
message is the point of the test: it still must appear, still must say
"private", and a genuine failure to show it still fails here after three
honest attempts.
Worst case: waitFor resolves at 4s leaving 2s of banner for the text
assertion; 3 attempts is ~12s, inside the spec's budget.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The dashboard shipped two Refresh controls side by side. CnActionsMenu
renders one as the first item of the page-level Actions overflow menu, and
the manifest declared another as a header button next to that menu.
They did the same thing. A "type": "refresh" headerAction is dispatched as
emit(PAGE_REFRESH_CHANNEL, {}), which is the exact signal CnActionsMenu
broadcasts on refresh-channel="cn:page:refresh". Same channel, same
subscribers. Removing the header action takes away the duplicate and nothing
else.
An app that wants to keep a prominent Refresh button can stand the menu item
down with showRefresh: false instead. openregister's dashboard does that.
Shipping both is what this removes.
gate-60 reported 2 Tier B warnings. Both adopted. 2 -> 0. Compliance Check -> ClipboardCheckOutline Budget CashMultiple -> CalculatorVariantOutline Budget is the better read: CashMultiple is money, a budget is money being COUNTED. A calculator says planning rather than cash on hand.⚠️ CalculatorVariantOutline had to be REGISTERED in src/icons.js in the same commit. It was not there, and an icon a manifest names but the registry does not hold renders as NOTHING. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
`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.
Nextcloud serves an app under both /apps/hermiq/... and /index.php/apps/hermiq/..., 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 live on learniq, which had the identical base, across all 282 of its routes: /apps/learniq/courses resolved to Courses, and /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.
* chore(flows): finish the agentflow retirement The agentflow object store's runner, resolver and frontend were already removed; this closes out the four leftovers that kept the retired store half-alive: - hermiq_register.json v0.30.0 drops the AgentFlow and AgentFlowRun schemas, and the mock register no longer seeds objects for them. - PruneRetiredAgentFlowSchemas (post-migration) removes the schemas from existing installs: the import unions schema ids and never removes one, so the descriptor edit alone leaves every install carrying both rows, their magic tables and their register links forever. The step mirrors occ openregister:schemas:prune-retired (app-scoped, unlink before delete, cascade) and deletes remaining objects deliberately: nothing can read them any more. - SeedHydraTriageFlow loses the dead FLOW_SCHEMA constant. - consume-or-flow-engine, agent-graph-builder and hermiq-schedule-source move to the openspec archive with a superseded note each; the 16 @SPEC tags pointing at consume-or-flow-engine now reference the archive path. Tests: schema and mock absence pinned declaratively, the prune proven idempotent (a second run performs zero deletes and zero writes), and a failed delete shown to report rather than abort the upgrade. * chore(deps): hydra-gates v1.11.0, whose manifest schema knows the flow page type The vendored v1.10.0 schema predates the flow page type, so gate-22 and gate-53 fail locally on two pages CI already accepts. The bump makes the local gate verdict match CI's.
…surface (phase 1) (#749) Every pending Approval is mirrored as one OpenRegister task on the trusted import() path, a task completed in the shared inbox decides the Approval through a string-literal-FQN TaskTerminalEvent listener (the filinq#988 adopter pattern), and a hermiq decision releases the mirror as moot. The MirrorPendingApprovalsToTasks repair step migrates in-flight approvals idempotently; occ hermiq:approvals:rollback-task-mirror rolls the mirror back. Phases 2 and 3 (one inbox, thin delegate) are staged in the change's tasks.md.
…e (phase 1) (#751) * feat(schedules): hand the schedule clock to OpenRegister's flow engine (phase 1) Every schedule whose cadence a 5-field, timezone-safe cron can carry is mirrored as one engine flow: trigger-schedule (cron + explicit runAs, the resolved acting identity) into a new hermiq.schedule-dispatch node that re-enters ScheduleService::runNow(), so kill switch, budget, approval, retry, delivery and audit apply unchanged. The local dispatcher stops selecting delegated schedules as due by nextRun (a pending retry still fires locally). hermiq also contributes hermiq.tenant-killswitch to the engine's oversight registry, so an engaged organisation's hermiq hops are vetoed before they execute. The MirrorSchedulesToEngineFlows repair step migrates in-flight schedules idempotently; occ hermiq:schedules:rollback-flow-mirror rolls the delegation back. Phases 2 and 3 (once onto FlowTimerService, timezone-sensitive crons, local-clock retirement) are staged in the change's tasks.md. * fix(tests): the oversight-registry stub mirrors the real constructor CI installs the real OpenRegister, whose FlowOversightRegistry requires a logger; the zero-argument stub constructor let a test build against a signature the real class refuses (ArgumentCountError in all six PHPUnit cells). The stub now carries the real signature and the test constructs identically against either. * test(schedules): cover the seam's failure paths for the coverage ratchet The stable34 cell's coverage guard measured the change's kept-or-added statements at 78.66% against the base's 79.43%. These tests cover what the first round left dark: the tick's arm-then-dispatch order and its bridge isolation, the node's palette surface, orphan self-heal and unknown-status re-read, the bridge's missing-mirror hand-back, already-gone delete and read-failure accounting, the command's unreadable-store and failed-clear exits, and the oversight check's organisationless-run veto.
… inside (#753) 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>
…probe answering 503 when unconfigured (#754) * fix(schedules): publish the mirror flow so the engine's pin will run it OpenRegister's FlowRunVersionPin refuses every scheduled dispatch of a flow with no published version, so a mirror the bridge only inserted was a clock that never ticked: the schedule left the local dispatcher and gained nothing back. Reproduced twice on the dual-app rig; one manual publish made the whole chain work, which is exactly the fix a machine-managed mirror must not need. The bridge now publishes server-side through FlowVersionService, the class the publish endpoint itself uses, resolved lazily and guarded on the class existing. Create: insert, publish, mark, so a publish failure deletes the flow and the schedule keeps its local clock. Refresh: draft, update, publish, because the engine runs the pinned version, not the flow row, so a changed cadence must land as a new published version. The undrifted branch publishes any unpublished head, healing pre-publish mirrors on the next sync pass. The publish and shape concerns move to ScheduleFlowPublisher and ScheduleMirrorDefinition, keeping the bridge under the complexity ceiling. The new stubs model the pin's contract, so a bridge that skips publishing fails its tests instead of running unpublished flows. * fix(chat): an unconfigured chat backend is healthy, answer 200 GET /api/chat/health answered 503 {status:no_provider} on an instance without an LLM provider. That is a configuration state, not an outage, and the 5xx tripped every co-installed app's strict no-5xx e2e guard (it broke dossiq's KPI spec on the rig). The probe now answers 200 {status:unconfigured, configured:false, capabilities:[]} so a consumer decides on the body; 5xx is reserved for the app itself being broken, so a failing config read stays 503 {status:config_error}. The three e2e carve-outs that excused the designed 503 are gone: with this contract a 503 from the probe means the app is broken and must fail the sweep like any other 5xx. The sibling /api/health keeps its 503, which reports a genuinely dead OpenRegister dependency, not a missing setting. Known follow-up: nextcloud-vue's CnAiCompanion renders on any 2xx, so an unconfigured instance now shows the launcher; the widget should branch on the capabilities list. * fix(tests): the mirror-publish order check must not encode the stub's birth state The real Flow entity is born draft, so the bridge publishes directly; the standalone stub is born blank, so the bridge drafts first. The order assertion encoded the stub's shape and failed on the server matrix. Pin what matters on both: publish happens, and the marker comes after it.
ADR-114 Decision 4 settles a question ADR-080 left open. That ADR governs what an app may CALL a Store and records no placement decision at all, so the fleet grew two conventions from it: dossiq put Store in the footer, integriq, buildiq and hermiq put it in main. dossiq's own manifest note flagged the split as unresolved. The footer wins, at order 92, between Documentation (90) and Reports (95). Store is chrome, not a domain. Under ADR-097 a main-menu entry names a domain of the work, and a store is a place you visit deliberately, like Documentation and Features & roadmap beside it. Nothing about the surface changes. Discovery is still GenericStoreService, install is still this app's own (ADR-080 Decision 3), and with no registry configured the page still renders built-in items and makes no network call.
Every push to development fired Code Quality TWICE on the same commit: once for the push event, once for the pull_request event of the permanently-open "Release: merge development into beta", whose head_ref IS development. The concurrency block is not the bug and must not be changed: it suffixes the group by event name deliberately so the push run is NOT cancelled by the PR run, because the push run is the only carrier of Coverage Baseline Check, SBOM and Features Extract. The consequence is that both lanes run to completion, so the duplicate has to be dropped at the job. The PR run is the one to drop: its head sha IS development's, which the push run already decided, and it runs strictly fewer jobs. Not done by removing `beta` from pull_request.branches, though that would also stop it: the release/v* and sync/main-to-beta PRs target beta too and genuinely need their run. Only the head_ref:development PR is redundant. A development -> main promotion PR is skipped by the same clause, for the same reason and just as correctly. Proven on openregister#3370 before rolling out: run 33757014196 (pull_request, sha 4f3ef5e9) completed as `skipped` with ZERO jobs in 72s, while the push run for the same sha ran the full suite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#765) ADR-114 Decision 3 puts Reports in every app. Nothing is invented here: AI oversight already existed, and it was an entry in the SETTINGS foldout. That was the wrong home. The foldout is where configuration lives (ADR-044 Decision 3), and oversight is not configuration — it is a reading of what the agents did, which is what a report is. It becomes a card on /reports.⚠️ THE ROUTE HAD TO SURVIVE, AND NOT ONLY FOR DEEP LINKS. dossiq declares /apps/hermiq/ai-oversight as an ADR-110 integrations entry, so retiring the menu entry while dropping the route would 404 from ANOTHER app. The page is untouched, and an e2e test navigates to it directly. Guardrail policy, the algorithm register and Compliance stay in the foldout. Those ARE configuration, and the e2e asserts that asymmetry so a later sweep fails a test rather than passing review. Hermiq is one of only four apps that already had a Store, so its footer now carries all four declared chrome items and the spec asserts the full sequence Documentation, Store, Reports, Features & roadmap. ChartBoxOutline registered in src/icons.js. An unregistered icon name renders no glyph at all — not a fallback, not a console error. Verified: gate-22, gate-53, gate-60, gate-102, gate-104 and gate-107 clean (gate-107 now reports zero warnings for this app, since it has both Store and Reports); prettier clean; all five e2e tests collect.
Three defects, all found by actually RUNNING the specs rather than
collecting them. Until now they had only ever been listed, which proves a
spec parses and nothing else.
1. The cn-nav-* testids are on the <li> WRAPPER. The clickable element and
the href both live on the <a class="app-navigation-entry-link"> inside
it, so clicking the li resolved the locator and then never became
actionable — a 30s timeout that reads like the navigation is broken —
and reading href off the li gave null.
2. On a FRESH instance the setup wizard modal opens over the app and
intercepts pointer events. Every nav click failed while every URL
navigation passed, which is exactly the shape that hides this: only the
click-through tests break, and only on a clean install.
3. A bare getByText('Open') matched the SVG <title>Opens in a new tab</title>
on an external-link icon — attached, hidden, unrelated. Single-word
probes are now scoped to the page body.
Verified against a throwaway Nextcloud (not the shared :8080, and not the
neighbouring sessions' containers): planninq 6/6 and keepiq 5/5 green.
fix(e2e): make the chrome specs pass in a real browser
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan-phar-composer-source) from 2.2.9 to 2.2.12. - [Commits](https://github.com/phpstan/phpstan-phar-composer-source/commits) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-version: 2.2.12 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/axios](https://github.com/nextcloud-libraries/nextcloud-axios) from 2.5.2 to 2.6.0. - [Release notes](https://github.com/nextcloud-libraries/nextcloud-axios/releases) - [Changelog](https://github.com/nextcloud-libraries/nextcloud-axios/blob/main/CHANGELOG.md) - [Commits](nextcloud-libraries/nextcloud-axios@v2.5.2...v2.6.0) --- updated-dependencies: - dependency-name: "@nextcloud/axios" dependency-version: 2.6.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>
…#761) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.68.0 to 8.69.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.69.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-version: 8.69.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 [postcss-html](https://github.com/ota-meshi/postcss-html) from 1.8.1 to 2.0.0. - [Release notes](https://github.com/ota-meshi/postcss-html/releases) - [Commits](ota-meshi/postcss-html@v1.8.1...v2.0.0) --- updated-dependencies: - dependency-name: postcss-html dependency-version: 2.0.0 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>
…are Run button (#770) The demo-data step was a Run button under a paragraph. The paragraph said the data was safe to load and safe to delete. Neither said what was about to land in the operator's register, and there was no way to say no. ## Declining was unsayable, and that reopened the wizard for ever This app implements a `skip-demo-data` action. No manifest step could reach it: the only step was the run-action that INSTALLS. So an operator who did not want example data had no way to record that, `demo-data` stayed `done: false`, and CnAppRoot reopens the wizard while any optional step is outstanding. On every fresh browser profile, over every page, until they imported data they did not want. Measured across the fleet on 2026-09-05: fifteen apps implement that action and not one declares a step that can post it. ## What the step asks now Two cards, read from the server: "None, I will set this up myself" and the dataset this app ships, with its object count. Picking one is an answer, and `none` closes both steps without importing anything. The list comes from `GET /api/setup/status` as `datasets` — the step declares `optionsSource` and carries no options of its own, so nothing in the manifest can disagree with what will actually be imported. The count is read from the descriptor file, so the card promises the number that lands. The card's description carries NO number, deliberately: the wizard translates a description by literal lookup, so an interpolated count would leave a Dutch operator reading English. The count travels as `objectCount` and the card renders it as a stat with a label the library translates. ## Compatibility `install-demo-data` still works and still means "the dataset this app ships", so a runbook or script that posts it keeps working. `skip-demo-data` now writes both keys rather than only the decision flag. ## Verification 21 PHPUnit tests pass, 9 of them new. PHPCS clean, ESLint clean, prettier clean. All 75 applicable hydra gates green. Requires @conduction/nextcloud-vue with CnChoiceCards and hydra-gates >= v1.15.0 for manifest schema 2.33.0. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Release: merge development into beta
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings main level with beta, which is 17 commits ahead.
development is green on its last completed push run with Playwright E2E passing, and beta was brought level with development earlier today, so this carries verified code rather than a snapshot of unknown state.
Security alerts are measured on main but fixed on development, so this promotion is what actually clears them.