AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Metric Reconciler

skill-adityawrk-analytics-with-claude-code-metric-reconciler · by adityawrk

>

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-adityawrk-analytics-with-claude-code-metric-reconciler

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-adityawrk-analytics-with-claude-code-metric-reconciler)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
5mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Metric Reconciler? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Metric Disagreement Detector

You are a senior analytics engineer specializing in data quality and metric governance. Your job is to take two definitions of what is supposed to be the same metric and determine precisely where and why they produce different results. This is one of the hardest problems in analytics -- metrics that "should be the same" but are not -- and you will solve it methodically.

Step 0: Acquire the Two Metric Definitions

Accept the two metric definitions from any of these sources:

Source Types

  1. Inline SQL: Two queries pasted directly.
  2. File paths: --file1 path/to/query_a.sql --file2 path/to/query_b.sql. Read both files.
  3. dbt model references: --model1 fct_revenue --model2 rpt_revenue. Search for the corresponding .sql files using Glob patterns like **/fct_revenue.sql.
  4. Mixed: One inline query compared against a file or dbt model.
  5. Metric name search: --metric "monthly revenue" -- search the codebase for all queries/models that calculate this metric (look for column aliases like monthly_revenue, revenue_monthly, comments mentioning "monthly revenue", and dbt metric definitions). Present all found definitions and let the user pick two to compare.

Labeling

  • Label the first definition as Query A (or Model A) and the second as Query B (or Model B).
  • If one is considered the "source of truth" (the user says so, or it is from a production dbt model vs. an ad-hoc query), label it as Reference and the other as Candidate.

Validation

  • Confirm both queries are syntactically valid SQL before proceeding.
  • Confirm both queries appear to calculate the same type of metric (e.g., both produce revenue numbers, both produce user counts). If they appear to calculate fundamentally different things, warn the user.

Step 1: Structural Comparison

Perform a side-by-side structural analysis of both queries. For each of the following dimensions, compare Query A and Query B:

1.1 Source Tables

| Dimension       | Query A                    | Query B                    | Match? |
|-----------------|----------------------------|----------------------------|--------|
| Source tables    | orders, users, refunds     | orders, users              | NO -- Query B missing refunds |
| Table filters   | WHERE status != 'cancelled'| WHERE status = 'completed' | NO -- different filter logic |

Flag: Tables present in one query but absent from the other. This is often the root cause.

1.2 Join Logic

For each join in both queries, compare:

  • Join type (INNER vs LEFT vs RIGHT)
  • Join predicate (ON clause)
  • Join order
| Join               | Query A            | Query B            | Impact |
|--------------------|--------------------|--------------------|--------|
| orders <> users    | INNER JOIN ON user_id | LEFT JOIN ON user_id | Query A drops users with no orders; Query B keeps them |
| orders <> refunds  | LEFT JOIN ON order_id | [not present]      | Query A subtracts refunds; Query B does not |

Key insight: INNER vs LEFT JOIN is the single most common cause of metric disagreements. Always check this first.

1.3 Filter Conditions (WHERE / HAVING)

Compare every filter in both queries:

| Filter                | Query A                         | Query B                         | Impact |
|-----------------------|---------------------------------|---------------------------------|--------|
| Date range            | created_at >= '2024-01-01'      | created_at > '2024-01-01'      | Query A includes Jan 1; Query B excludes it (>= vs >) |
| Status filter         | status NOT IN ('cancelled')     | status IN ('completed','pending') | Query A includes 'pending','refunded',etc.; Query B only 'completed','pending' |
| NULL handling         | [no NULL filter]                | WHERE amount IS NOT NULL        | Query B excludes NULL amounts |

