# Research / Discovery — xce-test-e2e-primitives ## Discovery type LIGHT (extension to an existing single-file test client). No external research needed. ## Key findings (from src/controller/testsuite/test.c) - Dispatch: `execute_line(line)` → `parse_argv` → `find_command(argv[0])` → `command->func(argc, argv)`; handlers return `int` (`<0` = errno-style error). Command table is `command_t {name, func, doc}` arrays per context. - Main read loop reads a line, `rc = execute_line(s)`, and on `rc<0` only `SET_ERROR(-rc)` + continues; `main` returns 0 → **failures never affect the exit code** (the core gap for scriptable E2E). - `cmd_jobsub`/`cmd_joblist` already drive the client via `active_ctx` and libxce client-side master-rotation/failover — `wait-primary` and the assertions can reuse these paths. - bug-786: `cmd_jobsub` can print `jobsubmit ok: JobId: 63-15--1-...` (uninitialized id) on a non-clean ack; controller then logs `handle_jobsubmit fail to lock job `. Root: success is reported without verifying the reply status/jobid. ## Design decisions - **Extend-in-place, single TU.** Add a `preprocess_and_run` wrapper (blank/`#`/`!`/auto-var-substitution) + file-scope verdict state; new commands as ordinary table entries; `main` returns `g_session_failed ? 1 : 0`. No new files, no new opcode, no JSON. - **Fixed auto-vars only** (`$?`, `$jobid`, `$jobcount`) — substitution, not a variable system; unset reference fails (no garbage). - **Shell-escape via `system()`**, status → `$?`; node lifecycle stays in the shell. - **`wait-primary`** loops an existing failover-aware client op until success/timeout (monotonic clock). - Exit-code trustworthiness depends on a clean exit; reuse `ASAN_OPTIONS=detect_leaks=0` for the soak (client leak cleanup is separate/out of scope). ## Risks - `system()` shell-escape = arbitrary execution — acceptable for a dev/test client only. - Auto-var substitution must be whole-token and conservative to avoid surprising expansions.