Conversation
Adds internal/relay/registry.go with the Conn interface and a thread-safe Registry mapping server-ids to a single binary connection (1:1) and to a list of phone connections (1:N). Sentinel errors ErrServerIDConflict and ErrNoServer let callers branch via errors.Is. Tests cover the AC: first-claim-wins semantics, reclaim after release, phone gating on a held server-id, removal-by-ConnID with sibling isolation, snapshot isolation for PhonesFor, lifecycle Counts, empty- slice cleanup, and a race-freedom hammer test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
Author
Code Review: #3Decision: PASS FindingsNone blocking. Implementation matches the architect's spec line-for-line. Verification
What I checkedGo correctness
Concurrency
Idiom & style
Security (security-sensitive label)
Test coverage
SummaryTight, well-documented implementation of a foundational data structure. Lock discipline is conservative and correct. Doc comments make the concurrency contract legible to future consumers (#4-#10). Ready to merge. |
3 tasks
Resolves additive doc conflicts from concurrent dispatch of #3 (registry), #9 (autocert), and #11 (threat-model): - docs/PROJECT-MEMORY.md: keep registry, autocert, and threat-model rows; drop superseded "TLS / autocert | Not started" placeholder; merge all Patterns established bullets. - docs/knowledge/INDEX.md: keep both new feature bullets; renumber the registry ADR link to 0003. - docs/lessons.md: keep all six new lesson sections (registry + autocert). - docs/knowledge/decisions/0002-connection-registry-passive-store.md -> 0003-connection-registry-passive-store.md (autocert ADR landed first via #9 / PR #13 and owns 0002). - docs/knowledge/features/connection-registry.md: update internal ADR link to 0003. No code changes. make vet / make test -race / make build all clean.
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.
What
Adds
internal/relay/registry.gowith:Conninterface (ConnID,Send,Close) — opaque connection handle for the routing core; real WS implementations land in relay: WS upgrade for /v1/server — accept binary connection, validate headers, claim server-id #4 / relay: WS upgrade for /v1/client — accept phone connection, look up server-id, register #5.Registry— a thread-safe store mapping server-ids to one binary (1:1) and to N phones (1:N). Singlesync.RWMutexguards both maps.ClaimServer,ReleaseServer,RegisterPhone,UnregisterPhone,BinaryFor,PhonesFor(snapshot copy),Counts.ErrServerIDConflict(4409) andErrNoServer(4404).Lock discipline:
SendandCloseare never invoked while the registry holds its mutex.ConnIDis invoked under the lock byUnregisterPhone— theConndoc comment names it as a non-blocking getter.PhonesForreturns a freshly-allocated slice so broadcast fan-out runs lock-free against the snapshot.Issue
Closes #3.
Testing
internal/relay/registry_test.go(package relay, stdlibtestingonly):TestClaimServer_FirstWinsSecondConflictsTestReleaseServer_ReclaimSucceedsTestRegisterPhone_RequiresBinaryTestUnregisterPhone_RemovesByConnIDTestPhonesFor_SnapshotIsolationTestCounts_AcrossLifecycle(asserts orphan phones surviveReleaseServerper spec open-question 1)TestUnregisterPhone_RemovesEmptySliceTestRegistry_RaceFreedom— 32 goroutines × 200 ops hammering the public APIVerified locally:
+ "go vet ./..." +clean+ "go test -race ./..." +clean+ "go test -race -count=20 -run TestRegistry_RaceFreedom ./internal/relay" +clean+ "go build ./cmd/pyrycode-relay" +succeedsArchitecture compliance
+ "envelope.go" +; tests inpackage relayper established convention.sync,errorsin production;errors,fmt,sync,testingin tests).UnregisterPhonedeletes the map entry when the slice empties (no orphan empty slices observable viaCounts/PhonesFor).ReleaseServeris intentionally narrow — does not touch phones, leaving the grace period (relay: 30-second grace period on binary disconnect before releasing server-id #8) free to layer cleanup on top.doc.go,envelope.go,cmd/pyrycode-relay/main.go, ordocs/— registry has no consumers in this ticket.🤖 Generated with Claude Code