draft-vods: statedb model + CBOR storage for draft VODs master
New pkg/statedb/draft_video.go: DraftVideo GORM model storing a draft VOD as permissioned-data-style record (CBOR body + denormalized query columns). - Model: URI (ats://, primaryKey), UserDID, Data (CBOR bytes), CID (sha256-of-CBOR CIDv1 via spid.GetCIDFromBytes), ContentCID + OriginUploadID (server-internal, not in the CBOR body). Explicit TableName() override matching Upload's pattern. Registered in StatefulDBModels. - ats:// URI: ats://{did}/place.stream.vod.drafts/self/{did}/ place.stream.vod.draftVideo/{tid} — personal space (spaceDid==authorDid, skey=self), spaceType as NSID string only (no space lexicon). - CBOR marshal/unmarshal of the generated VodDraftVideo struct via its whyrusleeping/cbor-gen MarshalCBOR/UnmarshalCBOR methods directly; CID recomputed on every write. - CRUD: CreateDraft, GetDraft, GetDraftByUpload, ListDrafts (time-cursor paginated, ownership-scoped), UpdateDraftMetadata (editable fields only, preserves source/durationMs/status), SetDraftReady (fills source/ durationMs + content_cid, status ready), SetDraftError (status error), DeleteDraft. SetDraft* are no-ops when no draft row exists for the upload (pre-drafts-era uploads, deleted drafts). Tests (draft_video_test.go): CRUD round-trip + CBOR fidelity, CID recomputed on metadata update, status preserved across metadata update, ownership scoping in ListDrafts, ready/error lifecycle, no-op on missing upload. All pass on sqlite. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>