Compare commits

..

4 Commits

Author SHA1 Message Date
Dean Wenstrand
eb5217e070 Add DrillResultGQL + drillResult on VideoCardFields
Session card drill outcome: longest run + owner's personal-best rank
(1/2/3 medal) among their sessions on the same drill + table/pocket setup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 10:48:21 -07:00
bfaed33c89 Merge pull request 'feed: select uploadCompletionCursor on VideoCardFields stream' (#296) from dean/feed-upload-completion-cursor into master
Reviewed-on: #296
2026-07-14 18:24:54 +00:00
Dean Wenstrand
1ce3aaed1b feed: select uploadCompletionCursor on VideoCardFields stream
All checks were successful
Tests / Tests (pull_request) Successful in 24s
Lets the client distinguish a finalized-but-not-fully-uploaded stream
(is_completed set, but received cursor short of last_intended_segment_bound)
from one that is genuinely processing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:15:41 -07:00
1bd03f2bbe Merge pull request 'dean/unify-shotlab-cohorts' (#295) from dean/unify-shotlab-cohorts into master
Reviewed-on: #295
2026-07-13 01:08:48 +00:00
3 changed files with 79 additions and 0 deletions

View File

@@ -393,6 +393,16 @@ export type DoesNotOwnShotErrOtherErrorNeedsNote =
| DoesNotOwnShotErr | DoesNotOwnShotErr
| OtherErrorNeedsNote; | OtherErrorNeedsNote;
export type DrillResultGql = {
__typename?: "DrillResultGQL";
attemptCount: Scalars["Int"]["output"];
drillTag: Scalars["String"]["output"];
isPersonalBest: Scalars["Boolean"]["output"];
longestRun: Scalars["Int"]["output"];
longestRunId?: Maybe<Scalars["Int"]["output"]>;
prRank: Scalars["Int"]["output"];
};
export type DrillRunLeaderboardGql = { export type DrillRunLeaderboardGql = {
__typename?: "DrillRunLeaderboardGQL"; __typename?: "DrillRunLeaderboardGQL";
entries: Array<RunGql>; entries: Array<RunGql>;
@@ -4155,6 +4165,7 @@ export type VideoGql = {
createdAt?: Maybe<Scalars["DateTime"]["output"]>; createdAt?: Maybe<Scalars["DateTime"]["output"]>;
currentHomography?: Maybe<HomographyInfoGql>; currentHomography?: Maybe<HomographyInfoGql>;
currentProcessing?: Maybe<VideoProcessingGql>; currentProcessing?: Maybe<VideoProcessingGql>;
drillResult?: Maybe<DrillResultGql>;
elapsedTime?: Maybe<Scalars["Float"]["output"]>; elapsedTime?: Maybe<Scalars["Float"]["output"]>;
endTime?: Maybe<Scalars["DateTime"]["output"]>; endTime?: Maybe<Scalars["DateTime"]["output"]>;
framesPerSecond: Scalars["Float"]["output"]; framesPerSecond: Scalars["Float"]["output"];
@@ -4784,6 +4795,7 @@ export type GetFeedQuery = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
uploadCompletionCursor: number;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
isCompleted: boolean; isCompleted: boolean;
lastSegmentUploadedAt?: any | null; lastSegmentUploadedAt?: any | null;
@@ -4794,6 +4806,15 @@ export type GetFeedQuery = {
name: string; name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>; tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>; }>;
drillResult?: {
__typename?: "DrillResultGQL";
drillTag: string;
longestRun: number;
longestRunId?: number | null;
prRank: number;
isPersonalBest: boolean;
attemptCount: number;
} | null;
playerSummaries: Array<{ playerSummaries: Array<{
__typename?: "PlayerSummaryGQL"; __typename?: "PlayerSummaryGQL";
clusterId: number; clusterId: number;
@@ -4898,6 +4919,7 @@ export type VideoCardFieldsFragment = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
uploadCompletionCursor: number;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
isCompleted: boolean; isCompleted: boolean;
lastSegmentUploadedAt?: any | null; lastSegmentUploadedAt?: any | null;
@@ -4908,6 +4930,15 @@ export type VideoCardFieldsFragment = {
name: string; name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>; tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>; }>;
drillResult?: {
__typename?: "DrillResultGQL";
drillTag: string;
longestRun: number;
longestRunId?: number | null;
prRank: number;
isPersonalBest: boolean;
attemptCount: number;
} | null;
playerSummaries: Array<{ playerSummaries: Array<{
__typename?: "PlayerSummaryGQL"; __typename?: "PlayerSummaryGQL";
clusterId: number; clusterId: number;
@@ -5045,6 +5076,7 @@ export type GetVideoFeedQuery = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
uploadCompletionCursor: number;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
isCompleted: boolean; isCompleted: boolean;
lastSegmentUploadedAt?: any | null; lastSegmentUploadedAt?: any | null;
@@ -5055,6 +5087,15 @@ export type GetVideoFeedQuery = {
name: string; name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>; tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>; }>;
drillResult?: {
__typename?: "DrillResultGQL";
drillTag: string;
longestRun: number;
longestRunId?: number | null;
prRank: number;
isPersonalBest: boolean;
attemptCount: number;
} | null;
playerSummaries: Array<{ playerSummaries: Array<{
__typename?: "PlayerSummaryGQL"; __typename?: "PlayerSummaryGQL";
clusterId: number; clusterId: number;
@@ -8193,6 +8234,7 @@ export type GetVideoCardQuery = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
uploadCompletionCursor: number;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
isCompleted: boolean; isCompleted: boolean;
lastSegmentUploadedAt?: any | null; lastSegmentUploadedAt?: any | null;
@@ -8203,6 +8245,15 @@ export type GetVideoCardQuery = {
name: string; name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>; tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>; }>;
drillResult?: {
__typename?: "DrillResultGQL";
drillTag: string;
longestRun: number;
longestRunId?: number | null;
prRank: number;
isPersonalBest: boolean;
attemptCount: number;
} | null;
playerSummaries: Array<{ playerSummaries: Array<{
__typename?: "PlayerSummaryGQL"; __typename?: "PlayerSummaryGQL";
clusterId: number; clusterId: number;
@@ -9020,6 +9071,7 @@ export const VideoCardFieldsFragmentDoc = gql`
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor
streamSegmentType streamSegmentType
isCompleted isCompleted
lastSegmentUploadedAt lastSegmentUploadedAt
@@ -9033,6 +9085,14 @@ export const VideoCardFieldsFragmentDoc = gql`
name name
} }
} }
drillResult {
drillTag
longestRun
longestRunId
prRank
isPersonalBest
attemptCount
}
playerSummaries { playerSummaries {
...PlayerSummaryFields ...PlayerSummaryFields
} }

View File

@@ -41,6 +41,7 @@ fragment VideoCardFields on VideoGQL {
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor
streamSegmentType streamSegmentType
isCompleted isCompleted
lastSegmentUploadedAt lastSegmentUploadedAt
@@ -54,6 +55,14 @@ fragment VideoCardFields on VideoGQL {
name name
} }
} }
drillResult {
drillTag
longestRun
longestRunId
prRank
isPersonalBest
attemptCount
}
playerSummaries { playerSummaries {
...PlayerSummaryFields ...PlayerSummaryFields
} }

View File

@@ -438,6 +438,7 @@ type VideoGQL {
reactions: [ReactionGQL!]! reactions: [ReactionGQL!]!
comments: [CommentGQL!]! comments: [CommentGQL!]!
playerSummaries: [PlayerSummaryGQL!]! playerSummaries: [PlayerSummaryGQL!]!
drillResult: DrillResultGQL
} }
type ShotGQL { type ShotGQL {
@@ -721,6 +722,15 @@ type SpinTypeBreakdownGQL {
follow: Int! follow: Int!
} }
type DrillResultGQL {
drillTag: String!
longestRun: Int!
longestRunId: Int
prRank: Int!
isPersonalBest: Boolean!
attemptCount: Int!
}
type DeployedConfigGQL { type DeployedConfigGQL {
allowNewUsers: Boolean! allowNewUsers: Boolean!
firebase: Boolean! firebase: Boolean!