docs(rectification): archive upstream playbook and add stop-rule task
The upstream interview playbook and evidence thresholds resolve task 0. Upstream stops and reports when evidence is thin — fewer than three dated events, fewer than two domains, or a tie — while this repo treats the same kind of thresholds as a confirmation gate and keeps asking when they are not met. Its label ladder has no confirmed rung at all, and every contract test asserts candidate_range_not_birth_time_truth. Task 1 capped the interview by round count, which is half of it. Task 6 adds the evidence-state stop rules, reframes exhausted as a normal delivery, adopts the upstream label ladder and closing wording, and keeps the 4/3 confirmation gate separate from the 3/2 delivery floor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
@@ -146,32 +146,55 @@ git worktree add -b codex/rectification-convergence-20260830 \
|
||||
|
||||
---
|
||||
|
||||
## 任务 0(P0,门控,不写代码)· 拿到上游访谈手册与一份真实会话
|
||||
## 任务 0(已完成 2026-08-31)· 上游访谈手册与阈值文档
|
||||
|
||||
### 事实
|
||||
三份文件已获取,归档于 `references/upstream/`(来源:上游维护者本地 skill 包 `~/.workbuddy/skills/jyotish-birth-time-rectification/`,获取日期 2026-08-31):
|
||||
|
||||
调研发现一个**仓库外**的独立 skill 包:`~/.workbuddy/skills/jyotish-birth-time-rectification/`,含 `references/interview_playbook.md`(访谈手册)与 `references/evidence_thresholds.md`。它不在 `yinduzhanxing` 仓库里,只有 `yinduzhanxing/tests/test_birth_time_rectification_skill_contract.py:7` 引用了这个路径。
|
||||
- `references/upstream/interview_playbook.md`
|
||||
- `references/upstream/evidence_thresholds.md`
|
||||
- `references/upstream/test_birth_time_rectification_skill_contract.py`
|
||||
|
||||
产品侧「本地 Agent 能收敛」的观察,如果另有机制,最可能就在这两份文件里。
|
||||
### 结论:上游的「收敛」= 从不试图确认分钟
|
||||
|
||||
### 要做什么
|
||||
**1. 停止规则与本仓方向相反。**
|
||||
|
||||
1. 向上游维护者索取 `interview_playbook.md` 与 `evidence_thresholds.md`,放进 `references/upstream/` 并在 PROGRESS 记录来源与获取日期。
|
||||
2. 索取**一次真实本地校正会话的完整记录**,要能回答三个问题:
|
||||
- 一共问了几轮?
|
||||
- 最后交付的是一个分钟,还是一个区间?区间多宽?
|
||||
- `confidence` / `can_apply` 是什么值?
|
||||
3. 把答案写进 PROGRESS,并据此确认或推翻这条判断:**「上游的收敛 = 问完固定题数后给出候选区间并停止」。**
|
||||
`interview_playbook.md` 的 Stop Rules 原文:
|
||||
|
||||
### 验收
|
||||
```
|
||||
Stop and report the current interval when any is true:
|
||||
- fewer than three dated events
|
||||
- fewer than two domains
|
||||
- tied first-place candidates
|
||||
- user uncertainty is too high to map support/conflict reliably
|
||||
```
|
||||
|
||||
- 两份文件在仓库里,或明确记录「无法获取」及原因。
|
||||
- 会话记录的三个问题有答案。
|
||||
- PROGRESS 给出结论:上游的终止机制是什么,Jyotisha 要复制的具体是哪一条。
|
||||
即:**证据不足 → 停下来,交付当前区间。**
|
||||
|
||||
### 如果拿不到
|
||||
本仓 `frontend/src/lib/birth-time-evidence.ts:188-189` 把 `minConfirmationEvents(4)` / `minConfirmationDomains(3)` 当作**确认门**,达不到 → **继续问**。
|
||||
|
||||
**不阻塞任务 1–3。** 任务 1 的修法不依赖这份手册——轮次预算该接还是要接。但拿不到这件事要写进 `BLOCKED.md`,因为它是「本地能收敛」这条观察唯一可能的另一种解释。
|
||||
同一类阈值,上游当「可以开始交付的地板」,本仓当「可以下结论的天花板」。前者三轮内必达,后者按 sealed holdout 的 `confirmation_coverage_rate: 0.0` 是零达成。**这是无限访谈的最终解释。**
|
||||
|
||||
**2. 上游的标签梯子没有「已确认」这一档。**
|
||||
|
||||
`evidence_thresholds.md`:`blocked → user_history_verification_required → manual_pattern_consensus → single_adapter_support → multi_adapter_consensus`。顶端自注 "this is still not birth-time truth";`standalone_core` 模式天花板更低,只到 `manual_pattern_consensus`。
|
||||
|
||||
`test_birth_time_rectification_skill_contract.py` 中**每一个** case(含最高档 `main_repository_enhanced`)都断言:
|
||||
|
||||
```python
|
||||
assert receipt["claim_status"] == "candidate_range_not_birth_time_truth"
|
||||
```
|
||||
|
||||
**3. 提问节奏是硬的三轮。**
|
||||
|
||||
第 1 轮 3–5 道 A/B/C/D 选择题;第 2 轮只要最强 domain 的带日期事件;第 3 轮只问能区分 top 候选的 1–3 个事件。手册明写 "Never collect a long autobiography before the first route decision."
|
||||
|
||||
**4. 终止话术是写死的。**
|
||||
|
||||
> 当前最优结果是候选时间段,而不是已经确认的唯一出生分钟。临时代表时间仅用于下一轮验证与比较。
|
||||
|
||||
### 对已完成任务的影响
|
||||
|
||||
任务 1 实现的 `budgetExhausted()`(轮次 8 / 答题 10 / 平台期 2)方向正确但只覆盖了一半——上游是**证据状态型**停止且三轮即止。差额由**任务 6** 补齐。
|
||||
|
||||
---
|
||||
|
||||
@@ -318,6 +341,42 @@ do_not_apply_as_birth_time_truth
|
||||
|
||||
---
|
||||
|
||||
## 任务 6(P0)· 接过上游的终止语义
|
||||
|
||||
### 事实
|
||||
|
||||
见任务 0 结论。任务 1 已接入轮次型预算,但上游的终止是**证据状态型**的,且 `exhausted` 在上游是正常终态而非兜底态。
|
||||
|
||||
### 要做什么
|
||||
|
||||
1. **增加证据型停止规则**,与既有轮次预算并列(任一命中即停并交付):
|
||||
- 带日期事件 < 3
|
||||
- 覆盖 domain < 2
|
||||
- 并列第一(已有 `separation` 可判)
|
||||
- 用户不确定度过高,无法可靠映射 support/conflict
|
||||
|
||||
阈值取 `references/upstream/evidence_thresholds.md` 的 Minimum Standalone Gate(3 事件 / 2 域),**不要沿用本仓的 4/3**——那组是确认门,语义不同,两者必须分开保留,不得互相覆盖。
|
||||
|
||||
2. **把 `exhausted` 从兜底态重新定位为正常终态。** 改命名与全部用户可见文案:走到这里是「交付完成」,不是「很遗憾没能完成」。计费上它必须是有效交付(与 `TASK-billing-pricing-20260830.md` 对齐)。
|
||||
|
||||
3. **引入上游的 label ladder**,替换「确认唯一分钟」作为默认目标:
|
||||
`blocked → user_history_verification_required → manual_pattern_consensus → single_adapter_support → multi_adapter_consensus`
|
||||
唯一分钟确认降级为 sealed holdout 通过后才开启的路径,**不得作为访谈的默认终点**。既有 `confirmation-gate.ts` 的 blocker 保持不变(红线 2),它现在正确地永不放行。
|
||||
|
||||
4. **采用上游的终止话术**,逐字使用任务 0 结论第 4 条那句。它是上游打磨出的合规表述,不要另写。
|
||||
|
||||
5. **收紧提问节奏到三轮形态**:第 1 轮 A/B/C/D 选择题批量出,第 2 轮只要最强 domain 的带日期事件,第 3 轮只问能区分 top 候选的 1–3 个。当前 8 轮预算作为**外层熔断**保留,不作为正常节奏。
|
||||
|
||||
### 验收
|
||||
|
||||
- 证据型停止规则有单测:3 事件以下、2 域以下、并列第一各自触发终止并交付区间。
|
||||
- 4/3 确认门与 3/2 交付地板在代码中是两个独立常量,不互相覆盖,注释写明语义差别。
|
||||
- 用户可见文案中不存在把正常终态描述为失败的表述。
|
||||
- 默认路径下系统不再以「确认唯一分钟」为目标;相关文案与 label 均出自新梯子。
|
||||
- 既有校正测试与任务 1 的四条属性测试全绿。
|
||||
|
||||
---
|
||||
|
||||
## 交付
|
||||
|
||||
- PROGRESS 写进 `PROGRESS-rectification-convergence-20260830.md`,任务 0 的会话记录结论单列。
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Evidence Thresholds
|
||||
|
||||
## Labels
|
||||
|
||||
- `blocked`: required input, route, or event evidence is missing.
|
||||
- `user_history_verification_required`: dates are too sparse or imprecise.
|
||||
- `parameter_sensitive`: small changes in the candidate grid materially alter the lead.
|
||||
- `manual_pattern_consensus`: standalone conversation evidence points to one interval, but no external calculator/audit was executed.
|
||||
- `single_adapter_support`: one user-supplied adapter supports the leading interval.
|
||||
- `multi_adapter_consensus`: multiple executed adapters support the same interval; this is still not birth-time truth.
|
||||
|
||||
## Standalone Cap
|
||||
|
||||
In `standalone_core`, the highest allowed label is `manual_pattern_consensus`.
|
||||
Never label `高置信候选` unless the current user actually provided and executed additional audit adapters.
|
||||
|
||||
## Minimum Standalone Gate
|
||||
|
||||
To move beyond `blocked`, require all of the following:
|
||||
|
||||
- one valid route: `range`, `block`, or `unknown`
|
||||
- at least three dated events
|
||||
- at least two domains
|
||||
- no unresolved tie for first place
|
||||
- the explicit boundary `不等于唯一真实出生分钟`
|
||||
|
||||
Use `medium` only when there are at least five dated events across at least two domains and the lead interval is clearly ahead.
|
||||
Use `low` when the evidence points somewhere but remains shallow or fragile.
|
||||
|
||||
## Optional Enhanced Gate
|
||||
|
||||
Use `高置信候选` only when all are visible and actually executed in the current user's environment:
|
||||
|
||||
- at least five dated events across at least two domains
|
||||
- a clear leading interval without a material tie
|
||||
- adapter status table with raw-result references
|
||||
- if used, separate visibility for `Vimshottari + Narayana`
|
||||
- if used, separate visibility for `Functional Benefic/Malefic`, relevant vargas, MEVG, Real Case Calibration, and holdout
|
||||
- no decisive conflict from any executed adapter
|
||||
|
||||
Any blocked, conflicting, or missing raw-evidence item caps the output at `manual_pattern_consensus`, `medium`, `low`, `parameter_sensitive`, or `blocked` as appropriate. `高置信候选` **不等于唯一真实出生分钟**.
|
||||
@@ -0,0 +1,70 @@
|
||||
# Interview Playbook
|
||||
|
||||
## Intake
|
||||
|
||||
Collect birth date, birthplace, timezone, known time/range, source of the time, confidence in that source, and the user's priority domain. Ask permission before collecting dated life events.
|
||||
|
||||
## Routes
|
||||
|
||||
### `range`
|
||||
|
||||
For a remembered time or bounded interval:
|
||||
|
||||
1. Restate the interval in clock time.
|
||||
2. Split it into `early / middle / late`.
|
||||
3. Ask 3-5 A/B/C/D questions across education, relocation, relationship, career, and recent learning/expression.
|
||||
4. Request dated events only in the strongest 2-3 domains.
|
||||
|
||||
### `block`
|
||||
|
||||
For `morning`, `afternoon`, `evening`, family recollections, or zodiac-hour style descriptions:
|
||||
|
||||
1. Convert the label into a stated coarse interval.
|
||||
2. Split that interval into `early / middle / late`.
|
||||
3. Ask the same domain questions.
|
||||
4. Request events from the leading domains only.
|
||||
|
||||
### `unknown`
|
||||
|
||||
For no usable time memory:
|
||||
|
||||
1. State that the first valid result can only be a broad block.
|
||||
2. Compare `morning / afternoon / evening / night` through high-signal domains.
|
||||
3. Do not refine the winning block until enough dated evidence exists.
|
||||
4. If one broad block leads, begin the next round by splitting only that block.
|
||||
|
||||
## Event Ledger
|
||||
|
||||
Use one row per event with:
|
||||
|
||||
- `id`
|
||||
- `domain`
|
||||
- `date`
|
||||
- `precision` (`day`, `month`, `year`)
|
||||
- `reliability` (`high`, `medium`, `low`)
|
||||
- `user wording`
|
||||
- `supports` (candidate labels helped by this event)
|
||||
- `conflicts` (candidate labels weakened by this event)
|
||||
|
||||
Confirm date precision instead of inventing a day.
|
||||
|
||||
## Question Rhythm
|
||||
|
||||
- First round: 3-5 high-information A/B/C/D questions.
|
||||
- Second round: ask only for dated events in the strongest domains.
|
||||
- Third round: ask only the next 1-3 events that could separate the top candidates.
|
||||
- Never collect a long autobiography before the first route decision.
|
||||
|
||||
## Stop Rules
|
||||
|
||||
Stop and report the current interval when any is true:
|
||||
|
||||
- fewer than three dated events
|
||||
- fewer than two domains
|
||||
- tied first-place candidates
|
||||
- user uncertainty is too high to map support/conflict reliably
|
||||
- an optional adapter was promised but cannot be executed and the user wants an audited result
|
||||
|
||||
## Final Wording
|
||||
|
||||
State: "当前最优结果是候选时间段,而不是已经确认的唯一出生分钟。临时代表时间仅用于下一轮验证与比较。"
|
||||
@@ -0,0 +1,271 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
SKILL = REPO_ROOT / "skills" / "jyotish-birth-time-rectification"
|
||||
if not SKILL.is_dir():
|
||||
SKILL = Path("/Users/wuyongnaren/.workbuddy/skills/jyotish-birth-time-rectification")
|
||||
|
||||
|
||||
def test_rectification_skill_resources_and_portable_contract_exist() -> None:
|
||||
skill_text = (SKILL / "SKILL.md").read_text(encoding="utf-8")
|
||||
for relative_path in (
|
||||
"references/main_repository_router.md",
|
||||
"references/interview_playbook.md",
|
||||
"references/evidence_thresholds.md",
|
||||
"references/api_reference.md",
|
||||
"references/manual_test_prompts.md",
|
||||
"references/testing_playbook.md",
|
||||
"references/adapter_integration_guide.md",
|
||||
"references/public_distribution_checklist.md",
|
||||
"assets/rectification_session_template.md",
|
||||
"scripts/example.py",
|
||||
):
|
||||
assert (SKILL / relative_path).is_file(), relative_path
|
||||
assert relative_path in skill_text
|
||||
|
||||
for required_term in (
|
||||
"standalone_core",
|
||||
"adapter_enhanced",
|
||||
"main_repository_enhanced",
|
||||
"range / block / unknown",
|
||||
"Vimshottari + Narayana",
|
||||
"Functional Benefic/Malefic",
|
||||
"MEVG",
|
||||
"Real Case Calibration",
|
||||
"候选时间段",
|
||||
"临时代表时间",
|
||||
"唯一真实出生分钟",
|
||||
"高置信候选",
|
||||
"Require no fixed repository path",
|
||||
"manual_test_prompts.md",
|
||||
"testing_playbook.md",
|
||||
"adapter_integration_guide.md",
|
||||
"public_distribution_checklist.md",
|
||||
):
|
||||
assert required_term in skill_text
|
||||
|
||||
assert "/Users/wuyongnaren/Documents/印度占星" not in skill_text
|
||||
|
||||
|
||||
def test_router_and_thresholds_define_portable_modes_and_caps() -> None:
|
||||
router = (SKILL / "references/main_repository_router.md").read_text(encoding="utf-8")
|
||||
for required_term in (
|
||||
"standalone_core",
|
||||
"adapter_enhanced",
|
||||
"main_repository_enhanced",
|
||||
"supports",
|
||||
"conflicts",
|
||||
"executed",
|
||||
"blocked",
|
||||
"not_applicable",
|
||||
):
|
||||
assert required_term in router
|
||||
assert "/Users/wuyongnaren/Documents/印度占星" not in router
|
||||
assert ".venv" not in router
|
||||
|
||||
thresholds = (SKILL / "references/evidence_thresholds.md").read_text(encoding="utf-8")
|
||||
assert "manual_pattern_consensus" in thresholds
|
||||
assert "高置信候选" in thresholds
|
||||
assert "不等于唯一真实出生分钟" in thresholds
|
||||
assert "standalone_core" in thresholds
|
||||
|
||||
|
||||
def test_template_and_api_reference_preserve_audit_and_portability() -> None:
|
||||
template = (SKILL / "assets/rectification_session_template.md").read_text(encoding="utf-8")
|
||||
for heading in (
|
||||
"Runtime mode",
|
||||
"supports",
|
||||
"conflicts",
|
||||
"Functional Benefic/Malefic (optional)",
|
||||
"External evidence / MEVG / Real Case (optional)",
|
||||
):
|
||||
assert heading in template
|
||||
|
||||
api_reference = (SKILL / "references/api_reference.md").read_text(encoding="utf-8")
|
||||
for term in (
|
||||
"route",
|
||||
"known_time",
|
||||
"known_block",
|
||||
"adapters",
|
||||
"repository_root",
|
||||
"main_repository_enhanced",
|
||||
"candidate_range_not_birth_time_truth",
|
||||
):
|
||||
assert term in api_reference
|
||||
assert "/Users/wuyongnaren/Documents/印度占星" not in api_reference
|
||||
|
||||
|
||||
def test_scaffold_runs_standalone_and_returns_candidate_only_receipt() -> None:
|
||||
request = {
|
||||
"route": "range",
|
||||
"known_time": {"start": "14:00", "end": "16:00"},
|
||||
"events": [
|
||||
{
|
||||
"id": "career-1",
|
||||
"domain": "career",
|
||||
"date": "2019-07",
|
||||
"precision": "month",
|
||||
"reliability": "high",
|
||||
"supports": ["middle", "late"],
|
||||
"conflicts": ["early"],
|
||||
"note": "工作结构变化后责任显著增加",
|
||||
},
|
||||
{
|
||||
"id": "relationship-1",
|
||||
"domain": "relationship",
|
||||
"date": "2016-10-03",
|
||||
"precision": "day",
|
||||
"reliability": "high",
|
||||
"supports": ["middle"],
|
||||
"conflicts": ["early"],
|
||||
"note": "关系进入与承诺加强",
|
||||
},
|
||||
{
|
||||
"id": "relocation-1",
|
||||
"domain": "relocation",
|
||||
"date": "2014",
|
||||
"precision": "year",
|
||||
"reliability": "medium",
|
||||
"supports": ["late"],
|
||||
"conflicts": [],
|
||||
"note": "离乡发展",
|
||||
},
|
||||
],
|
||||
}
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(SKILL / "scripts/example.py")],
|
||||
input=json.dumps(request),
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
receipt = json.loads(result.stdout)
|
||||
assert receipt["claim_status"] == "candidate_range_not_birth_time_truth"
|
||||
assert receipt["summary"]["claim_status"] == "candidate_range_not_birth_time_truth"
|
||||
assert receipt["runtime_mode"] == "standalone_core"
|
||||
assert receipt["summary"]["confidence_label"] in {"medium", "manual_pattern_consensus"}
|
||||
assert receipt["candidate_result"]["candidate_range"]["representative_time"]
|
||||
|
||||
|
||||
def test_scaffold_can_report_adapter_enhanced_without_fixed_repo_path() -> None:
|
||||
request = {
|
||||
"route": "unknown",
|
||||
"events": [
|
||||
{
|
||||
"id": "career-1",
|
||||
"domain": "career",
|
||||
"date": "2020-05",
|
||||
"precision": "month",
|
||||
"reliability": "high",
|
||||
"supports": ["afternoon"],
|
||||
"conflicts": ["night"],
|
||||
"note": "职业方向明显切换",
|
||||
},
|
||||
{
|
||||
"id": "relationship-1",
|
||||
"domain": "relationship",
|
||||
"date": "2018-09",
|
||||
"precision": "month",
|
||||
"reliability": "high",
|
||||
"supports": ["afternoon"],
|
||||
"conflicts": ["morning"],
|
||||
"note": "稳定关系建立",
|
||||
},
|
||||
{
|
||||
"id": "education-1",
|
||||
"domain": "education",
|
||||
"date": "2012",
|
||||
"precision": "year",
|
||||
"reliability": "medium",
|
||||
"supports": ["afternoon"],
|
||||
"conflicts": [],
|
||||
"note": "学习方向变化",
|
||||
},
|
||||
],
|
||||
"adapters": [
|
||||
{
|
||||
"name": "user_vimshottari_engine",
|
||||
"type": "calculator",
|
||||
"location": "./tools/rectify.py",
|
||||
"status": "executed",
|
||||
"summary": "Vimshottari and Narayana both prefer afternoon",
|
||||
"raw_result_ref": "outputs/rectify-afternoon.json",
|
||||
}
|
||||
],
|
||||
}
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(SKILL / "scripts/example.py")],
|
||||
input=json.dumps(request),
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
receipt = json.loads(result.stdout)
|
||||
assert receipt["runtime_mode"] == "adapter_enhanced"
|
||||
assert receipt["summary"]["confidence_label"] == "single_adapter_support"
|
||||
assert receipt["audit_appendix"]["adapter_statuses"][0]["status"] == "executed"
|
||||
|
||||
|
||||
def test_scaffold_main_repository_enhanced_can_execute_with_minimal_valid_payload() -> None:
|
||||
request = {
|
||||
"runtime_mode": "main_repository_enhanced",
|
||||
"repository_root": "/Users/wuyongnaren/Documents/印度占星",
|
||||
"request": {
|
||||
"birth_date": "1993-04-17",
|
||||
"start_time": "14:29",
|
||||
"end_time": "14:31",
|
||||
"lat": 36.683333,
|
||||
"lon": 114.35,
|
||||
"tz": 8,
|
||||
"events": [
|
||||
{"id": "edu-1", "domain": "education", "date": "2011-09", "precision": "month"},
|
||||
{"id": "career-1", "domain": "career", "date": "2019-07-01", "precision": "day"},
|
||||
{"id": "rel-1", "domain": "relationship", "date": "2021", "precision": "year"}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(SKILL / "scripts/example.py")],
|
||||
input=json.dumps(request),
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
receipt = json.loads(result.stdout)
|
||||
assert receipt["runtime_mode"] == "main_repository_enhanced"
|
||||
assert receipt["claim_status"] == "candidate_range_not_birth_time_truth"
|
||||
assert receipt["summary"]["claim_status"] == "candidate_range_not_birth_time_truth"
|
||||
|
||||
|
||||
def test_scaffold_main_repository_enhanced_returns_structured_block_when_fields_missing() -> None:
|
||||
request = {
|
||||
"runtime_mode": "main_repository_enhanced",
|
||||
"repository_root": "/Users/wuyongnaren/Documents/印度占星",
|
||||
"request": {
|
||||
"events": [
|
||||
{
|
||||
"date": "2020-05",
|
||||
"category": "career",
|
||||
"description": "职业方向明显切换",
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(SKILL / "scripts/example.py")],
|
||||
input=json.dumps(request),
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
receipt = json.loads(result.stdout)
|
||||
assert receipt["runtime_mode"] == "main_repository_enhanced"
|
||||
assert receipt["claim_status"] == "candidate_range_not_birth_time_truth"
|
||||
assert receipt["candidate_result"]["status"] == "blocked"
|
||||
assert receipt["candidate_result"]["reason"] == "missing_required_fields"
|
||||
assert "birth_date" in receipt["candidate_result"]["missing_fields"]
|
||||
Reference in New Issue
Block a user