# Calibration suggestion

A calibration fit that a helper made on a shared log and sent back to its owner, and where it stands: open, accepted, declined or cancelled.

## Generated table

**Record:** suggestion · **Covers:** `id`, `created_at`, `updated_at`, `deleted`, `owner_id`, `suggestion_id`, `share_id`, `profile_id`, `from_version`, `entry`, `message`, `from_name`, `status`, `decided_at`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `created_at` | string | yes | - | no | not part of a shared log |
| `decided_at` | string or null | yes | - | no | not part of a shared log |
| `deleted` | boolean | yes | - | no | not part of a shared log |
| `entry` | object; the same fields as a profile's `calibration` ([page](../profile/calibration.md)) | yes | - | no | not part of a shared log |
| `from_name` | string | yes | - | no | not part of a shared log |
| `from_version` | number | yes | - | no | not part of a shared log |
| `id` | string | yes | - | no | not part of a shared log |
| `message` | string | yes | - | no | not part of a shared log |
| `owner_id` | string or null | yes | - | no | not part of a shared log |
| `profile_id` | string | yes | - | no | not part of a shared log |
| `share_id` | string | yes | - | no | not part of a shared log |
| `status` | `'open'` or `'accepted'` or `'declined'` or `'cancelled'` | yes | - | no | not part of a shared log |
| `suggestion_id` | string | yes | - | no | not part of a shared log |
| `updated_at` | string | yes | - | no | not part of a shared log |

## What it holds

A suggestion is a calibration fit that someone ran on a log you shared and sent back to you. It names the profile version they fitted, their fit (`entry`), a message and the name they chose to show, and where it stands. It lives in your own records and syncs to your devices. No reader of a shared log is shown it.

## What to know first

**Only the server writes it.** A device cannot push one, and no connector tool reads or answers one: it is answered in the app.

**Accept re-runs the fit.** The owner's app runs the fit on the owner's own groups and saves that result, only if its parameters match the helper's.

**The group ids in `entry` are the owner's.** An id that matches no live group stays as sent, and Accept is then refused.

**A status moves one way.** `open` becomes `accepted`, `declined` or `cancelled`, never back. Stopping the share cancels its open ones. The app shows only open ones.

**The owner learns a typed name, not an account.** The name is unverified; no email or account id of the helper is stored.

## The fields

**`id`** and **`suggestion_id`** The same value: the id the server gave the suggestion when it made it. Never set by a device. It is also the record's key.

**`created_at`**, **`updated_at`** and **`decided_at`** Times in UTC. `created_at` is when the server received it. `updated_at` is when the server last wrote the record: the same as `created_at` while open, then the time of the answer. `decided_at` is null while open and is set when the status leaves `open`, including a cancel.

**`deleted`** Always false. No code deletes a suggestion record.

**`owner_id`** The owner of the log: the account whose records hold this one. The server sets it, not the helper. The helper's account is not stored in the record.

**`share_id`** The id of the share the helper used, as the owner's share list knows it.

**`profile_id`** The owner's own profile id (not a made-up one). The app files the suggestion under this profile.

**`from_version`** The profile version the helper fitted, a whole number. It is the same as `entry.from_version`. The server refuses a version that is not a live version of the profile. The owner's profile may have moved on since.

**`entry`** The helper's fit: one row, described on the [calibration](../profile/calibration.md) page, which says what each part holds. In a suggestion its group ids (`used`, `held_out` and the held-out residuals) are the owner's. Its `prior` and `aero_source` keep their kind and level and lose their `id`. The app sends only a fit that produces a result: mean velocity, drag factor, drop factors and the full drag curve. The server stores an entry of any method; the owner's app refuses to apply a tall-target or a velocity-by-temperature entry.

**`message`** What the helper wrote, cut to one plain line of at most 1,000 characters before cleaning. Empty if they wrote nothing. Example: "Fitted on the 1,500 and 2,000 yd groups."

**`from_name`** The name the helper chose to show, one plain line of at most 80 characters before cleaning. If it comes out empty the server stores "A Cold Bore Lab shooter". The app asks for a name and will not send without one. Nothing checks that it is true. Example: "Sam".

**`status`** `open` when sent. `accepted` when the owner accepts. `declined` when the owner declines or asks for a new fit. `cancelled` when the profile is deleted while it was open, when the share it came through is stopped, or when the helper's account is deleted.

**Limits, by writer.**

- Helper's app, the sheet "Suggest to ...": the name box holds 80 characters and the message box 1,000. Only a fit that converged can be sent. The helper's list of sent suggestions on this log shows the status of each.
- Sharer's app: no limits, no edits. It can accept or decline an open suggestion, and nothing else.
- Connector: no tool reads or writes suggestions.

## Who writes it

**The helper's app.** After a fit on a shared log (the Calibration screen of a log opened from "Shared with me", Community or a link), the button "Suggest to" followed by the sharer's name opens a small form with two boxes: "Your name (shown to", then the sharer's name, then ")", and "Message (optional)". "Send suggestion" sends the helper's fit with the name and the message. The sheet remembers the name for next time on that device. The helper must be signed in; an account is all it needs.

**Who may suggest.** Anyone who can read the share: the named person on a person share, an admin on an admins share, anyone with an account on a public share that they can open. The share's use setting (anything, pooled results only, or helping the sharer only) does not matter here. The owner cannot suggest to their own log. A stopped or unknown share gives the same "isn't shared any more" answer as a view does.

