@1aboveio/skills 1.0.10 → 1.0.11

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 (213) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/.codex-plugin/resources.json +297 -216
  3. package/README.md +3 -3
  4. package/package.json +10 -8
  5. package/skills/app-dev/airflow/SKILL.md +1 -1
  6. package/skills/app-dev/android-foundation/SKILL.md +35 -37
  7. package/skills/app-dev/android-foundation/references/delivery-focus.md +4 -2
  8. package/skills/app-dev/android-foundation/references/feature-work.md +50 -0
  9. package/skills/app-dev/android-foundation/references/setup.md +24 -9
  10. package/skills/app-dev/android-foundation/references/workspace.md +81 -0
  11. package/skills/app-dev/android-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
  12. package/skills/app-dev/android-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
  13. package/skills/app-dev/android-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
  14. package/skills/app-dev/app-debug/SKILL.md +1 -1
  15. package/skills/app-dev/better-auth/SKILL.md +1 -1
  16. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  17. package/skills/app-dev/data-quality/SKILL.md +1 -1
  18. package/skills/app-dev/ios-foundation/SKILL.md +15 -10
  19. package/skills/app-dev/ios-foundation/references/setup.md +25 -9
  20. package/skills/app-dev/ios-foundation/references/workspace.md +82 -0
  21. package/skills/app-dev/ios-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
  22. package/skills/app-dev/ios-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
  23. package/skills/app-dev/ios-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
  24. package/skills/app-dev/monorepo/SKILL.md +1 -1
  25. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  26. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  27. package/skills/app-dev/pyspark/SKILL.md +1 -1
  28. package/skills/app-dev/python-backend/SKILL.md +1 -1
  29. package/skills/app-dev/shadcn/SKILL.md +1 -1
  30. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  31. package/skills/cicd/cloud-build/SKILL.md +1 -1
  32. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  33. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  34. package/skills/cicd/docker/SKILL.md +1 -1
  35. package/skills/cicd/github-actions/SKILL.md +1 -1
  36. package/skills/cicd/github-flow/SKILL.md +1 -1
  37. package/skills/cicd/google-cloud/SKILL.md +1 -1
  38. package/skills/cicd/mergify/SKILL.md +1 -1
  39. package/skills/cicd/podman/SKILL.md +1 -1
  40. package/skills/content/article-review/SKILL.md +1 -1
  41. package/skills/content/article-to-image/SKILL.md +1 -1
  42. package/skills/content/flowchart-svg/SKILL.md +1 -1
  43. package/skills/content/image-gen/SKILL.md +1 -1
  44. package/skills/content/mermaid/SKILL.md +1 -1
  45. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  46. package/skills/content/wechat-publisher/SKILL.md +1 -1
  47. package/skills/content/wechat-search/SKILL.md +1 -1
  48. package/skills/content/xai-search/SKILL.md +1 -1
  49. package/skills/core/distill-writing/SKILL.md +3 -3
  50. package/skills/core/distill-writing/references/extraction.md +1 -1
  51. package/skills/core/doc-to-md/SKILL.md +1 -1
  52. package/skills/core/editorial-review/SKILL.md +82 -12
  53. package/skills/core/editorial-review/references/checklist.md +26 -1
  54. package/skills/core/house-style/SKILL.md +8 -3
  55. package/skills/core/house-style/references/analytical-reporting.md +123 -0
  56. package/skills/core/house-style/references/analytical-writing-patterns.md +79 -0
  57. package/skills/core/house-style/references/analytical-writing-research.md +129 -0
  58. package/skills/core/{write-doc → house-style}/references/bilingual.md +7 -5
  59. package/skills/core/house-style/references/definitions-and-metrics.md +86 -0
  60. package/skills/core/house-style/references/document-workflow.md +193 -0
  61. package/skills/core/house-style/references/initialization.md +66 -0
  62. package/skills/core/house-style/references/persistence.md +9 -4
  63. package/skills/core/house-style/references/rules.md +11 -4
  64. package/skills/core/house-style/scripts/init-guidance.mjs +213 -0
  65. package/skills/core/house-style/templates/analytical-report.md +54 -0
  66. package/skills/core/house-style/templates/gap-analysis.md +1 -1
  67. package/skills/core/plain-language/SKILL.md +2 -2
  68. package/skills/core/polish-cn/SKILL.md +9 -2
  69. package/skills/core/reg-parser/SKILL.md +3 -3
  70. package/skills/core/terminology/SKILL.md +8 -4
  71. package/skills/core/write-doc/SKILL.md +40 -151
  72. package/skills/core/write-report/SKILL.md +129 -0
  73. package/skills/core/{write-doc → write-report}/references/compliance-reports.md +4 -4
  74. package/skills/engineering/better-review/SKILL.md +37 -37
  75. package/skills/engineering/better-review/references/passes.md +35 -41
  76. package/skills/engineering/better-review/references/result.md +10 -9
  77. package/skills/engineering/e2e-test/SKILL.md +17 -17
  78. package/skills/engineering/e2e-test/references/authoring/playwright-config.md +11 -13
  79. package/skills/engineering/e2e-test/references/presentation-sweep.md +7 -7
  80. package/skills/engineering/e2e-test/references/reviewing.md +9 -11
  81. package/skills/engineering/e2e-test/references/route-manifest.md +1 -1
  82. package/skills/engineering/engineering/SKILL.md +124 -0
  83. package/skills/engineering/engineering/references/engineering-conventions.md +32 -0
  84. package/skills/engineering/engineering/references/feature-delivery.md +8 -0
  85. package/skills/engineering/engineering/references/init-scope.md +37 -0
  86. package/skills/engineering/engineering/scripts/init.mjs +160 -0
  87. package/skills/engineering/{contributing → engineering}/scripts/persist-conventions.mjs +1 -1
  88. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  89. package/skills/engineering/engineering-runtime/coherence/workflow.json +19 -19
  90. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
  91. package/skills/engineering/ensure-coverage/SKILL.md +22 -109
  92. package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +7 -5
  93. package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +4 -4
  94. package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +3 -3
  95. package/skills/engineering/ensure-coverage/references/depth/characterization.md +4 -65
  96. package/skills/engineering/ensure-coverage/references/depth/grading.md +5 -7
  97. package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +6 -12
  98. package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +1 -1
  99. package/skills/engineering/ensure-coverage/references/presentation/axis.md +6 -6
  100. package/skills/engineering/ensure-coverage/references/process/audit-mode.md +7 -23
  101. package/skills/engineering/ensure-coverage/references/process/output-template.md +18 -133
  102. package/skills/engineering/ensure-coverage/references/process/test-strategy.md +7 -12
  103. package/skills/engineering/ensure-coverage/scripts/README.md +12 -4
  104. package/skills/engineering/golden-path/SKILL.md +1 -1
  105. package/skills/engineering/harness-runtime/SKILL.md +3 -1
  106. package/skills/engineering/harness-runtime/bin/workspaces.mjs +52 -0
  107. package/skills/engineering/harness-runtime/native-workspace.mjs +239 -0
  108. package/skills/engineering/harness-runtime/references/workspaces.md +78 -0
  109. package/skills/engineering/harness-runtime/workspace-lifecycle.mjs +2154 -0
  110. package/skills/engineering/resolve-issues/SKILL.md +40 -61
  111. package/skills/engineering/resolve-issues/references/ci.md +13 -3
  112. package/skills/engineering/resolve-issues/references/delivery-progress.md +4 -3
  113. package/skills/engineering/resolve-issues/references/done.md +11 -2
  114. package/skills/engineering/resolve-issues/references/expire.md +9 -2
  115. package/skills/engineering/resolve-issues/references/implementation.md +33 -17
  116. package/skills/engineering/resolve-issues/references/preflight.md +3 -1
  117. package/skills/engineering/resolve-issues/references/principles.md +52 -0
  118. package/skills/engineering/resolve-issues/references/review.md +25 -15
  119. package/skills/engineering/resolve-issues/references/task-plan.md +64 -27
  120. package/skills/engineering/resolve-issues/references/workspaces.md +164 -0
  121. package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +185 -317
  122. package/skills/engineering/resolve-issues/scripts/next-actions.mjs +44 -7
  123. package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +36 -2
  124. package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +9 -8
  125. package/skills/engineering/resolve-issues/scripts/workspace-lifecycle.mjs +1 -0
  126. package/skills/engineering/resolve-release/SKILL.md +1 -1
  127. package/skills/engineering/rush-issues/SKILL.md +7 -5
  128. package/skills/engineering/rush-release/SKILL.md +1 -1
  129. package/skills/engineering/test-quality/SKILL.md +19 -4
  130. package/skills/engineering/test-quality/references/lint.md +1 -1
  131. package/skills/engineering/test-quality/references/principles.md +2 -2
  132. package/skills/engineering/test-quality/references/testing-conventions.md +1 -1
  133. package/skills/risk-compliance/compliance-audit/SKILL.md +4 -8
  134. package/skills/risk-compliance/compliance-audit/references/audience-and-reports.md +12 -0
  135. package/skills/risk-compliance/contract-compare/SKILL.md +17 -1
  136. package/skills/risk-compliance/contract-review/SKILL.md +6 -1
  137. package/skills/risk-compliance/contract-review/references/report-stage.md +17 -0
  138. package/skills/risk-compliance/doc-authenticity/SKILL.md +11 -1
  139. package/skills/risk-compliance/fraud-detection/LICENSE +3 -0
  140. package/skills/risk-compliance/fraud-detection/SKILL.md +148 -0
  141. package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/first-party-fraud.md +3 -2
  142. package/skills/risk-compliance/fraud-detection/references/archetypes/third-party-fraud.md +47 -0
  143. package/skills/risk-compliance/fraud-detection/references/collection-payout-features.md +151 -0
  144. package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/contexts/bank-transfer.md +4 -3
  145. package/skills/risk-compliance/fraud-detection/references/contexts/card-payment.md +70 -0
  146. package/skills/risk-compliance/fraud-detection/references/contexts/payment-collection.md +34 -0
  147. package/skills/risk-compliance/fraud-detection/references/contexts/payout.md +34 -0
  148. package/skills/risk-compliance/fraud-detection/references/enrichment.md +74 -0
  149. package/skills/risk-compliance/fraud-detection/references/entities.md +48 -0
  150. package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/feature-engineering.md +69 -33
  151. package/skills/risk-compliance/fraud-detection/references/feature-sql.md +150 -0
  152. package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-rationale.md +4 -2
  153. package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-template.md +45 -23
  154. package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/review-checklist.md +60 -20
  155. package/skills/risk-compliance/fraud-detection/references/workflow.md +216 -0
  156. package/skills/risk-compliance/fraud-detection/release-check.mjs +95 -0
  157. package/skills/risk-compliance/payment-analysis/SKILL.md +36 -17
  158. package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +2 -2
  159. package/skills/risk-compliance/payment-analysis/references/report-template.md +10 -2
  160. package/skills/risk-compliance/payment-analysis/references/visualization.md +11 -1
  161. package/skills/risk-compliance/portfolio-payment-analysis/LICENSE +3 -0
  162. package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +170 -0
  163. package/skills/risk-compliance/portfolio-payment-analysis/references/identity-and-reconciliation.md +46 -0
  164. package/skills/risk-compliance/portfolio-payment-analysis/references/metrics-and-reporting.md +170 -0
  165. package/skills/risk-compliance/portfolio-payment-analysis/references/risk-history.md +89 -0
  166. package/skills/risk-compliance/portfolio-payment-analysis/release-check.mjs +95 -0
  167. package/skills/risk-compliance/portfolio-payment-analysis/scripts/analyze.py +636 -0
  168. package/skills/risk-compliance/portfolio-payment-analysis/scripts/build_report.py +386 -0
  169. package/skills/risk-compliance/portfolio-payment-analysis/scripts/comparison_charts.py +425 -0
  170. package/skills/risk-compliance/portfolio-payment-analysis/scripts/csv_export.py +52 -0
  171. package/skills/risk-compliance/portfolio-payment-analysis/scripts/render.py +160 -0
  172. package/skills/risk-compliance/portfolio-payment-analysis/scripts/risk_history.py +435 -0
  173. package/skills/risk-compliance/similar-domain/SKILL.md +9 -4
  174. package/skills/risk-compliance/tld-detection/SKILL.md +124 -239
  175. package/skills/risk-compliance/tld-detection/agents/openai.yaml +1 -1
  176. package/skills/risk-compliance/tld-detection/references/clean.md +18 -51
  177. package/skills/risk-compliance/tld-detection/references/fx-conversion.md +56 -219
  178. package/skills/risk-compliance/tld-detection/references/metric-contract.md +109 -0
  179. package/skills/risk-compliance/tld-detection/references/pattern.md +99 -0
  180. package/skills/risk-compliance/tld-detection/references/report-template.md +49 -272
  181. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +46 -13
  182. package/skills/risk-compliance/tld-detection/scripts/detect_patterns.py +346 -0
  183. package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +51 -19
  184. package/skills/risk-compliance/tld-detection/scripts/profile_groups.py +109 -0
  185. package/skills/risk-compliance/tld-detection/scripts/render_charts.py +218 -0
  186. package/skills/risk-compliance/tld-detection/scripts/tld_common.py +243 -0
  187. package/skills/engineering/contributing/SKILL.md +0 -70
  188. package/skills/risk-compliance/fraud-analysis/SKILL.md +0 -114
  189. package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +0 -27
  190. package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +0 -30
  191. package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +0 -20
  192. package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +0 -20
  193. package/skills/risk-compliance/fraud-analysis/references/workflow.md +0 -175
  194. package/skills/risk-compliance/tld-detection/references/chinese-polish.md +0 -55
  195. package/skills/risk-compliance/tld-detection/references/clustering.md +0 -235
  196. package/skills/risk-compliance/tld-detection/references/decision.md +0 -189
  197. package/skills/risk-compliance/tld-detection/references/streams.md +0 -141
  198. package/skills/risk-compliance/tld-detection/references/terminology.md +0 -95
  199. package/skills/risk-compliance/tld-detection/references/workflow.md +0 -95
  200. /package/skills/{engineering/contributing → core/write-report}/LICENSE +0 -0
  201. /package/skills/core/{write-doc → write-report}/references/reports/audit-report-template.md +0 -0
  202. /package/skills/core/{write-doc → write-report}/references/reports/external-assessment-template.md +0 -0
  203. /package/skills/core/{write-doc → write-report}/references/reports/management-report-template.md +0 -0
  204. /package/skills/core/{write-doc → write-report}/references/reports/vars-report-template.md +0 -0
  205. /package/skills/{engineering/contributing → core/write-report}/release-check.mjs +0 -0
  206. /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/LICENSE +0 -0
  207. /package/skills/engineering/{contributing → engineering}/references/tracker-conventions.md +0 -0
  208. /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/release-check.mjs +0 -0
  209. /package/skills/engineering/{contributing → engineering}/scripts/persist-conventions-core.mjs +0 -0
  210. /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/authorized-payment-scam.md +0 -0
  211. /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/mechanisms/account-takeover.md +0 -0
  212. /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/taxonomy.md +0 -0
  213. /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/terminology.md +0 -0
