Repository navigation
L04-08: forward rollback with revalidation, and cross-surface parity (#40) - #218
Merged
Merged
Conversation
mberrys
force-pushed
the
l04-08-rollback-parity
branch
from
October 5, 2026 12:54
9d2728d to
5b48094
Compare
mberrys
force-pushed
the
l04-08-rollback-parity
branch
from
October 5, 2026 12:59
5b48094 to
a077678
Compare
…hread (#40) The Editor ran PDFOperationHistoryStore::rollbackTo synchronously on the GUI thread, where the #38 revalidation reaches PreflightEngine::run and is refused: "Preflight cannot run synchronously on the interactive thread." (LoopLibCore/sources/preflightengine.cpp:7147). Measured: UnitTestsEditorHost fixRollbackReturnsToARecordedRevision failed with "PreflightEngine::run must not run on the interactive thread" immediately before host.requestFixRollback(rollbackId) returned false, so "rollback revalidates the restored revision" was unsatisfiable from the Editor. Route the rollback through the session's PDFJobScheduler exactly like the Action List run. requestFixRollback keeps every synchronous validation (availability, path, store open, rollback point, current-bytes digest, audit event, validated profile) and the request construction, then submits a PDFJobKind::Other / Operator job. The worker builds its own PDFOperationHistoryStore and PDFArtifactStore (Qt SQL connections are thread-affine, so the GUI-thread store is never touched off-thread), runs rollbackTo and, on success, enforceRetention, recording both in a RollbackJobOutcome. jobFinished dispatches finishRollbackJob first, which announces the same success/retention/failure messages, re-opens the rolled-back revision and refreshes the rollback points. A second request while one is in flight is refused, and job cancellation is honored between restore and retention. The test pins the bundled :/profiles/loop-default.json deterministically and waits on the scheduler's jobFinished (the RolledBack event is the completion signal); probing the history while the worker held its SQLite connection contended for the database and made rollbackTo fail "database is locked", so the wait is on the scheduler, not the store. The unknown-revision refusal leg now also asserts no sibling revision was written. Note: the bundled profile is auto-selected at construction, so a refusal leg that calls requestFixRollback(rollbackId) before an explicit profile selection is unsatisfiable; the Editor's fail-closed refusal path is pinned by the unknown-revision leg and the profile requirement by Core's rollbackRefusesWithoutProfileOrOnCompromisedChain. Commands/results: - clang-format --dry-run --Werror LoopEditor/editorhost.h LoopEditor/editorhost.cpp UnitTests/tst_editorhosttest.cpp: clean. - cmake --build C:/.dev/repos/loop-build-l04 --target LoopLibCore LoopEditor LoopLibInteraction UnitTestsEditorHost UnitTestsProductOperatorLoop UnitTestsOperationHistory UnitTestsGovernedExecution: ok. - ctest --test-dir C:/.dev/repos/loop-build-l04 -R '^(UnitTestsEditorHost|UnitTestsProductOperatorLoop|UnitTestsOperationHistory|UnitTestsGovernedExecution)$': 4/4 passed; UnitTestsEditorHost 24 passed / 0 failed. - python scripts/agent/check-architecture.py: architecture contracts ok. - python scripts/agent/test_architecture_contracts.py: OK (8 tests, 1 skipped).
mberrys
force-pushed
the
l04-08-rollback-parity
branch
from
October 5, 2026 14:04
a077678 to
c587089
Compare
# Conflicts: # LoopLibCore/sources/pdfoperationhistorystore.cpp
# Conflicts: # UnitTests/tst_operationhistorytest.cpp
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.
Summary
L04-08 (#40), the final slice of the L04 Governed Operation Engine stack (refs #5). Rollback now creates a new revision that is revalidated and signed off like any other publication, a CLI rollback surface exists, and the cross-surface parity claim is bound to a named fixture that runs in CI.
Stack position
Slice 8 of 8. Base:
l04-07-provenance-signoff(#217). Root of the stack targetsdev; land bottom-up.Per-criterion: already satisfied vs built here
PDFArtifactStore(content-addressed, verify-then-restore) + history retention; unchangedrollbackTorestores the verified prior bytes as a new revision, revalidates through the #38 finalize path, records aRolledBackevent carrying{approval, revalidation, sign_off}+ report/profile digests; on revalidation failure it fails closed (removes the destination, appends the Failed event)verify()-before-append guard refuses to extend a compromised chain; fault injections: missing profile refuses, rewritten history refuses (no destination, no new event)UnitTestsProductOperatorLoop::governedPublicationParityAcrossSurfacesdrives CLI repair, CLI action-list, the Editor Action List route, and PageMaster over one fixture + plan, against committed receipts inUnitTests/testdata/governed-parity/;check_governed_parity.pynow runs in CI over those receipts (closes thed5-cross-surface-identity-equalityTODO)pdftool rollback(JSON-only), with the full registration trainParity claim, stated precisely
The recon's "all four surfaces share
source_sha256+effective_profile_digest" is false for PageMaster: it publishes a derived source-identity digest and its own resolved-profile digest. The test therefore asserts literal shared identity across repair / action-list / Editor and pins PageMaster's own digest through its manifest fixture; action-list plan-digest equality holds for the CLI action-list <-> Editor pair.Required proof
python scripts/agent/check-change.py --base 1a092d68 --head c587089b --head-branch l04-08-rollback-parity --build-dir <loop-build-l04>-> status: pass, 103/103 checks.9d2728d9. The stack rebase left this slice's own diff unchanged (patch-id verified) and the only later edit is a documentation-only fragment correction, so the proof carries for the code; CI re-runs the mapped lanes on the head above.PDFJobScheduler(the first proof run caught the Editor callingPreflightEngine::runon the interactive thread, which the engine refuses by invariant,preflightengine.cpp:7147); the worker builds its own store because Qt SQL connections are thread-affine.agent-fastis authoritative.Notes
Closes #40.quality-budgets.yamlmetric entry (protected file) — the lane + fixture paths are bound instead.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.