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

# Job editor document (snapshot)

> lastSaved vs draft vs shell projection in the Configure-tab editor

<Warning>
  **Restricted Access**: This documentation is only accessible to @tenzo.ai and @salv.ai email addresses.
</Warning>

## Goal

The Configure tab used to share fetch, save, and dirty state through hook-call order and four parallel baselines (`originalScriptValues`, JSON `lastSaved*Refs`, `orgBackgroundInfoBaselineRef`). Those clusters now share one last-confirmed snapshot.

## Three layers

| Layer        | Home                                                           | Role                                                                                                                                       |
| ------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **Draft**    | Mantine `scriptInfo` / `orgSettings` and the requirements list | What the user edits (`setFieldValue`, `getInputProps`). Not in Zustand.                                                                    |
| **Snapshot** | `jobDocumentStore.lastSaved`                                   | Last hydrate or successful persist. Dirty and discard read only this.                                                                      |
| **Shell**    | `jobSessionStore`                                              | Narrow projection for JobPage, the header, and sibling tabs (title, fetched, `JobShellSnapshot`, activation). Not a clone of `ScriptInfo`. |

Unsaved state is not in either store. It lives in `useScriptFormState` as two flags plus their synchronous nav refs, and dirty is a function of the draft: `useScriptDirtyCheck` is keyed on form values and reads the snapshot at comparison time. Anything that moves `lastSaved` away from the draft therefore has to write the form in the same turn or set the flag itself, because no comparison is scheduled on a commit's behalf.

`orgBackgroundInfoBaselineRef` is still the PATCH gate: a failed org GET leaves it unchanged (or null if it never loaded) so the editor will not write empty defaults over org-wide settings. Hydrate on failure copies that leftover baseline into `lastSaved.orgBackground` instead of an empty sentinel. Discard restores org text from the baseline ref, not from a failed-GET snapshot.

## Actions

* **`hydrate(campaignId, snapshot)`** — fetch writes this once after `mapScriptRead` and `settleFetchedScript` (virtual-calendar follow-up users, session auto-match, new-script default outro). Then one `setValues`.
* **`commit(campaignId, patch)`** — save (and question-bank persist, org PATCH, version-restore clocks) merge into `lastSaved`. No-op if `campaignId` does not match or `lastSaved` is null. Clock fields (`currentScriptVersionId`, `cosmosUpdatedAt`) only advance when the patch value is non-null.
* **`clear(campaignId)`** — campaign switch. Same turn as form reset so a late commit of the previous job cannot land.

`lastSaved == null` means “not hydrated yet.” Dirty skips; the post-generation one-shot waits.

## Late settle

Calendar provider, SWR outro text, and session auto-match can arrive after hydrate. A small effect patches only fields the draft still matches on `lastSaved` (so a dirty call intro cannot block a virtual-calendar user clear), then `commit`s those same field patches. User edits to a settled field are left alone. Post-generation one-shot save waits until calendar integration has resolved so it cannot persist pre-settle values.

## What this page does not cover

* **Phase 2** — collapse fetch/save/version into `useJobDocumentController`.
* **Phase 3** — provider composition. `JobDocumentProviders` nests four providers; its doc comment describes the grouping.
* **Phase 4** — org-template bootstrap aggregator. See [Job editor bootstrap](/internal/job-editor-bootstrap).
