Pure mapping from a LightningStep episode's admissions to ProgramStayInput[].
Shared by the per-episode forward sync (LightningStepAdapter.fetchEpisodeProgramStays) and the
backfill (which groups admissions by episode_id). One stay per admission (LS admissions ARE the
program changes); external_id is the LS admission id; program_external_id is program_id; LOC is
always null (LS has no level of care).
Time-of-day + half-open chaining (mirrors the Kipu chain): start_date uses timeadmission (falling
back to "00:00:00" when absent/empty); stays are sorted by start; each intermediate stay's
end_date is the NEXT stay's start_date; the last stay's end_date uses timedischarge (falling back
to "23:59:59"). Admissions whose dateadmission fails to normalize are silently dropped
(start_date is NOT NULL on program_stays).
Pure mapping from a LightningStep episode's admissions to ProgramStayInput[]. Shared by the per-episode forward sync (LightningStepAdapter.fetchEpisodeProgramStays) and the backfill (which groups admissions by episode_id). One stay per admission (LS admissions ARE the program changes); external_id is the LS admission id; program_external_id is program_id; LOC is always null (LS has no level of care).
Time-of-day + half-open chaining (mirrors the Kipu chain): start_date uses timeadmission (falling back to "00:00:00" when absent/empty); stays are sorted by start; each intermediate stay's end_date is the NEXT stay's start_date; the last stay's end_date uses timedischarge (falling back to "23:59:59"). Admissions whose dateadmission fails to normalize are silently dropped (start_date is NOT NULL on program_stays).