diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4232a22e..3ed3fff6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# 印度占星 Skill 更新日志
+## 2026-09-07 — 出生时间有多确定只问一次,校正按你选的范围去比
+
+填报出生资料时问一次「你对这个时间有多确定」:有医院记录、家人记得大概时间(差不多准 / 前后半小时 / 一小时 / 两小时),或只知道时段、完全不清楚。校正直接读档案里的范围,不再追问。家人说前后一小时,顶部就是两小时;前后两小时或傍晚这种超过两小时的范围,先切成三段再比。按你说的经历对不上、时间又贴着窗口边上时,会出一张卡问要不要放宽,放宽后设置页的范围跟着变。日级经历会补问一句日子是查过记录还是凭记忆。文案不用「偏移 / 误差 / 置信度 / 概率」。Skill 版本仍是 10.0.14。
+
## 2026-09-07 — 答完题后的范围跟顶部一致,不清楚出生时间时不再偏爱下午
生时校正点完选择题后,旁白里的范围跟输入框上方那一行走,不会再把开工搜索窗口说成「范围没变」。完全不清楚出生时间时,清晨、上午、下午、傍晚、夜里五段按段内平均分来比,不会因为下午更长就先天占优。Skill 版本仍是 10.0.14。
diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md
index 0c179bc3..74898ae2 100644
--- a/docs/BUG_HISTORY.md
+++ b/docs/BUG_HISTORY.md
@@ -8838,6 +8838,54 @@
- 复发自:unknown-time `block_scan`(`814c924e`)按时段长度偏置
- 修复版本:`517df002`
+## BUG-571 | 档案里声明的不确定度被忽略,有钟点一律 ±15
+
+- 状态:resolved
+- 首次发现:2026-09-07
+- 最近更新:2026-09-07
+- 影响面:`frontend/src/lib/birth-time-intake-model.ts`、`birth-time-intake.tsx`、`account-profile-patch.ts`、`case-service.ts::deriveRectificationOpenPlan`
+- 用户现象:家人记得大概时间时,intake 选不到前后半小时 / 一小时 / 两小时;校正开工窗口仍是填报钟点 ±15,档案里的 `uncertainty_before/after` 不参与搜索。
+- 触发条件:资料有填报钟点;来源本应是 `approximate` 或医院记录。
+- 根因:intake 单选只露出 `family_exact` / `period_only`(含 unknown)。开 Case 用固定 `FRESH_CASE_SEARCH_RADIUS_MINUTES = 15`,注释写明那是引擎边界、不是用户声明。
+- 修复:intake 改三档——医院记录(固定 ±2 无感检查)、家人大概时间(±15/30/60/120)、时段或完全不知道。`family_exact` 从新选项移除,读档映射成「差不多准」。有钟点时:`hospital_record` / `family_exact` → ±15;`approximate` → ±max(15, 声明值),上限 120,前后独立。窗口 exclusive span >120 先进 `block_scan`(BUG-573)。
+- 验证:`birth-time-intake.test.ts` 三档与 120 校验;`account-api.test.ts` 120 合法、90 非法;`rectification-v9-case-service.test.ts` 既有三处 `family_exact` 04:45–05:15 保留,新增 approximate ±60 → 04:00–06:00、±120 → 03:00–07:00。
+- 防复发:有钟点开 Case 不得再写死 ±15;`approximate` 校验集合必须与 intake 按钮同为 {15,30,60,120}。
+- 相关记录:BUG-572、BUG-573
+- 复发自:无
+- 修复版本:待合入 `origin/staging`(`codex/rectification-declared-uncertainty-20260907`)
+
+## BUG-572 | 事件吻合率低且贴窗口边缘时不提议放宽搜索窗
+
+- 状态:resolved
+- 首次发现:2026-09-07
+- 最近更新:2026-09-07
+- 影响面:`decision-from-dossier.ts`、`window-widen.ts`、`method-followup.ts`、`widen_agentic_rectification_case_window`、`set_agentic_rectification_widen_declined`
+- 用户现象:经历已经明显对不上家人记的时间,校正仍只在原来的 ±15/±30 里出区分卡,没有一键放宽。
+- 触发条件:训练门已开、`event_fit_rate.band=low` 且 `total≥3`、代表分钟距窗口边缘 ≤3 分钟、`stage=minute`、未采用、有填报钟点、当前证据指纹未拒过、当前半径 <120。
+- 根因:`event_fit_rate` 只进采用后八法报告。分钟阶段没有改 `candidate_range` 的 RPC;唯一改窗 RPC 要求 `stage=block_scan`。
+- 修复:服务端四选卡 `choice_kind: widen_window`(不进 Python 探针契约),排在区分卡之前。A/B 扩大窗口(必须包含旧窗、inclusive 宽 ≤241)、重算,并把档案写成 `approximate` + 新半径;`hospital_record` 只改窗口不改档案来源。C/D 记 `widen_declined_at_fingerprint`。档位 15→±30/±60,30→±60/±120,60→±120 / 「先补一件带月份的经历再说」。D 文案「说不好 / 先这样」(`clippedCopy` 最短 4 字)。不动采用/确认门、`MIN_SEPARATION_LEAD`、分钟级 `_relative_support`、`adopted_credible_range`。
+- 验证:`rectification-window-widen-20260907.test.ts` 六条;迁移合同锁 widen RPC 与不得改 `adopted_credible_range`。Docker `test:db` 在 `database-rectification-block-scan.test.ts` 加 widen 扩大/缩小与权限。
+- 防复发:放宽卡必须服务端生成;不得让模型问「偏移 / 误差」;widen RPC 只许扩大且包含旧窗。
+- 相关记录:BUG-571、BUG-573
+- 复发自:无
+- 修复版本:待合入 `origin/staging`(`codex/rectification-declared-uncertainty-20260907`)
+
+## BUG-573 | 选定时段或 ±120 窗口后直接进 4~6 小时分钟网格
+
+- 状态:resolved
+- 首次发现:2026-09-07
+- 最近更新:2026-09-07
+- 影响面:`scripts/rectification/api_service.py::block_scan`、`contracts.py` 可选 `blocks`、`advance_agentic_rectification_case_from_block_scan`、`search-window.ts`、`block-scan.ts`
+- 用户现象:只知道傍晚或家人说前后两小时时,选定后马上在 4~6 小时上按分钟比,网格过密、题也问不清。
+- 触发条件:exclusive span >120(例如 18:00–22:59、03:00–07:00、下午 12:00–17:59)。
+- 根因:`block_scan` 只服务全日五时段;`advance_*` 要求原窗 00:00–23:59,选定后一律 `stage=minute`。`set_stage` 也曾要求全日窗。
+- 修复:请求可带 1~5 段 `blocks`(须落在窗口内、除共享端点外不重叠)。无 `blocks` 时仍用五声明时段;全日默认步长 10。子窗三等分、无共享分钟;步长 >360→10、>180→5、其余 2。`advance_*` 改为新窗须为当前窗子区间;span>120 且 rounds<3 仍 `block_scan`,否则 `minute`。每 Case 最多 3 张子段卡,超过旁白「时段分不开,直接按分钟比」。unknown 仍先五时段,赢段再切三段。全零相对支持按 100/n 均分(三段 33.3/33.3/33.4),不再写死五段各 20。不改分钟级 `_relative_support`。
+- 验证:`test_rectification_v5_services.py` 自定义三段和为 100、等分 33.3/33.3/33.4、越界/重叠报错;`rectification-block-scan-20260906.test.ts` ±120 开 Case 为 block_scan、傍晚三子段、选下午后仍 block_scan;Docker 上午 08:00–11:59 选定后仍 block_scan,08:00–09:00 进 minute。
+- 防复发:exclusive span >120 不得直接 `stage=minute`。`block_scan` 全零均分必须按段数,不得写死 20%。
+- 相关记录:BUG-570、BUG-571
+- 复发自:unknown-time 选段后一律进分钟(`814c924e`)
+- 修复版本:待合入 `origin/staging`(`codex/rectification-declared-uncertainty-20260907`)
+
## BUG-574 | 报告列表 JSON 路径 select 在 staging PostgREST 上 500
- 状态:resolved
diff --git a/docs/tasks/PROGRESS-rectification-declared-uncertainty-20260907.md b/docs/tasks/PROGRESS-rectification-declared-uncertainty-20260907.md
new file mode 100644
index 00000000..5f9c3458
--- /dev/null
+++ b/docs/tasks/PROGRESS-rectification-declared-uncertainty-20260907.md
@@ -0,0 +1,56 @@
+# PROGRESS · 出生时间「有多确定」只问一次(2026-09-07)
+
+工作树:`.worktrees/rectification-declared-uncertainty-20260907`
+分支:`codex/rectification-declared-uncertainty-20260907`(跟踪 `origin/staging`)
+基线:任务书落地 commit `ad9283d1`(含 BUG-565~570);合入前 rebase 到当时 `origin/staging`(含 BUG-574 `b2a8d3a0`)。
+
+未改 `SKILL.md`(仍 10.0.14)、未改采用门 / 确认门 / `MIN_SEPARATION_LEAD` / 分钟级 `_relative_support`、未改 `page.tsx`、未改 `jyotish_api_server.py`、未改 `contracts/probe-question-v1.json`。迁移文件为 `20260907020000_rectification_declared_uncertainty.sql`(`20260907010000` 已被 `personal_report_card_summary` 占用)。
+
+本单状态:**待验收**。BUG-571 / 572 / 573 已实现。
+
+| 任务 | 状态 | BUG |
+| --- | --- | --- |
+| D1 intake 三档 + ±120 | 完成 | — |
+| D2 校正窗口读档案 | 完成 | BUG-571 |
+| D5 子段扫描 | 完成 | BUG-573 |
+| D3 放宽窗口一键卡 | 完成 | BUG-572 |
+| D6 日级可靠度 + 手测脚本 | 完成 | — |
+| D4 记录 | 完成 | 本文件 / BUG_HISTORY / CHANGELOG / DESIGN / VOICE / testing |
+
+## 实现要点
+
+- 窗口阶段看 **exclusive span**(04:00–06:00 = 120 → minute;03:00–07:00 = 240 → block_scan)。放宽上限看 **inclusive width ≤ 241**。
+- 子段是当前窗三等分、无共享分钟。unknown 仍先扫五个声明时段(步长 10),赢段再切三段。
+- 放宽卡优先级高于区分卡。`hospital_record` 答 A 只改窗口。
+- 日级可靠度只在**本回合刚写入**的 day 事件上问(`source_turn_id === askedTurnId`),不拦采用门、不改历史账本上的旧日事件采集顺序。
+
+### 书面偏差
+
+| 项 | 任务书 | 实际 | 原因 |
+| --- | --- | --- | --- |
+| D6 写回 | 「用现有证据修订链,不新造 RPC」 | 薄 RPC `set_agentic_rectification_evidence_date_reliability`(原地 high/medium) | revise/supersede 会新开证据行、改指纹,误伤训练门 |
+| 放宽 D 文案 | 「说不好」 | 「说不好 / 先这样」 | `clippedCopy` 最短 4 字 |
+| `block_scan` 全零均分 | 五段各 20% | 100/n(三段 33.3/33.3/33.4) | 自定义 blocks 时写死 20 只给到 60 |
+| 迁移时间戳 | `20260907010000_...` | `20260907020000_...` | staging 已占用 `20260907010000_personal_report_card_summary.sql` |
+
+### 既有断言改动
+
+| 文件 | 原值 | 新值 | 原因 |
+| --- | --- | --- | --- |
+| `rectification-v9-case-service` 04:45–05:15 | 有钟点一律 | 仅 `family_exact` / 医院记录;approximate 另写 | BUG-571 |
+| `database-rectification-block-scan` 08:00–11:59 | 选定后 `minute` | 选定后仍 `block_scan` | span 239>120 |
+| `rectification-block-scan` 选下午 | 进分钟 | 仍 `block_scan` | 12:00–17:59 span 359 |
+| `birth-time-intake` `/前后两小时/` | 扫组件源码 | 扫 `approximateUncertaintyOptions` | 文案在 model |
+
+## 测试
+
+| 命令 | 结果 |
+| --- | --- |
+| 非 DB `rectification-*` + `consultation-*` + `report-*` + `personal-report-*` + `birth-time-*` + `account-api` + `agent-voice-copy-contract` | **1913 pass / 0 fail**(≥ 1521) |
+| `.venv/bin/python -m pytest tests/test_rectification_v5_services.py -k 'not seven_events'` | **33 pass / 0 fail**(含自定义三段 100 与 33.3/33.3/33.4) |
+| `test_block_scan_seven_events_finishes_within_fifteen_seconds` | 本机连跑偶发超 15s,与 BUG-570 同一 P2,未改断言 |
+| `npx tsc --noEmit` | 0 错 |
+| `./node_modules/.bin/eslint --quiet src tests` | 0 error |
+| `frontend npm run test:db` | **37 pass / 0 fail**(547.7s;含 `database-rectification-block-scan`:08:00–11:59 选定后仍 `block_scan`,08:00–09:00 进 `minute`,widen 扩大成功 / 缩小失败 / service_role-only) |
+
+排除 `*-database.test.ts` 于非 DB 套件。ERR-011:Python 用 `.venv/bin/python -m pytest`。未改 `page.tsx`。未改分钟级 `_relative_support`。无 Docker 缺口,未写 `BLOCKED.md`。
diff --git a/docs/tasks/README.md b/docs/tasks/README.md
index 65602b53..f13d9666 100644
--- a/docs/tasks/README.md
+++ b/docs/tasks/README.md
@@ -67,7 +67,7 @@
| `TASK-rectification-range-reading-20260906.md` | `PROGRESS-rectification-range-reading-20260906.md` | 可信区间成为一等公民:采用时落库 `adopted_credible_range`,报告 `read_report_candidate_range` 与聊天 `verified_chart(accepted)` 都改读它并接同一份 `birth_time_sensitivity`(现在报告读的是开工窗口,BUG-568);引擎 >15 分钟只取 3 样本改为 ≤31 逐分钟;采用旁白加「稳定 / 随分钟变」两句;`declared_birth_window` 复用 | 已验收通过(test:db 37/0 为执行方数字,本机无 Docker) | `814c924e`(BUG-568);两条迁移待应用 |
| `TASK-rectification-unknown-time-20260906.md` | `PROGRESS-rectification-unknown-time-20260906.md` | 完全不知道出生时间的两段式路线:`stage=block_scan` 以 10 分钟步长扫 24 小时只做事件计分、出五时段四选卡(不写账本不采用),选定后进现有分钟流程;引擎加 `minute_step`;开场读 `birth_time_clue`;删 intake 劝退文案 | 已验收(带修复单:时段支持度按段长偏置,下午段先天 25%,P1) | `814c924e`;修复单 `TASK-rectification-capability-fix-20260907.md`(BUG-570) |
| `TASK-rectification-capability-fix-20260907.md` | `PROGRESS-rectification-capability-fix-20260907.md` | 能力补齐修复单:答后旁白把 `range_start/range_end`(搜索窗口)当范围比较,每题都说「范围没变」;`block_scan` 五段支持度按段内原始分求和,长时段先天占优(24/24/36/30/30 个候选);`TRACK_LABEL` 音译与产品 Vimshottari/Narayana 口径不一;BLK-001 写到 `docs/BLOCKED.md` 应回根目录 | 已验收通过(P2:block_scan 15 s 壁钟断言在门禁里可能间歇红) | `517df002`(BUG-569~570);staging 未部署,需先 Migrate Staging Database |
-| `TASK-rectification-declared-uncertainty-20260907.md` | `PROGRESS-rectification-declared-uncertainty-20260907.md` | 出生时间「有多确定」只在 intake 问一次:三档(医院记录 / 家人大概 ±15·30·60·120 / 时段或未知),校正窗口读档案(现在有钟点一律 ±15,声明值被忽略,BUG-571);吻合率 <60% 且代表分钟贴窗口边缘时出服务端一键放宽卡,放宽后重算并写回档案(BUG-572);窗口 >120 分钟先切三子段迭代到 ≤120 再进分钟(BUG-573);日级事件问一次可靠度;四个脚本化手测场景进 docs/testing | 待领取 | `codex/rectification-declared-uncertainty-20260907` |
+| `TASK-rectification-declared-uncertainty-20260907.md` | `PROGRESS-rectification-declared-uncertainty-20260907.md` | 出生时间「有多确定」只在 intake 问一次:三档(医院记录 / 家人大概 ±15·30·60·120 / 时段或未知),校正窗口读档案(现在有钟点一律 ±15,声明值被忽略,BUG-571);吻合率 <60% 且代表分钟贴窗口边缘时出服务端一键放宽卡,放宽后重算并写回档案(BUG-572);窗口 >120 分钟先切三子段迭代到 ≤120 再进分钟(BUG-573);日级事件问一次可靠度;四个脚本化手测场景进 docs/testing | 待验收 | `codex/rectification-declared-uncertainty-20260907` |
| `TASK-api-not-configured-mislabel-20260904.md` | `PROGRESS-api-not-configured-mislabel-20260904.md` | 16 处路由把数据库瞬断(部署切换窗口)兜底翻译成 503「服务尚未配置」;改为仅配置错误用该文案,其余 `service_unavailable`,收敛为共享 helper | 已验收 | `5483649b`(BUG-542);2 条子进程测试留 CI Node 22 复核 |
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505~509) |
diff --git a/docs/testing/rectification-declared-uncertainty-20260907.md b/docs/testing/rectification-declared-uncertainty-20260907.md
new file mode 100644
index 00000000..1999425a
--- /dev/null
+++ b/docs/testing/rectification-declared-uncertainty-20260907.md
@@ -0,0 +1,37 @@
+# Staging 人肉复核 · 出生时间有多确定只问一次(2026-09-07)
+
+给产品负责人。不要把真实案例里的年份、事件或候选分钟写进任何记录。
+
+对应 `TASK-rectification-declared-uncertainty-20260907.md` / BUG-571~573。测之前先做第 0 条。四个虚构脚本见 `rectification-scenarios-20260907.md`。
+
+## 0. 确认测的是新版本
+
+浏览器打开 staging 的 `/api/health`,看 `deployment.gitCommit` 前 8 位是否等于本单合入 staging 后的提交。不一致 = 先别测。本迁移必须先 `Migrate Staging Database`。
+
+## 1. intake 三档,家人一小时进校正是两小时窗(P0)
+
+设置 → 星盘资料。出生时间选「家人记得大概时间」,钟点填一个整点,范围点「前后一小时」,保存后开生时校正。
+
+- ✅ 预期:顶部目前范围是该钟点前后各一小时(共两小时)。没有「偏移 / 误差 / 置信度 / 概率」。校正过程不再问你有多确定。
+- ❌ 失败:范围仍是 ±15;或校正开场又问不确定度。
+
+## 2. 吻合低且贴边时出放宽卡,点 A 后设置页跟着变(P0)
+
+用上一档资料。口述三件带年月、不同领域、和这个两小时窗明显对不上的经历(不要用真实资料原句)。等到出现放宽卡。
+
+- ✅ 预期:卡在区分卡之前。A 是放宽到前后两小时(或下一档),没有采用。点 A 后顶部范围变宽;再打开设置,家人范围按钮停在更大的档。
+- ❌ 失败:没有放宽卡、先出了分钟区分卡;或点 A 后设置页还是前后一小时。
+
+## 3. 医院记录放宽不改档案来源(P1)
+
+另建资料,选「有出生证或医院记录」,走完能出放宽卡的条件后点 A。
+
+- ✅ 预期:窗口变宽,设置页来源仍是医院记录,没有变成「家人记得大概时间」。
+- ❌ 失败:来源被改成 approximate。
+
+## 4. 超过两小时先切三段(P0)
+
+资料选「只知道大概时段」填傍晚,或家人「前后两小时」。开校正,说够带年月经历。
+
+- ✅ 预期:先出三段钟点卡,不是分钟或采用。选一段后若仍超过两小时,再出子段卡。
+- ❌ 失败:一上来分钟卡;或选傍晚后立刻按分钟比。
diff --git a/docs/testing/rectification-scenarios-20260907.md b/docs/testing/rectification-scenarios-20260907.md
new file mode 100644
index 00000000..7364eb3d
--- /dev/null
+++ b/docs/testing/rectification-scenarios-20260907.md
@@ -0,0 +1,64 @@
+# 生时校正手测脚本(2026-09-07)
+
+虚构走查。不要填真实姓名、出生资料或真实经历。对应 `TASK-rectification-declared-uncertainty-20260907.md` 决策 9。
+
+测之前先看 `rectification-declared-uncertainty-20260907.md` 第 0 条。
+
+## 1. 范围:家人说两点到四点
+
+资料:家人记得大概时间,钟点 15:00,范围「前后一小时」。地点任意公开城市。
+
+开场后依次说(均可改年份,保持不同领域):
+
+1. 2016 年 9 月去外地上学
+2. 2018 年 7 月入职第一份工作
+3. 2023 年夏天搬家
+
+期望:
+
+- 顶部范围 14:00–16:00,不是 14:45–15:15
+- 若三件和这个窗对不上且代表分钟贴边:出现放宽卡,选项是前后两小时 / 不放宽 / 说不好
+- 点 A 后范围变成 13:00–17:00,设置页停在「前后两小时」
+- 不得出现:偏移、误差、置信度、概率、采用卡(在放宽之前)
+
+## 2. 时段:只知道傍晚
+
+资料:只知道大概时段,开始 18:00 结束 22:59。
+
+经历同上三件,领域仍要两个以上。
+
+期望:
+
+- 第一张卡是三段钟点(例如 18:00—19:xx),不是「更像 20 点」、不是采用
+- 选 A/B/C 后范围收到该子段;若仍大于两小时,再出一张子段卡
+- 输入框上方是比较时段 / 子段,不是分钟
+- 不得出现:全日 00:00–23:59 上的分钟卡
+
+## 3. 完全未知
+
+资料:完全不清楚。
+
+经历三件同上。
+
+期望:
+
+- 先出清晨 / 上午 / 下午 / 傍晚或夜里这类五时段卡(实际露出支持最高的三段)
+- 选定后若该时段超过两小时,再切子段,然后才分钟
+- 家人线索如果填了,只出现在旁白,窗口仍是全日直到点选
+- 不得出现:劝退「以后再做」;不得在全日窗上采用
+
+## 4. 必须停下
+
+资料:家人记得大概时间,钟点任意,范围「差不多准」。
+
+经历故意说不清:
+
+1. 「大概哪年有过事,具体不记得」
+2. 「地点也说不准」
+3. 连续几道选择题都点「说不好 / 先这样」
+
+期望:
+
+- 到不确定度停止规则时停下,旁白说明再问也分不开
+- 不采用、不编唯一出生分钟
+- 不得把「先这样,先看当前范围」当成已经选定时间
diff --git a/docs/testing/rectification-unknown-time-20260906.md b/docs/testing/rectification-unknown-time-20260906.md
index 9c27dc04..f1da4619 100644
--- a/docs/testing/rectification-unknown-time-20260906.md
+++ b/docs/testing/rectification-unknown-time-20260906.md
@@ -22,12 +22,14 @@
- ✅ 预期:出现四选卡,问哪一段更像出生时段(清晨 / 上午 / 下午 / 傍晚或夜里这类)。没有「更像 X 点」,没有采用。输入框上方是「第 1 步·比较时段」。
- ❌ 失败:仍在问经历却已经给出分钟或采用卡;或时段卡上写了代表分钟。
-## 3. 选定一段后进入分钟流程(P0)
+## 3. 选定一段后若仍超过两小时,先切子段(P0)
-在时段卡上选 A、B 或 C 中的一段。
+在时段卡上选 A、B 或 C 中的一段(例如下午 12:00–17:59)。
-- ✅ 预期:旁白说明已选定出生时段,接下来只在这一段里按分钟比较。目前范围变成该时段(不超过大约 6 小时),不再是 00:00–23:59。之后才可能出现分钟区分题。
-- ❌ 失败:范围仍是全日;或选定后立刻采用某个分钟。
+- ✅ 预期:范围变成该时段,不再是 00:00–23:59。若这一段超过大约两小时,下一张仍是三段钟点卡,不是分钟或采用。收到大约两小时及以内之后,才按分钟比较。
+- ❌ 失败:范围仍是全日;选定下午后立刻出现分钟或采用卡。
+
+更完整的子段与放宽走查见 `docs/testing/rectification-declared-uncertainty-20260907.md`。
## 4. 说不好会再收经历,不会结束校正(P1)
diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md
index 9b67ba00..b740c0aa 100644
--- a/frontend/DESIGN.md
+++ b/frontend/DESIGN.md
@@ -243,7 +243,7 @@ The birth-time rectification session is the consultation transcript plus a house
### Birth time intake
-- **Structure:** birth date, five radio choice rows for time knowledge, then only the time, uncertainty, period, or clue field required by the selected source.
+- **Structure:** birth date, then three radio rows for “你对这个时间有多确定”——医院记录精确到分钟、家人记得大概时间、只知道时段或完全不知道。家人那档再给四个范围按钮(差不多准 / 前后半小时 / 前后一小时 / 前后两小时 = ±15/30/60/120)。存量 `family_exact` 档案显示成「差不多准」。之后只露出该档需要的钟点、时段或线索字段。
- **Surface:** choice rows use the warm canvas and hairline system; the selected row uses `--color-action-soft` with a deep-brown border, never a dark promotional card.
- **States:** no source selected, source selected, source-specific details incomplete, ready to continue, assessing, rectifying, candidate saved, confirmed.
- **Copy:** labels describe what the user actually knows. “完全不清楚” starts rectification from remembered events and compares declared periods before any minute grid; it does not defer correction. Candidate results explicitly distinguish a reported time, a candidate range, and an active chart time.
diff --git a/frontend/docs/VOICE.md b/frontend/docs/VOICE.md
index d9c22750..09301a6a 100644
--- a/frontend/docs/VOICE.md
+++ b/frontend/docs/VOICE.md
@@ -46,6 +46,10 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
| 选择题只有题干,不知道为什么问、答了会怎样 | 题干下可展开「为什么问这题」;选项旁有一段「会让哪段领先 / 落后」。 | 解释由服务端生成,不让模型编分数。 |
| 每轮只有技法清单,不知道现在第几步 | 输入框上方有「第 N 步 · 原因 · 下一步」。 | 用户始终看得见该做什么。 |
| 完全不清楚出生时间后劝退「生时校正以后需要时再做」 | 可以直接开始生时校正:先从你记得的经历比出大致时段。 | 不知道钟点时先比时段,不劝退、不给分钟卡。 |
+| 问「偏移 / 误差有多少分钟」 | 你对这个时间有多确定? | 不确定度只在资料里问一次,校正不再追问。 |
+| 吻合率低时模型追问要不要把误差放到 ±2 小时 | 按你说的经历,出生时间可能比家人记的偏得更多。放宽后再比一次? | 放宽卡由服务端出,选项写「前后半小时 / 一小时 / 两小时」,不用偏移、误差、置信度、概率。 |
+| 只知道傍晚时直接给分钟或采用卡 | 先切成三段(写起止钟点),比完再按分钟收。分不开就说「时段分不开,直接按分钟比」。 | 超过两小时的窗口先走子段,不在 4~6 小时上铺分钟卡。 |
+| 记下精确到日的事后不问日子从哪来 | 刚才那个日子是查过记录,还是凭记忆? | 只问日级、只问一次;不答就跳过。 |
## 服务端探针 → Agent 题干
diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
index 26ab38f5..ac8d038a 100644
--- a/frontend/src/app/globals.css
+++ b/frontend/src/app/globals.css
@@ -863,6 +863,11 @@ button:disabled { cursor: default; opacity: .45; }
.birth-time-source-option > span { display: grid; gap: 3px; }
.birth-time-source-option b { color: var(--color-ink); font-size: var(--type-body-sm); font-weight: 600; }
.birth-time-source-option small, .birth-time-detail-note, .birth-time-legacy-note { margin: 0; color: var(--color-ink-secondary); font-size: var(--type-caption); line-height: 1.5; }
+.birth-time-uncertainty-fieldset { margin: var(--space-3) 0 0; padding: 0; border: 0; }
+.birth-time-uncertainty-fieldset legend { margin-bottom: var(--space-2); color: var(--color-ink-secondary); font-size: var(--type-caption); font-weight: 600; }
+.birth-time-uncertainty-list { display: flex; flex-wrap: wrap; gap: var(--space-2); }
+.birth-time-uncertainty-option { min-height: 44px; padding: 0 var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); font-size: var(--type-body-sm); cursor: pointer; }
+.birth-time-uncertainty-option.is-selected { border-color: var(--color-action); background: var(--color-action-soft); }
.birth-time-detail-grid { display: grid; grid-template-columns: minmax(0, 180px) minmax(0, 1fr); align-items: end; gap: var(--space-3); }
.birth-time-detail-grid > label { min-width: 0; }
.birth-time-detail-note { padding-bottom: 12px; }
diff --git a/frontend/src/components/birth-time-intake.tsx b/frontend/src/components/birth-time-intake.tsx
index 40851fcd..0b12ffe0 100644
--- a/frontend/src/components/birth-time-intake.tsx
+++ b/frontend/src/components/birth-time-intake.tsx
@@ -5,11 +5,13 @@ import { BirthDatePicker } from "@/components/birth-date-picker";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { birthTimeConsultationOptionsCopy } from "@/lib/birth-time-consultation-consent";
import {
+ approximateUncertaintyOptions,
birthTimeDisplayState,
birthTimeSourceDefaults,
birthTimeSourceOptions,
type BirthTimeDraft,
type BirthTimeDraftPatch,
+ type BirthTimeSource,
} from "@/lib/birth-time-intake-model";
type BirthTimeIntakeProps = {
@@ -79,13 +81,20 @@ export function BirthTimeIntakeFields({ value, onPatch }: BirthTimeIntakeProps)
const source = value.birthTimeSource;
const isConfirmed = value.birthTimeStatus === "confirmed";
const displayState = birthTimeDisplayState(value);
- const knowledgeMode = source === "period_only" || source === "unknown"
- ? "uncertain"
- : source ? "exact" : "";
+ const selectedSourceOption: BirthTimeSource | "" = source === "family_exact" || source === "approximate"
+ ? "approximate"
+ : source === "unknown"
+ ? "period_only"
+ : source === "hospital_record" || source === "period_only"
+ ? source
+ : "";
const usesClockTime = source === "hospital_record"
|| source === "family_exact"
|| source === "approximate"
|| source === "legacy_import";
+ const approximateRadius = source === "family_exact"
+ ? 15
+ : value.uncertaintyBeforeMinutes;
return (
@@ -126,20 +135,16 @@ export function BirthTimeIntakeFields({ value, onPatch }: BirthTimeIntakeProps)
)}
{!isConfirmed &&