File size: 7,118 Bytes
3a5b10f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
efdb021
3a5b10f
 
 
 
 
 
 
 
 
9fcad7c
3a5b10f
 
 
 
 
 
46a0566
3a5b10f
 
 
 
 
 
57ce2a8
3a5b10f
 
 
 
 
 
 
3cc1222
3a5b10f
 
 
 
 
 
 
21d0bcd
3a5b10f
 
 
 
 
4f9a837
3a5b10f
 
 
 
 
 
 
 
 
 
7306527
3a5b10f
 
 
 
 
 
 
 
 
 
 
b3d1b56
3a5b10f
 
 
 
 
28cf3cf
3a5b10f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# PROGRESS.md β€” Autonomous Build Ledger

This file is the memory for the overnight run. It outlives any single agent
session. The loop reads it at the start of every iteration, does the **next
unchecked task in the TONIGHT section only**, proves the task's acceptance
check, commits, and ticks the box.

## Protocol (read every iteration)

1. Do the next unchecked task under **TONIGHT**, exactly one per iteration.
2. Implement it per `docs/05_build_plan.md` and the other specs in `docs/`.
3. Run the task's **Check** command and paste the output (the loop's evaluator
   only sees what is printed).
4. If it passes: commit just that task's changes with the listed **Commit**
   message; tick the box; commit the ledger update.
5. If it fails after reasonable attempts: add a one-line note under **BLOCKED**,
   commit, and move to the next task. Do not halt the whole run.
6. **Never** start a task under **TOMORROW**.
7. **Never** add a dependency outside the night set in task **N1**.
8. The specs already exist in `docs/` β€” do not regenerate or edit them.

When every TONIGHT box is checked, run `uv run pytest -q` and
`uv run ruff check .`; if both are clean, print `DONE_ALL` and stop.

---

## Night dependency set (the ONLY packages to add tonight)

- Runtime: `pydantic`, `pydantic-settings`
- Dev: `pytest`, `ruff`

Everything else (docling, paddleocr/pytesseract, google-genai, ollama, gradio,
watchdog) belongs to TOMORROW and must NOT be added tonight.

---

## TONIGHT

- [x] **N1 β€” Project scaffold** (build plan 0.1)
  Run `uv init`; `uv python pin 3.11`; set `requires-python = ">=3.11"`. Create
  the `src/doc_agent/` package tree and `tests/` from the setup-doc layout (the
  `docs/` specs are already present β€” leave them). Add `.gitignore` (ignore
  `data/`, `.env`, `.venv/`, caches; **commit** `uv.lock` and `.python-version`)
  and an empty `README.md`. Add night deps: `uv add pydantic pydantic-settings`
  and `uv add --dev pytest ruff`.
  Check: `uv sync && uv run python -c "import sys; assert sys.version_info[:2]==(3,11)" && cat .python-version`
  Commit: `phase 0.1: project scaffold (uv, py3.11, package layout)`

- [x] **N2 β€” Config loader** (0.2)
  `src/doc_agent/config.py` with pydantic-settings: load env, validate combos
  (gemini requires key; `vision_direct` requires a multimodal backend), fail
  fast with clear messages. Add `tests/test_config.py`.
  Check: `uv run pytest tests/test_config.py -q`
  Commit: `phase 0.2: config loader with validation`

- [x] **N3 β€” Document schema** (1.1)
  `src/doc_agent/schema/models.py`: `Document` and `LineItem` per
  `docs/03_data_and_extraction_spec.md`, with money→float and date→ISO
  normalizers. Add `tests/test_schema.py`.
  Check: `uv run pytest tests/test_schema.py -q`
  Commit: `phase 1.1: pydantic document schema + normalizers`

- [x] **N4 β€” Validation rules** (1.2)
  `src/doc_agent/validation/rules.py`: hard rules H1–H4, soft rules S1–S4,
  monetary epsilon, returning a structured report. Pure functions, no I/O. Add
  `tests/test_validation.py` (reconciling totals pass H2/H3; mismatches fail;
  soft failures recorded without forcing review).
  Check: `uv run pytest tests/test_validation.py -q`
  Commit: `phase 1.2: validation rules (hard/soft + arithmetic checks)`

