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

# Journal-entry testing

> client.search.jeTesting — an audit procedure that publishes its own SQL

`client.search.jeTesting` runs journal-entry testing over a workspace's ledger
package and returns a `Job` whose result is a `JetResult`.

A sibling of `client.search.deep`, not a preset of it. Deep search retrieves and
cites; this performs a test: the run orients itself in the ingested ledger
tables, writes SQL over them itself, and answers with `sql_receipts` — every
statement it executed — so a figure and the query behind it travel together.

```ts theme={"dark"}
import { NdiClient, type models } from "ndi-sdk";

const client = new NdiClient({ api_key: process.env.NDI_API_KEY! });
const workspaceId = "550e8400-e29b-41d4-a716-446655440001";

let job = await client.search.jeTesting(workspaceId, {
  query: "test whether any posted journal line was approved by its own preparer",
  paths: ["ledger/journal.xlsx"],
});
job = await client.jobs.wait(job.job_id);

const result = job.result as models.JetResult;
console.log(result.answer);
for (const figure of result.figures ?? []) {
  console.log(figure.criterion, figure.count, "of", figure.population);
  console.log("  readable out of", figure.exception_listing_result_id);
}
for (const groundId of result.grounding_job_ids ?? []) {
  const grounded = await client.jobs.wait(groundId, { timeout: 300 });
  console.log(grounded.result);
}
```

`JetResult` is reachable as `models.JetResult`, the same way
`models.DeepSearchV2Result` is — search result types are not top-level exports.

***

## Method signature

```text theme={"dark"}
jeTesting(
  workspace_id: string,
  opts: {
    query: string;
    context?: string | null;
    reasoning_effort?: "none" | "minimal" | "low" | "medium" | "high";
    selection_id?: string | null;
    path_prefix?: string | null;
    paths?: string[] | null;
    session_id?: string | null;
    wait_seconds?: number;
    idempotency_key?: string | null;
  },
): Promise<Job>
```

### Parameters

| Parameter               | Type                                                     | Required | Description                                                                                                    |
| ----------------------- | -------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `workspace_id`          | `string`                                                 | Yes      | Workspace that already holds an ingested ledger package                                                        |
| `opts.query`            | `string`                                                 | Yes      | The procedure to perform, in your own words                                                                    |
| `opts.context`          | `string`                                                 | No       | Background the run should treat as given                                                                       |
| `opts.reasoning_effort` | `"none"` / `"minimal"` / `"low"` / `"medium"` / `"high"` | No       | Thinking budget; omitted uses the service default                                                              |
| `opts.selection_id`     | `string`                                                 | No       | Confirmed ledger source selection; requires a current understanding and cannot be combined with path selectors |
| `opts.path_prefix`      | `string`                                                 | No       | Limit the run to files under this prefix                                                                       |
| `opts.paths`            | `string[]`                                               | No       | The files of the package under test (max 64). Intersects with `path_prefix`                                    |
| `opts.session_id`       | `string`                                                 | No       | Continue an earlier run's thread                                                                               |
| `opts.wait_seconds`     | `number`                                                 | No       | Hold the submission request open (max 300)                                                                     |
| `opts.idempotency_key`  | `string`                                                 | No       | Override the key the SDK normally mints                                                                        |

### Returns

A `Job` whose `result` is a `JetResult` (`result_type` is `je_testing`).

***

## Reasoning budget

`reasoning_effort` changes how much the fixed JET engine thinks. Omit it to
use the service default, or select a larger budget for a more thorough run.
This does not change the model. JET no longer accepts `effort` or `tier`;
new JET jobs have `job.effort = null`.

There is no `top_k` (the run authors its own citation list) and no
`allow_clarification` (a run that cannot proceed says so in its answer).

## Reading the result

| Field               | What it is                                                                                            |
| ------------------- | ----------------------------------------------------------------------------------------------------- |
| `answer`            | The prose answer. Null only on a run that exhausted its budget first                                  |
| `figures`           | One entry per criterion: `definition`, `population`, `count`, `value`, and the `result_ids` behind it |
| `sql_receipts`      | Every statement executed, with its table bindings and a bounded preview                               |
| `binding`           | The definitional layer the run committed to — period column, posted encoding, clock                   |
| `discrepancies`     | Where the data contradicted the request's premise. Empty is an answer, not an omission                |
| `quality`           | How well a performed run went: fail-open checks, tool failures, missing artifacts                     |
| `execution_status`  | Whether the run tested what it was asked to test                                                      |
| `exhausted`         | Budget ran out before finishing — a partial answer, not a failure                                     |
| `degraded`          | The run broke before finalizing an answer; the working is published, `figures` is empty               |
| `grounding_job_ids` | Ground jobs planned for this answer's evidences. Poll each with `jobs.wait` after this result         |

A figure's `cannot_be_performed` means the workspace holds no material for that
criterion; `result_ids` then name the probes that establish the absence. A
receipt's `rows` are its bounded preview — `result_row_count` is the stored
result's real size.

There is no `usage` field on `JetResult` in this SDK, because it models no
LLM-usage shape at all; read it off the raw payload if you need it.

## Follow-ups

Pass an earlier result's `session_id` to ask a follow-up in the same thread. Only
the API key that started a thread may continue it, and a thread whose turn is
still running returns `409 session_busy`.

See [Search methods](/concepts/search-methods) and the
[je-testing API reference](/api-reference/je-testing).
