T1 scripts/birth_sky.py: real alt/az of the seven visible grahas (swe.calc_ut + swe.azalt, geometric altitude, azimuth converted from swe's south origin to north-east) and Yale BSC5 stars V<=4.0 (IAU 1976 precession); phase day / twilight_morning / twilight_evening / night. Thin POST /api/birth_sky registration in do_POST (no new handler method, no __new__). T2 GET /api/birth-sky?subject=: birth truth read server side through loadSubjectBirth + prepareChartViewProfile; zod contract; no billing, no writes, no birth data in the response. T3/T4 lib/birth-sky: sentence table, pure Canvas 2D drawBirthSky (night / paper palettes from DESIGN tokens, east on the left, serif headline with 1.5 s font wait), PNG export via navigator.share or Blob + a.download. Chart page prefetches and paints the cover once the chart is ok; the header button appears only when the PNG is ready. Dialog is a lazy chunk. T7 DESIGN §17, VOICE, CONTEXT glossary, CHANGELOG, real-device checklist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
15 lines
761 B
TypeScript
15 lines
761 B
TypeScript
import { readFileSync } from "node:fs";
|
|
|
|
import { birthSkyFromEngine, type BirthSkyOk, type BirthSkyPhase } from "../src/lib/birth-sky/contract.ts";
|
|
|
|
/** Real engine responses (scripts/generate_birth_sky_golden.py), fictional sample birth. */
|
|
export const birthSkyGolden = JSON.parse(
|
|
readFileSync(new URL("./fixtures/birth-sky-golden.json", import.meta.url), "utf8"),
|
|
) as { times: Record<BirthSkyPhase, string>; responses: Record<BirthSkyPhase, Record<string, unknown>> };
|
|
|
|
export function goldenSky(phase: BirthSkyPhase, timeBasis: BirthSkyOk["timeBasis"] = "reported"): BirthSkyOk {
|
|
const sky = birthSkyFromEngine(birthSkyGolden.responses[phase], timeBasis);
|
|
if (!sky) throw new Error(`golden ${phase} does not satisfy the contract`);
|
|
return sky;
|
|
}
|