proposal. This is the one error that is good news: your
follow-up turn would change what the session is looking for and needs new source
passes, so it was recorded, not run, and came back priced. Nothing has been
charged. It’s a 409 — not a 200 with a flag — precisely so a naive retry loop can
never silently spend.
The shape
kept_rows is what the session already holds and keeps either way; passes and
estimated_usd are what saying yes costs.
How to proceed
- Confirm: re-POST the same turn with
"confirm": true— sametext, a freshIdempotency-Key(the body changed; reusing the old key gets idempotency_conflict, not a silent spend). The confirmed run reserves its own estimate. - Or pre-authorize: send
max_spend_usd≥ the estimate on the original turn and the proposal runs without the 409 round-trip. - Or decline: do nothing, or post a different turn — a new non-confirm turn voids the outstanding proposal (at most one is outstanding per session; the newest ask wins).
- Proposals expire after 24 hours. A late confirm doesn’t run at stale prices — the
server responds with a fresh proposal (new estimate, new
expires_at).
Reproduce it
Deterministic on anfn_test_ key with the
FN_TEST_PROPOSAL sentinel: create a session with the sentinel
in the query, then post the first follow-up turn — it returns this 409, $0: