Class: Ecoportal::API::GraphQL::Diff::CrossObjectDiff
- Inherits:
-
Object
- Object
- Ecoportal::API::GraphQL::Diff::CrossObjectDiff
- Defined in:
- lib/ecoportal/api/graphql/diff/cross_object_diff.rb
Overview
Cross-object diff: two templates/pages that DO NOT share Mongo ids (UAT<->PROD,
page<->template). Because nothing has the same id as its counterpart, we cannot match by id
(that is VersionDiff). Instead we PAIR the fields as an equivalence problem
(Pairing::Engine — genome + type + label + options, human-assisted, ledger-backed), build
an id-correspondence map from the accepted pairs, then emit the SAME Change output against
that map so the existing CommandSynthesizer / Deploy layer can consume it unchanged.
This deliberately operates at the FIELD level — the load-bearing simplifying principle (domain ref §6): sections/stages are scaffolding, customer data lives in the data-fields, so a cross-object diff pairs FIELDS precisely and treats structure as context. Structure-level (stage/section) reconciliation across id-spaces is not attempted here (no reliable pairing signal for scaffolding) — it is left to the human review the engine already routes to.
engine = Pairing::Engine.new(ledger: ledger) # optional diff = CrossObjectDiff.new(uat_doc, prod_doc, engine: engine, strategy: Strategy.new(pairing: :assisted, scope: :data_migration)) diff.changes # => Change, ... diff.pairing # => Pairing::Engine::Result (accepted / ambiguous / unmatched — for review) diff.unresolved # => [field-doc, ...] sources the human must adjudicate (ambiguous+unmatched)
SAFETY — only ACCEPTED pairs are treated as equivalences; ambiguous/unmatched sources are
surfaced in unresolved and NEVER auto-paired or auto-removed. A same-label field whose
genome contradicts is escalated, not silently matched (the engine guarantees this).
Instance Attribute Summary collapse
-
#strategy ⇒ Object
readonly
Returns the value of attribute strategy.
Instance Method Summary collapse
- #changelog ⇒ Object
-
#changes ⇒ Object
Strategy-filtered change-set, emitted against the pairing map (target ids translated into the source id-space so the changes replay coherently through the synthesizer).
-
#initialize(source_doc, target_doc, engine: nil, strategy: Strategy.new(pairing: :assisted)) ⇒ CrossObjectDiff
constructor
A new instance of CrossObjectDiff.
-
#pairing ⇒ Object
The
Pairing::Engine::Resultfor the field sets (accepted / ambiguous / unmatched). - #summary ⇒ Object
- #to_h ⇒ Object
-
#unresolved ⇒ Object
Source field docs the engine could not confidently pair — the human review set.
Constructor Details
#initialize(source_doc, target_doc, engine: nil, strategy: Strategy.new(pairing: :assisted)) ⇒ CrossObjectDiff
Returns a new instance of CrossObjectDiff.
37 38 39 40 41 42 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 37 def initialize(source_doc, target_doc, engine: nil, strategy: Strategy.new(pairing: :assisted)) @source = source_doc || {} @target = target_doc || {} @engine = engine || Pairing::Engine.new @strategy = strategy || Strategy.new(pairing: :assisted) end |
Instance Attribute Details
#strategy ⇒ Object (readonly)
Returns the value of attribute strategy.
29 30 31 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 29 def strategy @strategy end |
Instance Method Details
#changelog ⇒ Object
61 62 63 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 61 def changelog changes.map(&:description) end |
#changes ⇒ Object
Strategy-filtered change-set, emitted against the pairing map (target ids translated into the source id-space so the changes replay coherently through the synthesizer).
57 58 59 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 57 def changes @changes ||= @strategy.filter(all_changes) end |
#pairing ⇒ Object
The Pairing::Engine::Result for the field sets (accepted / ambiguous / unmatched).
45 46 47 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 45 def pairing @pairing ||= @engine.pair(source_fields, target_fields) end |
#summary ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 65 def summary by_op = changes.group_by(&:op) { added: by_op.fetch(:added, []).size, removed: by_op.fetch(:removed, []).size, changed: by_op.fetch(:changed, []).size, moved: by_op.fetch(:moved, []).size, total: changes.size, paired: pairing.accepted.size, unresolved: unresolved.size } end |
#to_h ⇒ Object
78 79 80 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 78 def to_h { summary: summary, changes: changes.map(&:to_h), pairing: pairing.to_h } end |
#unresolved ⇒ Object
Source field docs the engine could not confidently pair — the human review set. These are NOT emitted as removals (we do not know they were deleted vs merely unpaired).
51 52 53 |
# File 'lib/ecoportal/api/graphql/diff/cross_object_diff.rb', line 51 def unresolved pairing.ambiguous.map(&:source) + pairing.unmatched end |