Arch-Traits Scorecard — Chunk 5#

Traits: T1 narrow interfaces · T2 no globals/init · T3 explicit composition root · T4 time/IO injected · T5 functional core · T6 concrete internal collaborators · T7 public helper/builder API · T8 package boundary discipline Scores: 0=absent · 1=weak/partial · 2=clear · 3=textbook

Score table#

ProjectT1T2T3T4T5T6T7T8Σ
P42-headscale2131211112
P43-tailscale3122213115
P44-wireguard-go3332332221
P45-delve2231321317
P46-air3331131116
P47-pop3111112111
P48-pocketbase2132213216
P49-nats-server2332332321
P50-temporal3233313220
P51-crush2332221318

Evidence#

P42-headscale (Σ=12)#

  • T1=2: report:P42-headscale--interfaces.md — AutoApprover(3m), AuthProvider(4m), nodeConnection(5m) are narrow; ControlServer(31m) and TailscaleClient(35m) are god interfaces
  • T2=1: report:P42-headscale--patterns.md — promauto.NewCounterVec called at package level via promauto init() side effects; architecturally central
  • T3=3: report:P42-headscale--architecture.md — NewHeadscale() documented as explicit composition root; manual DI; all deps passed via constructor
  • T4=1: report:P42-headscale--patterns.md — 347 context.Context uses but no clock injection; time.Now() ambient
  • T5=2: report:P42-headscale--architecture.md — layered monolith; some domain separation but no pure-logic packages isolated from IO
  • T6=1: report:P42-headscale--interfaces.md — ControlServer(31m) and TailscaleClient(35m) suggest broad interface use beyond just external seams
  • T7=1: report:P42-headscale--api-surface.md — gRPC/REST/CLI API only; no dedicated embedding API or test helper packages
  • T8=1: report:P42-headscale--structure.md — no internal/; hscontrol/ is main package; layered by convention only

P43-tailscale (Σ=15)#

  • T1=3: report:P43-tailscale--interfaces.md — consumer-side interface definitions confirmed: ipnLocalBackend defined in ssh/ consuming ipnlocal; Observer(1m), StateStore(2m), Extension(3m) are narrow; pattern explicitly used
  • T2=1: report:P43-tailscale--patterns.md — feature.Hook registers in init() for optional subsystem feature registration; architecturally central
  • T3=2: report:P43-tailscale--architecture.md — tsd.System is explicit DI container; explicit wiring partially undermined by init()-based feature.Hook registrations
  • T4=2: report:P43-tailscale--patterns.md — logger.Logf injected as func parameter (DI via function type); context pervasive; no clock injection
  • T5=2: report:P43-tailscale--interfaces.md — net/dns.OSConfigurator(4m) at OS boundary; some pure packages; mixed overall at this scale
  • T6=1: report:P43-tailscale--patterns.md — feature.Hook adds implicit indirection between internal subsystems; some interface-everywhere patterns
  • T7=3: report:P43-tailscale--api-surface.md — tsnet library is rich public embedding API; dedicated client/local library surface; textbook integrator-facing design
  • T8=1: report:P43-tailscale--structure.md — minimal internal/; flat public namespace; feature/ build flags

P44-wireguard-go (Σ=21)#

  • T1=3: report:P44-wireguard-go--interfaces.md — only 5 interfaces total; BindSocketToInterface(2m) and PeekLookAtSocketFd(2m) are capability extension interfaces; “minimum necessary abstraction” is stated philosophy
  • T2=3: report:P44-wireguard-go--patterns.md — no init() side effects documented; no package-level singletons; 5 direct deps; no promauto/registry patterns
  • T3=3: report:P44-wireguard-go--architecture.md — NewDevice(tun tun.Device, bind conn.Bind, logger *Logger); textbook 3-parameter composition root; nothing hidden
  • T4=2: report:P44-wireguard-go--patterns.md — tun.Device and conn.Bind are injected IO interfaces; //go:linkname fastrandn is ambient randomness (not injected); no clock injection
  • T5=3: report:P44-wireguard-go--structure.md — ratelimiter/, replay/, tai64n/ packages have zero intra-project deps; purely algorithmic; no IO
  • T6=3: report:P44-wireguard-go--architecture.md — no interfaces between client→Sublist→Account within server package; interfaces only at tun.Device and conn.Bind IO seams
  • T7=2: report:P44-wireguard-go--api-surface.md — tun/tuntest and conn/bindtest provide in-memory test doubles; clear embedding story; no dedicated examples package
  • T8=2: report:P44-wireguard-go--structure.md — no internal/ (deliberate: library-first); clean package layout device/tun/conn/ratelimiter; no import cycles

