Harden high-rigor Jyotish timing workflow
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Tajika Einstein 1905 Copy-Ready Checklist
|
||||
|
||||
Packet:
|
||||
`references/oracle/artifacts/pending_packets/external_template_einstein_varshaphala_1905_lahiri.json`
|
||||
|
||||
Steve Jobs sample:
|
||||
`references/oracle/artifacts/pending_packets/external_template_steve_jobs_varshaphala_1984_lahiri_pyjhora_20260627.json`
|
||||
|
||||
Use one external source only:
|
||||
- `JHora`
|
||||
- `PyJHora`
|
||||
- printed Tajika/Varshaphala example
|
||||
|
||||
Do not use local `scripts/varshaphala.py` output as evidence.
|
||||
|
||||
## Copy Steve Jobs Pattern Directly
|
||||
|
||||
Copy the same writing pattern for:
|
||||
|
||||
- `status`: set to `external_verified` only after all fields below are filled
|
||||
- `metadata.tool_name`
|
||||
- `metadata.tool_version_or_url`
|
||||
- `metadata.capture_date`
|
||||
- `metadata.source_artifact`
|
||||
- `metadata.operator_note`
|
||||
- `target.source_artifact`
|
||||
|
||||
Recommended metadata pattern:
|
||||
|
||||
- `metadata.tool_name`: `PyJHora` or `JHora`
|
||||
- `metadata.tool_version_or_url`: version string or source citation
|
||||
- `metadata.capture_date`: `YYYY-MM-DD`
|
||||
- `metadata.source_artifact`: `references/oracle/artifacts/<your-evidence-file>`
|
||||
- `metadata.operator_note`: note ayanamsa, node mode, timezone, solar-return convention, and any workaround
|
||||
- `target.source_artifact`: same artifact path as above
|
||||
|
||||
## Must Fill From External Source
|
||||
|
||||
These values must be copied from the external annual-chart source, not inferred locally:
|
||||
|
||||
- `target.solar_return_datetime`
|
||||
- `target.varsha_lagna_deg`
|
||||
- `target.muntha_sign`
|
||||
- `target.year_lord`
|
||||
- `target.mudda_dasha_first_lord`
|
||||
- `target.sahams.punya_saham`
|
||||
- `target.sahams.rajya_saham`
|
||||
- `target.sahams.vivah_saham`
|
||||
- `target.tajika_yogas`
|
||||
|
||||
## Fast Fill Order
|
||||
|
||||
1. Fill metadata first:
|
||||
- `metadata.tool_name`
|
||||
- `metadata.tool_version_or_url`
|
||||
- `metadata.capture_date`
|
||||
- `metadata.source_artifact`
|
||||
- `metadata.operator_note`
|
||||
|
||||
2. Fill annual header:
|
||||
- `target.solar_return_datetime`
|
||||
- `target.varsha_lagna_deg`
|
||||
|
||||
3. Fill annual rulership:
|
||||
- `target.muntha_sign`
|
||||
- `target.year_lord`
|
||||
- `target.mudda_dasha_first_lord`
|
||||
|
||||
4. Fill Sahams:
|
||||
- `target.sahams.punya_saham`
|
||||
- `target.sahams.rajya_saham`
|
||||
- `target.sahams.vivah_saham`
|
||||
|
||||
5. Fill yoga block:
|
||||
- `target.tajika_yogas`
|
||||
|
||||
6. Set:
|
||||
- `target.source_artifact`
|
||||
- `status = external_verified`
|
||||
|
||||
## Minimal Screen / Output Capture
|
||||
|
||||
Capture only these:
|
||||
|
||||
1. Settings / source header
|
||||
2. Solar return datetime
|
||||
3. Varsha Lagna
|
||||
4. Muntha + Year Lord
|
||||
5. First Mudda Dasha lord
|
||||
6. Sahams block
|
||||
7. Tajika Yogas block
|
||||
|
||||
## Final Apply / Validate
|
||||
|
||||
```bash
|
||||
python3 scripts/tajika_annual_oracle_queue.py \
|
||||
--oracle-file references/oracle/tajika_annual_oracle_cases.json \
|
||||
--apply-packet references/oracle/artifacts/pending_packets/external_template_einstein_varshaphala_1905_lahiri.json \
|
||||
--format json
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 scripts/tajika_annual_benchmark_dashboard.py \
|
||||
--oracle-file references/oracle/tajika_annual_oracle_cases.json \
|
||||
--format json
|
||||
```
|
||||
@@ -0,0 +1,216 @@
|
||||
# Tajika Einstein 1905 Field Copy Template
|
||||
|
||||
目标 packet:
|
||||
`references/oracle/artifacts/pending_packets/external_template_einstein_varshaphala_1905_lahiri.json`
|
||||
|
||||
已完成样板:
|
||||
`references/oracle/artifacts/pending_packets/external_template_steve_jobs_varshaphala_1984_lahiri_pyjhora_20260627.json`
|
||||
|
||||
用途:
|
||||
- 给你或副手直接照抄字段结构
|
||||
- 只替换 Einstein 1905 对应的外部真值
|
||||
- 尽量不思考格式, 只做复制和填空
|
||||
|
||||
---
|
||||
|
||||
## 1. 可直接照抄的整体填写顺序
|
||||
|
||||
1. 先复制 Steve Jobs packet 的 `metadata` 写法
|
||||
2. 再填 Einstein 1905 的外部年盘真值
|
||||
3. 最后把 `status` 改成 `external_verified`
|
||||
|
||||
---
|
||||
|
||||
## 2. 逐字段复制模板
|
||||
|
||||
把下面整段当作填空卡使用:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "external_verified",
|
||||
"metadata": {
|
||||
"tool_name": "<JHora or PyJHora>",
|
||||
"tool_version_or_url": "<version string or citation>",
|
||||
"capture_date": "<YYYY-MM-DD>",
|
||||
"source_artifact": "references/oracle/artifacts/<artifact-file>",
|
||||
"ayanamsa": "lahiri",
|
||||
"node_mode": "mean",
|
||||
"timezone": "UTC+00:53",
|
||||
"annual_system": "Varshaphala/Tajika",
|
||||
"target_year": 1905,
|
||||
"operator_note": "<short note: source, solar-return convention, timezone/DST handling, workaround if any>"
|
||||
},
|
||||
"target_placeholders": {
|
||||
"target.solar_return_datetime": "<copy from annual chart header>",
|
||||
"target.varsha_lagna_deg": <absolute zodiac degree>,
|
||||
"target.muntha_sign": "<sign name>",
|
||||
"target.year_lord": "<planet name>",
|
||||
"target.mudda_dasha_first_lord": "<planet name>",
|
||||
"target.sahams.punya_saham": <absolute zodiac degree>,
|
||||
"target.sahams.rajya_saham": <absolute zodiac degree>,
|
||||
"target.sahams.vivah_saham": <absolute zodiac degree>,
|
||||
"target.tajika_yogas": "<copy exact yoga block structure from source>",
|
||||
"target.source_artifact": "references/oracle/artifacts/<artifact-file>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 哪些字段直接照 Steve Jobs 抄格式
|
||||
|
||||
这些字段只需要抄格式, 不需要重新想写法:
|
||||
|
||||
- `status`
|
||||
- `metadata.tool_name`
|
||||
- `metadata.tool_version_or_url`
|
||||
- `metadata.capture_date`
|
||||
- `metadata.source_artifact`
|
||||
- `metadata.operator_note`
|
||||
- `metadata.ayanamsa`
|
||||
- `metadata.annual_system`
|
||||
- `metadata.target_year`
|
||||
- `target.source_artifact`
|
||||
|
||||
建议直接套这个写法:
|
||||
|
||||
```json
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora <version> isolated /tmp black-box run",
|
||||
"capture_date": "<YYYY-MM-DD>",
|
||||
"source_artifact": "references/oracle/artifacts/<artifact-file>",
|
||||
"ayanamsa": "lahiri",
|
||||
"node_mode": "mean",
|
||||
"timezone": "UTC+00:53",
|
||||
"annual_system": "Varshaphala/Tajika",
|
||||
"target_year": 1905,
|
||||
"operator_note": "Black-box annual output from <tool/source>. External evidence only; local annual engine output not used. Solar-return convention: <fill>. Timezone/DST handling: <fill>. <optional workaround note>"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 哪些字段必须从外部源逐个抄
|
||||
|
||||
这些值禁止本地推断:
|
||||
|
||||
- `target.solar_return_datetime`
|
||||
- `target.varsha_lagna_deg`
|
||||
- `target.muntha_sign`
|
||||
- `target.year_lord`
|
||||
- `target.mudda_dasha_first_lord`
|
||||
- `target.sahams.punya_saham`
|
||||
- `target.sahams.rajya_saham`
|
||||
- `target.sahams.vivah_saham`
|
||||
- `target.tajika_yogas`
|
||||
|
||||
---
|
||||
|
||||
## 5. 逐字段抄写提示
|
||||
|
||||
### A. metadata
|
||||
|
||||
```json
|
||||
"tool_name": "PyJHora"
|
||||
```
|
||||
- 填你实际使用的工具名
|
||||
|
||||
```json
|
||||
"tool_version_or_url": "PyJHora <version> isolated /tmp black-box run"
|
||||
```
|
||||
- 直接抄 Steve Jobs 文风
|
||||
- 如果是 JHora, 改成 JHora 对应版本说明
|
||||
|
||||
```json
|
||||
"capture_date": "2026-06-29"
|
||||
```
|
||||
- 填今天真实采集日期
|
||||
|
||||
```json
|
||||
"source_artifact": "references/oracle/artifacts/<artifact-file>"
|
||||
```
|
||||
- 填你保存的 stdout / 截图 / 引文文件
|
||||
|
||||
```json
|
||||
"operator_note": "Black-box annual output from <tool/source>. External evidence only; local annual engine output not used. Solar-return convention: <fill>. Timezone/DST handling: <fill>. <optional workaround note>"
|
||||
```
|
||||
- 这句可以直接复制
|
||||
- 只替换 `<fill>`
|
||||
|
||||
### B. annual header
|
||||
|
||||
```json
|
||||
"target.solar_return_datetime": "<copy exact timestamp with offset>"
|
||||
```
|
||||
- 从年盘抬头直接抄
|
||||
|
||||
```json
|
||||
"target.varsha_lagna_deg": <number>
|
||||
```
|
||||
- 抄绝对黄经
|
||||
- 如果外部只给星座+度分秒, 先换算后再填
|
||||
|
||||
### C. annual rulership
|
||||
|
||||
```json
|
||||
"target.muntha_sign": "<sign>"
|
||||
"target.year_lord": "<planet>"
|
||||
"target.mudda_dasha_first_lord": "<planet>"
|
||||
```
|
||||
|
||||
### D. sahams
|
||||
|
||||
```json
|
||||
"target.sahams.punya_saham": <number>
|
||||
"target.sahams.rajya_saham": <number>
|
||||
"target.sahams.vivah_saham": <number>
|
||||
```
|
||||
- 统一填绝对黄经
|
||||
|
||||
### E. tajika_yogas
|
||||
|
||||
```json
|
||||
"target.tajika_yogas": {
|
||||
"<copy exact source structure here>": null
|
||||
}
|
||||
```
|
||||
- 最省事方法:
|
||||
1. 直接照外部源标签抄
|
||||
2. 如果是 PyJHora stdout, 尽量保持与 Steve Jobs 样板同结构
|
||||
3. 不要翻译成我们本地解释层术语
|
||||
|
||||
### F. artifact echo
|
||||
|
||||
```json
|
||||
"target.source_artifact": "references/oracle/artifacts/<artifact-file>"
|
||||
```
|
||||
- 与 `metadata.source_artifact` 保持一致
|
||||
|
||||
---
|
||||
|
||||
## 6. 最短实操法
|
||||
|
||||
最快方法不是从空模板填, 而是:
|
||||
|
||||
1. 打开 Steve Jobs packet
|
||||
2. 复制它的 `metadata` 和 `target_placeholders` 结构
|
||||
3. 仅替换 Einstein 1905 对应值
|
||||
4. 保存到 Einstein packet
|
||||
|
||||
---
|
||||
|
||||
## 7. 填完后直接执行
|
||||
|
||||
```bash
|
||||
python3 scripts/tajika_annual_oracle_queue.py \
|
||||
--oracle-file references/oracle/tajika_annual_oracle_cases.json \
|
||||
--apply-packet references/oracle/artifacts/pending_packets/external_template_einstein_varshaphala_1905_lahiri.json \
|
||||
--format json
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 scripts/tajika_annual_benchmark_dashboard.py \
|
||||
--oracle-file references/oracle/tajika_annual_oracle_cases.json \
|
||||
--format json
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"status": "external_verified",
|
||||
"metadata": {
|
||||
"tool_name": "PyJHora",
|
||||
"tool_version_or_url": "PyJHora <version> isolated /tmp black-box run",
|
||||
"capture_date": "2026-06-29",
|
||||
"source_artifact": "references/oracle/artifacts/<artifact-file>",
|
||||
"ayanamsa": "lahiri",
|
||||
"node_mode": "mean",
|
||||
"timezone": "UTC+00:53",
|
||||
"annual_system": "Varshaphala/Tajika",
|
||||
"target_year": 1905,
|
||||
"operator_note": "Black-box annual output from <tool/source>. External evidence only; local annual engine output not used. Solar-return convention: <fill>. Timezone/DST handling: <fill>. <optional workaround note>"
|
||||
},
|
||||
"target_placeholders": {
|
||||
"target.solar_return_datetime": "<copy exact timestamp with offset>",
|
||||
"target.varsha_lagna_deg": <absolute zodiac degree>,
|
||||
"target.muntha_sign": "<sign name>",
|
||||
"target.year_lord": "<planet name>",
|
||||
"target.mudda_dasha_first_lord": "<planet name>",
|
||||
"target.sahams.punya_saham": <absolute zodiac degree>,
|
||||
"target.sahams.rajya_saham": <absolute zodiac degree>,
|
||||
"target.sahams.vivah_saham": <absolute zodiac degree>,
|
||||
"target.tajika_yogas": {
|
||||
"<copy exact yoga labels from external source>": null
|
||||
},
|
||||
"target.source_artifact": "references/oracle/artifacts/<artifact-file>"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
# Tajika Einstein 1905 Packet Paste Instructions
|
||||
|
||||
原 packet:
|
||||
`references/oracle/artifacts/pending_packets/external_template_einstein_varshaphala_1905_lahiri.json`
|
||||
|
||||
可直接粘贴块:
|
||||
`docs/benchmark/tajika_einstein_1905_packet_paste_block.jsonc`
|
||||
|
||||
## 最省力用法
|
||||
|
||||
不要从头编辑整个 packet。
|
||||
|
||||
直接做这 4 步:
|
||||
|
||||
1. 打开原 packet
|
||||
2. 找到并替换这 3 段:
|
||||
- 顶层 `status`
|
||||
- `metadata`
|
||||
- `target_placeholders`
|
||||
3. 把 `tajika_einstein_1905_packet_paste_block.jsonc` 里的对应内容整段复制进去
|
||||
4. 只替换 `<...>` 占位符
|
||||
|
||||
## 你真正需要改的只有这些占位符
|
||||
|
||||
- `<version>`
|
||||
- `<artifact-file>`
|
||||
- `<tool/source>`
|
||||
- `<fill>`
|
||||
- `<copy exact timestamp with offset>`
|
||||
- `<absolute zodiac degree>`
|
||||
- `<sign name>`
|
||||
- `<planet name>`
|
||||
- `<copy exact yoga labels from external source>`
|
||||
|
||||
## 注意
|
||||
|
||||
- `jsonc` 文件只是为了让人更方便复制, 占位符替换完后, 最终落回原 packet 时必须保持合法 JSON
|
||||
- `target.source_artifact` 与 `metadata.source_artifact` 要一致
|
||||
- `target.tajika_yogas` 优先照外部工具原样抄, 不要翻译成本地解释术语
|
||||
- 如果外部工具不是 `PyJHora`, 只改 `tool_name` 和 `tool_version_or_url`, 其他结构照抄即可
|
||||
|
||||
## 填完立刻执行
|
||||
|
||||
```bash
|
||||
python3 scripts/tajika_annual_oracle_queue.py \
|
||||
--oracle-file references/oracle/tajika_annual_oracle_cases.json \
|
||||
--apply-packet references/oracle/artifacts/pending_packets/external_template_einstein_varshaphala_1905_lahiri.json \
|
||||
--format json
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 scripts/tajika_annual_benchmark_dashboard.py \
|
||||
--oracle-file references/oracle/tajika_annual_oracle_cases.json \
|
||||
--format json
|
||||
```
|
||||
@@ -0,0 +1,285 @@
|
||||
# Full Reading Performance And VedAstro Ingestion Strategy (2026-06-30)
|
||||
|
||||
## Scope
|
||||
|
||||
This note records one strict round of:
|
||||
|
||||
1. whole-repo workflow review,
|
||||
2. external-source grounding,
|
||||
3. real `full-reading` stage timing collection,
|
||||
4. API strategy changes based on measured bottlenecks.
|
||||
|
||||
It is intended to prevent future work from drifting back into intuition-only performance decisions.
|
||||
|
||||
## High-Level Conclusion
|
||||
|
||||
The current project is **not bottlenecked by local Jyotish computation**.
|
||||
|
||||
The dominant runtime cost for real user-facing `full-reading` is:
|
||||
|
||||
1. `vedastro_official_snapshot`
|
||||
2. `vedastro_main_entry_overview`
|
||||
|
||||
Therefore, the highest-value optimization order is:
|
||||
|
||||
1. preserve the existing local-native calculation path,
|
||||
2. reuse existing `vedastro_service_adapter` request caching,
|
||||
3. add **API-level final chart response caching** for the normal `/api/chart` path,
|
||||
4. keep `high_rigor_workflow` explicitly marked as the lane that should move toward queue/async execution,
|
||||
5. do **not** spend engineering cycles micro-optimizing local Dasha/Varga/Yoga layers before fixing official-evidence ingestion cost.
|
||||
|
||||
## Repo Facts Confirmed
|
||||
|
||||
### Active closure lanes
|
||||
|
||||
`docs/research/ACTIVE_FRONTS.md` keeps work constrained to four fronts:
|
||||
|
||||
1. Relationship adjudicator closure
|
||||
2. Vimsopaka + functional-role closure
|
||||
3. Oracle closure batch
|
||||
4. VedAstro strict ingestion
|
||||
|
||||
This means performance/productization work should be treated as support for the fourth lane, not as an unrelated new product surface.
|
||||
|
||||
### Existing reusable building blocks
|
||||
|
||||
The repo already contains the main pieces required for an official-first architecture:
|
||||
|
||||
- `scripts/vedastro_service_adapter.py`
|
||||
- `scripts/vedastro_evidence_orchestrator.py`
|
||||
- `scripts/vedastro_priority.py`
|
||||
- `scripts/jyotish_engine.py`
|
||||
- `scripts/jyotish_api_server.py`
|
||||
- `mcp_server.py`
|
||||
|
||||
The correct strategy is to **reuse and tighten** these boundaries, not to create a second orchestration stack.
|
||||
|
||||
## External-Source Grounding
|
||||
|
||||
### Python performance measurement
|
||||
|
||||
The Python standard library documents `time.perf_counter()` as the high-resolution timer appropriate for measuring short durations and performance intervals.
|
||||
Source: [Python `time` documentation](https://docs.python.org/3/library/time.html)
|
||||
|
||||
The Python profiling documentation distinguishes deterministic profiling (`cProfile` / `profile`) from ad hoc guessing and supports evidence-first investigation of runtime cost.
|
||||
Source: [Python profiling documentation](https://docs.python.org/3/library/profile.html)
|
||||
|
||||
### Task-queue direction
|
||||
|
||||
FastAPI documents `BackgroundTasks` for simple post-response work, but this pattern is not a substitute for durable heavy workflow execution when requests are long-running.
|
||||
Source: [FastAPI BackgroundTasks](https://fastapi.tiangolo.com/tutorial/background-tasks/)
|
||||
|
||||
RQ documents a Redis-backed background job queue suitable for Python jobs that should leave the request path.
|
||||
Source: [RQ documentation](https://python-rq.org/docs/)
|
||||
|
||||
### Interpretation for this project
|
||||
|
||||
These sources support a two-layer discipline:
|
||||
|
||||
1. first instrument real runtime stages with in-code timers,
|
||||
2. then move only the truly expensive request-path layers to cache or queue.
|
||||
|
||||
For this repository, that means:
|
||||
|
||||
- measure `full-reading` stages before architectural change,
|
||||
- keep local chart math synchronous,
|
||||
- protect heavy VedAstro official ingestion behind cache and later queue/async boundaries.
|
||||
|
||||
## Real Timing Evidence
|
||||
|
||||
### Sample used
|
||||
|
||||
Real sample run:
|
||||
|
||||
- birth: `REDACTED_DATE REDACTED_TIME`
|
||||
- location: `36.4467, 114.2`
|
||||
- tz: `UTC+8`
|
||||
- reference date: `2026-06-30`
|
||||
|
||||
Command:
|
||||
|
||||
```bash
|
||||
python3 scripts/jyotish_engine.py full-reading \
|
||||
--year REDACTED_YEAR --month 4 --day 17 \
|
||||
--hour 14 --minute 49 \
|
||||
--lat 36.4467 --lon 114.2 --tz 8 \
|
||||
--today 2026-06-30 \
|
||||
--transit-date 2026-06-30 \
|
||||
--profile-stages
|
||||
```
|
||||
|
||||
### First measured run
|
||||
|
||||
Observed summary:
|
||||
|
||||
- total elapsed: `181.0154s`
|
||||
- modules: `57`
|
||||
- errors: `0`
|
||||
|
||||
Stage timings:
|
||||
|
||||
- `core_chart_and_setup`: `0.0036s`
|
||||
- `dasha_and_core_varga_stack`: `0.8380s`
|
||||
- `advanced_interpretation_and_timing_layers`: `0.4753s`
|
||||
- `dynamic_hooks`: `0.0001s`
|
||||
- `vedastro_official_snapshot`: `133.7938s`
|
||||
- `strict_contracts`: `3.5107s`
|
||||
- `vedastro_main_entry_overview`: `41.5806s`
|
||||
- `guided_topics`: `0.0003s`
|
||||
- `ai_prompt_pack`: `0.8122s`
|
||||
|
||||
### Second measured run with existing caches warmed
|
||||
|
||||
Same command, same birth payload, same reference date.
|
||||
|
||||
Observed stage timings:
|
||||
|
||||
- `core_chart_and_setup`: `0.0029s`
|
||||
- `dasha_and_core_varga_stack`: `0.9145s`
|
||||
- `advanced_interpretation_and_timing_layers`: `0.5279s`
|
||||
- `vedastro_official_snapshot`: `112.0435s`
|
||||
- `strict_contracts`: `2.9865s`
|
||||
- `vedastro_main_entry_overview`: `0.0735s`
|
||||
- `guided_topics`: `0.0003s`
|
||||
- `ai_prompt_pack`: `0.6211s`
|
||||
|
||||
### What the second run proves
|
||||
|
||||
The second run proves two different things:
|
||||
|
||||
1. `vedastro_main_entry_overview` is already benefiting from existing lower-level caching.
|
||||
2. `vedastro_official_snapshot` remains overwhelmingly expensive even after a warm rerun.
|
||||
|
||||
So the adapter cache is **useful but insufficient** at the user-visible workflow level.
|
||||
|
||||
## Root-Cause Interpretation
|
||||
|
||||
### What is not the bottleneck
|
||||
|
||||
The following are not the dominant latency problem:
|
||||
|
||||
- local Dasha
|
||||
- local Varga
|
||||
- Yoga / Ashtakavarga / Shadbala orchestration
|
||||
- strict workflow contract assembly
|
||||
- prompt pack generation
|
||||
|
||||
All of these are materially small relative to official evidence ingestion.
|
||||
|
||||
### What is the bottleneck
|
||||
|
||||
The dominant cost is the official evidence layer itself, especially:
|
||||
|
||||
- `run_official_full_snapshot_for_case(...)`
|
||||
- official full-snapshot section fanout and retry path
|
||||
|
||||
The repo also shows a second pattern difference:
|
||||
|
||||
- CLI `full-reading` attaches overview by directly calling `run_range_scan_for_case(...)`
|
||||
- API chart attaches overview through `orchestrate_vedastro_evidence(...)`, which already bundles official full snapshot and route-scoped scans
|
||||
|
||||
This means there are still opportunities to reduce duplication by reusing higher-level official results more aggressively.
|
||||
|
||||
## Strategy Decision
|
||||
|
||||
### Decision A: Normal chart path gets API-level final result caching
|
||||
|
||||
Why:
|
||||
|
||||
- `/api/chart` is the normal synchronous user path.
|
||||
- It packages chart + official evidence + prompt pack together.
|
||||
- The user cares about final response latency, not just adapter request latency.
|
||||
|
||||
Therefore a **final chart response cache** is justified at API level.
|
||||
|
||||
### Decision B: High-rigor workflow is the queue/async candidate lane
|
||||
|
||||
Why:
|
||||
|
||||
- `high_rigor_workflow` composes chart + rectification + historical backtest + thematic report.
|
||||
- It is heavier than normal chart consumption by design.
|
||||
- This lane is the correct place to expose queue/async execution strategy in future work.
|
||||
|
||||
### Decision C: Do not optimize local Jyotish math first
|
||||
|
||||
Why:
|
||||
|
||||
- measured evidence shows local-native layers are cheap relative to official ingestion.
|
||||
- optimizing them first would spend effort where the user does not feel the delay.
|
||||
|
||||
## Implementation Landed In This Round
|
||||
|
||||
### `scripts/jyotish_engine.py`
|
||||
|
||||
Landed:
|
||||
|
||||
- stage timing instrumentation for `full-reading`
|
||||
- `--profile-stages` CLI flag
|
||||
- summary output containing:
|
||||
- `stage_timing_enabled`
|
||||
- `stage_timings`
|
||||
- `slowest_stages`
|
||||
|
||||
This is now the baseline tool for future performance decisions.
|
||||
|
||||
### `scripts/jyotish_api_server.py`
|
||||
|
||||
Landed:
|
||||
|
||||
- API chart final-response cache helpers:
|
||||
- `_build_api_chart_cache_payload`
|
||||
- `_api_chart_cache_key`
|
||||
- `_load_api_chart_response_cache`
|
||||
- `_store_api_chart_response_cache`
|
||||
- runtime cache metadata attached to cached responses:
|
||||
- `scope`
|
||||
- `cache_hit`
|
||||
- `cache_key`
|
||||
- `cache_created_at`
|
||||
- `cache_expires_at`
|
||||
- `cache_ttl_seconds`
|
||||
- `_compute_chart(...)` now checks API-level cache before recomputing
|
||||
- `_high_rigor_workflow_plan_only(...)` now exposes execution strategy:
|
||||
- normal chart path uses sync chart response cache
|
||||
- high-rigor lane is the queue recommendation target
|
||||
|
||||
### Tests landed
|
||||
|
||||
Added/updated tests in `tests/test_api_server_security.py` to verify:
|
||||
|
||||
- API chart response cache contract exists and round-trips
|
||||
- cache key changes with VedAstro runtime state
|
||||
- high-rigor plan-only output explicitly surfaces chart-cache and queue strategy
|
||||
|
||||
## What Is Still Not Closed
|
||||
|
||||
1. The current official full snapshot still does not have an equivalent high-level final cache strong enough to collapse the `112s+` cost on rerun.
|
||||
2. `high_rigor_workflow` exposes queue recommendation metadata, but no durable job runner or polling endpoint is landed yet.
|
||||
3. CLI `full-reading` and API chart still do not fully unify around one deduplicated “official snapshot + overview reuse” path.
|
||||
|
||||
## Recommended Next Implementation Order
|
||||
|
||||
1. Add **official full snapshot result caching** at a higher semantic level than raw request caching.
|
||||
2. Make API chart reuse that official full snapshot cache before rebuilding the same evidence package.
|
||||
3. Introduce a minimal asynchronous lane for `high_rigor_workflow`:
|
||||
- enqueue request
|
||||
- return job id
|
||||
- poll result
|
||||
- keep synchronous mode for debug/local use
|
||||
4. Only after those are landed, decide whether deeper profiler work is still needed.
|
||||
|
||||
## Honesty Boundary
|
||||
|
||||
This document does **not** claim:
|
||||
|
||||
- that the entire full-reading path is now fast,
|
||||
- that all VedAstro-heavy routes are production-grade for synchronous use,
|
||||
- that queue/async execution is already complete,
|
||||
- that local and official evidence are fully deduplicated.
|
||||
|
||||
What it does claim is narrower and evidenced:
|
||||
|
||||
- stage timing is now real and reproducible,
|
||||
- the main bottleneck has been identified with measured data,
|
||||
- API-level final chart response caching is now partially landed,
|
||||
- the repo now has a documented, evidence-backed strategy for the next optimization steps.
|
||||
@@ -0,0 +1,115 @@
|
||||
# 2026-06 Local Drafts Disposition
|
||||
|
||||
Date: 2026-07-01
|
||||
|
||||
Purpose: freeze the governance boundary for `docs/research/local_drafts/2026-06` without deleting or moving the drafts. The draft directory is evidence and recovery memory, not runtime truth. Do not move or delete files in this pass.
|
||||
|
||||
Source-of-truth rule:
|
||||
|
||||
- Main repo truth stays in `SKILL.md`, `AGENTS.md`, `references/`, `scripts/`, `tests/`, and canonical `docs/research/*.md`.
|
||||
- `.workbuddy` is a historical distribution mirror and recovery reference only. It must not reverse-sync over this repo, and runtime code must not import from it.
|
||||
- A `promote` row means the draft should be converted into a canonical research note, benchmark artifact, test, or source change before it drives implementation.
|
||||
- A `reference-only` row means it can be cited as background after re-anchoring to current code and licenses.
|
||||
- An `archive` row means it should stay out of current implementation flow unless a future audit explicitly reopens it.
|
||||
|
||||
## Disposition Table
|
||||
|
||||
| Disposition | Draft | Reason |
|
||||
|---|---|---|
|
||||
| reference-only | antigravity_round31_api_completion_top50_2026_06_26.md | Older API exposure wishlist; re-check against current `jyotish_api_server.py` before reuse. |
|
||||
| promote | antigravity_round31_ayanamsa_ephemeris_timezone_risk_matrix_2026_06_26.md | Core accuracy boundary for ayanamsa, ephemeris, timezone and node-mode evidence. |
|
||||
| reference-only | antigravity_round31_cli_completion_top50_2026_06_26.md | Useful CLI wishlist, but many items are superseded by later tests and active plans. |
|
||||
| reference-only | antigravity_round31_cloud_sync_whitelist_final_draft_2026_06_26.md | Distribution-sync background only; current rule is no reverse contamination from `.workbuddy`. |
|
||||
| archive | antigravity_round31_codex_round32_top180_2026_06_26.md | Broad execution board superseded by later narrower closure plans. |
|
||||
| promote | antigravity_round31_copy_allowed_assets_top80_2026_06_26.md | License-safe reuse candidates need canonical whitelist linkage before code migration. |
|
||||
| promote | antigravity_round31_external_oracle_closure_top60_2026_06_26.md | External oracle closure remains a high-rigor blocker and should feed oracle queues. |
|
||||
| promote | antigravity_round31_extra_astronomical_edge_cases_polar_regions_2026_06_26.md | Polar and astronomical edge cases affect correctness and confidence boundaries. |
|
||||
| reference-only | antigravity_round31_extra_internationalization_i18n_readiness_2026_06_26.md | Product-localization idea; not a current strict accuracy front. |
|
||||
| reference-only | antigravity_round31_extra_offline_fallback_mode_2026_06_26.md | Frontend resilience idea; keep outside current engine-truth work. |
|
||||
| reference-only | antigravity_round31_extra_performance_profiling_memory_leaks_2026_06_26.md | Performance background; only promote after API payload profiling is reopened. |
|
||||
| archive | antigravity_round31_final_execution_board_2026_06_26.md | Round board superseded by current active fronts. |
|
||||
| reference-only | antigravity_round31_frontend_completion_top50_2026_06_26.md | UI exposure backlog, not current runtime truth. |
|
||||
| promote | antigravity_round31_jhora_pyjhora_capture_manual_review_2026_06_26.md | Human oracle capture standards belong with benchmark and operator docs. |
|
||||
| promote | antigravity_round31_license_quarantine_blacklist_top60_2026_06_26.md | License quarantine rules are project safety boundaries and should stay canonical. |
|
||||
| promote | antigravity_round31_local_accuracy_shortest_path_top50_2026_06_26.md | Local accuracy verification path supports regression confidence and user trust. |
|
||||
| reference-only | antigravity_round31_local_user_experience_top60_2026_06_26.md | UX backlog; not a main-chain source of truth. |
|
||||
| promote | antigravity_round31_single_source_of_truth_enforcement_2026_06_26.md | Single-source governance supports the current mirror-contamination fix. |
|
||||
| promote | antigravity_round31_true_missing_traditional_techniques_top30_2026_06_26.md | Traditional technique gap list should inform registry and roadmap truth. |
|
||||
| promote | antigravity_round31_whole_machine_fragment_reuse_fourth_pass_2026_06_26.md | Whole-machine reuse findings are high value, but must be re-anchored before integration. |
|
||||
| reference-only | antigravity_round32_api_direct_coding_top40_2026_06_26.md | Concrete API tasks, but must be reconciled with current endpoint map first. |
|
||||
| reference-only | antigravity_round32_cli_direct_coding_top40_2026_06_26.md | Concrete CLI tasks, but no longer authoritative without current test review. |
|
||||
| archive | antigravity_round32_codex_round33_top200_2026_06_26.md | Broad execution board superseded by current closure lanes. |
|
||||
| promote | antigravity_round32_copy_allowed_assets_top100_2026_06_26.md | License-safe assets list should merge with canonical reuse whitelist. |
|
||||
| reference-only | antigravity_round32_extra_accuracy_verification_blocks_2026_06_26.md | Trust-center idea; promote only if product verification UI is reopened. |
|
||||
| reference-only | antigravity_round32_extra_i18n_translation_2026_06_26.md | Localization backlog, not current strict workflow. |
|
||||
| reference-only | antigravity_round32_extra_offline_fallback_2026_06_26.md | Offline/PWA idea; reference only until frontend resilience is prioritized. |
|
||||
| reference-only | antigravity_round32_extra_payload_performance_2026_06_26.md | Performance backlog; useful when API payload slimming resumes. |
|
||||
| archive | antigravity_round32_final_execution_board_2026_06_26.md | Superseded round board. |
|
||||
| reference-only | antigravity_round32_frontend_direct_coding_top40_2026_06_26.md | UI backlog; not canonical runtime map. |
|
||||
| promote | antigravity_round32_jhora_pyjhora_fast_capture_pipeline_2026_06_26.md | Capture pipeline can reduce oracle bottlenecks and should feed operator docs. |
|
||||
| promote | antigravity_round32_license_blacklist_recheck_2026_06_26.md | GPL/AGPL isolation remains a hard boundary. |
|
||||
| promote | antigravity_round32_local_accuracy_shortest_chain_final_2026_06_26.md | Accuracy shortest chain should connect to benchmark and preflight gates. |
|
||||
| reference-only | antigravity_round32_local_ux_direct_top30_2026_06_26.md | UX backlog only. |
|
||||
| promote | antigravity_round32_oracle_sample_push_matrix_2026_06_26.md | Oracle sample matrix belongs in benchmark planning. |
|
||||
| reference-only | antigravity_round32_sync_script_blueprint_2026_06_26.md | Sync script idea; keep constrained by no reverse `.workbuddy` authority. |
|
||||
| promote | antigravity_round32_timezone_dst_polar_direct_tasks_2026_06_26.md | Timezone, DST and polar handling affect chart correctness. |
|
||||
| promote | antigravity_round32_true_missing_techniques_rerank_top20_2026_06_26.md | Technique gap rerank should feed registry and roadmap. |
|
||||
| promote | antigravity_round32_whole_machine_fragment_reuse_fifth_pass_2026_06_26.md | Fragment reuse findings are useful after license/source re-anchoring. |
|
||||
| promote | antigravity_round36_asc_degree_yogi_tight_orb_wealth_pack_2026_06_26.md | Wealth-specific Yogi/tight-orb material supports strict finance adjudication. |
|
||||
| promote | antigravity_round36_bhrigu_pada_all_event_expansion_pack_2026_06_26.md | Event expansion material is relevant to historical backtest and timing routes. |
|
||||
| promote | antigravity_round36_global_first_honesty_board_2026_06_26.md | Honesty boundary belongs near oracle and benchmark governance. |
|
||||
| reference-only | antigravity_round36_pakshi_swara_boundary_pack_2026_06_26.md | Advanced traditional technique background; not current route-critical. |
|
||||
| reference-only | antigravity_round36_rtn_anomalous_d9_deepening_pack_2026_06_26.md | Niche D9 deepening background; promote only with current evidence. |
|
||||
| promote | antigravity_round36_tajika_sahams_external_closure_pack_2026_06_26.md | Tajika/Saham external closure is an active benchmark frontier. |
|
||||
| reference-only | antigravity_round36_tithi_lord_freeze_gap_pack_2026_06_26.md | Technique detail backlog; not current main-chain blocker. |
|
||||
| reference-only | antigravity_round37_article_template_industrialization_board_2026_06_26.md | Interpretation template backlog; useful after truth arbitration. |
|
||||
| archive | antigravity_round37_codex_round38_top100_2026_06_26.md | Execution board superseded by later focused documents. |
|
||||
| promote | antigravity_round37_dasha_external_oracle_shortest_closure_board_2026_06_26.md | Dasha external closure is a high-rigor requirement. |
|
||||
| promote | antigravity_round37_public_benchmark_moat_board_2026_06_26.md | Public benchmark strategy should inform benchmark dashboard governance. |
|
||||
| promote | antigravity_round37_shadbala_absolute_value_frontier_board_2026_06_26.md | Shadbala absolute values remain a precision frontier. |
|
||||
| promote | antigravity_round37_tajika_sahams_annual_closure_board_2026_06_26.md | Annual chart closure aligns with current Tajika oracle work. |
|
||||
| reference-only | antigravity_round38_advanced_sensitive_points_top20_2026_06_26.md | Advanced sensitive points backlog; not current strict route source. |
|
||||
| reference-only | antigravity_round38_article_detail_template_batch2_2026_06_26.md | Template backlog; keep behind truth arbitration. |
|
||||
| archive | antigravity_round38_codex_round39_top150_2026_06_26.md | Execution board superseded by current active fronts. |
|
||||
| promote | antigravity_round38_dasha_external_oracle_packet_factory_2026_06_26.md | Dasha oracle packet factory should feed operator packet docs/tests. |
|
||||
| reference-only | antigravity_round38_mrityu_bhaga_authority_table_hunt_2026_06_26.md | Authority-table research, but not active route-critical. |
|
||||
| promote | antigravity_round38_open_source_copy_whitelist_sensitive_points_2026_06_26.md | License-safe sensitive-point whitelist should be reconciled before reuse. |
|
||||
| promote | antigravity_round38_public_benchmark_board_v2_2026_06_26.md | Benchmark dashboard v2 should be promoted if public benchmark work resumes. |
|
||||
| promote | antigravity_round38_shadbala_absolute_value_capture_matrix_2026_06_26.md | Shadbala absolute capture matrix belongs with oracle closure planning. |
|
||||
| promote | antigravity_round38_skill_global_rank_gap_after_round38_2026_06_26.md | Global gap assessment informs honest capability claims. |
|
||||
| promote | antigravity_round38_whole_machine_fragment_reuse_sixth_pass_2026_06_26.md | Fragment reuse shortlist needs canonical anchoring. |
|
||||
| promote | antigravity_round39_yogi_wealth_bridge_audit_2026_06_28.md | Directly relevant to current wealth strict adjudication. |
|
||||
| promote | antigravity_round40_article_technique_truth_arbitration_2026_06_27.md | Truth arbitration prevents noisy article-derived code migration. |
|
||||
| archive | antigravity_round40_codex_round41_skill_top60_2026_06_27.md | Round-specific action board, not canonical truth. |
|
||||
| promote | antigravity_round40_dasha_second_wave_closure_pack_2026_06_27.md | Dasha second-wave closure supports high-rigor timing validation. |
|
||||
| promote | antigravity_round40_shadbala_absolute_authority_ladder_2026_06_27.md | Shadbala authority ladder belongs with precision/oracle governance. |
|
||||
| promote | antigravity_round40_tajika_annual_second_wave_board_2026_06_27.md | Tajika second-wave board supports annual oracle closure. |
|
||||
| promote | antigravity_round40_whole_machine_fragment_reuse_shortlist_2026_06_27.md | Top 20 fragment shortlist should be re-anchored to current code/tests. |
|
||||
| archive | antigravity_sidecar_work_order_round33_2026_06_26.md | Sidecar work order; historical coordination only. |
|
||||
| archive | antigravity_sidecar_work_order_round34_2026_06_26.md | Sidecar work order; historical coordination only. |
|
||||
| archive | antigravity_sidecar_work_order_round35_2026_06_26.md | Sidecar work order; historical coordination only. |
|
||||
| archive | antigravity_sidecar_work_order_round36_2026_06_26.md | Sidecar work order; historical coordination only. |
|
||||
| archive | antigravity_sidecar_work_order_round37_2026_06_26.md | Sidecar work order; historical coordination only. |
|
||||
| archive | antigravity_sidecar_work_order_round40_2026_06_27.md | Sidecar work order; historical coordination only. |
|
||||
| promote | article_technique_coverage_matrix_2026_06_26.md | Article-to-technique coverage matrix should remain a canonical truth-arbitration input. |
|
||||
| reference-only | chayue_screenshot_coverage_matrix_2026_06_26.md | Source-specific screenshot coverage; useful as evidence only. |
|
||||
| reference-only | cloud_sync_minimum_whitelist_for_skill_truth_2026_06_26.md | Sync governance background; no reverse authority over main repo. |
|
||||
| promote | current_skill_core_gap_rerank_2026_06_26.md | Current skill gap rerank should feed active roadmap and registry work. |
|
||||
| promote | dasha_accuracy_closure_status_2026_06_26.md | Dasha closure status is a high-rigor timing boundary. |
|
||||
| promote | dasha_code_only_priority_rerank_2026_06_26.md | Code-only Dasha prioritization can guide scoped local improvements. |
|
||||
| promote | five_hard_fronts_master_board_2026_06_26.md | Five-front board is the best compact strategic index for precision gaps. |
|
||||
| archive | git_execution_card_skill_truth_only_2026_06_26.md | One-off git execution card; no ongoing truth role. |
|
||||
| promote | global_open_source_positioning_of_skill_2026_06_26.md | Honest positioning is required for claims and benchmark framing. |
|
||||
| promote | high_granularity_technique_deepening_backlog_2026_06_26.md | Technique deepening backlog should be reconciled with the registry. |
|
||||
| promote | jhora_capture_task_v2.md | Human oracle capture task should connect to benchmark packets. |
|
||||
| reference-only | recovered_old_skill_reuse_audit_2026_06_26.md | Recovery audit; reuse only after current-code and license recheck. |
|
||||
| promote | reuse_license_whitelist_for_skill_2026_06_26.md | Reuse license whitelist should be canonical before any migration. |
|
||||
| promote | skill_fragment_map_and_source_of_truth_2026_06_26.md | Source-of-truth map supports mirror and fragment discipline. |
|
||||
| promote | skill_single_source_of_truth_disposition_2026_06_26.md | Single-source disposition remains a governance anchor. |
|
||||
| promote | skill_truth_conflict_matrix_2026_06_26.md | Conflict matrix should inform future source-truth decisions. |
|
||||
| promote | three_fronts_skill_depth_audit_2026_06_26.md | Three-front depth audit is compact and still relevant to skill depth. |
|
||||
| reference-only | zhanxingyindu1_screenshot_coverage_matrix_2026_06_26.md | Source-specific screenshot coverage; useful as evidence only. |
|
||||
|
||||
## Immediate Next Use
|
||||
|
||||
When a future task needs one of these drafts, first copy the claim into a canonical target and verify it against current code/tests. Never import code or truth from `.workbuddy` or local drafts directly into the runtime chain.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Unique Main Chain Map
|
||||
|
||||
Date: 2026-07-01
|
||||
|
||||
This is the single current map for the Jyotish runtime chain. It does not replace `SKILL.md`, `AGENTS.md`, or `references/strict-workflow-router.md`; it names which file owns each entrypoint and how they should relate. The main repo is the source of truth. Historical mirrors, including `.workbuddy`, are reference/distribution material only and must not import from `.workbuddy`.
|
||||
|
||||
## Authority Rule
|
||||
|
||||
- Runtime truth lives in this repository: `scripts/`, `mcp_server.py`, `jyotish_vedic/`, `references/`, and `tests/`.
|
||||
- `SKILL.md` is the skill/user-facing instruction entry.
|
||||
- `AGENTS.md` is the hard override for high-rigor project behavior, including Functional Benefic/Malefic and honesty boundaries.
|
||||
- `references/strict-workflow-router.md` is the route checklist for career, relationship, finance, timing, historical verification, and technique reliability questions.
|
||||
- `.workbuddy` is a distribution mirror or historical recovery source. It can be inspected as evidence, but runtime code must not import from `.workbuddy`.
|
||||
|
||||
## Entrypoint Map
|
||||
|
||||
| Entry | Owner | Role | Calls / Depends On | Boundary |
|
||||
|---|---|---|---|---|
|
||||
| Skill entry | `SKILL.md` | Human/agent instruction surface for Jyotish analysis | `references/strict-workflow-router.md`, `AGENTS.md`, canonical references | Instruction truth only; not executable runtime. |
|
||||
| Web/API entry | `scripts/jyotish_api_server.py` | Local HTTP API for `jyotish-app` and high-rigor workflow jobs | `scripts/unified_consultation_orchestrator.py`, local modules, chart cache, rectification gate, historical backtest loader | Must route through local repo modules and preserve API/cache provenance. |
|
||||
| MCP entry | `mcp_server.py` | AI-native tool surface for chart, Dasha, Shadbala, Ashtakavarga, Varga, full reading, and `strict_workflow` | Local `scripts/` modules, `UnifiedConsultationOrchestrator`, functional-benefic layer, VedAstro evidence summaries | MCP strict workflow is the canonical reusable strict adjudication surface. |
|
||||
| Shared route contract | `scripts/unified_consultation_orchestrator.py` | Normalizes themes/questions and builds the surface-agnostic runtime planner | Web/API and MCP callers | Owns route naming and sync/async step planning; does not itself calculate astrology. |
|
||||
| VedAstro official entry | `scripts/vedastro_service_adapter.py` | Controlled official evidence boundary: official full snapshot, range scan, external technique calls | VedAstro official endpoint/env, official Python bridge/capability runner where configured | VedAstro official snapshot has priority when available; local modules supplement or fallback when official evidence is blocked. |
|
||||
| Strict workflow entry | `mcp_server.py::strict_workflow` | Main strict adjudication chain for career, relationship, finance, timing and event judgement | `mcp_server.py` evidence collectors, functional benefic/malefic, Shadbala, Ashtakavarga, Dasha, Varga, VedAstro official evidence | Must expose missing evidence, conflicts, confidence caps, and Technique Audit Table facts. |
|
||||
| Rectification entry | `scripts/jyotish_api_server.py` `/api/rectification_gate` | Birth-time rectification gate reused by high-rigor workflow | Chart payload, rectification references and frontend rectification engine outputs | Rectification is a gate/support layer, not proof by itself. |
|
||||
| Historical backtest entry | `scripts/historical_event_backtest.py` | Reusable historical event backtest runner | Calls `mcp_server.strict_workflow` for supported event domains | Measures route support for supplied events; blocked/unsupported cases must not be overstated as predictive accuracy. |
|
||||
|
||||
## Main Flow
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Skill["SKILL.md"] --> Router["references/strict-workflow-router.md"]
|
||||
Web["scripts/jyotish_api_server.py"] --> Orchestrator["scripts/unified_consultation_orchestrator.py"]
|
||||
MCP["mcp_server.py"] --> Orchestrator
|
||||
Orchestrator --> Strict["mcp_server.py::strict_workflow"]
|
||||
Web --> Rectification["/api/rectification_gate"]
|
||||
Web --> Backtest["scripts/historical_event_backtest.py"]
|
||||
Backtest --> Strict
|
||||
Strict --> VedAstro["scripts/vedastro_service_adapter.py"]
|
||||
Strict --> Local["local scripts: varga, dasha, shadbala, ashtakavarga, functional benefics"]
|
||||
```
|
||||
|
||||
## High-Rigor Domain Requirements
|
||||
|
||||
| Domain | Mandatory local evidence | Mandatory timing cross-check | External/oracle boundary |
|
||||
|---|---|---|---|
|
||||
| Career | D10 + A10, Shadbala, Ashtakavarga, Functional Benefic/Malefic | Vimshottari + Narayana Dasha | VedAstro official snapshot/range scan where available; PyJHora and jyotishganit remain external reference layers with license boundaries. |
|
||||
| Wealth | D2 / D11, Shadbala, Ashtakavarga, Functional Benefic/Malefic | Vimshottari + Narayana Dasha | Treat VedAstro official evidence as external context; do not upgrade blocked external layers to validation. |
|
||||
| Relationship | D9 + UL, Darakaraka/7th-house context, Functional Benefic/Malefic | Vimshottari + Narayana Dasha | External oracle closure remains required for high-confidence timing claims. |
|
||||
| Historical event | Route-specific Varga, Dasha, Shadbala, Ashtakavarga, Functional Benefic/Malefic | Vimshottari + Narayana Dasha | `scripts/historical_event_backtest.py` must mark blocked/unsupported/miss honestly. |
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- This document does not authorize copying code from `.workbuddy`, PyJHora, GPL/AGPL projects, or local drafts.
|
||||
- This document does not claim that every VedAstro official method runs on every request.
|
||||
- This document does not close external oracle validation by itself.
|
||||
|
||||
## Verification Hooks
|
||||
|
||||
- Runtime mirror guard: `tests/test_runtime_import_boundaries.py`
|
||||
- Preflight governance: `tests/test_preflight_fragment_scan.py`
|
||||
- Main-chain and draft governance docs: `tests/test_research_governance_docs.py`
|
||||
- Shared route planner: `tests/test_unified_consultation_orchestrator.py`
|
||||
- Historical event backtest: `tests/test_historical_event_backtest.py`
|
||||
@@ -0,0 +1,315 @@
|
||||
# Shortest-Path Closure Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Collapse the remaining Jyotish hard fronts into the smallest executable closure path: relationship adjudicator closure, Vimsopaka/functional-role closure, oracle closure, and VedAstro strict ingestion.
|
||||
|
||||
**Architecture:** Reuse existing strict workflow, adjudicator, oracle, and VedAstro bridge assets instead of opening new product surfaces. Drive every remaining change from fixed regression packs and external-truth comparison scripts so the project stops expanding sideways and starts closing hard boundaries.
|
||||
|
||||
**Tech Stack:** Python, pytest, existing MCP strict workflow code, existing full-reading/report pipeline, existing VedAstro adapter scripts, existing oracle comparison scripts, existing frontend static contract tests.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Must obey `/Users/wuyongnaren/Documents/印度占星/AGENTS.md` high-rigor rules.
|
||||
- Timing/event/outcome work must use `Vimshottari + Narayana Dasha` and relationship work must include `D9 + UL`.
|
||||
- Functional Benefic/Malefic must remain explicit in high-rigor evidence and user-visible audit surfaces.
|
||||
- Prefer existing repo-native code and reusable open-source references over new standalone implementations.
|
||||
- Do not expand scope into new product features while these closure fronts remain open.
|
||||
- Any claim touching oracle accuracy, global-first status, or perfect precision must stay blocked until external evidence says otherwise.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Freeze the closure board and stop scope drift
|
||||
|
||||
**Files:**
|
||||
- Create: `/Users/wuyongnaren/Documents/印度占星/docs/research/shortest_path_closure_board_2026_06_29.md`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/docs/research/ACTIVE_FRONTS.md`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/task_plan.md`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_skill_gap_truth_audit.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `/Users/wuyongnaren/Documents/印度占星/docs/research/ACTIVE_FRONTS.md`, `/Users/wuyongnaren/Documents/印度占星/task_plan.md`
|
||||
- Produces: `shortest_path_closure_board_2026_06_29.md` with four closure lanes (`relationship`, `vimsopaka_functional_role`, `oracle`, `vedastro_ingestion`) and a fixed task order
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_skill_gap_truth_registry_lists_hard_fronts_and_past_corrections() -> None:
|
||||
data = json.loads(REGISTRY.read_text(encoding="utf-8"))
|
||||
required_fronts = {
|
||||
"dasha_external_oracle",
|
||||
"shadbala_external_absolute_values",
|
||||
"tajika_sahams_annual_closure",
|
||||
"article_template_industrialization",
|
||||
"long_term_public_benchmark",
|
||||
}
|
||||
assert required_fronts <= set(data["hard_fronts"])
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_skill_gap_truth_audit.py -q`
|
||||
Expected: FAIL if the closure board / active fronts drift exposes missing hard-front accounting
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
```markdown
|
||||
# Shortest Path Closure Board
|
||||
|
||||
## Lane 1 - Relationship Adjudicator Closure
|
||||
1. lock legal_marriage/public_formalization regression pack
|
||||
2. close Jaimini marriage bridge v1 regression loop
|
||||
3. keep public_formalization_candidate narrative conservative everywhere
|
||||
|
||||
## Lane 2 - Vimsopaka + Functional Role Closure
|
||||
1. map NEECHA_BHANGA / GREAT_FRIEND / GREAT_ENEMY
|
||||
2. render functional benefic/malefic everywhere the user sees Technique Audit
|
||||
|
||||
## Lane 3 - Oracle Closure
|
||||
1. batch Dasha/Shadbala/JHora comparison pack
|
||||
2. promote first external verified packet
|
||||
3. update oracle dashboard only from validated packets
|
||||
|
||||
## Lane 4 - VedAstro Strict Ingestion
|
||||
1. keep current blocked boundary
|
||||
2. run one endpoint-backed smoke only after relationship loop is closed
|
||||
3. ingest only allowlisted event windows into evidence ledger
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_skill_gap_truth_audit.py -q`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/research/shortest_path_closure_board_2026_06_29.md docs/research/ACTIVE_FRONTS.md task_plan.md tests/test_skill_gap_truth_audit.py
|
||||
git commit -m "docs: freeze shortest-path closure board"
|
||||
```
|
||||
|
||||
### Task 2: Close the relationship adjudicator regression pack
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/main.js`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_frontend_productization.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `event_judgement.dominant_label`, `event_judgement.secondary_context`, `present_evidence.jaimini_marriage_support`
|
||||
- Produces: locked conservative handling for `public_formalization_candidate`, and red/green regression coverage for `legal_marriage` vs `public_formalization`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
```python
|
||||
def test_relationship_narrative_payload_does_not_translate_public_formalization_candidate_plus_synastry_support_plus_weak_core_promise_into_marriage_approach() -> None:
|
||||
strict = _collect_strict_evidence("relationship", _base_relationship_result())
|
||||
strict["event_judgement"]["dominant_label"] = None
|
||||
strict["event_judgement"]["secondary_context"] = [
|
||||
"darakaraka_active",
|
||||
"ul_support",
|
||||
"synastry_support",
|
||||
"synastry_compatibility_support",
|
||||
"public_formalization_candidate",
|
||||
]
|
||||
strict["confidence_cap"] = "low"
|
||||
payload = jyotish_engine._build_relationship_narrative_payload(strict)
|
||||
assert any("不能误读成接近结婚" in item for item in payload["risks"])
|
||||
assert any("不得越权抬升 legal_marriage" in item for item in payload["boundaries"])
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `python3 -m pytest tests/test_mcp_strict_workflow_relationship.py tests/test_frontend_productization.py tests/test_api_server_security.py -q -k "public_formalization or weak_core_promise or misread_as_near_marriage"`
|
||||
Expected: FAIL on the exact conservative boundary you are adding
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
```python
|
||||
if "public_formalization_candidate" in secondary_context:
|
||||
risks.append("当前虽更接近 public_formalization_candidate,但在 timing conflict 未解除前,不能误读成接近结婚。")
|
||||
boundaries.append("public_formalization_candidate 只表示公开化候选,不等于法律婚姻,不能越权替代 legal_marriage。")
|
||||
```
|
||||
|
||||
```javascript
|
||||
const status = hasPublicFormalizationCandidate && hasConflictWarning ? 'needs_context' : ...
|
||||
const statusLabel = hasPublicFormalizationCandidate && hasConflictWarning
|
||||
? '公开化候选,不等于婚姻逼近'
|
||||
: ...
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run: `python3 -m pytest tests/test_mcp_strict_workflow_relationship.py tests/test_frontend_productization.py tests/test_api_server_security.py -q -k "public_formalization or weak_core_promise or misread_as_near_marriage"`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add mcp_server.py scripts/jyotish_engine.py jyotish-app/main.js tests/test_mcp_strict_workflow_relationship.py tests/test_frontend_productization.py tests/test_api_server_security.py
|
||||
git commit -m "test: lock relationship public formalization boundaries"
|
||||
```
|
||||
|
||||
### Task 3: Close Vimsopaka semantic mapping and functional-role rendering
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/skill-map.js`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/references/strict-workflow-router.md`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_frontend_productization.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: existing dignity guardrail output and functional benefic/malefic evidence
|
||||
- Produces: user-visible audit rendering for functional benefics/malefics/yogakarakas/neutrals and Vimsopaka semantic labels
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
```python
|
||||
def test_report_artifact_relationship_strict_narrative_surfaces_public_formalization_candidate_boundary() -> None:
|
||||
html = artifact["html"]
|
||||
assert "Functional Benefic/Malefic" in html
|
||||
assert "Yogakaraka" in html
|
||||
assert "functional neutral" in html.lower() or "中性星" in html
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `python3 -m pytest tests/test_frontend_productization.py tests/test_api_server_security.py -q -k "Functional Benefic or Yogakaraka or Vimsopaka"`
|
||||
Expected: FAIL because at least one user-visible rendering path is incomplete
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
```python
|
||||
summary_parts.append(f"Yogakaraka: {', '.join(yogakarakas) if yogakarakas else 'None'}")
|
||||
summary_parts.append(f"Functional neutrals: {', '.join(functional_neutrals) if functional_neutrals else 'None'}")
|
||||
```
|
||||
|
||||
```javascript
|
||||
['Functional Benefic/Malefic / 功能吉凶星', '已接入', '按 Lagna 输出功能吉星、功能凶星、Yogakaraka 与中性星,并进入 Technique Audit Table']
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run: `python3 -m pytest tests/test_frontend_productization.py tests/test_api_server_security.py -q -k "Functional Benefic or Yogakaraka or Vimsopaka"`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add mcp_server.py scripts/jyotish_api_server.py jyotish-app/skill-map.js references/strict-workflow-router.md tests/test_frontend_productization.py tests/test_api_server_security.py
|
||||
git commit -m "feat: close functional role and vimsopaka rendering gaps"
|
||||
```
|
||||
|
||||
### Task 4: Batch the oracle closure work into one comparison pack
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/shadbala_oracle_comparison.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/oracle_benchmark_inventory.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/references/oracle/dasha_shadbala_oracle_cases.json`
|
||||
- Create: `/Users/wuyongnaren/Documents/印度占星/docs/research/oracle_batch_closure_pack_2026_06_29.md`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_dasha_oracle_closure_status.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: external oracle packets, current shadbala comparison script, oracle benchmark inventory
|
||||
- Produces: one batch comparison report with pass/fail/tolerance rows and updated blocked/unblocked truth summary
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_dasha_oracle_closure_status_markdown_keeps_global_calibration_blocked_until_non_dasha_packets_pass() -> None:
|
||||
markdown = build_status_markdown(sample_status)
|
||||
assert "Keep global calibration blocked" in markdown
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_dasha_oracle_closure_status.py -q`
|
||||
Expected: FAIL if the batch comparison summary or blocked boundary drifts
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
```markdown
|
||||
# Oracle Batch Closure Pack
|
||||
|
||||
| Case | Source | Domain | Pass | Notes |
|
||||
|---|---|---|---|---|
|
||||
| steve_jobs | JHora/PyJHora | Dasha | yes/no | boundary diff |
|
||||
| ... | ... | Shadbala | yes/no | tolerance diff |
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_dasha_oracle_closure_status.py -q`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/shadbala_oracle_comparison.py scripts/oracle_benchmark_inventory.py references/oracle/dasha_shadbala_oracle_cases.json docs/research/oracle_batch_closure_pack_2026_06_29.md tests/test_dasha_oracle_closure_status.py
|
||||
git commit -m "feat: batch oracle closure comparison pack"
|
||||
```
|
||||
|
||||
### Task 5: Keep VedAstro ingestion minimal and honest
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/vedastro_service_adapter.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/run_quality_gate.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_life_event_graph_v1.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_service_adapter_executor.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: current `external_window` payload contract and allowlist audit
|
||||
- Produces: one endpoint-backed smoke path or one controlled blocked path, both feeding the same evidence ledger contract
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
```python
|
||||
def test_life_event_graph_keeps_external_window_nodes_allowlisted() -> None:
|
||||
assert any(node["kind"] == "external_window" for node in strict["life_event_graph"]["event_nodes"])
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `python3 -m pytest tests/test_life_event_graph_v1.py tests/test_vedastro_service_adapter_executor.py -q`
|
||||
Expected: FAIL if the allowlist / blocked contract is incomplete
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
```python
|
||||
if not endpoint or not network_enabled:
|
||||
return {"status": "blocked", "reason": "vedastro_live_endpoint_or_network_flag_missing"}
|
||||
return {"status": "ok", "event_nodes": filtered_nodes}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run: `python3 -m pytest tests/test_life_event_graph_v1.py tests/test_vedastro_service_adapter_executor.py -q`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/vedastro_service_adapter.py scripts/run_quality_gate.py tests/test_life_event_graph_v1.py tests/test_vedastro_service_adapter_executor.py
|
||||
git commit -m "feat: keep vedastro ingestion minimal and allowlisted"
|
||||
```
|
||||
|
||||
## Self-Review
|
||||
|
||||
- Spec coverage: the plan covers the four remaining closure lanes called out by current active fronts.
|
||||
- Placeholder scan: no TBD/TODO placeholders remain.
|
||||
- Type consistency: plan uses the existing `dominant_label`, `secondary_context`, `relationship_narrative`, `external_window`, and blocked-boundary terminology already present in the repo.
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
Plan complete and saved to `docs/superpowers/plans/2026-06-29-shortest-path-closure-plan.md`. Two execution options:
|
||||
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
Which approach?
|
||||
@@ -0,0 +1,410 @@
|
||||
# Chart Async And Unified Stage Contract Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add a reusable lightweight async `job_id + poll` lane for normal `/api/chart` while promoting `full-reading` stage timings into a clearer unified contract.
|
||||
|
||||
**Architecture:** Reuse the existing file-backed high-rigor job runner by extracting shared chart/high-rigor job helpers inside `scripts/jyotish_api_server.py`. Reuse the existing `full-reading` stage timing instrumentation in `scripts/jyotish_engine.py` and only reshape it into grouped stage metadata instead of adding new heavy computation.
|
||||
|
||||
**Tech Stack:** Python, existing HTTPServer API server, existing file-backed scratch job records, pytest.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Reuse current job runner; do not add Redis, Celery, RQ, or a second queue.
|
||||
- Keep sync `/api/chart` behavior unchanged unless `async`/`enqueue` is explicitly requested.
|
||||
- Keep completed chart async result identical to sync chart payload.
|
||||
- Do not add new heavy computation for stage grouping; reshape existing timing only.
|
||||
- Preserve current honesty boundaries around VedAstro partial/blocked states.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Promote full-reading stage timings into a unified stage contract
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `summary["stage_timings"]: list[dict]`
|
||||
- Produces:
|
||||
- `summary["stage_contract_version"]: int`
|
||||
- `summary["stage_groups"]: list[dict]`
|
||||
- `summary["cache_recommendations"]: dict`
|
||||
- `summary["async_recommendations"]: dict`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
Add a focused test in `tests/test_cli_smoke.py` asserting the new contract fields:
|
||||
|
||||
```python
|
||||
def test_full_reading_summary_exposes_unified_stage_groups() -> None:
|
||||
result = run_engine(
|
||||
"full-reading",
|
||||
"--year", "1990",
|
||||
"--month", "1",
|
||||
"--day", "1",
|
||||
"--hour", "12",
|
||||
"--minute", "0",
|
||||
"--lat", "39.9",
|
||||
"--lon", "116.4",
|
||||
"--tz", "8",
|
||||
"--today", "2026-01-01",
|
||||
"--transit-date", "2026-01-01",
|
||||
)
|
||||
|
||||
summary = result["summary"]
|
||||
assert summary["stage_contract_version"] == 1
|
||||
assert isinstance(summary["stage_groups"], list)
|
||||
assert any(group["group"] == "official_evidence" for group in summary["stage_groups"])
|
||||
assert summary["cache_recommendations"]["api_chart_response"] == "recommended"
|
||||
assert summary["async_recommendations"]["chart_async_optional"] is True
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_cli_smoke.py::test_full_reading_summary_exposes_unified_stage_groups -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing `stage_contract_version` or `stage_groups`.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `scripts/jyotish_engine.py`, add a small helper near the stage-timing helpers:
|
||||
|
||||
```python
|
||||
def _build_unified_stage_contract(stage_timings):
|
||||
groups = {
|
||||
'local_core': ['core_chart_and_setup', 'dasha_and_core_varga_stack', 'advanced_interpretation_and_timing_layers', 'dynamic_hooks'],
|
||||
'official_evidence': ['vedastro_official_snapshot', 'vedastro_main_entry_overview'],
|
||||
'contract_and_prompt': ['strict_contracts', 'guided_topics', 'ai_prompt_pack'],
|
||||
}
|
||||
rows = []
|
||||
for group_name, stage_names in groups.items():
|
||||
matched = [row for row in stage_timings if row.get('stage') in stage_names]
|
||||
rows.append({
|
||||
'group': group_name,
|
||||
'stages': [row.get('stage') for row in matched],
|
||||
'elapsed_seconds': round(sum(float(row.get('elapsed_seconds', 0) or 0) for row in matched), 4),
|
||||
'execution_mode': (
|
||||
'sync_remote_heavy' if group_name == 'official_evidence'
|
||||
else 'sync_structuring' if group_name == 'contract_and_prompt'
|
||||
else 'sync_local'
|
||||
),
|
||||
})
|
||||
return {
|
||||
'stage_contract_version': 1,
|
||||
'stage_groups': rows,
|
||||
'cache_recommendations': {
|
||||
'api_chart_response': 'recommended',
|
||||
'official_full_snapshot_semantic': 'recommended',
|
||||
},
|
||||
'async_recommendations': {
|
||||
'chart_async_optional': True,
|
||||
'high_rigor_async_recommended': True,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then merge that helper output into `report['summary']` after `stage_timings` and `slowest_stages` are computed.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_cli_smoke.py::test_full_reading_summary_exposes_unified_stage_groups -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 2: Generalize the file-backed async job runner for chart and high-rigor scopes
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- existing `_write_high_rigor_job_record(job_id, payload)`
|
||||
- existing `_load_high_rigor_job_record(job_id)`
|
||||
- Produces:
|
||||
- shared `_enqueue_async_job(...)`
|
||||
- shared `_get_async_job(...)`
|
||||
- chart scope job records
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add tests in `tests/test_api_server_security.py`:
|
||||
|
||||
```python
|
||||
def test_chart_async_submit_returns_job_id(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
handler = _handler()
|
||||
monkeypatch.setattr(handler, '_enqueue_chart_job', lambda body: {
|
||||
'success': True,
|
||||
'endpoint': 'chart_async',
|
||||
'mode': 'async_submitted',
|
||||
'job_id': 'chart_test_job_1',
|
||||
'status': 'queued',
|
||||
'poll_path': '/api/chart/jobs/chart_test_job_1',
|
||||
'scope': 'api_chart_response',
|
||||
})
|
||||
|
||||
result = handler._compute_chart({'async': True, 'year': REDACTED_YEAR, 'month': 4, 'day': 17, 'hour': 14, 'minute': 49, 'lat': 36.42, 'lon': 114.2, 'tz': 8})
|
||||
|
||||
assert result['mode'] == 'async_submitted'
|
||||
assert result['job_id'] == 'chart_test_job_1'
|
||||
assert result['poll_path'].endswith('/chart_test_job_1')
|
||||
```
|
||||
|
||||
```python
|
||||
def test_chart_job_poll_endpoint_returns_cached_job_payload(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(jyotish_api_server, '_load_async_job_record', lambda scope, job_id: {
|
||||
'success': True,
|
||||
'endpoint': 'chart_async',
|
||||
'mode': 'async_result',
|
||||
'job_id': job_id,
|
||||
'status': 'completed',
|
||||
'result': {'success': True, 'runtime_cache': {'scope': 'api_chart_response'}},
|
||||
})
|
||||
handler = _HighRigorJobCaptureHandler('/api/chart/jobs/chart_test_job_2')
|
||||
handler.do_GET()
|
||||
payload = handler.payload()
|
||||
assert payload['job_id'] == 'chart_test_job_2'
|
||||
assert payload['result']['runtime_cache']['scope'] == 'api_chart_response'
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py -k "chart_async_submit_returns_job_id or chart_job_poll_endpoint_returns_cached_job_payload" -q
|
||||
```
|
||||
|
||||
Expected: FAIL because `/api/chart` has no async branch and `/api/chart/jobs/...` is not routed.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `scripts/jyotish_api_server.py`:
|
||||
|
||||
1. Add a generic job storage layer:
|
||||
|
||||
```python
|
||||
def _job_dir(scope: str) -> Path:
|
||||
path = Path(REPO_ROOT) / 'scratch' / 'local' / f'{scope}_jobs'
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
return path
|
||||
|
||||
def _job_path(scope: str, job_id: str) -> Path:
|
||||
return _job_dir(scope) / f'{job_id}.json'
|
||||
|
||||
def _load_async_job_record(scope: str, job_id: str) -> dict | None:
|
||||
path = _job_path(scope, job_id)
|
||||
...
|
||||
|
||||
def _write_async_job_record(scope: str, job_id: str, payload: dict) -> dict:
|
||||
...
|
||||
```
|
||||
|
||||
2. Keep high-rigor wrappers calling the shared helpers.
|
||||
3. Add `_enqueue_chart_job(body)` that runs `_compute_chart_sync(body_without_async_flags)` in a background thread.
|
||||
4. Add `_compute_chart_sync(body)` by moving current synchronous `_compute_chart` body there.
|
||||
5. Make `_compute_chart(body)` return `_enqueue_chart_job(body)` when `async` or `enqueue` is set.
|
||||
6. Add `GET /api/chart/jobs/{job_id}` in `do_GET`.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py -k "chart_async_submit_returns_job_id or chart_job_poll_endpoint_returns_cached_job_payload" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 3: Make chart async completion return the normal chart payload unchanged
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `_compute_chart_sync(body: dict) -> dict`
|
||||
- Produces:
|
||||
- async chart completed record with `result` equal to normal chart payload shape
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
Add:
|
||||
|
||||
```python
|
||||
def test_chart_async_job_executes_in_background(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
handler = _handler()
|
||||
writes = []
|
||||
|
||||
def fake_write(scope: str, job_id: str, payload: dict) -> dict:
|
||||
writes.append((scope, job_id, dict(payload)))
|
||||
return payload
|
||||
|
||||
def fake_sync(body: dict) -> dict:
|
||||
time.sleep(0.05)
|
||||
return {'success': True, 'modules': {'chart': {'planets': {}, 'ascendant': {}}}, 'runtime_cache': {'scope': 'api_chart_response'}}
|
||||
|
||||
monkeypatch.setattr(jyotish_api_server, '_write_async_job_record', fake_write)
|
||||
monkeypatch.setattr(handler, '_compute_chart_sync', fake_sync)
|
||||
|
||||
result = handler._enqueue_chart_job({'async': True, 'year': REDACTED_YEAR, 'month': 4, 'day': 17, 'hour': 14, 'minute': 49, 'lat': 36.42, 'lon': 114.2, 'tz': 8})
|
||||
|
||||
assert result['endpoint'] == 'chart_async'
|
||||
assert result['status'] == 'queued'
|
||||
|
||||
deadline = time.time() + 1.0
|
||||
while len(writes) < 3 and time.time() < deadline:
|
||||
time.sleep(0.01)
|
||||
|
||||
assert writes[-1][2]['status'] == 'completed'
|
||||
assert writes[-1][2]['result']['runtime_cache']['scope'] == 'api_chart_response'
|
||||
assert 'modules' in writes[-1][2]['result']
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py::test_chart_async_job_executes_in_background -q
|
||||
```
|
||||
|
||||
Expected: FAIL because chart async job path does not exist yet.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
Implement `_enqueue_chart_job(body)` as a thin wrapper around the shared async runner:
|
||||
|
||||
```python
|
||||
def _enqueue_chart_job(self, body):
|
||||
body_copy = dict(body or {})
|
||||
body_copy.pop('async', None)
|
||||
body_copy.pop('enqueue', None)
|
||||
return self._enqueue_async_job(
|
||||
scope='api_chart_response',
|
||||
endpoint='chart_async',
|
||||
job_prefix='chart',
|
||||
poll_base='/api/chart/jobs',
|
||||
compute_fn=lambda: self._compute_chart_sync(body_copy),
|
||||
)
|
||||
```
|
||||
|
||||
Keep completed `result` untouched.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py::test_chart_async_job_executes_in_background -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 4: Keep existing high-rigor async path working on top of the shared helper
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- shared async helper
|
||||
- Produces:
|
||||
- backward-compatible high-rigor async submit and polling
|
||||
|
||||
- [ ] **Step 1: Re-run existing high-rigor async tests as regression guards**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py -k "high_rigor_async_submit_returns_job_id or high_rigor_job_poll_endpoint_returns_cached_job_payload or high_rigor_async_job_executes_in_background" -q
|
||||
```
|
||||
|
||||
Expected: If this fails after Task 2/3 changes, fix compatibility before proceeding.
|
||||
|
||||
- [ ] **Step 2: Minimal compatibility implementation**
|
||||
|
||||
Keep wrappers like:
|
||||
|
||||
```python
|
||||
def _enqueue_high_rigor_job(self, body):
|
||||
...
|
||||
return self._enqueue_async_job(
|
||||
scope=_HIGH_RIGOR_JOB_SCOPE,
|
||||
endpoint='high_rigor_workflow_async',
|
||||
job_prefix='hrw',
|
||||
poll_base='/api/high_rigor_workflow/jobs',
|
||||
compute_fn=lambda: self._compute_high_rigor_workflow_sync(body_copy),
|
||||
)
|
||||
```
|
||||
|
||||
And route `GET /api/high_rigor_workflow/jobs/{job_id}` through the shared loader.
|
||||
|
||||
- [ ] **Step 3: Run regression tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py -k "high_rigor_async_submit_returns_job_id or high_rigor_job_poll_endpoint_returns_cached_job_payload or high_rigor_async_job_executes_in_background" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 5: Run focused regression bundle and update progress
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/progress.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- all prior tasks
|
||||
- Produces:
|
||||
- verification record in `progress.md`
|
||||
|
||||
- [ ] **Step 1: Run focused regression bundle**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest \
|
||||
tests/test_cli_smoke.py::test_full_reading_summary_exposes_stage_timing_contract \
|
||||
tests/test_cli_smoke.py::test_full_reading_summary_exposes_unified_stage_groups \
|
||||
tests/test_api_server_security.py -k "chart_async or high_rigor_async or runtime_cache or fragment_audit_blocks_registry_surface_drift" \
|
||||
tests/test_mcp_strict_workflow_career.py \
|
||||
tests/test_mcp_strict_workflow_relationship.py \
|
||||
tests/test_mcp_strict_workflow_finance.py \
|
||||
-q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 2: Run chart/high-rigor API regression bundle**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py tests/test_historical_event_backtest.py -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 3: Update progress.md**
|
||||
|
||||
Add an entry covering:
|
||||
|
||||
- unified stage contract added to `full-reading`
|
||||
- `/api/chart` async submit + poll landed
|
||||
- shared async helper now serves chart + high-rigor
|
||||
- focused verification results
|
||||
@@ -0,0 +1,357 @@
|
||||
# Technique Audit Strict Adjudication Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make the existing `Technique Audit Table` a required compact gate inside strict adjudication for `career`, `relationship`, and `finance`.
|
||||
|
||||
**Architecture:** Reuse the current strict workflow contracts in `mcp_server.py` and the current prompt-pack audit table in `scripts/jyotish_engine.py`. Add one compact shared audit summary, then surface it through the existing engine/API/frontend layers without adding new compute-heavy logic.
|
||||
|
||||
**Tech Stack:** Python, existing strict workflow collectors, existing prompt-pack contract, pytest, existing frontend static contract tests.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Reuse current `Technique Audit Table`; do not create a second audit table system.
|
||||
- Do not add new heavy computation or new external requests.
|
||||
- Keep `career`, `relationship`, and `finance` route-specific gates intact.
|
||||
- Preserve honesty boundaries: `blocked`, `fallback_used`, `conflicts`, and `confidence_cap` must remain explicit.
|
||||
- Functional benefic/malefic must remain visible as a first-class high-rigor gate.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add compact technique audit summary to strict workflow contracts
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_career.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_finance.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `strict["present_evidence"]`
|
||||
- `strict["official_primary_evidence"]`
|
||||
- `strict["local_supplemental_evidence"]`
|
||||
- `strict["fallback_used"]`
|
||||
- `strict["blocked_items"]`
|
||||
- `strict["conflicts"]`
|
||||
- Produces:
|
||||
- `strict["technique_audit_summary"]`
|
||||
- `strict["multi_reference_reading_summary"]["audit_gate_frame"]`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
```python
|
||||
def test_career_strict_contract_exposes_compact_technique_audit_summary() -> None:
|
||||
strict = _collect_strict_evidence("career", _sample_result())
|
||||
audit = strict["technique_audit_summary"]
|
||||
assert audit["functional_benefic_malefic"]["gate"] == "hard"
|
||||
assert audit["relevant_vargas"]["gate"] == "hard"
|
||||
assert audit["vimshottari_narayana_crosscheck"]["gate"] == "hard"
|
||||
assert audit["source_priority_boundary"]["fallback_used"] == strict["fallback_used"]
|
||||
```
|
||||
|
||||
```python
|
||||
def test_relationship_multi_reference_summary_carries_audit_gate_frame() -> None:
|
||||
strict = _collect_strict_evidence("relationship", _sample_result())
|
||||
frame = strict["multi_reference_reading_summary"]["audit_gate_frame"]
|
||||
assert frame["functional_benefic_malefic"]["used"] in {True, False}
|
||||
assert frame["source_priority_boundary"]["blocked_items"] == strict["blocked_items"]
|
||||
```
|
||||
|
||||
```python
|
||||
def test_finance_strict_contract_compact_audit_marks_dual_dasha_gate() -> None:
|
||||
strict = _collect_strict_evidence("finance", {"modules": {"source_priority": {"mode": "local_fallback_official_blocked"}}})
|
||||
audit = strict["technique_audit_summary"]
|
||||
assert audit["vimshottari_narayana_crosscheck"]["gate"] == "hard"
|
||||
assert "official_primary_chart_blocked" in audit["source_priority_boundary"]["blocked_items"]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py -k "compact_technique_audit_summary or audit_gate_frame or dual_dasha_gate" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing `technique_audit_summary` or `audit_gate_frame`.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
Add compact builders in `mcp_server.py`:
|
||||
|
||||
```python
|
||||
def _route_varga_gate_keys(route: str) -> list[str]:
|
||||
if route == "career":
|
||||
return ["d10_dasamsa", "a10_karma_pada", "amatyakaraka", "karakamsha"]
|
||||
if route == "relationship":
|
||||
return ["d9_navamsa", "upapada_lagna", "darakaraka", "vivah_saham"]
|
||||
if route == "finance":
|
||||
return ["d2_hora", "d10_dasamsa", "shadbala", "ashtakavarga_house_scores"]
|
||||
return []
|
||||
|
||||
def _build_technique_audit_summary(route: str, strict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
present = strict.get("present_evidence") or {}
|
||||
official = strict.get("official_primary_evidence") or {}
|
||||
local = strict.get("local_supplemental_evidence") or {}
|
||||
fallback_used = strict.get("fallback_used") or []
|
||||
blocked_items = strict.get("blocked_items") or []
|
||||
conflicts = strict.get("conflicts") or []
|
||||
return {
|
||||
"functional_benefic_malefic": {
|
||||
"gate": "hard",
|
||||
"used": bool((present.get("functional_benefic_malefic") or {}).get("status") == "used"),
|
||||
"note": (present.get("functional_benefic_malefic") or {}).get("effect_on_confidence"),
|
||||
},
|
||||
"relevant_vargas": {
|
||||
"gate": "hard",
|
||||
"required_keys": _route_varga_gate_keys(route),
|
||||
"present_keys": [key for key in _route_varga_gate_keys(route) if present.get(key)],
|
||||
},
|
||||
"vimshottari_narayana_crosscheck": {
|
||||
"gate": "hard",
|
||||
"used": bool(present.get("vimshottari_current")) and bool(present.get("narayana_current")),
|
||||
"required_timing_systems": ["Vimshottari", "Narayana"],
|
||||
},
|
||||
"source_priority_boundary": {
|
||||
"gate": "boundary",
|
||||
"official": official,
|
||||
"local": local,
|
||||
"fallback_used": fallback_used,
|
||||
"blocked_items": blocked_items,
|
||||
"conflicts": conflicts,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Attach it in `_attach_top_reader_contract(...)` and mirror it into `multi_reference_reading_summary["audit_gate_frame"]`.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py -k "compact_technique_audit_summary or audit_gate_frame or dual_dasha_gate" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 2: Compact and expose the audit summary through full-reading and prompt pack
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `modules[*_strict_evidence]`
|
||||
- Produces:
|
||||
- compact strict contracts that include `technique_audit_summary`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_full_reading_prompt_pack_carries_compact_technique_audit_summary() -> None:
|
||||
result = run_engine(...)
|
||||
career = result["ai_prompt_pack"]["evidence_snapshot"]["strict_workflow_contracts"]["career"]
|
||||
assert "technique_audit_summary" in career
|
||||
assert career["technique_audit_summary"]["functional_benefic_malefic"]["gate"] == "hard"
|
||||
assert "audit_gate_frame" in career["multi_reference_reading_summary"]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_cli_smoke.py -k "compact_technique_audit_summary" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing `technique_audit_summary`.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
Extend `_compact_strict_workflow_contract(...)` in `scripts/jyotish_engine.py`:
|
||||
|
||||
```python
|
||||
"technique_audit_summary": strict.get("technique_audit_summary") or {},
|
||||
```
|
||||
|
||||
Do not recompute anything new; just pass through the strict contract.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_cli_smoke.py -k "compact_technique_audit_summary" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 3: Surface the same compact audit summary in API outputs
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- strict contract from prompt pack / official full snapshot
|
||||
- Produces:
|
||||
- API outputs containing `technique_audit_summary`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
```python
|
||||
def test_high_rigor_summary_passes_through_compact_technique_audit_summary() -> None:
|
||||
result = handler._high_rigor_vedastro_official_summary(chart)
|
||||
assert result["technique_audit_summary"]["functional_benefic_malefic"]["gate"] == "hard"
|
||||
```
|
||||
|
||||
```python
|
||||
def test_consultation_workflow_surfaces_compact_technique_audit_summary(monkeypatch) -> None:
|
||||
result = handler._compute_consultation_workflow(payload)
|
||||
assert "technique_audit_summary" in result["vedastro_official"]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py -k "compact_technique_audit_summary" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing API passthrough key.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `scripts/jyotish_api_server.py`, add:
|
||||
|
||||
```python
|
||||
'technique_audit_summary': primary_contract.get('technique_audit_summary') or {},
|
||||
```
|
||||
|
||||
to the shared official summary output path.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py -k "compact_technique_audit_summary" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 4: Make frontend and AI chat consume the compact audit summary
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/main.js`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/ai-chat.js`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_frontend_productization.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- compact strict contract
|
||||
- Produces:
|
||||
- UI/AI references to `technique_audit_summary`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_frontend_consumes_compact_technique_audit_summary_in_top_reader_contract() -> None:
|
||||
main = read("main.js")
|
||||
ai_chat = read("ai-chat.js")
|
||||
assert "technique_audit_summary" in main
|
||||
assert "technique_audit_summary" in ai_chat
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_frontend_productization.py -k "compact_technique_audit_summary" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing frontend references.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `main.js` and `ai-chat.js`, read:
|
||||
|
||||
```javascript
|
||||
const techniqueAuditSummary = topReaderContract.technique_audit_summary || {};
|
||||
```
|
||||
|
||||
and surface only a compact summary line, not the whole raw audit table.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_frontend_productization.py -k "compact_technique_audit_summary" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
### Task 5: Run focused regression and update progress
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/progress.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- all changes from Tasks 1-4
|
||||
- Produces:
|
||||
- verification note in `progress.md`
|
||||
|
||||
- [ ] **Step 1: Run focused regression**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest \
|
||||
tests/test_mcp_strict_workflow_career.py \
|
||||
tests/test_mcp_strict_workflow_relationship.py \
|
||||
tests/test_mcp_strict_workflow_finance.py \
|
||||
tests/test_cli_smoke.py \
|
||||
tests/test_api_server_security.py \
|
||||
tests/test_frontend_productization.py \
|
||||
-k "compact_technique_audit_summary or audit_gate_frame" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 2: Update progress**
|
||||
|
||||
Add an entry that the compact `Technique Audit Table` gate now sits inside default strict adjudication.
|
||||
|
||||
- [ ] **Step 3: Run diff hygiene**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected: no output
|
||||
|
||||
## Self-Review
|
||||
|
||||
- Spec coverage: compact strict audit gate, prompt-pack passthrough, API passthrough, frontend consumption, and focused regression are all mapped to tasks.
|
||||
- Placeholder scan: no TODO/TBD placeholders remain.
|
||||
- Type consistency: `technique_audit_summary` and `audit_gate_frame` are used consistently across strict contract, prompt pack, API, and frontend.
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
**Plan complete and saved to `docs/superpowers/plans/2026-06-30-technique-audit-strict-adjudication.md`. Two execution options:**
|
||||
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
**Which approach?**
|
||||
@@ -0,0 +1,571 @@
|
||||
# Top Reader Adjudication Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Upgrade the default `career`, `relationship`, and `finance` reading workflows to use a shared top-reader-style adjudication skeleton with multi-reference summaries and selected modifier bridges, while reusing existing strict workflow code and minimizing extra compute.
|
||||
|
||||
**Architecture:** Reuse the current strict workflow builders in `mcp_server.py` as the primary evidence source, normalize them through a shared adjudication helper, and surface the reshaped contract through `jyotish_engine.py`, `jyotish_api_server.py`, and the existing prompt-pack/frontend consumer layers. Do not introduce a second engine or a full 641-callable VedAstro execution path; instead, reshape current evidence into a common four-stage contract plus a lightweight `multi_reference_reading_summary`.
|
||||
|
||||
**Tech Stack:** Python, existing strict workflow collectors, pytest, existing frontend productization tests, existing prompt-pack evidence snapshot contract.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Reuse current strict workflow collectors before adding new collectors.
|
||||
- Reuse existing bridge helpers before creating new scoring paths.
|
||||
- Reuse current full-reading/module outputs by reference where possible.
|
||||
- Do not add all-method VedAstro execution to the default path.
|
||||
- Prefer small contract reshaping over new compute-heavy logic.
|
||||
- Keep official calls cached and reused; do not add new heavyweight request fans.
|
||||
- Preserve the existing honesty boundaries: emit `blocked`, `conflicts`, and `confidence_cap` instead of smoothing over missing layers.
|
||||
- Keep `career`, `relationship`, and `finance` domain-specific evidence requirements intact while sharing structure.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add the shared adjudication contract builder in `mcp_server.py`
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_career.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_finance.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- existing strict route `present_evidence`
|
||||
- existing `event_judgement`
|
||||
- existing `official_primary_evidence`
|
||||
- existing `local_supplemental_evidence`
|
||||
- existing `conflicts`
|
||||
- existing `confidence_cap`
|
||||
- Produces:
|
||||
- `_build_adjudication_stages(route: str, present: Dict[str, Any], event_judgement: Dict[str, Any]) -> Dict[str, Any]`
|
||||
- `_build_multi_reference_reading_summary(route: str, present: Dict[str, Any], strict: Dict[str, Any]) -> Dict[str, Any]`
|
||||
- strict contract keys:
|
||||
- `adjudication_stages`
|
||||
- `multi_reference_reading_summary`
|
||||
- `verdict`
|
||||
- `dominant_label`
|
||||
- `main_conflicts`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add assertions to each strict workflow domain test file for the new shared fields:
|
||||
|
||||
```python
|
||||
def test_career_strict_contract_exposes_adjudication_stages() -> None:
|
||||
result = mcp_server._collect_strict_evidence("career", modules)
|
||||
assert result["adjudication_stages"]["promise"]["status"] in {"present", "weak", "missing"}
|
||||
assert result["adjudication_stages"]["activation"]["required_timing_systems"] == ["Vimshottari", "Narayana"]
|
||||
assert "multi_reference_reading_summary" in result
|
||||
assert "root_frame" in result["multi_reference_reading_summary"]
|
||||
```
|
||||
|
||||
Repeat the same shape expectation for `relationship` and `finance`, adapted to each route.
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py -k "adjudication_stages or multi_reference_reading_summary" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing strict contract keys such as `adjudication_stages` or `multi_reference_reading_summary`.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Implement shared helpers near the existing strict helper section in `mcp_server.py`:
|
||||
|
||||
```python
|
||||
def _build_adjudication_stages(route: str, present: Dict[str, Any], event_judgement: Dict[str, Any]) -> Dict[str, Any]:
|
||||
dominant_label = event_judgement.get("dominant_label")
|
||||
return {
|
||||
"promise": {
|
||||
"status": "present" if _has_promise_evidence(route, present) else "weak",
|
||||
"drivers": _promise_drivers(route, present),
|
||||
},
|
||||
"activation": {
|
||||
"status": "present" if _has_activation_evidence(route, present) else "weak",
|
||||
"required_timing_systems": ["Vimshottari", "Narayana"],
|
||||
"drivers": _activation_drivers(route, present),
|
||||
},
|
||||
"manifestation": {
|
||||
"status": "present" if dominant_label else "weak",
|
||||
"drivers": event_judgement.get("secondary_context") or [],
|
||||
},
|
||||
"label": {
|
||||
"status": "present" if dominant_label else "missing",
|
||||
"value": dominant_label,
|
||||
"verdict": event_judgement.get("verdict"),
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Also add a small route-aware summary builder:
|
||||
|
||||
```python
|
||||
def _build_multi_reference_reading_summary(route: str, present: Dict[str, Any], strict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
return {
|
||||
"root_frame": _summary_root_frame(route, present),
|
||||
"divisional_frame": _summary_divisional_frame(route, present),
|
||||
"visibility_frame": _summary_visibility_frame(route, present),
|
||||
"karaka_frame": _summary_karaka_frame(route, present),
|
||||
"timing_frame": _summary_timing_frame(route, present),
|
||||
"modifier_frame": _summary_modifier_frame(route, present),
|
||||
"conflict_frame": {
|
||||
"conflicts": strict.get("conflicts") or [],
|
||||
"confidence_cap": strict.get("confidence_cap"),
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Attach these fields inside each strict route result, reusing the current per-route `present` and `event_judgement`.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py -k "adjudication_stages or multi_reference_reading_summary" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add mcp_server.py tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py
|
||||
git commit -m "feat: add shared top-reader adjudication contract"
|
||||
```
|
||||
|
||||
### Task 2: Promote selected bridge layers into the shared modifier frame
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_finance.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_functional_layer.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- `present["functional_benefic_malefic"]`
|
||||
- `present["ashtakavarga_finance_support"]`
|
||||
- `present["wealth_promise_strength"]`
|
||||
- marriage route evidence already emitted into `present`
|
||||
- `yogi_active` in finance `event_judgement.secondary_context`
|
||||
- Produces:
|
||||
- `multi_reference_reading_summary["modifier_frame"]`
|
||||
- `adjudication_stages["manifestation"]["bridge_modifiers"]`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add focused bridge promotion assertions:
|
||||
|
||||
```python
|
||||
def test_finance_summary_modifier_frame_includes_yogi_and_ashtakavarga_only_as_modifiers() -> None:
|
||||
strict = mcp_server._collect_strict_evidence("finance", modules)
|
||||
modifier = strict["multi_reference_reading_summary"]["modifier_frame"]
|
||||
assert "functional_benefic_malefic" in modifier
|
||||
assert modifier["ashtakavarga_finance_support"]["source"] == "ashtakavarga_house_scores_bridge_v1"
|
||||
assert modifier["yogi_support"]["role"] == "modifier_only"
|
||||
```
|
||||
|
||||
```python
|
||||
def test_relationship_summary_modifier_frame_surfaces_label_lift_related_modifiers() -> None:
|
||||
strict = mcp_server._collect_strict_evidence("relationship", modules)
|
||||
modifier = strict["multi_reference_reading_summary"]["modifier_frame"]
|
||||
assert "functional_benefic_malefic" in modifier
|
||||
assert "manifestation_split" in modifier
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_finance.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_functional_layer.py -k "modifier_frame or yogi or manifestation_split" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing modifier-frame keys.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Extend the summary helpers in `mcp_server.py`:
|
||||
|
||||
```python
|
||||
def _summary_modifier_frame(route: str, present: Dict[str, Any]) -> Dict[str, Any]:
|
||||
frame = {
|
||||
"functional_benefic_malefic": present.get("functional_benefic_malefic"),
|
||||
"shadbala": present.get("shadbala"),
|
||||
"argala_support": present.get("argala_support"),
|
||||
}
|
||||
if route == "finance":
|
||||
frame["ashtakavarga_finance_support"] = present.get("ashtakavarga_finance_support")
|
||||
frame["yogi_support"] = {
|
||||
"role": "modifier_only",
|
||||
"value": present.get("wealth_promise_strength"),
|
||||
}
|
||||
if route == "relationship":
|
||||
frame["manifestation_split"] = {
|
||||
"role": "modifier_only",
|
||||
"signals": [
|
||||
"relationship_formation",
|
||||
"legal_marriage",
|
||||
"public_formalization",
|
||||
],
|
||||
}
|
||||
return frame
|
||||
```
|
||||
|
||||
Do not create new calculators here; only repackage current evidence and known route-specific bridge metadata.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_finance.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_functional_layer.py -k "modifier_frame or yogi or manifestation_split" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add mcp_server.py tests/test_mcp_strict_workflow_finance.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_functional_layer.py
|
||||
git commit -m "feat: promote selected bridge layers into shared modifiers"
|
||||
```
|
||||
|
||||
### Task 3: Compact and expose the new contract through `jyotish_engine.py`
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_official_full_snapshot.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- strict workflow contracts embedded in `modules`
|
||||
- Produces:
|
||||
- `_compact_strict_workflow_contract(strict: Dict[str, Any]) -> Dict[str, Any]`
|
||||
- `ai_prompt_pack["evidence_snapshot"]["strict_workflow_contracts"][route]["adjudication_stages"]`
|
||||
- `ai_prompt_pack["evidence_snapshot"]["strict_workflow_contracts"][route]["multi_reference_reading_summary"]`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add prompt-pack expectations:
|
||||
|
||||
```python
|
||||
def test_full_reading_prompt_pack_carries_adjudication_stages_and_multi_reference_summary() -> None:
|
||||
result = run_full_reading(...)
|
||||
strict = result["ai_prompt_pack"]["evidence_snapshot"]["strict_workflow_contracts"]["career"]
|
||||
assert "adjudication_stages" in strict
|
||||
assert "multi_reference_reading_summary" in strict
|
||||
assert "modifier_frame" in strict["multi_reference_reading_summary"]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_cli_smoke.py tests/test_vedastro_official_full_snapshot.py -k "adjudication_stages or multi_reference_reading_summary" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing keys in compact strict workflow contract or evidence snapshot.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Extend the strict contract compactor in `scripts/jyotish_engine.py`:
|
||||
|
||||
```python
|
||||
def _compact_strict_workflow_contract(strict):
|
||||
return {
|
||||
"confidence_cap": strict.get("confidence_cap"),
|
||||
"blocked": strict.get("blocked"),
|
||||
"blocked_items": strict.get("blocked_items") or [],
|
||||
"conflicts": strict.get("conflicts") or [],
|
||||
"official_primary_evidence": strict.get("official_primary_evidence") or {},
|
||||
"local_supplemental_evidence": strict.get("local_supplemental_evidence") or {},
|
||||
"adjudication_stages": strict.get("adjudication_stages") or {},
|
||||
"multi_reference_reading_summary": strict.get("multi_reference_reading_summary") or {},
|
||||
"verdict": strict.get("verdict"),
|
||||
"dominant_label": strict.get("dominant_label"),
|
||||
"main_conflicts": strict.get("main_conflicts") or [],
|
||||
}
|
||||
```
|
||||
|
||||
Also ensure the prompt-pack evidence snapshot reuses this compacted form instead of recomputing anything heavy.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_cli_smoke.py tests/test_vedastro_official_full_snapshot.py -k "adjudication_stages or multi_reference_reading_summary" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/jyotish_engine.py tests/test_cli_smoke.py tests/test_vedastro_official_full_snapshot.py
|
||||
git commit -m "feat: expose top-reader contract in prompt pack"
|
||||
```
|
||||
|
||||
### Task 4: Surface the reshaped contract in API outputs with no extra heavy recompute
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_historical_event_backtest.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- prompt-pack `evidence_snapshot`
|
||||
- existing consultation workflow contract
|
||||
- strict workflow contract summary
|
||||
- Produces:
|
||||
- consultation/high-rigor API outputs that include:
|
||||
- `adjudication_stages`
|
||||
- `multi_reference_reading_summary`
|
||||
- `verdict`
|
||||
- `dominant_label`
|
||||
- `main_conflicts`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add API-level shape assertions:
|
||||
|
||||
```python
|
||||
def test_consultation_workflow_passes_through_top_reader_contract(monkeypatch) -> None:
|
||||
result = handler._compute_consultation_workflow(payload)
|
||||
guided = result["guided_topics"][0]
|
||||
assert "adjudication_stages" in guided
|
||||
assert "multi_reference_reading_summary" in guided
|
||||
```
|
||||
|
||||
```python
|
||||
def test_high_rigor_summary_passes_through_multi_reference_summary(monkeypatch) -> None:
|
||||
summary = handler._high_rigor_vedastro_official_summary(prompt_official, range_scan, range_metadata)
|
||||
assert "multi_reference_reading_summary" in summary
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py tests/test_historical_event_backtest.py -k "top_reader_contract or multi_reference_reading_summary" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing API passthrough keys.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Update `scripts/jyotish_api_server.py` to reuse existing prompt-pack or strict contract nodes:
|
||||
|
||||
```python
|
||||
strict_contract = prompt_official.get("strict_workflow_contracts", {}).get(route_key, {})
|
||||
summary["adjudication_stages"] = strict_contract.get("adjudication_stages") or {}
|
||||
summary["multi_reference_reading_summary"] = strict_contract.get("multi_reference_reading_summary") or {}
|
||||
summary["verdict"] = strict_contract.get("verdict")
|
||||
summary["dominant_label"] = strict_contract.get("dominant_label")
|
||||
summary["main_conflicts"] = strict_contract.get("main_conflicts") or strict_contract.get("conflicts") or []
|
||||
```
|
||||
|
||||
Where guided topic objects are built, attach the same already-computed contract by reference or compact copy; do not call full-reading again.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_api_server_security.py tests/test_historical_event_backtest.py -k "top_reader_contract or multi_reference_reading_summary" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/jyotish_api_server.py tests/test_api_server_security.py tests/test_historical_event_backtest.py
|
||||
git commit -m "feat: surface top-reader adjudication contract in api outputs"
|
||||
```
|
||||
|
||||
### Task 5: Keep the frontend and user-facing surfaces simple while consuming the richer contract
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/main.js`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/ai-chat.js`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_frontend_productization.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- consultation workflow output
|
||||
- prompt-pack evidence snapshot
|
||||
- compact strict contract
|
||||
- Produces:
|
||||
- visible simple user summaries
|
||||
- AI chat context that includes the new top-reader contract
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add frontend token tests:
|
||||
|
||||
```python
|
||||
def test_ai_chat_and_complete_reading_surface_top_reader_contract_tokens() -> None:
|
||||
main = read_main_js()
|
||||
ai_chat = read_ai_chat_js()
|
||||
assert "multi_reference_reading_summary" in main
|
||||
assert "adjudication_stages" in main
|
||||
assert "multi_reference_reading_summary" in ai_chat
|
||||
assert "adjudication_stages" in ai_chat
|
||||
```
|
||||
|
||||
Also add one test that the UI still prefers compact summaries rather than dumping raw full evidence.
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_frontend_productization.py -k "top_reader_contract or multi_reference_reading_summary or adjudication_stages" -q
|
||||
```
|
||||
|
||||
Expected: FAIL with missing frontend references to the new contract.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Update frontend readers to expose only compact user-facing summaries and AI context:
|
||||
|
||||
```javascript
|
||||
const topReaderContract = chartData?.ai_prompt_pack?.evidence_snapshot?.strict_workflow_contracts?.[routeKey] || {};
|
||||
const adjudicationStages = topReaderContract.adjudication_stages || {};
|
||||
const multiReferenceSummary = topReaderContract.multi_reference_reading_summary || {};
|
||||
```
|
||||
|
||||
Use these to:
|
||||
|
||||
- show a compact “how this conclusion was formed” section
|
||||
- append structured context to AI chat
|
||||
- avoid rendering the full raw evidence tree unless already needed in an audit panel
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_frontend_productization.py -k "top_reader_contract or multi_reference_reading_summary or adjudication_stages" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add jyotish-app/main.js jyotish-app/ai-chat.js tests/test_frontend_productization.py
|
||||
git commit -m "feat: consume top-reader adjudication contract in frontend"
|
||||
```
|
||||
|
||||
### Task 6: Run the focused regression bundle and then the broader verification pass
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/progress.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes:
|
||||
- all modified code from Tasks 1-5
|
||||
- Produces:
|
||||
- recorded verification summary in `progress.md`
|
||||
|
||||
- [ ] **Step 1: Run the focused contract regressions**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest \
|
||||
tests/test_mcp_strict_workflow_career.py \
|
||||
tests/test_mcp_strict_workflow_relationship.py \
|
||||
tests/test_mcp_strict_workflow_finance.py \
|
||||
tests/test_mcp_strict_workflow_functional_layer.py \
|
||||
tests/test_cli_smoke.py \
|
||||
tests/test_vedastro_official_full_snapshot.py \
|
||||
tests/test_api_server_security.py \
|
||||
tests/test_historical_event_backtest.py \
|
||||
tests/test_frontend_productization.py \
|
||||
-k "adjudication_stages or multi_reference_reading_summary or top_reader_contract or modifier_frame" -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 2: Run the broader targeted verification**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py tests/test_api_server_security.py tests/test_cli_smoke.py tests/test_frontend_productization.py -q
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 3: Update `progress.md` with the landed contract and verification notes**
|
||||
|
||||
Add an entry similar to:
|
||||
|
||||
```markdown
|
||||
- 2026-06-30 Top-reader adjudication contract landed:
|
||||
- shared `promise -> activation -> manifestation -> label`
|
||||
- `multi_reference_reading_summary`
|
||||
- bridge promotion kept modifier-only
|
||||
- prompt-pack/API/frontend all consume the same compact contract
|
||||
- focused and targeted regressions passed
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run diff hygiene checks**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected: no output
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add progress.md
|
||||
git commit -m "docs: record top-reader adjudication verification"
|
||||
```
|
||||
|
||||
## Self-Review
|
||||
|
||||
### Spec coverage
|
||||
|
||||
- Shared four-stage skeleton: covered by Task 1
|
||||
- Multi-reference summary: covered by Tasks 1, 3, 4, and 5
|
||||
- Selected bridge promotion: covered by Task 2
|
||||
- Prompt-pack/API/frontend consumption: covered by Tasks 3, 4, and 5
|
||||
- Compute minimization and reuse constraints: enforced in every task through existing-contract reuse and no new engine work
|
||||
|
||||
### Placeholder scan
|
||||
|
||||
- No `TODO`, `TBD`, or “implement later” placeholders remain.
|
||||
- Each task includes exact files, exact commands, and exact expected behavior.
|
||||
|
||||
### Type consistency
|
||||
|
||||
- `adjudication_stages` and `multi_reference_reading_summary` are introduced first in `mcp_server.py`, then compacted in `jyotish_engine.py`, then consumed in `jyotish_api_server.py` and frontend.
|
||||
- `verdict`, `dominant_label`, and `main_conflicts` are named consistently across all tasks.
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
**Plan complete and saved to `docs/superpowers/plans/2026-06-30-top-reader-adjudication.md`. Two execution options:**
|
||||
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
**Which approach?**
|
||||
@@ -0,0 +1,405 @@
|
||||
# VedAstro Daily Window Priority Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Promote official VedAstro range-scan output into reusable day-window evidence that strict career/marriage/wealth workflows can consume directly.
|
||||
|
||||
**Architecture:** Reuse the existing `SearchEvents` adapter, orchestration, and strict workflow chain. Add adapter-level day-window aggregation, propagate it through `vedastro_evidence_orchestrator`, expose it inside `external_activation`, and surface it through `life_event_graph_v1` and `full-reading` outputs.
|
||||
|
||||
**Tech Stack:** Python 3, existing Jyotish engine, existing VedAstro service adapter, pytest.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Reuse existing `scripts/vedastro_service_adapter.py`, `scripts/vedastro_evidence_orchestrator.py`, `mcp_server.py`, and `scripts/jyotish_engine.py`; do not create a parallel official-event stack.
|
||||
- Keep official VedAstro as primary raw evidence and local Jyotish modules as adjudication/promise/timing cross-check layers.
|
||||
- Do not bypass D9/D10/D2/UL/A10/Narayana/Functional Benefic-Malefic gates.
|
||||
- Preserve existing response cache and free-tier queue logic.
|
||||
- Keep changes focused on daily-window extraction and propagation, not a month-grid product.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add failing adapter tests for daily-window aggregation
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_range_scan_replay.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_range_scan_replay.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `scripts.vedastro_service_adapter._normalize_range_scan_success(payload, endpoint, request_preview, attempt_count=1, retry_error_codes=None) -> dict`
|
||||
- Produces: adapter results with `daily_windows: list[dict]` and `top_daily_window: dict | None`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_range_scan_builds_ranked_daily_windows_from_same_day_events() -> None:
|
||||
payload = {
|
||||
"Status": "Pass",
|
||||
"Payload": [
|
||||
{
|
||||
"Name": "GocharJupiterAspect10th",
|
||||
"Description": "Career support transit.",
|
||||
"StartTime": "2026-07-18",
|
||||
"EndTime": "2026-07-18",
|
||||
"EventTags": ["Travel", "General"],
|
||||
},
|
||||
{
|
||||
"Name": "CareerExpansionWindow",
|
||||
"Description": "Strong career expansion signal.",
|
||||
"StartTime": "2026-07-18",
|
||||
"EndTime": "2026-07-18",
|
||||
"EventTags": ["career", "transit"],
|
||||
},
|
||||
{
|
||||
"Name": "GocharJupiterAspect10th",
|
||||
"Description": "Career support transit.",
|
||||
"StartTime": "2026-07-26",
|
||||
"EndTime": "2026-07-26",
|
||||
"EventTags": ["Travel", "General"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
report = vedastro_service_adapter._normalize_range_scan_success( # noqa: SLF001
|
||||
payload,
|
||||
"https://api.vedastro.org/api",
|
||||
_request_preview("career"),
|
||||
)
|
||||
|
||||
assert report["daily_windows"][0]["date"] == "2026-07-18"
|
||||
assert report["daily_windows"][0]["event_count"] == 2
|
||||
assert report["top_daily_window"]["date"] == "2026-07-18"
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_vedastro_range_scan_replay.py::test_range_scan_builds_ranked_daily_windows_from_same_day_events -q`
|
||||
|
||||
Expected: FAIL because `daily_windows` / `top_daily_window` are missing.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
Add a helper in `scripts/vedastro_service_adapter.py`:
|
||||
|
||||
```python
|
||||
def _build_daily_windows(domain: str, evidence_ledger: list[dict[str, Any]]) -> tuple[list[dict[str, Any]], dict[str, Any] | None]:
|
||||
...
|
||||
```
|
||||
|
||||
and call it from `_normalize_range_scan_success(...)`.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_vedastro_range_scan_replay.py::test_range_scan_builds_ranked_daily_windows_from_same_day_events -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/test_vedastro_range_scan_replay.py scripts/vedastro_service_adapter.py
|
||||
git commit -m "feat: add vedastro daily window aggregation"
|
||||
```
|
||||
|
||||
### Task 2: Propagate daily windows through orchestrator
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/vedastro_evidence_orchestrator.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_evidence_orchestrator.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_vedastro_evidence_orchestrator.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `run_range_scan_for_case(...) -> dict` with `daily_windows` and `top_daily_window`
|
||||
- Produces: orchestrator result keys:
|
||||
- `daily_windows_by_domain: dict[str, list[dict]]`
|
||||
- `top_daily_window_by_domain: dict[str, dict]`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_vedastro_orchestrator_surfaces_daily_windows_by_domain(monkeypatch) -> None:
|
||||
from scripts import vedastro_evidence_orchestrator as orchestrator
|
||||
|
||||
monkeypatch.setattr(orchestrator, "run_official_full_snapshot_for_case", lambda *args, **kwargs: {"status": "ok", "source_metadata": {}})
|
||||
monkeypatch.setattr(
|
||||
orchestrator,
|
||||
"run_range_scan_for_case",
|
||||
lambda *args, **kwargs: {
|
||||
"status": "ok",
|
||||
"available": True,
|
||||
"event_count": 2,
|
||||
"daily_windows": [{"date": "2026-07-18", "domain": "career", "score": 5, "event_count": 2}],
|
||||
"top_daily_window": {"date": "2026-07-18", "domain": "career", "score": 5, "event_count": 2},
|
||||
"evidence_ledger": [],
|
||||
},
|
||||
)
|
||||
|
||||
result = orchestrator.orchestrate_vedastro_evidence(
|
||||
{"year": REDACTED_YEAR, "month": 4, "day": 17, "hour": 14, "minute": 49, "lat": 36.42, "lon": 114.2, "tz": 8},
|
||||
route="career",
|
||||
reference_date="2026-06-30",
|
||||
)
|
||||
|
||||
assert result["daily_windows_by_domain"]["career"][0]["date"] == "2026-07-18"
|
||||
assert result["top_daily_window_by_domain"]["career"]["score"] == 5
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_vedastro_evidence_orchestrator.py::test_vedastro_orchestrator_surfaces_daily_windows_by_domain -q`
|
||||
|
||||
Expected: FAIL because orchestrator does not yet expose these keys.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `scripts/vedastro_evidence_orchestrator.py`, collect from each domain report:
|
||||
|
||||
```python
|
||||
daily_windows_by_domain[domain] = report.get("daily_windows") or []
|
||||
if isinstance(report.get("top_daily_window"), dict):
|
||||
top_daily_window_by_domain[domain] = report["top_daily_window"]
|
||||
```
|
||||
|
||||
and return them in the final payload.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_vedastro_evidence_orchestrator.py::test_vedastro_orchestrator_surfaces_daily_windows_by_domain -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/vedastro_evidence_orchestrator.py tests/test_vedastro_evidence_orchestrator.py
|
||||
git commit -m "feat: propagate vedastro daily windows through orchestrator"
|
||||
```
|
||||
|
||||
### Task 3: Promote daily windows into strict workflow external activation
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_career.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_finance.py`
|
||||
- Test: same files
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `modules.vedastro_range_scan_result.daily_windows` / `top_daily_window`
|
||||
- Produces: `present_evidence.external_activation.daily_windows` and `present_evidence.external_activation.top_daily_window`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_relationship_external_activation_exposes_top_daily_window() -> None:
|
||||
result = {
|
||||
"modules": {
|
||||
"vedastro_range_scan_result": {
|
||||
"backend": "vedastro_service_adapter_candidate",
|
||||
"status": "ok",
|
||||
"operation": "range_scan",
|
||||
"domain": "marriage",
|
||||
"evidence_ledger": [],
|
||||
"daily_windows": [{"date": "2026-08-02", "domain": "marriage", "score": 5, "event_count": 2}],
|
||||
"top_daily_window": {"date": "2026-08-02", "domain": "marriage", "score": 5, "event_count": 2},
|
||||
"source_metadata": {},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
strict = _collect_strict_evidence("relationship", result)
|
||||
external = strict["present_evidence"]["external_activation"]
|
||||
|
||||
assert external["top_daily_window"]["date"] == "2026-08-02"
|
||||
assert external["daily_windows"][0]["score"] == 5
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_mcp_strict_workflow_relationship.py::test_relationship_external_activation_exposes_top_daily_window -q`
|
||||
|
||||
Expected: FAIL because `external_activation` does not yet carry day-window fields.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
Extend `_derive_external_activation_support(...)` in `mcp_server.py` to read:
|
||||
|
||||
```python
|
||||
daily_windows = adapter_result.get("daily_windows") or []
|
||||
top_daily_window = adapter_result.get("top_daily_window")
|
||||
```
|
||||
|
||||
and include them in the returned dict.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_mcp_strict_workflow_relationship.py::test_relationship_external_activation_exposes_top_daily_window -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add mcp_server.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_finance.py
|
||||
git commit -m "feat: expose vedastro daily windows in strict workflow"
|
||||
```
|
||||
|
||||
### Task 4: Surface official day windows in life event graph
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_life_event_graph_v1.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_life_event_graph_v1.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `present_evidence.external_activation.daily_windows`
|
||||
- Produces: `life_event_graph.event_nodes[]` entries with `kind: "official_day_window"`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_life_event_graph_surfaces_ranked_official_day_window_nodes() -> None:
|
||||
strict = {
|
||||
"event_judgement": {"event_family": "career", "verdict": "moderate_probability_window", "score": 74},
|
||||
"present_evidence": {
|
||||
"external_activation": {
|
||||
"level": "moderate",
|
||||
"source": "vedastro_service_adapter_candidate",
|
||||
"daily_windows": [
|
||||
{
|
||||
"date": "2026-07-18",
|
||||
"domain": "career",
|
||||
"score": 5,
|
||||
"confidence": "medium_high",
|
||||
"event_count": 2,
|
||||
"signal_families": ["career_trigger"],
|
||||
"event_ids": ["GocharJupiterAspect10th", "CareerExpansionWindow"],
|
||||
"top_signal_label": "Career expansion window",
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
"confidence_cap": "medium",
|
||||
"missing_evidence": [],
|
||||
"blocked": False,
|
||||
}
|
||||
|
||||
graph = _build_life_event_graph("career", strict)
|
||||
|
||||
assert any(node["kind"] == "official_day_window" and node["date"] == "2026-07-18" for node in graph["event_nodes"])
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_life_event_graph_v1.py::test_life_event_graph_surfaces_ranked_official_day_window_nodes -q`
|
||||
|
||||
Expected: FAIL because no `official_day_window` nodes exist yet.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `_build_life_event_graph(...)`, after `external_window` nodes, append:
|
||||
|
||||
```python
|
||||
{
|
||||
"kind": "official_day_window",
|
||||
"date": window.get("date"),
|
||||
"domain": window.get("domain"),
|
||||
"score": window.get("score"),
|
||||
"confidence": window.get("confidence"),
|
||||
"event_count": window.get("event_count"),
|
||||
"top_signal_label": window.get("top_signal_label"),
|
||||
"signal_families": window.get("signal_families") or [],
|
||||
"event_ids": window.get("event_ids") or [],
|
||||
"source": external_activation.get("source"),
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_life_event_graph_v1.py::test_life_event_graph_surfaces_ranked_official_day_window_nodes -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add mcp_server.py tests/test_life_event_graph_v1.py
|
||||
git commit -m "feat: show official vedastro day windows in life event graph"
|
||||
```
|
||||
|
||||
### Task 5: Attach daily-window expansion to full-reading and verify output contract
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: existing `modules.vedastro_range_scan_result`
|
||||
- Produces: `modules.vedastro_range_scan_result.daily_windows`, `summary.guided_topics`, and strict contracts that can reach day-window evidence through downstream modules
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```python
|
||||
def test_full_reading_preserves_official_daily_window_fields_in_range_scan_result() -> None:
|
||||
result = run_engine(
|
||||
"full-reading",
|
||||
"--year", "REDACTED_YEAR",
|
||||
"--month", "4",
|
||||
"--day", "17",
|
||||
"--hour", "14",
|
||||
"--minute", "49",
|
||||
"--lat", "36.42",
|
||||
"--lon", "114.2",
|
||||
"--tz", "8",
|
||||
"--today", "2026-06-30",
|
||||
"--transit-date", "2026-06-30",
|
||||
)
|
||||
|
||||
vedastro = result["modules"]["vedastro_range_scan_result"]
|
||||
assert "daily_windows" in vedastro
|
||||
assert "top_daily_window" in vedastro
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `python3 -m pytest tests/test_cli_smoke.py::test_full_reading_preserves_official_daily_window_fields_in_range_scan_result -q`
|
||||
|
||||
Expected: FAIL if full-reading path still attaches only overview fields.
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
Ensure `scripts/jyotish_engine.py` keeps adapter-derived daily-window fields intact when composing:
|
||||
|
||||
- `modules.vedastro_range_scan_result`
|
||||
- `ai_prompt_pack.evidence_snapshot.vedastro_overview`
|
||||
|
||||
No reformatting layer should drop them.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `python3 -m pytest tests/test_cli_smoke.py::test_full_reading_preserves_official_daily_window_fields_in_range_scan_result -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/jyotish_engine.py tests/test_cli_smoke.py
|
||||
git commit -m "feat: preserve vedastro daily window evidence in full reading"
|
||||
```
|
||||
|
||||
## Self-Review
|
||||
|
||||
- Spec coverage: adapter aggregation, orchestrator propagation, strict workflow promotion, graph exposure, full-reading preservation are all covered.
|
||||
- Placeholder scan: no TBD/TODO placeholders remain.
|
||||
- Type consistency: `daily_windows` is always `list[dict]`; `top_daily_window` is always `dict | None`; `official_day_window` is the graph node name across tasks.
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
Plan complete and saved to `docs/superpowers/plans/2026-06-30-vedastro-daily-window-priority.md`. Two execution options:
|
||||
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
**Which approach?**
|
||||
@@ -0,0 +1,376 @@
|
||||
# VedAstro Official Hard-Override Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make `relationship`, `career`, and `wealth` default workflows enforce `VedAstro official -> local supplemental -> local fallback`, with honest `blocked`, `conflicts`, and `confidence_cap` output.
|
||||
|
||||
**Architecture:** Reuse the existing `vedastro_evidence_orchestrator`, `vedastro_priority`, `mcp_server` strict evidence collectors, `jyotish_engine`, and `jyotish_api_server` rather than creating a second workflow. Promote official-first evidence into a shared strict contract, then expose that same contract through API and report surfaces.
|
||||
|
||||
**Tech Stack:** Python standard library, existing MCP strict workflow, pytest, existing API/frontend static tests.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Official VedAstro data is primary when available.
|
||||
- Local modules may supplement, cross-check, or fallback, but may not silently overwrite official values.
|
||||
- Timing and event outputs must keep `Vimshottari + Narayana` dual-track rigor.
|
||||
- Relationship must keep `D9 + UL`.
|
||||
- Career must keep `D10 + A10`.
|
||||
- Wealth must keep `D2 / D11`.
|
||||
- Functional Benefic/Malefic must remain explicit in high-rigor outputs.
|
||||
- New behavior must be introduced with failing tests first.
|
||||
- Do not create a parallel orchestration stack when existing files can be extended safely.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add Red Tests For The Shared Official-First Strict Contract
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Modify: `tests/test_mcp_strict_workflow_career.py`
|
||||
- Modify: `tests/test_mcp_strict_workflow_finance.py`
|
||||
- Modify: `tests/test_historical_event_backtest.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces strict fields:
|
||||
- `official_primary_evidence: dict`
|
||||
- `local_supplemental_evidence: dict`
|
||||
- `fallback_used: list[str]`
|
||||
- `blocked_items: list[str]`
|
||||
- `conflicts: list[dict]`
|
||||
- `confidence_cap: str`
|
||||
|
||||
- [ ] **Step 1: Write the failing relationship test**
|
||||
|
||||
```python
|
||||
def test_relationship_strict_contract_exposes_official_primary_and_local_supplemental_layers() -> None:
|
||||
result = _base_relationship_result()
|
||||
result["modules"]["source_priority"] = {"mode": "vedastro_official_primary"}
|
||||
result["modules"]["vedastro_official_full_snapshot"] = {
|
||||
"status": "partial",
|
||||
"available": True,
|
||||
"official_chart": {"planets": {"Sun": {}}, "ascendant": {"sign": "Leo"}},
|
||||
"section_statuses": {"chart_core": "ok", "dasha_all": "ok", "events_overview": "partial"},
|
||||
}
|
||||
|
||||
strict = _collect_strict_evidence("relationship", result)
|
||||
|
||||
assert strict["official_primary_evidence"]["chart_core"]["status"] == "ok"
|
||||
assert strict["local_supplemental_evidence"]["upapada_lagna"]["role"] == "required_local_supplement"
|
||||
assert isinstance(strict["blocked_items"], list)
|
||||
assert isinstance(strict["fallback_used"], list)
|
||||
assert isinstance(strict["conflicts"], list)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Write the failing career and finance tests**
|
||||
|
||||
```python
|
||||
def test_career_strict_contract_marks_a10_as_local_supplement_to_official_primary() -> None:
|
||||
result = _base_career_result()
|
||||
result["modules"]["source_priority"] = {"mode": "vedastro_official_primary"}
|
||||
result["modules"]["vedastro_official_full_snapshot"] = {
|
||||
"status": "partial",
|
||||
"available": True,
|
||||
"official_chart": {"planets": {"Sun": {}}, "ascendant": {"sign": "Leo"}},
|
||||
"section_statuses": {"chart_core": "ok", "dasha_all": "ok"},
|
||||
}
|
||||
strict = _collect_strict_evidence("career", result)
|
||||
assert strict["official_primary_evidence"]["dasha"]["status"] == "ok"
|
||||
assert strict["local_supplemental_evidence"]["a10_karma_pada"]["role"] == "required_local_supplement"
|
||||
|
||||
|
||||
def test_finance_strict_contract_surfaces_official_block_and_local_fallback_usage() -> None:
|
||||
result = {"modules": {"source_priority": {"mode": "local_fallback_official_blocked"}}}
|
||||
strict = _collect_strict_evidence("finance", result)
|
||||
assert "official_primary_chart_blocked" in strict["blocked_items"]
|
||||
assert isinstance(strict["fallback_used"], list)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Write the failing backtest test**
|
||||
|
||||
```python
|
||||
def test_backtest_carries_conflicts_and_blocked_items_from_strict_contract(monkeypatch) -> None:
|
||||
def fake_strict_workflow(**kwargs):
|
||||
packet = _strict_packet("career", verdict="high_probability_window", dominant_label="career_status", score=84)
|
||||
packet["strict_workflow"]["blocked_items"] = ["official_event_radar_partial"]
|
||||
packet["strict_workflow"]["conflicts"] = [{"type": "official_local_dasha_conflict"}]
|
||||
return packet
|
||||
|
||||
monkeypatch.setattr(backtest.mcp_server, "strict_workflow", fake_strict_workflow)
|
||||
report = backtest.build_report(_payload([{"id": "career_turn_2019", "date": "2019-12-15", "domain": "career"}]))
|
||||
assert report["events"][0]["evidence"]["blocked_items"] == ["official_event_radar_partial"]
|
||||
assert report["events"][0]["evidence"]["conflicts"] == [{"type": "official_local_dasha_conflict"}]
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they fail**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_finance.py tests/test_historical_event_backtest.py -k "strict_contract or conflicts_and_blocked_items" -q`
|
||||
|
||||
Expected: FAIL because the strict contract fields do not yet exist.
|
||||
|
||||
### Task 2: Implement Shared Official-First Strict Contract In MCP Strict Workflow
|
||||
|
||||
**Files:**
|
||||
- Modify: `mcp_server.py`
|
||||
- Test: `tests/test_mcp_strict_workflow_relationship.py`
|
||||
- Test: `tests/test_mcp_strict_workflow_career.py`
|
||||
- Test: `tests/test_mcp_strict_workflow_finance.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- `_build_official_primary_evidence(route: str, modules: dict, present: dict) -> dict`
|
||||
- `_build_local_supplemental_evidence(route: str, present: dict) -> dict`
|
||||
- `_build_fallback_and_blocked(route: str, present: dict, missing: list[str]) -> tuple[list[str], list[str]]`
|
||||
- `_build_conflicts(route: str, present: dict, missing: list[str]) -> list[dict]`
|
||||
|
||||
- [ ] **Step 1: Implement helper skeletons in `mcp_server.py`**
|
||||
|
||||
```python
|
||||
def _build_official_primary_evidence(route: str, modules: Dict[str, Any], present: Dict[str, Any]) -> Dict[str, Any]:
|
||||
snapshot = present.get("vedastro_official_snapshot") or {}
|
||||
section_statuses = snapshot.get("section_statuses") or {}
|
||||
base = {
|
||||
"chart_core": {"source": "vedastro_official", "status": section_statuses.get("chart_core", "blocked")},
|
||||
"dasha": {"source": "vedastro_official", "status": section_statuses.get("dasha_all", "blocked")},
|
||||
"event_radar": {"source": "vedastro_official", "status": section_statuses.get("events_overview", "blocked")},
|
||||
}
|
||||
if route == "relationship":
|
||||
base["d9"] = {"source": "vedastro_official", "status": section_statuses.get("varga_d9", "unknown")}
|
||||
elif route == "career":
|
||||
base["d10"] = {"source": "vedastro_official", "status": section_statuses.get("varga_d10", "unknown")}
|
||||
elif route == "finance":
|
||||
base["d2_d11"] = {"source": "vedastro_official", "status": section_statuses.get("varga_d2_d11", "unknown")}
|
||||
return base
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Implement local supplemental mapping**
|
||||
|
||||
```python
|
||||
def _build_local_supplemental_evidence(route: str, present: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if route == "relationship":
|
||||
keys = ("upapada_lagna", "darakaraka", "narayana_current", "functional_benefic_malefic")
|
||||
elif route == "career":
|
||||
keys = ("a10_karma_pada", "narayana_current", "functional_benefic_malefic")
|
||||
else:
|
||||
keys = ("wealth_promise_strength", "narayana_current", "functional_benefic_malefic")
|
||||
return {
|
||||
key: {
|
||||
"role": "required_local_supplement",
|
||||
"present": bool(present.get(key)),
|
||||
}
|
||||
for key in keys
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Implement blocked, fallback, and conflict derivation**
|
||||
|
||||
```python
|
||||
def _build_fallback_and_blocked(route: str, present: Dict[str, Any], missing: List[str]) -> tuple[List[str], List[str]]:
|
||||
blocked_items: List[str] = []
|
||||
fallback_used: List[str] = []
|
||||
official = present.get("vedastro_official_snapshot") or {}
|
||||
if official.get("level") != "primary":
|
||||
blocked_items.append("official_primary_chart_blocked")
|
||||
fallback_used.append("local_chart_fallback")
|
||||
if "external_activation" in present and (present.get("external_activation") or {}).get("level") == "missing_required_external_radar":
|
||||
blocked_items.append("official_event_radar_partial")
|
||||
for key in missing:
|
||||
blocked_items.append(f"missing_required_{key}")
|
||||
return fallback_used, blocked_items
|
||||
|
||||
|
||||
def _build_conflicts(route: str, present: Dict[str, Any], missing: List[str]) -> List[Dict[str, Any]]:
|
||||
conflicts: List[Dict[str, Any]] = []
|
||||
dignity = present.get("dignity_guardrail") or {}
|
||||
if dignity.get("status") == "conflict":
|
||||
conflicts.append({
|
||||
"type": "official_local_divisional_conflict",
|
||||
"primary_source": "vedastro_official",
|
||||
"supplemental_source": "local_module",
|
||||
"impact": "interpretation",
|
||||
"resolution": "keep_official_primary_and_downgrade_confidence",
|
||||
"details": {"dignity_guardrail": dignity},
|
||||
})
|
||||
return conflicts
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Attach the new contract fields to each strict route**
|
||||
|
||||
```python
|
||||
strict["official_primary_evidence"] = _build_official_primary_evidence(route, modules, present)
|
||||
strict["local_supplemental_evidence"] = _build_local_supplemental_evidence(route, present)
|
||||
strict["fallback_used"], strict["blocked_items"] = _build_fallback_and_blocked(route, present, missing)
|
||||
strict["conflicts"] = _build_conflicts(route, present, missing)
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_finance.py tests/test_historical_event_backtest.py -k "strict_contract or conflicts_and_blocked_items" -q`
|
||||
|
||||
Expected: PASS for the new contract tests.
|
||||
|
||||
### Task 3: Promote Official Snapshot Section Status Into Shared Orchestration Metadata
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/vedastro_evidence_orchestrator.py`
|
||||
- Modify: `scripts/vedastro_priority.py`
|
||||
- Modify: `tests/test_vedastro_evidence_orchestrator.py`
|
||||
- Modify: `tests/test_vedastro_official_full_snapshot.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- `source_metadata.official_section_statuses`
|
||||
- `source_metadata.theme_requirements`
|
||||
- `official_snapshot_evidence(...).section_statuses`
|
||||
|
||||
- [ ] **Step 1: Write the failing orchestrator test**
|
||||
|
||||
```python
|
||||
def test_vedastro_orchestrator_surfaces_official_section_statuses_and_theme_requirements(monkeypatch) -> None:
|
||||
from scripts import vedastro_evidence_orchestrator as orchestrator
|
||||
|
||||
monkeypatch.setattr(orchestrator, "run_official_full_snapshot_for_case", lambda *args, **kwargs: {
|
||||
"status": "partial",
|
||||
"available": True,
|
||||
"official_chart": {"planets": {"Sun": {}}, "ascendant": {"sign": "Leo"}},
|
||||
"section_statuses": {"chart_core": "ok", "dasha_all": "ok", "events_overview": "partial"},
|
||||
"source_metadata": {},
|
||||
})
|
||||
monkeypatch.setattr(orchestrator, "run_range_scan_for_case", lambda *args, **kwargs: {
|
||||
"status": "ok",
|
||||
"available": True,
|
||||
"event_count": 1,
|
||||
"evidence_ledger": [],
|
||||
})
|
||||
|
||||
result = orchestrator.orchestrate_vedastro_evidence({"year": REDACTED_YEAR, "month": 4, "day": 17, "hour": 14, "minute": 49, "lat": 36.42, "lon": 114.2, "tz": 8}, route="relationship", reference_date="2026-06-29")
|
||||
assert result["source_metadata"]["official_section_statuses"]["dasha_all"] == "ok"
|
||||
assert result["source_metadata"]["theme_requirements"]["route"] == "relationship"
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_vedastro_evidence_orchestrator.py -k official_section_statuses -q`
|
||||
|
||||
Expected: FAIL because the metadata keys are missing.
|
||||
|
||||
- [ ] **Step 3: Implement minimal metadata propagation**
|
||||
|
||||
```python
|
||||
official_section_statuses = official_full_snapshot.get("section_statuses") if isinstance(official_full_snapshot, dict) else {}
|
||||
theme_requirements = {
|
||||
"route": route,
|
||||
"domains": domains,
|
||||
"requires_dual_dasha": True,
|
||||
}
|
||||
```
|
||||
|
||||
Add both into the orchestrator `source_metadata` and keep `official_snapshot_evidence()` returning `section_statuses`.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_vedastro_evidence_orchestrator.py tests/test_vedastro_official_full_snapshot.py -k "official_section_statuses or official_full_snapshot" -q`
|
||||
|
||||
Expected: PASS for the new metadata contract.
|
||||
|
||||
### Task 4: Surface The Shared Contract Through API And Report Payloads
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/jyotish_api_server.py`
|
||||
- Modify: `scripts/jyotish_engine.py`
|
||||
- Modify: `tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- API theme outputs that include `official_primary_evidence`, `local_supplemental_evidence`, `fallback_used`, `blocked_items`, `conflicts`
|
||||
- prompt/report payloads that carry the same structure
|
||||
|
||||
- [ ] **Step 1: Write the failing API test**
|
||||
|
||||
```python
|
||||
def test_high_rigor_workflow_plan_only_exposes_official_hard_override_contract() -> None:
|
||||
handler = _handler()
|
||||
result = handler._high_rigor_workflow_plan_only(
|
||||
{"year": REDACTED_YEAR, "month": 4, "day": 17, "hour": 14, "minute": 49, "lat": 36.42, "lon": 114.2, "tz": 8},
|
||||
["career", "marriage", "wealth"],
|
||||
[],
|
||||
)
|
||||
assert result["source_priority"]["mode"] == "vedastro_official_snapshot_first"
|
||||
assert result["execution_plan"][-1] == "return_official_primary_supplemental_fallback_conflict_contract"
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_api_server_security.py -k hard_override_contract -q`
|
||||
|
||||
Expected: FAIL because the execution plan and API contract are not yet updated.
|
||||
|
||||
- [ ] **Step 3: Implement API/report passthrough**
|
||||
|
||||
```python
|
||||
result["contract"] = {
|
||||
"official_primary_evidence": strict.get("official_primary_evidence") if isinstance(strict, dict) else {},
|
||||
"local_supplemental_evidence": strict.get("local_supplemental_evidence") if isinstance(strict, dict) else {},
|
||||
"fallback_used": strict.get("fallback_used") if isinstance(strict, dict) else [],
|
||||
"blocked_items": strict.get("blocked_items") if isinstance(strict, dict) else [],
|
||||
"conflicts": strict.get("conflicts") if isinstance(strict, dict) else [],
|
||||
}
|
||||
```
|
||||
|
||||
Update prompt/report payload builders to include the same keys when strict evidence exists.
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_api_server_security.py -k hard_override_contract -q`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 5: Verify The Closed Path And Update Project Logs
|
||||
|
||||
**Files:**
|
||||
- Modify: `progress.md`
|
||||
- Modify: `findings.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces:
|
||||
- final verification log for the official hard-override path
|
||||
|
||||
- [ ] **Step 1: Run focused strict-workflow verification**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_finance.py tests/test_historical_event_backtest.py -q`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 2: Run orchestration verification**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_vedastro_evidence_orchestrator.py tests/test_vedastro_official_full_snapshot.py tests/test_vedastro_python_bridge.py -q`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 3: Run API/static verification**
|
||||
|
||||
Run:
|
||||
`python3 -m pytest tests/test_api_server_security.py tests/test_frontend_productization.py -k "vedastro or hard_override_contract or source_priority" -q`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 4: Update project logs**
|
||||
|
||||
Record:
|
||||
- files changed
|
||||
- official-first contract now enforced where implemented
|
||||
- remaining blocked boundaries
|
||||
- exact verification commands and results
|
||||
|
||||
## Self-Review
|
||||
|
||||
- Spec coverage: official-first authority, shared contract, conflict honesty, blocked honesty, API/report propagation, and verification each map to a task.
|
||||
- Placeholder scan: no TBD/TODO placeholders remain.
|
||||
- Type consistency: the same contract keys are used across strict workflow, backtest, API, and report surfaces.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Monthly Adjudication Structure Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Replace the old month-facing "opportunity / pressure" simplification with a route-aware monthly adjudication structure for career, relationship, and finance that reuses existing strict workflow evidence.
|
||||
|
||||
**Architecture:** Reuse `mcp_server.py` strict workflow evidence as the single source, derive a lightweight `monthly_adjudication_summary` from existing promise/activation/manifestation layers plus VedAstro official day signals, then surface it through prompt-pack, guided topics, AI chat context, and frontend cards. Keep `official_day_signal_summary` as a compatibility layer during the transition.
|
||||
|
||||
**Tech Stack:** Python, existing strict workflow builders, pytest, current guided-topic/frontend consumers.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Reuse current strict workflow collectors before adding new collectors.
|
||||
- Reuse current `event_judgement`, `adjudication_stages`, and `official_day_signal_summary` outputs.
|
||||
- Do not add new heavy VedAstro calls for this task.
|
||||
- Keep `Functional Benefic/Malefic`, relevant vargas, and `Vimshottari + Narayana` hard gates visible.
|
||||
- Preserve `blocked`, `conflicts`, and `confidence_cap` honesty boundaries.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Define and test the new contract
|
||||
|
||||
- [ ] Add failing backend tests for `monthly_adjudication_summary` in career/relationship/finance strict workflow tests.
|
||||
- [ ] Add failing guided-topic and frontend tests asserting the new field is carried and displayed.
|
||||
|
||||
### Task 2: Implement route-aware monthly adjudication
|
||||
|
||||
- [ ] Add helper builders in `/Users/wuyongnaren/Documents/印度占星/mcp_server.py`.
|
||||
- [ ] Attach `monthly_adjudication_summary` to strict workflow contracts.
|
||||
- [ ] Keep `official_day_signal_summary` unchanged for compatibility.
|
||||
|
||||
### Task 3: Surface the contract through consumers
|
||||
|
||||
- [ ] Add `monthly_adjudication_summary` to compact prompt-pack contracts in `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`.
|
||||
- [ ] Add it to guided topics in `/Users/wuyongnaren/Documents/印度占星/scripts/guided_topic_discovery.py`.
|
||||
- [ ] Expose it in `/Users/wuyongnaren/Documents/印度占星/jyotish-app/main.js` and `/Users/wuyongnaren/Documents/印度占星/jyotish-app/ai-chat.js`.
|
||||
|
||||
### Task 4: Verify targeted regressions
|
||||
|
||||
- [ ] Run the strict workflow tests for career/relationship/finance.
|
||||
- [ ] Run the guided-topic smoke test.
|
||||
- [ ] Run the targeted frontend productization assertions.
|
||||
@@ -0,0 +1,351 @@
|
||||
# Unified Consultation Runtime Hardening Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make the consultation runtime planner execute real reusable steps, make thematic report consume upstream unified contracts before deriving again, and collapse monthly adjudication / interpretation axes / strict audit gate into one shared adjudication object reused by guided topics, AI payloads, and frontend.
|
||||
|
||||
**Architecture:** Keep the existing repo surfaces, but stop letting each layer rebuild its own partial truth. The API workflow becomes the single executor of route steps, full-reading/chart strict outputs become preferred upstream evidence for thematic report, and a compact `strict_adjudication_bundle` becomes the canonical shared object carried through backend, prompt-pack, guided topics, and UI.
|
||||
|
||||
**Tech Stack:** Python 3, existing `jyotish_api_server.py`, `jyotish_engine.py`, `guided_topic_discovery.py`, vanilla frontend JS, pytest.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Reuse existing repo code paths instead of inventing new parallel engines.
|
||||
- Use TDD: failing tests first, then minimal implementation.
|
||||
- Do not break current API payload compatibility where avoidable.
|
||||
- Preserve VedAstro official-first boundary and fallback honesty.
|
||||
- Keep edits scoped to the current workflow and display contract.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Lock the unified runtime and adjudication bundle contract in tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_frontend_productization.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `_compute_consultation_workflow(...)`, `_compute_thematic_report(...)`, `build_guided_topics(...)`
|
||||
- Produces: failing tests requiring `runtime_planner.executed_steps`, `strict_adjudication_bundle`, and thematic-report reuse behavior
|
||||
|
||||
- [ ] **Step 1: Write failing API workflow/runtime tests**
|
||||
|
||||
Add assertions to `tests/test_api_server_security.py` for:
|
||||
|
||||
```python
|
||||
assert result["runtime_planner"]["executed_steps"] == [
|
||||
"compute_chart",
|
||||
"run_rectification_gate",
|
||||
"run_historical_event_backtest",
|
||||
"run_thematic_report",
|
||||
]
|
||||
assert result["runtime_planner"]["skipped_steps"] == []
|
||||
assert result["thematic_report"]["mode"] == "upstream_contract_reuse"
|
||||
assert result["thematic_report"]["evidence_source"]["source"] == "consultation_workflow_upstream_contract"
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run targeted API workflow test to verify failure**
|
||||
|
||||
Run: `python3 -m pytest tests/test_api_server_security.py::test_consultation_workflow_reuses_chart_data_for_thematic_report_without_recursive_full_reading -q`
|
||||
|
||||
Expected: FAIL because `executed_steps` / `mode` / `evidence_source` are missing or different.
|
||||
|
||||
- [ ] **Step 3: Write failing shared adjudication bundle tests**
|
||||
|
||||
Add assertions in `tests/test_api_server_security.py` and `tests/test_cli_smoke.py`:
|
||||
|
||||
```python
|
||||
bundle = career["strict_adjudication_bundle"]
|
||||
assert bundle["monthly_adjudication_summary"]["primary_state"]["value"] == "推进"
|
||||
assert bundle["strict_audit_gate"]["functional_benefic_malefic"]["gate"] == "hard"
|
||||
assert bundle["interpretation_axes"][0]["axis"] == "角色定位"
|
||||
```
|
||||
|
||||
and:
|
||||
|
||||
```python
|
||||
assert topic["strict_adjudication_bundle"]["monthly_adjudication_summary"] == topic["monthly_adjudication_summary"]
|
||||
assert topic["strict_adjudication_bundle"]["strict_audit_gate"] == topic["strict_audit_gate"]
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run targeted adjudication tests to verify failure**
|
||||
|
||||
Run: `python3 -m pytest tests/test_api_server_security.py::test_thematic_report_interpretation_axes_are_strict_paragraphs_for_each_theme tests/test_cli_smoke.py::test_full_reading_guided_topics_can_carry_official_day_signal_summary -q`
|
||||
|
||||
Expected: FAIL because `strict_adjudication_bundle` is missing.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/test_api_server_security.py tests/test_cli_smoke.py tests/test_frontend_productization.py
|
||||
git commit -m "test: lock unified consultation runtime contract"
|
||||
```
|
||||
|
||||
### Task 2: Make runtime_planner a real executor and make thematic report prefer upstream unified contracts
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/unified_consultation_orchestrator.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `UnifiedConsultationOrchestrator.runtime_planner(...)`, `_compute_consultation_workflow(...)`
|
||||
- Produces: planner with `executed_steps` / `skipped_steps`, thematic input payload with `strict_workflow_contracts`, and `_compute_thematic_report(...)` mode `upstream_contract_reuse`
|
||||
|
||||
- [ ] **Step 1: Add failing helper-level test coverage if needed**
|
||||
|
||||
If `tests/test_unified_consultation_orchestrator.py` lacks direct planner coverage, add:
|
||||
|
||||
```python
|
||||
planner = orchestrator.runtime_planner(...)
|
||||
assert planner["sync_steps"][0] == "compute_chart"
|
||||
assert planner["reuse_contract"]["thematic_report"] == "thematic_report"
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Implement runtime executed/skipped step recording**
|
||||
|
||||
In `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`, refactor `_compute_consultation_workflow(...)` so it:
|
||||
- initializes `executed_steps = []`, `skipped_steps = []`
|
||||
- runs only steps listed in `runtime_planner["sync_steps"]`
|
||||
- appends actual executed step names
|
||||
- records skipped steps from the known runtime step set
|
||||
|
||||
- [ ] **Step 3: Pass upstream strict data into thematic report**
|
||||
|
||||
When building the thematic payload in `_compute_consultation_workflow(...)`, pass:
|
||||
|
||||
```python
|
||||
"upstream_contract": {
|
||||
"chart": chart_for_theme,
|
||||
"strict_workflow_contracts": prompt_snapshot_contracts,
|
||||
"guided_topics": chart_modules_guided_topics,
|
||||
}
|
||||
```
|
||||
|
||||
where `prompt_snapshot_contracts` comes from `chart["ai_prompt_pack"]["evidence_snapshot"]["strict_workflow_contracts"]` when available.
|
||||
|
||||
- [ ] **Step 4: Implement upstream-contract-first thematic reuse**
|
||||
|
||||
In `_compute_thematic_report(...)`, before calling `_derive_thematic_evidence(...)`, detect:
|
||||
|
||||
```python
|
||||
upstream_contract = body.get("upstream_contract")
|
||||
```
|
||||
|
||||
and if it contains usable `strict_workflow_contracts` or chart evidence, set:
|
||||
- `mode = "upstream_contract_reuse"`
|
||||
- `evidence_source["source"] = "consultation_workflow_upstream_contract"`
|
||||
- reuse upstream evidence/contracts before local derivation fallback
|
||||
|
||||
- [ ] **Step 5: Run tests to verify green**
|
||||
|
||||
Run: `python3 -m pytest tests/test_api_server_security.py::test_consultation_workflow_reuses_chart_data_for_thematic_report_without_recursive_full_reading tests/test_api_server_security.py::test_thematic_report_handles_missing_dasa_convergence_without_crash tests/test_unified_consultation_orchestrator.py -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/unified_consultation_orchestrator.py scripts/jyotish_api_server.py tests/test_api_server_security.py tests/test_unified_consultation_orchestrator.py
|
||||
git commit -m "feat: execute unified consultation runtime steps"
|
||||
```
|
||||
|
||||
### Task 3: Collapse monthly adjudication, audit gate, and axes into one canonical strict adjudication bundle
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/guided_topic_discovery.py`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_api_server_security.py`
|
||||
- Test: `/Users/wuyongnaren/Documents/印度占星/tests/test_cli_smoke.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: strict workflow contracts, `monthly_adjudication_summary`, `technique_audit_summary`, `interpretation_axes`
|
||||
- Produces: `strict_adjudication_bundle` with:
|
||||
- `monthly_adjudication_summary`
|
||||
- `monthly_adjudication_summary_humanized`
|
||||
- `strict_audit_gate`
|
||||
- `interpretation_axes`
|
||||
- `narrative_contract`
|
||||
|
||||
- [ ] **Step 1: Add bundle builder in API server**
|
||||
|
||||
Create a helper in `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_api_server.py` that returns:
|
||||
|
||||
```python
|
||||
{
|
||||
"theme": theme_name,
|
||||
"monthly_adjudication_summary": monthly_frame,
|
||||
"monthly_adjudication_summary_humanized": humanized,
|
||||
"strict_audit_gate": report_payload.get("technique_audit_summary") or {},
|
||||
"interpretation_axes": axes,
|
||||
"narrative_contract": {...},
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Attach canonical bundle to thematic report payload**
|
||||
|
||||
In `_apply_monthly_adjudication_to_theme_report(...)`, set:
|
||||
|
||||
```python
|
||||
report_payload["strict_adjudication_bundle"] = bundle
|
||||
```
|
||||
|
||||
while keeping legacy top-level fields for compatibility.
|
||||
|
||||
- [ ] **Step 3: Make guided topics read only the bundle first**
|
||||
|
||||
In `/Users/wuyongnaren/Documents/印度占星/scripts/guided_topic_discovery.py`, replace separate contract lookups with:
|
||||
|
||||
```python
|
||||
bundle = _as_dict(contract.get("strict_adjudication_bundle"))
|
||||
```
|
||||
|
||||
and populate:
|
||||
- `strict_audit_gate`
|
||||
- `monthly_adjudication_summary`
|
||||
- `official_day_signal_summary` fallback only if not in bundle
|
||||
|
||||
- [ ] **Step 4: Make prompt pack carry the bundle through**
|
||||
|
||||
In `/Users/wuyongnaren/Documents/印度占星/scripts/jyotish_engine.py`, ensure each strict workflow contract already exported into `ai_prompt_pack.evidence_snapshot.strict_workflow_contracts` includes `strict_adjudication_bundle`.
|
||||
|
||||
- [ ] **Step 5: Run backend/shared contract tests**
|
||||
|
||||
Run: `python3 -m pytest tests/test_api_server_security.py::test_apply_monthly_adjudication_to_theme_report_injects_four_layers_into_final_chinese_fields tests/test_api_server_security.py::test_thematic_report_interpretation_axes_are_strict_paragraphs_for_each_theme tests/test_cli_smoke.py::test_full_reading_guided_topics_can_carry_official_day_signal_summary -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/jyotish_api_server.py scripts/guided_topic_discovery.py scripts/jyotish_engine.py tests/test_api_server_security.py tests/test_cli_smoke.py
|
||||
git commit -m "feat: unify strict adjudication bundle"
|
||||
```
|
||||
|
||||
### Task 4: Make frontend and AI consume the single shared bundle
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/main.js`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/jyotish-app/ai-chat.js`
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/tests/test_frontend_productization.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `strict_adjudication_bundle`
|
||||
- Produces: UI and AI prompt entry consuming bundle first, legacy fields second
|
||||
|
||||
- [ ] **Step 1: Add failing frontend assertions**
|
||||
|
||||
Add assertions requiring:
|
||||
|
||||
```python
|
||||
assert "strict_adjudication_bundle" in main
|
||||
assert "strict_adjudication_bundle" in ai_chat
|
||||
```
|
||||
|
||||
and keep legacy checks for compatibility.
|
||||
|
||||
- [ ] **Step 2: Update guided topic card rendering**
|
||||
|
||||
In `/Users/wuyongnaren/Documents/印度占星/jyotish-app/main.js`, read:
|
||||
|
||||
```javascript
|
||||
const bundle = topic?.strict_adjudication_bundle || {};
|
||||
```
|
||||
|
||||
and derive:
|
||||
- `strict_audit_gate`
|
||||
- `monthly_adjudication_summary`
|
||||
- `interpretation_axes`
|
||||
|
||||
from the bundle first.
|
||||
|
||||
- [ ] **Step 3: Update AI chat payload construction**
|
||||
|
||||
In `/Users/wuyongnaren/Documents/印度占星/jyotish-app/ai-chat.js`, include:
|
||||
|
||||
```javascript
|
||||
guidedTopicContext.strict_adjudication_bundle
|
||||
```
|
||||
|
||||
as the first-class context object, while preserving old fields.
|
||||
|
||||
- [ ] **Step 4: Run frontend contract tests**
|
||||
|
||||
Run: `python3 -m pytest tests/test_frontend_productization.py::test_guided_topic_questions_reuse_ai_chat_entry tests/test_frontend_productization.py::test_complete_reading_surfaces_guided_topic_discovery -q`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add jyotish-app/main.js jyotish-app/ai-chat.js tests/test_frontend_productization.py
|
||||
git commit -m "feat: make frontend consume strict adjudication bundle"
|
||||
```
|
||||
|
||||
### Task 5: Run the smallest real regressions and inspect real-user output
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/wuyongnaren/Documents/印度占星/progress.md` (only if you are already tracking this thread there)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: completed runtime/thematic/bundle/frontend flow
|
||||
- Produces: verified real output for the REDACTED_DATE REDACTED_TIME REDACTED_PLACE case
|
||||
|
||||
- [ ] **Step 1: Run focused regression suite**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m pytest \
|
||||
tests/test_api_server_security.py::test_consultation_workflow_reuses_chart_data_for_thematic_report_without_recursive_full_reading \
|
||||
tests/test_api_server_security.py::test_thematic_report_interpretation_axes_are_strict_paragraphs_for_each_theme \
|
||||
tests/test_cli_smoke.py::test_full_reading_guided_topics_can_carry_official_day_signal_summary \
|
||||
tests/test_frontend_productization.py::test_guided_topic_questions_reuse_ai_chat_entry \
|
||||
-q
|
||||
```
|
||||
|
||||
Expected: all PASS.
|
||||
|
||||
- [ ] **Step 2: Run real consultation workflow sample**
|
||||
|
||||
Run a local Python one-off calling `_compute_consultation_workflow(...)` with:
|
||||
- `REDACTED_DATE REDACTED_TIME`
|
||||
- `lat=36.42`
|
||||
- `lon=114.2`
|
||||
- `tz=8`
|
||||
- themes `career/marriage/wealth`
|
||||
|
||||
Verify:
|
||||
- `runtime_planner.executed_steps` is populated
|
||||
- `thematic_report.mode == "upstream_contract_reuse"`
|
||||
- each theme contains `strict_adjudication_bundle`
|
||||
|
||||
- [ ] **Step 3: Summarize verified behavior**
|
||||
|
||||
Record the exact outputs observed for:
|
||||
- executed runtime steps
|
||||
- thematic report mode
|
||||
- presence of strict adjudication bundle in theme payloads and guided topics
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add progress.md
|
||||
git commit -m "docs: record unified consultation runtime verification"
|
||||
```
|
||||
|
||||
## Self-Review
|
||||
|
||||
- Spec coverage: the three requested root-cause cuts are directly covered by Tasks 2, 3, and 4.
|
||||
- Placeholder scan: no TBD/TODO placeholders remain.
|
||||
- Type consistency: the canonical object is always named `strict_adjudication_bundle`; runtime execution telemetry always uses `executed_steps` and `skipped_steps`.
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
Plan complete and saved to `docs/superpowers/plans/2026-07-01-unified-consultation-runtime-hardening.md`. Two execution options:
|
||||
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
Reference in New Issue
Block a user