# Zero check

The mark on a group shot to check the zero, and what the shooter did after it: moved the turret, saved the zero offsets, or left the zero as it was.

## Generated table

**Record:** observation · **Covers:** `zero_check`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `zero_check.action` | `'turret'` or `'offsets'` or `'none'` | no | - | no | as stored |
| `zero_check.at` | string | no | - | no | as stored |
| `zero_check.saved_version` | number | no | min 1 | no | as stored |
| `zero_check.turret_mil` | object | no | - | no | as stored |
| `zero_check.turret_mil.right` | number | yes, within | min -50; max 50 | no | as stored |
| `zero_check.turret_mil.up` | number | yes, within | min -50; max 50 | no | as stored |

## What it holds

A group can be marked as a zero check: a group shot at the zero range, dialed 0, to see where the rifle prints. The mark also records what the shooter did after looking at it: moved the turret by the correction, saved the zero offsets to the profile, or left the zero alone. The group's own centre (`group.center_up_mil`, `group.center_right_mil`) is the measurement; this block only says the group was a zero check and what came of it. An absent `zero_check` means an ordinary group.

## What to know first

**An empty block is a zero check with nothing done yet.** `zero_check: {}` marks the group; `action` appears once the shooter acts in the zero step or through `zero_check`.

**Several checks average.** The zero step and `zero_check` average the chosen checks' centres, each weighted by its shot count (at least 1).

**A turret move is a new zero.** The profile does not change, but fits leave out the groups shot before the latest recorded move.

**Saved offsets count on every model.** Saving them sets the profile's zero height and offset and turns on "Use my zero offsets in every solve".

## The fields

**`zero_check.action`** What was done after the check: `'turret'` (the turret was moved by the correction), `'offsets'` (the zero offsets were saved to the profile), `'none'` (left as it was). Absent while nothing was done.

**`zero_check.at`** When the action was recorded, an ISO time.

**`zero_check.turret_mil`** With `'turret'`: the move made, in mil, **`zero_check.turret_mil.up`** plus up and **`zero_check.turret_mil.right`** plus right, each -50 to 50. It is the group's offset reversed: a group 0.3 mil high records a move of -0.3 up.

**`zero_check.saved_version`** With `'offsets'`: the profile version the offsets were saved as, 1 or more.

**How the numbers are worked out.** The offset of the chosen checks is the mean of their centres weighted by shots (a check stored with no shot count weighs 1); its inches use each check's own range, `tan(mil / 1000) × range × 36`. The turret correction is the offset reversed, in the scope's unit (MOA = mil × 3.43775), and in whole clicks when the profile has a click size (half a click rounds away from zero). The offsets saved are the measured inches, to the hundredth: a group measures where the rifle prints, whatever was saved before.

## Who writes it

**The app.** The group form has a "Zero check" tick; ticking it fills an empty range with the profile's zero range and an empty dial with 0, and the saved group carries `zero_check: {}`. The zero step opens after such a group is added, from a zero-check group's row menu, and from the zero history in the profile screen's Zero section. It lists the profile's zero checks to choose from and has three buttons: "I'll move the turret" records `'turret'` with the move, "Keep the turret, save the offsets" saves the next profile version and records `'offsets'` with its number, "Leave it" records `'none'`. Each chosen group is read again before it is written.

**The connector.** `zero_check` with an `action` writes the same block on the groups it used.

## Who reads it

**The app.** The zero step and the Zero section's zero history read every zero check of the profile. The history lists them newest first with their offset, shot count and action, and a column that takes away the turret moves recorded on earlier checks, so a rifle that has not moved reads the same however the turret was dialed in between.

**The connector.** `zero_check` reads the profile's zero checks; `get_session` returns the block as stored.

**The fitter.** A recorded turret move changes the rifle's zero, so a fit leaves out every group of the profile shot before the latest one, with the reason `shot before the turret was moved on <date> (a different zero)` (owner, 2026-10-16). Saved offsets and "Leave it" set nothing aside. A zero check is otherwise fitted like any other group.

## Why it is stored

Zeroing is a series of small decisions. Keeping each check and what was done after it lets the app average several checks, show drift over time, and say which saved offsets came from which groups.

## Changing it

Only the zero step and `zero_check` set `action`; a later action on the same group replaces the earlier one. The saved-group editor keeps the block.

## Sharing and privacy

Every reader of a shared log gets the block as stored: whether a group was a zero check and what was done after it say nothing about place or notes.

---

[All reference pages](../index.md)
