Skip to content
bucker

Similar issues and grouping suggestions

Bucker groups events into issues by fingerprint. Two issues that are really one bug (the same failure reached by a slightly different stack, or reworded by a different library version) are found a second way: by comparing what the issues say. The result appears in three places:

  • Similar issues on an issue page, with any fix recorded for the neighbours.
  • Grouping suggestions: pairs of issues that look like the same bug, waiting in the project's review queue (Grouping, Review queue).
  • Merge, in the queue and in the issue stream, to fold the duplicates together.

Nothing is ever merged because it looked similar. A suggestion is a question for a person. The only automatic merging in the product is the opt-in auto-merge policy, which stays off until an organization's own confirmed and rejected pairs show it is accurate enough (the precision gate on the same screen).

What is compared

Each issue is turned into a 768-number vector from its exception type and message, its title and its culprit. Nothing else: not event payloads, not user data, not breadcrumbs, not source code. Two issues are close when their vectors are.

Two providers can make the vectors.

Provider What it understands Needs
Local (default) Shared words, identifiers and character runs. getUserById and findUserById match; two descriptions of the same failure in different words do not nothing
Hosted Meaning, so a message and its rewording are close an API key, and a person to get one

The local provider is deterministic and offline, which is why it is the default and the fallback. The hosted one speaks the OpenAI-compatible POST /v1/embeddings shape, so it works with OpenAI, Azure OpenAI, Voyage, Mistral, Together, vLLM and Ollama.

Turning the hosted provider on

This is a step for a person with an account at the provider. Bucker cannot get a key.

  1. Create an API key with the provider.
  2. On the API, worker and MCP services set EMBEDDING_PROVIDER=hosted and EMBEDDINGS_API_KEY, with identical values: every neighbour query filters on the model name, so a service that resolves a different provider silently finds nothing. Optional: EMBEDDINGS_API_URL (default https://api.openai.com/v1/embeddings) and EMBEDDINGS_MODEL (default text-embedding-3-small). The model must honour the dimensions request field and return 768; a model that cannot is refused, never padded.
  3. Deploy. Vectors made by the old provider are rebuilt automatically, a project at a time, because every vector records the model that made it and two models are never compared.

If EMBEDDING_PROVIDER=hosted is set and the key is not, Bucker keeps grouping on the local provider and says so: the worker logs a warning at boot, and a scan reports why it ran on the local provider. Silently grouping worse is the failure this avoids; refusing to group is worse still.

What leaves your deployment

With a hosted provider, an issue's exception type, message, title and culprit are sent to it when the issue is created and when its vector is rebuilt. Two switches keep things local:

  • An organization with AI features turned off (its AI switch) always uses the local provider, and nothing about its issues leaves the deployment.
  • Source code is never sent to the hosted provider by the codebase index unless the deployment sets EMBEDDINGS_ALLOW_SOURCE_CODE=true, a separate decision from grouping.

Bucker's hosted service embeds issues only: it leaves EMBEDDINGS_ALLOW_SOURCE_CODE unset, so code retrieval for root-cause analysis and fix context stays on the local provider. Sending source code too would wait on a per-organization AI-switch check on the codebase path, which does not exist yet.

If the provider fails while an issue is being embedded (an outage, a revoked key), the embedding is not stored, and the next nightly pass embeds it; it is not replaced by a local vector, which would put a weaker vector into a hosted index under the wrong name.

The nightly pass

A worker pass runs about once a day. For every project with at least two issues seen in the last week it embeds any issue that has no vector from the current provider (up to 500 per project per night, busiest projects first, 200 projects per night, so a large backlog drains over several nights rather than in one bill), and then scans for similar pairs at the usual threshold. Pairs you already decided are never asked again. GROUPING_SWEEP_ENABLED=false turns the pass off; Scan for duplicates in the queue still runs one project on demand.

Merging suggestions

Tick the suggestions that are the same bug and press Merge N selected. Each is confirmed (so it counts toward the precision statistic) and merged, up to 50 at a time. For each pair the older issue survives, because it holds the short ID people have already pasted into tickets.

  • A pair that cannot be merged (one side was merged elsewhere, deleted, or someone else decided it first) is skipped with its reason and stays in the queue.
  • Every merge is audited and can be undone from Grouping, Merge history, with the counters restored exactly.
  • It needs the right to triage issues in the project.

In the issue stream, select two or more issues of one project and choose Merge to pick the survivor yourself.

POST /orgs/:org/projects/:project/grouping-suggestions/merge
{ "suggestionIds": ["...", "..."] }

The response lists, per suggestion, merged or skipped with a reason.

What this is not

Bucker does not train or fine-tune a model, and it does not merge on similarity alone. The published wrong-merge rate of automatic embedding merges is high enough that the product keeps a person in the loop until your own data says otherwise.