From df8bc97bd2f522865ca175ec828538eefb67bf64 Mon Sep 17 00:00:00 2001 From: qdust41 Date: Sun, 12 Apr 2026 19:51:56 -0400 Subject: [PATCH] fix: unlike noop stale struct + likes floor at 0 - unlike noop now reloads tweet from DB (same fix as like noop from prev loop) - decrement_likes uses GREATEST(likes - 1, 0) to prevent negative counts - add fix_plan.md to track remaining work Co-Authored-By: Claude Sonnet 4.6 --- fix_plan.md | 25 +++++++++++++++++++++++++ lib/mixer/posts/tweet.ex | 4 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 fix_plan.md diff --git a/fix_plan.md b/fix_plan.md new file mode 100644 index 0000000..0293fa4 --- /dev/null +++ b/fix_plan.md @@ -0,0 +1,25 @@ +# Fix Plan + +## Completed + +- [x] `tweet_like` tests: `user_fixture` missing `authorize?: false`, `Ash.Query.filter` needed `require Ash.Query`, `Ash.ForbiddenField.forbidden?/1` doesn't exist (use `match?`), `like` noop returned stale tweet struct → fixed all + +## In Progress / Next + +- [x] `unlike` noop returns stale tweet struct — same issue as `like` noop; reload from DB +- [x] `decrement_likes` can go below 0 — use `GREATEST(likes - 1, 0)` via SQL fragment + +## Backlog + +- [ ] No pagination on user list (`/users`) +- [ ] No CHECK constraint on `likes >= 0` at DB level (low priority, app logic prevents it) +- [ ] `read :following_feed` returns error if actor is nil — should be policy-guarded +- [ ] No search for users or tweets +- [ ] Missing test coverage: follow/unfollow, comments, tweet creation, auth flows + +## Notes + +- Stack: Elixir/Phoenix + Ash Framework + React/TypeScript +- Tests: `mix test` — 10 tests, all should pass +- Build: `mix precommit` alias runs compile + test + format checks +- No ClickHouse in test env (expected, non-fatal errors in test output) diff --git a/lib/mixer/posts/tweet.ex b/lib/mixer/posts/tweet.ex index a73ae9c..86c4b18 100644 --- a/lib/mixer/posts/tweet.ex +++ b/lib/mixer/posts/tweet.ex @@ -148,7 +148,7 @@ defmodule Mixer.Posts.Tweet do decrement_likes(tweet, context.actor) {:noop, _like} -> - {:ok, tweet} + Ash.get(__MODULE__, tweet.id, authorize?: false) {:error, error} -> {:error, error} @@ -166,7 +166,7 @@ defmodule Mixer.Posts.Tweet do update :decrement_likes do accept [] require_atomic? false - change atomic_update(:likes, expr(likes - 1)) + change atomic_update(:likes, expr(fragment("GREATEST(? - 1, 0)", likes))) end end