Skip to content

API rejects documented collapsed-range insertion suggestions (INVALID_TRANSACTION: span must be non-empty) #10

Description

@laura-mlg

Summary

POST /v1/tmp/documents/{secret}/transactions rejects suggestion.add operations with a collapsed range (start == end), returning INVALID_TRANSACTION: "span [N, N) must be non-empty" — but the published agent documentation explicitly says collapsed ranges are the way to propose insertions.

Documentation says

From https://quarry.lithos.computer/quarry.SKILL.md (same text in /agent-docs):

Anchors are {block_id, start, end} offsets into the block's text; […] An empty replacement proposes a deletion; a collapsed range (start == end) proposes an insertion.

Reproduction (hosted server, 2026-08-19)

# 1. create a tmp document
curl -sS -X POST https://quarry.lithos.computer/v1/tmp/documents \
  -H 'Content-Type: application/json' \
  -d '{"content": "# Test\n\nAlpha paragraph.\n\nBravo paragraph."}'
# -> note document path/secret, read /blocks for a block_id and document_clock

# 2. propose an insertion at a collapsed range
curl -sS -X POST https://quarry.lithos.computer/v1/tmp/documents/<secret>/transactions \
  -H 'Content-Type: application/json' -H 'X-Agent-Id: ai:claude:repro' \
  -d '{
    "client_tx_id": "repro-collapsed-1",
    "base_clock": "<document_clock>",
    "actor": {"kind": "agent", "id": "ai:claude:repro", "label": "Claude"},
    "ops": [{"op": "suggestion.add", "block_id": "<block_id>",
             "start": 6, "end": 6, "replacement": "inserted-word "}]
  }'

Actual:

{"code":"INVALID_TRANSACTION","retryable":false,
 "message":"span [6, 6) must be non-empty",
 "details":{"op_index":0,"op":"suggestion.add","target":{"kind":"block","id":"…"}}}

Tested at offsets 0, mid-block, and end-of-block — all rejected the same way.

Expected: an open suggestion with kind: "replace", empty preview.before, rendering as an inline insertion.

Evidence the backend supports collapsed suggestions

Typing in the web editor's Suggesting mode produces exactly the object the API refuses to create — it stores and renders fine:

{"kind": "replace", "by": "user",
 "quote": "", "content": "adding something - test",
 "preview": {"before": "", "after": "adding something - test"},
 "anchor": {"blockId": "…", "startOffset": 0, "endOffset": 0}}

So this looks like transaction-layer validation being stricter than both the docs and the editor path. The practical impact for agents: there is no documented-and-working way to propose an inline text insertion via the API; multi-block suggestion.add_markdown works but is not rendered inline.

Environment

  • Server: https://quarry.lithos.computer (hosted), observed 2026-08-19
  • CLI: quarry 0.1.6 (Homebrew tap), though the issue is server-side validation

Report written with the help of an AI agent (Claude Code) driving the API; happy to provide request IDs if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions