# Checked Target API Examples

These literate tests mirror the high-value target API examples in
[`incr/README.mbt.md`](../incr/README.mbt.md) and [`getting-started.mbt.md`](getting-started.mbt.md).
They exist to catch docs/API drift for the recommended facade names, read
semantics, committed-change callbacks, and batch rollback behavior.

```mbt check
///|
suberror TargetApiBatchResultError {
  TargetApiBatchStop
}

///|
test "docs target api: direct constructor quick start" {
  let rt = @incr.Runtime()
  let x = rt.input(10, label="x")
  let y = rt.input(20, label="y")
  let sum = x.derived2(y, (a, b) => a + b, label="sum")
  let doubled = sum.map(v => v * 2, label="doubled")

  inspect(sum.read_or_abort(), content="30")
  inspect(doubled.read_or_abort(), content="60")
  x.set(5)
  inspect(doubled.read_or_abort(), content="50")
}

///|
test "docs target api: direct runtime read and update" {
  let rt = @incr.Runtime()
  let price = @incr.Input(rt, 100, label="price")
  let quantity = @incr.Input(rt, 5, label="quantity")
  let total = @incr.Derived(
    rt,
    () => price.get() * quantity.get(),
    label="total",
  )

  inspect(total.read_or_abort(), content="500")
  quantity.set(10)
  inspect(total.read_or_abort(), content="1000")
}

///|
test "docs target api: input views restrict authority at API boundaries" {
  let rt = @incr.Runtime()
  let input = @incr.Input(rt, 10, label="input")
  let view : @incr.InputView[Int] = input[:]
  let doubled = @incr.Derived(rt, () => view.get() * 2, label="doubled")

  inspect(doubled.read_or_abort(), content="20")
  input.set(21)
  inspect(doubled.read_or_abort(), content="42")
}

///|
test "docs target api: scope constructors own lifecycle" {
  let rt = @incr.Runtime()
  let scope = @incr.Scope::new(rt)
  let x = scope.input(10, label="x")
  let y = scope.input(20, label="y")
  let sum = scope.derived(() => x.get() + y.get(), label="sum")

  inspect(sum.read_or_abort(), content="30")
  scope.dispose()
  inspect(scope.is_disposed(), content="true")
}

///|
test "docs target api: committed-change callback skips same-value input set" {
  let rt = @incr.Runtime()
  let quantity = @incr.Input(rt, 10, label="quantity")
  let changes : Ref[Int] = { val: 0 }
  rt.set_on_change(() => changes.val = changes.val + 1)

  quantity.set(12)
  inspect(changes.val, content="1")

  quantity.set(12)
  inspect(changes.val, content="1")
}

///|
test "docs target api: batch_result rolls back raised errors" {
  let rt = @incr.Runtime()
  let amount = @incr.Input(rt, 100, label="amount")
  let result = rt.batch_result(fn() raise {
    amount.set(999)
    raise TargetApiBatchStop
  })

  inspect(result is Err(_), content="true")
  inspect(amount.get(), content="100")
}

///|
test "docs target api: read result and strict get inside derived" {
  let rt = @incr.Runtime()
  let base_price = @incr.Input(rt, 100, label="base_price")
  let quantity = @incr.Input(rt, 2, label="quantity")
  let tax_rate = @incr.Input(rt, 0.1, label="tax_rate")
  let subtotal = @incr.Derived(
    rt,
    () => base_price.get() * quantity.get(),
    label="subtotal",
  )
  let tax = @incr.Derived(
    rt,
    () => subtotal.get_or_abort().to_double() * tax_rate.get(),
    label="tax",
  )
  let total = subtotal.map2(tax, (s, t) => s.to_double() + t, label="total")

  match total.read() {
    Ok(value) => inspect(value, content="220")
    Err(err) => abort(err.format_path())
  }

  quantity.set(3)
  inspect(total.read_or_abort(), content="330")
}

///|
test "docs target api: watch keeps derived live across gc" {
  let rt = @incr.Runtime()
  let input = @incr.Input(rt, 1, label="input")
  let watch = {
    let derived = input.derived(v => v + 1, label="derived")
    derived.watch()
  }

  inspect(watch.read_or_abort(), content="2")
  rt.gc()
  input.set(2)
  inspect(watch.read_or_abort(), content="3")
  watch.dispose()
}
```
