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.
Defer MSI removal until after LGPL relink evidence is collected and normalize usr\bin install layout in run_qt_relink_test.ps1. Co-authored-by: Cursor <cursoragent@cursor.com>
Route GitHub Actions context through env vars, add Dependabot cooldown, and validate GitHub API slugs before urllib requests. PDF-standard MD5 usage in pdfsecurityhandler.cpp is intentionally unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
…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>
Remove const from compressed QByteArray and qMove it into PDFStream constructor, matching the pattern used elsewhere in pdfrgbtocmykfixup.cpp. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
…ation (#566) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Closes the 0.2.1 release-gate gaps for GitHub #520 and #241. ### #520 — fresh processing budget per search - `searchDocumentText()` now allocates an operation-scoped `PDFProcessingBudget` instead of reusing the session budget whose elapsed timer starts at session construction. - Budget exhaustion is surfaced as `PDFDocumentSearchResult::complete=false` / `budgetExceeded=true`; `QuickDocumentModel::search()` returns `false` without letting `PDFBudgetExceededException` escape to QML. - Adds `UnitTestsDocumentSearch` regression coverage and `scripts/ci/check_search_budget_gate.py`. ### #241 — independent validation release gate - Adds `scripts/ci/check_independent_validation_gate.py` to keep the oracle lane reviewable: conversion triad manifests, `run_independent_validators.py`, `UnitTestsStandardOracle` / `UnitTestsConversionOracle`, and self-certification source markers. - Wires both guards into `ci.yml` `source_integrity` and `scripts/agent/check-change.py`. ## Verification - `python3 scripts/ci/check_search_budget_gate.py` — pass - `python3 scripts/ci/check_independent_validation_gate.py` — pass - `ctest -R '^UnitTestsDocumentSearch$'` — pass - `python3 scripts/agent/check-change.py --base origin/dev` — focused tests 34/34 pass; clang-tidy exits non-zero on touched TUs due to pre-existing `'utility' file not found` diagnostic in this environment (not introduced by this diff) ## Plan See coordinator plan: `/cursor/stores/self/internal/issue-520-241-release-gates-plan.md` Fixes #520 Refs #241 <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-414bc936-d3b7-509a-86c5-5bf256827962?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-414bc936-d3b7-509a-86c5-5bf256827962&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/studio-berry/codesmith/loop/pr/566"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1791864821&installation_model_id=435800&pr_number=566&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F566&signature=bec110427aa6391d5e2b976b65459615377aef9982e2758dcf197848e81d2552"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer -->
- Add transparency, ai-art, and thin-parts-fill PDF fixtures - Unpend malformed-not-pdf and overprint-multiply-on manifest rows - Generate thin-parts-fill via LoopGenerateFixtures - Handle PdfTool input-error envelopes in corpus runner - Add/update golden snapshots for promoted fixtures Co-authored-by: michael berry <mberrys@users.noreply.github.com>
- Add transparency, ai-art, and thin-parts-fill PDF fixtures - Unpend malformed-not-pdf and overprint-multiply-on manifest rows - Generate thin-parts-fill via LoopGenerateFixtures - Handle PdfTool input-error envelopes in corpus runner - Add/update golden snapshots for promoted fixtures
<!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/studio-berry/codesmith/loop/pr/553"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1791600580&installation_model_id=435800&pr_number=553&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F553&signature=ab98d916d41408e5c1fb169c637fd5aac9ec72b93e39eaa53421abfcc2d7f7dc"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer -->
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
#196) - Wire canvas overlay clicks through selectFinding for full navigation - Add selectNextFinding/selectPreviousFinding with Alt+Up/Down shortcuts - Invalidate FindingCanvasNavigator on revision sync - Sync PreflightPane list highlight to selectedFindingId - Populate evidenceTargets from finding bbox in navigation requests - Add shell keyboard and inspector dispatch tests for finding navigation Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Move adjacent-finding selection into PreflightFindingsModel so EditorHost does not aggregate finding counts. Enable Alt+Up/Down shortcuts from Core preflightStateName and mirror Main.qml in the accessibility smoke target. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> Closes the documentation scope of GitHub #235 / Linear MB-463 for the **0.2.1** architecture-truth gate. PR #255 (2026-08-10) introduced ADR verification headers, generated architecture catalogs, and the `Documentation truth` CI workflow. This follow-up re-verifies that narrative against **current `dev`** at `e65cdd19` after DocumentContext revision authority (#236) and subsequent preflight/session work. ## Changes - **ADR-001** — align with revision-keyed caches, optional `PDFDocumentContext`, admission modes, byte-bounded eviction, and factory API - **ADR-002** — add `thin-parts`, graph-backed checks, and pointers to generated check catalogs - **All ADRs** — refresh `Last-verified` to `2026-09-13 @ e65cdd1…` - **`docs/adr/README.md`** — new ADR index with status table and catalog regeneration instructions - **`docs/architecture-source-of-truth.md`** — cross-link revision authority and `preflight-check-catalog.json` - **`docs/REPO_MAP.md`** — link ADR index in layout table - **`loop-preflight/README.md`** — clarify v2 examples vs v3 engine output ## Verification - `python3 scripts/generate-architecture-catalogs.py --check` — pass - `python3 scripts/agent/check-change.py --base origin/dev` — pass (includes mapped preflight focused tests) No protected contract or schema changes. Refs #235 <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-f35ce71d-cccd-5600-a2ca-25dac77ee16d?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-f35ce71d-cccd-5600-a2ca-25dac77ee16d&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/studio-berry/codesmith/loop/pr/565"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1791864553&installation_model_id=435800&pr_number=565&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F565&signature=a50e96230032f93f6325b2a26bec45140ef068785ea2a39a5697946431046be1"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer -->
## Summary Implements the Qt Quick operator loop across shell information architecture, first-class revision-bound preflight, report-backed Prepress Inspector, finding-to-canvas navigation, and bounded GUI/E2E verification. ## Issue linkage - Related to #193 - Related to #195 - Related to #127 - Related to #196 - Related to #170 ## Verification - Focused CTest: 9/9 passed. - Product operator-loop: 8/8 passed. - Quick accessibility smoke: 3/3 passed on native and software paths. - Repository gate: source, architecture, policy, preflight-truth, mirror-parity, formatting, builds, clang-tidy, and 29/29 policy-selected tests passed with the configured environment. No issues are auto-closed by this PR. <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/studio-berry/codesmith/loop/pr/564"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1791862718&installation_model_id=435800&pr_number=564&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F564&signature=07ad839c084425c0ba71236010ce4f16fdbad9e5842e8c5e44fe3acc388b79b9"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer -->
Fix whitespace alignment in the nested ternary that maps preflight verdict states to exit codes. Unblocks agent-fast on dev and RC PR #554. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## What changed Agent-fast on `dev` failed with `-Wclang-format-violations` on lines 298–299 of `UnitTests/tst_preflightcorpus.cpp` (nested ternary whitespace). This PR applies clang-format to that file only, unblocking RC PR #554. ## Proof - [x] `clang-format --dry-run --Werror UnitTests/tst_preflightcorpus.cpp` passes locally - [x] One `changes/cursor-fix-preflightcorpus-format-6547.md` fragment added - [ ] Changed behaviour has a test that fails without the change — N/A (format-only) - [ ] Protected-path or contract change — none ## Internal logic (touched behavior-bearing code) Format-only change; no logic touched. Anti-slop summary: Whitespace alignment only; no comments or logic changed. ## Security and rollback - [x] No security impact - Rollback: revert this commit ## Docs - [x] none needed — format-only fix ## Self-review (BSP-002 §4.3) - [x] Reviewed diff; format-only whitespace in ternary chain <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-ecb73197-e4af-511c-8e56-122ec4c8b371?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-ecb73197-e4af-511c-8e56-122ec4c8b371&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/studio-berry/codesmith/loop/pr/571"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1791933972&installation_model_id=435800&pr_number=571&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F571&signature=0fa64747af7a597566091c8ef76c5067c90f5578b7788d889b0fa4e6b5d1c284"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer -->
Extract preflight profile catalog, run submitter, and inspector dispatch into LoopLibInteraction. Add manifest-driven menu_group to the command catalog. Split RGB image XObject conversion out of pdfrgbtocmykfixup.cpp. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Implements **Option A** from the thermo-nuclear review of PR #572: decompose on `unstable` before merging #572 (`unstable`→`stable`). ### EditorHost decomposition - **`PreflightProfileCatalog`** (LoopLibInteraction): bundled/local profile scan, digest/check-set staleness, QFileSystemWatcher - **`PreflightRunSubmitter`** (LoopLibInteraction): scheduler worker extracted from `EditorHost::runPreflight()` - **`ShellInspectorDispatch`** (LoopLibInteraction): inspector selection builders; removed `"pending"` placeholder properties - **Manifest `menu_group`**: added to `docs/loop-shell-actions.json` + `CommandDescriptor`; deleted `shellMenuGroupForAction()` from EditorHost ### Core split - **`pdfrgbtocmykimagefixup.cpp`**: RGB image XObject conversion path extracted from `pdfrgbtocmykfixup.cpp` - **`pdfrgbtocmykhelpers`**: shared `isRgbColorSpaceName` / `targetProfileId` ### Small cleanups - Removed duplicate `#include "interactiontarget.h"` - Shared `resolvedPreflightVisual()` helper for preflight visual/color resolution ## Line counts | File | Before | After | |------|--------|-------| | `LoopEditor/editorhost.cpp` | 1,792 | **1,436** | | `LoopLibCore/sources/pdfrgbtocmykfixup.cpp` | 1,158 | **860** | | `LoopLibCore/sources/pdfrgbtocmykimagefixup.cpp` | — | **309** | ## Verification - `UnitTestsShellWorkspace` — pass (menu policy / manifest groups) - `UnitTestsEditorHost` — pass (preflight run, visual mapping, export parity) - `scripts/verify-command-catalog.py` — pass - `python3 scripts/agent/check-change.py --base origin/unstable` — focused_tests pass; changelog pass ## Follow-up (not in scope) - `editorhost.cpp` still above ~1,200-line target — `EditorHostShellBindings` ctor wiring extract - `pdfdocumentreader.cpp` 1,061-line cross (thermo §1.3, lower priority) - `findingnavigation` hard-coded check IDs; `looptokens` codegen; QML mirror duplication tax Does **not** merge #572 to `stable`. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-53742eb4-1b17-5dca-8a18-ed5c27ea95c8?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-53742eb4-1b17-5dca-8a18-ed5c27ea95c8&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/studio-berry/codesmith/loop/pr/573"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1791941795&installation_model_id=435800&pr_number=573&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F573&signature=f5d03e081da0364fa129e4e8dfcb55e9e2e64faff067775eebdafd826ae18ecf"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer -->
The widgets-free release profile build failed because tst_quickdocumentmodeltest.cpp passed a const QByteArray lvalue to PDFStream(PDFDictionary&&, QByteArray&&). Use std::move for both arguments in the two affected test helpers. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
- Pass rvalue refs to PDFStream in tst_rgbtocmykfixup.cpp (GCC 13) - Load font-embedded.pdf fixture in DocumentSearchTest instead of QPainter::drawText Co-authored-by: michael berry <mberrys@users.noreply.github.com>
- Unwrap PdfTool preflight JSON envelope in bleed stress tests - Use empty-page fixture for independent search-budget test - Surface budget error text via PDFException::getMessage() in search 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.
[0.2.1] Operator Completion, Product Surface & Trust Leftovers
Promotes
unstable→stablefor the 0.2.1 milestone (GitHub milestone 17) — the patch on the 0.2.0 line that closes the operator, product-surface and trust leftovers before governed-correction work starts in 0.3.0.Scope:
0.2.0.1-alpha(86ee1b5b) →d2e9ce9f— 105 non-merge commits.Canonical milestone text:
docs/github-milestones/0.2.1.md.Riding this promotion from PR #517, whose fragment is
changes/0.2.2.mdafter that branch name: #144 (async interactive-thread boundary) and #146 (interaction-trace contract evaluator).Added
pdfquick::tokens(LoopLibQuick/sources/looptokens.{h,cpp}): 4-px spacing scale and a semanticColorRoleset resolved perLoopTheme(Dark/Light/HighContrast), plus non-color cues so a status never reads by hue alone.resolveStateVisual()(loopstatevisual.{h,cpp}) is the one canonical finding/check presentation, and it holds the two invariants [0.2.1] Define and implement the Loupe UI design system #194 is actually about: an incomplete check and an actively waived finding never render as a pass.docs/LOOP_DESIGN_SYSTEM.mdcarries the token table with WCAG contrast figures and the current adoption state;UnitTestsLoopStateVisualis table-driven over severities, check statuses, waive decisions and out-of-schema inputs.PreflightPaneis now a state/run/cancel/export surface with profile selection and typed variables; the document badge renders Core's verdict through the canonical state kinds; the exported report is pinned againstPdfTool preflightby a parity suite;UnitTestsPreflightInteractionis registered and revived, restoring the sidecar contract coverage the retired plugin suite held.InspectorPanepluspdfinteraction::InspectorModel, rendering only facts a finding'sevidencealready carries (so the report and the Inspector cannot disagree), with navigate-to-finding and corrective-operation request signals on selection.UnitTestsFindingNavigationand shell/inspector tests.UnitTestsProductOperatorLoopdrives the Quick shell offscreen end to end; canvas-parity and Quick accessibility-smoke coverage; the smoke compiles the same QML the product ships, enforced by a byte-parity guard over theLoopEditor/qmlmirrors.pdf::PDFBlockingThreadGuardrefuses to run a blocking service on the registered interactive (canvas) thread, andPDFJobKindidentifies async work in job traces;pdfinteraction::evaluateTraceContracts()names the first contract a trace run violated and the phase responsible.scripts/ci/check_search_budget_gate.pyandscripts/ci/check_independent_validation_gate.py, wired intoci.ymlsource_integrityand intocheck-change.py.Changed
pdf::reducePreflightVerdict()is the single Core verdict (Pass/Fail/Incomplete/Error) consumed by Editor copy, PageMaster gate messages, Action List postflight steps and the certificate-issuance gate; budget exhaustion with zero findings is Incomplete (exit 8), never PASS. A whole-tree guard fails the build if any GUI source derives a pass or severity of its own.standards-convertflattens before CMYK normalization, honours an explicit flatten opt-out, and skips flattening entirely when the document has no live transparency, so an already-opaque vector document is never replaced by full-page rasters; the flatten is reported verbatim under a newtransparency_flattenreport field, and the newflatten_transparencyoperation parameter is available identically from PdfToolrepairand PageMaster export. The PDF/X profile now carries the checksPreflightEnginerequires, so PDF/X rules actually run.PDFDocumentWriterkeeps its exported four-argumentwriteIncrementaloverloads (as forwarding overloads, default argument removed so a four-argument call stays unambiguous) and publishesIncrementalWriteOutcomeonly after a successful commit.EditorHostclears its interactive-thread registration on teardown; the verdict operator summary is translatable and is assigned before its notify signal fires.check-change.pyresolvesclang-tidyby name instead of hardcodingclang-tidy-18.Fixed
searchDocumentText()allocates an operation-scopedPDFProcessingBudget, so an idle session's elapsed-timer exhaustion no longer throws through Quick search; exhaustion surfaces ascomplete=false/budgetExceeded=true, withUnitTestsDocumentSearchregression coverage.PreflightEnginerequires, sopreview()reported no blockers for any PDF/X target and every PDF/X conversion failed at postflight.PDFRgbToCmykFixupconverts supported RGB image samples through the CMS into CMYK ICCBased XObjects, so PDF/X-1a conversion no longer fails whenever content is rasterized.Domain/Encodeare not2 × mare rejected and their allocation bounded by the stream; tiling-pattern paint is bounded by a hard tile ceiling; the unfiltered inline-image row length is rounded once; xref entry count and the dense object table it implies are bounded; the JBIG2 referred-segment count is bounded before reserving; output-intent profile decoding is charged and the inline-image probe bounded; finished job closures are released and retained job history is bounded.UnitTests/tst_preflightinteraction.cppis registered in a CMake target and revived; the verdict operator-summary slot no longer depends on a signal that fired before assignment; the corpus and stress suites fail closed when a required fixture is absent instead ofQSKIP-ing past the comparison, and the parity corpus fixture is now a hard failure rather than a skip.canvastraceoverlay.cppincludes the QJson headers it uses; Core'sfailverdict maps to the Error treatment so preflight kinds stay distinct; a cancelled or failed run reports its terminal state instead of leaving the pane.Security
PDFLogScrubberredacts all-alphabetic bearer credentials.urllibfindings and hardened the CI workflows (Improve CI workflow and address security findings #553).Internal
Last-verifiedmetadata,docs/adr/README.mdis a new index, generated catalogs are regenerated, the source-of-truth hierarchy is cross-linked indocs/architecture-source-of-truth.md, anddocs/REPO_MAP.mdandAGENTS.mdno longer carry stale repository/default-branch claims. AGENTS.md additionally gains the internal-logic contract and the anti-slop review pass (docs(agent-policy): add the internal-logic contract and an anti-slop review pass #568).docs/github-milestones/0.2.1.mdplus manifest and living-sequence updates across the milestone docs (docs: consolidate 0.2.1 GitHub milestone with leftover-work plan #518).UnitTestsBlockingThreadGuardand the budget-exhaustion suite mapped intoagent-policy.json, the GUI preflight-truth and QML mirror-parity guards added tocheck-change.py, andcheck-change.pyresolvingclang-tidyby name.docs/v1-operator-acceptance.mdand the readiness evidence repointed at code that exists, and the legacy product-name token removed from the design-system docs.Closes
Closes #127
Closes #170
Closes #193
Closes #194
Closes #195
Closes #196
Closes #234
Closes #235
Closes #520
Closes #555
Closes #556
Closes #557
Closes #561
Closes #562
Closes #563
Closes #236
#236(DocumentContext revision authority) closed on this milestone and already shipped in0.2.0.1-alpha; its keyword here is documentary. Every other reference above is adev/unstablelanding whose issue is still open because closing keywords only take effect on the default branch — merging this PR intostableis what closes them.Not closed by this promotion (deliberately, work continues):
Refs #241
Refs #125
Refs #163
Refs #559
Refs #560
Refs #569
#241ships its release gates here, but the institutionalized acceptance criteria — the renderer-differential lane recording measurements rather than screenshots, and documented corpus licensing — are not in this patch.#263(SBOM and signed provenance) isnot plannedfor 0.2.1 and continues at 0.8.0-S07.Verification
CI,Documentation truth,Supply Chain PolicyandCodeQLare green onunstableatd2e9ce9f.unstable([0.2.1] RC | Preflight & GUI Foundation #554) was green onagent-fast / build,policy,source_integrity,architecture-docs,fuzzandsemgrep-cloud-platform/scan, pluspackage_script_testson both runners.Breaking changes
None. No public contract, schema version or persistence format changes: the export additions, the interaction-trace contract and the
flatten_transparencyparameter are additive, and the four-argumentwriteIncrementaloverloads are preserved.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.