@1aboveio/skills 1.0.9 → 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,232 +1,69 @@
1
- # BIN-country base-currency FX sensitivity
1
+ # Reproducible currency views
2
2
 
3
- Use this supplemental path when the user asks to convert transaction amounts
4
- to the card-origin currency, or when daily FX drift may conceal fixed local-
5
- currency anchors. Run it after canonical original-currency membership is
6
- complete. It is sensitivity evidence, not a replacement clustering universe.
3
+ Create USD and BIN-country-currency views from the same cleaned transaction
4
+ universe. Map each normalized BIN country to legal tender in effect on the
5
+ transaction date, preferably using ISO 4217 current and historic lists. Record
6
+ source, dated country-to-currency map and target minor units. Missing or
7
+ ambiguous mappings, including multiple legal tenders or transitions without a
8
+ declared justified choice, exclude the row from the BIN-country view, not USD.
9
+ Never infer country currency from descriptor, language, IP or transaction currency.
7
10
 
8
- ## Separation contract
11
+ ## Frankfurter v2 acquisition
9
12
 
10
- - Reuse the canonical cleaned authorization rows and descriptor normalization.
11
- - Keep canonical `C*` results unchanged.
12
- - Name supplemental families `FXC1`, `FXC2`, ... and publish separate files
13
- such as `<scope>_bin_base_currency_clusters.md` and
14
- `<scope>_bin_base_currency_methodology.md`.
15
- - Do not combine `C*` and `FXC*` attempts into one exposure total because the
16
- same authorization may belong to both views.
17
-
18
- ## Target currency
19
-
20
- Map normalized BIN country to the legal tender in effect on the transaction
21
- date. Use the ISO 4217 Maintenance Agency's current and historic lists as the
22
- preferred source for currency and minor unit, and record the complete run-
23
- specific country-to-currency map and source.
24
- Do not infer currency from language, descriptor, terminal country, shopper IP,
25
- or transaction currency. For countries with several legal tenders or a
26
- currency transition during the window, declare and justify the dated mapping;
27
- exclude ambiguous rows rather than silently choosing one.
28
-
29
- Missing BIN country remains in the canonical run but cannot be assigned a BIN-
30
- origin currency. Count it as an FX exclusion under
31
- `missing country-currency mapping`.
32
-
33
- ## Frankfurter v2 rates and cache contract
34
-
35
- Frankfurter v2 is mandatory for this sensitivity. Its public API requires no
36
- API key or other authentication. Before retrieval, choose and disclose either
37
- `default blended` or one or more named provider keys. The default blend is a
38
- real provider-selection decision: omit the `providers` filter from the URL and
39
- state that Frankfurter blended all eligible providers. For a named selection,
40
- append `&providers=<comma-separated-provider-keys>` and record those exact
41
- filter keys. In both modes, `expand=providers` is mandatory so the response
42
- identifies the providers that actually contributed to each non-peg row.
43
-
44
- Every request uses this exact endpoint and includes all five required query
45
- parameters, even for a one-day window. A named-provider request also includes
46
- the optional `providers` filter:
13
+ Use the immutable, versioned Frankfurter v2 cache for both views. Select either
14
+ `default blended` (omit `providers`) or named provider keys before retrieval;
15
+ record the selection. `expand=providers` identifies contributors and does not
16
+ select them. Request inclusive UTC transaction-date bounds, pivot `P`, and sorted
17
+ deduplicated source and target quotes, even for a single day:
47
18
 
48
19
  ```text
49
20
  GET https://api.frankfurter.dev/v2/rates?from=<YYYY-MM-DD>&to=<YYYY-MM-DD>&base=<P>&quotes=<comma-separated-currencies>&expand=providers
50
21
  GET https://api.frankfurter.dev/v2/rates?from=<YYYY-MM-DD>&to=<YYYY-MM-DD>&base=<P>&quotes=<comma-separated-currencies>&expand=providers&providers=<comma-separated-provider-keys>
51
22
  ```
52
23
 
