# Origin

Where a profile came from: read from another app, or copied from someone's shared profile, and what a copy keeps, changes and drops.

## Generated table

**Record:** profile · **Covers:** `source`, `copied_from`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `copied_from.copied_on` | string | yes, within | - | no | removed for every reader |
| `copied_from.share_id` | string | yes, within | - | no | removed for every reader |
| `copied_from.version` | number | yes, within | - | no | removed for every reader |
| `source` | object | no | - | no | removed for every reader |

## What it holds

Two optional marks say where a profile version came from. One records that the profile's numbers were read from another app, with the name the profile had there and the date it was read. The other records that the profile is a copy of a profile someone shared: which share, which version of it, and on what day. A profile made in the app or by the connector has neither. A hand edit never writes either mark, and neither changes a come-up.

## What to know first

**A copy stays marked for good.** Every later save, fit and restore carries the mark forward. Nothing in the app or the connector removes it. The connector therefore treats the copy's name and text as another person's words.

**A copy keeps the sharer's numbers and drops their private ids.** Rifle, scope, bullet, model and calibration come across as the share showed them. The coefficient set, the prior ids and the catalog source fields were never in the share. The sharer's "finished" mark is dropped.

**Any saved edit removes the other-app record.** A profile edit, a fit and a restore of a deleted profile all drop it from the new version. Older versions keep it.

**Name a copy by its id.** A reply shows a copy's name in quotes, cut to 40 characters, and two copies can look alike. Neither mark can be set by hand, and the solver never reads them.

**A shared log never shows `copied_from`.** The other-app record is shared as stored, on the versions that still carry it.

## The fields

**`source`** A record that the profile's numbers were read from another app, with the name the profile had there and the date it was read. It is set only on the sample profiles, which "Add sample profiles" on the Profiles screen adds. Since 2026-10-20 a fresh install starts with none of them: it gets one example profile, "Example .308 Win, 175 gr" (id `example-308`), made from the app's own starting values with every value marked "Don't know yet" and no `source` mark. A sample is written whole in one step: its name is the name it had in the other app, its notes are a line about the ammunition, and it carries a rifle name, sight height, twist, zero range, zero height and offset, the scope's units, both tracking factors, a scope name and a reticle, a bullet with its diameter, weight and length, both ballistic coefficients with the G7 model chosen, a muzzle velocity and an empty temperature table. It is stored without going through the save check. Absent on everything else. It only records where a sample's numbers came from; nothing reads it back.

**`copied_from`** Where a copy of a shared profile came from. It holds three members, all required when it is present: `copied_from.share_id` (the share the copy was made from, as the copier's app knows it), `copied_from.version` (the version number of the sharer's profile that was copied) and `copied_from.copied_on` (the day of the copy as a UTC date, `2026-10-08`). Example: share `s-1`, version 8, on 2026-10-08. Absent means the profile was not copied. It is set in one place, when a copy is made, and then never changes.

**Limits.** Neither field has a limit and neither is an input of the profile screen or the connector, so there is no limits table. The schema fixes the shape of both marks and requires every member of `copied_from`.

## Who writes it

**The app.** "Add sample profiles" writes the sample profiles with the `source` mark; the first run on a device with no profile writes the example profile, with no mark (until 2026-10-20 it wrote two samples). "Copy" on a Profiles card or in Share and devices (since 2026-10-20) copies one of the shooter's own profiles whole, calibration included, as a new profile at version 1 named after it with "copy" added ("Long gun copy"), with no `copied_from` (a shared copy's mark is not carried over). "Copy profile" on a shared log writes a copy with `copied_from`; so does a yes to the question the app asks before a change to a shared profile in use ("Edit" on the Profiles screen, "Log this shot" and "Other log" on the Calculator). Each time a profile is saved on the profile screen or by the Calibrate screen (a fit, "Use this one again", a direct save), or restored from Show deleted, the new version has no `source` and keeps `copied_from`. The profile screen has no field for either.

**The connector.** `copy_shared_profile` (token scope `profiles`) makes a copy with `copied_from`. `edit_profile`, and `calibrate_profile` and `tall_target` when they save, drop `source` and keep `copied_from`. `create_profile` writes neither mark.

**Never fitted, never set by the server.** No fit changes `copied_from`.

**Restoring a deleted profile** (`undeleteProfile`) is a new version of the last one, so it drops `source` and keeps `copied_from`. The [versions](versions.md) page describes it once. The soft delete itself writes a tombstone on every version and changes nothing in them.

**What a copy keeps, changes and drops.**

The copy is made from the shared profile's newest version, as the share showed it to the copier. What the share hid is therefore not in the copy.

