← all model tests
Wrightpass

a device that notifies nothing must be written to before any driver is emitted

Subscribing returned not one frame. There is nothing to decode, so there is nothing to emit, and the only honest move is a probe that writes the control byte the vendor characteristic advertises write-without-response for. A driver emitted here would be decoding an empty set. The device also states its hand: 0000fff1 carries a 0x2901 descriptor reading 'Control Point', and a packet capture of the vendor app shows it written on connect. Without that evidence the contract's own rule — never write to a characteristic on a hunch — makes refusing to write the correct answer, so the scenario has to supply the grounds it is testing the use of.

The answer conformed to the contract and every assertion held.

modelgemini-3.5-flash
temperature0
scenarioscenarios/wright/silent-until-control-write.json
cassette06bf2be35e40ba5a
latency0.0s
tokens4,668
What the model was given
System instructionassembled from the contract schema, not hand-written
You are meeting a Bluetooth Low Energy device nobody has written a driver for, and your job is to work out which characteristic carries a physical reading and exactly how it is encoded. Prefer evidence over inference, in this order: a 0x2904 presentation-format descriptor states the format, exponent and unit outright and must be read rather than guessed; a Bluetooth SIG assigned service or characteristic has a published encoding you already know; only when neither exists may you infer from the bytes. Probe before you commit — a driver emitted from a single frame is a guess wearing a uniform. You must never emit a driver whose unit you cannot name, and you must never emit one for a characteristic that plausibly carries battery level, firmware revision, a sequence counter or a status flag rather than a reading. Abandoning with a clear reason is a correct outcome and is worth more than a driver that decodes something into a believable wrong number.

Return JSON with these fields:
- mode (one of probe | emit | abandon, required): probe while anything material about the encoding is unknown. emit once a driver would decode correctly. abandon when this device cannot be driven and you can say why.
- understanding (string, required): What you now believe this device is and which characteristic carries the reading, in two sentences. Written every turn so a wrong track is visible early rather than at the end.
- evidence (array, required): What in the GATT tree, the advertisement or the frames supports your current belief. Cite the actual UUID, descriptor or byte offset. An empty list means you are guessing and should be probing instead.
- unresolved (array, required): Everything still unknown that would change the driver. Empty is the only condition under which you may emit.
- probe (object, null when it does not apply): Required when mode is probe. One operation for the phone to perform against the device.
- driver (object, null when it does not apply): Required when mode is emit. Kotlin implementing the Driver interface in android/app/src/main/java/ink/warrant/instrument/Driver.kt.
- abandon (object, null when it does not apply): Required when mode is abandon. Saying why is the deliverable.
## What the device advertises
{
  "name": "TQ-PRO",
  "service_uuids": [
    "0000fff0-0000-1000-8000-00805f9b34fb"
  ]
}

## The GATT tree as enumerated
[
  {
    "service": "0000fff0-0000-1000-8000-00805f9b34fb",
    "name": null,
    "characteristics": [
      {
        "uuid": "0000fff1-0000-1000-8000-00805f9b34fb",
        "properties": [
          "write_without_response"
        ],
        "descriptors": [
          {
            "uuid": "00002901-0000-1000-8000-00805f9b34fb",
            "name": "Characteristic User Description",
            "value": "Control Point"
          }
        ]
      },
      {
        "uuid": "0000fff2-0000-1000-8000-00805f9b34fb",
        "properties": [
          "notify"
        ],
        "descriptors": []
      }
    ]
  }
]

## Frames captured, by characteristic
Hex, in arrival order. A value that never changes across a capture is not necessarily static — it may simply be a quantity that did not move.

{
  "0000fff2-0000-1000-8000-00805f9b34fb": []
}

## What you have already tried on this device
Including any driver that was rejected and the gate that rejected it. A gate that failed will not pass because the next attempt is more confident: change the decoding, or abandon.

[
  "subscribed to 0000fff2 for 30 s and received no notifications",
  "the vendor's own app writes a single byte to 0000fff1 immediately after connecting, observed with a packet capture; the value written was 0x01"
]

## The interface your driver must implement
This is the actual file, read off disk. Your class has to satisfy every member of it — a class carrying only a decode function does not implement this interface and will not compile, however correct its arithmetic is. Note where the UUIDs live: `matches` and `characteristicFor` carry them, so the class names the device it is for.

