Conversation
Adds pdfquick::tokens (LoopLibQuick/sources/looptokens.h/.cpp): semantic spacing and colour-role tokens with dark/light/high-contrast values, each foreground/background pair WCAG contrast-checked. Adds resolveStateVisual() (loopstatevisual.h/.cpp), the canonical finding/check presentation mapping issue #194 asks for, with a table-driven test (UnitTestsLoopStateVisual) asserting an incomplete check and an actively-waived finding never resolve to the passed treatment. Documents both in docs/LOOP_DESIGN_SYSTEM.md, including why this uses the repo's current Loop/Quick naming rather than the issue's stale pre-rebrand Pdf4QtLibGui/Loupe paths, and what remains open (component implementations land with their consuming surfaces #193, Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NxoABBuEB3mYqr8QyA6KuB
scripts/ci/check_loop_identity.py fails CI on any tracked text file containing the pre-rebrand product name outside its historical-evidence allowlist. The "Naming note" section quoted that name three times while explaining why this doc uses current naming instead of issue #194's stale paths; reword it to make the same point without the literal token. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NxoABBuEB3mYqr8QyA6KuB
Adding UnitTestsLoopStateVisual to UnitTests/CMakeLists.txt bumped the project-wide CMake target count the Phase 5 Widgets inventory tracks (its generator enumerates every target to prove widgets-linkage status, not just widgets-related ones). Regenerate docs/generated/phase5-widgets-inventory.json via scripts/generate_phase5_widgets_evidence.py --write (new target's widgets_linkage is "none", as expected) and update the test's hardcoded target count (70 -> 71) to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NxoABBuEB3mYqr8QyA6KuB
agent-fast's clang-tidy step runs on every changed C++ file regardless of module classification, but the cmake --build step that generates each test's AUTOMOC .moc file only runs for targets selected by classify()/selected_values() against agent-policy.json's module_boundaries paths. UnitTestsBudgetExhaustion was already listed in core's `tests`, but its source file, UnitTests/tst_budgetexhaustiontest.cpp, was missing from core's `paths` glob list, so a change touching only that file never classified as "core" and the target was never built before clang-tidy ran on it standalone -- producing "tst_budgetexhaustiontest.moc file not found". Surfaced by 0aa0d4c's one-line fix to that file. Add the missing path entry so the target builds first, as it does for every other core test file already listed there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NxoABBuEB3mYqr8QyA6KuB
PDF/X-1a:2001 and PDF/X-3:2002 forbid live transparency, but standards-convert never called the existing PDFTransparencyFlattener operation (#164) -- live transparency was an unconditional, unfixable blocker even though Core already has a working flatten path that PageMaster's export pipeline uses as a separate stage. Wire PDFTransparencyFlattener::apply()/hasLiveTransparency() into PDFStandardConversion::preview()/apply(), mirroring the existing RGB-to-CMYK integration exactly: - New PDFStandardConversionSettings::flattenTransparency (default-on for X-1a/X-3, matching normalizeColor's existing default pattern; opt-in for X-4/PDF-A, which permit live transparency). - pdfx.transparency.allowed becomes a fixable preflight blocker only when flattening is requested, so unrelated fixtures without live transparency are unaffected (transparencyObjects stays 0, the rule already reports Passed). - The flatten runs before the output-intent/page-box rewrite and its report is surfaced verbatim under a new transparency_flatten report field -- a real, reported content change, never a silent approximation. - New flatten_transparency parameter on the standards-convert operation, available identically from PdfTool's repair command and PageMaster's export job (the one shared Core implementation). Also correct docs/STANDARD_CONVERSION.md's stale claim that an Editor adapter can land "after the 0.1.1 GUI gate": that gate is already complete per docs/LOOP_SHELL_CONTRACT.md, which gates product GUI work behind the still-closed S21/S22 admission contracts instead. Note that docs/REPO_MAP.md's LoopEditorPlugins/ module does not exist in the current Qt-Quick-based tree, so a future Editor adapter belongs under LoopLibInteraction/ + LoopEditor/qml/. No Qt/CMake toolchain is available in this environment, so the build and UnitTestsStandardOracle/UnitTestsConversionOracle/UnitTestsRepairOperation targets could not be run locally; clang-format, source-integrity, and architecture-catalog checks all pass. CI will provide the first real build/test signal for this change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgoNmy614kqRiTBjiSjRJU
Works the net-new findings from the September 2026 read-only review that were reproducible against the current tree, plus three adjacent defects the review did not name. Security / privacy - PDFLogScrubber scrubs credential material (URL userinfo such as a Sentry DSN, HTTP authorization values, secret-named key/value pairs) ahead of the existing path and email passes. The bare auth-scheme pass deliberately excludes "Token" so parser diagnostics are not redacted as secrets. - loop-ocr reads a staged raster once by descriptor instead of re-resolving the path for isfile(), PIL, and easyocr in turn, closing the TOCTOU window; language codes are shape-validated before they reach easyocr's model file names; PdfTool stages the raster 0600. - Diagnostics bundles truncate plugin display fields. Fail-closed behaviour - PdfTool extraction commands record output.empty-result and accept a shared --fail-if-empty (exit 1, findings) so an empty output directory cannot pass a pipeline that gates on produced files. - writeIncremental reports whether it appended or only byte-copied; damaged documents now carry a source digest, so its "file changed underneath us" guard is no longer silently disabled for permissively recovered documents. Bounds on attacker-controlled shapes - Damaged-document recovery bounds its dense object table by objects recovered, not by the highest declared object number. - PDFNameTreeLoader terminates cyclic Kids chains and caps depth, entry count, and key length (net-new: the cycle was unbounded recursion). - Structure-tree parsing bounds recursion depth on long acyclic chains. - PDFJBIG2Bitmap::paint validates grown dimensions on its expandY path, the one path that escaped the constructor's dimension check (net-new). Ergonomics - isPathContained no longer rejects a planned output whose target directory does not exist yet, keeping the stricter symlinked-parent rule for the file side. - makeUniqueFileName probes 128 sequential names, then random ones. - OCR option defaults are defined once and shared by capability discovery and the command-line parser. Not built or run here: this environment has no Qt, so the C++ changes are unverified by compilation. The Python sidecar tests pass and the new scrubber patterns were validated against a reference implementation of the same passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FDJQDFR5ctoKDJbp7LG4GS
Whole-file clang-format across LoopLibCore/PdfTool/UnitTests sources to clear format drift flagged by agent-fast. Add moc-generated autogen include dirs to UnitTests target so Qt meta-object headers resolve. Map agent-policy tidy gates to the three active test suites.
Add canonical milestone text for 0.2.1 (patch on the 0.2.0 line), register GitHub milestone 17 in the sync manifest, and update living-sequence references across milestone docs and the 0.5.0–0.10.0 roadmap extension. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Replace legacy product tokens in milestone issue summaries, rename the budget-exhaustion corpus schema kind to loop, and fix workflow working-directory typos left from the Loupe-to-Loop rebrand. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Manual .moc includes are generated at build time, so clang-tidy cannot analyze those sources during agent-fast. Exclude them from tidy while keeping format checks. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
…#144) Add pdf::PDFBlockingThreadGuard, a runtime thread-affinity check a blocking service adapter opens with so it refuses to run on the registered interactive (canvas) thread instead of silently stalling pointer and frame handling. Wire it into PreflightEngine::run(), the one blocking implementation already reached through PDFJobScheduler, and register EditorHost's owning thread as the interactive thread at construction. Add PDFJobKind to PDFJobTraceEvent so job traces identify async work by type, and document the interactive-thread boundary (what pointer/frame callbacks may do directly vs. what must go through a submitted job) in docs/JOB_SCHEDULER.md. Wiring an actual UI trigger for interactive preflight runs, and correlating PDFJobTraceEvent timing against InteractionTraceRecorder's slow-frame attribution, remain open follow-up work for #144. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xnr9TZYfGr1nMgBeh16CSb
Add pdfinteraction::evaluateTraceContracts() and its TraceContract/TracePhase enums (LoopLibInteraction/sources/interactiontracecontract.h/.cpp): the fixed-order pass/fail evaluator issue #146 AC7 asks for. Given an ordered QList<TraceContractCheck>, it returns the first unsatisfied contract and the phase responsible, matching scripts/ci/check_interaction_traces.py's CONTRACTS/PHASES tuples and docs/schemas/interaction-trace-report.schema.json exactly, so a future harness that supplies the nine checks in order gets AC7 for free. phaseForStage() is docs/INTERACTION_CONTRACT.md's TraceStage-to-phase attribution table given a type. The evaluator takes an already-assembled checklist rather than an InteractionTraceRecorder or a live replay, so it is fully testable with synthetic checks -- no InteractionController, no scheduler, no hit-test dispatch -- and is covered by the new UnitTestsInteractionTraceContract target. The prior gh-146 work (scenario/report schemas, the nine-scenario corpus, and check_interaction_traces.py) validates the corpus as data but has no test binary to produce a run; this evaluator is the piece that decides a run's verdict once one exists. Replaying a scenario through InteractionController, applying its cost model, and assembling a full report run remain open, as UnitTestsInteractionTraces/UnitTestsInteractionTracesPresent in docs/INTERACTION_CONTRACT.md's two-lanes table. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xnr9TZYfGr1nMgBeh16CSb
…readGuard docs/generated/phase5-widgets-inventory.json went stale when UnitTestsBlockingThreadGuard landed (issue #144 commit): it's a target directly in UnitTests/CMakeLists.txt, which scripts/generate_phase5_widgets_evidence.py scans, but the catalog was never regenerated for it. CI's policy job caught the drift -- test_verify_phase5_widgets_contract.py's crlf-currency check and its hardcoded target count (70) both went red against the actual count (71). Regenerate via scripts/generate_phase5_widgets_evidence.py --write and bump the test's hardcoded count to match. (scripts/generate-architecture-catalogs.py's separate architecture-catalog.json was already regenerated for this target in the #144 commit; this is the sibling widgets-surface catalog that step didn't cover.) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xnr9TZYfGr1nMgBeh16CSb
Rename leftover working-directory: loupe to loop in reusable Linux and Windows workflows so agent-fast/build can run generate_corpus.py --check. Rename schema_kind from loupe-processing-budget-exhaustion-corpus to loop-processing-budget-exhaustion-corpus in the corpus generator, test, and manifest so check_loop_identity passes. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
The agent-fast build proof never built the blocking-thread-guard test target because it was absent from the core module's test list, so its AUTOMOC .moc file was never generated and clang-tidy failed on tst_blockingthreadguardtest.cpp. Registering the target lets check-change.py build it (and generate the moc) before static analysis.
…ues (#194) Continue PR #525 on current origin/dev. Shared pdfquick::tokens cover spacing, typography, focus geometry, and colour roles; resolveStateVisual() is the canonical finding/check mapping. Incomplete and waived states never resolve as passed, and each state carries a unique icon plus accessible name. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Qt::red against white is only ~4.0:1. Use the light-theme fill (#B91C1C) so a destructive button label still meets WCAG text contrast in high contrast. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Drop restated enum notes, unused includes, and CMake/doc padding. Mapping invariants stay in tests and LOOP_DESIGN_SYSTEM.md. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Keep both UnitTests/tst_jbig2decodertest.cpp (PR 519) and UnitTests/tst_lifecycletest.cpp (dev) in the core module boundary paths. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Keep 0.2.1 in the living release train while adopting dev's consolidated 0.5.0-0.8.0 planned-train wording and retired-title note. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Resolve agent-policy.json conflict by keeping both tst_budgetexhaustiontest.cpp and tst_diagnosticstest.cpp in the core module paths. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
…ds-convert (#554) The target default was re-applied with '||' on top of the parsed value, so 'flatten_transparency: false' on PDF/X-1a/X-3 still flattened. The parsed setting becomes a three-state policy (Automatic/Always/Never) resolved once by flattensTransparency(), so an explicit opt-out is no longer overridden: preview() stops advertising a transparency.flatten change and apply() does not run the flattener. PDFStandardConversionSettings::flattenTransparency was added by this same PR and has never shipped in unstable or stable, so replacing it is not a break for a released consumer.
PDFTransparencyFlattener::apply() rasterizes every selected page, while preview() only advertises a transparency change when hasLiveTransparency() is true. Guarding the apply path with the same condition stops opaque vector/text documents from being silently replaced by full-page rasters.
…ecks (#554) preview() and apply() pass pdfxProfile() to PreflightEngine, but parseProfile() rejects a profile with an empty 'checks' array before it reads 'pdfx', so result.pdfx was never populated: preview() reported no blockers for any PDF/X target and every PDF/X apply() failed at postflight. The profile now carries the shared checks of loop-preflight/examples/profile-pdfx-x1a2001.json, which is what makes an explicit flatten opt-out fail closed.
The file overload handed the caller's outcome pointer to the device overload,
which filled it in before QSaveFile::commit(). A failed rename returned an
error while the outcome claimed the save had completed.
The commit-failure path is verified by construction rather than by a unit test:
QSaveFile::open() refuses a read-only target ('Existing file ... is not
writable') before the nested write runs, so a test cannot reach commit() on
this platform and none can be made to fail for the intended reason. The new
slot covers the file overload's success reporting (append vs verbatim copy).
…ds (#554) A defaulted parameter changes the mangled symbol, so the previous overloads would have disappeared from LoopLibCore. They return as forwarding overloads and the default argument is gone, which also keeps a four-argument call unambiguous. UnitTestsIncrementalSave now static_casts both signatures so a future defaulted parameter cannot silently remove them again. Symbol check (dumpbin is not installed here; this is the DLL's PE export table): LoopLibCore.dll exports exactly four writeIncremental symbols - the two four-argument signatures plus the two five-argument ones.
The standalone authorization pass required a digit or punctuation character in the credential, so an opaque value such as 'Bearer abcdefghijklmnop' reached support bundles verbatim. A second alternative now matches scheme-delimited all-letter tokens of 16+ characters; prose after a scheme name still survives.
PreflightPane.qml renders preflightVerdictOperatorSummary() directly, so its pass and fallback copy must go through a translation context instead of QStringLiteral - otherwise every non-English build shows English-only status.
…#554) stateChanged is operatorSummary's notifier, but setCurrentRevision() and cancelRun() emitted it before assigning the new text, so observers retained the previous run's summary.
…554) acceptResult() copied the raw error findings into the model, so a run whose blocking findings were all covered by an active disposition announced PASS while the findings list and canvas overlays still showed them as errors. The model now takes the verdict's waived IDs, exposes them through WaivedRole, and maps them to a non-blocking overlay severity.
…wn (#554) EditorHost::registerInteractiveThread() had no matching cleanup, so a host recreated in the same process left a stale registration that kept refusing synchronous blocking work on that thread.
…554) The schema pattern was lower-case only, so a client validating the published contract rejected 'EN' - a request the service accepts and normalizes to 'en'. The pattern is now case-tolerant in shape and says so in a description, and a test keeps the schema and the runtime normalization in step in both directions.
The overlay findings.isEmpty() exception was removed when every preflight surface moved onto reducePreflightVerdict, but the unit test still imported OVERLAY_FINDINGS_GUARD. Drop that stale contract and regenerate the Phase 5 widgets inventory for UnitTestsPreflightVerdict's LoopLibInteraction link. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Introduce the typed seven-workspace model on EditorHost with setWorkspace()/workspaceChanged, documentShellStatus and productionStateName projections, ProductionModel sync, manifest menu metadata on command descriptors, and interaction-to-inspector dispatch. Gate developer diagnostics behind LOOP_LOOP_DISTRIBUTION_BUILD. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Move InspectorPane into the Document workspace right column, add placeholder panes for Production Preview, Pages/Production, Inspect, Fix, and Compare (disabled), and mirror the layout in ProductQuickAccessibilitySmoke. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Add ShellToolBar with catalog-driven open/save/zoom/preflight actions and extend the bottom status bar with always-visible document, production, and preflight segments plus page/zoom context. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Replace hardcoded menu trees with MenuModel/ShellMenuBar grouping of catalog actions by menuGroup, target, and disposition, omitting HIDE/STOP-SHIPPING entries and gating ADVANCED items behind allowDeveloperDiagnostics. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Register UnitTestsShellWorkspace and UnitTestsShellInspectorDispatch with transition-matrix, menu-route, and selection-kind coverage. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Record the seven-workspace rail, contextual inspector dock, manifest menus, and always-visible status segments in the shell contract. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.