Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PMP-0006 — Pump input-power degradation

Statusverified — engine e2ff2f8, cxf:fnv1a128:8d0553cbafa876eb8c3007a3178aa9a3, 2026-08-20
Severity3
Methodstatistical
Phase2
CategoryEFFICIENCY_LOSS
ConfidenceMEDIUM
EstimationBASELINE_COMPARISON
G36
Clusters
Suppresses
Suppressed by
RelatedPMP-0001, PMP-0002, VFD-0001, VFD-0005
Playbooksvfd-pump-faults
SourceDOE/Hydraulic Institute, Improving Pumping System Performance: A Sourcebook for Industry, 2nd ed., PDF pp.106 and 112–113 — assessment uses baseline energy plus flow, head, speed, fluid, and electrical data to identify efficiency degradation; Library-authored host-fitted expected-power residual; no universal pump curve or portable residual threshold is claimed; Library precedents AHU-0038 (host-published baseline and validity gate) and CHW-0001 (positive-baseline cross-multiplied degradation comparison)
Operating statesnormal automatic pump operation after startup and before coast-down, with stable staging and a valid expected-power model

Preconditions (host-enforced): The host owns pump_kw_expected. Train it on known-good operation for this pump, document the fit period and model inputs, freeze or version the fit for evaluation, and publish it only when ready, fresh, and in-domain. Typical inputs may include speed, individual-branch flow, differential pressure, staging, and fluid properties; all used inputs must be valid. pump_kw and pump_kw_expected must cover the same motor/drive electrical boundary and use kW. Exclude startup, coast-down, exercise, manual/bypass operation, safety/current/torque/demand limiting, and changes in parallel-pump configuration. A same-drive VFD-0001 or VFD-0005 is related evidence; suppress only if that deployment proves the active drive state or speed input invalidates this baseline and can scope the association to this pump. yBaselineOk checks numerical positivity only—false means NO_EVAL, while true does not prove freshness/domain validity.

Points: pump_status, pump_kw, pump_kw_expected

Outputs:

  • yFault — True while a running pump’s measured input power has remained above the valid expected baseline by more than the allowed fraction for sustained_duration
  • yBaselineOk — Evaluability flag — true only when expected power is above minimum_expected_kw; false means NO_EVAL
  • yPowerHigh — Diagnostic direction flag — true when a numerically valid baseline has a positive residual above allowance; status is not part of this flag

Parameters:

NameDefaultUnitCXF pathDescription
minimum_expected_kw0.5kWbaselineOk.tExpected-power floor for numerical evaluability. NO_PORTABLE_DEFAULT: configure above the model’s low-load/noise region; equality is not evaluable.
max_positive_residual_fraction0.151allowance.kAllowed positive fraction of expected input power. ADOPTED_TUNABLE; 0.15 is an executable starting band, not a published pump-wide limit.
sustained_duration1800.0spersist.delayTimeContinuous excess required before alarm. ADOPTED_TUNABLE 30-minute window; commission against model residuals and plant time constants.

Description

This rule detects a pump motor/drive assembly drawing materially more active power than a known-good model expects at the same operating condition. The signature can accompany mechanical drag, impeller/strainer degradation, incorrect speed feedback, bypassed control, or reduced motor/drive efficiency; it can also be manufactured by a stale, out-of-domain, or badly scoped baseline. The model remains host-side and is published as an ordinary derived point.

Detection Logic

baseline_ok = pump_kw_expected > minimum_expected_kw
residual    = pump_kw - pump_kw_expected
allowance   = pump_kw_expected × max_positive_residual_fraction
power_high  = baseline_ok AND residual > allowance

yBaselineOk = baseline_ok
yPowerHigh  = power_high
yFault      = pump_status AND power_high, sustained for sustained_duration

PMP-0006 block graph

The graph deliberately cross-multiplies instead of dividing. For a positive valid baseline, actual−expected > fraction×expected is exactly the requested relative-residual test and cannot evaluate a zero denominator. Both comparisons are strict. yPowerHigh exposes residual direction independently of run status; only yFault is status-gated and persisted with delayOnInit=true.

