fix: persist reported birth-time status
This commit is contained in:
@@ -313,3 +313,19 @@
|
||||
- 相关记录:BUG-008、BUG-009、BUG-016、ERR-085、ERR-091
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(生产 smoke 待当前精确 SHA 发布后补齐)
|
||||
|
||||
## BUG-018 | 首次保存未确认出生时间没有写入档案状态
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:账户出生资料保存、未确认星盘咨询、生时校正后继续原问题
|
||||
- 用户现象:已经保存“大概时间”等出生资料,但继续咨询时仍提示出生时间状态发生变化,接口返回 409。
|
||||
- 触发条件:档案没有旧的 active minute、legacy minute、candidate 或 case pointer,第一次经账户接口保存未确认出生时间声明。
|
||||
- 根因:账户写入只在清除旧候选结果时补写 `birth_time_status=reported`;干净档案和首次 upsert 被提前跳过,留下完整声明但空状态,随后被服务端星盘真值校验拒绝。
|
||||
- 修复:所有未确认声明变更都原子写入 `reported` 并清空不可沿用的应用结果;首次创建档案时也写入同一状态;确认分钟仍禁止被普通资料编辑覆盖。
|
||||
- 验证:`frontend/tests/account-api.test.ts` 覆盖空状态档案与首次档案写入;生产使用认证账户重新保存合法声明后复跑范围终态 handoff、模型咨询、计费和会话删除。
|
||||
- 防复发:出生声明与 `birth_time_status` 必须由同一次服务端写入建立,不允许依赖后续校正流程补齐状态。
|
||||
- 相关记录:BUG-009、BUG-017
|
||||
- 复发自:无
|
||||
- 修复版本:待提交
|
||||
|
||||
@@ -132,7 +132,14 @@ export async function PATCH(request: Request) {
|
||||
}
|
||||
const applicationPatch = currentProfile
|
||||
? resolveAccountBirthTimeApplicationPatch(currentProfile, payload)
|
||||
: {};
|
||||
: payload.birth_time_source
|
||||
? {
|
||||
active_birth_time: null,
|
||||
birth_time: null,
|
||||
birth_time_status: "reported" as const,
|
||||
rectification_case_id: null,
|
||||
}
|
||||
: {};
|
||||
const baseProfile = {
|
||||
id: userId,
|
||||
...(payload.name !== undefined ? { name: payload.name } : {}),
|
||||
|
||||
@@ -217,10 +217,6 @@ export function resolveAccountBirthTimeApplicationPatch(
|
||||
const confirmed = current.birth_time_status === "confirmed"
|
||||
|| (current.birth_time_status === null && isBirthClockTime(current.birth_time ?? ""));
|
||||
if (confirmed) return {};
|
||||
if (!current.active_birth_time
|
||||
&& !current.birth_time
|
||||
&& current.birth_time_status !== "candidate"
|
||||
&& !current.rectification_case_id) return {};
|
||||
return {
|
||||
active_birth_time: null,
|
||||
birth_time: null,
|
||||
|
||||
@@ -324,11 +324,24 @@ test("ordinary declaration edits clear stale candidate application but never ove
|
||||
birth_time_status: "reported",
|
||||
rectification_case_id: null,
|
||||
});
|
||||
assert.deepEqual(resolveAccountBirthTimeApplicationPatch({
|
||||
...candidate,
|
||||
active_birth_time: null,
|
||||
birth_time: null,
|
||||
birth_time_status: null,
|
||||
rectification_case_id: null,
|
||||
}, edited), {
|
||||
active_birth_time: null,
|
||||
birth_time: null,
|
||||
birth_time_status: "reported",
|
||||
rectification_case_id: null,
|
||||
});
|
||||
});
|
||||
|
||||
test("account PATCH uses the shared validator and never writes client birth_time over account truth", () => {
|
||||
assert.match(source, /accountProfilePatchSchema\.safeParse/);
|
||||
assert.match(source, /resolveAccountBirthTimeApplicationPatch/);
|
||||
assert.match(source, /payload\.birth_time_source[\s\S]*birth_time_status: "reported"/);
|
||||
assert.doesNotMatch(source, /birth_time:\s*nullableString\(payload\.birth_time\)/);
|
||||
assert.match(source, /invalidatesUnconfirmedApplication/);
|
||||
assert.match(patchSource, /"birth_time_status"/);
|
||||
|
||||
Reference in New Issue
Block a user