feat: complete minute birth-time rectification flow

This commit is contained in:
Jesse_Chen
2026-07-25 01:15:48 +08:00
parent f90aba217f
commit 3ca30ed7de
93 changed files with 8347 additions and 1646 deletions
@@ -0,0 +1,258 @@
# 生时纠正网页端 AA 级已知答案盲测集
目的:用仓库已登记的公开 AA 级案例完整手测网页端自然语言校时,验证 Agent 能持续跨领域追问、调用 VedAstro 比较候选、输出审计表,并在用户显式确认后写回出生时间。
本文件不含真实用户隐私。测试人物及事件均来自公开名人资料;操作者仅以第一人称复述公开履历。此测试既验产品流程,也验已知答案回收能力,但单个案例通过不能证明普遍分钟级准确率。
## 角色分工与盲测规则
- **操作者**:只看“公开给操作者”部分,逐轮输入,不查看验收密封区。
- **验收者**:记录页面、接口和脱敏后端证据;流程结束后才打开密封区核对正确分钟。
- **Agent / 开发者**:不得把正确分钟、案例名或 `case_id` 注入提示词、候选排序或 VedAstro 请求。
- 每轮只问一个问题、只答一个问题。允许 Agent 改变措辞,但不允许跳过语义承接。
- 不设置最大事件数、最大轮数、连续不收敛停止或领域耗尽停止;未满足外部判别条件时继续问最有区分度的问题。
## 测试前提
- 本地前端:`http://localhost:3000`
- 本地占星后端:`http://127.0.0.1:5200`
- 使用专用测试账号;开始前清空其生时纠正会话与出生时间写回状态,保留点数、充值和消费历史。
- `VEDASTRO_ENABLE_NETWORK=1`,VedAstro 凭据只存在本地/部署环境,不写入截图、日志或本文。
- 浏览器 Network 和后端日志可用;所有证据必须脱敏,不记录 Cookie、JWT、邮箱、用户 ID、case ID 或完整模型提示词。
- 初始出生时间状态必须是“不确定”,不能预先保存密封答案。
## 公开给操作者:出生输入
| 字段 | 输入 |
|---|---|
| 出生日期 | `1955-02-24` |
| 出生地点 | `San Francisco, California, United States` |
| 纬度 / 经度 | `37.7749 / -122.4194` |
| 时区 | `UTC-08:00`,当地当日无夏令时 |
| 家庭记忆 | `大约晚上七点左右,可能前后差四十五分钟。` |
| 初始候选范围 | `18:3020:00` |
不要在用户可见输入中出现人物姓名或已知正确分钟。
## 场景 0:入口、首条消息与幂等
1. 从首页点击“生时纠正”。
2. 在加载期间再次点击一次入口,随后刷新页面一次。
3. 等待 Agent 首条引导消息,不先发送人生事件。
通过条件:
- 点击后立即出现同一套连续加载反馈;不能先后出现彼此割裂的“正在建立记录”“正在准备问题”两套遮罩。
- 只创建或恢复一个有效校时 case;重复点击、刷新和 handoff 重放不得创建第二个 case。
- 首条 Agent 消息自动出现,说明会逐步询问已经发生的事件,并且只提出一个开场问题。
- 首条消息以流式方式进入同一气泡;活动状态可与答案同时显示,完成后由进行态切换为完成态。
- 消息列表跟随新增内容滚动到底部;右侧滚动条默认隐藏,滚动时出现。
- 不显示候选卡片、历史录入卡片或“当前候选 xx:xx · 待验证”等额外操作区。
## 场景 1:教育事件、自然承接与模糊日期
按 Agent 的问题自然发送以下答案;不要一次粘贴多条。
| 轮次 | 操作者回答 | 预期 Agent 行为 |
|---:|---|---|
| 1 | `1972年秋天我进入里德学院读书。` | 承接“进入大学”,若需要时间精度,只问秋天大致是几月;不能只回复“已记录”。 |
| 2 | `大概是9月,但我只确定是秋季。` | 保留“1972-09,月级近似”而不是虚构具体日;继续追问这段教育经历发生了什么变化。 |
| 3 | `读了一个学期以后我退学了,但之后还在学校旁听了一段时间。` | 把退学和上一条教育经历关联;因缺时间可只追问退学年月,不得重新问入学年月。 |
| 4 | `正式退学大约是1972年12月。` | 合并为同一教育轨迹,识别 D24 教育层;下一问转向尚未覆盖的高区分领域。 |
检查:Agent 的每次回应都应先用自然语言说明这条事实为何有用或如何修正了当前理解,再问一个问题;不得连续输出“当前累计 / 下一步 / 本轮区分重点”模板。
## 场景 2:迁移、旅行与拒绝伪精确
| 轮次 | 操作者回答 | 预期 Agent 行为 |
|---:|---|---|
| 5 | `1974年我离开美国去了印度,待了几个月,对之后的生活方式影响很大。` | 识别迁移/远行与价值观变化;若月份缺失,只问时间精度。 |
| 6 | `我只记得是1974年,月份不确定,不要替我补。` | 保存年级精度并停止追问不存在的月份;不得反复要求年月。 |
| 7 | `回国后我先在加州工作,后来开始做自己的电脑项目。` | 承接回国和职业转折,但因两个事实混在一句,可选其中最有区分度的一件只问一个问题。 |
## 场景 3:事业、财务与同一事件补日期
| 轮次 | 操作者回答 | 预期 Agent 行为 |
|---:|---|---|
| 8 | `1976年4月我和伙伴正式创办了第一家公司。` | 识别创业事件并询问职责/转折等一个细节;不得再问年份月份。 |
| 9 | `我主要负责产品方向、设计判断和把技术变成普通人能用的东西。` | 作为 1976-04 创业事件的详情保存,不得新增“日期待补充”的独立事件。 |
| 10 | `后来公司上市,我的资产在很短时间里发生了很大变化。` | 识别财务事件并只追问上市时间。 |
| 11 | `是1980年12月12日。` | 合并回上市/资产变化事件,进入 D2/D11 财务层;不得保存成无主题日期。 |
| 12 | `1985年10月我离开了自己创办的公司。` | 记录为事业重大中断,并追问离开性质或之后去向中的一个。 |
| 13 | `更正一下,不是10月,是1985年9月;是权力冲突后离开管理层。` | 建立修订链:旧月份退出有效评分,新月份参与评分,不重复计分。 |
| 14 | `之后我创办了NeXT,1996年12月因为收购又回到了原来的公司体系。` | 分开识别新创业与回归,但只追问缺失且最有价值的一项;1996-12 不得再次询问。 |
## 场景 4:家庭、关系、健康与事故否定证据
| 轮次 | 操作者回答 | 预期 Agent 行为 |
|---:|---|---|
| 15 | `1978年5月我的第一个孩子出生。` | 识别家庭事件;若日期已足够,不追问具体日。 |
| 16 | `1991年3月18日我结婚。` | 识别关系事件并进入 D9 + UL/A7 验证;不再问年月。 |
| 17 | `2003年我被诊断出严重的胰腺疾病,最初没有立刻手术。` | 识别健康压力;允许年级精度,不把“未立刻手术”拆成第二条计分事件。 |
| 18 | `2004年7月底我接受了相关手术。` | 与 2003 诊断关联,但作为独立治疗节点评分;保持“月底”精度。 |
| 19 | `2009年4月我接受了肝移植。` | 识别第二个独立健康节点;不得又回到教育或事业模板。 |
| 20 | `没有经历过需要住院的重大车祸或骨折。` | 保存为事故领域的否定证据,不虚构事件、不强迫用户提供一个事故。 |
## 场景 5:停止生成与草稿恢复
1. 在 Agent 下一问出现后输入:`1985年10月我离开公司。`
2. 发送后立刻点击“停止”。
3. 检查该次请求未写入事件、未扣除本轮生成次数,文本完整恢复到输入框草稿。
4. 把草稿改为:`1985年9月我离开公司;这是一条界面撤回测试,不要重复计分。`
5. 再次发送。
通过条件:恢复的是用户原文,不是 Agent 改写;草稿可编辑;历史消息不丢失;最终只保留一次有效事实。普通 session 也应使用同一停止/草稿恢复行为。
## 场景 6:流式、历史、滚动和单问单答
从第 1 轮持续检查:
- 用户气泡按发送顺序位于右侧,Agent 气泡位于左侧;旧答案永不被新答案覆盖。
- Agent 文本按流式增量显示;不能等完整 JSON 返回后一次性铺开。
- 活动状态与正在生成的答案同时可见,不是互斥 `if`;完成后保留完成态图标。
- 用户停留在底部时自动跟随;用户主动上滚查看历史时不要强制抢回底部,出现“回到最新”入口即可。
- 一轮只出现一个明确问题。若用户已给日期,问题应询问性质、影响或下一个领域,不能重复问“几年几月”。
- 不使用固定确认模板替代模型回答;技术状态可以结构化保存,但用户可见回复必须承接具体事实。
## 场景 7VedAstro winner / runner-up 强制判别
当本地候选排序已形成第一名和第二名时,后端必须执行 VedAstro 外部验证。验收者只查看脱敏结构化证据:
1. 同一组出生地点、时区、Ayanamsa、Node mode 和历史事件分别扫描 winner 与 runner-up。
2. winner 与 runner-up 都必须有官方 VedAstro 原始响应的哈希/receiptHTTP `200``available: true` 本身不算判别成功。
3. 至少一个有日期的已发生事件被 VedAstro 支持;未来窗口不得计分。
4. winner 必须同时严格领先 runner-up
- `matched_event_count`
- `signal_lift`
- `event_hit_count`
5. 对 winner 执行 `±1 / ±2 / ±5` 分钟稳定性探针,并把变化写入候选差异表。
6. 以下任一情况都不得进入确认:VedAstro 不可用、调用失败、无 runner-up、无支持事件、三项指标任一打平/落后、输入口径不一致、响应无法语义归一化。
若未通过,Agent 应自然说明“还不能区分这两个候选”,继续提出一个最能区分候选的问题;不能抛出 409/500,也不能用本地分数冒充 VedAstro 结论。
## 场景 8:最终回答的三类表
达到可确认条件时,最终消息必须先用自然语言说明为何收敛,再显示以下三张 Markdown 表。允许增列,不得缺表或以卡片替代。
### 1. Technique Audit Table
至少包含:
| 技法/边界 | 最低验收内容 |
|---|---|
| Birth-time uncertainty | 初始范围、最终候选、精度边界 |
| D1 / Lagna | winner 与 runner-up 的稳定/差异 |
| Vimshottari Dasha | 已执行及关键事件命中状态 |
| Narayana Dasha | 已执行及与 Vimshottari 的一致/冲突 |
| D24 | 教育事件判别 |
| D10 + A10 | 事业事件判别;A10 不可静默省略 |
| D2 / D11 | 财务事件判别 |
| D9 + UL / A7 | 关系事件判别 |
| D30 | 健康/事故与否定证据 |
| Functional Benefic/Malefic | used / blocked 及对置信度的影响 |
| VedAstro official | winner/runner-up 双扫描、receipt、判别状态 |
| PyJHora / jyotishganit | used / partial / blocked,不能伪称完成 |
| MEVG / Global Web Evidence | used / blocked |
| Real Case Calibration | 本例为公开 AA 已知答案盲测;揭盲前不得引用答案 |
### 2. 事件验证表
每行至少包含:事件、日期与精度、领域、是否参与评分、支持的候选、Dasha/分盘依据、VedAstro 命中、冲突/备注。更正前的 `1985-10` 必须标记 superseded 且不计分;“无重大事故”必须标为否定证据。
### 3. 候选时间差异表
至少列出 winner 和 runner-up,字段包括:候选时间、本地排名、关键分盘差异、Vimshottari、Narayana、VedAstro `matched_event_count``signal_lift``event_hit_count``±1/2/5` 稳定性、主要支持、主要冲突。不得只展示 winner。
## 场景 9:显式确认与写回
Agent 在三表之后必须询问是否将 winner 写入出生资料,不能自动写回。操作者先回答:
`先不要更新,请再告诉我第二名为什么输。`
检查:Agent 解释 runner-up 的具体落后证据,不写库、不丢失三表。随后验收者揭盲;只有 winner 与密封答案一致且 VedAstro 强制判别全部通过,操作者才发送:
`我确认采用这个结果,请把出生时间更新为你刚才给出的第一候选。`
通过条件:
- 确认前出生资料不变;确认后仅写入已经展示的 winner。
- 刷新首页、普通 session 和再次进入生时纠正后均读取同一最终时间。
- 重放相同确认 action 不产生第二次写入、重复扣费或 409。
- 写回审计保留旧值、新值、确认消息关联和版本,但用户界面不暴露内部 ID。
## 场景 10409 / 并发回归
在独立重置后的第二轮执行:
1. 打开两个同账号标签页,同时进入生时纠正。
2. 标签 A 先提交一条事件;标签 B 用旧页面提交另一条事件。
3. 快速双击一次发送按钮,并重放一次相同 handoff/confirmation 请求。
通过条件:
- 服务端对相同 `action_id` 幂等;同一用户动作只保存一次。
- stale version 自动加载最新进度并安全重试,或把 B 的草稿原样恢复供用户确认;不能把“校正操作发生冲突,请加载最新进度后再试”作为终态。
- 冲突恢复后两标签都能继续;不返回首页、不丢历史、不创建重复 case。
- `/api/birth-time-conversation/handoff` 必须有明确响应;不能无限 pending 或空响应。
- 技术冲突不应被 Agent 当作人生事件,也不应改变候选排名。
## 总通过标准
以下任一项失败即整套测试失败:
1. 初始引导消息缺失,或入口等待期间无连续反馈。
2. 已给出的日期被重复询问,细节被误存成新事件,或修订前事实仍计分。
3. 新消息覆盖旧消息、非流式输出、底部不跟随,或活动状态与答案互相排斥。
4. 停止后草稿未恢复,已停止请求仍写入/计费。
5. Agent 因事件数、轮数、平台期或领域耗尽自行停止追问。
6. 缺少 winner/runner-up 双扫描,或 VedAstro 未严格区分三项指标便允许确认。
7. 缺少任一张最终表,或把内部审计信息只塞进不可见日志。
8. 未显式确认就写回,或显式确认后最终时间没有跨页面一致更新。
9. 入口、发送、handoff、确认重放导致重复 case、重复事件、重复扣费、不可恢复 409 或空响应。
10. 揭盲后第一候选不等于密封正确分钟。
## 验收记录模板
| 项目 | 结果 | 证据(截图/脱敏日志/请求序号) | 备注 |
|---|---|---|---|
| 入口与首条消息 | pass/fail | | |
| 自然语言承接 | pass/fail | | |
| 模糊日期与更正 | pass/fail | | |
| 跨领域持续追问 | pass/fail | | |
| 停止与草稿恢复 | pass/fail | | |
| 历史/流式/活动/滚动 | pass/fail | | |
| 入口/发送/确认幂等 | pass/fail | | |
| 409 自动恢复 | pass/fail | | |
| VedAstro 双候选判别 | pass/fail | | |
| 三类最终表 | pass/fail | | |
| 显式确认写回 | pass/fail | | |
| 已知答案回收 | pass/fail | | |
---
<details>
<summary><strong>仅验收者:已知答案密封区(完成候选排序后再展开)</strong></summary>
### 正确答案
- 公开案例:Steve Jobs(仅用于 AA 级已知答案回收,不得注入 Agent 上下文)
- 正确出生时间:`1955-02-24 19:15:00`
- 地点:San Francisco, California, United States
- 坐标:`37.7749, -122.4194`
- 时区:`UTC-08:00`
- 数据等级:仓库公开案例注册表标记为 `public_astro_databank_aa`
### 揭盲判定
- 第一候选必须是 `19:15`;输出范围包含 `19:15` 但第一候选不是 `19:15`,不算已知分钟回收通过。
- runner-up 不预先固定,由本轮真实排序产生,防止测试为答案定制。
- 如果 VedAstro 无法严格区分第一、第二候选,本轮应判为“正确阻断确认”,但“已知答案回收”仍为 fail;不得人工把 `19:15` 提升为 winner。
- 单例通过只证明这条公开案例回放通过,不得对外宣称普遍准确率或“已验证分钟级校时”。
### 仓库内公开依据
- `references/public_oracle_cases.json``steve_jobs_1955_aa` 出生种子。
- `references/famous-case-library.md`:公开 AA 案例索引。
- `references/oracle/artifacts/vedastro_steve_jobs_contract_probe.json`:既有 VedAstro 合同探针;本次验收仍必须产生新的请求 receipt,不能复用旧结果冒充实时验证。
</details>
@@ -0,0 +1,131 @@
# 生时纠正网页端完整手测集
目的:验证网页端是真正的连续问答,而不是固定模板;验证每一轮都能保留历史、承接上一轮语义,并最终形成候选时间范围。
## 测试前提
- 本地前端:`http://localhost:3000`
- 本地占星后端:`http://127.0.0.1:5200`
- 使用已经登录、出生资料已保存的测试账号。
- 进入“生时纠正”后,先等待 Agent 的首条引导消息,再发送第 1 条答案。
- 每次只发送一条答案;如果写错,使用发送后的“停止/撤回”恢复草稿,不要用下一条答案补救输入错误。
## A. 首轮进入与新事件
按顺序发送:
1. `2014年6月大学毕业。`
2. `2014年9月开始读研究生。`
3. `2017年6月硕士毕业。`
4. `2017年7月入职第一家公司,从事数据分析工作。`
逐轮检查:
- Agent 先确认刚刚这条具体经历,再提出一个问题;不能只显示“当前累计/下一步/本轮区分重点”。
- 同一页面保留所有历史气泡,新答案不能覆盖旧答案。
- 已经给出的年月不能被下一轮重复询问。
- 学业经历应逐步覆盖教育领域,工作经历应覆盖事业领域。
## B. 状态机回归:同一事件补细节
在 Agent 针对第 4 条询问“正式工作、实习还是兼职”等细节时,发送:
5. `是正式工作,入职后主要做数据分析,刚开始没有管理职责。`
检查:
- 回复应承接“2017年7月入职第一家公司”,而不是新建一条没有年月的事件。
- 事件摘要可以扩展为“入职第一家公司;正式工作;主要做数据分析”。
- 不得再次问“这件事是什么年月”。
- 如果 Agent 只问其中一个细节,回答后应继续追问尚未补齐的细节,而不是换成泛化问题。
## C. 同一事件补年月
如果 Agent 先问到一件没有精确年月的经历,使用这组专门回归:
6. `离开家去北京开始工作。`
7. `2023年3月。`
检查:
- 第 6 条先被保存为待补充年月的事件,但回复要复述“离开家去北京开始工作”。
- 第 7 条应把年月合并回原事件,最终显示 `2023-03 · 离开家去北京开始工作`
- 不应新增一条“日期待补充”或重复计分。
## D. 事业与方向变化
继续发送:
8. `2020年9月底主动离职,主要因为组织内耗严重、长期压抑,不是被辞退。`
9. `2023年4月重新开始正式工作,进入医疗器械公司。`
检查:
- Agent 应针对离职原因和后续职业转向回应。
- “主动离职”“组织内耗”“重新进入医疗器械公司”应作为事业事件语义的一部分保存。
- 第 9 条不能再次追问“哪一年哪一月开始工作”,因为年月已经给出。
## E. 纠错链
发送一条明确纠正:
10. `更正:刚才离职时间不是2020年9月底,而是2020年10月。`
检查:
- 旧事实保留在审计历史中,但不再作为有效评分事实。
- 新事实通过修订链关联旧事实,不重复计分。
- 候选范围应重新计算,不应继续沿用仅由旧日期得出的范围。
- 页面不能出现 409 后要求用户自己刷新才能继续的状态。
## F. 关系、健康与财务跨领域
继续发送已经发生的事实:
11. `2024年8月8日结束一段重要关系,双方最后没有继续走下去。`
12. `2024年9月发生车祸,眼睛上方缝了几针。`
13. `2025年10月开始出现欠薪,之后有明显的财务压力。`
检查:
- Agent 应切换到尚未覆盖的领域,不要一直重复事业问题。
- 关系事件、事故/健康压力、财务事件应分别记录。
- 不能把未来窗口当成已发生事件,也不能让用户用未来计划代替历史证据。
## G. 语义承接与更正输入
在任意一轮 Agent 提问后,依次测试:
14. 只回答细节:`正式工作。`
15. 只回答原因:`因为单位内部长期内耗,价值观不合。`
16. 只回答相对时间:`是在分手之后的第二个月左右。`
17. 纠正上一条:`刚才说的是2024年9月,不是2023年9月。`
检查:
- 状态机应根据上一轮问题类型决定是补细节、补日期还是建立纠正链。
- 相对时间不能在没有上下文时被强行当作精确日期;应继续询问缺失的绝对年月。
- 用户更正后,旧事实必须退出有效评分集合。
## H. 收敛与安全边界
当 Agent 已经收集足够事件后,检查最终回复是否包含:
- 当前候选范围,而不是未经验证的单一准确分钟;
- `local_fallback` 或对应计算状态;
- 哪些证据用于关系、事业、财务、事故等领域;
- 哪些证据仍存在冲突或不足;
- 未来窗口仅作为背景,不计入既成事件评分;
- 明确说明候选范围不能替代出生证明中的确定分钟。
## 通过标准
以下任一项失败即判定本轮网页测试失败:
1. 已有年月被重复询问;
2. 细节回答被保存成新的无日期事件;
3. 新回复覆盖旧消息;
4. Agent 连续两轮只输出“当前累计/下一步/本轮区分重点”而没有承接用户事实;
5. 纠错后旧事实仍参与有效评分;
6. 最终把候选范围伪装成确定出生分钟;
7. 生时纠正入口点击后无响应,或 API 返回冲突后无法恢复。