@1aboveio/skills 0.20.2 → 0.20.3

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 (85) hide show
  1. package/README.md +12 -5
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +220 -25
  4. package/runtime/skills/distribution/scripts/bundles.mjs +49 -5
  5. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -0
  6. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
  7. package/skills/compliance/compliance-audit/LICENSE +3 -0
  8. package/skills/compliance/compliance-audit/SKILL.md +466 -0
  9. package/skills/compliance/compliance-audit/references/findings-schema.md +290 -0
  10. package/skills/compliance/compliance-audit/references/vars-checklist.md +1068 -0
  11. package/skills/compliance/compliance-audit/references/vars-findings-schema.md +395 -0
  12. package/skills/compliance/compliance-audit/scripts/reconcile_tracker.py +454 -0
  13. package/skills/compliance/compliance-audit/scripts/test_validate_tracker.py +90 -0
  14. package/skills/compliance/compliance-audit/scripts/validate_tracker.py +752 -0
  15. package/skills/compliance/doc-authenticity/LICENSE +3 -0
  16. package/skills/compliance/doc-authenticity/SKILL.md +158 -0
  17. package/skills/compliance/doc-authenticity/references/agreement.md +66 -0
  18. package/skills/compliance/doc-authenticity/references/bank-statement.md +150 -0
  19. package/skills/compliance/doc-authenticity/references/forensic-signals.md +157 -0
  20. package/skills/compliance/doc-authenticity/references/image-signals.md +114 -0
  21. package/skills/compliance/doc-authenticity/references/invoice.md +66 -0
  22. package/skills/compliance/doc-authenticity/references/issuer-profiles.md +86 -0
  23. package/skills/compliance/doc-authenticity/references/verdict-and-report.md +95 -0
  24. package/skills/compliance/doc-authenticity/references/verdict.schema.json +81 -0
  25. package/skills/compliance/doc-authenticity/scripts/image_forensics.py +294 -0
  26. package/skills/compliance/doc-authenticity/scripts/pdf_forensics.py +401 -0
  27. package/skills/compliance/doc-authenticity/scripts/validate_codes.py +224 -0
  28. package/skills/compliance/doc-authenticity/scripts/validate_verdict.py +308 -0
  29. package/skills/compliance/report-writing/LICENSE +3 -0
  30. package/skills/compliance/report-writing/SKILL.md +206 -0
  31. package/skills/compliance/report-writing/references/audit-report-template.md +121 -0
  32. package/skills/compliance/report-writing/references/external-assessment-template.md +167 -0
  33. package/skills/compliance/report-writing/references/management-report-template.md +145 -0
  34. package/skills/compliance/report-writing/references/vars-report-template.md +224 -0
  35. package/skills/document-utils/doc-to-md/LICENSE +3 -0
  36. package/skills/document-utils/doc-to-md/SKILL.md +77 -0
  37. package/skills/document-utils/doc-to-md/scripts/convert.py +157 -0
  38. package/skills/document-utils/reg-parser/LICENSE +3 -0
  39. package/skills/document-utils/reg-parser/SKILL.md +201 -0
  40. package/skills/document-utils/reg-parser/references/checklist-schema.md +223 -0
  41. package/skills/document-utils/reg-parser/references/checklists/hk-amlo-checklist.json +1306 -0
  42. package/skills/document-utils/reg-parser/references/checklists/hk-amlo-checklist.md +469 -0
  43. package/skills/document-utils/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.json +634 -0
  44. package/skills/document-utils/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.md +233 -0
  45. package/skills/document-utils/reg-parser/references/checklists/hk-mso-guideline-checklist.json +2194 -0
  46. package/skills/document-utils/reg-parser/references/checklists/hk-mso-guideline-checklist.md +771 -0
  47. package/skills/document-utils/reg-parser/references/checklists/kyc-aml-checklist.md +258 -0
  48. package/skills/document-utils/reg-parser/references/checklists/visa-vars-checklist.md +1058 -0
  49. package/skills/document-utils/reg-parser/references/mandates/hk-amlo-cap615.md +389 -0
  50. package/skills/document-utils/reg-parser/references/mandates/visa-vars.md +205 -0
  51. package/skills/document-utils/reg-parser/scripts/compare_checklist.py +228 -0
  52. package/skills/document-utils/reg-parser/scripts/dump_checklist.py +348 -0
  53. package/skills/document-utils/reg-parser/scripts/preprocess-mandate.sh +171 -0
  54. package/skills/document-utils/reg-parser/scripts/test_quarantine.sh +102 -0
  55. package/skills/document-utils/reg-parser/scripts/validate_checklist.py +532 -0
  56. package/skills/document-utils/reg-parser/scripts/validate_mandate.py +242 -0
  57. package/skills/engineering/engineering-runtime/coherence/workflow.json +16 -16
  58. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -0
  59. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
  60. package/skills/payment/similar-domain/LICENSE +3 -0
  61. package/skills/payment/similar-domain/SKILL.md +178 -0
  62. package/skills/payment/similar-domain/references/entities.md +58 -0
  63. package/skills/payment/similar-domain/references/fingerprints.md +82 -0
  64. package/skills/payment/similar-domain/references/pivots.md +66 -0
  65. package/skills/payment/similar-domain/references/report-template.md +76 -0
  66. package/skills/payment/similar-domain/references/scoring.md +61 -0
  67. package/skills/payment/similar-domain/references/terminology.md +37 -0
  68. package/skills/payment/similar-domain/references/workflow.md +79 -0
  69. package/skills/payment/tld-detection/SKILL.md +76 -21
  70. package/skills/payment/tld-detection/references/clean.md +1 -1
  71. package/skills/payment/tld-detection/references/clustering.md +21 -6
  72. package/skills/payment/tld-detection/references/decision.md +7 -2
  73. package/skills/payment/tld-detection/references/fx-conversion.md +229 -0
  74. package/skills/payment/tld-detection/references/report-template.md +63 -27
  75. package/skills/payment/tld-detection/references/streams.md +90 -0
  76. package/skills/payment/tld-detection/references/terminology.md +15 -7
  77. package/skills/payment/tld-detection/references/workflow.md +1 -1
  78. package/skills/payment/tld-detection/scripts/detect_streams.py +542 -0
  79. package/skills/engineering/ensure-coverage/evals/evals.json +0 -125
  80. package/skills/engineering/rush-issues/evals/evals.json +0 -65
  81. package/skills/engineering/rush-release/evals/evals.json +0 -58
  82. package/skills/fullstack/shadcn/evals/evals.json +0 -90
  83. package/skills/payment/fraud-analysis/evals/evals.json +0 -40
  84. package/skills/payment/tld-detection/evals/evals.json +0 -107
  85. package/skills/payment/tld-detection/tests/test_detect_ladders.py +0 -132