- [x] **N5 β€” Confidence & routing** (1.3)
  `src/doc_agent/routing/score.py`: pure `score(data, report, model_signal)` and
  `route(score, report)` with hard-failure short-circuit. Add
  `tests/test_routing.py` (hard fail β‡’ review regardless of score; threshold
  boundary; missing required fields lower score).
  Check: `uv run pytest tests/test_routing.py -q`
  Commit: `phase 1.3: confidence scoring + routing decision`

- [x] **N6 β€” Modality detection** (2.1)
  `src/doc_agent/parsing/detect.py`: map a file to `native_pdf | image` by
  extension/MIME. Add `tests/test_detect.py`.
  Check: `uv run pytest tests/test_detect.py -q`
  Commit: `phase 2.1: modality detection`

- [x] **N7 β€” Backend interface + offline stub** (2.4 + stub)
  `src/doc_agent/backends/base.py`: the `ExtractionBackend` protocol,
  `BackendResult`, and a factory built from config.
  `src/doc_agent/backends/stub.py`: a `StubBackend` returning deterministic,
  schema-valid `Document` data with no network (this is the stub the smoke test
  and CLAUDE.md reference). **Do NOT implement `gemini.py` or `ollama.py`
  tonight.** Add `tests/test_backends.py` (factory returns configured backend;
  unknown backend β‡’ clear error; stub returns schema-valid data).
  Check: `uv run pytest tests/test_backends.py -q`
  Commit: `phase 2.4: backend interface + factory + offline stub backend`

- [x] **N8 β€” Core pipeline orchestration** (3.1, stub-backed)
  `src/doc_agent/core.py`: `process_document(path) -> ExtractionResult` chaining
  detect β†’ acquire β†’ `backend.extract` β†’ validate β†’ score β†’ route. Pure of
  side-effects (no file moves, no DB). For tonight, define the `acquire`
  interface and a minimal injectable path so the smoke test can supply a fake
  payload β€” **real Docling/OCR `acquire` is a TOMORROW task**. Define the
  `ExtractionResult` type here. Add `tests/test_core_smoke.py` running
  end-to-end with `StubBackend` + an injected payload (no network), asserting a
  populated result with a decision.
  Check: `uv run pytest tests/test_core_smoke.py -q`
  Commit: `phase 3.1: core pipeline orchestration (stub-backed smoke test)`

- [x] **N9 β€” Idempotency helper** (3.2)
  A content-hash helper so the same file is not reprocessed across runs. Add
  `tests/test_hash.py` (same file β†’ same hash).
  Check: `uv run pytest tests/test_hash.py -q`
  Commit: `phase 3.2: content-hash idempotency helper`

- [x] **N-FINAL β€” Full green gate**
  Run the whole suite and linter; fix anything red until clean.
  Check: `uv run pytest -q && uv run ruff check .`
  Commit: `chore: full suite + lint green` (only if any fixes were needed)

---

## β›” STOP β€” END OF AUTONOMOUS SCOPE

Do not proceed past this line. Everything below requires API keys, a local
model server, large/finicky native dependencies, or live datasets β€” all for the
morning, supervised.

---

## TOMORROW (DO NOT START β€” supervised, needs setup)

- [ ] Add deferred deps: `docling`, (`paddleocr` or `pytesseract`),
  `google-genai`, `ollama`, `gradio`, `watchdog`.
- [ ] 2.2 Docling parser (downloads layout models on first run).
- [ ] 2.3 OCR path (PaddleOCR/Tesseract β€” watch the Paddle/3.11 wheel risk;
  fall back to pytesseract if it won't resolve).
- [ ] Wire the real Docling/OCR `acquire` into `core.py`.
- [ ] 2.5 Gemini backend β€” **needs `GEMINI_API_KEY`**.
- [ ] 2.6 Ollama backend β€” **needs a local Ollama server + pulled model**.
- [ ] 4.1 persistence (SQLite + CSV); 4.2 watcher; 4.3 Gradio web demo.
- [ ] 5 evaluation harness β€” needs datasets + a real backend; **counts against
  the Gemini free-tier daily limit**, so run deliberately.
- [ ] 6 deploy to Hugging Face Spaces.

---

## BLOCKED

(none yet β€” the loop appends one-line entries here)

## RUN LOG

(the loop may append short per-iteration notes here)