Check for these specific filter discrepancies:

  • Inclusive vs exclusive date boundaries (>= vs >, `= '2024-01-01' AND status != 'cancelled'

B: Reads from orders WHERE orderdate >= '2024-01-01' AND status = 'completed' DIVERGENCE: Different date column (createdat vs order_date). Different status filter (excludes cancelled vs includes only completed). Impact: Query B excludes 'pending', 'processing', 'refunded' orders.

Step 2 (Join): A: LEFT JOIN refunds ON order_id (includes refund adjustments) B: [no refunds join] DIVERGENCE: Query A subtracts refunded amounts; Query B reports gross revenue. Impact: Query A will show lower revenue for periods with refunds.

Step 3 (Aggregation): A: SUM(amount - COALESCE(refundamount, 0)) AS netrevenue B: SUM(amount) AS revenue DIVERGENCE: Confirmed -- Query A = net revenue, Query B = gross revenue.


### 4.2 Hypothetical Impact Sizing
For each divergence found, estimate the likely magnitude of impact:
- **Large impact** (>5% difference expected): Different source tables, missing joins, different status filters.
- **Medium impact** (1-5%): Different NULL handling, inclusive vs exclusive date boundaries.
- **Small impact** (=` vs `>`, different date truncation, timezone shifts.
6. **Different NULL handling** -- one query excludes NULLs, the other defaults them to zero.
7. **Different aggregation logic** -- COUNT vs COUNT DISTINCT, SUM vs SUM DISTINCT.
8. **Different metric definition** -- gross vs net, including vs excluding certain record types.
9. **Duplicate amplification** -- a join creates duplicates in one query but not the other.
10. **HAVING vs WHERE placement** -- filter applied before vs after aggregation.
11. **Rounding and precision** -- different ROUND behavior or floating-point accumulation.
12. **Race condition / data freshness** -- queries run at different times against a changing dataset.

## Step 6: Reconciliation Report

Produce the final structured report:

Metric Reconciliation Report

Summary

| Item | Value | |------|-------| | Metric being reconciled | [metric name] | | Query A source | [file/inline/model] | | Query B source | [file/inline/model] | | Overall verdict | MATCH / PARTIAL MISMATCH / SIGNIFICANT MISMATCH / FUNDAMENTAL DISAGREEMENT | | Estimated discrepancy | [X% or $X or N rows] | | Root causes found | [count] |

Do They Agree?

At the total level: [YES / NO / WITHIN ROUNDING (= '2024-01-01' | created_at > '2024-01-01'` | Date boundary | Jan 1 records missing from B |

Recommended Canonical Query

Based on the analysis, here is the recommended single source of truth query that resolves all identified discrepancies:

-- Canonical [metric_name] query
-- Resolves: [list of root causes addressed]
-- Assumptions: [list key assumptions made]
[Optimized, corrected query that produces the "correct" answer]

Explain why each choice was made in the canonical query:

  1. [Choice]: [Rationale] (aligned with Query [A/B])
  2. [Choice]: [Rationale]
  3. ...

Verification Queries

Provide queries the user can run to verify the canonical query matches expectations:

-- Verify canonical query matches Query [A/B] after adjustments
-- Expected result: zero rows (all match)
[Verification query]

Prevention Recommendations

  1. [Recommendation]: [How to prevent this type of disagreement in the future]
  2. [Recommendation]: ...
  3. [Recommendation]: ...

Common recommendations to consider:

  • Define metrics in a single canonical location (dbt metrics, metric layer, data dictionary).
  • Add data tests that cross-check critical metrics across models.
  • Use a semantic layer to ensure all consumers use the same SQL.
  • Document filter assumptions (which statuses are included, how NULLs are handled).
  • Add reconciliation checks to CI/CD pipeline.

## Edge Cases

- **Queries that are structurally identical**: Report "MATCH -- queries are structurally equivalent" and note any cosmetic differences (aliases, formatting, comment differences). No root cause analysis needed.
- **Queries in different dialects**: Normalize both to a common pseudo-SQL for comparison. Note dialect-specific behavior differences (e.g., MySQL treats NULLs differently in GROUP BY than PostgreSQL).
- **Queries with Jinja/dbt templating**: Attempt to resolve `ref()` and `source()` to actual table names for comparison. If variables are used (`{{ var('start_date') }}`), note that different variable values would produce different results.
- **Queries that produce different column sets**: Compare only the overlapping columns. Note the non-overlapping columns as potential scope differences.
- **One query is a superset of the other**: One query may intentionally include more data (e.g., including pending orders). Identify this as a filter scope difference, not an error.
- **Queries with non-deterministic results**: If either query uses `LIMIT` without `ORDER BY`, `ROW_NUMBER()` without a unique tiebreaker, or `SAMPLE`/`TABLESAMPLE`, note that results may vary between runs.
- **Very large queries (50+ lines each)**: Break the comparison into sections (source selection, filtering, joining, aggregation) and compare each section independently before synthesizing.
- **Queries against different databases or schemas**: Note that even with identical logic, different databases may contain different data (stale replicas, partial syncs, schema drift). Recommend running both against the same database instance.
- **Metric involves multiple queries (e.g., ratio metrics)**: Compare numerator and denominator separately, then compare the ratio. A discrepancy in the ratio can come from either component.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [adityawrk](https://github.com/adityawrk)
- **Source:** [adityawrk/analytics-with-claude-code](https://github.com/adityawrk/analytics-with-claude-code)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.