Conversation
PdfTool benchmark gains a measured preflight phase (--profile), renders in cancellable slices, and handles SIGBREAK on Windows. A synthetic fixture generator, cancellation/recovery probes, a hostile corpus lane, schema-2 evidence, and a hosted Linux/Windows qualification workflow make the strict matrix runnable in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QFile::atEnd() is true immediately for procfs files, so currentRssHighWaterBytes() always returned -1 on Linux. That left preflight_high_water_bytes at -1, failing benchmarkWithPreflightProfileIsComplete and flagging every Linux matrix record as unmeasured. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NT3L5ao8UyQuTPPKySRDcP
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NT3L5ao8UyQuTPPKySRDcP
The job log only carried summary counts, so a failing hosted run could not be diagnosed without downloading the matrix artifact. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NT3L5ao8UyQuTPPKySRDcP
|
Status on head Generated by Claude Code |
Exit code 5 (PartialOutput) alone does not say which page failed or why. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NT3L5ao8UyQuTPPKySRDcP
|
Linux qualification results for
Next: read the render-error and stderr output from the run on Generated by Claude Code |
… DPI At 300 DPI a Letter page image is 33.7 MB and each rasterizer holds one, so 8 rasterizers exceed the 128 MiB raster-tile-cache pool: the extra pages are rejected as budget-exceeded and every run exits PartialOutput. Three fit. Also stop repeating a fixture after its first timeout. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NT3L5ao8UyQuTPPKySRDcP
|
Linux results for
Generated by Claude Code |
The rasterizer was released before the image was processed, so with more worker threads than rasterizers, more images than rasterizers held raster-tile reservations at once. The hosted linux qualification run shed 7 reservations at 3 rasterizers (101 MB of the 134 MB pool used) and every render exited PartialOutput with budget-exceeded. A budgeted run now releases the reservation and then the rasterizer after processImage; unbudgeted callers keep the early release. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…llation PDFEvidenceCollectSettings and PDFColorInventorySettings gain an optional operationControl. The colour inventory polls it per page and reports cancelled; the evidence collector polls it per page and returns an incomplete graph with incompleteReason "cancelled". PreflightEngine passes its operation control through and reports errorCode "cancelled" instead of evidence-incomplete, so an interrupt during the benchmark's preflight phase stops within one page instead of after the whole document. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Preflight renders and walks every page it covers, about 0.5-0.7 s per page on a hosted runner, so a full pass over the 10,000-page fixture cannot fit any practical timeout. benchmark gains --preflight-page-last <n>, which limits the preflight phase to pages 1..n while rendering still covers every page. PDFEvidenceCollectSettings and PDFColorInventorySettings gain pageIndices so the render and content walk skip pages the profile scope already discards. run_matrix.py passes 256 for fixtures above 1,000 pages and records it as profile.preflight_page_last. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e render-only The hostile raster-probe-pixel-budget case reached 15 GB RSS on both hosted platforms: the colour inventory probes each page at 150 DPI with several float bitmaps per pixel and no size limit. PDFColorInventorySettings gains maxProbePixels (2.5 million); larger pages are probed at a proportionally lower DPI. The cancellation probe ran with the preflight profile, whose document-wide setup does not poll for cancellation, so latency was 11-16 s against a 5 s policy. The probe now interrupts a render-only run, like the recovery probe. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
What changed
Implements #19 (L01-05, "Qualify hostile and production resource envelopes"). Session 11 (#542) left the envelope
incomplete, with 0 of 6 fixtures measured. There were two causes:PdfTool benchmarknever measured preflight or recovery, so every record was hardcodedincomplete, and the large fixtures only existed in an external DIV2K corpus that CI can't reach. This PR makes the strict matrix runnable and passable on hosted Linux and Windows runners. Close #19 withgh issue closeonce the qualification run's evidence is recorded.PdfTool (no
LoopLibCorechanges, so no protected paths are touched):benchmark --profile <profile.json>runs a measured preflight phase through the existingpdf::inspectPreflightFile. An envelope is nowcompleteonly when preflight ran, every page rendered, and there was no cancellation or budget exhaustion. Every other case keeps a namedincomplete_reason.SIGBREAK.CTRL_BREAK_EVENTis the only console interrupt that reaches a child started in its own process group, and PdfTool previously died on it without writing an envelope.BenchmarkPreflightProfileexposes only--profileonbenchmark, not the full preflight option set.Qualification tooling:
scripts/resource_envelope/synthetic_workload.pydeterministically generates the office (≈2.0 MB), image-heavy (≈501 MB) and 10,000-page (≈62 MB) fixtures, using SHAKE-256 noise images stored with FlateDecode. The pathological-vector and transparency-spots fixtures come from the existing generator, and their digests match the Session 11 records. The 10,000-page fixture uses a newsynthetic-image-heavyworkload whose caps equal the DIV2K ones.run_matrix.py:InternalError) and timeouts fail the record outright. A non-zero exit or missing envelope only flags it.recovery_ms).UnitTests/testdata/budget_exhaustion/PDF. Each must end in a contained exit code within its timeout and under the resident ceiling.--strictnow requires the probe and the hostile lane.build_resource_envelope_evidence.pybuilds schema-2 evidence carrying the CI run id and URL.validate_resource_envelope_evidence.pyacceptspassedonly when both platforms measured everything on one candidate SHA. Schema 1 (Session 11) is unchanged..github/workflows/resource-envelope-qualification.ymlcovers Linux and Windows builds ofPdfTool, fixture generation, the strict matrix (3 repetitions), and an evidence job. It runs onworkflow_dispatchand on PRs touching envelope paths, so normal CI stays fast.Decisions made with the requester: synthetic fixtures generated in CI instead of the DIV2K bundle;
recovery_msdefined as reopen-after-cancel; qualification in a separate workflow.Release changelog
Topic fragment:
changes/cc-issue-19-resource-envelopes.md(Category: added). Refs #19.Proof
check-change.py --base origin/dev: the source checks (changelog, source integrity, catalogs, policy adapters, architecture contracts, qt runtime) pass locally. The nativebuild:*andfocused_testschecks fail locally only because this worktree has no configured build directory; configuring one needs approval under AGENTS.md. The C++ is compiled and tested only by CI on this PR.changes/<sanitized-head-branch>.mdfragment, pluschanges/cc-issue-19-resource-envelopes.evidence.yamlUnitTestsPdfToolContractgainsbenchmarkWithoutPreflightProfileIsIncompleteandbenchmarkWithPreflightProfileIsComplete. These run in CI only.docs/RESOURCE_ENVELOPE_BUDGETS.jsongains asynthetic-image-heavyworkload with the same caps as DIV2K, and no cap is loosened.benchmarkgains the--profileoption. The matrix JSON schema version goes 2 → 3 (it adds probe and hostile sections), and the evidence schema adds version 2.resource-envelope-qualificationrun on this PR produces the measurements. They get committed underdocs/evidence/issue-19-resource-envelope/, with the run id, as a follow-up commit on this PR. If the run fails a budget (the 500 MB fixture against the 768 MiB resident ceiling is the most likely), the disposition says so rather than being tuned away.Local fixture check: the full bundle builds in 18 s and every fixture passes
qpdf --check.Internal logic (touched behavior-bearing code)
--profilefails withInvalidInvocationbefore any work, and a tampered hostile fixture or wrong manifest digest fails before running_load_fixture_manifest, and profiles throughimportPreflightProfilecomplete, and-1is never promoted to a measurementQuality pass
anyor equivalent cast added only to suppress a type errorQuality summary (1-3 sentences):
An early draft added a cancellation hook to
PDFRasterizerPoolinLoopLibCore/sources(a protected path). I replaced it with PdfTool-side sliced rendering so no protected interface changes. The old in-fixture cancellation path inrun_matrix.pyis replaced by the separate probe, and the duplicated post-hoc identity checks inrun_matrixare folded into one helper.Security and rollback
--profileis unchanged, and WindowsSIGBREAKhandling is the only behaviour change outsidebenchmarkDocs
docs/RESOURCE_ENVELOPE.mdanddocs/RESOURCE_ENVELOPE_QUALIFICATION.mdSelf-review (BSP-002 §4.3)
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.