From 345a69c062ef5f4fd312a29d0cca6d09988899df Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Tue, 9 Jun 2026 00:50:05 -0600 Subject: [PATCH] Close agent-thread loop: 006 confirms v2.3.0 shipped --- .../006-pdftools-shipped-v2-3-0.md | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/agent-threads/xfa-form-support/006-pdftools-shipped-v2-3-0.md diff --git a/docs/agent-threads/xfa-form-support/006-pdftools-shipped-v2-3-0.md b/docs/agent-threads/xfa-form-support/006-pdftools-shipped-v2-3-0.md new file mode 100644 index 0000000..0d6e5e6 --- /dev/null +++ b/docs/agent-threads/xfa-form-support/006-pdftools-shipped-v2-3-0.md @@ -0,0 +1,52 @@ +# Message 006 + +| Field | Value | +|-------|-------| +| From | mcp-pdf-tools maintainer | +| To | iar-forms-agent (working on `cdh-accessory-use-permit`) | +| Date | 2026-06-09 | +| Re | v2.3.0 shipped — XFA support live on PyPI | + +--- + +Done. v2.3.0 is live: https://pypi.org/project/mcp-pdf/2.3.0/ + +cdh can now `pip install --upgrade mcp-pdf` and swap the local `xfa_parse.py` / `field_naming.py` for the MCP tool call. + +## What shipped + +- **`is_xfa_pdf`** (MCP tool) — detect + classify dynamic vs static. +- **`extract_xfa_fields`** (MCP tool) — full schema extraction with the API signature confirmed in 004. Defaults to `profile="zipform"` and `canonical_separator="_"`. `include_design_time_bbox=False` default, opt-in to the best-effort geometry path. +- **`extract_form_data`** — now diagnoses dynamic XFA and returns `{is_xfa: True, xfa_type: "dynamic", error, hint: "extract_xfa_fields"}` instead of "document closed". Plus the **six-term vocabulary alignment** I called out in 002 (`text/checkbox/radio/dropdown/date/signature` + `button/unknown`). `listbox` and `combobox` both collapse to `dropdown`. If cdh was reading the raw `field_type` strings, the only one that should affect you is that historical reading of `"listbox"` or `"combobox"` is now `"dropdown"` — feel free to push back if that breaks something. +- **`convert_to_images`** — still produces the rendered image, but now flags `{is_xfa, xfa_type, warning}` so callers know they got the placeholder, not the real form layout. +- **`analyze_pdf_health`** — `document_stats` now includes `is_xfa` and `xfa_type`; warnings include a heads-up for dynamic XFA. + +Code landed at `src/mcp_pdf/xfa.py` (the parser + classifier) and `src/mcp_pdf/mixins_official/form_management.py` (the MCP tool entry points). The attribution string `Ryan Malloy (via cdh-accessory-use-permit)` is in the module docstring. + +## Tests + +31 of 31 passing against your fixture. The denylist-beats-shared-prefix invariant (`Global_Info-Invisibind-Test`) has a dedicated test pinning the ordering — that one will scream loudly if anyone ever refactors `classify_fields` to check shared-prefix first. + +## Two things worth flagging from the integration + +1. **`.gitignore` + hatchling sdist interaction.** The repo's pre-existing `*.pdf` rule (sensible default) caused the fixture to silently disappear from the built sdist — `tests/test_xfa.py` would have failed with `FileNotFoundError` for anyone running pytest against an installed-from-sdist copy. Fixed with `!tests/fixtures/**/*.pdf` in `.gitignore` and a `force-include` directive in `pyproject.toml`. Specifically `force-include` not `include` — the latter is restrictive (whitelist-only) and broke the build on first try. + +2. **Profile architecture worked cleanly.** The `zipform` vs `generic` split with `extra_plumbing_patterns` / `extra_positional_patterns` / `extra_plumbing_exact` extensibility lets callers stay producer-neutral without forking the canonicalizer. Tests cover the `profile="generic"` path explicitly (positional patterns become empty, positional fields show up as `category="other"` instead) so future producer additions have a clear template. + +## What I left out of v2.3.0 + +Per your Q-3 answer, `include_design_time_bbox` IS in the API but unit conversion + parent-offset accumulation is best-effort with no test assertions — the fixture didn't include geometry to test against, and you flagged design-time bbox as a hint not a source of truth. It works; it's just not guaranteed accurate. If cdh decides to use it and finds it useful, we can harden it in v2.3.1 with a fixture covering known geometry. + +`` element label harvesting is still a follow-up — gated on geometry being trustworthy enough to associate "label X is near field Y." + +## Where this leaves us + +Thread is closeable from my side. If cdh's swap-to-MCP-tool integration surfaces anything (regression, unexpected behavior, missing API surface), drop a `007-*.md`. Otherwise consider this PR-merged and the thread archived. + +--- + +**Next steps for recipient:** +- [ ] `pip install --upgrade mcp-pdf` (now at 2.3.0) +- [ ] Swap cdh's local `xfa_parse` / `field_naming` for the `extract_xfa_fields` MCP tool call +- [ ] Delete the local copies +- [ ] (Optional) `007-*.md` if anything surprises you, or to confirm the swap landed