statementproof 0.1.0__tar.gz → 0.1.1__tar.gz

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.
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: statementproof
3
+ Version: 0.1.1
4
+ Summary: Extract transactions from bank statement PDFs -- and prove the extraction is right, or say it isn't.
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/OrbitalKeyAi/statementproof
7
+ Project-URL: Documentation, https://orbitalkeyai.github.io/statementproof/
8
+ Project-URL: Source, https://github.com/OrbitalKeyAi/statementproof
9
+ Project-URL: Issues, https://github.com/OrbitalKeyAi/statementproof/issues
10
+ Keywords: bank-statement,pdf,csv,bookkeeping,accounting,reconciliation,extraction,converter,quickbooks,xero
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Financial and Insurance Industry
13
+ Classifier: Topic :: Office/Business :: Financial :: Accounting
14
+ Classifier: Topic :: Text Processing :: Filters
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Operating System :: OS Independent
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: pdfplumber>=0.10
22
+ Provides-Extra: dev
23
+ Requires-Dist: reportlab>=4.0; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # statementproof
27
+
28
+ **Convert bank statement PDFs to CSV — and find out when the conversion is wrong.**
29
+
30
+ Most PDF-to-CSV converters hand you rows with no way to check them. The best of them
31
+ (monopoly) does check totals — but tells you only that *something* is wrong, somewhere. The expensive failure isn't a crash you notice — it's one debit read as a credit,
32
+ which reconciles to nothing and turns up weeks later inside a client's books.
33
+
34
+ A bank statement is one of the few documents that carries its own checksum: the balances.
35
+ statementproof uses them.
36
+
37
+ ```
38
+ $ statementproof october.pdf
39
+
40
+ opening balance : 69.96
41
+ closing balance : 586.71
42
+ transactions : 21 extracted, 0 skipped
43
+
44
+ VERIFIED (21 transactions, checks: chain, aggregate)
45
+ ```
46
+
47
+ And when a row is misread:
48
+
49
+ ```
50
+ FAILED (21 transactions, checks: chain, aggregate)
51
+ [chain_break] row 14: running balance does not follow:
52
+ 534.66 +37.07 should give 571.73, statement shows 497.59 (off by -74.14)
53
+ ```
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install statementproof
59
+ ```
60
+
61
+ Python 3.9+. One dependency (`pdfplumber`).
62
+
63
+ ## Usage
64
+
65
+ ```bash
66
+ # check a statement and print the report
67
+ statementproof statement.pdf
68
+
69
+ # write the transactions to CSV
70
+ statementproof statement.pdf --csv transactions.csv
71
+
72
+ # layout report you can share — contains no financial data
73
+ statementproof statement.pdf --diagnostic
74
+ ```
75
+
76
+ Exit code is `0` when verified, `1` otherwise, so it drops into a script.
77
+
78
+ ## Three verdicts, and it will not bluff
79
+
80
+ | verdict | meaning |
81
+ |---|---|
82
+ | `VERIFIED` | the rows reproduce the statement's opening and closing balances, and each running balance follows from the last |
83
+ | `FAILED` | they don't — **with the row number, expected figure, and size of the gap** |
84
+ | `UNVERIFIED` | the statement carries no balances to check against. Output may be perfect; nothing proves it, so nothing is claimed |
85
+
86
+ A converter that returns a clean-looking CSV it cannot vouch for is the problem this
87
+ exists to solve, so `UNVERIFIED` is never dressed up as success.
88
+
89
+ ## Your statement never leaves your machine
90
+
91
+ This tool asks you to point it at a document carrying your name, address, account
92
+ number, employer, and every merchant you used last month. "Nothing uploaded" can't be a
93
+ policy — it has to be a property of the code.
94
+
95
+ **No networking library is imported anywhere in this package**, and
96
+ [`tests/test_privacy.py`](statementproof/tests/test_privacy.py) parses every module's
97
+ AST and **fails the build if one ever is.** No file is written unless you name it.
98
+
99
+ The `--diagnostic` flag exists because a library of real statement *layouts* is what
100
+ would most improve this tool — and a layout can be described without describing anyone's
101
+ money. It reports column positions, column density, date-token **shapes** (`DD/DD`, not
102
+ `10/02`), and where extraction broke. It contains no amounts, balances, descriptions,
103
+ dates, account numbers, names, or even the filename. It prints to your screen so you can
104
+ read all of it before deciding whether to share it. The tool never sends it anywhere.
105
+
106
+ Those exclusions are asserted by tests against a known statement, not merely intended.
107
+
108
+ ## How it works
109
+
110
+ **Geometry, not regex.** The most-cited converter failure is *"columns shift, debit and
111
+ credit values land in the wrong places."* That happens because `extract_text()` flattens
112
+ a two-dimensional page and discards the x-position — the only signal separating a debit
113
+ column from a credit column. statementproof reads each number's coordinates and clusters
114
+ the money columns by their right edges.
115
+
116
+ **Column roles from arithmetic, not headers.** Which column holds the running balance is
117
+ decided by behaviour, because header wording differs by bank and often vanishes on
118
+ continuation pages.
119
+
120
+ **Sign from the balance chain.** If the balance went down it was a debit, whether or not
121
+ a minus glyph survived extraction.
122
+
123
+ ## Limitations — read these first
124
+
125
+ **Text-layer PDFs only.** A statement downloaded from your bank's website normally has a
126
+ text layer; a scan or a phone photo does not. Given one, statementproof says so rather
127
+ than inventing rows. **OCR is not built yet.**
128
+
129
+ **Arithmetic consistency, not correctness.** It cannot see an error that leaves the
130
+ totals intact:
131
+
132
+ - a page header picked up as a row with a `0.00` amount
133
+ - a wrong date or a truncated description
134
+ - two errors that cancel out
135
+
136
+ *"Provably arithmetically consistent"* is the honest claim. *"Provably correct"* is not,
137
+ and is not made here.
138
+
139
+ **It has not met your bank.** Seven layouts extract exactly — six written by the author,
140
+ one reproduced from a real bank's published specimen. That seventh immediately found
141
+ three bugs the other six could not, including `MM/DD` dates with no year, which took
142
+ extraction from 21/21 to 0/21 while the author's own suite still reported 6/6 passing.
143
+ **Passing tests you wrote yourself is worth very little.**
144
+
145
+ If it fails on your statement, run `--diagnostic` and
146
+ [open an issue](https://github.com/OrbitalKeyAi/statementproof/issues) with that output.
147
+ It contains no financial data, and each new layout makes the parser better for everyone.
148
+
149
+ ## Tests
150
+
151
+ ```bash
152
+ python statementproof/tests/make_statements.py # build synthetic corpus
153
+ python statementproof/tests/make_real_derived.py # build real-bank-derived layout
154
+ python statementproof/tests/score.py # score extraction vs ground truth
155
+ python statementproof/tests/test_failure_modes.py # validator behaviour
156
+ python statementproof/tests/test_privacy.py # privacy promises
157
+ ```
158
+
159
+ Current: **7/7 layouts extracted exactly · 9/9 failure-mode tests · 8/8 privacy checks ·
160
+ 0 false assurances.**
161
+
162
+ "False assurance" — reporting `VERIFIED` on a bad extraction — is the number that
163
+ matters. A validator that green-lights an error is worse than no validator.
164
+
165
+ ## License
166
+
167
+ MIT.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "statementproof"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "Extract transactions from bank statement PDFs -- and prove the extraction is right, or say it isn't."
9
9
  readme = "statementproof/README.md"
10
10
  requires-python = ">=3.9"
@@ -26,6 +26,12 @@ dependencies = [
26
26
  "pdfplumber>=0.10",
27
27
  ]
28
28
 
29
+ [project.urls]
30
+ Homepage = "https://github.com/OrbitalKeyAi/statementproof"
31
+ Documentation = "https://orbitalkeyai.github.io/statementproof/"
32
+ Source = "https://github.com/OrbitalKeyAi/statementproof"
33
+ Issues = "https://github.com/OrbitalKeyAi/statementproof/issues"
34
+
29
35
  [project.optional-dependencies]
30
36
  dev = ["reportlab>=4.0"]
31
37
 
@@ -0,0 +1,142 @@
1
+ # statementproof
2
+
3
+ **Convert bank statement PDFs to CSV — and find out when the conversion is wrong.**
4
+
5
+ Most PDF-to-CSV converters hand you rows with no way to check them. The best of them
6
+ (monopoly) does check totals — but tells you only that *something* is wrong, somewhere. The expensive failure isn't a crash you notice — it's one debit read as a credit,
7
+ which reconciles to nothing and turns up weeks later inside a client's books.
8
+
9
+ A bank statement is one of the few documents that carries its own checksum: the balances.
10
+ statementproof uses them.
11
+
12
+ ```
13
+ $ statementproof october.pdf
14
+
15
+ opening balance : 69.96
16
+ closing balance : 586.71
17
+ transactions : 21 extracted, 0 skipped
18
+
19
+ VERIFIED (21 transactions, checks: chain, aggregate)
20
+ ```
21
+
22
+ And when a row is misread:
23
+
24
+ ```
25
+ FAILED (21 transactions, checks: chain, aggregate)
26
+ [chain_break] row 14: running balance does not follow:
27
+ 534.66 +37.07 should give 571.73, statement shows 497.59 (off by -74.14)
28
+ ```
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install statementproof
34
+ ```
35
+
36
+ Python 3.9+. One dependency (`pdfplumber`).
37
+
38
+ ## Usage
39
+
40
+ ```bash
41
+ # check a statement and print the report
42
+ statementproof statement.pdf
43
+
44
+ # write the transactions to CSV
45
+ statementproof statement.pdf --csv transactions.csv
46
+
47
+ # layout report you can share — contains no financial data
48
+ statementproof statement.pdf --diagnostic
49
+ ```
50
+
51
+ Exit code is `0` when verified, `1` otherwise, so it drops into a script.
52
+
53
+ ## Three verdicts, and it will not bluff
54
+
55
+ | verdict | meaning |
56
+ |---|---|
57
+ | `VERIFIED` | the rows reproduce the statement's opening and closing balances, and each running balance follows from the last |
58
+ | `FAILED` | they don't — **with the row number, expected figure, and size of the gap** |
59
+ | `UNVERIFIED` | the statement carries no balances to check against. Output may be perfect; nothing proves it, so nothing is claimed |
60
+
61
+ A converter that returns a clean-looking CSV it cannot vouch for is the problem this
62
+ exists to solve, so `UNVERIFIED` is never dressed up as success.
63
+
64
+ ## Your statement never leaves your machine
65
+
66
+ This tool asks you to point it at a document carrying your name, address, account
67
+ number, employer, and every merchant you used last month. "Nothing uploaded" can't be a
68
+ policy — it has to be a property of the code.
69
+
70
+ **No networking library is imported anywhere in this package**, and
71
+ [`tests/test_privacy.py`](statementproof/tests/test_privacy.py) parses every module's
72
+ AST and **fails the build if one ever is.** No file is written unless you name it.
73
+
74
+ The `--diagnostic` flag exists because a library of real statement *layouts* is what
75
+ would most improve this tool — and a layout can be described without describing anyone's
76
+ money. It reports column positions, column density, date-token **shapes** (`DD/DD`, not
77
+ `10/02`), and where extraction broke. It contains no amounts, balances, descriptions,
78
+ dates, account numbers, names, or even the filename. It prints to your screen so you can
79
+ read all of it before deciding whether to share it. The tool never sends it anywhere.
80
+
81
+ Those exclusions are asserted by tests against a known statement, not merely intended.
82
+
83
+ ## How it works
84
+
85
+ **Geometry, not regex.** The most-cited converter failure is *"columns shift, debit and
86
+ credit values land in the wrong places."* That happens because `extract_text()` flattens
87
+ a two-dimensional page and discards the x-position — the only signal separating a debit
88
+ column from a credit column. statementproof reads each number's coordinates and clusters
89
+ the money columns by their right edges.
90
+
91
+ **Column roles from arithmetic, not headers.** Which column holds the running balance is
92
+ decided by behaviour, because header wording differs by bank and often vanishes on
93
+ continuation pages.
94
+
95
+ **Sign from the balance chain.** If the balance went down it was a debit, whether or not
96
+ a minus glyph survived extraction.
97
+
98
+ ## Limitations — read these first
99
+
100
+ **Text-layer PDFs only.** A statement downloaded from your bank's website normally has a
101
+ text layer; a scan or a phone photo does not. Given one, statementproof says so rather
102
+ than inventing rows. **OCR is not built yet.**
103
+
104
+ **Arithmetic consistency, not correctness.** It cannot see an error that leaves the
105
+ totals intact:
106
+
107
+ - a page header picked up as a row with a `0.00` amount
108
+ - a wrong date or a truncated description
109
+ - two errors that cancel out
110
+
111
+ *"Provably arithmetically consistent"* is the honest claim. *"Provably correct"* is not,
112
+ and is not made here.
113
+
114
+ **It has not met your bank.** Seven layouts extract exactly — six written by the author,
115
+ one reproduced from a real bank's published specimen. That seventh immediately found
116
+ three bugs the other six could not, including `MM/DD` dates with no year, which took
117
+ extraction from 21/21 to 0/21 while the author's own suite still reported 6/6 passing.
118
+ **Passing tests you wrote yourself is worth very little.**
119
+
120
+ If it fails on your statement, run `--diagnostic` and
121
+ [open an issue](https://github.com/OrbitalKeyAi/statementproof/issues) with that output.
122
+ It contains no financial data, and each new layout makes the parser better for everyone.
123
+
124
+ ## Tests
125
+
126
+ ```bash
127
+ python statementproof/tests/make_statements.py # build synthetic corpus
128
+ python statementproof/tests/make_real_derived.py # build real-bank-derived layout
129
+ python statementproof/tests/score.py # score extraction vs ground truth
130
+ python statementproof/tests/test_failure_modes.py # validator behaviour
131
+ python statementproof/tests/test_privacy.py # privacy promises
132
+ ```
133
+
134
+ Current: **7/7 layouts extracted exactly · 9/9 failure-mode tests · 8/8 privacy checks ·
135
+ 0 false assurances.**
136
+
137
+ "False assurance" — reporting `VERIFIED` on a bad extraction — is the number that
138
+ matters. A validator that green-lights an error is worse than no validator.
139
+
140
+ ## License
141
+
142
+ MIT.
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: statementproof
3
+ Version: 0.1.1
4
+ Summary: Extract transactions from bank statement PDFs -- and prove the extraction is right, or say it isn't.
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/OrbitalKeyAi/statementproof
7
+ Project-URL: Documentation, https://orbitalkeyai.github.io/statementproof/
8
+ Project-URL: Source, https://github.com/OrbitalKeyAi/statementproof
9
+ Project-URL: Issues, https://github.com/OrbitalKeyAi/statementproof/issues
10
+ Keywords: bank-statement,pdf,csv,bookkeeping,accounting,reconciliation,extraction,converter,quickbooks,xero
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Financial and Insurance Industry
13
+ Classifier: Topic :: Office/Business :: Financial :: Accounting
14
+ Classifier: Topic :: Text Processing :: Filters
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Operating System :: OS Independent
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: pdfplumber>=0.10
22
+ Provides-Extra: dev
23
+ Requires-Dist: reportlab>=4.0; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # statementproof
27
+
28
+ **Convert bank statement PDFs to CSV — and find out when the conversion is wrong.**
29
+
30
+ Most PDF-to-CSV converters hand you rows with no way to check them. The best of them
31
+ (monopoly) does check totals — but tells you only that *something* is wrong, somewhere. The expensive failure isn't a crash you notice — it's one debit read as a credit,
32
+ which reconciles to nothing and turns up weeks later inside a client's books.
33
+
34
+ A bank statement is one of the few documents that carries its own checksum: the balances.
35
+ statementproof uses them.
36
+
37
+ ```
38
+ $ statementproof october.pdf
39
+
40
+ opening balance : 69.96
41
+ closing balance : 586.71
42
+ transactions : 21 extracted, 0 skipped
43
+
44
+ VERIFIED (21 transactions, checks: chain, aggregate)
45
+ ```
46
+
47
+ And when a row is misread:
48
+
49
+ ```
50
+ FAILED (21 transactions, checks: chain, aggregate)
51
+ [chain_break] row 14: running balance does not follow:
52
+ 534.66 +37.07 should give 571.73, statement shows 497.59 (off by -74.14)
53
+ ```
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install statementproof
59
+ ```
60
+
61
+ Python 3.9+. One dependency (`pdfplumber`).
62
+
63
+ ## Usage
64
+
65
+ ```bash
66
+ # check a statement and print the report
67
+ statementproof statement.pdf
68
+
69
+ # write the transactions to CSV
70
+ statementproof statement.pdf --csv transactions.csv
71
+
72
+ # layout report you can share — contains no financial data
73
+ statementproof statement.pdf --diagnostic
74
+ ```
75
+
76
+ Exit code is `0` when verified, `1` otherwise, so it drops into a script.
77
+
78
+ ## Three verdicts, and it will not bluff
79
+
80
+ | verdict | meaning |
81
+ |---|---|
82
+ | `VERIFIED` | the rows reproduce the statement's opening and closing balances, and each running balance follows from the last |
83
+ | `FAILED` | they don't — **with the row number, expected figure, and size of the gap** |
84
+ | `UNVERIFIED` | the statement carries no balances to check against. Output may be perfect; nothing proves it, so nothing is claimed |
85
+
86
+ A converter that returns a clean-looking CSV it cannot vouch for is the problem this
87
+ exists to solve, so `UNVERIFIED` is never dressed up as success.
88
+
89
+ ## Your statement never leaves your machine
90
+
91
+ This tool asks you to point it at a document carrying your name, address, account
92
+ number, employer, and every merchant you used last month. "Nothing uploaded" can't be a
93
+ policy — it has to be a property of the code.
94
+
95
+ **No networking library is imported anywhere in this package**, and
96
+ [`tests/test_privacy.py`](statementproof/tests/test_privacy.py) parses every module's
97
+ AST and **fails the build if one ever is.** No file is written unless you name it.
98
+
99
+ The `--diagnostic` flag exists because a library of real statement *layouts* is what
100
+ would most improve this tool — and a layout can be described without describing anyone's
101
+ money. It reports column positions, column density, date-token **shapes** (`DD/DD`, not
102
+ `10/02`), and where extraction broke. It contains no amounts, balances, descriptions,
103
+ dates, account numbers, names, or even the filename. It prints to your screen so you can
104
+ read all of it before deciding whether to share it. The tool never sends it anywhere.
105
+
106
+ Those exclusions are asserted by tests against a known statement, not merely intended.
107
+
108
+ ## How it works
109
+
110
+ **Geometry, not regex.** The most-cited converter failure is *"columns shift, debit and
111
+ credit values land in the wrong places."* That happens because `extract_text()` flattens
112
+ a two-dimensional page and discards the x-position — the only signal separating a debit
113
+ column from a credit column. statementproof reads each number's coordinates and clusters
114
+ the money columns by their right edges.
115
+
116
+ **Column roles from arithmetic, not headers.** Which column holds the running balance is
117
+ decided by behaviour, because header wording differs by bank and often vanishes on
118
+ continuation pages.
119
+
120
+ **Sign from the balance chain.** If the balance went down it was a debit, whether or not
121
+ a minus glyph survived extraction.
122
+
123
+ ## Limitations — read these first
124
+
125
+ **Text-layer PDFs only.** A statement downloaded from your bank's website normally has a
126
+ text layer; a scan or a phone photo does not. Given one, statementproof says so rather
127
+ than inventing rows. **OCR is not built yet.**
128
+
129
+ **Arithmetic consistency, not correctness.** It cannot see an error that leaves the
130
+ totals intact:
131
+
132
+ - a page header picked up as a row with a `0.00` amount
133
+ - a wrong date or a truncated description
134
+ - two errors that cancel out
135
+
136
+ *"Provably arithmetically consistent"* is the honest claim. *"Provably correct"* is not,
137
+ and is not made here.
138
+
139
+ **It has not met your bank.** Seven layouts extract exactly — six written by the author,
140
+ one reproduced from a real bank's published specimen. That seventh immediately found
141
+ three bugs the other six could not, including `MM/DD` dates with no year, which took
142
+ extraction from 21/21 to 0/21 while the author's own suite still reported 6/6 passing.
143
+ **Passing tests you wrote yourself is worth very little.**
144
+
145
+ If it fails on your statement, run `--diagnostic` and
146
+ [open an issue](https://github.com/OrbitalKeyAi/statementproof/issues) with that output.
147
+ It contains no financial data, and each new layout makes the parser better for everyone.
148
+
149
+ ## Tests
150
+
151
+ ```bash
152
+ python statementproof/tests/make_statements.py # build synthetic corpus
153
+ python statementproof/tests/make_real_derived.py # build real-bank-derived layout
154
+ python statementproof/tests/score.py # score extraction vs ground truth
155
+ python statementproof/tests/test_failure_modes.py # validator behaviour
156
+ python statementproof/tests/test_privacy.py # privacy promises
157
+ ```
158
+
159
+ Current: **7/7 layouts extracted exactly · 9/9 failure-mode tests · 8/8 privacy checks ·
160
+ 0 false assurances.**
161
+
162
+ "False assurance" — reporting `VERIFIED` on a bad extraction — is the number that
163
+ matters. A validator that green-lights an error is worse than no validator.
164
+
165
+ ## License
166
+
167
+ MIT.
@@ -1,117 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: statementproof
3
- Version: 0.1.0
4
- Summary: Extract transactions from bank statement PDFs -- and prove the extraction is right, or say it isn't.
5
- License: MIT
6
- Keywords: bank-statement,pdf,csv,bookkeeping,accounting,reconciliation,extraction,converter,quickbooks,xero
7
- Classifier: Development Status :: 3 - Alpha
8
- Classifier: Intended Audience :: Financial and Insurance Industry
9
- Classifier: Topic :: Office/Business :: Financial :: Accounting
10
- Classifier: Topic :: Text Processing :: Filters
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Operating System :: OS Independent
14
- Requires-Python: >=3.9
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: pdfplumber>=0.10
18
- Provides-Extra: dev
19
- Requires-Dist: reportlab>=4.0; extra == "dev"
20
- Dynamic: license-file
21
-
22
- # statementproof
23
-
24
- Bank statement PDF → CSV extraction that **tells you when it got it wrong.**
25
-
26
- Most converters hand you output with no way to know if it is correct. A bank
27
- statement is one of the few documents carrying its own checksum — the balances.
28
-
29
- ## What it does differently
30
-
31
- **1. Geometry, not regex.** The most-cited converter failure is *"columns shift,
32
- debit and credit values land in the wrong places."* That happens because
33
- `extract_text()` flattens a 2-D layout and discards x-position — the only signal that
34
- distinguishes a debit column from a credit column. This reads word coordinates and
35
- clusters money columns by their right edges.
36
-
37
- **2. Column roles from arithmetic, not headers.** Which column is the running balance
38
- is decided by behaviour, not by header text — header text differs across banks and is
39
- often missing on continuation pages.
40
-
41
- **3. Sign from the balance chain.** If the balance went down, it was a debit,
42
- regardless of whether a minus glyph survived extraction.
43
-
44
- **4. It refuses to bluff.** With nothing to check against, output is `UNVERIFIED` —
45
- never a silent pass.
46
-
47
- ## Verdicts
48
-
49
- | verdict | meaning |
50
- |---|---|
51
- | `VERIFIED` | transactions reproduce the statement's own balances |
52
- | `FAILED` | they do not — **with the offending row named** |
53
- | `UNVERIFIED` | statement carries no balances to check against |
54
-
55
- ## What it CANNOT catch — read this
56
-
57
- The check is **arithmetic consistency**, not correctness. It cannot see errors that do
58
- not disturb the arithmetic:
59
-
60
- - junk rows with a `0.00` amount (page headers picked up as transactions)
61
- - wrong dates
62
- - garbled or truncated descriptions
63
- - two errors that cancel out
64
-
65
- **"Provably arithmetically consistent" is the honest claim. "Provably correct" is not,
66
- and is not made here.**
67
-
68
- ## Free test mode — try it on your own statement
69
-
70
- ```bash
71
- python -m statementproof YOUR_STATEMENT.pdf # validate, print a report
72
- python -m statementproof YOUR_STATEMENT.pdf --csv out.csv
73
- python -m statementproof YOUR_STATEMENT.pdf --diagnostic # shareable layout report
74
- ```
75
-
76
- **It runs entirely on your machine. Nothing is uploaded, nothing is stored, no file is
77
- written unless you name one with `--csv`.**
78
-
79
- That is not a policy, it is a property of the code, and it is tested:
80
- `tests/test_privacy.py` parses every module's AST and **fails the build if any
81
- networking library is imported anywhere in the package.**
82
-
83
- ### The `--diagnostic` flag, and why it exists
84
-
85
- The single thing that would most improve this tool is a library of real statement
86
- *layouts*. A layout can be described without describing anyone's money, so
87
- `--diagnostic` prints exactly that: column positions, column density, date-token
88
- **shapes** (`DD/DD`, not `10/02`), and where extraction broke.
89
-
90
- It contains **no amounts, no balances, no descriptions, no dates, no account numbers,
91
- no names, and not even the filename.** It prints to your screen so you can read the
92
- whole thing before deciding whether to share it. The tool never sends it anywhere —
93
- there is no code that could.
94
-
95
- Those exclusions are asserted by tests against a known statement, not just intended.
96
-
97
- ## Status
98
-
99
- Early, and scoped to **text-layer PDFs only** — statements downloaded from a bank
100
- portal. Scans and photographs are not supported; the tool detects them and says so
101
- rather than producing garbage.
102
-
103
- **7/7 layouts extracted exactly, 0 false assurances.** Six are synthetic; the seventh
104
- is reproduced from a real bank's published specimen and is the useful one — it found
105
- three bugs the synthetic set never could, including `MM/DD` dates with no year, which
106
- alone produced **0/21 extracted** while the synthetic suite still reported 6/6.
107
-
108
- ⚠️ **Passing a test suite written by the author of the code under test is worth very
109
- little.** Six invented layouts passed while a real bank's date format extracted
110
- nothing. **No real customer file has been processed yet** — which is what the free
111
- test mode above is for.
112
-
113
- python statementproof/tests/make_statements.py # build synthetic corpus
114
- python statementproof/tests/make_real_derived.py # build real-bank-derived layout
115
- python statementproof/tests/score.py # score extraction
116
- python statementproof/tests/test_failure_modes.py # validator behaviour
117
- python statementproof/tests/test_privacy.py # privacy promises
@@ -1,96 +0,0 @@
1
- # statementproof
2
-
3
- Bank statement PDF → CSV extraction that **tells you when it got it wrong.**
4
-
5
- Most converters hand you output with no way to know if it is correct. A bank
6
- statement is one of the few documents carrying its own checksum — the balances.
7
-
8
- ## What it does differently
9
-
10
- **1. Geometry, not regex.** The most-cited converter failure is *"columns shift,
11
- debit and credit values land in the wrong places."* That happens because
12
- `extract_text()` flattens a 2-D layout and discards x-position — the only signal that
13
- distinguishes a debit column from a credit column. This reads word coordinates and
14
- clusters money columns by their right edges.
15
-
16
- **2. Column roles from arithmetic, not headers.** Which column is the running balance
17
- is decided by behaviour, not by header text — header text differs across banks and is
18
- often missing on continuation pages.
19
-
20
- **3. Sign from the balance chain.** If the balance went down, it was a debit,
21
- regardless of whether a minus glyph survived extraction.
22
-
23
- **4. It refuses to bluff.** With nothing to check against, output is `UNVERIFIED` —
24
- never a silent pass.
25
-
26
- ## Verdicts
27
-
28
- | verdict | meaning |
29
- |---|---|
30
- | `VERIFIED` | transactions reproduce the statement's own balances |
31
- | `FAILED` | they do not — **with the offending row named** |
32
- | `UNVERIFIED` | statement carries no balances to check against |
33
-
34
- ## What it CANNOT catch — read this
35
-
36
- The check is **arithmetic consistency**, not correctness. It cannot see errors that do
37
- not disturb the arithmetic:
38
-
39
- - junk rows with a `0.00` amount (page headers picked up as transactions)
40
- - wrong dates
41
- - garbled or truncated descriptions
42
- - two errors that cancel out
43
-
44
- **"Provably arithmetically consistent" is the honest claim. "Provably correct" is not,
45
- and is not made here.**
46
-
47
- ## Free test mode — try it on your own statement
48
-
49
- ```bash
50
- python -m statementproof YOUR_STATEMENT.pdf # validate, print a report
51
- python -m statementproof YOUR_STATEMENT.pdf --csv out.csv
52
- python -m statementproof YOUR_STATEMENT.pdf --diagnostic # shareable layout report
53
- ```
54
-
55
- **It runs entirely on your machine. Nothing is uploaded, nothing is stored, no file is
56
- written unless you name one with `--csv`.**
57
-
58
- That is not a policy, it is a property of the code, and it is tested:
59
- `tests/test_privacy.py` parses every module's AST and **fails the build if any
60
- networking library is imported anywhere in the package.**
61
-
62
- ### The `--diagnostic` flag, and why it exists
63
-
64
- The single thing that would most improve this tool is a library of real statement
65
- *layouts*. A layout can be described without describing anyone's money, so
66
- `--diagnostic` prints exactly that: column positions, column density, date-token
67
- **shapes** (`DD/DD`, not `10/02`), and where extraction broke.
68
-
69
- It contains **no amounts, no balances, no descriptions, no dates, no account numbers,
70
- no names, and not even the filename.** It prints to your screen so you can read the
71
- whole thing before deciding whether to share it. The tool never sends it anywhere —
72
- there is no code that could.
73
-
74
- Those exclusions are asserted by tests against a known statement, not just intended.
75
-
76
- ## Status
77
-
78
- Early, and scoped to **text-layer PDFs only** — statements downloaded from a bank
79
- portal. Scans and photographs are not supported; the tool detects them and says so
80
- rather than producing garbage.
81
-
82
- **7/7 layouts extracted exactly, 0 false assurances.** Six are synthetic; the seventh
83
- is reproduced from a real bank's published specimen and is the useful one — it found
84
- three bugs the synthetic set never could, including `MM/DD` dates with no year, which
85
- alone produced **0/21 extracted** while the synthetic suite still reported 6/6.
86
-
87
- ⚠️ **Passing a test suite written by the author of the code under test is worth very
88
- little.** Six invented layouts passed while a real bank's date format extracted
89
- nothing. **No real customer file has been processed yet** — which is what the free
90
- test mode above is for.
91
-
92
- python statementproof/tests/make_statements.py # build synthetic corpus
93
- python statementproof/tests/make_real_derived.py # build real-bank-derived layout
94
- python statementproof/tests/score.py # score extraction
95
- python statementproof/tests/test_failure_modes.py # validator behaviour
96
- python statementproof/tests/test_privacy.py # privacy promises
@@ -1,117 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: statementproof
3
- Version: 0.1.0
4
- Summary: Extract transactions from bank statement PDFs -- and prove the extraction is right, or say it isn't.
5
- License: MIT
6
- Keywords: bank-statement,pdf,csv,bookkeeping,accounting,reconciliation,extraction,converter,quickbooks,xero
7
- Classifier: Development Status :: 3 - Alpha
8
- Classifier: Intended Audience :: Financial and Insurance Industry
9
- Classifier: Topic :: Office/Business :: Financial :: Accounting
10
- Classifier: Topic :: Text Processing :: Filters
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Operating System :: OS Independent
14
- Requires-Python: >=3.9
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: pdfplumber>=0.10
18
- Provides-Extra: dev
19
- Requires-Dist: reportlab>=4.0; extra == "dev"
20
- Dynamic: license-file
21
-
22
- # statementproof
23
-
24
- Bank statement PDF → CSV extraction that **tells you when it got it wrong.**
25
-
26
- Most converters hand you output with no way to know if it is correct. A bank
27
- statement is one of the few documents carrying its own checksum — the balances.
28
-
29
- ## What it does differently
30
-
31
- **1. Geometry, not regex.** The most-cited converter failure is *"columns shift,
32
- debit and credit values land in the wrong places."* That happens because
33
- `extract_text()` flattens a 2-D layout and discards x-position — the only signal that
34
- distinguishes a debit column from a credit column. This reads word coordinates and
35
- clusters money columns by their right edges.
36
-
37
- **2. Column roles from arithmetic, not headers.** Which column is the running balance
38
- is decided by behaviour, not by header text — header text differs across banks and is
39
- often missing on continuation pages.
40
-
41
- **3. Sign from the balance chain.** If the balance went down, it was a debit,
42
- regardless of whether a minus glyph survived extraction.
43
-
44
- **4. It refuses to bluff.** With nothing to check against, output is `UNVERIFIED` —
45
- never a silent pass.
46
-
47
- ## Verdicts
48
-
49
- | verdict | meaning |
50
- |---|---|
51
- | `VERIFIED` | transactions reproduce the statement's own balances |
52
- | `FAILED` | they do not — **with the offending row named** |
53
- | `UNVERIFIED` | statement carries no balances to check against |
54
-
55
- ## What it CANNOT catch — read this
56
-
57
- The check is **arithmetic consistency**, not correctness. It cannot see errors that do
58
- not disturb the arithmetic:
59
-
60
- - junk rows with a `0.00` amount (page headers picked up as transactions)
61
- - wrong dates
62
- - garbled or truncated descriptions
63
- - two errors that cancel out
64
-
65
- **"Provably arithmetically consistent" is the honest claim. "Provably correct" is not,
66
- and is not made here.**
67
-
68
- ## Free test mode — try it on your own statement
69
-
70
- ```bash
71
- python -m statementproof YOUR_STATEMENT.pdf # validate, print a report
72
- python -m statementproof YOUR_STATEMENT.pdf --csv out.csv
73
- python -m statementproof YOUR_STATEMENT.pdf --diagnostic # shareable layout report
74
- ```
75
-
76
- **It runs entirely on your machine. Nothing is uploaded, nothing is stored, no file is
77
- written unless you name one with `--csv`.**
78
-
79
- That is not a policy, it is a property of the code, and it is tested:
80
- `tests/test_privacy.py` parses every module's AST and **fails the build if any
81
- networking library is imported anywhere in the package.**
82
-
83
- ### The `--diagnostic` flag, and why it exists
84
-
85
- The single thing that would most improve this tool is a library of real statement
86
- *layouts*. A layout can be described without describing anyone's money, so
87
- `--diagnostic` prints exactly that: column positions, column density, date-token
88
- **shapes** (`DD/DD`, not `10/02`), and where extraction broke.
89
-
90
- It contains **no amounts, no balances, no descriptions, no dates, no account numbers,
91
- no names, and not even the filename.** It prints to your screen so you can read the
92
- whole thing before deciding whether to share it. The tool never sends it anywhere —
93
- there is no code that could.
94
-
95
- Those exclusions are asserted by tests against a known statement, not just intended.
96
-
97
- ## Status
98
-
99
- Early, and scoped to **text-layer PDFs only** — statements downloaded from a bank
100
- portal. Scans and photographs are not supported; the tool detects them and says so
101
- rather than producing garbage.
102
-
103
- **7/7 layouts extracted exactly, 0 false assurances.** Six are synthetic; the seventh
104
- is reproduced from a real bank's published specimen and is the useful one — it found
105
- three bugs the synthetic set never could, including `MM/DD` dates with no year, which
106
- alone produced **0/21 extracted** while the synthetic suite still reported 6/6.
107
-
108
- ⚠️ **Passing a test suite written by the author of the code under test is worth very
109
- little.** Six invented layouts passed while a real bank's date format extracted
110
- nothing. **No real customer file has been processed yet** — which is what the free
111
- test mode above is for.
112
-
113
- python statementproof/tests/make_statements.py # build synthetic corpus
114
- python statementproof/tests/make_real_derived.py # build real-bank-derived layout
115
- python statementproof/tests/score.py # score extraction
116
- python statementproof/tests/test_failure_modes.py # validator behaviour
117
- python statementproof/tests/test_privacy.py # privacy promises
File without changes
File without changes
File without changes