Possible Diagnoses

  1. Fouled or damaged impeller, blocked strainer, or unexpected hydraulic load
  2. Bearing, seal, coupling, or alignment drag
  3. Motor or drive efficiency degradation
  4. Incorrect speed feedback or control in bypass/manual mode
  5. Different parallel-pump staging than the baseline condition
  6. Actual/expected points covering different electrical boundaries
  7. Stale, out-of-domain, or degradation-trained expected-power model
  8. Active power sensor scaling or wiring error

Energy Impact

EFFICIENCY_LOSS with BASELINE_COMPARISON. During evaluable alarm intervals the positive residual is directly measured kW above the host model, so the host may integrate it to kWh. That estimate inherits model error and must exclude invalid domains, startup, and mode changes. A low residual is intentionally not accused by this rule because it can mean successful turndown or a separate delivery failure.

Emissions Impact

Scope 2. Multiply evaluable excess kWh by the applicable marginal or accounting grid factor. Report the baseline/model uncertainty with the estimate.

Deviations

  • No Divide block is used. Downstream Boolean gating does not short-circuit an elementary Divide; cross-multiplication is equivalent in the positive baseline domain and guarantees no zero-denominator evaluation.
  • Expected power is a host-derived point, not a universal curve. The point contract requires model inputs, known-good fit period, electrical boundary, and in-domain readiness. The graph cannot certify those obligations.
  • All three defaults need commissioning. The 0.5 kW floor has NO_PORTABLE_DEFAULT; the 15% residual and 1800 s duration are adopted tunables, not source-transcribed thresholds.
  • Only positive residual is in scope. Low power may indicate successful reset, broken coupling, bad metering, or another delivery fault; conflating the directions would erase diagnosis.
  • VFD relationships stay informational in the library metadata. Whether a same-drive VFD-0001/0005 invalidates this model depends on its inputs and operating state; unconditional ID-level suppression could silence every pump or a baseline that does not use the disputed signal.
  • No simulation validation is claimed. The plant harness now preserves per-pump power, flow, and status proxies, but it has no frozen expected-power model trained on a disjoint known-good period. Synthetic vectors validate graph behavior only.

Test Vectors

23 scenarios, clock step 60 s over 3600 s.

