feat(setup): ask which example data to load, as cards, instead of a bare Run button - #1796
Conversation
…are Run button 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: Claude Opus 5 (1M context) <noreply@anthropic.com>
lib/Controller/SetupController.php:367:38: UnusedParam: Param actionId is
never referenced in this method
Every other app in this rollout uses `$actionId` to tell the legacy
`install-demo-data` id from the new one, because there the legacy id means
"the shipped set" and has to skip the "pick one first" refusal. Here the legacy
id is `seed-demo-data` and it still dispatches straight to `seedDemoData()`, so
`loadDataset()` never had a second caller to distinguish.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ❌ | ||||
| psalm | ❌ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ❌ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ❌ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 10:34 UTC
Download the full PDF report from the workflow artifacts.
…d without `test:l10n` and `l10n coverage (en.json)` fail on `development` itself, not on this branch. Measured on a clean archive of `origin/development`: exit 1, 97 translation keys used in source and missing from `l10n/en.json`. They arrived with the marketing surface merged an hour ago. Written by the check's own `--write`, which is what its failure message tells you to run: the key IS the English source, so the extraction is mechanical and reviewable in the diff rather than a judgement call. They are still untranslated in nl.json. That is a separate piece of work and this check does not ask for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ❌ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ❌ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 10:40 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ❌ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ❌ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 10:57 UTC
Download the full PDF report from the workflow artifacts.
…ting views shipped Three checks fail on this branch and two of them are not this branch. `check:l10n-js` reported `l10n/en.js` stale: the 97 keys extracted into en.json in the previous commit had not been built into the browser catalogue, which is the file the app actually loads. `stylelint` names two files this branch does not touch, both from the marketing surface merged into development an hour ago: CompetitorWatches.vue:404 word-break: break-word is deprecated SocialPerformanceView.vue:149 text-align: left, should be start `break-word` becomes `overflow-wrap: anywhere`, which is the modern spelling of "break rather than overflow" and leaves `word-break` its own meaning. `left` becomes `start`, which is the same thing in a left-to-right locale and the right thing in a right-to-left one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 11:02 UTC
Download the full PDF report from the workflow artifacts.
All six PHPUnit cells fail, and they fail on `development` too: zero failures,
zero errors, nineteen tests RISKY because strict coverage refuses a test that
executes a class its `@covers` list never mentions. They came in with the
marketing surface.
This test executed code that is not listed as code to be covered or used:
- OCA\Pipelinq\Service\Competitor\WatchOutcome
- OCA\Pipelinq\Service\Egress\EgressResult
- OCA\Pipelinq\Service\Search\HtmlTextExtractor
- OCA\Pipelinq\Service\Search\ExpectedCtrCurve
- OCA\Pipelinq\Service\Matomo\MatomoReportService
`@uses` rather than `@covers`: these tests pass through those classes on the
way to their subject rather than asserting on them.
The RISKY only surfaces WITH a coverage driver, which is why the local runs
that produced these tests were green — `--no-coverage` never evaluates the
list.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…declares
The Newman job fails before a single request runs:
::error::Demo-data seeding failed (HTTP 500)
Property 'stageEnteredAt' should match format 'date-time' but
'2026-09-02' does not.
`@days:N` resolves to `Y-m-d` and `@datetime:N` to a full ATOM timestamp. Two
lead definitions fed the first into a property the register declares as
`format: date-time`, so OpenRegister refused the object and the whole seed
returned 500.
Checked the rest against the register rather than by eye: `endDate`,
`expectedCloseDate` and `startDate` are the only other `@days` fields and none
of them is a date-time property.
The seeder is what the e2e and Newman suites both provision from, so this made
every list and dashboard spec run against an empty instance.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 11:07 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 11:13 UTC
Download the full PDF report from the workflow artifacts.
The step is a choice followed by a run-action now. `seed-demo-data` recorded the decision and not the dataset, so after a successful seed the choice step was still unmet, and CnAppRoot opens the wizard while ANY optional step is outstanding: every operator, on every fresh browser profile, got the app covered by the wizard after asking for demo data and receiving it. CI caught it rather than a person: the seed script asserts that no optional step is left unmet, and it failed with 48 demo objects already in the database. Seeding IS choosing the set, so it writes both keys, the way skipping already wrote both. The new controller test covers the whole step pair: what status reports, that the option list travels with it, that an unknown dataset is refused rather than stored, that running without a choice seeds nothing, and that a failed seed leaves the step undecided rather than closing it for someone who received no data. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ✅ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 11:19 UTC
Download the full PDF report from the workflow artifacts.
…hrough All six PHPUnit cells went red on a suite that is green locally. `beStrictAboutCoverageMetadata` makes a test RISKY when it executes a class its coverage block does not name, and that check only runs with a coverage driver, which this machine has none of. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report — ConductionNL/pipelinq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 637/637 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-05 11:37 UTC
Download the full PDF report from the workflow artifacts.
The problem, and it is not only cosmetic
The demo-data step was a Run button under a paragraph. The paragraph said the data is 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. This app implements a
skip-demo-dataaction that no manifest step could reach — the only step was the run-action that installs. So an operator who did not want example data could not record that,demo-datastayeddone: false, andCnAppRootreopens the wizard while any optional step is outstanding: over every page, on every fresh browser profile, 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:
Picking one is an answer.
nonecloses both steps without importing anything.The list comes from
GET /api/setup/statusasdatasets: the step declaresoptionsSourceand carries no options of its own, so nothing in the manifest can disagree with what will 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
objectCountand renders as a stat with a label the library translates.Compatibility
install-demo-datastill works and still means "the dataset this app ships", so a runbook or script that posts it keeps working.skip-demo-datanow writes both keys instead of only the decision flag.Verification
Depends on
@conduction/nextcloud-vue2.37.0 —CnChoiceCardsand thedisplay/optionsSourcemanifest keys (feat(setup): let a choice step explain itself, as cards over a server-owned list nextcloud-vue#996, published frommain).composer.lockhere.Follows ConductionNL/decidiq#1152 and ConductionNL/filinq#1010. This app SEEDS its objects rather than importing a descriptor, so the card names what the seeder creates and carries no object count: there is no honest number until it has run.
🤖 Generated with Claude Code