状態: 2026-08-26、検討保留。Issue #107の実装判断には使用しない。
まず既存の「隣接耕基本経路パターン1」をTabletで動作させ、実地検証することを優先する。
pattern registry、plugin、DSL、外部package、汎用入出力契約はIssue #107の対象外とする。
2番目の具体的な経路patternが必要になった時点で新しいIssueを起票し、Pattern 1との差分と
実地検証結果を材料に本案を再検討する。それまでは本書の設計を実装へ反映しない。本書はIssue #107の検討過程を記録した未確定案である。
decisions/は「現在も実装判断に効く確定済みの経緯・baseline」を置く場所であり、本書のような
検討中・未承認の設計案はここ(proposals/)に置く。承認され次第、内容をdecisions/・
specifications/側の正式文書へ切り出し、本書は当時の検討過程として残すかarchive/へ移す。
Issue #107の目的にある「将来複数の、選択可能で着脱可能な経路パターンロジック」をどう実現するかの
方式検討。現在のFinalTillagePlanResolver(track-core)は隣接耕基本経路パターン1
(docs/specifications/adjacent-tillage-basic-route-pattern-1.md)を単一objectとしてハードコード
実装している。これを、アプリの再ビルドなしにパターンを追加・変更できる構造へ拡張する方式を定める。
| 軸 | 外部コードplugin | 汎用スクリプトDSL | 固定schemaの単純な宣言型設定 | PC/サーバ側実行 |
|---|---|---|---|---|
| 表現力 | 最大 | 高 | engineが対応する規則の範囲に限定 | 最大 |
| 安全性 | 最低。任意コード実行、署名検証が必須 | 中〜高。sandbox化した実行環境なら安全 | 最高。実行可能コードを含まない | 高。Tabletは実行コードを持たない |
| オフライン動作 | 可 | 可 | 可 | 圃場でPCまたは通信が必要 |
| 作成難易度 | 高。Kotlin+Android Gradleの完全なビルド環境が必要 | 中 | 低〜中 | 低 |
| 再現性 | 中 | 中〜高 | 最高 | 高 |
| ビルド不要か | Yes(host app再ビルドは不要) | Yes | Yes | Yes(Tabletアプリ側は不要) |
事前コンパイル済みバイナリの配布(DexClassLoader等)による外部コードpluginも技術的には可能だが、
安全性・作成難易度はplugin方式のまま変わらず、Android 14以降のDynamic Code Loading規制
(minSdk 35のため即全面適用)やGoogle Play配布ポリシーの制約が新たに乗るため、優位性がない。
PC/サーバ側実行は実装コストが最も低いが、「圃場でPCまたは通信が必要」という点が、Tabletが貫いている
オフライン完結の設計(PMTilesオフライン地図、.dtrkローカル記録、NTRIP以外はオフライン動作)と衝突する。
「固定schemaの単純な宣言型設定」(パラメータの平坦な集合のみ、規則の組み合わせ不可)は、
「engineが未対応の新しい計算方法は表現できない」という制約が最も厳しく現れる形であり、
将来の拡張(一つ飛ばし耕・スパイラル耕等、adjacent-tillage-basic-route-pattern-1.mdの命名が
示唆する将来パターン)を想定すると表現力不足と判断し、この形では除外した。
初版では「外部コードplugin / スクリプトDSL / 宣言型データ / PC・サーバ側実行」の4方式対立で整理し、
「宣言型データを表現力不足として除外し、DSLを採用する」としていたが、これは不正確だった。後述する
採用案(「engineが提供する固定primitiveの組み合わせを表す木構造データ」)自体が宣言型データの一種であり、
「宣言型」と「DSL」を対立方式として比較すべきではない。実際には次の3段階のスペクトラムで捉える必要が
ある。
呼べるprimitiveの集合をengineが固定する以上、「engineが未対応の新しい計算方法には対応できずengine
更新が必要」という制約は2でも1と3の中間程度に残る(3ほど厳しくはないが、1のように任意の新しい計算を
その場で書けるわけではない)。これは2を選ぶことの代償として明示的に受け入れる。
現時点の結論は「DSL採用」ではなく、**「制約付き宣言型DSLを有力候補として検討中」**とするのが正確。
安全性(任意コード実行なし)と、単純な宣言型設定よりは高い表現力(primitiveの組み合わせ・条件分岐)を
両立できる点を根拠とする。
FinalTillagePlanResolver.resolve()の実際の入力は次の6引数(FinalTillagePlanResolver.kt:9-16)。
fun resolve(
field: Field,
profile: ProfileSnapshot,
headingDeg: Double,
tillageRegions: FieldTillageRegionsResult,
fixedResolution: FixedTillageConstraintResolutionResult,
toleranceM: Double = 0.02,
): FinalTillagePlanResult
初版ではEntranceSnapshotを直接の入力として説明していたが誤り。EntranceSnapshotは直接渡されず、
fixedResolution(Stage 2〜3の結果、仕上げ周回の開始anchor等を含む)という既に前段Stageが解決済みの
型として渡される。現行契約はStageごとに前Stageの出力型を次Stageへ渡す規則になっており、
FinalTillagePlanResolverはStage 4〜9の唯一のproducer、その手前(Stage 0〜3: 正規化・入口解決・
外周後未耕範囲計算・仕上げ周回anchor確定)は既に共通処理として切り出されている。
これは「patternへ生入力(圃場・Profile・入口)を渡し、Stage 0〜3相当の前処理もpattern側にやらせるのか、
それとも現行どおりengine共通のStage 0〜3が前処理した結果をpatternへ渡すのか」という、
入力境界に関するアーキテクチャの中心論点を残す。後者(現行どおり)であれば、Stage 0〜3の出力型
(FieldTillageRegionsResult・FixedTillageConstraintResolutionResult)自体がPattern 1固有の概念
(仕上げ周回anchor等)を含んでいないか確認する必要がある。含んでいれば、Stage 0〜3もPattern非依存な
形へ設計し直す必要がある。この点は未検証、次の調査対象とする。
パラメータの将来的な増減自体は、schemaにversion・additive fields・既定値・migration規則を持たせることで
対応でき、これはDSL固有の課題ではなく通常のAPI/設定のversioning問題として扱える。ただし上記の
入力境界(どのStageまでが共通か)は、パラメータ数の問題ではなく型設計の問題であり、別に解く必要がある。
TillagePlan.actions: List<RouteAction>の実際の型は、汎用的な「経路の命令列」ではなく、
Pattern 1というアルゴリズムの内部構造をそのまま表現した型になっている。
RouteActionRole(sealed class): CenterTillagePass(中央隣接耕1列)、CenterTillageLaneChangeFinishingLapApproach(仕上げ周回への接続移動)、FinishingLap(laneNumber: 1|2|3)TillagePhase(enum): CENTER_TILLAGE, FINISHING_LAP_3, FINISHING_LAP_1, FINISHING_LAP_2 —一方、RouteActionType { TILL, DEADHEAD }(RouteAction.kt:4)はPattern 1固有ではなく、
「耕すか、耕さない移動か」という農作業上の意味そのものであり、どのpatternでも共通に使える語彙として
共通契約に残せる。Pattern固有なのはRouteActionRole(pass番号・lap番号などPattern 1の内部構造)と
TillagePhaseの並び順であり、RouteActionTypeまで含めて全部作り直す必要はない。
将来、別のアルゴリズム(一つ飛ばし耕、スパイラル耕等)を追加する場合、RouteActionRoleや
FinishingLap(laneNumber)のような概念では表現できない。出力の型設計こそがDSL方式の本当の難所であり、
入力よりはるかに影響範囲が大きい(地図描画・将来の走行中誘導・#96作業記録すべてが出力契約を消費する)。
出力を、Pattern固有の型ではなく次の粒度に統一する方向で検討している。
付帯情報は2層に分ける案。
ただし現時点の「線分+タグ」という粒度だけでは、完成計画のdomain modelとして最低限次が未定義であり、
このままでは採用できない。
RouteActionType{TILL, DEADHEAD}相当の、pattern非依存の農作業上の意味(既存型は維持する方向、上記参照)FinishingLapApproachのKDocが説明する現行の考え方に相当)FinalTillagePlanResult.Solved/Stopped相当)「GeoJSON Feature(geometry + properties)の形と一致する」という理由は、表示・シリアライズ上の
利点にすぎず、domain契約として採用する十分な根拠にはならない。domain model(engineが完了検証・
guidance生成に使う型)と、GeoJSON presentation model(地図描画用の変換結果)は別の型として分ける。
本節の2層構造案は、上記の未定義項目を埋めたうえで改めて確定する。
耕し残し(UNTILLED_AREA_REMAINS)・DEADHEAD残存(DEADHEAD_TRACE_REMAINS)・経路連続性
(DISCONTINUOUS_ROUTE)の検証は、polygon演算・morphological closing・非軸平行/回転筆への精度対策
といった、このリポジトリで最も手間をかけてきた計算幾何そのもの(Track #105/#106参照)。これを
表現力を絞ったDSL側に再実装させるのは、DSLを絞った意味を失わせる。
一方、「常に耕し残しゼロ」を普遍的な不変条件としてengineに固定するのも誤り。patternによっては
意図的に一部を対象外にする(枕地のみ等)場合がありうる。
ここで、完了基準をpattern側に無制限に委ねると、packageが連続性やDEADHEAD被覆の検証そのものを
不要と宣言し、不安全な計画を「完成」と扱える余地が生まれる。これは避ける必要がある。したがって
次の二層に分ける。
「枕地のみ」のようなpatternを許容する場合も、耕し残し検査そのものを無効化するのではなく、
patternが自分の作業対象領域を先に宣言し、engineはその対象領域の内側だけで被覆を検証する形にする。
検証の有無をpatternが選べるのではなく、検証の対象範囲をpatternが宣言し、検証自体は常にengineが
安全invariantとして実行する。
これはゲームのMOD方式(host+組込みスクリプトVM、host APIをMODが呼び返す)と同じ構造。
上記2番目の「pattern → engine呼び出し」を、実行単位を持つスクリプトVMではなく、**「engineが用意した
固定primitiveの組み合わせを表す木構造データ(JSONのネスト構造)」**として表現する案を採る。
DSL側がLatLon(絶対測地座標)を直接扱うと、規則が特定の圃場の地理的位置に縛られ、「隣接列順で埋める」
のような本来位置非依存であるべき規則が再利用不能になる。DSLは何らかの局所平面座標系でベクトルを記述し、
絶対LatLonへの変換はengine側の境界(入力の正規化時・出力の最終シリアライズ時)でのみ行う、という方向は
維持する。
局所座標系自体は既に存在する(初版では「未検証」としていたが誤り)。FieldGeometryOps.normalize()
(FieldGeometryOps.kt:56)がFieldをLocalProjection(LocalProjection.kt:11)経由で局所メートル
平面座標(東=x、北=y)へ変換しており、原点は筆外周頂点の単純平均(FieldGeometryOps.kt:52,61-63)、
軸は東西・南北(entrance/heading基準ではない)で固定されている。
したがって次の2つの座標系を混同しない設計が必要になる。
FieldGeometryOpsが既に持つ、原点=筆重心相当・軸=東西南北のLocalProjection以下はIssue #107では調査・設計・実装しない。2番目の具体的な経路patternを扱う新Issueで、必要な項目だけを
再評価する。将来Issueでは、先にPattern 1と新patternの差分を整理し、両方から共通境界を導出する。
FieldTillageRegionsResult・FixedTillageConstraintResolutionResult)がPattern 1固有の概念をLocalProjection(EN座標)をそのまま使うか、入口・travel axis基準のdocs/specifications/adjacent-tillage-basic-route-pattern-1.mddocs/runbooks/navigation-field-geometry-pipeline-contract-pattern-1.mddocs/standards/navigation-field-geometry-contract-conformance.mddocs/decisions/issue69-tillage-spec-drift-audit.md(supersededされた旧概念の整理)