53
- `from` and `to` are the inclusive UTC transaction-date bounds, `base` is the
54
- declared pivot currency `P`, and `quotes` is the sorted, deduplicated set of
55
- source and target currencies needed by the run. `expand=providers` requests
56
- row-level contributing-provider keys; it does not select a provider and does
57
- not replace the optional `providers` filter. Do not use the v1 nested response,
58
- `/latest`, or an implicit latest date. A returned row means that its `rate` is
59
- quote-currency units per one unit of its `base` currency: with `base=P`,
60
- `rate(d, P→Q)` is units of `Q` per one unit of pivot `P`.
61
-
62
- Write the response to
63
- `reports/tld-detection/<scope>_frankfurter_v2_rates.cache.json`. Create this
64
- run-specific cache once, do not overwrite it, and record its SHA-256 in the
65
- methodology. The cache schema is versioned and contains at least:
66
-
67
- ```json
68
- {
69
- "schema_version": 1,
70
- "api": "Frankfurter",
71
- "api_version": "v2",
72
- "endpoint": "https://api.frankfurter.dev/v2/rates",
73
- "cache_created_at_utc": "<ISO-8601 UTC timestamp ending Z>",
74
- "requests": [
75
- {
76
- "request_url": "<complete run-specific request URL>",
77
- "retrieved_at_utc": "<ISO-8601 UTC timestamp ending Z>",
78
- "provider_selection": {"mode": "default blended", "providers": []},
79
- "query": {"from": "<date>", "to": "<date>", "base": "<P>", "quotes": ["<Q>"], "expand": ["providers"]},
80
- "returned_facts": [
81
- {"date": "<date>", "base": "<P>", "quote": "<Q>", "rate": "<positive decimal>", "providers": ["<contributing-provider-key>"]}
82
- ]
83
- }
84
- ]
85
- }
86
- ```
87
-
88
- Preserve every returned `date`, `base`, `quote`, and unrounded `rate` fact and,
89
- when Frankfurter returns it, the complete `providers` key array exactly as
90
- returned. An omitted `providers` member means Frankfurter marked that fact as
91
- peg-derived; it is not unknown provenance. Preserve the omission rather than
92
- writing `[]`, `null`, a guessed provider, or the request's selected providers.
93
- For named-provider requests, `provider_selection` and the optional URL/query
94
- filter record what was requested; add `"providers": ["<provider-key>"]` to the
95
- cached `query`. Each fact's `providers` array records which of those providers
96
- actually contributed; peg-derived facts still omit the member. The methodology
97
- repeats the cache path, complete request URL or
98
- URLs, UTC retrieval timestamp or timestamps, provider selection, query
99
- bounds/pivot/quotes/expansion, row-level provider identities and peg-derived
100
- omissions, schema version, and cache SHA-256. Never rely on a later live refetch
101
- to reproduce a run.
102
-
103
- Fail closed before conversion when the cache is missing; `schema_version` is
104
- missing or unsupported; a legacy/v1 cache is supplied; required metadata or a
105
- `date`/`base`/`quote`/`rate` fact is absent; the endpoint, complete URL, parsed
106
- query (including `expand=providers` and any provider filter), provider
107
- selection, retrieval timestamp, requested window, pivot, or quotes do not match
108
- the run; a present fact-level `providers` member is not an array of provider
109
- keys; a returned provider key was not preserved; a rate is non-positive; or
110
- duplicate facts conflict. Do not repair a cache mismatch by refetching during
111
- analysis and do not treat an invalid cache as ordinary row-level FX exclusions.
112
-
113
- ## Conversion
114
-
115
- For each authorization on UTC transaction date `d`, with source currency `S`,
116
- target BIN-origin currency `T`, source amount `a`, and API quotes expressed as
117
- currency units per pivot currency `P`:
118
-
119
- ```text
120
- base_amount = a / rate(d, P→S) × rate(d, P→T)
121
- ```
122
-
123
- Use `1` when `S = P` or `T = P`. If either required non-identity quote has no
124
- returned fact whose `date` is exactly `d`, exclude that authorization. Never
125
- fill weekends or missing dates with a prior-business-day, monthly average,
126
- latest, or next-day rate.
127
-
128
- Count exclusions by reason, date, and currency. Report:
129
-
130
- ```text
131
- canonical cleaned attempts → exact-date converted attempts → FX exclusions
132
- ```
133
-
134
- ## Converted partition universe
135
-
136
- For each frozen canonical descriptor partition `D`, define:
137
-
138
- ```text
139
- P_FX(D) = authorization attempts in D successfully converted using exact-date
140
- Frankfurter v2 facts under the validated cache contract
141
- |P_FX| = the attempt count of P_FX(D) for the current descriptor partition
142
- ```
143
-
144
- Identity legs valued at `1` remain exact-date conversions; every non-identity
145
- leg must have the matching returned date/base/quote/rate fact. Rows excluded
146
- for mapping, quote, or conversion reasons are not in `P_FX`.
147
-
148
- Compute FX candidate counts and both FX thresholds only from `P_FX` in the
149
- current descriptor:
150
-
151
- | Set | FX membership |
152
- |---|---|
153
- | High-count (seeds) | union of (a) FX pairs with count ≥ `max(30, 0.5% of \|P_FX\|)`, (b) the `P_FX` partition top 25 FX pairs by count, and (c) per target currency in `P_FX`, the top 10 FX pairs with count ≥30 |
154
- | Rung pool | FX pairs with count ≥ `max(5, 0.1% of \|P_FX\|)` |
155
-
156
- State the resulting thresholds per descriptor. FX-excluded rows never enter
157
- these denominators, rankings, rung pools, families, baselines, or cluster
158
- metrics. They remain only in exclusion coverage and reconciliation back to
159
- canonical `U`:
160
-
161
- ```text
162
- |U_D| = |P_FX(D)| + |FX exclusions in D|
163
- |U| = sum_D |P_FX(D)| + all FX exclusions
164
- ```
165
-
166
- ## Rounding and keys
167
-
168
- Round converted values once, half-up, to the target currency's ISO 4217 minor
169
- unit in effect on the transaction date. Record the exponent table actually
170
- used. Do not round rates before conversion.
171
-
172
- Inside each frozen descriptor partition, define the supplemental key as:
24
+ Create `reports/tld-detection/<scope>_frankfurter_v2_rates.cache.json` once per
25
+ run; never overwrite it. Record its SHA-256 and schema version. The cache must
26
+ contain `schema_version: 1`, `api: Frankfurter`, `api_version: v2`, endpoint,
27
+ `cache_created_at_utc`, and a `requests` array. Each request records complete
28
+ `request_url`, `retrieved_at_utc`, `provider_selection` with `mode` and
29
+ `providers`, parsed `query` (`from`, `to`, `base`, `quotes`, `expand`, plus
30
+ `providers` for named selection), and `returned_facts`. Preserve every returned
31
+ fact's date, base, quote and unrounded positive rate, and the complete contributor
32
+ `providers` array exactly as returned. If that member is omitted, preserve the
33
+ omission: it denotes a peg-derived fact, not an empty or guessed provider list.
34
+ Record request URLs, UTC timestamps, provider selection, contributors and peg
35
+ omissions, query bounds, pivot, quotes, cache path and hash in methodology.
36
+
37
+ Fail closed before conversion for a missing, unsupported, incomplete or legacy
38
+ cache, invalid timestamps or facts, nonpositive rates, conflicting duplicates, or
39
+ mismatch between the run and endpoint, full URL, parsed query, provider filter,
40
+ selection, bounds, pivot or quotes. A present fact `providers` must be an array
41
+ of provider keys; preserve returned contributors. Do not repair a mismatch by
42
+ refetching during analysis or classify an invalid cache as row-level exclusions.
43
+ Never use `/latest`, v1 or a later live refetch to reproduce the run.
44
+
45
+ ## Conversion and reconciliation
46
+
47
+ For transaction UTC date `d`, source `S`, target `T`, pivot `P`, and source amount
48
+ `a`, with quote rates in units of currency per unit of pivot:
173
49
 