@@ -0,0 +1,82 @@
1
+ # Fingerprints
2
+
3
+ What to record for each domain, and why each item identifies the people
4
+ behind it rather than the industry it sits in. Record the value, the source
5
+ you read it from, and the time. Categories are ordered by how much they
6
+ usually pay off.
7
+
8
+ ## Page and tag fingerprints (strongest)
9
+
10
+ These live inside the served HTML. They are set once by whoever configures
11
+ the site and copied across every site that person manages.
12
+
13
+ | Fingerprint | Why it identifies an operator |
14
+ |---|---|
15
+ | Analytics tokens (Cloudflare Web Analytics, Google Analytics / GTM container, Matomo, Yandex) | One account per operator; sharing it across brands is deliberate |
16
+ | Ad and tracking pixels (Meta, TikTok, Snap, affiliate-network pixels) | Tied to a paying advertiser account |
17
+ | Error-monitoring and session-replay keys (Sentry, Hotjar, Clarity, Smartlook) | Per-project keys from one engineering team |
18
+ | Block-page or error-page template: HTML skeleton, CSS reset, odd literal values (a specific outline colour, a min-width), font stack | A shared codebase; brands change the logo and palette, not the skeleton |
19
+ | Support-address pattern (`support@<brand>`) and the domain it points at | A mirror's support address names the parent brand |
20
+ | Hard-coded partner hosts: CDN paths, API hosts, game or payment providers, chat widgets | Platform vendor and integration account |
21
+ | Favicon and logo asset hashes | Reused assets across mirrors |
22
+ | JavaScript bundle names and hashes | Same build pipeline |
23
+ | Cookie names and consent-banner vendor IDs | Same front-end stack |
24
+
25
+ Distinguish **operator-level** identifiers (analytics account, template)
26
+ from **vendor-level** ones (a game provider, a chat widget). Vendor-level
27
+ identifiers narrow the field but are shared across many unrelated
28
+ operators.
29
+
30
+ ## Mail fingerprints (strong)
31
+
32
+ | Fingerprint | Why |
33
+ |---|---|
34
+ | Exact SPF string, including the order of includes | The combination of mail vendors is chosen per operator; a byte-identical string across brands is rarely coincidence |
35
+ | DKIM selectors | Per-sending-account |
36
+ | MX target (Google, Microsoft 365, Zoho, self-hosted) | Splits clusters: an operator rarely runs two mail platforms |
37
+ | Verification TXT records (Microsoft tenant ID, vendor verifications) | Tenant IDs identify one organisation; Google site-verification tokens are per-domain and do not pivot |
38
+ | Mail-related subdomains from certificates (`mailer.`, `click.`, `email.updates.`) | Marketing-mail vendor and its account |
39
+
40
+ ## Registration fingerprints (medium to strong)
41
+
42
+ | Fingerprint | Why |
43
+ |---|---|
44
+ | Registrar plus privacy-proxy service | Operators keep one registrar account per portfolio |
45
+ | Creation and last-updated timestamps | Same-hour timestamps across domains mean one batch action |
46
+ | Status-lock set (the exact combination of prohibited flags) | Set by registrar account defaults |
47
+ | Registrant fields when not private (organisation, country, state) | Direct |
48
+ | Expiry alignment | Renewed together |
49
+
50
+ ## DNS and hosting fingerprints (medium)
51
+
52
+ | Fingerprint | Why |
53
+ |---|---|
54
+ | Nameserver pair | CDN providers assign pairs per account, but reuse pairs across many accounts; strong only combined with something else |
55
+ | Hosting address and ASN when not behind a CDN | Direct, but shared hosting is common |
56
+ | CNAME targets for `www`, `api`, `cdn`, `m` | Names the platform vendor and sometimes the tenant |
57
+ | Subdomain naming from certificate transparency | Platform-specific patterns (`api.`, `cl.`, `evolutiongaming.`) and mirror schemes (`dd20--brand`) |
58
+ | Wildcard certificate issuer and issuance cadence | Same automation |
59
+
60
+ ## Brand and naming fingerprints (candidate generators, not evidence)
61
+
62
+ | Fingerprint | Use |
63
+ |---|---|
64
+ | Name stem and numbering scheme (`brand3`, `brand-9884`, `xx00--brand`) | Enumerate variants in step 3 |
65
+ | Licence seal number and validator link | Pivot into the licence register in step 4 |
66
+ | Legal entity, address, and licence text on the terms page | Entity pivot in step 4 |
67
+ | Affiliate program name | Brand-list pivot in step 4 |
68
+ | Sportsbook or casino platform named in the footer | Vendor-level filter |
69
+
70
+ ## Behaviour fingerprints (supporting)
71
+
72
+ | Fingerprint | Use |
73
+ |---|---|
74
+ | Geo-block behaviour: which countries, what status code, challenge or branded page | Same edge configuration |
75
+ | Redirect chain (`www` to apex, mirror to parent, country path) | Reveals the parent brand |
76
+ | Response headers beyond the CDN defaults | Same origin stack |
77
+
78
+ ## Recording rule
79
+
80
+ Every fingerprint row carries: domain, category, value, source (page,
81
+ DNS, certificate log, WHOIS, archive, review site), and observed-at time.
82
+ A fingerprint without a source cannot be re-checked and cannot be scored.
@@ -0,0 +1,66 @@
1
+ # Pivots
2
+
3
+ A pivot turns a fingerprint into the question "which other domains have
4
+ this value?" and sends it to a source class that can answer. This file
5
+ says which source class fits which fingerprint, what a hit means, and where
6
+ the false positives come from. It does not prescribe tools or commands.
7
+
8
+ ## Source classes
9
+
10
+ | Source class | Answers | Examples of the class |
11
+ |---|---|---|
12
+ | Page-source index | Which pages contain this string (token, CSS literal, hostname) | Code-search engines for HTML, URL scanners with body search, internet-scan datasets with HTTP bodies |
13
+ | Passive DNS | Which domains have or had this nameserver, MX, TXT, CNAME, or address | Commercial passive-DNS services, historical DNS archives |
14
+ | Certificate transparency | Which names appear on certificates, and when | Public CT log search |
15
+ | Reverse WHOIS | Which domains share registrant fields, registrar, or timestamps | Reverse-WHOIS services, registrar-side history |
16
+ | Web archive | What the site served before it was blocked or rebranded | Public web archives, cached copies |
17
+ | Review aggregators | Operator, licence, launch year, affiliate program, complaints | Casino / merchant review directories, complaint forums |
18
+ | Licence register | Every domain licensed under one number or entity | Regulator's public register |
19
+ | Affiliate directory | Every brand an affiliate program pays for | Affiliate-program brand lists, affiliate forums |
20
+ | Ordinary web search | Brand reviews, news, forum threads | General search — note it does not index page source |
21
+
22
+ ## Fingerprint to pivot map
23
+
24
+ | Fingerprint | Pivot to | Hit means | Trap |
25
+ |---|---|---|---|
26
+ | Analytics or pixel token | Page-source index | Same account configured both sites | A token can be scraped and pasted by an affiliate site; check the hit is the brand's own domain, not a review page |
27
+ | Block-page template literal | Page-source index | Same codebase | Framework defaults produce the same reset; pick a literal that is not in any public template |
28
+ | Support-address pattern | Page-source index, web search | Mirror names its parent | None significant |
29
+ | Exact SPF string | Passive DNS | Same mail-vendor set | Single common includes (a lone Google or Microsoft include) match millions of domains; pivot on the full string |
30
+ | Microsoft tenant or vendor verification TXT | Passive DNS | Same organisation tenant | Google site-verification tokens are per domain; they do not pivot |
31
+ | Nameserver pair | Passive DNS | Same CDN account, probably | CDN pairs are reused across accounts; always require a second fingerprint |
32
+ | Hosting address / ASN | Passive DNS, internet-scan dataset | Same origin | Shared hosting; CDN fronting hides the origin entirely |
33
+ | CNAME target | Passive DNS | Same platform tenant | Vendor-level unless the target embeds a tenant name |
34
+ | Subdomain naming scheme | Certificate transparency | Same platform or mirror generator | Scheme may belong to the platform vendor, shared by its unrelated tenants |
35
+ | Registrar + proxy + timestamp | Reverse WHOIS | Same registration batch | Popular registrar-proxy combinations are common; timestamps within minutes are the real signal |
36
+ | Brand name stem | Certificate transparency, web search | Candidate mirror | A name match is a candidate only; confirm with a fingerprint |
37
+ | Licence number | Licence register | Every domain under the licence | Registers lag; a delisted domain is history, not a false link |
38
+ | Legal entity or address | Web search, page-source index (terms pages) | Same operator on paper | Corporate-service addresses are shared by hundreds of unrelated companies |
39
+ | Affiliate program | Affiliate directory | Same marketing arm | Some programs serve several operators |
40
+
41
+ ## Running a pivot
42
+
43
+ 1. State the fingerprint, the source class, and the exact query.
44
+ 2. Record the hit count, even if zero. Zero from a source that cannot see
45
+ the fingerprint (web search for a token) is "not observable", not
46
+ "absent".
47
+ 3. For each hit, note which fingerprint produced it. A domain reached by
48
+ two independent pivots is already close to Confirmed.
49
+ 4. Filter high-noise pivots (nameserver pair, registrar, single mail
50
+ include) by intersecting with the set of hits from a strong pivot before
51
+ any of them becomes a candidate.
52
+ 5. Prefer pivots whose hit count is small. A pivot returning thousands of
53
+ domains is not evidence until narrowed.
54
+
55
+ ## Blocked-site pivots
56
+
57
+ When the live site is unreachable:
58
+
59
+ - Pivot on the block page itself (template, token, support address).
60
+ - Use certificate history for subdomains and mirror schemes.
61
+ - Use web archives for the pre-block or pre-rebrand HTML, which usually
62
+ still carries the same tokens.
63
+ - Use mirrors that are reachable from the analyst's location; they share
64
+ the parent's fingerprints by design.
65
+ - Use review aggregators for the entity chain; they visited the site from
66
+ an allowed location.
@@ -0,0 +1,76 @@
1
+ # Report template
2
+
3
+ Save:
4
+
5
+ ```text
6
+ reports/similar-domain/<seed>_cluster.md
7
+ ```
8
+
9
+ Use the first seed's registrable domain as `<seed>`; for multiple seeds
10
+ use a short scope name the user recognises. No Markdown bold in the report
11
+ body. After writing, grep banned strings in
12
+ [terminology.md](terminology.md).
13
+
14
+ ```markdown
15
+ # Domain cluster — <seed or scope>
16
+
17
+ ## Verdict
18
+ ## Cluster
19
+ ## Evidence matrix
20
+ ## Entity chain
21
+ ## Outliers
22
+ ## Coverage and caveats
23
+ ## Pivot log
24
+ ## Sources
25
+ ```
26
+
27
+ ## Chapter requirements
28
+
29
+ ### Verdict
30
+
31
+ At most three sentences: which domains form a cluster, what the strongest
32
+ evidence is, and which seeds do not belong. No new evidence here.
33
+
34
+ ### Cluster
35
+
36
+ One row per domain, sorted Confirmed → Probable → Possible. Columns: domain,
37
+ brand, role (parent, mirror, acquired brand), label, registered date,
38
+ current operator (if known), strongest two links. Seeds that are Unrelated
39
+ go in Outliers, not here.
40
+
41
+ ### Evidence matrix
42
+
43
+ Domains as rows, fingerprints as columns, cell shows the shared value or a
44
+ short marker. Include at least: analytics account, template, mail string
45
+ or platform, nameserver pair, registrar and proxy, registration timestamp,
46
+ licence or entity. This table is what lets a reader check the labels
47
+ without rerunning the work.
48
+
49
+ ### Entity chain
50
+
51
+ The operator history with dates: entities, licences, migrations, brand
52
+ acquisitions. Present conflicting operator names as a dated sequence. Cite
53
+ the page for each fact.
54
+
55
+ ### Outliers
56
+
57
+ Every seed or candidate that was checked and rejected, with the
58
+ fingerprints that differ. "Different brand" is not a reason; "different
59
+ analytics account, different mail platform, different CDN account" is.
60
+
61
+ ### Coverage and caveats
62
+
63
+ What could not be observed and why: geo-blocks, bot challenges, private
64
+ registration, resolver artefacts, pivots not run for budget reasons,
65
+ source classes not available. State whether the cluster is closed (a full
66
+ pass added nothing) or open.
67
+
68
+ ### Pivot log
69
+
70
+ One row per pivot: fingerprint, source class, query, hit count, domains
71
+ kept. Empty pivots stay in the log; they are what makes a negative result
72
+ credible.
73
+
74
+ ### Sources
75
+
76
+ Every external page cited, as links.
@@ -0,0 +1,61 @@
1
+ # Scoring
2
+
3
+ Weight each link by how hard it is to share by accident, count independent
4
+ signals, and label every domain.
5
+
6
+ ## Link strength
7
+
8
+ | Signal | Strength | Reason |
9
+ |---|---|---|
10
+ | Same analytics, tag-manager, pixel, or error-monitoring account ID | Very strong | One paying account, one admin |
11
+ | Same custom page template with non-default literals | Very strong | Shared codebase |
12
+ | Mirror serves the parent's support address or redirects to it | Very strong | Self-declared |
13
+ | Byte-identical SPF string with three or more vendor includes | Strong | Chosen combination of vendors |
14
+ | Same organisation tenant ID in TXT records | Strong | One tenant |
15
+ | Same registrar + proxy + timestamps within an hour | Strong | One batch action |
16
+ | Licence register lists both domains under one licence | Strong | Authoritative, but lags reality |
17
+ | Same registrar + proxy + identical lock set, days apart | Medium | Same account defaults |
18
+ | Same CDN nameserver pair | Medium | Per account, but pairs are reused |
19
+ | Same origin address or ASN outside a CDN | Medium | Shared hosting is common |
20
+ | Same platform vendor, CNAME target, or subdomain scheme | Weak | Vendor-level |
21
+ | Same affiliate program | Weak to medium | Some programs serve several operators |
22
+ | Same game providers, bonus wording, licence authority | Weak | Industry-wide |
23
+ | Similar brand name | Candidate only | Names are cheap |
24
+
25
+ ## Independence
26
+
27
+ Two signals count as independent only if a different party controls
28
+ each. Examples that count once, not twice: analytics token and block-page
29
+ template (same front-end deployment); nameserver pair and CDN analytics
30
+ token (same CDN account); registrar and proxy service (same registrar
31
+ account). Examples that count separately: analytics token and SPF string;
32
+ registration batch and page template; licence register and mail tenant.
33
+
34
+ ## Labels
35
+
36
+ | Label | Rule |
37
+ |---|---|
38
+ | Confirmed | Two independent strong-or-better signals, or one very strong signal plus any medium one |
39
+ | Probable | One strong or very strong signal, or two independent medium signals, or authoritative register listing without technical confirmation yet |
40
+ | Possible | One medium signal, or vendor-level signals only, or a name-scheme candidate |
41
+ | Unrelated | Checked, and the operator-level fingerprints differ (different analytics accounts, different template, different mail platform, different registrar behaviour) |
42
+
43
+ Only Confirmed and Probable enter the loop as new seeds. Possible domains
44
+ are parked with the one fingerprint that would promote them, so a later
45
+ pass can pick them up.
46
+
47
+ ## Negative evidence
48
+
49
+ A domain can share medium signals and still be Unrelated. Different mail
50
+ platforms, different CDN accounts, different analytics accounts, and a
51
+ registration years apart together outweigh a shared nameserver pair or
52
+ shared licence authority. Say so explicitly in the outliers section
53
+ rather than leaving the domain unlabelled.
54
+
55
+ ## Conflicts
56
+
57
+ When technical evidence and corporate evidence disagree, report both and
58
+ date them. Continuous technical evidence across a corporate break usually
59
+ means an entity swap on one platform; continuous corporate evidence across
60
+ a technical break usually means a platform migration. Neither breaks the
61
+ cluster; both belong in the entity chain.
@@ -0,0 +1,37 @@
1
+ # Terminology
2
+
3
+ | Term | Meaning in this skill |
4
+ |---|---|
5
+ | Seed | A domain the user supplied or a Confirmed/Probable domain fed back into the loop |
6
+ | Fingerprint | Any identifier on a domain that is not the brand name and can be shared across domains |
7
+ | Pivot | A reverse query: "which other domains carry this fingerprint?" |
8
+ | Candidate | A domain returned by a pivot or a name scheme, not yet scored |
9
+ | Cluster | The set of Confirmed and Probable domains linked by operator-level fingerprints |
10
+ | Operator-level | A fingerprint tied to one paying account or one codebase (analytics ID, template, mail tenant) |
11
+ | Vendor-level | A fingerprint tied to a platform many operators use (game provider, CDN, chat widget) |
12
+ | Mirror | A domain serving or redirecting to a parent brand to evade blocking, usually numbered or hyphenated |
13
+ | Entity chain | The dated sequence of legal operators, licences, and migrations behind a brand |
14
+ | Closed cluster | A full loop pass added no domain |
15
+ | Open cluster | Expansion stopped for budget or access reasons; unexplored pivots are listed |
16
+
17
+ ## Language
18
+
19
+ - Say "linked", "shares", "same account", "same template" for technical
20
+ evidence. Say "operated by", "licensed to" only with a cited entity
21
+ source.
22
+ - Say "not observable" when a source class cannot see the fingerprint;
23
+ say "absent" only when a source that can see it returned nothing.
24
+ - Say "Unrelated on current evidence" rather than "unrelated"; the
25
+ negative is bounded by the pivots run.
26
+ - Name the source class, not a product, when describing what was queried,
27
+ unless the user asked for the tool.
28
+
29
+ ## Banned strings in the report body
30
+
31
+ - "owned by" or "same company" without an entity citation in the same
32
+ paragraph
33
+ - "confirmed" applied to ownership (Confirmed is a label for a link, not a
34
+ legal finding)
35
+ - "definitely", "certainly", "no doubt"
36
+ - "unrelated" without "on current evidence" or an outliers row
37
+ - Any fingerprint value presented without a source
@@ -0,0 +1,79 @@
1
+ # Workflow detail
2
+
3
+ SKILL.md is the index. This file is the procedure those steps run.
4
+
5
+ ## Input
6
+
7
+ One or more **seed domains** (bare domain or URL) and the question behind
8
+ them. Typical questions:
9
+
10
+ | Question | What the cluster must answer |
11
+ |---|---|
12
+ | "Are these domains related?" | Which seeds share an operator, and on what evidence |
13
+ | "Who is behind this site?" | Entity chain with dates and licence |
14
+ | "Find the mirrors / sister sites" | Every domain the same operator runs, labelled by confidence |
15
+ | "Merchant background check" | Cluster plus history: licence changes, operator migrations, complaints |
16
+
17
+ Optional context that changes the work: a transaction file whose descriptor
18
+ URL is the seed, a date range, a jurisdiction of interest, or a list of
19
+ domains the user already believes are related (treat that list as
20
+ hypotheses, not facts).
21
+
22
+ ## Access limits
23
+
24
+ Expect at least one of these on every gambling, adult, crypto, or
25
+ high-risk-merchant seed:
26
+
27
+ - **Geo-block page** (403 with a branded page) — the page itself is a
28
+ fingerprint: template, analytics token, support address, favicon.
29
+ - **Bot challenge** (Cloudflare "Just a moment") — nothing behind it is
30
+ visible; use subdomains, certificate history, archives, and mirrors
31
+ instead.
32
+ - **Private registration** — the proxy service, registrar, dates, and lock
33
+ set are still visible and still cluster.
34
+ - **Local resolver artefacts** — a VPN or proxy on the analyst machine can
35
+ return fake addresses (for example the 198.18.0.0/15 range). Do not use
36
+ those as hosting fingerprints; use nameservers, certificates, and
37
+ third-party passive DNS instead.
38
+
39
+ Record each limit in the report's coverage caveats.
40
+
41
+ ## Order that must not move
42
+
43
+ Fingerprint → pivot → expand names → entity → score → loop → report.
44
+
45
+ Fingerprint the seed completely before running any pivot. Pivots run on
46
+ fingerprints, not on brand names; the name scheme (step 3) is a candidate
47
+ generator that must be confirmed by a fingerprint. Entity research (step 4)
48
+ names and dates the cluster but never adds a domain that has no technical
49
+ link unless a licence register or the operator's own terms page lists it
50
+ explicitly. Scoring (step 5) happens before a domain enters the loop, so the
51
+ loop never expands on a Possible.
52
+
53
+ ## Loop discipline
54
+
55
+ Each pass:
56
+
57
+ 1. Take every domain labelled Confirmed or Probable that has not yet been
58
+ fingerprinted.
59
+ 2. Fingerprint it fully (step 1).
60
+ 3. Pivot on any fingerprint not already pivoted (step 2). Skip pivots whose
61
+ result is already known from an earlier pass.
62
+ 4. Score new candidates (step 5).
63
+
64
+ Stop when a full pass adds no domain, or when the user's question is
65
+ answered and the remaining candidates are mirrors of brands already in the
66
+ cluster. State the stop reason in the report.
67
+
68
+ Set a budget before starting: a cluster of a large offshore operator can
69
+ run past a hundred domains. When the budget is hit, report the cluster as
70
+ "open" and list the unexplored pivots.
71
+
72
+ ## What counts as done
73
+
74
+ - Every seed has a label and a row in the evidence matrix.
75
+ - Every non-seed member has at least one fingerprint link to a seed or to
76
+ another Confirmed member.
77
+ - The entity chain explains the cluster's history where sources allow.
78
+ - Outliers (seeds that did not join) are explained by absence of shared
79
+ fingerprints, not just by a different brand.
@@ -1,11 +1,14 @@
1
1
  ---
