How it works (for the nerds).
The other pages explain a method. This one is the tour of the machine — every stage a swing passes through, from a BLE packet and a Bayer mosaic to a ranked cause with a drill attached. If you want to know what the software actually does between the strike and the sentence on screen, this is the page.
Everything described here is implemented and running — this is a description of the code, not a roadmap. What it is not yet is signed off: the numbers the pipeline produces are still being measured against a hand-annotated corpus before anything is called dependable. Where a stage is dark, gated or unproven, this page says so. See how we earn the numbers →
Two spines, one clock
There are only two kinds of evidence in the building: orientation, from sensors strapped to the body, and pixels, from cameras pointed at it. Each is a state trajectory in time, each climbs its own ladder from raw bytes to a coachable number, and they meet because they were stamped against the same microsecond clock from the very first byte.
- A
The inertial spine
BLE frame → raw accelerometer + gyroscope → on-host orientation filter → anatomical frame → a fixed-rate resampled grid → joint angles. A quaternion, all the way down.
- B
The optical spine
Sensor frame → pose keypoints → smoothed tracks → a grip-anchored shaft angle → image-plane landmarks. A pixel coordinate, all the way down.
- C
Degradation is the design
Each spine is self-sufficient. Sensors but no camera still scores a swing; a camera but no sensors still scores a swing. The fused case is their union, never a dependency chain — device presence is data the pipeline reads, not a branch someone wrote.
Analysis runs as a list of capability-gated stages over one typed context — twenty-odd of them in authored order, each with an off switch and a reason it skipped. Every permutation of hardware takes exactly one code path, and every new idea lands as one more stage rather than another branch inside a function nobody dares touch.
Illustrative — two independent ladders converging on one shared timebase.
Four transports, one contract
A Bluetooth sensor, a USB3 machine-vision camera, a microphone and a phone over the network have nothing in common physically. They have everything in common structurally: each is a source that registers with the central buffer, writes raw bytes into its own ring, and deregisters when the user lets it go.
- BLE
Bluetooth sensors
Wrist and torso IMUs over Qt Bluetooth LE. Scanning is asynchronous and continuous; a device appears in the list the moment it is discovered, and connecting is what constructs the instance that registers a source.
- CAM
Cameras
Four backends behind one interface — UVC webcams, Aravis (GenICam), Spinnaker (Teledyne / FLIR) and AVFoundation on macOS. One shared view component publishes each camera's frames to every subscriber, so the same feed can appear on several screens at once.
- MIC
Microphone
One active input, feeding two independent consumers: local speech-to-text, and an onset detector listening for the click of impact. The two are gated separately — you can have acoustic shot detection with the voice interface off.
- PPCP
Phone
A paired phone joins the session as just another camera. Its streams appear in the device list beside the USB and industrial ones, and the rest of the pipeline cannot tell the difference.
Enumerated → Selected → Recording → Deselected. Every device walks the same four stages, and the invariants are hard: nothing registers at startup, registration happens exactly once inside selection, and the buffer is paused around every register and deregister so the merge thread can never read a half-built or already-freed source. Adding a force plate is filling in this contract, not extending it.
Illustrative — heterogeneous devices, one registration contract.
What's actually in the bay
The abstraction above is real, but the devices underneath it each have a personality — and most of the awkward engineering in this project is a consequence of one of them.
- 1
WitMotion WT901BLE67
A six-axis BLE IMU: accelerometer and gyroscope at 10–200 Hz, 100 Hz by default. Its on-board fused orientation is deliberately discarded — measured against real motion, its joint axes came out 15–50° off and it gimbals near ±90° pitch, while its raw inertials are faithful to a fifth of a degree. We re-derive orientation on the host instead, with a selectable Madgwick or ESKF filter.
- 2
HackMotion wG3
A wrist instrument carrying two sensing units in one strap — lower arm and palm — so a single device fills both wrist slots. It exists in the pipeline as a criterion instrument: two independently-fusing six-axis sensors cannot agree on heading, and the error lands exactly on the bow/cup versus hinge split. Measured, its relative angle held to 0.58° over five minutes while its two units individually drifted 1.95° and 1.13°. It is also the device that forced the delayed-fetch work below.
- 3
Teledyne FLIR (Chameleon3)
USB3 Vision / GenICam, global shutter — no rolling-shutter skew on a club moving past 100 mph — and no compressed output at all: Mono8, Mono12, Bayer, YUV. Raw Bayer bytes are kept off the CPU hot path entirely; a GPU shader demosaics for display at screen rate while the pose estimator gets a properly demosaiced frame at its own, slower rate.
- 4
The phone, over PPCP
The PinPoint Capture Protocol: TLS 1.3 with an external pre-shared key, no unencrypted mode, carried either over WiFi (the phone dials the host) or over a USB cable (the host dials the phone through Apple's usbmux tunnel). Pairing is a QR code; discovery afterwards is DNS-SD. Every optional part degrades to absent, never broken — no discovery still leaves pairing working, no usbmux just means the cable is never offered.
- 5
The launch monitor that thinks it's GSPro
Almost no monitor speaks the Open Connect protocol itself — somebody wrote a bridge that speaks it on the device's behalf, and there are five for the Garmin R10 alone. PinPoint plays the server those bridges dial into, so one connector reaches an R10, an MLM2PRO, a SkyTrak+ or a PiTrac with no per-device work — and reaches none of Uneekor, Bushnell or Foresight's own software, which ship no Open Connect client at all. Note which way the club travels: the shot message has no club field, because in this protocol the simulator is what tells the device what's in play. It lives in libgspro, a sans-I/O MIT library that owns no socket, thread or clock — 115 socket-free tests and 23 byte-exact fixtures transcribed from sixteen real clients' source, and not one capture off a wire, because nothing here has met a device on a mat yet.
Illustrative — cameras, wrist and torso sensors, a phone and a mic.
From a strap angle to an anatomy
A sensor knows its own orientation in the world. It knows nothing about the arm it is taped to. Calibration is the step that turns one into the other, and it is a single composition applied everywhere: q_anat = A · q_raw · M.
- M
The mount
A constant per strap convention — how the sensor body sits on the limb. For a dorsal hand mount it is solved numerically rather than assumed; for arm segments it is a fixed convention.
- A
The reference pose
Solved per session, so the anatomical frame is identity at a pose the golfer actually held. The wizard captures two: arm at rest, then a T-pose, each requiring three cumulative seconds of stillness before it is accepted.
- Δ
Joints are relative
Running six-axis with no magnetometer means yaw is unobservable and drifts. It cancels: a joint angle is the relative rotation between two segments, so a drift shared by both sensors disappears in the subtraction. That is why two-sensor wrist angles work at all.
- !
What it costs
The cancellation is not perfect. Roughly 10–15° of cross-talk remains between flexion/extension and radial/ulnar deviation, because the heading the two sensors disagree on lands squarely on that split. It is documented in the header of the file that computes it, and it is why a criterion instrument matters.
Orientation is stored and computed as quaternions, never Euler angles — Euler exists only as a label on a screen. The stored sample keeps accelerometer, gyroscope and quaternion all in the one raw sensor frame, so nothing downstream has to guess which frame a field is in.
Illustrative — the mount, the reference pose, and why joints beat segments.
Four questions, and a golf ball
Camera calibration is not one thing. It answers four separate questions, and an operator may only need some of them — but one of the four is a precondition for the other three.
- 1
Focus first, or none of it counts
A solve computed from soft corners returns small residuals and large errors, and nothing in the arithmetic tells you. So focus sits inside calibration rather than beside it in a settings panel — and it is handled by what the camera can do (read the lens position, lock it, or nothing at all), never by which driver it happens to use.
- 2
Scale, distortion, pose
Millimetres per pixel at the hitting plane; whether a straight line is straight; where this camera sits relative to the ball and the other cameras. Clubhead speed needs the first, shaft angle away from frame centre needs the second, anything 3D needs the third.
- 3
A tier ladder, declared per swing
From nothing at all, through factory intrinsics, through a known-size object, to a printed ChArUco board and finally board-derived extrinsics. Every swing records the tier it was captured under, and a metric that needs scale reads that and refuses rather than producing a number in fictional millimetres.
- 4
The ball is the best reference in the building
A golf ball is 42.67 mm, spherical (so its projected diameter is independent of orientation), high-contrast against a mat, at exactly the plane that matters — and present in every single shot. That makes it both a calibration reference for an operator with no board and a permanent, free verifier: if its diameter in pixels drifts while the bay is nominally unchanged, something moved.
Every calibration record carries a mandatory uncertainty. A calibration without an error bar cannot be verified, cannot be compared to a later one, and cannot tell a metric whether to trust it. A ball ~40 px across measured to ±1 px is ±2.5 % scale — that is a real number, and it is carried rather than rounded away.
Illustrative — what an operator gets with what they own.
Always recording, never allocating
A swing you didn't know was coming has to be already in memory when you find out. So the app records continuously into pre-allocated rings and simply stops throwing the last few seconds away when a shot fires.
- 1
One ring per source, sized once
A fixed window per source, allocated at registration and never again — no allocation on the hot path, ever. Slot counts are powers of two: 60 fps over five seconds is 300 frames, which rounds to 512. Two 1080p60 mono cameras plus three sensors is around 2 GB of RAM, deliberately spent.
- 2
Lock-free, single producer
Each capture thread is the only writer to its own ring; slots are framed by generation counters so a reader can tell it was overtaken mid-read and retry. Consumers track sequence numbers, so an overrun is detected rather than silently papered over. Drop-oldest, never backpressure — a slow consumer must never stall a camera.
- 3
Raw bytes, described not interpreted
The buffer stores exactly what the device delivered — a Bayer mosaic stays a Bayer mosaic — alongside a format descriptor. Nothing in the buffer knows what a golf swing is.
- 4
A shot freezes a window
On a shot the rings keep filling through a short post-roll so the follow-through lands inside, then pause. The trailing window is frozen as an immutable object that analysis and export both read zero-copy and const. Two runs over the same frozen window are byte-identical — which is exactly what makes corpus-scale regression testing a plain diff.
Illustrative — the ring is always turning; a shot decides what to keep.
Everything arrives late, differently
A camera frame, a Bluetooth packet and an audio buffer describing the same instant arrive at different times, each delayed by its own capture chain. Aligning them is the linchpin of the whole design — get it wrong and every metric is quietly measured against the wrong moment.
- 1
One clock, read at first touch
Every timestamp in the app comes from a single shared monotonic clock — never wall time, never a per-device clock — and reading it is the first executable statement in every device callback. Where a device supplies its own hardware timestamp it is anchored to that clock at the first packet and re-anchored periodically through a low-pass filter to stop drift.
- 2
The buffer never compensates
Latency is deliberately not corrected inside the buffer. Sources are stamped at arrival, honestly; each detector back-dates by its own known latency when it makes a claim. One place to be wrong is better than four.
- 3
Three detectors, one arbiter
The sensor sees a shock, the mic hears a click, the ball's response in the hitting area collapses off a cliff. Each back-dates and reports a candidate; the first opens a 200 ms hold window; at the deadline the arbiter commits once — when two distinct modalities agree, or one is decisively strong. Two acoustic onsets are one voice, not two.
- 4
Audio pinpoints, the rest confirm
When modalities agree their estimates differ by a few milliseconds, so the committed timestamp comes from the highest-authority one — acoustic before inertial before vision — because audio is sample-accurate with stable latency while the others are coarse. That instant is written into the buffer as a marker before anything downstream is told a shot happened.
- 5
And the phone, which has its own clock entirely
A phone's clock shares no origin with the host's. PPCP runs a sync estimator that publishes an offset and its sigma. Measured on an iPhone: offset σ 1.16 ms over WiFi, 0.34 ms and 3.3 ppm skew over the cable. The estimator refuses to claim better than half the minimum round-trip time, so the number is floored by physics rather than optimism.
Illustrative — three arrivals, one committed instant.
Some data arrives afterwards
Every source described so far is a live producer: by the time the window freezes, everything that will ever exist for that shot is already in the ring. One class of device breaks that assumption entirely — it holds the real record internally and will only hand it over if you ask, after the fact.
- 1
Arrival time carries no information
A deferred source's samples land thousands at a time, in no relation to when they were measured. They must carry their own host-clock timestamps or they cannot be placed on the swing timeline at all — which is the whole reason the clock work above has to be exact.
- 2
The window is still built once, and still const
Nothing became mutable. What changed is that "delivered" is no longer simultaneous with "frozen": the rings freeze on time, the pipeline enters a short gathering state, and the window is constructed once the deferred sources have reported or their deadline has passed. No stage ever sees a window growing under it.
- 3
The stitch, and what it costs
The live link carries a thin, decimated view while the device holds the dense record. The pull is not free: the device's own sample counter stalls for the duration — measured at 289 ms mean across six pulls — so the clock fit has to re-anchor at every bracket rather than span one.
- 4
Motion-adaptive, not fixed rate
The replayed record isn't a flat 800 Hz. It is adaptive: a still pre-roll comes back at about 100 Hz, the downswing at nearly 800 Hz. Coverage of 16–50 % of the window is the correct answer, not a fault — and asking for a narrower window does not come back denser, because density is set by the motion.
The seam this needed already existed. The offline re-analysis path had been feeding the same frozen-window type from disk rather than from the ring for months — so a deferred source is a second implementation of a backing that was already in production, not a new hole cut in the buffer.
Illustrative — the freeze instant and the delivery instant come apart.
The body, down to the knuckles
Pose is the substrate everything optical stands on: the shaft tracker anchors on the hands, the body metrics read joint geometry, the segmentation falls back to it. Two entirely different models run, in two regimes, for two purposes — and the one that matters for measurement is not the one you watch on screen.
- 1
Live: a preview, and only a preview
The skeleton drawn over the running camera feed is MoveNet Lightning or Thunder — 17 body joints, GPU-accelerated through ONNX Runtime (CoreML on Apple Silicon, CUDA on Linux and Windows), throttled so inference lag never exceeds one cycle: while the model is busy the newest frame simply overwrites the pending one. It exists so you can see the capture is working. No measurement is ever taken from it.
- 2
Offline: 133 landmarks, whole body
The analysis runs ViTPose whole-body over the frozen window — a 256×192 crop in, a 133-channel heatmap stack out: 17 body joints, 6 for the feet, 68 across the face and 21 landmarks per hand. Two tiers ship — a ~330 MB base model bundled, a 1.23 GB large one on demand — through one decode path. The model computes all 133 channels either way, so reading the whole set costs nothing at inference time.
- 3
What the extra landmarks buy
The feet give a ground line at shoe level rather than the ankle — 8 to 12 cm lower — which tightens the ball search region and yields real stance width, foot flare and toe-line direction. The hands give the grip anchor the shaft tracker pivots on. And each swing is posed inside one fixed, aspect-locked person crop, so the golfer fills the model's input instead of occupying a corner of a 1080p frame.
- 4
Effort spent where the swing moves
Frames are not sampled uniformly: dense around impact, roughly four times sparser through mid-swing, a long stride across the address hold. The pose pass dominates the analysis wall-clock, so it is bounded to the detected swing span and concentrated where the club is actually accelerating.
- 5
Smoothing that can see the future
Because the window is frozen, the smoother is allowed to be non-causal. Every landmark coordinate gets its own three-state constant-jerk Kalman filter with a fixed-interval smoother pass back over it — 266 of them, one per axis per landmark — rebuilt at each step for the uneven sampling, with a 3σ gate rejecting outliers and a coast budget measured in time rather than frames. The classic occluded trail wrist at the top becomes a gap the backward pass bridges, and every smoothed point carries its own posterior sigma.
- 6
Deterministic, on purpose
The same window in gives the same track out, every time. That is not an accident of the model — it is a property the whole validation harness depends on.
Illustrative — effort concentrated at impact, then filtered in both directions.
A white ball on a white mat
The first ball detector needed a two-minute place-remove-validate calibration. Every swing in the corpus was recorded with it uncalibrated, because nobody ever did the chore — and an uncalibrated detector emits nothing. The lesson was blunt: reliability begins with removing the user from the loop.
- 1
Why the obvious approach fails
The hitting area is the brightest spot in the studio. Measured mat luminance directly around the ball ran to fully clipped in one session — a white ball on a white mat, literally invisible except for its contact shadow. Any cue built on absolute brightness reads zero there, however real the ball is. And a frozen background model meets a scene that never stops changing: the player's shadow sweeps the whole hitting area, and its changed-pixel mass dwarfs a 19-pixel ball by two orders of magnitude.
- 2
What replaced it
A self-calibrating temporal matched filter. It learns only the empty mat — one press, no ball-appearance profile, no drift monitor — and then watches a scale-matched response at the spot over time. Ball presence is a stable signal, not a bright pixel.
- 3
Stability is the whole tell
Across an entire three-and-a-half-second address — waggle, grounding the club, foot shuffles included — the response never dropped below about 85 % of its median. Then the ball leaves: the response collapses below 10 % of its address level within two frames at 149 fps, about 13 ms. That cliff is unmistakable, and it is also a third opinion for the shot arbiter.
- 4
And it hands the pipeline a ruler
Because the ball is a known 42.67 mm and its radius is measured, the same detector supplies the pixels-to-millimetres conversion at the hitting plane, plus a robust address ball centre. Low point, club length and strike geometry all read off it.
Illustrative — presence read from stability, departure from the collapse.
Physics as the discriminator
The previous tracker fought every false positive with another generic guard, and bought honesty by abstaining — coverage shrank with each patch. The current one promotes the physical structure of a golf swing to a first-class constraint, so counterfeits are rejected by understanding while real measurements are kept. There's a whole page on this; here is the mechanism in four lines.
- C1
The club is held in the hands
Club evidence must terminate just behind the grip, within about 260 mm. A line whose support continues on past the butt is a trouser crease, a screen edge or a shadow — vetoed however well it scores. The old weak form of this test ("the ray passes near the hands") was passed by every counterfeit ever adjudicated.
- C2
The club overlaps the body only at the ends
From takeaway to follow-through the club is in free space. A per-frame body polygon from the pose skeleton vetoes candidates supported mostly inside it — which is exactly where every adjudicated false positive lived.
- C3
The swing changes direction once
Phases come from the hands alone — grip speed and trajectory reversal — needing no club detection at all. Within each phase the rotation direction is known, and the chirality is detected per swing rather than hardcoded to a handedness. That makes a 180° flip structurally impossible rather than statistically unlikely.
- C4
Club and lead arm are a double pendulum
The wrist angle between them is anatomically bounded and evolves smoothly — hinging back, releasing monotonically through the downswing. That becomes a shape constraint enforced by isotonic regression rather than a smoothing fudge.
Estimation is global, not per-frame: a Viterbi pass over a grid of shaft angles across the whole clip, with emission costs from the image evidence and transition costs from the constraints above. A frame with no usable evidence is bridged by a bounded, monotone sweep — not by naive interpolation between two guesses. The solve wants one hard anchor per frame: on a taped club the bands supply it, and on a bare one the grip end and the hosel now do the same job from the shaft itself. The full story, in plain English →
Illustrative — one global path chosen through the evidence.
Putting it on one grid
Sensors sample at their own rate, cameras at theirs, and neither lands on the instants you actually want to read. Fusion is the step that makes everything answerable at the same moment — and synthesis is what fills the space between the moments that were measured.
- 1
Resample, don't interpolate blindly
Every bound segment is slerped onto one fixed 200 Hz grid, with the raw inertials rotated into the anatomical frame alongside. Rotations are interpolated as rotations — spherically, on the quaternion — never as three numbers that happen to look like angles.
- 2
Corroboration, not averaging
Where two modalities measure the same thing they are recorded side by side rather than blended into a single confident-looking number. A connected launch monitor's readings sit beside our own estimates on every swing, never replacing them. Where they agree, each vouches for the other and you get provenance for free.
- 3
Fusing an estimate that has no single source
Club length in pixels is estimated four different ways — from the ball, from the detected bands, from the located head, and from a persistent prior — and combined by inverse variance, with an explicit path to abstain when they disagree. A fused number that cannot say "I don't know" is not a measurement.
- 4
Synthesis is a separate tier, flagged
Between the located coaching positions, a dense club state is synthesized by Hermite interpolation on a 240 Hz grid, so quarter-speed replay and the shaft fan scrub smoothly. It rides alongside the real per-frame track and replaces nothing — and it carries a flag, so scoring and the estimands filter it out. Where a metric does read it (the low point of the arc genuinely lives between frames) that is a stated, narrow exception, not a quiet one.
Illustrative — resampled onto one timeline, then densified for display.
Anchored on the one thing we know
Almost every metric is "the value of this quantity at a moment" — at the top, at impact, at delivery. So finding those moments correctly matters more than any single measurement, and the ladder is built outward from the only instant that was directly observed.
- 1
Impact is the anchor, and it is never moved
It came from the shot arbiter, back-dated from a sample-accurate acoustic onset. Everything else is chained backwards and forwards from it: the top by back-chaining through the run of positive swing-plane rotation, the transition from the reversal of pelvis rotation, address as the last sustained stillness before movement, the finish from post-impact criteria.
- 2
A millisecond-cheap inertial pass first
The whole ladder falls out of the sensors alone, before a single frame is decoded — and it pays for itself immediately, because the heavy camera stages can then be bounded to the detected swing span instead of scanning the whole five-second ring. That is roughly half the pose inferences, not run.
- 3
Monotone by construction
Events carry a confidence and a provenance, and the chain must be strictly ordered. An event that violates the ordering is dropped by confidence, never reordered — a ladder that quietly re-sorted itself would be a ladder you could not trust at all. The segmentation's own confidence is the minimum across its load-bearing events.
- 4
Then the club refines it
On a camera-only swing there is no inertial ladder, so a vision one is adopted at vision-grade confidence — and once the shaft track exists, a refinement pass retimes address and takeaway from the club's own motion. It abstains below a confidence floor and beyond a maximum shift, and it is forbidden from touching impact. Nothing is ever invented; an event is either measured, refined, or absent.
Illustrative — the ladder grows outward from the observed instant.
Ninety-five things, each knowing its own limits
With a ladder of events and a fused set of streams, extraction is arithmetic — but the honesty lives in the bookkeeping around it. The catalogue owns what a metric is; the producers own how it is computed; and a metric never judges itself.
- 1
Joint angles, decomposed deliberately
The wrist is read from the relative rotation between forearm and hand: flexion/extension and radial/ulnar deviation from a Tait-Bryan decomposition chosen so that forearm twist drops out on the middle axis, then pronation and elbow flexion from a swing-twist decomposition about the forearm's long axis. Signs are hardware-locked and pinned by tests, because an inverted sign is a fault that fires happily on the wrong swings.
- 2
Everything the camera can add
Head movement, foot and pressure geometry, frontal-plane lower-body measures, upper-body measures, pelvis and thorax turn with X-factor and its stretch, club delivery, tempo. Each is its own stage with its own gate — the gate is the stage's own conditions, never the session type. A session type is a capture intent; it is not evidence about what was captured.
- 3
A route ladder, best first
Each metric declares an ordered list of ways it can be obtained — triangulated, inertial, fused, from a device, derived — each rung carrying its own requirement and whether it is a direct reading or an estimate. The app walks the ladder against what was actually connected, and the answer is what the swing card shows. "Needs a down-the-line camera" and "needs a launch monitor" reach you through the same mechanism.
- 4
Scored, unscored, and honest about which
Only a small set of metrics feeds the score. The rest are replay lanes — drawn, tabulated and diagnosable, but deliberately kept out of the number, so adding a new measurement can never silently move an athlete's score. Measurement sigma travels with the series and is quoted on the card.
No millimetres or miles per hour are invented from a monocular view. Where scale is not established, quantities stay in the image plane and say so — which is the same rule the calibration tier enforces from the other end. The full metric catalogue, explained →
Illustrative — how a metric is obtained, and whether it counts.
Numbers are content, not code
A number on its own is not a diagnosis. Turning readings into named movement patterns takes an authored model — and the design rule that shapes all of it is that no corridor is compiled in. Every band, every claim, every causal link is reviewable content that a coach can read, argue with and re-seat from data.
- 1
Five registries, joined by rules
Measures (a metric plus which reading — at the top, the change to the top, the trough between two positions), signals (the rule that watches one), conditions (the named characteristic), norms (what normal looks like, per context), and the edges between them. Shipped today: 134 measures, 131 signals, 157 conditions, 365 causal edges and 178 norms across a tree of 28 shot contexts, with 40 cited references.
- 2
Corridors, and what a grade means
A norm carries a centre and asymmetric tolerances by design, plus separate bounds outside which the reading is simply not believed. Grading is distance in tolerances, per side. Three states are never merged: a capture gap (nothing arrived), a swing finding (something arrived and was poor), and a capture fault (something arrived that this instrument cannot produce) — because grading a mis-tracked ball in either direction would launder a hardware problem into a confident diagnosis.
- 3
A signal fires on a deviation
Not merely on leaving the ideal band. Ideal is the middle of normal, so firing there would trip about a third of a healthy population on every characteristic, every swing. And a missing corridor yields "we could not assess this" — never a pass. That is the single most important branch in the engine.
- 4
A causal graph, validated as one
Causal edges must form a DAG and the library refuses to load a cycle. Edge strength is authored in words and read in words — "rarely" through "usually" — and nothing renders it as a percentage. Ranking combines how often a cause produces an effect with how common the cause is in the first place, then greedily covers the findings: a characteristic that itself has a cause in the pack is never presented as a root, because handing a coach a symptom and calling it the diagnosis is the failure mode this whole layer exists to avoid.
Illustrative — a reading becomes a finding, findings resolve to a cause.
A shot fires findings; only a session diagnoses
That sentence divides all the labour. One swing is an observation, and an observation is not a pattern — the whole hard part of this layer is the restraint required not to say more than fourteen swings support, made executable.
- 1
A ledger, not a running total
One row per condition per shot: fired or not, confidence, direction, the driving reading's distance from normal, the shot's context. Every tier, trend, chain grade and panel state is a pure reduction over those rows, and the ledger persists beside the session so review rebuilds an identical panel.
- 2
Recurrence is the unit of diagnosis
Graded by the Wilson score lower bound rather than the raw rate, because one-of-two and eight-of-ten have similar rates and utterly different evidence. Three assessable shots minimum before any pattern claim. Below that a firing sits in watching — which is the outlier discard, done by evidence weight rather than by deleting data. A single shank stays there forever if it never recurs. And a badly hit shot is never excluded: mishits are the most diagnostic swings in the session.
- 3
What the golfer never sees inflated
Trends are Theil–Sen slopes with a rank-correlation significance test, minimum five points, reported as improving / stable / worsening and nothing finer. Recurrence is always a count — "8 of 12 measurable shots" — because at this sample size a percentage is fabricated precision. And a measure the capture never took is excluded from every denominator, but still drawn, because "we did not look" is a fact you are owed.
- 4
Chains are confirmed, never discovered
157 conditions imply about ten thousand pairs; mining those over fifteen swings would produce nothing but coincidence. So the authored graph restricts testing to a handful of pre-specified links among this session's patterns — the causal network is the multiple-comparisons correction. Links grade upward: present together, coherent in direction and swing order, conditionally dependent in a paired contingency table, and finally moved together — the session's own natural experiment, and the most motivating thing a golfer can be shown.
- 5
And then something to actually do
The recommendation targets the most upstream confirmed node — fix the cause and the symptoms come free — with a drill attached. Where a cause is a physical restriction rather than a movement, the panel names a screen instead: a thirty-second test that costs no hardware and would anchor several patterns at once. Causes that can only be established by asking are offered as questions, visually distinct, and never counted as resolving anything.
Illustrative — recurrence, then a chain, then one thing to work on.
All of it is readable.
Every stage on this page is source you can clone, build and argue with — the constraints, the constants, the corridors and the reasons each of them is what it is. The first beta shipped in September 2026; it's still a prototype under validation, with 1.0 targeted for late in the year.