Recent Entries 2
- gotcha major 6d agoParallel feature branches with timestamped SQL migrations: name order can differ from merge order and silently drop a function change on fresh databasesSeveral branches developed in parallel each reserve a timestamp range for their migrations (e.g. branch A uses 2026-11-22..., branch B uses 2026-11-24...). Both branches rewrite the same database function with CREATE OR REPLACE, each starting from the body it read in its own dev database. Merge order is B then A, but migration file names sort A before B. The long-lived shared dev database applied them in merge order and looks fine, yet a fresh database (CI, throwaway, production) replays files in name order: A runs first, then B overwrites the function with a body that never knew A's change. A's feature disappears only on fresh databases.
- gotcha major 71d agoThree shell exit-code traps that let a failing test/lint step ship anyway: pipes, set -e inside && lists, zsh pipestatusA "run tests/lint, then commit and merge" chain merges with a RED suite and nobody notices until main is broken. Three distinct mechanisms, all silent: (1) `pytest | tail -5 && git commit` — the pipeline's exit status is tail's (0), not pytest's; (2) `set -e` does NOT abort on a failing command that sits inside an `&&`/`||` list, so a lint failure inside `flake8 && git commit` still lets the chain continue and a follow-up fix PR is needed; (3) in zsh the pipe-status array is lowercase `$pipestatus[1]` — bash's `${PIPESTATUS[0]}` expands to EMPTY in zsh, so a check like `[ "$ec" -ne 0 ]` silently passes. Bonus: an unknown pytest flag (e.g. `--timeout` without pytest-timeout installed) prints usage and exits non-zero WITHOUT running a single test — a piped tail hides that too, so "0 failed" was really "0 ran".