blue-js-sdk 2.0.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.
- package/CHANGELOG.md +446 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/ai-path/ADMIN-ELEVATION.md +116 -0
- package/ai-path/AI-MANIFESTO.md +185 -0
- package/ai-path/BREAKING.md +74 -0
- package/ai-path/CHECKLIST.md +619 -0
- package/ai-path/CONNECTION-STEPS.md +724 -0
- package/ai-path/DECISION-TREE.md +378 -0
- package/ai-path/DEPENDENCIES.md +459 -0
- package/ai-path/E2E-FLOW.md +1555 -0
- package/ai-path/FAILURES.md +403 -0
- package/ai-path/GUIDE.md +1217 -0
- package/ai-path/README.md +558 -0
- package/ai-path/SPLIT-TUNNEL.md +266 -0
- package/ai-path/cli.js +535 -0
- package/ai-path/connect.js +884 -0
- package/ai-path/discover.js +178 -0
- package/ai-path/environment.js +266 -0
- package/ai-path/errors.js +86 -0
- package/ai-path/examples/autonomous-agent.mjs +220 -0
- package/ai-path/examples/multi-region.mjs +174 -0
- package/ai-path/examples/one-shot.mjs +31 -0
- package/ai-path/index.js +60 -0
- package/ai-path/pricing.js +136 -0
- package/ai-path/recommend.js +413 -0
- package/ai-path/run-admin.vbs +25 -0
- package/ai-path/setup.js +291 -0
- package/ai-path/wallet.js +137 -0
- package/app-helpers.js +363 -0
- package/app-settings.js +95 -0
- package/app-types.js +267 -0
- package/audit.js +847 -0
- package/batch.js +293 -0
- package/bin/setup.js +376 -0
- package/chain/authz.js +109 -0
- package/chain/broadcast.js +472 -0
- package/chain/client.js +160 -0
- package/chain/fee-grants.js +305 -0
- package/chain/index.js +891 -0
- package/chain/lcd.js +313 -0
- package/chain/queries.js +547 -0
- package/chain/rpc.js +408 -0
- package/chain/wallet.js +141 -0
- package/cli/config.js +143 -0
- package/cli/index.js +463 -0
- package/cli/output.js +182 -0
- package/cli.js +491 -0
- package/client/index.js +251 -0
- package/client.js +271 -0
- package/config/index.js +255 -0
- package/connection/connect.js +849 -0
- package/connection/disconnect.js +180 -0
- package/connection/discovery.js +321 -0
- package/connection/index.js +76 -0
- package/connection/proxy.js +148 -0
- package/connection/resilience.js +428 -0
- package/connection/security.js +232 -0
- package/connection/state.js +369 -0
- package/connection/tunnel.js +691 -0
- package/consumer.js +132 -0
- package/cosmjs-setup.js +1884 -0
- package/defaults.js +366 -0
- package/disk-cache.js +107 -0
- package/dist/client.d.ts +108 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +400 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/errors/index.js +112 -0
- package/errors.js +218 -0
- package/examples/README.md +64 -0
- package/examples/connect-direct.mjs +106 -0
- package/examples/connect-plan.mjs +125 -0
- package/examples/error-handling.mjs +109 -0
- package/examples/query-nodes.mjs +94 -0
- package/examples/wallet-basics.mjs +61 -0
- package/generated/amino/amino.ts +9 -0
- package/generated/cosmos/base/v1beta1/coin.ts +365 -0
- package/generated/cosmos_proto/cosmos.ts +323 -0
- package/generated/gogoproto/gogo.ts +9 -0
- package/generated/google/protobuf/descriptor.ts +7601 -0
- package/generated/google/protobuf/duration.ts +208 -0
- package/generated/google/protobuf/timestamp.ts +238 -0
- package/generated/sentinel/lease/v1/events.ts +924 -0
- package/generated/sentinel/lease/v1/lease.ts +292 -0
- package/generated/sentinel/lease/v1/msg.ts +949 -0
- package/generated/sentinel/lease/v1/params.ts +164 -0
- package/generated/sentinel/node/v3/events.ts +881 -0
- package/generated/sentinel/node/v3/msg.ts +1002 -0
- package/generated/sentinel/node/v3/node.ts +263 -0
- package/generated/sentinel/node/v3/params.ts +183 -0
- package/generated/sentinel/plan/v3/events.ts +675 -0
- package/generated/sentinel/plan/v3/msg.ts +1191 -0
- package/generated/sentinel/plan/v3/plan.ts +283 -0
- package/generated/sentinel/provider/v2/events.ts +171 -0
- package/generated/sentinel/provider/v2/msg.ts +480 -0
- package/generated/sentinel/provider/v2/params.ts +131 -0
- package/generated/sentinel/provider/v2/provider.ts +246 -0
- package/generated/sentinel/session/v3/events.ts +480 -0
- package/generated/sentinel/session/v3/msg.ts +616 -0
- package/generated/sentinel/session/v3/params.ts +260 -0
- package/generated/sentinel/session/v3/proof.ts +180 -0
- package/generated/sentinel/session/v3/session.ts +384 -0
- package/generated/sentinel/subscription/v3/events.ts +1181 -0
- package/generated/sentinel/subscription/v3/msg.ts +1305 -0
- package/generated/sentinel/subscription/v3/params.ts +167 -0
- package/generated/sentinel/subscription/v3/subscription.ts +315 -0
- package/generated/sentinel/types/v1/bandwidth.ts +124 -0
- package/generated/sentinel/types/v1/price.ts +149 -0
- package/generated/sentinel/types/v1/renewal.ts +87 -0
- package/generated/sentinel/types/v1/status.ts +54 -0
- package/generated/typeRegistry.ts +27 -0
- package/index.js +486 -0
- package/node-connect.js +3015 -0
- package/operator.js +134 -0
- package/package.json +113 -0
- package/plan-operations.js +199 -0
- package/preflight.js +352 -0
- package/pricing/index.js +262 -0
- package/proto/amino/amino.proto +84 -0
- package/proto/cosmos/base/v1beta1/coin.proto +61 -0
- package/proto/cosmos_proto/cosmos.proto +112 -0
- package/proto/gogoproto/gogo.proto +145 -0
- package/proto/google/api/annotations.proto +31 -0
- package/proto/google/api/http.proto +370 -0
- package/proto/google/protobuf/any.proto +106 -0
- package/proto/google/protobuf/duration.proto +115 -0
- package/proto/google/protobuf/timestamp.proto +145 -0
- package/proto/sentinel/lease/v1/events.proto +52 -0
- package/proto/sentinel/lease/v1/genesis.proto +15 -0
- package/proto/sentinel/lease/v1/lease.proto +25 -0
- package/proto/sentinel/lease/v1/msg.proto +62 -0
- package/proto/sentinel/lease/v1/params.proto +17 -0
- package/proto/sentinel/node/v3/events.proto +50 -0
- package/proto/sentinel/node/v3/genesis.proto +15 -0
- package/proto/sentinel/node/v3/msg.proto +63 -0
- package/proto/sentinel/node/v3/node.proto +27 -0
- package/proto/sentinel/node/v3/params.proto +21 -0
- package/proto/sentinel/node/v3/querier.proto +63 -0
- package/proto/sentinel/plan/v3/events.proto +41 -0
- package/proto/sentinel/plan/v3/genesis.proto +21 -0
- package/proto/sentinel/plan/v3/msg.proto +83 -0
- package/proto/sentinel/plan/v3/plan.proto +32 -0
- package/proto/sentinel/plan/v3/querier.proto +53 -0
- package/proto/sentinel/provider/v2/events.proto +16 -0
- package/proto/sentinel/provider/v2/genesis.proto +15 -0
- package/proto/sentinel/provider/v2/msg.proto +35 -0
- package/proto/sentinel/provider/v2/params.proto +17 -0
- package/proto/sentinel/provider/v2/provider.proto +24 -0
- package/proto/sentinel/provider/v3/genesis.proto +15 -0
- package/proto/sentinel/provider/v3/params.proto +13 -0
- package/proto/sentinel/session/v3/events.proto +30 -0
- package/proto/sentinel/session/v3/genesis.proto +15 -0
- package/proto/sentinel/session/v3/msg.proto +50 -0
- package/proto/sentinel/session/v3/params.proto +25 -0
- package/proto/sentinel/session/v3/proof.proto +25 -0
- package/proto/sentinel/session/v3/querier.proto +100 -0
- package/proto/sentinel/session/v3/session.proto +50 -0
- package/proto/sentinel/subscription/v2/allocation.proto +21 -0
- package/proto/sentinel/subscription/v2/payout.proto +22 -0
- package/proto/sentinel/subscription/v3/events.proto +65 -0
- package/proto/sentinel/subscription/v3/genesis.proto +17 -0
- package/proto/sentinel/subscription/v3/msg.proto +83 -0
- package/proto/sentinel/subscription/v3/params.proto +21 -0
- package/proto/sentinel/subscription/v3/subscription.proto +33 -0
- package/proto/sentinel/types/v1/bandwidth.proto +19 -0
- package/proto/sentinel/types/v1/price.proto +21 -0
- package/proto/sentinel/types/v1/renewal.proto +21 -0
- package/proto/sentinel/types/v1/status.proto +16 -0
- package/protocol/encoding.js +341 -0
- package/protocol/events.js +361 -0
- package/protocol/handshake.js +297 -0
- package/protocol/index.js +15 -0
- package/protocol/messages.js +346 -0
- package/protocol/plans.js +199 -0
- package/protocol/v2ray.js +268 -0
- package/protocol/v3.js +723 -0
- package/protocol/wireguard.js +125 -0
- package/security/index.js +132 -0
- package/session-manager.js +329 -0
- package/session-tracker.js +80 -0
- package/setup.js +376 -0
- package/speedtest/index.js +528 -0
- package/speedtest.js +567 -0
- package/src/client.ts +502 -0
- package/src/index.ts +20 -0
- package/state/index.js +347 -0
- package/state.js +516 -0
- package/test-all-chain-ops.js +493 -0
- package/test-all-logic.js +199 -0
- package/test-all-msg-types.js +292 -0
- package/test-every-connection.js +208 -0
- package/test-feegrant-connect.js +98 -0
- package/test-logic.js +148 -0
- package/test-mainnet.js +176 -0
- package/test-plan-lifecycle.js +335 -0
- package/tls-trust.js +132 -0
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +34 -0
- package/types/chain.d.ts +746 -0
- package/types/connection.d.ts +425 -0
- package/types/errors.d.ts +174 -0
- package/types/index.d.ts +1380 -0
- package/types/nodes.d.ts +187 -0
- package/types/pricing.d.ts +156 -0
- package/types/protocol.d.ts +332 -0
- package/types/session.d.ts +236 -0
- package/types/settings.d.ts +192 -0
- package/v3protocol.js +1053 -0
- package/wallet/index.js +153 -0
- package/wireguard.js +307 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
# Sentinel AI Path — Operational Checklists
|
|
2
|
+
|
|
3
|
+
> **For AI agents.** Run these checklists programmatically before, during, and after VPN operations. Every check includes the exact code, expected result, and failure response. Assume the wallet has sufficient P2P for bandwidth consumption.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## How to Use
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
import {
|
|
11
|
+
setup, getEnvironment, createWallet, importWallet, getBalance,
|
|
12
|
+
discoverNodes, getNodeInfo, getNetworkStats,
|
|
13
|
+
estimateCost, PRICING, recommend,
|
|
14
|
+
connect, disconnect, status, isVpnActive, verify, onEvent,
|
|
15
|
+
} from './index.js'; // or 'sentinel-ai-connect' when published to npm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Each checklist item has:
|
|
19
|
+
- **Check**: what to verify
|
|
20
|
+
- **Code**: exact call
|
|
21
|
+
- **Pass**: expected result
|
|
22
|
+
- **Fail**: what the failure means and what to do
|
|
23
|
+
|
|
24
|
+
Run all checks in order. Stop at the first `CRITICAL` failure. `WARNING` items can be bypassed with degraded capability.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Checklist 1: Pre-Flight (Before Any Connection)
|
|
29
|
+
|
|
30
|
+
Run once per session. Verifies the machine can operate.
|
|
31
|
+
|
|
32
|
+
### 1.1 Node.js Version
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const [major] = process.versions.node.split('.').map(Number);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| | |
|
|
39
|
+
|---|---|
|
|
40
|
+
| **Pass** | `major >= 20` |
|
|
41
|
+
| **Fail** | CRITICAL. Node.js 20+ required for stable ESM, `crypto.randomUUID`, and `AbortSignal.timeout`. Upgrade Node.js. |
|
|
42
|
+
|
|
43
|
+
### 1.2 Environment Detection
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
const env = getEnvironment();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| Check | Pass | Fail |
|
|
50
|
+
|-------|------|------|
|
|
51
|
+
| `env.v2ray.available` | `true` | WARNING. Run `setup()` to download V2Ray 5.2.1. Without V2Ray, only WireGuard nodes work. |
|
|
52
|
+
| `env.v2ray.version` | Starts with `'5.2'` | WARNING. V2Ray 5.44.1+ has observatory bugs that break VMess. Delete and redownload 5.2.1. |
|
|
53
|
+
| `env.wireguard.available` | `true` | WARNING. WireGuard not installed. Limited to V2Ray nodes (~70% of network). |
|
|
54
|
+
| `env.admin` | `true` | WARNING. Not admin. WireGuard tunnel installation will be blocked. V2Ray still works. |
|
|
55
|
+
| `env.capabilities.length` | `> 0` | CRITICAL. No tunnel protocol available. Install V2Ray or WireGuard before proceeding. |
|
|
56
|
+
|
|
57
|
+
### 1.3 Full System Check
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
const check = await setup();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Check | Pass | Fail |
|
|
64
|
+
|-------|------|------|
|
|
65
|
+
| `check.ready` | `true` | See `check.issues` array for specific problems. |
|
|
66
|
+
| `check.issues.length` | `0` | Review each issue: `issue.severity`, `issue.message`, `issue.action`. Fix `error` severity items. `warning` items are non-blocking. |
|
|
67
|
+
| `check.preflight.ok` | `true` | Preflight found blockers. Check `check.preflight.issues` for details. |
|
|
68
|
+
| `check.preflight.ready.anyProtocol` | `true` | CRITICAL. Neither WireGuard nor V2Ray is operational. |
|
|
69
|
+
|
|
70
|
+
### 1.4 Orphan Detection
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const pf = check.preflight;
|
|
74
|
+
const orphans = pf.issues.filter(i => i.component === 'wireguard' && i.message.includes('orphan'));
|
|
75
|
+
const conflicts = pf.issues.filter(i => i.component === 'system');
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
| Check | Pass | Fail |
|
|
79
|
+
|-------|------|------|
|
|
80
|
+
| `orphans.length` | `0` | WARNING. Leftover WireGuard tunnels from a previous crash. Run `setup()` with autoClean or manually uninstall: `wireguard.exe /uninstalltunnelservice wgsent0` |
|
|
81
|
+
| `conflicts.length` | `0` | WARNING. Conflicting VPN software detected (NordVPN, ExpressVPN, etc.). May interfere with tunnel routing. |
|
|
82
|
+
|
|
83
|
+
### 1.5 Axios Adapter
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const axios = (await import('axios')).default;
|
|
87
|
+
const adapterOk = axios.defaults.adapter === 'http';
|
|
88
|
+
if (!adapterOk) axios.defaults.adapter = 'http';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| Check | Pass | Fail |
|
|
92
|
+
|-------|------|------|
|
|
93
|
+
| Adapter is `'http'` | `true` | Auto-fixed above. Without this, Node.js 20+ uses fetch adapter which silently fails on self-signed node certificates. The `connect()` function handles this automatically, but verify if making direct SDK calls. |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Checklist 2: Wallet & Funding
|
|
98
|
+
|
|
99
|
+
Run before every connection attempt.
|
|
100
|
+
|
|
101
|
+
### 2.1 Wallet Valid
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
const bal = await getBalance(process.env.MNEMONIC);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Check | Pass | Fail |
|
|
108
|
+
|-------|------|------|
|
|
109
|
+
| No exception thrown | Call succeeds | CRITICAL. If `INVALID_MNEMONIC`: check word count (must be 12 or 24), check for typos, verify BIP39 English wordlist. If network error: LCD endpoints may be down — retry in 30s. |
|
|
110
|
+
| `bal.address` starts with `'sent1'` | `true` | CRITICAL. Wrong address prefix means wrong chain derivation. |
|
|
111
|
+
| `bal.address.length >= 43 && bal.address.length <= 46` | `true` | CRITICAL. Malformed address — expected 43-46 characters. |
|
|
112
|
+
|
|
113
|
+
### 2.2 Balance Sufficient
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
const { funded, udvpn, p2p } = bal;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Check | Pass | Fail |
|
|
120
|
+
|-------|------|------|
|
|
121
|
+
| `funded` | `true` | CRITICAL. Balance below 1.0 P2P. Fund wallet at `bal.address`. Prices vary — use `estimateCost()` to check if current balance covers at least one session. |
|
|
122
|
+
| `udvpn > 0` | `true` | CRITICAL. Wallet is empty. Send P2P tokens to `bal.address`. |
|
|
123
|
+
|
|
124
|
+
### 2.3 Cost Estimation
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
const cost = await estimateCost({ gigabytes: 1 });
|
|
128
|
+
const canAfford = bal.udvpn >= cost.grandTotal.udvpn;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
| Check | Pass | Fail |
|
|
132
|
+
|-------|------|------|
|
|
133
|
+
| `canAfford` | `true` | CRITICAL. Balance `${bal.p2p}` insufficient for 1 GB session costing ~`${cost.grandTotal.p2p}`. Fund wallet with at least `${cost.grandTotal.p2p}`. |
|
|
134
|
+
| `cost.mode` | Any value returned | If exception: network issue querying node prices. Proceed with `funded: true` as a fallback estimate. |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Checklist 3: Network Reachability
|
|
139
|
+
|
|
140
|
+
Run before connection to verify chain infrastructure is accessible.
|
|
141
|
+
|
|
142
|
+
### 3.1 LCD Endpoint
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const res = await fetch('https://lcd.sentinel.co/cosmos/bank/v1beta1/balances/' + bal.address, {
|
|
146
|
+
signal: AbortSignal.timeout(10000),
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
| Check | Pass | Fail |
|
|
151
|
+
|-------|------|------|
|
|
152
|
+
| `res.ok` | `true` | WARNING. Primary LCD down. The SDK has 4 failover endpoints and handles this automatically. If all 4 fail, check your internet connection. |
|
|
153
|
+
|
|
154
|
+
### 3.2 Node Discovery
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
const nodes = await discoverNodes({ quick: true });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| Check | Pass | Fail |
|
|
161
|
+
|-------|------|------|
|
|
162
|
+
| `nodes.length > 0` | `true` | CRITICAL. Zero nodes returned. Chain may be down or LCD endpoints unreachable. Retry in 60s. |
|
|
163
|
+
| `nodes.length > 100` | `true` | WARNING. Unusually few nodes. Possible pagination issue or chain maintenance. Connection may still work. |
|
|
164
|
+
|
|
165
|
+
### 3.3 Network Health
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
const stats = await getNetworkStats();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
| Check | Pass | Fail |
|
|
172
|
+
|-------|------|------|
|
|
173
|
+
| `stats.totalNodes > 0` | `true` | CRITICAL. Network appears empty. |
|
|
174
|
+
| `stats.byProtocol.v2ray > 0` or `stats.byProtocol.wireguard > 0` | At least one `> 0` | CRITICAL. No nodes available for any protocol. |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Checklist 4: Connection
|
|
179
|
+
|
|
180
|
+
Run during the `connect()` call. Use `onProgress` to track each phase.
|
|
181
|
+
|
|
182
|
+
### 4.1 Progress Monitoring
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
const phases = new Set();
|
|
186
|
+
let lastPhase = null;
|
|
187
|
+
let lastError = null;
|
|
188
|
+
|
|
189
|
+
const vpn = await connect({
|
|
190
|
+
mnemonic: process.env.MNEMONIC,
|
|
191
|
+
// fullTunnel: true (default) for privacy, or protocol: 'v2ray' for per-app split tunnel
|
|
192
|
+
onProgress: (step, detail) => {
|
|
193
|
+
phases.add(step);
|
|
194
|
+
lastPhase = step;
|
|
195
|
+
// Log for diagnostics: console.log(`[${step}] ${detail}`);
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 4.2 Phase Completion Verification
|
|
201
|
+
|
|
202
|
+
After `connect()` returns successfully, verify all critical phases were reached:
|
|
203
|
+
|
|
204
|
+
| Phase | Expected in `phases` | If Missing |
|
|
205
|
+
|-------|---------------------|------------|
|
|
206
|
+
| `'wallet'` | Yes | CRITICAL. Wallet derivation never started. Check mnemonic. |
|
|
207
|
+
| `'session'` | Yes | CRITICAL. Node selection or payment never started. Check balance, check node availability. |
|
|
208
|
+
| `'handshake'` | Yes | CRITICAL. Handshake phase never reached. Payment may have failed — check `lastError`. Session may exist on-chain (tokens spent). |
|
|
209
|
+
| `'tunnel'` | Yes | CRITICAL. Tunnel installation never started. Handshake may have failed. |
|
|
210
|
+
| `'verify'` | Yes | WARNING. Verification phase was skipped. Tunnel may still work — proceed to manual verification (Checklist 5). |
|
|
211
|
+
|
|
212
|
+
### 4.3 Connect Result Validation
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
const { sessionId, protocol, nodeAddress, socksPort, ip } = vpn;
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
| Check | Pass | Fail |
|
|
219
|
+
|-------|------|------|
|
|
220
|
+
| `sessionId` defined and non-empty | `true` | CRITICAL. No session ID means the blockchain TX may have failed. Check wallet balance — if it decreased, the session exists but ID extraction failed. |
|
|
221
|
+
| `protocol` is `'wireguard'` or `'v2ray'` | `true` | WARNING. Unknown protocol `'${protocol}'`. Connection may still work. |
|
|
222
|
+
| `nodeAddress` starts with `'sentnode1'` | `true` | WARNING. Node address missing or malformed. Connection may still work if sessionId is valid. |
|
|
223
|
+
| If V2Ray: `socksPort` is a number > 0 | `true` | WARNING. No SOCKS5 port. V2Ray may not be routing traffic. Verify manually. |
|
|
224
|
+
| `ip !== null` | `true` | WARNING. IP verification failed (ipify.org may be unreachable through this node). Tunnel may still work. Run Checklist 5 to confirm. |
|
|
225
|
+
| `ip !== yourOriginalIp` | `true` | WARNING. IP didn't change. Possible split tunnel mode or full tunnel not installed. May be expected if `fullTunnel: false`. |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Checklist 5: Post-Connection Verification
|
|
230
|
+
|
|
231
|
+
Run immediately after `connect()` succeeds. Confirms the tunnel is actually working.
|
|
232
|
+
|
|
233
|
+
### 5.1 Connection State
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
const active = isVpnActive();
|
|
237
|
+
const st = status();
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
| Check | Pass | Fail |
|
|
241
|
+
|-------|------|------|
|
|
242
|
+
| `active` | `true` | CRITICAL. `isVpnActive()` returns false immediately after connect. Tunnel may have collapsed. Disconnect and retry with a different node. |
|
|
243
|
+
| `st.connected` | `true` | CRITICAL. Same as above — status shows disconnected. |
|
|
244
|
+
| `st.sessionId` matches `vpn.sessionId` | `true` | WARNING. Session ID mismatch. State may be stale. |
|
|
245
|
+
| `st.protocol` matches `vpn.protocol` | `true` | WARNING. Protocol mismatch. Likely a state tracking issue — tunnel may still work. |
|
|
246
|
+
|
|
247
|
+
### 5.2 Traffic Verification
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
const v = await verify();
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
| Check | Pass | Fail |
|
|
254
|
+
|-------|------|------|
|
|
255
|
+
| `v.connected` | `true` | CRITICAL. Tunnel down during verification. |
|
|
256
|
+
| `v.verified` | `true` | CRITICAL. Cannot confirm traffic flows through the tunnel. The tunnel may be installed but not routing. Disconnect and try a different node. |
|
|
257
|
+
| `v.ip !== null` | `true` | WARNING. IP check failed but `verified` may still be true from SDK verification. If both `ip === null` and `verified === false`, the tunnel is dead. |
|
|
258
|
+
|
|
259
|
+
### 5.3 Data Transfer Test
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
let testRes;
|
|
263
|
+
if (vpn.socksPort) {
|
|
264
|
+
// V2Ray: test through SOCKS5 proxy
|
|
265
|
+
const axios = (await import('axios')).default;
|
|
266
|
+
const { SocksProxyAgent } = await import('socks-proxy-agent');
|
|
267
|
+
const agent = new SocksProxyAgent(`socks5h://127.0.0.1:${vpn.socksPort}`);
|
|
268
|
+
testRes = await axios.get('https://api.ipify.org?format=json', {
|
|
269
|
+
httpAgent: agent, httpsAgent: agent, timeout: 15000, adapter: 'http',
|
|
270
|
+
});
|
|
271
|
+
} else {
|
|
272
|
+
// WireGuard: traffic routes automatically through the tunnel
|
|
273
|
+
const axios = (await import('axios')).default;
|
|
274
|
+
testRes = await axios.get('https://api.ipify.org?format=json', {
|
|
275
|
+
timeout: 15000, adapter: 'http',
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
| Check | Pass | Fail |
|
|
281
|
+
|-------|------|------|
|
|
282
|
+
| Response received within timeout | `true` | WARNING. Tunnel may be slow or congested. Increase timeout to 30s and retry once. If still fails, try a different node. |
|
|
283
|
+
| `testRes.data.ip` is not your real IP | `true` | CRITICAL (WireGuard full tunnel). Traffic is not routing through the VPN. NORMAL (V2Ray split tunnel) — only SOCKS5-proxied traffic routes through the tunnel. |
|
|
284
|
+
| `testRes.status === 200` | `true` | WARNING. Non-200 response. The test endpoint may be down. Try `https://ifconfig.me` as fallback. |
|
|
285
|
+
|
|
286
|
+
### 5.4 DNS Leak Check
|
|
287
|
+
|
|
288
|
+
```javascript
|
|
289
|
+
// Verify DNS resolves through the tunnel, not your ISP
|
|
290
|
+
const dnsRes = await axios.get('https://1.1.1.1/cdn-cgi/trace', {
|
|
291
|
+
httpAgent: agent, httpsAgent: agent, timeout: 10000, adapter: 'http', // V2Ray
|
|
292
|
+
// For WireGuard: omit agents, DNS is enforced by tunnel config
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Check | Pass | Fail |
|
|
297
|
+
|-------|------|------|
|
|
298
|
+
| Response received | `true` | WARNING. Cloudflare trace endpoint unreachable. DNS may still be correct — this is a secondary check. |
|
|
299
|
+
| Response does not contain your real ISP IP | `true` | WARNING. Possible DNS leak. If using WireGuard, check that `DNS = 10.8.0.1` is in the config. If using V2Ray, verify SOCKS5 proxy is routing DNS queries. |
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Checklist 6: Runtime Health Monitoring
|
|
304
|
+
|
|
305
|
+
Run periodically while connected (every 30-60 seconds).
|
|
306
|
+
|
|
307
|
+
### 6.1 Connection Still Active
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
const alive = isVpnActive();
|
|
311
|
+
const st = status();
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
| Check | Pass | Fail |
|
|
315
|
+
|-------|------|------|
|
|
316
|
+
| `alive` | `true` | CRITICAL. Connection lost. Begin reconnection (Checklist 8). |
|
|
317
|
+
| `st.connected` | `true` | CRITICAL. Same — status shows disconnected. |
|
|
318
|
+
| `st.uptimeMs > previousUptimeMs` | `true` | WARNING. Uptime not advancing. State may be stale. Verify with `verify()`. |
|
|
319
|
+
|
|
320
|
+
### 6.2 Traffic Still Flows
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
const v = await verify();
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
| Check | Pass | Fail |
|
|
327
|
+
|-------|------|------|
|
|
328
|
+
| `v.verified` | `true` | CRITICAL. Tunnel is up but traffic has stopped flowing. Disconnect and reconnect. |
|
|
329
|
+
| Time since last successful verify < 120s | `true` | WARNING. Verification hasn't succeeded in 2+ minutes. Network may be degrading. |
|
|
330
|
+
|
|
331
|
+
### 6.3 Balance Monitor (Every 5 Minutes)
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
const bal = await getBalance(process.env.MNEMONIC);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
| Check | Pass | Fail |
|
|
338
|
+
|-------|------|------|
|
|
339
|
+
| `bal.funded` | `true` | WARNING. Balance dropping below threshold. Plan for disconnection or top-up. Session continues until data allocation is consumed, but new sessions cannot be created. |
|
|
340
|
+
| `bal.udvpn > previousBalance - expectedConsumption` | `true` | INFO. Track spend rate. If balance is dropping faster than expected, session may have an issue. |
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Checklist 7: Disconnection
|
|
345
|
+
|
|
346
|
+
Run when work is complete or on shutdown.
|
|
347
|
+
|
|
348
|
+
### 7.1 Graceful Disconnect
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
const result = await disconnect();
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
| Check | Pass | Fail |
|
|
355
|
+
|-------|------|------|
|
|
356
|
+
| `result.disconnected` | `true` | WARNING. Disconnect reported failure, but tunnel is likely down. Proceed to verification. |
|
|
357
|
+
| No exception thrown | `true` | WARNING. Best-effort — the tunnel was probably torn down. Continue to post-disconnect verification. |
|
|
358
|
+
|
|
359
|
+
### 7.2 Post-Disconnect Verification
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
const active = isVpnActive();
|
|
363
|
+
const st = status();
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
| Check | Pass | Fail |
|
|
367
|
+
|-------|------|------|
|
|
368
|
+
| `active` | `false` | CRITICAL. Tunnel still active after disconnect. Orphaned tunnel. Attempt: `await disconnect()` again. If still active, escalate to manual cleanup (7.3). |
|
|
369
|
+
| `st.connected` | `false` | CRITICAL. Same — state still shows connected. |
|
|
370
|
+
|
|
371
|
+
### 7.3 Orphan Cleanup (If 7.2 Fails)
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
import { emergencyCleanupSync } from 'sentinel-dvpn-sdk';
|
|
375
|
+
emergencyCleanupSync();
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
| Check | Pass | Fail |
|
|
379
|
+
|-------|------|------|
|
|
380
|
+
| After cleanup: `isVpnActive() === false` | `true` | CRITICAL. Orphaned tunnel survived emergency cleanup. Manual intervention required: `wireguard.exe /uninstalltunnelservice wgsent0` (WireGuard) or kill V2Ray process by PID (NOT `taskkill /F /IM node.exe` — that kills your own process). |
|
|
381
|
+
|
|
382
|
+
### 7.4 System State Clean
|
|
383
|
+
|
|
384
|
+
```javascript
|
|
385
|
+
// Verify no system proxy left behind (V2Ray)
|
|
386
|
+
// On Windows, check registry or run:
|
|
387
|
+
// netsh winhttp show proxy
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
| Check | Pass | Fail |
|
|
391
|
+
|-------|------|------|
|
|
392
|
+
| No system proxy pointing to dead SOCKS5 port | `true` | WARNING. Orphaned system proxy will break system HTTP traffic. Clear it: `netsh winhttp reset proxy` |
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Checklist 8: Error Recovery
|
|
397
|
+
|
|
398
|
+
Run when any connection attempt fails or when runtime health check fails.
|
|
399
|
+
|
|
400
|
+
### 8.1 Classify the Error
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
try {
|
|
404
|
+
await connect(opts);
|
|
405
|
+
} catch (err) {
|
|
406
|
+
const code = err.code || 'UNKNOWN';
|
|
407
|
+
const msg = err.message;
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
| Error Code | Severity | Recovery Action |
|
|
412
|
+
|------------|----------|----------------|
|
|
413
|
+
| `INVALID_MNEMONIC` | Fatal | Fix mnemonic. Do not retry. |
|
|
414
|
+
| `INSUFFICIENT_BALANCE` | Fatal | Fund wallet. Do not retry until funded. |
|
|
415
|
+
| `ALREADY_CONNECTED` | Fatal | Call `disconnect()` first, then retry. |
|
|
416
|
+
| `ABORTED` | Fatal | Timeout or cancellation. Increase `timeout` or check network. |
|
|
417
|
+
| `SESSION_POISONED` | Fatal | Previous session is corrupted. Do not reuse. Fresh connection needed. |
|
|
418
|
+
| `NODE_OFFLINE` | Retryable | Try a different node. |
|
|
419
|
+
| `NODE_CLOCK_DRIFT` | Retryable | Skip this node. Try another. |
|
|
420
|
+
| `V2RAY_ALL_FAILED` | Retryable | All transports failed. Try a WireGuard node or different V2Ray node. |
|
|
421
|
+
| `WG_NO_CONNECTIVITY` | Retryable | Tunnel installed but dead. Try a different node. |
|
|
422
|
+
| `BROADCAST_FAILED` | Retryable | Chain TX failed. Wait 30s, retry. |
|
|
423
|
+
| `ALL_NODES_FAILED` | Retryable | Every candidate failed. Wait 60s, retry with different country or protocol. |
|
|
424
|
+
| `ALL_ENDPOINTS_FAILED` | Retryable | LCD/RPC all down. Check internet. Wait 60s, retry. |
|
|
425
|
+
| `V2RAY_NOT_FOUND` | Setup | Run `setup()` to install V2Ray binary. |
|
|
426
|
+
| `WG_NOT_AVAILABLE` | Setup | Install WireGuard or retry with `protocol: 'v2ray'`. |
|
|
427
|
+
| `SESSION_EXISTS` | Recoverable | Active session found. SDK reuses it automatically. If it keeps failing, wait for session expiry. |
|
|
428
|
+
| `PARTIAL_CONNECTION_FAILED` | Recoverable | Payment succeeded but tunnel failed. Session exists on-chain. Retry connection to same node — session will be reused (no double payment). |
|
|
429
|
+
|
|
430
|
+
### 8.2 Retry Strategy
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
const MAX_RETRIES = 3;
|
|
434
|
+
const BACKOFF = [5000, 10000, 20000]; // ms
|
|
435
|
+
|
|
436
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
437
|
+
try {
|
|
438
|
+
const vpn = await connect(opts);
|
|
439
|
+
// Run Checklist 4 + 5
|
|
440
|
+
break; // Success
|
|
441
|
+
} catch (err) {
|
|
442
|
+
if (['INVALID_MNEMONIC', 'INSUFFICIENT_BALANCE', 'ABORTED'].includes(err.code)) {
|
|
443
|
+
throw err; // Fatal — do not retry
|
|
444
|
+
}
|
|
445
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
446
|
+
await new Promise(r => setTimeout(r, BACKOFF[attempt]));
|
|
447
|
+
} else {
|
|
448
|
+
throw err; // Exhausted retries
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### 8.3 Post-Failure Cleanup
|
|
455
|
+
|
|
456
|
+
After any failed connection attempt:
|
|
457
|
+
|
|
458
|
+
```javascript
|
|
459
|
+
// Always verify no orphaned state
|
|
460
|
+
try { await disconnect(); } catch { /* best effort */ }
|
|
461
|
+
const stillActive = isVpnActive();
|
|
462
|
+
if (stillActive) {
|
|
463
|
+
const { emergencyCleanupSync } = await import('sentinel-dvpn-sdk');
|
|
464
|
+
emergencyCleanupSync();
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
| Check | Pass | Fail |
|
|
469
|
+
|-------|------|------|
|
|
470
|
+
| `isVpnActive() === false` after cleanup | `true` | Orphaned tunnel exists. See Checklist 7.3. |
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Checklist 9: Full End-to-End Validation
|
|
475
|
+
|
|
476
|
+
Run this as a single script to verify the entire pipeline works. This is the definitive test.
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
// Load mnemonic from .env (use dotenv or manual parsing)
|
|
480
|
+
// import 'dotenv/config'; // Requires: npm install dotenv
|
|
481
|
+
import {
|
|
482
|
+
setup, getEnvironment, getBalance, estimateCost, recommend,
|
|
483
|
+
connect, disconnect, status, isVpnActive, verify,
|
|
484
|
+
} from './index.js'; // or 'sentinel-ai-connect' when published to npm
|
|
485
|
+
|
|
486
|
+
const results = {
|
|
487
|
+
preflight: false,
|
|
488
|
+
wallet: false,
|
|
489
|
+
balance: false,
|
|
490
|
+
costEstimate: false,
|
|
491
|
+
recommendation: false,
|
|
492
|
+
connection: false,
|
|
493
|
+
stateConsistent: false,
|
|
494
|
+
trafficVerified: false,
|
|
495
|
+
disconnection: false,
|
|
496
|
+
cleanState: false,
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
// ── Preflight ──
|
|
501
|
+
const env = getEnvironment();
|
|
502
|
+
if (env.capabilities.length === 0) throw new Error('No tunnel protocol available');
|
|
503
|
+
const check = await setup();
|
|
504
|
+
if (!check.ready) throw new Error(`Setup issues: ${check.issues.join(', ')}`);
|
|
505
|
+
results.preflight = true;
|
|
506
|
+
|
|
507
|
+
// ── Wallet ──
|
|
508
|
+
const bal = await getBalance(process.env.MNEMONIC);
|
|
509
|
+
if (!bal.address.startsWith('sent1')) throw new Error('Bad address');
|
|
510
|
+
results.wallet = true;
|
|
511
|
+
|
|
512
|
+
// ── Balance ──
|
|
513
|
+
if (!bal.funded) throw new Error(`Underfunded: ${bal.p2p}`);
|
|
514
|
+
results.balance = true;
|
|
515
|
+
|
|
516
|
+
// ── Cost Estimate ──
|
|
517
|
+
const cost = await estimateCost({ gigabytes: 1 });
|
|
518
|
+
if (bal.udvpn < cost.grandTotal.udvpn) throw new Error(`Need ${cost.grandTotal.p2p}, have ${bal.p2p}`);
|
|
519
|
+
results.costEstimate = true;
|
|
520
|
+
|
|
521
|
+
// ── Recommendation ──
|
|
522
|
+
const rec = await recommend({ priority: 'reliability' });
|
|
523
|
+
if (rec.action === 'cannot-connect') throw new Error('No nodes available');
|
|
524
|
+
results.recommendation = true;
|
|
525
|
+
|
|
526
|
+
// ── Connection ──
|
|
527
|
+
const phases = new Set();
|
|
528
|
+
const vpn = await connect({
|
|
529
|
+
mnemonic: process.env.MNEMONIC,
|
|
530
|
+
fullTunnel: false,
|
|
531
|
+
onProgress: (step) => phases.add(step),
|
|
532
|
+
timeout: 120000,
|
|
533
|
+
});
|
|
534
|
+
if (!vpn.sessionId) throw new Error('No session ID');
|
|
535
|
+
if (!phases.has('wallet')) throw new Error('Wallet phase missing');
|
|
536
|
+
if (!phases.has('session')) throw new Error('Session phase missing');
|
|
537
|
+
if (!phases.has('handshake')) throw new Error('Handshake phase missing');
|
|
538
|
+
if (!phases.has('tunnel')) throw new Error('Tunnel phase missing');
|
|
539
|
+
results.connection = true;
|
|
540
|
+
|
|
541
|
+
// ── State Consistency ──
|
|
542
|
+
const st = status();
|
|
543
|
+
if (!st.connected) throw new Error('Status says disconnected after connect');
|
|
544
|
+
if (!isVpnActive()) throw new Error('isVpnActive false after connect');
|
|
545
|
+
if (st.sessionId !== vpn.sessionId) throw new Error('Session ID mismatch');
|
|
546
|
+
results.stateConsistent = true;
|
|
547
|
+
|
|
548
|
+
// ── Traffic Verification ──
|
|
549
|
+
const v = await verify();
|
|
550
|
+
if (!v.verified) throw new Error('Traffic verification failed');
|
|
551
|
+
results.trafficVerified = true;
|
|
552
|
+
|
|
553
|
+
// ── Disconnection ──
|
|
554
|
+
await disconnect();
|
|
555
|
+
results.disconnection = true;
|
|
556
|
+
|
|
557
|
+
// ── Clean State ──
|
|
558
|
+
if (isVpnActive()) throw new Error('Still active after disconnect');
|
|
559
|
+
if (status().connected) throw new Error('Status still connected after disconnect');
|
|
560
|
+
results.cleanState = true;
|
|
561
|
+
|
|
562
|
+
} catch (err) {
|
|
563
|
+
console.error(`FAILED: ${err.message} (code: ${err.code || 'none'})`);
|
|
564
|
+
} finally {
|
|
565
|
+
// Ensure cleanup even on failure
|
|
566
|
+
try { await disconnect(); } catch {}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// ── Report ──
|
|
570
|
+
console.log('\n═══ End-to-End Checklist Results ═══');
|
|
571
|
+
const entries = Object.entries(results);
|
|
572
|
+
const passed = entries.filter(([, v]) => v).length;
|
|
573
|
+
const total = entries.length;
|
|
574
|
+
|
|
575
|
+
for (const [name, ok] of entries) {
|
|
576
|
+
console.log(` ${ok ? 'PASS' : 'FAIL'} ${name}`);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
console.log(`\n ${passed}/${total} checks passed.`);
|
|
580
|
+
if (passed === total) {
|
|
581
|
+
console.log(' All systems operational. AI Path is fully functional.');
|
|
582
|
+
} else {
|
|
583
|
+
const firstFail = entries.find(([, v]) => !v)?.[0];
|
|
584
|
+
console.log(` First failure: ${firstFail}. Fix this before retrying.`);
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Expected Output (All Pass)
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
═══ End-to-End Checklist Results ═══
|
|
592
|
+
PASS preflight
|
|
593
|
+
PASS wallet
|
|
594
|
+
PASS balance
|
|
595
|
+
PASS costEstimate
|
|
596
|
+
PASS recommendation
|
|
597
|
+
PASS connection
|
|
598
|
+
PASS stateConsistent
|
|
599
|
+
PASS trafficVerified
|
|
600
|
+
PASS disconnection
|
|
601
|
+
PASS cleanState
|
|
602
|
+
|
|
603
|
+
10/10 checks passed.
|
|
604
|
+
All systems operational. AI Path is fully functional.
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Quick Reference: Which Checklist When
|
|
610
|
+
|
|
611
|
+
| Situation | Run |
|
|
612
|
+
|-----------|-----|
|
|
613
|
+
| First time using AI Path | Checklist 1 (preflight) → 2 (wallet) → 3 (network) → 9 (full E2E) |
|
|
614
|
+
| Before each connection | Checklist 2.2 (balance) → 4 (connection) → 5 (post-connect) |
|
|
615
|
+
| While connected (every 30-60s) | Checklist 6 (health) |
|
|
616
|
+
| Connection fails | Checklist 8 (error recovery) |
|
|
617
|
+
| Shutting down | Checklist 7 (disconnection) |
|
|
618
|
+
| After crash or unexpected restart | Checklist 1.4 (orphan detection) → 7.3 (orphan cleanup) |
|
|
619
|
+
| Validating a new environment | Checklist 9 (full E2E) |
|