diff --git a/CHANGELOG.md b/CHANGELOG.md index db112497..f5100c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # 印度占星 Skill 更新日志 +## 2026-09-11 — 带年月题问完还会按剩下的候选再问、再请你补事 + +生时校正里,带年月选择题问完、范围还没收窄到可以结束时,会先按剩下的候选再出一批带年月题;如果还是没有可问的,会点名还能把两端分开的那几条线(比如家里添丁、收入明显变过),请你记得哪件说哪件。你说「没有了」之后才给出目前范围。卡片标题是「目前范围」,下面会写还能再收窄什么。不会把「题问完」当成已经结束。Skill 10.0.24。 + + ## 2026-09-11 — 带年月选择题问完后会给出当前范围 生时校正里,训练门已经打开、带年月的选择题问完后,会直接给出当前范围和三列对照卡,并补一句还可以再想起什么来收一截。不会停在「没有拿到下一个问题」,也不会先逼你答性格对照题。时间线有卡时写「选择题已问完,下面是当前范围」;材料还不够时才请再说一件带年月的事。Skill 版本不变。 diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 4ecd119b..f03b8b80 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -10133,6 +10133,38 @@ - 复发自:BUG-629(性格题降权后仍被当成必答区分题) - 修复版本:`66f63c76`;门禁跟进 `f870d3d7` +## BUG-653 | 带年月题池空必须按剩余候选刷新探针,不得直接出卡 + +- 状态:resolved +- 首次发现:2026-09-11 +- 最近更新:2026-09-11 +- 影响面:`refreshDiscriminatorProbes`、`persistNextInterviewIfIdle` / `AfterChoice`、`event_probes.py` +- 用户现象:六道带年月选择题答完后,范围仍是约 20 分钟、头名约 29%,系统却直接出三列区间卡。 +- 触发条件:训练门已开、引擎一次性生成的带年月探针问完、TypeScript 侧只更新分数、未再拿剩余活跃候选去引擎生成探针。 +- 根因:区分探针只在引擎跑账本时按初始簇生成一次。选择题答完后不刷新。`MAX_PROBES=8`、每域每年一道、家人存在题被 0.85 先验整域丢弃,把还能切开剩余簇的题掐掉。 +- 修复:池空且未收敛时 `refreshDiscriminatorProbes` 用活跃候选 `column_times`、全部已答键 `asked_probe_keys`、`refresh_probes=true` 调引擎,探针并入 `inference_state.probes`,不改 `candidate_set_id` / 已答题。每个候选集最多刷新 2 次。剩余候选 ≤5 时刷新上限 12/4。带月份的家人 `dasha_boundary` 不再因先验丢弃,只用于排序。 +- 验证:`frontend/tests/rectification-probe-pool-exhausted-20260911.test.ts` T0/T1;`tests/test_candidate_discriminator_contract.py` 刷新上限与家人月级边界。 +- 防复发:刷新必须走现有 `keepAnswers` 回放路径(BUG-587 / BUG-594);`asked_probe_keys` 带全部已答键,同域同年去重(BUG-559)。性格题不得进刷新池(BUG-651)。 +- 相关记录:BUG-651、BUG-654、BUG-629、BUG-559、BUG-587、BUG-594 +- 复发自:BUG-651(池空即交付,未先按剩余候选再出题) +- 修复版本:待发布 + +## BUG-654 | 刷新后仍无带年月题须定向补事,卡片标题为目前范围 + +- 状态:resolved +- 首次发现:2026-09-11 +- 最近更新:2026-09-11 +- 影响面:`targetedCollectPool`、`decideRectification`、区间卡 `RectificationRangeDelivery` +- 用户现象:带年月题问完后直接出卡,标题写成「这次给出的范围」,没有「还能再收窄」;家人 / 财务 / 迁居等能切开 05:00 换升的线从未被问。 +- 触发条件:刷新后带年月池仍空,或用户尚未说「没有了」;交付文案把当前范围写成结束。 +- 根因:S1 锚定追问在训练门开后停;S2 池空直接 S3。交付条件把「池空」当成结束。卡片标题用「这次给出的范围」,BUG-651 的「再补什么」句只在 persist 旁白、不在卡上。 +- 修复:刷新后仍无带年月题则出定向补事口述题(剩余换升层映射到领域,≥2 个具体例子,不带推算年份)。答新事则重算回 S2;答「没有了」才交付。交付条件改为收敛,或刷新与定向补事都用尽,或用户主动停。卡片标题「目前范围」,卡下「还能再收窄」取定向补事首条。禁用「这次给出」「最终」。 +- 验证:`frontend/tests/rectification-probe-pool-exhausted-20260911.test.ts` T3/T4;`rectification-collection-question-pool.test.ts` 定向补事;`agent-voice-copy-contract.test.ts` 禁词。 +- 防复发:`!separation.sufficient && !probe` 在 `refreshExhausted && targetedCollectExhausted` 之前不得 `completeWithRange` / `finish`。不得静默空载体(BUG-652)。 +- 相关记录:BUG-653、BUG-651、BUG-652、BUG-629 +- 复发自:BUG-651(池空即交付,未做定向补事) +- 修复版本:待发布 + ## BUG-652 | 答题事务有决策无载体时必须回落到交付或缺口句 - 状态:resolved diff --git a/docs/tasks/PROGRESS-rectification-narrow-before-deliver-20260911.md b/docs/tasks/PROGRESS-rectification-narrow-before-deliver-20260911.md new file mode 100644 index 00000000..e4eb938c --- /dev/null +++ b/docs/tasks/PROGRESS-rectification-narrow-before-deliver-20260911.md @@ -0,0 +1,35 @@ +# 进度 · 带年月题问完不等于收敛:交付前先刷新再定向补事(2026-09-11) + +## 范围 + +- 分支:`codex/rectification-narrow-before-deliver-20260911`(基于 `origin/staging` @ `9941c34d`) +- BUG-653:带年月池空先按剩余活跃候选刷新探针 +- BUG-654:刷新后仍无题则定向补事;卡片「目前范围」+「还能再收窄」 +- 不改确认门、`SCORE_DELTA`、`MIN_ACCEPTANCE_*` +- Skill 10.0.23 → 10.0.24 + +## T0 + +真机事故是第六题后直接出 04:48–05:07 三列卡。BUG-651 T5「再补什么」只在 persist 旁白,不在卡片标题。本单把交付推迟到刷新与定向补事用尽。 + +## 完成 + +- T1 `refreshDiscriminatorProbes`:每个 `candidate_set_id` 最多 2 次;不改已答题 +- T2 刷新上限 12/4(剩余 ≤5);家人月级 `dasha_boundary` 不因 0.85 先验丢弃 +- T3 `targetedCollectPool` / 答「没有了」进 S3 +- T4 交付条件与卡片文案;卡下 `rectification-range-delivery__narrow` 有 CSS 规则 +- T5 BUG-653/654、CHANGELOG、场景 0b、Skill 10.0.24 + +## 验收(本机,未部署) + +- `frontend` `tsc --noEmit` 0 错 +- `npm run lint` 0 error(既有 warning 仍在) +- 相关 TAP `tests/rectification-*.test.ts` + `agent-voice-copy-contract` + `skill-registry`:**1197 / 1197** +- Python:`test_candidate_discriminator_contract.py` 11 + `test_rectification_event_probes.py` 35,fail=0 +- `run_quality_gate.py --profile quick`:Python 段 734 passed;随后整仓 `npm test` 曾因并行 Docker 超时失败 3 条(foundation DML / personal report job / v9 新鲜库迁移),另 1 条 CSS 合同已修 +- `next build --webpack`:`/` 仍 `○ Static`;Next 16 路由表不再印 First Load JS;`rootMainFiles` gzip 130934 B + +## 未做 + +- 部署后真机按场景 0b 走一遍(验收方 Claude) +- 未 commit / 未 push diff --git a/docs/testing/rectification-scenarios-20260907.md b/docs/testing/rectification-scenarios-20260907.md index 1e8929f0..b3642673 100644 --- a/docs/testing/rectification-scenarios-20260907.md +++ b/docs/testing/rectification-scenarios-20260907.md @@ -19,7 +19,7 @@ - 点「先这样,先看当前范围」后必须出现候选卡或当前范围,不得只剩「没有拿到下一个问题」 - 停止后卡片数字必须等于答题后的支持度(不是引擎刚算出来的裸相对支持度),范围不得比答题后更宽,点采用必须成功 -## 0b. 六道选择题答完必须出卡 +## 0b. 六道选择题答完必须先刷新再补事再出卡 资料:家人记得大概时间,钟点任意,范围「差不多准」。地点任意公开城市。 @@ -27,8 +27,10 @@ 期望: -- 第六题答完必须看到三列区间卡,正文有一句还可以再想起什么来再收一截 -- 不得出现「没有拿到下一个问题」 +- 第六题答完不得直接出卡;先出现新的带年月题(家人 / 财务 / 迁居等换运边界),或一条定向补事口述题 +- 答一件家人事后应重算并回到带年月题;答「没有了 / 就这些」后才出卡 +- 卡片标题为「目前范围 …(对照了 N 件经历)」,卡下有「还能再收窄:如果记得 …」 +- 不得出现「这次给出」「最终」「没有拿到下一个问题」 - 不得先出 D9/D10 性格对照卡挡住结果 - 时间线有卡时写「选择题已问完,下面是当前范围」,不得写「才会变」 diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md index 2f463e1b..629f02f8 100644 --- a/frontend/DESIGN.md +++ b/frontend/DESIGN.md @@ -233,7 +233,7 @@ The birth-time rectification session is the consultation transcript plus a house | `question-gap`, collect waiting | no “没有拿到下一个问题”; the last assistant line already has the precise gap | enabled, placeholder “再说一件带年月的事” | | `verified_idle` | one closing line `postAdoptVerifyDone` under the still-visible range card (same assistant column); no spinner, no reload | enabled | | `choice-pending` | the answered card (`data-selected` fill, a top row “正在记录…”) and the same live row from “正在记录本次选择…” through the follow-up turn | enabled (typing queues), stop visible | -| `candidates` | one range-delivery card of up to three compare columns (highest posterior first; “更像这个” adopts) under the offering message; a closed “查看验证报告” fold | enabled | +| `candidates` | one range-delivery card titled “目前范围 …(对照了 N 件经历)”, a “还能再收窄” caption under the title, then up to three compare columns (highest posterior first; “更像这个” adopts); a closed “查看验证报告” fold | enabled | | `adopting` | “正在采用 HH:MM…” through the follow-up turn | enabled (typing queues), stop visible | | `confirmed` | “已确认校正时间:HH:MM” | enabled | | `readonly` | “该校正已结束,只能查看历史。” and “再次校正” | disabled | @@ -252,7 +252,7 @@ The birth-time rectification session is the consultation transcript plus a house - **Accessibility:** native radio inputs remain focusable, every conditional field has a persistent label, status text uses live regions, and the complete flow is keyboard operable. - **Motion:** source-dependent fields enter with the existing 180ms opacity/vertical reveal; reduced-motion removes the translation. - **Life-event evidence:** after deterministic questionnaire completion, render three structured event rows by default and allow up to six. Each row uses a domain select, a precision select, and a matching year/month/day control; free-form descriptions are not part of scoring. -- **Candidate result:** keep the reported range, candidate interval, and active-time status visually separate. Delivery shows one range card: title (range + event count), up to three compare columns (time, relative likelihood, D9/D10/nakshatra traits, event-fit counts, next-12-month windows, “更像这个”), and the representative-minute boundary. An eight-method report sits in a closed `
` fold. Support numbers stay on the house board. Low confidence keeps evidence editing open; medium offers save or add evidence; high uses a separate confirmation action and never labels a column as the true birth time. +- **Candidate result:** keep the reported range, candidate interval, and active-time status visually separate. Delivery shows one range card: title “目前范围 HH:MM–HH:MM(对照了 N 件经历)”, a caption “还能再收窄:如果记得 …” under the title, up to three compare columns (time, relative likelihood, D9/D10/nakshatra traits, event-fit counts, next-12-month windows, “更像这个”), and the representative-minute boundary. An eight-method report sits in a closed `
` fold. Support numbers stay on the house board. Low confidence keeps evidence editing open; medium offers save or add evidence; high uses a separate confirmation action and never labels a column as the true birth time. - **Evidence accessibility:** every row keeps visible labels, validation errors use live regions, add/remove controls retain 44px targets, and scoring/confirmation loading states disable duplicate submission without hiding the existing evidence. - **One-question guide:** the guided journey renders only the persisted `nextAction` and one server-selected question. A deterministic question is visible immediately; Agent wording may replace it without changing the question identity, domain, precision request, progress, or permissions. The composer explicitly permits an approximate year. Spoken collect does not render skip chips; typing 「没有」 still declines the domain and 「记不清」 still skips it. Stop on spoken collect is not a composer button: `CHOICE_STOP_LABEL` (“先这样,先看当前范围”) stays on choice cards, and generating turns keep “停止回答”. The readonly range line is a status sentence, not a stop control. Discriminator cards fold “为什么问这题” under the stem. Hovering or selecting an option does not reveal an `answer_impact` time line. The method sentence (`vargaSentence`) lives in the expanded activity timeline, not in the spoken bubble. The composer has no `rectification-step-state` status sentence and no `rectification-composer-meta`. - **Draft review:** natural-language answers become one inline review card. The evidence domain is read-only and uses its Chinese label; precision controls which exact year, month, or day input is available. Incomplete drafts keep edit and skip paths visible, while confirmation is disabled until the structured date is valid. Status and errors use polite or assertive live regions without clearing the persisted journey. diff --git a/frontend/src/app/api/rectification/cases/[caseId]/route.ts b/frontend/src/app/api/rectification/cases/[caseId]/route.ts index 0bc9e9d7..1af9f0ca 100644 --- a/frontend/src/app/api/rectification/cases/[caseId]/route.ts +++ b/frontend/src/app/api/rectification/cases/[caseId]/route.ts @@ -176,6 +176,8 @@ function publicLatestResult( credibleRange: projected.credible_range ?? decision.credibleRange, credible_range: projected.credible_range ?? decision.credibleRange, skill_verification_report: toolProjection.skill_verification_report, + evidence: dossier.evidence, + declinedTopics: dossier.conversationSummary.declinedSkippedTopics, }); const withDelivery = { ...projected, diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 59c00c08..7d495a3f 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -3329,6 +3329,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .rectification-range-delivery__likelihood, .rectification-range-delivery__block p, .rectification-range-delivery__more, +.rectification-range-delivery__narrow, .rectification-range-delivery__shared, .rectification-range-delivery__column > p { margin: 0; diff --git a/frontend/src/components/rectification-range-delivery.tsx b/frontend/src/components/rectification-range-delivery.tsx index c64c5e4b..e9111fd0 100644 --- a/frontend/src/components/rectification-range-delivery.tsx +++ b/frontend/src/components/rectification-range-delivery.tsx @@ -32,7 +32,7 @@ export function RectificationRangeDelivery({ const columns = delivery?.columns ?? []; const title = range ? eventCount > 0 - ? `${RECTIFICATION_USER_COPY.rangeDeliveryTitle} ${range[0]}–${range[1]} · ${rangeDeliveryEventCopy(eventCount)}` + ? `${RECTIFICATION_USER_COPY.rangeDeliveryTitle} ${range[0]}–${range[1]}(${rangeDeliveryEventCopy(eventCount)})` : `${RECTIFICATION_USER_COPY.rangeDeliveryTitle} ${range[0]}–${range[1]}` : RECTIFICATION_USER_COPY.rangeDeliveryTitle; const markdown = delivery?.verification_markdown @@ -44,6 +44,9 @@ export function RectificationRangeDelivery({
{title}
+ {delivery?.narrow_hint ? ( +

{delivery.narrow_hint}

+ ) : null} {sharedTraits.length > 0 ? (