slide.getIncomingLinks not implemented + bg.listFolders errors on missing dir #60

Closed
opened 2026-05-11 02:52:42 +00:00 by mik-tf · 1 comment
Owner

Two unrelated noise sources surfaced while reproducing #58 in the dashboard via Hero Browser MCP. Neither is user-visible (the JS catches in try/catch), but both pollute the slides server logs on every dashboard load, and one represents a half-shipped feature.

The dashboard calls this RPC once per slide on every loadSlidesForDeck() (crates/hero_slides_admin/static/js/dashboard.js:2872) to render the "used as link source in N place(s)" badge introduced alongside D-09 / PR #55. For sample_deck (11 slides) every dashboard load fires 11 failing RPCs.

The handler is not registered in crates/hero_slides_server/src/rpc.rs dispatcher and there is no slide_get_incoming_links lib helper either. The UI catches and silently drops the error, so the badge just never appears — but the server logs every failure.

Two reasonable fixes — pick whichever fits the team intent:

  • A. Implement the backend. Walk every deck under the same collection root (state.registry.lookup_root(&col)), load_metadata for each, scan metadata.slides[*].source_link for entries whose deck_path + slide_name match the queried slide. Return {incoming_links: [{deck_path, slide_name}]}. ~30 LOC.
  • B. Remove the UI calls until the backend lands. ~5 LOC in dashboard.js.

(A) is the more useful endpoint per D-09's link-graph intent.

2. bg.listFolders — error when <deck>/backgrounds/ does not exist

Reproducer:

curl -sS --unix-socket ~/hero/var/sockets/hero_slides/rpc.sock \
  -X POST -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","method":"bg.listFolders","params":{"collection":"hero_slides_examples","deck":"sample_deck"},"id":1}' \
  http://localhost/rpc

{"jsonrpc":"2.0","error":{"code":-32000,"message":"Not a directory: .../sample_deck/backgrounds"},"id":1}

Should return an empty {folders: []} instead of erroring when the directory is absent. "No backgrounds" is the expected steady state for new decks; the only legitimate error is "deck path does not exist".

Why these were not fixed in PR #59

PR #59 closes #58 regression 2 (restoreVersion toast UX). I deliberately kept that PR scoped to the one named regression. These two issues are real but separate — filing here so they don't get lost.

Signed-off-by: mik-tf

Two unrelated noise sources surfaced while reproducing #58 in the dashboard via Hero Browser MCP. Neither is user-visible (the JS catches in `try/catch`), but both pollute the slides server logs on every dashboard load, and one represents a half-shipped feature. ## 1. `slide.getIncomingLinks` — Method not found The dashboard calls this RPC once per slide on every `loadSlidesForDeck()` (`crates/hero_slides_admin/static/js/dashboard.js:2872`) to render the "used as link source in N place(s)" badge introduced alongside D-09 / [PR #55](https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/55). For sample_deck (11 slides) every dashboard load fires 11 failing RPCs. The handler is **not registered** in `crates/hero_slides_server/src/rpc.rs` dispatcher and there is no `slide_get_incoming_links` lib helper either. The UI catches and silently drops the error, so the badge just never appears — but the server logs every failure. **Two reasonable fixes** — pick whichever fits the team intent: - **A. Implement the backend.** Walk every deck under the same collection root (`state.registry.lookup_root(&col)`), `load_metadata` for each, scan `metadata.slides[*].source_link` for entries whose `deck_path` + `slide_name` match the queried slide. Return `{incoming_links: [{deck_path, slide_name}]}`. ~30 LOC. - **B. Remove the UI calls** until the backend lands. ~5 LOC in dashboard.js. (A) is the more useful endpoint per D-09's link-graph intent. ## 2. `bg.listFolders` — error when `<deck>/backgrounds/` does not exist Reproducer: ``` curl -sS --unix-socket ~/hero/var/sockets/hero_slides/rpc.sock \ -X POST -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"bg.listFolders","params":{"collection":"hero_slides_examples","deck":"sample_deck"},"id":1}' \ http://localhost/rpc {"jsonrpc":"2.0","error":{"code":-32000,"message":"Not a directory: .../sample_deck/backgrounds"},"id":1} ``` Should return an empty `{folders: []}` instead of erroring when the directory is absent. "No backgrounds" is the expected steady state for new decks; the only legitimate error is "deck path does not exist". ## Why these were not fixed in PR #59 [PR #59](https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/59) closes [#58](https://forge.ourworld.tf/lhumina_code/hero_slides/issues/58) regression 2 (`restoreVersion` toast UX). I deliberately kept that PR scoped to the one named regression. These two issues are real but separate — filing here so they don't get lost. Signed-off-by: mik-tf
Author
Owner

