controller_host is recorded on the mounted compute sub-application
when the controller queries the compute capabilities; the test relied
on another test having made that call first and failed when run on
its own. Set the state directly in the test.
Every node lifecycle call (start/stop) emitted a "starting"/"stopping"
node.updated notification on entry, and for the whole duration of the
call asdict() masked the real status with the transitional one — every
compute event forwarded in that window was re-emitted as a duplicate
transitional status.
Stop-all/start-all on a 13-node project pushed two transitional events
per node before the final state. Clients that do not render these
transitional statuses (the Web UI) showed nodes flickering through an
unexpected suspended-looking state before reaching started/stopped.
Remove the transitional notification and the status masking: clients
see the real statuses again (started/stopped), from the forwarded
compute events plus the controller-side confirmation. The wait option
on the lifecycle routes, the strict stop error handling and
wait_for_status() are unchanged.
Resolve conflicts against the upstream wave (PRs #2952-#2965, incl. the
typed-response/schema hardening and the drop of Python 3.10):
- controller/node.py: keep upstream's _transitioning/_confirm_status
lifecycle guard; the kernel-anchor link wiring (node_started) runs
after the transition completes.
- controller/link.py: keep upstream's add_node rollback (release_ports
on create failure) and delete via release_ports; release_ports now
resolves ports live (same staleness reason as _bind_members) and
discards the node link unconditionally.
- schemas/controller/links.py: extend LinkFilterType with the eight
kernel-datapath filter types and LinkFilterParameter.type with "str"
so the newly typed /available_filters response validates; Link.filters
stays a free-form dict — the vocabulary is capability-gated per link
and validated by the controller (409), not by a strict request schema.
- schemas/controller/topology.py: drop the type: ignore made redundant
by the dict filters field.
- tests: route-level filter validation now expects the controller's 409
(unknown types, out-of-range values); packet_loss correlation is a
valid kernel parameter (positive test added); OpenAPI assertions match
the free-form filters property.
GET /computes/{id} answered with only part of the capabilities the compute
reports: the response schema kept a second, private Capabilities class of
its own (it knew ubridge_tc and nothing else), and FastAPI's response model
silently drops fields it does not define — so ubridge_tap and
ubridge_iol_tap never reached clients even though the compute had sent
them and links were already being built on those datapaths.
Import the one definition instead of duplicating it, so the next capability
cannot drift the same way.
Three fixes from live-calibrating the kernel impairment filters on an
isolated instance (Docker-to-Docker veth link, per-sequence evidence):
- update_filters skipped an unchanged filters dict as a no-op, so a
one-shot window_drop outage that had already passed could never be
re-armed: re-applying the same values produced no datapath command at
all. A PUT still carrying window_drop now reconciles, restarting the
schedule from the apply as documented. Measured: identical re-apply
moves the outage window from seq 50-70 to 70-91 (arm at +8s of the
new apply).
- gemodel parameter semantics were documented backwards in the
validation rules, available_filters, the MCP/copilot descriptions and
the feature docs. Measured against the kernel (per-direction counters,
offered = sent + dropped): p is the good-to-bad transition chance, r
the bad-to-good transition, 1-h the loss chance in the bad state (the
good state loses nothing) - mean one-way loss p/(p+r)*(1-h), e.g.
[10,30,100] -> 24.8%/25.7% measured vs 25% predicted, [5,45,100] ->
10.8% both ways vs 10%.
- kernel_datapath was silently stripped from every REST/MCP link payload
by the response model (LinkBase carried no such field), so clients
could not tell a kernel link from a relay one.
Also verified on the same setup: the 3-argument window_drop form works
exactly as specified ([3000,5000,100] -> a single seq 31-55 outage,
[20000,6000,100] -> seq 115-144), and both generations of the command
builder emit the parameters unpadded.
Adds an API test for the field and controller tests for the no-op skip
and the window_drop re-arm exemption.
Preserve image reconciliation, locking, and regression coverage while integrating upstream release, dependency, typing, and formatting updates. Align feature code with the new Ruff checks.
Review-driven session/transport fixes (each reproduced live against
sharkd 4.6.7 before fixing):
- raise the RPC stream limit to 16 MB: a full 1000-row frames page
measures ~190 KB against the 64 KB StreamReader default, which failed
the request with a 500 and desynchronized the resident session; a
line-over-limit ValueError is now treated as a transport failure
- verify JSON-RPC reply ids: a timed-out request's late reply was
served as the next request's answer; timeouts, dead pipes, malformed
and stale replies now kill the session for good instead
- make check-spawn atomic under one manager lock: concurrent requests
for the same pcap double-spawned sharkd and leaked the loser (process
plus /tmp scratch copy) forever
- refcount sessions and evict idle only (LRU, cap raised 8 -> 16): a
tag with more sources than the cap respawned every source on every
request, and concurrent requests could get their session killed
mid-RPC (spurious 502)
- map FilterError to sharkd's filter rejection (-13002) only; other
engine failures with a filter set are 502, not a client 400
- detail: accept an optional frame_number to disambiguate
same-microsecond frames (ts is not unique within a pcap); drop the
-8003 -> 404 mapping (the range is validated locally, engine errors
are real faults); a failed hex read is a 404 instead of "hex": null
- a pcap deleted mid-request is a 404, not a 500; the pcap-sized
scratch copy runs off the event loop; server shutdown kills every
resident session and drops its scratch directory
- pin the packet-list layout through scratch-HOME Wireshark
preferences: the column indexes are a contract the server owns
(protocol-level column negotiation is rejected by sharkd 4.6.x)
Range contract change (WebUI moved to an always-flat list): the merged
frame list is returned in full, deliberately uncapped - truncated and
per-second buckets are removed, frame_count always equals
len(frames), and rendering cost is the client's concern (the window
endpoint remains the incremental path).