Class: Ecoportal::API::GraphQL::Diff::Pairing::Engine
- Inherits:
-
Object
- Object
- Ecoportal::API::GraphQL::Diff::Pairing::Engine
- 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:
- consulting the LEDGER first — a previously-confirmed pair auto-resolves (method :ledger, confidence 1.0), so pairing improves over time and only novelty is scored;
- otherwise scoring every remaining source×target candidate with multi-signal confidence (genome + type + label + options — see Signals), picking the best target per source in a stable, greedy, one-to-one assignment (highest scores first).
It then CLASSIFIES each best candidate:
accepted— score >= accept_threshold: high confidence, auto-paired;ambiguous— accept > score >= review_threshold, OR the top two candidates are withintie_margin(genuinely close): route to a HUMAN to adjudicate;unmatched— no target scored >= review_threshold: escalate as a novelty.
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
-
#confirm!(candidate, matched_by: nil) ⇒ Object
Persist a confirmed pairing to the ledger (auto-accept or human decision).
-
#initialize(ledger: nil, kind: :field, **thresholds) ⇒ Engine
constructor
A new instance of Engine.
-
#pair(sources, targets) ⇒ Object
Pair
sources(id-space A) totargets(id-space B).
Constructor Details
#initialize(ledger: nil, kind: :field, **thresholds) ⇒ Engine
Returns a new instance of Engine.
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 |