Conversation
…orted (#665) Loop does not produce or validate PDF/X-5n, PDF/X-5g, or PDF/A-3. A document that declares one of those levels is reported unsupported instead of passing that class in silence. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
…t produced (#665) (#671) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## What changed Loop does not produce PDF/X-5n, PDF/X-5g, or PDF/A-3. Core has no external-resource or n-colorant output-intent rules for those levels, so this is not a converter and not a renamed PDF/X check. A document that declares one of those levels used to pass with nothing looking at the claim. The new `conformance-claims` check parses the declaration once and reports check status `unsupported` (reason `unsupported-conformance-level:<ids>`), which leaves the run incomplete. A file that does not declare them gets no finding. PDF/VT stays on #605. Refs #665. Protected paths: `LoopLibCore/sources/pdfconformanceclaim.h`, `LoopLibCore/sources/pdfconformanceclaim.cpp`, and `LoopLibCore/sources/preflightengine.cpp`. The claim table and the check belong in Core and do not depend on Widgets. No report schema or central type was added; `unsupported` is already a check status. ## Release changelog <!-- Promotion and release PRs (`dev` -> `unstable` -> `stable`) only: the full changelog goes here, shaped by `docs/CHANGELOG_FORMAT.md` - measured scope line, Added/Changed/Fixed/Security/Internal, one `Closes #<n>` line per issue whose acceptance criteria the release meets, `Refs #<n>` plus the outstanding criterion otherwise, verification naming workflows and SHAs, and a stated breaking-change answer. Topic PRs answer with their `changes/<branch>.md` fragment and leave this comment in place. --> ## Proof - [x] `python scripts/agent/check-change.py --base origin/dev --build-dir build` reports `pass` (head `b2c56079109a5c5728f2931173f9416c8cefa35e`, 71 checks) - [x] One `changes/feat-0.3.0-665-pdfx5-pdfa3-claims.md` fragment added (Category, Audience, Breaking-Change, Summary) - [x] Changed behaviour has a test that fails without the change (`UnitTestsPreflightEngine`, 110 passed, including declared PDF/X-5n, PDF/X-5g, and PDF/A-3 versus PDF/X-1a, PDF/X-4, PDF/A-2, and PDF/VT) - [x] Protected-path or contract change named above, with the reason it is required ## Internal logic (touched behavior-bearing code) - [x] Guard clauses handle invalid, stale, cancelled, absent, unauthorized, and terminal cases before the happy path - [x] Untrusted input is parsed once at the boundary into trusted typed or domain state, with no repeated checks downstream - [x] Invalid state stops before partial mutation or publication and returns a descriptive error or result - [x] Names carry the domain intent, and comments explain rationale rather than restating the code ## Anti-slop pass - [x] Redundant or explanatory comments that do not match the file's style removed - [x] Abnormal defensive checks and broad try/catch blocks removed where a trusted upstream boundary already guarantees the invariant, with real boundary and safety checks kept - [x] No `any` or equivalent cast added only to suppress a type error - [x] Python imports stay at file scope unless a local import is required - [x] Generated boilerplate, needless wrappers, and local-style drift removed - [x] Validation, security, cancellation, provenance, and failure handling preserved Anti-slop summary (1-3 sentences): The claim table is the only place production and validation are recorded. Metadata is parsed once into level ids, and undecodable catalog metadata stays `not_inspected` rather than `ok`. The profile severity is not promoted to an error, because a declared level is outside the validator. ## Security and rollback - [x] Untrusted input validated at the trust boundary; no new unsafe construct without an inline justification - [x] Rollback: revert the branch. The check is opt-in by profile id `conformance-claims`; the default profile is unchanged. ## Docs - [x] Docs updated in this PR, or "none needed" with the reason ## Self-review (BSP-002 §4.3) - [ ] Reviewed in the diff view, not the editor, at least 30 minutes after the final commit; overnight if the change touches security-sensitive code, data handling, or public API surface <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-9ed7e283-8e24-5230-b9cb-3763b3599a73?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-9ed7e283-8e24-5230-b9cb-3763b3599a73&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/671?ref=codesmith_pr_footer"><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=1792626384&installation_model_id=435800&pr_number=671&ref=codesmith_pr_footer&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F671&signature=2612d9c245c58e874184335effd2afc95cc2f64f26d3911412985b828e4edc3e"><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 -->
Record proof lanes, boundaries, fixture classes, and quality budgets as architecture contracts. CI and check-change fail when a mapped subsystem lacks a lane or a required budget, and when a PR evidence manifest omits those bindings. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
agent-fast failed because the architecture contract suite imported PyYAML, which CI does not install. The subset loader stays the contract parser; the parity check runs only where PyYAML is present. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Reject short sample buffers and reserve render pixels before QImage or codec output buffers so hostile image XObjects cannot bypass PDFProcessingBudget. Shared guard covers DCT, JPX, CCITT, JBIG2, and raw paths; scan id 43899b1. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Keep sample-length and codec dimension guards in createImage, but charge render pixels only when painting actually rasterizes. Avoid aborting Colorants evidence walks with BudgetExceededException from image Flate. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Unblock agent-fast format checks on the protected PDF image paths. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Register UnitTestsImageDecodeGuard so source_integrity and policy evidence checks stay current with UnitTests/CMakeLists.txt. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## What changed Hostile PDF image XObjects could allocate a full raster (or codec output buffer) before `PDFProcessingBudget` ran. This PR adds a shared `PDFImageDecodeGuard`, rejects short sample buffers / out-of-cap codec dimensions before allocation, and reserves render pixels before `getImage` on the paint path. Metadata-only walks (color-mode / Colorants evidence) that short-circuit paint do not charge pixels. Scan revision `43899b19` (`pdf-image-decode-budget-bypass` + related image codec deferred items). Attachment / launch / export candidates dismissed in store triage with citations. ## Release changelog Topic PR — see `changes/cursor-security-image-decode-budget-a16c.md`. ## Proof - [x] `python3 scripts/agent/check-change.py --base origin/dev`: focused tests + builds **pass**; `format` incomplete (`clang-format` missing in VM); `clang_tidy` fails resolving Qt/system headers in this environment (not a new logic diagnostic) - [x] Changelog fragment `changes/cursor-security-image-decode-budget-a16c.md` - [x] `UnitTestsImageDecodeGuard` covers truncated max-dimension images, low `maxRenderPixels`, small-image regression, excessive CCITT columns - [x] Protected paths: `pdfimage.*`, `pdfcolorspaces.cpp`, `pdfpagecontentprocessor.cpp`, new `pdfimagedecodeguard.*` — required for the decode boundary Test log: [walkthrough-image-decode-guard-tests.log](https://cursor.com/artifacts/c/art-beb3982b-b9bb-4dd6-85bb-46fedd59d753) ## Internal logic - Guard clauses reject invalid geometry / short samples before raster or codec buffers - Untrusted Width/Height/BPC/Columns validated once at the decode boundary - Failures throw before `QImage` / large `QByteArray` materialization ## Anti-slop pass Anti-slop summary: Kept one shared guard module instead of per-codec booleans; left stream session-budget threading open because budgeting Flate in `createImage` aborts Colorants evidence walks via `BudgetExceededException` (hard STREAM_FILTER ratio still applies). ## Security and rollback - Untrusted image dictionaries validated before allocation; render-pixel reserve before paint rasterization - Rollback: revert this branch / PR ## Docs - none needed (behavior hardening; triage lives in agent store `internal/codex-security-scan-43899b19/`) ## Self-review - Diff reviewed before opening this draft PR <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-2ed3ae12-5034-50bc-afe8-c05bdc89a16c?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-2ed3ae12-5034-50bc-afe8-c05bdc89a16c&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/673?ref=codesmith_pr_footer"><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=1792653141&installation_model_id=435800&pr_number=673&ref=codesmith_pr_footer&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F673&signature=5b02fb46b1b57bd4fac7a5b20dd7ecfee34519b8fa5571eb66277cd4d9fbaa51"><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 -->
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## What changed CI now treats architecture as a contract, not a narrative. `architecture/` records boundaries, invariants, proof lanes, ownership, fixture classes, and quality budgets. `scripts/agent/check-architecture.py` loads those files on every `check-change` run and on the source-integrity jobs. A pull request that touches a mapped subsystem other than documentation must ship `changes/<branch>.evidence.yaml`. Claims can cite `budget:<id>`, and that id must exist in `architecture/quality-budgets.yaml`. Quality budgets detect movement. Four Loop metrics are measured against committed baselines (preflight PDF count and canvas-parity caps). Latency, memory, parser agreement, packaging size, and the sealed rendering cap are declared with harness TODOs, and the mapped visual/data subsystems are still required to have a budget. ## Release changelog `changes/cursor-proof-lanes-806f.md` ## Proof - [x] `python scripts/agent/check-change.py --base origin/dev` reports `pass` (head `1bf13aa3d39c7d6c9d80e32e14fb762829049fe1`; no `--build-dir` because the selected module is documentation and no C++ target is in the diff) - [x] One `changes/cursor-proof-lanes-806f.md` fragment added (Category, Audience, Breaking-Change, Summary) - [x] Changed behaviour has a test that fails without the change (`scripts/agent/test_architecture_contracts.py`) - [ ] Protected-path or contract change named above, with the reason it is required No protected path is in the diff. The contract lives under `architecture/` so `docs/schemas/**` stays untouched. ## Internal logic (touched behavior-bearing code) - [x] Guard clauses handle invalid, stale, cancelled, absent, unauthorized, and terminal cases before the happy path - [x] Untrusted input is parsed once at the boundary into trusted typed or domain state, with no repeated checks downstream - [x] Invalid state stops before partial mutation or publication and returns a descriptive error or result - [x] Names carry the domain intent, and comments explain rationale rather than restating the code The checker parses architecture YAML with a block subset (CI does not install PyYAML), then fails closed on missing lanes, missing budgets, unknown `budget:` refs, sealed fixture edits without `sealed_output_approval: human`, and loosened caps without an unresolved marker. ## Anti-slop pass - [x] Redundant or explanatory comments that do not match the file's style removed - [x] Abnormal defensive checks and broad try/catch blocks removed where a trusted upstream boundary already guarantees the invariant, with real boundary and safety checks kept - [x] No `any` or equivalent cast added only to suppress a type error - [x] Python imports stay at file scope unless a local import is required - [x] Generated boilerplate, needless wrappers, and local-style drift removed - [x] Validation, security, cancellation, provenance, and failure handling preserved Anti-slop summary (1-3 sentences): The YAML loader stays because the agent environment must not add a dependency. Declared budgets keep an explicit `todo` instead of a fake measurement. Adapter text is generated from `agent-policy.json`. ## Security and rollback - [x] Untrusted input validated at the trust boundary; no new unsafe construct without an inline justification - [x] Rollback: revert `1bf13aa3d39c7d6c9d80e32e14fb762829049fe1`. No persistence format or public ABI changes. ## Docs - [x] Docs updated in this PR (`docs/architecture-source-of-truth.md`, generated policy adapters). The design narrative is in the worker store at `/cursor/stores/self/docs/architecture-contracts.md`. ## Self-review (BSP-002 §4.3) - [ ] Reviewed in the diff view, not the editor, at least 30 minutes after the final commit; overnight if the change touches security-sensitive code, data handling, or public API surface <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-a5ef665f-cbf8-598c-bf36-f801e453806f?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-a5ef665f-cbf8-598c-bf36-f801e453806f&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/672?ref=codesmith_pr_footer"><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=1792644469&installation_model_id=435800&pr_number=672&ref=codesmith_pr_footer&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F672&signature=1a42bc21510bb2abfc042d0546bfa2f095575711fb705bbf7ccb849f46b2ae1c"><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 -->
Catalog drift from #673 left the image-decode guard test unclaimed; architecture contracts and Release Gate failed until it is listed in agent-policy core paths/tests. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
mberrys
marked this pull request as ready for review
September 22, 2026 21:46
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.
Purpose
Promote the current assembled
devstate into the 0.3.0 qualification branch.This PR is intended as
dev → unstable, not a release-to-stablePR. It is the transport for exact-candidate qualification after the 0.3.0 foundation promotion in #670 and the subsequent architecture/security changes merged through #672 and #673.Current role
devunstableThe PR remains draft until the P0 queue in #638 is closed or explicitly re-scoped in GitHub.
Candidate contents
The current assembled diff includes architecture/proof-lane machinery from #672, image-decode hardening from #673, and current preflight/conformance work. Qualification applies to the assembled head SHA, not to topic PRs independently.
Required before Ready for Review
Promotion rule
After qualification and merge to
unstable, use a separateunstable → stablepromotion PR that names the exact qualified SHA and references #638. Do not use topic-branch evidence as a substitute for assembled-candidate proof.