コンテンツにスキップ

IBKR Phase 6 MVP deploy postmortem

作成日: 2026-04-13 対象ソース: AEGIS/WORK_LOG/2026-04-12_ibkr_implementation_handover.md, AEGIS/WORK_LOG/2026-04-12_ibkr_scaffold_phases_1a_3_4_5.md, AEGIS/WORK_LOG/2026-04-12_ibkr_synology_pivot.md, AEGIS/WORK_LOG/2026-04-12_ibkr_phase3b_phase6_mvp.md

Source fidelity note

この postmortem は、2026-04-12 の ibkr_*.md ログだけを根拠に書いている。 R4 queue で指定された issue 名のうち、元ログに failing command / error string まで残っていないものは、そのことを明記したうえで、ログに残っている 「採用した対処」と「再発防止の学び」だけを書く。

Executive summary

2026-04-12 の IBKR Phase 6 MVP は、当初の Mac local dry-run → Fargate 前提から、 既存 Saxo 運用と同じ Synology + GitHub Actions の deploy lane に切り替わった。 その後、Phase 3 Part B の smoke binary と、Phase 6 MVP の lt-ibkr-quote-collector まで進み、MVP は underlying snapshot 収集に スコープを絞って production 回収点を先に作った。

Phase 6.1 addendum

2026-04-13 の Phase 6.1 では、MVP の underlying collector を土台にして lt-ibkr-spread-collector を追加し、ibkr_spread_quote_v2 JSONL を Synology 上へ継続書き込みできる状態まで進めた。構成は 1 container 追加ではなく、 IBeam gateway / underlying quote collector / spread collector の 3-container 分離とし、認証寿命・scan cadence・障害切り分けを独立に扱う方針を採っている。

特に option chain 解決は、当初想定していた「month token を渡して secdef/info 一発で全 chain を取る」単純経路では live IBeam で安定しなかった。 実運用で採用した sequence は以下:

  1. POST /v1/api/iserver/secdef/search で underlying conidmonths を取得
  2. GET /v1/api/iserver/secdef/strikes で対象 month の strike ladder を取得
  3. Rust select_atm_put_spread 相当で short/long strike を決定
  4. GET /v1/api/iserver/secdef/info?strike=...&right=P を short / long それぞれに発行
  5. 各 leg conid で snapshot / whatIf を取得し、net bid/ask/mid と margin preview を組み立てる

このため、Phase 6.1 の collector hardening では search -> strikes -> info の live 実績 path を守りつつ、month-wide secdef/info は telemetry 用の best-effort retry に留めている。今後 secdef/info 一括解決が安定するまでは、 option chain API sequence の実態は「search → strikes → info」が正である。

Production issues encountered

Issue Logs preserve Resolution preserved in the logs Lesson learned
IP allowlist 元ログには allowlist 自体の失敗出力は残っていない。一方で、2026-04-12_ibkr_synology_pivot.md には、実運用標準が Mac/Fargate ではなく Tailscale + SSH key で Synology に入り、GitHub Actions から /volume1/aegis/repo を同期して deploy する方式だと明記されている。 deploy 経路を既存運用に寄せ、pt-docker/.env の必須変数検証、manual dispatch、verify job での auth_status / /iserver/accounts 確認までを workflow に固定した。 新規 broker lane を載せるときは、新しい実行面を増やす前に既存の deploy lane に合わせる方が切り分けが速い。
btrfs ACL chmod 2026-04-12 の ibkr_*.md には btrfs / ACL / chmod の失敗出力は残っていない。残っている事実は、secret は git 管理外の pt-docker/.env に置き、Synology 上で user が one-time bootstrap し、workflow 側は --env-file と fail-fast の env 検証で読む、という運用面の確定だけ。 permission 修復のような in-place 操作ではなく、pt-docker/.env の one-time bootstrap と workflow の fail-fast 検証に寄せた。共有 compose には手を入れず、IBKR gateway を別 compose / 別 workflow として切り出した。 ファイルシステム差異や権限の不確実性があるときは、mutable な現地修復より、secret bootstrap を最小化した immutable deploy に寄せる方が安全。
reqwest HTTP/2 403 元ログに 403 の文言は残っていないが、2026-04-12_ibkr_phase3b_phase6_mvp.md には Mac の SSH tunnel 経由で TLS handshake が Connection reset by peer で失敗したこと、2026-04-12_ibkr_implementation_handover.md と scaffold log には IBeam が self-signed 証明書を出すので Rust reqwest client で .danger_accept_invalid_certs(true) が必要だと残っている。 adapter 側のバグと決めつけず、ssh nas "curl" で 3 endpoint の実レスポンス shape を直接観測し、Rust 側は self-signed 前提で TLS verify off を explicit に扱うようにした。live 実行は fragile な Mac tunnel ではなく production container 側へ寄せた。 self-signed gateway を跨ぐときは、先に transport/TLS を疑い、remote curl で shape を固定してから client 実装に戻る方が早い。

Debugging vs implementing

正確な工数比率は、2026-04-12 の ibkr_*.md には記録されていないため算出しない。

実装として明示的に残っている単位:

  • Phase 1a / 3 / 4 / 5 scaffold
  • Synology pivot に伴う compose / workflow / config / README 更新
  • lt-ibkr-smoke binary 追加
  • lt-ibkr-quote-collector MVP 追加

デバッグ / 切り分けとして明示的に残っている単位:

  • Paper Trading Password reset の backend error と再試行待ち
  • UI session と API session の排他性の誤解整理
  • Mac / Fargate 前提から Synology + GHA への deploy lane 見直し
  • SSH tunnel 経由の TLS handshake failure と ssh nas "curl" による shape 確認

したがって、このセッションは「実装を進めながら、deploy lane と transport の 前提を何度も切り分け直した」性格が強く、体感の debug 量は小さくなかったと 言えるが、何時間対何時間かまではログから断定しない。

What worked

  • Phase 6 full scope を一気に載せず、underlying snapshot の JSONL 収集へ MVP を絞ったことで、production 投入前の回収点を近づけられた。
  • 既存 gateway compose を変更せず、host.docker.internal:host-gateway を 使って quote collector から loopback bind の gateway へ到達させたため、 稼働中 gateway の再作成を避けられた。
  • smoke / collector とも、実 API shape を見てから regression test を追加する 流れにできている。

Follow-ups carried forward

  • option chain / spread / whatIf は Phase 6.1 へ分離したまま。Phase 6 MVP は underlying quote collector に限定されている。
  • Paper password reset backend error は、次セッション開始時に再確認が必要。
  • IBKR shadow 観測の次段は、5 営業日 parity 観測と analyze_saxo_ibkr_parity.py による集計。