test: concurrent revision-authority stress scenario (#236) - #505
Merged
Conversation
Issue #236 requires that DocumentContext be the single revision authority for caches and asynchronous results, and holds the issue open until the concurrent stress scenario passes. The fence, the identity separation, and the revision-keyed session and job caches already landed; the acceptance scenario itself was the one criterion with no coverage. tst_documentsessiontest.cpp proves the fence in one orchestrated round, with every producer released after the mutation. This adds the acceptance scenario instead: render, preflight, thumbnail, and repair-plan jobs in flight together while the document is mutated at points the producers do not observe, and asserts the four correctness properties named in the issue - zero stale findings applied, zero stale tiles presented past an invalidation boundary, deterministic cancellation, and no cache serving a result for the wrong revision. A stress test that quietly stops exercising the fence is worse than none, so the non-vacuity checks are deterministic rather than timing-based: a final phase holds one producer per job kind inside its work function, mutates the document underneath all of them, and only then releases them, asserting both the consumer-side rejection and the scheduler-side Stale outcome. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaL7wNZgrcZibFiBZenb6t
The source_integrity job regenerates docs/generated/phase5-widgets-inventory.json and compares it against the tree; adding UnitTestsRevisionStress made the tracked copy stale (67 -> 68 targets). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaL7wNZgrcZibFiBZenb6t
The Phase 5 widgets contract test pins the generated target count, so a new test executable has to move it with the regenerated inventory. Verified by running the full scripts/ci unittest discovery (219 tests) locally. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaL7wNZgrcZibFiBZenb6t
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.
Why
#236 makes
PDFDocumentContextthe single revision authority for caches and asynchronous results, and states the issue stays open until "identity-separation tests, revision-bound cache/job tests, stale-result rejection, and the concurrent stress scenario pass".Reading
dev, the first three are already covered by work that landed from PRs #254/#258:PDFDocumentContext/PDFRevisionIdentity(aliasPDFRevisionToken) own the fence, separate from persistedPDFArtifactIdentity(UnitTestsIdentitySeparation);PDFDocumentSessioncache keys carry the revision, andPDFJobSchedulerdiscards results whose revision is no longer current (UnitTestsDocumentSession,UnitTestsJobScheduler);IJobSubmitterand keys surface caches by revision.The acceptance criterion with no coverage was the stress scenario itself. The existing
UnitTestsDocumentSession/concurrentScheduledResults_rejectSupersededRevisionsproves the fence in one orchestrated round — every producer is released after the mutation — which is not the hostile workload the issue describes.What changed
UnitTests/tst_revisionstresstest.cpp(new targetUnitTestsRevisionStress) runs the acceptance scenario: render, preflight, thumbnail, and repair-plan jobs in flight together across 64 rounds while the document is mutated and the effective profile changes at points the producers do not observe. Results are admitted through a single revision-gated consumer that models the findings model, the tile presenter, and the evidence cache under one mutex covering the fence and the retained entries together.It asserts the four properties the issue names:
A stress test that quietly stops exercising the fence is worse than none, so the non-vacuity checks are deterministic rather than timing-based:
Staleoutcome.A third test walks
PDFDocumentSessionacross document mutations and profile changes, asserting the session follows the context and drops its compiled-page cache rather than reconciling it.Also: policy test mapping (
agent-policy.json), the generated architecture catalog and Phase 5 widgets inventory, the pinned Phase 5 target count (67 → 68), the changelog fragment, and the#236rows indocs/REVISION_CONTEXT.md,docs/SEMANTIC_TRUST_ENGINE_ACCEPTANCE.md, anddocs/UPSTREAM_DIVERGENCE.md.No production code changed.
Proof
All checks are green on
8a6cb91. Theagent-fast / buildjob rancheck-change.pyend to end with"status": "pass":build:UnitTestsRevisionStress— pass (compiles and links against Qt 6.11.1);focused_tests— 25/25 ctest targets passed, includingUnitTestsRevisionStress;clang_tidy:UnitTests/tst_revisionstresstest.cpp— pass;source_integrity,policy,architecture-docs, and CodeQL are also green.The earlier revision of this description said the build and test evidence was unproven; that was true when the PR was opened (this session has no Qt toolchain, so
check-change.pycould only run the source-level checks locally) and CI has since supplied it. The two red checks along the way were both generated-evidence bookkeeping that follows from adding a target — a staledocs/generated/phase5-widgets-inventory.jsonand the Phase 5 contract test's pinned target count — fixed inf4ba214and8a6cb91.UnitTests/CMakeLists.txtis a protected path; the change to it is additive (one new test executable plus itsadd_test) and introduces no new public contract.🤖 Generated with Claude Code
https://claude.ai/code/session_01MaL7wNZgrcZibFiBZenb6t