{
  "$schema": "./computations.schema.json",
  "schema_version": 1,
  "registry_id": "telugu-calendar-utilities.computations",
  "vocabularies": {
    "owning_layers": [
      "engine-core",
      "derived",
      "calendar",
      "personal",
      "interpretation"
    ],
    "claim_kinds": [
      "deterministic-fact",
      "textual-rule",
      "regional-convention",
      "project-heuristic",
      "generated-interpretation"
    ],
    "method_kinds": [
      "formula",
      "algorithm",
      "decision-table",
      "interpretive-procedure"
    ],
    "implementation_roles": ["owner", "mirror"],
    "surfaces": [
      "python-library",
      "mcp",
      "ics",
      "website",
      "generated-data"
    ],
    "evidence_classes": [
      "astronomical",
      "textual",
      "published_panchangam",
      "regional_convention",
      "project_heuristic"
    ],
    "verification_states": [
      "verified",
      "partially_verified",
      "engine_pinned",
      "needs_locator",
      "heuristic",
      "contradicted"
    ],
    "exclusion_kinds": [
      "package-marker",
      "lookup-data",
      "data-model",
      "adapter",
      "serialization",
      "orchestration",
      "ui-only"
    ]
  },
  "coverage": {
    "roots": [
      {"path": "telugu_panchangam", "extensions": [".py"]},
      {"path": "src", "extensions": [".ts"]},
      {"path": "scripts", "extensions": [".py"]}
    ],
    "exclusions": [
      {
        "path": "telugu_panchangam/__init__.py",
        "kind": "package-marker",
        "reason": "Package metadata only; it owns no computation."
      },
      {
        "path": "telugu_panchangam/cities.py",
        "kind": "lookup-data",
        "reason": "Static location catalogue consumed as computation input."
      },
      {
        "path": "telugu_panchangam/engines/__init__.py",
        "kind": "package-marker",
        "reason": "Engine export surface only."
      },
      {
        "path": "telugu_panchangam/generate.py",
        "kind": "orchestration",
        "reason": "Coordinates engines and serializers without owning a domain computation."
      },
      {
        "path": "telugu_panchangam/generators/__init__.py",
        "kind": "package-marker",
        "reason": "Generator package marker only."
      },
      {
        "path": "telugu_panchangam/generators/anga_variants.py",
        "kind": "serialization",
        "reason": "Filters already-computed PanchangamDay records and serializes feed variants."
      },
      {
        "path": "telugu_panchangam/generators/ics.py",
        "kind": "serialization",
        "reason": "Frozen subscriber-facing representation of computed values."
      },
      {
        "path": "telugu_panchangam/gochara/__init__.py",
        "kind": "package-marker",
        "reason": "Gochara export surface only."
      },
      {
        "path": "telugu_panchangam/mcp/__init__.py",
        "kind": "package-marker",
        "reason": "MCP package marker only."
      },
      {
        "path": "telugu_panchangam/mcp/location.py",
        "kind": "adapter",
        "reason": "Geocoding and timezone input resolution, not a Panchangam computation."
      },
      {
        "path": "telugu_panchangam/mcp/server.py",
        "kind": "adapter",
        "reason": "MCP signatures delegate to canonical computation owners."
      },
      {
        "path": "telugu_panchangam/mcp/tools.py",
        "kind": "adapter",
        "reason": "Input validation, orchestration, and JSON projection of canonical results."
      },
      {
        "path": "telugu_panchangam/models/__init__.py",
        "kind": "package-marker",
        "reason": "Model export surface only."
      },
      {
        "path": "telugu_panchangam/models/panchangam_day.py",
        "kind": "data-model",
        "reason": "Typed result containers define outputs but perform no calculation."
      },
      {
        "path": "telugu_panchangam/panchangam_names.py",
        "kind": "lookup-data",
        "reason": "Canonical names and tables consumed by computations."
      },
      {
        "path": "telugu_panchangam/panchangam_provenance.py",
        "kind": "adapter",
        "reason": "Projects evidence metadata into MCP responses."
      },
      {
        "path": "telugu_panchangam/personal/__init__.py",
        "kind": "package-marker",
        "reason": "Personal-calculation package marker only."
      },
      {
        "path": "telugu_panchangam/personal/election_assessors/__init__.py",
        "kind": "package-marker",
        "reason": "Election-assessor export surface only."
      },
      {
        "path": "telugu_panchangam/personal/election_assessors/contracts.py",
        "kind": "data-model",
        "reason": "Shared outcome containers define result shapes but perform no calculation."
      },
      {
        "path": "telugu_panchangam/personal/election_assessors/facts.py",
        "kind": "adapter",
        "reason": "Compatibility exports delegate to the event-admission owner."
      },
      {
        "path": "telugu_panchangam/personal/election_assessors/primitives.py",
        "kind": "adapter",
        "reason": "Compatibility exports delegate to the partitioned domain owners."
      },
      {
        "path": "telugu_panchangam/personal/activity_catalog.py",
        "kind": "lookup-data",
        "reason": "User-facing activity labels and catalogue metadata."
      },
      {
        "path": "src/data/cities.ts",
        "kind": "lookup-data",
        "reason": "Browser location catalogue."
      },
      {
        "path": "src/data/systems.ts",
        "kind": "lookup-data",
        "reason": "Browser calculation-system labels."
      },
      {
        "path": "src/scorer/election-assessors/contracts.ts",
        "kind": "data-model",
        "reason": "Shared browser result and rule types perform no calculation."
      },
      {
        "path": "src/scorer/election-assessors/primitives.ts",
        "kind": "adapter",
        "reason": "Compatibility exports delegate to the partitioned browser mirrors."
      },
      {
        "path": "src/lib/analytics.ts",
        "kind": "adapter",
        "reason": "Analytics event delivery only."
      },
      {
        "path": "src/lib/birth-profile-api.ts",
        "kind": "adapter",
        "reason": "Validates and transports the externally owned DashaFlow birth-profile contract; it does not own the astronomical calculation."
      },
      {
        "path": "src/lib/dom.ts",
        "kind": "ui-only",
        "reason": "DOM utilities only."
      },
      {
        "path": "src/lib/feed-loader.ts",
        "kind": "adapter",
        "reason": "Fetches published computed feeds."
      },
      {
        "path": "src/lib/format.ts",
        "kind": "serialization",
        "reason": "Display formatting only."
      },
      {
        "path": "src/lib/html.ts",
        "kind": "ui-only",
        "reason": "HTML escaping and rendering helpers."
      },
      {
        "path": "src/lib/guest-profile-store.ts",
        "kind": "ui-only",
        "reason": "Browser-local guest profile state, validation, and storage migration; it owns no Panchangam computation."
      },
      {
        "path": "src/lib/profile-selection.ts",
        "kind": "ui-only",
        "reason": "Stable browser-local journey selection and compatibility migration; it owns no Panchangam computation."
      },
      {
        "path": "src/lib/remote-calculation-activation.ts",
        "kind": "adapter",
        "reason": "Fail-closed public and loopback-development activation policy for the birth-profile adapter; it owns no astrological calculation."
      },
      {
        "path": "src/lib/ics.ts",
        "kind": "serialization",
        "reason": "ICS parsing and field extraction, not domain calculation."
      },
      {
        "path": "src/lib/lagna-loader.ts",
        "kind": "adapter",
        "reason": "Loads generated Lagna data."
      },
      {
        "path": "src/lib/parse-description.ts",
        "kind": "serialization",
        "reason": "Parses the frozen ICS description into browser fields."
      },
      {
        "path": "src/main.ts",
        "kind": "ui-only",
        "reason": "Application bootstrap and navigation wiring."
      },
      {
        "path": "src/panels/profiles.ts",
        "kind": "ui-only",
        "reason": "Accessible browser-local profile management UI; it owns no Panchangam computation."
      },
      {
        "path": "src/selection-store.ts",
        "kind": "ui-only",
        "reason": "Browser selection state only."
      },
      {
        "path": "scripts/__init__.py",
        "kind": "package-marker",
        "reason": "Build-script package marker only."
      },
      {
        "path": "scripts/build_gochara_json.py",
        "kind": "orchestration",
        "reason": "Materializes canonical graha and gochara computations as browser data."
      },
      {
        "path": "scripts/build_lagna_json.py",
        "kind": "orchestration",
        "reason": "Materializes canonical Lagna transitions as browser data."
      },
      {
        "path": "scripts/build_landing_page.py",
        "kind": "orchestration",
        "reason": "Legacy/static landing build helper without a domain computation."
      },
      {
        "path": "scripts/generate_llm_phalalu.py",
        "kind": "orchestration",
        "reason": "Batch runner for the registered generated-interpretation owner."
      }
    ]
  },
  "computations": [
    {
      "id": "astronomy.drik-sidereal-longitudes",
      "title": "Drik sidereal planetary longitudes",
      "summary": "Swiss Ephemeris longitudes under the selected ayanamsa form the Drik astronomical basis.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/utils.py", "symbol": "sidereal_longitude_with_ayanamsa", "role": "owner"},
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._sun_lon", "role": "owner"},
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._moon_lon", "role": "owner"}
      ],
      "inputs": ["Julian day", "Swiss Ephemeris body", "ayanamsa"],
      "outputs": ["sidereal longitude in degrees [0, 360)"],
      "time_basis": "UTC Julian day; ayanamsa is explicit and defaults to Lahiri.",
      "method": {
        "kind": "algorithm",
        "summary": "Select the requested Swiss Ephemeris sidereal mode, calculate the body's geocentric ecliptic longitude at the supplied UT Julian day, normalize it to one revolution, and restore Lahiri mode for cached callers.",
        "steps": [
          "Validate the ayanamsa name and map it to a Swiss Ephemeris sidereal-mode constant.",
          "Set that global sidereal mode and call calc_ut with FLG_SWIEPH | FLG_SIDEREAL for the requested body.",
          "Take result[0] modulo 360 degrees as the longitude.",
          "Restore Lahiri mode before returning so later cached Lahiri calculations do not inherit mutable global state."
        ],
        "worked_examples": [{
          "label": "Hyderabad sunrise, 2026-06-11, Lahiri",
          "inputs": ["UT Julian day: 2461202.5077662035", "Bodies: Sun and Moon", "Ayanamsa: lahiri"],
          "calculation": ["Swiss Ephemeris is called separately for Sun and Moon with sidereal flags.", "Each returned longitude is normalized with value modulo 360."],
          "result": ["Sun: 55.8893662040 degrees", "Moon: 358.4708221648 degrees", "Moon-Sun elongation used downstream: 302.5814559608 degrees"]
        }],
        "notes": ["The example reproduces the repository runtime; it is not an independent ephemeris comparison.", "Swiss Ephemeris global sidereal mode makes restoration part of the computation contract."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical"], "verification_states": ["partially_verified"], "claim_ids": ["drik.sidereal_positions"], "note": "Representative Drik cells are independently compared; the full range remains broader than those cells."},
      "tests": ["tests/test_ayanamsa.py", "tests/test_utils.py"],
      "limitations": ["Accuracy and conventions inherit Swiss Ephemeris and the chosen ayanamsa."]
    },
    {
      "id": "astronomy.surya-siddhanta-longitudes",
      "title": "Surya Siddhanta mean-motion longitudes",
      "summary": "A bounded transcription of mean-motion and manda corrections produces solar and lunar longitudes for the Surya Siddhanta engine.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "ss_sun_longitude", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "ss_moon_longitude", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "ss_elongation", "role": "owner"}
      ],
      "inputs": ["Julian day"],
      "outputs": ["solar longitude", "lunar longitude", "Moon-Sun elongation"],
      "time_basis": "Julian day relative to the engine's Kali epoch constants.",
      "method": {
        "kind": "formula",
        "summary": "Compute mean longitude from elapsed Kali-epoch days and revolution counts, then apply one variable-circumference manda correction for the Sun and Moon.",
        "steps": [
          "Subtract the code epoch, including the Ujjain longitude adjustment, to obtain Kali ahargana.",
          "Convert ahargana and the body's revolution count into a normalized mean longitude.",
          "Compute anomaly from the fixed solar apogee or moving lunar apogee.",
          "Interpolate the manda epicycle circumference between its even- and odd-quadrant values.",
          "Subtract the arcsine manda correction and normalize to 0-360 degrees; subtract Sun from Moon for elongation."
        ],
        "formulae": [{
          "name": "Mean motion and manda correction",
          "expression": "K = JD - epoch\nL_mean = (K * revolutions / 1577917828 * 360) mod 360\nA = (L_mean - apogee) mod 360\nC = C_even - (C_even - C_odd) * abs(sin A)\nmanda = asin((C / 360) * sin A)\nL_true = (L_mean - manda) mod 360",
          "variables": ["K: Kali ahargana in days", "A: anomaly", "C: interpolated epicycle circumference in degrees", "L_true: returned longitude"]
        }],
        "worked_examples": [{
          "label": "Hyderabad sunrise, 2026-06-11",
          "inputs": ["UT Julian day: 2461202.5077662035", "Sun revolutions: 4,320,000", "Moon revolutions: 57,753,336"],
          "calculation": ["Apply the mean-motion formula with the Sun constants and solar apogee 77.333 degrees.", "Apply it again with the moving lunar apogee and lunar epicycle constants.", "Compute elongation as (Moon - Sun) modulo 360."],
          "result": ["Sun: 55.6206770967 degrees", "Moon: 0.5772516191 degrees", "Elongation: 304.9565745224 degrees"]
        }],
        "notes": ["The direct floating-point formula is a bounded modern transcription, not a complete traditional procedure.", "The ayanamsa constructor argument is validated but does not alter these longitudes."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["surya_siddhanta.mean_motion_manda", "panchangam.non_drik_engine_outputs"], "note": "The algorithm family is source-traced in part; production outputs remain regression-pinned rather than independently compared."},
      "tests": ["tests/test_surya_siddhanta_engine.py"],
      "limitations": ["This is not a complete textual transcription; direct floating-point trigonometry and simplified epoch/apogee constants intentionally differ from a full traditional procedure and from modern Drik positions."]
    },
    {
      "id": "astronomy.vakya-longitudes",
      "title": "Provisional Vakya lunar longitude",
      "summary": "A provisional nine-value project offset alters the inherited Surya Siddhanta lunar model.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "vakya_moon_longitude", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "vakya_elongation", "role": "owner"}
      ],
      "inputs": ["Julian day", "Vakya correction table"],
      "outputs": ["corrected lunar longitude", "corrected Moon-Sun elongation"],
      "time_basis": "Julian day with inherited Surya Siddhanta solar longitude.",
      "method": {
        "kind": "formula",
        "summary": "Choose one of nine project offsets from 3,031-day blocks since the code epoch and add it to the Surya Siddhanta Moon; the Sun remains the Surya Siddhanta Sun.",
        "steps": [
          "Compute absolute elapsed days K from the Surya Siddhanta code epoch.",
          "Select phase index floor(K / 3031) modulo 9.",
          "Read the corresponding correction from [0, +0.5, +1, +0.5, 0, -0.5, -1, -0.5, 0] degrees.",
          "Add the correction to the Surya Siddhanta Moon and normalize to one revolution.",
          "Subtract the inherited Surya Siddhanta Sun to obtain Vakya elongation."
        ],
        "formulae": [{
          "name": "Provisional lunar correction",
          "expression": "i = floor(abs(JD - epoch) / 3031) mod 9\nM_vakya = (M_SS + correction[i]) mod 360\nE_vakya = (M_vakya - S_SS) mod 360",
          "variables": ["i: nine-phase table index", "M_SS: Surya Siddhanta Moon longitude", "S_SS: Surya Siddhanta Sun longitude", "E_vakya: corrected elongation"]
        }],
        "worked_examples": [{
          "label": "Hyderabad sunrise, 2026-06-11",
          "inputs": ["UT Julian day: 2461202.5077662035", "Elapsed days from code epoch: 1,872,737.2182337036", "Surya Siddhanta Moon: 0.5772516191 degrees"],
          "calculation": ["floor(1,872,737.2182 / 3,031) modulo 9 = 5.", "Correction[5] = -0.5 degrees.", "Normalize 0.5772516191 - 0.5 and subtract the Surya Siddhanta Sun."],
          "result": ["Vakya Moon: 0.0772516191 degrees", "Vakya elongation: 304.4565745224 degrees"]
        }],
        "notes": ["This documents current code exactly; the table derivation is unresolved and tracked separately.", "The 3,031-day block must not be represented as a verified 248-year Vakya cycle."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical", "regional_convention", "project_heuristic"], "verification_states": ["engine_pinned"], "claim_ids": ["vakya.provisional_lunar_model", "panchangam.non_drik_engine_outputs"], "note": "No registered source derives the nine-value/3,031-day model; issue 176 tracks source reconstruction and possible correction."},
      "tests": ["tests/test_vakya_engine.py"],
      "limitations": ["The current model must not be described as a faithful 248-entry lunar-vākya table or as independently verified against a published Vakya Panchangam."]
    },
    {
      "id": "calendar.combustion-periods",
      "title": "Planetary Asta and Udaya calendar",
      "summary": "Swiss Ephemeris heliacal events produce per-location combustion setting and rising periods.",
      "owning_layer": "calendar",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/maudhya_calendar.py", "symbol": "combustion_periods", "role": "owner"}
      ],
      "inputs": ["date range", "location including altitude", "planet"],
      "outputs": ["combustion periods with Asta and Udaya instants"],
      "time_basis": "UTC heliacal event search converted for the requested location.",
      "surfaces": ["python-library", "mcp"],
      "provenance": {"evidence_classes": ["astronomical"], "verification_states": ["engine_pinned"], "claim_ids": [], "note": "Swiss Ephemeris event behavior is tested, but independent event-cell comparisons are not yet registered."},
      "tests": ["tests/test_maudhya_calendar.py"],
      "limitations": ["Heliacal visibility depends on observer, atmosphere, altitude, and Swiss Ephemeris modeling; the current fixed atmosphere and per-planet visibility parameters were tuned against a 2026 Hyderabad comparison set."],
      "method": {
        "kind": "algorithm",
        "summary": "Search Swiss Ephemeris heliacal events with a fixed atmosphere and per-planet observer parameters, pair disappearance with reappearance, and retain periods overlapping the requested range.",
        "steps": ["Validate the planet subset and build observer longitude, latitude, and altitude.", "Start each search 120 days before the requested range so an already-active Asta is retained.", "For Mars, Jupiter, and Saturn pair Heliacal Setting with Heliacal Rising; for Mercury and Venus search both superior- and inferior-conjunction event pairs.", "Advance beyond each exit, convert event Julian days to UTC, filter by overlap, and sort by Asta instant."],
        "worked_examples": [{"label": "Saturn Asta/Udaya, Hyderabad 2026", "inputs": ["Range: 2026-02-01 through 2026-05-01", "Observer: Hyderabad, altitude 531 m", "Planet: Saturn"], "calculation": ["Search Heliacal Setting with Saturn Snellen ratio 5.0.", "Search Heliacal Rising after entry with ratio 1.0.", "The resulting pair overlaps the requested range."], "result": ["Asta: 2026-03-13 13:17:49 UTC", "Udaya: 2026-04-21 23:43:55 UTC"]}],
        "notes": ["This is the heliacal-visibility calendar, distinct from the per-day fixed-elongation Maudhya flag.", "The current Hyderabad regression compares Saturn/Jupiter/Venus within about two days; the parameters are model calibration, not universal atmospheric constants."]
      }
    },
    {
      "id": "calendar.eclipse-events",
      "title": "Solar and lunar eclipse events",
      "summary": "Global eclipse searches are combined with per-location visibility and Sutak timing.",
      "owning_layer": "calendar",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/eclipses.py", "symbol": "list_eclipses_in_range", "role": "owner"},
        {"path": "telugu_panchangam/eclipses.py", "symbol": "get_eclipse_from_precomputed", "role": "owner"},
        {"path": "telugu_panchangam/eclipses.py", "symbol": "get_eclipse_for_date", "role": "owner"}
      ],
      "inputs": ["date or Julian-day range", "observer latitude and longitude"],
      "outputs": ["eclipse kind and subtype", "visibility", "start and end", "Sutak window"],
      "time_basis": "Swiss Ephemeris UTC events; Sutak is a fixed pre-end interval when locally visible.",
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["engine_pinned"], "claim_ids": ["panchangam.eclipse_events"], "note": "Event calculations are regression-pinned; the Sutak convention is a separate textual claim."},
      "tests": ["tests/test_eclipses.py"],
      "limitations": ["Local visibility is modeled and Sutak is omitted when the eclipse is not visible, but the current observer altitude is fixed to zero."],
      "method": {
        "kind": "algorithm",
        "summary": "Find Swiss Ephemeris global eclipse phases, assign them to the observer's local civil day, test local visibility, and add Sutak only for a visible event.",
        "steps": ["Search solar and lunar global events and decode subtype bits.", "Keep an event only when its maximum falls between local midnight and the next local midnight.", "For solar eclipses, require a matching local eclipse maximum; for lunar eclipses, sample Moon altitude across the phase window and require at least one sample above the horizon.", "Convert phase boundaries to UTC.", "If visible, start Sutak 12 hours before solar first contact or 9 hours before lunar first contact and end it at the eclipse end; otherwise leave Sutak null."],
        "formulae": [{"name": "Visible-event Sutak", "expression": "sutak_start = eclipse_start - H/24 day; sutak_end = eclipse_end", "variables": ["H: 12 hours for Solar, 9 hours for Lunar"]}],
        "worked_examples": [{"label": "Total lunar eclipse, Hyderabad 2026-03-03", "inputs": ["Observer: Hyderabad at zero modeled altitude", "Event kind: Lunar", "Subtype: Total"], "calculation": ["At least one of ten sampled instants has Moon altitude above zero, so the event is locally visible.", "Subtract 9 hours from phase start 09:50:06 UTC."], "result": ["Eclipse: 09:50:06-13:17:18 UTC", "Sutak: 00:50:06-13:17:18 UTC"]}],
        "notes": ["A visible late partial phase is sufficient for lunar visibility even when maximum occurs before local moonrise."]
      }
    },
    {
      "id": "calendar.graha-yuddha",
      "title": "Graha Yuddha periods",
      "summary": "Planetary-war entry, closest approach, victor, and exit are derived for tara graha pairs.",
      "owning_layer": "calendar",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/graha_yuddha.py", "symbol": "graha_yuddha_periods", "role": "owner"}
      ],
      "inputs": ["date range", "planetary longitudes and latitudes"],
      "outputs": ["entry", "minimum separation", "exit", "winner", "loser"],
      "time_basis": "UTC Julian-day numerical search.",
      "surfaces": ["python-library", "mcp"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["engine_pinned", "needs_locator"], "claim_ids": [], "note": "Numerical boundaries are tested; the one-degree admission and latitude-victor rules need claim-level registry locators."},
      "tests": ["tests/test_graha_yuddha.py"],
      "limitations": ["The result implements the project's documented one-degree and latitude rule, not every tradition's definition."],
      "method": {
        "kind": "algorithm",
        "summary": "Scan every selected Tara-graha pair for geocentric longitude separation below one degree, refine threshold crossings and closest approach, then choose the more northerly planet as victor.",
        "steps": ["Generate unordered pairs from Mercury, Venus, Mars, Jupiter, and Saturn.", "Scan at six-hour steps from 120 days before the range through 60 days after it.", "When angular separation crosses one degree, bisect the entry or exit with 44 iterations.", "Ternary-search the enclosed interval for minimum separation.", "Compare ecliptic latitudes at that instant; the greater latitude wins, and retain only periods overlapping the requested range."],
        "formulae": [{"name": "War admission", "expression": "delta = min(abs(lambda_1-lambda_2) mod 360, 360-(abs(lambda_1-lambda_2) mod 360)); in_war = delta < 1 degree", "variables": ["lambda_1, lambda_2: geocentric ecliptic longitudes"]}],
        "worked_examples": [{"label": "Venus-Jupiter, June 2026", "inputs": ["Range: 2026-06-01 through 2026-06-30", "Pair: Venus and Jupiter"], "calculation": ["The scan brackets entry and exit at the one-degree threshold.", "Minimum longitudinal separation rounds to 0.000 arcminutes.", "Venus has the greater ecliptic latitude at closest approach."], "result": ["Starts: 2026-06-08 19:18:54 UTC", "Exact: 2026-06-09 19:59:14 UTC", "Ends: 2026-06-10 20:43:12 UTC", "Winner: Venus; loser: Jupiter"]}],
        "notes": ["Ayanamsa cancels in pairwise longitude difference, so the implementation uses tropical coordinates for the separation search."]
      }
    },
    {
      "id": "calendar.rashi-ingresses",
      "title": "Planetary rashi ingresses",
      "summary": "Sidereal sign changes, including retrograde re-entry, are found over a requested range.",
      "owning_layer": "calendar",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/ingress.py", "symbol": "rashi_ingresses", "role": "owner"}
      ],
      "inputs": ["date range", "planet", "sidereal longitude model"],
      "outputs": ["ingress instant", "from rashi", "to rashi", "motion direction"],
      "time_basis": "UTC Julian-day crossing search.",
      "surfaces": ["python-library", "mcp"],
      "provenance": {"evidence_classes": ["astronomical"], "verification_states": ["engine_pinned"], "claim_ids": [], "note": "Crossing behavior is regression-tested; independent event-cell evidence is not registered."},
      "tests": ["tests/test_ingress.py"],
      "limitations": ["Moon is excluded and results follow the fixed sidereal model used by this module."],
      "method": {
        "kind": "algorithm",
        "summary": "Follow sidereal longitude through adaptive time steps, bisect each 30-degree sign-index change, and continue past the crossing so direct and retrograde re-entries are both emitted.",
        "steps": ["Validate the planet subset and select the requested ayanamsa.", "Compute sidereal longitude and speed; add 180 degrees for Ketu because it shares Rahu's Swiss body.", "Choose an adaptive step from distance to the nearest sign boundary and absolute speed.", "When the sign index changes, bisect for 44 iterations and record the new Rashi.", "Search again just after entry for its exit, repeat through the inclusive range, sort chronologically, and restore Lahiri mode."],
        "formulae": [{"name": "Rashi index", "expression": "r = floor((lambda mod 360) / 30) mod 12", "variables": ["lambda: configured sidereal longitude", "r: zero-based Rashi index"]}],
        "worked_examples": [{"label": "Sun enters Makara, 2026", "inputs": ["Range: 2026-01-01 through 2026-02-28", "Planet: Sun", "Ayanamsa: Lahiri"], "calculation": ["The sign index changes to Makara and the crossing is bisected.", "The following crossing supplies the exit from Makara."], "result": ["Makara entry: 2026-01-14 09:37:19 UTC", "Makara exit/Kumbha entry: 2026-02-12 22:38:58 UTC"]}],
        "notes": ["The Moon is intentionally absent from INGRESS_PLANETS; the output does include retrograde re-entry rather than assuming sign order is always forward."]
      }
    },
    {
      "id": "derived.anandadi-yoga",
      "title": "Anandadi Yoga",
      "summary": "A weekday and Nakshatra table assigns one of the 28 Anandadi Yogas.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/special_yogas.py", "symbol": "compute_anandadi_yoga", "role": "owner"}
      ],
      "inputs": ["Vaaram", "Nakshatra"],
      "outputs": ["Anandadi Yoga name"],
      "time_basis": "Panchangam day and its active Nakshatra.",
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "The table is regression-tested but still belongs to the broader derived-classification locator gap."},
      "tests": ["tests/test_anandadi.py"],
      "limitations": ["The table is a named textual convention, not an astronomical observation."],
      "method": {
        "kind": "formula",
        "summary": "Rotate the 28-name Anandadi sequence by the weekday's configured Nakshatra offset, then index it with the active Nakshatra.",
        "steps": ["Look up the zero-based weekday offset in VAARA_OFFSET.", "Look up the active Nakshatra's zero-based index in NAKSHATRA_ORDER.", "Subtract the weekday offset, reduce modulo 28, and index ANANDADI_YOGAS.", "Return null for an unrecognized weekday or Nakshatra."],
        "formulae": [{"name": "Anandadi index", "expression": "y = (n - o_v) mod 28", "variables": ["n: zero-based Nakshatra index", "o_v: weekday-specific starting offset", "y: index in the 28-name Anandadi sequence"]}],
        "worked_examples": [{"label": "Guruvaram with Anuradha", "inputs": ["Guruvaram offset: 16", "Anuradha Nakshatra index: 16"], "calculation": ["(16 - 16) mod 28 = 0.", "ANANDADI_YOGAS[0] is Ananda."], "result": ["Ananda"]}],
        "notes": ["The rotation and dispositions are regression-pinned; the exact source-edition locator remains open and is disclosed in Provenance."]
      }
    },
    {
      "id": "derived.bhadra-mukha-puchha",
      "title": "Bhadra Mukha and Puchha windows",
      "summary": "Vishti Karana duration is partitioned into Tithi-specific Bhadra face and tail windows.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/karana_windows.py", "symbol": "compute_bhadra_windows", "role": "owner"}
      ],
      "inputs": ["Tithi span", "Vishti Karana spans", "Ghati clock"],
      "outputs": ["Bhadra Mukha window", "Bhadra Puchha window"],
      "time_basis": "Observed Vishti duration expressed on the sunrise-anchored Ghati scale.",
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["verified"], "claim_ids": ["panchangam.bhadra_mukha_puchha"], "note": "The verse mapping and computation contract are registered as verified."},
      "tests": ["tests/test_bhadra_mukha_puchha.py"],
      "limitations": ["This implements the registered Tithi/Yama mapping and does not blend conflicting published tables."],
      "method": {
        "kind": "formula",
        "summary": "Find the Vishti Karana, select Tithi-specific quarters for Mukha and Puchha, scale nominal Ghati widths to the observed Vishti duration, and clip the results to the Panchangam day.",
        "steps": ["Select the first Vishti span; return no windows if none exists.", "Evaluate Tithi at the Vishti midpoint and read its Mukha/Puchha quarter pair.", "Divide Vishti into four equal quarters.", "Place Mukha at the start of its quarter for 5/30 of Vishti and Puchha at the end of its quarter for 3/30.", "Clip each interval to sunrise through next sunrise."],
        "formulae": [{"name": "Scaled sub-windows", "expression": "Q = V / 4; width_mukha = 5V / 30; width_puchha = 3V / 30", "variables": ["V: observed Vishti duration", "Q: one Vishti quarter"]}],
        "worked_examples": [{"label": "Twelve-hour Vishti during Shukla Chaturthi", "inputs": ["Vishti: 00:00-12:00 UTC", "Quarter mapping: Mukha 1, Puchha 4"], "calculation": ["One quarter is 3 hours.", "Mukha width is 12h * 5/30 = 2h, starting at quarter 1.", "Puchha width is 12h * 3/30 = 1h12m, ending at quarter 4."], "result": ["Bhadra Mukha: 00:00-02:00 UTC", "Bhadra Puchha: 10:48-12:00 UTC"]}],
        "notes": ["Only the registered eight-Tithi quarter table is used; unmatched Tithis return no Bhadra sub-window."]
      }
    },
    {
      "id": "derived.disha-shoola",
      "title": "Disha Shoola direction",
      "summary": "A weekday table returns the traditionally avoided travel direction.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/disha_shoola.py", "symbol": "disha_shoola", "role": "owner"}
      ],
      "inputs": ["Vaaram"],
      "outputs": ["avoided travel direction"],
      "time_basis": "Sunrise-anchored Panchangam weekday.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "The table is tested but its exact edition locator remains part of derived-classification debt."},
      "tests": ["tests/test_disha_shoola.py"],
      "limitations": ["Travel-direction rules vary by lineage and remedies are not automated."],
      "method": {
        "kind": "decision-table",
        "summary": "Return the avoided direction from the maintained seven-row weekday table.",
        "steps": ["Use the sunrise-anchored Vaaram as the lookup key.", "Return West, East, North, or South from DISHA_SHOOLA.", "Return null when the weekday is absent or unrecognized."],
        "worked_examples": [{"label": "Thursday travel direction", "inputs": ["Vaaram: Guruvaram"], "calculation": ["DISHA_SHOOLA[Guruvaram] = South."], "result": ["Avoided direction: South"]}],
        "notes": ["This is a classification input to travel Muhurtam, not an instruction or automated remedy."]
      }
    },
    {
      "id": "derived.ghati-clock",
      "title": "Sunrise-anchored Ghati clock",
      "summary": "The interval from sunrise to next sunrise is divided into 60 proportional Ghatis.",
      "owning_layer": "derived",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/ghati.py", "symbol": "make_clock", "role": "owner"},
        {"path": "telugu_panchangam/ghati.py", "symbol": "civil_to_ghati", "role": "owner"},
        {"path": "telugu_panchangam/ghati.py", "symbol": "ghati_to_civil", "role": "owner"},
        {"path": "telugu_panchangam/ghati.py", "symbol": "ghati_window", "role": "owner"}
      ],
      "inputs": ["sunrise", "next sunrise", "civil instant or Ghati value"],
      "outputs": ["seconds per Ghati", "civil/Ghati conversion", "Ghati window"],
      "time_basis": "Local sunrise to next local sunrise, divided into 60 equal parts.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Conversion behavior is tested; the textual use of scaled Ghatis is covered only in part."},
      "tests": ["tests/test_ghati.py"],
      "limitations": ["A Ghati is proportional to that local sunrise-to-sunrise interval, not fixed to civil minutes."],
      "method": {
        "kind": "formula",
        "summary": "Normalize the local sunrise-to-next-sunrise interval to 60 equal Ghatis and convert linearly in either direction.",
        "steps": ["Subtract sunrise from next sunrise in seconds.", "Divide by 60 to obtain seconds per Ghati.", "For civil-to-Ghati, divide elapsed seconds since sunrise by that scale.", "For Ghati-to-civil, add the scaled Ghati duration to sunrise."],
        "formulae": [{"name": "Ghati scale", "expression": "s_g = (T_next_rise - T_rise) / 60; g = (t - T_rise) / s_g; t = T_rise + g*s_g", "variables": ["s_g: seconds per proportional Ghati", "g: Ghatis since sunrise", "t: civil instant"]}],
        "worked_examples": [{"label": "Twenty-four-hour sunrise day", "inputs": ["Sunrise: 06:00", "Next sunrise: 06:00 next day", "Civil instant: 12:00"], "calculation": ["86,400 / 60 = 1,440 seconds per Ghati.", "Six elapsed hours / 24 minutes = 15 Ghatis."], "result": ["12:00 corresponds to Ghati 15.0"]}],
        "notes": ["The scale intentionally follows the observed local Panchangam day; it is not hard-coded to 24 civil minutes."]
      }
    },
    {
      "id": "derived.khar-maasa",
      "title": "Khar Maasa classification",
      "summary": "Solar sign classifies Dhanu or Meena periods as Khar Maasa.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/maasa_filters.py", "symbol": "khar_maasa_name", "role": "owner"}
      ],
      "inputs": ["solar rashi"],
      "outputs": ["Khar Maasa name or null"],
      "time_basis": "Solar rashi at the Panchangam-day snapshot.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "The classification is tested but remains under the broad locator gap."},
      "tests": ["tests/test_khar_maasa.py"],
      "limitations": ["Its effect depends on the activity profile; the flag alone is not an absolute verdict."],
      "method": {
        "kind": "decision-table",
        "summary": "Classify only Dhanu and Meena solar Rashis as Khar Maasa and return a display name.",
        "steps": ["Read the solar Rashi at the Panchangam snapshot.", "Map Dhanu to Dhanur and Meena to Meena.", "Return null for every other sign or missing input."],
        "worked_examples": [{"label": "Sun in Dhanu", "inputs": ["Solar Rashi: Dhanu"], "calculation": ["Dhanu matches KHAR_MAASA_SIGNS.", "Apply the display-name mapping Dhanu -> Dhanur."], "result": ["Khar Maasa: Dhanur"]}],
        "notes": ["Downstream activity profiles decide whether the classification affects a requested ceremony."]
      }
    },
    {
      "id": "derived.named-muhurtas",
      "title": "Thirty named Muhurtas",
      "summary": "Day and night are each divided into fifteen named proportional Muhurtas.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/muhurtas.py", "symbol": "named_muhurtas", "role": "owner"},
        {"path": "src/data/muhurtas.ts", "symbol": "MUHURTA_DAY", "role": "mirror"}
      ],
      "inputs": ["sunrise", "sunset", "next sunrise"],
      "outputs": ["30 named day/night windows and dispositions"],
      "time_basis": "Fifteen equal day parts and fifteen equal night parts.",
      "surfaces": ["python-library", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["verified"], "claim_ids": [], "note": "The checked table is maintained in docs/reference/07-muhurta-table.md and parity-tested."},
      "tests": ["tests/test_named_muhurtas.py"],
      "limitations": ["Names and dispositions follow the project's verified table; other almanacs may label variants differently."],
      "method": {
        "kind": "formula",
        "summary": "Tile daylight into fifteen equal named windows and, when next sunrise is available, tile the night into fifteen more.",
        "steps": ["Compute daylight duration and divide it by 15.", "Emit DAY_MUHURTAS in order with exact adjacent boundaries.", "If next-day data exists, divide sunset-to-next-sunrise by 15 and emit NIGHT_MUHURTAS.", "Mark daytime index 8 as Abhijit only when the engine exposes Abhijit; mark night index 14 as Brahma."],
        "formulae": [{"name": "Named Muhurta boundaries", "expression": "day_i = [rise + (i-1)D/15, rise + iD/15]; night_i = [set + (i-1)N/15, set + iN/15]", "variables": ["D: sunset minus sunrise", "N: next sunrise minus sunset", "i: one-based index from 1 through 15"]}],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11, Drik Ganita", "inputs": ["Sunrise: 05:41:11 IST", "Sunset: 18:50:12 IST", "Next sunrise: 05:41:17 IST"], "calculation": ["Daylight / 15 = 52m36s approximately.", "Night / 15 = 43m24s approximately."], "result": ["Day index 8, Vidhi/Abhijit: 11:49:23-12:41:59 IST", "Night index 14, Brahma: 04:14:28-04:57:52 IST"]}],
        "notes": ["Wednesday keeps the eighth named daytime interval but does not label it as Abhijit because the engine suppresses that window."]
      }
    },
    {
      "id": "derived.nakshatra-mukha",
      "title": "Nakshatra Mukha direction",
      "summary": "Nakshatras are classified as Adho, Urdhva, or Tiryan Mukha.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/nakshatra_filters.py", "symbol": "nakshatra_mukha", "role": "owner"}
      ],
      "inputs": ["Nakshatra name"],
      "outputs": ["Mukha direction or null"],
      "time_basis": "Active Nakshatra at the evaluated day or slot.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Classification behavior is tested; exact source locators remain incomplete."},
      "tests": ["tests/test_mukha_nakshatra.py"],
      "limitations": ["The direction is an activity input, not a general day-quality score."],
      "method": {
        "kind": "decision-table",
        "summary": "Look up the active Nakshatra in the maintained Adho, Urdhva, and Tiryan Mukha classification table.",
        "steps": ["Use the canonical engine spelling as the key.", "Return the exact NAKSHATRA_MUKHA table value.", "Return null for missing or unrecognized input."],
        "worked_examples": [{"label": "Revati classification", "inputs": ["Nakshatra: Revati"], "calculation": ["NAKSHATRA_MUKHA[Revati] = Tiryan."], "result": ["Mukha: Tiryan"]}],
        "notes": ["Activity code interprets the direction; this function does not grade the day by itself."]
      }
    },
    {
      "id": "derived.panchaka-nakshatra",
      "title": "Panchaka Nakshatra flag",
      "summary": "Dhanishtha through Revati are marked for activity-specific Panchaka restrictions.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/nakshatra_filters.py", "symbol": "is_panchaka_nakshatra", "role": "owner"}
      ],
      "inputs": ["Nakshatra name"],
      "outputs": ["Panchaka membership boolean"],
      "time_basis": "Active Nakshatra.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "The set is tested; individual activity consequences have separate provenance where available."},
      "tests": ["tests/test_panchaka_nakshatras.py"],
      "limitations": ["Restrictions are activity-specific and should not be presented as a universal prohibition."],
      "method": {
        "kind": "decision-table",
        "summary": "Test exact membership in the five-name Panchaka Nakshatra set.",
        "steps": ["Read the active Nakshatra name.", "Return true for Dhanishtha, Shatabhisha, Purva Bhadrapada, Uttara Bhadrapada, or Revati.", "Return false for every other string."],
        "worked_examples": [{"label": "Revati membership", "inputs": ["Nakshatra: Revati"], "calculation": ["Revati is in PANCHAKA_NAKSHATRAS."], "result": ["Panchaka Nakshatra: true"]}],
        "notes": ["The implementation deliberately treats all of Dhanishtha as Panchaka; it does not calculate a half-Nakshatra boundary."]
      }
    },
    {
      "id": "derived.panchaka-rahita",
      "title": "Panchaka Rahita remainder",
      "summary": "Tithi, Vaaram, Nakshatra, and Lagna ordinals are summed modulo nine to classify dosha.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/panchaka.py", "symbol": "get_panchaka_remainder", "role": "owner"},
        {"path": "telugu_panchangam/panchaka.py", "symbol": "evaluate_panchaka", "role": "owner"}
      ],
      "inputs": ["Tithi", "Vaaram", "Nakshatra", "Lagna"],
      "outputs": ["remainder", "dosha name", "auspicious flag", "activity cautions"],
      "time_basis": "Sunrise snapshot for the day field; recomputed at slot Lagna for Muhurtam.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["verified"], "claim_ids": ["panchangam.panchaka_rahita"], "note": "Formula and remainder meanings have registered source evidence."},
      "tests": ["tests/test_panchaka_rahita.py"],
      "limitations": ["Ordinal naming and activity cautions follow the registered convention."],
      "method": {
        "kind": "formula",
        "summary": "Convert the four named limbs to one-based ordinals, sum them modulo nine, and map the remainder to a named activity-specific caution.",
        "steps": ["Number Tithi 1-30, Vaaram 1-7, Nakshatra 1-27, and Lagna 1-12 in canonical table order.", "Add the four ordinals and reduce modulo 9.", "Map remainders 0, 3, 5, and 7 to Rahita; map 1, 2, 4, 6, and 8 to named cautions.", "At slot level recompute with the Lagna active at the slot start."],
        "formulae": [{"name": "Panchaka remainder", "expression": "r = (T + V + N + L) mod 9", "variables": ["T: one-based Tithi ordinal", "V: one-based Vaaram ordinal", "N: one-based Nakshatra ordinal", "L: one-based Lagna ordinal"]}],
        "worked_examples": [{"label": "Krishna Ekadashi, Thursday, Revati, Meena", "inputs": ["T=26", "V=5", "N=27", "L=12"], "calculation": ["26 + 5 + 27 + 12 = 70.", "70 mod 9 = 7.", "Remainder 7 maps to Rahita."], "result": ["Remainder: 7", "Name: Rahita", "Auspicious flag: true"]}],
        "notes": ["The output includes targeted avoid_for categories for non-Rahita remainders rather than treating every dosha as universal."]
      }
    },
    {
      "id": "derived.panchanga-shuddhi",
      "title": "Five-limb Panchanga Shuddhi",
      "summary": "Tithi, Vaaram, Nakshatra, Yoga, and Karana are individually graded and counted.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/panchanga_shuddhi.py", "symbol": "assess_shuddhi", "role": "owner"}
      ],
      "inputs": ["PanchangamDay five limbs"],
      "outputs": ["per-limb assessment", "0-5 Shuddhi count", "summary verdict"],
      "time_basis": "Panchangam day at sunrise.",
      "surfaces": ["python-library", "mcp"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchanga_shuddhi.five_limb_count"], "note": "The implemented count and tables are tested; the exact textual locator remains open."},
      "tests": ["tests/test_panchanga_shuddhi.py"],
      "limitations": ["A five-limb count is not a complete personal election chart."],
      "method": {
        "kind": "decision-table",
        "summary": "Grade each sunrise Panchangam limb with maintained rule sets, count only limbs graded shuddha, and map the count from zero through five to a verdict label.",
        "steps": ["Grade Tithi ashuddha only for Rikta 4th, 9th, and 14th classes.", "Grade Vaara from the four auspicious and three inauspicious weekday sets.", "Grade Nakshatra by Laghu/Mridu/Dhruva/Chara, Tikshna/Ugra, or Mishra category.", "Grade Yoga from auspicious, hard-avoid, partial-dosha, or neutral sets and Karana from movable versus Vishti/fixed sets.", "Count quality=shuddha and index the six verdict labels."],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11, Drik Ganita", "inputs": ["Krishna Ekadashi", "Guruvaram", "Revati", "Shobhana", "Bava"], "calculation": ["Each of the five values maps to shuddha in its respective table.", "Shuddha count = 5."], "result": ["Verdict: Sarva Shuddha", "Count: 5 of 5"]}],
        "notes": ["Mixed limbs do not increment the count; the result is a general day-level screen, not a personal Muhurtam verdict."]
      }
    },
    {
      "id": "derived.pitru-paksha",
      "title": "Pitru Paksha flag",
      "summary": "Bhadrapada Krishna Paksha is classified as the ancestral fortnight.",
      "owning_layer": "derived",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/pitru_paksha.py", "symbol": "is_pitru_paksha_day", "role": "owner"}
      ],
      "inputs": ["Maasam", "Paksham"],
      "outputs": ["Pitru Paksha boolean"],
      "time_basis": "Telugu Amanta month and fortnight for the Panchangam day.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual", "regional_convention"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "The Telugu regional convention is tested but not yet claim-located independently."},
      "tests": ["tests/test_pitru_paksha.py"],
      "limitations": ["Other regional month conventions can place the named fortnight differently."],
      "method": {
        "kind": "decision-table",
        "summary": "Remove Adhika or Nija display prefixes, then require base Maasam Bhadrapada and Paksham Krishna.",
        "steps": ["Return false if Maasam or Paksham is missing.", "Strip a leading Adhika or Nija prefix from Maasam.", "Return true only when the base month is Bhadrapada and Paksham is Krishna."],
        "worked_examples": [{"label": "Nija Bhadrapada Krishna", "inputs": ["Maasam: Nija Bhadrapada", "Paksham: Krishna"], "calculation": ["Strip Nija to obtain Bhadrapada.", "Both required values match."], "result": ["Pitru Paksha: true"]}],
        "notes": ["The flag covers the Krishna-paksha portion implemented by this Telugu Amanta convention."]
      }
    },
    {
      "id": "derived.sankramana-avoidance",
      "title": "Sankramana avoidance window",
      "summary": "A symmetric sixteen-Ghati interval is placed around exact solar ingress.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/sankramana.py", "symbol": "compute_sankramana_window", "role": "owner"}
      ],
      "inputs": ["solar ingress instant", "Ghati clock"],
      "outputs": ["avoidance start and end"],
      "time_basis": "Sixteen proportional Ghatis before and after ingress.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["verified"], "claim_ids": ["panchangam.sankramana_avoidance"], "note": "The duration and placement have registered textual evidence."},
      "tests": ["tests/test_sankramana_window.py"],
      "limitations": ["The window is a textual election rule, not uncertainty around the astronomical crossing."],
      "method": {
        "kind": "formula",
        "summary": "Center a symmetric window of sixteen local proportional Ghatis on the exact solar-ingress instant.",
        "steps": ["Return null when the Panchangam day has no solar ingress.", "Read seconds per Ghati from the sunrise-to-next-sunrise clock.", "Multiply by 16 for the half-width.", "Subtract and add that half-width around the ingress instant."],
        "formulae": [{"name": "Sankramana avoidance", "expression": "W = 16*s_g; start = ingress - W; end = ingress + W", "variables": ["s_g: seconds per proportional Ghati", "W: half-width"]}],
        "worked_examples": [{"label": "Mithuna ingress, Hyderabad 2026-06-15", "inputs": ["Ingress: 12:53:00 IST", "Seconds per Ghati: 1,440.15"], "calculation": ["16 * 1,440.15 seconds = 6h24m02.4s per side.", "Apply symmetrically around the ingress."], "result": ["Avoidance: 06:28:57-19:17:02 IST"]}],
        "notes": ["The same sixteen-Ghati half-width is used for all signs; alternative solstitial conventions are not blended."]
      }
    },
    {
      "id": "derived.special-yogas",
      "title": "Vaaram-Tithi-Nakshatra special Yogas",
      "summary": "Table rules identify Sarvartha Siddhi, Amrita Siddhi, Siddha, Visha, Dagdha, and Pushkara Yogas.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/special_yogas.py", "symbol": "get_special_yogas", "role": "owner"},
        {"path": "src/panels/tarabalam.ts", "symbol": "muSpecialYogasAt", "role": "mirror"}
      ],
      "inputs": ["Vaaram", "Tithi", "Nakshatra"],
      "outputs": ["list of applicable special Yoga names"],
      "time_basis": "Evaluated at the day snapshot and again at slot time where supported.",
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Python/browser parity is tested, while some table locators remain open."},
      "tests": ["tests/test_special_yogas.py", "tests/test_activity_surface_parity.py"],
      "limitations": ["Named Yogas with similar names in other traditions are not inferred beyond these exact tables."],
      "method": {
        "kind": "decision-table",
        "summary": "Evaluate independent weekday-Nakshatra, weekday-Tithi, Tithi-family, and Pushkara conjunction tables and return every matched Yoga in fixed order.",
        "steps": ["Test Sarvartha Siddhi and Amrita Siddhi weekday-Nakshatra tables.", "Convert Tithi to its 1-15 Paksha ordinal and test Visha and Dagdha weekday tables.", "Map Tithi to Nanda/Bhadra/Jaya/Rikta/Purna and test its Siddha weekday partner.", "On Sunday, Tuesday, or Saturday, test the Dvipushkara and Tripushkara Tithi-Nakshatra conjunctions.", "Append each match; do not collapse simultaneous Yogas."],
        "worked_examples": [{"label": "Guruvaram, Shukla Navami, Pushya", "inputs": ["Vaaram: Guruvaram", "Tithi ordinal within Paksha: 9", "Nakshatra: Pushya"], "calculation": ["Pushya is in Thursday's Sarvartha Siddhi set and is Thursday's Amrita Siddhi Nakshatra.", "Thursday's Visha Tithi is 9.", "No other configured rule matches these inputs."], "result": ["Sarvartha Siddhi Yoga", "Amrita Siddhi Yoga", "Visha Yoga"]}],
        "notes": ["The browser mirror is parity-tested against the Python owner; unresolved exact text locators remain visible in Provenance."]
      }
    },
    {
      "id": "derived.vishaghati",
      "title": "Nakshatra Vishaghati windows",
      "summary": "Nakshatra-specific poison-Ghati offsets produce clipped civil-time windows.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/karana_windows.py", "symbol": "compute_vishaghati", "role": "owner"}
      ],
      "inputs": ["Nakshatra spans", "Ghati clock", "day bounds"],
      "outputs": ["Vishaghati windows in civil time and Ghatis"],
      "time_basis": "Nakshatra duration mapped to the sunrise-anchored Ghati scale.",
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Offsets and clipping are tested; claim-level source coverage remains grouped with mixed daily windows."},
      "tests": ["tests/test_vishaghati.py"],
      "limitations": ["The selected offset table is tradition-specific."],
      "method": {
        "kind": "formula",
        "summary": "Place a short window at the Nakshatra-specific Ghati offset within each observed Nakshatra span, then clip it to the Panchangam day.",
        "steps": ["Read the configured offset Ghatis for the span's Nakshatra.", "Scale that offset over the span's full 60-Ghati transit.", "Set the width to four Vighatis using the day's proportional Ghati clock.", "Discard non-overlapping windows and clip partial overlaps to sunrise or next sunrise.", "Report both civil timestamps and sunrise-based Ghati coordinates."],
        "formulae": [{"name": "Vishaghati placement", "expression": "start = N_start + N_duration*offset/60; width = 4*s_g/60", "variables": ["offset: Nakshatra table value in Ghatis", "s_g: seconds per day Ghati", "N_duration: observed Nakshatra duration"]}],
        "worked_examples": [{"label": "Synthetic 24-hour Ashvini span", "inputs": ["Nakshatra span: 06:00 to 06:00 next day", "Ashvini offset: 50 Ghatis", "Day Ghati scale: 1,440 seconds"], "calculation": ["24h * 50/60 = 20h after Nakshatra start.", "Four Vighatis = 4 * 1,440/60 = 96 seconds."], "result": ["Vishaghati: 02:00:00-02:01:36 next day"]}],
        "notes": ["Offset placement scales with the observed Nakshatra span, while width scales with the local sunrise day; these are intentionally distinct clocks."]
      }
    },
    {
      "id": "gochara.graha-positions",
      "title": "Nine-graha sidereal positions",
      "summary": "Sidereal longitude produces rashi, Nakshatra, Pada, retrograde state, and next ingress for nine grahas.",
      "owning_layer": "calendar",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/gochara/positions.py", "symbol": "graha_positions", "role": "owner"}
      ],
      "inputs": ["Julian day", "ayanamsa"],
      "outputs": ["longitude", "rashi", "Nakshatra", "Pada", "retrograde", "next ingress date"],
      "time_basis": "Requested Julian day, normally local sunrise for daily surfaces.",
      "surfaces": ["python-library", "mcp", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical"], "verification_states": ["partially_verified"], "claim_ids": ["drik.sidereal_positions"], "note": "The same Drik longitude evidence boundary applies to these derived fields."},
      "tests": ["tests/test_graha_positions.py"],
      "limitations": ["Rahu and Ketu use the selected node convention; next-ingress dates are numerical search results and rasi_until is currently rendered as an IST calendar date rather than the requested city's local date."],
      "method": {
        "kind": "algorithm",
        "summary": "Compute sidereal longitude and speed for each of nine Grahas, derive the categorical fields, and search adaptively for the next 30-degree sign crossing.",
        "steps": ["Set the requested Swiss Ephemeris sidereal mode.", "Compute longitude and daily speed; derive Ketu as mean Rahu plus 180 degrees.", "Map longitude to Rashi, one of 27 Nakshatras, and one of four Padas; mark negative speed as retrograde.", "Step adaptively toward the nearest sign boundary and bisect the first sign-index change with 40 iterations.", "Convert the ingress to an IST date, emit the next Rashi, and restore Lahiri mode."],
        "formulae": [{"name": "Rashi, Nakshatra, and Pada", "expression": "r=floor(lambda/30); n=floor(lambda/(360/27)); pada=(floor((lambda/(360/27))*4) mod 4)+1", "variables": ["lambda: normalized sidereal longitude in degrees"]}],
        "worked_examples": [{"label": "Guru at Hyderabad sunrise, 2026-06-11", "inputs": ["UT Julian day: 2461202.5077662035", "Ayanamsa: Lahiri"], "calculation": ["Guru longitude = 91.7834 degrees, placing it in Rashi index 3 and Punarvasu Pada 4.", "Positive daily speed means it is not retrograde.", "The next sign-index crossing is searched numerically."], "result": ["Rashi: Karka", "Nakshatra: Punarvasu, Pada 4", "Next Rashi: Simha on 2026-10-31 IST"]}],
        "notes": ["The longitude evidence boundary is inherited from the Drik calculation; next-ingress date localization is currently fixed to IST."]
      }
    },
    {
      "id": "gochara.named-shani-conditions",
      "title": "Named Shani transit conditions",
      "summary": "Saturn's house from Janma Rashi is labeled as Sade Sati, Ashtama Shani, or Ardhastama Shani where applicable.",
      "owning_layer": "personal",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/gochara/rules.py", "symbol": "named_conditions", "role": "owner"},
        {"path": "src/shani-conditions.ts", "symbol": "shaniConditionFromMoonHouse", "role": "mirror"}
      ],
      "inputs": ["Janma Rashi", "current Saturn rashi"],
      "outputs": ["named Shani condition and phase"],
      "time_basis": "Transit snapshot relative to natal Moon sign.",
      "surfaces": ["python-library", "mcp", "website", "generated-data"],
      "provenance": {"evidence_classes": ["textual", "regional_convention"], "verification_states": ["partially_verified"], "claim_ids": ["gochara.named_shani_conditions"], "note": "Underlying adverse houses have support; conventional names and phases are explicitly bounded."},
      "tests": ["tests/test_gochara_rules.py", "src/__tests__/shani-conditions.test.ts"],
      "limitations": ["Names and phase labels are conventional presentation and not a complete natal transit judgment."],
      "method": {
        "kind": "decision-table",
        "summary": "Count Saturn's current sign inclusively from Janma Rashi and label only houses 12, 1, 2, 8, and 4.",
        "steps": ["Convert Janma Rashi and Shani Rashi to canonical indices.", "Compute the inclusive wrapped house number.", "Map 12/1/2 to rising/peak/setting Sade Sati, 8 to Ashtama Shani, and 4 to Ardhastama Shani.", "Return an empty list for every other house."],
        "formulae": [{"name": "Transit house", "expression": "h = ((index(transit)-index(janma)) mod 12)+1", "variables": ["h: inclusive house from Janma Rashi"]}],
        "worked_examples": [{"label": "Shani in Meena from Mesha Janma Rashi", "inputs": ["Janma Rashi: Mesha", "Shani Rashi: Meena"], "calculation": ["((11 - 0) mod 12) + 1 = 12.", "House 12 maps to the rising phase label."], "result": ["Sade Sati (rising phase)"]}],
        "notes": ["The labels summarize a Moon-sign transit convention; they do not infer natal placements, Dasha, aspects, or individualized outcomes."]
      }
    },
    {
      "id": "gochara.transit-verdicts",
      "title": "Gochara transit verdicts and Vedha",
      "summary": "Each graha's house from Janma Rashi is assessed against favourable houses and Vedha blocking rules.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/gochara/rules.py", "symbol": "gochara_for", "role": "owner"},
        {"path": "src/panels/gochara.ts", "symbol": "renderGochara", "role": "mirror"}
      ],
      "inputs": ["Janma Rashi", "current graha rashis"],
      "outputs": ["house", "favourable boolean", "Vedha blocker", "verdict"],
      "time_basis": "Daily transit snapshot relative to natal Moon sign.",
      "surfaces": ["python-library", "mcp", "website", "generated-data"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["verified"], "claim_ids": ["gochara.favourable_houses", "gochara.vedha_tables", "gochara.nodes"], "note": "Classical house and Vedha tables are claim-located; disclosed node handling is separately registered."},
      "tests": ["tests/test_gochara_rules.py", "tests/test_gochara_provenance.py"],
      "limitations": ["This is Moon-sign Gochara, not a full natal-chart or Dasha interpretation."],
      "method": {
        "kind": "decision-table",
        "summary": "Count each Graha's house from Janma Rashi, test its favourable-house set, and downgrade a favourable result when a non-exempt Graha occupies its mapped Vedha house.",
        "steps": ["Build a house-to-occupants index for the supplied sky.", "For each Graha, compute its inclusive house from Janma Rashi.", "Start adverse; change to favourable only when that house is in the Graha's favourable set.", "For non-node Grahas, find the Vedha house for that favourable position and scan its occupants.", "Ignore self, Rahu/Ketu, and the Surya-Shani or Chandra-Budha exemption pairs; otherwise mark blocked and name the first blocker."],
        "formulae": [{"name": "Gochara house", "expression": "h_g = ((index(rasi_g)-index(janma_rasi)) mod 12)+1", "variables": ["h_g: Graha house from natal Moon sign"]}],
        "worked_examples": [{"label": "Surya in Mithuna with Guru in Dhanu, Janma Mesha", "inputs": ["Janma Rashi: Mesha", "Surya: Mithuna", "Guru: Dhanu"], "calculation": ["Surya is in house 3, one of its favourable houses.", "Surya house 3 has Vedha house 9.", "Guru occupies house 9 and is not an exempt blocker."], "result": ["Surya verdict: blocked", "Vedha by: Guru"]}],
        "notes": ["Rahu and Ketu use Surya's favourable houses but intentionally receive no Vedha processing under the registered conservative policy."]
      }
    },
    {
      "id": "interpretation.daily-rasi-phalalu-deterministic",
      "title": "Deterministic daily Rasi Phalalu",
      "summary": "Computed Gochara facts are rendered into deterministic daily reading text.",
      "owning_layer": "interpretation",
      "claim_kind": "project-heuristic",
      "implementations": [
        {"path": "telugu_panchangam/personal/phalalu.py", "symbol": "rasi_phalalu", "role": "owner"},
        {"path": "src/panels/gochara.ts", "symbol": "buildPhalalu", "role": "mirror"}
      ],
      "inputs": ["Janma Rashi", "computed graha positions", "Gochara verdicts"],
      "outputs": ["deterministic explanatory reading"],
      "time_basis": "Daily transit snapshot.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual", "project_heuristic"], "verification_states": ["verified", "heuristic"], "claim_ids": ["gochara.favourable_houses", "gochara.vedha_tables"], "note": "Transit facts inherit verified rule tables; wording and synthesis remain project interpretation."},
      "tests": ["tests/test_phalalu.py"],
      "limitations": ["Narrative wording is interpretive and must not be treated as individualized professional advice."],
      "method": {
        "kind": "algorithm",
        "summary": "Compose fixed English sentences from Chandrabalam, verified Gochara verdicts, named Shani conditions, and optional Tarabalam, then assign a small project-defined day-quality label.",
        "steps": ["Compute all nine Gochara verdicts and any named Shani condition.", "Compute the Moon house and good/puja/bad Chandrabalam verdict.", "Count favourable, blocked, and adverse Grahas.", "Label good when Moon is good and at least four Grahas are favourable; label difficult when Moon is bad and at most two are favourable; otherwise label mixed.", "Render deterministic opener, optional Tara sentence, condition sentence, eight ordered Graha lines, and a count summary."],
        "worked_examples": [{"label": "Mesha reading from the 2026-06-11 sunrise sky", "inputs": ["Moon house: 12 (bad)", "Favourable Grahas: 2", "Blocked: 0", "Adverse: 7", "Condition: Sade Sati (rising phase)"], "calculation": ["Moon is bad and favourable count is at most 2, so day_quality=difficult.", "The fixed templates render the Moon opener, Shani condition, transit lines, and count."], "result": ["Day quality: difficult", "Summary: 2 of 9 grahas favour you today."]}],
        "notes": ["Transit facts are rule-derived; the thresholds, life-area wording, and synthesis are declared project heuristics."]
      }
    },
    {
      "id": "interpretation.daily-rasi-phalalu-generated",
      "title": "Model-generated daily Rasi Phalalu",
      "summary": "An external model produces prose that is checked against deterministic Gochara facts before acceptance.",
      "owning_layer": "interpretation",
      "claim_kind": "generated-interpretation",
      "implementations": [
        {"path": "telugu_panchangam/personal/llm_phalalu.py", "symbol": "generate_rasi_phalalu", "role": "owner"},
        {"path": "telugu_panchangam/personal/llm_phalalu.py", "symbol": "_verify", "role": "owner"}
      ],
      "inputs": ["date", "computed graha positions", "model response"],
      "outputs": ["verified transit citations", "generated prose"],
      "time_basis": "Daily generated-data batch for the supplied transit snapshot.",
      "surfaces": ["website", "generated-data"],
      "provenance": {"evidence_classes": ["project_heuristic"], "verification_states": ["heuristic"], "claim_ids": ["daily_horoscope.llm_interpretation"], "note": "Cited transit triples are checked; prose and advice are explicitly generated interpretation."},
      "tests": ["tests/test_llm_phalalu_verify.py"],
      "limitations": ["Verification prevents unsupported transit facts but cannot make generated prose a classical or professional authority."],
      "method": {
        "kind": "algorithm",
        "summary": "Generate structured prose for all twelve Rashis, then reject the batch unless every cited transit matches computed facts and the text passes narrow safety and consistency checks.",
        "steps": ["Compute the sky, Gochara verdicts, Moon house, and named conditions for all twelve Rashis.", "Request a schema-constrained JSON array with text, advice, and explicit transit citations.", "Require exactly twelve unique known Rashis, non-empty text/advice, and at least one citation per Rashi.", "Normalize known English/Sanskrit Graha aliases, then require exact computed position and verdict and require the cited Graha to be named in the prose.", "Reject intraday precision, waiting-period claims, and medical/legal/investment/contract guidance.", "Regenerate up to three times on verification drift; retry transient HTTP errors and use the fallback model only after primary 429 exhaustion."],
        "worked_examples": [{"label": "Verifier treatment of an English Graha alias", "inputs": ["Citation Graha: Sun", "Computed canonical Graha: Surya", "Citation position and verdict: exact engine values", "Prose explicitly names Surya"], "calculation": ["Canonicalize Sun to Surya.", "Compare position and verdict exactly.", "Confirm a recognized Surya/Sun label occurs in the text."], "result": ["Citation accepted", "Prose remains labeled model interpretation; only citation fields are engine-verified"]}],
        "notes": ["The verifier is a factual/safety boundary, not a semantic proof of the prose and not evidence of classical authority."]
      }
    },
    {
      "id": "panchangam.abhijit-muhurta",
      "title": "Abhijit Muhurta window",
      "summary": "The midday auspicious interval is derived proportionally from daytime length, except on Wednesday.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._abhijit_muhurta", "role": "owner"}
      ],
      "inputs": ["sunrise", "sunset", "weekday"],
      "outputs": ["Abhijit start/end or null"],
      "time_basis": "Proportional local daytime centered on the arithmetic midpoint between sunrise and sunset.",
      "method": {
        "kind": "formula",
        "summary": "Divide the sunrise-to-sunset interval into 15 equal Muhurta-length parts and return the eighth, middle part, except that the selected convention suppresses it on Wednesday.",
        "steps": [
          "If the weekday is Wednesday, return null and do not construct an Abhijit window.",
          "Subtract sunrise from sunset to obtain the local daylight duration D.",
          "Take the arithmetic midpoint M of the sunrise and sunset instants.",
          "Set the half-width H to D / 30, which makes the complete interval 2H = D / 15.",
          "Return M - H as the start and M + H as the end; the engine stores both as UTC instants and presentation layers convert them to local civil time."
        ],
        "formulae": [
          {
            "name": "Daylight duration and midpoint",
            "expression": "D = T_set - T_rise\nM = (T_rise + T_set) / 2",
            "variables": [
              "T_rise: computed sunrise instant for the location and date",
              "T_set: computed sunset instant for the location and date",
              "D: elapsed sunrise-to-sunset duration",
              "M: arithmetic midpoint of the sunrise-to-sunset interval"
            ]
          },
          {
            "name": "Abhijit interval",
            "expression": "H = D / 30\nstart = M - H\nend = M + H\nend - start = D / 15",
            "variables": [
              "H: half of one daytime Muhurta",
              "start: beginning of the eighth daytime part",
              "end: end of the eighth daytime part"
            ]
          }
        ],
        "worked_examples": [
          {
            "label": "Hyderabad, 2026-06-11, Drik Ganita (Asia/Kolkata)",
            "inputs": [
              "Weekday: Thursday, so the Wednesday exclusion does not apply",
              "Sunrise: 05:41:11 IST (00:11:11 UTC)",
              "Sunset: 18:50:12 IST (13:20:12 UTC)"
            ],
            "calculation": [
              "D = 18:50:12 - 05:41:11 = 13:09:01 = 47,341 seconds.",
              "M = (05:41:11 + 18:50:12) / 2 = 12:15:41.5 IST.",
              "H = 47,341 / 30 = 1,578.033 seconds, or 00:26:18.033.",
              "start = 12:15:41.5 - 00:26:18.033 = 11:49:23.467 IST; end = 12:15:41.5 + 00:26:18.033 = 12:41:59.533 IST."
            ],
            "result": [
              "Engine instants at whole-second precision: 11:49:23–12:41:59 IST.",
              "Published-reference comparison in the regression test: 11:50–12:42, within the test's one-minute display tolerance.",
              "Total duration: 52 minutes 36 seconds, equal to daylight duration / 15."
            ]
          }
        ],
        "notes": [
          "This midpoint is derived from sunrise and sunset; it is not a separate calculation of the Sun's meridian transit.",
          "The cited published reference also cautions against marriage and Upanayana during Abhijit; this low-level window function does not evaluate activity suitability.",
          "A criterion-level primary textual verse or edition locator has not yet been registered."
        ]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.abhijit_muhurta_method"], "note": "The maintained implementation formula and Wednesday convention have a direct published-Panchangam reference and a representative output comparison. This is not a primary textual locator or a broad multi-city comparison set."},
      "tests": ["tests/test_muhurta_windows.py", "tests/test_named_muhurtas.py"],
      "limitations": [
        "Wednesday returns no Abhijit window under the selected convention.",
        "The registered external method reference is a published Panchangam, not a primary textual edition.",
        "The low-level computation does not enforce activity-specific restrictions such as marriage or Upanayana suitability."
      ]
    },
    {
      "id": "panchangam.amrita-kalam",
      "title": "Amrita Kalam windows",
      "summary": "Nakshatra-specific Ghati offsets produce auspicious sub-windows.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "nakshatra_day_windows", "role": "owner"}
      ],
      "inputs": ["Nakshatra spans", "Amrita offset table", "day bounds"],
      "outputs": ["Amrita Kalam windows"],
      "time_basis": "Four-sixtieths of actual Nakshatra duration at the table offset.",
      "method": {
        "kind": "formula",
        "summary": "For the Nakshatra active at sunrise and its successor, place a four-Ghati window at that Nakshatra's configured Amrita offset and retain it only when its start lies inside the sunrise-to-next-sunrise Panchangam day.",
        "steps": ["Find the complete UTC span of the sunrise Nakshatra and the immediately following Nakshatra using the selected engine's Moon model.", "Look up the Nakshatra-specific Amrita start offset on a 60-Ghati scale.", "Scale both the offset and four-Ghati duration by the actual Nakshatra span rather than by clock minutes.", "Keep a window only when day_start <= start < next_sunrise."],
        "formulae": [{"name": "Nakshatra-scaled window", "expression": "start = N_start + N_duration * offset[n] / 60\nend = start + N_duration * 4 / 60", "variables": ["N_start: Nakshatra start", "N_duration: actual Nakshatra duration", "offset[n]: maintained Amrita Ghati offset for Nakshatra n"]}],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11, Drik Ganita", "inputs": ["Panchangam day: sunrise 05:41:11 IST to next sunrise 05:41:17 IST", "Sunrise Nakshatra: Revati; successor: Ashvini", "Offsets come from AMRITA_GHATIS"], "calculation": ["Construct one four-sixtieths window for each of the two full Nakshatra spans.", "Filter by each computed start against the Panchangam-day bounds."], "result": ["05:59:05.5-07:30:45.166667 IST", "23:49:07.4-01:17:56.2 IST; both starts fall within the Panchangam day"]}],
        "notes": ["The registered umbrella claim does not yet provide a criterion-level locator for the complete Amrita offset table."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative values are compared; the table's full locator coverage remains incomplete."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["Offsets follow one maintained table and are clipped to the Panchangam day convention."]
    },
    {
      "id": "panchangam.ayanam-rituvu",
      "title": "Ayanam and Rituvu",
      "summary": "Solar position classifies the half-year and six seasonal names.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "ayanam_name", "role": "owner"},
        {"path": "telugu_panchangam/engines/base.py", "symbol": "rituvu_name", "role": "owner"}
      ],
      "inputs": ["solar sign or tropical solar longitude"],
      "outputs": ["Ayanam", "Rituvu"],
      "time_basis": "Solar position at sunrise.",
      "method": {
        "kind": "decision-table",
        "summary": "Ayanam uses the engine's sidereal solar sign at sunrise, while Rituvu independently bins the shared tropical Swiss solar longitude into a twelve-sign-to-six-season lookup.",
        "steps": ["Compute the sidereal sunrise Sun sign index from the selected engine.", "Return Uttarayanam for sign indices 9, 10, 11, 0, 1, or 2; otherwise return Dakshinayanam.", "Compute tropical Swiss Sun longitude at the same sunrise instant.", "Take floor(tropical longitude / 30) modulo 12 and use that index in RITUVU_NAMES."],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11", "inputs": ["Drik sidereal Sun: 55.889366 degrees", "Sidereal sign index: floor(55.889366 / 30) = 1", "Tropical solar sign maps to the Grishma entries"], "calculation": ["Index 1 is in the Uttarayanam set.", "The tropical-sign lookup is evaluated separately from the sidereal sign."], "result": ["Ayanam: Uttarayanam", "Rituvu: Grishma"]}],
        "notes": ["This hybrid is intentional: Rituvu does not use the selected engine's sidereal Sun.", "Criterion-level source locators for the naming convention remain unresolved."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "regional_convention"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.calendar_semantics"], "note": "Calendar semantics need more exact source locators."},
      "tests": ["tests/test_drik_engine.py"],
      "limitations": ["Rituvu uses tropical solar longitude while other fields are predominantly sidereal."]
    },
    {
      "id": "panchangam.brahma-muhurta",
      "title": "Brahma Muhurta window",
      "summary": "A fixed pre-sunrise interval identifies Brahma Muhurta.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._brahma_muhurta", "role": "owner"}
      ],
      "inputs": ["sunrise instant"],
      "outputs": ["Brahma Muhurta start/end"],
      "time_basis": "Fixed civil interval before local sunrise.",
      "method": {
        "kind": "formula",
        "summary": "Return the fixed interval from 96 to 48 clock minutes before the computed sunrise.",
        "steps": ["Represent 48 minutes as 1/30 of a Julian day.", "Subtract two such units from sunrise for the start.", "Subtract one such unit from sunrise for the end.", "Convert both Julian instants to whole-second UTC datetimes."],
        "formulae": [{"name": "Fixed pre-sunrise interval", "expression": "m = 1 day / 30 = 48 minutes\nstart = sunrise - 2m\nend = sunrise - m", "variables": ["sunrise: computed location/date sunrise", "m: fixed 48-minute Julian-day fraction"]}],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11", "inputs": ["Sunrise: 05:41:11 IST"], "calculation": ["Start = 05:41:11 - 96 minutes.", "End = 05:41:11 - 48 minutes."], "result": ["Brahma Muhurta: 04:05:11-04:53:11 IST"]}],
        "notes": ["The interval is fixed in clock minutes and does not scale with seasonal day or night length."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative published values are checked; textual coverage remains grouped."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["The fixed-minute implementation does not scale this window by seasonal day length."]
    },
    {
      "id": "panchangam.choghadiya",
      "title": "Day and night Choghadiya",
      "summary": "Weekday-specific sequences label eight proportional day and night segments.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._choghadiya", "role": "owner"},
        {"path": "src/panels/today.ts", "symbol": "nightChoghadiya", "role": "owner"}
      ],
      "inputs": ["weekday", "sunrise", "sunset", "next sunrise"],
      "outputs": ["named proportional day and night windows"],
      "time_basis": "Eight equal local-day parts and eight equal local-night parts.",
      "method": {
        "kind": "decision-table",
        "summary": "Split daylight and night into eight equal intervals and label them from weekday-specific sequences; Python owns exact daytime instants and the browser owns the minute-based night fallback.",
        "steps": ["Select the eight daytime labels for weekday index 0=Sunday through 6=Saturday.", "Set daytime block length to (sunset - sunrise) / 8 and construct eight contiguous windows.", "For the browser night fallback, treat next sunrise as minutes after midnight by adding 1,440, then divide sunset-to-next-sunrise into eight.", "Rotate the seven-name night cycle from the weekday's configured start name and round rendered minute boundaries."],
        "formulae": [{"name": "Equal day or night block", "expression": "block = (period_end - period_start) / 8\nstart_i = period_start + i * block\nend_i = period_start + (i + 1) * block", "variables": ["i: zero-based block 0 through 7", "period: sunrise-to-sunset or sunset-to-next-sunrise"]}],
        "worked_examples": [{"label": "Hyderabad daytime, Thursday 2026-06-11", "inputs": ["Sunrise: 05:41:11 IST", "Sunset: 18:50:12 IST", "Thursday labels: Shubh, Rog, Udveg, Char, Labh, Amrit, Kaal, Shubh"], "calculation": ["Daylight 13:09:01 divided by 8 gives 01:38:37.625 per block.", "Apply the Thursday label at each contiguous boundary."], "result": ["First block: Shubh 05:41:11-07:19:48 IST", "Fourth block: Char 10:37:04-12:15:41 IST", "Eighth block: Shubh 17:11:34-18:50:12 IST"]}],
        "notes": ["The Python record does not return night Choghadiya; the browser fallback uses HH:MM inputs and rounded minutes.", "The table's criterion-level textual locator remains grouped and incomplete."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Day values have representative comparisons; browser-owned night extension is regression-tested through UI contracts."},
      "tests": ["tests/test_muhurta_windows.py", "tests/test_browser_smoke.py"],
      "limitations": ["The browser computes the night sequence separately from the Python day sequence."]
    },
    {
      "id": "panchangam.durmuhurtham",
      "title": "Durmuhurtham windows",
      "summary": "Weekday tables select proportional daytime Muhurtas plus the Tuesday night exception.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._durmuhurtham", "role": "owner"}
      ],
      "inputs": ["weekday", "sunrise", "sunset", "next sunrise"],
      "outputs": ["one or more Durmuhurtham windows"],
      "time_basis": "Selected fifteenths of local day or night.",
      "method": {
        "kind": "decision-table",
        "summary": "Divide daylight into 15 equal Muhurtas and return the weekday-selected indices; on Tuesday also divide the night into 15 and return its seventh part.",
        "steps": ["Read one or two 1-based daytime indices from DURMUHURTA_DAY_MUHURTAS for the weekday.", "Set day Muhurta length to (sunset - sunrise) / 15 and construct each selected interval.", "Set night Muhurta length to (next_sunrise - sunset) / 15.", "If the weekday has a night-table entry, currently only Tuesday part 7, append that interval."],
        "formulae": [{"name": "Selected Muhurta part", "expression": "part_size = (period_end - period_start) / 15\nstart_p = period_start + (p - 1) * part_size\nend_p = period_start + p * part_size", "variables": ["p: 1-based table-selected Muhurta", "period: daylight or Tuesday night"]}],
        "worked_examples": [{"label": "Hyderabad, Thursday 2026-06-11", "inputs": ["Sunrise: 05:41:11 IST", "Sunset: 18:50:12 IST", "Thursday weekday index 4 selects daytime parts 6 and 12"], "calculation": ["Daylight / 15 = 52 minutes 36.067 seconds.", "Apply the part formula for p=6 and p=12."], "result": ["10:04:11-10:56:47 IST", "15:19:48-16:12:24 IST"]}],
        "notes": ["Tuesday needs next-sunrise context because its second window is a night Muhurta."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative values are compared; exact table locators remain grouped."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["The Tuesday night exception requires next-sunrise context."]
    },
    {
      "id": "panchangam.eclipse-sutak",
      "title": "Daily eclipse and Sutak field",
      "summary": "The range-calendar eclipse result is attached to the local Panchangam day.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine.calculate", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine.calculate", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine.calculate", "role": "owner"}
      ],
      "inputs": ["date", "location", "calendar eclipse result"],
      "outputs": ["PanchangamDay.eclipse"],
      "time_basis": "Local Panchangam date with UTC event instants converted for presentation.",
      "method": {
        "kind": "algorithm",
        "summary": "Each engine conditionally requests the canonical location-aware eclipse calculation for the civil date and attaches the returned EclipseInfo unchanged to PanchangamDay.",
        "steps": ["When include_eclipse is false, skip the lookup and attach null.", "Otherwise pass the input civil date and Location to get_eclipse_for_date.", "The canonical calculator keeps an event only when its maximum falls within the location's two civil-midnight Julian bounds.", "Attach kind, subtype, visibility, UTC phase instants, and visibility-dependent Sutak fields to the day.", "Presentation layers convert UTC instants to the requested timezone."],
        "worked_examples": [{"label": "Hyderabad, 2026-02-17", "inputs": ["include_eclipse=true", "Canonical event: annular solar eclipse", "Local visibility: false"], "calculation": ["The event maximum falls within the Hyderabad civil date, so attach EclipseInfo.", "Because it is not locally visible, leave Sutak start/end null."], "result": ["kind=Solar; subtype=Annular; visible=false", "sutak_start=null; sutak_end=null"]}],
        "notes": ["This page documents day attachment; astronomical search, visibility, and Sutak calculation are separately inventoried."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["engine_pinned"], "claim_ids": ["panchangam.eclipse_events"], "note": "This is the daily projection of the canonical eclipse calculation."},
      "tests": ["tests/test_eclipses.py", "tests/test_integration.py"],
      "limitations": ["This record owns attachment to the day; event calculation is separately inventoried."]
    },
    {
      "id": "panchangam.festivals",
      "title": "Festival date rules",
      "summary": "Moment-specific Amanta month, Tithi, weekday, and specialty rules select named festivals.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._festivals", "role": "owner"}
      ],
      "inputs": ["Maasam", "Tithi at deciding moments", "weekday", "adjacent-day facts"],
      "outputs": ["festival names"],
      "time_basis": "Festival-specific sunrise, Madhyahna, Aparahna, Pradosha, Nishita, or moonrise rule.",
      "method": {
        "kind": "decision-table",
        "summary": "Evaluate maintained Telugu festival rules at each rule family's deciding instant, suppress duplicate day assignment, handle Amanta rollover and Adhika exclusions, and add monthly and solar-ingress observances.",
        "steps": ["Add the Makara Sankranti cluster from solar-ingress day assignment.", "For non-Adhika months, evaluate sunrise rules directly and Madhyahna, Aparahna, Pradosha, and Nishita tables at their configured instants.", "For moment rules, require the target Tithi now but not at the same moment one day earlier; when sunrise is Amavasya and Pratipat begins by the moment, advance the Amanta month.", "Evaluate weekday-in-month and last-weekday-in-Paksha rules.", "Evaluate moonrise and Nishita monthly Vratas even in Adhika months, with annual-variant suppression."],
        "formulae": [{"name": "Deciding instants", "expression": "Madhyahna = sunrise + 0.5 * daylight\nAparahna = sunrise + 0.7 * daylight\nPradosha = sunset + 0.05 day\nNishita = (sunset + next_sunrise) / 2", "variables": ["daylight: sunset - sunrise", "0.05 day: 72 clock minutes"]}],
        "worked_examples": [{"label": "Ugadi, Hyderabad 2026-03-19", "inputs": ["Sunrise Maasam/Tithi: Phalguna Amavasya, index 29", "Madhyahna Tithi: Shukla Pratipat, index 0", "Same moment previous day: index 29"], "calculation": ["Ugadi is the Chaitra index-0 Madhyahna rule.", "Because sunrise was Amavasya and Pratipat began by Madhyahna, advance moment Maasam from Phalguna to Chaitra.", "Previous-day Madhyahna was not index 0, so first-day suppression passes."], "result": ["Festival list includes Ugadi on 2026-03-19"]}],
        "notes": ["The forward-year fixture mixes independently compared and engine-pinned cells.", "The tables implement maintained Telugu/Amanta conventions, not a universal regional calendar."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["published_panchangam", "regional_convention"], "verification_states": ["partially_verified"], "claim_ids": ["festivals.forward_year_2027_2028"], "note": "Individual 2026 rules have comparisons; the forward-year fixture contains mixed independent and engine-pinned cells."},
      "tests": ["tests/test_festivals.py", "tests/test_festivals_forward_year.py"],
      "limitations": ["The table follows documented Telugu conventions and is not a universal regional festival calendar."]
    },
    {
      "id": "panchangam.gulika-kalam",
      "title": "Gulika Kalam",
      "summary": "A weekday table selects one of eight proportional daytime segments.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._gulika_kalam", "role": "owner"}
      ],
      "inputs": ["weekday", "sunrise", "sunset"],
      "outputs": ["Gulika Kalam start/end"],
      "time_basis": "One eighth of local sunrise-to-sunset daytime.",
      "method": {
        "kind": "decision-table",
        "summary": "Select a weekday-specific 1-based eighth of local daylight from the Gulika table.",
        "steps": ["Map weekday 0=Sunday through 6=Saturday to Gulika part [7, 6, 5, 4, 3, 2, 1].", "Compute daylight block size as (sunset - sunrise) / 8.", "Return the selected contiguous block as whole-second UTC instants."],
        "formulae": [{"name": "Day-part window", "expression": "B = (sunset - sunrise) / 8\nstart = sunrise + (part - 1) * B\nend = start + B", "variables": ["part: weekday-selected Gulika index", "B: one-eighth daylight duration"]}],
        "worked_examples": [{"label": "Hyderabad, Thursday 2026-06-11", "inputs": ["Weekday index: 4", "Gulika part: 3", "Sunrise/sunset: 05:41:11/18:50:12 IST"], "calculation": ["B = 13:09:01 / 8 = 01:38:37.625.", "Take the third block."], "result": ["Gulika Kalam: 08:58:26-10:37:04 IST"]}],
        "notes": ["The weekday table is conventional; location changes the result only through sunrise and sunset."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative city/date values are independently compared."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["Weekday-part tables are conventional and location-specific through sunrise/sunset."]
    },
    {
      "id": "panchangam.karana",
      "title": "Karana spans",
      "summary": "Each six-degree Moon-Sun elongation interval is mapped to fixed or repeating Karana names.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._karana_spans", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._karana_spans", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine._karana_spans", "role": "owner"}
      ],
      "inputs": ["Moon-Sun elongation over the Panchangam day"],
      "outputs": ["Karana names and boundary instants"],
      "time_basis": "Sunrise-anchored day with crossings solved in UTC Julian day.",
      "method": {
        "kind": "formula",
        "summary": "Divide Moon-Sun elongation into 60 six-degree half-Tithis, solve each boundary with the selected engine, map fixed or sevenfold repeating names, and return at most two spans intersecting daylight.",
        "steps": ["Compute E = (Moon - Sun) modulo 360 at sunrise and set half-Tithi index h=floor(E/6) modulo 60.", "For h and the next two indices, bisect the engine elongation at h*6 and (h+1)*6 degrees.", "Discard a span ending before sunrise or starting after sunset.", "Use KARANA_FIXED when h is a fixed index; otherwise use KARANA_REPEATING[(h-1) modulo 7].", "Stop after two intersecting spans."],
        "formulae": [{"name": "Karana index", "expression": "E = (M - S) mod 360\nh = floor(E / 6) mod 60", "variables": ["M: engine Moon longitude", "S: engine Sun longitude", "h: half-Tithi index"]}],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11, Drik Ganita", "inputs": ["Elongation: 302.5814559608 degrees", "Daylight: 05:41:11-18:50:12 IST"], "calculation": ["floor(302.5814559608 / 6) modulo 60 = 50.", "Solve consecutive six-degree crossings and retain the first two daylight-intersecting spans.", "Map indices through the fixed/repeating name tables."], "result": ["Bava: 00:58:16-11:52:44 IST", "Balava: 11:52:44-22:36:44 IST; spans are not clipped to daylight"]}],
        "notes": ["Boundary instants and the sunrise index inherit the selected engine's longitude model."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["drik.sidereal_positions", "panchangam.non_drik_engine_outputs", "panchangam.calendar_semantics"], "note": "Drik has representative comparisons; non-Drik spans are engine-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["Boundary times inherit the selected engine's longitude model."]
    },
    {
      "id": "panchangam.maasam-paksham",
      "title": "Amanta Maasam and Paksham",
      "summary": "Bounding new moons and solar signs determine lunar month, Adhika/Nija status, and fortnight.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "maasam_name", "role": "owner"},
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._maasam", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._maasam", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine._maasam", "role": "owner"}
      ],
      "inputs": ["Moon-Sun elongation", "solar longitude", "sunrise"],
      "outputs": ["Amanta month", "Adhika/Nija prefix", "Shukla/Krishna Paksham"],
      "time_basis": "Month at local sunrise bounded by engine-specific new moons.",
      "method": {
        "kind": "algorithm",
        "summary": "Find the new moons bounding sunrise from engine elongation, name the Amanta month from the Sun sign at the starting new moon, identify Adhika or Nija repetition, and derive Paksham from the sunrise Tithi index.",
        "steps": ["Iteratively locate the previous new moon using mean elongation rate 12.19 degrees/day for ten corrections, with a 29.530589-day fallback.", "Name the month from (starting-new-moon Sun-sign index - 11) modulo 12.", "Find the next bound; equal Sun signs at start and end imply Adhika.", "Otherwise inspect the previous bound; equal previous/start signs imply Nija.", "Set Paksham to Shukla for Tithi indices 0-14 and Krishna for 15-29."],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11, Drik Ganita", "inputs": ["Sunrise elongation: 302.5814559608 degrees", "Sunrise Tithi index: 25", "Engine-specific bounding new moons and solar signs"], "calculation": ["The bounding-new-moon Sun signs are equal, so prefix the derived Jyeshtha name with Adhika.", "Tithi index 25 lies in 15-29, so choose Krishna Paksham."], "result": ["Maasam: Adhika Jyeshtha", "Paksham: Krishna"]}],
        "notes": ["The numerical search is an implementation technique, not a separately verified new-moon series.", "The convention is Telugu Amanta; Purnimanta calendars differ."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual", "regional_convention"], "verification_states": ["needs_locator", "engine_pinned"], "claim_ids": ["panchangam.calendar_semantics", "panchangam.non_drik_engine_outputs"], "note": "Semantics need exact locators; non-Drik month outputs are regression-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_adhika_maasa_muhurta.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["The project follows Telugu Amanta conventions; Purnimanta calendars differ."]
    },
    {
      "id": "panchangam.nakshatra",
      "title": "Nakshatra and Pada",
      "summary": "Sidereal lunar longitude selects one of 27 Nakshatras and one of four Padas.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._nakshatra_span", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._nakshatra_span", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine._nakshatra_span", "role": "owner"}
      ],
      "inputs": ["engine lunar longitude"],
      "outputs": ["Nakshatra name", "start/end", "Pada"],
      "time_basis": "Active at local sunrise with UTC boundary crossings.",
      "method": {
        "kind": "formula",
        "summary": "Divide sidereal lunar longitude into 27 equal Nakshatras and each Nakshatra into four Padas, then solve the enclosing longitude crossings around sunrise.",
        "steps": ["Set Nakshatra size N=360/27 degrees.", "At sunrise choose n=floor(M/N) modulo 27.", "Bisect the Moon model at n*N in [sunrise-2 days, sunrise] and at (n+1)*N in [sunrise, sunrise+2 days].", "Compute Pada as floor((M/N)*4) modulo 4 plus 1.", "Map n through NAKSHATRA_NAMES and expose whole-second UTC boundaries."],
        "formulae": [{"name": "Nakshatra and Pada", "expression": "N = 360 / 27\nn = floor(M / N) mod 27\npada = floor((M / N) * 4) mod 4 + 1", "variables": ["M: selected engine Moon longitude", "n: Nakshatra index", "pada: 1 through 4"]}],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11, Drik Ganita", "inputs": ["Moon longitude: 358.4708221648 degrees", "N = 13.3333333333 degrees"], "calculation": ["floor(358.4708221648/N) modulo 27 = 26, Revati.", "The Pada formula yields 4.", "Bisect the Drik Moon at the two Revati boundaries."], "result": ["Revati, Pada 4", "Span: 2026-06-10 09:21:40 to 2026-06-11 08:16:35 IST"]}],
        "notes": ["Surya Siddhanta and Vakya use their own Moon functions, so their boundaries can differ from Drik."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["drik.sidereal_positions", "panchangam.non_drik_engine_outputs", "panchangam.calendar_semantics"], "note": "Drik has representative comparisons; non-Drik spans are engine-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_pada_on_daily.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["Names and boundaries inherit engine and ayanamsa choices."]
    },
    {
      "id": "panchangam.nitya-yoga",
      "title": "Nitya Yoga span",
      "summary": "The normalized sum of solar and lunar longitude selects one of 27 Nitya Yogas.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._yoga_span", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._yoga_span", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine._yoga_span", "role": "owner"}
      ],
      "inputs": ["solar longitude", "lunar longitude"],
      "outputs": ["Nitya Yoga name and boundary"],
      "time_basis": "Active at local sunrise with UTC crossing search.",
      "method": {
        "kind": "formula",
        "summary": "Add the selected engine's Sun and Moon longitudes modulo one revolution, divide the result into 27 equal Yoga sectors, and solve the enclosing crossings around sunrise.",
        "steps": ["Compute combined longitude Y=(S+M) modulo 360.", "Set N=360/27 and y=floor(Y/N) modulo 27.", "Bisect the combined-longitude function at y*N before sunrise and at (y+1)*N after sunrise, each within a two-day window.", "Map y through YOGA_NAMES and return whole-second UTC boundaries."],
        "formulae": [{"name": "Nitya Yoga index", "expression": "Y = (S + M) mod 360\ny = floor(Y / (360 / 27)) mod 27", "variables": ["S: engine Sun longitude", "M: engine Moon longitude", "y: Yoga index"]}],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11, Drik Ganita", "inputs": ["Sun: 55.8893662040 degrees", "Moon: 358.4708221648 degrees"], "calculation": ["Y=(55.8893662040+358.4708221648) modulo 360 = 54.3601883689 degrees.", "floor(Y/13.3333333333)=4, Shobhana.", "Solve the adjacent combined-longitude crossings."], "result": ["Shobhana", "Span: 2026-06-11 04:03:08 to 2026-06-12 01:00:09 IST"]}],
        "notes": ["The selected Sun/Moon model controls both classification and transition times."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["drik.sidereal_positions", "panchangam.non_drik_engine_outputs", "panchangam.calendar_semantics"], "note": "Drik has representative comparisons; non-Drik spans are engine-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["This is the 27-part Nitya Yoga, not every other named Yoga vocabulary."]
    },
    {
      "id": "panchangam.rahu-kalam",
      "title": "Rahu Kalam",
      "summary": "A weekday table selects one of eight proportional daytime segments.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._rahu_kalam", "role": "owner"}
      ],
      "inputs": ["weekday", "sunrise", "sunset"],
      "outputs": ["Rahu Kalam start/end"],
      "time_basis": "One eighth of local sunrise-to-sunset daytime.",
      "method": {
        "kind": "decision-table",
        "summary": "Select a weekday-specific 1-based eighth of local daylight from the Rahu table.",
        "steps": ["Map weekday 0=Sunday through 6=Saturday to Rahu part [8, 2, 7, 5, 6, 4, 3].", "Compute daylight block size as (sunset - sunrise) / 8.", "Return the selected contiguous block as whole-second UTC instants."],
        "formulae": [{"name": "Day-part window", "expression": "B = (sunset - sunrise) / 8\nstart = sunrise + (part - 1) * B\nend = start + B", "variables": ["part: weekday-selected Rahu index", "B: one-eighth daylight duration"]}],
        "worked_examples": [{"label": "Hyderabad, Thursday 2026-06-11", "inputs": ["Weekday index: 4", "Rahu part: 6", "Sunrise/sunset: 05:41:11/18:50:12 IST"], "calculation": ["B = 13:09:01 / 8 = 01:38:37.625.", "Take the sixth block."], "result": ["Rahu Kalam: 13:54:19-15:32:57 IST"]}],
        "notes": ["The weekday table is conventional; location changes the result only through sunrise and sunset."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative city/date values are independently compared."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["Weekday-part tables are conventional and location-specific through sunrise/sunset."]
    },
    {
      "id": "panchangam.rashi",
      "title": "Solar and lunar Rashi",
      "summary": "Thirty-degree sidereal longitude sectors determine solar and lunar signs.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine.calculate", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine.calculate", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine.calculate", "role": "owner"}
      ],
      "inputs": ["engine solar and lunar longitude"],
      "outputs": ["solar Rashi", "lunar Rashi"],
      "time_basis": "Longitude at local sunrise.",
      "method": {
        "kind": "formula",
        "summary": "Divide the selected engine's normalized sunrise Sun and Moon longitudes into twelve 30-degree sidereal signs.",
        "steps": ["Evaluate engine Sun and Moon longitude at local sunrise.", "For each body compute floor(longitude/30) modulo 12.", "Map both indices through RASHI_NAMES."],
        "formulae": [{"name": "Rashi index", "expression": "r = floor(longitude / 30) mod 12", "variables": ["longitude: normalized sidereal body longitude", "r: Rashi index, Mesha=0"]}],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11, Drik Ganita", "inputs": ["Sun: 55.8893662040 degrees", "Moon: 358.4708221648 degrees"], "calculation": ["floor(55.8893662040/30)=1.", "floor(358.4708221648/30)=11."], "result": ["Solar Rashi: Vrishabha", "Lunar Rashi: Meena"]}],
        "notes": ["These are sunrise classifications, not continuous sign-ingress spans."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["drik.sidereal_positions", "panchangam.non_drik_engine_outputs", "panchangam.calendar_semantics"], "note": "Drik has representative comparison evidence; non-Drik outputs are engine-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["Signs follow the selected engine and ayanamsa conventions."]
    },
    {
      "id": "panchangam.rise-set",
      "title": "Sunrise, sunset, moonrise, and moonset",
      "summary": "Swiss Ephemeris rise/transit searches produce local sky-marker instants.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/utils.py", "symbol": "get_sunrise", "role": "owner"},
        {"path": "telugu_panchangam/engines/utils.py", "symbol": "get_sunset", "role": "owner"},
        {"path": "telugu_panchangam/engines/utils.py", "symbol": "get_moonrise", "role": "owner"},
        {"path": "telugu_panchangam/engines/utils.py", "symbol": "get_moonset", "role": "owner"}
      ],
      "inputs": ["date", "latitude", "longitude", "fixed pressure 1013.25 hPa", "fixed temperature 15 C", "hard-coded altitude 0 m"],
      "outputs": ["UTC rise/set instants rendered in local timezone"],
      "time_basis": "Search from local-midnight Julian day with observer coordinates.",
      "method": {
        "kind": "algorithm",
        "summary": "Convert local civil midnight to UT Julian day and ask Swiss Ephemeris for the next Sun or Moon rise/set event using fixed observer and atmosphere parameters.",
        "steps": ["Localize 00:00 on the requested date in the IANA timezone and convert it to UTC Julian day.", "Call swe.rise_trans for Sun or Moon with CALC_RISE or CALC_SET.", "Use [longitude, latitude, 0 metres], pressure 1013.25 hPa, temperature 15 C, and Swiss default upper-limb/refraction behavior.", "Search sunset from sunrise and next sunrise from the following local midnight.", "Convert tret[0] to a whole-second UTC datetime."],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11", "inputs": ["Location: Hyderabad, Asia/Kolkata", "Altitude forced to 0 metres", "Swiss default rise/set flags and atmosphere"], "calculation": ["Search the next solar rise after local midnight, then solar set after that rise.", "Search the next lunar rise and set after local midnight."], "result": ["Sunrise: 05:41:11 IST; sunset: 18:50:12 IST", "Moonrise: 01:55:18 IST; moonset: 14:53:44 IST"]}],
        "notes": ["Swiss return codes are ignored; polar no-event cases are not represented safely.", "The Hindu disc-centre/no-refraction convention remains unresolved."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.rise_set_convention", "drik.sidereal_positions"], "note": "Swiss Ephemeris documents the current astronomical-default behavior; issue 177 tracks the Hindu-calendar convention decision and multi-city comparisons."},
      "tests": ["tests/test_utils.py", "tests/test_drik_engine.py"],
      "limitations": ["All engines use the astronomical upper-limb/refraction default, ignore Location.alt and return codes, and lack a registered multi-city decision fixture for the intended public convention."]
    },
    {
      "id": "panchangam.samvatsara",
      "title": "Samvatsara name",
      "summary": "Elapsed Kali-era solar years and the current lunar month map to the 60-year Telugu cycle.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "samvatsara_name", "role": "owner"},
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._samvatsara", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._samvatsara", "role": "owner"}
      ],
      "inputs": ["Julian day", "Maasam"],
      "outputs": ["60-year-cycle name"],
      "time_basis": "Year flips at Chaitra under the southern Chaitradi convention.",
      "method": {
        "kind": "formula",
        "summary": "Count mean sidereal years since the code Kali epoch, shift by lunar-month number so the name changes at Chaitra, then apply the repository's 60-name anchor.",
        "steps": ["Remove Adhika or Nija and convert Chaitra..Phalguna to month number 1..12.", "Set ahargana=JD-588465.5.", "Compute elapsed=floor((ahargana+(4-month_number)*30)/365.25636).", "Return SAMVATSARA_NAMES[(elapsed+12) modulo 60]."],
        "formulae": [{"name": "Sixty-year index", "expression": "A = JD - 588465.5\ny = floor((A + (4 - month_number) * 30) / 365.25636)\nindex = (y + 12) mod 60", "variables": ["month_number: Chaitra=1 through Phalguna=12", "y: elapsed project sidereal years", "12: project cycle anchor"]}],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11", "inputs": ["JD: 2461202.5077662035", "Maasam: Adhika Jyeshtha, base month number 3"], "calculation": ["A=1,872,737.0077662035 days.", "floor((A+30)/365.25636)=5,127.", "(5,127+12) modulo 60=39."], "result": ["SAMVATSARA_NAMES[39]: Parabhava"]}],
        "notes": ["The anchor and month shift are project conventions whose criterion-level locator remains unresolved."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "regional_convention"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.calendar_semantics"], "note": "Expected years are regression-tested; epoch/offset semantics need exact source documentation."},
      "tests": ["tests/test_samvatsara.py"],
      "limitations": ["Cycle anchoring follows the documented Telugu Chaitradi convention."]
    },
    {
      "id": "panchangam.sankramana-day",
      "title": "Daily Sankramana assignment",
      "summary": "Exact solar ingress is assigned to a Panchangam day with the project's after-sunset convention.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._sankramanam_name_and_jd", "role": "owner"}
      ],
      "inputs": ["sunrise", "sunset", "solar longitude crossing"],
      "outputs": ["entered Rashi", "ingress Julian day", "Sankranti flag"],
      "time_basis": "Ingress after local sunset is assigned to the next Panchangam day.",
      "method": {
        "kind": "algorithm",
        "summary": "Detect a solar-sign change across today's daylight or after yesterday's sunset, bisect the exact 30-degree crossing with the selected engine Sun, and assign after-sunset ingress to the following Panchangam day.",
        "steps": ["Compare Sun-sign indices at today's sunrise and sunset.", "If they differ, bisect the engine Sun between sunrise and sunset at the entered sign's boundary.", "Otherwise compare yesterday's sunrise and sunset with today's sunrise.", "When the sign changed after yesterday's sunset, bisect in [yesterday sunset, today sunrise] and assign it to today.", "Return no event when neither condition holds."],
        "worked_examples": [{"label": "Hyderabad, 2026-06-15, Drik Ganita", "inputs": ["Sunrise: 05:41:40 IST", "Sunset: 18:51:22 IST", "Sun changes from Vrishabha to Mithuna during daylight"], "calculation": ["Sunrise and sunset sign indices differ.", "Bisect Drik Sun longitude at 60 degrees between sunrise and sunset."], "result": ["Entered Rashi: Mithuna", "Ingress JD: 2461206.8076462564; local time 12:53:00 IST; assigned to 2026-06-15"]}],
        "notes": ["Day assignment is a convention separate from the astronomical crossing instant."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "regional_convention"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.calendar_semantics"], "note": "Crossing code is tested; day-assignment semantics need exact locator evidence."},
      "tests": ["tests/test_drik_engine.py", "tests/test_surya_siddhanta_engine.py"],
      "limitations": ["Day assignment is conventional and distinct from the astronomical crossing instant."]
    },
    {
      "id": "panchangam.slot-facts",
      "title": "Per-instant Panchangam facts",
      "summary": "Active Tithi, Nakshatra, Yoga, Karana, lunar Rashi, Vaaram, and special Yogas are recomputed for a slot.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine.facts_at", "role": "owner"},
        {"path": "src/panels/tarabalam.ts", "symbol": "muFactsAt", "role": "mirror"}
      ],
      "inputs": ["instant", "location", "engine longitude functions", "sunrise-anchored Vaaram"],
      "outputs": ["slot-time Panchangam facts"],
      "time_basis": "Exact evaluated instant; Vaaram remains anchored to the Panchangam sunrise day.",
      "method": {
        "kind": "algorithm",
        "summary": "At an arbitrary instant, evaluate the selected engine's Sun and Moon once and derive Tithi, Nakshatra, Yoga, Karana, lunar Rashi, Vaaram, and special-Yoga names without rebuilding a full day.",
        "steps": ["Normalize the datetime to UTC and convert it to Julian day.", "Evaluate and normalize engine Sun and Moon; compute elongation.", "Apply the 12-degree, 360/27-degree, 6-degree, and 30-degree index formulae used by the daily angas.", "Use caller-supplied sunrise Vaaram; only if absent, approximate it from UTC weekday.", "Pass Vaaram, Tithi, and Nakshatra names to the special-Yoga table."],
        "worked_examples": [{"label": "Hyderabad sunrise instant, 2026-06-11, Drik Ganita", "inputs": ["Instant: 2026-06-11 05:41:11 IST", "Sun/Moon: 55.8893662040/358.4708221648 degrees", "Vaaram supplied: Guruvaram"], "calculation": ["Apply all five index formulae at that instant.", "Evaluate special Yogas from Guruvaram and the derived Tithi/Nakshatra."], "result": ["Krishna Ekadashi, Revati, Shobhana, Bava, Meena, Guruvaram", "Special-Yoga list is table-derived from those exact slot facts"]}],
        "notes": ["The UTC-weekday fallback is approximate around the local sunrise boundary.", "The browser mirror implements Drik/Lahiri slot facts only."]
      },
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["drik.sidereal_positions", "panchangam.non_drik_engine_outputs", "panchangam.calendar_semantics"], "note": "Slot facts inherit the evidence state of the selected engine and calendar semantics."},
      "tests": ["tests/test_engine_facts_at.py", "tests/test_activity_surface_parity.py"],
      "limitations": ["The browser mirror currently implements Drik/Lahiri only for slot scoring."]
    },
    {
      "id": "panchangam.special-lunar-days",
      "title": "Ekadashi, Amavasya, Pournami, and Pradosham flags",
      "summary": "Sunrise and deciding-moment Tithi rules assign recurring lunar observances and Ekadashi names.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "ekadashi_name", "role": "owner"},
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._special_flags", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._special_flags", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine._special_flags", "role": "owner"},
        {"path": "src/panels/today.ts", "symbol": "ekadashiName", "role": "mirror"}
      ],
      "inputs": ["Maasam", "Paksham", "Tithi at deciding moments", "weekday", "solar sign"],
      "outputs": ["observance flags", "Ekadashi name"],
      "time_basis": "Panchangam-day deciding moments; names use Telugu Amanta convention.",
      "method": {
        "kind": "decision-table",
        "summary": "Classify recurring lunar days from sunrise and sunset Tithi indices, combine Pradosham with weekday, detect Sankranti from solar-sign changes, and name Ekadashi from Maasam/Paksham overrides.",
        "steps": ["At sunrise set Ekadashi for indices 10 or 25, Pournami for 14, and Amavasya for 29.", "Set Pradosham when index 12 or 27 is active at sunrise or sunset; add Shani/Soma for Saturday/Monday.", "Detect a solar-sign change across the engine's comparison window for Sankranti.", "For Adhika Maasam name Shukla/Krishna Ekadashi Padmini/Parama.", "Otherwise use the base Maasam/Paksham lookup and append Vaikunta for Shukla Ekadashi with Sun in Dhanu."],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11, Drik Ganita", "inputs": ["Sunrise Tithi index: 25", "Maasam/Paksham: Adhika Jyeshtha/Krishna", "Weekday: Thursday", "No solar-sign change"], "calculation": ["Index 25 matches Krishna Ekadashi.", "The Adhika-Krishna override selects Parama.", "Other special indices and weekday combinations do not match."], "result": ["is_ekadashi=true; name=Parama Ekadashi", "Other lunar-day and Sankranti flags are false"]}],
        "notes": ["Deciding moments and names follow maintained Telugu conventions rather than a universal calendar rule."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website", "generated-data"],
      "provenance": {"evidence_classes": ["published_panchangam", "regional_convention"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["festivals.forward_year_2027_2028", "panchangam.non_drik_engine_outputs"], "note": "Drik has representative comparisons; non-Drik flags are regression-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_festivals.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["Naming and deciding moments follow documented Telugu conventions."]
    },
    {
      "id": "panchangam.tithi",
      "title": "Tithi span",
      "summary": "Moon-Sun elongation is divided into thirty twelve-degree lunar days with solved boundaries.",
      "owning_layer": "engine-core",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine._tithi_span", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine._tithi_span", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine._tithi_span", "role": "owner"}
      ],
      "inputs": ["engine solar longitude", "engine lunar longitude"],
      "outputs": ["Tithi name", "start", "end"],
      "time_basis": "Active at local sunrise with boundary crossings solved in UTC Julian day.",
      "method": {
        "kind": "formula",
        "summary": "Divide normalized Moon-Sun elongation into 30 twelve-degree Tithis and bisect the selected engine's elongation for the enclosing boundaries around sunrise.",
        "steps": ["Compute E=(Moon-Sun) modulo 360 at sunrise.", "Set t=floor(E/12) modulo 30 and map through TITHI_NAMES.", "Bisect elongation at t*12 degrees in [sunrise-2 days, sunrise].", "Bisect the next boundary in [sunrise, sunrise+2 days].", "Convert both Julian days to whole-second UTC datetimes."],
        "formulae": [{"name": "Tithi index", "expression": "E = (M - S) mod 360\nt = floor(E / 12) mod 30", "variables": ["M: engine Moon longitude", "S: engine Sun longitude", "t: Tithi index, Shukla Pratipat=0"]}],
        "worked_examples": [{"label": "Hyderabad sunrise, 2026-06-11, Drik Ganita", "inputs": ["Sun: 55.8893662040 degrees", "Moon: 358.4708221648 degrees"], "calculation": ["E=302.5814559608 degrees.", "floor(E/12)=25, Krishna Ekadashi.", "Bisect Drik elongation at 300 and 312 degrees."], "result": ["Krishna Ekadashi", "Span: 2026-06-11 00:58:16-22:36:44 IST"]}],
        "notes": ["Surya Siddhanta and Vakya use the same sector definition with their own longitude models."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["partially_verified", "engine_pinned"], "claim_ids": ["drik.sidereal_positions", "panchangam.non_drik_engine_outputs", "panchangam.calendar_semantics"], "note": "Drik has representative comparisons; non-Drik spans are engine-pinned."},
      "tests": ["tests/test_drik_engine.py", "tests/test_surya_siddhanta_engine.py", "tests/test_vakya_engine.py"],
      "limitations": ["Boundary times differ by engine model and ayanamsa."]
    },
    {
      "id": "panchangam.vaaram",
      "title": "Sunrise-anchored Vaaram",
      "summary": "The weekday is selected for the Panchangam day and remains constant until the next sunrise.",
      "owning_layer": "engine-core",
      "claim_kind": "regional-convention",
      "implementations": [
        {"path": "telugu_panchangam/engines/drik.py", "symbol": "DrikGanitaEngine.calculate", "role": "owner"},
        {"path": "telugu_panchangam/engines/surya_siddhanta.py", "symbol": "SuryaSiddhantaEngine.calculate", "role": "owner"},
        {"path": "telugu_panchangam/engines/vakya.py", "symbol": "VakyaEngine.calculate", "role": "owner"}
      ],
      "inputs": ["local Panchangam date and sunrise"],
      "outputs": ["Vaaram name"],
      "time_basis": "Sunrise-to-next-sunrise day, not civil midnight.",
      "method": {
        "kind": "formula",
        "summary": "Derive weekday from sunrise Julian day and hold that Vaaram constant for the complete sunrise-to-next-sunrise Panchangam day.",
        "steps": ["Compute location/date sunrise as a UT Julian day.", "Set weekday index to int(JD_sunrise+1.5) modulo 7, where 0=Sunday.", "Map through VAARAM_NAMES and attach the single name to the day.", "Pass the same value into slot-time facts so it does not flip at civil midnight."],
        "formulae": [{"name": "Sunrise weekday", "expression": "weekday = int(JD_sunrise + 1.5) mod 7", "variables": ["JD_sunrise: UT Julian day of local sunrise", "weekday: Sunday=0 through Saturday=6"]}],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11", "inputs": ["Sunrise JD: 2461202.5077662035"], "calculation": ["int(2461202.5077662035+1.5) modulo 7 = 4.", "VAARAM_NAMES[4] is Guruvaram."], "result": ["Guruvaram from sunrise 2026-06-11 until the next sunrise"]}],
        "notes": ["Before local sunrise, civil-date weekday expectations can differ from active Panchangam Vaaram."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "regional_convention"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.calendar_semantics"], "note": "The sunrise-day semantic is tested but needs an exact textual locator."},
      "tests": ["tests/test_engine_facts_at.py", "tests/test_drik_engine.py"],
      "limitations": ["Civil-midnight weekday expectations can differ before local sunrise."]
    },
    {
      "id": "panchangam.varjyam",
      "title": "Varjyam windows",
      "summary": "Nakshatra-specific Tyajya Ghati offsets produce inauspicious sub-windows.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "nakshatra_ghati_window", "role": "owner"},
        {"path": "telugu_panchangam/engines/base.py", "symbol": "nakshatra_day_windows", "role": "owner"}
      ],
      "inputs": ["Nakshatra spans", "Varjyam offset table", "day bounds"],
      "outputs": ["Varjyam windows"],
      "time_basis": "Four-sixtieths of actual Nakshatra duration at the table offset.",
      "method": {
        "kind": "formula",
        "summary": "For the sunrise Nakshatra and its successor, place a four-Ghati Tyajya window at the maintained Nakshatra offset and retain it only when its start lies in the Panchangam day.",
        "steps": ["Find the full span of the sunrise Nakshatra and the immediately following span with the selected engine's Moon model.", "Read the Nakshatra-specific Varjyam start offset on a 60-Ghati scale.", "Scale the offset and four-Ghati duration by the actual Nakshatra span.", "Keep only windows whose starts satisfy sunrise <= start < next sunrise."],
        "formulae": [{"name": "Nakshatra-scaled Tyajya window", "expression": "start = N_start + N_duration * offset[n] / 60\nend = start + N_duration * 4 / 60", "variables": ["N_duration: actual Nakshatra duration", "offset[n]: VARJYAM_GHATIS entry for Nakshatra n"]}],
        "worked_examples": [{"label": "Hyderabad, 2026-06-11, Drik Ganita", "inputs": ["Panchangam day: 05:41:11 IST to next sunrise", "Sunrise Nakshatra: Revati; successor: Ashvini", "Offsets from VARJYAM_GHATIS"], "calculation": ["Construct the scaled Tyajya window for both spans.", "Discard a window when its computed start is outside the Panchangam day."], "result": ["Retained Varjyam: 2026-06-12 02:46:45-04:15:33.8 IST"]}],
        "notes": ["The Raman locator supports the Tyajyakala concept; the maintained complete offset table remains only partially evidenced."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative values are compared; the table's full locator coverage remains incomplete."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["Offsets follow one maintained table and are clipped to the Panchangam day convention."]
    },
    {
      "id": "panchangam.yamagandam",
      "title": "Yamagandam",
      "summary": "A weekday table selects one of eight proportional daytime segments.",
      "owning_layer": "engine-core",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/engines/base.py", "symbol": "PanchangamEngine._yamagandam", "role": "owner"}
      ],
      "inputs": ["weekday", "sunrise", "sunset"],
      "outputs": ["Yamagandam start/end"],
      "time_basis": "One eighth of local sunrise-to-sunset daytime.",
      "method": {
        "kind": "decision-table",
        "summary": "Select a weekday-specific 1-based eighth of local daylight from the Yamagandam table.",
        "steps": ["Map weekday 0=Sunday through 6=Saturday to Yamagandam part [5, 4, 3, 2, 1, 7, 6].", "Compute daylight block size as (sunset - sunrise) / 8.", "Return the selected contiguous block as whole-second UTC instants."],
        "formulae": [{"name": "Day-part window", "expression": "B = (sunset - sunrise) / 8\nstart = sunrise + (part - 1) * B\nend = start + B", "variables": ["part: weekday-selected Yamagandam index", "B: one-eighth daylight duration"]}],
        "worked_examples": [{"label": "Hyderabad, Thursday 2026-06-11", "inputs": ["Weekday index: 4", "Yamagandam part: 1", "Sunrise/sunset: 05:41:11/18:50:12 IST"], "calculation": ["B = 13:09:01 / 8 = 01:38:37.625.", "Take the first block from sunrise."], "result": ["Yamagandam: 05:41:11-07:19:48 IST"]}],
        "notes": ["The weekday table is conventional; location changes the result only through sunrise and sunset."]
      },
      "surfaces": ["python-library", "mcp", "ics", "website"],
      "provenance": {"evidence_classes": ["textual", "published_panchangam"], "verification_states": ["partially_verified"], "claim_ids": ["panchangam.mixed_daily_windows"], "note": "Representative city/date values are independently compared."},
      "tests": ["tests/test_muhurta_windows.py"],
      "limitations": ["Weekday-part tables are conventional and location-specific through sunrise/sunset."]
    },
    {
      "id": "personal.chandrabalam",
      "title": "Chandrabalam",
      "summary": "The Moon's house from Janma Rashi is classified for favourability and Puja exceptions.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/chandrabalam.py", "symbol": "chandra_position", "role": "owner"},
        {"path": "telugu_panchangam/personal/chandrabalam.py", "symbol": "chandra_verdict", "role": "owner"},
        {"path": "telugu_panchangam/personal/chandrabalam.py", "symbol": "rasi_from_nakshatra", "role": "owner"},
        {"path": "src/panels/tarabalam.ts", "symbol": "chandraOf", "role": "mirror"},
        {"path": "src/data/rasis.ts", "symbol": "rasiFromStar", "role": "mirror"}
      ],
      "inputs": ["Janma Rashi or birth Nakshatra/Pada", "day lunar Rashi"],
      "outputs": ["house number", "verdict", "favourability"],
      "time_basis": "Day or slot lunar Rashi relative to natal Moon sign.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Python/browser behavior is tested; exact source locators for the full verdict vocabulary remain open."},
      "tests": ["tests/test_chandrabalam.py", "tests/test_activity_surface_parity.py"],
      "limitations": ["Nakshatra-to-Rashi without Pada can be ambiguous at sign boundaries."],
      "method": {
        "kind": "formula",
        "summary": "Count the current Moon sign inclusively from Janma Rashi and classify houses into good, remedial-Puja, or avoid sets; optionally derive Janma Rashi from Nakshatra Pada.",
        "steps": ["Resolve Janma Rashi directly or map the birth Nakshatra/Pada over 108 Padas and twelve Rashis.", "Return unknown when a Nakshatra straddles two Rashis and Pada is absent.", "Compute the wrapped inclusive Moon house from 1 through 12.", "Classify 1/3/6/7/10/11 as good, 2/5/9 as puja, and 4/8/12 as bad."],
        "formulae": [{"name": "Moon house", "expression": "h = ((index(day_rasi)-index(janma_rasi)) mod 12)+1", "variables": ["h: Moon house from natal Moon sign"]}],
        "worked_examples": [{"label": "Mesha Janma Rashi, Moon in Mithuna", "inputs": ["Janma index: 0", "Day Moon index: 2"], "calculation": ["((2 - 0) mod 12) + 1 = 3.", "House 3 is in CHANDRA_GOOD."], "result": ["Position: 3", "Verdict: good", "Favourable: true"]}],
        "notes": ["The verdict table is parity-tested but its exact claim-level textual locator remains open."]
      }
    },
    {
      "id": "personal.homa-election",
      "title": "Homahuti and Agnivasa election",
      "summary": "Solar/lunar Nakshatra and Tithi/Vaaram remainders produce Homa offering guidance.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/homa.py", "symbol": "homahuti_group", "role": "owner"},
        {"path": "telugu_panchangam/personal/homa.py", "symbol": "agnivasa_remainder", "role": "owner"},
        {"path": "telugu_panchangam/personal/homa.py", "symbol": "homa_election", "role": "owner"},
        {"path": "src/panels/tarabalam.ts", "symbol": "muHomaElection", "role": "mirror"}
      ],
      "inputs": ["solar Nakshatra", "lunar Nakshatra", "Tithi", "Vaaram"],
      "outputs": ["Homahuti group/lord", "Agnivasa remainder", "admission guidance"],
      "time_basis": "Evaluated for the candidate slot.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["verified"], "claim_ids": ["muhurta.homahuti"], "note": "The exact Homahuti and Agnivasa rules have registered locators."},
      "tests": ["tests/test_yajna_evidence_audit.py", "tests/test_activity_surface_parity.py"],
      "limitations": ["This is election guidance and does not replace ritual prerequisites or a qualified practitioner; the current low-level reason list labels every Agnivasa remainder as earth-resident even when the admission gate fails, so consumers must rely on the admitted boolean until the tracked transparency fix lands."],
      "method": {
        "kind": "formula",
        "summary": "Apply two conjunctive hard gates: the lunar Nakshatra must fall in a benefic three-star Homahuti group counted from Surya, and the Tithi/Vaaram Agnivasa remainder must be zero or three.",
        "steps": ["Count lunar Nakshatra cyclically from solar Nakshatra and divide the 27-star cycle into nine groups of three.", "Map the group to its Graha lord and require Budha, Shukra, Chandra, or Guru.", "Convert full Tithi to ordinal 1-30 and Vaaram to Sunday-based ordinal 1-7.", "Compute the modulo-four Agnivasa remainder and require 0 or 3.", "Admit only when both requirements pass."],
        "formulae": [{"name": "Homahuti and Agnivasa", "expression": "group=floor(((N_moon-N_sun) mod 27)/3)+1; a=(T+1+V) mod 4", "variables": ["T: full Tithi ordinal 1-30", "V: Sunday-based weekday ordinal"]}],
        "worked_examples": [{"label": "Shukla Pratipat on Sunday, Ashvini Sun and Ardra Moon", "inputs": ["Solar Nakshatra: Ashvini", "Lunar Nakshatra: Ardra", "Tithi ordinal: 1", "Vaaram ordinal: 1"], "calculation": ["Ashvini-to-Ardra falls in group 2, ruled by benefic Budha.", "(1 + 1 + 1) mod 4 = 3, an admitted remainder.", "Both hard gates pass."], "result": ["Admitted: true"]}],
        "notes": ["Consumers must use the admitted boolean; the existing human reason string overstates earth residence when the remainder gate fails."]
      }
    },
    {
      "id": "personal.hora",
      "title": "Planetary Hora windows",
      "summary": "Chaldean order and weekday lord assign twelve day and twelve night planetary hours.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/lagna_hora.py", "symbol": "get_horas", "role": "owner"},
        {"path": "src/panels/today.ts", "symbol": "computeHoras", "role": "mirror"}
      ],
      "inputs": ["Vaaram", "sunrise", "sunset", "next sunrise"],
      "outputs": ["24 planetary Hora windows"],
      "time_basis": "Twelve equal day parts and twelve equal night parts.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": [], "note": "Order and segmentation are parity-tested, but a claim-level source locator is not yet registered."},
      "tests": ["tests/test_lagna_hora.py", "tests/test_browser_smoke.py"],
      "limitations": ["Planetary favourability labels in the browser are presentation, not personalized Hora judgment."],
      "method": {
        "kind": "formula",
        "summary": "Divide daylight and night into twelve equal parts and assign lords by the repeating seven-Graha Chaldean sequence starting from the weekday lord.",
        "steps": ["Compute next sunrise for the observer.", "Divide sunrise-to-sunset by 12 and sunset-to-next-sunrise by 12.", "Select the weekday lord's index in Sun, Venus, Mercury, Moon, Saturn, Jupiter, Mars order.", "Emit twelve day and twelve night windows, advancing one lord per window without resetting at sunset."],
        "formulae": [{"name": "Hora boundaries and lord", "expression": "day_i=[rise+(i-1)D/12,rise+iD/12]; lord_i=L[(start+i-1) mod 7]", "variables": ["D: daylight duration", "L: seven-lord sequence", "i: one-based Hora index"]}],
        "worked_examples": [{"label": "Hyderabad, Guruvaram 2026-06-11", "inputs": ["Sunrise: 05:41:11 IST", "Sunset: 18:50:12 IST", "Weekday lord: Jupiter"], "calculation": ["Day Hora length is approximately 1h05m45s.", "Start the lord cycle at Jupiter, followed by Mars."], "result": ["Jupiter Hora: 05:41:11-06:46:56 IST", "Mars Hora: 06:46:56-07:52:41 IST"]}],
        "notes": ["The astronomical segmentation and sequence are deterministic; browser favourability badges do not constitute a personal Hora election."]
      }
    },
    {
      "id": "personal.lagna-strength",
      "title": "Personal Lagna position and class",
      "summary": "Candidate Lagna is measured from Janma Rashi and classified by mobility and favourable houses.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/lagna_position.py", "symbol": "lagna_class_of", "role": "owner"},
        {"path": "telugu_panchangam/personal/lagna_position.py", "symbol": "lagna_position", "role": "owner"},
        {"path": "telugu_panchangam/personal/lagna_position.py", "symbol": "lagna_verdict", "role": "owner"},
        {"path": "src/muhurta-scorer.ts", "symbol": "muLagnaClassOf", "role": "mirror"},
        {"path": "src/muhurta-scorer.ts", "symbol": "muLagnaPosition", "role": "mirror"}
      ],
      "inputs": ["Janma Rashi", "candidate Lagna Rashi"],
      "outputs": ["relative house", "Lagna class", "verdict", "Ashtama flag"],
      "time_basis": "Candidate slot Lagna relative to natal Rashi.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Parity and unit behavior are tested; broad Lagna verdict semantics need claim-level locators."},
      "tests": ["tests/test_lagna_position.py", "src/scorer/__tests__/muhurta-scorer.test.ts"],
      "limitations": ["This house-only strength is not a complete election-chart Lagna assessment."],
      "method": {
        "kind": "formula",
        "summary": "Count candidate Lagna inclusively from Janma Rashi, classify its relative house, and independently classify the rising Rashi as movable, fixed, or dual.",
        "steps": ["Compute the wrapped one-based house from Janma Rashi to Lagna Rashi.", "Return own for house 1, ashtama for 8, trikona for 5 or 9, kendra for 4, 7, or 10, and neutral otherwise.", "Classify Mesha/Karka/Tula/Makara as Chara, Vrishabha/Simha/Vrischika/Kumbha as Sthira, and Mithuna/Kanya/Dhanu/Meena as Dvisvabhava.", "Treat the union of Kendra and Trikona houses as favourable."],
        "formulae": [{"name": "Relative Lagna house", "expression": "h = ((index(lagna)-index(janma)) mod 12)+1", "variables": ["h: candidate Lagna house from Janma Rashi"]}],
        "worked_examples": [{"label": "Mesha Janma Rashi, Vrischika Lagna", "inputs": ["Janma index: 0", "Lagna index: 7"], "calculation": ["((7 - 0) mod 12) + 1 = 8.", "House 8 maps to ashtama.", "Vrischika belongs to the Sthira class."], "result": ["Position: 8", "Verdict: ashtama", "Class: Sthira", "Favourable: false"]}],
        "notes": ["No planetary occupancy, aspects, dignity, Vargas, or house-lord strength are inferred by this helper."]
      }
    },
    {
      "id": "personal.lagna-transitions",
      "title": "Daily Lagna transitions",
      "summary": "Swiss Ephemeris houses and bisection locate ascendant sign changes through the day.",
      "owning_layer": "personal",
      "claim_kind": "deterministic-fact",
      "implementations": [
        {"path": "telugu_panchangam/personal/lagna_hora.py", "symbol": "get_lagna_transitions", "role": "owner"},
        {"path": "src/panels/today.ts", "symbol": "lagnaSegments", "role": "mirror"}
      ],
      "inputs": ["date", "location", "sunrise", "next sunrise"],
      "outputs": ["Lagna Rashi transition windows"],
      "time_basis": "Local sunrise-to-next-sunrise with UTC bisection of ascendant crossings.",
      "surfaces": ["python-library", "mcp", "website", "generated-data"],
      "provenance": {"evidence_classes": ["astronomical"], "verification_states": ["engine_pinned"], "claim_ids": [], "note": "Transitions are numerically and integration tested; independent city/date comparison cells are not registered."},
      "tests": ["tests/test_lagna_hora.py", "tests/test_lagna_json_builder.py"],
      "limitations": ["The browser mirror renders generated transitions; it does not independently recompute the ascendant."],
      "method": {
        "kind": "algorithm",
        "summary": "Compute the tropical Ascendant from Swiss houses, subtract Lahiri ayanamsa, scan sunrise to next sunrise at five-minute steps, and bisect every Rashi change to half-minute precision.",
        "steps": ["Compute next sunrise and set Lahiri sidereal mode.", "At an instant, obtain the Placidus Ascendant, subtract ayanamsa, normalize, and divide by 30 degrees.", "Scan in five-minute Julian-day increments.", "When the sign changes, bisect until the bracket is at most 0.5 minute and close the current Lagna window.", "Append the final window through next sunrise."],
        "formulae": [{"name": "Sidereal Lagna index", "expression": "r = floor(((asc_tropical - ayanamsa) mod 360)/30)", "variables": ["r: zero-based rising Rashi index"]}],
        "worked_examples": [{"label": "Hyderabad, 2024-01-01", "inputs": ["Location: 17.385 N, 78.4867 E", "Day start: local sunrise 06:45:59 IST"], "calculation": ["The sunrise Ascendant maps to Dhanu.", "A five-minute scan brackets the next sign change and bisection refines it."], "result": ["Dhanu Lagna: 06:45:59-07:47:23 IST", "Makara Lagna begins: 07:47:23 IST"]}],
        "notes": ["The Python owner computes the transitions; the browser consumes generated data and is not an independent astronomical implementation."]
      }
    },
    {
      "id": "personal.muhurta-activity-profiles",
      "title": "Activity-specific Muhurta profiles",
      "summary": "Source-profile rule tables define admissions, exclusions, preferences, and manual checks per activity.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/activity_rules.py", "symbol": "ACTIVITY_RULES", "role": "owner"},
        {"path": "telugu_panchangam/personal/activity_rules.py", "symbol": "get_activity_rules", "role": "owner"},
        {"path": "telugu_panchangam/personal/activity_check_contract.py", "symbol": "build_activity_check_contract", "role": "owner"},
        {"path": "tools/export_activity_rules.py", "symbol": "main", "role": "mirror"},
        {"path": "src/panels/tarabalam.ts", "symbol": "MU_ACTIVITY", "role": "mirror"}
      ],
      "inputs": ["activity identifier"],
      "outputs": ["automated constraints", "ranking preferences", "manual checks", "structured check classifications", "provenance identifier"],
      "time_basis": "Rules are applied to each candidate day and slot.",
      "surfaces": ["python-library", "mcp", "website", "generated-data"],
      "provenance": {"evidence_classes": ["textual", "project_heuristic"], "verification_states": ["needs_locator", "verified", "heuristic"], "claim_ids": ["muhurta.activity_rules"], "note": "The umbrella claim remains needs_locator and grants no authority. At the activity level, 34 of 35 canonical profiles are verified and the remaining generic any profile is an explicit heuristic; no profile is currently contradicted."},
      "tests": ["tests/test_activity_provenance_contract.py", "tests/test_activity_rules_export.py", "tests/test_activity_surface_parity.py", "tests/test_activity_check_contract.py", "src/scorer/__tests__/activity-check-contract.test.ts"],
      "limitations": ["Each activity's evidence state must be read from its own provenance claim; this umbrella record is not a blanket verification claim."],
      "method": {
        "kind": "interpretive-procedure",
        "summary": "Resolve an activity key to one declarative profile whose fields separately express hard day gates, slot gates, ranking preferences, unresolved manual checks, and provenance authority.",
        "steps": ["Resolve the single compatibility alias litigation to the canonical court profile.", "Load the profile by exact activity identifier; reject unknown identifiers in the public finder.", "Normalize source-facing Nakshatra spellings to engine spellings at comparison time.", "Apply allowed/avoid/required fields as hard gates and prefer/penalty fields as disclosed score changes.", "For all 30 browser activities, join deterministic Panchangam fields, exact personal/chart rule IDs and every source-authored manual row to the generated structured check contract; use its explicit chart, information or practical section instead of inferring from prose.", "Surface manual_checks and manual_prerequisites rather than pretending to compute horoscope or practitioner judgments.", "Read source_claim, audit_claim, heuristic_claim, and related_claims independently; never promote the umbrella record into authority for a profile."],
        "worked_examples": [{"label": "Wedding profile authority and gates", "inputs": ["Activity: wedding"], "calculation": ["Resolve directly to ACTIVITY_RULES[wedding].", "Require its admitted Maasams, Vaarams, Tithis, Nakshatras, Lagnas, and non-Vishti Karana; apply eclipse, Sankramana, Adhika, Pitru Paksha, Simha-Stha, Yoga, and combustion exclusions.", "Preserve the manual Pada, chart, and couple-specific prerequisites in output.", "Attach source_claim muhurta.wedding and disclose its related lineage-divergence claim."], "result": ["A structured rule profile, not a precomputed yes/no date", "Any surviving slot remains subject to listed practitioner checks"]}],
        "notes": ["At this snapshot 34 of 35 canonical profiles have verified activity-level claims; the generic any profile is an explicit heuristic.", "The generated check contract changes display classification only; it does not promote a manual source statement into an automated rule."]
      }
    },
    {
      "id": "personal.muhurta-slot-ranking",
      "title": "Muhurta day diagnosis, slot ranking, and chart screening",
      "summary": "Hard exclusions, exact Karnavedha daylight-limb gates, time-window subtraction, personal strengths, textual preferences, disclosed heuristics, and a bounded source-backed election-chart post-screen produce ranked slots.",
      "owning_layer": "personal",
      "claim_kind": "project-heuristic",
      "implementations": [
        {"path": "telugu_panchangam/personal/muhurta.py", "symbol": "diagnose_day", "role": "owner"},
        {"path": "telugu_panchangam/personal/muhurta.py", "symbol": "day_slots", "role": "owner"},
        {"path": "telugu_panchangam/personal/muhurta.py", "symbol": "night_slots", "role": "owner"},
        {"path": "telugu_panchangam/personal/muhurta.py", "symbol": "assign_tiers", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/karnavedha.py", "symbol": "evaluate_karnavedha_daylight", "role": "owner"},
        {"path": "telugu_panchangam/personal/slot_scorers.py", "symbol": "score_tara", "role": "owner"},
        {"path": "telugu_panchangam/personal/slot_scorers.py", "symbol": "score_chandra", "role": "owner"},
        {"path": "src/panels/tarabalam.ts", "symbol": "findMuhurta", "role": "mirror"},
        {"path": "src/panels/tarabalam.ts", "symbol": "muAssignTiers", "role": "mirror"},
        {"path": "src/muhurta-scorer.ts", "symbol": "computePersonalDosha", "role": "mirror"},
        {"path": "src/muhurta-scorer.ts", "symbol": "computeDayDosha", "role": "mirror"},
        {"path": "telugu_panchangam/personal/election_chart_rules.py", "symbol": "ELECTION_CHART_RULES", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_chart_rules.py", "symbol": "ELECTION_CHART_MANUAL_REMAINDERS", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_chart_rules.py", "symbol": "ELECTION_CHART_COMPLETE_ASSESSORS", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_chart.py", "symbol": "evaluate_election_window", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/conventions.py", "symbol": "ELECTION_CHART_CONVENTIONS", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/event_admission.py", "symbol": "planet_positions", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/chart_geometry.py", "symbol": "evaluate_well_situated", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/chart_geometry.py", "symbol": "evaluate_full_aspect", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/graha_nature.py", "symbol": "evaluate_house_free_of_natural_malefics", "role": "owner"},
        {"path": "telugu_panchangam/personal/election_assessors/chart_geometry.py", "symbol": "evaluate_all_planets_in_houses", "role": "owner"},
        {"path": "telugu_panchangam/personal/personal_election.py", "symbol": "evaluate_personal_election_window", "role": "owner"},
        {"path": "telugu_panchangam/personal/activity_check_contract.py", "symbol": "build_activity_check_contract", "role": "owner"},
        {"path": "tools/export_election_chart_rules.py", "symbol": "main", "role": "mirror"},
        {"path": "tools/export_activity_rules.py", "symbol": "main", "role": "mirror"},
        {"path": "src/scorer/election-chart-screening.ts", "symbol": "evaluateElectionWindow", "role": "mirror"},
        {"path": "src/scorer/election-assessors/event-admission.ts", "symbol": "completePlanetPositions", "role": "mirror"},
        {"path": "src/scorer/election-assessors/chart-geometry.ts", "symbol": "evaluateWellSituated", "role": "mirror"},
        {"path": "src/scorer/election-assessors/chart-geometry.ts", "symbol": "evaluateFullAspect", "role": "mirror"},
        {"path": "src/scorer/election-assessors/graha-nature.ts", "symbol": "evaluateHouseFreeOfNaturalMalefics", "role": "mirror"},
        {"path": "src/scorer/election-assessors/chart-geometry.ts", "symbol": "evaluateAllPlanetsInHouses", "role": "mirror"},
        {"path": "src/scorer/election-assessors/karnavedha-daylight.ts", "symbol": "evaluateKarnavedhaDaylight", "role": "mirror"},
        {"path": "src/scorer/personal-election-screening.ts", "symbol": "evaluatePersonalElectionRules", "role": "mirror"},
        {"path": "src/scorer/election-chart-enrichment.ts", "symbol": "enrichElectionChartSlots", "role": "mirror"},
        {"path": "src/lib/election-chart-api.ts", "symbol": "deriveElectionCharts", "role": "mirror"}
      ],
      "inputs": ["Panchangam days with timezone-aware sunrise, sunset, Tithi and Nakshatra transition spans", "activity profile", "birth profiles and an activity-specific primary role", "travel direction", "slot duration", "candidate city coordinates and IANA timezone", "candidate-time DashaFlow Lahiri planetary positions", "validated selected-city Drik/Lahiri Lagna transitions"],
      "outputs": ["day diagnosis", "candidate slots", "scores", "relative tiers", "reasons", "manual checks", "Karnavedha day-source outcomes", "personal-role and chart-screening states", "per-rule pass/fail/unknown outcomes", "removed and retained chart-screened slots", "capped, review-gated, and overlapping disposition counts"],
      "time_basis": "Karnavedha evaluates the Tithi and Nakshatra active at local sunrise once over the half-open interval [local sunrise, local sunset), using actual transition boundaries rather than candidate sampling. Day and night candidate windows otherwise use per-slot Panchangam facts. Source-specific personal and deterministic chart predicates sample each half-open window at its start, final represented civil minute, every 10 civil minutes from the start, and the minute before, at, and after every known interior Drik/Lahiri Lagna transition. Each sample minute is mapped to its canonical local Lagna before Whole Sign houses are projected.",
      "surfaces": ["python-library", "mcp", "website", "generated-data"],
      "provenance": {"evidence_classes": ["textual", "project_heuristic"], "verification_states": ["verified", "partially_verified", "heuristic", "contradicted"], "claim_ids": ["muhurta.any.shared_scoring", "muhurta.relative_tiers", "muhurta.wedding", "muhurta.annaprasana", "muhurta.annaprasana.raman_transcription_chart", "muhurta.annaprasana.source_divergence", "muhurta.raman_transcription.paksha_definition", "muhurta.karnavedha", "muhurta.karnavedha.vidyamadhava_divergence", "muhurta.karnavedha.chintamani_divergence", "election_day.karnavedha_daylight_policy_v1", "muhurta.seemantha", "muhurta.gruhapravesha", "muhurta.land_purchase.building", "muhurta.house_purchase.completed", "muhurta.gold_jewelry.purchase", "muhurta.purchase.general", "muhurta.service_entry", "muhurta.shantika_paushtika", "muhurta.pilgrimage", "muhurta.travel", "muhurta.surgery", "election_chart.well_placed.phaladeepika_2_36", "election_chart.dignity.phaladeepika_1_6", "election_chart.relationships.phaladeepika_2_21_22", "election_chart.full_graha_drishti.phaladeepika_2_23", "election_chart.navamsa.bphs_6_12", "election_chart.chandra_solar_clearance_policy_v1", "election_chart.gold_transition_envelope_v1", "election_chart.gold_qualification_policy_v1", "muhurta.vidyarambha", "muhurta.vidyarambha.raman_chapter_xi_scope", "muhurta.vidyarambha.chintamani_divergence", "election_chart.vidyarambha_co_location_policy_v1", "election_chart.vidyarambha_reject_precedence_policy_v1", "election_chart.natural_malefics.bphs_3_11_modern_witness", "election_chart.whole_sign_house_policy_v1", "election_chart.mean_node_policy_v1", "election_chart.budha_same_sign_association_policy_v1", "election_chart.raman_180_degree_paksha_policy_v1", "election_chart.lunar_phase_boundary_guard_policy_v1", "election_chart.annaprasana_fail_closed_aggregation_policy_v1", "election_chart.annaprasana.raman_transcription_policy_v1"], "note": "Aggregate scores and relative tier bands remain disclosed project heuristics. The 32 explicitly enumerated chart predicates and five documented personal predicates across four named roles retain their own source boundaries. Gold resolves four event-specific qualifications, Annaprasana resolves six event-specific clauses, and Karnavedha resolves two daylight-limb gates plus the vacant-eighth chart clause under named source and product conventions. Aksharabhyasa resolves its two Chapter VIII event clauses under the strict all-three co-location and reject-wins policies, while its overall assessment remains partial/provisional pending the shared baseline. Each completion statement is limited to its named event-specific contract; the general election-chart baseline remains unassessed."},
      "tests": ["tests/test_muhurta_finder.py", "tests/test_muhurta_lagna_integration.py", "tests/test_karnavedha_daylight_assessor.py", "tests/test_karnavedha_profile.py", "tests/test_election_chart_screening.py", "tests/test_annaprasana_profile.py", "tests/test_annaprasana_screenshot_evidence.py", "tests/test_vidyarambha_election_assessor.py", "tests/test_vidyarambha_projection.py", "tests/test_vidyarambha_screenshot_evidence.py", "tests/test_personal_election_parity.py", "tests/test_activity_check_contract.py", "tests/test_city_browser_projection.py", "tests/test_lagna_boundary_guard_audit.py", "tests/test_browser_smoke.py", "src/scorer/__tests__/muhurta-scorer.test.ts", "src/scorer/__tests__/karnavedha-daylight.test.ts", "src/__tests__/election-chart-api.test.ts", "src/scorer/__tests__/election-chart-screening.test.ts", "src/scorer/__tests__/election-chart-vidyarambha-projection.test.ts", "src/scorer/__tests__/personal-election-screening.test.ts", "src/scorer/__tests__/election-chart-enrichment.test.ts", "src/scorer/__tests__/activity-check-contract.test.ts", "src/__tests__/muhurta-profile-panel.test.ts"],
      "limitations": ["Relative rankings mean best available under the inputs, not absolute scriptural quality or professional advice.", "Automatic integration of candidate-time election-chart enrichment and the four source-specific personal-role screens into ranked output is website-only and Drik/Lahiri/Whole Sign only; pure Python evaluators provide parity, but Python/MCP slot ranking does not call DashaFlow or apply candidate-time chart rules. Python/MCP do apply Karnavedha's two day-level transition rules. Surya Siddhanta or Vakya chart results are not blended with Drik.", "Start/end, 10-minute cadence, and every known interior Drik Lagna transition are sampled, but this remains a discrete check rather than a continuous-time proof for every instant inside a window; missing Lagna boundary support makes screening unavailable. Karnavedha's two day-level limbs instead use actual transition boundaries once per day and fail closed when those boundaries are unavailable or uncertain.", "DashaFlow and Drik Panchang can place an Ascendant transition one or two civil minutes apart. A slot that only partly overlaps the five-minute guard around a local transition keeps pure house predicates and the Travel/Gruhapravesha Lagna rules unknown. Gold placement rules can still fail from resolved Rasi, Navamsa or solar-clearance factors, but otherwise remain unknown because their house factor is unresolved; its sign-based aspects remain computable. Seemantha and Surgery Moon/Nakshatra personal rules also remain computable.", "One search dynamically packs at most 24 unique instants per request and makes at most five chart requests; the number of highest-ranked base candidates screened is therefore data-dependent, and candidateLimitReached explicitly marks a short or empty result that did not exhaust every lower-ranked base candidate.", "Positive chart and personal source preferences are tie-break evidence only and do not change the raw heuristic score. Gold v1 uses a separate qualify effect: a known miss retains the slot with unchanged raw score and makes Good its maximum rating without manual-review wording; only an unknown remains review-gated. One retained slot can be counted in both dispositions when a conclusive miss and a separate unknown coexist.", "The Gold v1 assessor resolves four event-specific clauses, the Annaprasana v1 assessor resolves six, and the Karnavedha v1 assessor resolves two daylight-limb gates plus the vacant-eighth chart clause. None implements or claims completion of the general election-chart baseline tracked in GitHub issue #284.", "Annaprasana follows the named Raman-transcription policy rather than blending the reversed Budha/Shukra assignments in Iyer or the distinct Chandra treatment in Muhurta Chintamani. Whole Sign occupation, mean nodes, same-sign Budha association, the 180-degree Paksha split, the plus-or-minus 0.02-degree boundary guard, and fail-closed aggregation are disclosed product conventions.", "Karnavedha follows the named Raman half-open daylight policy and records Vidyamadhava and Muhurta Chintamani as non-blended alternatives; missing, unordered, timezone-naive, or non-covering transition evidence resolves unknown and fails admission.", "Aksharabhyasa implements only the Chapter VIII first-letter-writing clauses. The strict all-three ninth-house reading and hard-reject precedence are disclosed product conventions; Chapter XI study elections and the Muhurta Chintamani lineage are not blended.", "Outside the named Gold, Annaprasana, Karnavedha, and Aksharabhyasa event-specific clauses, Navamsa and full-aspect convention, qualitative aspect, strength, dignity, benefic/malefic, lordship, compatibility, lineage and real-world safety judgments remain manual."],
      "method": {
        "kind": "algorithm",
        "summary": "Apply profile day gates, evaluate Karnavedha's actual daylight-limb transition spans once per day, remove candidate named Muhurtas that intersect hard windows, evaluate slot-time and source-specific personal facts, rank survivors with transparent additive scores and relative tiers, then use a privacy-minimal candidate-time chart service to apply only deterministic source predicates.",
        "steps": ["Validate activity and Chandra mode and load its source profile.", "For Karnavedha, evaluate the Tithi and Nakshatra active at local sunrise across the complete half-open daylight interval [sunrise, sunset); a prohibited transition or missing, ambiguous, timezone-naive, unordered, or non-covering boundary fails admission.", "Return a diagnosis when any hard day-level gate fails; otherwise build fifteen named day slots or fifteen night slots and remove those overlapping applicable hard windows.", "For each survivor choose dominant Choghadiya, recompute slot facts when an engine is supplied, and apply profile admission gates.", "Preserve all generic group scoring. For Drik, evaluate the named primary-traveller, householder, mother or patient rule from exact returned Chandra facts and the canonical local Lagna at every sampled state; reject a prohibition present at any sample and count a preference only when it persists across all samples.", "Add disclosed contributions from Muhurta nature, Choghadiya, Tara, Chandra, Tithi, Vara, special/Nitya/Anandadi Yogas, Amrita, Lagna, Hora, Panchaka, and profile preferences or penalties.", "Attach grouped reasons, personal/day dosha flags, and manual rows classified by the generated structured contract for all 30 browser activities, then assign relative tiers and form the base-ranked candidate list.", "For a Drik activity with deterministic chart rules, sample each window's start, final represented minute and 10-minute cadence plus the minute before, at, and after every known interior Drik Lagna transition; map each sampled minute to the validated local Lagna. If boundary support is missing, retain and cap the base shortlist as unavailable.", "Dynamically pack no more than 24 ordered UTC instants into each request, validate the complete nine-graha Lahiri response, ignore sidecar house numbers, and recompute every Whole Sign house from planetary Rashi relative to the canonical local Lagna before evaluating generated predicates.", "For Gold, derive Navamsa and full classical Graha Drishti from the complete positions, apply the disclosed well-placed and 12-degree solar-clearance convention to both luminaries, and retain evidence naming the observed adverse factor or aspector.", "For Annaprasana, evaluate the vacant 10th, Budha outside 7th, Mangala outside 8th, Shukra outside 9th, named-benefic occupation of Lagna, and natural-malefic-free Lagna clauses. Treat the first, three exclusions and malefic clause as mandatory; use the named-benefic clause only as a tie-break preference.", "Classify Chandra in Annaprasana Lagna from the Raman-transcription 180-degree solar-elongation split, returning unknown within the disclosed plus-or-minus 0.02-degree boundary cells; fixed natural-malefic failure controls over simultaneous phase uncertainty.", "For Karnavedha candidate charts, reject a slot whenever the canonical Whole Sign eighth house is occupied; when both daylight gates and this chart predicate resolve across the unbounded candidate set, mark the named event-specific contract complete without extending that statement to the general election-chart baseline.", "For Aksharabhyasa, reject a candidate when any complete sampled state occupies the canonical Whole Sign eighth house; record a score-neutral preference only when Budha, Shukra and Guru are all co-located in the ninth at every sample. The hard reject wins and the overall assessor remains partial/provisional pending the shared baseline.", "If a window only partly overlaps the five-minute transition guard, make pure house predicates and Travel/Gruhapravesha Lagna rules unknown. For Gold, make only the house factor unresolved: keep Rasi/Navamsa/solar failures and sign-based aspects computable. Continue Moon/Nakshatra-only Seemantha and Surgery personal rules.", "Apply personal removals first and chart removals second so the categories are exclusive, then refill from further base-ranked candidates when failures leave fewer than ten competitive survivors, bounded to five requests; if that cap is reached, report the exact screened-candidate count, while a service failure retains the original top ten with an unavailable state and an empty base list makes no request.", "Apply reject failures as removals, Gold qualify failures as resolved tier caps, and prefer passes only as tie-break evidence. Unknown alone triggers review; instability alone does not.", "Sort by tier, raw score, source-specific personal preferences, chart preferences, absence of a computed personal dosha, date and time; never present unresolved qualitative checks as computed."],
        "formulae": [
          {"name": "Relative tier coordinate", "expression": "q = (score-floor)/(ceiling-floor); Excellent if q>=0.75, Good if q>=0.50, Fair if q>=0.25, else Avoid", "variables": ["floor, ceiling: minimum and maximum survivor scores in the batch"]},
          {"name": "Inclusive personal position", "expression": "position = ((target_index - natal_index + cycle_length) mod cycle_length) + 1", "variables": ["cycle_length: 12 for Rasi or 27 for Nakshatra", "natal_index: primary participant's Janma Rasi/Lagna or birth-Nakshatra index", "target_index: candidate Lagna or Nakshatra index"]},
          {"name": "Karnavedha single daylight limb", "expression": "pass iff aware(A,S,E,B) and A <= S < B and B >= E for the half-open interval [S,E)", "variables": ["S, E: local sunrise and sunset", "A, B: start and next transition of the Tithi or Nakshatra active at sunrise", "a transition exactly at sunset passes; missing, unordered, timezone-naive or non-covering evidence is unknown and fails admission"]},
          {"name": "Canonical Whole Sign house", "expression": "house(planet) = ((rashi_index(planet) - rashi_index(local_lagna) + 12) mod 12) + 1", "variables": ["rashi_index(planet): DashaFlow Lahiri planetary Rashi index 0-11", "rashi_index(local_lagna): selected-city Lagna index 0-11 from the validated local Drik/Lahiri transition map", "sidecar-returned house and Lagna fields are diagnostic and do not override this projection"]},
          {"name": "Gold v1 Navamsa", "expression": "navamsa_index = (start(rashi_modality) + floor(degree_in_rashi / (30/9))) mod 12", "variables": ["start: the Rasi itself for movable, ninth from it for fixed, fifth from it for dual", "degree_in_rashi: rounded sidereal degree from 0 inclusive to 30 exclusive", "within 0.01 degrees of an internal division boundary resolves unknown"]},
          {"name": "Gold v1 full Graha Drishti", "expression": "full_aspect(source,target) iff ((R(target)-R(source)+12) mod 12) is in offsets(source)", "variables": ["ordinary classical-graha offsets: {6}", "Kuja: {3,6,7}; Guru: {4,6,8}; Shani: {2,6,9}", "Rahu, Ketu, conjunction, self and partial aspects are excluded"]},
          {"name": "Gold v1 Chandra solar clearance", "expression": "clearance = abs(((longitude(Chandra)-longitude(Surya)+180) mod 360)-180); pass above 12.02 degrees, fail below 11.98 degrees, otherwise unknown", "variables": ["longitude: absolute sidereal ecliptic longitude", "12 degrees: disclosed project approximation", "0.02 degrees: two-position rounding guard"]},
          {"name": "Annaprasana v1 natural-malefic Lagna and Paksha", "expression": "house(p)=1+((RasiIndex(p)-RasiIndex(local Lagna)+12) mod 12); E=(longitude(Chandra)-longitude(Surya)) mod 360; waxing iff 0.02<E<179.98; waning iff 180.02<E<359.98; boundary cells resolve unknown", "variables": ["fixed natural malefics: Surya, Mangala, Shani, mean Rahu and mean Ketu", "Chandra: included only when waning and physically occupying Whole Sign house 1", "Budha association: same-sign inference only; an accompanying fixed malefic already controls failure", "0.02 degrees: disclosed two-position rounding guard around conjunction and opposition"]},
          {"name": "Aksharabhyasa partial chart clauses", "expression": "vacant_8 = every p in nine_grahas has H(p) != 8; trio_9 = H(Budha) = 9 AND H(Shukra) = 9 AND H(Guru) = 9", "variables": ["H(p): canonical local Whole Sign house", "vacant_8: hard reject; any known occupant removes the candidate", "trio_9: one preference under vidyarambha-benefic-trio-co-location-v1; no raw-score or tier change", "precedence: owner-approved reject-wins project convention; not textual authority", "overall assessment: partial/provisional pending the shared baseline"]},
          {"name": "Sampled election window", "expression": "samples = unique([start_minute, max(start_minute, end_minute - 1)] + [start_minute + 10k while before final_minute] + [transition_minute - 1, transition_minute, transition_minute + 1 for each known interior Drik Lagna transition])", "variables": ["start_minute: first included civil minute", "end_minute: exclusive civil-minute boundary", "k: positive integer cadence step", "transition_minute: precomputed Drik Lagna transition; transition samples are clipped to the half-open interval"]},
          {"name": "Partial transition guard", "expression": "review = window intersects [transition-5, transition+5] without fully spanning that guard", "variables": ["a review-gated pure house or Lagna-dependent personal rule resolves to unknown", "Gold placement keeps only its house factor unresolved while sign-based aspects remain computable", "a fully spanned guard evaluates both canonical local Lagna states"]}
        ],
        "worked_examples": [
          {"label": "Generic slot, Hyderabad 2026-06-11", "inputs": ["Activity: any", "Slot: 07:26:23-08:18:59 IST", "Mitra named Muhurta", "Rog Choghadiya"], "calculation": ["Mitra auspicious nature +1; Rog Choghadiya +0.", "Amrita Kalam overlap +2, Sarvartha Siddhi +2, Shobhana +1, Anandadi Chhatra +1.", "Total score = 7; no personal or day dosha.", "This score is at the top relative band among surviving slots."], "result": ["Score: 7", "Tier: Excellent"]},
          {"label": "Karnavedha daylight categories, Hyderabad 2026-01-08", "inputs": ["Local sunrise 06:48:13 and sunset 17:57:09", "Tithi transition next day 07:05:55", "Nakshatra transition 12:24:41"], "calculation": ["The Tithi transition is outside [06:48:13,17:57:09), so karnavedha.daylight-tithi-single passes.", "The Nakshatra transition is inside that interval, so karnavedha.daylight-nakshatra-single fails.", "The day fails before candidate generation; DashaFlow is not called."], "result": ["Tithi: pass", "Nakshatra: fail", "No Karnavedha candidate windows"]},
          {"label": "Wedding chart rejection at the sampled window edge", "inputs": ["Activity: wedding", "Start snapshot projects Kuja to house 7 in the local Lagna frame", "Final represented minute projects Kuja to house 8 in the local Lagna frame", "Both snapshots contain all nine canonical grahas"], "calculation": ["The start snapshot passes wedding.kuja-not-8.", "The final snapshot fails wedding.kuja-not-8.", "A reject predicate fails when either sample contains the prohibited condition.", "The different statuses also mark the sampled window unstable."], "result": ["The candidate window is removed", "No raw-score adjustment or re-tiering can override the source rejection"]},
          {"label": "Gold v1 four-rule qualification pass", "inputs": ["Activity: gold; canonical Lagna Mesha", "Surya Simha 11 degrees in house 5; Chandra Makara 15 degrees in house 10", "Guru Mesha 12 degrees; Shukra Karka 21 degrees; complete nine-graha payload"], "calculation": ["Surya is outside houses 6, 8 and 12, outside enemy and debilitation Rasi/Navamsa; Guru's fifth full aspect reaches Simha.", "Chandra is outside houses 6, 8 and 12 and Vrischika debilitation Rasi/Navamsa; its solar clearance exceeds 12 degrees.", "Shukra's seventh full aspect from Karka reaches Makara.", "All four qualify outcomes pass under the named v1 conventions."], "result": ["The four event-specific Gold v1 chart clauses are satisfied for this sampled state", "No duplicate practitioner-review remainder is added for those four clauses; the general election-chart baseline is not assessed"]},
          {"label": "Annaprasana v1 six-clause pass", "inputs": ["Activity: annaprasana; canonical Lagna Mesha", "Budha in house 1; Guru in house 2; Shukra and Surya in house 3", "Chandra in house 4; Mangala in house 6; Shani and Ketu in house 11; Rahu in house 5", "Complete nine-graha payload with no graha in house 10"], "calculation": ["House 10 is vacant; Budha, Mangala and Shukra are outside houses 7, 8 and 9 respectively.", "Budha physically occupies Lagna, so the source preference passes.", "No fixed natural malefic occupies Lagna and Chandra is outside Lagna, so the malefic prohibition passes.", "All six outcomes resolve under the named Raman-transcription policy."], "result": ["The slot survives all five mandatory Annaprasana chart prohibitions", "The Lagna-benefic preference supplies tie-break evidence only", "No event-specific chart remainder remains; the general election-chart baseline #284 remains open"]}
          ,{"label": "Aksharabhyasa hard-reject precedence", "inputs": ["Compatibility activity ID: vidyarambha", "One canonical chart sample with Surya in house 8", "Budha, Shukra and Guru all in house 9"], "calculation": ["The vacant-eighth predicate fails with observed occupant Surya.", "The strict all-three ninth-house preference passes.", "The owner-approved project convention applies the hard reject; the preference changes neither score nor tier and cannot neutralize it."], "result": ["The candidate is removed", "The event-specific clauses are resolved, but the overall assessment remains partial/provisional pending the shared baseline"]}
        ],
        "notes": ["The additive weights and relative-tier bands are project heuristics even when an individual activity gate has verified textual support.", "Chart predicates are generated from the Python rule table and retain claim-specific source locators. The DashaFlow sidecar supplies Lahiri planetary Rashi/degree facts but does not choose an activity or issue an auspiciousness verdict; the browser's validated local Drik/Lahiri Lagna map owns the house frame.", "Role preferences persist only stable saved-profile IDs in browser-local storage and are never sent, shared or exported; one-off participants remain session-only.", "Capped and review-gated counts are disposition counts, not necessarily unique slots; the summary reports their exact overlap.", "The Annaprasana method follows the six Raman-transcription clauses without importing Namakarana Lagna-strength wording or blending the Iyer/Chintamani disagreements.", "The Karnavedha method evaluates the two daylight limbs once per Panchangam day and the vacant-eighth rule per sampled candidate chart; it does not blend the named conflicting textual alternatives.", "The Aksharabhyasa method implements only Raman Chapter VIII's first-letter-writing chart clauses under a named co-location and reject-precedence policy; Chapter XI study elections and the distinct Muhurta Chintamani lineage remain documented alternatives.", "Edge, cadence and known Lagna-transition sampling improves whole-window coverage but does not establish continuous validity inside the entire interval."]
      }
    },
    {
      "id": "personal.nitya-yoga-disposition",
      "title": "Nitya Yoga disposition",
      "summary": "Each of the 27 Nitya Yogas is classified for slot scoring and partial-window cautions.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/nitya_yoga.py", "symbol": "nitya_disposition", "role": "owner"},
        {"path": "telugu_panchangam/personal/slot_scorers.py", "symbol": "score_nitya_yoga", "role": "owner"}
      ],
      "inputs": ["Nitya Yoga name", "slot start", "Yoga span"],
      "outputs": ["disposition", "score adjustment", "hard/partial caution"],
      "time_basis": "Active Yoga and candidate slot instant.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Disposition and partial-window behavior are tested; exact claim locators remain open."},
      "tests": ["tests/test_muhurta_finder.py"],
      "limitations": ["Disposition is one input to Muhurta ranking, not a standalone election verdict; partial-dosha windows currently use a fixed 24 civil minutes per Ghati rather than the proportional sunrise-to-sunrise Ghati clock."],
      "method": {
        "kind": "decision-table",
        "summary": "Classify the active Nitya Yoga, then apply a hard defer, fixed score, or time-bounded penalty according to the candidate slot and activity policy.",
        "steps": ["Map Vyatipata and Vaidhriti to hard-avoid.", "Map six named Yogas to partial-avoid windows of 3, 5, 6, or 9 fixed 24-minute Ghatis from Yoga start.", "Map seventeen named Yogas to auspicious and Vajra/Variyan or unknown values to neutral.", "For a hard-avoid Yoga, defer when the activity enables samskara skips or otherwise score -2.", "For a partial Yoga, score -1 only when slot start is within its configured window; score auspicious +1 and neutral 0."],
        "worked_examples": [{"label": "Shobhana at a candidate slot", "inputs": ["Active Nitya Yoga: Shobhana"], "calculation": ["Shobhana is in NITYA_AUSPICIOUS.", "Apply the auspicious slot adjustment."], "result": ["Disposition: auspicious", "Score adjustment: +1", "Defer: false"]}],
        "notes": ["Partial windows use fixed civil minutes in current code; they do not use the proportional Ghati clock documented on the Ghati page."]
      }
    },
    {
      "id": "personal.tarabalam",
      "title": "Tarabalam",
      "summary": "Cyclic distance from Janma Nakshatra produces one of nine Tara names and favourability.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/tarabalam.py", "symbol": "tara_number", "role": "owner"},
        {"path": "telugu_panchangam/personal/tarabalam.py", "symbol": "tara_name", "role": "owner"},
        {"path": "telugu_panchangam/personal/tarabalam.py", "symbol": "taras_for_day", "role": "owner"},
        {"path": "src/panels/tarabalam.ts", "symbol": "taraOf", "role": "mirror"}
      ],
      "inputs": ["Janma Nakshatra", "day or slot Nakshatra"],
      "outputs": ["Tara number", "Tara name", "favourability"],
      "time_basis": "Active day or slot Nakshatra relative to birth Nakshatra.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Formula and browser parity are tested; a claim-specific exact locator is not yet registered."},
      "tests": ["tests/test_tarabalam.py", "tests/test_activity_surface_parity.py"],
      "limitations": ["Tarabalam is one personal factor and should not be presented as a complete Muhurta judgment."],
      "method": {
        "kind": "formula",
        "summary": "Count inclusively from Janma Nakshatra to the active Nakshatra around the 27-star cycle, reduce the count to a repeating nine-Tara cycle, and classify the configured auspicious Tara numbers.",
        "steps": ["Look up both canonical Nakshatra indices.", "Compute the wrapped inclusive count from 1 through 27.", "Reduce that count to Tara number 1 through 9.", "Map to Janma, Sampat, Vipat, Kshema, Pratyak, Sadhana, Naidhana, Mitra, or Parama Mitra.", "Mark 2, 4, 6, 8, and 9 auspicious; a group passes good_for_all only if every member is auspicious."],
        "formulae": [{"name": "Tara number", "expression": "c=((index(day)-index(janma)) mod 27)+1; tara=((c-1) mod 9)+1", "variables": ["c: inclusive cyclic Nakshatra count"]}],
        "worked_examples": [{"label": "Ashvini birth star, Pushya active star", "inputs": ["Ashvini index: 0", "Pushya index: 7"], "calculation": ["Inclusive count = ((7 - 0) mod 27) + 1 = 8.", "Tara number = 8, named Mitra.", "8 is in AUSPICIOUS_TARAS."], "result": ["Tara: 8 Mitra", "Auspicious: true"]}],
        "notes": ["This project follows the disclosed Telugu convention that Tara 1 Janma is avoid rather than auspicious."]
      }
    },
    {
      "id": "personal.tithi-family",
      "title": "Fivefold Tithi family",
      "summary": "Tithi ordinal cycles through Nanda, Bhadra, Jaya, Rikta, and Purna families.",
      "owning_layer": "personal",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/personal/tithi_class.py", "symbol": "tithi_family", "role": "owner"},
        {"path": "telugu_panchangam/personal/slot_scorers.py", "symbol": "score_tithi_class", "role": "owner"},
        {"path": "src/muhurta-scorer.ts", "symbol": "muTithiFamily", "role": "mirror"},
        {"path": "src/muhurta-scorer.ts", "symbol": "muScoreTithiClass", "role": "mirror"}
      ],
      "inputs": ["Tithi name", "activity preference or exclusion"],
      "outputs": ["family name", "Rikta flag", "score or exclusion reason"],
      "time_basis": "Active day or slot Tithi.",
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Family mapping and parity are tested; exact source coverage remains broad."},
      "tests": ["tests/test_muhurta_finder.py", "src/scorer/__tests__/muhurta-scorer.test.ts"],
      "limitations": ["Activity-specific use must come from the selected profile rather than a universal family ranking."],
      "method": {
        "kind": "formula",
        "summary": "Extract the Paksha-local Tithi ordinal from the final word of the name and map its repeating fivefold remainder to a family.",
        "steps": ["Read the final token so Paksha prefixes and named Ekadashi prefixes do not affect classification.", "Normalize accepted aliases including Pratipada, Shashti, and Amavasya.", "Convert to an ordinal from 1 through 15.", "Map 1/6/11 Nanda, 2/7/12 Bhadra, 3/8/13 Jaya, 4/9/14 Rikta, and 5/10/15 Purna.", "Let the selected activity profile decide whether that family is preferred, penalized, neutralized, or excluded."],
        "formulae": [{"name": "Fivefold family index", "expression": "family_index = (t-1) mod 5", "variables": ["t: Paksha-local Tithi ordinal 1 through 15", "family order: Nanda, Bhadra, Jaya, Rikta, Purna"]}],
        "worked_examples": [{"label": "Shukla Navami", "inputs": ["Final token: Navami", "Tithi ordinal: 9"], "calculation": ["(9 - 1) mod 5 = 3.", "Family index 3 maps to Rikta."], "result": ["Family: Rikta", "Rikta flag: true"]}],
        "notes": ["The family mapping is stable across Shukla and Krishna Paksha; activity suitability is not inferred here."]
      }
    },
    {
      "id": "panchangam.graha-maudhya",
      "title": "Daily Guru and Shukra Maudhya",
      "summary": "Shortest-arc Sun-planet elongation is compared with configured combustion thresholds.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/gochara/combustion.py", "symbol": "compute_maudhya", "role": "owner"}
      ],
      "inputs": ["graha", "solar longitude", "planetary longitude"],
      "outputs": ["elongation", "threshold", "combust boolean"],
      "time_basis": "Drik snapshot at local sunrise.",
      "method": {
        "kind": "formula",
        "summary": "Compute the absolute shortest angular separation between the Sun and Guru or Shukra and compare it with the maintained strict combustion threshold.",
        "steps": ["Select threshold 11 degrees for Guru or 10 degrees for Shukra.", "Normalize planet-Sun difference onto the signed shortest arc and take its absolute value in 0-180 degrees.", "Set combust=true only when separation is strictly less than the threshold.", "Return graha, separation, flag, and threshold."],
        "formulae": [{"name": "Shortest-arc combustion", "expression": "d = abs((planet - sun + 180) mod 360 - 180)\ncombust = d < threshold[graha]", "variables": ["d: shortest angular separation", "threshold: Guru 11 degrees; Shukra 10 degrees"]}],
        "worked_examples": [{"label": "Illustrative Guru conjunction", "inputs": ["Sun longitude: 100 degrees", "Guru longitude: 109 degrees", "Guru threshold: 11 degrees"], "calculation": ["d=abs((109-100+180) modulo 360 - 180)=9 degrees.", "9 < 11."], "result": ["elongation_deg=9; combust=true; threshold_deg=11"]}],
        "notes": ["Equality is not combust because comparison is strict.", "Surya Siddhanta and Vakya do not populate outer-planet Maudhya fields."]
      },
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["astronomical", "textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Numerical behavior is tested; exact threshold locators remain under derived-classification debt."},
      "tests": ["tests/test_maudhya.py"],
      "limitations": ["Only Drik populates outer-planet Maudhya in PanchangamDay."]
    },
    {
      "id": "panchangam.simha-stha",
      "title": "Simha-stha Guru and Shukra",
      "summary": "Jupiter or Venus in Simha is flagged for activity-specific restrictions.",
      "owning_layer": "derived",
      "claim_kind": "textual-rule",
      "implementations": [
        {"path": "telugu_panchangam/gochara/simha_stha.py", "symbol": "is_simha_stha", "role": "owner"}
      ],
      "inputs": ["Guru or Shukra Rashi"],
      "outputs": ["Simha-stha boolean"],
      "time_basis": "Drik snapshot at local sunrise.",
      "method": {
        "kind": "decision-table",
        "summary": "Return true exactly when the already-computed Guru or Shukra Rashi name is Simha.",
        "steps": ["Receive the planetary Rashi name or null from the upstream longitude-to-Rashi computation.", "Compare it for exact equality with Simha.", "Return the Boolean result without applying strength, dignity, aspect, or time-window logic."],
        "worked_examples": [{"label": "Exact-name classification", "inputs": ["Guru Rashi: Simha", "Shukra Rashi: Karka"], "calculation": ["Simha equals Simha, so Guru passes.", "Karka does not equal Simha, so Shukra fails."], "result": ["simha_stha_guru=true", "simha_stha_shukra=false"]}],
        "notes": ["The function classifies an upstream sign result; it does not calculate planetary longitude.", "Surya Siddhanta and Vakya leave these flags at model defaults."]
      },
      "surfaces": ["python-library", "mcp", "website"],
      "provenance": {"evidence_classes": ["textual"], "verification_states": ["needs_locator"], "claim_ids": ["panchangam.derived_classifications"], "note": "Flag behavior is tested; exact scope and source locator remain open."},
      "tests": ["tests/test_simha_stha.py"],
      "limitations": ["Only Drik models the required planets; activity consequences are profile-specific."]
    }
  ]
}