2
2
  name: tld-detection
3
3
  description: >
4
- Explicit-only. Potential TLD (transaction-laundering) clusters from
5
- descriptor partitions, then exact currency-amount pairs, with same-descriptor
6
- baseline contrasts, high/medium/low risk tiers, exposure sizing, and a
7
- ≤3-sentence decision.
8
- Not payment-analysis or fraud-analysis.
4
+ Explicit-only. Potential TLD (transaction-laundering) clusters from an
5
+ authorization extract: stream inference first (wallet currency, preset
6
+ menus, frozen-rate batches, retail constants per descriptor and BIN-country
7
+ group), then exact original-currency amount pairs plus a separate
8
+ BIN-country base-currency FX sensitivity when requested or indicated, with
9
+ same-stream or same-descriptor baseline contrasts, high/medium/low risk
10
+ tiers, exposure sizing, and a ≤3-sentence decision.
11
+ Not payment-analysis, fraud-analysis, or website research (similar-domain).
9
12
  disable-model-invocation: true
10
13
  ---
11
14
 
@@ -15,11 +18,23 @@ Find **potential TLD clusters** in an authorization extract. TLD here is
15
18
  transaction laundering, not a domain name: hidden activity stuffed under a
16
19
  normal MCC, often mixed across descriptors.
