Skip to content

Report the eps the semantic map was actually clustered with - #422

Merged
lstein merged 4 commits into
masterfrom
lstein/fix/report-clustered-eps
Oct 6, 2026
Merged

lstein merged 4 commits into
masterfrom
lstein/fix/report-clustered-eps

Conversation

@lstein

@lstein lstein commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Fixes #380. Fixes #381.

Problem

resolve_cluster_eps shrinks every eps, typed or derived, to fit DBSCAN's neighbor-pair memory budget. Where that kicks in depends on the point cloud. /umap_data clustered with the shrunk value but never returned it. So on a large album tuned to 2.0 the spinner, /get_umap_eps and the cluster-info modal all said 2, while the map was drawn at 1.4. The modal also read the spinner directly, so it could show an unsaved edit, a value the spinner refused, or NaN (#381).

Change

  • /umap_data now returns {points, eps, requested_eps} instead of a bare array:
    • eps is the value actually clustered with.
    • requested_eps is the query param, else the stored value, or null when derived.
  • /cluster_labels adds eps (additive).
  • Frontend (umap.js): each draw records drawnEps together with points. A malformed response throws before anything is assigned.
    • The spinner keeps the requested number. It is what the album stores and what the next fetch asks for.
    • A new #umapEpsEffective note ("map: 1.4") appears only when the server shrank the request. Its tooltip explains why.
    • The cluster-info modal reads drawnEps, so it always describes the map the counts beside it come from.
  • Docs: docs/developer/api.md updated for the new response shape.

The auto badge is unchanged. The frontend always sends an explicit cluster_eps once the spinner is filled, so /umap_data can't tell "derived" from "typed". /get_umap_eps stays the source of truth for the badge.

Tests

  • Backend: with the pair budget forced small, the reported eps equals what DBSCAN received and /cluster_labels agrees. Also covers the stored and derived cases. Existing tests updated for the new shape.
  • Frontend: new umap-effective-eps.test.js covers the note show/clear cases, the modal vs spinner in each Cluster-info modal reports the spinner's value, not the strength the map was drawn with #381 repro, and a failed redraw. Existing mocks updated.
  • make test: 1291 backend and 989 frontend passing. Lint and format clean.

🤖 Generated with Claude Code

lstein and others added 3 commits October 4, 2026 17:33
The pair-budget shrink in resolve_cluster_eps applies to every eps, typed
or derived, and where it engages depends on the point cloud. /umap_data
used the shrunk value and discarded it, so on a large album the Cluster
Strength control and the cluster-info modal reported a number the map was
never clustered with.

/umap_data now returns {points, eps, requested_eps}, and /cluster_labels
adds eps. The frontend records the eps each draw used: the spinner keeps
the request, a note beside it shows the strength actually used when the
server shrank it, and the cluster-info modal reads the drawn value rather
than the spinner (which could also be mid-debounce, refused or half-typed).

Fixes #380
Fixes #381

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A derived strength was written into the spinner as a raw float (0.11944),
inconsistent with the two decimals its arrows produce. The field now shows
formatEps(eps) — two decimals, or two significant figures below 0.1 — and
the same formatter is used by the shrink note and the cluster-info modal.

The field's value is also what the map and labels are requested at, so the
exact value is remembered behind the rounded text and sent until the user
edits the field. A stored strength below the floor is shown unrounded, so
it never reads as the floor itself while marked unusable.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@lstein
lstein enabled auto-merge (squash) October 6, 2026 18:23
@lstein
lstein merged commit 62234bf into master Oct 6, 2026
11 checks passed
@lstein
lstein deleted the lstein/fix/report-clustered-eps branch October 6, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant