feat(el-runtime): native Windows port of el_runtime.c (+ engram_node_full corruption fix) #55

Merged
will.anderson merged 4 commits from feat/windows-el-runtime into stage 2026-06-20 00:06:09 +00:00
Member

Native Windows port of el_runtime.c plus the engram_node_full corruption fixes the port was based on (2026-06-15).

Commits (not yet in main):

  • Fix engram_node_full wrapper field corruption + add node_type/tier validation
  • allow SessionSummary node_type in validation allowlist
  • native Windows port of el_runtime.c (winsock/dlsym/CreateProcess)
  • promote http_handler typedefs to el_runtime.h (cross-module + Windows)

The first two are engram data-integrity fixes; the last two are the Windows runtime port. Opening for Will to review.

🤖 Generated with Claude Code

Native Windows port of el_runtime.c plus the engram_node_full corruption fixes the port was based on (2026-06-15). Commits (not yet in main): - Fix engram_node_full wrapper field corruption + add node_type/tier validation - allow SessionSummary node_type in validation allowlist - native Windows port of el_runtime.c (winsock/dlsym/CreateProcess) - promote http_handler typedefs to el_runtime.h (cross-module + Windows) The first two are engram data-integrity fixes; the last two are the Windows runtime port. Opening for Will to review. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tim.lingo changed target branch from main to stage 2026-06-17 18:32:34 +00:00
tim.lingo added 2 commits 2026-06-17 18:32:35 +00:00
Compiles for Windows x64 via mingw-w64 and still compiles clean on POSIX
(darwin/linux) — all Windows code is behind #ifdef _WIN32, POSIX path unchanged.

- el_platform_win.h (new): winsock2 + auto WSAStartup, el_closesocket(),
  dlsym->GetProcAddress, popen/_popen, mkdir/_mkdir, setenv/_putenv_s,
  timegm/_mkgmtime, localtime_r/gmtime_r. Threading unchanged — mingw
  winpthreads supplies <pthread.h> + -lpthread.
- el_runtime.c: include block guarded; 10 socket-close sites -> el_closesocket();
  setsockopt arg4 cast; tm_zone guarded; exec_bg fork/exec -> CreateProcess.

Part of feat/windows-port. Core-el change, for Will's review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(el-runtime): promote http_handler typedefs to el_runtime.h (cross-module + Windows)
El SDK Release / build-and-release (pull_request) Failing after 13m0s
a36a62ca14
http_handler_fn / http_handler4_fn were defined only inside el_runtime.c, so soul
modules (routes/chat/...) that reference them via cross-module forward declarations
couldn't see the types — which broke the Windows link of every module. Moving the
public function-pointer types to the shared header is the correct home and unblocks
the build on all platforms (identical typedef, C11-safe redefinition in el_runtime.c).

With this, the soul links into a native Windows neuron.exe (mingw, static) that boots
and serves HTTP on :7770 — verified /health → 200 {"status":"alive",...} in a Win11 VM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner

Review: feat(el-runtime): native Windows port of el_runtime.c (+ engram)

Thanks for the port Tim — the overall structure is solid (consistent _WIN32 guards, correct Winsock include ordering, WSAStartup via __attribute__((constructor)), winpthreads strategy). That said there are 5 blockers across two categories that need to land before this can merge.


Blockers — will not compile or link

1. nanosleep has no Windows shim
nanosleep() is called in four places in el_runtime.c with no shim in el_platform_win.h. On mingw-w64 this is a linker error. Needs a Sleep()-based replacement (e.g. timeBeginPeriod(1) + Sleep(ms) for sub-millisecond precision, or just Sleep(ns/1e6)).

2. Duplicate http_handler_fn / http_handler4_fn typedefs
These typedefs are now defined in both el_runtime.h (newly promoted) and as local typedefs inside el_runtime.c. C11 doesn't allow duplicate typedef declarations of the same type — this is a compile error under -Wpedantic/-Werror on all platforms, not just Windows.

3. el_mem_check declared but definition deleted
The function body was removed in this PR but the declaration remains in el_runtime.h. Any caller gets an undefined symbol at link time on both Windows and Unix.


Blockers — runtime correctness on Windows

