The feature renders nothing, and fails silently
the-gaps.md records "Mutual connections on a profile (People) — chips that open that user" as shipped in session 6. It has never displayed anything.
Found by the contract-test suite (#126 / PR #159) and confirmed independently.
Why
GET /api/follow/{userId}/mutual returns counts, not users:
GET /api/follow/c65092fa-…/mutual -> {"mutualFollowers":0,"mutualFollowing":0}
GET /api/follow/15e3d575-…/mutual -> {"mutualFollowers":1,"mutualFollowing":1}
GET /api/follow/15e3d575-…/mutual?otherUserId=c65092fa-…
-> {"mutualFollowers":1,"mutualFollowing":1}
But the client asks for an array under a mutual key:
public Task<List<FollowUser>> GetMutualAsync(string userId, …)
=> GetUserArrayAsync($"api/follow/{userId}/mutual", "mutual", ct);
…and GetUserArrayAsync is deliberately tolerant:
return json.TryGetProperty(property, out var arr) && arr.ValueKind == JsonValueKind.Array
? arr.Deserialize<List<FollowUser>>(JsonOptions) ?? new()
: new(); // <-- silently empty
So it returns an empty list, HasMutuals is false, the chips section collapses, and nothing indicates a problem. That tolerance is right for a genuinely optional array — it's exactly what hides this.
The API does not support the built feature
I checked for an alternative. The only mutual endpoint is this one, and both its parameter forms (userId alone, and userId + the spec-documented otherUserId) return the same counts object. There is no endpoint that lists mutual users, so clickable chips cannot be built as designed.
Fix
- Model the real response (
{mutualFollowers, mutualFollowing}) and change GetMutualAsync's return type — its current signature is a promise the API can't keep.
- Replace the chips with the counts, which is what's actually available.
- Record on the method that no user-list endpoint exists, so nobody reinstates the chips.
Wider point worth acting on
This is the second bug of the same shape in two days: a tolerant "absent array → empty list" read turning an API mismatch into a silently missing feature. The other was #144 (ListDataRow.ListId), which at least threw. Worth auditing the other GetUserArrayAsync call sites — followers, following, requests — against live payloads; followers and following are confirmed correct (#95), requests is unverified.
Acceptance criteria
The feature renders nothing, and fails silently
the-gaps.mdrecords "Mutual connections on a profile (People) — chips that open that user" as shipped in session 6. It has never displayed anything.Found by the contract-test suite (#126 / PR #159) and confirmed independently.
Why
GET /api/follow/{userId}/mutualreturns counts, not users:But the client asks for an array under a
mutualkey:…and
GetUserArrayAsyncis deliberately tolerant:So it returns an empty list,
HasMutualsis false, the chips section collapses, and nothing indicates a problem. That tolerance is right for a genuinely optional array — it's exactly what hides this.The API does not support the built feature
I checked for an alternative. The only mutual endpoint is this one, and both its parameter forms (
userIdalone, anduserId+ the spec-documentedotherUserId) return the same counts object. There is no endpoint that lists mutual users, so clickable chips cannot be built as designed.Fix
{mutualFollowers, mutualFollowing}) and changeGetMutualAsync's return type — its current signature is a promise the API can't keep.Wider point worth acting on
This is the second bug of the same shape in two days: a tolerant "absent array → empty list" read turning an API mismatch into a silently missing feature. The other was #144 (
ListDataRow.ListId), which at least threw. Worth auditing the otherGetUserArrayAsynccall sites —followers,following,requests— against live payloads;followersandfollowingare confirmed correct (#95),requestsis unverified.Acceptance criteria
GetMutualAsyncreturns the real shape; no caller can expect a user listGetUserArrayAsynckey (requests) checked against live data