P45-delve (Σ=17)#

  • T1=2: report:P45-delve--interfaces.md — MemoryReader(1m), LocationSpec(1m), service.Server(2m) are narrow; service.Client(~50m) is a god interface; Thread(10m) and Registers(8m) are wider
  • T2=2: report:P45-delve--patterns.md — sync.Once for CPU feature detection is justified one-time init; no architectural init() side effects; vendor/ present but unrelated
  • T3=3: report:P45-delve--architecture.md — execute() is the documented composition root; manual Config struct wiring; 4-layer system CLI→Service→Debugger→Proc all wired explicitly
  • T4=1: report:P45-delve--patterns.md — ~10 context.Context uses (minimal, intentional for debugger domain); no clock or IO injection
  • T5=3: report:P45-delve--structure.md — pkg/dwarf and pkg/proc have no service layer deps; service/ imports from pkg/ but not vice versa; clean directional layering
  • T6=2: report:P45-delve--interfaces.md — ProcessInternal extends Process via interface; some excess interface use; mostly appropriate
  • T7=1: report:P45-delve--api-surface.md — JSON-RPC 2.0 + DAP; embeddable in principle but no dedicated embedding/test API
  • T8=3: report:P45-delve--structure.md — Standard Go Layout cmd/pkg; service/ layer distinct from pkg/; clean pkg/dwarf, pkg/proc, pkg/proc/amd64 decomposition

P46-air (Σ=16)#

  • T1=3: report:P46-air--interfaces.md — only 2 project-owned interfaces: exiter(1m) for test seam, Streamer(5m) for I/O; no unnecessary interfaces
  • T2=3: report:P46-air--patterns.md — no init() side effects; single Engine struct owns all state; atomic.Bool for state; no package singletons
  • T3=3: report:P46-air--architecture.md — Engine struct created in main.go; all deps via struct fields; clear single wiring point
  • T4=1: report:P46-air--patterns.md — zero context.Context usage; custom channels for cancellation; FileWatcher interface exists but no clock injection
  • T5=1: report:P46-air--structure.md — flat single runner/ package; logic and IO mixed in same package; no pure-logic isolation
  • T6=3: report:P46-air--interfaces.md — only exiter(1m) and Streamer(5m); all other internal collaborators are concrete structs
  • T7=1: report:P46-air--api-surface.md — application binary only; no public library or embedding API
  • T8=1: report:P46-air--structure.md — no internal/; flat root-level main.go + runner/ package; minimal boundary discipline

P47-pop (Σ=11)#

  • T1=3: report:P47-pop--interfaces.md — 11 single-method lifecycle callbacks (BeforeSaveable, AfterCreateable, etc.); TableNameAble(1m), PaginationParams(1m); textbook optional extension interfaces
  • T2=1: report:P47-pop--patterns.md — dialect factories registered via init() in each dialect_*.go; global Connections map; var Debug bool; var ConfigName string
  • T3=1: report:P47-pop--patterns.md — NewConnection() exists but init()-based dialect auto-registration distributes composition; global Connections map populated by LoadConfigFile()
  • T4=1: report:P47-pop--patterns.md — time used for created_at/updated_at (likely time.Now() internal); no clock injection; context propagation via contextStore but not injected
  • T5=1: report:P47-pop--structure.md — root package is dense hub (72 .go files); sub-packages (columns/, slices/) are somewhat pure but root mixes IO and domain logic
  • T6=1: report:P47-pop--interfaces.md — dialect(~21m) and store(18m) are wide internal interfaces; core collaboration is interface-based internally
  • T7=2: report:P47-pop--api-surface.md — well-documented fluent Connection/Query API; public columns/, slices/, associations/ packages; genny/ for scaffolding
  • T8=1: report:P47-pop--structure.md — internal/defaults and internal/randx are minimal; root package has 72 files; no strong boundary discipline

