0005 — Network orchestration protocols (A–K)
Status: Accepted Date: 2026-05 Deciders: TwoMore mobile team
Context
After Phase 5 of the network audit, an Explore-agent trace of the live scorecard revealed ~120 parallel HTTP requests firing for a 40-match session: 40 × useMatchScoreCall per-item hooks inside LiveMatchRow, cross-session realtime noise triggering broad invalidation, and refetchQueries({ type: 'active' }) on every app-foreground resumption refetching all active queries regardless of freshness. The same fan-out pattern existed in SessionCard (~150 requests per 50-session feed) and ChallengeCard.
Without a shared vocabulary, each feature team invented its own approach: some used per-item hooks inside list-rendered children, others used broad invalidation, others used refetchQueries when invalidateQueries would suffice. The patterns weren't wrong in isolation; they compounded in production.
A secondary failure class emerged from the foreground UX layer: screens revealed their sections piecewise (each section's query resolved independently and painted as it finished), even when the underlying network shape was already good. Protocol G/H/I/J address the perception layer, not the network layer — the distinction matters because the two classes of bug require different fixes.
Options considered
Option A: Ad-hoc per-feature fix
Fix the 40× fan-out on the scorecard, the 150× fan-out on the session feed, and the foreground-resumption refetch individually, without establishing shared vocabulary.
- Pros: fastest per-fix
- Cons: the patterns recur in every new feature; each new engineer (human or agent) who builds a list-rendered component with async data will repeat the same fan-out mistake; no mechanical way to catch regressions; fixes drift
- Effort: ~1 day per bug as found
- Reversibility: high
Option B: Adopt TanStack Query best-practices documentation only
Document the "bulk hook + prop-drill" pattern in CLAUDE.md and trust contributors to follow it.
- Pros: low overhead; matches how most teams operate
- Cons: agentic contributors follow mechanical boundaries reliably but drift through documented conventions; the agentic-project-foundation research (ADR 0001) established this empirically — documentation without enforcement decays
- Effort: 0 (documentation is already partially in CLAUDE.md)
- Reversibility: high
Option C: Codify protocols A–K in CLAUDE.md with reusable primitives and mechanical enforcement
Define six network protocols (A–F) and five UX protocols (G–K) as named, composable rules. Build shared primitives that encode each protocol (safeMap for Protocol K, useScreenReady for Protocol G, prefetchXxx helpers for Protocol H). Add ESLint rules where the pattern is mechanically detectable.
- Pros: protocols compose; a new feature inherits all of them by using the primitives; new engineers (human or agent) have a shared vocabulary for diagnosing performance issues; regressions are mechanically caught where possible
- Cons: more primitives to learn; adds files to
presentation/hooks/andpresentation/cache/; some protocols (A, B, C) require per-feature bulk hooks that are non-trivial to scaffold automatically - Effort: ~2 weeks to define + retrofit existing features
- Reversibility: medium — the protocol definitions are non-destructive; removing them would just revert to Option A/B
Decision
Option C — codify protocols A–K with shared primitives.
Primary reason: the fan-out patterns recur deterministically whenever a list-rendered component gets async data. Without a named protocol and shared primitive, every new feature repeats the mistake. The protocols pay for themselves after the first prevented regression.
Dissenting consideration: eleven protocols is a lot to learn. Mitigated by: the protocols are layered — A (bulk hook), B (prop-or-fetch), and K (mapper resilience) cover 90% of incidents; G/H address the UX perception layer orthogonally; C/D/E/F are refinements that apply to specific patterns. A new engineer doesn't need to memorise all eleven; they apply when the relevant primitive (safeMap, useScreenReady, prefetchXxx) is touched.
Consequences
Positive
- A 40-match live scorecard costs 1 HTTP request instead of ~40 (Protocol A + B applied in Phase 5c)
- A 50-session home feed costs 3 HTTP requests instead of ~150 (Protocol A + B applied in Phase 5b)
safeMap(rows, mapper, context)inbase.adapter.ts(Protocol K) prevents a single Zod schema failure from crashing an entire query — the originating production crash ("undefined is not a function" fromeloTierSchema.parse('platinum')) is the canonical example- Foreground app-resumption uses
invalidateQueriesnotrefetchQueries(Protocol D), so queries withinstaleTimeare not refetched on every foreground event - The network protocols (A–F) and UX protocols (G–K) are explicitly separated — diagnosing whether a latency issue is a fetch-shape problem or a perception problem is now a defined question with a defined answer
Negative
- Bulk hooks add 2-4 files per new list-rendered entity (port method + adapter + presentation hook + cache key)
- Protocol B (prop-or-fetch) requires every
*Card/*Row/*Itemcomponent to expose optional props, which adds prop surface area even when the standalone use case doesn't need it - Protocol K's
safeMapsilently drops broken rows — a mapper bug that affects every row in a list will appear as an empty list, not an error state, making it harder to detect in testing
Neutral
- The separation of network protocols from UX protocols (Protocol I) establishes a diagnostic framework: "is this a fetch issue or a perception issue?" — answers determine which protocol to apply without trial-and-error
Implementation notes
safeMaphelper (Protocol K):packages/app/src/adapters/supabase/base.adapter.tsuseScreenReadyhook (Protocol G):packages/app/src/presentation/hooks/use-screen-ready.ts- Prefetch helpers (Protocol H):
packages/app/src/presentation/cache/prefetch.ts - Protocols defined in: CLAUDE.md — "Network protocols" and "Foreground UX protocols" sections
- Bulk hook examples:
useSessionsRsvps,useMySessionPayments,useSessionMatchScoreCalls,useClubsByIds
References
- networking-and-caching.md
- CLAUDE.md — Network protocols A–F; Foreground UX protocols G–K
- AGENTS.md — DATA-9 (realtime precision), DATA-10 (freshness contract)
- rebuild-log.md — Phase 5 series (2026-05-14) for the empirical request-count reduction data