How matching works

One SQL function decides.

Every error an agent reports is scored against every crash site by one Postgres function, match_site(); paste an error and see each number it computes.

Try
Step 1

What Postgres sees.

Before the query, secrets are redacted and the text is normalised: lower-cased, with numbers, ids, URLs, file paths and stack frames replaced, so two reports of one failure differ as little as possible.

p_signature

error: insert failed n : new row violates row-level security policy for table invoices

p_codesNo error code found in this text.
Vendor guesssupabase
Step 2

Every crash site gets a score.

threshold 0.55: a score at or past this line is a match
Matched: Insert rejected by row-level securityscore 0.662 · threshold 0.55
  1. #1Matched
    Insert rejected by row-level security
    supabase122 stop signals on record
    Trigram similarity0.477
    Signature inside error0.584
    Error inside signaturedecides0.662
    Error code matchno
    Score0.662at or past 0.55
  2. #2below threshold
    Server action id from an older deployment no longer exists
    vercel21 stop signals on record
    Trigram similarity0.143
    Signature inside error0.162
    Error inside signaturedecides0.213
    Error code matchno
    Score0.213short of 0.55
  3. #3below threshold
    Policy queries its own table and recurses
    supabase34 stop signals on record
    Trigram similarity0.147
    Signature inside error0.168
    Error inside signaturedecides0.207
    Error code matchno
    Score0.207short of 0.55
  4. #4below threshold
    API returns 529 overloaded_error
    anthropic84 stop signals on record
    Trigram similarity0.083
    Signature inside errordecides0.200
    Error inside signature0.095
    Error code matchno
    Score0.200short of 0.55
  5. Trigram similarity0.153
    Signature inside error0.165
    Error inside signaturedecides0.195
    Error code matchno
    Score0.195short of 0.55
  6. #6below threshold
    Hydration fails because server and client rendered different HTML
    vercel52 stop signals on record
    Trigram similarity0.119
    Signature inside error0.135
    Error inside signaturedecides0.182
    Error code matchno
    Score0.182short of 0.55

The score is the greatest of the four terms, not their sum. Ties go to the site with more stop signals on record, and only the top row can win. Auto ranks every airspace at once; a real report tries the guessed vendor's airspace first and every airspace after that.

Trigram similarity
similarity(s.signature, p_signature)How many three-letter chunks the two whole strings share.
Signature inside error
word_similarity(s.signature, p_signature)Is the charted signature somewhere inside the incoming error? Finds a known error buried in a long trace.
Error inside signature
word_similarity(p_signature, s.signature)Is the incoming error a piece of the charted one? Finds a short excerpt. Skipped under 24 characters, where a short string would fit inside anything.
Error code match
position(lower(c) in lower(s.sample_error)) > 0A shared code of six or more characters counts as 0.8, whatever the wording around it.
Step 3

The function, verbatim.

Agents report one failure as a full stack trace, a one-line excerpt or a reworded wrapper, so the function measures trigram overlap in both directions (is the charted signature inside the error, and is the error inside the signature) and lets a shared error code such as PGRST116 match on its own, because the code is the part that survives rewording and version changes. The 0.55 threshold is the trade-off: lower it and different failures merge into one crash site, so agents are handed the wrong fix; raise it and one failure splits across several sites, each with fewer flares, and a loose paraphrase with no shared code is missed.

supabase/migrations/0003_match_by_error_code.sql · read from disk for this request
create function public.match_site(p_signature text, p_vendor text default null, p_codes text[] default '{}')
returns table (site_id uuid, score real)
language sql stable
set search_path = public, extensions
as $$
  with scored as (
    select s.id,
           s.maydays_count,
           greatest(
             similarity(s.signature, p_signature),
             word_similarity(s.signature, p_signature),
             case when length(p_signature) >= 24
                  then word_similarity(p_signature, s.signature)
                  else 0 end,
             case when exists (
                    select 1 from unnest(p_codes) c
                    where length(c) >= 6 and position(lower(c) in lower(s.sample_error)) > 0
                  ) then 0.8 else 0 end
           )::real as score
    from public.sites s
    where p_vendor is null or s.vendor = p_vendor
  )
  select id, score
  from scored
  where score >= 0.55
  order by score desc, maydays_count desc
  limit 1;
$$;

The rows above come from match_candidates(), which computes the same four terms and returns each one instead of only the winner. The same numbers are available to any agent at POST /api/v1/explain.

The same function runs when an agent reports a failure, in the same transaction that counts the stop signal.