fix: keep western labels near their planets and chats on the current person
Independent Staging Quality Gate / validate (push) Failing after 6m46s
Independent Staging Quality Gate / publish (push) Skipped

Cap planet captions at 30 degrees with a third ring, fall back only within the current person's sessions, and load self when the people catalog fails.
This commit is contained in:
jesse-ux
2026-09-25 23:02:17 +08:00
parent b8712dad50
commit d08ffdc0a6
28 changed files with 538 additions and 545 deletions
@@ -7,8 +7,9 @@ import type { ChatProfileCatalogStatus } from "@/lib/chat-profile-picker-model";
/**
* Load state for the ordinary-chat person list.
* The page effect still owns the chart-library fetch; this hook only records
* whether that read is in flight, ready, or failed. A failure stays failed
* until an explicit retry, so a self-only fallback cannot look like deletion.
* whether that read is in flight, ready, failed, or degraded. A people-API
* outage is degraded: only the signed-in person is listed, with an explicit
* sentence, so it does not look like everyone else was deleted.
*/
export function useChatProfileCatalog(accountId: string | undefined) {
const accountRef = useRef(accountId);
@@ -32,10 +33,15 @@ export function useChatProfileCatalog(accountId: string | undefined) {
setStatus("failed");
}, []);
const markDegraded = useCallback((forAccountId: string) => {
if (accountRef.current !== forAccountId) return;
setStatus("degraded");
}, []);
const beginReload = useCallback(() => {
if (!accountRef.current) return;
setStatus("loading");
}, []);
return { status, markReady, markFailed, beginReload };
return { status, markReady, markFailed, markDegraded, beginReload };
}
+3 -1
View File
@@ -60,6 +60,8 @@ import {
payloadMessage,
waitForUndoWindow,
} from "@/lib/home-cloud-sync";
import { sessionMatchesSubject } from "@/lib/chat-profile-picker-model";
import { readCurrentSubjectId } from "@/lib/current-subject";
import { completedOnboardingTranscript, isProfileComplete, selectedBirthPlace } from "@/lib/home-profile";
import { pendingConsultationStorageKey, timestamp } from "@/lib/home-types";
import {
@@ -620,7 +622,7 @@ export function useConsultationRun(params: ConsultationRunParams) {
} catch (caught) {
const remaining = sessions.filter((session) => session.id !== currentSession.id);
setSessions(remaining);
const fallbackId = fallbackSessionId(remaining);
const fallbackId = fallbackSessionId(remaining.filter((session) => sessionMatchesSubject(session, readCurrentSubjectId())));
setActiveSessionId(fallbackId);
setRequestError({
sessionId: fallbackId,
+15 -5
View File
@@ -157,7 +157,10 @@ export function useSessionManagement(params: SessionManagementParams) {
void fetchSessions(undefined, { subject }).then((page) => {
if (cancelled || generation !== requestGeneration || subject !== readCurrentSubjectId()) return;
const incoming = readSessions(page.sessions, modelCatalog).sessions;
setSessions((current) => mergeSubjectSessionRows(current, incoming));
setSessions((current) => mergeSubjectSessionRows(current, incoming, {
subjectId: subject,
complete: page.nextCursor == null,
}));
setSessionsCursor(page.nextCursor);
}).catch(() => undefined);
};
@@ -389,10 +392,17 @@ export function useSessionManagement(params: SessionManagementParams) {
}
function activateFallbackSession(candidates: ChatSession[]) {
const fallbackId = fallbackSessionId(candidates);
const scoped = candidates.filter((session) => sessionMatchesSubject(session, readCurrentSubjectId()));
const fallbackId = fallbackSessionId(scoped);
if (!fallbackId) {
setActiveSessionId("");
if (!uiPreview.current) writeSessionUrl(null, "replace");
void startNewChat().then((created) => {
if (created) {
if (!uiPreview.current) writeSessionUrl(created.id, "replace");
return;
}
setActiveSessionId("");
if (!uiPreview.current) writeSessionUrl(null, "replace");
});
return;
}
const fallback = candidates.find((session) => session.id === fallbackId);
@@ -431,7 +441,7 @@ export function useSessionManagement(params: SessionManagementParams) {
if (uiPreview.current) return;
const listed = sessionsRef.current;
const query = parseSessionUrlQuery(search);
const fallbackId = fallbackSessionId(listed);
const fallbackId = fallbackSessionId(listed.filter((session) => sessionMatchesSubject(session, readCurrentSubjectId())));
const requestedId = query.sessionId;
if (query.present && !requestedId) {
writeSessionUrl(null, "replace");