diff --git a/docs/superpowers/plans/2026-07-17-birth-time-journey.md b/docs/superpowers/plans/2026-07-17-birth-time-journey.md new file mode 100644 index 00000000..97ecdb05 --- /dev/null +++ b/docs/superpowers/plans/2026-07-17-birth-time-journey.md @@ -0,0 +1,115 @@ +# Birth Time Journey 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:** Build a deterministic first-use birth-time journey that separates reported and active times, routes uncertain data into free rectification, and connects the web UI to the existing candidate scanner. + +**Architecture:** A pure TypeScript state machine owns route and application decisions. An authenticated Next.js route adapts Supabase persistence and the existing Python scan/score API to that state machine. A focused React component renders the input contract, while `page.tsx` only coordinates the established onboarding shell. + +**Tech Stack:** Next.js 16 App Router, React 19, TypeScript, Zod, Supabase/PostgreSQL, Node test runner, Python Jyotish API. + +## Global Constraints + +- Agent copy may guide the user but may not determine route, confidence, or application eligibility. +- `reported_birth_time` is immutable historical input; `birth_time` mirrors only `active_birth_time` for compatibility. +- Rectification intake and questions never call the consultation billing endpoint. +- Questionnaire scoring cannot apply an exact minute because the current engine only ranks coarse clusters. +- Scanner failure must fail closed into rectification. +- Do not modify or import files from `.workbuddy` mirrors. + +--- + +### Task 1: Deterministic Journey Domain + +**Files:** +- Create: `frontend/src/lib/birth-time-journey.ts` +- Test: `frontend/tests/birth-time-journey.test.ts` + +**Interfaces:** +- Produces: `assessBirthTime(input: BirthTimeAssessmentInput, scan?: CandidateScan): JourneySnapshot` +- Produces: `scoreJourneyAnswers(snapshot: JourneySnapshot, scoring: RectificationScoring): JourneySnapshot` +- Produces: source, period, status, route, input, snapshot, scan, and scoring types used by later tasks. + +- [ ] Write table-driven failing tests for all five sources, invalid source-specific input, stable hospital scan, sensitive hospital scan, scanner failure, and `canApply=false` after questionnaire scoring. +- [ ] Run `npm test -- --test-name-pattern='birth time journey'` and confirm the module is missing. +- [ ] Implement exhaustive source routing and scan stability comparison without persistence or prose generation. +- [ ] Run the focused test and confirm every route and gate passes. + +### Task 2: Birth-Time Persistence Contract + +**Files:** +- Create: `frontend/supabase/migrations/20260717020000_birth_time_journey.sql` +- Create: `tests/test_birth_time_journey_contract.py` + +**Interfaces:** +- Produces: profile columns and `public.birth_time_rectification_cases` expected by the route. + +- [ ] Write a failing SQL contract test for columns, checks, backfill, foreign key, RLS policies, and column-level grants. +- [ ] Run `/Users/jesse/Downloads/Copse/astrology/yinduzhanxing/.venv/bin/python -m pytest -q tests/test_birth_time_journey_contract.py` and confirm the migration is missing. +- [ ] Add an idempotent migration that backfills old `birth_time` values, constrains enums and uncertainty ranges, creates the cases table, and grants only owner-scoped operations. +- [ ] Run the SQL contract test and the existing Supabase contract tests. + +### Task 3: Authenticated Journey Service and Route + +**Files:** +- Create: `frontend/src/lib/birth-time-journey-service.ts` +- Create: `frontend/src/app/api/birth-time-journey/route.ts` +- Test: `frontend/tests/birth-time-journey-service.test.ts` + +**Interfaces:** +- Consumes: domain types and `assessBirthTime`/`scoreJourneyAnswers` from Task 1. +- Produces: `POST /api/birth-time-journey` events `assess` and `answer_question`. + +- [ ] Write failing service tests with fake persistence and scanner ports for stable assessment, scanner failure, and answer accumulation. +- [ ] Implement a typed service port so tests never require live Supabase or Python. +- [ ] Implement the route's Zod boundary, authenticated profile read, free scanner calls, case persistence, and sanitized JSON response. +- [ ] Run focused service/domain tests and lint. + +### Task 4: First-Use Birth Intake UI + +**Files:** +- Create: `frontend/src/components/birth-time-intake.tsx` +- Create: `frontend/src/components/birth-time-rectification.tsx` +- Modify: `frontend/src/app/page.tsx` +- Modify: `frontend/src/app/globals.css` +- Test: `frontend/tests/birth-time-intake.test.ts` + +**Interfaces:** +- Consumes: the journey source/status types and `JourneySnapshot`. +- Produces: source-specific profile draft updates, assessment requests after location, and answer events. + +- [ ] Write failing tests for source-specific required fields, summary labels, and payload construction. +- [ ] Implement the source cards, conditional fields, accessible labels, and uncertainty/period copy. +- [ ] Implement the rectification status/question card with progress and explicit non-application language. +- [ ] Replace the old exact-time-only fields in `page.tsx`, extend profile parsing/persistence, add the `rectification` onboarding step, and block consultation until an active time exists. +- [ ] Add scoped responsive styles and run the focused UI helper tests plus lint. + +### Task 5: Compatibility and End-to-End Verification + +**Files:** +- Modify: `frontend/src/app/api/onboarding/route.ts` +- Modify: `frontend/src/mastra/index.ts` +- Modify: `tests/test_frontend_productization.py` + +**Interfaces:** +- Consumes: active time and birth-time status persisted by earlier tasks. +- Produces: existing onboarding and consultation behavior with deterministic entry mode. + +- [ ] Update onboarding completeness to require an active/confirmed time while accepting backfilled legacy profiles. +- [ ] Add `entryMode` to the consultation input and pass the deterministic value to the Python workflow instead of hard-coding `direct_chart`. +- [ ] Add regression assertions that the web path exposes five time-confidence choices, keeps rectification free, and contains no client-controlled application gate. +- [ ] Run frontend tests, relevant Python tests, lint, and `npm run build`. +- [ ] Start Next.js from the worktree and manually verify the first-use UI, source-dependent fields, rectification card, `/api/birth-time-journey` authentication behavior, and absence of consultation credit requests. + +### Task 6: Review and Commit + +**Files:** +- Review every path changed by Tasks 1-5. + +**Interfaces:** +- Produces: a review-clean commit on `codex/birth-time-journey`. + +- [ ] Run the TypeScript no-excuse checks and measure pure LOC for every changed source file. +- [ ] Review boundary parsing, exhaustive variants, RLS, billing isolation, and legacy compatibility. +- [ ] Re-run the full frontend test/lint/build gate and relevant Python contract tests on the final diff. +- [ ] Commit the implementation with a focused message and record the worktree path and commit SHA. diff --git a/docs/superpowers/specs/2026-07-17-birth-time-journey-design.md b/docs/superpowers/specs/2026-07-17-birth-time-journey-design.md new file mode 100644 index 00000000..29332064 --- /dev/null +++ b/docs/superpowers/specs/2026-07-17-birth-time-journey-design.md @@ -0,0 +1,150 @@ +# Birth Time Journey Design + +## Goal + +Turn the first-use birth-time question into one continuous journey: the assistant explains and guides, while deterministic code owns state transitions, time-quality assessment, candidate scanning, routing, and whether a time may become the active chart time. + +## Delivery Scope + +This delivery connects the web onboarding flow to the repository's existing candidate-time scanner. It includes: + +- five explicit birth-time knowledge levels from the first time question; +- separate reported and active birth times; +- deterministic direct-chart versus rectification routing; +- a free rectification intake path that does not use `/api/consult` billing; +- candidate scanning with latitude, longitude, timezone, Lahiri ayanamsa, and the local domain engine; +- high-information choice questions and persisted answers; +- a hard application gate that refuses unsupported minute-level certainty. + +The existing Python scorer only ranks coarse candidate clusters. It does not prove an exact minute against dated life events. Therefore this delivery may save rectification evidence and candidate ranges, but it must keep `can_apply=false` for scored questionnaire results. A hospital-record time may become active only when the deterministic ±2-minute sensitivity scan is stable. + +## Responsibilities + +### BirthTimeJourney + +`advanceBirthTimeJourney(event, context) -> JourneySnapshot` is the only module allowed to choose the next state or route. + +It owns: + +- validation of source-specific inputs; +- uncertainty ranges; +- state transitions; +- stable-scan interpretation; +- `direct_chart`, `rectification`, or `pending` routing; +- `can_apply` decisions. + +It does not generate prose, call a language model, persist data, or calculate a chart. + +### Journey API + +`POST /api/birth-time-journey` authenticates the user, parses the event, loads the user's profile/case, calls the deterministic module, calls the existing Python scan/score endpoints when required, and persists the returned snapshot. + +The route is free. It must never reserve consultation credits. + +### Birth Intake UI + +The UI renders the input contract returned by the journey and uses fixed, user-facing Chinese copy for `assistant_intent`. It never chooses a route from chat text. + +The existing `onboardingAgent` remains responsible only for the welcome message and starter questions after birth intake is complete. The normal `jyotishAgent` remains unavailable until an active birth time exists. + +## State Model + +States are: + +- `collect_date` +- `collect_time_confidence` +- `collect_reported_time` +- `collect_location` +- `assessing` +- `rectifying` +- `candidate` +- `ready` + +Routes are `pending`, `direct_chart`, and `rectification`. + +Birth-time sources are: + +- `hospital_record` +- `family_exact` +- `approximate` +- `period_only` +- `unknown` + +Source rules: + +| Source | Required input | Deterministic uncertainty | Route | +| --- | --- | --- | --- | +| Hospital record | exact time | ±2 minutes | stable scan → direct; sensitive/error → rectification | +| Family exact | exact time and 5/10/15-minute uncertainty | selected range | rectification | +| Approximate | center time and 15/30/60-minute uncertainty | selected range | rectification | +| Period only | morning/forenoon/afternoon/evening/late night | predefined range | rectification, no exact-time application | +| Unknown | optional family clue | whole-day unresolved | rectification, no exact-time application | + +## Persistence + +`profiles.birth_time` remains as a compatibility mirror of `active_birth_time` for existing calculation code. + +New profile fields: + +- `reported_birth_time` +- `active_birth_time` +- `birth_time_source` +- `birth_time_period` +- `uncertainty_before_minutes` +- `uncertainty_after_minutes` +- `birth_time_status` +- `rectification_confidence` +- `rectification_case_id` + +`birth_time_rectification_cases` stores the questionnaire, answers, candidate scan, scoring result, algorithm settings, status, and confirmation metadata. Row-level security restricts every operation to the owning user. Raw reported time is never overwritten when active time changes. + +Existing profiles with `birth_time` are backfilled as reported and active times with `birth_time_status='confirmed'` and `birth_time_source='legacy_import'`, so existing users are not forced through onboarding again. + +## API Events + +The first version accepts two events: + +- `assess`: evaluate the stored birth-time declaration after location is known; +- `answer_question`: add or replace one A/B/C/D answer and recompute deterministic cluster scoring. + +The response is a `JourneySnapshot` containing: + +- `state` +- `assistantIntent` +- `input` +- `route` +- `confidence` +- `canApply` +- `reportedRange` +- `questionnaire` +- `scoring` + +Unknown fields, invalid choices, missing authentication, and missing profile inputs are rejected at the HTTP boundary. Scanner failure safely routes to rectification and never silently activates the reported time. + +## UI Flow + +1. Ask the user's name. +2. Ask the birth date and show the five time-confidence choices. +3. Reveal only the time, uncertainty, period, or clue fields required by that choice. +4. Ask for birth location. +5. Show an assessment status card while the deterministic route runs. +6. If stable hospital data is accepted, continue to the existing starter questions. +7. Otherwise show the first three rectification questions, progress, current range, and the explicit note that no exact minute has been applied. + +The account sheet uses the same birth-time fields, so later edits preserve the same contract. + +## Error Handling + +- Scanner unavailable: persist `rectifying`, show a retry-safe explanation, keep `can_apply=false`. +- Invalid source-specific input: keep the current collection state and show a field-level message. +- Persistence failure: return an error and do not advance the visible journey. +- Score endpoint failure: keep prior answers and prior snapshot; do not fabricate a result. +- Old profile: use the migration backfill and compatibility read path. + +## Verification + +- Unit tests cover every source route, stable/sensitive hospital scans, and the application gate. +- Route/service tests cover scanner payloads, failure fallback, and answer accumulation. +- SQL contract tests cover constraints, RLS, grants, and immutable reported-time semantics. +- Existing frontend, lint, TypeScript, build, and relevant Python rectification tests remain green. +- Manual QA runs the new first-use journey in the real Next.js page and observes both direct and rectification presentations without charging credits.