Skip to content

Reconcile SEARCH_TYPE_CONFIDENCE table with BS#1351 rotation-picker trust policy #1356

@jakebromberg

Description

@jakebromberg

Why now

BS#1351's rotation-picker gate trusts only search_type === 'direct'. The SEARCH_TYPE_CONFIDENCE table in the same file (apps/backend/services/library.service.ts:841) assigns positive confidence to the four search_types BS#1351 explicitly rejects:

const SEARCH_TYPE_CONFIDENCE: Record<LookupResponse['search_type'], number | null> = {
  direct: 0.9,
  fallback: 0.5,
  alternative: 0.3,
  compilation: 0.3,
  song_as_artist: 0.3,
  none: null,
};

Two trust policies live in the same file. The picker says non-direct is noise. The canonical-entity mapper says non-direct is signal worth quantifying. A reviewer can't tell which represents intended policy.

The fragility

fireAndForgetCanonicalEntity (apps/backend/controllers/library.controller.ts:148-165 per the BS-wide review) writes library.canonical_entity_id for ANY non-null linkage with no threshold check. flowsheet-linkage.service.ts:93 correctly gates with AUTO_ACCEPT_THRESHOLD = 0.9, blocking non-direct. But the threshold is the only thing stopping non-direct from materializing wrong data, and that's an easy guard to weaken under pressure (e.g., "add a gray-zone review queue, lower the threshold to 0.7 for recall").

The columns library.canonical_entity_id + library.canonical_entity_confidence retain the wrong-album linkages from low-confidence writes today. Any future consumer that reads canonical_entity_id without a confidence floor inherits the same Yenbett-class defect BS#1351 closed at the picker layer.

No current consumer materializes the wrong release_id through this path (projectMainRow in the library-identity-consumer job hardcodes discogs_release_id: null, so tier-2 of the picker reads NULL even when library.canonical_entity_id is low-confidence). But the configuration is fragile.

Proposed reconciliation

One of:

  1. Set non-direct to null in the table to match the picker's policy. mapLookupToCanonicalEntity would return null for non-direct, fireAndForgetCanonicalEntity would no-op. Eliminates the low-confidence write path entirely.

  2. Export a single trust predicate (isTrustedLmlAlbumMatch(response): boolean) from library.service.ts that derives search_type === 'direct' AND confidence >= AUTO_ACCEPT_THRESHOLD. Use it from the picker gate and from fireAndForgetCanonicalEntity's precondition.

  3. Keep the table but add a hard threshold inside fireAndForgetCanonicalEntity (e.g., refuse to write below 0.9). Documents the asymmetric intent: confidence ranks are descriptive (for audit / future re-judging), not prescriptive.

Option 1 is the smallest change and lets the two policies converge. Option 2 captures the relationship explicitly. Option 3 preserves the original B-0 calibration framing.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglmlTouches library-metadata-lookup

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions