R2Kernel™ 1.0.0rc9
RC9 is a prerelease for evaluation, not general operating or hard-real-time
approval. It adds explicit installer options for every choice plus
--non-interactive; a release that requires license acceptance, including the
published runtime, still needs interactive review. It also adds subsystem
self-binding, launch-time bindings, per-instance CPU claims and brokered sockets
for multi-process packages, and it defines federation readiness by peer acknowledgement. RC8
remains an immutable historical prerelease; its artifacts and tags are not
replaced. Upgrade the runtime and SDKs together, and upgrade the hosts of a
federation together. Local Control remains protocol v5 without mixed-version
fallback or automatic replay.
Upgrade notes
- Real-time priority of managed packages. The launcher bounds each managed
package's
RLIMIT_RTPRIOto its admitted CPU claim (0 forpolicy: otheror no CPU claim). A limit inherited from the service unit or a container does not let a package raise its own real-time priority. Declare the priority in the package'sresources.cpu, or per instance withr2kernel launch run --resourcesor the REST startresourcesfield. See Real-Time Scheduling. - Federation. A peer is listed in
subscriptions_syncedonly after it acknowledges this host's current subscription request. Peers without acknowledgement support stay connected but never satisfy readiness, so upgrade all hosts of a federation together. - REST package routes.
POST /api/v1/control/packages/{id}/startandrestartreject unknown fields;stopaccepts onlyinstance_id. Other fields return400. - Strict resource claims.
resourcesinpackage.yamland every claim under it reject unknown keys. Examples of such keys are a misspelt key such assandoxornetwrok, acapabilitieslist outsidegrant, or an extracpukey. RC8 ignored them, so a misspeltsandboxran the package without its brokered sandbox. A package that RC8 accepted with such a key is now refused when it is validated, installed or launched, withunknown field at line <N> column <M>. Correct the key at that line and install the package again. - Strict package manifest. Every top-level key of
package.yamlmust be one ofschema_version,name,version,description,subsystem_manifest,entrypoint,parameters,resources,frontend,contracts,lifecycleandmetadata. RC8 ignored other keys, so a misspeltresourcessection (for exampleresouces:) ran the package without its claims and sandbox. Such a package is now refused when it is validated, installed or launched, withunknown field at line <N> column <M>. Keep custom data undermetadata. - Package parse errors. A parse error of
package.yaml, of a subsystem manifest or of a Gateway role check names the file, the kind of error and its line and column, for exampleinvalid type at line 3 column 13; it no longer repeats a value, key or key path of the file. Tools that matched the old message text must match the location instead. - Subsystem name length. A subsystem name has at most 128 UTF-8 bytes and no NUL character, the limit of a Control source identity. RC8 registered a longer name, which could never use managed Control; Control now refuses it at registration, and its refusal does not repeat the name.
- Link-layer capability grants. A
resources.link_layercapability (CAP_NET_RAW,CAP_NET_ADMIN) is granted only when the resource authority policy approves it for the claimed interface inlink_layer_grants. A package that relied on its manifest alone is refused at launch until the operator adds the entry, for example{"interface": "enp5s0", "capabilities": ["CAP_NET_RAW"]}, tolink_layer_grantsin/etc/r2kernel/resource-authority.jsonand runssudo systemctl restart r2kernel-resourced. A policy without the field approves nothing; a policy the RC9 installer creates has an emptylink_layer_grants. The capability applies to the whole host. See Resource Authority. - Resource service mode.
resource_service.mode: autoandrequiredboth require a runningr2kernel-resourced; Control's startup error names the mode and the remedy. Usedisabledonly for standalone Core development. - Managed launch. The resource service creates each package directly inside
its lease scope with
clone3(Linux 5.7+). Whereclone3is unavailable, for example under a container system-call filter that blocks it, managed launches are refused. - Installer.
--install-tokenis deprecated; use--install-token-file PATHorR2KERNEL_INSTALL_TOKEN. - SDK.
EventTransport.apply_staterejects a non-emptyremote_subscriptions; send-only users keep callingrecv_event(peer, timeout_ms=0)for every connected peer;timeout_ms=0does not wait on the network (it can wait for the transport lock behind a concurrentflush_nor blockingrecv_event); one call applies at most 64 setup frames and returnsNone(C: NotFound) when no Event is available, and the next call continues. JSON produced by the C++ SDK escapes every control character (U+0000–U+001F). - Timed-request late policy.
late_policyis exactlydrop,rejectorexecute_immediately(codes 0, 1 and 2); any other value is refused on send and on receive and never falls back toexecute_immediately. C++:TimedExchangeTimingOptions::late_policyset to an empty string is refused instead of meaningexecute_immediately. Python: alate_policywith surrounding spaces is refused instead of being trimmed. - C ABI Event receive.
r2kernel_event_client_recv/_recv_exkeep an Event whose topic, publisher or payload does not fit the caller's buffers at the head of the queue and returnBufferTooSmall(-4) with every required length in the length outputs; retry with buffers of at least those sizes to receive it. A caller that retries with the same buffers receives -4 again without waiting, so a receive loop built against RC8 or earlier, which skipped any non-zero result, spins on that Event and receives no later Event. Upgrade SDK builds and C ABI callers together with the runtime library. - C ABI federation transport results.
r2kernel_event_transport_accept_peer,_apply_state_jsonand the_recv_eventcalls no longer consume their item when an output buffer is null or too small for a non-empty value: they returnBufferTooSmall(-4) with every required length and keep the item for the next call (one kept Event per peer; a keptapply_statereport's connected/disconnected transitions are reported again, ahead of its own, by the nextapply_state_json). A size query with a null buffer no longer discards the item; call again with buffers of the reported sizes. (r2kernel_event_client_recvwith a null buffer still skips that field.)r2kernel_event_transport_accept_peercan returnR2KERNEL_EVENT_TRANSPORT_ALREADY_CONNECTED(1). This is not an error: the duplicate connection was closed, the peer stays connected on its existing session, andout_peer_idis not written. A caller that treats every non-zero result as a failure must handle 1.r2kernel_event_transport_flush_nreturns SystemError (-3) instead of -2 when a send expires, and closes that peer's connection. Federation and Timed Exchange sends never raise SIGPIPE: a send to a closed peer fails with SystemError (-3), so a C or C++ host does not need to ignore SIGPIPE. - C ABI federation transport functions. New
r2kernel_event_transport_recv_event_timeouttakes an explicit wait:timeout_ms0 never blocks (it processes frames already delivered, at most 64 setup frames per call, and returns NotFound (-2) when no Event is available), a positive value waits at most that long, a handled signal (EINTR) during that wait neither ends it early nor closes the session, and a negative value returns InvalidArgument (-1).recv_eventandrecv_event_exstill wait up to the transport'sio_timeout_ms. Ten new functions split accept and apply into steps that wait on the network without holding the transport:r2kernel_event_transport_session_setup,r2kernel_event_session_setup_accept,r2kernel_event_session_peer_id,r2kernel_event_transport_install_session,r2kernel_event_session_close,r2kernel_event_session_setup_close,r2kernel_event_transport_apply_begin_json,r2kernel_event_apply_plan_connect,r2kernel_event_transport_apply_finishandr2kernel_event_apply_plan_close. A transport handle has at most one open apply plan: while one is open,apply_begin_jsonandapply_state_jsonreturn InvalidArgument (-1). A plan closed withr2kernel_event_apply_plan_closeinstead ofr2kernel_event_transport_apply_finishleaves the apply incomplete; the peers its begin already disconnected are listed indisconnectedby the next apply. The signatures of existing functions are unchanged. - Signals during federation waits. A signal handled while
recv_event,recv_event(timeout_ms>0),accept_peerorapply_stateof anEventTransport, or the matching C ABI function, waits on the network no longer fails the call or closes the session: the wait continues with the time left. In Python a Ctrl+C during such a wait therefore raisesKeyboardInterruptonly after the wait returns, at the latest when its timeout (io_timeout_msfortimeout_ms=None) has passed. - C ABI timed requests.
r2kernel_codec_encode_timed_exchange_request,r2kernel_codec_decode_timed_exchange_requestand their_v2forms return InvalidArgument (-1) for a late-policy code other than 0 (drop), 1 (reject) or 2 (execute_immediately), on encode and on decode, in both envelope versions. A caller that passed another code, or received a request carrying one, now gets -1 instead of a request.
Installation
The installer uses every choice given as an option or R2KERNEL_*
environment value and asks only the remaining questions. Every value option
accepts --option VALUE and --option=VALUE. --non-interactive (alias
--yes) never prompts; a missing decision, such as
--existing-prefix overwrite|abort for a non-empty prefix, is an error that
names the option. License acceptance remains manual and interactive only:
--non-interactive refuses a release that requires license acceptance, which
includes the published runtime release.
install.sh parses every argument and checks the prefix location with the
verified installer before any sudo prompt; checks that need the release, the
prefix contents or root run after elevation, before anything is downloaded or
installed. It elevates only for a protected prefix (root-owned, not a symbolic
link, not group/other writable), forwards exactly the
installer's documented R2KERNEL_* values through sudo and never the install
token, uses sudo -n with --non-interactive, removes its temporary directory
on exit or interruption, and exits with the installer's status. An installer
running as root refuses a prefix that is not protected; re-run install.sh
with --prefix PATH for a user prefix. The prefix must be a dedicated
directory, and an existing prefix is replaced only where an earlier R2Kernel
install created it. install.sh pins the SHA256 of the installer and of
release-manifest.json and the release version.
r2kernel-uninstall removes a no-service prefix that the calling user owns
without sudo, after checking that nobody else can change the path to it; root
refuses a prefix another user owns. Entry-point links written through another
spelling of the prefix, or for a relative --prefix, are removed with the
prefix. Installing, upgrading, uninstalling and running r2kernel-doctor no
longer write __pycache__ directories into <prefix>/runtime/tools. The
installer runs its service-upgrade coordinator, often as root, with Python in
isolated mode (python3 -I -B): a module in the directory the installer was
started from is never imported, PYTHON* environment variables and the user
site directory are ignored, and no bytecode is written. r2kernel-uninstall
refuses a user-owned prefix when it or a directory on the path to it has a
POSIX access ACL.
See Installation.
Bindings
A registered App or Component subsystem may bind its own declared requirement
when control.self_binding.mode: local (the default). Self-bindings target only
local providers, never replace an operator binding, explicit unbind or live
launch binding intent (an intent whose lease is still carried by a current
registration), are refused for Gateway or exclusive-arbitration targets
already bound by another source, and are removed when the source registration
ends or re-registers. An operator binding takes precedence, and an applied
launch binding intent displaces an exclusive self-binding, as an operator
binding does. By default the
source must be a member of a managed lease. Bindings are a registry and routing
contract; local Control access is bounded by caller authentication and the
runtime IPC group, not by bindings.
Setting a binding for a source that is not registered is refused, and the
response carries binding.state: "source_missing" so deployment tools can
retry. To declare bindings before a node starts, pass them with the managed
start (r2kernel launch run --bind, or bindings in the REST package start).
They are validated against the package manifest, applied right after that
instance's own process has registered (the registration reply does not wait
for them), reused by restart and runtime apply of the running
instance, and discarded when the instance's lease ends. Stopping an instance
removes its record, so a later start must send its bindings again. Binding rows report their origin.
See Subsystem Binding Model and Subsystem SDK Guide.
Resource control
- Per-instance CPU claims. A managed start can replace the package's
resources.cpufor one instance. The claim is validated and admitted like the manifest claim, kept with the running instance's record forrestart, and reported ascpu_origin.resources.cpu_instance_override: forbiddenrefuses it. - Brokered sockets for multi-process packages. A package leader can pass
brokered sockets to its child processes through
R2KERNEL_INHERITED_FDS; the Python and C++ SDKs validate the inherited descriptor without any broker fallback.resources.sandbox.fd_delegation: lease_scopelets every process of the lease scope request network and CAN sockets directly (Linux 6.5+); device descriptors stay leader-only. - Brokered sandbox diagnostics. Packages see
R2KERNEL_SANDBOX_NETWORK=brokered(andR2KERNEL_SANDBOX_CAN=brokered); the kernel logs denied socket calls subject tokernel.seccomp.actions_logged. A brokered sandbox also denies the socket families that reach the network withoutAF_INET/AF_INET6and the io_uring system calls. - Stops and cleanup. The resource service keeps serving other admitted requests while a stop runs. A stop takes at most about 9 s (3 s graceful, 2 s forced, 2 s exact-child reap, 2 s scope retirement); clients wait up to 10 s and then report the outcome as unknown while the operation continues. A failed cleanup is retried automatically with back-off (1–30 s) and does not consume launch capacity; at 64 retained reservations new launches are refused explicitly. Exhaustion of the request queue, reply capacity or incomplete-request capacity (including rotation of a peer's oldest incomplete request) is an explicit refusal to a connected requester.
- Manifest reads.
package.yamland the subsystem manifest are regular files of at most 1 MiB; a file's type is checked before it is opened, so a FIFO never blocks and a device node is never opened. A parse error names the file, the kind of error and its line and column and never repeats text of the file. These limits do not cover the spec and role documents named under Known limitations. - Package reads with the manager's identity. The resource service reads a
package with the user, group and supplementary groups of the manager that
asked for the launch, never with more access than the requesting manager
has: the package directory,
package.yaml, the subsystem manifest, the Gateway role check and every path that validation checks. A launch of a package the manager cannot read is refused, even when the package account could read it; only the instance's runtime directory and log files are created as root, for the package account. When the resource service prepares a launch, the Gateway role check runs in a separate process with the requesting manager's identity, a 256 MiB data limit and the 5 s launch preparation deadline, so a FIFO or an endless file there fails the launch and no longer blocks or grows the resource service. - Package runtime state. On an installed runtime an instance's runtime
directory is
<prefix>/var/run/packages/<uid>/<instance-id>, owned by the package user. Stopping the instance keeps it with its logs.GET /api/v1/control/packagesanswers500with"code": "package_store_unavailable"when Control cannot open, lock or read the package store. - Install root. The symlinked package install-root refusal names
packages.install_dir, the active configuration file and the resolved path to configure. Symlinked install roots remain unsupported. - Containers. Container Deployment describes the supported arrangement: Control, the resource service and the packages in one PID namespace with a writable, delegated cgroup v2 subtree. Container runtimes are not part of release qualification.
See Resource Control.
Federation readiness
subscriptions_synced lists the peers that acknowledged, on the current native
connection, this host's latest subscription request with a matching digest. A
peer leaves the list on reconnect or after a local subscription change until it
acknowledges again. Outstanding and unsupported acknowledgements are reported
as subscription_ack_pending and subscription_ack_unsupported. A subscription
request is sent only when the set changes, on a new connection, or as a retry
after two control status intervals.
Security-mode hints only choose which host initiates first. A hint change never
closes an established connection, except that an authenticated
optional/required record closes a plaintext session that peer id initiated.
Compatible pairs connect even with a
missing or wrong hint within two control status intervals plus the connect time.
A disabled host and a required host never connect; required never accepts
plaintext. While a peer record is authenticated and fresh, an unauthenticated
snapshot for that peer is ignored. Failed outbound connects back off from 1 s,
doubling to 30 s per peer (connect_backoff). When two hosts dial each other
at once, both keep the connection initiated by the lexically smaller host id;
the losing connection is counted in duplicate_sessions_closed. Federation
connection setup (accept, handshake, connect) runs outside the Event data-path
lock, so a silent TCP client no longer delays Event forwarding or receive. A
peer that closes its connection in the middle of a frame is disconnected at
once; the complete frames it sent before are still delivered.
Each Event send ends within the federation I/O timeout, also for an Event
written in several parts; a peer that has not taken a whole Event by then is
disconnected and counted in send_deadline_disconnects, and its queued Events
are discarded (counted in dropped). With federation security optional or
required, the backend raises federation.io_timeout_ms and
federation.connect_timeout_ms to at least 3000 ms (default 200 ms and
250 ms), so the Event send deadline and the pre-authentication accept budget
cap are then at least 3 s. One flush batch starts no send after one I/O
timeout. Per control tick, pre-authentication accepts take at most half the
control status interval (capped by the I/O timeout); the pending connections'
handshakes progress together, so a connection that stalls at any handshake
step (silent, or a ClientHello and then nothing), or that its peer reset before
the accept, cannot hold back a peer queued behind it within the tick's accept
limit (16 connections, or one per configured peer if there are more); a
connection without a first frame within half that budget, or
without a later handshake frame within the budget, is closed.
These connection rules are verified with two controllers on one host.
See Deployment Checks.
Time sync, Terminal and HTTPS settings
Time-sync probes have a 2 s deadline, the supervisor stops the processes it
started when it exits normally, on SIGTERM or SIGINT, when its parent exits,
and on an error return (on a signal or parent exit, before it writes its final
status; the kernel also ends them when the supervisor is killed with SIGKILL),
and a managed companion that exits is restarted with
back-off from 1 s to 30 s. Control and r2kernel timesync doctor accept the
time-sync service status as clock evidence only when the running service wrote
it recently; otherwise they report why it was rejected. A Terminal login at the
session limit is reported in the Console. The Console waits up to 30 s in total
for the HTTPS settings service, refuses a request that cannot start within that
time as busy, and reports an unanswered save as possibly saved. Control's HTTPS
listener runs at most 32 TLS handshakes at once and at most 4 from one source
address. All Control HTTP listeners together keep at most 256 connections open
and at most 64 from one source address, and close a connection that sends no
complete request head within 10 s of being established or of its last response.
Request bodies are limited to 2 MiB except for package upload; the package API
proxy also bounds body arrival time. The package API proxy now refuses upstream
responses over 2 MiB with 502, the package WebSocket proxy and the Control
event/control WebSockets refuse messages over 2 MiB, and a proxied WebSocket
is closed, whatever the package sends, when for 60 s its browser sends no
frame (including the answer to the proxy's 30 s ping) and takes no message
the proxy had to wait to send; a page keeps its session while the proxy's messages to it have to
wait for its connection to accept more data and each then gets through within 60 s, and a page that has gone away is
closed at the latest about 120 s after its connection stopped accepting data. One source address holds at most a quarter
of the package API and WebSocket proxy slots. The local Unix control socket
gives one local user at most 16 MiB of its 64 MiB request-byte budget. An
accept error such as too many open files on the listeners named in
Runtime Configuration pauses that
listener for 1 s instead of stopping Control. A federation accept failure of
one connection (for example a peer that reset first) does not end that control
tick's accepts; only a listener-level error such as too many open files does.
Both are logged at most once per 5 s. On the local Unix control socket,
requests that fail on the socket itself, failed Event resource operations and
failed notification deliveries are each logged at most once per 5 s with the
count since the previous line.
See Time Sync Operations and Web and API Security.
SDK
Unprepared codec calls (before initialize() or without a managed Subsystem)
perform a single conversion per call and still re-read the selected spec roots
on every call, with a one-time warning. For repeated use, initialize the
Subsystem or create a SchemaContext and PreparedCodec. A lifecycle hook that
returns false is logged with the phase and the last warning or error logged
during the hook by that hook's own thread. C++ frame-transform notifications,
and heartbeat status sent through a CoreClient other than the native
R2KernelClient, are bounded at 100 ms in total per notification (each socket
call gets only the time left).
A running Python subsystem, or a C++ subsystem with the native
R2KernelClient, stays registered across a Control restart: when Control does
not acknowledge a heartbeat status, the subsystem registers again with its
unchanged session, process ID, lease and notify endpoint and restores its
status, Event publications, Event subscriptions and Control handler;
self-bindings are not requested again. After a failed attempt, the next one is
due 1 s, 2 s and then every 4 s later and runs in the first heartbeat after
that time. Control waits at most 750 ms for the resource broker to prove the
lease of a registering process and asks again every 100 ms while the broker is
absent, restarting or busy; any broker answer decides at once. A first
registration does not wait for the Event resource work of other subsystems; a
registration that replaces an expired one is answered within 1.5 s, if
necessary with a refusal to retry that carries reason
registration_gate_busy or registration_cleanup_pending. The Python and C++
SDKs retry these refusals: at startup within R2KERNEL_STARTUP_RETRY_COUNT
attempts (default 20) R2KERNEL_STARTUP_RETRY_DELAY_MS apart (default
100 ms), and later from the heartbeat. When Control kept a C++ publication's
shared-memory slots, the publisher continues its Event generation after the
re-registration, so subscribers receive exactly the Events published after it.
A lifecycle change (fault(), degrade(), pause(), a transition that
Control requests) sends one status update and never waits for or starts a
re-registration (Python, and C++ with the native R2KernelClient); while a
heartbeat runs or the registration is being restored, the update is left to the
next heartbeat with an info line, and an update Control does not accept is
logged as an error and the next heartbeat registers again. In C++, a lifecycle
status left to the heartbeat when terminate() or reset() stops it is not
sent (see Known limitations). The Python SDK
removes its Control notification socket when the process exits normally or is
terminated by SIGTERM with its default action. Only the process that created
a notification socket removes it: a child forked from that process (os.fork,
or multiprocessing with the fork start method, including Pool workers)
removes none of its parent's sockets when it exits, is terminated or closes an
inherited client, and it gets back the default SIGTERM action. Such a child
also leaves its parent's Control connections open and never waits for a lock
another thread of the parent held at the fork; it cannot use the parent's
prepared Control lanes and needs its own client. At start, Control removes the
notification sockets of its own user that killed SDK clients left behind, and
the resource broker removes those of every client identity it serves, in each
case only when the socket's process no longer exists and nothing listens on it.
When an exchange on a prepared Control lane misses its deadline after it
reached Control, or Control closes or resets the lane's connection (end of
stream before a frame, or a send that fails with EPIPE or a receive that fails
with ECONNRESET), the Python and C++ SDKs fail that exchange without replay and re-prepare the lane once, within its
preparation timeout, with its original capacities and completion mode. A
transaction failure that Control reports in its reply is not re-prepared,
although Control then closes the connection. The late
exchange is still a failed exchange. Re-preparations are counted as
prepared_lane_recoveries and prepared_lane_recovery_failures.
The C++ SDK refuses an Operation start received in JSON form whose
timed_late_policy is not drop, reject or execute_immediately
(invalid_argument) instead of passing it to the handler.
See Typed Payload and Codec Guide.
Startup deadline and cancellation
Managed startup applies the original transaction deadline to preparation, process startup, gate delivery and response delivery. Preparation errors do not receive a fresh response budget. A caller disconnect, authorized cancellation, expiry or shutdown prevents an unfinished startup from being committed, while other admitted operations continue to progress. Capacity exhaustion is an explicit refusal, not an unbounded accumulation of launch work.
Reply expiry and process cleanup are different contracts. Cleanup has a separate bounded teardown phase; an expired reply does not prove that every resource is already retired. Cleanup failure retains exact process/resource recovery identity and reports failure rather than silently releasing authority. A late process-start result must still be owned and cleaned up. An incomplete startup frame does not authorize application execution; a partial reply does not permit a second response or automatic replay.
These are transaction and ownership guarantees, not a universal filesystem, kernel scheduling or host WCET bound. Broker-owned foreground success still requires whole-scope completion, exact child reap and resource release.
Current-run Event readiness
Gated fixtures require this attempt's publisher startup acknowledgement before
opening its gate. Use a fresh private 0700 run directory, an absent gate and a
unique topic/publisher identity for every attempt. The helper must observe the
current publisher registration; an already-ready topic owned by another
publisher or an unobserved name is insufficient. An absent, stale or mismatched
acknowledgement leaves the gate closed.
Existing-path refusal occurs before SDK registration. Neither participant
deletes a caller's old gate to make it fresh, and the helper creates only an
exclusive empty 0600 gate after all required checks. Follow the shipped fixture
README for the complete invocation and identity inputs.
Explicit cross-host readiness requires both sender and receiver status, actual
native peers and acknowledged subscriptions on both hosts. Requested clock
checks must pass on both hosts. Diagnostic topology fallback never approves
one-way latency evidence. Gate success is neither receiver callback evidence nor
a performance qualification. The native connected list reports new connection
transitions, not current membership.
Event buffering remains bounded and may drop data under overload. Use supported queue-depth and payload-capacity settings for the workload, and inspect sequence gaps.
Mixed-mode Event connections
For a Disabled/Optional native Event pair, the Disabled host initiates the plaintext connection, independent of host-name ordering or publication direction. Optional keeps its secure outbound policy and accepts this permitted plaintext inbound connection. The advertised transport mode is only a connection-planning hint. It does not authenticate a registration or grant remote Control authority. Required remains secure-only; a failed secure handshake never authorizes a plaintext retry.
External HTTPS configuration
Protected external configuration remains readable through the HTTPS settings service. Successful inspection does not imply permission to save. The response separately reports write capability and a read-only reason; the Console shows saved/running values while disabling connection changes, PEM inputs and Save when writing is unavailable. External settings writes are refused before configuration or TLS-material mutation.
Known limitations
These defects exist in RC9 and are not fixed in it.
- A package holding any brokered CAN socket is not confined to its claimed
interfaces: it can bind the socket again or name another interface in each
send and so reach every CAN interface of the host, including interfaces
another package claims exclusively, and a package without
resources.sandbox.can: brokeredcan open raw CAN sockets itself, because Linux requires no capability for them. - A brokered UDP socket is bound to its claimed adapter, but its holder can
name another interface for each datagram (
IP_PKTINFO) and so send through every adapter of the host, including adapters another package claims exclusively. - An approved
CAP_NET_RAWorCAP_NET_ADMINlink-layer grant is ambient and host-wide in the package process: it applies to every interface,CAP_NET_ADMINamounts to host network administration, and the declared protocols are not enforced. - Core reads the spec files a package supplies without a size limit or a
file-type check (the spec documents it resolves from the spec roots, such as
message sets, API specs,
defaults.yamland prepared-context sources, the prepared codec'sdefaults.yaml, and the Gateway contract documents and subsystem manifest read to check a gateway's role), so a FIFO in place of such a file blocks the reading thread and a device or very large file is read without limit. r2kernel package validate,r2kernel launch runand package installation in Control run the Gateway role check in their own process without a deadline or size limit, so a FIFO or an endless file among the Gateway files of a local package directory or in a spec root blocks or grows that process (archives installed through Control cannot contain FIFOs or symbolic links).- A launch preparation helper thread of the resource service (it has 4) can
be held by a metadata call such as
staton a filesystem whose operations block, for example a FUSE mount that the manager controls inside the package directory, because the 5 s preparation deadline frees the reply but not the thread. - When Control cannot open, lock or read the package store, package install,
start and stop answer
400with the error text, and onlyGET /api/v1/control/packagesanswers500with"code": "package_store_unavailable". - Uninstalling a package does not remove its instances' runtime directories
under
<prefix>/var/run/packages/<uid>/, so remove them as root when the instance ID is not used again. - Control writes each failed transport-resource cleanup step, and the UDP management listener each notification it sends, as its own log line without a rate limit, and Control sets no length limit of its own on Event topic names.
- Heartbeat status updates, Event publish and subscribe requests and Timed Exchange handler registration still wait without a bound behind operations that hold Control's Event resource gate across resource broker requests, so a stalled resource broker makes the SDKs' restores time out and retry.
- The Control WebSockets
/api/v1/ws/eventsand/api/v1/ws/controlhave no ping, idle limit or send timeout. - A C++ child process created with
fork()that destroys, or exits with, an inheritedR2KernelClientends the parent's Control lanes: the parent's next call on such a lane fails and re-prepares it. - A C++ lifecycle status left to the heartbeat when
terminate()orreset()stops the heartbeat is lost, because no next heartbeat runs, so Control shows the previous lifecycle state and reports the session as inactive aftercontrol.subsystem_timeout. - Control also runs the in-process Gateway role check on every read of its
package store for each package under
packages.additional_paths, not only at installation. - A control tick attempts at most 16 federation accepts, or one per configured peer if there are more, failed attempts included, so reset or silent connections that fill this limit delay the peers queued behind them to the next tick.
Qualification boundaries
The declared local C++ acceptance profile is Required-authority raw-eight-byte echo, period and caller/scheduled-completion deadlines of 1 ms, Core FIFO99 on CPUs 0 and 1, and caller/handler FIFO80. Every scheduled slot, skip, failure, caller deadline, scheduled-completion deadline and after-window completion belongs to the result; no catch-up, replay or deadline relaxation converts a failed run into acceptance. Measured results accompany the RC9 release page. On a virtual machine without CPU isolation, strict 1 ms results depend on the guest kernel and hypervisor; see the host conditions in Real-Time Scheduling.
Python is outside strict 1 ms periodic acceptance. Guest affinity does not prove physical CPU/hypervisor isolation. Finite synthetic results do not establish general WCET/hard-real-time, cross-host 1 kHz Control, physical actuator completion, hardware PTP accuracy or native ARM execution. Container runtimes are not part of release qualification. Benchmark demos remain withdrawn.