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

# Ingest outcomes & feedback

> ntro.ingest — canonical ingest-stage models, persistence helpers, and workflow feedback for file-upload steps.

Ingest sits between **unstructured input** (bytes, CSV uploads) and **typed subledger rows**. Runbooks use **`ntro.ingest`** for shared **outcome contracts** and **tenant Postgres writes** into the `ingest` schema — see also [Subledgers](/sdk/subledgers) for `ledgers.*` and [Workflows overview](/workflows/runbooks/overview) for orchestration.

## Package layout

| Module                                          | Role                                                                                                                           |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `ntro.ingest.IngestOutcome`                     | Structured summary of one ingest attempt: parsed/accepted/rejected counts, status, message, optional `reasons` and `progress`. |
| `IngestIssueSummary` / `IngestProgressSnapshot` | Supporting types for reject reasons and progress gates.                                                                        |
| `insert_submitted_record`                       | Persists structured rows to `ingest.submitted_records` (data-ingest / agent submissions).                                      |
| `insert_extracted_record`                       | Persists reviewed AI extraction to `ingest.extracted_payloads`.                                                                |

`IngestOutcome` is re-exported from `ntro.workflow` next to `NtroWorkflow` so workflow code can depend on a single import surface.

## User feedback from workflows

`NtroWorkflow.set_user_feedback(kind=..., payload=...)` attaches a **workflow-agnostic envelope** to the current pending action:

* Top-level `feedback` on the pending action
* `display_hint.config.feedback` for **Tenant UI** components (e.g. `FILE_UPLOAD` reads `kind: "ingest"` and shows counts / message)

While a signal gate is open (e.g. waiting for more accepted rows), **`await_signal_with_action`** merges the latest stored feedback into the merged action so operators keep seeing progress.

## Example: attach ingest feedback

```python theme={null}
from ntro.ingest import IngestOutcome
from ntro.workflow import NtroWorkflow

class MyWorkflow(NtroWorkflow):
    async def _step_collect(self, ctx) -> dict:
        outcome = IngestOutcome(
            parsed_rows=100,
            accepted_rows=0,
            rejected_rows=100,
            status="empty",
            message="No rows matched required columns after parse.",
        )
        self.set_user_feedback(kind="ingest", payload=outcome)
        await self.await_signal_with_action(
            predicate=lambda: self._have_enough_rows(),
            action={"kind": "submit_file", "reason": "Upload expense CSV."},
            display_hint={
                "component": "FILE_UPLOAD",
                "config": {"title": "Upload expenses"},
            },
        )
```

## Data lifecycle (reference)

1. **Unstructured** — raw files / bytes (`ingest.submitted_documents`).
2. **Loosely structured** — `ntro.ingest` outcomes + `ingest.submitted_records` / events.
3. **Structured + typed** — `ntro.subledger` / `ledgers.*`.
4. **External GL shape** — `ntro.capabilities.gl` posting contracts when applicable.

## Related

<CardGroup cols={2}>
  <Card title="Workflows overview" icon="diagram-project" href="/workflows/runbooks/overview">
    `NtroWorkflow`, `@runbook.step`, and pending-action wiring.
  </Card>

  <Card title="Subledgers" icon="table" href="/sdk/subledgers">
    Domain rows after ingest.
  </Card>
</CardGroup>
