tancho / docs /ARCHITECTURE.md
masterleopold's picture
Bundle the synthetic final pack, thresholds and raw outputs for offline scoring reproduction
f635a54 verified
|
Raw History Blame Contribute Delete
33.5 kB
# Tancho Observation Program 詳細実装設計
| 項目 | 内容 |
|---|---|
| 文書版 | 1.0 |
| 日付 | 2026年9月21日 |
| 状態 | Release 1実装用 |
| 上位要件 | [Tancho PRD](tancho-prd-2026-09-21.md) |
| 対象範囲 | `slope_failure_v1`、`access_clearance_v1`を初回実装。後続profileの拡張点も定義 |
対象ミッションの正本は [Tanchoのミッション台帳](tancho-mission-inventory-2026-09-21.md)、製品要件の正本は [Tancho PRD](tancho-prd-2026-09-21.md)、開発順と採用条件の正本は [Open-weight Cosmos 3 Edge Generator計画](open-weight-generator-plan-2026-09-21.md) とする。本書は、その方針をコードへ実装できる粒度まで落とした詳細設計である。
## 1. 設計の不変条件
1. 対象の発見と範囲抽出は、物体検出器、面分類器、地図照合が担う。
2. 同じCosmos 3 Edge派生checkpointを、Reasoner roleとGenerator roleの別呼出しで使う。
3. Reasonerは未回答の運用上の問いを選ぶ。Generatorは検査済みの問いに必要な観測関係を組む。
4. モデルは座標、角度、距離、速度、滞在時間、緯度経度、PX4命令、安全制約を出さない。
5. 観測コンパイラ、軌道計画器、RFLが数値の視点と経路を決める。
6. モデルの生出力を補修、丸め、近い列挙値へ置換しない。不正出力はそのまま拒否する。
7. 決定論的fallbackで飛行できても、モデルの採用成績には数えない。
8. 旧 `tancho-viewpoints-1.0` と固定場面SITLの意味を変更しない。新しい版からadapterで接続する。
## 2. データフロー
```text
FrameBundle + telemetry + detector/classifier/map outputs
│
▼
build_mission_context()
│ MissionContext(trusted)
▼
Cosmos 3 Edge / Reasoner role
│ raw ObservationIntent
▼
validate_and_bind_intents()
│ VerifiedIntentSet(trusted IDs/revision)
▼
Cosmos 3 Edge / Generator role
│ raw ObservationProgram
▼
validate_observation_program()
│ VerifiedObservationProgram
▼
compile_observations()
│ CompiledViewPlan
▼
adapt_to_viewpoints_v1()
│ tancho-viewpoints-1.0
▼
trajectory planner → RFL → PX4 → capture
│
▼
verify_observation_result()
```
モデル呼出し間で渡すのは、生のReasoner JSONではなく `VerifiedIntentSet` である。アプリケーションがcanonical JSONのSHA-256から `intent_id` と `intent_revision` を作り、内部で固定する。Generator promptでは各intentを安定した `sequence` で示し、生出力の `intent_sequence` を検証器がopaque IDへ束縛する。
## 3. MissionContext 1.0
### 3.1 生存期間と上限
| 項目 | 値 |
|---|---|
| schema | `tancho-mission-context-1.1` |
| 最大対象数 | 32 |
| 最大根拠画像数 | 8 |
| 最大完了済みquestion数 | 対象ごと32 |
| 最大センサー数 | 8 |
| 時刻 | 同期済みの整数milliseconds |
| 有効期限 | アプリケーションが設定。モデルは延長不可 |
上限はメモリ使用量と攻撃面を閉じるための契約上限であり、運用上必要な件数を示す値ではない。上限を超えた入力は分割し、同じcontextとして黙って切り捨てない。
### 3.2 JSON形状
```json
{
"schema_version": "tancho-mission-context-1.1",
"context_id": "ctx-...",
"mission_id": "mission-...",
"mission_profile": "slope_failure_v1",
"captured_at_ms": 0,
"expires_at_ms": 0,
"input_sha256": "64 lowercase hex",
"model_revision": "...",
"profile_revision": "...",
"map_revision": "...",
"calibration_id": "...",
"envelope_revision": "...",
"evidence_ids": ["frame-1"],
"sensor_capabilities": ["rgb"],
"targets": [
{
"target_id": "target-1",
"category": "landslide_area",
"source": "area_classifier",
"geometry_ref": "geometry-1",
"map_relations": ["intersects_road"],
"required_questions": ["landslide_road_connection"],
"completed_questions": []
}
],
"policy": {
"max_intents": 4,
"max_observations": 8,
"max_viewpoints": 8,
"max_reobservation_cycles": 1
}
}
```
`input_sha256` は画像bytesのhash、対象レジストリ、センサー能力、各revision、policyを含むcanonical入力からアプリケーションが計算する。`context_id` もアプリケーションが発行し、モデル出力との照合にだけ使う。
### 3.3 列挙値
`sensor_capabilities` は初版で `rgb` と `thermal` のみを許す。SIYI A8 miniだけの構成は `rgb` だけになる。`thermal` をモデルが出力に追加しても能力が増えたとは扱わない。
`source` は `object_detector`、`area_classifier`、`map`、`map_difference`、`telemetry` のいずれか。`category` と `map_relations` は [§7](#7-ミッションプロファイル) のprofileで許可されたものだけを受ける。
## 4. Reasoner role
### 4.1 モデル生出力
```json
{
"schema_version": "tancho-observation-intent-1.0",
"context_id": "ctx-...",
"mission_id": "mission-...",
"outcome": "inspect",
"evidence_ids": ["frame-1"],
"intents": [
{
"sequence": 0,
"target_id": "target-1",
"question": "landslide_road_connection",
"priority": 1,
"evidence_ids": ["frame-1"]
}
],
"reason_code": "unanswered_question"
}
```
### 4.2 outcomeと整合条件
| outcome | intents | evidence_ids | reason_code |
|---|---:|---:|---|
| `inspect` | 1以上、policy以下 | 1以上 | `unanswered_question` |
| `satisfied` | 0 | 1以上 | `all_required_questions_completed` |
| `unsupported_sensor` | 0 | 1以上 | `required_sensor_unavailable` |
| `insufficient_evidence` | 0 | 0以上 | `target_unresolved` または `evidence_unusable` |
`priority` は1が最優先で1〜3。`sequence` は0から欠番なし。`question` はprofileの許可表にあるだけでなく、そのtargetの `required_questions` に明示され、`completed_questions` に無いことを要求する。同じ `target_id + question` の重複は拒否する。`completed_questions` は `required_questions` の部分集合でなければならない。`satisfied` は全targetで両集合が一致した場合だけ許可する。これにより、Reasonerは画像だけから任務目的を推測して質問を増やせず、旧 `no_action` の移行も具体的な完了対象に束縛される。
### 4.3 検証後の内部表現
`validate_and_bind_intents(raw, context, now_ms)` は生出力を変更せず検査し、成功時だけ次をアプリケーション側で追加する。
- `intent_id = sha256(context_id + sequence + target_id + question)` の64文字lowercase hex
- `intent_revision = sha256(canonical verified intent set)`
- `source_output_sha256 = sha256(raw model bytes)`
これらは次のモデルに渡す信頼済みIDであり、Reasoner自身には生成させない。
## 5. Generator role
### 5.1 入力
Generatorは同じFrameBundle、MissionContext、VerifiedIntentSetを受ける。Reasonerの自由文や未検証JSONをプロンプトへ連結しない。プロンプトには、アプリケーションが検証したintentの `sequence`、対象、question、priority、根拠画像IDを渡す。`intent_id`、`intent_revision`、context/mission IDなどのopaqueな値はモデルに再生成させない。
### 5.2 モデル生出力
```json
{
"schema_version": "tancho-observation-program-1.1",
"outcome": "observe",
"observations": [
{
"sequence": 0,
"intent_sequence": 0,
"view_relation": "along_axis",
"coverage": "both_sides",
"detail_level": "damage",
"sensor": "rgb",
"stop_condition": "corridor_continuity_visible"
}
],
"reason_code": "program_created"
}
```
### 5.3 outcomeと整合条件
| outcome | observations | reason_code |
|---|---:|---|
| `observe` | 1以上、policy以下 | `program_created` |
| `uncompilable_intent` | 0 | `unsupported_observation_primitive` |
Generatorは `satisfied` を返せない。問いが既に満たされたかを決めるのはReasonerである。Generatorはセンサー能力を変更できず、入力intentを追加、削除、改名できない。`observe` の場合は各intentが少なくとも1回参照される。完了済みquestionに結び付くintentは入力段階で存在できない。
### 5.4 共通の観測語彙
| field | 初版の列挙値 |
|---|---|
| `view_relation` | `overview`, `nadir`, `oblique`, `cross_section`, `along_axis`, `context`, `intercept`, `search_sweep` |
| `coverage` | `full_target`, `boundary`, `upper_lower_edges`, `both_sides`, `connection`, `upstream_downstream`, `target_and_context`, `facade_foot`, `approach_corridor`, `search_region` |
| `detail_level` | `detect`, `identify`, `state`, `damage` |
| `sensor` | `rgb`, `thermal` |
検証器は `intent_sequence` をVerifiedIntentSetの同じsequenceへ決定論的に結び、そこで初めてopaqueな `intent_id`、context/mission ID、`intent_revision` を付与する。未知sequence、欠落intent、同じ `intent_sequence + view_relation + coverage + detail_level + sensor + stop_condition` の重複は拒否する。旧1.0入力は保存済み証拠の検証用に読み取れるが、新しいpromptと教師は1.1だけを生成する。順序違いだけの重複教師を別正解として数えない。
## 6. アプリケーション状態機械
```text
CAPTURED
→ CONTEXT_VALIDATED
→ INTENTS_PENDING
→ INTENTS_VERIFIED
→ PROGRAM_PENDING
→ PROGRAM_VERIFIED
→ COMPILED
→ SAFETY_VALIDATED
→ EXECUTING
→ RESULT_CAPTURED
→ RESULT_VERIFIED
├─ COMPLETE
└─ CAPTURED(policyのcycle上限内だけ)
```
どの状態からも `ABORTED` へ移れる。状態を飛ばさない。context、intent、program、compiled plan、trajectory、実測結果のhashを同じ監査recordへ結び付ける。
`max_reobservation_cycles` はアプリケーションpolicyであり、モデルは変更できない。固定場面baselineは1を維持する。ミッション別の別値は、飛行時間と帰還余力を測定してからprofile revisionとして固定する。
### 6.1 失敗時の処理
| 失敗 | 処理 | モデル成功に数えるか |
|---|---|---|
| JSON・schema・ID・revision違反 | 生出力を保存して停止 | 数えない |
| 推論timeout・provider不一致 | 停止または明示的fallback | 数えない |
| context期限切れ | 全出力を破棄し再撮影 | 数えない |
| 未搭載センサー要求 | program拒否 | 数えない |
| compiler解なし | `uncompilable` として停止または人へ返す | 数えない |
| RFL拒否 | 拒否理由を保存して停止または明示的fallback | 数えない |
| 実行中に対象消失・地図更新 | 実行を中止し、新contextからやり直す | 数えない |
| 撮影品質未達 | cycle上限と資源内だけReasonerへ戻す | 最終達成時だけ閉ループ成功 |
fallbackを使う場合は `decision_source = deterministic_fallback` と記録する。モデル出力をfallbackの入力に使わず、モデル採用ゲートの分母から除外もしない。
## 7. ミッションプロファイル
profileは、許可された対象、問い、観測語彙、停止条件の組合せをコード上の定数として持つ。ここで正解の観測セットを一意に規定しない。questionから常に同じprogramが出るなら画像不要のlookup課題になるため、可視状態、遮蔽、既観測範囲によって必要な観測が変わる評価対を必須にする。
### 7.1 `slope_failure_v1`
| category | question |
|---|---|
| `landslide_area` | `landslide_extent`, `landslide_road_connection`, `landslide_river_connection`, `landslide_occluded_region`, `slope_precursor_detail` |
許可する停止条件は `full_boundary_visible`、`upper_lower_edges_visible`、`connection_visible`、`occluded_region_resolved`、`precursor_detail_visible`。`thermal` は許可しない。
### 7.2 `access_clearance_v1`
| category | question |
|---|---|
| `road_segment`, `rail_segment`, `obstruction_area`, `bridge` | `corridor_continuity`, `obstruction_material`, `obstruction_extent`, `roadbed_loss`, `bridge_damage`, `approach_access` |
停止条件は `corridor_continuity_visible`、`obstruction_type_and_extent_visible`、`roadbed_edges_visible`、`bridge_damage_context_visible`、`approach_corridor_visible`。道路の「覆われる型」と「路体が失われる型」を別caseにする。
### 7.3 `flood_river_v1`
| category | question |
|---|---|
| `flood_area`, `river_segment`, `embankment`, `building`, `debris_area` | `flood_extent`, `flood_boundary`, `building_waterline`, `embankment_damage`, `channel_blockage`, `debris_accumulation` |
停止条件は `flood_boundary_visible`、`facade_waterline_visible`、`bank_damage_context_visible`、`channel_cross_section_visible`、`upstream_downstream_context_visible`。
### 7.4 `rescue_v1`
| category | question |
|---|---|
| `person`, `vehicle` | `person_state`, `person_surrounding_hazard`, `rescue_access`, `notification_frame`, `vehicle_state`, `vehicle_occupant_evidence` |
停止条件は `person_state_and_context_visible`、`rescue_approach_visible`、`notification_frame_sufficient`、`vehicle_state_and_context_visible`。RGBで状態を判定できる必要画質は現時点で未測定なので、profileの画質値を運用値として固定しない。
### 7.5 `building_earthquake_v1`
| category | question |
|---|---|
| `building`, `fire_region`, `person` | `building_collapse_extent`, `facade_damage`, `entrance_access`, `road_encroachment`, `fire_context` |
停止条件は `roof_and_collapse_extent_visible`、`required_facades_visible`、`facade_foot_visible`、`entrance_access_visible`、`fire_perimeter_context_visible`。熱画像を必須とするcaseで `thermal` が無ければReasonerは `unsupported_sensor` を返す。
### 7.6 `orbitpod_recovery_v1`
| category | question |
|---|---|
| `orbitpod_track`, `river_search_region` | `intercept_region`, `cross_river_search`, `detector_handoff` |
停止条件は `intercept_region_covered`、`search_region_covered`、`orbitpod_detector_handoff`。許可するview relationは `intercept` と `search_sweep` を中心とする。物体検出後の並走、索の位置合わせ、吸着、吊り上げは本profileの外である。
### 7.7 未実装profile
山岳遭難、森林火災、野生動物は初版registryへ登録しない。未知profileとして拒否する。センサー、運用上の問い、独立素材、停止条件が揃ってから新しいversionで追加する。
## 8. 観測コンパイラ
### 8.1 入力と出力
```python
compile_observations(
program: VerifiedObservationProgram,
context: MissionContext,
scene: SceneSnapshot,
vehicle: VehicleSnapshot,
) -> CompiledViewPlan
```
`SceneSnapshot` は対象geometry、地形mesh、占有・自由・未知を区別した障害物地図、道路・河川・建物等のmap geometry、各revisionを持つ。`VehicleSnapshot` は現在位置、速度、残電力、時刻を持つ。どちらもモデル出力から作らない。
`CompiledViewPlan` は `tancho-compiled-viewplan-1.0` とし、各視点に `observation_sequence` と `intent_id` を残す。既存の `tancho-viewpoints-1.0` へ渡すadapterは飛行用フィールドだけを変換し、元planと出力のhashを監査recordへ残す。
### 8.2 コンパイル手順
1. profileの `view_relation + coverage + detail_level + sensor + stop_condition` を幾何制約へ変換する。
2. 対象surface、boundary、connection、axis、search regionを信頼済みgeometryから取り出す。
3. カメラ校正とdetail levelから必要GSDまたは画素条件を取得する。未測定の条件は推測せず `missing_quality_requirement` で失敗する。
4. 承認領域内に、profile固定の角度・距離samplingで視点候補を作る。この候補はモデルへ見せない。
5. 視錐台、遮蔽、未知空間、地形・障害物離隔、ジンバル可動域、画質余裕を検査する。
6. 1つの観測要求に複数視点が必要なら、必要coverageを満たす最小集合を決定論的に選ぶ。
7. programのsequenceとintent priorityを保ち、同順位内だけ移動時間を短くする。
8. 全視点を既存の範囲、期限、帰還検査へ渡す。総視点数がpolicy上限を超えたら切り捨てず失敗する。
### 8.3 決定規則
複数の成立解は、次のlexicographic keyで一意に選ぶ。
```text
(
uncovered_required_area,
unknown_space_intersection,
collision_clearance_penalty,
sensor_resolution_deficit,
number_of_viewpoints,
total_travel_seconds,
canonical_quantized_coordinates
)
```
前4項目は0が必須で、満たさない候補は採用しない。後3項目が同じ場合は1cm単位に量子化したENU座標の辞書順をtie-breakに使う。量子化は選択の再現性のためだけに使い、危険な座標を範囲内へ丸める処理には使わない。
### 8.4 OrbitPodの分岐
`orbitpod_recovery_v1` は静止対象コンパイラへ入れない。位置列、時刻、流向、川幅geometryから待受け領域と探索走査を作る `compile_dynamic_search()` へ送る。OrbitPod検出後は状態機械を `DETECTOR_HANDOFF` で終了し、低遅延tracking controllerへ移す。Generatorを追跡loop内で再呼出ししない。
## 9. モデルpromptとdecode
roleごとにsystem instruction、schema、許可語彙を分ける。Reasoner promptへGeneratorの列挙値を、Generator promptへReasonerの未検証文章を入れない。画像は同じbytesをrole間で再利用し、processor後のpixel hashも記録する。
decodeはtemperature 0、1回だけ、修復・再試行なしを評価条件とする。運用で再試行を導入する場合は、評価値と分け、attemptごとのraw出力を残す。可能ならgrammar constrained decodingを使うが、grammarが正しい意味を保証したとは数えない。
### 9.1 実行provider
新規学習は `deploy/modal_training/` からModal H100 1基で実行する。payloadは学習コード、固定Cosmos Framework revision、親model revision、training pack、save/resume/finish設定をファイル単位のSHA-256で固定する。成果物は `tancho-observation-program-artifacts` Volumeのrun ID別directoryへ保存し、同じrun IDを上書きしない。起動は既定でdry runとし、明示した `--execute` だけがcloud resourceを作る。
fresh model-in-loop SITLは `deploy/modal_observation_program/pipeline.json` の順序で実行する。PX4/Gazeboはnested Dockerを必要とするためModal VM Sandbox、ReasonerとGeneratorはModal H100、compilerとRFLは決定論的CPU stageとする。全stageは同じcontext、画像hash、公開checkpoint revision、監査chainをModal Volumeで受け渡す。Nebius call、保存済みmodel出力のfallback、Generator生出力の修復を含む試行はRelease 1証拠として拒否する。
既公開v4を作ったNebius job IDとarchive hashは履歴provenanceとして保持する。providerを遡及的にModalへ書き換えない。2026年9月22日以降に作る学習・SITL receiptは `deploy/execution-provider-policy.json` と `tancho/execution_provider.py` でModal以外をfail-closedにする。
## 10. 学習データ
### 10.1 1レコード
```text
sample_id
leakage_group_id
split
role = reasoner | generator
mission_profile
context.json
frames/*
verified_intents.json # generator roleだけ
target.json
provenance.json
```
`target.json` はモデルの厳格JSONだけを持つ。chain-of-thoughtを教師や公開物へ入れない。教師の作成理由、代替正解、レビュー記録は別ファイルに保存する。
### 10.2 分割
world、災害イベント、地点、関連飛行、遮蔽物配置、元画像hashのいずれかが同じものを同じ `leakage_group_id` に入れる。回転、左右反転、色変更、同一sceneの別カメラを独立現場として数えない。実写に位置・姿勢・校正が無ければ、Reasonerと意味的なGenerator教師には使えても、コンパイラの正解座標には使わない。
### 10.3 必須対照
- 同じ画像でquestionを変え、必要観測を変える
- 同じquestionで遮蔽・可視範囲だけを変え、必要観測を変える
- 同じpromptと数値条件で画像だけを交換する
- 灰色、欠損、古い画像を入れる
- RGBだけのcontextでthermal必須の問いを出す
- completed questionを含むcontextを入れる
- mission profileと対象categoryを意図的に食い違わせる
- questionから固定表を引くだけのrule baselineを先に測る
画像を見ないruleが最終評価の正解へ到達したprofileは、Generatorの学習課題として不成立と判定し、GPU学習へ進めない。
### 10.4 段階追加
1. schemaとrole分離のsynthetic smoke
2. `slope_failure_v1`
3. `access_clearance_v1`
4. `flood_river_v1`
5. `rescue_v1` と `building_earthquake_v1`
6. `orbitpod_recovery_v1`
各段階は以前のprofileをreplayし、role比とprofile比をmanifestへ固定する。データ数、学習率、更新数、checkpoint間隔、費用上限はdevelopment dataと検出力設計から事前固定し、本書では根拠のない件数を置かない。
## 11. 評価
### 11.1 Reasoner単体
- strict schema valid率
- questionのmicro/macro precision、recall、F1
- 不要なinspect率
- completed question再要求率
- `unsupported_sensor` recall
- evidence grounding率
### 11.2 Generator単体
- 必要観測primitiveのmicro/macro precision、recall、F1
- 不要観測数
- 全intent coverage率
- sensor/profile違反率
- strict schema valid率
- rule baseline、base Cosmos 3 Edge、公開v5との比較
複数の観測セットが同じ目的を満たす場合は、finalを開く前に許可した同値集合をgoldへ記録する。結果を見てから同値扱いを追加しない。
### 11.3 コンパイラ
- gold programのcompile成功率
- coverage、遮蔽、画質、衝突、envelope、期限、帰還の各条件
- 同一入力のbyte-identical出力
- 1条件だけを変えたときの期待された差
- 解なしを解なしとして返す率
### 11.4 閉ループ
- モデル生出力に由来する観測達成率
- 実画像の有効率
- mission完了時間、移動距離、消費電力
- 不要な再観測数
- fallback率と人の介入数
- 対象消失、古い地図、推論停止、通信断での停止結果
## 12. テスト設計
### 12.1 unit
- 全schemaの正常例と、未知・欠落・重複key
- NaN、Infinity、bool-as-number、長過ぎる文字列、件数超過
- 未知context・target・evidence・intent ID
- 古い時刻、異なるrevision、変更された画像bytes
- profile/category/question/primitiveの全許可・拒否matrix
- completed questionの復活、同一観測の重複
- unavailable sensor、role間schema取り違え
### 12.2 compiler property/golden
- 同一入力の決定性
- targetの平行移動・90度回転でplanも対応して変換される
- 障害物追加で貫通経路を作らない
- 狭いenvelope、未知空間、画質不足、帰還余力不足で失敗する
- 道路を覆う型と路体流失型が別のcoverageを要求する
- OrbitPodを静止対象compilerへ渡すと拒否する
### 12.3 integration
- raw Reasoner → verified intent → raw Generator → verified program → compiled plan → viewpoints v1
- 各境界でhashとrevisionが保持される
- fallbackをモデル成功として記録しない
- cycle上限、return reserve、対象消失、provider不一致で停止する
- 旧viewpoint/PX4/SITLテストの結果を変更しない
モデルの文章をそのまま写しただけのテストは作らない。安全境界、role混同、画像依存、決定性を壊す変更を検出できるテストに限る。
## 13. コード配置と公開API
| file | 公開関数・型 |
|---|---|
| `tancho/mission_profiles.py` | `MissionProfile`, `profile(name)`, `validate_profile_relation(...)` |
| `tancho/mission_context.py` | `build_context(...)`, `validate_context_v1(...)`, `MissionContext` |
| `tancho/observation_intent.py` | `parse_intent_output(raw)`, `validate_and_bind_intents(...)`, `VerifiedIntentSet` |
| `tancho/observation_program.py` | `parse_program_output(raw)`, `validate_observation_program(...)`, `VerifiedObservationProgram` |
| `tancho/observation_program_prompts.py` | `reasoner_prompt(...)`, `generator_prompt(...)` |
| `tancho/observation_program_inference.py` | `infer_role(...)`、1回・期限付きのrole呼出しとreceipt |
| `tancho/observation_compiler.py` | `compile_program(...)`, `compile_observations(...)`, `CompiledViewPlan`, `CompileError` |
| `tancho/dynamic_search_compiler.py` | `compile_dynamic_search(...)` |
| `tancho/viewpoint_adapter.py` | `adapt_to_viewpoints_v1(...)` |
| `tancho/observation_program_runtime.py` | 状態機械と監査record |
| `tancho/observation_result.py` | `verify_observation_result(...)` |
| `tancho/observation_flight.py` | `prepare_px4_mission(...)`、RFL合格後の未送信mission生成 |
| `training/build_observation_program_pack.py` | role別pack生成・分割検査 |
| `training/observation_program_loader.py` | native Cosmos SFT loaderとpack再検査 |
| `training/build_observation_program_review.py` | 旧素材からの未承認review queue生成 |
| `training/promote_observation_program_review.py` | 人レビューexportの改ざん・権利・契約検査とSFT packへの昇格 |
| `training/build_observation_program_synthetic_r1.py` | scene ground truthへ結び付いたRelease 1合成教師と独立validation生成 |
| `training/score_observation_program.py` | 単体・paired・profile回帰評価 |
| `training/check_observation_program_release.py` | 学習、評価、SITL、Orin、匿名公開の最終hard gate |
| `deploy/modal_training/` | immutable payload作成、Modal H100 dry run/明示実行、Volume成果物receipt |
| `deploy/modal_observation_program/` | Modal VM+H100のfresh SITL stage契約と準備record |
| `tancho/execution_provider.py` | 新規学習・SITLのModal provider policyとreceipt検査 |
既存 `tancho/contracts.py`、`tancho/reasoner_mission.py`、`tancho/viewpoint_plan.py`、`tancho/px4_mission.py` は初版で変更しない。新runtimeからadapter経由で呼び、既存の評価と履歴を保持する。
## 14. 実装PRの分割
1. **Contracts**: profile registry、MissionContext、Reasoner/Generator validator、unit tests
2. **Compiler**: 静止対象compiler、compiled plan、viewpoints v1 adapter、golden/property tests
3. **Slope and access data**: 合成world、teacher、rule floors、凍結split
4. **SFT and evaluation**: role別pack、学習recipe、単体評価、回帰評価
5. **Closed loop SITL**: 新runtime、監査record、fresh inference、失敗注入
6. **Additional profiles**: flood、rescue、building、OrbitPodを1profileずつ追加
7. **Open-weight release**: checkpoint、hash、model card、schema、compiler、全評価
PR 1と2はGPUを使わない。PR 3で画像不要のrule floorを測り、課題が成立した場合だけPR 4の有料学習へ進む。
### 14.1 既存ラベルから学習packへの昇格
既存の人レビュー済みdecisionは再レビューしない。Release 1に一意対応する山王谷34件だけを対象にし、元の `inspect`、`no_action`、`abstain` を、それぞれ `inspect/unanswered_question`、`satisfied/all_required_questions_completed`、`insufficient_evidence/evidence_unusable` へ固定写像する。元decision、observation goal、source manifest、frame bytes、ontology crosswalk、期待Reasoner targetをproof JSONへ束縛し、`label_authority=deterministic_legacy_migration` とする。新しい構造化target自体を人が再確認したとは記録しないため `human_reviewed=false` を維持する。
旧ラベルのscreen pointやrangeは、Generator 1.1のview relation、coverage、detail level、stop conditionを一意に含意しない。そのため実写34件はReasoner教師だけに使い、旧数値からGenerator教師を推定しない。Generator教師は§14.2の決定論的scene ground truthから供給する。loaderはproof欠損、source bytes変更、旧decision変更、crosswalk変更、期待target変更をすべて拒否する。
新規素材を人がレビューする場合だけ `review.html` と `promote_observation_program_review.py` の経路を使う。この経路は元queueの非review部分、source manifest、全frame bytes、reviewer、timezone付き時刻、利用許諾、profile relation、両role契約を検査し、1件でも未確認・改ざん・禁止があればpackを作らない。既存34件の再ラベリングには使わない。
### 14.2 決定論的scene ground truth
合成教師は人レビュー済み実写と同じ権限を名乗らない。`source_kind=synthetic`、`human_reviewed=false`、`label_authority=deterministic_scene_ground_truth` を設定し、renderer、world seed、target geometry、visibility、profile、role、question、期待するstrict targetを含むproof JSONのcanonical SHA-256へ各recordを結び付ける。packは対応する `proofs/<sha256>.json` が無い、hashが違う、split/profile/role/targetが一致しない場合に学習用途で開けない。AI生成文、keyword候補、画像だけから推定したgeometryはこの権限を使えない。
Release 1のprocedural packは法面と道路について、明瞭、樹木遮蔽、利用不能のsceneを固定投影で描画する。同じ非画像入力のvisual pairでReasonerの `inspect` / `insufficient_evidence` とGeneratorの観測primitiveを変え、画像を無視するshortcutを検出する。world seedはカメラ座標として直接使わず、SHA-256から固定範囲のcamera/look-at parameterへ写像する。これによりtrain、development、finalのseed番号が異なっても同じ宣言済みcamera envelopeに入り、各splitはworld、event、site、flight、画像hashで分離される。v4ではtrain seed 1〜24、validation seed 101〜104、development seed 201〜204、final seed 301〜304を用いた。これは実写独立評価を代替せず、合成成績と実写成績を分けて報告する。
## 15. 未確定値
次は実装漏れではなく、測定または運用判断が必要な未確定値としてmanifestに空で持つ。
- 人、車両、外壁、亀裂、護岸損傷ごとの必要画質
- missionごとの再観測cycle上限
- 観測primitiveの最終採用閾値
- Orin NX上のReasoner・Generator各roleのdeadlineと同時負荷
- thermal sensorの機種、校正、利用可能profile
- OrbitPodの位置更新周期、探索高度、tracking controllerへの引渡し条件
これらを仮の数値で埋めた教師を作らない。値が無いprofile/caseは `unsupported_sensor`、`missing_quality_requirement`、または未実装として明示的に止める。
## 16. PRD要件との対応
| PRD要件 | 詳細設計 | 主な実装 |
|---|---|---|
| FR-CTX-001〜004 | §3 | `mission_context.py` |
| FR-REA-001〜004 | §4 | `observation_intent.py` |
| FR-GEN-001〜005 | §5、§7 | `observation_program.py`, `mission_profiles.py` |
| FR-CMP-001〜005 | §8 | `observation_compiler.py`, `dynamic_search_compiler.py`, `viewpoint_adapter.py` |
| FR-FLT-001〜003 | §6、§8 | `observation_program_runtime.py`, 既存RFL/PX4経路 |
| FR-RES-001〜002 | §6、§11.4 | runtimeと結果検証器 |
| FR-AUD-001〜002 | §2、§6 | runtime監査record |
| FR-PUB-001〜002 | §10、§11、§14 | pack、評価、release package |
| NFR-SAF-001〜004 | §1、§6、§8、§12 | validator、compiler、runtime |
| NFR-DET-001〜002 | §4.3、§8.3、§12 | canonicalizationとgolden tests |
| NFR-REP-001〜003 | §9.1、§10.2、§11 | provider policy、split validatorとfinal runner |
| NFR-PER-001〜003 | §6、§9、§15 | runtime metricsとdeadline guard |
| NFR-DAT-001〜003 | §10、§14 | provenance manifestとrelease builder |
| MR-001〜008 | §9〜§11 | training pack、recipe、score report |
## 17. 実装完了の定義
各PRは対象要件ID、変更schema、migrationの有無、正常系・拒否系テスト、既存回帰結果を記録する。Release 1の実装完了はPRD §12の全項目が証拠artifactへ結び付いた時点とする。schemaとprofileの変更はversionを上げ、保存済み評価入力の意味を上書きしない。