Files
command-center/agent/managed-skills/pdf-widget-layer-census/SKILL.md
T
Frank 8af40c402b chore(agent): commit the machine tier and the doctrine text the checkout was already running
Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and
`merge --ff-only` refuses while tracked paths are dirty. Discard is not available here
(workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed.

- `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already
  byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new
  prose — the commit exists so the trunk merge can proceed.
- `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat
  owns (AGENTS.md § Live-sync tiers).

`ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the
only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the
inert all-zero AWS example id — and they appear inside the two skill pages that teach
that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged
gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal
dies with this landing. No `--no-verify` was used: the gate ran and its verdict is
recorded here.

Refs #61
2026-10-21 01:44:51 -07:00

61 lines
2.7 KiB
Markdown

---
name: pdf-widget-layer-census
description: "Census a real-world \"flat\" PDF before assuming it needs field injection: Quartz/Preview exports often already carry an AcroForm widget layer under underscore rules; also audits pdf-lib flatten residue."
---
# Real-PDF census (widget-first, then judge)
A PDF that *looks* flat (`pdftotext` shows `____` fill rules) may already contain a
full AcroForm widget layer — macOS Preview/Quartz exports write widgets with
transparent rects under drawn underscores. Injecting fields into such a file
duplicates/shadows widgets. Always census before touching the pipeline.
## Steps
1. **Surface facts** (host):
```bash
pdfinfo file.pdf # "Form: AcroForm" hints at a widget layer
pdftotext -layout file.pdf - # label lines + underscore rules = intended fields
```
2. **Widget census** — authoritative check. With the franksign sidecar image,
the image ENTRYPOINT *is* `inject_fields.py`; override it:
```bash
podman run --rm --entrypoint python -v ~/Downloads:/in:z \
localhost/franksign-pdf-field-sidecar:local -c "
import pymupdf
d = pymupdf.open('/in/file.pdf')
for p in d.pages():
for w in p.widgets():
print(w.field_name, w.field_type_string, [round(v) for v in w.rect])
print('widgets:', sum(1 for p in d.pages() for _ in p.widgets()),
'annots:', sum(1 for p in d.pages() for _ in p.annots()))
"
```
3. **Fill test**: if widgets exist, `fillTemplate()` (pdf-lib) consumes the file
AS-IS — spec.json + sidecar are unnecessary for it. Flatten-verify below.
## Flatten audit gotchas
- `pdfinfo` prints `Form: AcroForm` even on correctly flattened pdf-lib output —
pdf-lib `flatten()` removes every *widget/annotation* but leaves the field
*dictionary*. Truth = MuPDF widget enumeration (0), not the pdfinfo line.
- `describeForm(bytes, specJson)` in `packages/pdf` parses the SPEC, not the
PDF, for the field list — pass a spec or skip it; calling it spec-less throws
`JSON Parse error`.
## Decision rule
- widgets > 0 → the widget layer IS the spec (names/types/rects, flip y to
bottom-left origin); NEVER run `inject_fields.py` over it.
- widgets = 0 → genuine flat form: sidecar injection with a spec (position
detection = issue #14 territory: underscore-run rects, label-derived names).
- Missing signature widget is normal ("please sign" is prose); franksign
decision 19: the typed full name is the signature.
## Privacy
Real documents are personal: scratch copies in /tmp, placeholder fill values,
destroy scratch (`rm /tmp/*` is fine OUTSIDE the repo; repo deletions still go
to `.AGENTTRASH/`). Never commit the document, a spike script touching it, or
its extracted text into the vault.