> ## 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/operate/lab-view)に記載されている通り、測定を直接作成して実行時に `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/operate/lab-view)でチャンネルが `occupied` として表示されることはありません — それは実行中の実測定のみが行います。プランはカレンダーを予約し、`cell_measurement` は現時点を予約します。

## フィールド

| フィールド                                                  | 説明                                                                                                                                              |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                                                 | 人間が読みやすい名前（必須、プロジェクト内で一意）。                                                                                                                      |
| `status`                                               | デフォルトは `"requested"`。`requested` または `scheduled` として作成します。                                                                                      |
| `protocol_id`                                          | このテストで実行する[プロトコル](/ja/simulate/protocols)（実験テンプレート）。必須 — すべての計画測定はプロトコルを指名する必要があり、そのプロトコルは完全に指定された有効なプロトコルでなければなりません（[プロトコルの検証](#プロトコルの検証)を参照）。 |
| `cell_specification_id`                                | このテストが実行される[セル仕様](/ja/core-concepts/cells)。必須。                                                                                                  |
| `estimated_duration_seconds`                           | `requested` 行では必須。                                                                                                                              |
| `channel_id`, `planned_start_time`, `planned_end_time` | `scheduled` 行では必須。`planned_end_time` は `planned_start_time` より後である必要があります。                                                                      |
| `cell_instance_id`                                     | テストを実行する具体的なセルインスタンス。通常はスケジューラーが設定します。`cell_specification_id` と `cell_instance_id` の両方が設定されている場合、インスタンスは指定された仕様に属していなければなりません。                  |
| `setup_duration_seconds`, `teardown_duration_seconds`  | オペレーターのセットアップとティアダウン時間（秒）。デフォルトは `0`。                                                                                                           |
| `program_id`                                           | このテストが属するプログラム（例: Formation、Cycling）。任意項目。[プログラム](#プログラム)を参照してください。同じ組織内のプログラムを参照する必要があります。プランへリンクした実測定にコピーされます。                                |
| `test_setup`, `notes`                                  | 任意の自由形式の計画メタデータ。                                                                                                                                |
| `started_measurement_id`                               | 実測定がプランにリンクされた時点で自動的に設定されます。                                                                                                                    |

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

## 測定のリクエスト

チャンネルなしの `requested` プランを作成し、実行する[プロトコル](/ja/simulate/protocols)、テスト対象のセル仕様、見積もり実行時間を指定します。具体的なセルインスタンスとチャンネルは後でスケジューラーが選択します。

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

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

planned = client.planned_measurement.create({
    "name": "Formation cycling",
    "protocol_id": "experiment-template-id",
    "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",
    "protocol_id": "experiment-template-id",
    "cell_specification_id": "cell-spec-id",
    "estimated_duration_seconds": 7200,
})
```

<Tip>
  **Request test** フォームの Protocol セクションの先頭には英語のプロンプトが表示されます。試験内容を入力して（例：`"1C/1C cycling for 200 cycles between 4.2 V and 2.5 V"`）**Generate** をクリックすれば、YAML を書いたりビジュアルビルダーを操作したりせずに、検証済みの UCP プロトコルが得られます。添付したセル仕様はコンテキストとして使われるため、電圧上下限を明示的に書く必要はほとんどありません。詳細は [AI によるプロトコル作成](/ja/operate/ai-protocol-authoring) を参照してください。
</Tip>

### プロトコルの検証

`protocol_id` は組織内の[実験テンプレート](/ja/simulate/experiment-templates)を参照する必要があり、また、その基盤となるプロトコルは実際のセルで実行可能な状態でなければなりません — 計画測定はラボが実行する正確なテストを固定するため、中途半端に設定されたプロトコルは、後で失敗した実行として現れるのではなく、リクエスト時点で拒否されます。

`create` と `update` は、`protocol_id` が次のいずれかの場合、`IonworksError`（HTTP 400）でプランを拒否します。

* **組織内に存在しない。** エラー: `protocol_id '…' does not reference a protocol in this organization.`
* **未解決の入力が残っている。** `input["…"]` プレースホルダーで作成されたプロトコル（[パラメータ化入力](/ja/simulate/protocols#パラメータ化入力)を参照）は、計画測定にリンクする前にすべての入力を具体的な値に解決しておく必要があります。エラーには未指定の入力名が列挙されます: `protocol_id '…' references a protocol with unresolved inputs (C-rate, Temperature [°C]). Planned measurements require a fully-specified protocol — set all input values first.`
* **UCP 検証に失敗する。** 構造的に無効なプロトコル（不正なステップ定義、一貫性のない終了条件など — `POST /protocols/validate` と同じチェック）は、内部の検証エラーとともに拒否されます。

プロトコルを先に修正してから、リクエストを再試行してください。実行したいプロトコルがまだ完全に指定されていない場合は、複製してコピー側で入力を固定してください — プロトコルの作成と入力設定の方法については[プロトコル](/ja/simulate/protocols)を参照してください。

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

`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",
    "protocol_id": "experiment-template-id",
    "cell_specification_id": "cell-spec-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",
})
```

### UI でチャンネルを選ぶ

スケジュールダイアログのチャンネルピッカーには、各チャンネルの名前と並んでリアルタイムの空き状況と電気的定格が表示されるため、適合性を判断するために[ラボビュー](/ja/operate/lab-view)へ移動する必要はありません:

* **主要行** — `cycler / channel`。
* **定格** — 最大電流と電圧範囲（例: `40 A · 0–5 V`）。チャンネルの[定格](/ja/operate/equipment#channel-ratings)から取得されます。未設定のフィールドは省略されます。
* **状態** — `free`、`occupied`、または `stale`。ラボウォールと同じ[チャンネル占有状態](/ja/operate/lab-view#channel-occupancy)ルールから導出されます。運用停止（out-of-commission）チャンネルは一覧には表示されますが無効化されています。

運用停止でないすべてのチャンネルは選択可能なままです — 使用中（occupied）や滞留（stale）チャンネルも、将来の時間枠を予約できるように表示されます。ピッカーはプロトコルに対する「適合度」で絞り込みや並べ替えを行いません。定格はあくまで参考情報です。

### スケジュール衝突

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

| 拒否理由              | 発生条件                                                                                                                     | ステータス |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ | ----- |
| スケジュール済みプランとの重複   | 同じチャンネル上のキャンセルされていない `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   |
| 無効な `protocol_id` | プロトコルが組織内に存在しない、未解決の `input["…"]` プレースホルダーが残っている、または UCP 検証に失敗する。[プロトコルの検証](#プロトコルの検証)を参照。                               | 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` する）だけです。サーバーは新しい値に対して重複と運用停止のチェックを再実行します。

## テストスケジューラーの行アクション

**テストスケジューラー**ページ（プロジェクトごとに **Lab → Test scheduler** から開く）には、バックログのすべてのプランが一覧表示されます。各行のオーバーフローメニューには以下のアクションが表示されます。表示されるアクションはプランの現在のステータスに応じて変わります — エラーになる操作はボタンを押せる状態にせず、UI 側で非表示にします。

| アクション                                   | 表示されるステータス               | 動作                                                                                    |
| --------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------- |
| Edit（編集）                                | `requested`, `scheduled` | リクエストのフィールド（名前、セル仕様、プロトコル、実行時間）を変更します。                                                |
| Copy（複製）                                | すべてのステータス                | この行の内容をあらかじめ入力したリクエストフォームを開きます。送信するまで新規プランは作成されません。複製は常に `requested` としてバックログに追加されます。 |
| Schedule / Reschedule（スケジュール / 再スケジュール） | `requested`, `scheduled` | チャンネルと時間枠を割り当て、または既存の割り当てを変更します。                                                      |
| Unschedule（スケジュール解除）                    | `scheduled`              | チャンネルと時間枠を解放し、テストを `requested` としてバックログに戻します。                                         |
| Reopen（再開）                              | `cancelled`              | キャンセルされたプランを `requested` としてバックログに戻します。                                               |
| Cancel（キャンセル）                           | `requested`, `scheduled` | プランを終端の `cancelled` 状態に移行させます。**Reopen** で復元可能です。                                     |
| Delete（削除）                              | `cancelled`              | 行を完全に削除します。取り消しはできません。                                                                |

**Delete** は意図的に **Cancel** の後ろに配置されています — アクティブなリクエスト、予約済みチャンネル、または実行済みテストの記録を一度のクリックで削除できないようにするためです。まず Cancel し、その後に必要であれば Delete してください。

**Copy** は、ほぼ同じ内容のテスト（同じセル仕様とプロトコル、異なるメモやセットアップ）を続けて追加する最も速い方法です。**Request test** ボタンと同じリクエストフォームを使用するため、通常のバリデーションが適用されます。新規プランは独自の名前と監査フィールドを持ち、元のプランは変更されません。

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

プランを手動で `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/operate/lab-view)上のチャンネル占有状態は実行中の `cell_measurement` によって駆動されます。予定行は監査証跡として残ります。

### リクエスターの自動ウォッチ

`scheduled` プランが実際の `cell_measurement` にリンクされて `in_progress` に遷移すると、リクエスター（プランの `requested_by`）が開始された測定のウォッチャーとして自動的に追加されます。リクエスターは次回のラボステータス更新で、[ラボビュー](/ja/operate/lab-view)の **My Channels** にその実行が表示されます — 手動で **Watch** をクリックする必要はありません。

動作:

* 両方のリンク経路で発火します: `planned_measurement_id` を指定した `cell_measurement` の作成、および `started_measurement_id` を伴うプランの `in_progress` への PATCH。
* 冪等です — 再リンクや再遷移で重複したウォッチは作成されず、すでにウォッチしているユーザーはそのままウォッチを続けます。
* `requested_by` のみが自動ウォッチされます。`scheduled_by` やラボオペレーターは対象外です。彼らは引き続きチャンネルページや測定ページから手動でウォッチできます。
* ベストエフォートです — ウォッチの失敗が測定の作成やプランの更新を失敗させることはありません。リンクとステータス遷移は成功します。

通知を受け取りたくないリクエスターは、開始後に測定の詳細ページからウォッチを解除できます。

## プログラム

**プログラム**は組織スコープのカタログ項目で、`Formation`、`Cycling`、`RPT`
のようなラボテストの種別を表す短い再利用可能な名前です。プランに
`program_id` を設定するとそのテストがどの種別に属するかが記録され、実測定が
プランにリンクした時点でその値がコピーされます。

| フィールド        | 説明                                             |
| ------------ | ---------------------------------------------- |
| `program_id` | このプランにタグ付けする Program。任意。プランと同じ組織に属している必要があります。 |

プログラムは自由入力のタグではありません。カタログは**組織設定 →
プログラム**から管理し、リクエストおよびスケジュールのフォームはその一覧から
選択するため、同じ種別を全員が同じ表記で扱えます。名前は組織内で一意です
（大文字小文字を区別しません）。

タグ付けされると、その Program はプラン上とテストスケジューラの計画テーブルに
表示されるため、ラボオペレーターはリクエストがどの種別に属するのかを一目で
把握できます。

```python theme={null}
# 作成時にプランにタグ付け
planned = client.planned_measurement.create({
    "name": "Formation cycling",
    "estimated_duration_seconds": 7200,
    "program_id": "program-id",
})

# 既存のプランに Program を後から付ける
client.planned_measurement.update(
    "planned-measurement-id",
    {"program_id": "program-id"},
)
```

プログラムは完全に任意です。`program_id` は登場するすべての箇所で null 許容
です。プロジェクト名やセル仕様名だけでテスト内容が分かる場合は、使わなくても
問題ありません。

## 権限

予定測定のエンドポイントは既存の `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/operate/lab-view">
    予定測定がスケジュールされるサイト、サイクラー、チャンネルをセットアップします。
  </Card>

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