Skip to content

Release: merge development into beta - #725

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

Release: merge development into beta#725
github-actions[bot] wants to merge 29 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 2 commits August 31, 2026 10:29
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>
rubenvdlinde and others added 2 commits August 31, 2026 13:15
…1.44-beta.20260831102716

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

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

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

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 9f38eb6

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

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

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ dd73b23

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:40 UTC

Download the full PDF report from the workflow artifacts.

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

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ d8c0ae7

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 14:40 UTC

Download the full PDF report from the workflow artifacts.

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>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 0d15e39

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 16:41 UTC

Download the full PDF report from the workflow artifacts.

`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>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 41f1029

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 17:55 UTC

Download the full PDF report from the workflow artifacts.

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

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 0832f6a

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 20:47 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 2 commits September 1, 2026 06:59
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>
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ bfaeacb

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-09-01 05:19 UTC

Download the full PDF report from the workflow artifacts.

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 0bfc89e

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-09-01 05:36 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ e131891

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-09-01 06:09 UTC

Download the full PDF report from the workflow artifacts.

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

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

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

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

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

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

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

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

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

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 595b1bc

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-09-01 10:43 UTC

Download the full PDF report from the workflow artifacts.

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.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 3db7ebb

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-09-01 17:15 UTC

Download the full PDF report from the workflow artifacts.

* 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.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 13e81ed

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-09-02 11:03 UTC

Download the full PDF report from the workflow artifacts.

…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.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ e589aad

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-09-02 12:16 UTC

Download the full PDF report from the workflow artifacts.

…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.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 8942c11

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-09-02 13:17 UTC

Download the full PDF report from the workflow artifacts.

… 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>
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 7febe3a

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-09-02 19:19 UTC

Download the full PDF report from the workflow artifacts.

…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.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ dbb9e74

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-09-02 19:44 UTC

Download the full PDF report from the workflow artifacts.

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.
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/hermiq @ 5074ddf

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-09-03 10:26 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 10 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>
…#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>
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