GET /api/v1/videos/{video_id}/transcript — transcript text plus source provenance.
GET /api/v1/videos/{video_id}/summary — summary text, highlights, takeaways, and AI provenance.
Status contract, honest per ADR-010 (degrade-never-error):
no_transcript is a terminal success, not an error. GET /transcript returns 200 with empty text and source: "none", so a caller stops polling instead of retrying forever.
rate_limited is non-terminal — a per-user retry state (ADR-014), never a shared terminal one. Include a retry_after hint.
GET /summary before ready → 409 with the current status in the body, so the caller knows to keep polling rather than treating it as missing.
All reads are user-scoped through RLS. A caller must never read another user's video.
Non-goals
Webhooks / push. Polling only for now; revisit if the poll loop proves painful in practice.
Re-analysis with a different model (the shared transcript table already makes this cheap — separate issue when there's a caller for it).
Acceptance
caveman: me return this user's transcript, not another user's transcript
Red-first tests per endpoint and per status value
no_transcript returns 200, not 404 — explicit test
rate_limited is never persisted as terminal — explicit test
RLS test: token for user A cannot read user B's video, and gets 404 rather than 403 (no existence leak)
A submit-then-poll-to-terminal round trip covered end to end in test/acceptance
Handoff
Branch from main, one file per commit, squash-merge PR back to main, human review gate.
## Problem
Submission (#24) is useless without a way to read the result back. A caller needs to poll to a terminal state and then pull the transcript or summary.
Depends on #23, #24.
## Scope
`GET /api/v1/videos/{video_id}` — status envelope:
```json
{ "video_id": "...", "title": "...", "status": "queued|transcribing|summarizing|ready|no_transcript|rate_limited|failed", "updated_at": "..." }
```
`GET /api/v1/videos/{video_id}/transcript` — transcript text plus source provenance.
`GET /api/v1/videos/{video_id}/summary` — summary text, highlights, takeaways, and AI provenance.
Status contract, honest per ADR-010 (degrade-never-error):
- `no_transcript` is a **terminal success**, not an error. `GET /transcript` returns `200` with empty text and `source: "none"`, so a caller stops polling instead of retrying forever.
- `rate_limited` is **non-terminal** — a per-user retry state (ADR-014), never a shared terminal one. Include a `retry_after` hint.
- `GET /summary` before `ready` → `409` with the current status in the body, so the caller knows to keep polling rather than treating it as missing.
All reads are user-scoped through RLS. A caller must never read another user's video.
## Non-goals
- Webhooks / push. Polling only for now; revisit if the poll loop proves painful in practice.
- Re-analysis with a different model (the shared transcript table already makes this cheap — separate issue when there's a caller for it).
## Acceptance
- [ ] `caveman: me return this user's transcript, not another user's transcript`
- [ ] Red-first tests per endpoint and per status value
- [ ] `no_transcript` returns 200, not 404 — explicit test
- [ ] `rate_limited` is never persisted as terminal — explicit test
- [ ] RLS test: token for user A cannot read user B's video, and gets 404 rather than 403 (no existence leak)
- [ ] A submit-then-poll-to-terminal round trip covered end to end in `test/acceptance`
## Handoff
Branch from `main`, one file per commit, squash-merge PR back to `main`, human review gate.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Submission (#24) is useless without a way to read the result back. A caller needs to poll to a terminal state and then pull the transcript or summary.
Depends on #23, #24.
Scope
GET /api/v1/videos/{video_id}— status envelope:GET /api/v1/videos/{video_id}/transcript— transcript text plus source provenance.GET /api/v1/videos/{video_id}/summary— summary text, highlights, takeaways, and AI provenance.Status contract, honest per ADR-010 (degrade-never-error):
no_transcriptis a terminal success, not an error.GET /transcriptreturns200with empty text andsource: "none", so a caller stops polling instead of retrying forever.rate_limitedis non-terminal — a per-user retry state (ADR-014), never a shared terminal one. Include aretry_afterhint.GET /summarybeforeready→409with the current status in the body, so the caller knows to keep polling rather than treating it as missing.All reads are user-scoped through RLS. A caller must never read another user's video.
Non-goals
Acceptance
caveman: me return this user's transcript, not another user's transcriptno_transcriptreturns 200, not 404 — explicit testrate_limitedis never persisted as terminal — explicit testtest/acceptanceHandoff
Branch from
main, one file per commit, squash-merge PR back tomain, human review gate.