17
20
 
18
- First partition the cleaned authorizations by **descriptor**. Inside each
19
- descriptor, the clustering key is the **currency-amount-pair**. Geometric
20
- relationships between exact anchors are the stuffing signal (掺量). BIN
21
- country is not a membership key; report it in the cluster-versus-baseline
22
- comparison after membership is frozen.
21
+ First partition the cleaned authorizations by **descriptor**, then infer the
22
+ **streams** inside each descriptor: a billing name is not a merchant, and one
23
+ descriptor can carry a casino cashier, a shop checkout and a generated batch
24
+ at once. Inside each stream, the clustering key is the
25
+ **currency-amount-pair**. Geometric relationships between exact anchors are
26
+ the stuffing signal (掺量) for traffic priced in the processing currency;
27
+ cashier menus converted live from a wallet currency do not form exact
28
+ ladders and are found by stream inference instead. BIN country is not a
29
+ membership key; report it in the cluster-versus-baseline comparison after
30
+ membership is frozen.
31
+
32
+ The original-currency run is canonical. When the user requests home/base-
33
+ currency detection, or when date-varying transaction amounts may conceal fixed
34
+ prices in card-origin currencies, add the separate BIN-country base-currency
35
+ FX sensitivity in [references/fx-conversion.md](references/fx-conversion.md).
36
+ Never merge its `FXC*` membership, exposure, or risk tiers into canonical
37
+ `C*` results.
23
38
 