**The server.** It checks the share, the profile and the fit, then makes the record and tells the owner's devices. It writes the record again when the owner answers, and when the profile is deleted, the share is stopped or the helper's account is deleted. It keeps an owner's newest 200 suggestion records and marks older answered ones deleted. A helper can have 3 open suggestions on one share at a time, and can send 20 an hour.

**The owner's app.** It never writes the record. "Accept" and "Decline" ask the server, which makes the change and sends it back on the next sync. A decline from "Ask for a new fit" also records the word "changed" for the helper to see. If the owner is offline, an accept saved on the device is told to the server later.

**The connector.** No tool reads or writes suggestions. A suggestion is answered only in the app.

**Not written by.** A backup restore (backups hold no suggestions), a sync push (refused) or the fitter.

## Who reads it

**The owner's app.** The Profiles screen shows a count of open suggestions on each profile. The profile's Calibrate screen lists them as cards: "(the helper's name) suggested a calibration" and the message with a Review button. A card that is open shows three tables. "What changes" lists each parameter now and as the helper sent it, with the helper's stated uncertainty; only the velocity row shows the re-run's value. The come-ups before and after, and the miss of each group, come from the fit run again on the owner's own log, and are shown only when that fit matches. My shares in the Account screen counts the open suggestions of each share and links to the profile.

**The check.** When a card opens, the app loads the newest version of the profile and the groups, and runs the fit again with the helper's used and held-out groups. It refuses first if a listed group is missing from the owner's log (the message says to ask for a new fit) or if the method cannot be applied from a suggestion. It also stops if the suggestion is no longer open, or if a full fit started from a drag shape this device does not have. After the run it compares the parameters by value, within a small tolerance. Per-session velocity biases are named by session, which the helper cannot know in the owner's terms, so they are compared as sorted lists of values. The check ignores the quality numbers and the residuals in the entry.

**Accept.** The app asks the server to mark the suggestion accepted first, then saves the owner's own re-run as a new profile version, the same way a fit made on the Calibrate screen is saved: see [versions](../profile/versions.md) and the [calibration](../profile/calibration.md) record. Nothing in that version says it came from a suggestion. If the data, the profile or the suggestion changed while the card was open, the app checks again and asks the owner to review again; it never saves a stale fit.

**If the profile moved on.** A suggestion fitted on version 2 can be opened when the profile is at version 5. The card says "Your profile changed since this fit" and the fit runs on version 5. If it comes out differently, the owner can ask for a new fit, which declines it with the word "changed".

**The helper's app.** It reads a different, smaller thing: its list of suggestions it sent. For each, the server sends the sharer's label and the profile's name as they were when it was sent, the version, the helper's own name and message, the status, both times and the reason word. The app's list shows the version, the date and the status, with "changed" turned into "their log changed, so they asked for a new fit". Never the owner's record. The helper's app gets a live message when the status changes.

**The solver and the connector** do not read a suggestion.

## Why it is stored

A calibration needs the owner's groups and the owner's profile, so the owner should apply it. A suggestion is the helper's fit parked in the owner's own records, so it reaches every device, works offline and survives a restart. The entry is kept whole so the owner's app can re-run it and compare. The message and the name are for the owner to judge it. The status is there so a suggestion answered on one device is not offered on another.

## Changing it

A suggestion is not versioned. It is one record that the server rewrites in place when its status changes. It is never edited by hand. The owner's answer is the only change from open, apart from the cancels. Past the newest 200 suggestion records of an owner, the server marks the oldest answered ones deleted, so the owner's devices drop them; an open one is never removed. Accepting makes a new profile version; that version is what changes the calibration. An answered suggestion stays stored but the app stops showing it. A hand edit has no effect on a calibration (`on_edit: none`).

**When it is cancelled.** If every version of the profile is deleted, the profile's open suggestions become `cancelled`. If the share is stopped, its open suggestions become `cancelled` (since 2026-10-15). If the helper deletes their account, their open suggestions become `cancelled`. A suggestion that was already answered keeps its answer.

**When the share stops.** Stopping a share cancels its open suggestions and tells each helper, as a profile delete does; an answered one keeps its answer. A stopped share takes no new suggestion.

## Sharing and privacy

No row of the table is part of a shared log: no reader of a log, whatever the audience, is shown a suggestion. Only the owner (on every device they sign in on) holds the record. Who else sees what:

| Who | What they see |
|---|---|
| The owner | Everything in the table: the name and message the helper typed, the fit, the helper's group ids in the owner's terms. |
| The helper | A list of what they sent: the sharer's label and the profile's name as sent, the version, their own name and message, the status, the times, and the word "changed" on a decline. Not the record. |
| The admins, other readers of the log | Nothing. |

What the owner can work out about the helper: the name they typed (which they may have made up), when they sent it (`created_at`), which version and which groups they used, how well their fit held up on the groups they held out, and that they could read the log. For a person share the owner knows who it was shared with; the typed name does not prove it was that person. The owner cannot tell who a helper on a public or admins share is.

What the helper can work out about the owner: what the log showed them, and from their list of sent suggestions the profile's name and the sharer's label as they were when it was sent (the label is the display name of a public share, or the owner's confirmed account email on a share with one person or with the admins), whether and when the owner answered, that the owner asked for a new fit, and that the profile was deleted. A later rename is not shown. A suggestion sent before 2026-10-15 shows the current names while its share is live and none once it is stopped. The list stays while both accounts exist.

---

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