Commit Graph
6 Commits
Author SHA1 Message Date
Claude 288b52d89c feat(causal): webserver bench with a planted, known-answer bottleneck
examples/causal_bench.rs (required-features smarm-causal): the Phase 2
RFC 007 test case — a real urus server replacing the synthetic demo as
validation workload.

Shape: 16 plain-OS-thread clients hammer GET /order/:id over blocking
loopback keep-alive TCP (OS threads can't absorb injected virtual delay
— the established trick, so only server code is delayable). The handler
calls a single store actor (crud's once-cell pattern, serialization
structural) burning 400µs of calibrated *work* under
causal_site!("store") — work-shaped, not timed, or injection reads as a
no-op. 50µs handler render lands under the enclosing pipeline site.

Known answer: store serialized + saturated => ceiling 2500 rps; speedup
p => x1/(1-p): +33% @25, +100% @50. The five lib sites are tens of µs
and parallel across conns => ~0. Verdict mirrors the demo: store @25 >
+15%, others < +10%, SKIPPED under 4 cores; magnitudes trusted to ~±15%
per the smarm-side validation notes, ranking is the hard check.

1-core sandbox smoke (verdict SKIPPED but numbers indicative): store
+26.2% @25 / +74.0% @50, all other sites within ±2%. Unlike the demo
this workload keeps its bottleneck structure on one core — everything
but the store is IO-parked — and the theory shortfall there is plain
core contention (render/parse share the store's CPU), which the 24-core
sweep should close.
2026-07-13 08:59:49 +00:00
Claude 072ee126f9 feat: smarm-causal passthrough feature
Mirrors the smarm-trace precedent: urus itself gains no causal code
paths yet — this just lets downstream binaries (the Phase 2 causal
bench lives in examples/) flip smarm's instrumentation on through the
urus dep. Whole suite is green with the feature enabled: the causal
runtime is behaviorally inert while no experiment is active.
2026-07-13 08:25:49 +00:00
Claude 86c8d31b93 docs(channels): example, README section, ROADMAP v0.6 mark-done — chunk 4
examples/channels_chat.rs (required-features phoenix): ephemeral
room:* and persistent session:* side by side over phoenix.js V2 JSON,
stdin-driven graceful shutdown (the ws_chat pattern). Smoke-tested
live: rejoin after transport drop lands on the same instance (state
counter persists across three transports), broadcasts carry the new
join generation's ref.

README: channels section (feature split, core trait walkthrough,
session persistence semantics incl. the re-entrant-join contract).
ROADMAP: v0.6 marked done with the full as-landed decision list,
chunked as committed.
2026-06-12 15:26:21 +00:00
Claude 0531390613 feat(channels): core protocol machinery — v0.6 chunk 1
Feature 'channels' (zero new deps): wire-neutral ChannelFrame/FrameRef +
Encode/Decode codec traits (one method each, whole-envelope — the codec
owns the wire format end to end); Channel trait; ChannelFactory +
TopicRouter + shipped PrefixRouter (exact map + head:* prefix map);
ChannelSocket (reply/push/broadcast/broadcast_from/broadcast_to);
ChannelHub (router + PubSub<Broadcast<P>>, in-runtime + non-static per
the v0.5 pattern, hub.upgrade(conn) entry, server-side hub.broadcast).

Topology as ratified: one channel actor per (socket, topic), linked to
the conn actor, select(&[&inbound, &bus_rx]) with inbound at index 0;
subscription pinned to the channel actor pid. Subscribe-before-ok-reply
makes the join ack first-class (the v0.5 on_open race, answered
structurally). Cleanup is the sender-drop chain (conn handler drops ->
inbound closes -> closed arm wakes -> terminate); bus arm dropped from
the select set once observed closed (closed arms stay ready forever).
Heartbeat answered conn-side on topic 'phoenix'; rejoin replaces the
old generation with a phx_close to the old join_ref; lazy prune of dead
channel entries on first failed forward (the pubsub discipline).

As-landed deviations from the ratified sketch (module docs, veto by
diff): join takes &mut self (trait-object callable; construction moved
to ChannelFactory which still gets the full raw topic); reply(status,
payload) with the ref threaded invisibly (the sketch listed both);
broadcast gained the event parameter (unencodable without it); route()
returns Arc not Box. Outbound payloads encode from borrows (FrameRef)
so bus fan-out never clones P; payload-less control frames
(phx_close, error/heartbeat replies) encode as the codec's empty
payload rather than conjuring a P.

11 runtime-backed unit tests with a toy pipe codec (core provably
JSON-free). Suites: 78 w/ feature, 67 featureless, both green.
2026-06-12 13:53:52 +00:00
Claude 49538ccc83 feat(ws): RFC 6455 opening handshake — Conn::upgrade, 101 short-circuit (v0.4 chunk 1)
Design (as agreed in the v0.4 pass):
- Dep #3 spent: sha1_smol 1.0.1 (zero transitive deps) instead of a
  vendored SHA-1 — user call: no hand-rolled crypto. Consequence noted
  in ROADMAP: the v0.6 wire-format JSON question now costs dep #4.
- Base64 stays in-tree but ENCODE-ONLY (RFC 4648 vectors tested): it is
  an encoding, not crypto, and the decode direction (where parsing bugs
  live) is deliberately not implemented.
- src/ws/{mod,handshake}.rs: validate() implements §4.2.1 (GET, 1.1,
  Host, upgrade/connection token lists case-insensitively, key shape =
  base64 of exactly 16 bytes, version 13). Version mismatch -> 426 +
  sec-websocket-version: 13 (§4.2.2); everything else -> 400. Rejected
  upgrades stay plain HTTP with keep-alive intact (tested: 400 then 101
  on the same connection).
- Conn grows pub upgrade: Option<WsUpgrade> (opaque marker; chunk 3
  turns it into the duplex/handler handoff payload — shape deliberately
  uncommitted while the handler API is open). Conn::upgrade(self) is the
  commit point: 101 + accept key + marker + halt, or the rejection.
- conn_actor: upgrade marker + status 101 -> write head, leave the HTTP
  loop. Until chunk 3 that drops the fd (clients see 101 then EOF);
  status check is defensive against a post-handler plug clobbering 101.
- serialise_response: 1xx no longer get content-length injected
  (RFC 7230 §3.3.2). 204 left alone on purpose — separate conversation.

Accept-key path pinned to the §1.3 worked example end-to-end (unit +
wire). Suite: 34 unit + 33 integration + 2 doc.
2026-06-12 05:38:14 +00:00
Markk116 3b6c466210 Initial commit 2026-05-26 23:16:45 +02:00