P48-pocketbase (Σ=16)#

  • T1=2: report:P48-pocketbase--interfaces.md — Mailer(1m), RecordProxy(2m), Resolver(1m), optional extensions MaxBodySizeCalculator/SetterFinder(1m each) are narrow; core.App(~150m) is the acknowledged god interface
  • T2=1: report:P48-pocketbase--patterns.md — core.SystemMigrations.Register() in init(); Fields registry populated via optional init() registration; architecturally central
  • T3=3: report:P48-pocketbase--architecture.md — examples/base/main.go is canonical composition root; pocketbase.New() wires all components; core.App passed explicitly to every subsystem
  • T4=2: report:P48-pocketbase--interfaces.md — Mailer and blob.Driver interfaces mean IO is injectable; 197 context.Context uses; no clock injection
  • T5=2: report:P48-pocketbase--structure.md — tools/ sub-packages (hook, store, types, tokenizer, search) are pure utilities; core/ mixes DB and domain logic
  • T6=1: report:P48-pocketbase--patterns.md — core.App(~150m) passed as the single dependency everywhere; every package depends on the fat interface rather than concrete types
  • T7=3: report:P48-pocketbase--api-surface.md — examples/base as canonical library reference; tests/ fixtures; hook-based plugin system; rich Go embedding story
  • T8=2: report:P48-pocketbase--structure.md — no internal/ (deliberate for embeddability); clear core/apis/forms/plugins layering; tools/ as utility library; good discipline

P49-nats-server (Σ=21)#

  • T1=2: report:P49-nats-server--interfaces.md — Authentication(1m), DeleteBlock(2m), WAL(12m) are narrow; RaftNode(53m) and StreamStore(44m) are justified-wide system ports; bimodal distribution
  • T2=3: report:P49-nats-server--patterns.md — no init() side effects; CONTRIBUTING.md explicitly discourages new deps; Server struct owns all state; no package singletons
  • T3=3: report:P49-nats-server--architecture.md — NewServer(opts *Options) is the explicit composition root; ~300-line function; all state visible in Server struct fields
  • T4=2: report:P49-nats-server--dependencies.md — internal/fastrand avoids global mutex; Logger is injectable interface; no clock injection
  • T5=3: report:P49-nats-server--structure.md — server/stree, server/avl, server/gsl, server/ats, server/thw are pure data-structure/algorithm packages; conf/ is pure parser; no IO in these packages
  • T6=3: report:P49-nats-server--architecture.md — deliberate: no interface indirection between client/Sublist/Account on hot paths; interfaces only for StreamStore/ConsumerStore/RaftNode at behavioral-substitution seams
  • T7=2: report:P49-nats-server--api-surface.md — server package exported for embedding; NewServer/InProcessConn/HTTPHandler; test/ black-box package; functional but not elaborate
  • T8=3: report:P49-nats-server--structure.md — internal/ for OCSP/LDAP/fastrand (security primitives); server/ sub-packages for algorithms; clear OS-portability via build tags in pse/ and sysmem/

P50-temporal (Σ=20)#

  • T1=3: report:P50-temporal--interfaces.md — dynamicconfig.Client(1m), Authorizer(1m), ClaimMapper(1m), hsm.Environment(2m), StateMachineDefinition(4m) are narrow and consumer-defined; architectural migration from MutableState(80m) to narrow HSM interfaces is ongoing
  • T2=2: report:P50-temporal--architecture.md — fx DI removes need for init() globals; hsm.Registry registration via fx.Invoke not init(); 2,555-file codebase makes certainty partial
  • T3=3: report:P50-temporal--architecture.md — temporal/fx.go TopLevelModule + fx.New() is explicit; nested fx.App per service; everything wired via providers; file:temporal/fx.go
  • T4=3: report:P50-temporal--patterns.md — goro.AdaptivePool backed by injectable clock.TimeSource; 8,416 context.Context references; common/clock package; textbook time injection
  • T5=3: report:P50-temporal--patterns.md — common/tasks, common/goro, common/backoff, common/collection are pure logic; service/history/hsm has pure state machine logic separated from IO
  • T6=1: report:P50-temporal--architecture.md — fx DI means every component is declared as interface in fx.In structs; internal collaborators are interface-typed by framework convention
  • T7=3: report:P50-temporal--api-surface.md — temporal/ package for embedding; temporaltest/ for test servers; WithAuthorizer/WithDynamicConfigClient functional options; textbook integrator API
  • T8=2: report:P50-temporal--structure.md — no internal/ (deliberate for embeddability); 60+ packages under service/history/api/ (one per RPC handler); clear layering; good discipline

