fix(account): a new birth declaration drops a confirmed minute too (M2, BUG-264 product revision)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c61095b1eb
commit
5e97db4077
@@ -269,6 +269,12 @@ export type AccountBirthTimeApplicationPatch = Readonly<{
|
||||
active_birth_time?: string | null;
|
||||
birth_time_status?: "accepted" | "reported";
|
||||
rectification_case_id?: null;
|
||||
/** Only when a confirmed or legacy minute is dropped: the legacy column the chart falls back to. */
|
||||
birth_time?: null;
|
||||
/** Only when a confirmed adoption is dropped; `guard_adopted_birth_date` clears them too. */
|
||||
active_birth_date?: null;
|
||||
active_birth_timezone_offset?: null;
|
||||
active_birth_provenance?: null;
|
||||
}>;
|
||||
|
||||
function normalizeApplicableBirthClock(value: string | null | undefined): string | null {
|
||||
@@ -299,6 +305,29 @@ function resolveExactFamilyBirthTime(
|
||||
return normalizeApplicableBirthClock(reportedTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stored and submitted declarations differ only in shape: Postgres returns a
|
||||
* `time` as `HH:MM:SS`, the form sends `HH:MM`; numbers may arrive as strings;
|
||||
* an empty string and null both mean "not given". The profile form resubmits
|
||||
* every birth field on each save, so a raw `!==` would read a name-only save
|
||||
* as a new declaration and drop a confirmed minute.
|
||||
*/
|
||||
function sameDeclarationValue(submitted: unknown, stored: unknown): boolean {
|
||||
const empty = (value: unknown) => value === null || value === undefined || value === "";
|
||||
if (empty(submitted) || empty(stored)) return empty(submitted) && empty(stored);
|
||||
if (typeof submitted === "string" && typeof stored === "string") {
|
||||
const clock = /^(\d{2}:\d{2})(?::00(?:\.0+)?)?$/;
|
||||
const a = clock.exec(submitted);
|
||||
const b = clock.exec(stored);
|
||||
if (a && b) return a[1] === b[1];
|
||||
return submitted === stored;
|
||||
}
|
||||
const a = Number(submitted);
|
||||
const b = Number(stored);
|
||||
if (Number.isFinite(a) && Number.isFinite(b)) return a === b;
|
||||
return submitted === stored;
|
||||
}
|
||||
|
||||
export function resolveAccountBirthTimeApplicationPatch(
|
||||
current: AccountBirthTimeState | null,
|
||||
patch: AccountProfilePatch,
|
||||
@@ -315,11 +344,28 @@ export function resolveAccountBirthTimeApplicationPatch(
|
||||
const confirmed = current.birth_time_status === "confirmed"
|
||||
|| (current.birth_time_status === null
|
||||
&& normalizeApplicableBirthClock(current.birth_time) !== null);
|
||||
if (confirmed) return {};
|
||||
|
||||
const declarationChanged = declarationFields.some((field) => (
|
||||
patch[field] !== undefined && patch[field] !== current[field]
|
||||
patch[field] !== undefined && !sameDeclarationValue(patch[field], current[field])
|
||||
));
|
||||
// Product 2026-09-29 (TASK-mobile-chart-and-confirmed-edit M2, revising
|
||||
// BUG-264): a confirmed or adopted minute survives every edit except a new
|
||||
// declaration. Once the user changes the birth date, time or place, the chart
|
||||
// follows the new declaration exactly as an unconfirmed one would, and the
|
||||
// old minute is dropped everywhere the chart could still read it.
|
||||
if (confirmed) {
|
||||
if (!declarationChanged) return {};
|
||||
return {
|
||||
...(exactFamilyBirthTime
|
||||
? { active_birth_time: exactFamilyBirthTime, birth_time_status: "accepted" as const }
|
||||
: { active_birth_time: null, birth_time_status: "reported" as const }),
|
||||
rectification_case_id: null,
|
||||
...(current.birth_time != null ? { birth_time: null } : {}),
|
||||
...(current.active_birth_date != null || current.active_birth_timezone_offset != null
|
||||
? { active_birth_date: null, active_birth_timezone_offset: null, active_birth_provenance: null }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
const repairsMissingStatus = current.birth_time_status === null
|
||||
&& current.active_birth_time === null
|
||||
&& current.birth_time === null
|
||||
|
||||
Reference in New Issue
Block a user