complydoc 0.3.0__py3-none-any.whl
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.
- complydoc/CHANGELOG.md +347 -0
- complydoc/__init__.py +6 -0
- complydoc/audit.py +467 -0
- complydoc/cli.py +1148 -0
- complydoc/config/__init__.py +0 -0
- complydoc/config/loader.py +335 -0
- complydoc/config/model_prices.json +1628 -0
- complydoc/config/pricing.yaml +264 -0
- complydoc/config/readiness.yaml +230 -0
- complydoc/config/schema.py +406 -0
- complydoc/config/sensitive.yaml +371 -0
- complydoc/cost/__init__.py +0 -0
- complydoc/cost/estimator.py +387 -0
- complydoc/cost/price_table.py +192 -0
- complydoc/cost/pricing_import.py +241 -0
- complydoc/cost/tokenizer.py +89 -0
- complydoc/cost/vision.py +106 -0
- complydoc/discovery.py +68 -0
- complydoc/geometry.py +40 -0
- complydoc/ingest/__init__.py +0 -0
- complydoc/ingest/base.py +290 -0
- complydoc/ingest/docx.py +146 -0
- complydoc/ingest/engines/__init__.py +0 -0
- complydoc/ingest/engines/base.py +46 -0
- complydoc/ingest/engines/rapidocr.py +104 -0
- complydoc/ingest/engines/registry.py +53 -0
- complydoc/ingest/engines/tesseract.py +75 -0
- complydoc/ingest/extractors/__init__.py +0 -0
- complydoc/ingest/extractors/base.py +110 -0
- complydoc/ingest/extractors/pdfium.py +65 -0
- complydoc/ingest/extractors/plumber.py +53 -0
- complydoc/ingest/extractors/pypdfreader.py +47 -0
- complydoc/ingest/extractors/registry.py +58 -0
- complydoc/ingest/image.py +92 -0
- complydoc/ingest/ocr.py +126 -0
- complydoc/ingest/pdf.py +697 -0
- complydoc/ingest/registry.py +55 -0
- complydoc/ingest/xlsx.py +90 -0
- complydoc/offline.py +97 -0
- complydoc/overall.py +254 -0
- complydoc/quickwins.py +299 -0
- complydoc/readiness/__init__.py +0 -0
- complydoc/readiness/analyser.py +116 -0
- complydoc/readiness/base.py +89 -0
- complydoc/readiness/registry.py +52 -0
- complydoc/readiness/scoring.py +120 -0
- complydoc/readiness/signals/__init__.py +0 -0
- complydoc/readiness/signals/acroform.py +23 -0
- complydoc/readiness/signals/columns.py +75 -0
- complydoc/readiness/signals/date_formats.py +60 -0
- complydoc/readiness/signals/encryption.py +31 -0
- complydoc/readiness/signals/fonts.py +59 -0
- complydoc/readiness/signals/garbled.py +75 -0
- complydoc/readiness/signals/image_area.py +38 -0
- complydoc/readiness/signals/language.py +73 -0
- complydoc/readiness/signals/ocr_confidence.py +38 -0
- complydoc/readiness/signals/page_size.py +32 -0
- complydoc/readiness/signals/rotation_skew.py +198 -0
- complydoc/readiness/signals/scan_dpi.py +50 -0
- complydoc/readiness/signals/tables.py +124 -0
- complydoc/readiness/signals/text_coverage.py +38 -0
- complydoc/readiness/signals/text_layer.py +35 -0
- complydoc/report/__init__.py +0 -0
- complydoc/report/charts.py +339 -0
- complydoc/report/diffing.py +108 -0
- complydoc/report/html_writer.py +394 -0
- complydoc/report/json_writer.py +24 -0
- complydoc/report/limitations.py +385 -0
- complydoc/report/models.py +400 -0
- complydoc/report/preview.py +379 -0
- complydoc/report/templates/report.html.j2 +1732 -0
- complydoc/report/text_writer.py +69 -0
- complydoc/sample/employee-record.pdf +0 -0
- complydoc/sample/financial-summary.pdf +0 -0
- complydoc/sample/invoice-scan.pdf +79 -0
- complydoc/sample/supplier-list.docx +0 -0
- complydoc/sample/supplier-onboarding.pdf +0 -0
- complydoc/sample/terms-and-conditions.pdf +0 -0
- complydoc/sampling.py +78 -0
- complydoc/sensitive/__init__.py +0 -0
- complydoc/sensitive/base.py +125 -0
- complydoc/sensitive/detectors/__init__.py +0 -0
- complydoc/sensitive/detectors/ner.py +113 -0
- complydoc/sensitive/detectors/regex_detector.py +68 -0
- complydoc/sensitive/masking.py +60 -0
- complydoc/sensitive/registry.py +59 -0
- complydoc/sensitive/scanner.py +224 -0
- complydoc/sensitive/validators.py +313 -0
- complydoc/skill/SKILL.md +122 -0
- complydoc/skill/__init__.py +0 -0
- complydoc/text.py +96 -0
- complydoc/vendor/__init__.py +14 -0
- complydoc/vendor/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +100256 -0
- complydoc/vendor/tiktoken_cache/fb374d419588a4632f3f557e76b4b70aebbca790 +199998 -0
- complydoc/warm.py +44 -0
- complydoc-0.3.0.dist-info/METADATA +362 -0
- complydoc-0.3.0.dist-info/RECORD +100 -0
- complydoc-0.3.0.dist-info/WHEEL +4 -0
- complydoc-0.3.0.dist-info/entry_points.txt +2 -0
- complydoc-0.3.0.dist-info/licenses/LICENSE +21 -0
complydoc/CHANGELOG.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes, newest first. Versions follow [semantic versioning](https://semver.org):
|
|
4
|
+
the major number changes when a report's JSON shape or a config file's meaning breaks,
|
|
5
|
+
the minor number when something is added, the patch number when a measurement is
|
|
6
|
+
corrected. `schema_version` in the JSON is versioned separately and is the field to
|
|
7
|
+
branch on when reading reports programmatically.
|
|
8
|
+
|
|
9
|
+
## [0.3.0] — 2026-09-10
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- The release can publish to PyPI. Publishing the drafted release uploads the
|
|
14
|
+
wheel and sdist already attached to it — the artefacts that were built and
|
|
15
|
+
attested, not a rebuild — over Trusted Publishing, so there is no token
|
|
16
|
+
stored anywhere. The tag deliberately does not do it: a version on PyPI
|
|
17
|
+
cannot be replaced or reused, so the last step before it is a person.
|
|
18
|
+
- PyPI metadata: classifiers, and Homepage, Changelog and Issues links. The
|
|
19
|
+
README's images are absolute URLs now, because PyPI renders it with no
|
|
20
|
+
repository context and relative paths arrive broken.
|
|
21
|
+
- `complydoc demo` audits six synthetic sample documents that ship with the
|
|
22
|
+
tool and opens the report. Evaluating this used to mean finding a folder
|
|
23
|
+
first. The samples carry the problems the tool exists to find — a scan with
|
|
24
|
+
no text layer, a two-column page the readers disagree about, a whitespace
|
|
25
|
+
table, and identifiers of several kinds — and no real person is described in
|
|
26
|
+
any of them.
|
|
27
|
+
- The README shows the report. The product is the page it produces, and the
|
|
28
|
+
repository did not show it.
|
|
29
|
+
- Global readiness, on the front page as a ring. AI readiness asks whether the
|
|
30
|
+
text can be got off the page; this asks whether the folder can be put through
|
|
31
|
+
a pipeline at all, combining content with the cost path it forces and what it
|
|
32
|
+
carries that should not leave. Weights are in `readiness.yaml` and printed
|
|
33
|
+
beside the score. A factor the run did not measure is dropped and the rest
|
|
34
|
+
renormalised — never counted as nought — and the report says how many of the
|
|
35
|
+
three it was built from.
|
|
36
|
+
- The ring shows the composition rather than the score, because the mean hides
|
|
37
|
+
the tail: a folder averaging 71 can still hold two documents nothing can be
|
|
38
|
+
read from, and those two are the ones somebody has to deal with.
|
|
39
|
+
- Quick wins: what to do next, ranked by how much of the folder each touches.
|
|
40
|
+
Every entry names the documents it applies to, says whether complydoc can do
|
|
41
|
+
it or a person has to, and where the consequence follows from prices already
|
|
42
|
+
in the report it is computed — the OCR entry quotes what those documents cost
|
|
43
|
+
today on the image path. None of them predicts a score, because signals
|
|
44
|
+
interact and the only honest way to know is to fix the documents and run the
|
|
45
|
+
audit again.
|
|
46
|
+
- Every sensitive finding carries an evidence tier: `confirmed` when a checksum
|
|
47
|
+
passed, `corroborated` when a label sits beside it, `pattern` for a shape
|
|
48
|
+
alone, and `model` for a statistical guess. The security table shows it and
|
|
49
|
+
breaks a severity tie on it, so a confirmed card number sorts above a name a
|
|
50
|
+
model thought it saw.
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- Cost is off the front page. The tile and the per-1,000 chart move to the Cost
|
|
55
|
+
tab, which is what that tab is for, and the chart leads it. An audit's front
|
|
56
|
+
page should answer whether these documents can be used, not what the pipeline
|
|
57
|
+
would bill — the price only matters once the answer to the first question is
|
|
58
|
+
yes. The only figure left is what a quick win would save, which is the reason
|
|
59
|
+
to act on it rather than a cost breakdown.
|
|
60
|
+
- The model detector reports no confidence rather than 1.0. The small English
|
|
61
|
+
pipeline exposes no per-entity score, so recording one put a guess level with
|
|
62
|
+
a passed checksum — the one place this tool was reporting a number that meant
|
|
63
|
+
something other than what it said. `confidence` is now null there, and the
|
|
64
|
+
`min_confidence: 0.5` configured for names and organisations is gone: it
|
|
65
|
+
filtered nothing and implied a threshold that was never applied.
|
|
66
|
+
- `schema_version` is 3. The report carries `overall` and `quick_wins`, every
|
|
67
|
+
sensitive match carries `evidence`, and `confidence` on a match may be null.
|
|
68
|
+
- The summary quotes Claude Sonnet 5 rather than whichever model happened to be
|
|
69
|
+
cheapest. The cheapest was a moving target — it changed with a catalogue
|
|
70
|
+
refresh rather than with the folder — and it flattered the estimate with a
|
|
71
|
+
model few people would actually run. `compare.headline_model` in
|
|
72
|
+
`pricing.yaml` sets it, and the report falls back to the cheapest priced model
|
|
73
|
+
and still names it when that one is not in the comparison.
|
|
74
|
+
- A model that carried its own id as its name now borrows the catalogue's, so
|
|
75
|
+
the chart no longer reads `zai/glm-5.3-flash` beside `Claude Sonnet 5`. The
|
|
76
|
+
seven curated entries that were written that way are fixed as well.
|
|
77
|
+
- How many documents each architecture reaches is stated once per architecture
|
|
78
|
+
in the legend, instead of beside every bar. On a dozen models that was ninety
|
|
79
|
+
copies of three numbers, crowding out the figures that differ. It stays on
|
|
80
|
+
each bar's own hover.
|
|
81
|
+
- The explanation of a sensitive mark follows the mark instead of appearing
|
|
82
|
+
under the page, and there is one of it. The mark used to carry an SVG
|
|
83
|
+
`<title>` as well, which is the browser's own tooltip, so pointing at a mark
|
|
84
|
+
drew the same words twice in two different boxes. The mark now carries an
|
|
85
|
+
`aria-label`, which says the same thing to a screen reader without drawing
|
|
86
|
+
anything.
|
|
87
|
+
- A mark says what was found, masked exactly as the findings table masks it —
|
|
88
|
+
the last few characters, with the separators kept so the shape stays legible.
|
|
89
|
+
A rectangle and a category left the reader hunting for which item it was.
|
|
90
|
+
`--reveal` puts the whole value there as it does everywhere else.
|
|
91
|
+
- The summary tiles say one thing each. The heading above the first chart no
|
|
92
|
+
longer repeats the tile directly above it.
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- `.complydoc`, where a run writes when nobody passes `--out`, is git-ignored.
|
|
97
|
+
Those reports carry the text read off each page and a picture of every page,
|
|
98
|
+
so a default run inside a repository was leaving document content untracked
|
|
99
|
+
in the working tree.
|
|
100
|
+
|
|
101
|
+
### Performance
|
|
102
|
+
|
|
103
|
+
- A 392-page book took 2.1 GB of memory and now takes 0.99 GB. pdfplumber
|
|
104
|
+
caches every object it parses off a page, and nothing released them, so the
|
|
105
|
+
whole document's characters — 680,000 of them — stayed in memory until the
|
|
106
|
+
run ended. They are dropped as soon as each page has been read. It matters
|
|
107
|
+
most where it was worst: a process pool holds one document per worker, so
|
|
108
|
+
the old figure was multiplied by the number of workers.
|
|
109
|
+
- The coverage helper is fourteen times faster. It called `np.clip` four times
|
|
110
|
+
per rectangle, and numpy's per-call overhead on a single Python float dwarfs
|
|
111
|
+
the arithmetic — on a dense page that was a tenth of the whole run. Plain
|
|
112
|
+
`min`/`max` gives the identical answer.
|
|
113
|
+
|
|
114
|
+
### Internal
|
|
115
|
+
|
|
116
|
+
- Type suppressions are down from twenty to four, and each was removed by
|
|
117
|
+
fixing what caused it rather than by widening the annotation. The largest
|
|
118
|
+
group came from one helper that returned `object` where it had a `Config` in
|
|
119
|
+
hand, which cost eight `type: ignore` comments in commands downstream. The
|
|
120
|
+
four that remain are in the network guard, where assigning to a standard
|
|
121
|
+
library method cannot be expressed in the type system.
|
|
122
|
+
- One severity table instead of two. The report and the readiness score each
|
|
123
|
+
had their own copy, so a fourth severity would have had to be remembered in
|
|
124
|
+
both; the band label is public now rather than reached for as a private name
|
|
125
|
+
from another module.
|
|
126
|
+
- Dead code removed: an unused page property, and a price helper left behind
|
|
127
|
+
when model selection moved from price spread to product line.
|
|
128
|
+
|
|
129
|
+
## [0.2.0] — 2026-09-10
|
|
130
|
+
|
|
131
|
+
### Added
|
|
132
|
+
|
|
133
|
+
- `complydoc compare <path>` runs an audit with every reader and every OCR
|
|
134
|
+
engine installed, so comparing does not mean naming each one by hand. It says
|
|
135
|
+
which it is using before it starts, and says so plainly when there is nothing
|
|
136
|
+
installed to compare against.
|
|
137
|
+
- Extractors are pluggable, and more than one can run in a single pass.
|
|
138
|
+
`--extractor` picks which library reads the text layer; `--compare-extractor`
|
|
139
|
+
reads every page with a second one as well and reports where the two differ.
|
|
140
|
+
Only the first reaches a finding — the rest are measured, never adopted.
|
|
141
|
+
Comparison lives inside a run, so it is the same page on the same machine at the
|
|
142
|
+
same moment rather than two runs that would differ for reasons of their own.
|
|
143
|
+
`complydoc extractors` lists them. With `--extracted-text` on, what each reader made
|
|
144
|
+
of a page is kept, so the Documents page can switch between them and show the text
|
|
145
|
+
itself rather than only how much of it there was.
|
|
146
|
+
- pdfium as a second extractor: measured against pdfplumber on a real 392-page book
|
|
147
|
+
the two agree on the text within one to two per cent, and pdfium reads it about
|
|
148
|
+
thirteen times faster. It provides no table structure and a box per line rather
|
|
149
|
+
than per word, so the signals that need those report that they could not measure
|
|
150
|
+
rather than returning a number that means something else.
|
|
151
|
+
- A third reader for a PDF's text layer, `pypdf`. It is already a dependency,
|
|
152
|
+
so it costs no install and no measurable time, and it shares no code with
|
|
153
|
+
either of the others — which is the only reason a third reading is worth
|
|
154
|
+
having. It returns text and no geometry, so it reports coverage as not
|
|
155
|
+
measured rather than as nought per cent, and the findings that need boxes say
|
|
156
|
+
the same.
|
|
157
|
+
- OCR engines are pluggable the same way, with `--ocr-engine`,
|
|
158
|
+
`--compare-ocr-engine` and `complydoc engines`. Tesseract is included for anyone
|
|
159
|
+
who already has it; it is not a dependency, because it needs a system binary.
|
|
160
|
+
- Where two readers parted company is now shown, not just measured. Each other
|
|
161
|
+
reader's pane carries its own text with the words only it found underlined
|
|
162
|
+
and the words only the kept reader found struck through, so the difference is
|
|
163
|
+
read in place rather than by flipping between two panes and holding both in
|
|
164
|
+
your head. The page bar gains a control that jumps to the next page the
|
|
165
|
+
readers read differently, which on a long document is a handful of pages
|
|
166
|
+
among hundreds.
|
|
167
|
+
- The report tells a reader that walked a page in the wrong order apart from
|
|
168
|
+
one that read different words. They look the same to any similarity score and
|
|
169
|
+
they call for different things: the first scrambled a page it could read, the
|
|
170
|
+
second could not read part of it.
|
|
171
|
+
- A live bar, count and clock while a folder is read. A run over a few hundred
|
|
172
|
+
documents takes minutes, and a terminal that says nothing for minutes is
|
|
173
|
+
indistinguishable from one that has hung. A pipe still gets one line per
|
|
174
|
+
document, and `--quiet` still gets nothing.
|
|
175
|
+
- A vendored model catalogue from models.dev: every current model from the eight
|
|
176
|
+
first-party providers, so `--model` reaches one without anyone having hand-written an
|
|
177
|
+
entry for it. `complydoc models --new N` lists the most recently released, because an
|
|
178
|
+
alphabetical dump sorts a two-year-old model above this month's. It is data on disk —
|
|
179
|
+
a run still reaches no network — and `make prices` refreshes it. Imported prices are
|
|
180
|
+
marked as imported, kept apart from the handful someone verified against a provider's
|
|
181
|
+
page, and a report that prices against one says so in its limitations.
|
|
182
|
+
Batch prices come from litellm, the only one of the two sources that publishes them.
|
|
183
|
+
- The report compares three models per provider rather than whichever ten had been
|
|
184
|
+
written down, so every provider is represented and two of them are no longer missing
|
|
185
|
+
altogether. Each provider is topped up from the catalogue with its most recently
|
|
186
|
+
released models that take images; `compare.per_provider` in `pricing.yaml` sets the
|
|
187
|
+
number. A refreshed catalogue brings a refreshed comparison.
|
|
188
|
+
- Batch pricing, where the provider publishes one. The cost page shows what the same
|
|
189
|
+
tokens cost through a batch endpoint beside the interactive price. Never inferred from
|
|
190
|
+
the customary half price: a discount nobody can check does not belong in a budget.
|
|
191
|
+
- `--save-text <dir>` keeps the text complydoc read, one file per document. Reading a
|
|
192
|
+
scanned folder is the slow part of an audit and it was being thrown away, so the next
|
|
193
|
+
tool to want the text ran OCR over the same pages again.
|
|
194
|
+
- The summary says how long the work took by stage — reading, OCR, signals, identifier
|
|
195
|
+
scan — and what the measured rate means for 100, 1,000, 10,000 and 100,000 documents.
|
|
196
|
+
|
|
197
|
+
### Changed
|
|
198
|
+
|
|
199
|
+
- The difficulty component is called readiness. A high score always meant a document
|
|
200
|
+
that was easy to process, which read backwards under a name promising the opposite.
|
|
201
|
+
The command is `complydoc readiness`, the config file is `readiness.yaml`, the JSON
|
|
202
|
+
carries `readiness` where it carried `difficulty`, and `schema_version` is 2. The
|
|
203
|
+
score bands read the same way round as the number now: ready, workable, needs work,
|
|
204
|
+
not ready. Signal directions are `higher_is_better` and `lower_is_better`.
|
|
205
|
+
- The Documents page is a page viewer rather than a grid of the first twelve pages.
|
|
206
|
+
Every page of a document is reachable, by stepping or by typing a page number, and
|
|
207
|
+
the page sits beside the text that was read off it instead of in a separate tab.
|
|
208
|
+
The two halves are one row of equal height and each scrolls inside its own frame.
|
|
209
|
+
- The Documents page is the file list and the two panels, and nothing else. The
|
|
210
|
+
folder-wide table of readiness signals, the per-document summary line and the list
|
|
211
|
+
of poorly rated signals moved to that document's own Signals tab, where they answer
|
|
212
|
+
a question the reader has actually asked.
|
|
213
|
+
- The text read off each page is in the report by default. Reading a page beside what
|
|
214
|
+
was extracted from it is the point of the tool, and it was behind a flag. The report
|
|
215
|
+
says on its security page that the masking covers the findings table and not the file,
|
|
216
|
+
since the file now reproduces the pages those values were read off.
|
|
217
|
+
`--no-extracted-text` restores a report with no document content.
|
|
218
|
+
- Sensitive marks on the page layout explain themselves on hover: what was found, why it
|
|
219
|
+
was reported, and why that matters. The value itself is never in the explanation.
|
|
220
|
+
- Readings are compared by word rather than by character, and spacing is no
|
|
221
|
+
longer a difference. Every reader breaks lines somewhere slightly different,
|
|
222
|
+
and counting that marked every page of every document. One measure now backs
|
|
223
|
+
both the number in the table and the marks on the page.
|
|
224
|
+
- The report is laid out to the width of the window rather than a 60rem reading
|
|
225
|
+
column, so the page and its text get the room.
|
|
226
|
+
- Findings on the security page arrive ordered by severity, and every column there
|
|
227
|
+
can be sorted.
|
|
228
|
+
- The page heading repeating the folder path, the timestamp and the version is gone.
|
|
229
|
+
All of it is recorded once, in the footer.
|
|
230
|
+
- The panels are one fixed frame, identical on every document and every page. Their
|
|
231
|
+
height used to follow whichever page image was loaded, so the workspace resized
|
|
232
|
+
every time you stepped a page or picked another file. A document nobody could open
|
|
233
|
+
now draws the same workspace with the reason inside it, rather than a different
|
|
234
|
+
block that resized the page on arrival.
|
|
235
|
+
- The file list sits at the height of the panels, not the column that holds them.
|
|
236
|
+
- Every page starts the same distance below the tab bar, whether or not it opens on
|
|
237
|
+
a heading.
|
|
238
|
+
- `complydoc pricing-import` reads the vendored table, so it works without litellm
|
|
239
|
+
installed, and the entry it generates is marked `price_source: imported` rather than
|
|
240
|
+
being stamped with a `last_verified` date nobody earned.
|
|
241
|
+
|
|
242
|
+
### Performance
|
|
243
|
+
|
|
244
|
+
Measured on this machine: a folder of 102 documents 17.6s to 10.9s with OCR and
|
|
245
|
+
7.4s to 2.9s without, a 392-page book 56.9s to 31.0s.
|
|
246
|
+
|
|
247
|
+
- Skew was measured by rotating the whole page once per candidate angle. The same
|
|
248
|
+
measurement falls out of projecting the ink pixels, which are a tenth of the page,
|
|
249
|
+
and a coarse pass now finds the degree before the fine pass refines it.
|
|
250
|
+
- The entity model loaded a tagger, a dependency parser and a lemmatiser that nothing
|
|
251
|
+
reads, and parsed every page once per category rather than once.
|
|
252
|
+
- The whitespace table pass pulled the text out of every candidate before applying the
|
|
253
|
+
geometric test that rejects almost all of them. The cheap test runs first now, and it
|
|
254
|
+
reuses the words the page has already been asked for instead of clustering its
|
|
255
|
+
characters into words a second time.
|
|
256
|
+
- Worker processes fork from a server that has loaded the models, instead of each
|
|
257
|
+
loading its own copy, and the number of them is chosen from the size of the folder.
|
|
258
|
+
|
|
259
|
+
### Fixed
|
|
260
|
+
|
|
261
|
+
- Two extractors that read a page in a different order are now reported as
|
|
262
|
+
disagreeing. The comparison used to be a character count, which cannot see the
|
|
263
|
+
case it most needs to: on a two-column page, one library reads down the columns
|
|
264
|
+
and another straight across, interleaving every sentence, and both return the
|
|
265
|
+
same number of characters. Readings are now compared in order, and the report
|
|
266
|
+
names the kind of difference rather than only that there was one.
|
|
267
|
+
- Pointing at a sensitive mark on the page layout does something. The marks are drawn
|
|
268
|
+
as outlines, and an SVG shape with no fill answers the pointer only along its stroke —
|
|
269
|
+
on a mark six pixels tall that is two hairlines, so hovering the middle of one hit
|
|
270
|
+
nothing. The explanation also appears under the page at once rather than waiting for
|
|
271
|
+
the browser's own tooltip, and the marks can be tabbed to.
|
|
272
|
+
- DOCX merged cells were counted by object identity, which made the count depend on
|
|
273
|
+
memory reuse and differ between processes reading the same file. They are read from
|
|
274
|
+
the markup now.
|
|
275
|
+
- The OCR engine registers its own shutdown cleanup, at the point it creates the
|
|
276
|
+
native threads, instead of relying on another module importing it during
|
|
277
|
+
interpreter teardown — when the import machinery may already be gone, and a run
|
|
278
|
+
that had already succeeded aborts with a mutex error.
|
|
279
|
+
- The file list sat in the right place only some of the time. `.spread:not([hidden])` also
|
|
280
|
+
matched a panel hidden along with the whole Pages view, because the attribute sits on the
|
|
281
|
+
container, so the list was being centred on a zero-height ghost whenever the signals tab
|
|
282
|
+
was showing. It also now re-aligns when a page is first shown, which it could not do while
|
|
283
|
+
it was hidden.
|
|
284
|
+
- An imported price is no longer reported as a verification that went stale. It was
|
|
285
|
+
never claimed to be verified, and warning once per model buried the run's real
|
|
286
|
+
limitations under a dozen copies of what the provenance entry says once.
|
|
287
|
+
|
|
288
|
+
### Documentation
|
|
289
|
+
|
|
290
|
+
- The README is written for someone running the tool: what it does, how to run it, what the
|
|
291
|
+
flags mean. Architecture, adding a signal, fixtures and the release process moved to
|
|
292
|
+
CONTRIBUTING.md, and this changelog now ships inside the package, so an installed copy can
|
|
293
|
+
say what changed in the version you have.
|
|
294
|
+
- The README says how to keep an installed copy up to date, and why `--reinstall`
|
|
295
|
+
matters as much as `--force`.
|
|
296
|
+
|
|
297
|
+
## [0.1.0]
|
|
298
|
+
|
|
299
|
+
First release.
|
|
300
|
+
|
|
301
|
+
### Audit
|
|
302
|
+
|
|
303
|
+
- Three independent components — cost, extraction readiness, sensitive data — run
|
|
304
|
+
together or one at a time. The report states which of them ran.
|
|
305
|
+
- Cost estimated from measured page geometry and a real tokenizer, across text, OCR and
|
|
306
|
+
vision paths for every priced model. Vision formulas and prices live in
|
|
307
|
+
`pricing.yaml` with a `last_verified` date; a price older than 90 days is reported as
|
|
308
|
+
stale rather than quoted plainly.
|
|
309
|
+
- Nineteen readiness signals, each contributing a measured value, a rating and one
|
|
310
|
+
sentence saying why. Weights and thresholds are configuration, not code, and are
|
|
311
|
+
printed alongside any score. A new signal is one new file plus a registration.
|
|
312
|
+
- Sensitive data scan covering national identifiers for the UK, US, IE, NL, PT, ES, FR
|
|
313
|
+
and DE, EU VAT numbers, IBANs, payment cards and local NER for names and
|
|
314
|
+
organisations, each with its own checksum or validator.
|
|
315
|
+
- Wall-clock time measured per document and projected to a backlog, including the
|
|
316
|
+
observed OCR rate on the machine that ran it.
|
|
317
|
+
|
|
318
|
+
### Safety
|
|
319
|
+
|
|
320
|
+
- The network guard replaces the socket module's outbound entry points before any
|
|
321
|
+
document is opened, in every process, and the test suite asserts a full audit
|
|
322
|
+
completes with it armed. `run.offline_guard` records this in every report.
|
|
323
|
+
- Matched values are masked to the last four characters at most. `--reveal` prints them
|
|
324
|
+
in full, and the report says on its face that it was used. Categories marked
|
|
325
|
+
`never_reveal` stay masked regardless.
|
|
326
|
+
|
|
327
|
+
### Reports
|
|
328
|
+
|
|
329
|
+
- One self-contained HTML file — no network, no bundler, no server — with summary, cost,
|
|
330
|
+
security and per-document pages, and a document browser showing each page beside what
|
|
331
|
+
was extracted from it and what OCR read.
|
|
332
|
+
- A JSON report of the same run, and `--print-json` for piping into another tool.
|
|
333
|
+
- A limitations section generated from the run's own facts: what could not be opened,
|
|
334
|
+
which pages held no readable text, which detectors were unavailable, which prices are
|
|
335
|
+
unverified.
|
|
336
|
+
|
|
337
|
+
### Running it
|
|
338
|
+
|
|
339
|
+
- `complydoc` on its own audits the current directory.
|
|
340
|
+
- `--jobs` spreads documents over a process pool, `--sample` reads a deterministic
|
|
341
|
+
type-proportional subset of a large folder, `--password` opens encrypted PDFs.
|
|
342
|
+
- A packaged agent skill, installed with the tool, so an agent can be told to use it.
|
|
343
|
+
|
|
344
|
+
[Unreleased]: https://github.com/duartecaldascardoso/complydoc/compare/v0.3.0...HEAD
|
|
345
|
+
[0.3.0]: https://github.com/duartecaldascardoso/complydoc/compare/v0.2.0...v0.3.0
|
|
346
|
+
[0.2.0]: https://github.com/duartecaldascardoso/complydoc/compare/v0.1.0...v0.2.0
|
|
347
|
+
[0.1.0]: https://github.com/duartecaldascardoso/complydoc/releases/tag/v0.1.0
|