# Ammunition

What the load is called, its lot, and whether it is factory ammunition or a handload with its recipe: all for people, none of it read by the solver.

## Generated table

**Record:** profile · **Covers:** `ammo.name`, `ammo.lot`, `ammo.load`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `ammo.load` | object | no | - | no | removed for public readers when the load is a handload |
| `ammo.load.brass` | string | no | - | no | removed for public readers |
| `ammo.load.brass_firings` | number | no | - | no | removed for public readers |
| `ammo.load.charge_gr` | number | no | - | no | removed for public readers |
| `ammo.load.coal_in` | number | no | - | no | removed for public readers |
| `ammo.load.jump_in` | number | no | - | no | removed for public readers |
| `ammo.load.kind` | `'factory'` or `'handload'` | yes, within | - | no | removed for public readers when the load is a handload |
| `ammo.load.part_no` | string | no | - | no | removed for public readers when notes are hidden |
| `ammo.load.powder` | string | no | - | no | removed for public readers |
| `ammo.load.primer` | string | no | - | no | removed for public readers |
| `ammo.lot` | string | no | - | no | as stored |
| `ammo.name` | string | yes | - | no | as stored |

## What it holds

These fields name the ammunition and how it was made. `ammo.load` is an optional block: factory or handload, and a handload's recipe. Absent means the shooter has not said, and a profile without it is complete. No solver reads any of it.

## What to know first

**A recipe is hidden from public readers.** It is shown to the owner, to an admin reader, and on a share with one person or with the admins. A public reader never gets it. An unknown reader counts as public.

**The name and the lot are shown to everyone.** They are typed text, and hiding notes does not hide them, so a charge typed into one reaches every reader. A factory load's part number goes to a public reader only with notes.

**The connector can set only the name and the lot.** It has no input for the load or its recipe. An input it does not know is not used and the reply names it; an edit made only of such inputs saves nothing and answers "Nothing to change".

**Changing the name or the lot can cost a calibration.** On a profile with a fitted drag curve the connector refuses to save until told keep or reset, and the app offers reset first. A change to the load never asks.

## The fields

**`ammo.name`** What the shooter calls the load, for example a maker and product name or "142 gr handload". Required, but it may be empty. A profile made with New profile, or by the connector without `ammo_name`, starts with an empty name; the two sample profiles a fresh install starts with come with a load name already filled in. The profile screen asks for it in Load and bullet as "Load name".

**`ammo.lot`** The lot number on the box, or the shooter's own batch label. Optional; absent and empty both mean none. Guided setup asks for it as "Lot". The in-app help says that a new lot or a changed recipe should be a new profile version, which saving does by itself.

**`ammo.load`** Whether the rounds are bought or made, and the recipe. Optional as a whole. Absent means the shooter has not said. The block is removed when its `ammo.load.kind` is removed, so a recipe cannot exist without a kind.

**`ammo.load.kind`** `factory` or `handload`. Required inside the block. Guided setup shows it as "Factory or handload" with a third choice, "Not said", which removes the whole block.

**`ammo.load.part_no`** The part number printed on the box of factory ammunition. Text. Shown in guided setup only when the kind is factory.

**The recipe of a handload.** These are shown in guided setup only when the kind is handload. All are optional.

- `ammo.load.powder`: the powder's name. Text.
- `ammo.load.charge_gr`: the powder charge, in grains.
- `ammo.load.primer`: the primer's make and type. Text.
- `ammo.load.brass`: the brass maker. Text.
- `ammo.load.brass_firings`: how many times the brass has been fired.
- `ammo.load.coal_in`: cartridge overall length, base to tip, in inches.
- `ammo.load.jump_in`: how far the bullet sits off the rifling, in inches, if the shooter knows it.

Example, all made up: name "Example 142 gr handload", lot "batch 3", kind handload, powder "Powder Q", charge 41.2 gr, primer "Primer S", brass "Brass Z", fired 3 times, overall length 2.78 in, jump 0.02 in.

When the shooter switches the kind in guided setup, the questions that no longer apply are cleared when the step is saved (the setup form does this; the save itself keeps whatever members it is not told to remove): going from handload to factory removes the recipe, and going the other way removes the part number. A value that is not a finite number is refused. A stored 0 is a number (zero grains, zero jump), not an absent value.

**Limits, by writer.** App: the save check the profile screen's sections share. Connector: the input of `edit_profile` and `create_profile`. Conversion: the step every solve goes through first. Solve: what the solver itself refuses for one answer.

| Field | App | Connector | Conversion | Solve |
|---|---|---|---|---|
| `ammo.load.charge_gr` | >= 0 | not settable | n/a | n/a |
| `ammo.load.brass_firings` | >= 0 | not settable | n/a | n/a |
| `ammo.load.coal_in` | >= 0 | not settable | n/a | n/a |
| `ammo.load.jump_in` | >= 0 | not settable | n/a | n/a |

