# Refuse deleting a lineup origin or landing a live link still names \(\#213\) · dara/icarus

[View on GitCafe](https://git.cafe/dara/icarus/commit/d7d9d580f8ffbebb1cf151b52b8f96888ddabe66)

Repository: [dara/icarus](https://git.cafe/dara/icarus)

Visibility: public

Requested revision: d7d9d580f8ffbebb1cf151b52b8f96888ddabe66

Requested commit: d7d9d580f8ffbebb1cf151b52b8f96888ddabe66

Commit: d7d9d580f8ffbebb1cf151b52b8f96888ddabe66

Tree: d2caac6296c26159db34d701013cab78f3e286cf

Author: Dara Adedeji

Committer: GitHub

## Message

```
Refuse deleting a lineup origin or landing a live link still names (#213)

* Refuse deleting a lineup end a live link still names

A teammate's new lineup from a shared origin could land first; deleting a
lineup on a canvas that had not drawn it yet took the origin with it, and
the server accepted that delete. The teammate's link was left without its
origin, so hydration dropped the lineup for everyone while the chip said
synced.

- Server: with the new opt-in applyBatch flag checkLineupEndDeletes, an
  origin or landing delete fails with LINEUP_END_IN_USE while a live link
  on its page names it. Links deleted earlier in the batch are already
  tombstones. Clients without the flag (shipped builds, the web build that
  sends only checkLineupLinkEnds) keep today's behavior.
- Client: sends the flag; the outbox claims link deletes first and holds an
  origin or landing delete while a link delete on its page is still unsent
  (restart key order, batch cap, another client id, backoff).
- The refusal lands in attention with a plain message. Keep mine asks
  again; use theirs brings back the origin with the teammate's lineup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Read only a page's live links when checking an end delete

Review follow-up: each origin or landing delete scanned every lineup row
on its page, tombstones and payloads included, so a batch deleting many
lineups could exceed the transaction read budget. A new index reads only
the page's live links. It is additive; Convex backfills it on deploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Check an end delete with one indexed lookup

Review follow-up: reading every live link on the page per end delete
still re-read their payloads (notes can be large) once per end, which a
batch of many deletes could push past the transaction read limit. Two
additive indexes on a link's page, kind, deleted flag and origin or
landing id let each check read at most one row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Read each page's links once per batch for end deletes

Review follow-up: the nested-path indexes went through payload.data, a
record, which Convex's schema check rejects, and a lookup still read the
whole link row once per end. Back to the live-links index: a batch reads a
page's live links once, keeps only their origin and landing ids, and
follows its own accepted link adds, patches and deletes. Reads per batch
are at most one page's live links per page, which the page snapshot query
already reads in one go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep a patched tombstone out of a batch's live links

Review follow-up: the server accepts a patch to a deleted link and leaves
it deleted, but the batch's copy of the page's live links took any
accepted payload write as live, so a later delete of that link's origin
was refused. Only an add makes a link live; a patch updates a link the
copy already holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Say why an origin or landing delete was refused

Wires LINEUP_END_IN_USE into #212's specific attention reasons, so the
sync button and toast explain the refusal instead of calling it a
conflict: another lineup in the cloud still uses the spot, Keep mine
tries again, Use cloud brings that lineup back here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
```

## Parents

- [c01bea87cea7d8d41b2d14703c48da3cc04f8459](https://git.cafe/dara/icarus/commit/c01bea87cea7d8d41b2d14703c48da3cc04f8459?format=markdown)

[Source at this commit](https://git.cafe/dara/icarus/tree/d7d9d580f8ffbebb1cf151b52b8f96888ddabe66?format=markdown)
