# setup-remote スキル契約 v0（遠隔の閲覧・承認 + 素材受け渡しのセットアップ）

- 日付: 2026-08-02
- 状態: **v0 ドラフト・要オーナーレビュー**（方針・優先順位はオーナー承認済み 2026-08-02。
  判断根拠・比較調査は非公開の内部記録で管理する）
- 前提: `contract-2026-07-25-project-structure-v0.md`（承認レポートの実体 =
  `<project>/.akari/reports/*.html` + キーフレーム静止画）、
  `contract-2026-08-02-creator-root-v1.md`（作業場の正準構造。素材の投げ込み口 `inbox/`、
  **secrets はマシン設定にのみ置く**原則）、
  プレビューサーバー（`akari --preview`、既定ポート 4567）
- スコープ: スマホ等の**別デバイス**から (a) 承認レポート・プレビューを閲覧する経路、
  (b) 撮影素材を作業場へ届ける経路 — の**セットアップを対話ガイドする新スキル** `setup-remote`
- 非スコープ: チャット常駐エージェントによる承認往復（通知 → 返信で承認。将来の別契約）、
  クラウド同期レーン（Dropbox 等）の実装自動化（v0 は案内のみ）、
  公開インターネットへの露出（§3 ハードルール）

## 0. 位置づけ — 一言で言い切る

承認は本質的に**机の前にいなくてもできる**。解析・レンダはマシンが回し、人間は「レポートを見て
OK / 差し戻しを言う」だけ — その閲覧と素材の受け渡しを、道具 1 つ（Tailscale）のセットアップで
スマホから可能にする。私設ネットワーク限定 = **デフォルト非公開**であり、「設定ミスで世界に公開
されていた」が構造的に起きない手段だけを既定とする。

## 1. 決定事項（v0 の骨格）

| 論点 | 決定 |
|---|---|
| 手段 | **Tailscale**（tailnet 限定）。閲覧 = `tailscale serve` でプレビューサーバーと承認レポートヘルパーを tailnet 限定 HTTPS 化。素材 = **Taildrop**（共有シートからデバイス直送。クラウド不経由・実用上サイズ無制限・画質劣化なし） |
| 不採用 / 保留 | Cloudflare Tunnel + Access（tailnet 外の人への共有が要件になったときの**別契約**。「公開してからゲートで守る」構造は既定にしない）。Cloudflare Pages（レポートはローカル随時生成のため噛み合わない） |
| 素材搬送路の優先順位 | **Taildrop（v0 で実装）** → Dropbox カメラアップロード → iCloud 写真 → Google Drive（順次。v0 では選択肢として提示のみ）。Google フォトは対象外（Library API 制限により自動取得不可） |
| 対応 OS | macOS / Windows 両対応を前提に書く（Tailscale / Taildrop とも両対応。手順の分岐は SKILL.md 側） |

## 2. スキルの責務 — 5 フェーズ

1. **doctor**: Tailscale の導入状態を決定論で判定（未導入 / 導入済み・未ログイン / 構成済み）。
   プレビューサーバーの起動可否・serve 設定の現況もここで検出
2. **導入ガイド — 人間手番の受け渡し**: インストーラーの sudo・GUI ログイン・スマホ側アプリ導入は
   **自動化しない**（macOS の cask は .pkg で sudo 対話必須 — 実測済み）。スキルは
   「ここはあなたの番」を明確に指示 → 完了を doctor で確認 → 次へ進む、を繰り返す構造とする
3. **serve 設定**: `tailscale serve` で許可リスト（§3）の 2 件を tailnet 限定 HTTPS URL にする。
   外部から見える口を安定させるため、**外部ポートを固定し内部ポートを写像する**形を既定とする:

   | 外部 | 内部 | 中身 |
   |---|---|---|
   | `https://<host>.ts.net/` | 4567 | プレビューサーバー |
   | `https://<host>.ts.net:8443/` | ヘルパーの動的ポート | 承認レポート + `decisions.json` |

   レポートヘルパーの内部ポートは起動ごとに変わりうるが、外部 URL は固定される（チャットに
   貼ったリンクが起動のたびに死なない）。パス分岐（`--set-path /report`）はプレフィックス
   除去の挙動を実測してから選択肢に加える — 未実測の間は既定にしない