ScenarioDescription
baseline_zero_not_evaluableA zero expected-power baseline is not evaluable; no divide exists and both diagnostic/fault outputs stay false.
baseline_negative_not_evaluableA negative expected value remains numerically safe and not evaluable; cross-multiplication creates no Inf or NaN path.
baseline_just_below_floorThe denominator guard is strict below its configured floor.
baseline_exact_floorExactly minimum_expected_kw remains not evaluable under the strict comparator.
baseline_just_above_floorA small but valid baseline makes evaluability true and can support the full delayed verdict.
actual_equals_expectedMeasured power on the baseline has zero positive residual.
exact_positive_residual_thresholdExactly 15 percent excess is clear because the comparison is strict.
just_above_positive_residualOne test increment above 15 percent asserts yPowerHigh immediately and yFault after 30 minutes.
negative_residual_not_this_ruleActual power below expected is deliberately silent; delivery/proof faults own that direction.
stopped_pump_exposes_diagnostic_onlyPower residual direction is diagnostic detail independent of status, while yFault remains status-gated.
transient_excess_powerA 20-minute power excursion clears before the 30-minute persistence window.
violation_ends_at_delay_boundaryThe residual clears exactly at 1800 seconds before timer evaluation and never alarms.
sustained_excess_and_recoveryA mature excess-power alarm clears immediately when actual power returns to baseline.
baseline_change_resets_timerA valid baseline change that brings the residual inside allowance resets persistence; a later excess serves a new full window.
invalid_baseline_resets_timerExpected power falling to zero clears evaluability and diagnostic state; a later valid baseline must serve a new full persistence interval.
baseline_changes_but_candidate_stays_trueA model update within the still-faulting region does not reset the timer because the Boolean candidate never falls.
pump_start_begins_timerA standing residual does not accumulate while stopped; persistence starts only after proven run status rises.
pump_status_drop_resets_timerA stopped interval resets persistence even while the baseline residual remains high; restart requires a new full duration.
two_short_excess_episodesTwo sub-duration excess-power episodes separated by a compliant interval do not accumulate.
residual_threshold_chatterMeasured power alternates just below and above the 15 percent boundary, so yPowerHigh chatters but persistence never matures.
degraded_fit_learns_fault_as_normalActual and expected are both high because the fit learned degraded operation; the residual is zero and the graph stays silent, pinning the known-good training precondition.
invalid_stale_baseline_raw_behaviorA stale but positive expected-power value looks valid to the graph and can alarm; model freshness/in-domain status is a mandatory host NO_EVAL gate.
vfd_relationship_is_host_sideThe raw pump baseline alarm remains active with sustained excess; a deployment may suppress only when a same-drive VFD finding actually invalidates this model.
vectors.json
{
  "schema": "cxf-library/vectors/v1",
  "clock": {
    "step_s": 60,
    "horizon_s": 3600
  },
  "scenarios": [
    {
      "name": "baseline_zero_not_evaluable",
      "description": "A zero expected-power baseline is not evaluable; no divide exists and both diagnostic/fault outputs stay false.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 10.0,
        "pump_kw_expected": 0.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "baseline_negative_not_evaluable",
      "description": "A negative expected value remains numerically safe and not evaluable; cross-multiplication creates no Inf or NaN path.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 10.0,
        "pump_kw_expected": -1.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "baseline_just_below_floor",
      "description": "The denominator guard is strict below its configured floor.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 2.0,
        "pump_kw_expected": 0.49
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "baseline_exact_floor",
      "description": "Exactly minimum_expected_kw remains not evaluable under the strict comparator.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 2.0,
        "pump_kw_expected": 0.5
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "baseline_just_above_floor",
      "description": "A small but valid baseline makes evaluability true and can support the full delayed verdict.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 0.7,
        "pump_kw_expected": 0.51
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 1740,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 1860,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "actual_equals_expected",
      "description": "Measured power on the baseline has zero positive residual.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 10.0,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "exact_positive_residual_threshold",
      "description": "Exactly 15 percent excess is clear because the comparison is strict.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 11.5,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "just_above_positive_residual",
      "description": "One test increment above 15 percent asserts yPowerHigh immediately and yFault after 30 minutes.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 11.51,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 1740,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 1860,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "negative_residual_not_this_rule",
      "description": "Actual power below expected is deliberately silent; delivery/proof faults own that direction.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 8.0,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "stopped_pump_exposes_diagnostic_only",
      "description": "Power residual direction is diagnostic detail independent of status, while yFault remains status-gated.",
      "inputs": {
        "pump_status": false,
        "pump_kw": 12.0,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "transient_excess_power",
      "description": "A 20-minute power excursion clears before the 30-minute persistence window.",
      "inputs": {
        "pump_status": true,
        "pump_kw": [
          {
            "t": 0,
            "value": 12.0
          },
          {
            "t": 1200,
            "value": 10.0
          }
        ],
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 1140,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 1260,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "violation_ends_at_delay_boundary",
      "description": "The residual clears exactly at 1800 seconds before timer evaluation and never alarms.",
      "inputs": {
        "pump_status": true,
        "pump_kw": [
          {
            "t": 0,
            "value": 12.0
          },
          {
            "t": 1800,
            "value": 10.0
          }
        ],
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "sustained_excess_and_recovery",
      "description": "A mature excess-power alarm clears immediately when actual power returns to baseline.",
      "inputs": {
        "pump_status": true,
        "pump_kw": [
          {
            "t": 0,
            "value": 12.0
          },
          {
            "t": 2700,
            "value": 10.0
          }
        ],
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 1740,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 1860,
          "to_s": 2640,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 2760,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "baseline_change_resets_timer",
      "description": "A valid baseline change that brings the residual inside allowance resets persistence; a later excess serves a new full window.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 12.0,
        "pump_kw_expected": [
          {
            "t": 0,
            "value": 10.0
          },
          {
            "t": 1200,
            "value": 11.0
          },
          {
            "t": 1500,
            "value": 10.0
          }
        ]
      },
      "expect": [
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3240,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 3360,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "invalid_baseline_resets_timer",
      "description": "Expected power falling to zero clears evaluability and diagnostic state; a later valid baseline must serve a new full persistence interval.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 12.0,
        "pump_kw_expected": [
          {
            "t": 0,
            "value": 10.0
          },
          {
            "t": 1200,
            "value": 0.0
          },
          {
            "t": 1500,
            "value": 10.0
          }
        ]
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 1260,
          "to_s": 1440,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3240,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 3360,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "baseline_changes_but_candidate_stays_true",
      "description": "A model update within the still-faulting region does not reset the timer because the Boolean candidate never falls.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 13.0,
        "pump_kw_expected": [
          {
            "t": 0,
            "value": 10.0
          },
          {
            "t": 900,
            "value": 10.5
          }
        ]
      },
      "expect": [
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 1740,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 1860,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "pump_start_begins_timer",
      "description": "A standing residual does not accumulate while stopped; persistence starts only after proven run status rises.",
      "inputs": {
        "pump_status": [
          {
            "t": 0,
            "value": false
          },
          {
            "t": 600,
            "value": true
          }
        ],
        "pump_kw": 12.0,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 2340,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 2460,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "pump_status_drop_resets_timer",
      "description": "A stopped interval resets persistence even while the baseline residual remains high; restart requires a new full duration.",
      "inputs": {
        "pump_status": [
          {
            "t": 0,
            "value": true
          },
          {
            "t": 1200,
            "value": false
          },
          {
            "t": 1500,
            "value": true
          }
        ],
        "pump_kw": 12.0,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3240,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 3360,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "two_short_excess_episodes",
      "description": "Two sub-duration excess-power episodes separated by a compliant interval do not accumulate.",
      "inputs": {
        "pump_status": true,
        "pump_kw": [
          {
            "t": 0,
            "value": 12.0
          },
          {
            "t": 900,
            "value": 10.0
          },
          {
            "t": 1200,
            "value": 12.0
          },
          {
            "t": 2400,
            "value": 10.0
          }
        ],
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "residual_threshold_chatter",
      "description": "Measured power alternates just below and above the 15 percent boundary, so yPowerHigh chatters but persistence never matures.",
      "inputs": {
        "pump_status": true,
        "pump_kw": [
          {
            "t": 0,
            "value": 11.49
          },
          {
            "t": 60,
            "value": 11.51
          },
          {
            "t": 120,
            "value": 11.49
          },
          {
            "t": 180,
            "value": 11.51
          },
          {
            "t": 240,
            "value": 11.49
          },
          {
            "t": 300,
            "value": 11.51
          },
          {
            "t": 360,
            "value": 11.49
          },
          {
            "t": 420,
            "value": 11.51
          },
          {
            "t": 480,
            "value": 11.49
          }
        ],
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "degraded_fit_learns_fault_as_normal",
      "description": "Actual and expected are both high because the fit learned degraded operation; the residual is zero and the graph stays silent, pinning the known-good training precondition.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 12.0,
        "pump_kw_expected": 12.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        },
        {
          "output": "yFault",
          "from_s": 0,
          "to_s": 3600,
          "equals": false
        }
      ]
    },
    {
      "name": "invalid_stale_baseline_raw_behavior",
      "description": "A stale but positive expected-power value looks valid to the graph and can alarm; model freshness/in-domain status is a mandatory host NO_EVAL gate.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 12.0,
        "pump_kw_expected": 8.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 1860,
          "to_s": 3600,
          "equals": true
        }
      ]
    },
    {
      "name": "vfd_relationship_is_host_side",
      "description": "The raw pump baseline alarm remains active with sustained excess; a deployment may suppress only when a same-drive VFD finding actually invalidates this model.",
      "inputs": {
        "pump_status": true,
        "pump_kw": 12.0,
        "pump_kw_expected": 10.0
      },
      "expect": [
        {
          "output": "yBaselineOk",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yPowerHigh",
          "from_s": 0,
          "to_s": 3600,
          "equals": true
        },
        {
          "output": "yFault",
          "from_s": 1860,
          "to_s": 3600,
          "equals": true
        }
      ]
    }
  ]
}