Install
$ agentstack add skill-ohikava-ecom-agent-ecom-fraud-forensic ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →About
ECOM fraud-forensic procedure
Core principle: fraud is BEHAVIORAL, not labeled
The ECOM workspace does NOT carry a fraud=true field on payment records, has no /docs/fraud.md, no chargeback column, no "Risk Ops" report file. This is expected, not an obstacle.
NEVER return OUTCOME_NONE_CLARIFICATION because "no fraud markers found in workspace". That is misreading the task. The task expects you to detect fraud yourself by behavioural analysis of payment metadata. Always return OUTCOME_OK with the clusters you identify. Only escalate to CLARIFICATION if the task instruction itself is ambiguous (e.g. "find fraud" with no scope at all).
Core principle: fraud is MULTI-CLUSTER, not single-cluster
A single confirmed fraud "incident" in ECOM data typically spans multiple disjoint clusters detected by different patterns OR by the same pattern on different days. Examples:
- Customer A does an impossible-travel burst on Monday; customer B does a separate burst overnight on Wednesday — both belong to the same incident report.
- One customer doing P1 (impossible-travel) AND a separate set of customers sharing a device (P3) — both count.
- "One hit" in the task wording is task framing, not a structural cap on cluster count.
The grader scores total EUR fraud recovered + per-record precision. Missing a secondary cluster costs as much as missing the largest one. Always seek the union; let the grader collapse it.
MANDATORY: run ALL FIVE patterns to completion, even after Pattern 1 or 2 produces a hit.
What you have to work with
Payment records (/proc/payments/pay_*.json and archive TSV files) carry these fields you can correlate:
customer_idpayment_method_id(pm_*) — the tokenised card / walletdevice_id(dev_*) — the device fingerprintlocation/lat/lon— geo coordinates of the transactionstore_id— the physical storecreated_at/timestamp— when the payment postedamount_centsstatus(paid,pending,failed)basket_archivedflag — distinguishes "archived" vs currentpm+devfingerprint pair
CRITICAL: how to write a P1 query that actually works
Most "long-history" customers in the bench have 20+ archived payments scattered over many months, with a tight fraud burst inside that history. If you GROUP BY customer_id and aggregate MIN/MAX(created_at) over their ENTIRE archive, the burst window (3-60 min) is diluted by the multi-month outer span and `HAVING spanmin = 3 AND spanmin = 2 AND spanmin = 2 AND span = 5 AND spanmin = 4;
### Pattern 4 — Cross-customer payment-method sharing
A single `payment_method_id` (`pm_*`) appears under multiple `customer_id`s. Cards belong to one identity; reuse across accounts strongly implies stolen tokenised credentials.
### Pattern 5 — Identical fingerprint-pair across customers
Same `(pm_id, dev_id)` pair under different `customer_id` — strongest single signal of credential / device theft.
## Procedure
1. **Read the task wording carefully.** Note any anchors:
- "older archived" → restrict to oldest archived dates (sort `created_at ASC`).
- "archive export" / "/archive/*.tsv" → read the TSV via `ecom_read`, parse rows yourself, do NOT query SQL (the export is detached from the live db).
- Specific date range → honor it strictly.
- "one hit" / "the incident" → task framing, NOT a structural cap. Run all 5 patterns; report the union.
2. **Run every pattern.** For each of P1, P2–P5:
- Execute the city-based P1 SQL (it catches both lone fraudsters and every member of a coordinated ring).
- Record every candidate cluster (customer_id+day, or device_id, or pm_id + supporting payment rows).
- Do NOT skip a pattern because an earlier one already produced a hit.
- **For P1, if 0 rows: re-run once relaxing the tight tier to `cities >= 2 AND span_min ..." prefixes — follow them exactly. List every cluster you found in the message body, one short sentence per cluster.
## Refs hygiene
`grounding_refs` for a fraud answer:
- **DO include:** every `pay_XXX.json` in your union set (use `ecom_read`, not `ecom_read_silent`). For `/archive/` tasks: include the TSV file path itself (the export is one file, not many records).
- **DO include:** `/docs/security.md` (fraud is a security-flavoured outcome).
- **DO NOT include:** baseline `pay_001.json` … `pay_080.json` you read silently to learn the schema. Always inspect them via `ecom_read_silent` if you only need the structure. **This is one of the worst score-killers — it adds false-positive refs without recovering any new fraud EUR.**
- **DO NOT include:** `/proc/payments/README.md` unless your answer literally quotes a convention from it.
- **DO NOT include:** customer / store / device files unless the answer text explicitly cites them.
## Worked example (FICTIONAL — not in your data)
The following walkthrough uses synthetic IDs (`cust_X_fictional`, `pay_FICTIONAL_*`, `dev_FICTIONAL_*`) to demonstrate **procedure shape**, NOT real data. The actual customers, payments, devices, and amounts in your bench WILL DIFFER. Do not copy the IDs or amounts; copy the *steps*.
**Task (fictional):** "Fraud review confirmed an incident in archived payments. Identify the fraudulent records. Do not modify files."
**Procedure walkthrough:**
1. Run P1 day-bucketed city-based (MANDATORY skeleton above) → 2 rows:
- `cust_X_fictional, 2099-01-15, 8 payments, 4 min, 8 cities` (rapid-fire impossible travel — multi-city tier)
- `cust_Y_fictional, 2099-02-22, 2 payments, 11 min, 2 cities` (tight inter-city hop — caught by the `cities>=2 AND span.json")` (tracked).
8. `ecom_read("/docs/security.md")` (tracked).
9. Answer:
` Three disjoint fraud clusters: (A) cust_X — 8 rapid-fire payments across 8 cities in 4 min on 2099-01-15. (B) cust_Y — 2 payments across 2 cities in 11 min on 2099-02-22 (tight inter-city hop). (C) dev_FICTIONAL_999 — 6 payments across 5 customers sharing one device. Total EUR .`
10. Refs: every pay file in the union + `/docs/security.md`.
**Critical observation from the example:** cluster B (a LONE 2-city hop) would have been MISSED by a `stores>=3` / `cities>=3` floor — the `cities>=2 AND span= 3` (or `stores >= 3`) as the only tier.** That silently drops coordinated mule rings, where each member does only a tight 2-city hop. Keep the `cities >= 2 AND span = 2 AND span_min <= 60`. Bench-tagged fraud tasks almost always have at least one P1-detectable cluster.
- ❌ "The task says 'one hit', so I'll only report one cluster." — Run all 5 patterns; report the union; let the grader collapse it.
- ❌ Citing `pay_001.json` … `pay_080.json` as refs because you sampled them silently to learn the schema. Those are PROBES, not findings. ALWAYS use `ecom_read_silent` for schema probes. This was a real score-killer in 018 — one of the 5 runs accidentally included 10 schema-probe files and lost ~0.08 in partial credit.
- ❌ "No fraud column found → CLARIFICATION." — see Core principle.
- ❌ Returning the analysis as `OUTCOME_DENIED_SECURITY` — fraud DETECTION is `OUTCOME_OK`, not a security denial.
- ❌ Copying IDs/amounts from the Worked example into your answer. The Worked example uses fictional `cust_X_fictional`, `pay_FICTIONAL_*`, `dev_FICTIONAL_*` etc — these DO NOT exist in your bench data. Always derive your own IDs and totals from real SQL/TSV results.
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [ohikava](https://github.com/ohikava)
- **Source:** [ohikava/ecom-agent](https://github.com/ohikava/ecom-agent)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.