4. close(fd) in http_worker / http_worker_v2 (line ~1576, ~1826)
http_worker and http_worker_v2 call close(fd) in their teardown paths. On Windows, close() is the CRT file-descriptor closer — it does nothing to Winsock sockets. Every HTTP request leaks one SOCKET handle. The accept()-loop error paths were correctly migrated to el_closesocket() but the normal teardown paths were not. A long-running server exhausts system handle space and starts rejecting connections.

5. accept()int cfd truncates 64-bit SOCKET handle (line ~1613, ~1863)
accept() returns SOCKET (UINT_PTR, 64-bit unsigned). Storing that in int cfd silently truncates the upper 32 bits. HttpWorkerArg.fd is also typedef'd as int (line ~1539), so the corrupted handle is passed through to the worker thread. Any socket handle above 0x7FFFFFFF causes WSAENOTSOCK or closes the wrong descriptor. GCC -Wconversion fires on mingw-w64 for this narrowing. Fix: HttpWorkerArg.fd should be SOCKET (or uintptr_t) behind #ifdef _WIN32.


Significant — fix before merge

6. unsetenv("TZ") shim sets TZ="" instead of removing it
_el_apply_zone() calls unsetenv("TZ") + tzset() to restore the OS local timezone. POSIX: TZ removed → tzset reads /etc/localtime → correct local time. Your shim calls _putenv_s("TZ", "") which sets TZ to an empty string, not removes it — _tzset() sees TZ="" and silently falls back to UTC. All El programs doing local-timezone date operations on Windows return UTC. Fix: use _putenv_s("TZ=", "") (the environment deletion form) or check SetEnvironmentVariable("TZ", NULL).

7. IANA timezone names silently broken on Windows CRT
_el_apply_zone() passes IANA names (e.g. America/New_York) to setenv("TZ"). The Windows CRT only understands POSIX timezone specs (e.g. EST5EDT,M3.2.0,M11.1.0). On Windows, IANA names produce no error — the CRT just defaults to UTC. Either require callers to pass POSIX specs, or bundle a minimal IANA→POSIX lookup table.

8. el_closesocket(int s) parameter type
SOCKET is UINT_PTR (64-bit). The int parameter means handles above 0x7FFFFFFF are sign-extended before being passed to closesocket(). Same root issue as finding #5. Parameter should be SOCKET or uintptr_t behind #ifdef _WIN32.

9. EINTR retry after accept() never fires on Windows
The accept() error path checks errno == EINTR. On Windows, Winsock errors come from WSAGetLastError(), not errno. Any transient socket error permanently exits the server loop instead of retrying.


Minor

  • setenv shim ignores overwrite=0 — no current callers use it but the contract is violated
  • WSAStartup return not checked; inited set to 1 even on failure (silently breaks all networking with no diagnostic)
  • No CI changes / no cross-compile verification included — at minimum confirm a local x86_64-w64-mingw32-gcc build succeeds

What's working

Platform detection is clean and consistent, WSAStartup/include ordering is correct, threading via winpthreads needs no changes, exec_bg/CreateProcess path is properly guarded, setsockopt cast to const char* is correct.

Do not merge until the 5 blockers above are resolved.

