---
name: STAGESHARE_LOGS
for: wellscope.stageshare/1.0.0
homepage: https://dx.horizontalwireline.ai/STAGESHARE_LOGS.md
---

# Stage Share LAS — promote, Sync, depths, resend, inject

Room LAS is isolated from partner `GET /v1/logs`. Contract stays `wellscope.stageshare/1.0.0`. Privilege `stageshare`. Operator `hwx_` writes. Guests read with `sst_`. Verified `@hwireline.com` / `@hwireline.ai` invite sessions are room admins (`you.admin`) and may relabel, hide/remove, add, and ask the cabin to Sync.

Canonical: `GET https://dx.horizontalwireline.ai/STAGESHARE_LOGS.md`

Heartbeat / CCLR lead: [`/STAGESHARE_UPLINK.md`](https://dx.horizontalwireline.ai/STAGESHARE_UPLINK.md).

## Columns

`tally` | `live` | `rih` | `corr` | `pump` | `pooh`

- **live** — current recorder file. Append only. Do not PATCH it to another column (`409 cannot_reassign_live`).
- **Promote** copies live bytes into a **frozen** slot (`rih` / `corr` / `pump` / `pooh` / `tally`) and resets live to 0 bytes so the next pass appends from offset 0.

Promote at **end of that pass**, before the tool turns around. If you wait until uphole (or RIH) has already started, those extra feet are in the live file and will move with it.

## Always read the span first

DX measures first/last `DEPT` from the bytes on disk (not just the header, not the gold tool line).

```
GET /v1/stageshare/rooms/{id}/logs/{lid}
Authorization: Bearer hwx_…
```

```
{
  "id": "log_…",
  "filename": "CURRENT-Unit_2.LAS",
  "column_id": "live",
  "bytes": 6135,
  "depth_min_ft": 8.0,
  "depth_max_ft": 14.5,
  "span": {
    "first_ft": 8.0,
    "last_ft": 14.5,
    "min_ft": 8.0,
    "max_ft": 14.5,
    "n_rows": 26,
    "bytes": 6135,
    "direction": "in"
  }
}
```

`direction` is `in` (last > first), `out` (last < first), or `hold`.

Dry-run the move (no copy, live untouched):

```
POST /v1/stageshare/rooms/{id}/logs/{lid}/promote
{
  "preview": true,
  "column_id": "rih",
  "filename": "2026-08-31_13-40-00-RIH.LAS"
}
```

200 `{ preview: true, live_id, bytes, column_id, filename, span, existing_frozen_id, reuse }`.

Confirm `span.last_ft` is the **end of that pass**, not the current tool if it already reversed. Example of a bad promote: RIH ended ~8080, tool already walking up, `span.last_ft` is 8068 `direction: out` — do **not** commit that to RIH.

## Commit only if the depths match

```
POST /v1/stageshare/rooms/{id}/logs/{lid}/promote
{
  "column_id": "rih",
  "filename": "2026-08-31_13-40-00-RIH.LAS",
  "expect_first_ft": 8.0,
  "expect_last_ft": 8080.0,
  "expect_tol_ft": 2
}
```

- Omit `expect_*` to move anyway (legacy).
- Mismatch → **409** `{ "error": "depth_mismatch", "field", "expected", "got", "tol_ft", "span" }`. Live file stays. Fix the recorder or wait, then preview again.
- Optional `expect_depth_min_ft` / `expect_depth_max_ft` (min/max of first and last).
- Default tolerance **2 ft**.
- Optional `depth_min_ft` / `depth_max_ft` still stored as labels; if omitted, DX stores the measured min/max.
- 201 new frozen slot when that **filename** is new. 200 reused the row with the **same filename**. A different filename on the same column creates a new row and **keeps** the previous occupant visible so both passes plot until someone hides one. Relabel/Move (`PATCH`) still hides a displaced occupant.
- Depth comments written on **live** whose `depth_ft` sits in the promoted span move to the destination column (`moved_comments` on the 201/200 and on WS `log-promoted`). Chat rows (`depth_ft` null) stay put.
- Live `id` is unchanged, `bytes: 0`. Next append `X-Append-Offset: 0`.
- Sync never promote-resets live. Use promote only at end of a pass.

Do **not** PUT the same body after a successful promote.

## Resend if the frozen copy is wrong or lost

The frozen `id` from promote (or `GET …/logs`) is the slot. Replace bytes in place:

```
PUT /v1/stageshare/rooms/{id}/logs/{frozen_id}/content
Authorization: Bearer hwx_…
Content-Type: text/plain
```

Body = the full LAS (trimmed / reprocessed). 204. DX remasures depths and broadcasts `las-update`. Guests refetch that id.

Works while the room is `live` **or** `frozen` (5-day recording window). Not after revoke / purge.

If you never got an id: `POST …/logs` `{ "filename", "column_id": "rih", "role": "frozen" }` (reuses the newest row with that **filename**, or the live slot) then PUT.

## Sync (Pi inventory is the source of truth)

The cabin Edge Stage View posts what it is actually showing. DX diffs and does **not** delete extras.

```
POST /v1/stageshare/rooms/{id}/logs/sync
Authorization: Bearer hwx_…
{
  "columns": [
    { "column_id": "rih", "filename": "2026-08-31_12-01-19-RIH.LAS", "bytes": 1163291, "depth_min_ft": -25, "depth_max_ft": 5150.5 },
    { "column_id": "live", "filename": "CURRENT-Unit_2.LAS", "bytes": 2790034 }
  ]
}
```

Response buckets:

- `matched` — same name + bytes on that column
- `stale` — same name, different bytes and/or column → `{ id, action: "put", want_column_id, want_bytes }`
- `missing` — on Pi, not on DX → `{ action: "create_then_put", column_id, filename }`
- `extra` — on DX, not in the Pi list (keep; admin may hide or delete)

Then for each `missing` / `stale`:

1. `POST …/logs` `{ filename, column_id, role }` — reuse **only** when the filename matches that id (or the live slot). Do not reuse “newest RIH” and clobber another pass.
2. Frozen / reference: `PUT …/content`. Live: append-only (`X-Append-Offset`). Sync never promote-resets live.

Staff on an invite (`you.admin`) can `POST …/logs/sync/request`. Hub broadcasts `sync-needed`. If the last Pi handshake is older than 2 minutes → **409** `cabin_offline`. Overlay: “Cabin will sync” vs “Cabin offline — run Sync on the Pi”.

When `you.admin` is true, the guest LAS list shows column `<select>`, Remove, **Add LAS**, and **Sync**. Cabin Copy `ss_` has no email and is never admin. Visibility-only PATCH stays any `sst_`.

## Inject a reprocessed file after the fact

Same two calls. Use a new filename. `role` is `frozen` (or `reference` / `collars` on `tally`). Not `live` on a recorded room.

```
POST /v1/stageshare/rooms/{id}/logs
{
  "filename": "2026-08-31_13-40-00-RIH-reprocess.LAS",
  "column_id": "rih",
  "role": "frozen"
}
```

201 `{ id, reuse, upload: { mode: "single" } }`. Then `PUT …/logs/{id}/content` with the file.

Reuse `true` means that **filename** already had a row. A new filename creates a new row (413 at the 48-object cap). Relabel (`PATCH { column_id }`) onto an occupied column **hides** the previous occupant (`visible: false`); it is not deleted.

Cap remains **48** objects. 413 if a new slot is required at the cap.

## What not to do

- Do not promote because the tool line moved. Promote because **this pass’s LAS** is finished.
- Do not promote a few seconds after turnaround and hope DX trims the extra feet. Preview `span` / `direction` first.
- Do not PATCH live → rih.
- Do not POST this to `/v1/inbound` or partner `/v1/logs`.
- Do not bump `wellscope.stageshare` — 1.0.0 already allows promote, preview, expect, PUT replace, and Sync.
