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

# 予定測定

> 将来のラボテストをリクエストし、チャンネルと時間枠にスケジュールし、実測定が開始したときにプランへリンクします

**予定測定 (planned measurement)** は、実施予定のテストをプロジェクト単位で記録したものです。*リクエスター*はチャンネルを持たない `requested` として作成し（見積もり実行時間を伴います）、後で*スケジューラー*がチャンネルと `[planned_start_time, planned_end_time)` の時間枠を割り当て、`scheduled` に移行させます。

予定測定は実際の[セル測定](/ja/data/measurements)を作成したり変更したりすることは決してありません。実テストが開始すると、実際の `cell_measurement` がプランへリンクバックし、プランを `in_progress` に移行させます — 予定行はリクエストとスケジュールの監査証跡として残ります。

## 使い分け

予定測定はオプションです — [ラボビュー](/ja/data/lab)に記載されている通り、測定を直接作成して実行時に `channel_id` を設定することもできます。次のような場合に予定測定を使用します:

* プロジェクトまたは特定の[セル仕様](/ja/core-concepts/cells)に対してリクエストされたテストの**バックログ**を追跡したい。
* 2 人のスケジューラーが同じチャンネルと時間枠を予約しないよう、**将来のチャンネル時間を予約**したい。
* （科学者や PM からの）*リクエスト*と、（ラボオペレーターによる）*スケジュール*の決定を分離したい。
* 各テストを誰がリクエストし、誰がスケジュールしたかの監査証跡を残したい。

サイクラーが 1 台だけで、テストをアドホックに開始する場合は、測定を直接チャンネルにリンクし続け、予定測定は使わないでください。

## ライフサイクル

```
requested ──► scheduled ──► in_progress ──► completed
    │             │
    └── cancelled ┘
```

| ステータス         | 意味                                                                                          |
| ------------- | ------------------------------------------------------------------------------------------- |
| `requested`   | まだチャンネルが決まっていない将来のテスト。`estimated_duration_seconds` が必須です。*リクエスター*が作成する状態です。                 |
| `scheduled`   | *スケジューラー*が `channel_id` と `[planned_start_time, planned_end_time)` の予約を割り当てた状態。3 つすべてが必須です。 |
| `in_progress` | 実際の `cell_measurement` が開始しプランにリンクされた時点で自動的に設定されます。`started_measurement_id` を保持します。         |
| `completed`   | リンクされた実測定が終了した時点で設定されます。                                                                    |
| `cancelled`   | 完了前に中止されたプラン。監査証跡として行は保持されます。                                                               |

スケジュールは**完全に手動**です — スケジューラーがチャンネルと時刻を選びます。自動オプティマイザはありません。

`scheduled` プランで将来のチャンネル時間を予約しても、[ラボビュー](/ja/data/lab)でチャンネルが `occupied` として表示されることはありません — それは実行中の実測定のみが行います。プランはカレンダーを予約し、`cell_measurement` は現時点を予約します。

## フィールド

| フィールド                                                  | 説明                                                                                                                             |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `name`                                                 | 人間が読みやすい名前（必須、プロジェクト内で一意）。                                                                                                     |
| `status`                                               | デフォルトは `"requested"`。`requested` または `scheduled` として作成します。                                                                     |
| `estimated_duration_seconds`                           | `requested` 行では必須。                                                                                                             |
| `channel_id`, `planned_start_time`, `planned_end_time` | `scheduled` 行では必須。`planned_end_time` は `planned_start_time` より後である必要があります。                                                     |
| `cell_specification_id`                                | リクエスターがテスト対象としたい[セル仕様](/ja/core-concepts/cells)。任意。                                                                            |
| `cell_instance_id`                                     | テストを実行する具体的なセルインスタンス。通常はスケジューラーが設定します。`cell_specification_id` と `cell_instance_id` の両方が設定されている場合、インスタンスは指定された仕様に属していなければなりません。 |
| `setup_duration_seconds`, `teardown_duration_seconds`  | オペレーターのセットアップとティアダウン時間（秒）。デフォルトは `0`。                                                                                          |
| `protocol`, `test_setup`, `notes`                      | 任意の自由形式の計画メタデータ。                                                                                                               |
| `started_measurement_id`                               | 実測定がプランにリンクされた時点で自動的に設定されます。                                                                                                   |

`name` はプロジェクト内で一意（大文字小文字を区別しない）です。重複する名前でプランを作成すると `IonworksError` が `error_code == "CONFLICT"`（HTTP 409）で発生します。作成を冪等にするには `create_or_get` を使用してください。

## 測定のリクエスト

チャンネルなしの `requested` プランを作成し、見積もり実行時間と、必要であればテスト対象のセル仕様を指定します。具体的なインスタンスは後でスケジューラーが選択します。

```python theme={null}
from ionworks import Ionworks

client = Ionworks(project_id="your-project-id")

planned = client.planned_measurement.create({
    "name": "Formation cycling",
    "cell_specification_id": "cell-spec-id",
    "estimated_duration_seconds": 7200,
    "notes": "Run at 25 C",
})
# planned.status == "requested"、planned.channel_id は None
```

名前で冪等にリクエストするには `create_or_get` を使用します:

```python theme={null}
planned = client.planned_measurement.create_or_get({
    "name": "Formation cycling",
    "estimated_duration_seconds": 7200,
})
```

## チャンネルへのスケジュール

`schedule` でチャンネルと時間枠を割り当てます — これは `requested` プランを `scheduled` に移行する便利なラッパーです。

```python theme={null}
planned = client.planned_measurement.schedule(
    "planned-measurement-id",
    channel_id="channel-id",
    planned_start_time="2026-07-21T09:00:00+00:00",
    planned_end_time="2026-07-21T11:00:00+00:00",
)
# planned.status == "scheduled"
```

