feat: fuzzy clustering with local embeddings #4

Merged
Breadway merged 2 commits from feature/fuzzy-clustering into main 2026-10-12 09:50:42 +08:00
Owner

Closes BUG-6

Stacked on #3. Part of ECO-EP1.

What

  • Fuzzy matching for reports with no fingerprint: behavior reports and freezes without a stack. Cosine similarity against the centroids of live fuzzy clusters for the same app and kind (never across either); best match at or above the threshold wins, otherwise a new cluster starts; centroids are running means.
  • Local only. Default embedder is a feature-hashing bag of words and bigrams (256 dims, no model to download). Optional HttpEmbedder for a local sentence-embedding service (BREADBUG_EMBED_URL), restricted to loopback/private addresses so report text never leaves the host.
  • Vectors are stored with a model name and never compared across models; reembed_all rebuilds centroids from member reports when the model changes.
  • Fewer than three distinct meaningful words means nothing to match on; the report stays unclustered.
  • Evaluation set (tests/fixtures/fuzzy_eval.json, 8 problems x 3 differently worded descriptions) with a test that enforces precision >= 0.95 and recall >= 0.65. Measured: precision 1.00, recall 0.71 at the 0.30 default threshold (highest cross-problem similarity is 0.27).

Honest limits

The built-in embedder only matches descriptions that share vocabulary. About 29% of same-problem pairs in the set fall below the threshold, so some duplicates will sit in separate clusters until a human merges them (BUG-7). That is the safe direction: a wrong merge hides a bug, a missed merge costs a click. docs/embedding-eval.md explains how to plug in a real embedding model and retune. I did not stand up an ML service as part of this PR.

Tests

7 embed unit tests (tokens, determinism, similarity ordering, centroid/bytes, local-only URL rule, HTTP reply parsing against a mock), the quality test, and 5 HTTP integration tests (paraphrases cluster and unrelated reports do not; never crosses apps or kinds; too little text stays unclustered; threshold configurable; model change does not mix vector spaces and reembed fixes it). clippy -D warnings clean.

Closes BUG-6 Stacked on #3. Part of ECO-EP1. ## What - Fuzzy matching for reports with no fingerprint: behavior reports and freezes without a stack. Cosine similarity against the centroids of live fuzzy clusters for the **same app and kind** (never across either); best match at or above the threshold wins, otherwise a new cluster starts; centroids are running means. - **Local only.** Default embedder is a feature-hashing bag of words and bigrams (256 dims, no model to download). Optional `HttpEmbedder` for a local sentence-embedding service (`BREADBUG_EMBED_URL`), restricted to loopback/private addresses so report text never leaves the host. - Vectors are stored with a model name and never compared across models; `reembed_all` rebuilds centroids from member reports when the model changes. - Fewer than three distinct meaningful words means nothing to match on; the report stays unclustered. - Evaluation set (`tests/fixtures/fuzzy_eval.json`, 8 problems x 3 differently worded descriptions) with a test that enforces precision >= 0.95 and recall >= 0.65. Measured: **precision 1.00, recall 0.71 at the 0.30 default threshold** (highest cross-problem similarity is 0.27). ## Honest limits The built-in embedder only matches descriptions that share vocabulary. About 29% of same-problem pairs in the set fall below the threshold, so some duplicates will sit in separate clusters until a human merges them (BUG-7). That is the safe direction: a wrong merge hides a bug, a missed merge costs a click. `docs/embedding-eval.md` explains how to plug in a real embedding model and retune. I did not stand up an ML service as part of this PR. ## Tests 7 embed unit tests (tokens, determinism, similarity ordering, centroid/bytes, local-only URL rule, HTTP reply parsing against a mock), the quality test, and 5 HTTP integration tests (paraphrases cluster and unrelated reports do not; never crosses apps or kinds; too little text stays unclustered; threshold configurable; model change does not mix vector spaces and reembed fixes it). clippy `-D warnings` clean.
feat: fuzzy clustering with local embeddings
All checks were successful
check / check (push) Successful in 30s
5cbb322e1f
Reports with no stable fingerprint (behavior reports, freezes without a
stack) are matched by cosine similarity of locally computed vectors against
the centroids of same-app, same-kind fuzzy clusters. The built-in embedder
is a feature-hashing bag of words and bigrams (no model, no third party);
an optional local HTTP embedder (loopback/private only) is supported.
Vectors carry a model name and are never compared across models;
reembed_all rebuilds centroids. Evaluated on a labeled paraphrase set:
precision 1.00, recall 0.71 at the 0.30 default threshold, enforced by a
test. Documented in docs/embedding-eval.md.

Refs BUG-6
Breadway changed target branch from feature/symbolication to main 2026-10-11 20:15:46 +08:00
Breadway force-pushed feature/fuzzy-clustering from 5cbb322e1f
All checks were successful
check / check (push) Successful in 30s
to a6daaf43e8
All checks were successful
check / check (push) Successful in 51s
2026-10-11 20:17:27 +08:00
Compare
Sign in to join this conversation.
No reviewers
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
Breadway/breadbug-server!4
No description provided.