```kotlin
package ink.warrant.instrument

import android.bluetooth.BluetoothGattCharacteristic
import java.util.UUID

/**
 * The driver contract, from `docs/architecture.md` §5.
 *
 * ```
 * Driver
 *   matches     scan filter — service UUID, name prefix, manufacturer data
 *   produces    kind: measurement · unit · range
 *   read()      raw bytes → { value, unit, tool_id, timestamp, raw }
 * ```
 *
 * NOTHING ABOVE THIS CARES WHICH TOOL IT IS. A `measurement` field knows only that a number
 * arrived from a paired device without passing through a human, and that is the sole property
 * that makes it *measured* rather than typed. A new tool is a driver, not a schema change.
 *
 * This is the seam Wright writes into: point it at an unfamiliar device, it enumerates the
 * GATT services, infers the encoding, and emits one of these.
 */
interface Driver {

    /** Stable identifier for the driver itself, not the device. Goes onto the record. */
    val id: String

    /** Human-facing name, for the pairing screen. */
    val label: String

    /** What this driver produces. The unit is fixed by the driver, never chosen by a person. */
    val produces: Produces

    /** The scan filter. A device matches if any of these is satisfied. */
    val matches: Match

    /**
     * Which characteristic on a connected device this driver reads. Returning null means "this
     * device advertised the right thing but does not actually expose the characteristic", which
     * is a real and common failure and must not be confused with a zero reading.
     */
    fun characteristicFor(services: List<UUID>): CharacteristicRef?

    /**
     * Raw bytes to a value. The one place a wire format is understood.
     *
     * Returning null means "these bytes are not a reading" — a keep-alive, a status frame, a
     * truncated packet. A driver that guesses here produces a plausible number from nonsense,
     * which is the single worst thing it could do.
     */
    fun decode(raw: ByteArray): Double?
}

data class Produces(
    val unit: String,
    /** Plausible range. Outside it, the reading is reported but flagged — see [Driver.decode]. */
    val min: Double,
    val max: Double,
)

data class Match(
    val serviceUuids: List<UUID> = emptyList(),
    val namePrefixes: List<String> = emptyList(),
)

data class CharacteristicRef(val service: UUID, val characteristic: UUID)

/**
 * Whether a value is inside what this driver claims it can produce.
 *
 * This is a PLAUSIBILITY check and nothing more. It will not catch a wrong scale factor that
 * yields a sensible-looking number — see architecture.md §5, which chooses this deliberately
 * over the aviation route of certified tooling and formal verification. Good enough, cheap, and
 * honest about which it is.
 */
fun Produces.plausible(value: Double): Boolean = value in min..max

/** Convenience for the 16-bit Bluetooth SIG UUIDs, which are all offsets into one base. */
fun sig(short: Int): UUID =
    UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", short))

internal fun BluetoothGattCharacteristic.supportsNotify(): Boolean =
    properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0

internal fun BluetoothGattCharacteristic.supportsRead(): Boolean =
    properties and BluetoothGattCharacteristic.PROPERTY_READ != 0

```

## Your budget
{
  "probes used": 2,
  "probes left": 4,
  "note": "A driver emitted from a single frame is a guess wearing a uniform. But probing forever is also a failure: if the budget runs out, abandon and say what a person with the vendor's documentation would need to finish."
}
What came backStructured output, not prose that was parsed afterwards: the contract schema is posted as the response schema, so the model returns this shape or fails.
{
  "mode": "probe",
  "understanding": "The TQ-PRO device requires a control byte write of 0x01 to characteristic 0000fff1 to start streaming notifications on characteristic 0000fff2. We need to perform this write and subscribe to 0000fff2 to capture the measurement frames.",
  "evidence": [
    "GATT service 0000fff0-0000-1000-8000-00805f9b34fb contains write characteristic 0000fff1 (Control Point) and notify characteristic 0000fff2",
    "Vendor app packet capture showed a write of 0x01 to 0000fff1 immediately after connecting"
  ],
  "unresolved": [
    "The format, encoding, and physical unit of the measurement data streamed from 0000fff2"
  ],
  "probe": {
    "op": "write_then_subscribe",
    "service": "0000fff0-0000-1000-8000-00805f9b34fb",
    "characteristic": "0000fff1-0000-1000-8000-00805f9b34fb",
    "bytes": "01",
    "samples": 10,
    "why": "Writing 0x01 to the Control Point (0000fff1) is expected to trigger the device to start notifying measurement frames on 0000fff2."
  },
  "driver": null,
  "abandon": null
}
What this scenario asserted

Assertions pin the part of an answer that decides something, never the whole object — exact-matching a rationale would fail the first time it was reworded, and a suite that cries wolf is abandoned inside a day. Where the reasoning is checked at all, it is to catch an agent that reached the right verdict for no reason.

assertedaboutwhat happened
okequalsmodeis probe, want probe
okabsentdriveris None
okinprobe.opis write_then_subscribe, want one of ['write_then_subscribe']