最初から `scheduled` として一度に作成することもできます:

```python theme={null}
planned = client.planned_measurement.create({
    "name": "RPT",
    "status": "scheduled",
    "channel_id": "channel-id",
    "planned_start_time": "2026-07-21T09:00:00+00:00",
    "planned_end_time": "2026-07-21T11:00:00+00:00",
})
```

チャンネル上ですでに使用中の枠と衝突する場合、スケジュールは拒否されます。別のチャンネルまたは時間枠を選んで再試行してください。

| 拒否理由            | 発生条件                                                                                                                     | ステータス |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ | ----- |
| スケジュール済みプランとの重複 | 同じチャンネル上のキャンセルされていない `scheduled` プランと時間枠が重複する。                                                                           | 409   |
| アクティブな測定との重複    | 同じチャンネル上のアクティブな `cell_measurement` と時間枠が重複する。`estimated_end_time` のないアクティブな測定はデフォルトでスケジュールをブロックします。                      | 409   |
| 運用停止チャンネル       | 対象チャンネルの `out_of_commission` が `true`。新規の `scheduled` 予約のみが拒否されます — 既存プランは通常通り遷移できます。                                    | 400   |
| 必須フィールドの欠落      | `scheduled` 行に `channel_id`、`planned_start_time`、`planned_end_time` が欠けている、または `planned_end_time <= planned_start_time`。 | 400   |

既存プランのキャンセルや完了は、チャンネルが運用停止になった後でも常に許可されます。

## 一覧取得とフィルタリング

`list` はプロジェクト単位で、`PaginatedList[PlannedMeasurement]` を返します。ライフサイクルステータス、チャンネル、名前でフィルタリングできます。

```python theme={null}
# スケジューラーのキュー: まだリクエスト状態のもの
requested = client.planned_measurement.list(status="requested")

# ラボのカレンダー: スケジュール済みプランを開始時刻順で
scheduled = client.planned_measurement.list(
    status="scheduled",
    order_by="planned_start_time",
    order="asc",
)

# 特定チャンネル上のすべて
on_channel = client.planned_measurement.list(channel_id="channel-id")

# ページネーション
page = client.planned_measurement.list(limit=25, offset=0)
print(page.count, page.total)

# ID で 1 件取得
planned = client.planned_measurement.get("planned-measurement-id")
```

## 更新、キャンセル、削除

```python theme={null}
# 部分更新 — メモや見積もり実行時間をその場で編集
client.planned_measurement.update(
    "planned-measurement-id", {"notes": "Revised setup"}
)

# キャンセル — 監査証跡として行は保持
client.planned_measurement.cancel("planned-measurement-id")

# 削除 — 行を完全に削除
client.planned_measurement.delete("planned-measurement-id")
```

プランを再スケジュールするには、新しいチャンネルまたは時間枠で `schedule` を再度呼び出す（あるいは個別フィールドを `update` する）だけです。サーバーは新しい値に対して重複と運用停止のチェックを再実行します。

## 実測定をプランにリンクする

プランを手動で `in_progress` に遷移させることはありません。実行が開始したら、`planned_measurement_id` を設定した `cell_measurement` を作成します — バックエンドがそれをリンクし、アトミックにプランを `in_progress` へ移行させます。

```python theme={null}
measurement = client.cell_measurement.create(
    cell_instance_id,
    {
        "measurement": {
            "name": "Formation run",
            "channel_id": "channel-id",
            "planned_measurement_id": "planned-measurement-id",
        },
        "time_series": time_series,
    },
)
```

以下の**すべて**が成立しない限り、リンクは HTTP 400 で拒否されます:

* プランが `scheduled` である。
* 測定が `time_series` タイプであり、`channel_id` を持っている（`channel_id` のない `planned_measurement_id` は拒否）。
* プランと測定が同じプロジェクトおよび組織にある。
* 測定の `channel_id` がプランの `channel_id` と一致する。
* プランに `cell_instance_id` が設定されている場合、測定は同じセルインスタンスで実行される必要がある。

2 つの並行測定が同じプランを取得することは決してありません — リンクは `status = scheduled` に対するアトミックな compare-and-set であり、負けた側はリンクされないまま残されます（警告としてログに記録されます）。

リンク後は、[ラボビュー](/ja/data/lab)上のチャンネル占有状態は実行中の `cell_measurement` によって駆動されます。予定行は監査証跡として残ります。

## 権限

予定測定のエンドポイントは既存の `cell_measurement` 権限を再利用します:

| アクション           | 権限                        |
| --------------- | ------------------------- |
| 一覧、取得           | `cell_measurement:read`   |
| 作成              | `cell_measurement:create` |
| 更新、スケジュール、キャンセル | `cell_measurement:update` |
| 削除              | `cell_measurement:delete` |

## `project_id`

すべての `client.planned_measurement.*` メソッドは任意の `project_id` を受け付けます。省略した場合、[`Ionworks` クライアント](/ja/api-client)に設定されている `project_id`（または `IONWORKS_PROJECT_ID` 環境変数）にフォールバックします。どこからも `project_id` が取得できない場合は `ValueError` が発生します。

## 次のステップ

<CardGroup cols={2}>
  <Card title="ラボビュー" icon="flask-vial" href="/ja/data/lab">
    予定測定がスケジュールされるサイト、サイクラー、チャンネルをセットアップします。
  </Card>

  <Card title="測定" icon="flask" href="/ja/data/measurements">
    スケジュール済みプランへリンクバックする実際の `cell_measurement` を作成します。
  </Card>
</CardGroup>
