Release: merge development into beta - #758
Open
github-actions[bot] wants to merge 117 commits into
Open
Conversation
…action-surface Artifacts only. Every task box is unticked; nothing here is wired to anything yet, and each change is picked up by `/opsx-apply` when it is scheduled. Committed because these were sitting UNTRACKED in the shared checkout across ten apps at once. An untracked directory is one file-sweep away from being swept into an unrelated commit and one branch switch away from being lost, and these carry the design reasoning rather than just a title.
…0260820130046 chore(release): 0.1.141-unstable.20260820130046
…0260820201847 chore(release): 0.1.141-unstable.20260820201847
…0260820203911 chore(release): 0.1.141-unstable.20260820203911
…0260820205557 chore(release): 0.1.141-unstable.20260820205557
`CnObjectDataWidget.editable` defaults to TRUE, so every property named in a data widget's `include` list becomes a text box the user can type into. That put lifecycle state and audit stamps — `status`, `lifecycle`, `submittedAt`, `approvedBy`, `openedAt`, `closedAt`, `publishedAt`, `enactedAt` — in front of users as editable fields. These are written by the backend when a transition lands (`TransitionEngine` stamps them through `saveObject()`), so an input for them is a control that can only ever fail or confuse: the guarded path is the lifecycle buttons, and `LifecycleValidationListener` rejects anything that is not a legal transition. Locked with per-field `overrides.<field>.editable: false` rather than `editable: false` on the widget: these panels mix process state with fields the user legitimately edits, and a blanket lock would make those read-only too. NOT fixed here: widgets that declare no `include` at all render EVERY schema property, and enumerating their fields in the manifest would drift the moment the schema changes. 52 such widgets fleet-wide expose 124 process fields. Closing those needs a server-side "system-owned" marker, which OpenRegister does not have — `readOnly:true` has no bypass for backend callers and would break the transition that writes the field. Filed as ConductionNL/openregister#2644. Inserted textually, one compact line per widget, so the diff is the change and nothing else: a full JSON re-serialisation reflowed hand-compacted lines and turned this into thousands of lines of churn. A verifier re-parses both files and asserts the only structural difference is the added overrides, and that no non-process field was locked.
…0260820212102 chore(release): 0.1.141-unstable.20260820212102
…0260820214311 chore(release): 0.1.141-unstable.20260820214311
…0260820220515 chore(release): 0.1.141-unstable.20260820220515
fix(manifest): process and audit fields are no longer editable inputs
…0260820223149 chore(release): 0.1.141-unstable.20260820223149
…0260820224848 chore(release): 0.1.141-unstable.20260820224848
stylelint 15.11.0 -> 17.14.1 with every package that peers on it: @nextcloud/stylelint-config ^2.4.0 -> ^3.2.2 stylelint-config-recommended-scss ^13.1.0 -> ^17.0.1 stylelint-config-recommended-vue ^1.6.1 -> ^2.0.0 postcss-html ^1.8.1 -> ^2.0.0 stylelint-config-html (absent) -> ^2.0.0 None can move alone: vue-config@2 peers 'postcss-html ^2.0.0' and 'stylelint-config-html >=2.0.0'; postcss-html@2 breaks vue-config@1.6.1's own '^1.0.0' peer; scss-config@17 peers 'stylelint ^17'. @nextcloud/stylelint-config is the member that decides it — v2.4.0 still declares indentation / string-quotes / number-leading-zero / selector-list-comma-newline-after, all removed in stylelint 16. Then 10 real errors, in 4 files: 8x word-break: break-word -> overflow-wrap: break-word 1x word-wrap: break-word -> overflow-wrap: break-word 1x clip: rect(0,0,0,0) -> clip-path: inset(50%) Fixed by hand, NOT with --fix. The autofix also rewrites the 86 advisory csstools/use-logical warnings (text-align: left -> start, padding-left -> padding-inline-start, ...) across 28 files. Those change how the UI lays out under RTL and have nothing to do with this bump; openbuild, scholiq and hermiq all carry the same warnings unfixed. A dependency upgrade should not smuggle in a directional-CSS change. Result: 10 errors -> 0, exit 0. The 86 warnings are unchanged and non-blocking.
…0260820231107 chore(release): 0.1.141-unstable.20260820231107
…0260820233952 chore(release): 0.1.141-unstable.20260820233952
build(deps-dev): move the whole stylelint family to 17 as one upgrade
…0260821000125 chore(release): 0.1.141-unstable.20260821000125
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The catalog register's slug moves with the app's identity, and a repair step renames the existing row BEFORE the import so the rename lands on the register that already holds the data. Why the repair step is not optional. OpenRegister resolves a register by SLUG and by nothing else, and its not-found branch is not an error path — it is the "create a new one" path. Shipping the renamed slug in the register JSON alone would therefore rename nothing: the import finds no match, CREATES A SECOND, EMPTY REGISTER, and every stored object stays behind on the old row, reachable by nothing. Nothing errors; the app just looks new. Why it moves no data. An object is bound to its register by NUMERIC id — every shard table's `_register` column holds the id, and the tables are named `oc_openregister_table_<registerId>_<schemaId>`. The slug appears nowhere in the physical layout, so this is a one-column UPDATE on one row (id 11 on the dev instance, which it keeps). The step is idempotent, non-destructive, and never throws (it runs under <install>, where an escaping exception aborts the install and the app never enables). When both the old and new slugs already exist it REFUSES and renames neither — merging two registers is a decision about data, not a rename. It also re-points a stored app-config `register` value that still holds an old slug, guarded on the VALUE rather than the key. `vng-gemma` deliberately stays exactly as it is: it holds VNG GEMMA reference data, is not this app's own store, and its name is answered to elsewhere. Also fixes an inconsistency the app-id rename left behind: `x-openregister.app` has said `stackiq` since #708 while the register row still said `voorzieningen` — which is precisely the fork this step exists to prevent. Installs that have imported since then may already carry an empty `stackiq` register, and the step refuses rather than merging on those.
…ace moved (#728) * fix(decidiq): contract delegation was silently off — the event namespace moved `ContractApprovalService` pinned `\OCA\Decidesk\Event\DecisionRequestedEvent`. The decision app renamed to `OCA\Decidiq` with no compatibility alias, so `isDelegationConfigured()` began returning false on instances where the app was installed, and contract approvals stopped delegating. Nothing reported it, and nothing could: `class_exists` going false is exactly what an uninstalled optional app looks like, which is the case the guard was written for. The feature reads as "not configured" rather than "broken". Measured on a running instance: OCA\Decidesk\Event\DecisionRequestedEvent MISSING OCA\Decidiq\Event\DecisionRequestedEvent EXISTS The constant is now a LIST, newest first, resolved to the first that exists. The old spelling stays until no supported install ships it — dropping it would break the integration in the other direction during a staggered upgrade, which is the window this broke in to begin with. An app cannot move another app's class name; it can only follow it. So the test asserts that property rather than a literal: the list names the current namespace, tries it first, and still names the old one. Pinning one spelling fails a test now instead of silently disabling a feature later. NOT changed: `SOURCE_APP = 'softwarecatalog'`. That is this app's id AS THE DECISION APP KNOWS IT and is echoed back on the conclusion event, so it moves only when both sides move together. Found by a fleet sweep for stale cross-app namespaces after the same defect was confirmed in dossiq; openregister (→ Keepiq) and decidiq (→ Filinq) carried it too and are fixed in their own repos. * fix(psalm): resolve the event class ONCE, and narrow it where it is used Psalm rejected the previous commit: `Type null cannot be called as a class` at `new $eventClass(...)`. It was right, and the shape it caught is worth naming. The method called `isDelegationConfigured()` — which resolves the class and throws away the answer — and then resolved AGAIN at the call site with no guard. Two lookups of the same thing, only the first of them checked. The second had a `?string` reaching `new`, so an instance with no decision app installed would have gone from a clear "delegation is not available" to a fatal on a null class name. Now it resolves once, narrows, and fails closed on the null — the same refusal as before, from the value actually used.⚠️ I did not run psalm locally before pushing; I ran phpunit, phpcs and phpstan, and phpstan does not flag this. One tool green is not the gate green, and the tools disagree by design. psalm "No errors found", phpcs 0, phpstan [OK] on the touched file.
#724) The final step had no `task`, so the guided tour stopped without telling the user where to go next. It now closes on the documentation, per the fleet rule that a walkthrough's last step points somewhere. The CTA targets the `Documentation` nav item that already exists in this app's menu, so it lands on a real destination rather than a URL invented for the copy. The same step also carried voice defects the shared writing skill bans: "Nicely done" is praise rather than voice, the em-dash is stripped fleet-wide, and "reopen this tour anytime from the … menu" is housekeeping in the one line a user is most likely to act on. The title now states what the user actually has, and the body says what to do with it.
…es this site (#726) * fix(docs): publish from development, to the worker that actually serves this site Two silent failures, both of which had to be fixed before this site could update at all. 1. The workflow triggered on `documentation`, a branch that exists but nobody updates. Green and idle for months while the live site aged. 2. `worker-name` was never passed, so the callee derived it from `cname`. Since the app-id rename `cname` is the NEW host, while the worker that actually holds the custom domains is still named after the OLD app id. The derived name points at a worker that does not exist — deploying it CREATES a second worker while both custom domains keep routing to the original. Every deploy green, reaching nobody, with the live-site verification added in ConductionNL/.github#555 as the only thing that would ever have noticed. Measured today: both hostnames still serve the pre-rename title while docs/docusaurus.config.js has carried the new one since the rename. Nothing has carried a build to the edge. * fix(docs): ship the og:image file the config already names The docs build FAILS, and has been failing — it was simply never run, because the workflow triggered on a branch nobody updates. Making the trigger correct surfaced it on the first run. The app-id rename updated `docusaurus.config.js` to point og:image at the new filename and left the actual PNG under its old name, so the AI-baseline validator's last check fails: ✗ og:image URL resolves to a file in the build and `npm run build` exits 1 via postbuild. Nothing could have published even with a correct trigger and a correct worker. Renames the asset to the name the config has been asking for. No references to the old filename remain. Verified locally: npm ci --legacy-peer-deps && npm run build now exits 0 with all 10 AI-baseline checks passing.
GitHub is the only host for this org — Codeberg was a mirror and is no longer used, including for issues. Many of these links also carried a PRE-RENAME repo name: this repo is now ConductionNL/stackiq (was softwarecatalog), nldesign is thematiq, OpenConnector is integriq, and decidesk is decidiq. Converted (24 files): - 21 PHP @link docblock tags -> github.com/ConductionNL/stackiq (13 files) - 4 PHP @link tags naming OpenConnector -> github.com/ConductionNL/integriq - 8 README dependency links (openregister, opencatalogi, nldesign->thematiq, tilburg-woo-ui, launchpad) - docs/static/llms.txt org link -> github.com/ConductionNL (its label already said "GitHub") - .forgejo/workflows/tests-live.yml: the live `git clone` of openregister was still pointing at codeberg.org — CI would clone from a dead host. - 4 hydra change records ("repo" field, issue-less only) Issue / PR numbers deliberately NOT mapped. Codeberg numbers do not correspond to GitHub ones, so rewriting only the host would point at a real but unrelated GitHub item. The two decidesk PR-160 links are replaced with plain text. Deliberately left alone (see PR body): - 32 "configuration" URLs in lib/Settings/softwarecatalogus_register.json. These are RUNTIME-fetched register config pointing at opencatalogi/.../publication_register_magic.json — a file that does not exist in ConductionNL/opencatalogi on ANY branch. Repointing the host would swap a dead Codeberg URL for a dead GitHub one and merely look fixed. - 4 hydra records whose codeberg "repo" sits next to an issue number/URL. - The beta-surface-alignment openspec requirement that MANDATES the word "Codeberg" in docs/GOVERNMENT-FEATURES.md, and that doc line. - .forgejo runner labels and the CODEBERG_TOKEN secret reference.
This repository's only issue forms lived under `.forgejo/issue_template/`. GitHub is the fleet's only host, so those forms are invisible to everyone filing an issue here. Two approved fleet changes make this urgent: 1. `.forgejo/` is being removed fleet-wide. Without this port that removal would delete the only issue forms this repo has, leaving contributors with a blank issue box. 2. The shared library's `DEFAULT_FORGE` moves from `codeberg` to `github`. The in-product "Request a feature" deep-link then targets a GitHub Issue Form named exactly `feature-request.yml`. If that file is absent GitHub silently drops every pre-filled field instead of erroring, so the app context (app, page, surface, object, spec-ref) would be lost without a single visible failure. Copies all four templates to `.github/ISSUE_TEMPLATE/`, keeping the filenames identical. `.forgejo/` is deliberately left untouched; its removal is a separate later change. Conversion is lossless: Forgejo's issue-template schema is derived from GitHub's, and every construct used here (markdown/input/textarea/dropdown blocks, `render: shell`, `validations.required`, `labels`, `assignees`, `title`) is valid GitHub issue-form syntax. Nothing was dropped or reworded. The top-level `type: "Feature"` in feature-request.yml was verified against the ConductionNL org issue types, where "Feature" exists and is enabled. No `config.yml` was added: `.forgejo/issue_template/` has no equivalent.
'quality / E2E Tests (Playwright)' has been red on development. The product
is fine; the assertion was ambiguous.
Each component row renders the NAME and its purl, so getByText('lodash')
substring-matched two spans — <span>lodash</span> and
<span>pkg:npm/lodash@4.17.21</span> — and Playwright's strict mode failed
the assertion rather than choosing one. Adding the purl column is what made
a previously-unique string match twice, so this broke without either the
component or the test being edited.
The express assertion had the identical defect and never ran: the lodash
line failed first and masked it. Fixing only the reported line would have
surfaced express as the next failure. Verified against the fixtures —
cyclonedx-1.5-valid.json is express/pkg:npm/express@4.19.2 and vue.
The absence assertion is deliberately left as a substring match: for
'is it gone' the looser match is the STRONGER claim, since it also fails if
the purl survives, and toHaveCount tolerates multiple matches so strict mode
never applies there.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…stackiq application id (#723) * fix(repair): move OpenRegister schemas from softwarecatalog onto the stackiq application id OpenRegister resolves a REGISTER by slug alone, but a SCHEMA by the PAIR (application, slug) via SchemaMapper::findByApplicationAndSlug(). This app passes appId: Application::APP_ID = 'stackiq', while every schema it already owns still carries application = 'softwarecatalog'. The pair matches nothing, and ImportHandler's not-found branch is not an error path — it is the create-a-new-one path. The next import therefore builds a second, EMPTY schema set under the new application id while every stored object stays bound to the old rows. Nothing errors; the app renders empty collections. Measured on a live install: 21 schemas under softwarecatalog, zero under stackiq, and zero slug collisions — all 21 move cleanly. A DIFFERENT COLUMN from RenameDutchSchemaSlugs (that step rewrites openregister_schemas.slug, this one openregister_schemas.application), and the third store keyed by app id after oc_appconfig and oc_preferences. Registered after RenameDutchSchemaSlugs so the collision check sees the final slugs, and before InitializeSettings because that triggers the register import. The step refuses rather than merges where a slug already has a twin under the new application id, distinguishes a FAILED READ from an EMPTY RESULT, never deletes a schema and never throws — it runs under <install>, where an escaping exception aborts the install. * fix(repair): run RenameDutchSchemaSlugs before the schema re-point on install E2E failed on one test: the SBOM component table showed "lodash" twice where the second import should have replaced the first. Development is 95/0; this branch was 94/1, and the pre-merge commit on this branch was green — so the merge introduced it. Cause is a missing prerequisite in <install>. MigrateSchemaApplicationId says of its own position: POSITION IS LOAD-BEARING IN BOTH DIRECTIONS. After RenameDutchSchemaSlugs, so the collision check is judged against the slugs the rows will actually carry; before InitializeSettings, which is what triggers the register import. <post-migration> honours that — MigrateRegisterSlug, RenameDutchSchemaSlugs, then MigrateSchemaApplicationId. <install> ran the first and third and skipped the second, so on the fresh-install path the collision check was judged against pre-rename slugs. That path is not an edge case: an app-id rename presents to Nextcloud as a fresh install, which is the whole reason this block repeats the steps. The failure mode follows from the step's own contract — it refuses rather than merges, leaving two rows where it sees a twin. Two schema rows is two component rows, which is the duplicate "lodash" the test caught. I had also claimed in the merge commit that the ordering constraint was against MigrateRegisterSlug. It is not; it is against RenameDutchSchemaSlugs, a different class rewriting a different column.
GitHub is the only host this organisation publishes to. No local checkout has a Codeberg git remote, so nothing is pushed there and no workflow under .forgejo/ has ever run for this repository. Issue templates: the 4 templates under `.forgejo/issue_template/` were already ported to `.github/ISSUE_TEMPLATE/` and were verified present there before deletion (including `feature-request.yml`, which the in-product "Request a feature" deep-link targets by that exact filename). Release workflows: the deleted `.forgejo/workflows/` release jobs (release-beta.yml release-stable.yml ) are superseded by `.github/workflows/release.yml`, which is the live release path for this repository. .github/workflows/ is untouched — that is the live CI. Any CODEBERG_TOKEN reference lived only inside the deleted files and goes with them. Removes 12 file(s) under .forgejo/.
* fix(docs): pass secrets to the reusable documentation workflow A called workflow receives no secrets from its caller unless they are passed explicitly or inherited. Without `secrets: inherit` the callee sees an empty `secrets.CF_API_TOKEN`, its "Publish to the Cloudflare Worker" step skips itself on its own guard, and the run finishes green having written only gh-pages — which nothing serves. The live docs site never changes and no check goes red to say so. Measured on planninq run 32715324775: all three jobs green, GitHub Pages deploy success, Worker publish skipped, warn step reporting the Worker was not updated. * fix(docs): map the Cloudflare secrets explicitly instead of inheriting all `secrets: inherit` handed the reusable documentation workflow every secret this repo holds — the Nextcloud signing cert and key, the appstore token, the deploy keys — for the sake of two Cloudflare values. It also would not have worked. The org secrets are CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID and `inherit` passes secrets under their original names, while the callee reads CF_API_TOKEN / CF_ACCOUNT_ID — so the publish step would still have skipped itself and the run would still have gone green over an unchanged live site. Maps the two names explicitly instead, so nothing else crosses the boundary. Depends on ConductionNL/.github#568, which declares both as optional secrets on the callee: an explicit mapping only compiles for names the callee declares. * fix(docs): map the Cloudflare secrets from the names that actually exist This branch introduced the mapping reading `secrets.CLOUDFLARE_API_TOKEN` / `secrets.CLOUDFLARE_ACCOUNT_ID`, which are not secrets anywhere in this org. Mapping from a non-existent secret is not an error - it yields an empty string - so the callee`s "Publish to the Cloudflare Worker" step would have skipped itself on its own guard and the run would still have gone green, exactly the failure this PR set out to fix. Caught before merge; measured on planninq run 32760529026, where the same spelling did land. The real org secrets are CF_API_TOKEN / CF_ACCOUNT_ID, the same names the callee declares and the same ones ConductionNL/.github deploy-docs.yml reads directly. Only the mapping values change; the keys stay. The comment claimed the names differ on each side. They do not, and that claim is what produced the wrong values. Replaced with the reason that still holds: `secrets: inherit` would hand the callee every secret this repo holds for the sake of two Cloudflare values.
Closes #739. Running the repo's own lint fixer produced a file the repo's own format check rejected, so fixing lint the documented way landed a red `Frontend Check (format)`. It is not a rule disagreement, and eslint-config-prettier cannot prevent it. That package only turns rules OFF, and the culprit is not a formatting rule: `import-extensions/ban-inline-type-imports` rewrites an import, and its AUTOFIXER emits its own text — import type {Page} from '@playwright/test'; — which is not what prettier wants (`{ Page }`, no semicolon). Any autofixer that constructs source can do this; disabling formatting rules does not stop it. So `lint-fix` now re-runs the formatter afterwards, which makes the two tools ordered instead of competing: eslint decides what the code SAYS, prettier decides how it LOOKS, in that order, always. That matches the config's own stated doctrine — "exactly one of them is allowed an opinion and prettier is it". Verified both directions on a clean tree: `eslint --fix` alone leaves prettier --check REJECTING, and the chained script leaves it passing. WORTH KNOWING, and the reason this went unnoticed: the two tools do not cover the same files. lint -> eslint src (src only) format -> prettier "**/*.{js,ts,vue,css,scss}" (everything, incl. tests/) `tests/e2e/**` is format-checked but never linted, so an eslint --fix run there is outside the workflow CI exercises — which is exactly where I hit this. Whether to widen eslint's scope to tests/ is a real decision with a findings backlog behind it, so it stays in #739 rather than riding along here.
…m repo root (#743) The 2026-08-24 fleet structure audit found softwarecatalog carrying 63 root files beyond the nextcloud-app-template baseline — the largest root in the fleet, against a fleet median of ~40. Most were one-off investigation scripts and status notes from finished work. Removed (39 files, ~6.5k lines): - 27 one-off scripts: check_*.php, debug_*.php, find_objects_*.php, cleanup_*.php, enhance_archimate_service.php, and the test_*/test-* shell and PHP scripts superseded by test_archimate_unified.sh or by the Newman/Postman suite. - test_small_archimate.xml — an unreferenced fixture; the kept ArchiMate suite reads lib/Settings/GEMMA_release.xml instead. - 11 point-in-time status docs: AMEF_TESTING.md, ARCHIMATE_IMPORT_FIX.md, ARCHIMATE_PROJECT_STATUS.md, CIRCLE_TEST_DOCUMENTATION.md, FIX_VERIFICATION_SUMMARY.md, INTEGRATION_TEST_RESULTS.md, KOPPELINGEN_GEBRUIK_REFACTOR.md, README_DEBUG.md, WORKFLOW-UNSTABLE-RELEASE.md, Openregister.md, aanvullende-informatie.md is retained (issues.md links it). Deliberately KEPT, because each is live-referenced: - test-setup.sh — invoked as `bash stackiq/test-setup.sh` by .claude/commands/test.md and six persona test skills. - compare_archimate.php — documented in docs/ARCHIMATE_QUICK_TEST.md and docs/ARCHIMATE_TESTING_GUIDE.md (4 call sites). - compare_archimate.py — invoked by test_archimate_unified.sh:260. - test_archimate_unified.sh — the consolidated ArchiMate suite. - issues.md — NOT scratch. 3,659 lines tracking 137 VNG IGS issues and 1,026 acceptance criteria; README.md calls it "the master file", it is listed in .distignore, and nine .claude commands/skills read it to drive the persona test suite. - BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md — named by open task 4.1 of the active openspec change organisation-parent-hierarchy-rbac-fix. test_archimate_unified.sh's header comment is updated so its "this replaces" list reads as history rather than pointing at files that no longer exist. Root file count: 96 -> 57. Refs ADR-099 Decision 2 (the repository root is a closed set).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Part of the 2026-08-25 fleet structure audit (ADR-100 Decision 2: the repository root is a closed set; generated files are never tracked). Ignore rules added: .stale/ /.e2e-state/ .phpunit.cache `.stale/` was missing from ALL 19 fleet repos and is the one that matters most operationally: agent scratch there grew unbounded and filled the dev disk once already. Refs ConductionNL/hydra ADR-100. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Every `@self.configuration` in this register pointed at https://codeberg.org/Conduction/opencatalogi/raw/branch/master/ apps-extra/opencatalogi/lib/Settings/publication_register_magic.json which returns **HTTP 404**. Verified with curl, not assumed from the host name. Three separate things had rotted at once: host ...... codeberg is no longer where opencatalogi lives path ...... the old monorepo layout `apps-extra/opencatalogi/...` is gone; the app is at its repo root now filename .. `publication_register_magic.json` was renamed to `publication_register.json` So repointing the host alone would still have 404'd. The replacement is the live file, confirmed HTTP 200 on main, master and development; `main` is the repo's default branch and is what this now uses. This matters because a `configuration` URL is FETCHED at register-import time. A 404 there does not announce itself as a broken link — the import simply does not get the configuration it asked for, which is the quiet-failure shape this codebase has been bitten by before. 32 occurrences, all byte-identical, replaced in one pass. JSON re-parsed clean afterwards.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Found by gate-96 (manifest-copy-style, ConductionNL/.github#581). Two getting-started tour steps, both already real user copy. The second takes a colon rather than a period, because the clause after the dash explains what "the heart of your catalogue" means and belongs to the same sentence: "Organisations are the heart of your catalogue: they own the contracts, modules and compliance records you track." The welcome step also loses the comma splice the dash was hiding, joining with "and" instead of leaving two sentences fused. Verified: gate-96 0 findings over 153 strings, check:manifest PASS, test:l10n PASS, check:schema-l10n PASS.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* 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. * 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.
) * fix(l10n): regenerate all 38 browser catalogues, and add the check Every locale catalogue was stale: l10n/<locale>.json is read server-side by PHP `$l->t()`, while the browser only ever sees `OC.L10N.register(...)` from l10n/<locale>.js, and a raw .json is not served from an app directory at all. A key added to the JSON and forgotten in the JS renders in English for every browser with nothing reporting it. Ported keepiq's generator, which reads the app id from appinfo/info.xml rather than hard-coding it — a catalogue registered under a stale id is silently ignored by `t()`, which matters in a fleet that renames apps. Backfilled first, then generated. This app had only 4 keys living solely in .js, but the same step run blind cost opencatalogi 21,662 translations and integriq 5,240, so the order is now fixed rather than judged per app. Verified with the assertion that matters: comparing every rebuilt .js against its pre-change version, keys DROPPED = 0. Not "no locale has fewer keys than its json" — that comparison is blind to this failure, which is how dossiq silently lost 631 real translations before I went back and re-checked. nl.js carries 691 keys, de.js 278. check:l10n-js exits 0 after the build. * fix(l10n): translate the 59 untranslated manifest strings The catalogue fix in the previous commit made the browser able to READ Dutch. This gives it Dutch to read. 59 strings: the getting-started tour, the nav, and the organisation, contract, module and compliance surfaces. Domain terms as this catalogue's users have them: leverancier, moduleversie, compliance-claim, onderbouwend bewijs, audittrail. GEMMA stays GEMMA, and the two catalogue descriptions keep the Dutch word the domain actually uses: "Blader door de dienstencatalogus, gefilterd op GEMMA-architectuurdimensie." The English original wrote "the service (dienst) catalogue" precisely because dienst is the term of record. Compliance stays Compliance. It is the word on the page in Dutch organisations, and "naleving" would read as a translation of a label nobody calls that. Built on the same branch rather than a fresh one, because the generator these translations need is in this PR and not yet on development. Verified: 0 manifest strings left without Dutch, keys DROPPED = 0, nl.js registers under "stackiq" with 750 keys and resolves "Organisations" -> "Organisaties", check:l10n-js PASS.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…760) This app already has the generator and the `check:l10n-js` script; it just never ran them in CI. That is the whole difference between an app that stays translated and one that quietly stops. Adding a key to l10n/<locale>.json and forgetting the .js is invisible without this check: the server renders Dutch, the browser renders English, and every other check passes. `l10n/<locale>.json` is read server-side by PHP; the browser only ever sees `OC.L10N.register(...)` from `l10n/<locale>.js`, loaded as a script tag. Measured across the fleet today: the apps running this check had zero drift, while the four without it had accumulated 142, 329, 257 and 1,090 unreachable entries between them. Same code, same generator. The check was the difference. It also caught a translation PR that merged green having changed nothing a browser loads, which is how the whole thing started. Appended to the existing frontend-checks list rather than replacing it, so every check this repo already runs still runs. Verified before pushing: the workflow YAML still parses, and `node scripts/build-l10n-js.js --check` exits 0 on this tree, so the new leg is green on arrival rather than red for someone else to clean up.
* fix(deps): development cannot npm install
* fix(deps): rebase the lock on development's, not a from-scratch resolve
The previous commit deleted package-lock.json before installing. That
turns a five-package pin into a full re-resolution: on pipelinq it moved
172 package versions, added 64 and removed 132, when five were intended.
One of those unintended moves broke boot. dexie went 4.4.4 -> 4.4.5, and
@conduction/nextcloud-vue's published dist BUNDLES its own dexie copy, so
the app loaded two and Dexie throws at module load:
pageerror: Two different versions of Dexie loaded in the same app:
4.4.5 and 4.4.4
The E2E boot gate caught it -- "the bundle loaded but rendered nothing" --
while build, lint, stylelint and unit tests were all green. A passing
build says nothing about whether the app mounts.
Starting from development's lock and letting npm move only what the
manifest forces cuts the change to 85/17/46 and leaves dexie alone.
Control: development's own E2E run is 309 passed / 1 failed with no
dexie pageerror and no boot-gate failure, so the breakage was mine.
---------
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Untracked: build.log changed.tsv inst.log lint.log stylelint.log t2.log test_unit.log
#764) The App Store keys everything on the app id, so renaming <id> to stackiq 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 softwarecatalog -- 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.
* feat(demo): generated demo data for every schema (ADR-111 rules 1-2)
This app declares schemas and shipped no demo data, so it opened on an empty
list: the person evaluating it had to author objects by hand against a schema
they did not know yet. Fleet-wide, 562 of 598 schemas were in that state.
🔴 GENERATED, NOT WRITTEN. Every value is derived from the schema that will
validate it — `enum` picks from the enum, `pattern` is satisfied, `format`
drives the shape, `minimum`/`maxLength` are honoured, `required` is always
populated. Hand-written demo data is wrong in a way nobody sees until the demo
(a status outside its own enum, a required field omitted) and it fails at
import, in front of whoever asked for the demo.
Produced and validated by the single file gate-99 also runs:
`vendor/conduction/hydra-gates/scripts/lib/generate_mock_register.py`.
`--keep` preserves curated objects and tops up only what is short.
🔴 IT DOES NOT INSTALL ITSELF (ADR-111 rule 3). `x-openregister.type: mock` is
imported ON DEMAND — sample data appearing on a production instance because
somebody upgraded is a data-integrity incident, not a convenience:
occ openregister:descriptors:list --app=<app> --import=<register>
The setup-wizard step offering this on first run (ADR-111 rule 4, gate-100)
follows once OpenRegister's shared installer lands — deliberately not
twenty-one copies of the same logic.
Verified: `--check` re-validates every object against its own schema with
jsonschema and reports zero findings.
* fix(demo-data): attribute the descriptor to the app id, not the directory
`x-openregister.app` is what the descriptor inventory resolves a register to
an app by, and the generator was writing the CHECKOUT DIRECTORY name into it —
naming an app that does not exist. A cross-app id is a runtime lookup: it
finds nobody rather than erroring. The file is renamed to match and the
directory-named one removed, so exactly one mock descriptor remains.
---------
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
#777) Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
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.