Skip to content

[editor] EditorHost owns profile discovery, preflight preparation, result routing and presentation #559

Description

@mberrys

Summary

LoopEditor/editorhost.cpp grew from 899 to 1,639 lines in the preflight/shell change set
(4acb0560) and now owns profile discovery, filesystem watching, menu classification, preflight
preparation, async result routing, report export, workspace state and presentation. It also reimplements
Core's profile preparation instead of calling one shared operation.

This is the "Consider" finding #10 of the hostile-PDF audit of 4acb0560cffef7a49f6e460b7c76326906271959,
split out as its own work item because it has no security impact and touching it inside the hardening
commit would have tripled that change set.

Evidence

Size and responsibility: LoopEditor/editorhost.cpp is 1,639 lines at the audited revision (899
before the preflight work landed). It owns the preflight profile watcher (QFileSystemWatcher +
reloadPreflightProfiles), the preflight worker outcome map, menu/action policy classification, the
workspace request state, and bumpPresentation()-driven presentation concerns.

Duplicated profile preparation. The import → bind → resolve → parse sequence exists in four places:

  • LoopEditor/editorhost.cpp:673-700 (inside the submitted job work closure)
  • LoopEditor/editorhost.cpp:824 (report/export path)
  • PdfTool/pdftoolpreflight.cpp:409
  • LoopLibCore/sources/preflightengine.cpp:5611

The primitives are pdf::importPreflightProfile, pdf::bindPreflightProfileVariables,
PreflightProfileResolver::resolveExplicitProfile and pdf::PreflightEngine::parseProfile. Three
callers, one sequence, no shared "prepare this profile" operation — so an invariant added to one copy
(e.g. a validation or a diagnostics field) silently does not apply to the others.

Proposed approach

  1. Add one Core-side operation that turns a profile choice + variable bindings into the resolved,
    parsed profile (and its diagnostics), with a single error surface. Core already exports all four
    primitives; this is a composition, not new behaviour.
  2. Migrate LoopEditor/editorhost.cpp (both sites), PdfTool/pdftoolpreflight.cpp and
    LoopLibCore/sources/preflightengine.cpp to it.
  3. Only then split EditorHost: move profile discovery + filesystem watching and async result routing
    into their own types, leaving the host as wiring and presentation. Do this as a pure move with no
    behaviour change, one type per commit.

Acceptance criteria

  • One prepared-profile operation exists in LoopLibCore, and none of the four call sites re-implements
    the sequence (a git grep for the four primitives shows a single production composition point).
  • No behaviour change: UnitTestsEditorHost, UnitTestsPreflightEngine, UnitTestsPreflightProfileResolver,
    UnitTestsPreflightVerdict, UnitTestsPreflightCorpus and UnitTestsPdfToolContract pass unchanged.
  • Any structural split keeps the mapped-module contract intact: LoopEditor/editorhost.cpp/.h are in
    the quick module's path list in agent-policy.json, so check-change.py must still select the same
    targets after the move (adjust the policy path list if files are added, and run the proof).
  • LoopLibCore still must not depend on Widgets, and no Core change may depend on LoopEditor.

Out of scope

  • Any change to preflight semantics, verdicts, or the operator-visible behaviour of the preflight run.
  • The shell placeholder surface (separate issue).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions