> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trysinker.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Debug

> Fault injection and demo automation for testing autonomous recovery without real network failures.

<Warning>
  Debug methods are intended for testing only. Do not call `injectFault()` in production — it will cause the next real submission to return a synthetic failure.
</Warning>

## Overview

The `sinker.debug` object provides access to the fault injection system. Register a fault before enqueueing a transaction to simulate any failure class on demand.

```ts theme={null}
// Register a fee_too_low fault
await sinker.debug.injectFault('fee_too_low');

// Enqueue a real transaction — the next submit will be faulted
const handle = await sinker.enqueue(rawTxBase64);

// The agent retries automatically
const result = await handle.waitFor('finalized');
```

***

## Methods

### debug.injectFault()

Register a one-shot synthetic failure to inject into the next `POST /internal/submit` call.

```ts theme={null}
const result = await sinker.debug.injectFault(failureClass, rawError?);
```

<ParamField path="failureClass" type="FaultClass" required>
  The failure class to inject. One of:

  * `'fee_too_low'`
  * `'expired_blockhash'`
  * `'bundle_failed'`
  * `'compute_exceeded'`
  * `'slot_skip'`
</ParamField>

<ParamField path="rawError" type="string">
  Optional custom error string stored in the lifecycle entry's `raw_error` field.
  Defaults to `"Injected fault: {failureClass} (demo)"`.
</ParamField>

**Returns:** `Promise<FaultInjectResult>`

<ResponseField name="ok" type="boolean">
  `true` when the fault was registered successfully.
</ResponseField>

<ResponseField name="next_failure" type="FaultClass">
  The failure class that was registered (echoed back for confirmation).
</ResponseField>

**Example — test each failure class:**

```ts theme={null}
const faultClasses = [
  'fee_too_low',
  'expired_blockhash',
  'slot_skip',
] as const;

for (const fc of faultClasses) {
  await sinker.debug.injectFault(fc);
  const handle = await sinker.enqueue(rawTxBase64);

  const entries = await handle.lifecycle();
  const faulted = entries.find(e => e.stage === 'failed');
  console.log(fc, '→', faulted?.failure?.type);
}
```

***

### debug.runFaultDemo()

Register a fault and enqueue a transaction in one call. Returns the fault registration result and the tx handle.

```ts theme={null}
const { faultRegistered, tx_id } = await sinker.debug.runFaultDemo(
  'fee_too_low',
  rawTxBase64,
);

console.log('Fault registered:', faultRegistered);
console.log('Transaction ID:', tx_id);
```

<ParamField path="failureClass" type="FaultClass" required>
  The failure class to inject.
</ParamField>

<ParamField path="txBytes" type="string" required>
  Base64-encoded pre-signed transaction bytes.
</ParamField>

**Returns:** `Promise<{ faultRegistered: boolean; tx_id: string }>`

***

## What the sidecar does on a faulted submit

When a fault is registered and `POST /internal/submit` is called:

1. The tx queue is drained normally and bytes are retained for retry
2. The fault spec is consumed (cleared from `next_fault`)
3. A lifecycle entry is written with `stage: "failed"` and the specified `failure_class`
4. `TxStatusChanged` SSE events are emitted for each `tx_id`
5. A `BundleSettled` SSE event fires with `stage: "failed"` and `failure_type`
6. HTTP 200 is returned with a structured result — **no Jito call is made**

The agent receives the SSE events and executes its normal retry policy, including fetching raw bytes via `GET /tx/raw/:tx_id` and re-enqueueing.

***

## Fault coverage

All five failure classes have been validated against the full agent retry cycle on mainnet-beta:

| Class               | Fault injected | Agent retry                  | Result |
| ------------------- | -------------- | ---------------------------- | ------ |
| `fee_too_low`       | ✅              | Escalate tip to p95          | ✅ PASS |
| `expired_blockhash` | ✅              | Re-enqueue (fresh blockhash) | ✅ PASS |
| `bundle_failed`     | ✅              | Inspect error → retry        | ✅ PASS |
| `compute_exceeded`  | ✅              | Hold (instruction broken)    | ✅ PASS |
| `slot_skip`         | ✅              | Re-enqueue (same tip)        | ✅ PASS |
