| The collection lists newest first and pages correctly, and a filtered listing returns full pages rather than short ones | COL-100, COL-101 | A | collection.featuretests.test.ts |
| A collection read is refused when the owner key does not match the signed-in user, and a favorites page contains only the caller’s rows | COL-102, COL-105 | A | collection.featuretests.test.ts |
| An unauthenticated read returns an empty collection rather than throwing, so a screen mid-sign-in never renders an error | COL-103 | A | collection.featuretests.test.ts |
| The unpaginated listing sorts newest-first and honours a status filter | COL-104 | A | collection.featuretests.test.ts |
| A favorite carries the moment it was favorited in its own field, distinct from when its row was created, and a fully drained favorites listing stays in newest-first order | COL-106, COL-106b | A | collection.featuretests.test.ts |
| Favorites hooks drain every page automatically, and skip the drain entirely while authentication has not settled | COL-121 | B | useCollectionPreferences.featuretests.test.tsx |
| Paginated mode reports whether more pages exist and whether one is loading; “load more” is a no-op in unpaginated mode and is fenced while offline | COL-122, COL-123 | B | useCollection.featuretests.test.tsx |
| Searching favorites matches name, notes and tags case-insensitively, clamps the requested limit, and is honest about only searching a recent window | COL-107, COL-108, COL-109 | A | collection.featuretests.test.ts |
| Filtering favorites by tag matches the whole tag, not a substring of one | COL-110 | A | collection.featuretests.test.ts |
| Favorite statistics aggregate by strain type, average potency and the five most-used tags; collection statistics count every bucket the screens display | COL-111, COL-112 | A | collection.featuretests.test.ts |
| Asking for the status of a strain that is not in the collection returns the empty shape, not an error, and the home preview returns only the three fields it renders | COL-113, COL-114 | A | collection.featuretests.test.ts |
| The My Strains list counts only completed orders, keys a line with no strain id by its name, converts every purchase unit to grams, sorts ranked strains first then alphabetically, and returns nulls rather than absent fields | COL-116, COL-117, COL-118, COL-119, COL-120 | A | collection.test.ts, collection.featuretests.test.ts |
| The six tabs filter to their own status, and the manage-favorites route opens on the Favorites tab | COL-130, COL-131 | B | collection-management.helpers.test.ts |
| Sorting by rank puts unranked strains last; sorting by name is A–Z | COL-132 | B | collection-management.helpers.test.ts |
| The chosen card layout persists across mounts, maps to its own column count, drops to two columns on a narrow or large-text screen, falls back to the default when the stored value is unreadable, and warns without crashing when the write fails | COL-134, COL-135, COL-136, COL-137 | B | CollectionScreens.test.tsx, collectionCardVariantPreferenceStorage.test.ts, collection-management.featuretests.test.ts |
| A cold offline launch shows the controls, not a false empty state; retry is blocked while offline; the genuine empty state appears only after an online resolve | COL-138, COL-139, COL-140 | B | CollectionColdOffline.test.tsx |
| ”No results for your search” is a different state from “your collection is empty” | COL-141 | B | CollectionScreens.test.tsx |
| Every write action is blocked while the screen reports that actions are unavailable, and a user without the entitlement sees the mock collection behind the access gate | COL-142, COL-145 | B | CollectionScreens.test.tsx |
| Switching accounts never shows the previous account’s rows | COL-144 | B | CollectionColdOffline.test.tsx |