# What does openai.fine_tuning_job.succeeded prove?

> Prove that the fine-tuning job finished and named a model. Version 1.0.0, certification Provisional.

Canonical: https://provely.sh/verify/openai/openai.fine_tuning_job.succeeded  
Last reviewed: 2026-09-05  
Skill version: 0.1.0  
Certification: provisional  

**Prove that the fine-tuning job finished and named a model. The job reached the status succeeded and the member fine_tuned_model holds a name. The level does not prove that the model answers a request. No published operation states that.**

*Contract identity.*

| Fact | Value |
| --- | --- |
| Contract id | `openai.fine_tuning_job.succeeded` |
| Version | `1.0.0` |
| Hash | `13b56dac6222a5f4` |
| Completion level | `succeeded` |
| Publisher | Built and signed by Provely. |
| Certification | Provisional |
| Skill | [OpenAI Platform API 0.1.0](/verify/openai) |
| Valid for provider API versions | `spec_2_3_0` |

## What is the intent?

Fine-tune the base model on the training file.

## What is the subject and the action?

| Member | Value |
| --- | --- |
| Subject type | `openai.fine_tuning_job` |
| Subject identity | fine_tuning_job_id = `$action.result.id` |
| Canonical effect | `ai.fine_tuning_job_start` |
| Provider operation | `POST /fine_tuning/jobs` |
| Idempotency | none, retry is not safe |

## How does the evidence correlate with this operation?

| Strategy | Assurance | Keys | Required |
| --- | --- | --- | --- |
| `resource_id` | strong | fine_tuning_job_id from `$action.result.id` | yes |
| `fingerprint` | weak | training_file from `$input.training_file` | no |

## Which evidence does the contract require?

Minimum evidence level `E2`. An independent channel is required. Minimum channels: 1.

| Channel | Level | Independence | Verifier | Description |
| --- | --- | --- | --- | --- |
| `fine_tuning_job_readback` | E2 | provider readback | `http` | Read the fine-tuning job from the provider. A condition path is $observed.fine_tuning_job_readback.status, and a second one is $observed.fine_tuning_job_readback.fine_tuned_model. |
| `fine_tuning_job_succeeded_events` | E3 | provider event | `webhook` | The fine_tuning.job.succeeded events of this job. The payload carries the identifier of the job and no other member of it, so the name of the model comes from the read-back. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. |

## Which conditions must all hold for VERIFIED?

| Condition | Meaning | Path | Operator | Expected | Evidence |
| --- | --- | --- | --- | --- | --- |
| `fine_tuning_job_present` | The provider holds the job with the returned identifier. | `$observed.fine_tuning_job_readback.id` | `eq` | `$action.result.id` | `fine_tuning_job_readback` |
| `fine_tuning_job_status_succeeded` | The job reached the status succeeded. | `$observed.fine_tuning_job_readback.status` | `eq` | `succeeded` | `fine_tuning_job_readback` |
| `fine_tuning_job_named_a_model` | The member fine_tuned_model holds a name. The schema states that the value is null while the job runs. | `$observed.fine_tuning_job_readback.fine_tuned_model` | `exists` | `undefined` | `fine_tuning_job_readback` |
| `fine_tuning_job_training_file_matches` | The job trained on the file that the intent named. | `$observed.fine_tuning_job_readback.training_file` | `eq` | `$input.training_file` | `fine_tuning_job_readback` |
| `fine_tuning_job_created_in_window` | The provider created the job after the operation started. OpenAI writes created_at in seconds since the epoch. | `$observed.fine_tuning_job_readback.created_at` | `time_after` | `$operation.created_at` | `fine_tuning_job_readback` |
| `fine_tuning_job_finished_in_window` | The provider finished the job after the operation started. The schema states that finished_at is null while the job runs. | `$observed.fine_tuning_job_readback.finished_at` | `time_after` | `$operation.created_at` | `fine_tuning_job_readback` |
| `fine_tuning_job_succeeded_event` | At least one fine_tuning.job.succeeded event names this job. | `$observed.fine_tuning_job_succeeded_events.count` | `gte` | `1` | `fine_tuning_job_succeeded_events` |

## Which conditions give CONTRADICTED?

