feat(client): host auto-discovery and proofed routing - #75
Open
Florious95 wants to merge 23 commits into
Open
Conversation
added 18 commits
September 5, 2026 13:52
Log http_code/body_len/parse/host_id/bound/mac match booleans, generation deadline/cancel, Proven, offer/emitted, transport.create, AuthFrame/READY. No token or MAC values. Behavior unchanged.
Okio readByteArray(1025) throws EOFException on short /pair/identify JSON, so the App mapped server HTTP 200 to 599 and never proved or created WS. Cap with request(1025) then read remaining bytes. Regression talks to a real short JSON responder on a literal LAN IPv4.
This was referenced Sep 5, 2026
added 2 commits
September 6, 2026 00:07
Refs #79. Current pairing save() writes schema_version=2. Tests that omit it look like v1 prefs, so load() synthesizes legacyBootstrapUrl and the identify coordinator never create()s the JVM fake transport.
Refs #79. URL-only (no host coordinator) tailnet targets must not dial before Up/Error; Starting direct-dial can stick in RECONNECTING without a clock pump. HostId records still let the coordinator own LAN/TS timing.
added 2 commits
September 6, 2026 02:01
Issue 82: HostDialCoordinator.onReady cancels the round, so a later non-permanent peer close must not stay on a dead READY socket.
HostDialCoordinator.onReady cancels the round. A later non-permanent close must scheduleReconnect (new identify generation) instead of onTargetFailed, which is a no-op once round is null. Pre-READY still advances the next proven target. Refs #82
Unbound installs have no pairing record and never start a manager, so the default CONNECTING workspace stayed on 连接中/正在连接主机. Keep configured cold start on CONNECTING. Refs #83
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
Implement the client side of bounded host auto-discovery from literal host records, NSD, and typed tsnet peers, proving an endpoint before WebSocket auth. This PR is based on frozen
eaaa7d47d88e7e2de6c82988fe462e7adf29f86dand targetspr/foreground-resume-refresh; it does not touchserver/**, merge, release, deploy, or pushmain.Changes
/pair/whoamiand HMAC-bound/pair/identifyseams, bounded discovery, proof-before-WS pairing, legacy exact-404 compatibility, and deterministic candidate proof before fallback dialing.PeerSnapshot(knownId,cursor)), with complete-table known-ID lookup and non-overlapping 256-row cursor pages; add Go behavior coverage for 9/33/>256 fairness.HostIdentityVerifiertest seam; production remainsHostIdentifyClientwith literal-IP/no-DNS/no-redirect guards.Validation (Grok Bot)
381281b194bf663b92618c99d37f297d866b9164.cd tools/tsnetbind && go test -count=1 -v ./...: PASS, 1 package / 5 tests, 0 failures, 1191 ms;/workspace/host-discovery-android-runner/logs/go-test-381281b1.log.ANDROID_HOME=/home/box/Android/Sdk ANDROID_NDK_HOME=/home/box/Android/Sdk/ndk/27.2.12479018 bash tools/tsnetbind/build.sh: PASS for Go source revision13f8b2f31da381a4bfcbefb21dd11dd13143f29e; artifact Git commit51d4a08fe8e90d3e13bcf72fd619ee7a1538552d; AAR SHA-2561bd5f924c1d53f477d33eee0a6c6b9d14a15786b7032e281f52b711cf2222dd7(7,974,616 bytes), sources JAR SHA-2566df63e789abd537912473def74b93d4af2eb164ac23f4b7abd29f069b5a13a0e(8,986 bytes);/workspace/host-discovery-android-runner/logs/aar-13f8b2f3.log.libgojni.soLOAD segments all reportp_align=0x4000; verification receipt is in the evidence file../gradlew --rerun-tasks -Pkotlin.compiler.execution.strategy=in-process :app:compileDebugKotlin: PASS, 23 tasks, 32,577 ms;/workspace/host-discovery-android-runner/logs/compile-381281b1-final.log.--rerun-tasksand-Pkotlin.compiler.execution.strategy=in-process: PASS, apptestDebugUnitTest171 tests / 0 failures pluscore-conn:test3 tests / 0 failures, 60,548 ms;/workspace/host-discovery-android-runner/logs/inner-381281b1.log. Exact filters and class set are recorded inEVIDENCE.md.Risk / boundary
This is source/AAR/inner-JVM validation only. No device, NSD hardware path, real tailnet, paired server/client acceptance, instrumentation, performance A/B, signing, install-over, production process, or credential access is claimed. Architecture tooling remains unknown because its declared directory is absent. Final paired/device/performance acceptance remains a follow-up after both endpoint implementations are available.
Repair (identify HTTP 200 → WS READY) — execution evidence, not independent acceptance
Goal. After HTTP 200
/pair/identify, the App mustHostIdentifyResult.Proven→ onetransport.create→ AuthFrame → READY. Do not treat server 200 or a host Python replica as App Proven.Root cause (device DiagLog, not guess).
OkHttpHostHttpTransport.executecalled OkioreadByteArray(1025). Real identify JSON is ~163–177 bytes, so Okio threwEOFException. The App loggedhttp_code=599 body_len=0 verdict=Rejected reason=identify rejected proved=0, exhausted the generation, and neverconnectTarget. Fixture/Darwin still saw HTTP 200. Probe SHAae5e125dda43876891b8c94560c28195439c9108.Fix.
request(1025)then read remaining bytes; oversized bodies still fail closed. Common path only (OkHttpHostHttpTransport.execute). No HMAC/LocalAddr/host_id/nonce relaxation, no Proxy.NO_PROXY change. Fix SHA1c9ed5d977a17f0d1ff0314340a030da8d9f2085onpr/host-auto-discovery-client.Tests (Grok Bot,
--rerun-tasks, in-process Kotlin). pairingtestDebugUnitTest67 / 0 fail includingOkHttpHostIdentifyBodyCapTest;core-conn:test3 / 0 fail. Full:app:testDebugUnitTest654 with 11 fails is not claimed as 171-green: failures are RemapThroughputTest (host path), ColdStartReconnectTest, ForegroundServiceWiringTest, DiagLogExportDirBoundedTest — outside this inner loop / environment. Original owning 171 list was not re-run as that exact filter.Device (own
emulator-5590, synthetic fixture:8765and isolated Darwin:19918). Before: EOF 599, WS=0. After: Proven +connectTarget create=true+auth_frame+auth_ack ok=true ready=trueon both handlers. DESIGN 17OK (17 tests)52.91s. Foreground: READY chrome 会话/设置/收藏, resume/rapid keep 会话, MISS 重连中; 快捷键/查看 MISS because discovery allowlist empty (前置未满足). AAR unchanged1bd5f924c1d53f477d33eee0a6c6b9d14a15786b7032e281f52b711cf2222dd7. Debug APK sha256d7e379289422c2e05f11ea88b753c32af85c01487d19ae90e41be1dd9451290a(40474947 bytes) from source1c9ed5d.This is owning-PR execution evidence. It is not a seal / independent acceptance PASS.
Issue 79 (cold-start / foreground gate)
#79 — not closed.
Two roots, not nine product bugs:
seedConfigomittedschema_version=2, soload()treated prefs as v1 and turned on the identify coordinator. JVM fake transport nevercreate()d. Current pairingsave()writes schema 2. Tests now seed schema 2; user assertion unchanged (one connection on paired cold start).whenSettled+ start generation only when no host coordinator. HostId records still let the coordinator own LAN/TS timing. R2 key staging unchanged.HEAD
72117404cc1c7624d474dfb92466d30fc24f34ee. Full:app:testDebugUnitTest655 / 1 fail (RemapThroughputTestIssue 81 only). The nine Issue 79 names executed and passed. Issue 80/81 not fixed. EOF body-cap not reverted. Execution evidence, not independent acceptance.Issue 82 (READY drop reconnect) — retained, not re-fixed here
#82 — not closed. Owning fix remains
f53f91b6a3ac188b5cb84875f8510f6592b3af43. This Issue 83 commit re-ranCoordinatorReadyDropReconnectTest(4) andForegroundResumeTest(4): 0 failures. Independent acceptance PASS on f53 is not overwritten.Issue 83 (unbound skip → quiet empty workspace)
#83 — still OPEN. Not merged, not signed, not performance-gated.
Goal. New install /
pm clearwith no pairing record: tap 以后再说 must enter a quiet empty workspace, not endless 连接中 / 正在连接主机. Configured cold start must still dial. Healthy READY must not rebuild. Disconnect must still recover. Do not fake READY or relax identify.Root cause.
WorkspaceViewModeldefaulted toCONNECTING. Unbound skip never callsstartPersistentConnection, so no manager ever leaves CONNECTING.isLoadingstayed true (LoadingContent+ banner) andenterLevel1hungrefreshing. NSD is a separate apparatus gap.Fix. Unbound initial state is
ConnectionUi.UNBOUND(not READY, not STOPPED). Skip shows title + empty body, no spinner/copy. Configured cold start stillCONNECTINGand starts the manager. AAR unchanged.HEAD.
d99c02b15614691d56d013008d1410020bf20aa1onpr/host-auto-discovery-client. Base stilleaaa7d47. Ancestor of frozen f53.Tests (Grok Bot,
--rerun-tasks --no-build-cache, in-process Kotlin). START2026-09-05T19:21:20ZEND19:22:19Z, 59s, exit 0. XML 34 tests / 0 failures / 6 classes:WorkspaceViewModelTest12,WorkspaceUnboundSkipTest2,ColdStartReconnectTest9,CoordinatorReadyDropReconnectTest4,ForegroundResumeTest4,ConnReconnectPolicyTest3. Issue 80/81 not run, not claimed, not fixed. Performance not run.APK. debug
app-debug.apk40474947 B, SHA-25648e88183e64d8e47ebd7b157e08cc5e2937b05c0be1a95c2dc7f9dd3a7599471from sourced99c02b1. assembleDebug 35s, 44 executed, exit 0.Device (own
emulator-5572, AVDempty-ws-api35-20260906). Did not use 5580/5590/8876/8765/19928/19918 or production 9900/10361.c35e2aba…:pm clear, prefs absent, skip; after 15s still 连接中 / 正在连接主机; XML SHAebbdb3bf346d878db92c22abc8a15aef6817487459b2c529d46f325d0881a22amatches the Issue 83 field.48e88183…: same steps; quiet empty 工作区, no 连接中 / 正在连接主机 / 暂无工作区; XML SHA9e4745d324d5c30b3ff22982dfeb3d68fbf47f859cec7f39e24b3e04b491fa57stable across immediate and +15s.Execution evidence, not independent acceptance. Issue 80/81 remain FAIL. NSD discovery remains a separate case.