Release: merge development into beta - #460
Merged
Merged
Conversation
Stage 1 of the original-look restyle. The Vault menu entry becomes \"All secrets\" with a key icon (KeyVariant registered in src/icons.js — unregistered icon names render no icon at all), and the Certificates and Emergency access entries move from the footer to the settings foldout. Documentation, Features & roadmap, My activity and Password health deliberately stay in the footer. Also removes the duplicated \"Personal settings\" opener: CnAppNav auto-prepends its own entry at the top of the settings foldout while the manifest already declares the UserSettings entry (action: user-settings), so the same dialog had two openers. nav.includePersonalSettings:false keeps the explicit manifest entry as the only one — the e2e specs assert it, and the upcoming manifest-driven nav override renders it directly. The manifest schema rejects _note on nav and menu entries, hence this explanation lives here. Placement assertions in page-surfaces.spec.ts follow the relabel and the two moved entries; the local restyle plan file is gitignored.
…resh data
Completes the Stage-2 dashboard restyle:
- recent-activity-text (the ADR-049 placeholder) is replaced by a live
feed off GET /api/v1/audit/me: When (relative time via
format:date-time), Action and Item columns, newest-first. The endpoint
is asked for 6 entries while the table shows 5, so the View-all footer
appears exactly when a sixth entry exists, linking to My activity.
- The pending-apps count banner grew into the real approval queue: an
object-table of the actual pending applications (name, registered by,
requested), capped at 3 with a View-all footer to the applications
page. Its def-level visibleWhen collapses the whole card - grid row
included - for non-admins and empty queues, decided before the grid's
first paint so nothing pops in and reflows the page.
- KPI color identity: total-secrets primary, folders success,
rotation-due error, shared-with-you deliberately theme-default. The
*-text token variants, NOT the bare tokens - on current server builds
the bare --color-error/--color-success are pale background tints
(verified live: #FFE7E7 / #D8F3DA) while the *-text variants are the
strong readable colors on both server generations.
- The quick-action tiles get real icons and working links. They declared
iconType:class with MDI component names, which renders nothing (class
expects a Nextcloud core CSS class) - now inline SVG paths filled with
the tile's text color. And linkType:app resolves as
generateUrl('/apps/' + value), so their full-path values produced
/apps//apps/keepiq/... and 404'd; the router is hash-based, so the
values are now keepiq#/secrets and keepiq#/applications.
- The dashboard is current on every visit: its endpoint-bound widgets
fetch through the library's shared 5-minute cache, so creating a
secret and returning showed pre-creation totals and a feed without the
event. A router hook drops that cache on every navigation that lands
on the dashboard; within-page dedupe keeps working.
- L10n: the feed and queue strings land in all 37 locales (Item and
No recent activity with their real per-locale translations, the queue
title/empty text and View all with nl/de/fr/es/it translations), the
dashboard header strings that silently fell back to English (Vault
overview, its description, Rotation due) are translated, and the
Dutch folder pickers now say "Hoofdmap" for the vault root instead of
the literal "Kluiswortel".
…alias Adds the CnBreadcrumbs stub to the vitest alias for @conduction/nextcloud-vue (one span per crumb, aria-current="page" on the last, nothing for an empty trail — mirroring the real component's contract). The declared ^2.3.0 range already covers the library release carrying CnBreadcrumbs, so the dependency update is a lockfile refresh at merge time.
…olbar and rich empty state The vault page gets a visible title (folder name, or "Secrets" at the root), a CnBreadcrumbs folder trail below it (home crumb + parentId walk with cycle/depth guards; current folder unlinked; nothing at the root), and a rich NcEmptyContent empty state. The toolbar becomes a declarative toolbarItems() list where per-item placement is the only knob: Refresh is the sole visible secondary button (New secret stays CnIndexPage's add), and one "More actions" overflow carries New vault/New folder (level-appropriate label), Ask for a credential, Import, Team sharing, the former "My data" entries, and the type filter as a radio group — all data-testids and disabled conditions unchanged. CnIndexPage's refresh action and the visible button both drive the existing fetch. e2e specs that clicked toolbar buttons directly (secret-import, export-gdpr) now open the overflow first. Six new strings ride the l10n pipeline (en + nl).
The parity ratchet requires every English source key in all required locales. The six vault-restyle strings (Refresh, No secrets found, Add your first secret using the button above, More actions, New vault, Filter by type) gain translations in the 35 remaining locale catalogs, the .js catalogs are regenerated, and the ratchet is tightened to record the progress.
The secret list shows the current folder's direct subfolders as rows above the secrets, file-manager style (root = the top-level vaults): folder icon plus name, click navigates into the folder, where the Stage-5 breadcrumbs walk back up. Rows come from a pure helper (subfolderRows) with ids prefixed "folder:" so they cannot collide with secret ids; folders sort first as one name-sorted group, the inline search filters them client-side (everything visible in the list is searchable), they render on page 1 only, and they carry no bulk checkbox. The move dialogs already reached any depth through their flat folder list; their options now carry full "A / B / C" path labels so same-named nested folders are distinguishable. New vitest specs cover the row assembly and path labels; a new e2e test navigates root -> vault -> nested folder purely via rows and breadcrumbs.
The Stage-7 rail introduces five strings (Vaults, All vaults, Admin settings, Opens in a new tab, Keepiq navigation). They land in the English source and all 36 required locales, the .js catalogs are regenerated, and the parity ratchet is tightened to record the progress.
…acing the in-page folder pane KeepiqAppNav fills CnAppRoot's #menu slot: it renders manifest.menu by section/order exactly like CnAppNav (captions, :to route items so the href$ e2e selectors keep working, the user-settings action via the cnOpenUserSettings inject, external hrefs) and reuses CnAppNav's cn-app-nav__* class names and cn-nav-* testids as a documented e2e-parity contract. Below the main entries, a component-owned Vaults caption and an "All vaults" item host NavFolderTree — a recursive NcAppNavigationItem tree over the folder store, display-capped at depth 5 with a "…" node standing in for hidden levels (single hidden child: navigates into it; several: opens the parent page whose subfolder rows list them) and deepest-visible-ancestor highlighting. The caption lives in the component, not the manifest: buildManifest drops route-less menu entries, so a manifest caption never reaches the nav (library follow-up noted in the plan). The isAdmin-gated Admin-settings link-out (new tab + open-in-new marker) is replicated so the custom rail does not lose it. SecretList drops the in-page folder pane and its two-pane layout; the create-folder e2e goes through the More-actions overflow and asserts the new tree; the CnFolderSidebar vitest stub is removed.
The level-aware create dialog introduces two strings (Vault name, Create vault). They land in the English source and all 36 required locales, the .js catalogs are regenerated, and the parity ratchet is tightened.
…ype-icon map Review polish on the restyle: root-level entries ARE the vaults, so they carry the safe glyph everywhere — the nav tree's top level, the vault rows on the root list, the New-vault overflow entry and the create dialog's submit. The redundant "All vaults" host item leaves the rail (the Vaults caption already names the group and the extra link double-highlighted next to All secrets); the tree now renders directly under the caption. The create dialog's wording follows the SELECTED parent (New vault / Vault name / Create vault at the root, folder wording inside a vault) and its parent picker gains the path labels. The page title and the toolbar (Refresh + More actions) share one row aligned with the content via CnIndexPage's #header slot. The secret-type icon map now covers every seeded type: totp gets a clock, passkey a fingerprint, card a credit card and identity an ID card. The create-folder e2e accepts the level-aware submit label.
The Lint Check and Code Quality (eslint + format) jobs failed on the branch files: hyphenated template attributes where the config requires camelCase, unsorted imports, a useless v-bind, missing blank lines between multi-line props, and prettier formatting drift in seven files. All fixes are auto-applied style changes; no behavior changes.
A shared change added `Flows` and `Flow` to this app's manifest nav after the catalogue was last filled, so both rendered English for a Dutch user. The manifest is data the renderer walks rather than source the extractor scans, so nothing flagged them. Both map to themselves. Dutch Nextcloud keeps the product term: decidiq, dossiq and openregister already carry `Flows -> "Flows"` and `Flow -> "Flow"`, so this matches the fleet rather than inventing a Dutch word for a feature name nobody calls anything else. An identical value is the right answer here, which is worth distinguishing from the case I unpicked on pipelinq earlier: there, 43 English strings had been copied into nl.json to satisfy a parity check, and read as translated while being nothing of the kind. The test is whether the Dutch genuinely IS the English, not whether the two strings happen to match. Then `l10n:build`, because nl.json alone ships nothing. Verified: 0 manifest strings left without Dutch, keys DROPPED = 0 against the pre-change catalogues, check:l10n-js PASS.
#457) The PHPUnit cell that runs the coverage ratchet fails with "scripts/coverage-guard.php predates merge-base comparison (it does not report the 'against' capability)". That message names a plausible cause rather than the measured one, but the underlying fact is simple: this copy is the 17,288-byte version and the workflow is written against the 35,733-byte canonical one, which additionally reports `deletion-neutral`. Without that capability, deleting well-tested dead code still reads as a coverage drop. Measured across the 21-app fleet: 8 apps already carry the canonical copy and their ratchets run and report normally; 11 carry a stale variant. This is vendored-copy drift, the same shape as the six drifted app-manifest schemas. Copied verbatim from ConductionNL/.github at quality-config/coverage-guard.php rather than patched locally. Reimplementing a gate has cost us before: a hand-rolled version found 1 finding where the real gate found 13.
…findings The frontend restyle (PR #448) left four Playwright specs and three hydra gates red. The UI is correct; the specs and traceability tags were stale. Playwright: - NcActionButton renders data-testid on its <li role="presentation"> wrapper while the click handler sits on the inner button, so the specs' native li.click() on 'open-create-folder' / 'import-secrets' fired nothing and the dialogs never opened. New clickOverflowAction() helper opens "More actions" and clicks the inner button. - The breadcrumb-navigation test reloaded the page to pick up API-created folders, but a reload wipes the in-memory CryptoKey and lands on the lock gate. It now reloads, unlocks again and reopens the vault. - The create-folder test asserted '.secret-list-view__sidebar', a pane the restyle removed; it now asserts the new subfolder row. - compromise-recovery pressed Escape once against STACKED dialogs (recovery on top of user-settings) — the recorded CI flake. It now presses Escape once per remaining dialog. - The one waitForLoadState('networkidle') became domcontentloaded (ADR-074 rule 4, hydra gate-58). Hydra gates: - gate-46: five @SPEC tags pointed at dashboard/spec.md#app-navigation- renders, which never existed. The requirement + scenario now live in menu-architecture/spec.md (the menu's own spec) and the tags — plus navigation.spec.ts's @e2e tag — point there. - gate-16: the 17 restyle-touched methods in KeepiqAppNav.vue, SecretList.vue and favicon.js carry @SPEC tags against their real anchors (folder-management, list-and-pagination, secret-types, create-a-folder-and-move-a-secret, settings-foldout). Verified against a CI-seeded instance: the full suite passes and all applicable hydra gates pass at full coverage.
feat: frontend restyle — minimal nav, live dashboard, vault breadcrumbs, folder tree and vault-aware UI
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| 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-27 14:07 UTC
Download the full PDF report from the workflow artifacts.
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 111/111 | |||
| npm | ✅ | ✅ 550/550 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-27 17:27 UTC
Download the full PDF report from the workflow artifacts.
The App Store keys everything on the app id, so renaming <id> to keepiq made it a brand new store entry starting from nothing. The release workflow derives its version baseline from the git tags and info.xml of THIS repo, neither of which knows anything about what shipped as doriath -- so the version line restarts below it. filinq was about to publish 0.0.40 while docudesk sits at 0.1.0-beta.3 on the store. The store has no version ordering rule (_check_permission validates existence and ownership only), so that uploads with a 200 and is then never offered to anyone already on the higher version. previous-app-id folds the old entry's published versions into the baseline, so the renamed app picks the line up instead of restarting it.
…465) The App Store serves 0.2.0-beta.1 (doriath) for this app, and the release workflow was computing a beta BELOW it. The baseline comes from this repo's latest stable tag and appinfo/info.xml, neither of which knows what was published while the fleet released from Codeberg -- that line had walked up a minor that only exists as prerelease tags, which the stable-tag filter cannot see. The store has no version ordering rule (_check_permission validates existence and ownership only), so a lower version uploads with a 200 and is then never offered to anyone already on the higher one. Setting the baseline to 0.2.0 makes the next beta 0.2.1-beta.<ts>, which clears it. Minor bump only -- the major is unchanged.
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| 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-27 18:39 UTC
Download the full PDF report from the workflow artifacts.
#448 (frontend-improvements) added `Registered by` and `Requested` to the manifest. The manifest is data the renderer walks rather than source the l10n extractor scans, so neither reached the catalogue and both rendered English for a Dutch user. Registered by -> Geregistreerd door Requested -> Aangevraagd This is the drift the fleet check was added to catch, arriving the ordinary way: not a historical backlog, just the next PR that adds a manifest string. It took a couple of hours to appear, which is roughly the rate to expect. Worth noting `check:l10n-js` did NOT catch it and could not: nl.json and nl.js were in sync at 617 keys each, both simply missing the strings. That check guards source-versus-artifact drift, not manifest-versus-catalogue coverage. Different failure, different detector — humaniq's validate-l10n-parity.js is the one that asserts every manifest string has a key, and this app does not run it. Then `l10n:build`, because nl.json alone ships nothing. Verified: 0 manifest strings left without Dutch, keys DROPPED = 0 against the pre-change catalogues, check:l10n-js PASS, check-l10n-parity PASS.
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 111/111 | |||
| npm | ✅ | ✅ 550/550 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-27 21:05 UTC
Download the full PDF report from the workflow artifacts.
#472) Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
.github#597 set cancel-in-progress on the shared quality.yml, but a caller-level concurrency cancels the whole run before the called workflows setting can apply -- so that fix reached only the apps that declare no concurrency of their own. Measured 2026-08-28 over push runs on development since #597 merged: caller silent 0 of 11 cancelled caller says true 7 of 13 cancelled (54%) This repo is in the second group. pull_request keeps cancelling, where superseding really is correct.
The skip-discipline gate now runs here (hydra-gates 1.10.0, #472) and reports one V3 finding — an exclusion with no reason recorded. The reason exists and is a good one; it sits in a block comment above the test, and `test.fixme(title, fn)` records no description in report.json. The body was a single line pointing AT that comment: // Intentionally empty — see block comment for the precise blocker. which tells a human where to look and a machine nothing. The reason moves onto the fixme itself, and the parenthetical leaves the title. Same test, still excluded, now attributable. Verified: npm ci rc=0, npm run lint rc=0 (0 errors), prettier clean, and `playwright test --list` compiles all 8 tests with the exclusion intact. Part of ConductionNL/.github#609. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
* refactor(manifest): the flow pages are an index and a flow `flows` and `flow-detail` are deprecated aliases. `flows` predates named index sources: a flow lives in OpenRegister's native flow table rather than a register/schema pair, so an object-backed index had nothing to bind to and the list needed a page type of its own. `config.entitySource` closes that, so the list is an ordinary `index` and only the EDITOR still needs its own type, now named `flow`. Behaviour is unchanged - both aliases resolve to the same components. The list page's `_note` is updated in the same commit: it asserted the old rationale (that an index "cannot address" a flow), which this change disproves. `config.app` is untouched and is load-bearing: the editor stamps it on a flow created there and the index filters on it. Requires @conduction/nextcloud-vue 2.21, where a named source's columns and create button are actually read. * chore(deps): bump @conduction/nextcloud-vue to ^2.21.0 The flow pages need 2.21.0: earlier releases DECLARE a named index source's columns, create button and row actions without reading them, so the migrated page renders a columnless table with no working create action. The lock is the part that matters. CI installs with `npm ci`, which honours package-lock.json and ignores how permissive the caret is — bumping the range alone would change nothing about what actually installs. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Adds `keepiq-compose.yaml` and a setup page describing it. The compose brings up Postgres and Nextcloud, installs openregister (required), thematiq and integriq (optional) and keepiq from release tarballs, and enables them in dependency order. Nothing is bind-mounted: Nextcloud installs an app by deleting its directory and extracting an archive over it, so pointing that at a checkout deletes the working tree — measured on a development machine on 2026-08-27, where an app-store update fired on a container restart and removed every top-level file including .git. Release tarballs rather than a clone for a second reason: a tarball is a complete app carrying vendor/ and the built js/, and an app with no vendor/ does not fail loudly — it warns once and keeps loading, so it looks installed while every service needing a dependency is absent. The openregister dependency is not declared in appinfo/info.xml — no app in the fleet declares an <app> dependency — so the compose encodes what the manifest does not. Verified: docker compose config parses and interpolates; the same generated file was booted end to end for portaliq, which produced 17 registers, 86 schemas and 13 magic tables for its own register, with the portal content API returning a real site rather than an empty shell. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Two defects, both measured against a booted demo rather than inferred from
the code.
The verification step told you to run
curl -s -o /dev/null -w '%{http_code}' http://localhost:PORT/apps/APP/
and described a pass. That request is unauthenticated, and a Nextcloud app
page requires a login, so it prints 401 on a perfectly healthy demo. A reader
following the page would conclude the demo was broken. The command now sends
the demo credentials and says in words that a bare 401 is expected.
Thematiq additionally has no app route at all — it declares
<admin-section>theming</admin-section> — so /apps/thematiq/ answers 404 even
authenticated. Its page now opens Settings -> Administration -> Theming.
Verified on two booted demos: the corrected commands return 200.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…484) * feat(walkthrough): a first-visit tour built from this app's own menu ADR-043. The app had no walkthrough, so a new user arrived on a shell with no orientation at all. Every step targets a route READ FROM THIS MANIFEST, never invented. CnWalkthrough resolves target {kind: nav-item, ref} by querying [data-cn-route=<ref>], which CnAppNav emits from the ROUTE - so a tour pointing at a menu id that differs from its route still renders, as a centred anchorless coachmark that points at nothing. Verified: every ref resolves to a page this manifest declares. Where a menu label is a translation KEY rather than a sentence, the copy uses the key's last segment as a word. Printing launchpad.menu.dashboards at a user is worse than useless, and falling back to the route gives 'Click dashboard-detail in the menu' - an internal identifier read aloud. Verified: manifest validates against schema 2.26.0, every target ref resolves, and no raw translation key reaches the copy. * fix(walkthrough): point the tour at flows, and translate its copy gate-70 walkthrough-flows-stop - this app ships a flows page and no tour step targeted it. The gate's own measurement is why it exists: across 20 manifests, 12 apps shipped a flows page and exactly ONE tour mentioned it, so the automation surface was discoverable only by someone who already knew. Detected the way the gate detects it - type:'flows' OR the migrated form, an index over config.entitySource:'flows'. Matching on type alone would miss every app the flow-page migration touched, which is all of them. The step advances on route-match and sets allowManualNext. The same gate fails a step advancing only on object-created: that turns 'here is where flows live' into 'build an automation before you may continue', and a tour nobody can finish is worse than one that never mentions flows. gate-102 manifest-l10n-coverage - the tour's titles, bodies and tasks had no l10n/nl.json key. Added, and the browser catalogue rebuilt where the app ships one, because the browser reads nl.js rather than nl.json. * style(walkthrough): drop the em-dash from the flows step gate-96 (manifest-copy-style) fails this: voice.md section 8 is unambiguous — no em-dashes, Conduction strips them fleet-wide. The nl.json KEY is the English string, so it is renamed with it; leaving the key behind would orphan the Dutch translation of a string that still ships. The Dutch VALUE carried the same em-dash and gets the same treatment — the gate only counts manifest strings, but it is the same user-facing sentence. Note for a later sweep: this app's nl.json still holds 16 other em-dash strings from Vue copy. They are outside this gate's scope (it reads manifest strings) and outside this PR's. * fix(l10n): refresh the browser catalogue after the em-dash rename check:l10n-js reported 'Stale browser catalogue: l10n/nl.js'. Renaming the key in nl.json without nl.js leaves the two halves of the same catalogue disagreeing, and the runtime reads the .js one. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
The walkthrough merge broke `vault-unlock.spec.ts`: a locked vault issued `GET /api/preferences/walkthrough_completed_version`, and that spec asserts — on the wire, not the DOM — that a locked vault requests NO Keepiq API endpoint. It is an allowlist that fails closed, precisely so a new request behind the lock screen is a deliberate act with a reason. The router guard could not have caught this, and says so: it works by refusing to resolve a route, so it only covers what mounts inside the `<router-view>`. CnAppRoot reads `manifest.walkthrough` and fetches the tour's completion preference when the SHELL mounts, before any route resolves — a shell-level sibling, which that guard's own note warns needs its own gating. So the manifest handed to the shell now omits `walkthrough` while locked. Withheld, not disabled: `isLocked` is read inside the render function, so the tour returns the moment the vault is unlocked and still runs on a user's first unlocked visit. Drawing a product tour over a locked vault would be wrong regardless of the request. Fails closed like the guard beside it — only an explicit `false` unlocks — so a store that failed to initialise withholds the tour rather than shipping it. Both properties are mutation-verified: reading the check as `!store?.isLocked` fails the fail-closed test, and removing the withholding fails the first. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…t a leak (#488) The first-visit tour added in #484 made CnAppRoot resolve `walkthrough_completed_version`, and that fetch runs before any route resolves — so it fires behind the lock screen and the vault-unlock invariant failed closed, exactly as designed. Judged rather than silenced. It is the same shell layer, the same GenericPreferencesController and the same `pref_`-namespaced session-user UI flag as the `support-dialog-seen` entry directly above it, and it carries no vault material. The a11y snapshot from the failing run shows the bare unlock form with no walkthrough card, so only the probe reaches the wire; a tour that painted over the lock screen would still fail this test on its own traffic. The `\b` anchor keeps the entry from widening onto neighbouring paths. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
… instead (#490) Two sessions fixed the same failure minutes apart. #486 withheld the walkthrough from the manifest while the vault is locked, so CnAppRoot never resolves the completion preference and the probe cannot reach the wire. #488 then allowlisted that probe — which the file's own note calls pure masking surface: an entry that cannot fire would silently swallow a real regression of exactly this shape. #486 is the better fix; the entry goes. What is NOT fixed by #486 is the order-dependence. The tour's seen state is per user, not per test, so whichever spec runs first wears it — every spec here unlocks, and the tour is offered on the first unlocked visit by design. audit-trail.spec.ts started needing a retry the moment #484 landed, having never retried in the three preceding development runs. Seeding the marker in global-setup, as dossiq already does, removes that. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
2.22.1 carries the theme app-id fix (nextcloud-vue#840). CnAppRoot calls useScopedTheme() with no slug, so this app resolved theme tokens, the token-set catalogue and the contrast check through a hardcoded 'nldesign' app id. thematiq is renaming to 'thematiq', and every path in that composable degrades to default styling by design — so once a renamed build is installed this app would render unthemed with nothing in any log. The LOCK is what moves here. A caret range alone changes nothing, because npm ci installs what package-lock.json pins. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
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>
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
* feat(nav): a Flows surface in this app, on the shared page types ADR-110 Decision 4. A flow is app-specific — it operates on this app's objects — so the authoring surface belongs here rather than behind a deep link to another app's list. The ENGINE stays single (ADR-065): these pages are a scoped view onto OpenRegister's one native flow store, not a per-app store. Two manifest pages and one settings entry, no component files: `type: "flows"` and `type: "flow-detail"` are shipped page types in @conduction/nextcloud-vue 2.19.0, scoped by `config.app`. Note the layout of the diff: entries are appended textually rather than by reserialising the manifest. A `json.dump` round-trip rewrote pipelinq's file as a 3,950-line diff for a 20-line addition — correct output, unreviewable change. * build(deps): @conduction/nextcloud-vue 2.19.0 for the flows page types Required by the manifest change: `type: "flows"` / `type: "flow-detail"` are rejected by the compiled validator in earlier versions, and CI installs with `npm ci` — so the LOCK is what decides, not the `^2.x` range. Several of these locks were pinned many minors back, which is why some lockfile diffs are large: npm restructures the nested tree (mostly @esbuild platform binaries under @nextcloud/vue) to satisfy 2.19.0's peers. No direct dependency other than @conduction/nextcloud-vue changes. * test(router): classify the flow routes as vault-protected keepiq denies by default and asserts that every manifest page is explicitly classified, so adding two pages without classifying them fails — which is the test doing its job. Flows and FlowDetail are PROTECTED, not public. A flow in this app can read and write vault secrets, so the authoring surface must sit behind the lock exactly as the secret list does: a locked vault that still lets someone edit the automation over it is not locked. 656 unit tests green. * fix(icons): register Sitemap, or the Flows entry renders with no icon An icon name a manifest uses but src/icons.js does not register renders as NOTHING — not a fallback (ADR-077 rule 3). The Flows menu entry this PR adds uses `Sitemap`, and this app never registered it, so the entry would have shipped with an empty icon slot. Caught by gate-60 icon-vocabulary. I had checked `Sitemap` was registered in dossiq and carried the assumption to the fleet; each app keeps its own icons.js, and six of the twelve did not have it. The six failing gate runs were exactly those six apps. Both halves are required: the import alone is dead code, the registry entry alone does not resolve. * feat(flows): give the flow-detail canvas its sidebar The manifest _note claimed the controls rendered in the NC app sidebar, but the sidebarComponent field it described did not exist. Every #/flows/:id -- and #/flows/new, the same route with the literal id -- drew a bare canvas: savable and runnable, but with no way to name, describe, trigger or step-edit the flow, because those controls all live in CnFlowSidebar. Mirrors pipelinq#1490. ADR-110 Decision 4.
beta held 32 commit(s) development did not. Merged with -s ours: development's tree is kept BYTE FOR BYTE and only the ancestry is recorded. That is the payload -- without it the merge base never moves and the next development -> beta promotion conflicts on the version file exactly as before. 13 of 19 promotion PRs were CONFLICTING for this reason. Nothing is silently imported. What beta holds and development does not, and which this deliberately does NOT bring over: .forgejo/.beta-release-trigger .forgejo/issue_template/bug-report.yml .forgejo/issue_template/feature-request.yml .forgejo/issue_template/technical-task.yml .forgejo/issue_template/user-story.yml .forgejo/workflows/documentation.yml .forgejo/workflows/release-beta.yml .forgejo/workflows/release-stable.yml CODE_OF_CONDUCT.md CONTRIBUTING.md README.md SECURITY.md SUPPORT.md docs/scripts/validate-ai-baseline.mjs Those are dead Forgejo/Codeberg CI (removed from development on 2026-08-24/25 by 'chore(ci): remove dead Forgejo/Codeberg CI configuration'), generated Docusaurus build output, and community-health files that never existed on development. Each can be added deliberately if wanted; resurrecting them as a side effect of a sync is how a merge silently undoes a decision.
…260830084410 chore(sync): carry beta back into development
…0841 chore(sync): record beta's ancestry on development
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-30 09:11 UTC
Download the full PDF report from the workflow artifacts.
Dexie refuses to run twice in one page: it throws "Two different versions of Dexie loaded in the same app". Nextcloud loads openregister's global integration script and hermiq's agent leaf on every page, alongside whichever leaf app you are in, so all three have to agree on one dexie. After the dependabot sweep on 2026-08-30 they did not. openregister resolved 4.4.4 while hermiq resolved 4.4.5, and the throw happened before the leaf app mounted, so every app page rendered as bare Nextcloud chrome with no content. This pins the floor at ^4.4.5 and regenerates the lock, matching the apps that were already there. Verified in the browser: the Dexie error is gone from the console and app pages render their navigation and content again.
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 111/111 | |||
| npm | ✅ | ✅ 550/550 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-30 09:59 UTC
Download the full PDF report from the workflow artifacts.
Contributor
Author
Quality Report — ConductionNL/keepiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 111/111 | |||
| npm | ✅ | ✅ 550/550 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-30 10:32 UTC
Download the full PDF report from the workflow artifacts.
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.
Automated PR to sync development changes to beta for beta release.
Merging this PR will trigger the beta release workflow.