WillTools 2026-09-09 -- clean snapshot of the development repo for review
ci / test (push) Successful in 6m14s
ci / test (push) Successful in 6m14s
History-free snapshot of the private development repository at 77a82eb. Code, docs and the public catalogue only: no plant or job knowledge layers, no client, job or producer names (tools/scrub.py clean against the widened term list; a second word-level grep clean). The intro deck is left out because its slide images cannot be checked for job drawings.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""List the PDF library against its ledger.
|
||||
|
||||
python tools/library.py
|
||||
|
||||
Stage 1 of `knowledge/library/RUNBOOK.md`, and nothing more. It answers three
|
||||
questions and refuses to grow a fourth: what is in the drop folder that the
|
||||
ledger has never seen, what has changed under a name the ledger already knows,
|
||||
and how many documents are sitting in each status.
|
||||
|
||||
The identity is the CONTENT HASH, not the filename. A file that moved is the
|
||||
same document; a second copy of a hash already listed is a no-op, which is what
|
||||
makes a re-run cheap -- and it has already saved one 929-page manual from being
|
||||
extracted twice.
|
||||
|
||||
This prints filenames from a gitignored folder, so its OUTPUT can carry a
|
||||
producer's name even though this file never does. Do not paste a line of it
|
||||
into a tracked file; `CLAUDE.md` section 3 has the placeholders.
|
||||
|
||||
Host CPython. The pipeline is discipline, not machinery: if this ever needs a
|
||||
second screen of code, delete the addition and follow the runbook by hand.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
LIBRARY = os.path.join(ROOT, 'knowledge', 'library')
|
||||
LEDGER = os.path.join(LIBRARY, 'LEDGER.md')
|
||||
|
||||
# A ledger index row: | id | `sha256` | `file` | kind | pages | status |
|
||||
_ROW = re.compile(
|
||||
r'^\|[^|]*\|\s*`([0-9a-f]{64})`\s*\|\s*`([^`]+)`\s*\|'
|
||||
r'([^|]*)\|([^|]*)\|([^|]*)\|')
|
||||
|
||||
|
||||
def sha256(path: str) -> str:
|
||||
"""Streamed, because the manual is 122 MB and a read() of it is not free."""
|
||||
h = hashlib.sha256()
|
||||
with open(path, 'rb') as f:
|
||||
for block in iter(lambda: f.read(1 << 20), b''):
|
||||
h.update(block)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def read_ledger():
|
||||
"""Index rows as (hash, filename, status). Missing file is not an error."""
|
||||
if not os.path.exists(LEDGER):
|
||||
return []
|
||||
rows = []
|
||||
with open(LEDGER, encoding='utf-8') as f:
|
||||
for line in f:
|
||||
m = _ROW.match(line.strip())
|
||||
if m:
|
||||
rows.append((m.group(1), m.group(2).strip(),
|
||||
m.group(5).strip().strip('`')))
|
||||
return rows
|
||||
|
||||
|
||||
def dropped_pdfs():
|
||||
"""Every PDF actually sitting in the drop folder, repo-relative."""
|
||||
found = []
|
||||
for base, dirs, files in os.walk(LIBRARY):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
||||
for name in sorted(files):
|
||||
if name.lower().endswith('.pdf'):
|
||||
found.append(os.path.join(base, name))
|
||||
return found
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not os.path.isdir(LIBRARY):
|
||||
print('no library folder at knowledge/library/ -- nothing to list')
|
||||
return 0
|
||||
|
||||
rows = read_ledger()
|
||||
by_hash = {h: (name, status) for h, name, status in rows}
|
||||
by_name = {}
|
||||
for h, name, _ in rows:
|
||||
by_name.setdefault(os.path.basename(name), set()).add(h)
|
||||
|
||||
print('ledger: {0} row(s), {1} distinct document(s)'
|
||||
.format(len(rows), len(by_hash)))
|
||||
|
||||
new, changed, known = [], [], 0
|
||||
for path in dropped_pdfs():
|
||||
rel = os.path.relpath(path, ROOT).replace('\\', '/')
|
||||
digest = sha256(path)
|
||||
if digest in by_hash:
|
||||
known += 1
|
||||
elif os.path.basename(path) in by_name:
|
||||
changed.append((rel, digest))
|
||||
else:
|
||||
new.append((rel, digest))
|
||||
|
||||
print('drop folder: {0} PDF(s) -- {1} already in the ledger'
|
||||
.format(known + len(new) + len(changed), known))
|
||||
|
||||
if new:
|
||||
print('\nNEW -- inventory these (runbook stage 1):')
|
||||
for rel, digest in new:
|
||||
print(' {0} {1}'.format(digest[:16], rel))
|
||||
if changed:
|
||||
print('\nHASH CHANGED -- a known filename holding new content. This is '
|
||||
'a NEW document: reset its row to `inventoried` and re-extract.')
|
||||
for rel, digest in changed:
|
||||
print(' {0} {1}'.format(digest[:16], rel))
|
||||
|
||||
elsewhere = [n for h, n, _ in rows
|
||||
if not os.path.exists(os.path.join(LIBRARY,
|
||||
os.path.basename(n)))]
|
||||
if elsewhere:
|
||||
print('\nrecorded at another location (not in the drop folder), {0}: '
|
||||
'{1}'.format(len(elsewhere), ', '.join(sorted(set(elsewhere)))))
|
||||
|
||||
counts = {}
|
||||
for _, _, status in rows:
|
||||
counts[status] = counts.get(status, 0) + 1
|
||||
if counts:
|
||||
print('\nstatus: ' + ' | '.join(
|
||||
'{0} {1}'.format(k, v) for k, v in sorted(counts.items())))
|
||||
debt = counts.get('extracted', 0)
|
||||
if debt:
|
||||
print('\n{0} document(s) EXTRACTED AND NOT LANDED. That is the debt the '
|
||||
'library exists to drain, not a stage on the way to done -- '
|
||||
'runbook stage 3.'.format(debt))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user