Skip to content

[0.4.0-A] Grounded explanation, context package, and safe next actions #53

Description

@cursor

[AI] Define module boundaries, safety policy, and first vertical slice

Why this issue gates the others

#34 (natural-language job specs), #48 (generative UI), #58 (pull quote details from scanned specs), #59 (suggest job title), and any statistical component of #36 all depend on decisions that belong here. Until this closes, each of those would invent its own answer to the same questions — and the answers would differ.

Nothing AI-facing should ship before this issue concludes.

Part 1 — The boundary questions to decide

1.1 Where does inference run?

Does the feature require a model?
├─ Local only (bundled or user-supplied)
│    + preserves the local-first exit criteria (#197)
│    + no document content leaves the machine
│    − model size in the installer; CPU cost; weaker capability
├─ Remote, opt-in, off by default
│    + capability
│    − document content leaves the machine  → needs consent, and
│      cannot sit on the path of any core workflow
└─ Either, per deployment
     − two code paths, two failure modes, two test matrices

The hard constraint: #197's exit criteria require reports exportable without network access, and preflight is local-first by design. So any remote option is opt-in, off by default, absent from the release profile unless explicitly enabled, and never required by a core workflow.

1.2 What may an AI component touch?

Recommended default, to be confirmed here:

Data Permitted
Document metadata (title, dimensions, page count) yes
Extracted text only with explicit consent per document
Rendered page images only with explicit consent per document
Preflight findings (structured) yes
Customer/job data no
Anything, to a remote endpoint, by default no

Customer artwork is confidential — often under NDA before a product launch. Treat "may the model see the artwork?" as the default-deny question it is.

1.3 What may an AI component do?

This is the one that matters most.

Can the output be reviewed by a human before it takes effect?
├─ NO  → the feature must not exist in that form. Redesign it.
└─ YES → what is the blast radius if it is wrong?
          ├─ Cosmetic (a suggested title)     → suggest inline, easily dismissed
          ├─ Configuration (a job spec)       → draft + explicit confirmation
          └─ Document mutation                → FORBIDDEN as a direct action.
               Must produce a PDFRepairPlan reviewed through the normal
               transaction/preview path like every other operation.

No AI component ever mutates a document directly. Everything goes through PDFRepairTransaction — plan, preview, candidate, revalidate — exactly like a fixup. There is no AI-specific execution path. This single rule makes the safety story tractable, because the existing review machinery already covers it.

1.4 Determinism and reproducibility

Preflight's value rests on determinism: same input, same profile, same result. An AI component that varies run to run cannot participate in that guarantee.

Therefore AI output is never an input to a preflight finding, a pass/fail decision, a certificate (#133), or a profile digest (#132). AI may help an operator decide; it may not compute technical truth.

Part 2 — Module boundary

Pdf4QtLibCore ────────────── no AI dependency, ever.
                             Deterministic technical truth lives here.
       ▲
       │ structured data only (findings, metadata, text)
       │
LoupeAI module ───────────── optional, feature-flagged, separable.
       │                     Produces SUGGESTIONS and DRAFTS only.
       ▼
Editor / PdfTool surfaces ── operator reviews and confirms.
  • Core never links an AI dependency. A build with AI disabled must be byte-identical in Core.
  • The module is gated like the OCR plugin: PDF4QT_MODULE_AI, defaulting OFF in PDF4QT_LOUPE_DISTRIBUTION — the same pattern already proven for PDF4QT_PLUGIN_OCR (CMakeLists.txt:81).
  • All AI output crosses back as typed, validated structures — never as text interpolated into a command.

Part 3 — First vertical slice

Pick the smallest feature that exercises the whole boundary without risking anything. #59 (suggest job title from live text and metadata) is the right candidate:

  • cosmetic blast radius — a wrong title costs nothing;
  • exercises consent (reads document text), the suggest-not-act pattern, the feature flag, and the disabled-build path;
  • ships value independent of everything else.

Explicitly not first: #58 (pull quote details from scanned specs), because wrong extracted numbers flow into pricing, and #34's NL parsing, whose blast radius is configuration.

Acceptance criteria

  • An ADR under docs/adr/ records decisions for 1.1–1.4 with rationale.
  • A documented module boundary showing Core has no AI dependency.
  • PDF4QT_MODULE_AI exists, defaults OFF in the release profile, and a disabled build is byte-identical in Core — asserted by test.
  • A written data policy stating what AI components may access and what requires per-document consent.
  • A written rule, enforced by test, that no AI path reaches document mutation without a reviewed PDFRepairPlan.
  • AI output is excluded from findings, pass/fail, certificates, and profile digests.
  • The first vertical slice ([AI] Suggest job title from live text and metadata #59) is implemented under these rules and demonstrates the full suggest → review → accept flow.
  • Any remote option is off by default, requires explicit consent, and is absent from the release profile.

Test strategy

  • Build-isolation test: PDF4QT_MODULE_AI=OFF produces Core binaries identical to a build where the module does not exist.
  • Mutation guard: static check plus a runtime test asserting no AI code path calls PDFRepairTransaction::apply() without an operator confirmation step.
  • Determinism guard: assert no PreflightResult field is influenced by AI output — run preflight with the module enabled and disabled; results must be byte-identical.
  • Consent: with consent withheld, assert no document text or page image reaches the module.
  • Offline: with the module enabled and networking disabled, assert core workflows are unaffected.

Dependencies


Migration provenance (imported record)
Field Value
Tracker ID #82
Evidence Imported from Linear; see the managed migration section for the complete source record.
Created 2026-08-04

Labels: enhancement, P1-high, audit:still-open
Source: mberrys/Frisket-pdf#119 (created 2026-08-06T19:14:41Z)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions