Every fec error message was written to stderr, and COMMAND.COM can only
redirect handle 1 -- ">" is the whole vocabulary, "2>" is not parsed at all.
So a failing compile recorded exit code 1 and a zero-byte log, and the actual
message went to a screen nobody reads. Confirmed directly: `FEC.EXE --check`
on a fixture that must fail produced rc=1 and 0 bytes of stdout.
That is why an unexpected compiler failure was undiagnosable. It also means
the M6 reject cases have only ever asserted "exit code was nonzero" -- the
error text they nominally check has never been observable to the runner.
Add fe_diag_stream(), which resolves once to stdout when FE_DIAG_STDOUT is set
and stderr otherwise, and route diag.c and driver.c through it. The default is
unchanged, so interactive use keeps writing to stderr; the runner sets the
variable in RUN.BAT. The stderr references in check.c and emit_c.c are the
Ferro language's own std.io.stderr writer and are deliberately untouched.
Verified in DOSBox-X: 155 passed. A rejecting compile now records its message,
source excerpt and caret in RESULTS\<key>.LOG.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BScg8CF1sAAM2zVHAu5zvW
조건부 이동, 이중 destroy, 직접 drop 호출에 대한 실패 fixture를 추가하고
runtime harness와 test-dos.bat를 그에 맞춰 갱신한다.
M5는 아직 완료가 아니다. 모든 경로에서 정확히 1회 cleanup, defer/drop의 선언
역순 병합, try 전파 경로 cleanup, MaybeMoved 런타임 live flag, struct drop과
필드 역순 drop, 분기/루프 상태 합류, 누수/이중해제 카운터 harness가 남아 있다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PQm6oAvWX4Lp3iSN5AHGT