@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.
- package/.codex-plugin/plugin.json +1 -1
- package/.codex-plugin/resources.json +297 -216
- package/README.md +3 -3
- package/package.json +10 -8
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/android-foundation/SKILL.md +35 -37
- package/skills/app-dev/android-foundation/references/delivery-focus.md +4 -2
- package/skills/app-dev/android-foundation/references/feature-work.md +50 -0
- package/skills/app-dev/android-foundation/references/setup.md +24 -9
- package/skills/app-dev/android-foundation/references/workspace.md +81 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/SKILL.md +15 -10
- package/skills/app-dev/ios-foundation/references/setup.md +25 -9
- package/skills/app-dev/ios-foundation/references/workspace.md +82 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/xai-search/SKILL.md +1 -1
- package/skills/core/distill-writing/SKILL.md +3 -3
- package/skills/core/distill-writing/references/extraction.md +1 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/editorial-review/SKILL.md +82 -12
- package/skills/core/editorial-review/references/checklist.md +26 -1
- package/skills/core/house-style/SKILL.md +8 -3
- package/skills/core/house-style/references/analytical-reporting.md +123 -0
- package/skills/core/house-style/references/analytical-writing-patterns.md +79 -0
- package/skills/core/house-style/references/analytical-writing-research.md +129 -0
- package/skills/core/{write-doc → house-style}/references/bilingual.md +7 -5
- package/skills/core/house-style/references/definitions-and-metrics.md +86 -0
- package/skills/core/house-style/references/document-workflow.md +193 -0
- package/skills/core/house-style/references/initialization.md +66 -0
- package/skills/core/house-style/references/persistence.md +9 -4
- package/skills/core/house-style/references/rules.md +11 -4
- package/skills/core/house-style/scripts/init-guidance.mjs +213 -0
- package/skills/core/house-style/templates/analytical-report.md +54 -0
- package/skills/core/house-style/templates/gap-analysis.md +1 -1
- package/skills/core/plain-language/SKILL.md +2 -2
- package/skills/core/polish-cn/SKILL.md +9 -2
- package/skills/core/reg-parser/SKILL.md +3 -3
- package/skills/core/terminology/SKILL.md +8 -4
- package/skills/core/write-doc/SKILL.md +40 -151
- package/skills/core/write-report/SKILL.md +129 -0
- package/skills/core/{write-doc → write-report}/references/compliance-reports.md +4 -4
- package/skills/engineering/better-review/SKILL.md +37 -37
- package/skills/engineering/better-review/references/passes.md +35 -41
- package/skills/engineering/better-review/references/result.md +10 -9
- package/skills/engineering/e2e-test/SKILL.md +17 -17
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +11 -13
- package/skills/engineering/e2e-test/references/presentation-sweep.md +7 -7
- package/skills/engineering/e2e-test/references/reviewing.md +9 -11
- package/skills/engineering/e2e-test/references/route-manifest.md +1 -1
- package/skills/engineering/engineering/SKILL.md +124 -0
- package/skills/engineering/engineering/references/engineering-conventions.md +32 -0
- package/skills/engineering/engineering/references/feature-delivery.md +8 -0
- package/skills/engineering/engineering/references/init-scope.md +37 -0
- package/skills/engineering/engineering/scripts/init.mjs +160 -0
- package/skills/engineering/{contributing → engineering}/scripts/persist-conventions.mjs +1 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +19 -19
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
- package/skills/engineering/ensure-coverage/SKILL.md +22 -109
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +7 -5
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +4 -4
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +3 -3
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +4 -65
- package/skills/engineering/ensure-coverage/references/depth/grading.md +5 -7
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +6 -12
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +1 -1
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +6 -6
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +7 -23
- package/skills/engineering/ensure-coverage/references/process/output-template.md +18 -133
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +7 -12
- package/skills/engineering/ensure-coverage/scripts/README.md +12 -4
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/SKILL.md +3 -1
- package/skills/engineering/harness-runtime/bin/workspaces.mjs +52 -0
- package/skills/engineering/harness-runtime/native-workspace.mjs +239 -0
- package/skills/engineering/harness-runtime/references/workspaces.md +78 -0
- package/skills/engineering/harness-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/engineering/resolve-issues/SKILL.md +40 -61
- package/skills/engineering/resolve-issues/references/ci.md +13 -3
- package/skills/engineering/resolve-issues/references/delivery-progress.md +4 -3
- package/skills/engineering/resolve-issues/references/done.md +11 -2
- package/skills/engineering/resolve-issues/references/expire.md +9 -2
- package/skills/engineering/resolve-issues/references/implementation.md +33 -17
- package/skills/engineering/resolve-issues/references/preflight.md +3 -1
- package/skills/engineering/resolve-issues/references/principles.md +52 -0
- package/skills/engineering/resolve-issues/references/review.md +25 -15
- package/skills/engineering/resolve-issues/references/task-plan.md +64 -27
- package/skills/engineering/resolve-issues/references/workspaces.md +164 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +185 -317
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +44 -7
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +36 -2
- package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +9 -8
- package/skills/engineering/resolve-issues/scripts/workspace-lifecycle.mjs +1 -0
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/rush-issues/SKILL.md +7 -5
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/test-quality/SKILL.md +19 -4
- package/skills/engineering/test-quality/references/lint.md +1 -1
- package/skills/engineering/test-quality/references/principles.md +2 -2
- package/skills/engineering/test-quality/references/testing-conventions.md +1 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +4 -8
- package/skills/risk-compliance/compliance-audit/references/audience-and-reports.md +12 -0
- package/skills/risk-compliance/contract-compare/SKILL.md +17 -1
- package/skills/risk-compliance/contract-review/SKILL.md +6 -1
- package/skills/risk-compliance/contract-review/references/report-stage.md +17 -0
- package/skills/risk-compliance/doc-authenticity/SKILL.md +11 -1
- package/skills/risk-compliance/fraud-detection/LICENSE +3 -0
- package/skills/risk-compliance/fraud-detection/SKILL.md +148 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/first-party-fraud.md +3 -2
- package/skills/risk-compliance/fraud-detection/references/archetypes/third-party-fraud.md +47 -0
- package/skills/risk-compliance/fraud-detection/references/collection-payout-features.md +151 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/contexts/bank-transfer.md +4 -3
- package/skills/risk-compliance/fraud-detection/references/contexts/card-payment.md +70 -0
- package/skills/risk-compliance/fraud-detection/references/contexts/payment-collection.md +34 -0
- package/skills/risk-compliance/fraud-detection/references/contexts/payout.md +34 -0
- package/skills/risk-compliance/fraud-detection/references/enrichment.md +74 -0
- package/skills/risk-compliance/fraud-detection/references/entities.md +48 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/feature-engineering.md +69 -33
- package/skills/risk-compliance/fraud-detection/references/feature-sql.md +150 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-rationale.md +4 -2
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-template.md +45 -23
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/review-checklist.md +60 -20
- package/skills/risk-compliance/fraud-detection/references/workflow.md +216 -0
- package/skills/risk-compliance/fraud-detection/release-check.mjs +95 -0
- package/skills/risk-compliance/payment-analysis/SKILL.md +36 -17
- package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +2 -2
- package/skills/risk-compliance/payment-analysis/references/report-template.md +10 -2
- package/skills/risk-compliance/payment-analysis/references/visualization.md +11 -1
- package/skills/risk-compliance/portfolio-payment-analysis/LICENSE +3 -0
- package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +170 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/identity-and-reconciliation.md +46 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/metrics-and-reporting.md +170 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/risk-history.md +89 -0
- package/skills/risk-compliance/portfolio-payment-analysis/release-check.mjs +95 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/analyze.py +636 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/build_report.py +386 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/comparison_charts.py +425 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/csv_export.py +52 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/render.py +160 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/risk_history.py +435 -0
- package/skills/risk-compliance/similar-domain/SKILL.md +9 -4
- package/skills/risk-compliance/tld-detection/SKILL.md +124 -239
- package/skills/risk-compliance/tld-detection/agents/openai.yaml +1 -1
- package/skills/risk-compliance/tld-detection/references/clean.md +18 -51
- package/skills/risk-compliance/tld-detection/references/fx-conversion.md +56 -219
- package/skills/risk-compliance/tld-detection/references/metric-contract.md +109 -0
- package/skills/risk-compliance/tld-detection/references/pattern.md +99 -0
- package/skills/risk-compliance/tld-detection/references/report-template.md +49 -272
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +46 -13
- package/skills/risk-compliance/tld-detection/scripts/detect_patterns.py +346 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +51 -19
- package/skills/risk-compliance/tld-detection/scripts/profile_groups.py +109 -0
- package/skills/risk-compliance/tld-detection/scripts/render_charts.py +218 -0
- package/skills/risk-compliance/tld-detection/scripts/tld_common.py +243 -0
- package/skills/engineering/contributing/SKILL.md +0 -70
- package/skills/risk-compliance/fraud-analysis/SKILL.md +0 -114
- package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +0 -27
- package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +0 -30
- package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +0 -20
- package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +0 -20
- package/skills/risk-compliance/fraud-analysis/references/workflow.md +0 -175
- package/skills/risk-compliance/tld-detection/references/chinese-polish.md +0 -55
- package/skills/risk-compliance/tld-detection/references/clustering.md +0 -235
- package/skills/risk-compliance/tld-detection/references/decision.md +0 -189
- package/skills/risk-compliance/tld-detection/references/streams.md +0 -141
- package/skills/risk-compliance/tld-detection/references/terminology.md +0 -95
- package/skills/risk-compliance/tld-detection/references/workflow.md +0 -95
- /package/skills/{engineering/contributing → core/write-report}/LICENSE +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/audit-report-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/external-assessment-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/management-report-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/vars-report-template.md +0 -0
- /package/skills/{engineering/contributing → core/write-report}/release-check.mjs +0 -0
- /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/LICENSE +0 -0
- /package/skills/engineering/{contributing → engineering}/references/tracker-conventions.md +0 -0
- /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/release-check.mjs +0 -0
- /package/skills/engineering/{contributing → engineering}/scripts/persist-conventions-core.mjs +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/authorized-payment-scam.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/mechanisms/account-takeover.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/taxonomy.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/terminology.md +0 -0
|
@@ -1,232 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Reproducible currency views
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
##
|
|
11
|
+
## Frankfurter v2 acquisition
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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>"es=<comma-separated-currencies>&expand=providers
|
|
50
21
|
GET https://api.frankfurter.dev/v2/rates?from=<YYYY-MM-DD>&to=<YYYY-MM-DD>&base=<P>"es=<comma-separated-currencies>&expand=providers&providers=<comma-separated-provider-keys>
|
|
51
22
|
```
|
|
52
23
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
(
|
|
51
|
+
converted = a / rate(d, P→S) × rate(d, P→T)
|
|
176
52
|
```
|
|
177
53
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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).
|