feat(truffle): connectMille and the reconnect facade#29
Merged
Conversation
Completes Phase 1's client half. connectMille dials, runs the open handshake, and returns a RemoteFileExplorer that owns one live session and swaps it underneath the caller on reconnect — an application holds the facade, so a dropped connection does not invalidate the reference it is using. Two behaviours are the point of the facade rather than incidental to it. A dropped connection leaves the last mirror snapshot readable through getSnapshot(). The user was looking at something; a stale tree beats a blank one. `remote.explorer` still throws while offline, so new work fails fast instead of hanging on a promise that will never settle. Mutations are never replayed. A write that did not return a result frame did not happen as far as the caller is concerned, and re-issuing it after a gap could duplicate a rename or clobber a file that changed in the interim. This is the one place where doing less is the correct behaviour. Backoff and retry policy live in state.ts as pure functions with an injected random, so the schedule is asserted directly rather than observed through a network. Jitter is clamped so a large value cannot push a retry past the ceiling. ACCESS_DENIED, PROTOCOL_MISMATCH and LIMIT_EXCEEDED are terminal: the answer will not change, and a client redialling a denial looks like a brute-force attempt to whoever reads the server's log. Reject codes are mapped explicitly rather than passed through. The server says why it refused; the client says what kind of failure this is. INVALID_REQUEST means *we* sent something malformed — a permanent protocol mismatch, not a transient fault, so treating it as retryable would loop on a bug forever. Reconnecting to a replaced host emits identityReset, because every EntryId the caller holds then refers to nothing, or worse to something else. Also bumps the Truffle peer/dev dependency to 0.7.8. The diff across packages/core/src, crates/truffle-napi/src and crates/truffle-core/src between 0.7.6 and 0.7.8 is empty — the release is Swift/SPM packaging and release plumbing — but the live probe was re-run against it regardless. And fixes Cargo.toml's repository URL, which pointed at github.com/jamesyong/file-explorer: a repository that never moved and 404s today, unlike the jamesyong-42 references that redirect. Verified across a real tailnet with both public APIs, not just the fake mesh: connect, browse, mutate, a read-only export refusing writes with EROFS, read-write on a read-only export refused outright, then the server killed and replaced mid-session — stale → reconnecting → online, exactly one identityReset, tree usable again. Thirteen checks. Suite green: mille 413, mille-truffle 30, mille-ui 470, playground 29. Claude-Session: https://claude.ai/code/session_01BxUdtf4tecfv4uLAqRa1CR
docs/api.html and docs/index.html still linked to jamesyong-42. Two kinds of breakage, only one of which the redirect covers. github.com/jamesyong-42/mille redirects to vibecook-dev, so those links worked. jamesyong-42.github.io/mille does not — GitHub Pages has no post-transfer redirect. It returns 404 while vibecook-dev.github.io/mille returns 200, so the "Docs site" link on the published site pointed at nothing. Checked both with curl rather than assuming they behaved the same way; an earlier note in this repo claimed all the stale references still resolved, which was true only of the github.com ones. Claude-Session: https://claude.ai/code/session_01BxUdtf4tecfv4uLAqRa1CR
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.
Summary
connectMilleand theRemoteFileExplorerfacade — spec §26 PR 5, completing Phase 1's client half. Owns one live session and swaps it underneath the caller on reconnect.state.tsas pure functions with injected randomness, so an unbounded loop or a wrongly-retried terminal error fails an assertion rather than needing a network to observe.packages/core/src,crates/truffle-napi/srcandcrates/truffle-core/srcbetween 0.7.6 and 0.7.8 is empty (Swift/SPM packaging and release plumbing), but the live probe was re-run against it anyway.mainstill had:Cargo.tomlpointed atjamesyong/file-explorer, a repo that never moved and 404s; and the docs site linked tojamesyong-42.github.io, which 404s because GitHub Pages has no post-transfer redirect (thegithub.comones do redirect, which is why this was missed).Test Plan
pnpm -r --if-present test— mille 413, mille-truffle 30, mille-ui 470, playground 29, allfail 0.pnpm -r --if-present typecheckclean.EROFS, read-write on a read-only export refused outright, then the server killed and replaced mid-session —stale → reconnecting → online, exactly oneidentityReset, tree usable again.prettier --checkclean on changed files (docs/*.htmlfail onmainalready; unchanged by this PR).🤖 Generated with Claude Code