## Review: `feat(el-runtime): native Windows port of el_runtime.c (+ engram)` Thanks for the port Tim — the overall structure is solid (consistent `_WIN32` guards, correct Winsock include ordering, `WSAStartup` via `__attribute__((constructor))`, winpthreads strategy). That said there are 5 blockers across two categories that need to land before this can merge. --- ### Blockers — will not compile or link **1. `nanosleep` has no Windows shim** `nanosleep()` is called in four places in `el_runtime.c` with no shim in `el_platform_win.h`. On mingw-w64 this is a linker error. Needs a `Sleep()`-based replacement (e.g. `timeBeginPeriod(1)` + `Sleep(ms)` for sub-millisecond precision, or just `Sleep(ns/1e6)`). **2. Duplicate `http_handler_fn` / `http_handler4_fn` typedefs** These typedefs are now defined in both `el_runtime.h` (newly promoted) and as local `typedef`s inside `el_runtime.c`. C11 doesn't allow duplicate typedef declarations of the same type — this is a compile error under `-Wpedantic`/`-Werror` on all platforms, not just Windows. **3. `el_mem_check` declared but definition deleted** The function body was removed in this PR but the declaration remains in `el_runtime.h`. Any caller gets an undefined symbol at link time on both Windows and Unix. --- ### Blockers — runtime correctness on Windows **4. `close(fd)` in `http_worker` / `http_worker_v2` (line ~1576, ~1826)** `http_worker` and `http_worker_v2` call `close(fd)` in their teardown paths. On Windows, `close()` is the CRT file-descriptor closer — it does nothing to Winsock sockets. Every HTTP request leaks one `SOCKET` handle. The `accept()`-loop error paths were correctly migrated to `el_closesocket()` but the normal teardown paths were not. A long-running server exhausts system handle space and starts rejecting connections. **5. `accept()` → `int cfd` truncates 64-bit `SOCKET` handle (line ~1613, ~1863)** `accept()` returns `SOCKET` (`UINT_PTR`, 64-bit unsigned). Storing that in `int cfd` silently truncates the upper 32 bits. `HttpWorkerArg.fd` is also `typedef`'d as `int` (line ~1539), so the corrupted handle is passed through to the worker thread. Any socket handle above `0x7FFFFFFF` causes `WSAENOTSOCK` or closes the wrong descriptor. GCC `-Wconversion` fires on mingw-w64 for this narrowing. Fix: `HttpWorkerArg.fd` should be `SOCKET` (or `uintptr_t`) behind `#ifdef _WIN32`. --- ### Significant — fix before merge **6. `unsetenv("TZ")` shim sets `TZ=""` instead of removing it** `_el_apply_zone()` calls `unsetenv("TZ") + tzset()` to restore the OS local timezone. POSIX: TZ removed → tzset reads `/etc/localtime` → correct local time. Your shim calls `_putenv_s("TZ", "")` which sets TZ to an *empty string*, not removes it — `_tzset()` sees `TZ=""` and silently falls back to UTC. All El programs doing local-timezone date operations on Windows return UTC. Fix: use `_putenv_s("TZ=", "")` (the environment deletion form) or check `SetEnvironmentVariable("TZ", NULL)`. **7. IANA timezone names silently broken on Windows CRT** `_el_apply_zone()` passes IANA names (e.g. `America/New_York`) to `setenv("TZ")`. The Windows CRT only understands POSIX timezone specs (e.g. `EST5EDT,M3.2.0,M11.1.0`). On Windows, IANA names produce no error — the CRT just defaults to UTC. Either require callers to pass POSIX specs, or bundle a minimal IANA→POSIX lookup table. **8. `el_closesocket(int s)` parameter type** `SOCKET` is `UINT_PTR` (64-bit). The `int` parameter means handles above `0x7FFFFFFF` are sign-extended before being passed to `closesocket()`. Same root issue as finding #5. Parameter should be `SOCKET` or `uintptr_t` behind `#ifdef _WIN32`. **9. `EINTR` retry after `accept()` never fires on Windows** The `accept()` error path checks `errno == EINTR`. On Windows, Winsock errors come from `WSAGetLastError()`, not `errno`. Any transient socket error permanently exits the server loop instead of retrying. --- ### Minor - `setenv` shim ignores `overwrite=0` — no current callers use it but the contract is violated - `WSAStartup` return not checked; `inited` set to 1 even on failure (silently breaks all networking with no diagnostic) - No CI changes / no cross-compile verification included — at minimum confirm a local `x86_64-w64-mingw32-gcc` build succeeds --- ### What's working Platform detection is clean and consistent, WSAStartup/include ordering is correct, threading via winpthreads needs no changes, `exec_bg`/`CreateProcess` path is properly guarded, `setsockopt` cast to `const char*` is correct. **Do not merge until the 5 blockers above are resolved.**
will.anderson added 1 commit 2026-06-19 23:59:35 +00:00
will.anderson added 1 commit 2026-06-20 00:06:00 +00:00
Merge branch 'stage' into feat/windows-el-runtime
El SDK CI - stage / build-and-test (pull_request) Failing after 15s
99b113ea9d
Resolve el_runtime.c conflict: include both sys/resource.h (from stage)
and el_closesocket POSIX shim (from Windows port) within the #else block.
will.anderson merged commit 2d751890ea into stage 2026-06-20 00:06:09 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: neuron-technologies/el#55