ci/woodpecker/push/deploy Pipeline was successful
Root cause of a real run's failure: Phase 2 passed (patroni-0 reached standby_leader, patroni-1's basebackup completed, role flipped to "replica"), but Phase 3's canary write then failed to propagate within 5s moments later. patroni_lag() queried the REPLICA's own /patroni endpoint for lag data — but that field only exists on the LEADER side (derived from pg_stat_replication); a replica's own /patroni response never has it. So $LAG_INFO was always empty, and Phase 2's gate `[ -z "$LAG_INFO" ] || ...` short-circuited permanently true — the lag check never actually ran. Phase 2 degraded to "did role flip to replica 3x in a row", which can be true before the replica has genuinely caught up on WAL backlog from its own basebackup. Fixed by replacing patroni_lag() with cluster_member_lag_state(), which queries the LEADER's /cluster endpoint (real pg_stat_replication-backed data, same shape verified in the original dry run) and extracts the specific replica's state/lag fields from its member object. Phase 2 now requires literal state=streaming AND (lag=0 or absent), not just "field was empty because we asked the wrong node." Phase 4's informational lag log line updated to match.