···241241 return nil, err
242242 }
243243244244+ // For beans, build a roaster URI -> name map so we can include the
245245+ // roaster name in suggestion fields. This lets clients verify the
246246+ // roaster matches before setting source_ref.
247247+ var roasterNames map[string]string
248248+ if collection == atproto.NSIDBean {
249249+ roasterNames = buildRoasterNameMap(ctx, source)
250250+ }
251251+244252 // dedupKey -> aggregated suggestion
245253 type candidate struct {
246254 suggestion EntitySuggestion
···265273 for _, f := range config.allFields {
266274 if v, ok := recordData[f].(string); ok && v != "" {
267275 fields[f] = v
276276+ }
277277+ }
278278+279279+ // For beans, resolve roasterRef to a roaster name
280280+ if roasterNames != nil {
281281+ if ref, ok := recordData["roasterRef"].(string); ok && ref != "" {
282282+ if rn, ok := roasterNames[ref]; ok {
283283+ fields["roasterName"] = rn
284284+ }
268285 }
269286 }
270287···359376 }
360377361378 return score
379379+}
380380+381381+// buildRoasterNameMap loads all indexed roaster records and returns a map
382382+// from AT-URI to roaster name. Used to resolve roaster references in bean
383383+// suggestions so the client can verify roaster match before setting source_ref.
384384+func buildRoasterNameMap(ctx context.Context, source RecordSource) map[string]string {
385385+ records, err := source.ListRecordsByCollectionOldest(ctx, atproto.NSIDRoaster)
386386+ if err != nil {
387387+ return nil
388388+ }
389389+ m := make(map[string]string, len(records))
390390+ for _, r := range records {
391391+ var data map[string]any
392392+ if err := json.Unmarshal(r.Record, &data); err != nil {
393393+ continue
394394+ }
395395+ if name, ok := data["name"].(string); ok && name != "" {
396396+ m[r.URI] = name
397397+ }
398398+ }
399399+ return m
362400}
363401364402func countNonEmpty(fields map[string]string) int {