Closed by #61 — squash-merged as f34f18a on development.

Resolution

1. slide.getIncomingLinks — implemented (Option A from issue body). New handler walks every deck under the same collection root, loads metadata.toml, scans slides.*.source_link, and returns {collection, deck, slide} matches. Dashboard "used as link source in N place(s)" badges now render; the ~11x-per-load Method not found server log spam is gone.

2. bg.listFolders — now returns {folders: [], root_files: []} when the target dir is absent instead of -32000. Matches the issue's stated expected behavior.

Verified locally before merge

  • python3 scripts/smoke_openrpc.py — 91 methods, METHOD_MISSING 0.
  • Curl reproducer from the issue body returns the empty shape.
  • Positive end-to-end: probe link hero_slides_intro/07_s92_link_probesample_deck/01_intro, getIncomingLinks returns the linker, deleted probe after.

Latent finding (not fixed here)

legacy_param_shim synthesizes path = <deck_path>/backgrounds for all bg.* methods at rpc.rs:399, but the lib helpers append content/background/ to whatever they receive. The synthesized path therefore never matches the actual filesystem layout — after this PR bg.listFolders always returns empty until the shim is reconciled. Not user-visible (UI catches errors in try/catch and would render empty anyway), but a follow-up issue may be worth filing if anyone tries to use bg.uploadFile / bg.createFolder / etc. and discovers they're writing into a non-existent <deck>/backgrounds/content/background/ path.

Signed-off-by: mik-tf

Closed by https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/61 — squash-merged as `f34f18a` on `development`. ## Resolution **1. `slide.getIncomingLinks`** — implemented (Option A from issue body). New handler walks every deck under the same collection root, loads `metadata.toml`, scans `slides.*.source_link`, and returns `{collection, deck, slide}` matches. Dashboard "used as link source in N place(s)" badges now render; the ~11x-per-load `Method not found` server log spam is gone. **2. `bg.listFolders`** — now returns `{folders: [], root_files: []}` when the target dir is absent instead of `-32000`. Matches the issue's stated expected behavior. ## Verified locally before merge - `python3 scripts/smoke_openrpc.py` — 91 methods, METHOD_MISSING 0. - Curl reproducer from the issue body returns the empty shape. - Positive end-to-end: probe link `hero_slides_intro/07_s92_link_probe` → `sample_deck/01_intro`, `getIncomingLinks` returns the linker, deleted probe after. ## Latent finding (not fixed here) `legacy_param_shim` synthesizes `path = <deck_path>/backgrounds` for all `bg.*` methods at `rpc.rs:399`, but the lib helpers append `content/background/` to whatever they receive. The synthesized path therefore never matches the actual filesystem layout — after this PR `bg.listFolders` always returns empty until the shim is reconciled. Not user-visible (UI catches errors in try/catch and would render empty anyway), but a follow-up issue may be worth filing if anyone tries to use `bg.uploadFile` / `bg.createFolder` / etc. and discovers they're writing into a non-existent `<deck>/backgrounds/content/background/` path. Signed-off-by: mik-tf
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_slides#60
No description provided.