Skip to content

fix: restore the app identity development lost in a merge (learniq cannot boot without it) - #463

Merged
rubenvdlinde merged 8 commits into
developmentfrom
feat/learniq-reframe
Aug 19, 2026
Merged

fix: restore the app identity development lost in a merge (learniq cannot boot without it)#463
rubenvdlinde merged 8 commits into
developmentfrom
feat/learniq-reframe

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

development is currently broken

development has the namespace rename but not the app identity:

value on development
lib/AppInfo/Application.php namespace OCA\Learniq, APP_ID = 'learniq'
lib/Settings/ learniq_register.json
.github/workflows/* app-name: learniq
appinfo/info.xml <id>scholiq</id>, <namespace>Scholiq</namespace>

Nextcloud resolves OCA\{namespace}\AppInfo\Application from info.xml. With Scholiq there and OCA\Learniq in the code, the app cannot boot at all.

How it happened

The GitHub-side merge ca67455 resolved appinfo/info.xml to development's side, reverting all 100 lines. The later release commit 4e176be only touched <version>, so the revert predates it — I checked, rather than assuming the release automation did it.

Because that resolution is now an ancestor, a plain git merge origin/development silently takes development's file again. That is exactly what happened on this branch before this commit, which is how I found it.

What this does

Restores the Learniq info.xml<id>, <namespace>, the repair steps (RenameRegisterSlug, MigrateAppConfigKeys), the learniq_register.json references, and the ≤128-character summaries the App Store schema requires — while keeping development's release version (0.1.1-unstable.20260819175834) so the release automation is not fought.

Also carries an e2e guard: reading OC.generateUrl straight after goto throws an opaque TypeError on Nextcloud's maintenance and login pages, both of which return a normal 200. Observed 2026-08-19 — a concurrent session ran occ, the instance went into maintenance for under a minute, and 15 tests failed pointing at application code. The guard now names the environment cause instead.

Verified locally

  • /apps/learniq/200, nav renders 24 top-level entries, Compliance present, primaryRole resolves under the learniq app id
  • Register slug learniq; canary GradeEntry d4caa278 field fingerprint unchanged (6ca294bb6174…); table_name ~ 'oc_openregister_table_[a-z]' still 0
  • All 8 declared groups present (36 total on the instance)
  • Paired RBAC proof on one actor: learner reads a Course 200, is refused another learner's GradeEntry 404 (OR masks read denials), create 403 — with admin's 200 on the same object as the positive control
  • PHPUnit 952 tests / 21 errors / 1 failure, identical to the development baseline. The 21 errors are a host environment gap (no ext-zip, no openregister), not code
  • eslint 0 errors · stylelint clean
  • hydra-gates 2 failing (19, 61 — both pre-existing), COVERAGE: 63 of 63 applicable gates ran

Note on the local instance

installed_version was 0.3.0 while the release train moved to 0.1.1-unstable…. Nextcloud refuses a downgrade and 503s the whole instance with needsDbUpgrade: true. Realigning installed_version cleared it. Worth knowing before anyone else pulls this.

🤖 Generated with Claude Code

Renames every remaining SCHOLIQ_-prefixed constant (SCHOLIQ_REGISTER,
SCHOLIQ_NATIVE_COLLECTION_SCHEMA) to LEARNIQ_*, declaration and every
self::/static:: use together in the same edit. Renames the private
isScholiqXapiStatement() method to isLearniqXapiStatement() in
XapiCompletionHandler and LessonProgressHandler, and every call site.

Also fixes stale "Scholiq" prose in docblocks, comments, and log/error
messages across lib/ (class headers, register/event-filter descriptions,
stale scholiq_register.json file references, and two factually-wrong
autoloader-ordering comments that still described the OLD app id's
alphabetical position relative to openregister).

Deliberately NOT renamed: the wire/format identifiers kept for backward
compatibility (scholiq-json, scholiq-native, scholiq-learning-record,
scholiqField, scholiqNative, _scholiqRecordId, FORMAT_SCHOLIQ_JSON, the
course-<id>_scholiq.json export filename), the AVG processing-activity
register codes (scholiq-ai-features and siblings), the three repair
steps' OLD_APP_ID/OLD_SLUG/REGISTER_SLUG_PREFIX constants and their
historical-fact prose, @SPEC tags pointing at real openspec/ paths that
still exist under the old name, and two newly-identified persisted
external identifiers with no migration path: the NC Files folder prefix
'Scholiq/{tenant}/...' (CoursePackageFileWriter, LearningRecordBundleWriter,
LearningRecordImportIntakeService) and the NC group-name prefix
'scholiq-cohort-' generated by RolloverService::groupName().
Renames SCHOLIQ_SCHEMAS -> LEARNIQ_SCHEMAS (and its scholiqResults ->
learniqResults local variable) in LearniqNotificationSettings.vue, and
fixes stale "Scholiq" prose, CSS class/id names (scholiq-notif-settings__*,
scholiq-settings__*, scholiq-dashboards__*, scholiq-admin, scholiq-domain-
dashboard, scholiq-dataexchange-settings__*), stale lib/Settings/
scholiq_register.json file references, and user-facing settings copy
across the Vue views, manifest.json (Prometheus metric help text and
dashboard/manifest _note fields), main.js, icons.js and app.css.

Verified before renaming: every touched CSS class/id is component-scoped
with no cross-file selector or test dependency (checked via grep across
src/ and tests/ before each rename).

Also corrects two DashboardAdmin.vue/DashboardTeacher.vue/main.js
comments that claimed dashboard visibility was gated on a literal
`scholiq-{role}` NC group — that group naming was already dead (per
RoleSelector.php's own comment, it "never existed on any instance");
the real mechanism is DashboardRoleService resolving dashboardRoles
from NC's admin group and the unprefixed role-backing groups. The old
comment was inaccurate under the old name too, not just stale naming.
Renames the global function scholiq_nc_base_is_safe_to_load() (and the
$scholiqNcRoot variable) to learniq_nc_base_is_safe_to_load()/
$learniqNcRoot across tests/bootstrap-nc-guard.php, bootstrap.php and
bootstrap-unit.php together, plus SCHOLIQ_E2E_SEEDED -> LEARNIQ_E2E_SEEDED
and SCHOLIQ_DOCS_CAPTURE -> LEARNIQ_DOCS_CAPTURE (both env var names, kept
in sync with the root playwright.config.ts in the next commit).

Fixes two e2e assertions that were checking live reality against the
wrong string and would fail against the deployed app: detail-pages.spec.ts
and index-pages.spec.ts asserted `page.title()` contains 'Scholiq' — the
live page title is 'Learniq - Nextcloud'. Also fixes a silently-broken
soft-check in nextcloud-app.spec.ts: a combobox-option filter searched
`/scholiq/i` while its own comment said to look for 'learniq', so the
option was never found and the click branch never ran.

Otherwise the usual stale-prose/temp-dir-prefix/mock-domain cleanup
(scholiq_test_* -> learniq_test_*, https://scholiq.example ->
https://learniq.example, etc.), plus fixing PortalContributionProviderTest
to assert 'Learniq' (matching PortalContributionProvider.php's already-
renamed manifest label — the two had drifted out of sync mid-rename).

Deliberately left unchanged: fixture data mirroring protected production
literals (the 'Scholiq/materials/...' mock file paths matching the
production NC-Files-folder-prefix decision, scholiq-cohort-* group-name
fixtures), the historical/documents-the-rename-itself mentions, GitHub
issue shorthand (scholiq#35, scholiq#265), and @e2e/@SPEC tags paired
with real openspec/ anchors.
…root config

Renames the remaining "Scholiq" prose in routes.php's AppHost-adoption
comments to "Learniq" (the app's own name, its URLs, its bespoke
SettingsController). Renames SCHOLIQ_DOCS_CAPTURE -> LEARNIQ_DOCS_CAPTURE
in the root playwright.config.ts, matching tests/e2e/playwright.config.ts's
comment and the env var tests/bootstrap already reads.

Left unchanged (deliberate, out of scope for this pass): the literal old
register-slug/app-id/app-config-namespace values in routes.php's
'scholiq-ai-features' AVG code and 'scholiq-native JSON' format mentions,
and appinfo/info.xml's codeberg.org/Conduction/nextcloud-scholiq URLs —
those are an external repo-hosting decision, not code-identifier residue,
and changing them without confirming the remote was actually renamed
would just replace one wrong URL with another.
The naming sweep touched this file, so gate-16 saw the method as changed.
Excluded with a reason: it answers 'is this event about one of our
objects' and returns '' for every negative case, so callers bail out. The
register it matches against is the app id - which is exactly why the
rename's diff surfaced it.
development ended up with the namespace rename but NOT the app identity:
Application.php declares APP_ID 'learniq' and namespace OCA\Learniq, the
register is learniq_register.json, CI passes app-name: learniq - while
appinfo/info.xml still said <id>scholiq</id> and <namespace>Scholiq</namespace>.

Nextcloud resolves OCA\{namespace}\AppInfo\Application from info.xml, so
that combination cannot boot the app at all.

Cause: the GitHub-side merge ca67455 resolved info.xml to development's
side, reverting all 100 lines. The later release commit only touched
<version>, so the revert predates it. Because that resolution is now an
ancestor, a plain merge silently takes development's file again - which is
what happened here before this commit.

Restores the Learniq info.xml (id, namespace, repair steps, learniq
register references, and the <=128-char summaries the App Store schema
requires) while KEEPING development's release version so the release
automation is not fought.

Also carries the e2e guard for OC.generateUrl: reading it straight after
goto throws an opaque TypeError on Nextcloud's maintenance and login
pages, which both return a normal 200. Observed 2026-08-19 - a concurrent
session ran occ, the instance went into maintenance for under a minute,
and 15 tests failed pointing at application code.
Its docblock justified matching only the 'scholiq' slug by claiming the
step runs BEFORE RenameRegisterSlug 'because info.xml lists it first'.
That is false: appinfo/info.xml lists RenameRegisterSlug FIRST and
RenameDutchColumns LAST. So by the time it ran, the slug was already
'learniq', its LIKE 'scholiq%' lookup matched zero registers, and the step
reported success while migrating nothing.

Now matches BOTH prefixes, which removes the dependency on step order
entirely - an ordering assumption stated only in a comment is enforced by
nothing.

Also clears the three phpcs errors CI flagged (doc long-description
capitalisation in the three repair steps) and prettier-formats the visual
spec. phpcs errors: 3 -> 0. Repair-step tests still 11/11.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/scholiq @ 93775e5

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

Quality workflow — 2026-08-19 23:23 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/scholiq @ 0476d8c

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

Quality workflow — 2026-08-19 23:53 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit c70cdbe into development Aug 19, 2026
39 of 42 checks passed
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