@@ -1,272 +1,49 @@
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>_evidence.md
10
- reports/tld-detection/<scope>_evidence.zh.md
11
- reports/tld-detection/<scope>_evidence.zh.html
12
- reports/tld-detection/<scope>_methodology.md
13
- reports/tld-detection/<scope>_methodology.zh.md
14
- reports/tld-detection/<scope>_methodology.zh.html
15
- ```
16
-
17
- HTML is preferred when there are charts (Chart.js bars). No Markdown bold in report body.
18
- The main report (`_clusters`), complete evidence (`_evidence`), and methodology
19
- must link to one another. These are distinct reading layers, not three copies
20
- of the same explanation. Use a new revision-qualified directory or scope for
21
- each delivered revision. Never overwrite prior reports, evidence, methodology,
22
- or chart assets; record the previous revision and pin links to the intended
23
- revision. A presentation-only revision reuses accepted saved results without
24
- rerunning inference, detection, or risk assignment. Preserve memberships, risk
25
- tiers, baselines, exposure, and all statistics. After
26
- writing, run `editorial-review`, then `polish-cn` on all Chinese deliverables as
27
- specified in [chinese-polish.md](chinese-polish.md).
28
- Verify unchanged facts, synchronize Chinese Markdown and HTML, then grep
29
- banned strings in [terminology.md](terminology.md).
30
-
31
- English Markdown headings on the left; Chinese HTML / `.zh.md` on the right.
32
-
33
- ```markdown
34
- # Potential transaction laundering (TLD) currency-amount pairs — <window>
35
- # 潜在交易清洗(TLD)币种金额对 — <window>
36
-
37
- ## Period Conclusion # 本期结论(月报用“本月结论”)
38
- [Plain-language decision summary] # [先查谁、为什么、目前不能判断什么]
39
- [Evidence and methodology links] # [完整证据与方法链接]
40
- ## Main Findings # 主要发现
41
- ### <Exact descriptor and finding> # <账单名称与发现>
42
- ## Next Checks # 下一步核查
43
- ```
44
-
45
- Use exactly these three top-level sections in the main report. Do not repeat
46
- a closing Verdict or require a table for every descriptor. Include only
47
- supported observations that explain a conclusion or a bounded next check.
48
- Retain uncertainty and negative evidence needed to interpret the finding.
49
- For each finding: observed evidence with period and denominator, then supported
50
- payment-pattern hypothesis and limitations, then its reconciled relationship
51
- to exact amount clusters. Do not lead with raw detector labels.
52
-
53
- The complete evidence document contains payment-pattern tables, the High-risk
54
- inventory, by-tier/by-descriptor and overall exposure, every cluster profile,
55
- anchor rates, country breakdowns, and secondary charts. Keep the detailed
56
- requirements below here, not in the main report. No evidence is deleted merely
57
- because it is not selected for the main narrative.
58
-
59
- The separate methodology document uses this structure:
60
-
61
- ```markdown
62
- # Transaction laundering (TLD) currency-amount-pair detection methodology — <scope/window>
63
- # 交易清洗(TLD)币种金额对识别方法 — <范围/时段>
64
-
65
- ## Universe and cleaning # 分析总体与清洗
66
- ## Descriptor partition logic # Descriptor 分区逻辑
67
- ## Payment-pattern inference # 收款模式推断
68
- ## Currency-amount-pair logic # 币种金额对逻辑
69
- ## Baseline and audit details # 基线与审计明细
70
- ```
71
-
72
- ## Chapter requirements
73
-
74
- ### Period conclusion / 本期结论
75
-
76
- Answer these three questions directly and in this order:
77
-
78
- 1. What is the highest investigation-priority risk tier found?
79
- 2. Which clusters are High, Medium, and Low risk; what characteristics support
80
- each tier; and what share do they represent inside their descriptors?
81
- 3. What is the exact-member exposure by risk tier, descriptor, and across all
82
- authorization attempts?
83
-
84
- Risk tiers prioritize investigation and do not confirm TLD. Summarize the
85
- answers in ordinary language; keep the full inventories and exposure tables in
86
- evidence. Order findings `High → Medium → Low`, then by evidence strength and
87
- attempts inside each tier, retaining stable IDs. The opening summary has at
88
- most three short sentences; do not repeat it at the end.
89
-
90
- ### Separate methodology / 独立方法文档
91
-
92
- Document the logic and values actually used for this run, not generic skill
93
- instructions. State the authorization grain and window; give the census from
94
- [clean.md](clean.md), BIN-country and currency mix, and portfolio
95
- constants.
96
-
97
- Partition logic defines the normalized descriptor key, normalization rules,
98
- the unknown bucket, descriptor counts, and shares. Currency-amount-pair
99
- logic explains within-descriptor ranking, adjacent currency-specific
100
- absolute residual caps, sensitivity evidence, the multi-anchor support floor,
101
- exact final membership, and the ≥100-attempt threshold. BIN country is
102
- post-formation attribution, not a partition or membership key.
103
-
104
- The ranking table contains partition, currency, exact amount, attempts,
105
- share of the descriptor, share of all authorization attempts, and selected
106
- cluster id or `baseline`. Chart attempt bars within the most relevant
107
- descriptors, sorted by count descending.
108
-
109
- Audit details contain drop counts, currency caps, sensitivity results,
110
- multi-anchor support floor, ≥100 cluster attempts, min-n for
111
- cluster-versus-baseline rate ranking (not the definition anchor table),
112
- descriptor-local high-count rule, baseline definitions, below-threshold
113
- families, risk-tier rules, all run-specific materiality thresholds, and files
114
- used. No skill name in the HTML footer; filenames only.
115
-
116
- ### Payment patterns in complete evidence / 完整证据中的收款模式
117
-
118
- Use Direct top-up pattern / 直接充值模式, FX-converted top-up pattern /
119
- 换汇充值模式, E-commerce pattern (Retail pattern) / 电商模式, or Other pattern /
120
- 其他模式. Include this caption: names are hypotheses based on authorization
121
- data, not verified businesses or successful settlements. No raw menu/frozen/
122
- off-menu labels in reader-facing headings; retain them in methodology.
123
-
124
- One table per descriptor, with pattern, inferred top-up currency, actual charge
125
- currency, attempts, share of descriptor, top issuing countries, approval rate,
126
- suspected-fraud response share, and relevant repeat/retry behavior. Split display
127
- rows where charge currencies imply different direct/FX top-up subtypes, while
128
- preserving counts and all other/insufficient-sample attempts. Several inferred
129
- top-up currencies may be listed separately without inventing several cashiers.
130
-
131
- Show fixed amounts / 定额 as a supplementary characteristic, not an exclusive
132
- pattern. Record whether source-to-top-up rate consistency was tested; a raw
133
- `live` result is not proof of live conversion. Do not call fixed amounts generated
134
- traffic or infer tax, fees, or verified goods from a fitted retail constant.
135
-
136
- Explain the clearest observed differences and the unresolved business question
137
- in ordinary language. Patterns do not partition canonical detection; a cluster
138
- may span several patterns. Describe any pattern allocation only where supported
139
- by a recorded row-level reconciliation, never by guessing from matching labels.
140
- Methodology holds raw labels, parameters, cache, coverage, drift, alternatives,
141
- and excluded/missing inference coverage; those rows remain in canonical detection.
142
- When a finding includes a supported menu whose presets do not double at each
143
- step, explain the distinction in that finding: the menu describes a pricing
144
- hypothesis, while the three-level, fixed-2x, 100-attempt gate selects formal
145
- amount clusters. Showing two different lists or saying they overlap is not
146
- an explanation of why both can be valid. Preserve their separate counts and
147
- row-reconciled intersection; never force menu prices into cluster anchors.
148
-
149
- ### High-risk inventory in complete evidence / 完整证据中的高风险组合
150
-
151
- Include High-risk clusters only. For each, show descriptor, representative
152
- anchors, attempts, share of its descriptor, share of all authorization attempts,
153
- risk basis, standout evidence, and the clearest independent corroborating
154
- characteristic. Do not describe the tier as confirmation that TLD occurred.
155
-
156
- ### Exposure in complete evidence / 完整证据中的风险敞口
157
-
158
- Exposure is the disjoint exact-member attempt count of all identified clusters,
159
- separated into High, Medium, and Low risk. The by-tier-and-descriptor table
160
- reports descriptor attempts, cluster attempts, share of descriptor, share of
161
- all authorization attempts, risk tier, and cluster IDs. The overall view has
162
- one row per risk tier plus `Baseline` / `基线`, and the rows conserve all
163
- authorization attempts. Never combine the three tiers into a single “confirmed”
164
- or “supported TLD” impact figure.
165
-
166
- ### Cluster analysis in complete evidence / 完整证据中的金额组合
167
-
168
- One subsection per identified currency-amount pair. Show the risk tier and
169
- concise basis immediately below the cluster heading, then use one consolidated
170
- profile/comparison table. Do not emit separate Definition, Characteristics,
171
- Specification, and Metrics tables because they repeat descriptor, attempts,
172
- and cluster context.
173
-
174
- The consolidated table has columns `Section`, `Item`, `Cluster / value`, and
175
- `Same-descriptor baseline`. It contains each fact exactly once:
176
-
177
- | Section | Items |
178
- |---|---|
179
- | Definition | Descriptor, seed, representative anchors |
180
- | Population | Descriptor attempts, cluster attempts, cluster share of descriptor |
181
- | Specification | MCC |
182
- | Metrics | Authorization success rate, suspected fraud as share of attempts, Top 3 issuing banks, Top 3 BIN countries |
183
-
184
- Use `—` in the baseline column for definition/specification values that have no
185
- comparison. The baseline population is the same descriptor after removing the
186
- cluster's exact keys. Express anchors as `USD 11.7 → USD 23.39* → USD 46.78`.
187
-
188
- Follow the consolidated table with one anchor table whose columns are anchor,
189
- attempts, authorization success rate, and suspected fraud as share of attempts.
190
- Always compute both rates for every theoretical level from that level's exact
191
- member attempts, including levels with fewer than the contrast min-n (default
192
- 30). Do not write `n/a` on this table because the rung is small. For a level
193
- containing multiple nearby exact values, display its highest-count amount with
194
- `*`; the table totals attempts and rates across that level and explains `*`.
195
-
196
- For every Top 3 cluster BIN country, add a table with country, cluster attempts,
197
- share of cluster, total attempts in the same descriptor-country slice, and
198
- cluster coverage of that slice. In canonical original-currency results only,
199
- mark exact 100% single-country composition as a standout. Treat `Mixed` as
200
- neutral. Do not assign a threshold or risk points to country-slice coverage,
201
- and do not promote any composition below 100% merely because it is high. In FX
202
- results, caption even 100% concentration as descriptive because BIN country
203
- constructs target currency; it cannot raise the FX tier.
204
-
205
- Follow the tables with transaction-date and transaction-time charts comparing
206
- the cluster with the same-descriptor baseline. These are characteristics, not
207
- cluster membership conditions.
208
-
209
- When clustering finds no qualifying family, omit currency-amount-pair subsections,
210
- publish the ranking and below-threshold candidates in the methodology
211
- document, show zero identified-cluster exposure, and still write the three
212
- main-report sections. Candidate rankings are not risk hits; do not invent
213
- cluster charts or promote descriptor-level leads to formal tiers.
214
-
215
- For an FX sensitivity, keep the same consolidated layout, label anchors as
216
- base-currency anchors, and link separate `<scope>_bin_base_currency_clusters*`
217
- and methodology files. Define `|P_FX|` as the exact-date-converted attempts in
218
- the current frozen canonical descriptor partition. Use only `P_FX` for FX
219
- high-count/rung-pool thresholds and the same-descriptor baseline; keep excluded
220
- rows only in exclusion coverage and reconciliation to canonical `U`. State both
221
- converted-universe and all-authorization exposure denominators.
222
-
223
- ### Main findings and next checks / 主要发现与下一步核查
224
-
225
- Follow [decision.md](decision.md). The opening summary is limited to three
226
- short sentences, not the whole report. Explain whom to review and why in Main
227
- findings, using only established evidence. Put specific checks against orders,
228
- products, sellers, websites, or fulfillment in Next checks and connect each to
229
- an observed finding. State when evidence cannot support a priority or useful
230
- check rather than inventing one.
231
- Explain observations in business language and retain uncertainty. In a zero-
232
- cluster run, state zero identified-cluster exposure without implying low risk;
233
- descriptor-level leads remain separate from formal cluster tiers. For a period
234
- focus, separate current activity from historical findings. The final chat
235
- handoff follows the same structure rather than leading with detector IDs.
236
-
237
- ## Charts
238
-
239
- Preserve useful original charts in the concise report. Put the most important
240
- amount and cluster-versus-baseline rate charts inline beside the relevant
241
- finding. Use expandable sections for date/hour views, secondary clusters, and
242
- candidate rankings, with full evidence links. Keep all valid original charts
243
- available in the main report, not only linked elsewhere. Zero-cluster reports
244
- may reuse candidate rankings with an explicit not-risk-hits caption; never
245
- invent cluster charts. Canonical and FX charts stay in separate reports.
246
-
247
- For presentation revisions, inventory original chart IDs and compare payloads
248
- before and after: chart type, labels, series, values, axes, orientation,
249
- normalization, denominators, currency, and timezone semantics. Retain local
250
- chart dependencies. Initialize hidden charts only when visible and resize
251
- on expansion. Verify nonblank canvases, readable labels, expansion behavior,
252
- and no page horizontal overflow at desktop and mobile widths. For Markdown,
253
- retain chart captions and links to the corresponding HTML views. Correct an
254
- invalid source chart only as an explicit analytical correction in a separate
255
- revision with the reason recorded, never silently during presentation work.
256
-
257
- | View | Mark |
258
- |---|---|
259
- | Representative-anchor attempts | Horizontal bar |
260
- | Cluster vs same-descriptor baseline rates | Grouped bar |
261
- | Transaction date trend, cluster vs same-descriptor baseline | Two-series line, each series normalized to its own attempt total |
262
- | Transaction time by BIN-country local hour, cluster vs same-descriptor baseline | Two-series line, each series normalized to its own attempt total |
263
-
264
- Label axes with the full metric (`授权笔数`, `比率 %`, `每日授权占比 %`,
265
- `每小时授权占比 %`). State that transaction time uses the BIN country's local
266
- hour and UTC when the BIN country has no configured timezone.
267
-
268
- ## What the report is not
269
-
270
- Not a payment overview (`payment-analysis`). Not a holdout rule pack
271
- (`fraud-analysis`). Not a recommendation to file a SAR or to terminate a
272
- merchant.
1
+ # Reporting
2
+
3
+ Lead with the key observations, investigation priorities, uncertainty and next
4
+ checks. State the period and populations, keep currency views separate, and label
5
+ all denominators. Read `{house-style baseDir}/references/analytical-reporting.md` and
6
+ its required references. For each analytical topic, put its supported point near its
7
+ chart and show the evidence and decision-relevant limitations. Do not impose a fixed
8
+ finding quota. When evidence cannot support a point, name the concrete shortfall and
9
+ what it prevents the reader from concluding or doing. Use the requested language and
10
+ format; no fixed bilingual or file-count requirement applies.
11
+
12
+ ## Evidence and methodology
13
+
14
+ Retain exact group IDs and amount keys, group/out-group profiles, daily and hourly
15
+ counts, status coverage, and ID unions for combined totals. Record source files,
16
+ cleaning census, aggregation rules, parameters, timezone, FX mapping/cache and
17
+ exclusion reconciliation. Link these details from the main report when stored
18
+ separately. The saved profile and offline charts use the same group/out-group
19
+ interface for concentration, escalation and pricing; see the
20
+ [metric contract](metric-contract.md) for schemas and formulas. Keep sensitive
21
+ identifiers in the authorized evidence destination.
22
+
23
+ ## Revisions
24
+
25
+ Save each delivered revision to a new path under `reports/tld-detection/` and
26
+ link the intended evidence, methodology and prior revision. For presentation-only
27
+ changes, reuse accepted membership, metrics, tiers and valid chart payloads;
28
+ do not rerun analysis. Request missing artifacts and disclose unverified rendering.
29
+
30
+ ## Language and review
31
+
32
+ A descriptor is a billing name, not a verified merchant identity. BIN country is
33
+ the card-issuing country, not customer location. Suspected fraud is not confirmed
34
+ fraud; an authorization decline is not a chargeback. Spell out transaction
35
+ laundering (TLD) on first use.
36
+
37
+ For Chinese, use 账单名称, 授权成功, 疑似欺诈 and 调查优先级; preserve exact
38
+ identifiers and never translate an authorization decline as 拒付.
39
+ For review, reuse the shared analytical rules already read in unchanged context; reload them
40
+ after context loss. Give their resolved paths and this template to `write-report`, which
41
+ coordinates editorial review and requires delegated reviewers to read them. Return remaining
42
+ domain checks to this workflow without repeating a completed writing pass. For Chinese output,
43
+ pass this template's Chinese-polish step to the writer when `polish-cn` is available; that is
44
+ a domain selection, not the writer's generic optional default. Reuse its completed pass.
45
+ Do not send raw transactions, card identifiers or
46
+ credentials to polishing services. Protect amounts, dates, currencies, IDs,
47
+ denominators, tiers and FX provenance; verify each remains attached to the correct
48
+ population and period. Missing facts remain unknown. Disclose any review or
49
+ polishing step that could not run rather than claiming it passed.
@@ -9,6 +9,7 @@ import re
9
9
  from collections import Counter, defaultdict
10
10
  from dataclasses import dataclass
11
11
  from decimal import Decimal
12
+ from fractions import Fraction
12
13
  from pathlib import Path
13
14
  from typing import Iterable, Mapping, Sequence
14
15
 
@@ -30,8 +31,38 @@ def _rank(keys: Iterable[Pair], counts: Mapping[Pair, int]) -> list[Pair]:
30
31
  return sorted(keys, key=lambda key: (-counts[key], key[1], key[0]))
31
32
 
32
33
 
33
- def _residual(lower: Pair, upper: Pair, multiplier: Decimal) -> Decimal:
34
- return abs(upper[1] - lower[1] * multiplier)
34
+ def _residual(lower: Pair, upper: Pair, multiplier: Decimal) -> Fraction:
35
+ return abs(Fraction(upper[1]) - Fraction(lower[1]) * Fraction(multiplier))
36
+
37
+
38
+ def _decimal_exact(value: Fraction) -> Decimal:
39
+ # Residuals of finite decimals also have finite decimal representations.
40
+ denominator = value.denominator
41
+ twos = fives = 0
42
+ while denominator % 2 == 0:
43
+ denominator //= 2
44
+ twos += 1
45
+ while denominator % 5 == 0:
46
+ denominator //= 5
47
+ fives += 1
48
+ if denominator != 1:
49
+ raise ValueError("residual is not a finite decimal")
50
+ scale = max(twos, fives)
51
+ integer = value.numerator * 2 ** (scale - twos) * 5 ** (scale - fives)
52
+ return Decimal((int(integer < 0), tuple(map(int, str(abs(integer)))), -scale))
53
+
54
+
55
+ def _adjacent(lower: Pair, upper: Pair, multiplier: Decimal, cap: Decimal) -> bool:
56
+ """Require distinct positive rungs and an unambiguous doubling fit.
57
+
58
+ The absolute cap controls price noise. A candidate must also be closer to
59
+ 2x than to 1x or 3x, so a large cap cannot manufacture tiny-price ladders.
60
+ """
61
+ return (
62
+ Decimal(0) < lower[1] < upper[1]
63
+ and _residual(lower, upper, multiplier) <= cap
64
+ and _residual(lower, upper, multiplier) < Fraction(lower[1]) / 2
65
+ )
35
66
 
36
67
 
37
68
  def _expand_levels(
@@ -53,22 +84,22 @@ def _expand_levels(
53
84
  candidate
54
85
  for candidate in available - claimed
55
86
  if candidate[0] == seed[0]
56
- and any(_residual(anchor, candidate, multiplier) <= cap for anchor in previous)
87
+ and any(_adjacent(anchor, candidate, multiplier, cap) for anchor in previous)
57
88
  }
58
89
  else:
59
90
  candidates = {
60
91
  candidate
61
92
  for candidate in available - claimed
62
93
  if candidate[0] == seed[0]
63
- and any(_residual(candidate, anchor, multiplier) <= cap for anchor in previous)
94
+ and any(_adjacent(candidate, anchor, multiplier, cap) for anchor in previous)
64
95
  }
65
96
  if not candidates:
66
97
  break
67
98
 
68
- def candidate_residual(candidate: Pair) -> Decimal:
99
+ def candidate_residual(candidate: Pair) -> Fraction:
69
100
  if direction == 1:
70
- return min(_residual(anchor, candidate, multiplier) for anchor in previous)
71
- return min(_residual(candidate, anchor, multiplier) for anchor in previous)
101
+ return min(_residual(anchor, candidate, multiplier) for anchor in previous if anchor[1] < candidate[1])
102
+ return min(_residual(candidate, anchor, multiplier) for anchor in previous if candidate[1] < anchor[1])
72
103
 
73
104
  primary = min(candidates, key=lambda candidate: (-counts[candidate], candidate_residual(candidate), candidate[1]))
74
105
  next_level = {primary} | {
@@ -80,13 +111,13 @@ def _expand_levels(
80
111
  return levels
81
112
 
82
113
 
83
- def _fit_residual(levels: Mapping[int, set[Pair]], multiplier: Decimal) -> Decimal:
84
- total = Decimal("0")
114
+ def _fit_residual(levels: Mapping[int, set[Pair]], multiplier: Decimal) -> Fraction:
115
+ total = Fraction(0)
85
116
  for level, anchors in levels.items():
86
117
  if level > 0:
87
- total += sum(min(_residual(lower, anchor, multiplier) for lower in levels[level - 1]) for anchor in anchors)
118
+ total += sum(min(_residual(lower, anchor, multiplier) for lower in levels[level - 1] if lower[1] < anchor[1]) for anchor in anchors)
88
119
  elif level < 0:
89
- total += sum(min(_residual(anchor, upper, multiplier) for upper in levels[level + 1]) for anchor in anchors)
120
+ total += sum(min(_residual(anchor, upper, multiplier) for upper in levels[level + 1] if anchor[1] < upper[1]) for anchor in anchors)
90
121
  return total
91
122
 
92
123
 
@@ -120,7 +151,7 @@ def detect_ladders(
120
151
  for seed in _rank(rung_pool, normalized):
121
152
  if seed not in unused:
122
153
  continue
123
- candidates: list[tuple[tuple[object, ...], dict[int, set[Pair]], Decimal, Decimal]] = []
154
+ candidates: list[tuple[tuple[object, ...], dict[int, set[Pair]], Decimal, Fraction]] = []
124
155
  for multiplier in (CLUSTER_MULTIPLIER,):
125
156
  cap = config.absolute_caps[seed[0]]
126
157
  levels = _expand_levels(
@@ -153,7 +184,7 @@ def detect_ladders(
153
184
  "pairs": family,
154
185
  "rule": "adjacent-absolute-residual",
155
186
  "absolute_cap": config.absolute_caps[seed[0]],
156
- "fit_residual": fit_residual,
187
+ "fit_residual": _decimal_exact(fit_residual),
157
188
  "multi_anchor_levels": {level: anchors for level, anchors in levels.items() if len(anchors) > 1},
158
189
  "alternatives": {},
159
190
  }
@@ -249,6 +280,7 @@ def sensitivity_analysis(
249
280
  multi_anchor_min_attempts=config.multi_anchor_min_attempts,
250
281
  ),
251
282
  )
283
+ ladders = [ladder for ladder in ladders if ladder["seed"][0] == currency]
252
284
  output.append(
253
285
  {
254
286
  "currency": currency,
@@ -283,6 +315,7 @@ def partitioned_sensitivity_analysis(
283
315
  multi_anchor_min_attempts=config.multi_anchor_min_attempts,
284
316
  ),
285
317
  )
318
+ ladders = [ladder for ladder in ladders if ladder["seed"][0] == currency]
286
319
  output.append(
287
320
  {
288
321
  "currency": currency,