| Condition | Class | Reason | Path | Operator | Expected |
| --- | --- | --- | --- | --- | --- |
| `fine_tuning_job_on_wrong_training_file` | wrong subject | The job trained on a different file than the intent named. | `$observed.fine_tuning_job_readback.training_file` | `ne` | `$input.training_file` |
| `fine_tuning_job_predates_operation` | pre existing state | The fine-tuning job is older than the operation. It proves nothing. | `$observed.fine_tuning_job_readback.created_at` | `time_before` | `$operation.created_at` |

## Which observed states map to a verdict before completion?

| Rule | Match | Verdict | Reason |
| --- | --- | --- | --- |
| `terminal_failure` | `$observed.fine_tuning_job_readback.status` eq `"failed"` | FAILED | The training did not finish. The member error of the job states the cause. |
| `cancelled` | `$observed.fine_tuning_job_readback.status` eq `"cancelled"` | CONTRADICTED | A person or an agent cancelled the fine-tuning job. Ask a person before a second run starts. |
| `still_running` | `$observed.fine_tuning_job_readback.status` in `["validating_files","queued","running"]` | PENDING | The job has not reached a terminal status. The training may take hours, so the runtime observes again later. |

## How long does the runtime observe?

| Timing member | Value |
| --- | --- |
| Initial delay | 1000 ms |
| Poll interval | 30000 ms |
| Backoff | exponential factor 2, max 1800000 ms |
| Maximum attempts | 360 |
| Timeout | 604800000 ms |
| Stale read window | 60000 ms |
| On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person |

## Where do these rules come from?

- `openai.openapi#/paths/~1fine_tuning~1jobs/post`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/paths/~1fine_tuning~1jobs/post/responses/200`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/components/schemas/FineTuningJob/properties/status`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/components/schemas/FineTuningJob/properties/fine_tuned_model`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.docs.fine_tuning#fine-tuning-jobs/the-status-of-a-fine-tuning-job`: [openai.docs.fine_tuning](https://platform.openai.com/docs/guides/supervised-fine-tuning), retrieved 2026-09-09
- `openai.openapi#/components/schemas/FineTuningJob/properties/id`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/paths/~1fine_tuning~1jobs~1{fine_tuning_job_id}/get/responses/200`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.docs.fine_tuning#fine-tuning-jobs/the-members-that-a-running-job-leaves-empty`: [openai.docs.fine_tuning](https://platform.openai.com/docs/guides/supervised-fine-tuning), retrieved 2026-09-09
- `openai.docs.fine_tuning#fine-tuning-jobs/the-fine-tuned-model`: [openai.docs.fine_tuning](https://platform.openai.com/docs/guides/supervised-fine-tuning), retrieved 2026-09-09
- `openai.openapi#/components/schemas/FineTuningJob/properties/training_file`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/components/schemas/CreateFineTuningJobRequest/properties/training_file`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/components/schemas/FineTuningJob/properties/created_at`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.openapi#/components/schemas/FineTuningJob/properties/finished_at`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.events#/events/fine_tuning.job.succeeded`: [openai.events](https://developers.openai.com/api/reference/resources/webhooks), retrieved 2026-09-09
- `openai.openapi#/components/schemas/WebhookFineTuningJobSucceeded/properties/data`: [openai.openapi](https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml), retrieved 2026-09-09
- `openai.docs.webhooks#webhooks/the-event-types`: [openai.docs.webhooks](https://platform.openai.com/docs/guides/webhooks), retrieved 2026-09-09

### Can openai.fine_tuning_job.succeeded return VERIFIED from the action response alone?

No. The minimum evidence level is E2. The action response is E1. The completion conditions read `fine_tuning_job_readback` and `fine_tuning_job_succeeded_events`.

### What happens after the timeout?

The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation goes to a person for review.

## Read next

- [Read the OpenAI Platform API verification page](https://provely.sh/verify/openai)
- [Read the openai.batch.all_requests_succeeded contract](https://provely.sh/verify/openai/openai.batch.all_requests_succeeded)
- [Read the openai.batch.completed contract](https://provely.sh/verify/openai/openai.batch.completed)
- [Read what a completion contract contains](https://provely.sh/contracts)
- [Read what a receipt proves](https://provely.sh/docs/receipts)
