Protos Networking v0.1
Protos Networking v0.1
Section titled “Protos Networking v0.1”Canonical source:
spec/io/NETWORK.mdat locked revisione99b712ecf658a527b1fe82c8beba2c1286d8dc9. The source document’s own status and authority declarations apply; this website rendering does not upgrade, downgrade, or redefine them.
Language version: 0.1 Status: Draft Last updated: 2026-09-09
This document is the primary normative owner of portable network authority,
numeric IP-address/endpoint semantics, and the initial TCP connection/listener
capability model introduced by D047 / specification revision 0.1.388.
D052 / specification revision 0.1.393 fixes the ordinary-object/delegation topology of
acquired live TCP resources without selecting host/backend machinery.
General byte-I/O, Future commitment/cancellation, lifecycle, and half-close
semantics remain owned by IO_CORE.md and BYTE_IO.md; Process bootstrap-local
provisioning remains owned by PROCESS_IO.md; Actor and P transfer boundaries
remain owned by their concurrency specifications.
1. Scope and governing model
Section titled “1. Scope and governing model”Networking is capability-oriented. Knowing an address or endpoint is data and
never grants authority to communicate with it. A concrete Network object is a
live authority capability whose effective routing/namespace/policy domain is
selected by the host or by a future explicitly standardized derivation
facility.
The initial portable model standardizes numeric IP data and TCP only. DNS/name resolution, Happy Eyeballs, UDP/datagrams, NetworkInterface enumeration, formal Network-policy introspection/attenuation, TLS, QUIC, HTTP, WebSocket, Unix-domain sockets, raw sockets, service discovery, generic socket options, and socket-local deadline/timeout APIs are outside this revision.
No network authority is ambient by implication. Importing a module, knowing an
IpAddress, possessing Process, creating an Actor, or creating P work does not
confer a Network capability.
2. IpAddress semantic data
Section titled “2. IpAddress semantic data”An IpAddress is ordinary frozen Protos data. Its canonical semantic state is:
version // exactly Integer 4 or Integer 6bits // exact Integer address bitsFor version 4, bits is in 0 .. 2^32-1. For version 6, bits is in
0 .. 2^128-1.
D047 creates no new Core value-identity family. Two independently materialized
standard IP-address objects with the same version and bits may be structurally
equal without being identical under ===. Standard IpAddress equality and
hashing depend only on version and bits and execute no network, DNS, routing, or
host-interface operation.
The address is data, not authority. It contains no hostname, resolver, native socket address, interface index/name, route handle, Network capability, or host resource identity.
D048 / specification revision 0.1.391 closes the bounded public
construction/recognition checkpoint. IpAddress is a standard frozen
factory/prototype that carries no Network authority; its public placement is
defined in section 3.1. Its canonical construction
uses ordinary polymorphic invocation:
IpAddress(version, bits) -> IpAddressThe standard factory behavior requires the invocation receiver to be exactly the
canonical standard IpAddress factory/prototype and requires exactly two supplied
arguments. version must belong to the ordinary unbounded Integer family and
be exactly 4 or 6. bits must belong to that same ordinary unbounded Integer
family and must be in 0 .. 2^32-1 for version 4 or 0 .. 2^128-1 for version
6. A Float is not accepted even when finite, integral, and in range. Invalid
construction signals a fresh ordinary Error
synchronously and performs no DNS, routing, Network or host I/O.
Every successful invocation returns one fresh ordinary frozen object whose
immediate delegation parent is exactly the canonical standard IpAddress
factory/prototype and whose own local slot names are exactly version and
bits, containing the validated semantic values. These are ordinary public
member-readable data slots. Factory provenance is not itself semantic membership:
an ordinary program object constructed through the normal object/delegation/freeze
mechanisms is a recognized standard IpAddress exactly when it is frozen, its
immediate parent is exactly the canonical standard IpAddress factory/prototype,
its own local slot names are exactly version and bits, and those slot values
satisfy the same canonical numeric invariants. Extra own slots, merely transitive
ancestry, an open or closed-but-not-frozen object, or coincidental shape under a
different parent is not recognized.
The standard factory/prototype additionally exposes:
IpAddress.recognizes(value) -> true | falseFor the exact canonical receiver and exactly one supplied argument, this
predicate accepts any candidate and returns canonical true exactly for the
recognized standard shape above, otherwise canonical false. Recognition
observes the frozen state, immediate parent, exact own-slot names and required
semantic-family/range state directly; it invokes no candidate getter, callback,
equality or hashing behavior and performs no network/host operation. Invalid
receiver or arity follows the ordinary standard receiver/arity Error rule.
Standard IpAddress equality/hash behavior requires a recognized receiver,
compares/hashes only canonical version plus bits, and yields canonical
false rather than signaling merely because the other argument is not a
recognized IpAddress. === remains ordinary object identity, so independently
constructed equal addresses remain distinct identities.
3. IpEndpoint semantic data
Section titled “3. IpEndpoint semantic data”An IpEndpoint is ordinary frozen Protos data whose canonical semantic state is:
address // IpAddressport // Integer 1..65535Standard endpoint equality/hash are structural by address plus port. ===
remains ordinary object identity. An endpoint contains no hostname, DNS result
cache, interface/scope identifier, transport-protocol tag, Network authority,
TLS identity, proxy identity, or native handle.
Port zero is not a standard IpEndpoint value in this initial model. Automatic
local-port selection is an acquisition request and is represented separately by
the listen request below rather than by overloading endpoint data with a verb.
D048 / specification revision 0.1.391 also closes the endpoint
construction/recognition surface. IpEndpoint is a standard frozen
factory/prototype carrying no Network authority, placed as defined in section
3.1, and is constructed through
ordinary invocation:
IpEndpoint(address, port) -> IpEndpointThe standard factory behavior requires the invocation receiver to be exactly the
canonical IpEndpoint factory/prototype and exactly two supplied arguments.
address must be a recognized standard IpAddress under section 2. port must
belong to the ordinary unbounded Integer family and be in 1 .. 65535; a
Float is not accepted even when finite, integral, and in range. Invalid
construction signals a fresh ordinary Error synchronously
and performs no network/DNS/host effect.
Each success returns one fresh ordinary frozen object whose immediate delegation
parent is exactly canonical IpEndpoint and whose own local slot names are
exactly address and port. The address slot retains the exact supplied
recognized IpAddress object; port retains the validated Integer. Both are
ordinary public member-readable data slots.
A candidate is recognized as a standard IpEndpoint exactly when it is an
ordinary frozen object, its immediate parent is exactly canonical IpEndpoint,
its own local slots are exactly address and port, its address is a
recognized standard IpAddress, and its port is an ordinary unbounded Integer
in 1 .. 65535. Factory provenance is unnecessary; extra own state,
transitive-only ancestry, mutable state or coincidental shape under another
parent is insufficient.
The standard factory/prototype exposes:
IpEndpoint.recognizes(value) -> true | falsewith the same direct, callback-free, host-effect-free recognition rule as
IpAddress.recognizes. Standard endpoint equality/hash requires a recognized
receiver and depends only on recognized address plus port; an unrecognized
other argument compares false and === remains ordinary object identity.
IpAddress and IpEndpoint are data suitable for ordinary value transfer under
the applicable Actor/P snapshot rules once their standard construction contract
is implemented. Such transfer never transfers Network routing state or
communication authority.
3.1 Placement of the canonical IP families
Section titled “3.1 Placement of the canonical IP families”D172 places the canonical families in the Standard Library rather than in the
Core Prelude. Core requires no public Prelude binding named IpAddress or
IpEndpoint; an unqualified lookup of either name in a context that does not
itself bind it follows ordinary missing-slot semantics.
Within one Process there is exactly one canonical IpAddress
factory/prototype and exactly one canonical IpEndpoint factory/prototype,
shared by all of that Process’s Actors and P work. Both are FROZEN, carry no
mutable state, and are the exact objects referred to as canonical in sections 2
and 3. They are published as:
std:network/IpAddresses.IpAddress // the canonical IpAddressstd:network/IpEndpoints.IpEndpoint // the canonical IpEndpointThe std:network/IpAddresses module instance contains the local slot
IpAddress, and the std:network/IpEndpoints module instance contains the
local slot IpEndpoint, from the creation of that module’s moduleContext,
before its body executes (see the cache-before-execution steps in
spec/semantics/MODULES.md). The slot value is the canonical family itself, not
a per-instance copy or wrapper. Module instances remain Actor-local under the
ordinary module rules: for Actors A and B,
IpAddresses@A !== IpAddresses@B, while
IpAddresses@A.IpAddress === IpAddresses@B.IpAddress, and likewise for
IpEndpoints. Sharing is permitted because the family objects are frozen
standard objects; no module state becomes global.
The runtime’s internal access to the canonical families, as used by Actor and P
value transfer and by the Network/TcpConnection/TcpListener operations
below, is not a Prelude binding, does not perform an implicit import, never
creates or initializes a module instance as a side effect, and confers no
Network authority. In particular, transferring a recognized IpAddress or
IpEndpoint produces a fresh logical copy whose immediate parent is the same
canonical family, without importing std:network modules in the source or the
destination.
4. IPv4, IPv6, and scope
Section titled “4. IPv4, IPv6, and scope”IPv4 and IPv6 remain semantically distinct. Core performs no implicit IPv4-mapped-IPv6 normalization and defines no host-default dual-stack listener behavior. A version-6 listen request is semantically IPv6-only; a version-4 request is IPv4-only.
IPv6 routing/interface scope belongs to the Network authority domain rather
than to portable IpAddress or IpEndpoint identity. For an address that
requires scope, an operation may proceed only when the supplied Network
capability provides one unambiguous authorized interpretation. If the capability
admits multiple incompatible interpretations, the operation fails rather than
silently selecting a host interface.
A future interface/scoped-Network facility may narrow authority without changing
IpAddress or IpEndpoint representation/equality.
5. Network capability
Section titled “5. Network capability”Network is the standard prototype of live network-authority capabilities. A
concrete Network may represent a complete network domain, a VPC/VRF/namespace,
one interface-scoped domain, one service, one permitted destination set, or
another non-amplifying policy domain. The base portable API does not require the
policy to be enumerable as CIDRs, ports, interfaces, or a bitmask.
The effective authority of a Network never grows merely because one of its
standard operations is invoked. D047 introduces no public NetworkPolicy,
permissions(), CIDR/port introspection, generic restrict() primitive, or
firewall DSL. Hosts may provision already-restricted capabilities. Ordinary
Protos encapsulation may expose a narrower application mechanism around a
broader capability without granting the wrapped capability itself.
The initial TCP acquisition operations are conceptually:
network.connectTcp(endpoint) -> Future<TcpConnection>network.listenTcp(localRequest) -> Future<TcpListener>After successful ordinary dispatch, argument/request semantic invalidity follows the existing Future-returning I/O validation rule: the operation result is a failed Future and no backend network effect attributable to that invalid request occurs.
No hostname/String-to-endpoint coercion or DNS lookup is performed by either operation.
6. TCP connect acquisition
Section titled “6. TCP connect acquisition”connectTcp(endpoint) accepts a concrete numeric IpEndpoint under the standard
recognition contract selected by D048 / specification revision 0.1.391.
The endpoint version remains explicit.
Successful resolution transfers one fresh live TcpConnection capability to
the caller. The connection’s logical remote endpoint equals the supplied endpoint
under standard structural endpoint equality; the logical local endpoint is the
endpoint selected within the Network authority domain for that established flow.
Cancellation of a still-acquiring Future may produce the ordinary Future
cancelled outcome only under the general I/O cancellation/commitment rules.
A cancelled acquisition guarantees that no TcpConnection capability is
transferred to the caller. It does not promise that no physical preparatory
network activity was externally observable; address resolution at lower host
layers, ARP/neighbor discovery, routing probes, TCP SYN traffic, or equivalent
backend preparation may already have occurred.
If backend work later obtains a live connection after the caller can no longer receive it, producer/runtime custody must release that untransferred resource. No late resource may be abandoned merely because the Future already terminalized.
7. TCP local-listen request
Section titled “7. TCP local-listen request”listenTcp(localRequest) accepts an ordinary Protos object whose relevant local
slots are exactly:
ipVersion // exactly Integer 4 or Integer 6address // matching-version IpAddress or canonical nullport // Integer 1..65535 or canonical nullAll three slots are required and extra local slots make the request invalid.
Delegated slots do not supply these option fields. address when non-null must
match ipVersion. address: null means that the request supplies no single
local-address constraint beyond the requested IP version and the authority of
the supplied Network. port: null requests selection of an available non-zero
local port.
The ordinary values are validated and captured before acquisition effects attributable to the request. Neither unspecified IP bit-patterns nor integer zero are reinterpreted as acquisition commands. Host wildcard/ephemeral conventions are backend details.
Successful resolution transfers one fresh live TcpListener capability.
Cancellation/late-resource custody follows the same acquisition rule as TCP
connect.
The initial portable model defines no backlog option. Implementations may use bounded admission/queues/backpressure while preserving the observable Future, accept, close and resource-custody contracts.
7.1 TCP live-resource object topology
Section titled “7.1 TCP live-resource object topology”D052 / specification revision 0.1.393 fixes the Protos-visible topology shared by the live
TCP resource families defined below.
A successfully acquired TcpConnection or TcpListener is an ordinary identity-bearing Protos
object whose structural state is OPEN at acquisition. Each family has one canonical standard
frozen behavior prototype in the applicable Core standard-object domain. A concrete capability’s
immediate parent is exactly its family protocol prototype, and that protocol prototype’s immediate
parent is exactly Object.
Core v0.1 requires no public Prelude binding, constructor, or global identifier named
TcpConnection or TcpListener. The family protocol prototype is nevertheless ordinary observable
Protos state when a program already possesses a live resource: ordinary parent() returns it and
ordinary reflection observes its local standard selectors. The prototype itself carries no TCP
resource authority.
The TcpConnection protocol prototype owns the standard local behavior selectors read, write,
close, shutdownRead, shutdownWrite, localEndpoint, and remoteEndpoint. The TcpListener
protocol prototype owns accept, localPort, and close. A freshly acquired concrete resource has
no mandatory local Protos slots merely to duplicate those selectors or encode backend state.
Application code may create/shadow ordinary local slots while the resource object’s structural state
permits it.
Delegating from a family protocol prototype or from a concrete live capability never manufactures TCP family membership or authority. Standard TCP behavior validates that the original receiver is an actual acquired member of the required live-resource family before exercising family-specific state; an ordinary descendant that only inherits lookup fails that receiver-domain check.
The nearer family-prototype close selector is the standard Closable resource lifecycle operation,
not the structural Object.close() transition. Successful or failed resource close does not by
itself alter the receiver’s ordinary OPEN/CLOSED/FROZEN structural state. Structural mutation/freeze
and ordinary lookup/shadowing remain governed by the object model; resource lifecycle remains
governed by Core I/O.
The D047 Actor/P rule remains unchanged: concrete TCP live-resource capabilities and ordinary graphs that reach them are not transferable under the initial contract. The authority-free family protocol prototypes do not themselves grant network/resource authority.
D052 does not define stronger endpoint object-identity observations. D047 continues to require the
logical remote endpoint of an outgoing successful connection to equal the supplied endpoint under
standard structural equality. This revision does not specify whether repeated endpoint accessors
return one identity or fresh equal identities, nor whether remoteEndpoint() === suppliedEndpoint.
8. TcpListener
Section titled “8. TcpListener”A TcpListener is a live identity-bearing capability and satisfies Closable.
Its initial operations include:
listener.accept() -> Future<TcpConnection>listener.localPort() -> IntegerlocalPort() is synchronous observation of the actual acquired non-zero local
port and performs no network acquisition.
The initial Core deliberately does not require a single
listener.localEndpoint(): a listener request with address: null may cover
multiple local addresses, so inventing one endpoint would misrepresent the
logical listening domain.
Multiple accept() Futures may be pending concurrently on one logical listener.
Core imposes no one-pending-accept restriction, no owner-thread affinity, and no
portable global acceptance order beyond the ordering actually established by
the logical listener/backend. Each successful accept transfers one fresh
TcpConnection capability exactly once.
Listener close/cancellation composes with the existing Closable lifecycle and
Future rules. No host file descriptor, selector registration, event-loop token,
carrier identity, or queue implementation becomes Protos-visible identity.
9. TcpConnection
Section titled “9. TcpConnection”A TcpConnection is a live identity-bearing capability satisfying exactly the
initial portable I/O capability surface required by TCP:
ByteReadableByteWritableClosableReadShutdownWriteShutdownIt does not thereby satisfy Flushable, Syncable, ByteSeekable, ByteSized,
or Truncatable. TCP is an ordered byte flow, so the existing byte-I/O ordering,
write contribution, cancellation, close, and half-close semantics apply without
a parallel network-stream universe.
It additionally exposes synchronous data snapshots:
connection.localEndpoint() -> IpEndpointconnection.remoteEndpoint() -> IpEndpointThese describe the logical TCP flow presented by the Network capability. They do not promise discovery of an underlay address, NAT predecessor, proxy client identity, route, interface, fd/socket handle, or physical transport endpoint that the backend does not expose as the logical flow.
A successful byte write means only the contribution guarantee already defined by
Core byte I/O; it does not imply remote-application receipt and adds no portable
flush() delivery promise.
10. Error portability
Section titled “10. Error portability”The initial TCP surface uses the existing portable I/O Error categories. It does not expose POSIX errno values, Winsock status codes, Java exception classes, or native backend types as standard Protos Error ancestry.
This does not freeze network errors forever. A future narrower network Error category must be justified by a portable semantic distinction useful to Protos programs, not merely by a host status-code taxonomy.
11. Actor, P, and distributed-runtime boundary
Section titled “11. Actor, P, and distributed-runtime boundary”Network, TcpConnection, and TcpListener are live resource capabilities and
have no Actor-transfer or P-transfer contract in this initial model. Attempting
to move them through a boundary that accepts only ordinary transferable values
fails under that boundary’s existing non-transferable-value rules.
Core defines no Erlang-style active socket mode that injects TCP bytes directly into an Actor mailbox. An Actor reads a connection using ordinary byte-I/O Future operations and may then send application messages explicitly.
The distributed Protos runtime may use local IPC or network transports
internally. Those mechanisms do not constitute a user Network capability and
do not grant user networking authority. Future resource proxies/delegation must
separately define semantic identity, authority, ordering, cancellation, lifetime
and failure behavior before live networking capabilities may cross such a
boundary.
12. Implementation freedom and scale
Section titled “12. Implementation freedom and scale”The semantics do not expose or require epoll, kqueue, io_uring, IOCP, Java NIO, Network.framework, one thread per connection, one Actor per connection, one event loop, or any other host scheduling architecture. An implementation may use any of them while preserving the same Future/I/O/lifecycle/authority observations.
A listener must not require a semantic single-accept bottleneck. A trivial program that never receives Network authority pays no conceptual requirement to create DNS caches, interface registries, event-loop objects, distributed proxies, TLS state, UDP state, or network policy structures.
13. Deferred facilities
Section titled “13. Deferred facilities”D048 / specification revision 0.1.391 resolves the former
IpAddress / IpEndpoint construction and recognition checkpoint. The following
remain separate explicit future designs:
- DNS/name resolution and resolver authority;
- Happy Eyeballs and general time/delay composition;
- UDP/datagram operations and truncation/size rules;
- public NetworkInterface discovery/selection;
- formal transferable Network attenuation/policy algebra;
- TLS, QUIC, HTTP and WebSocket;
- Unix-domain/raw sockets;
- service discovery;
- generic socket options and socket-local deadlines/timeouts; and
- a stronger
===identity relation among TcpConnection endpoint observations or the original outgoing acquisition endpoint.