Portwing targets a documented ~97% production coverage floor, not 100%.
Go cannot cleanly reach 100% without production-code distortion. Certain patterns produce statements that are structurally unreachable or require impractical test infrastructure:
os.Exitinmain()— the test harness invokesrun()directly; covering theos.Exitline requires exec-subprocess tricks that obscure test intentjson.Marshalerror branches on primitive-only structs — the Go JSON encoder never errors onstring,int,bool, ormap[string]anywith those value types; the error return exists as a defensive API contract, not a reachable pathcrypto/rand.Readfailure branches — cryptographically random bytes failing is not testable without kernel-level interventionconn.SetWriteDeadlineerror branches on live WebSocket connections — requires an OS-level file-descriptor manipulation that would destabilize the test suite- Long-period cleanup tickers (5-minute
time.Ticker) — waiting 5 minutes per test run is impractical; the ticker path is covered by code inspection - Compile-time
GOOS=windowsbranches — dead code on linux/darwin; cannot be compiled or executed in CI
The enforced floor defaults to 97% (COVERAGE_MIN in
scripts/ci/go-test.sh; the env override exists for local experiments, CI
does not set it, so 97 is what every CI run enforces). Achieved total as of
2026-09-02: 97.4% (run 33684784256, job 100429523414, commit
7f61a77), with 97.3% on the four commits before it. Keeping a floor below
the achieved total is the org standard for the Go repos: drydock stays at
100% because TypeScript supports line-level istanbul-ignore, and Go has no
equivalent.
The floor sat at 96 while the achieved total climbed from 96.4% to 97.4%, which turned it into 1.4 points of slack a regression could have hidden in. 97 restores about 0.4 points of headroom, roughly 25 statements, which is the room a change that lands slightly ahead of its tests needs. It is a whole number rather than the measured total because the floor is here to catch a real regression, not to pin a figure that moves a tenth of a point whenever a test file lands. New production code should still land with tests, or the floor becomes the first thing a refactor trips over.
The following blocks are documented as structurally unreachable. They are not coverage gaps that need fixing — do not add contorted tests or refactor production code to cover them.
os.Exit(run(os.Args, os.Stdin, os.Stdout, os.Stderr))os.Exit is unreachable from tests. All test coverage goes through run()
directly, which is 94.9% covered. Covering main() itself would require an
exec-subprocess round-trip that adds no meaningful signal.
buildAckPayload (line ~151), BroadcastWatcherSnapshot (line ~220),
BroadcastContainerAdded (line ~230), BroadcastContainerUpdated (line ~244),
BroadcastContainerRemoved (line ~258): all call json.Marshal on structs or
map[string]any values whose fields are string, int, []byte, and other
JSON-safe primitives. The Go JSON encoder never returns an error for these types.
The if err != nil guard is a defensive API pattern, not a reachable path.
protoTriggers := make([]protocol.ComponentDescriptor, len(triggers))
for i, t := range triggers {
protoTriggers[i] = protocol.ComponentDescriptor{
Type: t.Type,
Name: t.Name,
Configuration: t.Configuration,
}
}GetTriggerComponents() (line 304) always returns an empty slice — "No
triggers in v1.0 - agent-side triggering deferred to v2.0" (line 305) — so
triggers is always empty and the loop body never executes. Documented by
TestSendComponentSync_TriggersAlwaysEmpty in
internal/adapter/drydock/drydock_coverage_test.go:792-800, which asserts
GetTriggerComponents() stays empty rather than asserting coverage; the test
fails loudly if the product ever adds v2.0 triggers and makes the loop
reachable.
data, err := json.Marshal(toDrydockContainer(container))
if err != nil { ... }The value actually marshaled is toDrydockContainer(container)'s return, the
drydockContainer wire type in internal/adapter/drydock/wire.go:10-33, not
adapter.Container itself. It marshals cleanly for the same reason: every
field on drydockContainer and the structs it embeds (drydockContainerImage,
drydockContainerRegistry, drydockContainerTag, drydockContainerDigest,
drydockContainerUpdateKind, drydockContainerError, drydockRuntimeDetails,
and adapter.ContainerResult/adapter.EnvVar pulled in from
internal/adapter/model.go:22-34) is a string, bool, slice of strings, or
map[string]string — no funcs, channels, complex numbers, or cyclic pointers,
which are the only things that make encoding/json return an error. The error
branch is a defensive guard; unreachable in practice.
MarshalPrivateKeyPEM (line 51): x509.MarshalPKCS8PrivateKey error on a
valid in-memory Ed25519 key is unreachable.
GenerateKeyPair (line 64): ed25519.GenerateKey(rand.Reader) can only fail if
crypto/rand returns an error — a kernel-level failure not reachable in tests.
NewNonce (line 96): same rand.Read failure category.
if runtime.GOOS == "windows" {
return nil
}This branch is compile-time dead on linux/darwin. It is the correct defensive
pattern for cross-platform code and is not testable without GOOS=windows.
The deferred f.Close() error surfacing path is structurally unreachable: the
kernel returns a close error only when a dirty page cannot be flushed (e.g. on
NFS). Not reproducible in unit tests without low-level filesystem mocking.
m, err := c.collector.Collect()
if err != nil { ... }sendMetrics is called on a live WebSocket connection's timer goroutine.
Covering the error path requires injecting a failing MetricsCollector, which
is only wired up in the integration-test binary. The branch is 1 statement.
if err := conn.SetWriteDeadline(...); err != nil {
c.failConn("set write deadline failed")
return
}SetWriteDeadline on a *websocket.Conn only fails if the underlying file
descriptor is already closed. Triggering this without a data race requires
OS-level fd manipulation. Not testable cleanly in unit tests.
case <-heartbeat.C:The heartbeat ticker fires every 30 seconds. Covering this branch in a unit test requires waiting 30 s or injecting a mock ticker, neither of which is worth the fragility trade-off. The branch is 3 statements.
writeToolResult marshals any data — in practice always a well-formed struct
or map. The err != nil guard is a defensive pattern; not triggered by any
production call site.
case <-ticker.C:cleanup is a RateLimiter maintenance goroutine that sleeps for 5 minutes
between sweeps. Covering the ticker branch in a unit test requires a 5-minute
sleep or a mock ticker injected into unexported state. Not worth the test
fragility for 3 statements.
The reusable Go CI / Build & Test job calls:
./scripts/ci/go-test.shinternal/banner/gen is excluded because it contains only generated constants
with no testable logic. The benchmarks/ subtree is likewise excluded — it
contains load-test harnesses, not production code.
The floor check extracts the total: line from go tool cover -func and
compares it against COVERAGE_MIN.