Definitions
The definitions the agent and Ask both run on. Each has an owner, a version, SQL and tests. Edits make a new version.Failing integration
failing_integration unit: integrations agent detector canonical: opsA POS integration that is losing orders. Ops looks at each branch's own link over the last hour; Integrations looks at whole releases, because a bad vendor version shows up as many small local problems. The ops definition is canonical for counting.
A branch's POS integration failed at least min_failures orders in the last window_minutes, and those are more than error_rate of its orders in that window. An order failed if an injection attempt errored, or it is still not in the POS stuck_seconds after acceptance and nobody rejected or cancelled it. When every failure is a mapping error on one item, item_id and channel_id name it and fix says to switch that item off on that channel rather than pause the channel.
latest change: auth_expired is read from the auth event stream as of now (stored expiry only when there is no event), refresh_failed added, and fix says to escalate to the POS partner when the last refresh failed.
- pass count_betweenobserved 6, expected between 1.0 and 150.0
- pass friday_late_eveningobserved 4, expected between 1.0 and 50.0
- pass uniqueobserved {'duplicates': 0}, expected integration_id unique
- pass detector_shapeobserved {'missing_columns': [], 'bad_rows': 0, 'rows': 6}, expected columns ['subject_type', 'subject_id', 'started_at', 'evidence'], evidence is an object
SQL, rendered for now
WITH fails AS (
SELECT e.order_id, max(e.at) AS last_failed_at, arg_max(e.payload, e.at) AS last_error,
any_value(TRY_CAST(e.payload->>'item_id' AS INTEGER)) AS item_id,
any_value(coalesce(e.payload->>'modifier', (e.payload->>'modifier_id'))) AS modifier,
bool_or((e.payload->>'error') ILIKE '%mapping%' OR (e.payload->>'error') ILIKE '%modifier%'
OR (e.payload->>'error') ILIKE '%E_COMBO%') AS mapping_error
FROM order_events e
WHERE e.type ILIKE '%injection_fail%'
AND e.at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (60) MINUTE AND e.at <= TIMESTAMP 'Fri 23:00:00'
GROUP BY e.order_id
),
closed AS (
SELECT e.order_id, min(e.at) AS closed_at
FROM order_events e
WHERE (e.type ILIKE '%cancel%' OR e.type ILIKE '%reject%') AND e.at <= TIMESTAMP 'Fri 23:00:00'
GROUP BY e.order_id
),
recent AS (
SELECT b.pos_integration_id AS integration_id, o.id AS order_id, o.accepted_at, o.channel_id,
f.item_id, f.modifier,
coalesce(f.mapping_error, FALSE) OR o.rejection_reason = 'payload mapping error' AS mapping_error,
f.order_id IS NOT NULL
OR ((o.injected_at IS NULL OR o.injected_at > TIMESTAMP 'Fri 23:00:00') AND x.order_id IS NULL
AND o.accepted_at <= TIMESTAMP 'Fri 23:00:00' - INTERVAL (90) SECOND) AS failed,
f.last_failed_at, f.last_error
FROM orders o
JOIN branches b ON b.id = o.branch_id
JOIN channels c ON c.id = o.channel_id
LEFT JOIN fails f ON f.order_id = o.id
LEFT JOIN closed x ON x.order_id = o.id
WHERE o.accepted_at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (60) MINUTE AND o.accepted_at <= TIMESTAMP 'Fri 23:00:00'
AND c.kind <> 'dine_in' AND b.pos_integration_id IS NOT NULL
),
per_integration AS (
SELECT integration_id, count(*) AS orders,
count(*) FILTER (WHERE failed) AS failed_orders,
min(accepted_at) FILTER (WHERE failed) AS first_failure_at,
arg_max(last_error, last_failed_at) AS last_error,
list(order_id ORDER BY accepted_at) FILTER (WHERE failed) AS failed_order_ids,
count(*) FILTER (WHERE failed AND mapping_error) AS mapping_failures,
count(DISTINCT item_id) FILTER (WHERE failed AND item_id IS NOT NULL) AS failing_items,
min(item_id) FILTER (WHERE failed AND item_id IS NOT NULL) AS item_id,
any_value(modifier) FILTER (WHERE failed AND modifier IS NOT NULL) AS modifier,
mode(channel_id) FILTER (WHERE failed) AS failing_channel_id
FROM recent
GROUP BY integration_id
),
auth_state AS (
SELECT e.integration_id, arg_max(e.type, e.at) AS last_auth_event, max(e.at) AS last_auth_event_at
FROM integration_events e
WHERE (e.type ILIKE '%auth_expired%' OR e.type ILIKE '%token_refresh%' OR e.type ILIKE '%auth_refresh%')
AND e.at <= TIMESTAMP 'Fri 23:00:00'
GROUP BY e.integration_id
),
events AS (
SELECT e.integration_id, count(*) AS error_events, arg_max(e.type, e.at) AS last_event, max(e.at) AS last_event_at
FROM integration_events e
WHERE e.at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (60) MINUTE AND e.at <= TIMESTAMP 'Fri 23:00:00'
AND (e.type ILIKE '%fail%' OR e.type ILIKE '%error%' OR e.type ILIKE '%expired%')
GROUP BY e.integration_id
)
SELECT 'integration' AS subject_type, i.id AS subject_id, i.id AS integration_id, i.branch_id,
b.merchant_id, i.vendor_id, i.version, p.first_failure_at AS started_at,
CASE WHEN p.failing_items = 1 AND p.mapping_failures = p.failed_orders THEN p.item_id END AS item_id,
CASE WHEN p.failing_items = 1 AND p.mapping_failures = p.failed_orders THEN p.failing_channel_id END AS channel_id,
CASE WHEN p.failing_items = 1 AND p.mapping_failures = p.failed_orders THEN 'switch item off on channel'
WHEN coalesce(a.last_auth_event ILIKE '%refresh_failed%', FALSE) THEN 'escalate to the POS partner'
WHEN CASE WHEN a.last_auth_event IS NULL THEN coalesce(i.auth_expires_at <= TIMESTAMP 'Fri 23:00:00', FALSE)
ELSE a.last_auth_event ILIKE '%expired%' OR a.last_auth_event ILIKE '%refresh_failed%' END THEN 'refresh the POS token'
ELSE 'investigate the POS link' END AS fix,
CASE WHEN p.failed_orders = p.orders OR (CASE WHEN a.last_auth_event IS NULL THEN coalesce(i.auth_expires_at <= TIMESTAMP 'Fri 23:00:00', FALSE)
ELSE a.last_auth_event ILIKE '%expired%' OR a.last_auth_event ILIKE '%refresh_failed%' END) THEN 'high'
ELSE 'medium' END AS severity,
json_object(
'vendor', v.name,
'version', i.version,
'integration_status', i.status,
'window_minutes', 60,
'orders', p.orders,
'failed_orders', p.failed_orders,
'error_rate', round(p.failed_orders / p.orders, 3),
'threshold', 0.2,
'auth_expires_at', i.auth_expires_at,
'auth_expired', CASE WHEN a.last_auth_event IS NULL THEN coalesce(i.auth_expires_at <= TIMESTAMP 'Fri 23:00:00', FALSE)
ELSE a.last_auth_event ILIKE '%expired%' OR a.last_auth_event ILIKE '%refresh_failed%' END,
'refresh_failed', coalesce(a.last_auth_event ILIKE '%refresh_failed%', FALSE),
'last_auth_event', a.last_auth_event,
'last_auth_event_at', a.last_auth_event_at,
'last_sync_at', i.last_sync_at,
'last_error', p.last_error,
'error_events', coalesce(ev.error_events, 0),
'last_event', ev.last_event,
'last_event_at', ev.last_event_at,
'failed_order_ids', p.failed_order_ids[1:20],
'mapping_failures', p.mapping_failures,
'item_id', CASE WHEN p.failing_items = 1 THEN p.item_id END,
'modifier', CASE WHEN p.failing_items = 1 THEN p.modifier END,
'channel_id', p.failing_channel_id
) AS evidence
FROM per_integration p
JOIN integrations i ON i.id = p.integration_id
JOIN branches b ON b.id = i.branch_id
LEFT JOIN integration_vendors v ON v.id = i.vendor_id
LEFT JOIN events ev ON ev.integration_id = i.id
LEFT JOIN auth_state a ON a.integration_id = i.id
WHERE p.failed_orders >= 3 AND p.failed_orders / p.orders > 0.2
ORDER BY started_at, i.id
Every integration on a POS release whose order failure rate over the last release_window_hours is at least release_error_rate and regression_factor times the rest of that vendor's releases (or the rest of the fleet when the vendor has one release), on at least release_min_orders orders spread over at least release_min_hours hours of the window. A regression is a change: the release was rolled out within the history (version_upgraded) or had a good day before it went bad; a release that has always run hotter than its siblings is a vendor-quality topic, not an incident. started_at is when the rollout reached the first integration (its version_upgraded event), else the first failure after the release's last good day.
latest change: A regression needs evidence of a change (a rollout event, or a good day before it went bad) and at least 12 hours of orders in its 24-hour window.
- pass count_betweenobserved 71, expected between 30.0 and 150.0
- pass uniqueobserved {'duplicates': 0}, expected integration_id unique
- pass detector_shapeobserved {'missing_columns': [], 'bad_rows': 0, 'rows': 71}, expected columns ['subject_type', 'subject_id', 'started_at', 'evidence'], evidence is an object
SQL, rendered for now
WITH fails AS (
SELECT DISTINCT e.order_id
FROM order_events e
WHERE e.type ILIKE '%injection_fail%'
AND e.at <= TIMESTAMP 'Fri 23:00:00' AND e.at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (7) DAY
),
attempts AS (
SELECT i.id AS integration_id, i.vendor_id, i.version, o.accepted_at,
CAST(o.accepted_at AS DATE) AS day, f.order_id IS NOT NULL AS failed
FROM orders o
JOIN branches b ON b.id = o.branch_id
JOIN integrations i ON i.id = b.pos_integration_id
JOIN channels c ON c.id = o.channel_id
LEFT JOIN fails f ON f.order_id = o.id
WHERE o.accepted_at <= TIMESTAMP 'Fri 23:00:00' AND o.accepted_at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (7) DAY
AND c.kind <> 'dine_in'
),
releases AS (
SELECT vendor_id, version, count(*) AS orders, count(*) FILTER (WHERE failed) AS failed,
count(DISTINCT date_trunc('hour', accepted_at)) AS hours_with_orders
FROM attempts
WHERE accepted_at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (24) HOUR
GROUP BY vendor_id, version
),
baselines AS (
SELECT r.*, r.failed / r.orders AS rate,
(sum(r.failed) OVER (PARTITION BY r.vendor_id) - r.failed)
/ nullif(sum(r.orders) OVER (PARTITION BY r.vendor_id) - r.orders, 0) AS vendor_rate,
(sum(r.failed) OVER () - r.failed) / nullif(sum(r.orders) OVER () - r.orders, 0) AS fleet_rate
FROM releases r
),
regressed AS (
SELECT *, coalesce(vendor_rate, fleet_rate, 0) AS baseline
FROM baselines
WHERE orders >= 200 AND hours_with_orders >= 12
AND rate >= 0.02
AND rate >= 3 * coalesce(vendor_rate, fleet_rate, 0)
),
daily AS (
SELECT a.vendor_id, a.version, a.day, count(*) AS orders, count(*) FILTER (WHERE a.failed) AS failed
FROM attempts a
JOIN regressed r ON r.vendor_id = a.vendor_id AND r.version = a.version
GROUP BY a.vendor_id, a.version, a.day
),
last_good AS (
SELECT vendor_id, version, max(day) FILTER (WHERE failed / orders < 0.02) AS last_good_day
FROM daily
GROUP BY vendor_id, version
),
onset AS (
SELECT d.vendor_id, d.version,
min(d.day) FILTER (WHERE d.day > coalesce(g.last_good_day, DATE '-infinity')) AS onset_day,
list(json_object('day', strftime(d.day, '%Y-%m-%d'), 'orders', d.orders, 'failed', d.failed)
ORDER BY d.day) AS daily
FROM daily d
JOIN last_good g ON g.vendor_id = d.vendor_id AND g.version = d.version
GROUP BY d.vendor_id, d.version
),
first_failure AS (
SELECT a.vendor_id, a.version, min(a.accepted_at) AS started_at
FROM attempts a
JOIN onset s ON s.vendor_id = a.vendor_id AND s.version = a.version
WHERE a.failed AND a.day >= s.onset_day
GROUP BY a.vendor_id, a.version
),
upgrades AS (
SELECT i.vendor_id, i.version, min(e.at) AS first_upgrade_at
FROM integration_events e
JOIN integrations i ON i.id = e.integration_id
WHERE e.type ILIKE '%version_upgraded%' AND e.at <= TIMESTAMP 'Fri 23:00:00'
AND coalesce(e.payload->>'to', i.version) = i.version
GROUP BY i.vendor_id, i.version
),
per_integration AS (
SELECT integration_id, count(*) AS orders, count(*) FILTER (WHERE failed) AS failed
FROM attempts
WHERE accepted_at > TIMESTAMP 'Fri 23:00:00' - INTERVAL (24) HOUR
GROUP BY integration_id
)
SELECT 'integration' AS subject_type, i.id AS subject_id, i.id AS integration_id, i.branch_id,
b.merchant_id, i.vendor_id, i.version, coalesce(up.first_upgrade_at, ff.started_at) AS started_at,
'high' AS severity,
json_object(
'release', v.name || ' ' || r.version,
'vendor', v.name,
'version', r.version,
'window_hours', 24,
'release_orders', r.orders,
'release_failed', r.failed,
'release_error_rate', round(r.rate, 4),
'baseline_error_rate', round(r.baseline, 4),
'times_baseline', round(r.rate / nullif(r.baseline, 0), 1),
'integrations_on_release', count(*) OVER (PARTITION BY r.vendor_id, r.version),
'onset_day', strftime(s.onset_day, '%Y-%m-%d'),
'first_upgrade_at', up.first_upgrade_at,
'daily', s.daily,
'integration_orders', coalesce(pi.orders, 0),
'integration_failed', coalesce(pi.failed, 0)
) AS evidence
FROM regressed r
JOIN integrations i ON i.vendor_id = r.vendor_id AND i.version = r.version
JOIN branches b ON b.id = i.branch_id AND b.pos_integration_id = i.id
LEFT JOIN integration_vendors v ON v.id = i.vendor_id
LEFT JOIN onset s ON s.vendor_id = r.vendor_id AND s.version = r.version
LEFT JOIN first_failure ff ON ff.vendor_id = r.vendor_id AND ff.version = r.version
LEFT JOIN upgrades up ON up.vendor_id = r.vendor_id AND up.version = r.version
LEFT JOIN last_good g ON g.vendor_id = r.vendor_id AND g.version = r.version
LEFT JOIN per_integration pi ON pi.integration_id = i.id
WHERE up.first_upgrade_at IS NOT NULL OR g.last_good_day IS NOT NULL
ORDER BY i.vendor_id, i.version, i.id
Parameters
change one, see what changes tonight, then save it as a new version with a noteHistory
append-only; nothing is edited in place- definitionHead of Integrations integrations v3 A regression needs evidence of a change (a rollout event, or a good day before it went bad) and at least 12 hours of orders in its 24-hour window.
- definitionCOO ops v3 Names the item and channel when every failure in the window is a mapping error on one item.
- definitionCOO ops v4 auth_expired is read from the auth event stream as of now (stored expiry only when there is no event), refresh_failed added, and fix says to escalate to the POS partner when the last refresh failed.
- definitionHead of Integrations integrations v1 First version: a release failing at least 2% of its orders and 3x the rest of its vendor (or the fleet), on at least 200 orders in 24 hours.
- definitionHead of Integrations integrations v2 Seven days of daily history; the onset is taken from the rollout log when there is one.
- definitionCOO ops v1 First version: at least 3 failed orders and more than 20% of the integration's orders in the last 60 minutes.
- definitionCOO ops v2 Orders the POS rejected or that were cancelled no longer count as failed unless an injection attempt errored; menu drift was showing up as broken links.