24
39
  **Produce:** cluster results and a separate run-specific methodology document
25
40
  under `reports/tld-detection/`.
@@ -37,8 +52,9 @@ Follow these steps in order. Detail:
37
52
  |---|---|---|
38
53
  | 0 Pre-flight | File, grain, columns, window | Stop if auth grain, descriptor, amount, or currency column is missing; caption missing BIN country |
39
54
  | 1 Clean | Dedup | Record drop counts; do not filter BIN country |
40
- | 2 Cluster | Partition; rank pairs; identify anchors; freeze exact keys; compare with same-descriptor baseline | Partition = descriptor; ≥3 levels; adjacent levels = 2x; ≥100 attempts; absolute residual cap per candidate currency |
41
- | 3 Risk | Assign high/medium/low investigation priority | Mixed BIN countries are neutral; exact 100% single-country concentration is a standout |
55
+ | 1b Streams | Infer wallet currency, preset menu, frozen-rate batches, retail lists per descriptor and BIN-country group with `scripts/detect_streams.py` | Every stream label carries coverage, day drift, scheme share; off-menu remainder is reported, never dropped |
56
+ | 2 Cluster | Run canonical original-currency detection inside each stream; add the separate FX sensitivity when applicable; freeze exact keys; compare with the same-stream baseline (same-descriptor when the descriptor has one stream) | Partition = descriptor, sub-partitioned by stream; ≥3 levels; adjacent levels = 2x; ≥100 attempts; absolute residual cap per candidate currency |
57
+ | 3 Risk | Assign high/medium/low investigation priority | In canonical results, Mixed BIN countries are neutral and exact 100% single-country concentration is a standout; FX concentration is descriptive only and cannot raise tier |
42
58
  | 4 Decision | Conclusion + basis for the book | ≤3 sentences; no new evidence |
