Follow-up from CodeRabbit review on #842 (deferred there — flagged Major but out of scope for the "surface, never reconcile" series).
Context
ServicePolicyBuilder.build reads the Policy Store (applied_rules_for_scopes), runs detect_conflicts, and raises before compute_and_apply. This is atomic for a single writer: the store read is side-effect-free and the raise precedes any write.
Problem
Two concurrent /apply calls can each read the same clean snapshot, both pass detect_conflicts, then both proceed to the PCE separate read-modify-write and append opposite effects on the same (role.id, scope.id) — neither seeing the other rule. The conflict is silently persisted.
This is a pre-existing property of the PCE read-modify-write, not introduced by #842.
Options
- Optimistic concurrency: re-read + revalidate conflicts at commit time (CAS on a store version/etag), reject on mismatch.
- Serialize applies (single-writer lock / queue at the Controller).
- Transactional store write spanning read → detect → persist.
Acceptance
- Concurrent opposing applies cannot both commit from the same clean snapshot.
- Regression test covering two opposing concurrent applies.
Ref: ADR aiac/docs/adr/0001-identify-never-reconcile.md — the "atomic-by-construction" claim is single-writer; this closes the concurrent gap.
Follow-up from CodeRabbit review on #842 (deferred there — flagged Major but out of scope for the "surface, never reconcile" series).
Context
ServicePolicyBuilder.buildreads the Policy Store (applied_rules_for_scopes), runsdetect_conflicts, and raises beforecompute_and_apply. This is atomic for a single writer: the store read is side-effect-free and the raise precedes any write.Problem
Two concurrent
/applycalls can each read the same clean snapshot, both passdetect_conflicts, then both proceed to the PCE separate read-modify-write and append opposite effects on the same(role.id, scope.id)— neither seeing the other rule. The conflict is silently persisted.This is a pre-existing property of the PCE read-modify-write, not introduced by #842.
Options
Acceptance
Ref: ADR
aiac/docs/adr/0001-identify-never-reconcile.md— the "atomic-by-construction" claim is single-writer; this closes the concurrent gap.