aws-samples / aws-samples/sample-analytics-agent-progressive-disclosure
P2: statistical realism gaps and over-correction — spend anti-correlates with revenue, telemetry matches facts exactly, identifiers are pure functions of keys
- Dominant language
- Python
- Stars
- 1
- Forks
- 2
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 3
Description
## Summary
Lower-severity findings, grouped because they share a theme: the data is internally consistent but does not carry the statistical texture of real data. Two of them are **over-corrections introduced by the 2026-08-06 datafix** — the fix removed a contradiction and replaced it with an implausible perfection.
None of these block a demo the way the P0/P1 issues do. They matter because they determine which questions a customer can be invited to ask, and because one of them (the over-correction) removes the single most common real-world analytics task.
---
## C1. Marketing spend anti-correlates with revenue, and is 0.333% of GMV
Over the 84 overlapping days:
```
daily channel spend vs daily GMV Pearson r = -0.288
daily channel spend vs daily new users Pearson r = -0.303
```
Negative is worse than zero: on days with more spend there is *less* revenue. ROI and CAC are therefore a ratio of two unrelated series. (Redshift has no `corr()`; computed client-side over the 84-row series.)
Separately, the magnitude is off. Spend inside the window totals 504,024 against GMV of 151,238,025 — **0.333%**, where real e-commerce marketing spend is 5–20% of GMV. So even after the axis in the P0 issue is fixed, ROAS lands at 145x versus a realistic 2–8x.
**Fix**: give spend and conversion a shared daily driver (the same weekday/trend/campaign factor that already shapes orders), and scale spend up by roughly 20–60x.
---
## C2. Over-correction: telemetry matches facts exactly, and 2.1M rows have zero violations
```
register events 213,520 = users 213,520 exact
use_coupon events 324,596 = redeemed 324,596 exact
purchase events 647,265 = valid orders 647,265 exact
sessions.duration_seconds vs (end - start): 0 mismatches across 2,135,195 rows
payments: 689,255 = 647,265 valid + 41,990 refunded (a deterministic function of order status)
```
Real telemetry differs from fact tables by 2–10% because of duplicate client-side firing, dropped events, and timezone skew. Real session data contains clock-skew artifacts. Perfect agreement is as much a generator fingerprint as the pre-fix inversion was.
**The concrete cost**: "why don't our event counts match our order counts?" is arguably the most common real analytics task, and **it cannot be demonstrated on this dataset because there is never a discrepancy**. Same for data-quality triage and telemetry validation.
Note for the checker design: this class needs the **opposite verdict polarity** from every other check. A "0 violations" result is the signal, not the pass. The current L1–L5 framework treats 0 as pass everywhere, so it cannot report this family at all.
**Fix**: inject 2–5% duplicate/dropped events and a small fraction of session-duration skew. Keep the closure self-tests, but assert a *tolerance band* rather than exact equality.
---
## C3. Generator fingerprints
**Identifiers are pure functions of primary keys** — 100% of values embed their own key:
```
orders.order_no, dwd_orders_valid.order_no, payments.payment_no, users.username
push_token = 'tok_' || , device_id = 'dev_' ||
```
So `push_token` is derivable from `device_id`. Multi-device identification, account-sharing detection and identifier parsing all become tautologies.
**IPs do not cluster by user** — one user with 68 events has 68 distinct IP addresses (all in the `10.x.x.x` private range). Real users have a handful over 91 days. Any geo, fraud or device-sharing analysis is unusable.
**No psychological pricing** — `products.price` cent endings are uniform, where real retail prices cluster heavily on `.99 / .00 / .90`. This is a single root cause that cascades into five downstream columns (`order_items.unit_price`, `order_items.actual_amount`, `orders.actual_amount`, `orders.discount_amount`, `payments.refund_amount`).
**Category granularity** — 200 SKUs spread across 101 categories (1–4 SKUs each), so "top selling category" is noise.
**Fix**: draw identifiers from independent streams; assign each user 1–5 IPs and reuse them; give `products.price` a realistic ending distribution; either reduce the category count or raise the SKU count.
---
## C4. Documentation: "monotonic" is being read as "citable"
`docs/data-audit.md`'s post-fix review table claims retention now decays monotonically, which is true. It does not claim the *rates* are realistic, and they are not:
| Metric | Measured | Real-world range |
|---|---|---|
| D1 retention | **74.1%** | 25–40% (top-tier apps ~40%) |
| D7 retention | **34.7%** | 10–20% |
| Funnel view_home → purchase | **46.4%** | 0.5–2% |
| Coupons issued per user | **45.5** | a few |
| Daily order CV | **0.172** | 0.2–0.4 (no day-level shocks: promos, paydays, outages) |
The risk is a reader concluding "retention was fixed, so retention numbers can be quoted". Suggest labelling these explicitly in the review table as **shape usable, absolute value not citable**.
**One correction in the other direction**: the same doc lists the heavy tail as "too thin". Measured, top 10% of users account for **48.39%** of GMV, against a real-world 50–70% — essentially at the lower bound. **This known limitation is milder than the doc implies**, and Pareto-style analysis is in fact usable. Worth softening.
---
## Suggested priority
C2 first (it removes an entire analysis family and the fix is small), then C1 (needed before ROI/CAC mean anything), then C4 (documentation only), then C3 (cosmetic realism).
Measured 2026-08-13 against `analytics-agent-wg` / `app_analytics` through a read-only role.
Contributor guide
Research direction
Start with docs/data-audit.md and reproduce the C1–C3 measurements described in the issue using the read-only app_analytics data. Trace the generator sources for spend, telemetry, identifiers, IPs, pricing, and categories, then address the prioritized realism gaps while keeping closure self-tests and update the review documentation to distinguish usable shape from citable values.
Written by the indexing model from the issue text.
Assessment
- Domain
- data, documentation
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100