43
59
  | 5 Report | Answer highest-risk, cluster-characteristic, and exposure questions; write + proofread | Sort high → medium → low; no confirmed-TLD wording |
44
60
 
@@ -51,7 +67,20 @@ column aliases: [workflow.md](references/workflow.md).
51
67
  ### 1 — Clean
52
68
 
53
69
  [references/clean.md](references/clean.md). Deduplicate first. Do not
54
- FX-convert the clustering key. Do not drop non-US BIN rows.
70
+ FX-convert the canonical clustering key. Do not drop non-US BIN rows.
71
+
72
+ ### 1b — Streams
73
+
74
+ [references/streams.md](references/streams.md). Run
75
+ `scripts/detect_streams.py` on the cleaned universe with a daily FX cache.
76
+ It converts each charge into candidate wallet currencies (the card country's
77
+ legal tender, EUR, USD, GBP, CHF), finds the values charges pile up on, and
78
+ peels each descriptor-country group into streams: a wallet-currency preset
79
+ menu (10-scheme or 12-scheme), a retail price list times one constant, a
80
+ frozen-rate batch, or off-menu. Streams are the unit for the behaviour
81
+ contrast (repeat cards, retry after decline, hour concentration, address
82
+ verification, 3-D Secure) and for the same-descriptor baseline in step 2.
83
+ A descriptor with several streams is several upstreams; say so.
55
84
 
56
85
  ### 2 — Cluster
