状態: 2026-08-21に現行契約から置換された履歴baseline。現行実装判断には使用しない。
現行契約は
隣接耕基本経路パターン1 圃場幾何パイプライン実装契約
とする。Issue #69 / Track #89。Track #72の旧契約を置き換え、入口から退出までの値の流れを再構築した当時の契約。
当時の状態: 2026-08-19利用者承認済み。 本書は当時の現行契約として、旧
navigation-field-geometry-pipeline-contract.mdをTrack #72の履歴baselineとして凍結した。
Track #87/#88の意味論はneeds-reviewのまま継承せず、後続restart Trackは本書と
navigation-field-geometry-contract-conformance.mdに従う。2026-08-20追補:
docs/decisions/navigation-field-ready-tillage-route-policy.mdで、耕し残しを作らない、
空走り跡を後続耕耘で消す、同じ入口から退出する、の三原則と、通常実筆の完成を不規則形状の一般探索より
優先する方針を利用者承認済み。本追補は本書の既耕外周移動・partial plan実行可否・後続Track順を上書きする。
基本耕耘計画を、次の既決規則どおりに一続きのdecision chainとして生成する。
DEADHEADにして、Track #72の旧契約は、B-2d重ね幅solverとB-2e中央lane生成を、
finishingLap3StartAnchorを確定する全体評価より前へ置いた。その結果、
requiredParityとfinishingSideのproducerが存在せず、simulator-ui/HTTPの自由入力で代用された。
Track #87/#88は、その未接続状態のlane群を一般path-cover問題として再順序化した。
本restartでは次を禁止する。
requiredParityとfinishingSideを利用者、UI、HTTP requestへ公開すること。本書は次の既決仕様を変更しない。
docs/standards/ui-design-guidelines.mddocs/specifications/p6-ui-spec.mddocs/runbooks/navigation-pc-closed-loop-implementation.mddocs/runbooks/navigation-tablet-preview-claude-implementation.md仕様乖離の確認事実はdocs/decisions/issue69-tillage-spec-drift-audit.mdを参照する。
本書はTrack #72旧契約の全内容を破棄するものではない。実装Trackは、次の境界に従って旧契約を参照する。
明示的に置き換えるもの:
requiredParity、finishingSideを外部入力とする境界。本書が明示的に上書きしない限り継承するもの:
candidateLaneId、workAreaId、passId、segmentIndexの責務分離。PerimeterConnectionCandidate生成機構(entryConnection/lapTravel/exitConnectionの3部構成、LengthIndexedLineによる経路抽出と安全性検証)を、Stage 10のWorkArea間transfer生成技術としてPerimeterDeadheadTransferは追い詰め・周回・仕上げ周回とdeadheadClearanceWidthCm未設定時はDEADHEAD中心線だけを保証する限定。JOIN_MITREのmitreLimit=5.0は、旧契約どおり旧17章C1〜C6は、旧契約に記録された「実装前に要承認」という状態をそのまま継承する。本書への記載によって
未承認項目を承認済みとは扱わない。各変更を必要とする実装Trackは、着手前に承認状態を確認し、未承認なら停止する。
本書と旧契約が矛盾する場合は上の置換対象に限って本書を優先し、それ以外を黙って変更しない。
旧契約の軸定義を保持する。
| 名称 | 意味 |
|---|---|
travelAxis |
選択されたheadingDeg方向。中央passの走行方向 |
lateralAxis |
headingDeg + 90°方向。中央laneが並ぶ方向 |
longitudinalProjection |
点のtravelAxis上のスカラー値 |
lateralOffset |
点のlateralAxis上のスカラー値 |
headingDegはTrack #86のcenterTillageDirectionCandidates(field)による辺identity付き候補、
またはその候補を起点とした自由回転から得る。plannerは最適headingを自動選択しない。
位置だけでは接続条件を表せないため、全anchorは進行方向を持つ。
enum class TillageAnchorRole {
ENTRANCE,
CENTER_TILLAGE_START,
FINISHING_LAP_3_START,
EXIT,
}
data class DirectedRouteAnchor(
val point: LatLon,
val headingDeg: Double,
val role: TillageAnchorRole,
)
位置一致は既存geometry tolerance以内、方向一致は正規化した角度差で判定する。
方向toleranceの数値はfixture実測で決める技術事項とし、本書では固定しない。
data class FixedTillageAnchors(
val entrance: DirectedRouteAnchor,
val centerTillageStartAnchor: DirectedRouteAnchor,
val finishingLap3StartAnchor: DirectedRouteAnchor,
val exitAnchor: DirectedRouteAnchor,
)
entrance: 選択した入口境界点と進入方位。centerTillageStartAnchor: 導入工程から最初の中央passへ入る位置・方向。finishingLap3StartAnchor: 仕上げ3列目を開始する位置・方向。最後の中央passから直接、またはまだ仕上げていないexitAnchor: 仕上げ2列目の最後から入口へ向いて直進退出する位置・方向。finishingLap3StartAnchorは中央laneから推測しない。入口、導入circulationと逆向きの仕上げcirculation、
固定されたlap 3→1→2、最後の退出条件を先に解いて生成する。
enum class LateralSpanSide { MIN, MAX }
data class CenterTillageBoundaryConstraint(
val startAnchor: DirectedRouteAnchor,
val finishAnchor: DirectedRouteAnchor,
val startSide: LateralSpanSide,
val finishingSide: LateralSpanSide,
val firstPassDirection: TravelDirection,
val lastPassDirection: TravelDirection,
val requiredParity: OverlapParity,
)
この型はUI/HTTPの入力ではなく、planner内部で固定工程と安全な接続可能性から生成する。
直接接続できない場合は開始側・終了側の接続方法によって複数候補になり得る。
偶奇は次の不変式で導出する。
firstPassDirection == lastPassDirection → requiredParity = ODD
firstPassDirection != lastPassDirection → requiredParity = EVEN
理由: boustrophedonではpassごとに進行方向が反転するため、奇数列なら最初と最後が同方向、
偶数列なら逆方向になる。requiredParityを独立した農作業上の選択肢として扱わない。
startSideとfinishingSideは、各anchorへ安全に接続する中央lane側を利用可能spanのMIN/MAXから決める。
anchor座標とspan端の完全一致は要求しない。直接一致しない場合は、導入側またはまだ仕上げていない外周帯上の
DEADHEAD接続を生成し、接続全体が物理境界・安全条件を満たし、移動跡が後続TILLで覆われることを検証する。
Field + ProfileSnapshot + TillagePlanningSettings
+ EntranceSnapshot + selected heading
│
▼
入口解決・固定経路生成
│
├─ EntranceResolution
├─ introduction circulation / finishing circulation
├─ perimeter laps 1/2/3
├─ perimeterTilledCoverage
├─ centerWorkRemainingRegion
├─ FixedTillageAnchors
└─ duringInitialLoopTargets / deferredTargets
│
▼
CenterTillageBoundaryConstraint
│
├─ startSide / finishingSide
├─ firstPassDirection / lastPassDirection
└─ requiredParity
│
▼
terminal-constrained overlap/pitch/lane layout探索
│
├─ laneCount / actualPitch / actualOverlap
├─ first lane / last lane
└─ endpoint residual
│
▼
polygon clip・segment・通常boustrophedon順序案
│
▼
不規則形状の局所接続・WorkArea局所plan案
│
▼
暫定coverage ledger・外周吸収・不要WorkArea除外
│
▼
残存WorkAreaの全体transfer・中央traversal確定
│
▼
最終coverage ledger
│
▼
遅延追い詰め挿入
│
▼
TillagePlan composer・invariant
│
▼
PC preview → 利用者レビュー → Tablet preview
| 値 | producer | consumer | UI/HTTP入力可否 |
|---|---|---|---|
EntranceSnapshot |
登録入口、確認済み境界横断、手動境界指定 | 入口resolver、plan snapshot | 入口選択として可 |
headingDeg |
辺候補選択または自由回転 | 軸、中央pass、orientation | 方向操作として可 |
EntranceResolution |
resolveEntrance |
固定経路、追い詰めschedule | 不可 |
| 導入circulation | 入口resolver | 導入action、仕上げcirculation | 曖昧入口時の確認だけ可 |
| 仕上げcirculation | 導入circulationの反転 | 3→1→2と退出 | 不可 |
finishingLap3StartAnchor |
fixed finishing traversal resolver | 中央終端側、未仕上げ外周transfer、composer | 不可 |
centerTillageStartAnchor |
導入工程・orientation resolver | 中央開始制約、composer | 不可 |
startSide/finishingSide |
anchorとlateral spanの照合 | lane layout | 不可 |
firstPassDirection/lastPassDirection |
anchorへの安全な接続候補 | parity resolver、lane traversal | 不可 |
requiredParity |
方向関係の不変式 | B-2d solver | 不可 |
perimeterTilledCoverage |
perimeter lap 1/2/3のTILL中心線を作業機幅で面化し物理圃場内へclip |
centerWorkRemainingRegion、coverage ledger、preview |
不可 |
centerWorkRemainingRegion |
圃場の耕耘対象からperimeterTilledCoverageを差し引くcoverage resolver |
lane layout、0/1/複数lane判定、不規則形状判定 | 不可 |
laneCount/pitch/overlap |
centerWorkRemainingRegionを覆うlayout resolver(複数lane内部でB-2d solverを再利用) |
lane生成、preview | 不可 |
| first/last lane | terminal-constrained layout resolver | traversal、invariant | 不可 |
duringInitialLoopTargets/deferredTargets |
corner target + entrance visit order + orientation | composer、遅延追い詰め配置 | 不可 |
| WorkArea/internal plan案 | ordered lane traversal + 局所安全接続 | 暫定coverage、全体transfer、候補比較 | 安全検証済み候補の選択だけ可 |
| 外周吸収対象 | 暫定coverage ledger | WorkArea除外、全体transfer | 不可 |
| final traversal | 残存WorkAreaの全体評価 | 最終coverage、遅延追い詰め、composer | 不可 |
| action別耕耘責任 | 全走行順と後続作業幅coverageの時系列評価 | TILL/DEADHEAD分割、最終coverage、composer |
不可 |
PC CLI、simulator-ui、Tablet plannerへ公開するplan requestは、少なくとも次だけを持つ。
data class TillagePlanRequest(
val field: FieldSnapshot,
val entrance: EntranceSnapshot,
val profile: ProfileSnapshot,
val settings: TillagePlanningSettings,
val centerDirection: CenterDirectionSelection,
)
requiredParity、finishingSide、WorkArea開始側/終端側を自由入力としてrequestへ追加してはならない。
安全検証済みの完成候補をpreviewした後、その候補を選ぶためのopaqueなplan candidate IDは選択操作として許可する。
candidate IDだけを示し、geometryや差異を表示せず利用者へ内部探索の判断責務を移してはならない。
各Stageは、入力値の全producerが同じStage以前に存在することを必須とする。
後段で決める値を仮入力として受け取ってはならない。
入力: TillagePlanRequest
出力:
UNSUPPORTED検証:
implementWidthCm > 00 <= overlapWidthCm < implementWidthCm0..implementWidthCmcornerTillMaxInteriorAngleDegが有限かつ0 < value <= 180。レイヤー0の既定値は160度Track #73/#74の頂点分類と既存normalizeを保持する。
出力:
physicalFieldGeometryFieldVertexClassificationResultcornerTillTargetsUNSUPPORTED入力polygonを破壊的に簡略化しない。cornerTillTargetsは凸頂点のうち、内角が
cornerTillMaxInteriorAngleDeg未満の頂点だけとする。内角が閾値と等しい頂点を含め、閾値以上の
緩い隅は追い詰めない。凹頂点とCOLLINEAR頂点へCornerTillを生成しない。この閾値は追い詰め対象の
選別だけに使い、中央耕の方向、開始側、外周geometryを変えない。
Track #75の純粋幾何を保持し、入口非依存の領域を生成する。
出力:
allowedTillageTargetsafeCenterlineRegioncenterTillageRegion(中央pass中心線の候補生成・安全配置に使う。中央耕の担当面積ではない)perimeterTilledCoverage(lap 1/2/3のTILL中心線を作業機幅の半分で面化し、物理圃場内へclipしたunion)centerWorkRemainingRegion(allowedTillageTarget - perimeterTilledCoverage。中央耕が実際に担当する未耕範囲)外周3列のpitchは基準重ね幅を使い、中央の自動重ね幅調整の対象にしない。
このStageのperimeterTilledCoverageは外周3列が最終的に担う予定被覆である。後段で重複区間の先行通過を
DEADHEADへ変えても、最後の通過へ割り当てた実TILLのunionが同じ被覆を満たすことを再検証する。
DEADHEADは実耕耘被覆へ含めない。centerWorkRemainingRegionが空なら、中央pass 0本で
正常に外周工程へ進める。centerTillageRegionの幅だけから中央lane数を決めてはならない。
中央lane数を先に期待値として固定してはならず、0/1/複数laneはcenterWorkRemainingRegionを覆うために
必要な本数として導出する。特定の実筆をsingle-laneにすることはcontract fixtureや完了条件ではない。
入力:
EntranceSnapshotheadingDeg実行:
resolveEntrance()で近傍角、対角側、introductionVisitOrderを求める。introductionVisitOrder.last()に対応する各inset ring上の点を、仕上げ周回の基準始点とする。introductionVisitOrderと逆順にたどる。FinishingLapApproach(DEADHEAD)で次のringの基準始点へ接続する。approachHeadingDeg + 180°方向へ直進するExitを生成する。finishingLap3StartAnchorとする。FinishingLapApproach(DEADHEAD)を構築できるよう、centerTillageOrientation()と入口visit orderから、centerTillageStartAnchor、duringInitialLoopTargets、deferredTargetsを求める。出力:
data class FixedTillageConstraintResult(
val entranceResolution: EntranceResolution,
val introductionCirculation: PerimeterCirculation,
val finishingCirculation: PerimeterCirculation,
val introductionActions: List<RouteActionDraft>,
val finishingActions: List<RouteActionDraft>,
val anchors: FixedTillageAnchors,
val duringInitialLoopTargets: List<Int>,
val deferredTargets: List<Int>,
)
固定仕上げtraversalの全接続は連続し、最後のlap 2は入口へ向いたexitAnchorで終わらなければならない。
入口が頂点の許容誤差内にあり導入circulationが一意でない場合は、既存resolveEntrance契約どおり
explicitCirculationAtCornerの利用者確認を要求する。plannerが走査順で暗黙決定してはならない。
成立する固定traversalが無ければ、中央lane生成へ進まずUNSUPPORTEDとする。
入力:
centerTillageRegioncenterWorkRemainingRegionFixedTillageAnchorsheadingDeg実行:
centerTillageLateralSpanで中心線を安全に配置できるspanを算出する。headingDegのtravel/lateral軸でcenterWorkRemainingRegionの被覆対象spanと連結成分を算出する。travelAxisのFORWARD/REVERSEで定める。requiredParityを導出する。出力:
CenterTillageLateralSpanCenterWorkRemainingRegionと選択方向に対する被覆span/連結成分CenterTillageBoundaryConstraint候補始終端anchor座標とspan端の完全一致は要求しない。各anchorへ接続可能なMIN/MAX側とpass方向を求める。
実際のlane endpointが未確定のため、このStageではtransferを完成させず、接続側・方向・経由する未仕上げ外周帯を
候補条件として出力する。後段でlane endpointが得られた時点で安全なtransfer geometryを生成・検証する。
Stage 5は、Track #78〜#80のpitch探索を純粋な内部solverとして再利用する。
入力:
CenterTillageBoundaryConstraint候補centerWorkRemainingRegion被覆対象実行:
centerWorkRemainingRegionが空なら0 laneの正常結果を返す。centerWorkRemainingRegionをrequiredParityは適用しない。Dを求め、requiredParityを満たすlaneCount >= 2を列挙する。centerWorkRemainingRegionを覆う候補だけを残す。actualPitchCm間隔で逆算する。候補優先順位:
centerWorkRemainingRegion被覆を満たす。|endpointResidualCm|最小。|adjustmentCm|最小。出力は0 lane正常完了と、1 lane以上のlayoutを型で区別する。0 laneを空のCenterLaneLayoutや
InvalidInputとして表現しない。
sealed class CenterLaneLayoutResult {
data class NoCenterWork(
val perimeterTilledCoverage: List<FieldPolygon>,
) : CenterLaneLayoutResult()
data class Planned(
val layouts: List<CenterLaneLayout>,
) : CenterLaneLayoutResult()
}
data class CenterLaneLayout(
val boundaryConstraint: CenterTillageBoundaryConstraint,
val adjustment: OverlapAdjustment,
val orderedLaneOffsetsFromFinish: List<Double>,
val firstLaneOffset: Double,
val lastLaneOffset: Double,
)
orderedLaneOffsetsFromFinish.first()は必ずfinish側、last()はstart側とする。
公開presentationでは実走順に反転して表示してよいが、solver出力の逆算順序を曖昧にしない。
外周3列後の未耕範囲を1passで覆える場合は通常の1列計画として扱い、列数偶奇を成立条件にしない。
この場合は入口側で耕耘を終えることを優先し、入口側から反対端へ安全なDEADHEADで先行移動した後、
反対端から入口方向へ1列を耕す。要求偶奇を満たしたと偽って返さず、single-lane例外と実際の方向を結果へ残す。
先行移動跡は直後のsingle-lane TILL作業幅で覆われなければならない。安全な先行移動を生成できない場合は停止する。調整範囲内で解が無い場合だけ、
既決設定に従うDEADHEAD/DOUBLE_TILL fallback候補を生成する。始終端座標の直接一致は緩和できるが、
安全な接続、退出条件、物理境界は破ってはならない。
Track #81〜#84のpolygon交差・数値堅牢化を保持する。
入力:
CenterLaneLayoutcenterTillageRegionsafeCenterlineRegioncenterWorkRemainingRegionheadingDeg出力:
CenterTillageCandidateLaneRouteSegmentcenterWorkRemainingRegion被覆検証結果finishingSideを別引数として受け取らず、CenterLaneLayout.boundaryConstraint.finishingSideだけを使う。
最後のlane中心線がfinish anchorを通り、方向がlastPassDirectionと一致することを再検証する。
最初に、中央laneが各1本の連続segmentとなる通常ケースを解く。
規則:
firstPassDirectionから交互に反転する。lastPassDirectionでfinish anchorへ到達する。safeCenterlineRegion内のDEADHEADであり、その移動跡を後続の外周TILLが覆う。single-lane例外では上記の複数lane用の始終端偶奇を要求しない。入口側から反対端への安全なDEADHEADを
先頭actionとし、唯一のpassを反対端から入口方向へ走って入口側で終える。これは値の黙示補正ではなく、
物理的に列数を選べない場合の明示的な正常経路である。
通常ケースでは一般Hamiltonian/path-cover探索を使わない。全ハード制約を満たせなければ、
勝手に並び替えずStage 8の不規則形状処理へ渡す。
Stage 8は、polygon clipでlaneが複数segmentへ分裂した場合だけを対象にする。
通常実筆で全laneが各1本の連続segmentなら、入力の通常traversalを変更しないidentity結果を返して後段へ進む。
分裂segmentに対する一般的な局所plan探索の実装は、通常実筆を入口から退出まで完成・現地試用した後へ延期する。
実際の登録筆で分裂が発生した場合は、そのgeometry、Stage、入力、警告を記録し、実例に基づく後続Trackで扱う。
保持するTrack #87の技術部品:
契約:
candidateLaneIdは同じ候補中心線、workAreaIdは連続作業領域、passIdは実際に連続走行するpass、segmentIndexは遅延追い詰めによる同一passの中断区間を表す。passIdのsegmentIndexとして表してはならない。このStageでは全WorkAreaの訪問順とWorkArea間transferをまだ確定しない。外周耕で吸収されるWorkAreaを
Stage 9で判定できる局所plan案とgeometryを出力する。
出力:
局所同点候補は、全ハード制約→局所耕し残し→局所DEADHEAD距離→多重耕耘→決定的ID順で並べる。
旧契約の3領域分離を保持する。
physicalFieldGeometryallowedTillageTargetallowedCornerTillTargetStage 2の固定外周geometryとStage 8のWorkArea/局所plan案から、次を算出する。
remainingUntilledAreaM2outsidePhysicalFieldTilledAreaM2safetyMarginViolationAreaM2外周吸収判定はWorkArea間transferのproducerである。吸収済みWorkAreaを除外した残存WorkArea群をStage 10へ渡す。
外周と中央の重複があるだけで吸収扱いせず、旧契約のcoverage/tolerance規則で当該WorkAreaの作業が不要と証明する。
始終端側のWorkAreaが吸収される場合は、残存WorkAreaまたは未仕上げ外周帯への安全な接続を再計算する。
Stage 9で吸収済みWorkAreaを除外した後、残存WorkAreaだけを対象に、全WorkAreaの訪問順、局所internal plan、
WorkArea間transferをcenterTillageStartAnchorとfinishingLap3StartAnchorを固定して同時評価する。
出力:
CenterTillageTraversalPlanCandidateCenterTillageTraversalPlan候補は、安全条件→未計画WorkArea数/面積→総DEADHEAD距離→多重耕耘→transfer数→決定的ID順で並べる。
空間的に異なる安全な候補が複数あれば自動的に1件へ潰さず、PC previewで比較可能にする。
通常形状の最初の実装では、Stage 7の単調boustrophedon順を固定し、最後の中央passから未仕上げ外周帯を通って
finishingLap3StartAnchorへ接続する。探索を打ち切る場合は安全なgreedy解を診断候補として保持してよいが、
三原則と完成条件を満たさないpartial planを実行可能候補として返さない。
Stage 10の確定traversalに対し、Stage 9と同じ3領域・数値規則でcoverageを再計算する。
coverageはここでは確定計画の検証結果であり、耕し残しを減らすために始終端拘束を外してはならない。
全走行順を時系列で後方から評価し、同じ場所を複数回通る場合は原則として最後の通過へ耕耘責任を割り当てる。
先行通過をDEADHEADへ変えられるのは、その移動軌跡が後続TILL作業幅unionで完全に覆われる場合だけとする。
一つの走行内で条件が変わる場合はgeometryをTILL/DEADHEAD区間へ分割する。既耕部分の移動は、その後に
再耕耘できる場合だけ許可し、未耕部分を通る候補より優先しない。
狭い首部分でlap 3/1/2が重なる場合は3と1を上げて2で耕し、lap 2の行き/帰りが重なる場合は行きで上げ、
帰りで耕す。これは固定の列番号だけで決めず、後続作業幅が先行区間の担当範囲を完全に覆うことをgeometryで検証する。
coverage不足が残る場合は、不足geometryと必要な補正走行を明示する。数cmでも黙って許容せず、完成条件を
満たさない計画は診断用partial planとして保持してよいがTabletへ送らない。
入力:
deferredTargets各deferred targetについて、中央耕と外周耕が重なる既耕部へ接続できるpass上の中断候補を生成する。
中断点から既耕重複部を通って対象隅へ移動し、同じ経路で中断点へ帰還できることを検証する。
生成action列:
CenterTillagePass(passId=P, segmentIndex=i)
→ CenterTillageDetour(TO_CORNER, cornerIndex=C)
→ CornerTill(DEFERRED, cornerIndex=C)
→ CenterTillageDetour(RETURN_TO_INTERRUPTION, cornerIndex=C)
→ CenterTillagePass(passId=P, segmentIndex=i+1)
必須条件:
passId。segmentIndexは0から連続する。安全な配置が無ければ対象を黙って省略せず、未計画の追い詰めとして位置・理由を明示する。
他の安全に計画済みactionは保持する。
初めてここでTillagePlanを構築する。
正方向のaction順:
入口進入
→ 導入外周移動 + duringInitialLoopTargetsのCornerTill
→ 中央耕(必要なら遅延追い詰めを挿入)
→ 仕上げlap 3
→ 仕上げlap 1
→ 仕上げlap 2
→ 入口へ直進退出
composerは順序を新たに最適化しない。前Stageで確定したgeometryと順序を型へ写し、
構造invariantを適用するだけとする。
必須invariant:
centerTillageStartAnchorから中央traversalが連続する。finishingLap3StartAnchorへ連続する。安全・圃場境界・仕上げ順・退出・耕し残しゼロ・後続耕耘による空走り跡消去に違反する計画は完成計画として返さない。
未計画区画や未配置の追い詰めがある場合は、診断用partial planとしてPC previewできるがTabletへ送らない。
PC previewは最終結果だけでなく、次を順に可視化する。
TillagePlanの全action順。各層は色だけでなく、番号、矢印、線種、文言を併用する。
PCで利用者レビューを通過した同じTillagePlanをTabletへ渡す。
Tablet/Compose/TypeScriptでplannerを再実装しない。Tabletは計画入力、状態遷移、表示だけを担当する。
EntranceSnapshotを確定する。finishingLap3StartAnchorを確定する。centerTillageStartAnchorを確定する。入口を反対側へ変えたfixtureでは、入口resolution、導入/仕上げcirculation、anchor、side、
first/last方向、required parity、lane配置が再計算される。requiredParityまたはfinishingSideを
利用者が手で合わせる操作は存在しない。
centerTillageOrientationを新headingで再計算する。cornerTillTargetsとintroductionVisitOrderから、duringInitialLoopTargetsとdeferredTargetsを分ける。polygon clipによる同一laneの分裂と、CornerTillのための意図的なpass中断は別概念とする。
前者はcandidateLaneId/WorkArea、後者は同一passIdのsegmentIndexで表す。
DEADHEAD/DOUBLE_TILL fallback、探索打ち切り、greedy解のいずれも、次を破ってはならない。
警告を付けても不安全な計画は返さない。最適性を証明できないgreedy解でも、全完成条件を検証済みなら
「安全だが非最適な既知解」として返してよい。全体解が無ければ、安全に計画できた区画と未計画区画を
分けたdiagnostic partial planをPCへ返せるが、Tabletへ送らない。未検証の妥協解は返さない。
一部だけが該当する場合はdiagnostic partial planとして、安全に計画済みの範囲、未計画geometry、理由、該当Stageを返す。
圃場全体について安全なactionを1件も構築できない場合だけ計画不能とする。安全検証済みの複数候補は、
差異を可視化したうえで利用者が選択できる。ただし未計画・未被覆・後続耕耘で消えない空走り跡を含む候補は
実行可能な完成計画として選択できない。
局所solver testより先に、次の3fixtureをgeometry contract fixtureとして作る。
これらは内部値の幾何回帰を検証するもので、production producer配線の証拠とは別に扱う。
assert:
同じfield/Profile/headingで入口だけを反対側へ変更する。
assert:
assert:
duringInitialLoopTargetsとdeferredTargetsが期待どおり。passId維持、segmentIndex連番、座標連続。Stage 3以降へ進む前に、fixtureの境界座標をrequestへ直接注入せず、次をPC上で再現する。
REGISTEREDとして確定する。RECENT_CROSSING候補として生成する。MANUAL_BOUNDARYをfallbackとして使う。EntranceSnapshotが同じproduction serviceからStage 3、JSON/GeoJSON、PC表示へ届くことをassertする。登録入口のdomain・保存形式が未実装なら、fixture値やPC専用形式で代用せず未配線として記録する。
geometry fixture A〜Cがgreenでも、Dが未達ならfixed constraint Trackを完了しない。
次は回帰fixtureとして保持する。
各restart Trackは、局所テストだけでなく、当該Stageまでのend-to-end fixtureを通す。
その時点でまだ最終TillagePlanを作れないTrackは、次の安定した中間成果をassertする。
| Track境界 | 最低限greenにするもの | PC可視化gate |
|---|---|---|
| fixed constraints | 筆選択→登録入口または外→内横断→利用者確認→4 anchor→3/1/2→exit。手動指定はfallbackとして別試験 | 入口source、候補/確定状態、anchor/circulation表示 |
| terminal lane layout | anchor→side/direction/parity→lane | 逆算laneと数値表示 |
| normal traversal | start→交互lane→finish | 順序・矢印・接続表示 |
| irregular local plan | split/WorkArea→局所plan案 | WorkArea/局所接続表示 |
| perimeter absorption | 局所plan案→外周吸収→残存WorkArea | 吸収理由・除外geometry表示 |
| final traversal | 残存WorkArea→確定plan | candidateではなく確定順表示 |
| final coverage | 確定traversal→coverage | 残り・重複geometry表示 |
| delayed CornerTill | deferred→中断復帰 | detour全action表示 |
| composer | 全action→invariant | 完成順序の再生表示 |
赤い既存テストの修正を後続Trackへ送らない。入力契約を変えるTrackでは、同じTrack内で
pc-tool request、simulator-ui、該当テストを新契約へ反転する。
Track #91〜#94でStage 7までを完了した。2026-08-20追補後は、特殊形状の先回り実装より実圃場での
入口から退出までの完成を優先し、次の順で別Trackとして実装する。
通常形状ではStage 8/9をidentity結果として通過する。分裂segmentの一般探索は削除せず診断部品として保留するが、
入口から退出までの通常実筆完成をブロックしない。穴のあるドーナツ状polygonは当面非対応とする。
各Trackは単独で意味のある出力と可視化を持ち、全テスト・release buildをgreenに保つ。
次の8項目は2026-08-19に利用者が一括承認した。
2026-08-20追補として、次も利用者承認済みとする。
承認により行うこと:
navigation-field-geometry-pipeline-contract.mdを本契約で置き換える。navigation-field-geometry-review-gates.mdを新Stageへ更新する。p6-ui-spec.mdへ確定した型ではなく、製品挙動としての契約を反映する。superseded、Track #89をbaselineまたはadoptedとして完了する。契約対応表の利用者確認前に行わないこと:
docs/decisions/issue69-tillage-spec-drift-audit.mddocs/specifications/p6-ui-spec.mddocs/runbooks/navigation-pc-closed-loop-implementation.mddocs/runbooks/navigation-tablet-preview-claude-implementation.mddocs/runbooks/navigation-field-geometry-pipeline-contract.md(Track #72旧baseline、凍結)docs/runbooks/navigation-field-geometry-review-gates.md