@1aboveio/skills 0.19.3 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/package.json +1 -1
- package/runtime/skills/distribution/generated/recipes.json +54 -48
- package/runtime/skills/distribution/scripts/bundles.mjs +113 -7
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
- package/skills/cicd-pipeline/cloud-build/SKILL.md +6 -6
- package/skills/cicd-pipeline/mergify/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +15 -84
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
- package/skills/engineering/rush-release/SKILL.md +46 -25
- package/skills/engineering/rush-release/evals/evals.json +22 -8
- package/skills/engineering/rush-release/references/cut.md +21 -4
- package/skills/engineering/rush-release/references/preflight.md +25 -6
- package/skills/engineering/rush-release/references/promotion.md +70 -0
- package/skills/engineering/rush-release/references/publish.md +49 -16
- package/skills/engineering/rush-release/scripts/plan.mjs +33 -7
- package/skills/engineering/smoke/SKILL.md +4 -4
- package/skills/engineering/smoke/references/manifest.md +3 -3
- package/skills/payment/payment-analysis/SKILL.md +5 -3
- package/skills/payment/tld-detection/SKILL.md +163 -0
- package/skills/payment/tld-detection/agents/openai.yaml +9 -0
- package/skills/payment/tld-detection/evals/evals.json +107 -0
- package/skills/payment/tld-detection/references/clean.md +51 -0
- package/skills/payment/tld-detection/references/clustering.md +219 -0
- package/skills/payment/tld-detection/references/decision.md +85 -0
- package/skills/payment/tld-detection/references/report-template.md +169 -0
- package/skills/payment/tld-detection/references/terminology.md +69 -0
- package/skills/payment/tld-detection/references/workflow.md +78 -0
- package/skills/payment/tld-detection/scripts/detect_ladders.py +390 -0
- package/skills/payment/tld-detection/tests/test_detect_ladders.py +132 -0
- package/skills/engineering/resolve-issues/SKILL.md +0 -168
- package/skills/engineering/resolve-issues/agents/openai.yaml +0 -9
- package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +0 -499
- package/skills/engineering/resolve-issues/references/breaker.md +0 -82
- package/skills/engineering/resolve-issues/references/deliverables.md +0 -27
- package/skills/engineering/resolve-issues/references/delivery.md +0 -108
- package/skills/engineering/resolve-issues/references/evidence-lane.md +0 -21
- package/skills/engineering/resolve-issues/references/exact-head-ci.md +0 -287
- package/skills/engineering/resolve-issues/references/fan-out.md +0 -33
- package/skills/engineering/resolve-issues/references/finalization.md +0 -68
- package/skills/engineering/resolve-issues/references/guarantees.md +0 -10
- package/skills/engineering/resolve-issues/references/high-risk.md +0 -29
- package/skills/engineering/resolve-issues/references/incidents/848/README.md +0 -156
- package/skills/engineering/resolve-issues/references/intake.md +0 -86
- package/skills/engineering/resolve-issues/references/integration-gate.md +0 -53
- package/skills/engineering/resolve-issues/references/interference.md +0 -87
- package/skills/engineering/resolve-issues/references/loop.md +0 -134
- package/skills/engineering/resolve-issues/references/model-catalog.md +0 -9
- package/skills/engineering/resolve-issues/references/postmortem.md +0 -27
- package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +0 -41
- package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +0 -48
- package/skills/engineering/resolve-issues/references/pre-flight.md +0 -41
- package/skills/engineering/resolve-issues/references/regression-checklist.md +0 -26
- package/skills/engineering/resolve-issues/references/run-state.md +0 -288
- package/skills/engineering/resolve-issues/references/sandboxed-testing.md +0 -48
- package/skills/engineering/resolve-issues/references/spawn-contract.md +0 -96
- package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +0 -40
- package/skills/engineering/resolve-issues/references/why.md +0 -653
- package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +0 -49
- package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +0 -721
- package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +0 -962
- package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +0 -220
- package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +0 -420
- package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +0 -256
- package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +0 -168
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +0 -9
- package/skills/engineering/resolve-issues/scripts/doctrine.mjs +0 -62
- package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +0 -191
- package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +0 -413
- package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +0 -332
- package/skills/engineering/resolve-issues/scripts/finalize.mjs +0 -488
- package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +0 -3307
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +0 -16
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +0 -51
- package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +0 -17
- package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +0 -166
- package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +0 -92
- package/skills/engineering/resolve-issues/scripts/guide-index.mjs +0 -73
- package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +0 -159
- package/skills/engineering/resolve-issues/scripts/interference.mjs +0 -427
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +0 -9
- package/skills/engineering/resolve-issues/scripts/next-operations.mjs +0 -419
- package/skills/engineering/resolve-issues/scripts/postmortem.mjs +0 -909
- package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +0 -345
- package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +0 -415
- package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +0 -697
- package/skills/engineering/resolve-issues/scripts/report.mjs +0 -494
- package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +0 -172
- package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +0 -79
- package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +0 -334
- package/skills/engineering/resolve-issues/scripts/run-state.mjs +0 -4792
- package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +0 -395
- package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +0 -290
- package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +0 -170
- package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +0 -293
- package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +0 -197
- package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +0 -127
- package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +0 -893
- package/skills/engineering/resolve-issues/scripts/workspaces.mjs +0 -829
- package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +0 -290
- package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +0 -80
- package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +0 -102
- package/skills/engineering/resolve-release/LICENSE +0 -3
- package/skills/engineering/resolve-release/SKILL.md +0 -113
- package/skills/engineering/resolve-release/agents/openai.yaml +0 -9
- package/skills/engineering/resolve-release/references/assembly.md +0 -137
- package/skills/engineering/resolve-release/references/auto-when-green.md +0 -56
- package/skills/engineering/resolve-release/references/candidate.md +0 -167
- package/skills/engineering/resolve-release/references/exposure.md +0 -178
- package/skills/engineering/resolve-release/references/handoff.md +0 -24
- package/skills/engineering/resolve-release/references/postmortem.md +0 -230
- package/skills/engineering/resolve-release/references/preflight.md +0 -208
- package/skills/engineering/resolve-release/references/principles.md +0 -94
- package/skills/engineering/resolve-release/references/regression-checklist.md +0 -36
- package/skills/engineering/resolve-release/references/related-skills.md +0 -13
- package/skills/engineering/resolve-release/references/routing.md +0 -149
- package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +0 -285
- package/skills/engineering/resolve-release/references/versioning.md +0 -202
- package/skills/engineering/resolve-release/references/why.md +0 -53
- package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +0 -389
- package/skills/engineering/resolve-release/scripts/build-changes.mjs +0 -209
- package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +0 -407
- package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +0 -904
- package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +0 -81
- package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +0 -612
- package/skills/engineering/resolve-release/scripts/close-attempt.mjs +0 -135
- package/skills/engineering/resolve-release/scripts/closeout-release.mjs +0 -161
- package/skills/engineering/resolve-release/scripts/doctrine.mjs +0 -106
- package/skills/engineering/resolve-release/scripts/durable-processing.mjs +0 -522
- package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +0 -659
- package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +0 -1014
- package/skills/engineering/resolve-release/scripts/finalize-release.mjs +0 -526
- package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +0 -169
- package/skills/engineering/resolve-release/scripts/green-gate.mjs +0 -599
- package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +0 -752
- package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +0 -56
- package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +0 -1538
- package/skills/engineering/resolve-release/scripts/postmortem.mjs +0 -381
- package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +0 -510
- package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +0 -326
- package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +0 -272
- package/skills/engineering/resolve-release/scripts/report.mjs +0 -417
- package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +0 -114
- package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +0 -238
- package/skills/engineering/resolve-release/scripts/review-packet.mjs +0 -503
- package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +0 -263
- package/skills/engineering/resolve-release/scripts/version-assert.mjs +0 -339
- package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +0 -485
- package/skills/engineering/resolve-release/scripts/version.mjs +0 -1199
- package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +0 -449
- package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +0 -21
- package/skills/engineering/resolve-release/vendor/README.md +0 -60
- package/skills/engineering/resolve-release/vendor/acorn.mjs +0 -6233
- package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +0 -341
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +0 -70
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +0 -7
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +0 -2033
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +0 -2033
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +0 -7
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +0 -49
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +0 -5
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +0 -549
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +0 -549
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +0 -36
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +0 -47
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +0 -82
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +0 -11
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +0 -22
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +0 -11
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +0 -11
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +0 -25
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +0 -85
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +0 -85
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +0 -20
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +0 -20
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +0 -61
- /package/skills/{engineering/resolve-issues → payment/tld-detection}/LICENSE +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "TLD Detection"
|
|
3
|
+
short_description: "Risk-tiered TLD clusters from exact currency-amount pairs"
|
|
4
|
+
|
|
5
|
+
policy:
|
|
6
|
+
# Codex counterpart to SKILL.md disable-model-invocation: true
|
|
7
|
+
# (Claude Code / Pi). Keeps explicit invoke; blocks description-based
|
|
8
|
+
# auto-selection.
|
|
9
|
+
allow_implicit_invocation: false
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "tld-detection",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "We think some merchants are stuffing TLD volume through a normal MCC. Authorizations_2026-03.csv has descriptors, MCC, BIN country, amount, currency, timestamp, and response codes. Find potential TLD clusters.",
|
|
7
|
+
"expected_output": "Deduplicates auths without a US-BIN filter; partitions by normalized descriptor; detects exact currency-amount pairs with explicit absolute residual caps; freezes membership; compares each cluster with the same descriptor after removing that cluster; assigns High, Medium, or Low investigation priority; and quantifies exposure by risk tier and descriptor.",
|
|
8
|
+
"expectations": [
|
|
9
|
+
"Uses normalized descriptor as the partition key and does not use BIN country as a membership key.",
|
|
10
|
+
"Uses adjacent currency-specific absolute residual caps with sensitivity evidence and no percentage tolerance.",
|
|
11
|
+
"Requires at least three theoretical levels with a fixed 2x relationship between adjacent levels.",
|
|
12
|
+
"Reports only currency-amount pairs with at least 100 exact-member attempts and compares each with the same descriptor after removing that cluster.",
|
|
13
|
+
"Reports Top 3 issuing banks and BIN countries only after membership is frozen.",
|
|
14
|
+
"Assigns every identified cluster High, Medium, or Low risk without treating the tier as confirmation of TLD.",
|
|
15
|
+
"Sorts results High to Medium to Low and reports exact-member exposure separately by tier and descriptor.",
|
|
16
|
+
"Keeps run-specific methodology in a separate linked document.",
|
|
17
|
+
"Provides a Verdict of at most three sentences without confirmed-laundering language."
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": 2,
|
|
22
|
+
"prompt": "Same descriptor seems to mix several ticket sizes that look like 9.99, 19.99, 39.99, 79.99. Another TLD name might be split across three billing descriptors. Cluster the book and tell me if those patterns hold.",
|
|
23
|
+
"expected_output": "Builds descriptor partitions and identifies qualifying currency-amount pairs independently inside them using at least three theoretical levels and a fixed 2x relationship; matching amounts across descriptors never merge membership.",
|
|
24
|
+
"expectations": [
|
|
25
|
+
"Builds descriptor partitions before currency-amount pairs.",
|
|
26
|
+
"Requires at least three theoretical levels and rejects non-2x relationships.",
|
|
27
|
+
"Requires at least 100 exact-member attempts before reporting a cluster.",
|
|
28
|
+
"Reports materially different currency-amount pairs under one descriptor.",
|
|
29
|
+
"Assesses MCC fit without calling a descriptor fabricated."
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": 3,
|
|
34
|
+
"prompt": "For each detected currency-amount pair, compare its behavior with the rest of the same descriptor.",
|
|
35
|
+
"expected_output": "Keeps BIN country out of the membership key, freezes exact membership, builds a same-descriptor baseline by removing only that cluster, compares the required rates and Top 3 dimensions, reports both BIN-country conditional shares, and charts transaction date and BIN-country local-hour distributions against that baseline.",
|
|
36
|
+
"expectations": [
|
|
37
|
+
"Does not partition detection by BIN country.",
|
|
38
|
+
"Uses the same descriptor after removing the current cluster as baseline.",
|
|
39
|
+
"Reports authorization success rate and suspected fraud as a share of attempts for Cluster and Baseline.",
|
|
40
|
+
"In each cluster definition, the anchor table reports attempts, authorization success rate, and suspected-fraud share for every theoretical level, including levels with fewer than 30 attempts.",
|
|
41
|
+
"For each Top 3 cluster BIN country, reports its share of the cluster and the cluster's share of all attempts in the same descriptor-country slice.",
|
|
42
|
+
"Treats exact 100% single-country concentration as a standout, Mixed as neutral, and country-slice coverage as descriptive without a risk threshold.",
|
|
43
|
+
"Charts transaction-date and BIN-country local-hour shares for Cluster and Baseline, normalizing each series independently."
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": 4,
|
|
48
|
+
"prompt": "Inside descriptor ACME, USD 10.00 is followed by 19.99 with 180 attempts, 20.00 with 40 attempts, and then 39.99. Build the potential TLD ladders.",
|
|
49
|
+
"expected_output": "Uses an explicit USD adjacent absolute residual cap; selects a primary exact anchor deterministically; may retain another exact anchor at the same theoretical level only if it clears the stated multi-anchor support floor; and applies exact descriptor, currency, and amount membership afterward.",
|
|
50
|
+
"expectations": [
|
|
51
|
+
"Runs ladder discovery only inside descriptor ACME.",
|
|
52
|
+
"Uses absolute adjacent residuals rather than percentage matching.",
|
|
53
|
+
"Selects the highest-count candidate as the primary anchor.",
|
|
54
|
+
"Retains an additional anchor only when it independently clears the declared support floor.",
|
|
55
|
+
"Never assigns every amount in a tolerance interval to the ladder."
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": 5,
|
|
60
|
+
"prompt": "Inside one descriptor I see an approximate EUR x2 amount pattern, but its selected exact amount keys total only 96 authorization attempts. Should it be reported?",
|
|
61
|
+
"expected_output": "Does not report the 96-attempt family; records it below threshold, keeps its transactions outside reported clusters, publishes its ranking, and does not invent a cluster from MCC or comparison features.",
|
|
62
|
+
"expectations": [
|
|
63
|
+
"Does not report the 96-attempt family.",
|
|
64
|
+
"Keeps its rows outside reported clusters.",
|
|
65
|
+
"Does not invent a cluster from comparison features.",
|
|
66
|
+
"Still provides a no-ladder Verdict of at most three sentences."
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": 6,
|
|
71
|
+
"prompt": "Descriptors ALPHA and BETA both have the exact USD 9.99, 19.99, 39.99 ladder with over 100 attempts, across several BIN countries. Should those transactions become one cluster?",
|
|
72
|
+
"expected_output": "Creates two descriptor-local currency-amount pairs, permits the same exact amounts in both descriptors, keeps their membership and same-descriptor baselines separate, and reports each independently.",
|
|
73
|
+
"expectations": [
|
|
74
|
+
"Creates two ladders because descriptor is the partition boundary.",
|
|
75
|
+
"Permits the same exact pairs in different descriptor ladders.",
|
|
76
|
+
"Does not merge matching fingerprints across descriptors.",
|
|
77
|
+
"Does not merge membership, metrics, or baselines.",
|
|
78
|
+
"Treats BIN country as post-membership reporting data."
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": 7,
|
|
83
|
+
"prompt": "USD 14.xx amounts are representative, but one percentage tolerance becomes too wide at larger amounts. Detect the ladders without sweeping a numeric interval into membership.",
|
|
84
|
+
"expected_output": "Runs a documented absolute-cap sensitivity grid, uses a currency-specific adjacent residual cap, searches every descriptor-local rung-pool seed, allows only sufficiently supported exact multi-anchors, rejects upper rungs outside the absolute cap, and freezes exact membership before BIN-country attribution.",
|
|
85
|
+
"expectations": [
|
|
86
|
+
"Does not use a percentage tolerance.",
|
|
87
|
+
"Reports the tested cap grid and selected cap.",
|
|
88
|
+
"Uses finite exact anchor sets with a stated multi-anchor support floor.",
|
|
89
|
+
"Rejects an upper rung whose adjacent residual exceeds the cap.",
|
|
90
|
+
"Computes BIN-country reporting values only after exact membership is frozen."
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": 8,
|
|
95
|
+
"prompt": "One cluster is 100% US BIN and covers 21.3% of its descriptor's US BIN attempts. Another is mixed and covers 33.8% of one descriptor-country slice. Grade and order the risk.",
|
|
96
|
+
"expected_output": "Treats the exact 100% single-country concentration as a standout and uses 21.3% only to explain its scale; treats Mixed as neutral and 33.8% as descriptive rather than a threshold; combines independent structural and behavioral evidence; assigns High, Medium, or Low risk; and sorts High to Medium to Low.",
|
|
97
|
+
"expectations": [
|
|
98
|
+
"Does not classify Mixed as Weak or automatically lower its risk tier.",
|
|
99
|
+
"Does not infer risk from a 20%, 33.8%, or other country-slice coverage threshold.",
|
|
100
|
+
"Requires exact 100% single-country composition for the BIN-country standout.",
|
|
101
|
+
"Reports cluster composition and descriptor-country slice coverage as separate conditional percentages.",
|
|
102
|
+
"Uses at least one independent corroborating characteristic before making a 100% single-country cluster High risk.",
|
|
103
|
+
"Preserves stable cluster IDs while sorting High to Medium to Low."
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Data cleaning
|
|
2
|
+
|
|
3
|
+
Run on the authorization extract before any clustering. Record every drop
|
|
4
|
+
count in the report appendix.
|
|
5
|
+
|
|
6
|
+
Do not filter to US-BIN here. Issuer country remains available for the
|
|
7
|
+
cluster-versus-baseline Top 3 BIN-country comparison.
|
|
8
|
+
|
|
9
|
+
## 1. Exact-row dedup
|
|
10
|
+
|
|
11
|
+
Drop bitwise-duplicate rows (same values in every column used). Count
|
|
12
|
+
them. They are extract artefacts, not extra attempts.
|
|
13
|
+
|
|
14
|
+
## 2. Identity dedup
|
|
15
|
+
|
|
16
|
+
If `Transaction ID` / `Auth ID` is unique when present, keep one row per
|
|
17
|
+
id (first by time).
|
|
18
|
+
|
|
19
|
+
Otherwise, if `Order ID` is present, keep one row per
|
|
20
|
+
(`Order ID`, time, amount, currency, masked PAN / last4 if present).
|
|
21
|
+
Retries of the same order at different times stay distinct.
|
|
22
|
+
|
|
23
|
+
If none of those identities exist, **skip this step** — keep the
|
|
24
|
+
exact-row-deduped table and say identity-dup was skipped. Do not stop
|
|
25
|
+
the run. Do not invent a customer id from BIN + amount.
|
|
26
|
+
|
|
27
|
+
## 3. Amount and currency
|
|
28
|
+
|
|
29
|
+
- Clustering key uses the **original** amount and currency.
|
|
30
|
+
- Normalize `10`, `10.0`, `10.00` to the same decimal key.
|
|
31
|
+
- Drop rows with missing amount or currency; count them.
|
|
32
|
+
- Do not FX-convert before clustering. A 9.99 EUR rung is not a 9.99 USD
|
|
33
|
+
rung. Amount sums later stay inside one currency; never add EUR to USD.
|
|
34
|
+
|
|
35
|
+
## 4. Missing dimensions
|
|
36
|
+
|
|
37
|
+
Rows with missing descriptor or BIN / issuer country stay in the
|
|
38
|
+
clustering universe. Missing descriptors enter the `UNKNOWN_DESCRIPTOR`
|
|
39
|
+
partition; missing countries enter the `UNKNOWN_BIN_COUNTRY` reporting
|
|
40
|
+
bucket after membership is frozen.
|
|
41
|
+
|
|
42
|
+
## Output of this step
|
|
43
|
+
|
|
44
|
+
A cleaned table plus a one-line census:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
raw N → exact-dup drop n1 → identity-dup drop n2 (or skipped)
|
|
48
|
+
→ missing amount/currency n3 → cleaned universe U
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
All later attempt counts use `U`, not `raw N`.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Currency-amount-pair clustering
|
|
2
|
+
|
|
3
|
+
Goal: partition the cleaned universe by descriptor, find stuffing (掺量)
|
|
4
|
+
as **approximate geometric ladders** inside each descriptor, then decompose
|
|
5
|
+
each qualifying ladder into BIN-country attribution components and contrast
|
|
6
|
+
it against the remainder.
|
|
7
|
+
|
|
8
|
+
## Descriptor partition
|
|
9
|
+
|
|
10
|
+
Partition key = `normalized descriptor`.
|
|
11
|
+
|
|
12
|
+
- Trim, case-fold, and collapse repeated whitespace. Preserve the most
|
|
13
|
+
frequent source spelling for display.
|
|
14
|
+
- Do not fuzzy-match or strip dynamic suffixes unless the extract documents
|
|
15
|
+
their semantics.
|
|
16
|
+
- Use `UNKNOWN_DESCRIPTOR` for missing values; do not drop them.
|
|
17
|
+
|
|
18
|
+
Freeze descriptor assignment before ranking amounts. Report each descriptor's
|
|
19
|
+
attempt count and share of `U`. A ladder belongs to exactly one descriptor;
|
|
20
|
+
the same exact currency-amount-pair may legitimately belong to ladders in
|
|
21
|
+
different descriptors.
|
|
22
|
+
|
|
23
|
+
BIN country is **not** a partition or membership key. Normalize it after
|
|
24
|
+
ladder formation and report its attempt counts, shares, auth rates, suspected-
|
|
25
|
+
fraud rates, and local-hour shapes as attribution components.
|
|
26
|
+
|
|
27
|
+
## Currency-amount-pair
|
|
28
|
+
|
|
29
|
+
Key = (`currency`, `amount`) on the original (not FX-converted) amount.
|
|
30
|
+
|
|
31
|
+
Count = authorization **attempts** in the current partition. Rank
|
|
32
|
+
descending by count. Ties: smaller amount first, then currency code.
|
|
33
|
+
|
|
34
|
+
## High-count set and rung pool
|
|
35
|
+
|
|
36
|
+
Work **per partition, then per currency**. In the table below, `|P|` is
|
|
37
|
+
the authorization-attempt count of the current partition.
|
|
38
|
+
|
|
39
|
+
| Set | Membership |
|
|
40
|
+
|---|---|
|
|
41
|
+
| High-count (seeds) | union of (a) pairs with count ≥ `max(30, 0.5% of \|P\|)` (b) the partition top 25 pairs by count (c) per currency in the partition, the top 10 pairs with count ≥ 30 |
|
|
42
|
+
| Rung pool | pairs with count ≥ `max(5, 0.1% of \|P\|)` |
|
|
43
|
+
|
|
44
|
+
State the thresholds. Use the high-count set for ranking. Test every rung-pool
|
|
45
|
+
pair as a possible seed for a three-level 2x relationship; otherwise a
|
|
46
|
+
representative lower-volume path can be structurally impossible to discover.
|
|
47
|
+
Extra levels may be quieter amounts in
|
|
48
|
+
the rung pool, and (c) keeps a smaller currency visible inside the partition.
|
|
49
|
+
|
|
50
|
+
If the rung pool has fewer than three pairs in every currency of a partition,
|
|
51
|
+
that partition has no three-level ladder to test. Still publish its ranking
|
|
52
|
+
table when it is among the largest partitions or has a below-threshold family.
|
|
53
|
+
|
|
54
|
+
## Ladder detection
|
|
55
|
+
|
|
56
|
+
Ladder detection has two separate phases. **Discovery** uses an adjacent,
|
|
57
|
+
currency-specific absolute residual cap. **Membership and every downstream
|
|
58
|
+
metric use the exact descriptor plus selected currency-amount-pairs only.**
|
|
59
|
+
Never widen final membership to a numeric interval or another descriptor.
|
|
60
|
+
|
|
61
|
+
### Adjacent absolute-residual rule
|
|
62
|
+
|
|
63
|
+
For exact amounts `a < b` in one descriptor and currency, multiplier `m` has:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
residual = |b - a · m|
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
They are adjacent anchors only when `residual ≤ ε_currency`. Do not use one
|
|
70
|
+
percentage tolerance across amounts: its absolute allowance grows with the
|
|
71
|
+
amount and can merge materially different upper-rung prices.
|
|
72
|
+
|
|
73
|
+
Configure and report one cap per currency represented in a partition's rung
|
|
74
|
+
pool. For a two-decimal currency, test a sensitivity grid such as `0.02,
|
|
75
|
+
0.05, 0.10, 0.15, 0.25` and retain the smallest operationally justified cap
|
|
76
|
+
under which material paths are stable. Fail closed when a rung-pool currency
|
|
77
|
+
has no cap; currencies below the rung-pool threshold need no cap.
|
|
78
|
+
|
|
79
|
+
Use the bundled deterministic implementation after producing a cleaned
|
|
80
|
+
authorization CSV:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python3 {baseDir}/scripts/detect_ladders.py cleaned-authorizations.csv \
|
|
84
|
+
--descriptor-column descriptor --bin-country-column bin_country \
|
|
85
|
+
--currency-column currency --amount-column amount \
|
|
86
|
+
--cap USD=0.15 --multi-anchor-min-attempts 24 \
|
|
87
|
+
--sensitivity-cap USD=0.02 --sensitivity-cap USD=0.05 \
|
|
88
|
+
--sensitivity-cap USD=0.10 --sensitivity-cap USD=0.15 \
|
|
89
|
+
--sensitivity-cap USD=0.25
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The CLI does not clean or deduplicate the CSV; complete
|
|
93
|
+
[clean.md](clean.md) first.
|
|
94
|
+
|
|
95
|
+
### Family from a seed (up and down)
|
|
96
|
+
|
|
97
|
+
Starting from every rung-pool seed, expand recursively upward and downward
|
|
98
|
+
using only adjacent matches. A theoretical level may contain several exact
|
|
99
|
+
anchors. Select the highest-count match as its primary anchor; retain an
|
|
100
|
+
additional match only when that exact pair independently clears the stated
|
|
101
|
+
portfolio support floor (default 24 attempts, corresponding to the Worldpay
|
|
102
|
+
portfolio rung floor). Record that floor and test it separately for a new
|
|
103
|
+
portfolio.
|
|
104
|
+
|
|
105
|
+
Every retained key must be in the partition's rung pool and match an anchor
|
|
106
|
+
in the adjacent level. The finite retained keys become the explicit anchor
|
|
107
|
+
set. Tolerance never acts on transactions after selection: final membership
|
|
108
|
+
is exact equality on (`descriptor`, `currency`, `amount`). BIN country is
|
|
109
|
+
attached only after this membership is frozen.
|
|
110
|
+
|
|
111
|
+
### Required 2x family
|
|
112
|
+
|
|
113
|
+
A candidate family must use **`m = 2`** between every adjacent theoretical
|
|
114
|
+
level and contain **at least three theoretical levels**. Example: 1x, 2x, 4x,
|
|
115
|
+
8x around the seed, including downward (`19.99` can find `9.99` and `39.99`).
|
|
116
|
+
There is no two-level exception, and relationships based on `m = 3`, `4`, `5`,
|
|
117
|
+
`10`, or any other multiplier do not form clusters.
|
|
118
|
+
|
|
119
|
+
For each seed, rank qualifying paths by: more theoretical levels; more exact-
|
|
120
|
+
member attempts; then lower summed adjacent residual. The attempt threshold
|
|
121
|
+
below independently determines whether the family becomes a reported cluster.
|
|
122
|
+
|
|
123
|
+
### Minimum cluster size
|
|
124
|
+
|
|
125
|
+
Sum attempts only over rows in the partition whose keys are the selected
|
|
126
|
+
exact currency-amount-pairs. A family is a reported cluster only when that
|
|
127
|
+
exact membership has **≥100 authorization attempts**. Keep smaller
|
|
128
|
+
families in the run methodology document as `below threshold`; do not validate them or
|
|
129
|
+
issue cluster verdicts for them. Their rows remain in canonical baseline
|
|
130
|
+
`B` and descriptor remainder `B_D` unless selected exact keys are claimed
|
|
131
|
+
by another reported ladder in the same descriptor.
|
|
132
|
+
|
|
133
|
+
### Several groups
|
|
134
|
+
|
|
135
|
+
Within each partition, process unused rung-pool seeds in descending attempt
|
|
136
|
+
count. A currency-amount-pair joins **at most one** reported cluster in that
|
|
137
|
+
partition — the first qualifying family that claims it. Below-threshold
|
|
138
|
+
families do not reserve keys. Never let a claim in one partition reserve the
|
|
139
|
+
same pair in another partition.
|
|
140
|
+
|
|
141
|
+
Name clusters `C1`, `C2`, … by descending total attempts. For each, record
|
|
142
|
+
the descriptor partition, seed, currency, multiplier, absolute cap, summed
|
|
143
|
+
fit residual, theoretical levels, all exact anchors and counts, multi-anchor
|
|
144
|
+
levels, total attempts, and post-formation BIN-country components.
|
|
145
|
+
|
|
146
|
+
Ignore one-off round amounts (`100`, `1000`) unless they sit on a ladder.
|
|
147
|
+
A popular SKU price is not a cluster by itself.
|
|
148
|
+
|
|
149
|
+
### None found
|
|
150
|
+
|
|
151
|
+
If no family qualifies in any partition, **do not invent clusters** from
|
|
152
|
+
MCC or comparison features. Publish the partition and pair rankings, contrast
|
|
153
|
+
the top pairs only as context if useful, and skip cluster verdicts.
|
|
154
|
+
|
|
155
|
+
## Baseline
|
|
156
|
+
|
|
157
|
+
For each cluster, **Baseline** means every authorization in the same descriptor
|
|
158
|
+
after removing that cluster's exact member keys. Other identified
|
|
159
|
+
currency-amount pairs remain in this baseline. This is the only comparison
|
|
160
|
+
population used in cluster characteristics. If the cluster consumes the whole
|
|
161
|
+
descriptor, report comparison values as `n/a`.
|
|
162
|
+
|
|
163
|
+
For the overall impact table only, `Baseline` means rows in the cleaned universe
|
|
164
|
+
that belong to no identified currency-amount pair. Keep this distinct from the
|
|
165
|
+
per-cluster same-descriptor baseline.
|
|
166
|
+
|
|
167
|
+
If two currencies each have a ladder, they are separate clusters. Do not
|
|
168
|
+
merge across currencies.
|
|
169
|
+
|
|
170
|
+
## Contrast vs baseline
|
|
171
|
+
|
|
172
|
+
Same window and descriptor. Compare each cluster with its baseline on:
|
|
173
|
+
|
|
174
|
+
| Metric | Formula |
|
|
175
|
+
|---|---|
|
|
176
|
+
| Authorization success rate | approvals / attempts |
|
|
177
|
+
| Suspected fraud as share of attempts | suspected-fraud attempts / attempts |
|
|
178
|
+
| Top 3 issuing banks | count and share of that series |
|
|
179
|
+
| Top 3 BIN countries | count and share of that series |
|
|
180
|
+
|
|
181
|
+
Separately report Descriptor, descriptor total attempts, cluster attempts,
|
|
182
|
+
cluster share of descriptor, and MCC.
|
|
183
|
+
|
|
184
|
+
Require a stated min-n before ranking a cluster-versus-baseline rate
|
|
185
|
+
(default attempts ≥ 30). Below that, show the contrast rate as `n/a (n=…)`.
|
|
186
|
+
The definition anchor table is not a ranking contrast: always compute
|
|
187
|
+
authorization success rate and suspected-fraud share for every theoretical
|
|
188
|
+
level from that level's exact member attempts, including n < min-n. Combined
|
|
189
|
+
`*` levels use the combined attempts of the level. Do not write `n/a` on the
|
|
190
|
+
anchor table because the rung is small.
|
|
191
|
+
|
|
192
|
+
Use the contrast to assign investigation-priority risk under
|
|
193
|
+
[decision.md](decision.md), not as a fraud label. Treat materially different
|
|
194
|
+
authorization, suspected-fraud, issuing-bank, date, and local-hour behavior as
|
|
195
|
+
independent characteristics under thresholds declared in the run methodology.
|
|
196
|
+
|
|
197
|
+
For each Top 3 cluster BIN country, report both its share of the cluster and
|
|
198
|
+
the cluster's share of all attempts in the same descriptor-country slice. An
|
|
199
|
+
exact 100% single-country cluster is a standout. `Mixed` is neutral, and
|
|
200
|
+
country-slice coverage is descriptive only: do not set a universal threshold
|
|
201
|
+
or award risk points for values such as 20% or 33.8%.
|
|
202
|
+
|
|
203
|
+
## What not to do
|
|
204
|
+
|
|
205
|
+
- Do not treat MCC as a partition or clustering key.
|
|
206
|
+
- Do not discover ladders across descriptor boundaries.
|
|
207
|
+
- Do not use BIN country as a ladder partition or membership key.
|
|
208
|
+
- Do not k-means the amounts.
|
|
209
|
+
- Do not convert to USD and then look for ladders.
|
|
210
|
+
- Do not search only upward from the busiest rung.
|
|
211
|
+
- Do not use a percentage tolerance across amounts.
|
|
212
|
+
- Do not assign every amount inside an interval; select finite exact anchors first.
|
|
213
|
+
- Do not retain a low-support additional anchor merely because it is near a primary anchor.
|
|
214
|
+
- Do not report a cluster with fewer than three theoretical levels.
|
|
215
|
+
- Do not use any adjacent-level multiplier other than 2x.
|
|
216
|
+
- Do not report a cluster with fewer than 100 attempts.
|
|
217
|
+
- Do not put the same pair in two clusters within one partition.
|
|
218
|
+
- Do not merge matching amount fingerprints across descriptors.
|
|
219
|
+
- Do not call the output a customer segment or a marketing cohort.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Risk decision
|
|
2
|
+
|
|
3
|
+
After currency-amount-pair detection and same-descriptor baseline comparison,
|
|
4
|
+
assign investigation-priority risk tiers. This is prioritization, not a finding
|
|
5
|
+
that transaction laundering occurred.
|
|
6
|
+
|
|
7
|
+
## Eligibility versus risk
|
|
8
|
+
|
|
9
|
+
The cluster gate (at least three theoretical levels, fixed 2x adjacency, at
|
|
10
|
+
least 100 exact-member attempts) determines which currency-amount pairs enter
|
|
11
|
+
the result. Passing that gate does not by itself determine High, Medium, or Low
|
|
12
|
+
risk.
|
|
13
|
+
|
|
14
|
+
Risk uses independent post-membership evidence:
|
|
15
|
+
|
|
16
|
+
- structural strength beyond the minimum, such as a fourth or later level
|
|
17
|
+
- cluster share of its descriptor
|
|
18
|
+
- authorization-success and suspected-fraud differences versus the same-
|
|
19
|
+
descriptor baseline
|
|
20
|
+
- issuing-bank differences versus that baseline
|
|
21
|
+
- transaction-date and BIN-country-local-hour differences versus that baseline
|
|
22
|
+
- externally evidenced MCC or merchant-business mismatch; never infer this
|
|
23
|
+
from a suggestive descriptor name alone
|
|
24
|
+
|
|
25
|
+
Declare portfolio-specific thresholds for a materially different rate,
|
|
26
|
+
distribution, or descriptor share in the run methodology before assigning
|
|
27
|
+
risk. Do not invent universal cutoffs after seeing the results.
|
|
28
|
+
|
|
29
|
+
## BIN-country evidence
|
|
30
|
+
|
|
31
|
+
BIN country is post-membership evidence, not a partition, membership key, or
|
|
32
|
+
veto. `Mixed` is neutral and must never reduce a risk tier by itself.
|
|
33
|
+
|
|
34
|
+
For every Top 3 cluster BIN country, report both conditional views:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
cluster composition = cluster attempts in country / all cluster attempts
|
|
38
|
+
country-slice coverage = cluster attempts in country /
|
|
39
|
+
all attempts in the same descriptor and country
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
An exact **100% single-BIN-country cluster** is a standout characteristic.
|
|
43
|
+
Country-slice coverage explains how large that concentration is inside the
|
|
44
|
+
descriptor-country population, but it has no fixed threshold and contributes
|
|
45
|
+
no independent risk points. Values such as 20% or 33.8% are descriptive, not
|
|
46
|
+
self-interpreting risk signals. Any value below 100% is not promoted merely
|
|
47
|
+
because it is numerically high.
|
|
48
|
+
|
|
49
|
+
## Risk tiers
|
|
50
|
+
|
|
51
|
+
Assign exactly one tier to every identified currency-amount pair:
|
|
52
|
+
|
|
53
|
+
| Tier | Use when |
|
|
54
|
+
|---|---|
|
|
55
|
+
| High | An exact 100% single-country standout has at least one independent corroborating risk characteristic, or several independently strong non-country characteristics converge |
|
|
56
|
+
| Medium | At least two independent characteristics materially differ from the same-descriptor baseline, but High is not justified |
|
|
57
|
+
| Low | The structural cluster gate is met, but observed corroborating evidence is limited or not material |
|
|
58
|
+
|
|
59
|
+
Do not use a generic 0–100 score unless the business has approved and calibrated
|
|
60
|
+
its weights and cutoffs. Missing fields reduce confidence and must be disclosed;
|
|
61
|
+
they are not evidence that risk is Low.
|
|
62
|
+
|
|
63
|
+
Sort report results `High → Medium → Low`. Within a tier, sort by the number and
|
|
64
|
+
magnitude of independently supported characteristics, then by exact-member
|
|
65
|
+
attempts. Preserve stable cluster IDs when sorting an existing result.
|
|
66
|
+
|
|
67
|
+
## Length and required content
|
|
68
|
+
|
|
69
|
+
The Verdict is at most three sentences for the whole book:
|
|
70
|
+
|
|
71
|
+
1. State the highest risk tier found and that it is an investigative priority,
|
|
72
|
+
not confirmation that TLD occurred.
|
|
73
|
+
2. For High-risk clusters, give descriptor, representative anchors, attempts,
|
|
74
|
+
descriptor share, standout evidence, and the clearest independent
|
|
75
|
+
corroborating characteristic.
|
|
76
|
+
3. Give exact-member exposure by risk tier and as a share of all authorization
|
|
77
|
+
attempts.
|
|
78
|
+
|
|
79
|
+
If no currency-amount pair qualifies, state that none qualified, name the top
|
|
80
|
+
descriptor and candidate amounts, and report zero identified-cluster exposure.
|
|
81
|
+
Do not invent a cluster. Do not recommend filing a SAR, terminating a merchant,
|
|
82
|
+
or correcting an MCC.
|
|
83
|
+
|
|
84
|
+
First use of TLD is “transaction laundering (TLD)”. Proofread with
|
|
85
|
+
[terminology.md](terminology.md).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Report template
|
|
2
|
+
|
|
3
|
+
Save:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
reports/tld-detection/<scope>_clusters.md
|
|
7
|
+
reports/tld-detection/<scope>_clusters.zh.md
|
|
8
|
+
reports/tld-detection/<scope>_clusters.zh.html
|
|
9
|
+
reports/tld-detection/<scope>_methodology.md
|
|
10
|
+
reports/tld-detection/<scope>_methodology.zh.md
|
|
11
|
+
reports/tld-detection/<scope>_methodology.zh.html
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
HTML is preferred when there are charts (Chart.js bars). No Markdown bold in report body.
|
|
15
|
+
The cluster report and methodology document must link to each other. After
|
|
16
|
+
writing, grep banned strings in [terminology.md](terminology.md).
|
|
17
|
+
|
|
18
|
+
English Markdown headings on the left; Chinese HTML / `.zh.md` on the right.
|
|
19
|
+
|
|
20
|
+
```markdown
|
|
21
|
+
# Potential TLD currency-amount pairs — <window>
|
|
22
|
+
# 潜在 TLD 币种金额对 — <window>
|
|
23
|
+
|
|
24
|
+
## TLD Risk Assessment # TLD 风险评估
|
|
25
|
+
[Separate methodology link] # [独立方法文档链接]
|
|
26
|
+
## High-Risk Clusters # 高风险 Cluster
|
|
27
|
+
## TLD Risk Exposure # TLD 风险敞口
|
|
28
|
+
### By risk tier and descriptor # 按风险等级及 Descriptor
|
|
29
|
+
### Overall exposure # 整体风险敞口
|
|
30
|
+
## All Identified Currency-Amount Pairs # 全部识别出的币种金额对
|
|
31
|
+
### Currency-Amount Pair C1 # 币种金额对 C1
|
|
32
|
+
#### Definition # 定义
|
|
33
|
+
#### Characteristics # 特征
|
|
34
|
+
## Verdict # 结论
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The separate methodology document uses this structure:
|
|
38
|
+
|
|
39
|
+
```markdown
|
|
40
|
+
# TLD currency-amount-pair detection methodology — <scope/window>
|
|
41
|
+
# TLD 币种金额对识别方法 — <范围/时段>
|
|
42
|
+
|
|
43
|
+
## Universe and cleaning # 分析总体与清洗
|
|
44
|
+
## Descriptor partition logic # Descriptor 分区逻辑
|
|
45
|
+
## Currency-amount-pair logic # 币种金额对逻辑
|
|
46
|
+
## Baseline and audit details # 基线与审计明细
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Chapter requirements
|
|
50
|
+
|
|
51
|
+
### TLD Risk Assessment / TLD 风险评估
|
|
52
|
+
|
|
53
|
+
Answer these three questions directly and in this order:
|
|
54
|
+
|
|
55
|
+
1. What is the highest investigation-priority risk tier found?
|
|
56
|
+
2. Which clusters are High, Medium, and Low risk; what characteristics support
|
|
57
|
+
each tier; and what share do they represent inside their descriptors?
|
|
58
|
+
3. What is the exact-member exposure by risk tier, descriptor, and across all
|
|
59
|
+
authorization attempts?
|
|
60
|
+
|
|
61
|
+
Risk tiers prioritize investigation and do not confirm TLD. List results in
|
|
62
|
+
`High → Medium → Low` order, then by evidence strength and attempts inside each
|
|
63
|
+
tier. The ≤3-sentence conclusion lives in Verdict, not here.
|
|
64
|
+
|
|
65
|
+
### Separate methodology / 独立方法文档
|
|
66
|
+
|
|
67
|
+
Document the logic and values actually used for this run, not generic skill
|
|
68
|
+
instructions. State the authorization grain and window; give the census from
|
|
69
|
+
[clean.md](clean.md), BIN-country and currency mix, and portfolio
|
|
70
|
+
constants.
|
|
71
|
+
|
|
72
|
+
Partition logic defines the normalized descriptor key, normalization rules,
|
|
73
|
+
the unknown bucket, descriptor counts, and shares. Currency-amount-pair
|
|
74
|
+
logic explains within-descriptor ranking, adjacent currency-specific
|
|
75
|
+
absolute residual caps, sensitivity evidence, the multi-anchor support floor,
|
|
76
|
+
exact final membership, and the ≥100-attempt threshold. BIN country is
|
|
77
|
+
post-formation attribution, not a partition or membership key.
|
|
78
|
+
|
|
79
|
+
The ranking table contains partition, currency, exact amount, attempts,
|
|
80
|
+
share of the descriptor, share of all authorization attempts, and selected
|
|
81
|
+
cluster id or `baseline`. Chart attempt bars within the most relevant
|
|
82
|
+
descriptors, sorted by count descending.
|
|
83
|
+
|
|
84
|
+
Audit details contain drop counts, currency caps, sensitivity results,
|
|
85
|
+
multi-anchor support floor, ≥100 cluster attempts, min-n for
|
|
86
|
+
cluster-versus-baseline rate ranking (not the definition anchor table),
|
|
87
|
+
descriptor-local high-count rule, baseline definitions, below-threshold
|
|
88
|
+
families, risk-tier rules, all run-specific materiality thresholds, and files
|
|
89
|
+
used. No skill name in the HTML footer; filenames only.
|
|
90
|
+
|
|
91
|
+
### High-risk clusters / 高风险 Cluster
|
|
92
|
+
|
|
93
|
+
Include High-risk clusters only. For each, show descriptor, representative
|
|
94
|
+
anchors, attempts, share of its descriptor, share of all authorization attempts,
|
|
95
|
+
risk basis, standout evidence, and the clearest independent corroborating
|
|
96
|
+
characteristic. Do not describe the tier as confirmation that TLD occurred.
|
|
97
|
+
|
|
98
|
+
### Risk exposure / 风险敞口
|
|
99
|
+
|
|
100
|
+
Exposure is the disjoint exact-member attempt count of all identified clusters,
|
|
101
|
+
separated into High, Medium, and Low risk. The by-tier-and-descriptor table
|
|
102
|
+
reports descriptor attempts, cluster attempts, share of descriptor, share of
|
|
103
|
+
all authorization attempts, risk tier, and cluster IDs. The overall view has
|
|
104
|
+
one row per risk tier plus `Baseline` / `基线`, and the rows conserve all
|
|
105
|
+
authorization attempts. Never combine the three tiers into a single “confirmed”
|
|
106
|
+
or “supported TLD” impact figure.
|
|
107
|
+
|
|
108
|
+
### Currency-amount-pair analysis / 全部识别出的币种金额对
|
|
109
|
+
|
|
110
|
+
One subsection per identified currency-amount pair. Definition contains only
|
|
111
|
+
Descriptor, seed, representative anchors, and cluster attempts. Express
|
|
112
|
+
anchors as `USD 11.7 → USD 23.39* → USD 46.78`. Follow that with an anchor
|
|
113
|
+
table whose columns are anchor, attempts, authorization success rate, and
|
|
114
|
+
suspected fraud as share of attempts. Always compute both rates for every
|
|
115
|
+
theoretical level from that level's exact member attempts, including levels
|
|
116
|
+
with fewer than the contrast min-n (default 30). Do not write `n/a` on this
|
|
117
|
+
table because the rung is small. For a level containing multiple nearby exact
|
|
118
|
+
values, display its highest-count amount with `*`; the table totals attempts
|
|
119
|
+
and rates across that level and explains `*`.
|
|
120
|
+
|
|
121
|
+
Show the risk tier and concise basis immediately below the cluster heading.
|
|
122
|
+
Characteristics contain Descriptor, descriptor total attempts, cluster
|
|
123
|
+
attempts, cluster share of descriptor, and MCC. Then compare Cluster with the
|
|
124
|
+
baseline formed by removing that cluster from the same descriptor. The
|
|
125
|
+
comparison contains authorization success rate, suspected fraud as a share of
|
|
126
|
+
attempts, Top 3 issuing banks, and Top 3 BIN countries.
|
|
127
|
+
|
|
128
|
+
For every Top 3 cluster BIN country, add a table with country, cluster attempts,
|
|
129
|
+
share of cluster, total attempts in the same descriptor-country slice, and
|
|
130
|
+
cluster coverage of that slice. Mark exact 100% single-country composition as a
|
|
131
|
+
standout. Treat `Mixed` as neutral. Do not assign a threshold or risk points to
|
|
132
|
+
country-slice coverage, and do not promote any composition below 100% merely
|
|
133
|
+
because it is high.
|
|
134
|
+
|
|
135
|
+
Follow the tables with transaction-date and transaction-time charts comparing
|
|
136
|
+
the cluster with the same-descriptor baseline. These are characteristics, not
|
|
137
|
+
cluster membership conditions.
|
|
138
|
+
|
|
139
|
+
When clustering finds no qualifying family, omit currency-amount-pair subsections,
|
|
140
|
+
publish the ranking and below-threshold candidates in the methodology
|
|
141
|
+
document, show zero identified-cluster exposure, and still write Verdict.
|
|
142
|
+
|
|
143
|
+
### Verdict / 结论
|
|
144
|
+
|
|
145
|
+
[decision.md](decision.md). **≤3 sentences** for the whole book, then an
|
|
146
|
+
optional one-row-per-cluster table (risk tier + short basis). No extra
|
|
147
|
+
bullets under this heading.
|
|
148
|
+
|
|
149
|
+
## Charts
|
|
150
|
+
|
|
151
|
+
Place each currency-amount pair's charts inside its analysis after the
|
|
152
|
+
characteristics tables.
|
|
153
|
+
|
|
154
|
+
| View | Mark |
|
|
155
|
+
|---|---|
|
|
156
|
+
| Representative-anchor attempts | Horizontal bar |
|
|
157
|
+
| Cluster vs same-descriptor baseline rates | Grouped bar |
|
|
158
|
+
| Transaction date trend, cluster vs same-descriptor baseline | Two-series line, each series normalized to its own attempt total |
|
|
159
|
+
| Transaction time by BIN-country local hour, cluster vs same-descriptor baseline | Two-series line, each series normalized to its own attempt total |
|
|
160
|
+
|
|
161
|
+
Label axes with the full metric (`授权笔数`, `比率 %`, `每日授权占比 %`,
|
|
162
|
+
`每小时授权占比 %`). State that transaction time uses the BIN country's local
|
|
163
|
+
hour and UTC when the BIN country has no configured timezone.
|
|
164
|
+
|
|
165
|
+
## What the report is not
|
|
166
|
+
|
|
167
|
+
Not a payment overview (`payment-analysis`). Not a holdout rule pack
|
|
168
|
+
(`fraud-analysis`). Not a recommendation to file a SAR or to terminate a
|
|
169
|
+
merchant.
|