57
86
 
@@ -68,14 +97,27 @@ and amount; keep only clusters with ≥100 authorization attempts. Compare each
68
97
  cluster with the baseline formed by removing that cluster from the same
69
98
  descriptor. Do not invent clusters from MCC or comparison features.
70
99
 
100
+ If the FX sensitivity applies, run it only after the cleaned universe and
101
+ canonical partitions are frozen. Follow
102
+ [references/fx-conversion.md](references/fx-conversion.md) and its mandated
103
+ Frankfurter v2 request/cache contract. Within each frozen canonical descriptor
104
+ partition, `|P_FX|` is only its exact-date-converted attempts; use only `P_FX`
105
+ for FX high-count and rung-pool thresholds and the FX same-descriptor baseline.
106
+ Excluded rows stay outside FX detection and appear only in exclusion coverage
107
+ and reconciliation to canonical `U`. Use `FXC1`, `FXC2`, ... ids and publish
108
+ separate result and methodology files. Because BIN country constructs the
109
+ target currency in this view, country concentration, including 100%, is
110
+ descriptive only and cannot raise the FX tier.
111
+
71
112
  ### 3 — Risk
72
113
 
73
114
  [references/decision.md](references/decision.md). Assign every identified
74
115
  currency-amount pair exactly one investigation-priority tier: High, Medium,
75
- or Low. BIN-country mixture is neutral and never downgrades a cluster. Treat
76
- an exact 100% single-BIN-country cluster as a standout; separately report the
77
- cluster's share of that descriptor-country slice without using an arbitrary
78
- coverage threshold or risk points.
116
+ or Low. In canonical results, BIN-country mixture is neutral and exact 100%
117
+ single-country concentration is a standout; separately report descriptor-
118
+ country slice coverage without a threshold or risk points. In FX results,
119
+ country concentration remains descriptive because it constructs the target
120
+ currency and is not independent risk evidence.
79
121
 
80
122
  ### 4 — Decision
81
123
 
@@ -84,7 +126,10 @@ book. A one-line table per cluster is allowed under that.
84
126
 
85
127
  ### 5 — Report
86
128
 
87
- [references/report-template.md](references/report-template.md). Terms:
129
+ [references/report-template.md](references/report-template.md). The cluster
130
+ report opens with the stream table (one row per stream: label, attempts,
131
+ share, countries, behaviour), because the reader needs to know how many
132
+ upstreams share the descriptor before reading any cluster. Terms:
88
133
  [references/terminology.md](references/terminology.md).
89
134
 
