Skip to content

v0.6.0

Choose a tag to compare

@sb2bg sb2bg released this 17 Jul 08:02
· 53 commits to main since this release
  • Exports the tidy build helper through Marionette's dependency build.zig.
    The helper locates its own dependency, so src/main_tidy.zig resolves inside
    Marionette while scan paths continue to resolve inside the consuming
    package; a nested consumer build now guards that boundary.

  • Clarifies the two supported network-testing altitudes. Node-scoped
    std.Io.net is the canonical literal same-code path for codecs, framing,
    partial I/O, and stream lifecycle; experimental Endpoint(Message) remains
    a protocol-modeling surface with an explicitly documented shallow-copy and
    delivery contract. The redundant public ByteEndpoint facade is removed
    while its pooled byte machinery remains private to deterministic
    std.Io.net.

  • Closes the simulator-TCB audit's runner and lifecycle gaps: runSimCase
    forwards every simulation option, keeps setup OOM distinct from scenario
    failure, accepts infallible scenarios, deinitializes pointer-valued apps
    before replay comparison, and rejects empty fuzz campaigns. Process-scoped
    Env/Io capabilities now fail while killed, manual restart invalidates
    file caches, and a failed restart rolls back partial tasks and handles.

  • Hardens suspension and trace ownership. File metadata has stable allocation
    across disk-latency suspension, guarded fiber-stack arithmetic is checked,
    network enqueue/dequeue publishes only after fallible trace recording, closed
    streams reclaim queued pooled frames, async/group storage honors dynamic
    alignment, killed Group.await owners release their group state before the
    fiber stack is destroyed, and trace-summary plus low-level world time/random
    state roll back cleanly on allocation failure. Suspended file operations now
    hold kill-safe path snapshots, streaming operations reacquire handles on
    resume, and per-path leases serialize pathname mutations with in-flight I/O.
    Queued handle operations therefore follow a completed rename or reject a
    completed deletion instead of recreating or writing through an obsolete
    pathname. Process kill retires task-owned gate state and aborts a
    main-context pathname wait instead of letting a stale capability keep
    driving the scheduler. Killed async tasks now release their copied closure
    contexts and never-started scheduler adapters immediately; only the future
    result record remains until its required await/cancel collection.

  • Makes final stream delivery transactional: the I/O bridge borrows a ready
    frame, reserves inbox capacity, publishes the network and io.net trace pair
    atomically, and only then removes the frame. Allocation failure leaves the
    original bytes queued for an exact retry.

  • Confines every RealDisk operation beneath its configured root by walking
    parent components through non-following directory handles and refusing final
    symlinks. Exclusive create plus non-following reopen closes the create race;
    the regression covers every file surface and verifies outside data is
    unchanged.

  • Makes Env.io() the single application-facing authority for clocks, sleeps,
    and randomness, removing the parallel Env.clock / Env.random interfaces
    and routing BUGGIFY draws through std.Random.IoSource. Scheduler timer
    jumps cross automatic process/network fault boundaries and yield to work
    created at each intermediate boundary, while World.clock() remains the
    explicit raw harness clock. App sleeps round to ticks, stale killed-node I/O
    returns error.Canceled, full-range task-start jitter and network-latency
    jitter avoid overflow, beyond-clock process and network transitions stay
    inert, and failed liveness transitions remain retryable. Tidy now targets
    Zig 0.16's real escape hatches—alternate host I/O backends, raw OS access,
    global logging, host-only process queries, threads, and ambient allocators—
    instead of obsolete time, entropy, filesystem, and network APIs.

  • Makes the disk contract match its declared sector model: torn writes land a
    prefix of whole sectors, reorder is one consistently traced crash-global
    reversal, and scripted corruption rejects missing files. The WAL example now
    spans two sectors so its planted recovery bug depends on a real sector-prefix
    tear instead of accidental byte tearing. Reclassifies XITDB-001 as a
    Marionette model bug: its minimized 7-byte-sector counterexample disappears
    under the corrected whole-sector prefix model while the same crash-point
    sweep continues to exercise real unacknowledged windows.

  • Canceling a task blocked in Group.await now cancels the group's members,
    waits for their completion, and resurfaces error.Canceled to the outer
    future.

  • Updates the dusty crash and shutdown validations for upstream commit
    e7a4f4b: a dead pooled connection is evicted so the same client redials
    after server restart, and graceful shutdown with a parked keep-alive handler
    completes instead of timing out. The old DUSTY-001/002 scenarios remain as
    positive regression coverage for the upstream fixes. The fixed revision is
    now pinned in build.zig.zon.

  • Removes the cancelled production endpoint bus, its deprecated
    Production.endpoint/byteEndpoint methods, and the private FIFO/socket
    transport. Production networking is host std.Io.net; Marionette endpoints
    are simulation-only. This also removes the blocking host-accept test from
    the ReleaseSafe gate.

  • Binding a simulated std.Io.net listener to port 0 now allocates an
    ephemeral port, matching POSIX bind semantics (issue #2). Ports come
    from the IANA dynamic range (49152-65535) via a rotating cursor shared
    across process backends, so ports are unique world-wide, allocation is
    deterministic per seed, and a just-closed port is not immediately
    reused. The assigned port is surfaced through the returned socket's
    address (server.socket.address.getPort()), and listen fails with
    AddressInUse only once the whole range is occupied.

  • Completes the architecture clobber set in Marionette's corrected fiber
    context switch. The x86_64 LLVM path now names the xmm and ymm
    aliases as well as zmm, so CPUs without the wider register classes do
    not retain stale SIMD values across a switch. AArch64 now clobbers the
    allocatable x18 on targets such as Linux while omitting it on Android,
    Darwin, Fuchsia, Windows, and OpenHarmony targets where LLVM reserves it
    as a platform register by default.

  • Hardens stream write backpressure from review findings. Writers now
    park on a world-global backpressure key instead of their own
    connection, so a writer blocked because another connection filled the
    shared byte pool is woken by any drain, not only its own peer's; a full
    directed path queue (EventQueueFull) now backpressures the same way
    instead of failing the write with SystemResources; and the peer is
    re-resolved and validated before every retry, so a peer that closes or
    dies while the writer is parked surfaces as ConnectionResetByPeer
    rather than a stale-pointer retry.

  • Adds opt-in randomized task start jitter
    (simulate(.{ .task_start_jitter_ns = ... })): every scheduler-backed
    task draws a seeded initial delay and becomes runnable only after that
    much virtual time, so seed sweeps explore start orderings the
    cooperative scheduler otherwise masks structurally. A capability test
    deterministically reproduces a connect-before-listen race and replays
    it byte-identically from its seed. The option defaults off, consumes no
    randomness, and emits no trace when disabled, so existing traces are
    unchanged; enabled draws are trace-visible as scheduler.start_jitter.

  • Lands 16e, large transfers: a dusty scenario uploads a 512 KiB
    position-patterned body the server verifies byte-for-byte, then
    downloads a 1 MiB chunked body the client verifies byte-for-byte, both
    over one keep-alive connection and spanning hundreds of simulated
    packets. This forced two stream-fidelity fixes in the simulated
    std.Io.net backend: writes larger than a pool slot are now segmented
    into 16 KiB frames like a real transport instead of failing with
    MessageTooLarge, and a full byte pool now applies write backpressure
    (the writer parks until the receiver drains a frame and wakes it)
    instead of surfacing NetworkDown mid-stream. Two peers both blocked
    writing at each other is a real deadlock, exactly as on TCP, and
    surfaces through deadlock detection.

  • Lands 16d, dusty pooled keep-alive depth: a pool-reuse scenario (idle
    gaps in virtual time, concurrent fetches growing the pool, sequential
    fetches reusing both connections, connection count pinned via the new
    io.net.connect trace event) and a pool-poisoning crash scenario
    (server killProcess under a pooled keep-alive connection, restart
    through a registered lifecycle, fresh-client isolation probe). Pins
    netShutdown under partition in the before-response scenario: shutdown
    is local in simulation, succeeds mid-partition, and is trace-visible as
    the new io.net.shutdown event; partition-respecting peer visibility is
    a recorded gap.

  • Records two confirmed dusty 0.1.0 bugs found by the 16d scenarios
    (FOUND_BUGS DUSTY-001/002): the client connection pool never evicts a
    dead connection because write failures never mark it closing, so a
    poisoned client can never recover even after the server returns; and the
    server's graceful-shutdown drain busy-spins forever once any earlier
    connection has closed, because the drain waits on a latched, never-reset
    std.Io.Event.

  • Adds mar.expectTraceContains, the trace-substring assertion the dusty
    and xitdb validations each defined privately; failures print the needle
    and the trace tail.

  • Removes the World-config runner family: runCase, expectPass,
    expectFailure, and expectFuzz. It was a complete parallel API to
    runSimCase/expectSim* with no consumers; harnesses with genuinely
    custom state drive World directly or use the world-only mar.run.
    Check and world_checks stay, since the sim runner accepts them.

  • Removes the SimControl root export; Control is the single name for
    the simulator-control capability bundle (the two were aliases of the
    same type).

  • Removes ByteTransport, CodecTransport, and the codec namespace
    (including CodecRecvLifetime and default_codec_encode_buffer_size).
    These were convenience wrappers with a single in-repo consumer, and a codec
    interface is a serialization concern that belongs to the app, not the
    simulator. The toy SQL example now encodes into an owned, value-only
    Endpoint(Message) payload; the redundant public byte-endpoint facade is
    removed as described above.

  • Adds the pinned lazy beanstalkz validation (validate-beanstalkz): the
    unmodified g41797/beanstalkz work-queue client runs against a
    harness-owned in-memory beanstalkd speaking the text protocol over
    simulated std.Io.net streams. Covers a produce/consume round trip with
    bury/kick transitions and the pinned error.Timeout empty-reserve
    contract, sequential connection churn (connect, put, quit,
    shutdown(.both), close) drained in FIFO order, a blocking
    reserve-with-timeout parked across a five-second virtual publish
    delay, and a server-process crash under a parked reserve that surfaces
    the pinned error.CommunicationFailure reset contract before a
    registered restart recovers on a fresh incarnation. All scenarios replay
    byte-identically from the same seed.