Class: Ecoportal::API::GraphQL::Diff::Pairing::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/ecoportal/api/graphql/diff/pairing/engine.rb

Overview

The equivalence-matching engine for CROSS-OBJECT pairing (UAT<->PROD, page<->template).

Given two lists of field docs living in different id-spaces, it proposes pairings by:

1. consulting the LEDGER first 

It then CLASSIFIES each best candidate:

- `accepted`  

NEVER guesses: only accepted pairs are safe to auto-apply / auto-record; ambiguous and unmatched are surfaced for human resolution. Confirmed decisions are written back to the ledger by the caller (or via #confirm!) so the next run needs no human on them.

Defined Under Namespace

Classes: Result

Constant Summary collapse

DEFAULTS =
{ accept_threshold: 0.85, review_threshold: 0.5, tie_margin: 0.1 }.freeze

Instance Method Summary collapse

Constructor Details

#initialize(ledger: nil, kind: :field, **thresholds) ⇒ Engine

Returns a new instance of Engine.

Parameters:

  • ledger (Ledger, nil) (defaults to: nil) —

    consulted first + written to on #confirm!.

  • kind (Symbol) (defaults to: :field) —

    entity kind recorded in the ledger (default :field).



44
45
46
47
48
# File 'lib/ecoportal/api/graphql/diff/pairing/engine.rb', line 44

def initialize(ledger: nil, kind: :field, **thresholds)
  @ledger = ledger
  @kind   = kind
  @cfg    = DEFAULTS.merge(thresholds)
end

Instance Method Details

#confirm!(candidate, matched_by: nil) ⇒ Object

Persist a confirmed pairing to the ledger (auto-accept or human decision). No-op without a ledger. matched_by overrides the candidate's dominant signal (e.g. :human when a person adjudicated). Returns the recorded Entry (or nil).



63
64
65
66
67
68
69
70
71
# File 'lib/ecoportal/api/graphql/diff/pairing/engine.rb', line 63

def confirm!(candidate, matched_by: nil)
  return nil unless @ledger

  @ledger.record(
    kind: @kind, source_id: candidate.source_id, target_id: candidate.target_id,
    matched_by: matched_by || candidate.matched_by, confidence: candidate.score,
    signals: candidate.signals
  )
end

#pair(sources, targets) ⇒ Object

Pair sources (id-space A) to targets (id-space B). Returns a Result.



51
52
53
54
55
56
57
58
# File 'lib/ecoportal/api/graphql/diff/pairing/engine.rb', line 51

def pair(sources, targets)
  sources = Array(sources)
  targets = Array(targets)

  accepted, remaining_sources, remaining_targets = apply_ledger(sources, targets)
  scored = score_all(remaining_sources, remaining_targets)
  assign(scored, remaining_sources, accepted)
end