Skip to content

Release: merge development into beta - #607

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

Release: merge development into beta#607
github-actions[bot] wants to merge 19 commits into
betafrom
development

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automated PR to sync development changes to beta for beta release.

Merging this PR will trigger the beta release workflow.

Reminder: Add a major, minor, or patch label to this PR to control the version bump. Default is patch.

github-actions Bot and others added 6 commits August 31, 2026 10:44
The 0.2.11-beta.20260831104311 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.
…2.11-beta.20260831104311

chore(release): sync beta back into development
)

Bumps [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom) from 29.7.0 to 30.5.0.
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.5.0/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: jest-environment-jsdom
  dependency-version: 30.5.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>
Bumps [ajv-formats](https://github.com/ajv-validator/ajv-formats) from 2.1.1 to 3.0.1.
- [Release notes](https://github.com/ajv-validator/ajv-formats/releases)
- [Commits](ajv-validator/ajv-formats@v2.1.1...v3.0.1)

---
updated-dependencies:
- dependency-name: ajv-formats
  dependency-version: 3.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>
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.

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

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ 5a7f215

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

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

Download the full PDF report from the workflow artifacts.

#609)

Second app in the fleet-wide move off `#` routing, after stackiq
(softwarecatalog#899) proved the pattern.

Verified BEFORE switching, because history mode fails at the SERVER when
the AppHost SPA catch-all is missing: /apps/zaakafhandelapp/zaken and
/taken already returned 200 with the app shell.

Two parts, and the second is the one that matters:

1. createWebHashHistory -> createWebHistory.

2. routerBase(), derived from the URL actually being served. Nextcloud
   serves this app under BOTH /apps/zaakafhandelapp/... and
   /index.php/apps/zaakafhandelapp/..., but generateUrl() returns only
   the form the instance is configured for. Arriving on the other form
   leaves the path outside the router base, vue-router cannot resolve it,
   and the catch-all redirects to '/' -- the visitor lands on the
   dashboard with no error and the deep link is silently swallowed.

   This app's own e2e suite uses the /index.php form
   (tests/e2e/app-path.ts: APP = '/index.php/apps/zaakafhandelapp'), so
   without routerBase() every deep link the suite makes would break. That
   is exactly how it was caught on stackiq.

The 11 spec files built URLs as `${APP}/#/<route>`; all now use real
paths.

Verified against the published @conduction/nextcloud-vue
(USE_LOCAL_LIB=false):

  /apps/zaakafhandelapp/                    -> Dashboard
  /apps/zaakafhandelapp/zaken               -> Zaken
  /index.php/apps/zaakafhandelapp/zaken     -> Zaken
  /index.php/apps/zaakafhandelapp/klanten   -> Klanten
  RELOAD on /index.php/.../zaken            -> 200, still Zaken

That reload is the point: it is the case hash mode existed to avoid, and
the catch-all serves it rather than 404ing. No hash anywhere.

e2e: ui-nav-navigation + ui-case-views, 21 passed / 3 failed, and the
three re-ran green in isolation -- they failed on `cn-app-root` never
mounting, i.e. the shell did not boot, which is the shared dev container
dropping into maintenance mid-run rather than a routing regression.

eslint exits 0 and `prettier --check "**/*.{js,ts,vue,css,scss}"` is
clean -- the FULL glob, tests included, not just src/.

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ 70345c5

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

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

Download the full PDF report from the workflow artifacts.

…e de-hashing (#615)

Follow-up to #609, which turned E2E red on development: 12 failed / 81
passed where the previous commit was green. Both causes were mine.

1. THE DE-HASH SWEEP WAS TOO NARROW. It replaced `${APP}/#/x` but not
   `${APP}/#${route}`, where the route variable already carries its own
   leading slash. Three call sites kept the `#`, so under history routing
   they resolved to the app root and every assertion about the target
   page failed. spaNavigate() and gotoIndex() are the two helpers, which
   is why nine record-index tests went down together.

2. THE APP HAD NO CATCH-ALL. appinfo/routes.php enumerates a page route
   per index (/zaken, /klanten, …), so those deep links worked while
   anything NOT in that list -- /features-roadmap, /auditTrail, any
   detail route -- 404'd at the server. Under hash routing this never
   showed, because the route travelled in the fragment and the server
   only ever saw the app root.

⚠️ MY PRE-CHECK FOR #609 WAS WRONG, and this is the lesson: I probed
/zaken and /taken, which are both ENUMERATED routes, and concluded a
catch-all existed. Probing an enumerated path proves nothing. Probe a
NONSENSE path:

  /apps/zaakafhandelapp/zzz-nonsense -> 404   (no catch-all)
  /apps/stackiq/zzz-nonsense         -> 401   (catch-all present)

Re-probed every converted app that way afterwards; only this one and
openregister (still on hash routing, so unaffected) were missing it.

The catch-all is spelled inline rather than via Routes::standard(),
because this file also declares a `resources` block the builder does not
carry. It is LAST so every explicit route above keeps priority.

Also raised one test's budget from 90s to 240s, with the reason in the
file: it walks 8 index pages by hard goto. Under hash routing those were
SAME-DOCUMENT navigations; under history routing each is a full page
load, so the walk costs roughly an order of magnitude more wall-clock.
The assertion is unchanged.

⚠️ The catch-all does not take effect until Nextcloud's route cache is
dropped. With memcache.local = APCu, `occ app:disable/enable` is not
enough -- a container restart is.

Verified: ui-record-views 10/11 and ui-utility-pages 8/9, i.e. 11 of the
12 CI failures recovered. The one remaining is NOT routing: the audit
page reports "Could not load log entries" because OpenRegister answers
`Register not found: 'zaakafhandelapp'` on this workstation -- the
register is not provisioned locally, and CI seeds it.

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ 5c8d444

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

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

Download the full PDF report from the workflow artifacts.

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

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

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

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

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

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

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

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

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

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ 2d33688

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

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

Download the full PDF report from the workflow artifacts.

* fix(routes): stop the SPA catch-all swallowing the whole ZGW API

The catch-all added in #615 broke every GET on this app's seventeen
`api/...` resources. Measured on the dev instance:

  GET /apps/zaakafhandelapp/api/taken      -> 200 text/html (SPA shell)
  GET /apps/zaakafhandelapp/api/klanten    -> 200 text/html (SPA shell)
  GET /apps/zaakafhandelapp/api/zrc/zaken  -> 200 text/html (SPA shell)

⚠️ It fails SILENTLY. The shell is served with HTTP 200, so a JSON caller
gets a 200 with HTML in it -- no 404, no 500, nothing in the log. The
response was byte-identical to a nonsense path like /zzz-nonsense, which
is what gave it away.

Being LAST in the `routes` array is not enough, and that is the trap.
Nextcloud's RouteParser processes the `routes` array BEFORE the
`resources` array (RouteParser::parseDefaultRoutes builds the routes
collection, then addCollection()s the resources one) and Symfony matches
in insertion order. So the catch-all registers ahead of every
resource-generated route no matter where it sits among the routes. On top
of that, `.+` overrides Symfony's default `[^/]+` and therefore matches
slashes, so `/{path}` happily consumed `api/zrc/zaken`.

`(?!api/)` is the fix: the SPA never needs an `api/` path, and a lookahead
leaves every other deep link untouched (`apixyz` still routes to the SPA;
only the `api/` prefix is excluded).

Verified on the dev instance after a container restart -- the route cache
is APCu-backed, so `occ app:disable/enable` is NOT enough to pick a
requirements change up:

  api/taken, api/klanten, api/zrc/zaken   -> reach their controllers
  zaken, auditTrail, zzz-nonsense         -> 200, SPA shell (unchanged)

The API calls now answer 500 `Unknown object type: taken` rather than
HTML, which is a pre-existing local seeding gap: the point is that app
code RUNS again instead of the request being answered by the shell.

tests/Unit/RoutesCatchAllTest.php guards it, and asserts the requirement
as a REGEX against real paths rather than as a literal string, so it keeps
holding if the spelling is ever rewritten. Confirmed it FAILS on the
pre-fix `.+` ("the catch-all must NOT match api/taken") and passes on the
fix -- 3 tests, 15 assertions. phpcs: 0 errors.

The same lookahead is going into \OCA\OpenRegister\AppHost\Routes so no
future adopter of `Routes::standard()` inherits this. zaakafhandelapp is
the only app in the fleet that declares both a `resources` block and a
catch-all, so the blast radius of the original defect is this app alone.

* test(contract): cover dashboard#catchAll, the endpoint gate-25 flagged

gate-25 (contract-coverage) has been failing on development since #615 --
"1 new public endpoint(s) missing a contract test". That endpoint is
`dashboard#catchAll`: #615 added a public, network-facing GET /{path} and
no test that exercised it.

Covered rather than excluded, for the same reason the five page routes in
this file are: serving no data does not make a route contract-free.
catchAll() delegates to page(), and a delegation that quietly rendered as
a guest or pointed at the `error` template would hand every deep link a
blank page while still answering HTTP 200. So the test asserts the full
shell contract -- status, app, template, renderAs, params -- and then
asserts equality with page() so a future rewrite that stops delegating
has to say so out loud.

287 unit tests pass, phpcs 0 errors.

---------

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ 13404e0

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

Quality workflow — 2026-09-01 12:31 UTC

Download the full PDF report from the workflow artifacts.

… inside (#622)

its own card.

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

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

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

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

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

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

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

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ 7e21ff0

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

Quality workflow — 2026-09-02 19:08 UTC

Download the full PDF report from the workflow artifacts.

* feat(nav): give zaakafhandelapp a flows surface of its own

ADR-110 Decision 4: a zaakafhandelapp flow operates on cases, so the authoring
surface belongs in the app whose objects it drives rather than behind a link to
another app's list. This was one of two apps with a manifest-driven UI and no
flow surface at all.

Adds the Flows entry to the settings foldout and its /flows and /flows/:id
pages on the shared CnFlowIndexPage and CnFlowDetail, scoped app:"zaakafhandelapp".
type:"index" over the named flows source is the canonical shape; nextcloud-vue
marks the dedicated `flows` page type deprecated.

Also moves Features & roadmap from order 91 to 100. ADR-114 Decision 1 fixes
the footer orders fleet-wide (Documentation 90, Store 92, Reports 95, roadmap
100); 91 reads the same today and would have put roadmap above Store and
Reports the moment either lands.

* fix(l10n): add the flow labels to en and regenerate the js catalogues

l10n/*.js are GENERATED from the matching .json by scripts/build-l10n-js.js, so
the hand-edit did not match generator output. Regenerated, and Flow / Flows go
into en.json too so the two catalogues agree.

* fix(l10n): translate the new chrome labels into every required locale

tests/l10n/check-l10n-parity.js requires all 36 European locales to carry every
English source key, in BOTH the .json catalogues and the .js ones. A new
user-facing label is therefore 36 translations, not one.

Measured against origin/development before and after: 0 missing keys on the base,
so these are the strings this branch introduced and nothing else.

The .js catalogues are generated from the .json by scripts/build-l10n-js.js and
were regenerated, not hand-edited.

* feat(walkthrough): point the getting-started tour at the new flows surface

gate-70 (walkthrough-flows-stop) reds an app that ships a flows page whose tour
never mentions it: the surface is then discoverable only to somebody who
already knows it is there. Adding Flows in this branch armed that gate, and it
fired.

The stop is view-only, per the gate's own forcing-flows-stop rule: optional,
allowManualNext, and it advances on a route match rather than on creating a
flow. Nobody is made to author automation to finish the tour.

target.ref is the PAGE id `Flows`, not the menu id `FlowsMenu`.
CnWalkthrough.resolveTarget() looks a nav-item ref up as
[data-cn-route="<ref>"], which CnAppNav sets from item.route, so a stop keyed
on the menu id resolves to nothing. An OPTIONAL step whose target is absent is
SKIPPED silently, with no console error and no change to the step count, so
that mistake does not degrade politely: the stop simply never appears.

The English copy is three short sentences on purpose. One claim per sentence
translates safely into 36 locales; a compound one does not. All three strings
are added to every required locale, the way #339 added the CnTabs aria-labels.

---------

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

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/zaakafhandelapp @ b67ec96

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

Quality workflow — 2026-09-03 11:10 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 7 commits September 3, 2026 14:52
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>
…ready had (#627)

ADR-114 Decision 3 puts Reports in every app. Nothing is invented here: the
audit trail already existed, and it was an entry in the SETTINGS foldout.

That was the wrong home for it. The settings foldout is where configuration
lives (ADR-044 Decision 3), and an audit trail is not configuration — it is a
reading of what happened, which is what a report is. It becomes a card on
/reports; the PAGE is untouched and stays routable at /auditTrail, because a
report is a card or an entry, never both (ADR-112 Decision 2).

Case types and roles stay in the foldout. They ARE configuration, and the e2e
asserts that asymmetry so a later sweep that cards them fails a test rather
than passing review.

Three new strings, translated into all 36 required locales. The parity check
reports full parity, not merely no regression.

Verified: gate-22, gate-53, gate-60, gate-102, gate-104 and gate-107 clean;
prettier clean; all five e2e tests collect.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
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
ADR-114 puts Documentation, Store, Reports and Features & roadmap in the
footer in that order. This app had three of the four; gate-107 goes from
4 of 5 to 5 of 5.

The page writes no backend. Openregister hosts the store plane, so
adopting it is a type:"store" page plus a top-level `store` block and
nothing else. With no registry configured the page renders the app's own
items and makes no network call.

There is deliberately no `installable` allowlist, following decidiq's
precedent: a configuration set exists to introduce schemas the instance
does not have yet, so listing schemas this app already owns would refuse
exactly the sets worth installing. An EMPTY `installable` would mean
install NOTHING rather than install anything, so omitting the key and
declaring an empty list are different things.

StoreOutline had to be registered in src/icons.js. An unregistered name
renders no glyph at all, with no fallback and no console error.

nextcloud-vue moves ^2.31.1 -> ^2.36.1, the version that ships
CnStorePage; without it the store page renders nothing. The published
tarball was unpacked to confirm the component is in it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(chrome): give zaakafhandelapp a Store
One test red on every development push since #627, and it was right to fail: it
asserted a menu entry that #627 deliberately removed.

ADR-112 D2 says a report is a card OR an entry, never both, and an audit trail
is a reading of what happened rather than configuration. So #627 moved
AuditTrail out of the settings foldout and onto the Reports page, leaving the
page untouched and still routable at /auditTrail. It did not update the nav
spec, which kept asserting `cn-nav-entry-AuditTrail` was attached — and an id
with no menu entry can never be attached, so the assertion could only fail.

Nothing goes unwatched by removing it. app-chrome.spec.ts already asserts BOTH
halves of that move: that no `cn-nav-entry-AuditTrail` exists, and that the
Reports page reached from the footer offers it. SETTINGS_NAV_IDS only claims
which entries the settings foldout still holds.

menu-layout.json was left behind by the same commit. A settingsSection id with
no matching menu entry is a silent no-op, so `AuditTrail` sat there pointing at
nothing with nothing to report it. Removed, with the trap written into the file
rather than only into this message.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant