Fix #150: silent auxiliary fetches + key source #151

Merged
crueber merged 1 commit from fix/issue-150 into main 2026-09-05 19:06:14 +00:00
Owner

Fixes #150 — owners page spammed SOCIAL:<UPPERCASE-REPO> not found toasts.

ROOT CAUSE (two halves, both verified live against a stack carrying the exact rows):

  1. Ghost rows are real backend state, not phantom keys. A fork writes repos/<o>/<r>/fork.json BEFORE the child manifest exists (internal/pulls/merge.go runFork; manifest share is delegated/pending). The owners listing (repoRegistry.Repos in cmd/walhub/serve.go) lists by prefix, so the child (o/r-fork, e2e/demo2-fork) appears as a row — while every manifest-gated read 404s (social Counts via repoAlive, commits, summary). Verified: GET /api/v1/owners/o/repos → [r, r-fork] but GET /o/r-fork/api/social → 404 not found: repo o/r-fork not found.
  2. There is NO uppercase-key source — the uppercase is pure CSS. The tray chip renders the useData key verbatim inside .chip, and .chip carries Tailwind uppercase (web/src/ui.css), so key social:o/r-fork DISPLAYS as SOCIAL:O/R-FORK (verified: tray innerText uppercases a lowercase key). The key shares full() with the request URL and the backend 404 echoes the URL parts verbatim, so the fetch was always correctly-cased lowercase; no wrong-cased fetch exists to eliminate.

FIX (frontend-only, amends the #137/#142 tray-on-error contract): 404 on an auxiliary per-row fetch is missing DATA, not a failure. New shared tolerateMissing(promise, missing) helper in web/src/lib/data.js (404 → missing value, everything else rethrows into the unchanged tray path). <StarCount> resolves 404 → null and hides the count (placeholder only while loading); <ActivityStamp> keeps its {commits: []} mapping through the same helper. Audit: <RepoRow>s two probes are the only per-row fetches on / and /:owner. No backend/SDK/styling change; no new deps.

PROOF: pre-fix drive of / shows the 2 reported toasts; post-fix scratch stack seeded with the exact fork-leftover state (healthy o/r + ghost o/r-fork + e2e/demo2-fork) shows 0 toasts in dark AND light, ghost rows render hidden-count + no-commits-yet, healthy row renders count + stamp, zero JS exceptions.

TESTS: node --test web/test/unit/*.test.js → 322 pass (new tolerate-missing.test.js: 404→missing incl. the real start() path with empty tray; 401/403/500/network passthrough; resolved passthrough). Doc decision appended to `docs/go/12_web_ui.md$.

Fixes #150 — owners page spammed `SOCIAL:<UPPERCASE-REPO> not found` toasts. ROOT CAUSE (two halves, both verified live against a stack carrying the exact rows): 1. Ghost rows are real backend state, not phantom keys. A fork writes `repos/<o>/<r>/fork.json` BEFORE the child manifest exists (`internal/pulls/merge.go runFork`; manifest share is delegated/pending). The owners listing (`repoRegistry.Repos` in `cmd/walhub/serve.go`) lists by prefix, so the child (`o/r-fork`, `e2e/demo2-fork`) appears as a row — while every manifest-gated read 404s (social `Counts` via `repoAlive`, commits, summary). Verified: `GET /api/v1/owners/o/repos → [r, r-fork]` but `GET /o/r-fork/api/social → 404 not found: repo o/r-fork not found`. 2. There is NO uppercase-key source — the uppercase is pure CSS. The tray chip renders the `useData` key verbatim inside `.chip`, and `.chip` carries Tailwind `uppercase` (`web/src/ui.css`), so key `social:o/r-fork` DISPLAYS as `SOCIAL:O/R-FORK` (verified: tray innerText uppercases a lowercase key). The key shares `full()` with the request URL and the backend 404 echoes the URL parts verbatim, so the fetch was always correctly-cased lowercase; no wrong-cased fetch exists to eliminate. FIX (frontend-only, amends the #137/#142 tray-on-error contract): 404 on an auxiliary per-row fetch is missing DATA, not a failure. New shared `tolerateMissing(promise, missing)` helper in `web/src/lib/data.js` (404 → missing value, everything else rethrows into the unchanged tray path). `<StarCount>` resolves 404 → null and hides the count (placeholder only while loading); `<ActivityStamp>` keeps its `{commits: []}` mapping through the same helper. Audit: `<RepoRow>`s two probes are the only per-row fetches on `/` and `/:owner`. No backend/SDK/styling change; no new deps. PROOF: pre-fix drive of / shows the 2 reported toasts; post-fix scratch stack seeded with the exact fork-leftover state (healthy `o/r` + ghost `o/r-fork` + `e2e/demo2-fork`) shows 0 toasts in dark AND light, ghost rows render hidden-count + no-commits-yet, healthy row renders count + stamp, zero JS exceptions. TESTS: `node --test web/test/unit/*.test.js` → 322 pass (new `tolerate-missing.test.js`: 404→missing incl. the real start() path with empty tray; 401/403/500/network passthrough; resolved passthrough). Doc decision appended to `docs/go/12_web_ui.md$.
Owners page spammed social:{o}/{r} toasts for listed repos whose
manifest-gated reads 404 (fork-provisioned prefixes without a child
manifest). StarCount now resolves 404 to hidden via the shared
tolerateMissing helper; ActivityStamp uses the same helper. Appends the
FIXED decision incl. the uppercase-key root cause (CSS .chip uppercase,
no wrong-cased fetch exists).
Sign in to join this conversation.
No description provided.