Repository navigation
Conversation
A protected-source withdrawal also records rows for companion revisions (unretired predecessors and later candidates). reduceCredentialPolicy only reduces the active revision's policy, and for any other revision it threw a plain error, which the worker retried as DEPENDENCY_UNAVAILABLE and maintenance re-queued forever. Return retire-runtime for a recorded withdrawal on a revision that is not the Agent's active one, so Compute reports the existing replay-awaiting refusal. The row stays pending, so egress stays refused.
Record deployment work in the protected withdrawal fixture so one later candidate can fail for good while another stays queued. Both get companion withdrawal rows from the real withdraw route and must report CREDENTIAL_WITHDRAWAL_REQUIRES_RUNTIME_RETIREMENT without dispatching a reduction; a call without a recorded withdrawal still fails as before. Document the reason in the withdrawal reference.
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. What this changesThis PR replaces repeated companion-revision withdrawal failures with the existing retirement refusal and documents replay recovery. Example: Version 2 is selected while versions 3 and 4 hold the same protected credential source, with one deployment failed and the other queued.
Review scores
ProductKind: Bug fix · Worth it: Yes · Fix scope: Complete Merge readiness✅ Ready for maintainer review The previous flow-documentation finding is resolved, and no new actionable defect was found; this maintainer-authored PR remains open for landing review. Priority: P2 Before mergeNone. FindingsNone. Tests
Agent review detailsHow this fits togetherOCC records authorized source withdrawals in PostgreSQL; the worker invokes Kubernetes Compute and the policy reducer, then records withdrawal results and recovery work. flowchart TD
A[Authorized withdrawal request] --> B[OCC withdrawal rows]
B --> C[Controller worker]
C --> D[Kubernetes Compute]
D --> E[Policy reducer]
E -->|Selected revision| F[Credential Proxy peer]
E -->|Companion revision| G[Retirement refusal]
G --> C
Technical reviewBest possible solution: Use the existing retirement-refusal path for companion revisions while preserving pending withdrawals and documented replay recovery. Do we have a high-confidence way to reproduce the issue? Source inspection confirms that companion withdrawals reach main's selected-revision error and the worker's retry classification; the author reports base-failing and head-passing PostgreSQL runs, which were not rerun during this read-only review. Is this the best way to solve the issue? The change is a focused repair in the existing reducer, preserves its selected-revision invariant, and reuses Compute and worker handling rather than adding another recovery mechanism. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 6fa1aa00c9f9. Provenance checked
TestingProof path: in-process harness. SecurityNone. EvidenceWhat I checked:
Likely related people:
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment HistoryReview history (1 earlier review cycle)
Reviewed October 23, 2026, 4:01 AM ET / 08:01 UTC (Revision 2). |
Check for another active revision right after the withdrawal lookup, before the repository-attempt read. Cover a revision that loses active ownership to the deploying candidate while its reduction is recorded but unobserved: it requires retirement without observing or repeating the operation. Explain the claim loop and the recorded deployment work in the test. Point the operator guides to the withdrawal reference when revisionId names another version.
… lifecycle flow reduceCredentialPolicy reduces protected sources only on the selected version; elsewhere it sends nothing and the refusal awaits a replay. List CREDENTIAL_WITHDRAWAL_REQUIRES_RUNTIME_RETIREMENT among the codes that fail withdrawal work at once.
|
@clawsweeper re-review Added the lifecycle flow update (section 9 and the reason-code list) in 6fc32e0, plus a superseded-revision custody case in the test and guide wording from an internal review. |
|
🦞👀 Re-review progress:
|
Problem
With a Credential Proxy Driver that declares
policyReduction(no bundled Driver does; the protected-execution fixture does), withdrawing a protected source from an Agent also records withdrawals for its companion revisions (credentialWithdrawalCompanionRevisions): unretired predecessors and every later admitted revision, for example a candidate whose deployment failed or is still running.reduceCredentialPolicyonly reduces the policy of the Agent's active revision. For any other revision it threw a plainError("no exact admitted owner or withdrawal"). The Kubernetes Compute Driver passed it through, the worker classified it as retryableDEPENDENCY_UNAVAILABLE(not a replay reason), and the companion's withdrawal was retried on every maintenance pass (or, without maintenance, through the hour-long recovery chain) without ever settling. While an attempt was queued, deleting the source answeredCREDENTIAL_WITHDRAWAL_IN_PROGRESS. Egress stayed refused throughout, because any withdrawal row blocks use on that revision, so this was a liveness bug, not an exposure.Change
reduceCredentialPolicynow returnsretire-runtimewhen a source withdrawal is recorded for the revision and another revision is the Agent's active one. The check runs inside the existing transaction, under the Namespace and Agent locks, before any reduction is recorded or dispatched. Compute then reports the existingCREDENTIAL_WITHDRAWAL_REQUIRES_RUNTIME_RETIREMENTrefusal. The worker records it once as a permanent result that waits for a replay, and maintenance no longer re-queues it.Why this direction rather than treating "withdrawal recorded and no installation ever recorded" as withdrawn:
retire-runtimenever marks anything withdrawn.pending, so OCC keeps refusing egress for the source on that revision (checkEgressUseInand the send authorization both refuse on any withdrawal row).Unchanged on purpose:
sourceIdundefined) is unaffected: it never has a source withdrawal row.How it settles: the next deployment that succeeds retires every earlier version, including the companion, which also drops it from the read's companion walk. If the companion becomes the selected version instead, a replay reduces it in place. The read can report the companion's pending withdrawal (with its
revisionIdandwithdrawalInProgress: false, which already means "replay needed"). The withdrawal reference documents the reason code, the lifecycle flow traces the refusal, and the two operator guides now send a reader whoserevisionIdnames another version to that reference instead of the stop procedure.The test fixture now records deployment work (
recordOperations: truethrough the sharedpostgresApphelper), so it can tell a failed candidate from one still deploying.Verification
tests/integration/credential-proxy-withdrawal.test.ts(PostgreSQL Platform lane) now deploys two later candidates: one whose reconcile work fails permanently through the real work queue, then one still queued. The real withdraw route records a companion row for each. Through the real Kubernetes Compute Driver, each candidate's withdrawal now rejects withCREDENTIAL_WITHDRAWAL_REQUIRES_RUNTIME_RETIREMENT; its row stayspending; it records no reduction operation; and the peer receives no reduction (appliesstays 0). Before the withdrawal, the same call on a candidate still fails with the original "exact admitted owner" error.Comparison {}instead of the expected code) and pass with the fix.pendinginstead ofretire-runtime; applying the branch only without a recorded reduction; dropping the transaction result passthrough.taskset -c 0-1), 3.2 s to 3.8 s each, against one prepared lane database reused across runs.1a53e15a3asked for the lifecycle flow update; it is in6fc32e0d8.postgres-worker-agent-revision-credential-sources.test.mjs.tsc --build tsconfig.json tests/tsconfig.json, ESLint and Prettier on touched files,pnpm docs:checkand the flow-doc validator pass. The lifecycle flow is at 2497 of 2500 words.Risks
policyReduction, so production installs with bundled Drivers see no change.