# What does linear.issue.in_state prove?

> Prove that the issue sits in the workflow state that the person named. Version 1.0.0, certification Provisional.

Canonical: https://provely.sh/verify/linear/linear.issue.in_state  
Last reviewed: 2026-09-05  
Skill version: 0.1.0  
Certification: provisional  

**Prove that the issue sits in the workflow state that the person named. The issue sits in the state that the person authorised, and that state belongs to the intended team.**

*Contract identity.*

| Fact | Value |
| --- | --- |
| Contract id | `linear.issue.in_state` |
| Version | `1.0.0` |
| Hash | `95967bbb661df54d` |
| Completion level | `in_state` |
| Publisher | Built and signed by Provely. |
| Certification | Provisional |
| Skill | [Linear GraphQL API 0.1.0](/verify/linear) |
| Valid for provider API versions | `fp_2026_09` |

## What is the intent?

Get the issue into this workflow state of this team.

## What is the subject and the action?

| Member | Value |
| --- | --- |
| Subject type | `linear.issue` |
| Subject identity | issue_id = `$action.result.issueCreate.issue.id` |
| Canonical effect | `work.issue_create` |
| Provider operation | `mutation issueCreate` |
| Idempotency | none, retry is not safe |

## How does the evidence correlate with this operation?

| Strategy | Assurance | Keys | Required |
| --- | --- | --- | --- |
| `resource_id` | strong | issue_id from `$action.result.issueCreate.issue.id` | yes |
| `fingerprint` | weak | team_id from `$input.team_id`; title from `$input.title` | no |

## Which evidence does the contract require?

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

| Channel | Level | Independence | Verifier | Description |
| --- | --- | --- | --- | --- |
| `issue_readback` | E2 | provider readback | `http` | Read the issue with its team, its workflow state, and its assignee. The http verifier returns the parsed GraphQL body. A path starts with $observed.<channel>.data, and $observed.<channel>.errors states a refusal. |
| `issue_state_events` | E3 | provider event | `webhook` | The Issue.update events of this issue that carry the workflow state identifier of the intent. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. |
| `issue_created_events` | E3 | provider event | `webhook` | The Issue.create events for the intended title since the operation started. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. A count above one shows a second issue, and the API has no idempotency key to stop it. |

## Which conditions must all hold for VERIFIED?

| Condition | Meaning | Path | Operator | Expected | Evidence |
| --- | --- | --- | --- | --- | --- |
| `issue_readback_carries_no_errors` | The answer carries no errors array. Linear answers the status code 200 for an operation that succeeded in part, so the status code states nothing. | `$observed.issue_readback.errors` | `absent` | `undefined` | `issue_readback` |
| `issue_present` | The provider holds the issue with the returned identifier. | `$observed.issue_readback.data.issue.id` | `eq` | `$action.result.issueCreate.issue.id` | `issue_readback` |
| `issue_team_matches` | The issue belongs to the team that the intent named. | `$observed.issue_readback.data.issue.team.id` | `eq` | `$input.team_id` | `issue_readback` |
| `issue_created_in_window` | The provider created the issue after the operation started. | `$observed.issue_readback.data.issue.createdAt` | `time_after` | `$operation.created_at` | `issue_readback` |
| `workflow_state_belongs_to_the_team` | The workflow state of the issue belongs to the team of the intent. Each team has its own set of workflow states, so the runtime reads the team of the state and never pins an identifier. | `$observed.issue_readback.data.issue.state.team.id` | `eq` | `$input.team_id` | `issue_readback` |
| `workflow_state_name_matches` | The workflow state of the issue carries the name that the person named. The identifier and the name must name one state. | `$observed.issue_readback.data.issue.state.name` | `eq` | `$input.state_name` | `issue_readback` |
| `issue_in_the_promised_state` | The workflow state of the issue is the state of the intent. The type of the state alone separates nothing, because a team can hold more than one state of one type. | `$observed.issue_readback.data.issue.state.id` | `eq` | `$input.state_id` | `issue_readback` |
| `issue_state_event` | At least one Issue.update event of this issue carries the workflow state identifier of the intent. | `$observed.issue_state_events.count` | `gte` | `1` | `issue_state_events` |

## Which conditions give CONTRADICTED?

| Condition | Class | Reason | Path | Operator | Expected |
| --- | --- | --- | --- | --- | --- |
| `issue_on_wrong_team` | wrong subject | The issue belongs to a different team than the intent named. | `$observed.issue_readback.data.issue.team.id` | `ne` | `$input.team_id` |
| `issue_title_differs` | wrong subject | The issue carries a different title than the intent named. | `$observed.issue_readback.data.issue.title` | `ne` | `$input.title` |
| `issue_predates_operation` | pre existing state | The issue is older than the operation. It proves nothing. | `$observed.issue_readback.data.issue.createdAt` | `time_before` | `$operation.created_at` |
| `duplicate_issue_present` | duplicate side effect | Linear created more than one issue with this title since the operation started. Do not retry. | `$observed.issue_created_events.count` | `gt` | `1` |
| `workflow_state_of_another_team` | wrong subject | The workflow state of the issue belongs to another team than the intent named. Stop and ask a person. | `$observed.issue_readback.data.issue.state.team.id` | `ne` | `$input.team_id` |

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

| Rule | Match | Verdict | Reason |
| --- | --- | --- | --- |
| `issue_readback_refused` | `$observed.issue_readback.errors` exists `undefined` | UNVERIFIABLE | Linear answered the read with the status code 200 and an errors array. The answer is a refusal and it is no evidence. |
| `issue_left_the_workflow` | (`$observed.issue_readback.data.issue.state.type` in `["canceled","duplicate"]`) and (not (`$observed.issue_readback.data.issue.state.id` eq `"$input.state_id"`)) | CONTRADICTED | A person or an agent moved the issue into a canceled state or a duplicate state. The issue can never reach the promised state. Ask a person. |
| `authorised_state_carries_another_name` | (`$observed.issue_readback.data.issue.state.id` eq `"$input.state_id"`) and (not (`$observed.issue_readback.data.issue.state.name` eq `"$input.state_name"`)) | CONTRADICTED | The identifier of the intent names a workflow state with another name than the person named. Ask a person. |
| `issue_not_in_the_promised_state_yet` | `$observed.issue_readback.data.issue.state.type` in `["triage","backlog","unstarted"]` | PENDING | The issue has not reached the promised workflow state. The runtime observes again. |

## How long does the runtime observe?

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

## Where do these rules come from?

- `linear.graphql#/mutations/issueUpdate`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/inputs/IssueUpdateInput/fields/stateId`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/Issue/fields/state`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.docs.states#workflow-states/a-workflow-state-belongs-to-one-team`: [linear.docs.states](https://linear.app/developers/graphql), retrieved 2026-09-09
- `linear.docs.issues#issues-in-the-linear-graphql-api/update-an-issue`: [linear.docs.issues](https://linear.app/developers/graphql), retrieved 2026-09-09
- `linear.docs.issues#issues-in-the-linear-graphql-api/error-handling`: [linear.docs.issues](https://linear.app/developers/graphql), retrieved 2026-09-09
- `linear.docs.issues#issues-in-the-linear-graphql-api/error-handling/p2`: [linear.docs.issues](https://linear.app/developers/graphql), retrieved 2026-09-09
- `linear.docs.issues#issues-in-the-linear-graphql-api/the-endpoint`: [linear.docs.issues](https://linear.app/developers/graphql), retrieved 2026-09-09
- `linear.graphql#/queries/issue`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/Issue/fields/id`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/IssuePayload/fields/issue`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/Issue/fields/team`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/inputs/IssueCreateInput/fields/teamId`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/Issue/fields/createdAt`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/WorkflowState/fields/team`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.graphql#/types/WorkflowState/fields/name`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.docs.states#workflow-states/the-name-and-the-position-of-a-workflow-state`: [linear.docs.states](https://linear.app/developers/graphql), retrieved 2026-09-09
- `linear.graphql#/types/WorkflowState/fields/id`: [linear.graphql](https://api.linear.app/graphql), retrieved 2026-09-09
- `linear.events#/events/Issue.update`: [linear.events](https://linear.app/developers/webhooks), retrieved 2026-09-09
- `linear.webhooks.graphql#/types/IssueWebhookPayload/fields/stateId`: [linear.webhooks.graphql](https://studio.apollographql.com/public/Linear-Webhooks/variant/current/schema/reference/objects), retrieved 2026-09-09
- `linear.docs.webhooks#linear-webhooks/the-fields-of-a-data-change-event`: [linear.docs.webhooks](https://linear.app/developers/webhooks), retrieved 2026-09-09

### Can linear.issue.in_state return VERIFIED from the action response alone?

No. The minimum evidence level is E2. The action response is E1. The completion conditions read `issue_readback` and `issue_state_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 Linear GraphQL API verification page](https://provely.sh/verify/linear)
- [Read the linear.issue.assigned contract](https://provely.sh/verify/linear/linear.issue.assigned)
- [Read the linear.issue.created contract](https://provely.sh/verify/linear/linear.issue.created)
- [Read what a completion contract contains](https://provely.sh/contracts)
- [Read what a receipt proves](https://provely.sh/docs/receipts)