4. **Taildrop 受信設定**: 受信先フォルダを固定し、作業場の `inbox/` へ接続する
   （直接指定できる場合は直接、できない場合は受信箱 → `inbox/` への移送手順を案内）
5. **疎通確認**: 別デバイスから (a) serve URL が開ける (b) テストファイルを Taildrop 送信して
   `inbox/` に現れる — の両方が通ったら、URL と受信経路を完了レポートに記録して終了

## 3. 安全規律（ハードルール）

- 既定は **tailnet 限定のみ**。公開インターネットへ出す `tailscale funnel` は**既定で使わない・
  提案もしない**。ユーザーが明示的に要求した場合のみ、リスク説明 + 明示承認を経て扱う
- serve してよい対象は**次の許可リスト 2 件に限る**（2026-08-12 拡張）:
  - (a) **プレビューサーバー**（`akari --preview`、既定 4567）
  - (b) **decision-cards レポートヘルパー**（`packages/decision-cards/report-helper.mjs`。
    承認レポートの配信と `decisions.json` の read / write / commit を担う。`127.0.0.1` バインド）

  これ以外のポート・アプリ・ファイルシステムは serve しない。許可リストを増やすときは
  **本契約を改訂してから**行う（スキル側の判断で足さない）
- secrets を作業場・プロジェクトに書かない（creator-root v1 の原則。Tailscale の認証情報は
  Tailscale 側が管理し、スキルは一切保持しない）
- スキルが勝手にインストールを完遂しない（§2-2 の人間手番）。ネットワーク設定の変更は
  すべて事前提示 + 承認後に実行

## 4. intake との接続

- Taildrop の受信先 → 作業場 `inbox/`（creator-root v1 §3 の投げ込み口）が受け皿
- 「直近で撮ったやつで編集よろしく」の**自動選択規約（直近 N 件 / 直近 24h 等）は v0 では
  定めない** — 人間が `inbox/` 内のファイルを指す運用でよい。自動選択は intake 側の将来契約
- クラウド同期レーン（Dropbox 等）を使う場合も「同期フォルダ = 監視対象」に正規化される設計を
  崩さない（搬送手段が何であれ、最終形は「ローカルフォルダにファイルがある」）

## 5. 成果物と受け入れ基準

成果物: `skills/setup-remote/SKILL.md`（+ 必要なら決定論の `bin/doctor.mjs`）、
`docs/skills.md` / `docs/skills.ja.md` への登録（19 スキル目・「プロジェクト・素材の準備」区分）。

- **L0**: SKILL.md の体裁・スキル lint が通る
- **L1**: doctor が 3 状態（未導入 / 未ログイン / 構成済み）を正しく判定する
- **L2**: 実機スモーク — 別デバイスから (a) プレビューの serve URL が開ける
  (b) 承認レポートを開いて決定を保存 → `decisions.json` が実際に更新される
  (c) Taildrop のテストファイルが `inbox/` に現れる（§2-5 の疎通確認そのもの）

## 6. 将来（非スコープの明示）

- チャット常駐エージェント連携: 承認ゲート到達 → チャット通知（リンク or レポート画像化）→
  返信で承認 / 差し戻し。前提検証が済んでから別契約を切る
- クラウド同期レーンの doctor 化・自動セットアップ（Dropbox → iCloud → Google Drive の順）
- tailnet 外への共有（クライアント・協力者にブラウザだけで見せる）: Cloudflare Tunnel +
  Access（One-time PIN）系の別契約
- `inbox/` からの自動素材選択規約（直近 N 件）と create-project / analyze-footage への自動接続