| Part | In the copy |
|---|---|
| Rifle, scope (including turret directions, tracking factors and travel), bullet, drag, muzzle velocity, temperature table | kept as the sharer had them, except the zero air when the share hides location: its pressure rounded to 0.1 inHg and its altitude removed |
| `model` and its options | kept |
| `calibration` and its history | kept as recorded; the copy does not re-fit |
| `ammo.aero` (a private coefficient set) | not in the copy: the share never held it |
| Ids inside the calibration (prior id, coefficient id) and the bullet catalog's source fields | not in the copy, for the same reason; the kind stays |
| `ammo.load` (handload recipe) and the unmeasured list | kept as the share showed them: whole on a share with one person or with the admins and for an admin viewer; otherwise only a factory load's kind and part number (the part number only when the share showed notes), and no unmeasured list |
| The calibration goal | kept; when the share hides location its latitude is rounded to the whole degree, its pressure to 0.1 inHg and its bearing to 10 degrees, and its altitude is removed |
| `come_ups` (confirmed come-ups) | kept as the share showed them: without the notes when the share hides notes |
| `setup.sections` | kept |
| `setup.finished_at` | dropped: "finished" was the sharer's word |
| `source` | dropped |
| `notes` | the sharer's notes (empty when the share hides notes), with one line put in front: "Copied from a shared profile "TITLE" vN on DATE." The line names no sharer (since 2026-10-15; a copy made earlier names the sharer, by account email on a share with one person or with the admins). |
| `name` | new: "TITLE (copy)"; the app and the connector add a number ("(copy 2)") when the copier already has that name |
| `profile_id`, `key`, `id`, `version`, `created_at`, `updated_at`, `owner_id`, `deleted` | new: a new profile of the copier's, at version 1, not deleted, with the owner set by the server |
| `copied_from` | new |

The sharer's log is never copied, so the copy starts with no groups. A copy of a shared latest version with an impossible bullet outline is stuck: the copy is saved without the save check, and the profile screen then refuses every save until the outline is fixed, as the [bullet shape](bullet-shape.md) page describes.

Every path that makes a copy runs the same function: "Copy profile" on a shared log, the app's question before a change to a shared profile in use, and the connector's `copy_shared_profile`. A copy is not checked against the limits of the other pages.

## Who reads it

**The solver and the fitter** read neither mark.

**The app.** A shared log looks for the newest copy of its share among the reader's own profiles, by `copied_from.share_id` and `copied_from.version`. If the sharer has saved a newer version, it says so and lists which setup answers changed; otherwise it says the copy is from this version. Nothing in the app reads the other-app record back.

**The connector.** Every tool that names a profile reads `copied_from` to decide whether to treat the name and text as another person's: `list_profiles`, `get_profile`, `check_profile`, `explain_dope`, and the name in the reply of `edit_profile`, `create_profile`, `delete_profile`, `calibrate_profile`, `tall_target`, `solve`, `range_card`, `sensitivity` and `compare_models`. `get_profile` shows the other-app record of a profile that is not a copy, as stored.

**The share filter.** It removes `copied_from` from every shared view and passes the other-app record on as stored.

**What the connector does with a copy.**

A profile with `copied_from` is treated as holding another person's words. The rule is exact:

| Where | What happens |
|---|---|
| Any spoken line or error that names the profile | the name is cut to 40 characters, put in quotes, with no quotes inside |
| `list_profiles` | the name is shown that way, with `copied: true` |
| `get_profile` | every string that is not a number, a date, an id or a word on the connector's short list of the app's own codes (some of the app's codes are not on it, such as the turret wording, the kind of a calibration goal, the solver version of a calibration, the kind of a starting shape, the kind of a coefficient source and the kind of the profile's origin, and these move too) moves under `copied_text`, by its path; the numbers stay; `copied_from` is shown with its three members |
| `check_profile`, `explain_dope` | solve a copy with only its numbers and codes, its name as a reply says it and empty notes |
| Naming a profile to a tool | `edit_profile`, `calibrate_profile`, `tall_target`, `check_profile` and `explain_dope` take an id or a name, and for a copy the name a reply shows also matches; if two profiles match, the tool refuses and asks for the id. `delete_profile` takes an id or the stored name (any letter case). `solve`, `range_card`, `sensitivity` and `compare_models` take an id only |

Some words are lost in the copy that `check_profile` and `explain_dope` work on: the scope name, the reticle, the load's text and `scope.turret.wording`. Neither of them says a dial, so nothing is heard differently. `solve` and `range_card` read the stored copy and say its dial in clockwise words when the sharer's turret was set that way. `sensitivity` and `compare_models` also read the stored copy; they never word a turn for any profile.

## Why it is stored

**The copy mark** exists for two jobs. The shared log needs to find "my copy of this share" to tell the copier the sharer's profile has moved on. And the connector needs to know that the copy's words came from someone else, since a copy keeps the sharer's name, notes and load text inside the copier's own records, and those words must not reach a spoken reply as if they were the copier's.

**The other-app record** says where a sample profile's numbers came from and when they were read, so the numbers can be traced. After any edit the numbers are no longer the other app's, so the mark goes.

## Changing it

The edit category is none: neither field is a ballistic input, so no edit, copy or restore asks whether to keep or reset a calibration because of them. A copy brings its calibration along as recorded and does not ask. The copier's own later edits ask the usual keep-or-reset question, described on the pages of the fields they change. Older groups' eligibility does not depend on either mark.

## Sharing and privacy

`copied_from` and its three members, `copied_from.share_id`, `copied_from.version` and `copied_from.copied_on`, are removed from every shared view, for a person, the public and the admins, and with notes and location shown or hidden. The profile's notes are a separate field with their own switch (see [versions](versions.md)). The other-app record, `source`, is removed from every shared view as well (since 2026-10-13; before that it was shared as stored). A copy hides nothing from its owner.

---

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