Issue #69 / Track #89。圃場幾何plannerの実装が、局所的にはgreenでも入口から退出までの契約から
逸脱することを防ぐ常設規約。本書はstandards/であり、Issue本文・runbook・実装上の便宜より優先する。
apps/android-tabletにおける圃場geometry、計画request、PC preview、simulator-ui、Tablet受け渡し、
関連fixtureの設計・実装・レビュー・記録へ適用する。
現行契約は、2026-08-21に利用者承認され、2026-08-30 Issue #114で中央終端→lap 3独立接続を撤回し、
同日Issue #115事前検討で外周3列と中央耕のProfile指定重ね幅を明確化し、Issue #115コメント #5769/#5770で
中央列間・WorkArea間接続のTILL/DEADHEAD分類を確定し、コメント #5772〜#5774で「最後の中央pass終点=仕上げlap 3開始
anchor 同一点」の強制を撤回し、Issue #119で中央耕を各WorkArea内の単一連続往復とし、終端隅から仕上げ
circulation方向のロータリー上げ空走(DEADHEAD)で仕上げlap 3開始位置へつなぐ契約(空走最短の候補を採用、
全境界で座標連続)へ変更した
docs/runbooks/navigation-field-geometry-pipeline-contract-pattern-1.mdとする。
docs/runbooks/navigation-field-geometry-pipeline-contract-restart.mdはTrack #89〜#95、
docs/runbooks/navigation-field-geometry-pipeline-contract.mdはTrack #72の履歴baselineであり、
現行実装判断には使用しない。
実装Trackは、コード変更前にIssue本文またはtrack_record(record_type=decision)へ次の対応表を保存する。
| 必須項目 | 記載内容 |
|---|---|
| 対象Stage | 契約のStage番号と見出し |
| 農作業上の起点 | 現地で利用者・車両・受信データの何を契機に処理が始まるか |
| 入力 | 型、直前Stage |
| producer provenance | production producer、利用者確認、fallback producer、fixture/test producerを分離して列挙 |
| 出力 | 型、consumer、直後Stage |
| 継承条項 | 旧契約から保持する章・技術 |
| 置換条項 | 無効化する旧仕様・既存実装 |
| 禁止事項 | 当該Trackで導入してはならない入力・fallback・候補化 |
| contract fixture | 正常長方形、入口反転、90度回転のうち当該Stageまでのassert |
| operational E2E fixture | 実際の筆選択・位置履歴・利用者操作から始め、fixture値の直接注入なしで当該Stageへ到達する手順 |
| regression fixture | 変更で落ちる既存テストと同Track内の反転方法 |
| 可視化gate | PCで利用者が確認するlayer・値・順序 |
| 停止条件 | 契約変更として利用者承認へ戻す条件 |
1項目でも空欄なら実装へ進まない。後から必要になった値を表へ追記するだけでは契約変更にならない。
現行契約にproducer/consumerが無ければ停止し、利用者承認を得て契約を先に変更する。
production producerを未実装のままfixture/test producerで代用する場合は、対応表へ「未配線」と記載し、
同Trackの完成条件にしてはならない。fallback producerだけを実装して通常運用の本番配線と称してはならない。
requiredParity、startSide、finishingSideをplan requestの自由入力にしない。開始側・終了側・必要な偶奇は、CenterTillagePassの直後を「任意で1本の中央耕終了→lap 3空走DEADHEAD固定。終端隅からlap 3走行中心線へ短く寄り、その中心線を仕上げcirculationと同じ回転方向にfinishingLap3StartAnchorにその走行方向と揃った向きで到着。逆走・U ターンなし。role はFinishingLapApproach以外)、その直後にfinishingLap3StartAnchorから始まるlap 3本体」とする。この空走はTILLへは変えない(中央列間・WorkArea間のCenterTillageLaneChange(#5769/#5770)とは異なる)。「中心線へ寄る」経路をfieldPolygon内に引けないCENTER_GEOMETRY_OPERATION_FAILED。FinishingLapApproach(3)(耕したまま接続するTILL)は生成しない。最後の中央pass終点は連続往復の終端隅でfinishingLap3StartAnchorとの座標一致は完成条件にしない。CenterPass終点 → 空走 → FinishingLap(3) 始点を含む全境界の座標連続は必須とする(#115で設けた「1境界だけ除外」は撤回)。finishingLap3StartAnchorのlateral offsetへ固定しない。終端WorkArea/DEADHEAD、TILLへ分類する。部分的に覆われる接続は同じgeometryを内部区間へDEADHEADとして残る全区間は後続TILLで覆われなければならない。centerWorkRemainingRegionは、fieldPolygon - perimeterTilledCoverageをProfileで指定されたoverlapWidthCm / 100.0メートルだけ外周側へbufferし、fieldPolygonでclipした中央耕の被覆対象とする。中央laneはuncovered = fieldPolygon - union(all planned TILL coverage)と、そこから求めるcentralUncoveredはapps/android-tablet/contract-gates/check-navigation-contract-ratchet.shは、監査で判明した既知乖離の
productionコード上の出現箇所と件数をbaseline化する。新規ファイルへの拡散、件数増加、baseline外の出現を失敗させる。
cd apps/android-tablet
./gradlew navigationContractConformance
全subprojectのcheckはこのtaskへ依存する。既知乖離を除去したTrackは、同じ変更内でbaseline上限を減らす。
上限増加、除去済みentryの復活、tokenの言い換えによる回避は禁止する。baseline増加が必要なら契約変更として
利用者承認を得て、理由をTrackへ記録する。ratchetは意味上の正しさを証明しないため、次のgateを省略できない。
各Trackは局所unit testに加え、次の2系統を別々に実行する。
「本番と同じHTTP endpointを通る」だけではoperational E2Eにならない。fixtureが作った入口、固定座標、
内部enum等をrequestへ直接注入した場合はcontract fixtureとして分類し、production producer配線の証拠としない。
次を段階的に伸ばし、前Trackのassertを削らない。
EntranceSnapshot → fixed anchors → boundary constraint → lane layout
→ local WorkArea plan → perimeter absorption → final traversal
→ final coverage → TillagePlan → exit anchor
最低限、値、方向、ID、座標連続性、production producer/consumerの本番配線をassertする。局所テストだけがgreen、
手作りfixtureだけがTillagePlanを構築、定義以外に本番呼び出しが無い、のいずれかなら失敗とする。
中央passが1本以上あるfixtureでは、中央耕が各WorkArea内で単一の連続往復であること(最終passが端の列で
終わる、wing分割が無い)、最後のCenterTillagePassの直後が「任意で1本の中央耕終了→lap 3空走(DEADHEAD、
role はFinishingLapApproach以外)、その直後にFINISHING_LAP_3 phaseのFinishingLap(laneNumber == 3)
本体」で、その間に他のactionが無いことを直接assertする。空走が全区間DEADHEADで、その全軌跡に後続外周耕
(3→1→2)TILLによる被覆参照があること、およびCenterPass終点 → 空走 → FinishingLap(3)始点を含む
全境界で座標連続であることをassertする。最後の中央pass終点とfinishingLap3StartAnchorの座標一致はassertしない
(偶然一致してもよいが、一致しないこと自体もfixture値として固定しない)。中央耕終了地点とlap 3開始位置の
座標差だけを理由にROUTE_DISCONTINUOUSへ停止しないこともassertする。action全体の座標連続性、coverage、
最終退出だけではこの構造の代替証拠にならない。
ProfileのoverlapWidthCmを0以外にしたfixtureでは、外周後の基礎未耕範囲を同値だけ外周側へbufferした
centerWorkRemainingRegionを、中央TILL coverageだけで覆うことを直接assertする。全TILL unionによる最終
coverageだけでは、外周3列が同じ帯を既に覆っているため、中央耕との重ね幅の代替証拠にならない。
overlapWidthCm=0では拡張しないこと、基礎未耕範囲が空なら中央0列を維持することも別々にassertする。
中央列間・WorkArea間接続(CenterTillageLaneChange)のfixtureでは、全区間が後続TILLで覆われる場合、全区間が
覆われない場合、一部だけ覆われる場合を分けて、順にDEADHEAD、TILL、同一geometry上のTILL/DEADHEAD分割となる
ことをassertする。分類前後で接続geometry、中央passの列順・始終端、anchorが変わらないこと、およびDEADHEADと
して残る全区間に後続被覆参照があることを直接assertする。中央耕終了→lap 3の空走はこの分類対象外で、常に
DEADHEAD固定であることを別途assertする。
Issue #114で廃止した「耕したまま接続するTILL」の専用処理・専用停止原因(FinishingLapApproach(3) /
CENTER_TO_FINISHING_CONNECT_FAILED / INTERNAL_TRANSFER)を別名で復活させない。中央耕終了→lap 3は
ロータリー上げのDEADHEAD空走で表す。中央耕を逆算できない・空走を通せない・空走が後続被覆できない場合は
中央geometry/traversal、中央未耕、DEADHEAD_TRACE_NOT_COVERED、またはaction境界の座標断絶という実際の
原因で分類する。根拠なく特定の凹形状を専用接続失敗fixtureとして固定しない。
PCでplannerへ完成済みsnapshotや内部値を直接渡して成立したfixtureは、planner以降の契約証拠に限る。
Tablet製品化Trackでは、その結果だけを「PC実装済みロジックをTabletで動かした証拠」として受領しない。
利用者の実操作、端末のproduction repository、実際の位置・履歴producerから開始し、当該Trackが追加した
adapter、状態機械、共通service、直後consumerまでを最初に細い1経路で貫通させる。後から局所機能を増やす場合も、
このproduction経路を各Trackの初期実装・初期レビュー・完了gateで継続して実行する。
実機化で入力の取得時点、取消、再評価、永続化、表示、fallbackの意味が未確定と判明した場合、それを
planner内部の問題として吸収しない。入力producerまたはworkflow契約の不足として実装を停止し、製品仕様と
パイプライン契約を先に更新して利用者承認を得る。
docs/runbooks/navigation-field-geometry-review-gates.mdに従い、当該Stageのanchor、方向、順序、除外理由、
coverage、transfer、detourをPCで可視化する。利用者確認前はTrackをbaseline/adoptedとして完了せず、
次Trackへ進まない。見つかった差異を後工程で吸収せず、producerを所有するTrack・契約へ戻す。
利用者へ渡す確認手順は、内部Stageのフォーム操作からではなく、実際の農作業の開始点(筆選択、圃場進入、
作業設定等)から時系列で記述する。利用者が現地では実行できない操作を要求する手順は受領不可とする。
Track完了前に、次をすべてTrackへ記録する。
rg等で確認したproduction/fallback/fixture producer定義、本番call site、consumer call site。この証跡が無いTrackは、コードと局所テストがgreenでも完了条件を満たさない。
契約と実装が両立しない場合は、実装を契約へ合わせるか、実装前に契約を変更する。先にコードを入れてから
文書を追認させない。契約変更には、理由、代替案、影響Stage、fixture変更、製品挙動、移行方法を提示し、
利用者の明示承認を必要とする。
緊急例外でも安全・退出・物理境界invariantは緩和しない。例外は期限と除去Trackを持つ一時的なdecisionとして
記録し、ratchet baselineを恒久的に増やす根拠にはしない。
この仕組みが機械的に保証するのは、既知乖離の拡大防止、必須checkへの接続、契約fixtureの回帰検知である。
農作業としての妥当性や未知の仕様解釈まで自動保証はできない。そのため、型によるproducer/consumer制約、
end-to-end fixture、PC可視化、利用者承認を合わせて完了条件とする。