## 7. L2 実測記録（2026-08-12・オーナー実機 iPhone + macOS）

**通った項目**:

| 検証 | 結果 |
|---|---|
| 別デバイスからのプレビュー閲覧 | ✓ tailnet 経由で表示。体感速度は「十分すぎる」（WireGuard 直結のため） |
| **レポート内に埋めた動画の再生** | ✓ iOS 実機で再生・**シーク成功**（H.264 640x360 / 6 秒） |
| Taildrop 着弾 | ✓ 受信先の実パス = **`~/Downloads/`**（macOS GUI 版・実測で確定） |
| Taildrop の無劣化性 | ✓ 92MB / HEVC / 1180x2556 / 60fps / **15.7Mbps のまま**再エンコードなし |
| Taildrop → 作業場 `inbox/` | ✓ **移送運用**で接続（`~/Akari/inbox/`）。macOS スタンドアロン版は受信先を設定変更できないため、直接指定ではなく移送を採る（§2-4 の想定どおり） |
| **承認の往復（`decisions.json`）** | ✓ スマホのタップが Mac のファイルへ書き戻ることを実測。単選カード（`thumbnail`: 既定 → 別候補）・整数スライダ（`direction.intensity`: 50 → 75）・**確定（`completedAt` 記入）** の 3 経路が通過。`byDefault: false` / `answeredAt` も期待どおり更新され、ファイルは `0600` を維持 |

- Taildrop の実測は「チャット添付は搬送路として筋が悪い」（§非スコープの根拠）を裏づけた —
  同じ 92MB は Telegram Bot API 標準（受信 20MB）では原理的に通らない
- 受信物が HEVC だった点は、プレビューサーバー側の H.264 自動プロキシ層が実運用で必要になることの実例

**未達の項目（L2 は未クローズ）**:

| 未達 | 状況 |
|---|---|
| HTTPS | **`tailscale serve` の TLS が未成立**。上記の実測は tailnet 内の平文 HTTP で代替した（WireGuard 内側のため機密性は保たれるが、secure context を要する機能は使えない）。**平文 HTTP を既定にはしない** |

**HTTPS 失敗の切り分け結果（2026-08-12）** — スキル側・serve 設定側の不備ではないと確定:

- tailnet で HTTPS は有効（`tailscale status --json` の `CertDomains` に当該ドメインあり）
- serve の設定自体は正常（同じ経路が平文 HTTP では 200 / 0.28 秒で応答する）
- CAA は発行を許可している（`ts.net` に `issue "letsencrypt.org"`）
- Let's Encrypt の注文が毎回 `status: invalid`（注文 ID は毎回新規 = レート制限ではなく検証失敗）
- **`_acme-challenge.<host>.<tailnet>.ts.net` に使い捨て TXT が 5 件累積**していた。
  DNS-01 の検証失敗と符合する（現行トークンが正しく公開されていない疑い）
- → **tailnet 側（Tailscale の DNS / 制御プレーン）の問題**。再試行を重ねても TXT が増えるだけで
  好転しないため、打ち切って次の一手に回す。候補: (a) マシン名を変更して
  `_acme-challenge` の名前ごと作り直す（serve URL が変わる）(b) Tailscale サポートに問い合わせる

## 8. 改訂履歴

| 日付 | 変更 | 理由 |
|---|---|---|
| 2026-08-02 | v0 初版 | — |
| 2026-08-12 | §3 serve 許可リストを 1 件 → 2 件へ拡張（decision-cards レポートヘルパーを追加）。§2-3 に外部ポート写像を明記。§5 L2 に承認往復の実測を追加 | 元のスコープ（§0「レポートを見て OK / 差し戻しを言う」）は最初から承認を含んでいたが、ハードルールが `serve = プレビューのみ` と狭すぎ、**承認レポートを配信する経路が契約上ふさがっていた**。スコープの拡大ではなくスコープとハードルールの不整合の是正 |
