@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.
Files changed (206) hide show
  1. package/README.md +9 -4
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +54 -48
  4. package/runtime/skills/distribution/scripts/bundles.mjs +113 -7
  5. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
  6. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
  7. package/skills/cicd-pipeline/cloud-build/SKILL.md +6 -6
  8. package/skills/cicd-pipeline/mergify/SKILL.md +1 -1
  9. package/skills/engineering/engineering-runtime/coherence/workflow.json +15 -84
  10. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
  11. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
  12. package/skills/engineering/rush-release/SKILL.md +46 -25
  13. package/skills/engineering/rush-release/evals/evals.json +22 -8
  14. package/skills/engineering/rush-release/references/cut.md +21 -4
  15. package/skills/engineering/rush-release/references/preflight.md +25 -6
  16. package/skills/engineering/rush-release/references/promotion.md +70 -0
  17. package/skills/engineering/rush-release/references/publish.md +49 -16
  18. package/skills/engineering/rush-release/scripts/plan.mjs +33 -7
  19. package/skills/engineering/smoke/SKILL.md +4 -4
  20. package/skills/engineering/smoke/references/manifest.md +3 -3
  21. package/skills/payment/payment-analysis/SKILL.md +5 -3
  22. package/skills/payment/tld-detection/SKILL.md +163 -0
  23. package/skills/payment/tld-detection/agents/openai.yaml +9 -0
  24. package/skills/payment/tld-detection/evals/evals.json +107 -0
  25. package/skills/payment/tld-detection/references/clean.md +51 -0
  26. package/skills/payment/tld-detection/references/clustering.md +219 -0
  27. package/skills/payment/tld-detection/references/decision.md +85 -0
  28. package/skills/payment/tld-detection/references/report-template.md +169 -0
  29. package/skills/payment/tld-detection/references/terminology.md +69 -0
  30. package/skills/payment/tld-detection/references/workflow.md +78 -0
  31. package/skills/payment/tld-detection/scripts/detect_ladders.py +390 -0
  32. package/skills/payment/tld-detection/tests/test_detect_ladders.py +132 -0
  33. package/skills/engineering/resolve-issues/SKILL.md +0 -168
  34. package/skills/engineering/resolve-issues/agents/openai.yaml +0 -9
  35. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +0 -499
  36. package/skills/engineering/resolve-issues/references/breaker.md +0 -82
  37. package/skills/engineering/resolve-issues/references/deliverables.md +0 -27
  38. package/skills/engineering/resolve-issues/references/delivery.md +0 -108
  39. package/skills/engineering/resolve-issues/references/evidence-lane.md +0 -21
  40. package/skills/engineering/resolve-issues/references/exact-head-ci.md +0 -287
  41. package/skills/engineering/resolve-issues/references/fan-out.md +0 -33
  42. package/skills/engineering/resolve-issues/references/finalization.md +0 -68
  43. package/skills/engineering/resolve-issues/references/guarantees.md +0 -10
  44. package/skills/engineering/resolve-issues/references/high-risk.md +0 -29
  45. package/skills/engineering/resolve-issues/references/incidents/848/README.md +0 -156
  46. package/skills/engineering/resolve-issues/references/intake.md +0 -86
  47. package/skills/engineering/resolve-issues/references/integration-gate.md +0 -53
  48. package/skills/engineering/resolve-issues/references/interference.md +0 -87
  49. package/skills/engineering/resolve-issues/references/loop.md +0 -134
  50. package/skills/engineering/resolve-issues/references/model-catalog.md +0 -9
  51. package/skills/engineering/resolve-issues/references/postmortem.md +0 -27
  52. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +0 -41
  53. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +0 -48
  54. package/skills/engineering/resolve-issues/references/pre-flight.md +0 -41
  55. package/skills/engineering/resolve-issues/references/regression-checklist.md +0 -26
  56. package/skills/engineering/resolve-issues/references/run-state.md +0 -288
  57. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +0 -48
  58. package/skills/engineering/resolve-issues/references/spawn-contract.md +0 -96
  59. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +0 -40
  60. package/skills/engineering/resolve-issues/references/why.md +0 -653
  61. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +0 -49
  62. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +0 -721
  63. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +0 -962
  64. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +0 -220
  65. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +0 -420
  66. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +0 -256
  67. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +0 -168
  68. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +0 -9
  69. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +0 -62
  70. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +0 -191
  71. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +0 -413
  72. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +0 -332
  73. package/skills/engineering/resolve-issues/scripts/finalize.mjs +0 -488
  74. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +0 -3307
  75. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +0 -16
  76. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +0 -51
  77. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +0 -17
  78. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +0 -166
  79. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +0 -92
  80. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +0 -73
  81. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +0 -159
  82. package/skills/engineering/resolve-issues/scripts/interference.mjs +0 -427
  83. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +0 -9
  84. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +0 -419
  85. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +0 -909
  86. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +0 -345
  87. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +0 -415
  88. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +0 -697
  89. package/skills/engineering/resolve-issues/scripts/report.mjs +0 -494
  90. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +0 -172
  91. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +0 -79
  92. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +0 -334
  93. package/skills/engineering/resolve-issues/scripts/run-state.mjs +0 -4792
  94. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +0 -395
  95. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +0 -290
  96. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +0 -170
  97. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +0 -293
  98. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +0 -197
  99. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +0 -127
  100. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +0 -893
  101. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +0 -829
  102. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +0 -290
  103. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +0 -80
  104. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +0 -102
  105. package/skills/engineering/resolve-release/LICENSE +0 -3
  106. package/skills/engineering/resolve-release/SKILL.md +0 -113
  107. package/skills/engineering/resolve-release/agents/openai.yaml +0 -9
  108. package/skills/engineering/resolve-release/references/assembly.md +0 -137
  109. package/skills/engineering/resolve-release/references/auto-when-green.md +0 -56
  110. package/skills/engineering/resolve-release/references/candidate.md +0 -167
  111. package/skills/engineering/resolve-release/references/exposure.md +0 -178
  112. package/skills/engineering/resolve-release/references/handoff.md +0 -24
  113. package/skills/engineering/resolve-release/references/postmortem.md +0 -230
  114. package/skills/engineering/resolve-release/references/preflight.md +0 -208
  115. package/skills/engineering/resolve-release/references/principles.md +0 -94
  116. package/skills/engineering/resolve-release/references/regression-checklist.md +0 -36
  117. package/skills/engineering/resolve-release/references/related-skills.md +0 -13
  118. package/skills/engineering/resolve-release/references/routing.md +0 -149
  119. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +0 -285
  120. package/skills/engineering/resolve-release/references/versioning.md +0 -202
  121. package/skills/engineering/resolve-release/references/why.md +0 -53
  122. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +0 -389
  123. package/skills/engineering/resolve-release/scripts/build-changes.mjs +0 -209
  124. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +0 -407
  125. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +0 -904
  126. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +0 -81
  127. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +0 -612
  128. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +0 -135
  129. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +0 -161
  130. package/skills/engineering/resolve-release/scripts/doctrine.mjs +0 -106
  131. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +0 -522
  132. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +0 -659
  133. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +0 -1014
  134. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +0 -526
  135. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +0 -169
  136. package/skills/engineering/resolve-release/scripts/green-gate.mjs +0 -599
  137. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +0 -752
  138. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +0 -56
  139. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +0 -1538
  140. package/skills/engineering/resolve-release/scripts/postmortem.mjs +0 -381
  141. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +0 -510
  142. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +0 -326
  143. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +0 -272
  144. package/skills/engineering/resolve-release/scripts/report.mjs +0 -417
  145. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +0 -114
  146. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +0 -238
  147. package/skills/engineering/resolve-release/scripts/review-packet.mjs +0 -503
  148. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +0 -263
  149. package/skills/engineering/resolve-release/scripts/version-assert.mjs +0 -339
  150. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +0 -485
  151. package/skills/engineering/resolve-release/scripts/version.mjs +0 -1199
  152. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +0 -449
  153. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +0 -21
  154. package/skills/engineering/resolve-release/vendor/README.md +0 -60
  155. package/skills/engineering/resolve-release/vendor/acorn.mjs +0 -6233
  156. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +0 -21
  157. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +0 -341
  158. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +0 -70
  159. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +0 -2
  160. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +0 -1
  161. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +0 -7
  162. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +0 -1
  163. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +0 -2033
  164. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +0 -2033
  165. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +0 -7
  166. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +0 -1
  167. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +0 -2
  168. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +0 -1
  169. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +0 -2
  170. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +0 -1
  171. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +0 -2
  172. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +0 -1
  173. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +0 -49
  174. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +0 -21
  175. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +0 -5
  176. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +0 -549
  177. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +0 -549
  178. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +0 -2
  179. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +0 -1
  180. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +0 -2
  181. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +0 -1
  182. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +0 -36
  183. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +0 -47
  184. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +0 -82
  185. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +0 -11
  186. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +0 -22
  187. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +0 -21
  188. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +0 -21
  189. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +0 -11
  190. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +0 -11
  191. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +0 -25
  192. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  193. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +0 -85
  194. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +0 -85
  195. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +0 -2
  196. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +0 -1
  197. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +0 -2
  198. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +0 -1
  199. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +0 -20
  200. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +0 -20
  201. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +0 -2
  202. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +0 -1
  203. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +0 -2
  204. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +0 -1
  205. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +0 -61
  206. /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.