P51-crush (Σ=18)#

  • T1=2: report:P51-crush--interfaces.md — PublisherT and SubscriberT are textbook narrow generics; MessageItem hierarchy (Identifiable 1m, Animatable 2m, Expandable 1m) is narrow; Workspace(~41m) is acknowledged facade
  • T2=3: report:P51-crush--architecture.md — all code under internal/; no init() side effects; App struct owns all state; no package singletons documented
  • T3=3: report:P51-crush--architecture.md — setupWorkspace() + app.New() is explicit composition root; manual DI throughout; all deps wired via constructor injection
  • T4=2: report:P51-crush--patterns.md — 584 context.Context uses; proper ticker/ctx.Done() patterns for cancellation; no explicit clock injection; IO is cancellable
  • T5=2: report:P51-crush--structure.md — internal/csync (pure generics), internal/pubsub (pure generics), internal/stringext, internal/filepathext are pure; agent loop is inherently IO-heavy
  • T6=2: report:P51-crush--interfaces.md — domain service interfaces (session.Service, message.Service) exist mainly for testability; coordinator receives them as constructor params; reasonable internal use
  • T7=1: report:P51-crush--structure.md — everything under internal/; no public library surface; REST API over Unix socket exists but is not a Go library
  • T8=3: report:P51-crush--structure.md — aggressive internal/ usage for all ~50 packages; no accidental public API; textbook package visibility discipline for an application binary

Pattern observations#

T3 (composition root) is strong across this chunk: 8 of 10 projects score 2 or 3. Manual constructor injection dominates; only temporal uses a DI framework (fx). Pop(1) and tailscale(2) are the outliers, both held down by init()-based extension mechanisms.

T2 (no globals/init) splits the chunk sharply. Projects built as libraries (wireguard-go, nats-server) and application binaries (air, crush) score 3 by avoiding init()-based registration entirely. Projects with plugin/dialect/metric registration patterns (headscale, tailscale, pop, pocketbase) score 1. Temporal is a clean 2 via fx.

T6 (concrete internal collaborators) correlates with architectural philosophy. Performance-first servers (wireguard-go, nats-server, air) score 3 — they explicitly avoid interface indirection on hot paths. fx-based temporal scores 1 because fx mandates interface-typed dependencies throughout. Pop and pocketbase score 1 due to wide internal interfaces (dialect(21m), core.App(150m)).

T5 (functional core) separates the protocol/systems projects from the application-layer projects. wireguard-go, nats-server, delve, and temporal all have clear pure-logic packages (algorithm sub-packages, pkg/ layers, common/* utilities). air and pop score 1: single-package or dense-root structure prevents isolation.

T1 (narrow interfaces) shows an interesting split: projects that use single-method lifecycle interfaces (pop: 11×1m callbacks; pocketbase: optional extensions; temporal: Authorizer/ClaimMapper) score 3 even when they also have god interfaces. The score reflects whether the pattern is present and intentional, not whether it is applied universally.

Standout scores: wireguard-go and nats-server both reach Σ=21 — the highest in this chunk — through complementary strengths: wireguard-go via minimal abstraction at every layer; nats-server via deliberate hot-path concreteness combined with rich pure algorithm sub-packages.


Blind scoring — no –testing.md reports read. Confidence: high for all projects except P47-pop (api-surface read only for confirmation; 4 of 7 non-testing reports provide sufficient signal).