The charge is in grains and the lengths in inches. The conversion and the solver never look at these fields, so neither can refuse them. The app has no upper bound: a charge of 99999 grains saves, and so does a count of 2.5 firings. The text fields have no length limit in the app or the schema (only the profile's overall size cap); the connector limits the name and the lot to 80 characters each, and it refuses a longer one with an input error.

## Who writes it

**The app.** The profile screen's Load and bullet section asks for these. The two sample profiles of a fresh install are written with a load name, and no lot or load. Its rows are "Load name", "Lot", "Factory or handload", "Part number" for a factory load and, for a handload, "Powder", "Charge", "Primer", "Brass", "Times fired", "Overall length" and "Jump to the rifling". None of these questions has a "Don't know yet" tick. A load block is merged one member at a time, and a blank optional answer removes that member.

**The connector.** `edit_profile` takes `ammo_name` and `ammo_lot`; `create_profile` takes the same two. An empty `ammo_lot` removes the lot. Neither tool takes the load or any member of it. An input named `load`, `powder` or the like is not used, and the reply names it ("I ignored: ..."; since 2026-10-15): `create_profile` makes the profile with no load, and `edit_profile` saves the other changes and keeps a load that is already there, recipe included. An edit that sends only such inputs saves nothing and answers "Nothing to change: I ignored" and their names. Copying a shared profile writes all three exactly as the shared view held them, which for a public share means without the recipe; restoring a deleted profile writes them as they were. The [origin](origin.md) and [versions](versions.md) pages describe both.

**The fitter.** It writes none of these.

## Who reads it

**The solver and the fitter.** Neither reads the name, the lot or the load. A group shot with an earlier version is judged for a fit by the bullet, the twist, the sight height and the zero, not by the lot or the recipe, so changing the lot never makes older groups ineligible.

**The app.** The setup summary lists the answered questions of the step, and a recipe row appears only for a handload. The printable worksheet (`#/setup/<profile>/print`) prints every question of the step as a blank box and prints none of the stored values. A person who has copied a shared profile sees "changed since your copy" for any of these fields that changed in the sharer's newer version. A shared log's Profile tab opens the profile screen read-only on the shared profile, built from the shared view, so it holds only what that reader is allowed.

**The connector.** `get_profile` returns the owner's whole load, recipe included, because the owner may see it; since 2026-10-15 its typed words (the name, the lot, the powder and the rest) come under `stored_text`, beside the numbers. `get_shared_profile` returns what the shared view held: the numbers of the recipe under `profile`, and every typed word under `sharer_text` by its path (`ammo.name`, `ammo.lot`, `ammo.load.powder`, `ammo.load.part_no`, and so on), each one cleaned and cut to 80 characters. The kind stays under `profile` when it is `factory` or `handload`. `get_profile` on a profile the account copied from a share is split the same way, with the words under `copied_text`. `check_profile` reads none of these fields, but the profile audit knows how to word three load paths if they are listed as not measured (powder charge, overall length, bullet jump). The app never lists them, so that wording is not reached by anything the app saves.

## Why it is stored

The name and lot exist so that a shooter, and anyone shown the profile, can tell which ammunition the numbers belong to. The lot matters because two lots of the same load can have different velocities, and the shooter's habit is to start a new version when the lot changes. The recipe exists for a handloader's own record and for the admins who help interpret a shared log: a powder charge and an overall length are the first things asked when two shooters compare results. The solver does not need them. Keeping the kind apart from the recipe lets a factory load carry a part number and nothing else.

## Changing it

An edit saves a new version; the [versions](versions.md) page explains that once for every field.

**The edit category depends on the field.** A change to `ammo.name` or `ammo.lot` is in the "ammo" category, with the muzzle velocity, and reset is the choice offered first. The app asks keep or reset on a profile with anything a reset could remove: a fitted drag curve, a calibration record, a Spin trim, velocity-by-temperature rows, or a scope factor other than 1. The connector refuses to save until it is told `calibration: keep` or `calibration: reset` only when the profile has a fitted drag curve or a calibration record; otherwise it saves without asking. Adding or removing the lot counts as a change. A change to anything in `ammo.load` is in no category: it never asks and never touches the calibration. Both are checked by `editEffect`; what a reset removes is on the [calibration](calibration.md) page.

## Sharing and privacy

**The rule.** A reader of a shared log sees a handload's recipe only if the reader is an admin, or the share is with one person, or the share is with the admins. The same rule applies when the viewer is an admin on a public share. A public share read by anyone else, and any share whose audience the filter does not recognise, shows no recipe. The sharing screen and the terms page say this in plain words.

**What each reader gets of the load.** The two filters (the web app's and the server's) give the same answer for every case that was run, and a shared test file pins them.

| The stored load | Public reader (not an admin) | One person, the admins, or an admin reader |
|---|---|---|
| A handload | `ammo.load` removed: no kind, no recipe | `ammo.load` as stored |
| A factory load | `ammo.load.kind` and `ammo.load.part_no` only | `ammo.load` as stored, any other member included |
| No kind, a wrong kind, or a value that is not a block | removed | as stored |

A reader who is not allowed the recipe therefore cannot tell a handload from a load the shooter never described. The factory part number is typed text that every reader of the share sees, except a public reader when the share hides notes. On a factory load, a recipe member that was typed anyway is kept for a person, the admins and an admin reader, and dropped for a public reader.

**What reaches every reader.** `ammo.name` and `ammo.lot` are not filtered. They reach every reader of the share, and hiding notes does not touch them: the switch empties the profile's notes, removes each confirmed come-up's note and, for a public reader, removes a factory load's part number (`ammo.load.part_no`, since 2026-10-24). The shared view cleans none of its text. If a recipe, a charge, or a note to oneself is typed into the name or the lot (or into the part number on a share that shows notes), a public reader sees it, and so does every earlier version of the profile in the same shared log. The setting that hides notes, and the one that hides location, do not change what is said here for any member of the load.

**What a copy keeps.** A shared profile copied by another account carries the name, the lot and the load exactly as the copier was shown them. A copy made from a public share has no recipe, because the copier never received one. The copy records where it came from in a field that is removed from every shared view.

**What the values let a reader work out.** A recipe lets a person reproduce the load. Together with the bullet and the velocity, a charge and an overall length let a reader judge how hot the load is. A lot or a batch label can point to a purchase.

---

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