P5a plan: PDF documents — seven Ornith tasks with acceptance tests first

docs/plans/p5a: 01 kind+fetch limits, 02 pdftext child + runner, 03 dcache PDF tables,
04 pdfpool, 05 pdfdoc render (map/pages/grep), 06 api, 07 digest citations, metrics, CLI,
skill, unit, README. Given tests compile against a panic-only skeleton and fail there for the
intended reasons; PDFs for tests are built by internal/pdftest (given), plus two qpdf-encrypted
fixtures.

Owner changes for the run: vendor go-pdfkit/extract v0.3.0 + reader v0.6.0 (pinned via
tools.go until task 02); AGENTS.md, tools/run-plan.sh (enforces a Co-Authored-By trailer for
the model), docs/implementer-log.md, `make gate`; gofmt (whitespace) on clean.go and guard;
TestUnsupportedType uses a zip now that PDFs are supported; requestDeadline 90→210 s and
writeTimeout 120→240 s for the PDF path's worst case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 20:47:38 -07:00
co-authored by Claude Opus 5.5
parent 3f2b78d4aa
commit cfde35397a
115 changed files with 26422 additions and 43 deletions
+46
View File
@@ -0,0 +1,46 @@
# P5a implementation plan: PDF documents
> **For the implementing model:** do not work from this file. The owner gives you one task file
> at a time. This file is the index for the owner and the reviewer.
**Goal:** `docs/P5a.md`. sift fetches, extracts and serves PDFs, so agents stop running
`pdftotext` in the shell. Engine: `github.com/go-pdfkit/extract` v0.3.0 (bake-off, P5a §3),
vendored by the owner before the run.
| Task | Package(s) | Given |
|---|---|---|
| 01-kind-fetch | `internal/clean`, `internal/fetch` | `clean/kind_test.go`, `fetch/pdf_test.go` |
| 02-pdftext | `internal/pdftext`, `cmd/sift` (one dispatch line) | `pdftext/pdftext_test.go`, `internal/pdftest/pdftest.go`, `tests/testdata/pdf/*` |
| 03-dcache | `internal/dcache` | `dcache/pdf_test.go` |
| 04-pdfpool | `internal/pdfpool` | `pdfpool/pdfpool_test.go` |
| 05-pdfdoc | `internal/pdfdoc` | `pdfdoc/pdfdoc_test.go` |
| 06-api | `internal/api` | `api/pdf_test.go` |
| 07-digest-cli-docs | `internal/digest`, `internal/metrics`, `cmd/sift`, `internal/api` (metric calls), `skill/`, `nix/module.nix`, `README.md` | `digest/pages_test.go`, `metrics/pdf_test.go` |
**Order matters:** 05 imports 02's types; 06 uses 01–05; 07 wires metrics into 06's file.
**How this plan was made:** acceptance tests first, no reference implementation. The given tests
compiled against a panic-only skeleton of every new name, on this repository at the plan
commit, and failed there for the intended reasons; every earlier test stayed green. The PDFs the
tests use are built by `internal/pdftest` (a given file) at test time. The only binary fixtures
are two small qpdf-encrypted copies of the three-page test document (`tests/testdata/pdf/README.md`).
**Owner changes made before the run** (plan commit):
- `go.mod`, `go.sum`, `vendor/`: `go-pdfkit/extract` v0.3.0, `go-pdfkit/reader` v0.6.0 (and its
`pdffont`), pinned through `tools.go` until task 02 imports them. `flake.nix` uses
`vendorHash = null`, so the nix build reads `vendor/`.
- `internal/api/api_test.go`: `TestUnsupportedType` now uses `application/zip`; a PDF is no
longer unsupported.
- `gofmt -w` on `internal/clean/clean.go`, `internal/guard/guard_test.go`,
`internal/guard/iana.go` (whitespace only), so the new `make gate` target passes on master.
- `AGENTS.md`, `tools/run-plan.sh`, `docs/implementer-log.md`, `make gate`.
**Attribution:** `tools/run-plan.sh` gives the model the exact trailer
`Co-Authored-By: <model> <<model>@llama.cpp.invalid>` and refuses a commit without it.
**Where it runs:** a separate checkout (`~/src/sift-impl` on straylight), branch `p5a`. Nothing
reaches orion until the owner's review, the merge, and straylight's pin bump.
## Changes during the run
(none yet)