fix: make ticket failure precondition atomic - #28
Conversation
There was a problem hiding this comment.
Deterministic Validator approval for exact head 1e40d0fe26a4e09a808bff6e516ef0f22d3459eb.
Ticket: PLF-28
Correlation ID: planfile-pr-28-PLF-28
Model: zai/glm-5.3
Reviewed diff chunks: 2
Advisory LLM verdict: APPROVE
Advisory summary: Reviewed all 2 diff chunk(s). Adds optimistic concurrency (expected_updated_at compare-and-set) to ticket update/fail paths across store, API, and client, with a dedicated /fail-if-current endpoint, 409 conflict handling, and capability advertisement. Guard applies in both single-file and sharded storage under the mutation lock. | Test coverage for the compare-and-set failure precondition is solid: stale updated_at returns 409 without mutation (including no history/event changes and sharded-store coverage), current timestamps are accepted (including from evidence projections), and the fail-if-current endpoint requires the precondition (422). Server implementation chunks are reviewed separately.
Advisory findings: none
The LLM output above is advisory and was not used as the approval trust root.
Merge will be attempted after this approval when explicitly authorized.
Decision record (recomputable)
DECISION D-028-6476
TICKET PLF-28
HEAD_SHA 1e40d0fe26a4e09a808bff6e516ef0f22d3459eb
CORRELATION_ID planfile-pr-28-PLF-28
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["notify=PASS","ci-loop=PASS"]
INPUT required_checks = ["ci-loop","notify"]
INPUT required_checks_source = "protected registry (env/request)"
INPUT reviewer_login = "ifuri-validator-agent[bot]"
VERDICT APPROVE AUTHORITY DETERMINISTIC
REJECTED REQUEST_CHANGES BECAUSE NO_UNSAFE_CHANGE_REASON_FOUND
ADVISORY llm_verdict = "APPROVE" MODEL "zai/glm-5.3"
ASSERT VERDICT_AUTHORITY != "ADVISORY"
Summary
expected_updated_atenforcement to ticket failure transitionsPOST /tickets/{id}/fail-if-current, where the precondition is requiredticket.fail.expected_updated_atin/healthWhy
Subactor Core's stale-execution watchdog can re-read a candidate before failing it, but without a server-side compare-and-set another process can still update the ticket between that read and the failure mutation. The distinct endpoint is important for rolling upgrades: an older Planfile returns 404 instead of silently ignoring an unknown JSON field and performing an unsafe legacy failure.
Verification
1e40d0fgit diff --checkpasses