v3.022; 3, 4 and 5 in v3.028; 6 in v3.031; 7 to 10 on the server (live); 11 to 16 in the app in v3.039; 17, 18, 19, 21 in v3.050; 20 in v3.061. All 21 done. Everything else is waiting for a pick.| # | Problem (before) | Fix (now) | Risk |
|---|---|---|---|
| 1 | "Branch New Song" worked on a song an admin took down. Branch, then publish, and the same track was live again with no review, and could earn tips. | Branching is refused for songs taken down by HOOP ("taken down after a review"). Songs the creator took down themselves can still be branched. The takedown message no longer points to Branch for admin takedowns. | High · moderation |
| 2 | Agree on the split saved whatever the share was at that moment, not the number the collaborator saw. The owner could lower it just before, or change it while publishing, and tips then paid the lower number. | The app sends the number on the card. If it changed, the server says so and the card reloads with the new number. Setting the split, agreeing and all three publish paths now take the same per-song lock, so a change can't slip in between the check and the publish. | High · money |
Checked with tests against a real database (and one app test on the real screen), each fix broken on purpose once to confirm its test fails. Older app versions that don't send the number still work as before; that half closes fully once everyone updates.
| # | Problem (before) | Fix (now) | Risk |
|---|---|---|---|
| 3 | A creator whose song was reported could tap Take down first. The admin takedown then failed ("already taken down"), no strike was counted, and later the creator could restore it or delete it forever, removing the evidence. | An admin can now take down a song the creator already took down. It becomes a HOOP takedown, so the strike counts and Restore and Delete forever are blocked. While a report is still open, a song the creator took down can't be deleted forever ("Someone reported this song and a moderator hasn't looked at it yet…"). If the platform owner undoes such a takedown, the song goes back to the creator's own takedown, not back online. | Medium · moderation |
| 4 | The "earned" number on a song included the collaborators' cut. Example: a 100 Spark tip with one collaborator pays the creator side 50 (25 each), but both the owner and the collaborator saw 50. | Each person now sees their own share: 25 each in that example. The collaborator invite card still shows the whole song's creator side, because it tells the invitee how big the pot is. | Medium · money |
| 5 | When the Spark purchase behind a tip was refunded, the money was taken back from the creator's balance, but every "earned" and revenue number still counted the tip. | Earned, the dashboard total, Revenue (gross, platform, collaborators, net, by song) and the song's tip total all subtract refunded tips. The balance was already correct. The "Recent" list on Revenue still lists tips only; refunds show in the totals. | Medium · money |
How it was checked: two tests against a real database walk real numbers through (takedown → admin takedown → restore / delete / undo; two tips, a split and a refund). Each of the 8 changes was broken on purpose once and its test failed every time. Tests: takedown_dodge_1005_db_test, earned_refund_1005_db_test in backend/internal/domain/music/, and music_purge_reported_1005_test in the app. No database migration. The new "can't delete while reported" message reaches phones with the next TestFlight build; until then they show a generic failure.
| # | Problem (before) | Fix (now) | Risk |
|---|---|---|---|
| 6 | Branching a collaboration made a solo copy: the audio and lyrics came along, the collaborators didn't. The owner then got every tip on a song someone else co-wrote, and nobody was told. | Haikal chose A. Each collaborator on the original (except anyone who declined, or who is no longer a Creator) gets a new invite on the branch, with the same role and share, in the bell and in chat. They decide again: the branch can't be released until they accept and agree the split. After branching, the owner sees "N collaborators were invited again — the song can be released once they accept". | Medium · money |
How it was checked: a test against a real database branches a song with four collaborators (accepted, pending, declined, no longer a Creator) and checks who is invited, with which role and share, that agreement isn't copied, that the invite notification arrives and that the branch can't be released. Four ways of breaking it were tried; the test failed every time. Test: fork_collabs_1005_db_test. No database migration.
| # | Problem (before) | Fix (now) | Risk |
|---|---|---|---|
| 7 | Once a song was published, anyone could play its older, unreleased takes by adding ?v=1, ?v=2… to the play link (version numbers just count up). Those takes were also cached publicly. | Only the live version is public. Earlier versions play only for the owner, accepted collaborators and admins, and are never put in a public cache. Accepted collaborators can now also preview a draft. | Low · privacy |
| 8 | No limits: one account could create any number of drafts and branches, and "Your music" loaded every song in one go. | At most 100 unfinished songs (drafts and branches not yet released) per creator; the 101st gets "You have 100 unfinished songs — release or delete some first". Released, in-review and taken-down songs don't count. "Your music" returns the newest 500; the totals (plays, tips, likes) still count every song. Numbers agreed by Haikal; easy to change later. | Low |
| 9 | Delete forever removed the audio first and the song row second, with nothing locked. If the second step failed, the song stayed in the list but could never play. A tip landing in the same moment could slip past the "has tips" check; its record was then deleted with the song while the money had already moved. | Delete forever now locks the song, runs its checks, deletes the row, and only then removes the audio. A tip locks the same song row, so the two can't overlap: either the tip lands first and the delete is refused, or the delete goes first and the tip finds no song. | Low · money |
| 10 | The daily song quota (and magic pen, style helper, AI covers) switched to a new day at 8 am Malaysia time, because the server runs on UTC. | "Today" is Malaysia time everywhere in Studio: limits reset at midnight. | Low |
How it was checked: tests against a real database for 7 (who can play which version, cache header) and 9 (a tip held open while a delete runs: the delete waits, then is refused; a clean delete removes row then audio), plus a fixed-time test for 10 and two source checks (the tip takes the lock; no "today" in Studio uses server time). Eight ways of breaking these were tried; the tests failed every time. Test file: studio_r2_server_1005_db_test. No database migration.
| # | What | Risk |
|---|
| # | Problem (before) | Fix (now) |
|---|---|---|
| 11 | Publish on a song that's in an EP/album published the whole release in one tap, and any problem showed "That round failed" (the real reason was read from the wrong place). | It asks first: "Publish “My EP”? This publishes the whole release, not just this song…". If the server refuses, its own reason is shown (for example "add a cover first"); offline says "Can't reach the network right now". |
| 12 | Collaborators saw Branch and Rollback on the versions page; both always failed. | Only the owner sees them. |
| 13 | Branch, Rollback, Take down, Restore, Delete forever: a double tap sent two requests (two branches); offline nothing happened. | A second tap is ignored while the first is running; offline shows "Can't reach the network right now". |
| 14 | The "Can't reach server, retrying…" banner never retried. | It retries by itself: after 2, 4, 8, 16, 32 seconds, then every minute, until it works. |
| 15 | After changing a cover or deleting a comment, the song list and the "Keep creating" card still showed the old cover / count. | Both refresh right after. |
| 16 | The Songs tile counted taken-down songs the list hides; the Releases tile showed 0 when it couldn't load. | Songs counts what the list shows; Releases shows "–" when it couldn't load. |
Also: the phone's own message for the 100-unfinished-songs limit (item 8). How it was checked: tests that open the real Studio screen (only the network is faked) for 11 to 14 and 16, a source check for 15, and pure checks for the retry timing and the Songs count. Ten ways of breaking these were tried; the tests failed every time. About 80 existing Studio test files give the same results as before. Test: music_studio_r2_app_1005_test. Phones get these with the next TestFlight build; the web version has them now.
| # | Before | Now |
|---|---|---|
| 17 | Every visit to Studio started with empty rows waiting for the network; offline there was nothing but an error line. | Studio shows the last saved songs and releases immediately, then refreshes. Offline you still see them, with "Can't reach server, retrying…" on top. Switching account clears the saved copy. |
| 18 | All songs (up to 500) were drawn at once; songs in review could only be found in "All". | 50 rows, then "Show more (N)". An "In review" chip appears when you have songs in review. When the chips don't fit next to "Your music" on a narrow phone, the row scrolls sideways instead of overflowing. |
| 19 | One tap on the remove icon removed a collaborator. | "Remove Ben from this song? Ben will no longer be credited or share in tips…" with Cancel / Remove. |
| 21 | Recent tips and Top supporters showed raw Spark numbers while the rest of Studio shows MYR; some dates were machine-format ("10-05 14:30", "2026-10-05"); 26 unused text entries. | All amounts in MYR; dates follow the app language; the 26 unused entries removed (English and Chinese). |
How it was checked: tests on the real Studio screen for 17 (saved copy shows offline), 18 (50 rows, show more, In review chip), 19 (asks first, cancel keeps, remove removes) and 21 (MYR in tips), plus checks for dates and the removed text. Six ways of breaking these were tried; the tests failed every time. Existing Studio tests give the same results as before (two were updated because they expected the old one-tap remove / publish).
| # | Before | Now |
|---|---|---|
| 20 | Small filter chips (12.5 pt text) and a 24-tall Cover button under the song cover: hard to tap. | Haikal chose A: chips one size bigger (13.5 pt text, more padding), Cover button 32 tall with a larger icon and text. On narrow phones the chip row scrolls sideways instead of overflowing. Leong was told; easy to switch back. |
How it was checked: a test measures the chip height and the Cover button (32), and opens Studio at 360 wide with all five chips to make sure nothing overflows. Three ways of breaking it were tried; the test failed every time.
For Haikal to test everything from this page. Server items (1–10) are live now; app items (11–21) are on the web version (hoop-web.pages.dev, refresh once) and reach phones with the next TestFlight build.
| # | How to test | What you should see |
|---|---|---|
| 1 | Needs an admin. Admin takes down a published song (moderation). As the creator, open the song → Versions → tap Branch. | Refused: “This song was taken down by HOOP after a review…”. Then take down one of your own songs yourself and Branch it: that works. |
| 2 | Two accounts (owner + accepted collaborator) on a draft. Owner sets a split (e.g. 70/30). On the collaborator's phone the split card shows 30%. Before they tap Agree, the owner changes it to 10%. Collaborator taps Agree. | Collaborator sees “The split changed” and the card reloads showing 10%. Nothing is agreed until they tap again. |
| 3 | Needs an admin + a second account. Account B reports A's song. A takes the song down (Take down), then tries Delete forever. | Delete forever refused: “Someone reported this song and a moderator hasn't looked at it yet…”. Admin can still take it down (strike counts); after that A can't Restore or Delete it. |
| 4 | A song with one accepted collaborator receives a tip (e.g. 100 Sparks). Owner and collaborator each open the song. | Each sees only their own share under “earned” (e.g. MYR 0.25 each), not the whole creator side. |
| 5 | Needs a refunded Spark purchase that paid for a tip (test store refund). Open Revenue and the song page. | Gross, platform, collaborators, net and the song's earned all drop by the refunded tip. Balance unchanged (it was already right). |
| 6 | Owner of a song with collaborators (one accepted, one pending, one declined) → Versions → Branch. | Toast: “N collaborators were invited again — the song can be released once they accept”. Accepted + pending get a new invite on the branch (bell + chat); declined don't. Publishing the branch is blocked until they accept and agree. |
| 7 | Publish a song that has 2+ versions. As someone not credited (or logged out), open the play link with ?v=1. | Refused (“Only the people credited can play earlier versions”). The live version plays for everyone; the owner and accepted collaborators can play v1. |
| 8 | Create drafts until you have 100 unfinished songs (or ask me to set up a test account near the limit). Try New song / Save draft / Upload / Branch. | “You have 100 unfinished songs — release or delete some first”. Editing an existing draft still works. Released / in-review / taken-down songs don't count. |
| 9 | Race, hard to do by hand: checked by an automated test (a tip held open while Delete forever runs). Manual check: Delete forever on a song with no tips still works; a song with tips is still refused. | Song with tips → “can't be erased”. Song without tips → gone, and it doesn't come back. |
| 10 | Use Compose until the daily limit, then check after midnight Malaysia time (not 8 am). | The daily count resets at 00:00 Malaysia time. |
| 11 | A draft song that's inside an EP/album → tap Publish on the song. | A question first: “Publish “My EP”? This publishes the whole release, not just this song…”. Not yet = nothing published. If it fails, the real reason shows (e.g. missing cover), not “That round failed”. |
| 12 | As an accepted collaborator, open the song → Versions. | No Branch and no Rollback buttons (the owner still sees them). |
| 13 | Owner → Versions → tap Rollback twice quickly. Then switch on airplane mode and tap Branch / Rollback / Take down / Restore / Delete forever. | Only one action happens. Offline: “Can't reach the network right now” (before: nothing happened). |
| 14 | Airplane mode on, open Studio, wait, then turn the network back on without touching anything. | “Can't reach server, retrying…” shows, then the list appears by itself within a few seconds of the network coming back. |
| 15 | Change a song's cover, close the song page. Also: delete a comment on a song, go back. | The list row and the “Keep creating” card show the new cover right away; the comment count drops by one. |
| 16 | Have one taken-down song. Look at the Songs tile vs the All list. Then open Studio with the releases call failing (airplane mode on a fresh install). | Songs tile = number of songs in the All list. Releases shows “–”, not 0, when it couldn't load. |
| 17 | Open Studio once online. Close the app, turn on airplane mode, open Studio again. | Your songs show immediately from the last time, with “Can't reach server, retrying…” on top. Logging in as another account never shows the previous account's songs. |
| 18 | An account with more than 50 songs → Your music. Also: submit a song for review. | 50 rows, then “Show more (N)”; tapping it shows the next 50. An “In review” chip appears when you have a song in review; it shows only those. |
| 19 | Owner of a draft with a collaborator → Collaborators → tap the remove icon. | “Remove Ben from this song?” with Cancel / Remove. Cancel keeps them; Remove removes them. |
| 20 | Open Studio → Your music; open a song page. | Filter chips are a size bigger and easy to tap; on a narrow phone the chip row slides sideways. The Cover button under the song cover is taller and easier to tap. |
| 21 | Open a song with tips → Recent tips / Top supporters. Switch the app language (English ↔ 中文) and open Revenue → Recent. | Tip amounts show as MYR (e.g. MYR 2.50), like everywhere else. Dates follow the app language (e.g. “Oct 5, 2026” / “2026年10月5日”). |
Compose / edit song page (A, B, C all done): music-compose-review