Repository navigation
Design Decisions
Six decisions shape SlideBridge. The README records the first three as design notes, and the others can be read from the code; where a decision has shown its cost in a run, the cost is stated with it.
A pipeline of five stages can pass its data in memory, which is faster, or through files, which is easier to inspect and to resume. SlideBridge writes JSON, PDF, PNG, and a manifest under one work folder (work/json, work/pdf, work/images, work/reconciled/manifest.json), and each stage reads what the previous one left.
The gain is that a failed or doubtful stage can be run again alone, that --resume can skip decks whose JSON already exists and renders that already validate, and that a person can open any intermediate file to see what the tool believed. The cost is disk space and the risk of stale artifacts: a resumed run trusts the files that are present. If the stages ever ran in a long-lived service, an in-memory hand-off with files as a checkpoint would be the next step.
LibreOffice can produce a PDF that looks plausible and is wrong, with a missing page or an empty image, and a review pack built on it would put the wrong picture next to the wrong text. The render stage therefore validates its output and aborts when the PDF page count differs from the slide count, when the PNG count differs from the PDF page count, or when any image has zero bytes. Warnings are for doubtful slides, whereas these conditions are failures, and the exit code is 1.
The price is strictness: a deck on which the two libraries disagree about the number of slides cannot be processed at all, and the user has no override. A report-and-continue mode, with the mismatch recorded in the audit files, would be the change if real decks showed the strict rule to be too blunt.
The tool cannot know whether its reading order is right, since a slide stores its shapes in drawing order and not in reading order. It sorts by geometry, scores each slide from a handful of named penalties (no title 0.10, a grouped shape 0.15, a chart-like slide 0.20, no text on a slide with shapes 0.35, and a fragment-heavy slide 0.10), and flags the slides under 0.60 and the slides with tables, groups, or missing titles for a person to check first.
An alternative would have been a layout model that attempts to repair the order, which promises more and cannot be audited in the same way. The heuristic route keeps every number in constants.py, and keeps the screenshot above every table, so that the reviewer can see what the sort missed. The cost is that the penalties were chosen by hand and have not been calibrated on real decks, and that one of them, the image-and-text mismatch, is defined and never applied. Calibration against a set of real decks, with the penalty tests pinned to exact values, would settle both.
Screenshots can come from PowerPoint itself, through its automation interface, or from LibreOffice running headless. PowerPoint would match what the author of a deck sees, and it would tie the tool to Windows and to a licensed Office installation. LibreOffice runs on Windows, Linux, and macOS without a window, and find_soffice checks the PATH, an environment variable, and the standard install folders for each.
The consequence, which the README states, is that screenshots can differ from what PowerPoint shows. The conversion also runs as a subprocess with a five-minute timeout and one retry. The decision would change for a user who needs exact fidelity and owns the licence: a second renderer behind the same stage interface would serve them.
When an editor works in a plain document and not in the review pack, the edited text has to be matched back to the right table cell. A single fuzzy score would be simple, and it would call a copied sentence and a rewritten one by the same name. The matcher instead tries an exact match, then containment, then a fuzzy match at 78 or above, then a window of up to three segments at 74 or above, and labels the outcome Unchanged, Grammar, Clarity, Rewritten, Merged, Split, or Not Found.
The labels are useful when the segments are right, and the module's docstring says the segmenter errs toward larger chunks to avoid over-fragmenting. The probes on Evidence show the opposite on some inputs: a sentence that ends in a number is cut into single digits. This is a defect in the first step and not in the cascade, which suggests that the segmenter needs tests of its own before the matcher is trusted.
The integrations package holds protocol interfaces for the filesystem, LibreOffice, PDF rendering, DOCX, schema, and quality-check boundaries, a set of stage hooks that can abort a run, and a registry of named skills, about 800 lines across three modules. The stated purpose is that local adapters implement the protocols now and can later give way to adapters backed by an external tool server without any change to the orchestration.
Building a seam before its second user is a bet, and the bet has not paid yet: only the schema validator from that package is used, and nothing in the command line or the tests imports the rest. The cost is code that reads as functionality and is not exercised. The decision stays defensible if a second adapter appears; if none does, deleting the unused modules would be the honest correction.
Designed and authored by Daniel Boles; implemented with coding agents. Licence: Apache-2.0.