From 9ae2dd19fe60e5dbd07afdfdced1c8a93b0a8807 Mon Sep 17 00:00:00 2001 From: Vojtech <119944107+cvrysanek@users.noreply.github.com> Date: Tue, 12 May 2026 17:16:01 +0400 Subject: [PATCH] fix(memory-admin): pass RBAC user_groups (not YAML config) to /corporate-memory/admin (#253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(memory-admin): pass RBAC user_groups (not YAML config) to /corporate-memory/admin `GET /corporate-memory/admin` was passing `corporate_memory.groups` from instance.yaml (a dict, default `{}`) as the template's `groups=`. The template's `renderItemCard` does `GROUPS.map(g => ...)` to build the mandate-form audience picker, which throws `{}.map is not a function` the moment any pending item renders. The thrown TypeError bubbles up through `renderReviewItems` and gets swallowed by the `loadReviewQueue` catch block, which paints "Error loading pending items." over a perfectly valid `/api/memory/admin/pending` response. Bug was dormant since the initial system commit because `renderItemCard` only runs when at least one pending item exists, so test fixtures and empty queues never tripped it. Mandate form actually targets RBAC user_groups (audience strings like `group:Admin`), not the unrelated `corporate_memory.groups` YAML section. Route now passes the user_groups list shaped as `[{name, members_count}]`. Template additionally guards the `.map` call with `Array.isArray(GROUPS) ? GROUPS : []` so a future shape regression degrades to "no group options" instead of crashing the list. No DB migration; no API change. * test(memory-admin): assert /corporate-memory/admin renders GROUPS as array Server-side regression for the bug Vojta's previous commit fixed: the route used to pass `corporate_memory.groups` (a dict, default `{}`) into the template as `groups=`, so `const GROUPS = {{ groups | tojson }}` rendered as `{}` and `GROUPS.map(...)` inside renderItemCard threw at runtime. The bug was dormant because renderItemCard only runs when at least one pending item exists — empty queues never tripped it. Test seeds one pending knowledge_item and asserts the rendered HTML contains `const GROUPS = [` (array prefix), so any future regression that flips the variable back to a dict shape fails immediately rather than waiting for an operator to seed the queue and notice the broken admin page. * release: 0.51.1 — corporate-memory admin pending-banner hotfix Patch bump: ships the /corporate-memory/admin GROUPS-shape fix (dict → array of {name, members_count}) and its server-side regression test. No DB migration, no API change, no operator action required — upgrades land transparently. --------- Co-authored-by: ZdenekSrotyr --- CHANGELOG.md | 5 ++++ app/web/router.py | 17 ++++++++++++- app/web/templates/corporate_memory_admin.html | 2 +- pyproject.toml | 2 +- tests/test_corporate_memory_page.py | 25 +++++++++++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a36ad4..e4403dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C ## [Unreleased] +## [0.51.1] — 2026-05-12 + +### Fixed +- **`/corporate-memory/admin` no longer fails with "Error loading pending items." once pending knowledge items exist.** `GET /corporate-memory/admin` was passing the `corporate_memory.groups` YAML section (a dict, default `{}`) into the template as `groups=`, but `renderItemCard` evaluates `GROUPS.map(g => ...)` to build the mandate-form audience picker — `{}.map is not a function` threw inside the template literal, bubbled up to `renderReviewItems`, and the `loadReviewQueue` catch block painted the misleading "Error loading pending items." banner over a perfectly valid `/api/memory/admin/pending` response. Bug was dormant since the initial system commit because `renderItemCard` only runs when at least one pending item exists, so test fixtures and empty queues never tripped it. Fix: route now passes RBAC user_groups (`user_groups` table) shaped as `[{name, members_count}]`, which is what the mandate form actually targets (audience targeting is `group:`, not `corporate_memory.groups`); template hardens the `.map` call with `Array.isArray(GROUPS) ? GROUPS : []` so a future shape regression degrades to "no group options" instead of crashing the whole list. No DB migration; no API change. + ## [0.51.0] — 2026-05-12 ### Fixed diff --git a/app/web/router.py b/app/web/router.py index 42479e2..386656f 100644 --- a/app/web/router.py +++ b/app/web/router.py @@ -974,6 +974,21 @@ async def corporate_memory_admin( "WHERE relation_type = 'likely_duplicate' AND resolved = FALSE" ).fetchone()[0] + # Mandate-form audience picker needs RBAC user_groups, not the + # `corporate_memory.groups` YAML section — those are unrelated. + # Template expects an array of {name, members_count} so it can render + # `