Files
Jyotisha/docs/superpowers/plans/2026-06-30-vedastro-daily-window-priority.md
T
2026-07-08 18:34:13 +08:00

15 KiB

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: <repo>/tests/test_vedastro_range_scan_replay.py
  • Test: <repo>/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

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:

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
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: <repo>/scripts/vedastro_evidence_orchestrator.py
  • Modify: <repo>/tests/test_vedastro_evidence_orchestrator.py
  • Test: <repo>/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

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": 1955, "month": 2, "day": 24, "hour": 19, "minute": 15, "lat": 37.7749, "lon": -122.4194, "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:

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
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: <repo>/mcp_server.py
  • Modify: <repo>/tests/test_mcp_strict_workflow_career.py
  • Modify: <repo>/tests/test_mcp_strict_workflow_relationship.py
  • Modify: <repo>/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

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:

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
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: <repo>/mcp_server.py
  • Modify: <repo>/tests/test_life_event_graph_v1.py
  • Test: <repo>/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

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:

{
    "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
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: <repo>/scripts/jyotish_engine.py
  • Modify: <repo>/tests/test_cli_smoke.py
  • Test: <repo>/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

def test_full_reading_preserves_official_daily_window_fields_in_range_scan_result() -> None:
    result = run_engine(
        "full-reading",
        "--year", "1955",
        "--month", "2",
        "--day", "24",
        "--hour", "19",
        "--minute", "15",
        "--lat", "37.7749",
        "--lon", "-122.4194",
        "--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
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?