h2. The Ask {{graft_figures}} in {{src/quber/core/figures/graft.py}} turns every figure that overlaps no picture in the parse into an error string (lines 158-162) and never adds it to {{pairs}}, so {{_attach}} never runs and no element in the document ever carries that figure's text. The module's own docstring states the intended behaviour and contradicts the code: "A figure over no picture at all is surfaced as an error and never dropped, since a figure the scan read that nothing holds is a value that vanishes." It is worse than a plain drop. The correction step in {{src/quber/core/figures/correct.py}}, around line 116, deletes the printed text fragments that sit under any figure the scan returned, including the unmatched ones. The printed labels are removed from the parse on the strength of a figure whose text is then thrown away. The page ends up holding less than if the figure scan had never run. h3. Reproduce Document: {{s3://qubera-docs/rj.reit/SEVN-Q1-2026-Earnings-Presentation.pdf}}, 23 pages, put through the playground's quber workflow on 2026-07-27. Artifacts in {{experiments/ade_rag_playground/data/uploads/sevn-q1-2026-aarnings-pres-artifacts/}}. The figure stage nominated 7 pages (6, 7, 8, 9, 10, 11, 17), scanned all 7, spent 21 credits, and produced 11 figure records plus 1 table read off a page image. {{SEVN-Q1-2026-Earnings-Presentation.figure.complete.json}} records 3 errors, all of the unmatched kind: two on page 9 and one on page 17. Page 9 of the deck prints a stacked bar chart on the left and two donut charts down the right side. "Geographic Region" reads South 32%, East 31%, West 23%, Midwest 14%. "Property Type" reads Office 23%, Hotel 17%, Student Housing 16%, Industrial 15%, Multifamily 12%, Other 10%, Self Storage 7%. Both are, per the footnote, based on principal balance of loans held for investment as of March 31, 2026. ADE read both donuts correctly. Their text is in {{SEVN-Q1-2026-Earnings-Presentation.figures.json}} under chunk ids {{6624116f-8d51-4b8e-8b1b-3605daf55c8e}} and {{f095af71-2fc4-476d-8a3c-5aa9d95c3b5c}}, both with {{picture_ref: null}}. Docling detected no picture over either donut, so the graft had nothing to attach them to. The correction step then removed 22 text fragments from page 9, every donut segment label and percentage, listed in the {{removed}} array of the same file with reasons such as "Donut chart segment label for East region". h3. Actual In the document that gets ingested: * Page 9 of {{SEVN-Q1-2026-Earnings-Presentation.unified.json}} holds 9 text items: the slide title, the two donut headings, the footnote, the page furniture and the page number. No segment label, no percentage. * No picture on page 9 carries a description for either donut. Only {{#/pictures/11}}, the bar chart, has one. * In the playground's Postgres store ({{ade_playground.chunks}}, document_id 173, slug {{sevn-q1-2026-aarnings-pres}}, 328 chunks) the string "Midwest" appears zero times. The geographic breakdown is unreachable by retrieval. The values survive only in {{SEVN-Q1-2026-Earnings-Presentation.figures.json}} and the raw page response {{SEVN-Q1-2026-Earnings-Presentation.p9.ade.json}}, neither of which the ingest reads for figure text. The third error, on page 17, is the decorative green banner at the foot of the page. Nothing is lost there. h3. Expected A figure that matches no picture in the parse should be inserted into the document as a new picture at the box the scan drew, and then carry its text the same way a matched figure does. The pieces already exist in the same function for the split case: {{_prov}} builds the provenance, {{_crop}} cuts the bitmap, {{document.insert_picture(sibling=..., after=True)}} places it, and {{_attach}} puts the text and the scan's identity on it. What is missing is the anchor for a figure that has no surviving sibling on its page, and the decision of where it sits in reading order. h3. Severity High. This is a financial document. A chart the scan read, and for which the pipeline then deleted the printed labels, leaves the document holding neither reading. Any deck whose charts docling misses on detection loses that content silently, and the only trace is an error string in the run record. h2. Why now / What's open The fix has to settle five points that are not decided yet: # Where the injected picture sits in the body's reading order, given there is no picture on the page to anchor to. # Whether it carries a bitmap cut from the page, and at what resolution when no picture on the page supplies a dpi. # The parse classifies nothing for an injected picture, so the furniture check that drops logos and wordmarks has no class to read. Page 17's decorative banner would be injected as a described picture. Decide whether that is accepted or filtered another way. # Idempotency: on a second run over the enriched parse the injected picture should match the same figure's box and be filled rather than duplicated. # Whether the run record keeps surfacing the unmatched case in {{errors}} once it is handled, reworded to say the figure was injected. It should stay visible, since it is still a gap in the parse. h2. Acceptance Criteria (provisional) h3. AC1: An unmatched figure's reading reaches the document * *Verify by:* rerun the playground quber workflow over {{SEVN-Q1-2026-Earnings-Presentation.pdf}}. * *Expected:* page 9 of the unified document carries a picture for each donut chart, each holding the text the scan read. * *Show:* the page 9 picture list before and after, and the descriptions traced back to chunk ids {{6624116f-8d51-4b8e-8b1b-3605daf55c8e}} and {{f095af71-2fc4-476d-8a3c-5aa9d95c3b5c}}. h3. AC2: The printed labels are retrievable again * *Verify by:* reingest the document and query the playground store. * *Expected:* the geographic and property type breakdowns are retrievable, including the values that were deleted from the parse. * *Show:* a count of "Midwest" in {{ade_playground.chunks}} greater than zero, and the chunk text carrying South 32%, East 31%, West 23%, Midwest 14%. h3. AC3: Nothing that was already working regresses * *Verify by:* the same run, over all 7 scanned pages. * *Expected:* matched and split figures attach exactly as before; page 17's decorative banner does not introduce spurious content. * *Show:* per page counts of pictures and attached descriptions, and the page 17 elements. h3. AC4: A second pass does not duplicate * *Verify by:* run the workflow twice over the same document. * *Expected:* the second run matches the injected picture to the same figure box and fills it, rather than adding another picture. * *Show:* picture counts and refs from both runs. h3. AC5: The gap stays visible in the run record * *Verify by:* read {{SEVN-Q1-2026-Earnings-Presentation.figure.complete.json}} after the fix. * *Expected:* the unmatched figures are still surfaced, worded to say the figure was injected rather than that it failed. * *Show:* the three entries for pages 9 and 17. h2. Current State To Do. The defect is confirmed against a real run, and the missing behaviour is named in the module's own docstring. The approach is open: the five points above are undecided and need a plan or design review before implementation. h2. Links Epic QUE-1 (Document Processing). Standards: see docs/ENGINEERING_STANDARDS.md