Repository navigation
L04-04: bind exact-plan approval with expiry, revocation, and approver rights (#36) - #214
Merged
Merged
Conversation
mberrys
force-pushed
the
l04-04-approval-binding
branch
from
October 5, 2026 12:54
ef80c0f to
8e06e5a
Compare
mberrys
force-pushed
the
l04-04-approval-binding
branch
from
October 5, 2026 12:59
8e06e5a to
08ddc82
Compare
…#36) Add the exact-plan approval authorization model for issue #36. PDFApprovalRecord gains an optional expiresUtc (null = no declared expiry) and isExpiredAt(); PDFGovernedExecutionApproval gains an optional effectiveProfileDigest. A new ApprovalRevoked provenance kind revokes an approval through the append-only history chain, mirroring certificate invalidation with no second registry. resolveApprovalAuthorization() is the single decision point and fails closed on a non-affirmative decision, an unauthorized kind/actor, an expired or undeclared-required expiry, a revoked decision reference, or a profile-digest mismatch. validateGovernedApproval, finalizeGovernedPublication, publishGovernedArtifact, and validateGovernedSignOff call it before any write through an optional PDFApprovalAuthorizationContext (default {} keeps existing call sites compiling). Tests: UnitTestsGovernedExecution adds approvalExpiryWindowIsEnforced, approverRightsAreAllowlisted, profileBindingRefusesMismatch, revokedApprovalIsRefusedBeforeWrite, revokedApprovalRefusesLaterAttempt (RED-verified: short-circuiting the resolver makes all five fail). UnitTestsOperationHistory adds approvalExpiryAndRevocationKindRoundTrip and pins ApprovalRevoked in the kind list. The governed-execution test switches QTEST_APPLESS_MAIN to QTEST_GUILESS_MAIN because the revocation fixtures open a QSqlDatabase.
) Every in-repo production caller of the governed gateway now passes an explicit PDFApprovalAuthorizationContext instead of relying on the permissive default. PdfTool repair and action-list run/batch resolve revocation against the output .loop-history chain and bind the approval to computeProfileDigest() of the profile in scope; the operator --approval-file path keeps the operator's actor id and is checked against the profile actually in scope. PageMaster binds the resolved effective profile digest. PageMaster and the Editor Action List worker have no operation-history store in scope, so their contexts leave history null and revocation cannot be resolved there until #37 centralizes execution.
mberrys
force-pushed
the
l04-04-approval-binding
branch
from
October 5, 2026 14:04
08ddc82 to
2d18b06
Compare
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-04 (#36), slice 4 of the L04 Governed Operation Engine stack (refs #5). The execution gateway now decides authorization from the approval's own facts: expiry, revocation (history-chain
ApprovalRevokedevents, mirroring certificate invalidation), approver rights (actor/kind allowlists), and an optional effective-profile binding. Every in-repo production caller passes an explicit authorization context.Stack position
Slice 4 of 8. Base:
l04-03-isolated-preview(#213). Children stack on this branch; land bottom-up.Per-criterion: already satisfied vs built here
resolveApprovalAuthorizationrefuses non-affirmative decisions, empty actor, unauthorized kind/actor, expired or undeclared-required expiry, revoked reference, and profile mismatch; threaded throughvalidateGovernedApproval/finalizeGovernedPublication/publishGovernedArtifact/validateGovernedSignOffPDFGovernedExecutionApproval::effectiveProfileDigest+context.expectedProfileDigest; profile-mismatch fixtureregistry_digestinside the operation-plan envelopePDFApprovalRecord::expiresUtc+isExpiredAt; expired / requireExpiry-without-expiry / fresh fixturesApprovalRevokedkind + resolver history scan; revocation race (validate passes, revocation appended, publish refused, no output) + ordering variantRequired proof
python scripts/agent/check-change.py --base 99e08022 --head 2d18b060 --head-branch l04-04-approval-binding --build-dir <loop-build-l04>-> status: pass, 96/96 checks (LoopLibCore/PdfTool/loop-pdf-worker builds, mapped suites, clang-tidy, format, changelog, architecture contracts).ef80c0f9. 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.expiresUtc, so already-committed chains stay verifiable; the kind is persisted by name, so the new enumerator does not shift stored values.agent-fastis authoritative.Notes
Closes #36.requiredPolicyIdwas added (the allowlists plus the approval's ownpolicyIdcover the declared rights).Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.