- Shipped
- September 23, 2026 at 8:21 AM UTC
- Author
- Kamo
- Commit
- f59df8f
An audio slide's navigation lives in media_meta_json (duration, waveform peaks, chapters), which the editor writes and the player reads back verbatim. It is saved (bounded to 256K and to a JSON object, and kept only while the slide has media), duplicated, frozen at publish and served on the player DTO. Publish also writes media_duration_ms from it — declared on the version from the start and never written — and the course estimate counts an audio lesson's real length. The fingerprint hashes an AUDIO slide's transcript and metadata, so correcting a transcript line or moving a chapter is a publishable change. Every other slide hashes exactly as before: widening the hash to all slides would have turned every published course with a video transcript "unpublished" the day this shipped. GET **************** serves a slide's (or a question's) media with Range support, authorized by the member's own assignment: the file must be in the version they were assigned, in HR Resources, in their organization, live and untrashed. The imaging stream it replaces for learners needs VIEW_DOCUMENTS, which 32 of the 149 members holding any right did not have — every one of them met a dead player. Because a learner is authorized by the file's presence in a course, saving a unit now refuses a file its author cannot open (422 naming the slide or question), and attaching any file at all needs VIEW_DOCUMENTS, the right the imaging stream itself demands; publishing re-runs both checks over the whole course, so a draft saved earlier or by a co-author is held to the same rule. Otherwise MANAGE_TRAINING alone could publish a file its holder cannot read into a course and assign it to themselves. The learner path also only ever serves a picture, a video or a recording — never a document a crafted save named. HR Resources is also narrower than every other byte rule (issued packages are SERVICE_APPLICATION, per-party documents LOAN or ACCOUNT_MEMBER_VAULT, and chat/voicemail/call media have their own collections). Reads are audited like /imaging/stream, and the Range answer is one shared helper (ImgRangeResponses) that /imaging/stream now uses too. Publish refuses an audio slide without a description in audio's own words. Needs kamo-shared-library "feat(imaging,training): audio uploads pass the MIME check, and slides carry media metadata" (media_meta_json on both slide entities; the DDL is applied).
