@1aboveio/skills 0.20.2 → 0.20.4

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 +14 -6
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +220 -25
  4. package/runtime/skills/distribution/scripts/bundles.mjs +167 -48
  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,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 1AboveIO
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: doc-authenticity
3
+ version: 0.4.0
4
+ description: "Screen PDF documents and raster images for fabrication, tampering, Photoshop or other image-editor use, and content validity. Detects file type, runs format-specific authenticity forensics, classifies bank statements, conversation logs, invoices, agreements, and other documents, then applies type-specific validity checks. Produces separate authenticity (NO_EVIDENCE_OF_MODIFICATION / SUSPICIOUS / LIKELY_MODIFIED / INCONCLUSIVE) and validity (VALID / INVALID / INCONCLUSIVE) verdicts. Use whenever a user asks whether a document, screenshot, scan, statement, invoice, contract, chat log, receipt, or payment evidence is genuine, original, edited, Photoshopped, manipulated, fake, or valid."
5
+ ---
6
+
7
+ # Document and Image Authenticity
8
+
9
+ Use this file as the workflow index. Load only the references required by the
10
+ detected file type and document type.
11
+
12
+ Authenticity and validity answer different questions:
13
+
14
+ - **Authenticity:** does the supplied file show evidence of modification,
15
+ compositing, or recreation after its claimed origin?
16
+ - **Validity:** are the document's material claims, identifiers, calculations,
17
+ parties, and required terms internally correct and externally supportable?
18
+
19
+ An edited file can remain valid, and a cleanly generated fake can be invalid
20
+ without retaining an edit trail. Always issue both verdict axes independently.
21
+
22
+ ## Workflow
23
+
24
+ ### 1. Determine file type
25
+
26
+ Inspect magic bytes and decode the file; do not trust its extension.
27
+
28
+ | `file_type` | Input | Action |
29
+ |---|---|---|
30
+ | `pdf` | Bytes begin with a valid PDF header and parse as PDF | Use the PDF authenticity branch |
31
+ | `image` | JPEG, PNG, WebP, TIFF, BMP, or another Pillow-decodable raster image | Use the image authenticity branch |
32
+
33
+ A PDF containing scanned page images is still `file_type: pdf`; F7 records that
34
+ its content is scanned or flattened. If the file is neither PDF nor a supported
35
+ raster image, stop and report that this skill does not support the format.
36
+
37
+ Record the MIME type, extension/magic agreement, file size, SHA-256, and supplied
38
+ claim in `verdict.json`. Default output to `./doc-authenticity-out/<file-stem>/`
39
+ in the current workspace; if unwritable, use another writable workspace and
40
+ disclose the path.
41
+
42
+ ### 2. Detect authenticity by file type
43
+
44
+ #### PDF
45
+
46
+ Run:
47
+
48
+ ```bash
49
+ uv run {baseDir}/scripts/pdf_forensics.py <input.pdf> --out <outdir>
50
+ ```
51
+
52
+ Read `references/forensic-signals.md`, inspect `forensics.json` and extracted
53
+ pages, then rate every PDF authenticity check F1-F9. Copy the script's media
54
+ type, byte size, SHA-256, and extension/magic result into `verdict.json`.
55
+
56
+ #### Image
57
+
58
+ Run:
59
+
60
+ ```bash
61
+ uv run {baseDir}/scripts/image_forensics.py <input-image> --out <outdir>
62
+ ```
63
+
64
+ Read `references/image-signals.md`, inspect `image-forensics.json`, and inspect
65
+ `ela.png` for JPEG inputs. Rate every image authenticity check I1-I9. Copy the
66
+ script's media type, byte size, SHA-256, and extension/magic result into
67
+ `verdict.json`.
68
+
69
+ For both branches, metadata absence is NA, not PASS. An editor trace proves tool
70
+ contact, not deceptive editing. ELA or another pixel heuristic alone can produce
71
+ at most FLAG. A flattened or uniformly re-exported file can conceal prior edits.
72
+ Marker presence and PDF byte-range coverage are not cryptographic validation.
73
+ If encryption or corruption blocks extraction, keep the detected file type,
74
+ rate unavailable checks NA, and return an appropriately limited verdict.
75
+
76
+ ### 3. Detect document type
77
+
78
+ Classify the visible content after extraction/OCR. File type and document type
79
+ are independent: an invoice can be either a PDF or an image.
80
+
81
+ | `doc_type` | Classification signals |
82
+ |---|---|
83
+ | `bank_statement` | Account holder and account identifiers, statement period, opening/closing balance, transaction ledger, bank issuer |
84
+ | `conversation_log` | Ordered messages or transcript entries with participants/senders and timestamps, including chat screenshots and exported chats |
85
+ | `invoice` | Supplier and customer, invoice number/date, line items, quantities/prices, tax, total, and payment terms/details |
86
+ | `agreement` | Named parties, operative terms/obligations, effective or execution date, governing provisions, and signature blocks |
87
+ | `other` | None of the above, or evidence is too incomplete to classify reliably |
88
+
89
+ Classify from document structure, not the filename or user's label. Quote the
90
+ observed fields that support the classification. If two types appear, choose the
91
+ type governing the material claim and note embedded secondary content in `detail`.
92
+
93
+ ### 4. Run validity checks by document type
94
+
95
+ Only these document types have specialized validity profiles:
96
+
97
+ | `doc_type` | Required reference | Required checks |
98
+ |---|---|---|
99
+ | `bank_statement` | `references/bank-statement.md` | C1-C5 and D1-D5 |
100
+ | `invoice` | `references/invoice.md` | N1-N8 |
101
+ | `agreement` | `references/agreement.md` | A1-A8 |
102
+ | `conversation_log` | None | No specialized validity checks; validity is INCONCLUSIVE |
103
+ | `other` | None | No specialized validity checks; validity is INCONCLUSIVE |
104
+
105
+ Run the validity profile regardless of whether the source is PDF or image. Use
106
+ OCR only when native text is unavailable and disclose OCR uncertainty. Verify
107
+ all arithmetic programmatically. Verify banks, tax identifiers, company status,
108
+ addresses, signatory authority, and governing-law facts against current primary
109
+ sources where available.
110
+
111
+ Conversation logs can still contribute evidence to another document's packet,
112
+ but this skill does not equate a visually coherent chat with a valid transaction
113
+ or valid counterparty. Their standalone validity remains INCONCLUSIVE unless a
114
+ future specialized profile is added.
115
+
116
+ ### 5. Verdict and report
117
+
118
+ Read `references/verdict-and-report.md`. Apply its rubrics independently to:
119
+
120
+ - authenticity: `NO_EVIDENCE_OF_MODIFICATION | SUSPICIOUS | LIKELY_MODIFIED | INCONCLUSIVE`
121
+ - validity: `VALID | INVALID | INCONCLUSIVE`
122
+ - confidence per axis: `HIGH | MEDIUM | LOW`
123
+ - check result: `PASS | FLAG | FAIL | NA`
124
+
125
+ Write `report.md` and `verdict.json` conforming to
126
+ `references/verdict.schema.json` schema version 2.2. Include every required
127
+ check for the selected file/document route, including NA rows:
128
+
129
+ | Route | Required check IDs |
130
+ |---|---|
131
+ | PDF bank statement | F1-F9 + C1-C5 + D1-D5 |
132
+ | Image bank statement | I1-I9 + C1-C5 + D1-D5 |
133
+ | PDF invoice | F1-F9 + N1-N8 |
134
+ | Image invoice | I1-I9 + N1-N8 |
135
+ | PDF agreement | F1-F9 + A1-A8 |
136
+ | Image agreement | I1-I9 + A1-A8 |
137
+ | PDF conversation log / other | F1-F9 only |
138
+ | Image conversation log / other | I1-I9 only |
139
+
140
+ Validate before delivery:
141
+
142
+ ```bash
143
+ python3 {baseDir}/scripts/validate_verdict.py <outdir>/verdict.json
144
+ ```
145
+
146
+ Fix all errors and rerun until exit 0. For multiple files, produce one directory
147
+ per file plus `summary.md` listing file type, document type, both verdicts and
148
+ confidences, and decisive evidence.
149
+
150
+ ## Operating rules
151
+
152
+ - Evidence must quote the observed value, row, field, marker, coordinate, or
153
+ external source result. “Looks fine” is not evidence.
154
+ - Every FLAG must name a plausible innocent explanation.
155
+ - Do not treat public bank or company details as proof of account ownership.
156
+ - Recommend source-side verification for high-stakes decisions.
157
+ - This skill is defensive. Refuse guidance on evading these checks or making an
158
+ altered artifact pass them, then continue with defensive analysis.
@@ -0,0 +1,66 @@
1
+ # Agreement Validity Checks (A1-A8)
2
+
3
+ Run all checks for a document classified as `agreement`. This is document and
4
+ counterparty validation, not legal advice or an enforceability opinion. Use
5
+ PASS, FLAG, FAIL, or NA and quote exact clauses, page numbers, names, and dates.
6
+
7
+ ## A1 — Party identity and capacity
8
+
9
+ Verify each party's exact legal name, registration number, status, jurisdiction,
10
+ and registered address against current primary registries. Confirm the named
11
+ entity has capacity to enter the stated transaction. A nonexistent or mismatched
12
+ party is FAIL.
13
+
14
+ ## A2 — Document identity, dates, and completeness
15
+
16
+ Check title, version, effective date, execution date, page numbering, headers,
17
+ footers, and whether all referenced schedules/exhibits are present. Impossible
18
+ chronology or missing material pages/schedules is FAIL; benign unsigned drafts or
19
+ pagination defects may be FLAG when clearly disclosed.
20
+
21
+ ## A3 — Execution and signatures
22
+
23
+ Check signature blocks, names, roles, dates, witnesses, seals, and electronic
24
+ signature evidence. Verify digital signatures cryptographically when present.
25
+ An image of a signature is not proof of authorization. A broken signature or a
26
+ signature demonstrably attributed to the wrong person is FAIL.
27
+
28
+ ## A4 — Material terms and internal consistency
29
+
30
+ Compare defined terms, subject matter, quantities, price, currency, payment
31
+ schedule, duration, renewal, termination, and liability provisions throughout
32
+ the agreement. Conflicting material values or undefined operative parties are
33
+ FAIL when not resolved by an order-of-precedence clause.
34
+
35
+ ## A5 — Obligations, deliverables, and milestones
36
+
37
+ Confirm each material obligation has an accountable party, deliverable or
38
+ performance standard, timing, acceptance mechanism, and remedy where expected.
39
+ Ambiguity is generally FLAG; direct contradictions between obligations and
40
+ schedules are FAIL.
41
+
42
+ ## A6 — Governing law and required provisions
43
+
44
+ Check governing law, jurisdiction/dispute mechanism, notices, assignment,
45
+ confidentiality/data protection, sanctions/compliance, and any transaction- or
46
+ jurisdiction-specific mandatory wording. Rate only against verified requirements;
47
+ use NA rather than inventing a legal requirement.
48
+
49
+ ## A7 — Amendments, references, and precedence
50
+
51
+ Verify amendment numbers/dates, recitals, cross-references, annex labels,
52
+ incorporated documents, and order of precedence. Missing or circular references
53
+ that change obligations are FAIL; harmless numbering errors are FLAG.
54
+
55
+ ## A8 — Authority and external corroboration
56
+
57
+ Verify signatory titles/authority through board resolution, power of attorney,
58
+ company records, trusted e-signature audit trail, or direct counterparty
59
+ confirmation. Rate NA when authority evidence is unavailable. Do not treat a
60
+ company logo, stamp image, or public contact details as proof of authority.
61
+
62
+ ## Decisive validity evidence
63
+
64
+ A nonexistent party, invalid/broken signature, unauthorized signatory supported
65
+ by primary evidence, impossible execution chronology, missing operative schedule,
66
+ or irreconcilable material terms can independently support `INVALID`.
@@ -0,0 +1,150 @@
1
+ # Bank Statement — Content & Domain Checks (C1–C5, D1–D5)
2
+
3
+ Detailed procedure for the bank-statement-specific layers. Work from the
4
+ extracted text in `pages/*.txt`; quote row-level evidence.
5
+
6
+ ## Content plausibility (C-checks)
7
+
8
+ ### C1 — Balance arithmetic
9
+
10
+ The single highest-value check. Parse every transaction row into
11
+ (date, description, debit/credit amount, running balance) and verify:
12
+
13
+ 1. `opening_balance ± each transaction = next running balance`, row by row.
14
+ 2. `opening + sum(credits) − sum(debits) = closing`.
15
+ 3. Any "money in / money out" summary box equals the transaction sums.
16
+
17
+ Do this in Python (a throwaway script is fine). Mind the parsing traps before
18
+ declaring a FAIL: negative amounts as `(123.45)` or `123.45 DR` / `CR`
19
+ suffixes; thousand separators and European decimal commas; multi-line
20
+ descriptions that split a row across text lines; statements that list newest
21
+ first (reconcile in reverse). A parsing artifact misread as a balance break is
22
+ the most damaging false positive this skill can make — when a row doesn't
23
+ reconcile, re-read the raw text around it before rating.
24
+
25
+ A genuine break — especially several rows suddenly offset by the same amount
26
+ (one edited transaction shifts every balance after it, and fabricators forget
27
+ to propagate) — is decisive FAIL evidence. Quote the first broken row, the
28
+ expected vs printed balance, and the offset.
29
+
30
+ ### C2 — Date sequence
31
+
32
+ - Transactions in consistent chronological order (all ascending or all
33
+ descending), all inside the printed statement period.
34
+ - Statement period itself sane: start < end, matches the "statement date".
35
+ - Value dates vs posting dates: value date may trail/lead a bit; a value date
36
+ *months* away from its posting date is an anomaly.
37
+ - Feb 30ths, dates that don't exist, or a period that ends after the file's
38
+ CreationDate (cross-check F2) → FAIL.
39
+ - Weekend/holiday postings: card transactions post on weekends routinely;
40
+ BACS/ACH batch credits (salary) on a Sunday is odd but not impossible —
41
+ FLAG, don't FAIL, and only when it recurs.
42
+
43
+ ### C3 — Transaction plausibility
44
+
45
+ - Exact-duplicate rows (same date, description, amount) — real duplicates
46
+ happen (two coffees), so look for *implausible* duplicates: identical
47
+ salary credits twice in a month, duplicated references.
48
+ - Round-number saturation: fabricated statements over-index on 100.00 /
49
+ 500.00 / 1,000.00. Compute the share of round amounts; > ~40% of rows in a
50
+ personal account is anomalous.
51
+ - Description/amount coherence: "TESCO STORES" for 4,900.00, a salary line
52
+ labelled like a card purchase, references that don't match the described
53
+ counterparty format (e.g. faster-payment references, card scheme suffixes).
54
+ - Copy-paste artifacts: identical timestamps-in-reference across different
55
+ days, sequential references out of order.
56
+
57
+ ### C4 — Internal cross-consistency
58
+
59
+ - "Page X of Y" matches actual page count and pages are all present.
60
+ - Account number/sort code/IBAN printed identically on every page.
61
+ - Customer name/address identical everywhere it appears (watch for one
62
+ respelled instance — a splice trace).
63
+ - Summary boxes (opening, closing, money in, money out) agree with C1's sums.
64
+ - Statement number / period continuity if the user supplied adjacent
65
+ statements: closing of month N = opening of month N+1.
66
+
67
+ ### C5 — Formatting consistency
68
+
69
+ Fabricators editing one row rarely match the original formatting exactly:
70
+
71
+ - Decimal places uniform (no `1,234.5` among `1,234.50`).
72
+ - Thousand-separator style uniform; currency symbol placement uniform.
73
+ - One date in `01/02/2026` among `1 Feb 2026` rows.
74
+ - Column alignment in the raw extracted text: a value whose x-position drifts
75
+ from its column (the script emits word x-coordinates) suggests re-set text.
76
+
77
+ ## Domain knowledge (D-checks)
78
+
79
+ ### D1 — Account identifiers mechanically valid
80
+
81
+ Run `scripts/validate_codes.py` with everything extractable:
82
+
83
+ - **IBAN** — mod-97 checksum, length-per-country. An invalid checksum on a
84
+ printed IBAN is decisive FAIL (banks do not misprint IBANs).
85
+ - **US ABA routing number** — 9 digits, checksum `3(d1+d4+d7)+7(d2+d5+d8)+(d3+d6+d9) ≡ 0 (mod 10)`.
86
+ - **UK sort code** — format `XX-XX-XX`; the script checks format and known
87
+ leading-range → bank-group hints, not the private EISCD modulus tables.
88
+ Format-valid ≠ real; pair with D3.
89
+ - **Account number** — country format (UK 8 digits, etc.).
90
+
91
+ ### D2 — SWIFT/BIC belongs to the named bank
92
+
93
+ - Format: 8 or 11 chars, `AAAA BB CC (DDD)` — bank code letters, ISO country
94
+ code, location code. Country letters must match the statement's country.
95
+ - The 4-letter bank code should correspond to the claimed bank (BARC→Barclays,
96
+ HSBC/MIDL→HSBC, LOYD→Lloyds, NWBK→NatWest, ABBY→Santander UK, CHAS→JPMorgan
97
+ Chase, BOFA→Bank of America, CITI→Citi, DEUT→Deutsche, BNPA→BNP…). Verify
98
+ by web search when available; otherwise rate from knowledge and say so.
99
+ - A BIC whose country code contradicts the branch address → FAIL.
100
+
101
+ ### D3 — Bank / branch / address consistency
102
+
103
+ - UK sort-code leading pairs map to bank groups (e.g. 20–29 Barclays [20s],
104
+ 40–49 HSBC/first direct, 30–39 Lloyds group, 07/08 Nationwide/co-ops,
105
+ 04 challengers/fintechs — Monzo 04-00-04, Starling 60-83-71 under NatWest
106
+ ranges…). A sort code from bank A on bank B's letterhead → FAIL. Web-search
107
+ the exact sort code when possible.
108
+ - Postcode/ZIP format valid for the country; branch address city consistent
109
+ with the branch name.
110
+ - Contact details: phone country code, domain of any printed email/URL
111
+ belongs to the bank (statement footer URLs on lookalike domains → FAIL).
112
+
113
+ ### D4 — Template & branding match the claimed bank
114
+
115
+ - Regulatory footer text expected per jurisdiction: UK statements carry
116
+ FSCS protection wording and "Authorised by the PRA / regulated by the FCA
117
+ and PRA" + registration number; US statements carry Member FDIC / Equal
118
+ Housing Lender; EU statements name the local deposit-guarantee scheme. Its
119
+ *absence* on a full statement is a FLAG; a *wrong* registration number is a
120
+ FAIL (verify the FCA/FDIC number by search when available).
121
+ - Layout matches the bank's known statement style where you know it (column
122
+ order, summary-box placement, typography). Check `issuer-profiles.md` for
123
+ the issuer's typography and its evidence grade — Verified rows can support
124
+ a FAIL; knowledge-grade rows support at most a FLAG (brand font ≠ statement
125
+ font). Rate only what you actually know; "I don't know this bank's
126
+ template" → NA, not PASS.
127
+ - Producer tooling vs bank expectations (ties back to F1): e.g. big
128
+ retail banks emit composition-platform or server-library producers; a
129
+ boutique layout claiming a tier-1 bank with a Word producer contradicts D4
130
+ and F1 together.
131
+
132
+ ### D5 — Address plausibility
133
+
134
+ - Customer address: real-format street/city/postcode for the country;
135
+ consistent across pages and with the user-supplied KYC context (if the
136
+ packet's proof-of-address disagrees with the statement, flag it for the
137
+ analyst — that's a packet-level finding, not necessarily forgery).
138
+ - Geocode-sanity by knowledge/search: postcode district matches the city
139
+ (e.g. an "M1" postcode in London → FAIL-grade inconsistency).
140
+
141
+ ## Scoring reminders (bank statements specifically)
142
+
143
+ - C1 multi-row breaks and D1 checksum failures are decisive validity FAILs;
144
+ F6 splices on amounts are decisive authenticity FAILs. Together they support
145
+ `LIKELY_MODIFIED` authenticity and `INVALID` validity.
146
+ - A statement that is a clean scan (F-layer NA) but reconciles perfectly and
147
+ has valid, mutually consistent identifiers has authenticity INCONCLUSIVE and
148
+ may have validity VALID. A scan can still depict a fabricated original.
149
+ - When the user names the expected bank, D3/D4 disagreements weigh more; when
150
+ they don't, an unknown template is NA.
@@ -0,0 +1,157 @@
1
+ # Forensic Signals — Interpretation Guide (F1–F9)
2
+
3
+ How to read `forensics.json` and rate each F-check. The recurring theme:
4
+ distinguish **evidence of tampering** (FAIL) from **evidence of an untidy but
5
+ innocent document journey** (FLAG) from **no signal** (NA).
6
+
7
+ ## F1 — Producer / Creator tool
8
+
9
+ `metadata.producer` and `metadata.creator` name the software that generated
10
+ the PDF. Banks generate statements with **document-composition platforms**;
11
+ fabricators use **desktop editors and web tools**.
12
+
13
+ **Consistent with a bank (PASS):**
14
+ - Quadient / Inspire, OpenText Exstream, HP Exstream, Smart Communications /
15
+ SmartCOMM, Messagepoint, Papyrus (ISIS), StreamServe / OpenText StreamServe,
16
+ Xenos, Elixir, Crawford Technologies
17
+ - Big-bank in-house stacks often show generic library names: iText, Apache
18
+ FOP, PDFBox, Aspose, BIRT, JasperReports, Eclipse BIRT, XSL-FO processors
19
+ (AntennaHouse, RenderX XEP), wkhtmltopdf / headless Chromium ("Skia/PDF")
20
+ — these are server-side generation traces and are normal.
21
+
22
+ **Editor-associated (FLAG, often FAIL with corroboration):**
23
+ - iLovePDF, Smallpdf, Sejda, PDFescape, pdfFiller, DocHub, SodaPDF, PDF24
24
+ - Adobe Acrobat (as *Producer* on a re-save; banks don't hand-edit statements
25
+ in Acrobat), Foxit PhantomPDF / PDF Editor, PDF-XChange Editor, Nitro
26
+ - Canva, Photoshop, Illustrator, GIMP — image tools have no business
27
+ producing a bank statement
28
+ - Word / LibreOffice / Google Docs ("Microsoft® Word", "Writer", "Skia/PDF
29
+ m… Google Docs renderer") — someone authored this as a document
30
+
31
+ **Ambiguous (FLAG with innocent explanation, or NA):**
32
+ - "Microsoft: Print To PDF", macOS Quartz PDFContext, browser "Save as PDF" —
33
+ the classic customer flow: opened online banking, printed to PDF. The
34
+ original bank metadata is destroyed, not forged. Lean FLAG + note; push the
35
+ weight onto C/D checks.
36
+ - Scanner strings (ScanSnap, Epson Scan, "TWAIN") — see F7; usually NA here.
37
+
38
+ Rate FAIL only when the editor trace is corroborated (e.g. editor producer
39
+ **and** incremental updates **and** a font splice), or when the claimed bank's
40
+ statements are reliably known to carry different tooling (see the bank notes
41
+ in `bank-statement.md`).
42
+
43
+ ## F2 — Creation vs modification timestamps
44
+
45
+ `metadata.creation_date` vs `metadata.mod_date`.
46
+
47
+ - Equal or mod within seconds of creation → PASS (single-pass generation).
48
+ - ModDate later than CreationDate → someone re-saved it. FLAG, innocent
49
+ explanations abound (mail clients, previewers, print-to-PDF chains).
50
+ - **ModDate earlier than CreationDate, impossible dates, or dates after the
51
+ statement was supposedly issued but before it covers** → strong anomaly;
52
+ FAIL when corroborated.
53
+ - Timezone offsets wildly inconsistent with the bank's country → FLAG.
54
+ - Statement period ends *after* the file's CreationDate → the file predates
55
+ the data it reports. FAIL. (Check against the period parsed in C2.)
56
+
57
+ ## F3 — Incremental updates
58
+
59
+ `structure.eof_count`, `structure.xref_sections`, `structure.prev_pointers`.
60
+ A PDF saved incrementally appends a new body + xref; the count of `%%EOF`
61
+ markers approximates the number of save generations.
62
+
63
+ - 1 EOF → single generation. PASS.
64
+ - 2+ EOFs → the file was modified after creation. What matters is **what
65
+ changed**: `structure.updated_objects` lists object numbers that appear in
66
+ more than one generation. Content-stream or font objects updated → the
67
+ visible page was altered → FAIL. Only metadata/annotation objects → FLAG
68
+ (e.g. a viewer stamped it opened).
69
+ - Note: a digital-signature workflow legitimately adds a generation (that's
70
+ how signing works). Cross-check F8 before rating.
71
+
72
+ ## F4 — XMP metadata consistency
73
+
74
+ `xmp` block: `xmp_toolkit`, `history`, `derived_from`, and agreement with
75
+ docinfo.
76
+
77
+ - XMP history events (`saved` entries with softwareAgent) narrate the edit
78
+ chain — an entry with an editor agent after creation corroborates F1/F3.
79
+ - `derived_from` naming another document → this file was built from a source
80
+ file. FLAG→FAIL depending on what the source appears to be.
81
+ - Docinfo says one producer, XMP says another → the metadata was partially
82
+ scrubbed or spoofed. FLAG, FAIL with corroboration.
83
+ - Absent XMP entirely: common in minimal server-side generators. NA, not
84
+ suspicious on its own.
85
+
86
+ ## F5 — Font inventory
87
+
88
+ `fonts` array: name, subset prefix (6 letters + `+`), embedded flag, per page.
89
+
90
+ - Bank statements are typographically boring: 1–3 families, consistently
91
+ subset-embedded. PASS.
92
+ - A family appearing **twice with different subset prefixes** (e.g.
93
+ `ABCDEF+Helvetica` and `GHIJKL+Helvetica`) means two tools embedded that
94
+ font — classic edit trace. FAIL with corroboration, FLAG alone.
95
+ - Non-embedded standard-14 fonts (plain `Helvetica`, `Arial`) mixed with
96
+ embedded subsets → text added by a lightweight editor. FLAG→FAIL.
97
+ - A font present on exactly one page that otherwise matches the others'
98
+ typography → localized edit. Investigate with F6.
99
+
100
+ ## F6 — In-line font splice
101
+
102
+ `text_fonts` in the per-page extraction: font name and size per word. The
103
+ smoking gun is a **single value rendered in a different font/size than its
104
+ row** — a pasted-over balance or name.
105
+
106
+ - Compare each transaction row's amount/balance cells to the column's modal
107
+ font. One cell differing in font name, or in size by >0.3pt, while the rest
108
+ of the column is uniform → FAIL, and quote the exact row and fonts.
109
+ - Whole-column or whole-block differences (headers vs body, bold totals) are
110
+ design, not splices. PASS.
111
+ - Kerning/width anomalies aren't extracted by the script; if the user supplies
112
+ a rendered image and something looks visually off, say so as a FLAG with a
113
+ note that pixel-level analysis wasn't performed.
114
+
115
+ ## F7 — Text layer type
116
+
117
+ `pages[].char_count`, `pages[].image_coverage`.
118
+
119
+ - Native text, low image coverage → full forensic surface. PASS (as a check,
120
+ this "passes" when the layer is native — it's about signal availability).
121
+ - Full-page image, no/synthetic text (OCR layer) → scan or flattened export.
122
+ Most F-checks and F6 go NA. **This alone must not drive the verdict
123
+ negative** — it drives it toward INCONCLUSIVE unless C/D find substance.
124
+ - Hybrid: native text pages plus one image-only page in the same statement →
125
+ FLAG; why would page 2 of a digital statement be a picture?
126
+
127
+ ## F8 — Digital signatures
128
+
129
+ `signatures` block: presence, field name, and whether byte ranges structurally
130
+ cover the file. The bundled script does not verify the signature value,
131
+ certificate chain, revocation status, or trust anchor; it reports
132
+ `cryptographic_validation: not_performed`. Use a trusted signature verifier
133
+ before rating F8 PASS or FAIL.
134
+
135
+ - A cryptographically valid signature covering the full file from the issuing
136
+ bank is the strongest possible PASS; this lifts the
137
+ `NO_EVIDENCE_OF_MODIFICATION` confidence cap (see rubric).
138
+ - Signature present but broken byte range / document modified after signing →
139
+ FAIL, decisive, only after a signature verifier confirms the failure. A
140
+ malformed-looking byte range from the extractor alone is FLAG.
141
+ - No signature → NA for most retail statements (banks rarely sign customer
142
+ PDFs); FLAG only if the claimed issuer is known to sign — check the
143
+ signature table in `issuer-profiles.md` (Verified rows only) or a verified
144
+ local sample before flagging absence.
145
+
146
+ ## F9 — Structural anomalies
147
+
148
+ Grab bag from `structure` and `annotations`:
149
+
150
+ - **FreeText / Square / Ink annotations** overlapping content → text placed on
151
+ top of the page. FAIL if over a value, FLAG if marginal.
152
+ - **Redaction annotations** (`/Redact`) → content was masked. FLAG minimum.
153
+ - JavaScript, launch actions, embedded files → not typical of statements;
154
+ FLAG (and a mild malware caution to the analyst).
155
+ - Broken xref rebuilt by the library, objects claimed but missing, garbage
156
+ after `%%EOF` → hand-edited or corrupted; FLAG→FAIL with corroboration.
157
+ - `pikepdf` repair warnings surface in `structure.repairs` — quote them.
@@ -0,0 +1,114 @@
1
+ # Image Authenticity Signals — Interpretation Guide (I1–I9)
2
+
3
+ Use these checks for JPEG, PNG, WebP, TIFF, BMP, and other Pillow-decodable raster images.
4
+ The goal is to detect evidence of editing or recomposition, including traces
5
+ from Photoshop and other image tools. No individual metadata or pixel test can
6
+ prove originality: editors can strip metadata, and legitimate messaging or
7
+ export workflows routinely recompress images.
8
+
9
+ ## I1 — Container integrity
10
+
11
+ - PASS: the decoder accepts the file, declared format matches magic bytes, and
12
+ the marker/chunk stream terminates normally without unexplained trailing data.
13
+ - FLAG: extension and magic disagree, non-zero payload follows JPEG EOI, or the
14
+ decoder reports repairable corruption. Innocent causes include transfer damage.
15
+ - FAIL: embedded active payload or a deliberately deceptive polyglot is found.
16
+
17
+ ## I2 — Editor metadata and signatures
18
+
19
+ Inspect EXIF `Software`, XMP `CreatorTool`/history, IPTC, PNG text chunks, JPEG
20
+ APP13 `Photoshop 3.0`/`8BIM`, APP14 Adobe markers, and raw strings.
21
+
22
+ - PASS: source-native capture/export tooling is identified and no editor trace exists.
23
+ - FLAG: Photoshop, Lightroom, GIMP, Canva, Affinity, Pixelmator, ImageMagick,
24
+ or another editor is named. The trace proves tool contact, not a deceptive edit;
25
+ resizing, color correction, and metadata work are innocent explanations.
26
+ - FAIL: editor history records a material post-capture composite/change and the
27
+ user requires an unedited original, or editor evidence corroborates a pixel splice.
28
+ - NA: metadata is absent or stripped. Never treat absent editor strings as PASS.
29
+
30
+ ## I3 — Capture-device provenance
31
+
32
+ - PASS: coherent camera/device make, model, lens, and capture settings are present,
33
+ or a platform-native screenshot marker is independently verifiable.
34
+ - FLAG: mutually inconsistent make/model/software fields or camera metadata on a
35
+ purported screenshot. Re-encoding can copy stale metadata, so seek corroboration.
36
+ - NA: device metadata absent. Messaging apps commonly strip it.
37
+
38
+ ## I4 — Timestamp consistency
39
+
40
+ Compare EXIF original/digitized/modify times, filesystem times, visible timestamps,
41
+ and the claimed event date. Filesystem timestamps alone are weak transfer evidence.
42
+
43
+ - PASS: embedded capture chronology is possible and agrees with the claim.
44
+ - FLAG: modify time is later than capture, with export or messaging as an innocent cause.
45
+ - FAIL: impossible chronology directly contradicts the claim and is corroborated.
46
+ - NA: no embedded timestamp or no claimed event time.
47
+
48
+ ## I5 — Encoding and quantization
49
+
50
+ Record baseline/progressive mode, chroma subsampling, JPEG quantization tables,
51
+ quality estimate, PNG chunks, and encoder comments.
52
+
53
+ - FLAG: unusual or mixed encoder signatures, thumbnail/main-image mismatch, or
54
+ repeated-save indicators. Social platforms and format conversion are common causes.
55
+ - FAIL only with independent evidence of a material edit.
56
+ - NA when the format or available tooling cannot expose the signal.
57
+
58
+ ## I6 — Recompression / error-level consistency
59
+
60
+ Open `ela.png` and inspect the numeric tile errors in `image-forensics.json`.
61
+ Compare like regions: text against text, flat background against flat background.
62
+ Naturally detailed edges always produce more error than flat areas.
63
+
64
+ - PASS: comparable regions have broadly consistent error and no material area is isolated.
65
+ - FLAG: a semantically important region has a sharply different error profile.
66
+ - FAIL: a localized error boundary exactly surrounds altered material and is
67
+ corroborated by I2, I7, or content inconsistency.
68
+ - NA: lossless source, uniformly flattened/re-exported image, or inadequate resolution.
69
+
70
+ ELA alone must never produce LIKELY_MODIFIED. A full-image export after editing
71
+ can normalize errors, while an untouched image can have nonuniform errors.
72
+
73
+ ## I7 — Splice, copy-move, and boundary evidence
74
+
75
+ Inspect material regions at native pixels for hard seams, halos, mismatched blur,
76
+ duplicate texture, inconsistent antialiasing, alignment, perspective, shadow, and
77
+ noise. Automated copy-move matches need manual confirmation because repeated UI
78
+ components and textures create false positives.
79
+
80
+ - FAIL: a material value/object has a confirmed compositing boundary or duplicated
81
+ source patch with no plausible scene explanation.
82
+ - FLAG: a visible anomaly is plausible but not conclusive.
83
+ - NA: resolution/compression is too poor for reliable inspection.
84
+
85
+ ## I8 — Sensor, noise, and resampling consistency
86
+
87
+ For camera photos, compare local noise, demosaicing/CFA behavior, sharpening,
88
+ resampling grids, and depth-of-field. For screenshots, assess raster scaling and
89
+ text antialiasing instead; camera sensor tests are NA.
90
+
91
+ - FLAG: a material region has inconsistent noise/resampling.
92
+ - FAIL only when localized and independently corroborated.
93
+ - NA when the source type, resolution, or tools do not support the test.
94
+
95
+ ## I9 — Trusted provenance or signature
96
+
97
+ The bundled script only scans for possible C2PA/JUMBF markers and reports
98
+ `cryptographic_validation: not_performed`; marker presence is not validation.
99
+ Use a trusted C2PA or signature verifier before rating I9 PASS or FAIL.
100
+
101
+ - PASS: valid C2PA/Content Credentials or another trusted signature covers the
102
+ file and validates to the expected source.
103
+ - FAIL: provenance exists but fails validation or the protected file was changed.
104
+ - NA: no signed provenance. This is normal and not suspicious by itself.
105
+
106
+ ## Rating reminders
107
+
108
+ - An editor name proves editor contact, not fraud.
109
+ - Metadata absence means NA, not PASS.
110
+ - A clean marker stream proves only that the current export is structurally clean.
111
+ - A screenshot of a genuine page and a fabricated screenshot can look identical.
112
+ - Prefer the original file from the capture device or source application. Comparing
113
+ hashes, native exports, adjacent frames, chat exports, or issuer-side records is
114
+ stronger than analyzing a forwarded JPEG.