Issue #97 / Track #98。
状態: 2026-08-21利用者承認済み。2026-08-26角上入口契約変更、2026-08-27/2026-08-28/2026-08-29
入口・出口候補producer方式変更(全筆常時監視の境界横断検出を廃止、直近2点だけの方向算出から境界横断
までの点列の平均進行方向へ変更、計画開始操作と地図タップの分離、軌跡管理基盤の統合と検出済み候補の
identityベース保持)、2026-08-30横断前予測入口を「筆外の現在位置から最近傍境界点への最短経路」へ
変更し、さらに入口producerを筆決定時の単発スナップショットへ変更、距離範囲queryを確定、参考用exitを
廃止した、利用者承認済みの現行契約。2026-08-29 Issue #111によりStage 11をTablet計画編集へ拡張し、
初期仮方向、非同期再計算・キャンセル、構造化停止原因、利用者向け2分類、完成仮計画の地図表示から
「この計画を使う」で後続工程へ渡す境界までを追加した。2026-08-30 Issue #114により、旧restart契約の
中央終端→lap 3独立接続(FinishingLapApproach(3)/CENTER_TO_FINISHING_CONNECT_FAILED)を撤回した。
2026-08-30 Issue #115事前検討により、外周3列と中央耕の境界へもProfile指定の重ね幅を適用した。同日
Issue #115コメント #5769/#5770により中央transferのTILL/DEADHEAD分類を確定し、コメント #5772〜#5774
により「最後の中央pass終点=仕上げlap 3開始anchor 同一点」の強制を撤回した。2026-08-30 Issue #119により、
中央耕を各WorkArea内の単一の連続往復とし(wing分割を廃止)、終端隅から仕上げcirculation方向のロータリー
上げ空走(DEADHEAD)で仕上げlap 3開始位置へつなぐ契約とした。終端WorkArea/構成はこの空走が最短の候補として
選び、CenterPass終点 → 空走 → FinishingLap(3)始点を全境界で座標連続とする(#115の「1境界除外」は撤回)。本書は
docs/runbooks/navigation-field-geometry-pipeline-contract-restart.mdを置き換える。
旧restart契約はTrack #89〜#95時点の履歴baselineとして凍結し、現行実装判断には使用しない。
製品挙動の正本は
docs/specifications/adjacent-tillage-basic-route-pattern-1.md
とする。本契約はその挙動を実装Stage、型、producer/consumer、fixture、可視化へ落とす。
本契約と製品仕様が矛盾する場合は製品仕様を優先し、契約またはコードを黙って補完せず変更承認へ戻す。
次を満たす完成TillagePlanを生成する。
DEADHEAD)。計画経路はcenterTillageStartAnchorから始まる。入口から同anchorまでの開始前移動は運転者が未耕圃場内を
現地判断で行い、plannerは具体的な線、action、coverageを生成しない。
duringInitialLoopTargets、deferredTargets、追い詰め対象抽出、CornerTill geometry/action/schedule。cornerTillMaxInteriorAngleDegと追い詰め専用停止条件。safeCenterlineRegion。finishingLap3StartAnchorに最も近い中央pass端点を中央耕終了地点として、そこから逆算する形で内部導出し、requiredParity、startSide、finishingSideを独立の外部入力にする構造。DEADHEADと、1列専用の始終端・偶奇分岐。travelAxis、lateralAxis、有向anchor、座標・方向の共通定義。candidateLaneId、workAreaId、passId、segmentIndexの責務分離。PerimeterConnectionCandidateの経路抽出技術。ただしWorkArea間の接続に限定する。旧契約または旧Trackに存在すること自体は継承理由にならない。本書にproducer/consumerが無い部品は完成経路へ
接続せず、削除または診断専用へ隔離する。
| 名称 | 意味 |
|---|---|
travelAxis |
利用者が選択した中央耕の基準軸。各passはこの軸の正方向または逆方向を走る |
lateralAxis |
travelAxis + 90° |
longitudinalProjection |
点のtravelAxis上の値 |
lateralOffset |
点のlateralAxis上の値 |
headingDegは中央laneを配置する基準軸を定める値であり、最初の中央passの有向走行方向ではない。
各passの有向方向、開始側、終了側、必要な偶奇は、各WorkAreaの連続往復候補(4構成)のうち、
中央耕終了→finishingLap3StartAnchorの空走(仕上げcirculation方向)が最短の構成を選び、そこから逆算して
導出する。plannerは受け取った軸を別の軸へ自動最適化してはならないが、同じ軸上の正方向・逆方向のどちらを
各passが走るかはこの逆算に従って決める。
CenterDirectionSelection.headingDegは中央laneを配置する無向の基準軸である。一方、
DirectedRouteAnchor.headingDegは、その点から経路が進む、またはその点へ経路が到達する有向の接線方向である。
両者を同じ意味として比較しない。
中央耕の基準軸は初期仮方向、辺候補選択、自由回転のいずれかから得る。初期仮方向は、確認済み入口の進入方向に
方向として最も近い既存の辺方向候補(centerTillageDirectionCandidates、既存順・重複除去なし、0°/360°境界を
正しく扱い角度差最小、同差なら既存順先頭)をTablet側が与える(2026-08-29改訂、旧
defaultCenterTillageHeadingDeg規則を廃止)。初期仮方向は筆と入口が確定した時点で1回だけ決定し、fix更新
ごとに選び直さない。利用者が辺を選択・自由回転した方向とは扱わない。これらはCenterDirectionSelection内で
由来を区別し、plan requestの4要素は増やさない。plannerは由来を選択規則に使わず、渡されたheadingDegだけを
消費して方向を自動最適化しない。辺候補の巡回は初期仮方向として選ばれた候補の次から既存順で行い、辺長優先・
新代表辺抽出規則・角度閾値・ヒステリシスを追加しない。中央耕方向を変更しても、入口、
外周中心線、外周周回方向、退出geometryは変更しない。
enum class TillageAnchorRole {
CENTER_TILLAGE_START,
FINISHING_LAP_3_START,
EXIT,
}
data class DirectedRouteAnchor(
val point: LatLon,
val headingDeg: Double,
val role: TillageAnchorRole,
)
CENTER_TILLAGE_START: 仕上げ側から逆算した最初の中央passの開始点と、実際の有向走行方向。FINISHING_LAP_3_START: 固定した外周3→1→2→退出から求める3列目開始点・方向。EXIT: 外周2列目が入口境界へ到達する点。位置は進入入口と同じ境界点、方向は進入方向の逆向きとする。入口anchorを完成経路の先頭へ置かない。入口はEntranceSnapshotとして周回方向とexitを決める入力であり、
開始前移動を表すroute anchorではない。
EntranceSnapshotは境界点、進入方位、sourceに加え、入口が筆の頂点の許容誤差内にある場合に利用者が確認した
導入側のcirculationAtCornerをnullableで保持する。辺上入口ではnullとし、位置から一意に解決する。
circulationAtCornerをplan requestの独立フィールドに分離せず、確認済み入口snapshotの一部としてproducerから
Stage 3へ渡す。角上入口で値が無い場合はAmbiguousEntranceCornerとして停止し、走査順や進入方位によるfallbackを
行わない。
完成判定はEXITの境界点と方向で行う。入口境界より圃場外側の具体的な退出線を、完成条件、DEADHEAD、coverageへ
含めない。内部表現や表示都合で補助線を描く場合も、計画actionとして扱わない。
中央0列では中央passが存在しないため、centerTillageStartAnchorをfinishingLap3StartAnchorと同一にする。
この場合の完成計画は同anchorの仕上げlap 3から始まり、空の中央actionや架空の接続actionを作らない。
計画actionは次の2種類だけを持つ。
enum class RouteActionType { TILL, DEADHEAD }
TILL: 基本計画の耕耘責任を持つ。DEADHEAD: 次のTILLへ接続する計画内移動。全軌跡が時間的に後のTILL作業幅unionで覆われなければならない。中央列間・WorkArea間の接続は、接続geometryを確定した後に時系列coverageで分類する。時間的に後のTILLで
覆われる区間はDEADHEAD、覆われない区間はその移動時に耕すTILLとする。1本の接続内で条件が変わる場合は、
同じgeometryを内部区間へ分割してよい。分類によって接続geometry、中央passの列順・始終端、anchorを変更せず、
分類のための別経路やfallbackを生成しない。DEADHEADとして残す区間だけは、後続TILLによる全軌跡被覆を必須とする。
最後の中央passは連続往復の終端隅で終わる。中央耕終了地点とlap 3開始位置は同一点である必要がなく、両者の
座標一致を完成条件にしない。両者の間に、ロータリーを上げた空走(DEADHEAD固定)を1本置く。この空走は、
中央耕を終えた隅から仕上げlap 3の走行中心線へ短く寄り、その中心線を仕上げcirculationと同じ回転方向に
たどってfinishingLap3StartAnchor(その走行方向と揃った向き)へ至る経路とする。逆走・U ターンは生成しない。
中心線をたどる部分は仕上げlap 3が後で耕すため、既耕の中央部を横切らず、空走の全軌跡が後続外周耕(3→1→2)の
TILL作業幅で覆われる。この空走は常にDEADHEADとし、一部をTILLへ変えない(この点で中央列間・WorkArea間の
CenterTillageLaneChange(#5769/#5770)とは異なる)。FinishingLapApproach(3)(耕したまま接続するTILL)とは
別roleとする。CenterPass終点 → 空走 → FinishingLap(3)始点の各境界は座標連続とする(#115で設けた「1境界
だけ除外」は撤回)。中央耕終了地点がfinishingLap3StartAnchorと許容誤差以内なら空走actionを省略し直接
lap 3本体へ入る。FinishingLapApproach(3)(耕したまま接続するTILL)は生成しない。
lap 3→lap 1、lap 1→lap 2のfinishing工程間接続はTILLとする。現地の細かな作業機操作はモデル化せず、
外周本体とは別の「耕しながら列間移動」actionとして表す。これらをDEADHEAD候補へ変更しない。
plannerは作業機の上げ下げ地点・操作手順を計画しない。旧DOUBLE_TILLを候補fallbackや利用者設定として使わない。
複数回耕す区間も各通過時点のTILLとして表し、初回実装では厳密な多重走行最適化を行わない。
安全余白は持たないが、exit以外の計画中心線はfield polygon内に置く。作業幅coverageはfield polygonへclipする。
これは利用者設定の安全距離ではなく、入力polygonに対する物理的な幾何条件である。
uncovered = fieldPolygon - union(all planned TILL work-width coverage)
perimeterResidual = uncoveredの連結成分のうちfield boundaryに接するもの
centralUncovered = uncovered - perimeterResidual
境界接触は契約fixtureで固定するgeometry tolerance以内で判定する。凸角、凹角、くびれ、角度、大きさで分類しない。
大きなperimeterResidualも完成を妨げない。centralUncoveredがtoleranceを超えて残る計画は完成ではない。
data class TillagePlanRequest(
val field: FieldSnapshot,
val entrance: EntranceSnapshot,
val profile: ProfileSnapshot,
val centerDirection: CenterDirectionSelection,
)
初回のパターン1requestに含めないもの:
作業機Profileは少なくともimplementWidthCmとoverlapWidthCmを持つ。既定値は150cmと10cmである。
overlapWidthCmは、外周lap同士、中央lane同士、および外周3列と中央耕の境界へ適用する。
| 値 | production producer | consumer | 外部入力 |
|---|---|---|---|
FieldSnapshot |
選択中の登録筆 | normalize、全geometry | 筆選択として可 |
EntranceSnapshot |
登録入口、または選択済みの筆に対する横断前の最短経路予測・実横断観測・利用者方向指定のいずれかから生成し、利用者が確認した入口候補。角上入口では利用者確認済みcirculationAtCornerを含む |
circulation、exit | 入口確認・変更として可 |
ProfileSnapshot |
選択中Profile | 外周、中央、coverage | Profile選択として可 |
CenterDirectionSelection |
初回は確認済み入口の進入方向に最も近い既存辺候補(centerTillageDirectionCandidates、既存順・重複除去なし、同差なら既存順先頭)による初期仮方向、以後は同候補の既存順巡回(初期候補の次から)、または自由回転 |
中央laneの基準軸だけ。先頭passの有向方向は決めない | 方向操作として可。初期仮方向は利用者選択済みとしない |
| 仕上げcirculation | 辺上入口位置、または角上入口で確認済みの導入側circulationの反転 | 外周3→1→2 | 不可 |
| perimeter layout | field + Profile | remaining region、finishing traversal、coverage | 不可 |
centerWorkRemainingRegion |
fieldPolygon - perimeterTilledCoverageをProfile指定のoverlapWidthCm / 100.0メートルだけbufferし、fieldでclip |
中央lane生成、中央TILL coverage検証、preview | 不可 |
finishingLap3StartAnchor |
3→1→2→exit resolver | 中央耕終了地点の選択、中央逆算、composer | 不可 |
| center lane/WorkArea順、開始側・終了側・必要な偶奇 | 各WorkAreaの連続往復候補のうち中央耕終了→lap 3空走(circulation方向)最短の構成からの逆算 | center traversal | 不可。独立のplan request入力にしない |
centerTillageStartAnchor |
逆算結果の最初のpass | composer、preview | 不可 |
中央耕終了→lap 3空走(ロータリー上げDEADHEAD) |
終端隅から仕上げcirculation方向のlap 3中心線traversal | coverage、composer | 不可 |
| plan内transfer | 隣接pass/WorkArea/外周lap間接続resolver | coverage、composer | 不可 |
| perimeter residual | final TILL coverageとfield boundary | completion、preview | 不可 |
TillagePlan |
composer + invariant | PC preview、Tablet | 完成候補選択だけ可 |
| 非同期plan結果 | Tabletの正式な計算実行担当がPattern1TillagePlanService.planから受け取る |
単一のTablet計画workflow state。編集識別子・最新再計算番号・未キャンセル・入力一致を満たす結果だけ採用 | 不可 |
入口候補producerは、筆決定時の現在位置と、その時点までの共通参照用軌跡を入力に1回だけ実行する。
fix受信ごとの横断前予測・実横断監視・候補更新は行わない。
横断前、選択済みの筆の外側に現在位置がある場合は、現在位置から筆polygon境界上の最近傍点までの直線を
筆へ最短で到達する予測経路とする。予測入口位置は最近傍境界点、予測進入方向は現在位置から同点へ向かう
方位である。境界辺への垂足が線分上にあれば垂足、線分外なら最寄りの頂点を使う。過去の点列の正味の
移動方向や最新2点の方向を、この横断前予測の入力にしない。複数の境界点が同じ最短距離になる場合は、
幾何演算が返すいずれか1点を採用してよい。一意性判定、浮動小数点誤差を含む同距離判定、距離差の
製品閾値は設けない。提示された入口が利用者の意図と異なる場合は、実際に筆へ進入した後で改めて
計画作成を開始し、実横断を復元する。
筆決定時に現在位置が筆内の場合は、その時点までの未圧縮Hotを過去方向へ遡って最後の外→内横断を探す。
この実横断復元producerは、連続した測位点列を組み立てる。隣接する
2測位点の点間距離がレイヤー0設定entranceCrossingMaxSegmentDistanceM以内の場合だけ同じ点列として
接続し、超えた場合はそれより古い点を接続しない。既定値は5m、値は0より大きい有限値とする。これは
入口位置・進行方向の推定に使う点列を制限するproducer設定であり、受信後の経過時間による候補拒否値では
ない。各測位点は受信時点で品質条件を満たさなければならない。
実横断の入口位置と進行方向は分離して求める。点列内に実際に観測できた圃場外→内の境界横断があれば、その横断
線分(最後の外側点→最初の内側点)と境界の交点を入口位置とし、点列の最初の点から横断点までの正味の
移動方向(距離加重平均と同値の直線近似)を進行方向とする。緯度・経度の単純平均を入口位置にはしない。
点列内に境界横断が観測できなければ、その場から入口を捏造しない。
共通参照用軌跡(TrajectoryRepository)はHot(未圧縮、fixId・品質付き)とCold(RDP圧縮済み)を持ち、
最新点から過去方向へ遡った累積走行距離の指定範囲を返すqueryを提供する。距離は現在保持するCold+Hotの
折れ線長から算出し、segment境界をまたいで接続・加算しない。Coldの距離は圧縮後geometryによる参照用の
近似距離であり、原測位点に基づく厳密な走行距離ではない。実横断判定はfixId・品質が必要なためHotだけを使う。
API境界はqueryByTravelDistance(fromLatestM, toLatestM)相当とし、0以上の有限値かつ
fromLatestM <= toLatestMを要求する。不正値を黙って補正しない。返却順は古い点から新しい点とする。
横断前予測・実横断復元は筆決定時に1回だけ評価する。利用者が候補を取り消した後、同じ計画フロー中の
fix受信で候補を復活させない。予測fix identity、予測抑止フラグ、時間経過による再評価を設けない。
レイヤー0設定が破損している場合、横断前予測と実横断復元を含む候補2の自動producerは実行しない
(既定値へ黙って置き換えて動作を継続しない)。登録入口、および次段落の
利用者による明示的な方向指定は、この破損の影響を受けない(由来を区別して自動候補だけを無効化する)。
この設定をEntranceSnapshotまたはTillagePlanRequestへ格納せず、Stage 0以降のplannerへ渡さない。
登録入口・候補2の自動入口のいずれも無い場合、現在地から利用者が明示的に指定した方向と筆境界の
交点を第3の入口取得手段とする(操作時点の品質・鮮度を要求する)。
入口の由来を内部状態または診断記録に保持する場合は、登録入口、横断前予測、実横断復元、利用者方向指定を
実際のproducer経路どおりに区別し、横断前予測を実横断として記録しない。由来はplanner入力でも
利用者操作の入力でもないため、入口確定画面を含む利用者向けUIには表示しない。
Tablet入口producerは反対側境界の参考用exitを生成・保持・表示しない。Pattern 1のEXIT anchorは、
Stage 3以降で確認済みEntranceSnapshot.boundaryPointと同じ位置、approachHeadingDeg + 180°の方向として
plannerが導出する。入口未確定のままexitだけを決めるfallback・状態・型を持たない。
筆選択自体の起点はTablet側UIの計画開始操作(WorkMenu「耕うん計画を作成」)であり、通常の地図タップは
筆選択として働かない。この起点・地図タップの範囲・筆選択モードはTablet側UI状態機械の責務であり、
本契約のStage 0以降には影響しない。
TillagePlanRequest
→ validation / field classification
→ perimeter 3-lap layout
→ finishing 3→1→2→exit resolution
→ center remaining regionをProfile固定pitchの中央lane / passで覆う実geometryを生成
→ 各WorkAreaの連続往復候補(4構成)を列挙し、終端隅→lap 3の空走(仕上げcirculation方向)最短の候補を終端に予約
→ そこから隣接center lane / WorkArea traversalを逆算
→ center remaining regionを全作業幅coverageが覆うことを検証
→ center開始からfinishing lap 3までの正方向traversalへ変換
→ plan内transfer生成
→ TILL/DEADHEAD時系列割当
→ final coverage / perimeter residual / central uncovered
→ TillagePlan composer / invariant
→ PC preview・利用者gate
→ Tablet計画編集・後続の正式承認工程への受け渡し
開始前移動、追い詰め、利用者による現地仕上げはこのchainへ入れない。
入力: TillagePlanRequest
検証:
implementWidthCm > 00 <= overlapWidthCm < implementWidthCm出力: 正規化前request、またはINVALID_INPUT。
検証失敗時は自由文detailだけでなく、第5章の安定した構造化原因を生成する。原因は型付き停止結果へ
一度だけ保持して上位へ伝達し、利用者向け分類を自由文解析で決めない。
追い詰め角、安全余白、自動重ね幅調整量、fallback actionは検査しない。
入力: Stage 0出力
出力:
SUPPORTED / OUT_OF_SCOPE / INVALID_INPUT / GEOMETRY_FAILURE凸・凹は分類情報として保持してよいが、凹形状を停止理由にしない。穴、複数面、自動修復を必要とするpolygonは
パターン1の対象外とする。
対象分類は単一の共有処理(FieldPlanningGeometry.classifyFieldForPattern1)へ委譲する。Stage 1と、Tabletの
計画開始前判定(壊れた筆を初期方向選択・入口確認・計算より前に止める)の両方が同じ共有処理を呼び、分類
ロジックを2か所へコピーしない。TabletとPCで同じ筆が同じ分類になる。共有処理は自由文から分類を推測せず、
Pattern1PlanStopCauseの型付き構造化原因(FIELD_SHAPE_OUT_OF_SCOPE = 穴・複数面 /
FIELD_DATA_REQUIRES_REPAIR = 自己交差・退化形状 / FIELD_COORDINATE_NONFINITE = 非有限座標)を返す。
Stage 0→Stage 1以降の正式な順序と結果は変えない。正常な対応筆(SUPPORTED)は
centerTillageDirectionCandidatesが最低1件を返すことを、共有判定または契約テストで保証する。対応筆なのに
候補0件になる場合は新しいfallbackを追加せず、実装を停止して形状と原因を報告する。
入力: normalized field、Profile
標準区間:
局所狭窄区間:
OUT_OF_SCOPE。圃場全体を1周または2周で覆える狭小圃場:
NOT_IMPLEMENTED。3周を重ねて完成計画にしない。出力:
PerimeterLapLayout(lap1, lap2, lap3)入力: EntranceSnapshot、Stage 2 layout
処理:
EntranceSnapshot.circulationAtCornerを使い、AmbiguousEntranceCornerで停止する。exitAnchorを生成する。finishingLap3StartAnchorを生成する。出力:
finishingLap3StartAnchorexitAnchor入口から中央開始までのgeometry、action、anchorを生成しない。
入力: field、Profile、Stage 2 perimeter coverage、center direction、finishingLap3StartAnchor
処理:
baseRemaining = fieldPolygon - perimeterTilledCoverageを求め、baseRemainingをProfileで指定されたoverlapWidthCm / 100.0メートルだけ外周側へbufferし、fieldPolygonでclipした領域を、中央耕が作業幅で覆うべきcenterWorkRemainingRegionとする。baseRemainingが空なら拡張対象も空とする。この領域はcoverage検証対象であり、lateralAxis範囲からProfileの固定pitchで配置する。lane格子の位相をfinishingLap3StartAnchorのlateralOffsetへ固定しない(anchorを通る仮想laneを作らない)。各laneのcenterWorkRemainingRegionをすべて覆うまで必要なlaneを追加し、0/1/複数lane候補と分裂segmentをoverlapWidthCm分だけ小さな中央未耕部分を黙って捨てない。独立safeCenterlineRegionを生成・入力しない。TILL/DEADHEADの時系列
割当は後段のcoverage検証のために行い、終端lane、列順、開始側、終了側を決める入力には使わない。coverage上の
分類のために同じ走行geometryを内部区間へ分けてもよいが、新しい移動経路、座標の断絶、利用者操作は作らない。
出力:
centerWorkRemainingRegionと、中央candidate coverageによる被覆結果0 laneは外周だけで中央対象を覆えた正常結果。1 laneは特別な先行移動を持たない正常結果。
0 laneではcenterTillageStartAnchor = finishingLap3StartAnchorとし、Stage 5の逆算中央traversalを空で通過する。
入力: Stage 4 lane/segment、finishingLap3StartAnchor、Stage 3の仕上げlap 3本体geometry(circulation順)、
finishingCirculation
処理:
(WorkArea, 連続往復構成)について、その往復の終端隅からfinishingLap3StartAnchor.pointまで、finishingLap3StartAnchor(その走行方向とfieldPolygon内に引けない候補は採用しない(直線で代用しない)。finishingLap3StartAnchorまで実際にたどる空走経路の(workAreaIndex, 構成index)昇順で決定的にCENTER_GEOMETRY_OPERATION_FAILED。centerTillageStartAnchorとする。中央passが1本以上ある場合、最後のCenterTillagePassの直後に上記の空走(ロータリー上げDEADHEAD、
FinishingLapApproach(3)=耕したまま接続するTILLとは別role)を1本置き、その直後をfinishingLap3StartAnchor
から始まるlap 3本体とする。中央耕終了地点がfinishingLap3StartAnchor.pointと許容誤差以内なら空走actionを
省略し直接lap 3本体へ入る。中央耕終了地点とfinishingLap3StartAnchor.pointの座標一致は完成条件にせず、
両者の座標差だけを理由に停止しない。CenterPass終点 → 空走 → FinishingLap(3)始点の各境界は座標連続とする。
中央lane・連続往復候補・全WorkArea/pass traversalの構成、または空走の生成に失敗した場合は
CENTER_GEOMETRY_OPERATION_FAILED、traversalを構成できても中央未耕が残る場合は
CENTRAL_UNTILLED_AREA_REMAINS、合成後のaction境界で座標が連続しない場合はROUTE_DISCONTINUOUSとする。
CENTER_TO_FINISHING_CONNECT_FAILED・INTERNAL_TRANSFERは復活させない。新しい入力、fallback、停止codeが
必要になった場合は実装を止め、契約変更へ戻す。
中央0列の場合はWorkArea/pass逆算を行わず、空のcenter traversalと
centerTillageStartAnchor = finishingLap3StartAnchorを返す。
初回実装では、順位規則は「空走経路長最短 + (workAreaIndex, 構成index) の決定的tie-break」だけとする。
多重走行量・外周帯滞在長などの追加評価軸、一般Hamiltonian/path-cover化、固定候補上限は導入しない
(現地試験で必要と判明した時点で追加)。
出力:
centerTillageStartAnchor入力: Stage 5 traversal skeleton、field、Stage 2/3外周geometry
対象:
開始前の入口→中央開始は対象外。
中央列間・WorkArea間transferはfield内に連続して存在するgeometryとして、中央passの列順・始終端を変えずに
確定する。このStageでは、後続TILLで覆われるかどうかを理由に接続geometryを変更・除外せず、TILL/DEADHEADも
まだ確定しない。成立しないWorkAreaを黙って省略しない。
出力:
入力: Stage 3固定外周、Stage 6 traversal
正方向:
centerTillageStartAnchor
→ center pass / WorkArea transfer
→ 最後のcenter pass終点(= 連続往復の終端隅。finishingLap3StartAnchor と同一点である必要はない)
→ 中央耕終了→lap 3の空走(ロータリー上げDEADHEAD、仕上げcirculation方向、finishingLap3StartAnchor で終わる)
→ finishingLap3StartAnchor から lap 3
→ lap 1
→ lap 2
→ entrance boundary上のexit anchor
passと外周本体はTILLとする。中央列間・WorkArea間接続は、完成geometryを時間的に後のTILL coverageと照合し、
覆われる区間をDEADHEAD、覆われない区間をその移動時に耕すTILLへ分類する。部分的に覆われる場合は同じ
接続geometryを内部区間へ分割して分類してよいが、分類によって接続geometry、列順、中央passの始終端を変えない。
中央終了→lap 3には、Stage 5で生成したロータリー上げの空走(DEADHEAD固定。仕上げcirculation方向で
finishingLap3StartAnchorに到着)を1本置く(中央耕終了地点がanchorと許容誤差以内なら省略)。この空走は
lap 3の走行中心線上をたどるため常に後続外周耕のTILLで覆われ、TILLへは変えない。時系列coverage検証で
覆われないことが判明した場合はDEADHEAD_TRACE_NOT_COVEREDで停止する(Stage 5の候補採用条件を満たしていれば
発生しない安全網)。続くfinishingLap3StartAnchorからlap 3本体が始まる。lap 3→lap 1、lap 1→lap 2は最初から明示的なTILL
接続として構築する。DEADHEADとして残した区間の未被覆を警告だけで通さず、TILL/DEADHEAD分類のために
別の接続経路やfallbackを生成しない。
入力: Stage 7全action、field、Profile
算出:
perimeterResidualcentralUncoveredcenterWorkRemainingRegionの未被覆完成条件:
centralUncoveredがtolerance内で空。CenterTillagePassの直後は「任意で1本の中央耕終了→lap 3空走(DEADHEAD)、finishingLap3StartAnchorから始まるlap 3本体」であり、間に他のactionが無い。最後の中央passfinishingLap3StartAnchorとの座標一致は完成条件にしない。baseRemainingが空でない場合、中央TILL coverageだけで、Profile指定の重ね幅を含むcenterWorkRemainingRegionを覆う。中央TILL coverageには、中央passに加え、Stage 7でTILLへ分類した中央列間・WorkArea間接続区間を含む。
DEADHEADへ分類した接続区間は含めない。
perimeterResidualの存在・角度・大きさは完成失敗にしない。厳密な多重走行面積・全距離最適性を完成条件にしない。
最終uncovered = fieldPolygon - union(all planned TILL coverage)と、そこから求めるcentralUncoveredは実際の
計画全体の未被覆を表し、Profileの重ね幅で拡張しない。全TILL unionは、外周3列と中央耕の重ね幅を証明する
代替にはならない。
共有点で前actionの到達接線と次actionの出発接線が異なることは、それ自体を不連続としない。本契約は旋回軌跡、
操舵角、最小旋回半径をモデル化しないため、方向連続性を完成条件へ追加しない。
Stage 7/8の確定結果を型へ写す。composerは探索・再順序化・fallbackを行わない。
必須invariant:
centerTillageStartAnchor。CenterTillagePassの直後は、任意で1本の中央耕終了→lap 3空走(DEADHEAD、role はFinishingLapApproach 以外)、その直後にfinishingLap3StartAnchorから始まるlap 3本体であるFinishingLapApproach(3)centralUncoveredが空である。中央0列ではplan先頭のanchorから直ちにlap 3が始まり、中央actionは0件である。
PC previewは次を順に可視化する。
開始前移動の線と追い詰め対象・経路は表示しない。内部WorkArea候補は診断表示として完成計画と区別する。
Tablet側でplannerまたはStage呼出順を再実装しない。:track-coreの
Pattern1TillagePlanService.planだけを画面を止めない計算実行担当から呼び、純粋な状態遷移処理の中で
同期実行しない。成功、失敗、キャンセルは明示イベントとして単一の計画workflow stateへ戻す。
処理:
ProfileSnapshot、確認済み入口の進入方向にTillagePlanRequestを組み立てる。筆選択時に共有のclassifyFieldForPattern1で対象判定し、対象外・データ不良の筆は初期方向選択・入口確認・計算へ進めずFinalTillagePlanResult.Solvedだけを完成仮計画として地図へ表示する。筆境界、確認済み入口、経路全体、centerTillageStartAnchorと進行方向、TILL/DEADHEAD、仕上げ外周3→1→2、exit anchor、centerTillageDirectionCandidatesを既存順に巡回し、重複を除去しない。初期仮方向としてTillagePlanと計画時のTillagePlanRequest snapshotを後続の正式承認工程へ操作は画面下部のコンパクトな段階別計画編集パネルに置く。大きなbottom sheetで地図を覆わず、地図上の
常設ボタンを増やさない。固定画面骨格を維持し、強調する主操作を常に1つ以下にする。段階別計画編集パネルは
通常作業ドックと同じ高さ定数を共有し、通常時・計画時とも固定104dpとする(可変高さを使わず、状態遷移で
地図領域の高さも主操作の位置も動かさない。主操作は右端の固定枠、状態文言は1行を基本とし長い場合は省略、
操作は1行、主操作64dp以上・補助操作48dp以上、低頻度操作は三点メニュー、長い失敗詳細はダイアログへ
逃がし固定領域を伸ばさない)。計算中・入口確認中・失敗時も同じ104dpを維持する。
| 結果 | 意味 |
|---|---|
COMPLETE |
全完成条件を満たす |
DIAGNOSTIC_PARTIAL |
一部geometryはあるが実行不可 |
OUT_OF_SCOPE |
穴、複数面、自動修復必要、1列幅未満等 |
NOT_IMPLEMENTED |
対応可能だが未実装。例: 圃場全体を1〜2周で覆う狭小圃場 |
INVALID_INPUT |
Profile、入口、方向、座標等が不正 |
GEOMETRY_FAILURE |
対象入力だが幾何演算に失敗 |
共通計算処理は、失敗を最初に把握した下位処理で型付きのPattern1PlanStopCauseを生成し、上位へそのまま
伝達する。既存の粗い停止理由や自由文のdetailからserviceが原因を推測・再構成してはならない。
構造化原因が保持する情報は次の4項目に限定する。
code: 安定した原因コード。問い合わせ識別子も兼ね、別のdiagnostic IDを追加しない。stage: 発生段階。nature: 下表の原因種別。implicatedInputs: FIELD / ENTRANCE / ENTRANCE_CORNER_CIRCULATION / PROFILE /CENTER_DIRECTIONのうち、変更・診断対象となる入力。構造化原因は型付き停止結果へ一度だけ保存する。TillagePlanPipelineResult.stopCauseを公開上の参照入口に
する場合は、その停止結果へ委譲する計算プロパティ等とし、同じ原因を二重保存しない。既存のdetail、
warnings、diagnosticGeometryは診断情報として別に保持し、構造化原因へ複製しない。生の診断情報を
Tabletの利用者向け表示へ直接出さない。
| nature | 意味 | Tablet利用者向け分類 |
|---|---|---|
INPUT_DEPENDENT |
方向・入口・設定を変えると結果が変わり得る。成功保証はしない | 条件を変更して再作成できる |
INPUT_REJECTED |
特定入力が明確に不正で、変更対象が定まる | 条件を変更して再作成できる |
OUT_OF_SCOPE_BY_SPEC |
Pattern 1仕様上の対象外 | この経路計画を使用できない |
NOT_IMPLEMENTED |
仕様上は対応可能だが現在未実装 | この経路計画を使用できない |
DATA_DEFECT |
workflow内で修正できない筆データ不良 | この経路計画を使用できない |
INTERNAL_ERROR |
内部不整合または条件変更で解決できない演算失敗 | この経路計画を使用できない |
Tablet側はnatureから2分類を、codeとimplicatedInputsから安全な詳細文言と戻り先を決める。
原因を1つの変更対象へ絞れない場合は、利用者が入口・中央方向・作業機設定等から選ぶ。共通計算結果へ
Tablet固有の画面名・利用者向け表示文言を埋め込まず、自由文detail/summaryを分類に使わない。
全停止経路を網羅し、原因の意味、nature、利用者の行動、戻り先が同一の場合に限り、複数経路を同じ
構造化原因へまとめる。まとめた各停止分岐も個別にテストする。
| 監査参照 | 安定原因code | stage | nature | implicatedInputs / Tablet動作 |
|---|---|---|---|---|
| S0-1 | FIELD_COORDINATE_NONFINITE |
REQUEST_VALIDATION | DATA_DEFECT | FIELD / 使用不可 |
| S0-2〜S0-3 | ENTRANCE_GEOMETRY_NONFINITE |
REQUEST_VALIDATION | INTERNAL_ERROR | ENTRANCE / 使用不可 |
| S0-4 | CENTER_DIRECTION_NONFINITE |
REQUEST_VALIDATION | INTERNAL_ERROR | CENTER_DIRECTION / 使用不可 |
| S0-5 | ENTRANCE_OFF_FIELD_BOUNDARY |
REQUEST_VALIDATION | INPUT_REJECTED | ENTRANCE / 入口確認へ戻る |
| S0-6 | WORK_PITCH_INPUT_INVALID |
REQUEST_VALIDATION | INPUT_REJECTED | PROFILE / 作業機設定へ戻る。Tablet通常経路では事前検証で計算前に止める |
| R-1a | ENTRANCE_CORNER_CIRCULATION_UNCONFIRMED |
ENTRANCE_FINISHING | INPUT_REJECTED | ENTRANCE_CORNER_CIRCULATION / 角入口の外周方向確認へ戻る |
| R-1a | FINISHING_TRAVERSAL_UNRESOLVED |
ENTRANCE_FINISHING | INTERNAL_ERROR | 使用不可。角入口未確認とは分離する |
| — | PERIMETER_WIDTH_BELOW_ONE_LANE |
PERIMETER_LAYOUT | OUT_OF_SCOPE_BY_SPEC | 使用不可。作業機変更で成功するとは案内しない |
| R-1b | FIELD_SHAPE_OUT_OF_SCOPE |
FIELD_CLASSIFICATION | OUT_OF_SCOPE_BY_SPEC | FIELD / 穴・複数面等は使用不可。Stage 1共有分類(classifyFieldForPattern1)とTablet計画開始前判定で同一 |
| R-1b | FIELD_DATA_REQUIRES_REPAIR |
FIELD_CLASSIFICATION | DATA_DEFECT | FIELD / 自己交差・退化形状(線・点・頂点不足・全頂点一直線・全頂点同一点)等の要修復データは使用不可。Stage 1共有分類とTablet計画開始前判定で同一。壊れた筆は初期方向選択・入口確認・計算より前に停止し、独立した「初期方向算出不可」状態を設けない |
| R-1c | CENTER_REGION_UNCOMPUTABLE |
CENTER_REGION | INTERNAL_ERROR | 使用不可 |
| R-2 | CENTER_GEOMETRY_OPERATION_FAILED |
WORKAREA_TRAVERSAL | INPUT_DEPENDENT | ENTRANCE・CENTER_DIRECTION・PROFILEから変更対象を選ぶ |
| R-1d | FINISHING_TRAVERSAL_UNRESOLVED |
ENTRANCE_FINISHING | INTERNAL_ERROR | 使用不可 |
| R-3 | ROUTE_DISCONTINUOUS |
WORKAREA_TRAVERSAL | INPUT_DEPENDENT | CENTER_DIRECTION・ENTRANCEから変更対象を選ぶ |
| R-1f | TEMPORAL_COVERAGE_COMPUTATION_FAILED |
TEMPORAL_COVERAGE | INTERNAL_ERROR | 使用不可 |
| R-4 | DEADHEAD_TRACE_NOT_COVERED |
TEMPORAL_COVERAGE | INPUT_DEPENDENT | CENTER_DIRECTION・ENTRANCEから変更対象を選ぶ |
| R-5 | CENTRAL_UNTILLED_AREA_REMAINS |
COMPLETION_VALIDATION | INPUT_DEPENDENT | CENTER_DIRECTION・PROFILEから変更対象を選ぶ |
| R-6 | PLAN_INVARIANT_FAILED |
PLAN_COMPOSITION | INTERNAL_ERROR | 使用不可 |
| — | SMALL_FIELD_LAP_COUNT_NOT_IMPLEMENTED |
PERIMETER_LAYOUT | NOT_IMPLEMENTED | 1〜2周で覆える狭小圃場。使用不可だが仕様上対象外とは表示しない |
Issue #114では、CENTER_TO_FINISHING_CONNECT_FAILEDを停止原因から廃止する(唯一のconsumerだった
INTERNAL_TRANSFER stageも削除)。これらは復活させない。中央lane・連続往復候補・全WorkArea traversalの
構成、または中央耕終了→lap 3の空走生成に失敗した場合はCENTER_GEOMETRY_OPERATION_FAILED、中央未耕は
CENTRAL_UNTILLED_AREA_REMAINS、合成後のaction境界の座標断絶はROUTE_DISCONTINUOUS、中央耕終了→lap 3の
空走が後続外周耕で覆えない場合はDEADHEAD_TRACE_NOT_COVEREDで表す。中央耕終了地点と
finishingLap3StartAnchor.pointの座標差だけを理由に停止させない。
1〜2周で覆える狭小圃場は、Stage 2で専用に検出してNOT_IMPLEMENTEDで停止する。これは既存契約へ
適合させる計算動作の追加であり、「幾何・計算ロジックは不変」の対象外とする。3周を重ねた完成計画を
返さず、1周または2周で覆える専用fixtureで回帰検証する。
禁止事項:
OUT_OF_SCOPEにする。detail/summaryを解析して利用者向け分類を決める。centerWorkRemainingRegionを中央TILL coverageだけで覆う。circulationAtCornerが無ければAmbiguousEntranceCornerで停止する。EntranceSnapshotの保存・再読込後も保持され、独立request入力や走査順fallbackを使わない。OUT_OF_SCOPE。uncoveredとcentralUncoveredは全TILL coverageから算出し、Profileの重ね幅で拡張しない。NOT_IMPLEMENTEDで、重複3周を返さない。baseRemainingが空なら、Profileの重ね幅が0より大きくても拡張対象は空で、重ね幅のためだけに中央passを追加しない。SUPPORTEDで、centerTillageDirectionCandidatesが1件以上を返す。FIELD_SHAPE_OUT_OF_SCOPE(OUT_OF_SCOPE_BY_SPEC)。FIELD_DATA_REQUIRES_REPAIRFIELD_COORDINATE_NONFINITE。EdgeAligned)と扱わない。headingDegは中央laneの基準軸であり、先頭中央passが必ず同じ有向方位へ走るとはassertしない。CenterPassの直後が「任意で1本の中央耕終了→lap 3空走(DEADHEAD。FinishingLapApproach 以外)、その直後にFINISHING_LAP_3 phaseのFinishingLap(laneNumber == 3)FinishingLapApproach(3)(耕したまま接続するTILL)を置かない。DEADHEADとして残る区間に後続被覆参照がある)。CenterPass終点は連続往復の終端隅であり、finishingLap3StartAnchor.pointとの座標一致はassertしない。CenterPass終点 → 空走 → FinishingLap(3)始点の各境界は座標連続であることをassertする。ROUTE_DISCONTINUOUSへ停止しないことを確認する。e726ebb6(再現入口 (33.204093667, 133.105705438)、進入方向 108.899°、初期仮方向はinitialProvisionalHeadingで算出)では、入口からの開始前移動をplanへ含めず、北東側のcenterTillageStartAnchorから中央耕を開始し、各WorkArea内で単一の連続往復で耕り(訪問順の列offsetがDEADHEAD固定)で仕上げ外周centerWorkRemainingRegionを覆い、外周3列とfixture座標をplan requestへ直接注入せず、次から開始する。
EntranceSnapshotだけをplan requestへ渡す。classifyFieldForPattern1による対象判定、Solved/停止結果、地図表示/利用者向け2分類、固定してよい外部入力は、圃場データ、GNSS入力、保存済みProfile、正式な接続境界に置く計算時間制御用の
計算実装だけとする。完成済みの筆・入口・Profile・方向を一括して直接注入し、Tabletの取得・確認・
状態遷移を省略してはならない。PCで作った完成requestをTablet production配線の代替証拠にしない。
開始前移動をfixtureから注入せず、production producerが未配線なら完成Trackにしない。
契約を変更するTrack内で、次の既存テストを同時に削除または反転する。
頂点分類、offset、clip、WorkArea、既存接続候補など継承部品のテストは、役割を新契約へ合わせて保持する。
Issue #111では次も同時に行う。
SeedHeadingUnavailable)」状態のテストを削除し、対象外・データ不良のdefaultCenterTillageHeadingDeg前提で組んでいたテストを、進入方向に最も近い辺候補前提へIssue #114 / Issue #115 / Issue #119の実装では次も同時に行う。
CENTER_TO_FINISHING_CONNECT_FAILED(耕したまま接続するTILLの専用失敗分類)とINTERNAL_TRANSFER stageはDEADHEAD空走」で表す。FinishingLapApproach(3)(耕したまま接続するTILL)を禁止する一方、lap 3→1、lap 1→2の既存TILL接続と、DEADHEAD空走(別role)は維持・生成する。finishingLap3StartAnchorのlateralOffsetへ固定する処理、anchorへの切り詰め処理、finishingLap3StartAnchor.pointの同一点検査、EndpointRef(個別pass端点の最寄り)によるbuildTerminalTraversalのwing分割、およびそれらを前提としたテストを削除する。FinishingLap(3)の1境界だけをdiscontinuity()の座標連続チェックからFinalTillagePlanResolverTest.assertCompleteの除外は撤回し、DEADHEADが両者を連続でつなぐ形へ戻す。すべてのモデル化対象action境界で座標連続をassertする。RouteActionRoleの新subclass、名前はFinishingLapApproachと混同しない)、CenterPassの直後は任意で1本の空走→FinishingLap(3)本体)、assignTemporalTillageでの各Trackはnavigation-field-geometry-contract-conformance.mdの開始gateを満たし、変更で落ちる既存テストを同Track内で
反転する。推奨順序は次のとおり。
各境界でmachine ratchet、対象module test、release build、A〜Gの到達済みassert、operational E2E、PC可視化をgreenにする。
2026-08-21の利用者承認により同一変更で行う。
navigation-field-geometry-contract-conformance.mdの現行契約参照を本書へ変更する。navigation-field-geometry-pipeline-contract-restart.mdを履歴baselineとしてarchiveまたは明示凍結する。navigation-field-geometry-review-gates.mdをStage 0〜11へ更新する。defaultCenterTillageHeadingDeg規則を廃止)、(b)壊れた筆は共有のclassifyFieldForPattern1FinishingLapApproach(3))と専用の接続失敗分類(CENTER_TO_FINISHING_CONNECT_FAILED)を撤回する。lateralOffsetへ固定せず、anchorへの切り詰めを行わない。finishingLap3StartAnchorまで仕上げDEADHEAD、headingDegと揃った到着、CenterPassとFinishingLap(3)本体の間にこの空走をFinishingLapApproach(3)=耕したまま接続するTILLとは別role)、その全区間が後続外周耕のTILLでCenterPass終点 → 空走 → FinishingLap(3)始点を含む全境界で座標連続とする。中央耕終了地点とlap 3開始centerWorkRemainingRegionを中央耕の被覆対象とする。中央laneはProfileの固定pitchで配置し、全TILL unionuncoveredの定義は変更しない。DEADHEAD、覆われない区間を接続時に耕すTILLへ分類する。分類によって接続DEADHEADとしてEntranceSnapshot.circulationAtCornerへ保持する。AmbiguousEntranceCornerで停止し、進入方位・走査順・DEADHEAD、finishingLap3StartAnchor.headingDegと揃った到着、逆走・U ターンなし)でつなぎ、正式なplan actionとして持つ。finishingLap3StartAnchorの座標一致は完成条件にしない。上記1〜10は2026-08-21に利用者承認済み。11はIssue #107のTablet実装計画レビューにより2026-08-26に
利用者承認済み。12はIssue #115事前検討コメント #5760〜#5762と2026-08-30の利用者確認により承認済み。
13はIssue #119の2026-08-30利用者承認による。
変更理由、検討した代替案、影響Stage、fixture変更、PC requestからの移行方法は
Issue #107 隣接耕基本経路パターン1 Tablet実装計画
第3章を参照する。各実装Trackは本契約と仕様適合規約の開始gateを満たしてからコード変更へ進む。