@quolu/lattice 0.52.3 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/LICENSE +147 -147
  2. package/README.ja.md +355 -355
  3. package/README.md +258 -258
  4. package/bin/lattice-bridge.mjs +25 -0
  5. package/bin/lattice-hub.mjs +67 -0
  6. package/bin/lattice-mcp.mjs +0 -0
  7. package/bin/lattice-scripted-adapter.mjs +0 -0
  8. package/bin/lattice-scripted-worker.mjs +0 -0
  9. package/bin/lattice-work-order-adapter.mjs +0 -0
  10. package/bin/lattice.mjs +0 -0
  11. package/docs/bridge-setup.md +132 -132
  12. package/docs/schemas/lattice.executor_packet.v1.schema.json +57 -57
  13. package/docs/schemas/lattice.executor_receipt.v1.schema.json +66 -66
  14. package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +360 -360
  15. package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -56
  16. package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -72
  17. package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -81
  18. package/docs/schemas/lattice.plan_create_input.v4.schema.json +85 -85
  19. package/docs/schemas/lattice.run_request.v1.schema.json +238 -238
  20. package/docs/schemas/lattice.runtime_adapter_capabilities.v2.schema.json +55 -55
  21. package/docs/schemas/lattice.runtime_adapter_registration_input.v1.schema.json +78 -78
  22. package/docs/schemas/lattice.runtime_adapter_registration_input.v2.schema.json +86 -86
  23. package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -298
  24. package/docs/schemas/lattice.todo_extraction.v3.schema.json +146 -146
  25. package/docs/schemas/lattice.todo_revision.v2.schema.json +260 -260
  26. package/docs/schemas/lattice.todo_revision_set.v3.schema.json +363 -363
  27. package/package.json +103 -103
  28. package/sensor/LICENSE +21 -21
  29. package/sensor/NOTICE +19 -19
  30. package/sensor/dist/bin/lattice-sensor.js +9 -9
  31. package/sensor/dist/db/index.js +24 -24
  32. package/sensor/dist/db/migrations.js +41 -41
  33. package/sensor/dist/db/queries.js +164 -164
  34. package/sensor/dist/db/schema.sql +205 -205
  35. package/sensor/dist/directory.js +5 -5
  36. package/sensor/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  37. package/sensor/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  38. package/sensor/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  39. package/sensor/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  40. package/sensor/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  41. package/sensor/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  42. package/sensor/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
  43. package/sensor/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
  44. package/sensor/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
  45. package/sensor/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  46. package/sensor/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  47. package/sensor/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
  48. package/sensor/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
  49. package/sensor/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
  50. package/sensor/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  51. package/sensor/dist/mcp/liveness-watchdog.js +53 -53
  52. package/sensor/dist/mcp/server-instructions.js +95 -95
  53. package/sensor/package.json +56 -56
  54. package/src/artifact-contracts-v2.mjs +325 -325
  55. package/src/artifact-contracts.mjs +895 -895
  56. package/src/boundary-compiler.mjs +712 -712
  57. package/src/boundary-observation-compiler-v2.mjs +344 -344
  58. package/src/bounded-seam.mjs +230 -230
  59. package/src/bridge-address.mjs +107 -107
  60. package/src/bridge-cli.mjs +303 -297
  61. package/src/bridge-config.mjs +382 -346
  62. package/src/bridge-daemon.mjs +378 -378
  63. package/src/bridge-hub-heartbeat.mjs +170 -0
  64. package/src/bridge-hub-protocol.mjs +198 -0
  65. package/src/bridge-hub-server.mjs +544 -0
  66. package/src/bridge-launch-agent.mjs +323 -323
  67. package/src/bridge-registrar.mjs +102 -102
  68. package/src/bridge-server.mjs +376 -376
  69. package/src/cli-help.mjs +308 -308
  70. package/src/cli-stdio.mjs +40 -40
  71. package/src/control-compiler.mjs +532 -532
  72. package/src/dag-chain.mjs +261 -261
  73. package/src/factory-diagnostics.mjs +188 -188
  74. package/src/git-process.mjs +72 -0
  75. package/src/hash-chain.mjs +76 -76
  76. package/src/hooks-cli.mjs +1057 -1057
  77. package/src/isolation-runner.mjs +409 -409
  78. package/src/node-version-guard.mjs +44 -44
  79. package/src/project-cli.mjs +3 -3
  80. package/src/project-identity.mjs +130 -130
  81. package/src/rc1-black-box-oracle.mjs +906 -906
  82. package/src/rc1-comparison.mjs +154 -154
  83. package/src/rc1-evidence-bundle.mjs +456 -456
  84. package/src/rc1-v4-campaign.mjs +708 -708
  85. package/src/rc1-v4-transform.mjs +467 -467
  86. package/src/rc1-v5-artifact-set.mjs +855 -855
  87. package/src/rc1-v5-behavior-evidence.mjs +594 -594
  88. package/src/rc1-v5-campaign.mjs +797 -797
  89. package/src/rc1-v5-transform.mjs +421 -421
  90. package/src/rc1-v6-artifact-set.mjs +807 -807
  91. package/src/rc1-v6-behavior-evidence.mjs +273 -273
  92. package/src/rc1-v6-campaign.mjs +623 -623
  93. package/src/rc1-v6-causal-binding.mjs +473 -473
  94. package/src/rc1-v6-measurement.mjs +313 -313
  95. package/src/rc2-artifact-set.mjs +1584 -1584
  96. package/src/rc2-campaign.mjs +1506 -1506
  97. package/src/rc2-delivery-policy-front-end.mjs +1079 -1079
  98. package/src/rc2-delivery-policy-oracle.mjs +134 -134
  99. package/src/rc2-delivery-policy-transform.mjs +1127 -1127
  100. package/src/rc2-rc1-transfer-front-end.mjs +511 -511
  101. package/src/rc3-actual-dogfood.mjs +652 -652
  102. package/src/rc3-dogfood-scaffold.mjs +315 -315
  103. package/src/rc3-scripted-campaign.mjs +1383 -1383
  104. package/src/rc4-stage1-dogfood.mjs +673 -673
  105. package/src/runtime-adapter-registry.mjs +524 -524
  106. package/src/runtime-cli.mjs +4588 -4588
  107. package/src/runtime-contracts.mjs +824 -824
  108. package/src/runtime-control-store.mjs +604 -604
  109. package/src/runtime-controller-protocol.mjs +587 -587
  110. package/src/runtime-decision-verifier.mjs +701 -701
  111. package/src/runtime-diff-observer.mjs +361 -361
  112. package/src/runtime-direct-os-observer.mjs +301 -301
  113. package/src/runtime-driver-state.mjs +166 -166
  114. package/src/runtime-engine.mjs +779 -779
  115. package/src/runtime-errors.mjs +356 -356
  116. package/src/runtime-event-store.mjs +189 -189
  117. package/src/runtime-front-end.mjs +925 -925
  118. package/src/runtime-gate-store.mjs +481 -481
  119. package/src/runtime-hold-recompile.mjs +916 -916
  120. package/src/runtime-io-sentinel.mjs +391 -391
  121. package/src/runtime-lifecycle-lock.mjs +294 -294
  122. package/src/runtime-managed-supervisor.mjs +1490 -1490
  123. package/src/runtime-multi-epoch-store.mjs +838 -838
  124. package/src/runtime-projection.mjs +269 -269
  125. package/src/runtime-pull-intake.mjs +1192 -1192
  126. package/src/runtime-scripted-adapter-controller.mjs +1160 -1160
  127. package/src/runtime-scripted-executor.mjs +163 -163
  128. package/src/runtime-scripted-worktree.mjs +104 -104
  129. package/src/runtime-seam-resolve.mjs +428 -428
  130. package/src/runtime-seam-treatment.mjs +173 -173
  131. package/src/runtime-socket-owner.mjs +125 -125
  132. package/src/runtime-work-order-contracts.mjs +91 -91
  133. package/src/runtime-work-order-controller.mjs +1171 -1171
  134. package/src/runtime-worktree-executor.mjs +199 -199
  135. package/src/schedulability-compiler-v2.mjs +303 -303
  136. package/src/schedulability-verifier-v2.mjs +317 -317
  137. package/src/seam-apply.mjs +549 -549
  138. package/src/seam-commit-shared.mjs +22 -22
  139. package/src/seam-commit-transform.mjs +81 -81
  140. package/src/seam-commit.mjs +18 -18
  141. package/src/seam-cost.mjs +322 -322
  142. package/src/seam-derivation.mjs +188 -188
  143. package/src/seam-gate.mjs +146 -146
  144. package/src/seam-proposal-contracts.mjs +446 -446
  145. package/src/seam-proposal-queries.mjs +521 -521
  146. package/src/seam-proposal.mjs +2011 -2011
  147. package/src/seam-ref.mjs +33 -33
  148. package/src/seam-rewrite.mjs +286 -286
  149. package/src/seam-transform.mjs +554 -554
  150. package/src/seam-verification.mjs +260 -260
  151. package/src/sensor-adapter.mjs +432 -432
  152. package/src/sensor-cli.mjs +139 -139
  153. package/src/sensor-diff.mjs +661 -661
  154. package/src/sensor-node-runtime.mjs +53 -53
  155. package/src/sensor-runtime.mjs +52 -52
  156. package/src/timestamp-contract.mjs +8 -8
  157. package/src/todo-audit-pending.mjs +91 -91
  158. package/src/todo-chain.mjs +178 -178
  159. package/src/todo-cli.mjs +8 -8
  160. package/src/todo-contracts.mjs +728 -728
  161. package/src/todo-dashboard-registry.mjs +573 -573
  162. package/src/todo-dispatch-shape.mjs +190 -190
  163. package/src/todo-gantt-html-independence.mjs +239 -239
  164. package/src/todo-gantt-html-shared.mjs +226 -226
  165. package/src/todo-gantt-html-style.mjs +131 -131
  166. package/src/todo-gantt-html.mjs +248 -248
  167. package/src/todo-gantt-layout.mjs +974 -974
  168. package/src/todo-gantt-live.mjs +361 -361
  169. package/src/todo-gantt-nested.mjs +263 -263
  170. package/src/todo-gantt-presentation.mjs +217 -217
  171. package/src/todo-gantt-scope.mjs +123 -123
  172. package/src/todo-gantt-svg.mjs +353 -353
  173. package/src/todo-independence-contracts.mjs +595 -595
  174. package/src/todo-independence-guidance.mjs +322 -322
  175. package/src/todo-independence.mjs +640 -640
  176. package/src/todo-markdown-renderer.mjs +260 -260
  177. package/src/todo-migration.mjs +448 -448
  178. package/src/todo-narrative-anchor.mjs +130 -130
  179. package/src/todo-note-store.mjs +629 -629
  180. package/src/todo-parallel-candidates.mjs +114 -114
  181. package/src/todo-revision.mjs +995 -995
  182. package/src/todo-split.mjs +472 -472
  183. package/src/todo-status.mjs +690 -690
  184. package/src/todo-store-git-transaction.mjs +418 -418
  185. package/src/todo-store.mjs +42 -21
  186. package/src/treatment-compiler.mjs +728 -728
  187. package/src/treatment-runner.mjs +656 -656
  188. package/src/witness-scaffold.mjs +180 -180
@@ -1,132 +1,132 @@
1
- # Optional network bridge
2
-
3
- Latticeのproject dashboardは既定でloopbackだけにbindし、bridge用socketや設定を作らない。
4
- LAN上のreverse proxyなどから閲覧する時だけ、利用者がlisten IPを明示してbridgeを有効化する。
5
- `postinstall`では質問やnetwork公開を行わない。
6
-
7
- TTYでは`lattice bridge setup`で安全側既定の対話wizardを開始できる。最初の公開確認は既定で無効を選び、
8
- cancelした場合は設定を変更しない。非TTYではhangせず、次の非対話commandを案内する。
9
- portを省略するか`auto`にすると、49152–65535から候補を重複なく選び、
10
- 実際のexclusive bindとhealth確認に成功したportだけを保存する。
11
-
12
- ```bash
13
- lattice bridge setup --listen 192.168.1.50 --port auto --dashboard --allow-host lattice.example.com --json
14
- ```
15
-
16
- `--dashboard`は現在のlocal dashboard descriptorをrequestごとに解決するため、dashboard再起動でportが変わっても
17
- bridge設定はstaleにならない。固定upstreamを使う場合だけ`--upstream http://127.0.0.1:4318`を指定する。
18
- listen IPは常に許可Hostへ入り、reverse proxyで公開するhostnameは`--allow-host`を反復して追加する。
19
- 許可されていないHostは421となるため、DNS rebinding originへ工程情報を返さない。
20
-
21
- ```bash
22
- lattice bridge status --json
23
- lattice bridge reconfigure --listen 192.168.1.50 --port auto --dashboard --json
24
- lattice bridge disable --json
25
- ```
26
-
27
- 設定は`~/.lattice/bridge.json`へmode 0600でatomic保存する。`setup`/`reconfigure`は実bridge daemonが
28
- 選択socketをexclusive bindしhealthを返すまで成功にしない。起動に失敗した場合は旧設定へ戻す。
29
- `disable`もbridge socketの停止確認後に成功し、loopbackのlocal dashboardは停止しない。
30
- configまたはdaemon descriptorが壊れている場合、`disable`は公開socketのfail-closed停止を優先して破損control
31
- fileを除去し、JSON結果の`recovery`へ処置を明示する。その後は`setup`で再設定できる。
32
-
33
- 自動化・隔離testではabsoluteな`LATTICE_CONFIG_DIR`で設定rootを変更できる。無効な設定、低いport、
34
- 使用中の明示port、危険なrequest target、到達不能upstreamはsilent fallbackせずtyped errorを返す。
35
-
36
- ## listen IPがDHCPで動く場合
37
-
38
- 設定したlisten IPがホストから消えると、古いsocketは死んだアドレスへ取り残され、LANから到達できなくなる。
39
- daemonは各reconcileで実効アドレスを解決し直し、同一subnet(IPv4 /24、IPv6 /64)に生きたアドレスがあれば
40
- そこへbindし直す。VPNや別NICなど異なるnetworkのアドレスは採用せず、候補が無ければ
41
- `BRIDGE_LISTEN_ADDRESS_ABSENT`で公開socketをfail-closedにする。再bind先は許可Hostへ自動で加わる。
42
-
43
- `LATTICE_BRIDGE_REGISTRAR_SSH_HOST`と`LATTICE_BRIDGE_REGISTRAR_SCRIPT`を両方設定すると、新しいbindingを
44
- 張るたびに`ssh <host> <script> <port>`でreverse proxy hostへ自己登録する。アドレスは送らず、remote側が
45
- ssh送信元から決めるため、各hostは自分自身しか登録できない。登録の失敗はbridgeを落とさずstderrへ
46
- typedに報告する。この配線が無いと、Caddy等が持つリテラルはlease変更のたびに黙って陳腐化する。
47
-
48
- ## reverse proxyへ逆トンネルで繋ぐ(LAN bindを使わない)
49
-
50
- reverse proxy hostへsshで到達できるなら、LANへbindせずloopbackだけで公開できる。bridgeが動くhostから
51
- 接続しに行くため、そのhostのLAN addressはreverse proxyのどこにも現れず、追従も自己登録も不要になる。
52
-
53
- ```bash
54
- lattice bridge setup --listen 127.0.0.1 --port 53939 --dashboard --allow-host lattice.example.com --json
55
- ssh -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 \
56
- -R 172.18.0.1:53939:127.0.0.1:53939 proxy-host
57
- ```
58
-
59
- reverse proxyはこの固定endpointだけを見る。転送口のbind先は、reverse proxyが到達できるaddressにする。
60
- Docker上のreverse proxyでは、containerの`127.0.0.1`はcontainer自身のloopbackでありhostのそれではないため、
61
- hostのloopbackへ開いた口には届かない。対象networkのgateway(`docker network inspect`の`Gateway`)へbindする。
62
-
63
- sshdは既定の`GatewayPorts no`だと`127.0.0.1`にしかbindできない。`clientspecified`にすると、clientが明示した
64
- addressだけにbindする(`yes`と違い全interfaceへは晒さない)。host firewallがINPUTをDROPしている場合は、
65
- その1 portだけを許可する。`ExitOnForwardFailure=yes`は、転送口を開けないまま接続だけ生かす状態を防ぐ。
66
- 常駐はprocess supervisorのKeepAliveに任せ、切断時は張り直す。
67
-
68
- ## Docker Caddy/Cloudflare Tunnelへ接続する
69
-
70
- bridgeを有効化したMacとreverse proxy hostの間で、まず許可Hostを付けたLAN到達を確認する。
71
- この段階が失敗している時はDNSやTunnelを追加しない。
72
-
73
- ```bash
74
- curl --fail --header 'Host: lattice.example.com' \
75
- http://MAC_LAN_IP:BRIDGE_PORT/projects/
76
- ```
77
-
78
- Caddyは既存のDocker networkと証明書運用を維持し、Lattice用siteだけを追加する。
79
-
80
- ```caddyfile
81
- lattice.example.com {
82
- reverse_proxy MAC_LAN_IP:BRIDGE_PORT {
83
- flush_interval -1
84
- }
85
- }
86
- ```
87
-
88
- 本番反映はcontainer内で`caddy validate`を通してから`caddy reload`する。Caddyfileを単一ファイルで
89
- bind mountしている構成では、atomic renameでhost側fileを置換するとcontainerが旧inodeを参照し続ける。
90
- 更新前backupを残し、inodeを維持するin-place更新を使うか、directory bind mountへ変更する。
91
-
92
- remote-managed Cloudflare Tunnelでは、Tunnel実行tokenを設定APIの代用にしない。Cloudflareの正規管理面で
93
- public hostname `lattice.kitepon.dev` を次のoriginへ対応付ける。
94
-
95
- - Service: `https://caddy:443`
96
- - TLS Origin Server Name: `lattice.kitepon.dev`(管理面に同等の設定がある場合は`Match SNI to Host`でもよい)
97
-
98
- `http://caddy:80`は選ばない。CaddyのHTTPからHTTPSへのredirectをTunnelがorigin応答として返す構成は、
99
- 外部requestが同じ公開URLへ戻るredirect loopになり得るためである。外部gateではredirectを追って200にせず、
100
- 最初の応答がHTTPSの200であることを確認する。
101
-
102
- 受入は次の3 gateを独立して記録し、後段の成功で前段を代用しない。
103
-
104
- 1. **LAN bridge**: reverse proxy hostから許可Host付きで`http://MAC_LAN_IP:BRIDGE_PORT/projects/`が200。
105
- 2. **Docker Caddy**: Caddyへ`Host: lattice.kitepon.dev`を付けたHTTPS requestが200。証明書検証を省略する
106
- 内部probeを外部公開成功の証拠にはしない。
107
- 3. **Cloudflare public HTTPS**: `https://lattice.kitepon.dev/projects/`がredirectなしで200となり、一覧から開いた
108
- `/projects/<project_id>/`のHTML titleが`Lattice — <project名> 依存工程図`である。
109
-
110
- 公開viewerの404も、ブラウザとAPIの両契約を別々に確認する。未知URLへ`Accept: text/html`を
111
- 付けたrequestはHTTP 404かつ`Content-Type: text/html`で、`noindex, nofollow`と
112
- `/projects/`、`https://kitepon.dev/`への戻り先を持つ。`Accept: application/json`では
113
- HTTP 404かつ`Content-Type: application/json`で、既存の
114
- `lattice.todo_gantt_http_error.v1`を返す。
115
-
116
- ```bash
117
- curl --silent --show-error --include --header 'Accept: text/html' \
118
- https://lattice.kitepon.dev/unknown
119
- curl --silent --show-error --include --header 'Accept: application/json' \
120
- https://lattice.kitepon.dev/unknown
121
- ```
122
-
123
- 外部gateはHTMLだけで閉じず、各projectの
124
- `https://lattice.kitepon.dev/projects/<project_id>/events`も確認する。応答は200かつ
125
- `Content-Type: text/event-stream`で、接続直後に`event: state`と現在の`head_digest`を返さなければならない。
126
- 接続を開いたまま正規のTodo更新を行い、新しい`state`が同じstreamへ届くことを確認する。切断後に再接続しても
127
- 再び初回`state`が届き、そのdigestが最新headと一致することまでを継続・再接続gateとする。
128
-
129
- ```bash
130
- curl --fail --show-error --include --no-buffer --max-time 15 \
131
- https://lattice.kitepon.dev/projects/PROJECT_ID/events
132
- ```
1
+ # Optional network bridge
2
+
3
+ Latticeのproject dashboardは既定でloopbackだけにbindし、bridge用socketや設定を作らない。
4
+ LAN上のreverse proxyなどから閲覧する時だけ、利用者がlisten IPを明示してbridgeを有効化する。
5
+ `postinstall`では質問やnetwork公開を行わない。
6
+
7
+ TTYでは`lattice bridge setup`で安全側既定の対話wizardを開始できる。最初の公開確認は既定で無効を選び、
8
+ cancelした場合は設定を変更しない。非TTYではhangせず、次の非対話commandを案内する。
9
+ portを省略するか`auto`にすると、49152–65535から候補を重複なく選び、
10
+ 実際のexclusive bindとhealth確認に成功したportだけを保存する。
11
+
12
+ ```bash
13
+ lattice bridge setup --listen 192.168.1.50 --port auto --dashboard --allow-host lattice.example.com --json
14
+ ```
15
+
16
+ `--dashboard`は現在のlocal dashboard descriptorをrequestごとに解決するため、dashboard再起動でportが変わっても
17
+ bridge設定はstaleにならない。固定upstreamを使う場合だけ`--upstream http://127.0.0.1:4318`を指定する。
18
+ listen IPは常に許可Hostへ入り、reverse proxyで公開するhostnameは`--allow-host`を反復して追加する。
19
+ 許可されていないHostは421となるため、DNS rebinding originへ工程情報を返さない。
20
+
21
+ ```bash
22
+ lattice bridge status --json
23
+ lattice bridge reconfigure --listen 192.168.1.50 --port auto --dashboard --json
24
+ lattice bridge disable --json
25
+ ```
26
+
27
+ 設定は`~/.lattice/bridge.json`へmode 0600でatomic保存する。`setup`/`reconfigure`は実bridge daemonが
28
+ 選択socketをexclusive bindしhealthを返すまで成功にしない。起動に失敗した場合は旧設定へ戻す。
29
+ `disable`もbridge socketの停止確認後に成功し、loopbackのlocal dashboardは停止しない。
30
+ configまたはdaemon descriptorが壊れている場合、`disable`は公開socketのfail-closed停止を優先して破損control
31
+ fileを除去し、JSON結果の`recovery`へ処置を明示する。その後は`setup`で再設定できる。
32
+
33
+ 自動化・隔離testではabsoluteな`LATTICE_CONFIG_DIR`で設定rootを変更できる。無効な設定、低いport、
34
+ 使用中の明示port、危険なrequest target、到達不能upstreamはsilent fallbackせずtyped errorを返す。
35
+
36
+ ## listen IPがDHCPで動く場合
37
+
38
+ 設定したlisten IPがホストから消えると、古いsocketは死んだアドレスへ取り残され、LANから到達できなくなる。
39
+ daemonは各reconcileで実効アドレスを解決し直し、同一subnet(IPv4 /24、IPv6 /64)に生きたアドレスがあれば
40
+ そこへbindし直す。VPNや別NICなど異なるnetworkのアドレスは採用せず、候補が無ければ
41
+ `BRIDGE_LISTEN_ADDRESS_ABSENT`で公開socketをfail-closedにする。再bind先は許可Hostへ自動で加わる。
42
+
43
+ `LATTICE_BRIDGE_REGISTRAR_SSH_HOST`と`LATTICE_BRIDGE_REGISTRAR_SCRIPT`を両方設定すると、新しいbindingを
44
+ 張るたびに`ssh <host> <script> <port>`でreverse proxy hostへ自己登録する。アドレスは送らず、remote側が
45
+ ssh送信元から決めるため、各hostは自分自身しか登録できない。登録の失敗はbridgeを落とさずstderrへ
46
+ typedに報告する。この配線が無いと、Caddy等が持つリテラルはlease変更のたびに黙って陳腐化する。
47
+
48
+ ## reverse proxyへ逆トンネルで繋ぐ(LAN bindを使わない)
49
+
50
+ reverse proxy hostへsshで到達できるなら、LANへbindせずloopbackだけで公開できる。bridgeが動くhostから
51
+ 接続しに行くため、そのhostのLAN addressはreverse proxyのどこにも現れず、追従も自己登録も不要になる。
52
+
53
+ ```bash
54
+ lattice bridge setup --listen 127.0.0.1 --port 53939 --dashboard --allow-host lattice.example.com --json
55
+ ssh -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 \
56
+ -R 172.18.0.1:53939:127.0.0.1:53939 proxy-host
57
+ ```
58
+
59
+ reverse proxyはこの固定endpointだけを見る。転送口のbind先は、reverse proxyが到達できるaddressにする。
60
+ Docker上のreverse proxyでは、containerの`127.0.0.1`はcontainer自身のloopbackでありhostのそれではないため、
61
+ hostのloopbackへ開いた口には届かない。対象networkのgateway(`docker network inspect`の`Gateway`)へbindする。
62
+
63
+ sshdは既定の`GatewayPorts no`だと`127.0.0.1`にしかbindできない。`clientspecified`にすると、clientが明示した
64
+ addressだけにbindする(`yes`と違い全interfaceへは晒さない)。host firewallがINPUTをDROPしている場合は、
65
+ その1 portだけを許可する。`ExitOnForwardFailure=yes`は、転送口を開けないまま接続だけ生かす状態を防ぐ。
66
+ 常駐はprocess supervisorのKeepAliveに任せ、切断時は張り直す。
67
+
68
+ ## Docker Caddy/Cloudflare Tunnelへ接続する
69
+
70
+ bridgeを有効化したMacとreverse proxy hostの間で、まず許可Hostを付けたLAN到達を確認する。
71
+ この段階が失敗している時はDNSやTunnelを追加しない。
72
+
73
+ ```bash
74
+ curl --fail --header 'Host: lattice.example.com' \
75
+ http://MAC_LAN_IP:BRIDGE_PORT/projects/
76
+ ```
77
+
78
+ Caddyは既存のDocker networkと証明書運用を維持し、Lattice用siteだけを追加する。
79
+
80
+ ```caddyfile
81
+ lattice.example.com {
82
+ reverse_proxy MAC_LAN_IP:BRIDGE_PORT {
83
+ flush_interval -1
84
+ }
85
+ }
86
+ ```
87
+
88
+ 本番反映はcontainer内で`caddy validate`を通してから`caddy reload`する。Caddyfileを単一ファイルで
89
+ bind mountしている構成では、atomic renameでhost側fileを置換するとcontainerが旧inodeを参照し続ける。
90
+ 更新前backupを残し、inodeを維持するin-place更新を使うか、directory bind mountへ変更する。
91
+
92
+ remote-managed Cloudflare Tunnelでは、Tunnel実行tokenを設定APIの代用にしない。Cloudflareの正規管理面で
93
+ public hostname `lattice.kitepon.dev` を次のoriginへ対応付ける。
94
+
95
+ - Service: `https://caddy:443`
96
+ - TLS Origin Server Name: `lattice.kitepon.dev`(管理面に同等の設定がある場合は`Match SNI to Host`でもよい)
97
+
98
+ `http://caddy:80`は選ばない。CaddyのHTTPからHTTPSへのredirectをTunnelがorigin応答として返す構成は、
99
+ 外部requestが同じ公開URLへ戻るredirect loopになり得るためである。外部gateではredirectを追って200にせず、
100
+ 最初の応答がHTTPSの200であることを確認する。
101
+
102
+ 受入は次の3 gateを独立して記録し、後段の成功で前段を代用しない。
103
+
104
+ 1. **LAN bridge**: reverse proxy hostから許可Host付きで`http://MAC_LAN_IP:BRIDGE_PORT/projects/`が200。
105
+ 2. **Docker Caddy**: Caddyへ`Host: lattice.kitepon.dev`を付けたHTTPS requestが200。証明書検証を省略する
106
+ 内部probeを外部公開成功の証拠にはしない。
107
+ 3. **Cloudflare public HTTPS**: `https://lattice.kitepon.dev/projects/`がredirectなしで200となり、一覧から開いた
108
+ `/projects/<project_id>/`のHTML titleが`Lattice — <project名> 依存工程図`である。
109
+
110
+ 公開viewerの404も、ブラウザとAPIの両契約を別々に確認する。未知URLへ`Accept: text/html`を
111
+ 付けたrequestはHTTP 404かつ`Content-Type: text/html`で、`noindex, nofollow`と
112
+ `/projects/`、`https://kitepon.dev/`への戻り先を持つ。`Accept: application/json`では
113
+ HTTP 404かつ`Content-Type: application/json`で、既存の
114
+ `lattice.todo_gantt_http_error.v1`を返す。
115
+
116
+ ```bash
117
+ curl --silent --show-error --include --header 'Accept: text/html' \
118
+ https://lattice.kitepon.dev/unknown
119
+ curl --silent --show-error --include --header 'Accept: application/json' \
120
+ https://lattice.kitepon.dev/unknown
121
+ ```
122
+
123
+ 外部gateはHTMLだけで閉じず、各projectの
124
+ `https://lattice.kitepon.dev/projects/<project_id>/events`も確認する。応答は200かつ
125
+ `Content-Type: text/event-stream`で、接続直後に`event: state`と現在の`head_digest`を返さなければならない。
126
+ 接続を開いたまま正規のTodo更新を行い、新しい`state`が同じstreamへ届くことを確認する。切断後に再接続しても
127
+ 再び初回`state`が届き、そのdigestが最新headと一致することまでを継続・再接続gateとする。
128
+
129
+ ```bash
130
+ curl --fail --show-error --include --no-buffer --max-time 15 \
131
+ https://lattice.kitepon.dev/projects/PROJECT_ID/events
132
+ ```
@@ -1,57 +1,57 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/kitepon-rgb/Lattice/blob/main/docs/schemas/lattice.executor_packet.v1.schema.json",
4
- "title": "lattice.executor_packet.v1",
5
- "description": "The single context packet issued at dispatch. It is the machine record of the context an executor received.",
6
- "$comment": "Runtime validation additionally enforces canonical JSON bytes, the self-digest rule for `packet_digest`, and that `context_content_digest` equals the SHA-256 of the canonical JSON projection of exactly {todo_id, task_ref, scope, base_sha, verifier_refs, forbidden_operations} — plan attribution fields are excluded so that an epoch rebind is provably content-preserving.",
7
- "type": "object",
8
- "additionalProperties": false,
9
- "required": [
10
- "schema",
11
- "packet_id",
12
- "todo_id",
13
- "task_ref",
14
- "scope",
15
- "base_sha",
16
- "plan_ref",
17
- "plan_epoch",
18
- "verifier_refs",
19
- "forbidden_operations",
20
- "context_content_digest",
21
- "packet_digest"
22
- ],
23
- "properties": {
24
- "schema": { "const": "lattice.executor_packet.v1" },
25
- "packet_id": { "$ref": "#/$defs/identifier" },
26
- "todo_id": {
27
- "$ref": "#/$defs/identifier",
28
- "$comment": "Carried through from `run_request.v1`. It is not qualified by any TODO store project/plan/revision identity."
29
- },
30
- "task_ref": { "$ref": "#/$defs/identifier" },
31
- "scope": { "type": "object" },
32
- "base_sha": { "$ref": "#/$defs/gitSha" },
33
- "plan_ref": { "$ref": "#/$defs/identifier" },
34
- "plan_epoch": { "type": "integer", "minimum": 0 },
35
- "verifier_refs": {
36
- "type": "array",
37
- "maxItems": 256,
38
- "items": { "type": "string" }
39
- },
40
- "forbidden_operations": {
41
- "type": "array",
42
- "minItems": 1,
43
- "maxItems": 256,
44
- "items": { "type": "string" }
45
- },
46
- "context_content_digest": { "$ref": "#/$defs/digest" },
47
- "packet_digest": { "$ref": "#/$defs/digest" }
48
- },
49
- "$defs": {
50
- "identifier": {
51
- "type": "string",
52
- "pattern": "^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$"
53
- },
54
- "digest": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
55
- "gitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" }
56
- }
57
- }
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/kitepon-rgb/Lattice/blob/main/docs/schemas/lattice.executor_packet.v1.schema.json",
4
+ "title": "lattice.executor_packet.v1",
5
+ "description": "The single context packet issued at dispatch. It is the machine record of the context an executor received.",
6
+ "$comment": "Runtime validation additionally enforces canonical JSON bytes, the self-digest rule for `packet_digest`, and that `context_content_digest` equals the SHA-256 of the canonical JSON projection of exactly {todo_id, task_ref, scope, base_sha, verifier_refs, forbidden_operations} — plan attribution fields are excluded so that an epoch rebind is provably content-preserving.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "schema",
11
+ "packet_id",
12
+ "todo_id",
13
+ "task_ref",
14
+ "scope",
15
+ "base_sha",
16
+ "plan_ref",
17
+ "plan_epoch",
18
+ "verifier_refs",
19
+ "forbidden_operations",
20
+ "context_content_digest",
21
+ "packet_digest"
22
+ ],
23
+ "properties": {
24
+ "schema": { "const": "lattice.executor_packet.v1" },
25
+ "packet_id": { "$ref": "#/$defs/identifier" },
26
+ "todo_id": {
27
+ "$ref": "#/$defs/identifier",
28
+ "$comment": "Carried through from `run_request.v1`. It is not qualified by any TODO store project/plan/revision identity."
29
+ },
30
+ "task_ref": { "$ref": "#/$defs/identifier" },
31
+ "scope": { "type": "object" },
32
+ "base_sha": { "$ref": "#/$defs/gitSha" },
33
+ "plan_ref": { "$ref": "#/$defs/identifier" },
34
+ "plan_epoch": { "type": "integer", "minimum": 0 },
35
+ "verifier_refs": {
36
+ "type": "array",
37
+ "maxItems": 256,
38
+ "items": { "type": "string" }
39
+ },
40
+ "forbidden_operations": {
41
+ "type": "array",
42
+ "minItems": 1,
43
+ "maxItems": 256,
44
+ "items": { "type": "string" }
45
+ },
46
+ "context_content_digest": { "$ref": "#/$defs/digest" },
47
+ "packet_digest": { "$ref": "#/$defs/digest" }
48
+ },
49
+ "$defs": {
50
+ "identifier": {
51
+ "type": "string",
52
+ "pattern": "^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$"
53
+ },
54
+ "digest": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
55
+ "gitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" }
56
+ }
57
+ }
@@ -1,66 +1,66 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/kitepon-rgb/Lattice/blob/main/docs/schemas/lattice.executor_receipt.v1.schema.json",
4
- "title": "lattice.executor_receipt.v1",
5
- "description": "The receipt an executor returns for one dispatched packet. `packet_digest` is what attributes it to the packet it received.",
6
- "$comment": "Runtime validation additionally enforces canonical JSON bytes and the self-digest rule for `receipt_digest`. Acceptance is decided by event order, not by the receipt's own claims: the binding is checked against the `executor_dispatched` / `epoch_rebound` event that recorded the handle, worktree and packet digest for that TODO.",
7
- "type": "object",
8
- "additionalProperties": false,
9
- "required": [
10
- "schema",
11
- "receipt_id",
12
- "executor_handle",
13
- "worktree_id",
14
- "base_sha",
15
- "plan_epoch",
16
- "packet_digest",
17
- "todo_id",
18
- "checkpoint_digest",
19
- "observed_diff",
20
- "receipt_digest"
21
- ],
22
- "properties": {
23
- "schema": { "const": "lattice.executor_receipt.v1" },
24
- "receipt_id": { "$ref": "#/$defs/identifier" },
25
- "executor_handle": { "$ref": "#/$defs/identifier" },
26
- "worktree_id": { "$ref": "#/$defs/identifier" },
27
- "base_sha": { "$ref": "#/$defs/gitSha" },
28
- "plan_epoch": { "type": "integer", "minimum": 0 },
29
- "packet_digest": {
30
- "$ref": "#/$defs/digest",
31
- "$comment": "Attribution to the received `executor_packet.v1`. This is the only link back to the dispatch."
32
- },
33
- "todo_id": {
34
- "$ref": "#/$defs/identifier",
35
- "$comment": "Carried through from `run_request.v1`. It is not qualified by any TODO store project/plan/revision identity, so a receipt alone does not prove which TODO store task it belongs to."
36
- },
37
- "checkpoint_digest": { "$ref": "#/$defs/digest" },
38
- "observed_diff": {
39
- "type": "array",
40
- "maxItems": 256,
41
- "items": {
42
- "type": "object",
43
- "additionalProperties": false,
44
- "required": ["path", "change"],
45
- "properties": {
46
- "path": { "$ref": "#/$defs/repoRelativePath" },
47
- "change": { "enum": ["added", "modified", "deleted"] }
48
- }
49
- }
50
- },
51
- "receipt_digest": { "$ref": "#/$defs/digest" }
52
- },
53
- "$defs": {
54
- "identifier": {
55
- "type": "string",
56
- "pattern": "^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$"
57
- },
58
- "digest": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
59
- "gitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
60
- "repoRelativePath": {
61
- "type": "string",
62
- "minLength": 1,
63
- "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.?(?:/|$))[^\\u0000-\\u001f\\u007f\\\\]+$"
64
- }
65
- }
66
- }
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/kitepon-rgb/Lattice/blob/main/docs/schemas/lattice.executor_receipt.v1.schema.json",
4
+ "title": "lattice.executor_receipt.v1",
5
+ "description": "The receipt an executor returns for one dispatched packet. `packet_digest` is what attributes it to the packet it received.",
6
+ "$comment": "Runtime validation additionally enforces canonical JSON bytes and the self-digest rule for `receipt_digest`. Acceptance is decided by event order, not by the receipt's own claims: the binding is checked against the `executor_dispatched` / `epoch_rebound` event that recorded the handle, worktree and packet digest for that TODO.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "schema",
11
+ "receipt_id",
12
+ "executor_handle",
13
+ "worktree_id",
14
+ "base_sha",
15
+ "plan_epoch",
16
+ "packet_digest",
17
+ "todo_id",
18
+ "checkpoint_digest",
19
+ "observed_diff",
20
+ "receipt_digest"
21
+ ],
22
+ "properties": {
23
+ "schema": { "const": "lattice.executor_receipt.v1" },
24
+ "receipt_id": { "$ref": "#/$defs/identifier" },
25
+ "executor_handle": { "$ref": "#/$defs/identifier" },
26
+ "worktree_id": { "$ref": "#/$defs/identifier" },
27
+ "base_sha": { "$ref": "#/$defs/gitSha" },
28
+ "plan_epoch": { "type": "integer", "minimum": 0 },
29
+ "packet_digest": {
30
+ "$ref": "#/$defs/digest",
31
+ "$comment": "Attribution to the received `executor_packet.v1`. This is the only link back to the dispatch."
32
+ },
33
+ "todo_id": {
34
+ "$ref": "#/$defs/identifier",
35
+ "$comment": "Carried through from `run_request.v1`. It is not qualified by any TODO store project/plan/revision identity, so a receipt alone does not prove which TODO store task it belongs to."
36
+ },
37
+ "checkpoint_digest": { "$ref": "#/$defs/digest" },
38
+ "observed_diff": {
39
+ "type": "array",
40
+ "maxItems": 256,
41
+ "items": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["path", "change"],
45
+ "properties": {
46
+ "path": { "$ref": "#/$defs/repoRelativePath" },
47
+ "change": { "enum": ["added", "modified", "deleted"] }
48
+ }
49
+ }
50
+ },
51
+ "receipt_digest": { "$ref": "#/$defs/digest" }
52
+ },
53
+ "$defs": {
54
+ "identifier": {
55
+ "type": "string",
56
+ "pattern": "^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$"
57
+ },
58
+ "digest": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
59
+ "gitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
60
+ "repoRelativePath": {
61
+ "type": "string",
62
+ "minLength": 1,
63
+ "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.?(?:/|$))[^\\u0000-\\u001f\\u007f\\\\]+$"
64
+ }
65
+ }
66
+ }