90
135
  ```text
@@ -112,6 +157,7 @@ Track a task plan. One item is `in_progress` at a time.
112
157
 
113
158
  1. Pass pre-flight
114
159
  2. Freeze cleaned universe and descriptor partitions
160
+ 2b. Run stream inference and record streams per descriptor
115
161
  3. Assign High / Medium / Low risk tiers
116
162
  4. Publish descriptor currency-amount pairs + same-descriptor baselines
117
163
  5. Write ≤3-sentence decision
@@ -121,7 +167,8 @@ Track a task plan. One item is `in_progress` at a time.
121
167
 
122
168
  | Need | Skill |
123
169
  |---|---|
124
- | Potential TLD clusters, currency-amount pairs, stuffing / 掺量, MCC miscoding, descriptor mixing | `tld-detection` |
170
+ | Potential TLD clusters, currency-amount pairs, stuffing / 掺量, MCC miscoding, descriptor mixing, upstream streams behind one descriptor | `tld-detection` |
171
+ | Which websites, mirrors and operators sit behind a merchant domain | `similar-domain` |
125
172
  | Volume, journey Sankey, auth rate, decline mix, settlement overview | `payment-analysis` |
126
173
  | Proxy/confirmed fraud labels, holdout precision/recall, rule packages | `fraud-analysis` |
127
174
 
@@ -134,7 +181,9 @@ rule package.
134
181
  |---|---|
135
182
  | Grain, columns, window | [workflow.md](references/workflow.md) |
136
183
  | Dedup | [clean.md](references/clean.md) |
184
+ | Wallet currency, preset menus, frozen-rate batches, retail constants, behaviour metrics | [streams.md](references/streams.md) |
137
185
  | Currency-amount pairs, anchors, same-descriptor baseline | [clustering.md](references/clustering.md) |
186
+ | BIN-country base-currency FX sensitivity | [fx-conversion.md](references/fx-conversion.md) |
138
187
  | ≤3-sentence conclusion | [decision.md](references/decision.md) |
139
188
  | Report chapters | [report-template.md](references/report-template.md) |
140
189
  | Language / banned strings | [terminology.md](references/terminology.md) |
@@ -143,7 +192,13 @@ rule package.
143
192
 
144
193
  - [ ] Auth grain; dedup counts are stated; no BIN-country row filter
145
194
  - [ ] Partition key is normalized descriptor; missing descriptor is an explicit bucket
195
+ - [ ] Stream inference ran; each descriptor lists its streams with coverage, scheme, drift and behaviour, and the off-menu remainder
196
+ - [ ] A frozen-rate stream is reported as generated traffic evidence, not as player deposits
146
197
  - [ ] Clustering key is original currency + amount, not USD
198
+ - [ ] Canonical `C*` results use original amounts; any FX run is separate, uses `FXC*` ids, and does not alter canonical membership or exposure
199
+ - [ ] FX run records as-of-date country→legal-tender mapping, the versioned immutable Frankfurter v2 exact-date request/cache facts, formula, minor-unit rounding, exclusions, and converted-universe coverage
200
+ - [ ] Within each frozen descriptor, `|P_FX|` contains only exact-date-converted attempts; FX thresholds and same-descriptor baselines use only `P_FX`, while exclusions reconcile only to canonical `U`
201
+ - [ ] FX country concentration is descriptive only because BIN country constructs the target currency; it does not independently raise risk
147
202
  - [ ] Each rung-pool currency has an explicit adjacent absolute-residual cap and sensitivity evidence
148
203
  - [ ] Multi-anchor levels state their portfolio support floor; final membership uses exact selected amount keys
149
204
  - [ ] Cluster attempts ≥100
@@ -151,9 +206,9 @@ rule package.
151
206
  - [ ] Currency-amount pairs show seed and representative anchors; `*` marks a multi-amount level
152
207
  - [ ] Same amount pair may recur across descriptor partitions; never merge them automatically
153
208
  - [ ] BIN country is post-membership reporting data, not a membership key; Mixed is neutral
154
- - [ ] Exact 100% single-country concentration is a standout; descriptor-country coverage is shown without a risk threshold
209
+ - [ ] Canonical exact 100% single-country concentration is a standout; FX concentration is descriptive only; descriptor-country coverage has no risk threshold
155
210
  - [ ] Each cluster baseline is the same descriptor after removing that cluster
156
- - [ ] Definition summary contains only descriptor, seed, anchors, and attempts
211
+ - [ ] Each cluster uses one consolidated profile/comparison table; descriptor, seed, anchors, attempts, descriptor totals/share, MCC, and baseline metrics are not repeated in separate definition/characteristic/metric tables
157
212
  - [ ] Anchor table reports attempts, authorization success rate, and suspected-fraud share for every level, including n < 30
158
213
  - [ ] Characteristics contain descriptor total, cluster attempts/share, MCC, and cluster-vs-baseline auth rate, suspected-fraud share, top 3 banks, and top 3 BIN countries
159
214
  - [ ] Decision prose is ≤3 sentences (conclusion + basis)
@@ -26,7 +26,7 @@ the run. Do not invent a customer id from BIN + amount.
26
26
 
27
27
  ## 3. Amount and currency
28
28
 
29
- - Clustering key uses the **original** amount and currency.
29
+ - The canonical clustering key uses the **original** amount and currency. A BIN-country base-currency sensitivity may derive a separate key only after this cleaned universe is frozen; see [fx-conversion.md](fx-conversion.md).
30
30
  - Normalize `10`, `10.0`, `10.00` to the same decimal key.
31
31
  - Drop rows with missing amount or currency; count them.
32
32
  - Do not FX-convert before clustering. A 9.99 EUR rung is not a 9.99 USD
@@ -5,6 +5,14 @@ as **approximate geometric ladders** inside each descriptor, then decompose
5
5
  each qualifying ladder into BIN-country attribution components and contrast
6
6
  it against the remainder.
7
7
 
8
+ ## Streams first
9
+
10
+ Run [streams.md](streams.md) before ranking pairs. When a descriptor carries
11
+ several streams, treat each stream as the partition for rung pools, ladders
12
+ and the baseline; report descriptor totals alongside. Exact-key detection
13
+ finds frozen-rate batches (they are exact, geometric and repeated); it does not
14
+ find live-converted menus, which stream inference reports as menu streams.
15
+
8
16
  ## Descriptor partition
9
17
 
10
18
  Partition key = `normalized descriptor`.
@@ -26,7 +34,10 @@ fraud rates, and local-hour shapes as attribution components.
26
34
 
27
35
  ## Currency-amount-pair
28
36
 
29
- Key = (`currency`, `amount`) on the original (not FX-converted) amount.
37
+ Key = (`currency`, `amount`) on the original (not FX-converted) amount. This is
38
+ the canonical key. A requested BIN-country base-currency analysis is a separate
39
+ sensitivity under [fx-conversion.md](fx-conversion.md), never a replacement for
40
+ or input to canonical membership.
30
41
 
31
42
  Count = authorization **attempts** in the current partition. Rank
32
43
  descending by count. Ties: smaller amount first, then currency code.
@@ -195,10 +206,13 @@ authorization, suspected-fraud, issuing-bank, date, and local-hour behavior as
195
206
  independent characteristics under thresholds declared in the run methodology.
196
207
 
197
208
  For each Top 3 cluster BIN country, report both its share of the cluster and
198
- the cluster's share of all attempts in the same descriptor-country slice. An
199
- exact 100% single-country cluster is a standout. `Mixed` is neutral, and
200
- country-slice coverage is descriptive only: do not set a universal threshold
201
- or award risk points for values such as 20% or 33.8%.
209
+ the cluster's share of all attempts in the same descriptor-country slice. In
210
+ the canonical original-currency run only, an exact 100% single-country cluster
211
+ is a standout. `Mixed` is neutral, and country-slice coverage is descriptive
212
+ only: do not set a universal threshold or award risk points for values such as
213
+ 20% or 33.8%. In the FX sensitivity, even 100% concentration is descriptive,
214
+ must be captioned as constructed by the target-currency mapping, and cannot
215
+ raise the FX tier.
202
216
 
203
217
  ## What not to do
204
218
 
@@ -206,9 +220,10 @@ or award risk points for values such as 20% or 33.8%.
206
220
  - Do not discover ladders across descriptor boundaries.
207
221
  - Do not use BIN country as a ladder partition or membership key.
208
222
  - Do not k-means the amounts.
209
- - Do not convert to USD and then look for ladders.
223
+ - Do not convert to USD or another currency and use that result as the canonical ladder run. Keep any BIN-country base-currency detection in the separate FX sensitivity.
210
224
  - Do not search only upward from the busiest rung.
211
225
  - Do not use a percentage tolerance across amounts.
226
+ - Do not turn stream inference into cluster membership: its relative tolerance is discovery in the wallet currency; canonical membership stays exact on original currency and amount.
212
227
  - Do not assign every amount inside an interval; select finite exact anchors first.
213
228
  - Do not retain a low-support additional anchor merely because it is near a primary anchor.
214
229
  - Do not report a cluster with fewer than three theoretical levels.