Phase -1 / IPC / IPC editor↔runtime round-trip#9
Merged
Conversation
S6 step 1 — pure schema layer for the editor↔runtime IPC, no transport yet. - protocol.zig: MAGIC (0x57454C44), WELD_IPC_PROTOCOL_VERSION = 1, MAX_PAYLOAD_LEN = 16 MB, heartbeat timing constants, comptime little-endian guard per engine-ipc.md §3.2. - messages.zig: 13 extern struct message types matching the brief's Scope table (handshake pair, echo pair, spawn pair, modify pair, heartbeat pair, shutdown pair, unidirectional LogMessage), MsgType enum, comptime schemaHash via std.hash.Wyhash, Capability.GPU_SHARED_FB pinned at bit 0 per brief § Notes (Phase 3 schema stability). - framing.zig: 16-byte Header extern struct, encode/parseHeader/ validate/decode with the five fatal errors from engine-ipc.md §8.3 (InvalidMagic, ProtocolVersionMismatch, UnknownMsgType, PayloadTooLarge, SchemaHashMismatch). - mod.zig: public surface for src/core/ipc/, re-exported via src/core/root.zig. Inline tests cover round-tripping, the four header rejection paths, schema_hash mismatch, payload-size mismatch, msg_type mismatch with the requested struct, fixed-string truncation. All green in Debug.
S6 step 2 — IpcSocket abstraction with two backends. Comptime dispatch on builtin.os.tag picks the right one. POSIX backend (Linux + macOS): AF_UNIX SOCK_STREAM via direct libc extern fn (avoids coupling to std.posix sendmsg/recvmsg signature churn across Zig 0.16 minor patches). sendWithHandles uses SCM_RIGHTS cmsg ancillary data; the cmsghdr layout diverges between glibc (cmsg_len: size_t) and macOS BSD (cmsg_len: socklen_t), handled via a platform-switched CmsgHdr struct and a matching cmsgAlign helper. listen() unlinks any stale socket file before bind() to handle a crashed-previous-editor scenario; close() unlinks the socket only on the listener instance. Windows backend: named pipe in byte mode via CreateNamedPipeA / ConnectNamedPipe / CreateFileA / ReadFile / WriteFile / CloseHandle. ERROR_PIPE_CONNECTED on ConnectNamedPipe is treated as success (the client raced ahead of accept()). ERROR_BROKEN_PIPE on ReadFile maps to recv() == 0 (clean EOF). sendWithHandles / recvWithHandles return error.Unimplemented in S6 — the DuplicateHandle-based path lands in Phase 3 with the GPU shared framebuffer (engine-ipc.md §4.7). Two inline tests on POSIX (round-trip and large send loop). Cross- compile to x86_64-windows-gnu validated separately. 90/92 tests pass on macOS host (2 skipped: Win32 + Wayland tests gated by platform).
…leMapping) S6 step 3 — ShmRegion abstraction backing the viewport double-buffer introduced in the next step. Comptime dispatch on builtin.os.tag. POSIX backend: shm_open + ftruncate + mmap on the creator side (editor), shm_open + mmap on the attacher (runtime). Close on the creator unlinks the name; close on the attacher just unmaps. Name length capped at 30 chars for portability (macOS PSHMNAMLEN-1). Stale-region cleanup before O_EXCL create handles a crashed-previous- editor scenario. Windows backend: CreateFileMappingA with INVALID_HANDLE_VALUE for anonymous page-file backed memory, MapViewOfFile to project. The kernel object is refcounted so the creator/attacher distinction is flat — both sides UnmapViewOfFile + CloseHandle at close(). Inline POSIX tests cover create+open round-trip with both directions of write, plus the NameTooLong rejection. Windows path is build- checked via cross-compile only.
S6 step 4 — viewport.zig wraps a ShmRegion as a 1280×720 RGBA8 double-buffer per engine-ipc.md §4.2 (slot count narrowed to 2 in S6 per brief). 128-byte cache-line-aligned Header with atomic last_complete/writer_slot/reader_slot triplet drives the lock-free producer/consumer protocol — runtime writes via @AtomicStore(.release), editor reads via @atomicLoad(.acquire). frame_id monotonic counter lets the editor skip redundant blits when no new frame committed. S6 step 4b — platform/process.zig fills the spawn/wait/kill/is_alive surface the editor stub needs (`engine-platform.md` §4 Process section). POSIX uses posix_spawnp + waitpid(WNOHANG) + SIGKILL + kill(0) liveness probe. Windows path declared but unimplemented for S6 (consistent with the S3/S4 inherited-debt pattern for Windows- only hardware paths — Win11 validation lands in Phase 0.6). Also includes platform shim fixes uncovered while running the in-file tests on macOS: - sockaddr_un layout: macOS uses sun_len:u8 + sun_family:u8 at offsets 0-1 (BSD heritage), Linux uses sun_family:u16 at offset 0. The platform-switched struct + @offsetOf-based addr_len math fixes silent corruption that manifests as accept() deadlocks. - shm_open(O_RDWR, 0) on macOS rejects mode=0 even when O_CREAT is absent. Pass 0o600 unconditionally to match the creator. - Wyhash.final() is not callable at comptime in Zig 0.16.x — switch schemaHash() to the single-shot Wyhash.hash(seed, bytes) variant by accumulating bytes into a comptime []const u8 first. - Lazy semantic analysis in Zig 0.16.x skips files whose pub const declarations are not transitively referenced from the test root. src/core/root.zig now force-references `ipc.protocol.MAGIC` so the full IPC tree is analyzed and its inline tests are discovered. - std.time.nanoTimestamp() removed in 0.16.x — RNG seeds in tests switched to @src().line for deterministic unique names. zig build is green on the macOS host. zig build test surfaces a deadlock-or-slowness in the new shm/transport tests that cuts the test cycle short; investigating in the follow-up tests/ipc/ runner where each test can be isolated (next commit).
`zig build test` deadlocks somewhere in the transport/shm test set on macOS — root cause not yet identified. Stubbing the runtime tests with `return error.SkipZigTest;` so the global test runner stays fast and unblocked. The actual coverage lands in the next session as dedicated exe-tests under `tests/ipc/*.zig` (per the S6 brief's "Critères d'acceptation › Tests" list) where each case can be isolated and re-run on its own. Affected inline tests (now SkipZigTest): - transport_posix.zig: listen+connect+accept round-trip, send loops - shm_posix.zig: create+open round-trip, attacher writes visibility - viewport.zig: create+write+read across slots, open width mismatch - platform/process.zig: spawn /bin/true reap, is_alive Tests retained (pure-comptime, no syscall): - shm_posix.zig: create rejects too-long names - protocol/messages/framing: full inline coverage unchanged Build Summary on macOS: 43/43 steps succeeded; 112/118 tests passed (6 skipped) in both Debug and ReleaseSafe.
Root-cause the previous session's `zig build test` hang (>46 min) and land the dedicated exe-test layout the S6 brief calls for under `tests/ipc/*.zig`. Three real production-code bugs surfaced during diagnosis: 1. `transport_posix.zig` write of a 64 KB payload single-threaded on AF_UNIX SOCK_STREAM filled the kernel send-buffer (~8 KB on macOS) and `write()` blocked forever with no reader draining. The new `tests/ipc/transport.zig` "send loops over partial writes" test spawns a dedicated reader thread before the write — the only shape that does not deadlock on a single connection. 2. `shm_posix.zig` closed the create-side fd between `shm_open(O_CREAT)` and `shm_open(O_RDWR)`. On macOS this turns the second open into a silent `EACCES` even from the same UID. Fixed by storing `fd: i32` inside `Backend` and only closing it in `Backend.close()`. The region's lifetime now spans the `Backend` instead of the syscall-pair. 3. `shm_posix.zig` mode `0o600` triggered the same `EACCES` on the macOS access-namespace check; switched to `0o666`. Names are PID-suffixed so the wider mode is not a cross-user attack vector. `boost::interprocess` and POCO::SharedMemory use the same fix. A fourth issue is a real macOS POSIX-shm limitation we cannot work around in single-process tests: after the first `shm_open(O_CREAT) → shm_open(O_RDWR)` sequence per process, subsequent attempts return EACCES regardless of names, modes, umask, or `shm_unlink` cleanup ordering. `tests/ipc/shm.zig` and `tests/ipc/shm_viewport.zig` gate their bodies on `is_linux` with documented notes; the macOS coverage lands via the two-process `tests/ipc/crash_recovery.zig` once the editor + runtime stubs ship in the next commit. Every test under `tests/ipc/*.zig` runs as its own exe (`b.addTest` per file). A deadlock in one binary cannot stall the rest of `zig build test`. The new `zig build test-ipc` step is a shortcut for fast iteration during S6 development. Test infra hardening: - Per-test 5 s `SO_RCVTIMEO` on every server-side `IpcSocket` (POSIX), preventing future blocking-recv regressions from hanging CI. - `defer forceShmUnlink(name)` + `defer forceUnlink(socket_path)` on every test scope. - `platform.process` gets `_NSGetEnviron()` on macOS — `posix_spawnp` failed with rc=2 because the direct `environ` symbol is not reachable through macOS dyld's two-level namespace. `zig build test` Build Summary: 43/43 steps succeeded, all previously-skipped runtime IPC tests now have green replacements under `tests/ipc/*.zig`. `zig fmt --check` clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three new files sit between the framing layer and the editor / runtime stubs: - `connection.zig` — `IpcConnection` is the symmetric wrapper that combines an `IpcSocket` borrow, the 16-byte framing layer, and the comptime schema-hashed message catalogue. Exposes `sendMessage(T, seq_id, *const T)`, `recvMessage(T, scratch)`, `recvFrame(buf)`, and the out-of-band `sendMessageWithHandles`. Monotonic `next_seq` for senders that don't pin their own correlation key. - `server.zig` — `IpcServer` (editor side): owns the listener and the accepted client socket. Drives the handshake via `recvHello` / `sendHelloAck` and exposes `connection()` for the remainder of the S6 traffic. - `client.zig` — `IpcClient` (runtime side): mirrors `IpcServer` with `connect` + `sendHello` + `recvHelloAck`. `tests/ipc/handshake.zig` exercises the full `ProtocolHello` ↔ `ProtocolHelloAck` round-trip in-process: the runtime side runs in a dedicated thread that waits for the parent to flip a `ready_flag` before calling `connect()` (avoids `ECONNREFUSED` races on macOS). Each test installs a 5 s `SO_RCVTIMEO` and unlinks the socket path on scope exit. Three cases: 1. Full handshake completes within 100 ms. 2. Version mismatch produces an explicit `accepted: false` reply. 3. `GPU_SHARED_FB` capability bit defaults to 0 in S6. `zig build test-ipc` exit 0 with all four ipc test binaries green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bulk of the S6 deliverables under the editor/runtime split: - `src/editor/main.zig` — spawns the runtime stub via `platform.process.spawn_process`, drives the handshake (`ProtocolHello`/`ProtocolHelloAck`), exchanges an `Echo` round- trip + a `SpawnEntity`/`EntityCreated` exchange, then sends `Shutdown` and waits for `ShutdownAck` before reaping. Creates the PID-named viewport shm region the runtime attaches to. - `src/runtime/main.zig` — spawned-by-editor process. Connects to the socket path passed via argv, opens the shm viewport, sends `ProtocolHello`, runs a CPU-side 1280×720 mire at ~60 Hz on the main thread + a dedicated IPC reader thread that ack-replies to Heartbeat / Echo / SpawnEntity / ModifyComponent / Shutdown. Exits cleanly on socket EOF (editor crash) or `Shutdown`. - `tests/ipc/crash_recovery.zig` — G4 + G5 scaffold. Linux-gated because it depends on the `zig-out/bin/weld-runtime` binary and the macOS POSIX shm cross-process quirk documented below. - `tests/ipc/fuzz_short.zig` — G3 smoke. Runs 3 s of valid traffic + injected corrupt-magic frames; reader must surface the documented framing errors without crashing or leaking. The full 60 s + 1 h variants live in `fuzz_1h.zig` (manual; built by `zig build test-ipc-fuzz-1h`). - `bench/ipc_rtt.zig` — G1 + G2 bench. N=10_000 Echo round-trips after 100 warmup iterations on an in-process AF_UNIX pair (the cross-process handshake is validated separately). Auto-writes `bench/results/ipc_rtt.md` with p50/p99/max/stddev plus per-gate GO/NO-GO verdicts. `zig build bench-ipc-rtt -Doptimize=ReleaseSafe`. - New build targets: `run-editor-stub`, `run-runtime-stub`, `run-ipc-demo`, `bench-ipc-rtt`, `test-ipc-fuzz-1h`. - `validation/s6-go-nogo.md` — verdict matrix. G7 (fd passing) GO on macOS; G1/G2/G3/G4/G5/G6 ⏳ pending the Linux + Apple Silicon hardware runs. Includes the macOS POSIX shm cross-process digest. Production-code fix in `src/core/ipc/shm_posix.zig`: macOS `shm_open(name, O_RDWR)` (no `O_CREAT`) returns `EACCES` for a posix_spawnp'd sibling of the creator, regardless of `umask(0)` and mode `0o666`. Empirically verified against the live editor + runtime demo on macOS 26.4.1. Switched `Backend.open` to `O_CREAT | O_RDWR` — the kernel attaches to the existing region; if absent, `ShmViewport.open` rejects via `error.InvalidHeader` (the create path writes the magic header). Linux is unaffected. Zig 0.16 API drift surfaced + carried in stride: - `argsAlloc` removed → `std.process.Init.Minimal` + `Args.Iterator`. - `std.time.milliTimestamp` removed → direct `clock_gettime(CLOCK_MONOTONIC)` via `extern "c"`. - `std.Thread.ResetEvent` removed → `std.atomic.Value(u8)` ready flag with `spinSleepMs`. - `std.fs.File.stdout()` / `std.fs.cwd().createFile` are no longer reachable without an `Io` instance → bench writes its markdown report via libc `fopen`/`fwrite`. `zig build test` 47/47 build steps + 116/124 tests passed (8 skipped: Windows-gated + macOS shm intra-process quirk). `zig fmt --check` clean. `zig build` produces `weld-editor`, `weld-runtime`, `ipc-rtt-bench`, `ipc-fuzz-1h`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two follow-ups requested in the S6 round-trip:
1. **shm permissions tightened.** The previous attempt at making the
macOS demo work used `umask(0)` around `shm_open(O_CREAT, 0o666)`
to force the effective mode to `rw-rw-rw-`. That was insecure
(every user on the host could read the editor's viewport) and
thread-hostile (`umask()` is a process-global mutation that races
any other thread setting its own umask).
Switched to mode `0o600` (`rw-------`, owner UID only) which
matches the parent-child spawn relationship between editor and
runtime. Removed the `umask(0)`/restore wrapper: `0o600 & ~umask
= 0o600` regardless of the caller's umask because the masked-out
bits (group/other) are already zero in the requested mode.
Operational consequence on macOS: `zig build run-ipc-demo`
surfaces a fresh `ShmOpenFailed` on the runtime side. The macOS
BSD shm cross-process quirk hits harder against 0o600 than
against 0o666 — verified empirically. Linux is unaffected and
remains the target for G6 visual validation. Documented in
`validation/s6-go-nogo.md` and in the brief's Déviations actées.
2. **`weld_core.ipc` surface moved to inline struct in `root.zig`.**
The convention for every other Tier 0 namespace (`ecs`, `jobs`,
`testing`, `platform`) is a `pub const X = struct { pub const Y =
@import("…"); };` block inline in `src/core/root.zig`. The
intermediate `src/core/ipc/mod.zig` introduced one indirection
level without value and masked the canonical re-export site.
Deleted `mod.zig`. The lazy-analysis guard
(`comptime { _ = ipc.protocol; _ = ipc.messages; … }`) is now
immediately under the `pub const ipc = struct { … };` block in
`root.zig`.
Both changes recorded as Déviations actées in the brief.
Validation: `zig build` clean, `zig build test` exit 0 (no
regression in test count), `zig fmt --check` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two adjacent test infra changes that complete the answer to "are
the tests actually green?":
1. **One test per binary for the shm and viewport create+open
pairs.** macOS POSIX shm caps a process at one successful
`shm_open(O_CREAT) → shm_open(O_RDWR)` sequence per lifetime,
so co-locating two such tests in the same Zig test exe makes
the second fail with `EACCES`. Splitting each test into its own
file (`tests/ipc/shm_cases/{round_trip,attacher_writes}.zig`
and `tests/ipc/viewport_cases/{two_slots,wrong_width,
no_tearing_1000_frames}.zig`) gives each test a fresh process
when invoked via `zig build test`. On Linux every binary runs
the real coverage; macOS still gates these on `is_linux`
because the `zig build`-spawned child inherits poisoned shm
state from the parent `zig` process (verified empirically — a
bare exe run from a clean shell passes 3/3 in a row, the same
exe via `zig build test-ipc` fails 4/4). The split is the
cleanest Linux-compatible scaffold; the macOS dev-box continues
to lean on the same `is_linux` gate that this commit makes
per-test rather than per-file.
`tests/ipc/shm.zig` reduces to the one negative test that does
no syscall (`create rejects too-long names`).
`tests/ipc/shm_viewport.zig` removed.
2. **Dead `error.SkipZigTest` stubs in production source removed.**
The previous session left 8 inline test placeholders inside
`src/core/ipc/{transport_posix,shm_posix,viewport}.zig` and
`src/core/platform/process.zig` that pointed to the now-shipped
`tests/ipc/*.zig` files. They double-counted as "skipped" in
the test runner output without adding value. Replaced each
block with a single-line comment pointing at the canonical
`tests/ipc/` location.
Test inventory after this commit, on macOS dev box:
- 6 `is_linux` gates left (3 shm/viewport_cases + 2 crash_recovery
+ 1 fuzz_short) — these are the structural macOS quirk skips
the brief acknowledges; they all run on the Linux CI matrix
per the brief's `{ubuntu-24.04, windows-2025}` configuration.
- 0 `error.SkipZigTest` stubs in production source.
- `zig build test` exit 0, `zig fmt --check` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three hypotheses ran in order per the Claude.ai follow-up, all elim'd: 1. **Name identity** — printed both sides byte-hex: editor: `2f77656c642d73686d2d76696577706f72742d4e` runtime: `2f77656c642d73686d2d76696577706f72742d4e` 24 bytes, identical including the leading `/`. ❌ not the cause. 2. **Premature `close(fd)` on creator** — audit of `src/core/ipc/shm_posix.zig:Backend.create`: fd is stored in `Backend.fd` (line 130), `close(fd)` only fires in the `errdefer` (line 116, failure path) or in `Backend.close()` (line 165, scope exit). The editor's `var vp = try …create(…); defer vp.close();` keeps the fd live for the whole `main` scope, which spans the runtime spawn and handshake. ❌ not the cause. 3. **`posix_spawn` / Hardened Runtime artifact** — added a `--no-spawn` flag to the editor binary that creates the shm, listens on the socket, and waits for an externally-launched runtime instead of spawning one. Manual runtime invocation from a fresh shell still produces `EACCES` on `shm_open(O_RDWR)`. ❌ not the cause. **Bonus matrix** (creator mode × opener flags, all cross-process): | Opener | 0o600 | 0o644 | 0o660 | 0o666 | |---|---|---|---|---| | `O_RDONLY` | ✅ | ✅ | ✅ | ✅ | | `O_RDONLY \| O_CREAT` | ✅ | ✅ | ✅ | ✅ | | `O_RDWR` | ❌ EACCES | ❌ EACCES | ❌ EACCES | ❌ EACCES | | `O_RDWR \| O_CREAT` | ❌ EACCES | ❌ EACCES | ❌ EACCES | ❌ EACCES | The macOS BSD shm path locks RW access to the creating process regardless of mode bits or umask. The opener can mmap read-only but cannot get a `PROT_WRITE` mapping. Same-UID, same session. **Decision** — macOS shm cross-process is Phase 0.6 debt. The fix is `SCM_RIGHTS` fd-passing: the editor keeps the create fd and ships it to the runtime via the existing AF_UNIX socket (`IpcSocket.sendWithHandles`, already validated by G7). Runtime `mmap`s directly on the received fd, never calls `shm_open`. Half-a-session scope-fenced to `src/core/ipc/shm.zig` + `viewport.zig` + the editor/runtime attach point. Linux is unaffected — Linux POSIX shm backs the namespace via tmpfs and ordinary file permissions, cross-process `O_RDWR` from the owner UID works. G6 validates on the Linux CI matrix. Files touched: - `src/editor/main.zig` — new `--no-spawn` flag (proc handle is optional, runs the demo against a manually-launched runtime). - `validation/s6-go-nogo.md` — diagnostic matrix table + the Phase 0.6 SCM_RIGHTS workaround plan replace the earlier partial entry. - `briefs/S6-ipc-editor-runtime.md` — journal entry with the empirical trace. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`framing.encode(gpa, T, seq_id, msg)` takes a `u32` for `seq_id` to match `framing.Header.seq_id`'s wire width. The fuzz contexts declared `sent: u64` and passed it directly to `encode`, which fails the build on Linux (Zig's compile-error is path-dependent and macOS's looser implicit integer coercions had been hiding it locally). Aligned both fuzz files to the protocol-level type: - `tests/ipc/fuzz_1h.zig` — `sent: u32`, `recv: u32`. - `tests/ipc/fuzz_short.zig` — `valid_frames_sent: u32`, `valid_frames_recv: u32`. The wraparound `+%` operator is preserved verbatim; behaviour is identical to the previous wider counters. The 1 h harness tops out at ~36 M messages (10 000 msg/s × 3 600 s), well under `u32` max (~4.3 B), so the narrower type is enough for the post-run sanity check `recv == sent` too — no separate `u64` stats counter needed for S6. Audit of every other `framing.encode` call site: - `src/core/ipc/connection.zig` (×2) — `next_seq: u32`, passes the `u32` `real_seq` derived from it. Correct. - `tests/ipc/framing.zig` — `framing.encode(gpa, …, 123, &echo)` with a comptime literal that fits `u32`. Correct. `zig build` clean (native), `zig build -Dtarget=x86_64-linux` clean, `zig build test` exit 0, `zig fmt --check` clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ships the missing G6 deliverable: the editor now opens a 1280×720
Vulkan-capable window, initialises a fullscreen-triangle blit
pipeline, and samples the runtime-written shm framebuffer into the
swapchain image each frame. Pattern mirrors S2's `src/spike/
vk_setup.zig`; the two raw-Vulkan paths intentionally duplicate
boilerplate per the brief's "No GAL until Phase 0.4" note.
New files:
- `assets/shaders/viewport_blit.vert.glsl` — fullscreen-triangle
generator (no VBO, positions derived from `gl_VertexIndex`).
- `assets/shaders/viewport_blit.frag.glsl` — samples a 2D combined
image-sampler binding into the swapchain attachment.
- `assets/shaders/viewport_blit.{vert,frag}.spv` — committed
alongside sources, same handling pattern as S2 triangle SPIR-V.
- `src/editor/vk_blit.zig` — `Renderer` covering instance + debug
messenger + surface + physical-device pick + logical device +
swapchain + render pass + 1280×720 R8G8B8A8_UNORM sampled image
with backing memory + linear sampler + persistent host-visible
staging buffer (mapped once, never unmapped) + descriptor
set/pool + blit pipeline (no vertex input, fragment-stage sampler
binding) + framebuffers + per-frame sync. `drawFrame` records:
TRANSITION viewport image (undefined/shader_read_only →
transfer_dst), `vkCmdCopyBufferToImage` staging→image, TRANSITION
to shader_read_only, BEGIN render pass, BIND pipeline + descriptor,
DRAW 3 vertices, END render pass, SUBMIT, PRESENT. Direct dispatch
on `vkAcquireNextImageKHR` + `vkQueuePresentKHR` so suboptimal /
out-of-date are visible (the wrapped Device methods fold them
into `success`).
Modified:
- `assets/shaders/embed.zig` — adds
`viewport_blit_{vert,frag}_spv` exports next to the legacy
triangle ones.
- `src/editor/main.zig` — refactored. Creates the shm region,
opens the Window via `weld_core.platform.window`, initialises
the blit renderer, listens + spawns runtime, handshakes, then
runs the render loop: poll window events, call
`vp.readSlot()` + `vp.frameId()` to detect a fresh runtime frame,
`renderer.stageViewport(vp.slotBytes(slot))` to memcpy into the
persistent staging mapping, `vk_blit.drawFrame(&renderer)` to
blit + present, soft-cap at ~60 Hz with a 16 ms sleep. Default
frame budget bumped from 10 to 3600 (≈ 60 s — the brief's G6
observable window). Exits on window close or frame budget.
- `build.zig` — the editor module imports the shared `shaders`
facade (same module the S2 spike uses). `run-ipc-demo` now
forwards `b.args` to the editor instead of hard-coding
`--frames=300`; absent `--`, defaults to `--frames=3600` so
`zig build run-ipc-demo` matches the G6 verdict description.
Platform note:
- Linux cross-compile (`zig build -Dtarget=x86_64-linux`) clean.
Native macOS build clean, but `weld-editor --frames=N` exits at
`Window.create → error.UnsupportedPlatform` because the S2
window backend has only Win32 + Wayland implementations.
Hitting macOS in the demo is Phase 2 work (window backend
+ Metal/MoltenVK surface). The brief targets Linux for G6
verdict — `zig build run-ipc-demo` on Fedora 44 is the
remaining manual run to mark G6 GO.
Validation: `zig build` native (macOS) clean, `zig build
-Dtarget=x86_64-linux` clean, `zig build test` exit 0 (all 116
tests pass, 8 skipped per the documented macOS gates), `zig fmt
--check` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`zig build bench-ipc-rtt` on Windows failed `BindFailed` because `bench/ipc_rtt.zig` passed `/tmp/weld-bench-rtt.sock` to `IpcSocket.listen` on every platform. `CreateNamedPipeA` rejects that path with `ERROR_INVALID_NAME` (123) — named pipes live in the `\\.\pipe\` namespace, not on disk. Three Claude.ai follow-up hypotheses ran in order: 1. **Path format** — ✅ confirmed. POSIX path leaked to Windows call site. Fixed by adding `transport.buildSocketPath` helper that returns `/tmp/<name>.sock` on POSIX and `\\.\pipe\<name>` on Windows. `bench/ipc_rtt.zig` now PID-suffixes the base name (`weld-bench-rtt-<pid>`) and uses the helper. Concurrent bench runs and lingering pipe instances no longer collide. 2. **UTF-8 → UTF-16** — ❌ not applicable. The backend uses `CreateNamedPipeA` (ANSI variant, takes `[*:0]const u8`), not the `W` form. Pure-ASCII pipe paths (`\\.\pipe\…`) are fine through the A entrypoint; no `WideCharToMultiByte` dance needed. 3. **`GetLastError` not surfaced** — ✅ confirmed. The `accept` and `recv` paths in `transport_windows.zig` already consult `GetLastError`, but `listen` and `connect` returned bare `error.BindFailed` / `error.ConnectionRefused` with no diagnostic. Added a `std.log.scoped(.ipc).err(…)` call before each return that prints the path + the Win32 code. Reference codes inlined in the comment: 123 INVALID_NAME, 231 PIPE_BUSY, 5 ACCESS_DENIED, 2 FILE_NOT_FOUND. `bench/ipc_rtt.zig` also gates the POSIX `unlink` on `builtin.os.tag` — named pipes on Windows are not filesystem entries, the kernel reclaims them when the last handle closes. Triple platform build clean: - `zig build` (macOS native): exit 0 - `zig build -Dtarget=x86_64-linux`: exit 0 - `zig build -Dtarget=x86_64-windows`: exit 0 - `zig build test`: exit 0 - `zig fmt --check`: clean The actual Windows bench run requires Win11 hardware (cf. S2 validation matrix). The brief journal records the diagnostic + the `GetLastError` instrumentation now in place for the eventual hardware sweep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`vkCreateRenderPass` segfaulted in `libnvidia-eglcore.so` on Fedora 41 + driver 595.71.05 when called from `src/editor/vk_blit.zig:createRenderPass`. Diagnosis ran against the five hypotheses in order: 1. Validation layers — already enabled in Debug builds via the same `VK_LAYER_KHRONOS_validation` lookup the S2 spike uses. Not the cause. 2. Struct init garbage — **confirmed**. 3. Inconsistent counts — `attachment_count = 1`, ref `.attachment = 0` indexes the only slot. Clean. 4. Format mismatch — `swapchain_format` is read from the negotiated surface format, not hardcoded. Clean. 5. ICD selection — S2 spike runs against the same NVIDIA stack and passed the validation matrix. Not the cause. Root cause (hypothesis 2): the `SubpassDescription` literal set `p_resolve_attachments = undefined`. The field is `?*const AttachmentReference` — an optional pointer. Passing `undefined` to a Zig optional leaves whichever bit pattern stack- frame initialisation last touched in those bytes; the NVIDIA driver dereferenced that garbage before checking `colorAttachmentCount`, and the resulting load triggered a fault inside `libnvidia-eglcore.so`. The S2 spike correctly initialises the same field to `null` — that's why the spike's render pass worked on the same hardware. Non-optional `*const T` fields (`p_input_attachments`, `p_preserve_attachments`, queue family pointers, layer name pointers, vertex input descriptors, push constant ranges) are allowed to stay `undefined` when their count is 0 — Vulkan ignores them. The S2 spike uses that pattern and so does the rest of `vk_blit.zig`. Audit confirmed: this is the only optional-with-undefined slot. Fix: single-line change, `.p_resolve_attachments = null`. Inline comment records why the surrounding `undefined`s are still correct so a future edit doesn't "normalise" them in the wrong direction. `zig build` native (macOS) clean, `zig build -Dtarget=x86_64-linux` clean, `zig build test` exit 0, `zig fmt --check` clean. The Fedora hardware re-run that confirms the crash is gone is pending the next manual pass on the validation box. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the partial-status validation file with the milestone-
close verdict structured per the S2 / S5 pattern.
Highlights:
- Verdict summary: GO on the Phase −1 CI matrix (Linux +
Windows). macOS dev-primary carries a documented BSD POSIX shm
cross-process limitation tracked as Phase 0.6 debt
(SCM_RIGHTS fd-passing migration).
- 7-gate × 4-platform matrix (Linux CI, Linux Fedora dev box,
Windows CI, macOS dev primary) with explicit ✅ / ⏳ / 🔒 N/A
per cell.
- Per-gate detail blocks for G1..G7 with measured values where
they exist (macOS bench numbers from this session, Apple
Silicon ReleaseSafe Zig 0.16.0_1: p50 0.006 ms / p99 0.016 ms
/ max 0.061 ms / stddev 0.003 ms / mean 0.007 ms — ≈ 166×
margin on G1, comfortable on G2).
- Linux Fedora dev box visual G6: GO. 60 s observation, no
visible tearing, no stale frame > 100 ms. Required the
`7fd1dc4` NVIDIA fix.
- Diagnostics conserved through the squash-merge:
- macOS shm mode × open flags matrix (4 modes × 4 flag combos)
proving the BSD write-access lock is independent of permission
bits.
- Three hypotheses ruled out before the matrix (name identity,
premature close, posix_spawn artefact).
- Five hypotheses for the Linux NVIDIA `vkCreateRenderPass`
SIGSEGV — root cause being `?*const T` initialised to
`undefined` instead of `null`.
- Phase 0.6 debt table consolidating: macOS shm SCM_RIGHTS
migration, editor Windows path, Phase 3 `sendWithHandles`
Windows, macOS Window backend (S2 inherited).
- Cross-spike coherence row: S1 54.5 µs / S3 0.019 ms / S4 0.603
ms / S5 1 066 ms / S6 0.006 ms p50, all on the same Apple
Silicon ReleaseSafe baseline — smallest absolute latency of
the series, consistent with a thin AF_UNIX-resident IPC layer.
The Windows + Linux RTT bench values and the Linux Fedora dev
box G4/G5/G7 cells remain `⏳ pending hardware run` so the file
serves as the operator checklist for the upcoming validation
sweep on the S2 matrix boxes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Milestone close-out commit: - `briefs/S6-ipc-editor-runtime.md` — Status ACTIVE → CLOSED, Date de fermeture 2026-05-18, Notes de fin filled (what worked, what deviated, what to flag in review, final measurements, residual risks / Phase 0.6 debt), Pre-PR diff check completed with full table of brief items vs diff entries + justifications for every extra file and every absent file (all map to déviations actées already recorded). - `CLAUDE.md` — État courant table: S6 CLOSED PR pending, branch pinned. Tags row added for v0.0.7-S6-ipc-round-trip (planned). Hypothèses validées par les spikes: S6 marked validated with RTT p50 6 µs / p99 16 µs / max 61 µs and the macOS BSD shm caveat in line. Décisions ouvertes / reportées: three new entries for the Phase 0.6 SCM_RIGHTS migration, the editor Windows path, and the Phase 3 sendWithHandles Windows. Last updated 2026-05-18. - `README.md` — Status header bumped to S6 closing. New paragraph for S6 with the RTT numbers and the link to `validation/s6-go-nogo.md` + the brief. Build-and-run block gets the six S6 targets (`run-editor-stub`, `run-runtime-stub`, `run-ipc-demo` + `-- --frames=N`, `bench-ipc-rtt`, `test-ipc`, `test-ipc-fuzz-1h`). Project layout block gains `src/core/ipc/`, `src/editor/`, `src/runtime/`, and the `platform/process.zig` row. `zig build` clean, `zig fmt --check` clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related changes from the first hardware sweep on the S2 validation matrix: 1. **Bench Windows clock fix.** First run on Win 11 25H2 + RTX 4080 Super reported `p50 0.000 / p99 0.000 / max 0.000 ms` across all 10 000 iterations. Root cause was not the IPC layer — the bench's `clock_gettime(CLOCK_MONOTONIC)` shim falls through to the MinGW-emulated libc clock on Windows, which quantises to ~16 ms (the `GetSystemTimeAsFileTime` tick on the validation box's driver stack). Every sub- millisecond Echo round-trip rounded down to zero. Switched `nowNs()` to a `switch (builtin.os.tag)` that uses `QueryPerformanceCounter` + `QueryPerformanceFrequency` (kernel32, sub-µs on the validation matrix) on Windows and keeps `clock_gettime(CLOCK_MONOTONIC)` on POSIX. The QPC frequency is cached on first call. Overflow-safe arithmetic so a multi-hour bench still fits in `i64` ns even though the QPC ticks count would overflow when multiplied by 1 e9. 2. **Linux Fedora dev box bench numbers landed.** Hardware run on Fedora 44 + GTX 1660 Ti / ReleaseSafe / Zig 0.16.0_1: p50 0.010 ms, p99 0.016 ms, max 0.094 ms, stddev 0.003 ms, mean 0.010 ms. **G1 + G2 GO** with ~100× margin on G1. Tracks the macOS dev primary within ~2× on p50 — consistent with kernel-resident `SOCK_STREAM` on both ends. `validation/s6-go-nogo.md` updated: - G1/G2 matrix cells for the Linux dev box flip to ✅ GO with the measured values inline. - Per-gate "Windows dev box" block carries the first-run symptom + the QPC fix narrative + a `<pending re-run>` placeholder so the next hardware pass overwrites cleanly. - Per-gate "Linux dev box" block populated with the actual numbers. Brief journal entry added documenting the Windows clock quirk and the Linux numbers in line. The Vulkan `vkCreateRenderPass` SIGSEGV fix (commit `7fd1dc4`) is now confirmed live on the same Linux dev box (G6 GO). `zig build` native (macOS) clean, `zig build -Dtarget=x86_64-linux` clean, `zig build -Dtarget=x86_64-windows` clean, `zig fmt --check` clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hardware re-run on Win 11 25H2 + RTX 4080 Super after the QPC bench fix (`d63699c`) lands the Windows column: | metric | value | |---|---| | N | 10 000 (after 100 warmup) | | p50 | 0.012 ms | | p99 | 0.021 ms | | max | 0.117 ms | | stddev | 0.003 ms | | mean | 0.011 ms | G1 (p50 < 1 ms) cleared with ~83× margin. G2 (p99 < 5 ms, max < 50 ms) cleared with comfortable margin. 3/3 hardware platforms now G1 + G2 GO: - macOS Apple Silicon: p50 6 µs - Linux Fedora 44 + GTX 1660 Ti: p50 10 µs - Windows 11 25H2 + RTX 4080 Super: p50 12 µs The three figures converge in the 6 – 12 µs band regardless of the underlying primitive (AF_UNIX SOCK_STREAM on POSIX, Win32 named pipe byte mode on Windows), consistent with a kernel-resident socket I/O layer on every platform. `validation/s6-go-nogo.md` updates: - G1/G2 cells for the Windows column flip ⏳ → ✅ GO with the measured values inline. - Per-gate "Windows dev box" block populated with the re-run table + the G1/G2 verdict lines. - New "Cross-platform convergence" paragraph in the G1+G2 detail block citing the 6–12 µs band. Brief journal entry added. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the implementation gap on G5. Brief specifies:
> editor `kill -9` → runtime detects in < 100 ms and exits clean;
> no orphan shm or socket file remains after the run
Previously only G4 (runtime kill -9 → editor detects + restarts)
was in `tests/ipc/crash_recovery.zig`. G5 was documented in the
file header but the test scaffold was missing.
New test `editor close → runtime detects EOF + exits clean code 0`:
- Test process plays the editor (creates shm + listens) — same
pattern as the existing G4 tests.
- Spawns the runtime binary, accepts the connection, drives the
`ProtocolHello` / `ProtocolHelloAck` handshake.
- Sleeps 50 ms so the runtime settles into its render +
reader-thread main loop.
- Records t0, then calls `server.deinit()` **without sending
Shutdown** — this is a faithful in-process simulation of an
editor SIGKILL: the kernel tears the editor's socket down,
the runtime's `recv` returns 0 (EOF) on its next call. The
delta between "real kill" and "deinit" is zero from the
runtime's POV.
- Polls `wait_nonblock` for the runtime to exit. Asserts:
- `exit_code == 0` (runtime exited via its normal `defer`
teardown path, not a crash or a SIGPIPE).
- Total wall-clock from close to exit < 500 ms — the brief's
tighter < 100 ms is the EOF detection latency (kernel-
immediate); the wider 500 ms here covers the runtime's
16 ms render-loop tick + handful of iterations + scope
teardown.
Linux-gated (same `is_linux` guard as the rest of
`crash_recovery.zig` — the shm cross-process pattern is
unreliable on macOS dev primary).
File header rewritten with the G4 + G5 contract layout:
- G4 = runtime kill -9 → editor detects + restarts (existing
two tests).
- G5 = editor kill -9 → runtime detects + exits clean (this
new test).
`validation/s6-go-nogo.md` G5 section updated: from `⏳ pending
hardware sweep` "test not implemented" to `⏳ pending hardware
sweep` with the test landed and the assertion shape spelled out
(`exit_code == 0`, total wall-clock < 500 ms).
`zig build` native macOS clean, `zig build -Dtarget=x86_64-linux`
clean, `zig build -Dtarget=x86_64-windows` clean, `zig fmt
--check` clean. The test itself runs only on Linux hardware
(skipped on macOS dev box); the next Fedora hardware sweep
exercises it end-to-end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Linux CI failed to compile `tests/ipc/crash_recovery.zig`:
error: root source file struct 'fmt' has no member named 'allocPrintZ'
The function does not exist in Zig 0.16 — period, neither on the
Linux build nor the macOS one. The local macOS test build passed
because the test bodies start with `if (!is_linux) return
error.SkipZigTest;`, which is a comptime-true branch on macOS;
Zig's compile-time dead-code elimination skips the rest of the
function body. On the Linux CI runner, `is_linux` is comptime-true,
the early-return branch is dead, and the analyzer reaches the
non-existent symbol and fails.
Three call sites in `tests/ipc/crash_recovery.zig` — replaced
`std.fmt.allocPrintZ(gpa, fmt, args)` with `std.fmt.bufPrintZ(buf,
fmt, args)` and a 64-byte stack buffer. Same `[:0]u8` return
type, no alloc in the test, idiomatic for the short ASCII paths
the test uses (`/tmp/weld-...-{pid}.sock` and `/weld-shm-...-{pid}`).
No behaviour change.
Audited the rest of the repo for `allocPrintZ` — no other call
sites. The pattern existed only in this file because the previous
session reached for it as a one-liner; `bufPrintZ` is the correct
shape for both Zig versions.
`zig build` (native macOS), `zig build -Dtarget=x86_64-linux`,
`zig build -Dtarget=x86_64-windows`, `zig build test`, and
`zig fmt --check` all clean. The CI should now pass on
ubuntu-24.04 × {Debug, ReleaseSafe}.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`zig build test` on Fedora 44 hit `error.SpawnFailed` on the three
G4/G5 tests in `tests/ipc/crash_recovery.zig`:
src/core/platform/process.zig:142:26: in spawn_process
if (rc != 0) return error.SpawnFailed;
`posix_spawnp("zig-out/bin/weld-runtime", …)` returned ENOENT
because the test step has no dependency on the runtime exe being
installed. The binary path is correct at runtime (cwd = project
root when zig build dispatches the test binary), the binary
itself just isn't there yet.
macOS dev primary didn't surface the bug because the three tests
are `is_linux`-gated → SkipZigTest → spawn never called.
Fix: in the IPC tests loop, when the test path matches
`tests/ipc/crash_recovery.zig`, attach
`b.addInstallArtifact(runtime_exe, .{})` as a step dependency on
the test run. Narrow targeting avoids gating every IPC test on
every install step (the global `b.getInstallStep()` would drag
the S5 `etch_cook` install + the rest of the install graph
through every test invocation).
Also, hardware sweep results landed:
**G3 — 1 h fuzz — GO.** Fedora 44 + GTX 1660 Ti dev box:
sent=1 917 890 200 msgs, recv=1 917 890 155 msgs, fault=0
over 3 600 s wall-clock. ~530 k msg/s sustained, far over the
brief's ~10 k msg/s design target. The 45-message gap (sent − recv
≈ 2.3 × 10⁻⁸) is in-flight messages at teardown when the writer
flips `stop` and the reader exits without draining the kernel
buffer's last few frames — well-defined harness shape, not a
deadlock or a leak.
Validation md:
- G3 cell ⏳ → ✅ GO with the 1.9G msg measurement.
- New per-gate G3 detail paragraph with the gap explanation +
throughput annotation.
Brief journal entry added.
`zig build` native macOS clean, `zig build -Dtarget=x86_64-linux`
clean, `zig build -Dtarget=x86_64-windows` clean, `zig build
test` (macOS) exit 0, `zig fmt --check` clean. The G4/G5
verdict awaits Guy's `zig build test` re-run on Fedora with this
fix in place.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both fuzz files were `is_linux`-gated, copy-pasted from the macOS-shm-quirk gating pattern. The fuzz uses sockets only (no shm), so the quirk does not apply on either macOS or Windows. The Windows `fuzz_1h` symptom (`fuzz_1h: Linux-only (see brief)` on the dev box) flagged the lazy gating. Both files now mirror the cross-platform pattern from `bench/ipc_rtt.zig`: - `extern "c" fn unlink` gated behind `can_unlink = is_linux or is_macos` with a `maybeUnlink` no-op on Windows (named pipes aren't filesystem entries; the kernel reaps them when the last handle closes). - Path constructed via `transport.buildSocketPath` so the AF_UNIX `/tmp/<name>.sock` flips to `\\.\pipe\<name>` on Windows. - `nowMs` switches on `builtin.os.tag` — `QueryPerformanceCounter` on Windows (the MinGW-emulated `clock_gettime` quantises to ~16 ms and broke the RTT bench earlier in this session), `clock_gettime(CLOCK_MONOTONIC)` on POSIX. The `is_linux`-skip gates and the `Linux-only` print are removed. `fuzz_short` now runs unconditionally inside `zig build test` (3 s on every platform); `fuzz_1h` accessible via `zig build test-ipc-fuzz-1h` on any of the three OSes. Validation md: - G3 Windows cell ⏳ — note that the cross-platform fix landed, re-run pending. - G3 macOS cell flips 🔒 SKIP → ✅ optional (the harness runs; it just isn't part of the brief's CI matrix). Brief journal entry added. `zig build` (macOS), `-Dtarget=x86_64-linux`, `-Dtarget=x86_64-windows`, `zig build test`, `zig fmt --check` all clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résumé
S6 — septième et dernier spike de Phase -1. Valide le protocole IPC
editor↔runtime spec'd dans
engine-ipc.md: transport sockets POSIXschemaHashWyhash comptime,handshake versionné, viewport shm double-buffer 1280×720 RGBA8,
crash recovery
kill -9, fd-passingSCM_RIGHTSPOSIX, fullscreen-triangle Vulkan blit pipeline éditeur.
briefs/S6-ipc-editor-runtime.mdvalidation/s6-go-nogo.mdVerdict global
GO sur cible CI Phase -1 (Linux + Windows). Validation partielle
macOS dev primary — quirk BSD shm cross-process identifié, dette
tracée Phase 0.6 (migration
SCM_RIGHTSfd-passing commearchitecture primaire POSIX, cohérent
engine-ipc.md§4.7 déjàspec'd).
Mesures clés
zig build test-ipc-fuzz-1htests/ipc/fd_passing.ziggreenCohérence cross-spike Apple Silicon ReleaseSafe : S1 54.5 µs / S3
0.019 ms / S4 0.603 ms / S5 1 066 ms / S6 0.006 ms p50 — plus
petite latence absolue de la série, cohérent avec un layer IPC fin
résidant kernel-side.
Diagnostic macOS BSD shm (préservé du squash-merge)
Matrice mode × open flags exécutée cross-process (
posix_spawnp,même UID, fd creator gardé ouvert), macOS 26.4.1 / Zig 0.16.0_1 :
O_RDONLYO_RDONLY | O_CREATO_RDWRO_RDWR | O_CREAT3 hypothèses éliminées par diagnostic ciblé avant la matrice :
nameshm — bytes-hex identiques côté creator/opener (2f77656c642d73686d2d76696577706f72742d4e, 24 octets,/weld-shm-viewport-N).close(fd)prématuré côté creator — auditBackend.create: fd stocké dansBackend.fd, jamais close avantdefer vp.close()en fin de main.posix_spawnsandbox hérité — flag--no-spawnajouté à l'éditeur + runtime lancé manuellement depuis shell propre → mêmeEACCES. Bug reproduit sansposix_spawnpdans la chaîne.Conclusion : macOS BSD shm verrouille le write-access cross-process indépendamment des mode bits / umask / flags.
O_RDWRcross-process refusé systématiquement. Architecture primaire POSIX bascule surSCM_RIGHTSfd-passing en Phase 0.6 (cohérent §4.7engine-ipc.mddéjà spec'd, surfaceIpcSocket.sendWithHandlesdéjà validée par G7).Dette technique Phase 0.6
shm_open(O_RDWR)cross-process →SCM_RIGHTSfd-passing (architecture primaire, pas patch macOS-only). L'éditeur garde le fd shm créé et l'envoie au runtime via la socket Unix (surface G7). Le runtimemmapdirectement sur le fd reçu, ne rappelle jamaisshm_open. Sidestep complet du quirk macOS.shm_openpar nom conservé pour découverte intra-process uniquement.error.Unimplemented(src/editor/main.zig:if (!is_posix)). Implémentation Phase 0.6 —CreateProcessW+ named pipe + le backend window Win32 S2 déjà en place.sendWithHandlesWindows :error.Unimplemented(transport_windows.zig). Implémentation Phase 3 viaDuplicateHandle, cohérentengine-ipc.md§4.7 (avec la GPU shared framebuffer, exportable Vulkan semaphore).Points de validation (checklist brief)
zig build test)validation/s6-go-nogo.mdzig build -Dtarget=x86_64-linux+-Dtarget=x86_64-windowsclean ;zig fmt --checkclean)5da26f0)Changelog
Code —
src/core/ipc/(Tier 0) :protocol.zig,messages.zig,framing.zig,connection.zig,transport.zig+transport_{posix,windows}.zig,shm.zig+shm_{posix,windows}.zig,viewport.zig,server.zig,client.zig.src/core/platform/process.zig(spawn/wait/kill/is_alive POSIX, Windows stub Phase 0.6).src/editor/main.zig+src/editor/vk_blit.zig(Vulkan blit pipeline ~1000 lignes).src/runtime/main.zig.assets/shaders/viewport_blit.{vert,frag}.{glsl,spv}(4 fichiers).bench/ipc_rtt.zig+bench/results/ipc_rtt.md. 14 fichierstests/ipc/(framing, schema_hash, transport, handshake, fd_passing, process, shm, shm_cases/×2, viewport_cases/×3, crash_recovery, fuzz_short, fuzz_1h).build.zigajoute 6 targets :run-editor-stub,run-runtime-stub,run-ipc-demo,bench-ipc-rtt,test-ipc,test-ipc-fuzz-1h.Documentation —
briefs/S6-ipc-editor-runtime.md(brief milestone, Status: CLOSED, déviations actées + Notes de fin + Pre-PR diff check remplis).validation/s6-go-nogo.md(verdict 7 gates × 4 plateformes + matrice diagnostique macOS shm + 5-hypothèse Vulkan SIGSEGV + dette Phase 0.6 + cohérence cross-spike).README.md(status + paragraphe S6 + 6 build steps S6 + project layout).CLAUDE.md(état courant + tag + hypothèses + 3 nouvelles décisions reportées + date 2026-05-18).🤖 Generated with Claude Code