Compare commits

..

13 Commits

Author SHA1 Message Date
a05614e4d1 Add Session Coach generation operations
All checks were successful
Tests / Tests (pull_request) Successful in 44s
2026-07-21 13:41:24 -07:00
Dean Wenstrand
9ec52d9d94 Regenerate schema for leaderboard taxonomy filters
All checks were successful
Tests / Tests (pull_request) Successful in 11s
Adds the optional taxonomy args to getLongestRunsLeaderboard and
getMakesLeaderboard (gameType, rankedOnly, excludeDrills, and
table/pocket size bounds) generated from the backend resolvers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:19:39 -07:00
650b3bc13c Regenerate schema with upstream Strawberry
All checks were successful
Tests / Tests (pull_request) Successful in 11s
2026-07-20 14:46:00 -07:00
feeb5b7038 Add HomographyBackendGQL enum and VideoMetadataInput.homographyBackend
All checks were successful
Tests / Tests (pull_request) Successful in 11s
Regenerated from backend Python: adds the HomographyBackendGQL enum
(CLASSIC/TABLENET) and the optional homographyBackend field on
VideoMetadataInput, for per-video homography backend selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 18:26:53 -07:00
3340314166 Merge pull request 'Add per-session Coach GraphQL contract' (#297) from loewy/session-coach-v1 into master
Reviewed-on: #297
2026-07-17 18:33:58 +00:00
6b8fdd4262 Add per-session Coach GraphQL contract
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-07-16 16:45:55 -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
Dean Wenstrand
4a1c41aae1 Regenerate schema and hooks from backend master
All checks were successful
Tests / Tests (pull_request) Successful in 12s
Union of the cohort funnel, Shot Lab picker queries, and transient
homography IDs — converges the three divergent submodule pointers
(gql master, railbird master, railbird-mobile master).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:03:33 -07:00
Dean Wenstrand
4122284bbd Merge Shot Lab queries with cohort funnel 2026-07-12 17:59:33 -07:00
b30dbd01f5 Fetch shot paths and features for the Shot Lab picker
All checks were successful
Tests / Tests (pull_request) Successful in 11s
The recorded-shot picker now renders per-shot table diagrams, so
GetRecordedStreamShots needs serializedShotPaths plus the pocketing and
cue-object features that PlaneShotDiagram consumes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:13:17 -07:00
303261f2d7 Add recorded Shot Lab queries 2026-07-11 20:56:47 -07:00
6 changed files with 2829 additions and 1550 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -41,6 +41,7 @@ fragment VideoCardFields on VideoGQL {
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor
streamSegmentType streamSegmentType
isCompleted isCompleted
lastSegmentUploadedAt lastSegmentUploadedAt

View File

@@ -0,0 +1,62 @@
# Lightweight two-step picker data for loading a recorded shot into Shot Lab.
query GetRecordedStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
createdAt
screenshotUri
framesPerSecond
totalShots
owner {
id
username
profileImageUri
}
}
}
}
query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {
getOrderedShots(
filterInput: { videoId: [$videoId] }
shotsOrdering: { orderings: [{ startFrame: { descending: false } }] }
limit: $limit
) {
shots {
id
videoId
startFrame
endFrame
serializedShotPaths {
b64EncodedBuffer
}
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures {
make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
}
pocketingIntentionInfo {
ballId
pocketId
pathMetadataIndex
}
}
}
}

View File

@@ -0,0 +1,99 @@
query GetSessionCoach($videoId: Int!) {
getSessionCoach(videoId: $videoId) {
videoId
processingId
analysisVersion
state
generatedAt
processingStatus
ineligibilityReason
summary
shotCount
madeCount
missedCount
unknownOutcomeCount
analyzedShotCount
makePercentage
primaryCandidate {
...SessionCoachCandidateFields
}
candidates {
...SessionCoachCandidateFields
}
agentGeneration {
...SessionCoachGenerationFields
}
}
}
mutation RequestSessionCoachGeneration($videoId: Int!) {
requestSessionCoachGeneration(videoId: $videoId) {
state
agentGeneration {
...SessionCoachGenerationFields
}
}
}
fragment SessionCoachCandidateFields on SessionCoachCandidateGQL {
id
rank
family
kind
title
body
action
supportingShotIds
drillId
limitations
evidence {
bucketKey
bucketLabel
attemptCount
madeCount
missedCount
makePercentage
comparisonAttemptCount
comparisonMadeCount
comparisonMakePercentage
patternShotCount
score
rankReason
}
}
fragment SessionCoachGenerationFields on SessionCoachGenerationGQL {
id
state
createdAt
completedAt
decision {
selectedCandidateId
title
body
suggestedAction
drillId
drillReason
practiceAttemptCount
practiceTarget
}
diagnostics {
analysisVersion
promptVersion
providerKey
modelName
inputHash
attemptCount
maxAttempts
enqueueCount
latencyMs
inputTokens
cachedInputTokens
outputTokens
failureCode
updatedAt
startedAt
lastEnqueuedAt
abstentionReason
}
}

View File

@@ -24,8 +24,19 @@ query GetLiveTableState($videoId: Int!) {
identifierToColor { identifierToColor {
hex hex
} }
homography { }
...HomographyInfo }
}
query GetShotTableState($shotId: Int!) {
getShotTableState(shotId: $shotId) {
shotId
videoId
frameIndex
tableState {
identifierToPosition
identifierToColor {
hex
} }
} }
} }

File diff suppressed because it is too large Load Diff