174
50
  ```text
175
- (target BIN-origin currency, rounded base_amount)
51
+ converted = a / rate(d, P→S) × rate(d, P→T)
176
52
  ```
177
53
 
178
- Apply the fixed 2x, three-level, multi-anchor support, disjointness, and ≥100
179
- exact-member gates as the canonical detector after applying the `P_FX`-only
180
- high-count and rung-pool thresholds above. Final FX membership is exact
181
- equality on descriptor, target currency, and rounded base amount; tolerance is
182
- discovery-only.
183
-
184
- Scale absolute residual caps in target-currency minor units. A defensible
185
- starting sensitivity grid is 1, 2, and 5 minor units, retaining the smallest
186
- cap under which material paths are stable. Report currency-specific cluster
187
- counts and covered attempts; do not repeat the portfolio-wide total on every
188
- currency row.
189
-
190
- ## Baseline, risk, and reporting
191
-
192
- For each `FXC*` family, the comparison baseline uses only `P_FX` for the same
193
- frozen canonical descriptor and removes that family's exact FX keys. FX-
194
- excluded rows cannot enter the same-descriptor baseline. Show exposure against
195
- both the converted universe and all canonical cleaned authorization attempts.
196
- Reconcile identified FX attempts + converted baseline + FX exclusions to the
197
- canonical cleaned universe.
198
-
199
- BIN country causally determines target currency in this view. Therefore:
200
-
201
- - show BIN-country composition and descriptor-country slice coverage;
202
- - caption exact 100% single-country concentration as descriptive and
203
- constructed by the target-currency mapping;
204
- - do not count country concentration as independent risk evidence;
205
- - do not raise the FX tier because of country concentration;
206
- - assign High/Medium/Low using only structural and other independent
207
- `P_FX` same-descriptor characteristics.
208
-
209
- Use the three-section main report, complete linked evidence, and methodology
210
- layout in [report-template.md](report-template.md), with separate FX filenames
211
- and revision-qualified paths. Put the consolidated per-cluster table in FX
212
- evidence, not the concise main report.
213
- Keep the anchor table and BIN-country attribution table separate because they
214
- are one-to-many detail, not duplicate cluster facts. Include the same four
215
- charts as the canonical report and label converted anchors with their target
216
- base currency.
217
-
218
- ## FX audit checklist
219
-
220
- - [ ] Canonical cleaned universe and `C*` results were frozen first
221
- - [ ] As-of-date country-to-legal-tender mapping and minor units are recorded
222
- - [ ] Frankfurter `/v2/rates` uses explicit `from`, `to`, `base`, `quotes`, and `expand=providers`; authentication is not required
223
- - [ ] Provider selection/default blend, complete request URL, UTC retrieval time, returned facts with contributing provider keys or documented peg-derived omission, cache path/SHA-256, and supported cache schema version are recorded
224
- - [ ] Missing, mismatched, incomplete, or legacy cache facts fail closed before conversion
225
- - [ ] Formula supports non-pivot source currencies
226
- - [ ] Exact-date no-fill coverage and every exclusion are reconciled
227
- - [ ] Per descriptor, `|P_FX|` is only exact-date-converted attempts; thresholds and same-descriptor baselines use only `P_FX`
228
- - [ ] `FXC*` membership uses exact descriptor + target currency + rounded amount
229
- - [ ] Caps and sensitivity are expressed per currency in minor units
230
- - [ ] Country concentration is descriptive and excluded from FX risk evidence
231
- - [ ] Converted and all-authorization exposure denominators are both shown
232
- - [ ] `C*` and `FXC*` exposure are never added together
54
+ An identity leg equals 1. Every non-identity leg needs an exact-date fact; do
55
+ not fill missing dates using earlier, later, monthly or latest rates. Keep rates
56
+ unrounded; round the final amount once, half-up, to the target currency's dated
57
+ ISO minor unit. Record the exponent table. Each converted amount key contains
58
+ MID, normalized descriptor, target currency and rounded amount. Concentration and
59
+ escalation use exact selected keys; pricing fits retain their frozen transaction
60
+ IDs as described in [pattern.md](pattern.md).
61
+
62
+ Report each view's source count, converted count and exclusions by reason, date,
63
+ currency and scope. Reconcile source = converted + excluded independently for
64
+ both views; USD and BIN-country results may contain the same transaction. Each
65
+ partition's selection thresholds, group profiles and out-group baseline use only
66
+ successfully converted transactions in that view and target currency. Exclusions
67
+ are not baseline. Combine overlapping groups or views only by the union of
68
+ transaction IDs. BIN country constructs the BIN-country target, so its
69
+ concentration cannot independently raise investigation priority.
@@ -0,0 +1,109 @@
1
+ # Script and metric contract
2
+
3
+ ## Input: prepared transactions (schema version 1)
4
+
5
+ `tld_common.py` validates this JSON boundary. FX preparation remains governed by
6
+ [fx-conversion.md](fx-conversion.md); these scripts do not fetch rates or infer
7
+ country-to-currency mappings. Supply the prepared amounts and retain conversion
8
+ provenance with the run. Missing conversion is an exclusion, never a zero amount.
9
+
10
+ ```json
11
+ {
12
+ "schema_version": 1,
13
+ "period": {"start": "2026-01-01", "end": "2026-01-03", "timezone": "UTC"},
14
+ "transactions": [{
15
+ "transaction_id": "T1", "transaction_time": "2026-01-01T12:00:00Z",
16
+ "currency": "USD", "amount": "10.00", "mcc": "5999",
17
+ "billing_descriptor": "SHOP", "mid": "M1", "card_scheme": "Visa",
18
+ "card_bin": "411111", "card_issuer": "Example bank", "card_bin_country": "US",
19
+ "authorized": true, "suspected_fraud": false,
20
+ "views": {
21
+ "usd": {"currency": "USD", "amount": "10.00"},
22
+ "bin_country": {"currency": "USD", "amount": "10.00"}
23
+ }
24
+ }]
25
+ }
26
+ ```
27
+
28
+ Dates are inclusive in the declared IANA reporting timezone. Transaction times
29
+ must have an explicit offset; reject naive timestamps. Convert to reporting-local
30
+ date/hour before selecting the window. Money is a finite nonnegative decimal
31
+ string, never a binary float. Required identity and business fields are nonempty
32
+ strings; `card_bin_country` alone may be null, which excludes the BIN-country view.
33
+ Both view keys are required. An excluded view has
34
+ `{"excluded_reason":"missing exact-date quote"}` instead of currency/amount.
35
+ Authorization and suspected-fraud values are independently true, false or null;
36
+ missing optional status fields become null, never false. Do not infer one from
37
+ the other. Exact duplicate transaction records may be removed; conflicting records
38
+ with one ID fail validation. Original currencies are uppercased and descriptor
39
+ case/whitespace normalized; MID remains a separate key. Reject malformed rows
40
+ rather than silently dropping them. Out-of-period rows are counted in the census.
41
+
42
+ ## Shared Python interface
43
+
44
+ `load_dataset(path)` reads and validates JSON. `validate_dataset(payload)` returns
45
+ a normalized dataset; `dataset_sha256` binds its reporting period and normalized,
46
+ deduplicated in-period transaction content, sorted by ID. `view_rows(data)` returns
47
+ one row per eligible transaction/view with `view`, target `currency` and `amount`,
48
+ `charge_currency` and `charge_amount`, normalized `descriptor`, `date` and `hour`,
49
+ and the original identity/status/dimension fields. Amounts remain decimal strings.
50
+ `scope_of(row)` returns `mid`, `descriptor`, `view`, `currency`.
51
+
52
+ Detection output is a group manifest:
53
+
54
+ ```json
55
+ {
56
+ "schema_version": 1,
57
+ "dataset_sha256": "<normalized dataset digest>",
58
+ "period": {"start": "2026-01-01", "end": "2026-01-03", "timezone": "UTC"},
59
+ "groups": [{
60
+ "id": "G1", "pattern": "concentration",
61
+ "scope": {"mid":"M1", "descriptor":"shop", "view":"usd", "currency":"USD"},
62
+ "member_ids": ["T1"], "details": {}
63
+ }]
64
+ }
65
+ ```
66
+
67
+ Allowed patterns: `concentration`, `escalating`, `pricing`. Each group has a unique
68
+ nonempty ID and a nonempty, duplicate-free member list. `validate_groups(data,
69
+ payload)` returns validated groups after checking schema, period, digest, known
70
+ IDs, exact scope, and conversion eligibility. Reject cross-scope, excluded, stale
71
+ or unknown membership. Different groups and views may share transaction IDs.
72
+
73
+ ## Metric definitions
74
+
75
+ For group G, out-group B is all eligible transactions in the identical scope and
76
+ reporting period minus G. Each population has its own denominator. Rates are
77
+ fractions in JSON (0–1), displayed as percentages in charts.
78
+
79
+ | Metric | Numerator | Denominator / behavior |
80
+ |---|---|---|
81
+ | Transaction count | Unique transaction IDs | Count, including all statuses |
82
+ | Payment success rate | `authorized == true` | Population transaction count; null if count is zero or any authorization status is unknown |
83
+ | Suspected-fraud rate | `suspected_fraud == true` | Population transaction count; null if count is zero or any fraud status is unknown |
84
+ | Status coverage | Transactions with known corresponding status | Population transaction count; null for empty populations |
85
+ | Daily share | Population count that local date | That population's whole-period count; null if population is empty |
86
+ | Hour count | Population transactions at local hour 00–23 | Counts, not rates; repeated DST hours combine and nonexistent hours stay zero |
87
+ | Daily amount-tier count | Population transactions in tier on date | Same explicit tiers for G and B; conserve the daily transaction count |
88
+
89
+ Produce period totals plus one daily record for every date, 24 period-hour counts,
90
+ and date-by-hour counts. Zero-fill counts; do not turn unavailable rates into zero.
91
+ Always include rate numerators and unknown counts. Default tiers are each exact
92
+ selected group amount plus `other`; an optional sorted decimal edge list defines
93
+ half-open bins `[lower, upper)`, with unbounded first/last bins. Record the tier
94
+ scheme and retain all outside-group amounts. Sum tier and hour counts to daily
95
+ and period totals as reconciliation checks. Combined exposure is the union of
96
+ member IDs, never the sum of overlapping group counts.
97
+
98
+ ## Outputs and charts
99
+
100
+ `profile_groups.py` writes schema-versioned JSON containing dataset binding,
101
+ period, census, group scopes/membership, out-group membership, tiers and metrics.
102
+ `render_charts.py` consumes only that saved profile and writes standalone offline
103
+ HTML with SVG charts and accessible data tables. Required paired views are daily
104
+ amount-tier counts, daily success/fraud rates, daily transaction counts, daily
105
+ shares, and 24-hour counts. Include date-by-hour detail and status coverage.
106
+ Use the same axes and tier definitions for both populations; gaps/unknown rates
107
+ remain N/A. Escape source labels as text. No CDN, live FX request or recomputation
108
+ of transaction metrics belongs in rendering. Outputs refuse overwriting existing
109
+ files unless explicitly requested with `--overwrite`.
@@ -0,0 +1,99 @@
1
+ # Patterns
2
+
3
+ Evaluate all three patterns inside the MID/descriptor and currency-view scopes
4
+ in SKILL.md. Record each method's parameters, tested population, coverage and
5
+ exact transaction IDs. Patterns may overlap; one pattern's selection must not
6
+ remove transactions from another pattern's search. Use the same profiling and
7
+ rating workflow for every eligible group. Names describe observations or
8
+ hypotheses, not verified business activity.
9
+
10
+ ## 1. Amount concentration
11
+
12
+ Count exact converted amounts, such as 8.00 or 9.9. Select keys meeting the
13
+ run's declared minimum transaction count and share; record the denominator.
14
+ A single price may qualify without an escalating sequence. No calibrated
15
+ universal concentration threshold is supplied.
16
+
17
+ ## 2. Escalating amounts
18
+
19
+ Look for doubling amounts such as 8 → 16 → 32 → 64. Default to at least three
20
+ levels and 100 transactions; these gates apply only to escalation.
21
+ For positive amounts `a < b`, the adjacent residual is `abs(b - 2*a)`.
22
+ Require it to be within the declared currency-specific absolute cap and strictly
23
+ less than `a/2`: the fit must be closer to 2x than to 1x or 3x. Ties fail.
24
+
25
+ Test a cap sensitivity grid and record the chosen cap per currency. Search upward
26
+ and downward from candidate seeds. A level may retain multiple exact anchors;
27
+ record the additional-anchor support floor. Tolerance selects a finite set of
28
+ amount keys, never every transaction in an interval. Freeze their member IDs.
29
+
30
+ ## 3. Pricing patterns
31
+
32
+ Look for a coherent price menu or retail-price structure, including patterns
33
+ that conversion makes variable in the charge currency. Preserve original charge
34
+ amounts and dates alongside the two converted views.
35
+
36
+ | Form | Evidence to test | Interpretation limit |
37
+ |---|---|---|
38
+ | Preset menu | Repeated prices such as 10, 20, 50, with sufficient support and coverage above a jittered control | A menu need not double; escalation's three-level/100-transaction gates do not apply |
39
+ | FX-converted menu | Dated conversion into a candidate pricing currency makes charges align with supported presets | Inferred pricing currency can differ from both charge currency and BIN-country currency |
40
+ | Retail-like prices | Several distinct prices ending in .99, .95, .98 or .00, possibly after dividing by a fitted constant | A fit does not establish goods, tax, fees or fulfillment |
41
+
42
+ Declare support, coverage, tolerance and control criteria before accepting a
43
+ pricing group. Test candidate currencies and daily drift; BIN-country legal
44
+ tender is a candidate, not proof of pricing currency. For a supported top-up
45
+ hypothesis, use **direct** when inferred pricing currency equals original charge
46
+ currency, and **FX-converted** otherwise. Split mixed charge currencies correctly.
47
+ Do not infer a top-up from the charge currency alone.
48
+
49
+ Fixed amounts are a supplementary feature, not another pattern. Fixed FX needs
50
+ stable charges alongside measured source-to-pricing-currency rate movement and
51
+ adequate day coverage. Same-currency fixed prices do not demonstrate fixed FX;
52
+ untested or raw `live` labels do not establish floating FX.
53
+
54
+ Freeze pricing membership by transaction ID, preserving the matched prices,
55
+ source currencies, dates, inferred currency and fit rule. Unlike concentration
56
+ or escalation, date-varying pricing membership cannot be reconstructed from a
57
+ single converted amount list. Reconcile those IDs into each reporting view's
58
+ eligible partition, report exclusions, and profile each resulting group against
59
+ that partition's out-group. An inferred pricing currency is explanatory evidence,
60
+ not a third reporting view. If country was used to select members, its concentration
61
+ is not independent rating evidence. Keep other/insufficient-evidence rows visible.
62
+
63
+ ## Detection engines
64
+
65
+ The canonical `detect_patterns.py` interface reuses `detect_ladders.py` and
66
+ `detect_streams.py` as internal engines. Their standalone CLIs remain available
67
+ for compatibility, but use the canonical interface in SKILL.md for new runs. The
68
+ canonical manifest preserves member IDs, parameters and diagnostics for all three
69
+ independent detections.
70
+
71
+ Escalation uses prepared converted amounts. Its rung pool requires count >=
72
+ max(5, 0.1% of partition transactions); additional anchors default to 24
73
+ transactions. Each exact key can belong to only one reported ladder per partition;
74
+ below-threshold families do not reserve keys. Other pattern types may overlap.
75
+ Record cap sensitivity and validate keys and counts.
76
+
77
+ Pricing discovery uses original charges once per MID, descriptor, source currency
78
+ and BIN-country group, with at least 80 positive transactions. Zero amounts remain
79
+ available to concentration but provide no pricing support. Freeze discovered IDs,
80
+ then project them into each eligible reporting partition without reapplying the
81
+ 80-row gate. Record projected exclusions. Peak and menu tolerances default to 1.2%
82
+ and 1.5%; all parameters and diagnostics are saved in the manifest.
83
+
84
+ Candidate generation uses the existing float-based heuristic; final retail and
85
+ menu membership use exact rational checks. Quotes, cross-rates and positive source
86
+ amounts must be between 1e-100 and 1e100 inclusive, and converted candidates at least
87
+ 0.005 for the cent-based peak engine. Unsupported inference ranges fail explicitly;
88
+ they are not treated as missing FX. Original decimal values and source/target quote
89
+ strings are retained in evidence. Exact final checks do not make heuristic discovery
90
+ exhaustive. Small groups or missing quotes are not evidence of absent pricing.
91
+
92
+ The optional `--pricing-rates` adapter is JSON of the form
93
+ `{"base":"USD","rates":{"2026-01-01":{"EUR":"0.9"}}}`. Rates are decimal
94
+ strings in units of quote currency per base unit, from validated exact UTC-date
95
+ quotes. No prior-date carry or implicit pegs are used; same-currency conversion
96
+ needs no quote. The detector selects quotes by UTC transaction date, independently
97
+ of the reporting timezone used for profiles. The adapter does not fetch rates
98
+ or convert the prepared reporting views. Retain its provenance and reconcile
99
+ missing quotes; see [fx-conversion.md](fx-conversion.md).