nightly reds: daslang-live loads live_host, pinvoke panic leak, Windows 64 KB pipe, LINT030 argument order, CRLF/tsan/fast-math lanes - #3993
Conversation
…veHost shared module's lifecycle exports before any require names it, and the lazy module scan now defers that module, so live mode never turned on and no HTTP API started - every dasImgui playwright test waited out its ready budget since the lazy-load merge; the host asks the deferred-module loader for live_host before the dlsym, and tests/live_host/test_host_ready.das spawns the daslang-live beside dastest's own daslang on a lifecycle fixture, polls /status and ends it over /shutdown, red on the old binary at 50 s and green at 0.8 s; pinvoke_named and pinvoke_impl2_core composed their message in a string alive across throw_error_at, whose longjmp unwinds nothing, and the new by-name ambiguity test's recover made the ASan lane report the 87 bytes - throw_pinvoke_error moves the text to a stack buffer and releases the string first, src/builtin/ARCHITECTURE.md sec.4 says why; the dasLLAMA image layout stamp hashed source text as checked out, so the Windows lane read every line one byte longer and asked for a re-stamp no other platform could match - the gate folds CRLF before hashing, proven by hashing the folder converted to CRLF against the committed stamp; the tree-sitter generate gate compares bytes against a CRLF checkout on Windows - the four generated artifacts join .gitattributes as eol=lf like dasClangBind's; the fast-math lane's float2string compare reads fmt's printing through a fast-math TU and the vecmath backend rows pin IEEE NaN, tie and out-of-range answers, so those three targets pin precise math the way test_isnan_fastmath_region.cpp does and #error when built otherwise; the four stale nolint markers the whole-tree lint reported go; and the builtin module's handmade page stops telling the reader to `require builtin`, a spelling that resolves to a sibling file, so doc-verify's one red page compiles - the generator writes the implicit-module sentence for a module registered with no require line Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e tsan lane's tray child exits 66 on libdbus's own lock order - dbus_bus_get_private takes the library's two global locks one way and dbus_connection_close the other, both on the main thread, a lock-order report on internals the tray neither holds nor can reorder - so .github/tsan_suppressions.txt names the dlopened library's module as the frame (proved in the daslinux VM under a -DDAS_USE_SANITIZER=tsan build: the report, then twelve passes and no report); the Windows AOT host ran every module_cache child and read nothing back because report_child(t, phase, run_child(cmd, out), out, marker) nests the run beside the out it writes in one argument list, an evaluation order the AOT C++ leaves to the compiler and MSVC and clang-cl take right to left while the interpreter, the JIT and the Linux compilers go left to right - run_child_reported and run_driver_reported make the run a statement of its own at all 62 sites, tests/module_cache/ARCHITECTURE.md says why, and test_aot.exe on zen2 passes the folder; and the watchdog's chatty-child arm moved twenty thousand lines in 96 s on a 64-core Windows box because spawn_process asked CreatePipe for the default 4 KB while the supervisor drains every 250 ms, 16 KB a second - the pipe is created at the POSIX 64 KB (a 1 MB pipe passed the lines in 4 s and failed the string-heap bar, since one drain is what the heap sees between collects), src/builtin/ARCHITECTURE.md sec.5 carries the mechanism, and the arm reads 9 s Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n their clocks: every deadline in tests/watchdog/test_watchdog.das and tests/fio/test_process.das goes through guard(), which triples it on a Debug host - shared_module_extension() names one - and caps it at five minutes; the deadlines guard a child's startup or exit, and a Debug daslang compiles what a child requires several times slower (a Debug box took 12 s to a ready file with a 15 s deadline, 30 s to a tray with a 30 s one), so a slow runner read the clock as a red; both files pass on a Release Mac (6, 47) and on a Debug Windows tree (6, 46) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ite that depends on it is the defect: LINT030 (daslib/lint.das) reads a variable mentioned in one argument beside a nested call in another that writes it through a mutable by-reference parameter, off the ordinary walk - one frame per call, its slot advanced per argument, every read recorded into the slot at the frame's own closure depth, the mentions flowing into the parent's slot on the way out, a variable the outer call itself takes by reference not counted since the callee sees its final state whatever the order - and fires on the outer call; it ships default-off beside LINT029, because the tree's library code carries the shape where a callee takes `var` to hand out a pointer or advance a builder (faker's twin draws, the gemm emitter parts, the kv accessors, array_data_ptr beside length - about ninety sites, a sweep of their own); the fixture holds five shapes and four that stay silent, the module_cache tests arm the rule per file and test_default_cache_path.das takes its nineteen sites through run_reported, and CLAUDE.md's fails-silently list, the language skill's calling section, lint.rst and ARCHITECTURE_LINT.md carry the fact - the interpreter and the JIT go left to right, the AOT C++ goes the compiler's way Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…popped off the frame stack attributes what it writes by reference to the parent's slot, so a writer nested in an expression (`pair(1 + bump(x), x)`) is found where the argument-root check missed it, mentions and writes cross into the parent only from the same closure depth so a call inside a block argument's body stays inside it, and the frame stack clears at function entry with the visitor's other stacks; the fixture pins the nested writer and the block-body call; the module_cache tests sequence the four sites where a message string read the output a sibling run wrote and arm the rule in the two child-spawning files that lacked it, and tests/README.md lists the live_host readiness test; the [extern] binder's refusal message crosses the panic jump the way the pinvoke family's does now, and src/builtin/ARCHITECTURE.md sec.4 names every site Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…AUDE.md carries the argument-order shape once, in the fails-silently list, with the sequenced form and the arming spelling, and the idiom-table row goes; src/builtin/ARCHITECTURE.md sec.5 states the chatty child's rate in the present tense and sec.4 names the FMT_THROW stash's file; src/builtin/REVIEW.md binds a C++ edit under a `// src/builtin/ARCHITECTURE.md sec.N` comment to the section it cites, since C++ carries no [arch] annotation; tests/module_cache/ARCHITECTURE.md keeps the fact - a nested run reads its output empty on a Windows AOT host - and the duty moves to tests/module_cache/REVIEW.md as a rule: a child runs as a statement of its own and the file carries `options _lint = "LINT030"`; the dasllama image-stamp section says CRLF folds to LF before the hash, and the gate's read_lf drops the comment that restated it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… its guards decide - a block handed to a nested call in a sibling argument runs while that argument is evaluated, so its read of the written variable is reported, where a block the outer call itself takes stays silent; the outer call taking the written variable by reference is silent, since the callee sees its final state whatever the order, and the fixture fails with that exclusion forced off; a by-value parameter's write and a nolint-marked site stay silent; tests/.das_test admits tests/live_host only where dasHV is built too, since test_host_ready.das polls the host over its client and a DAS_HV_DISABLED build would fail the folder's compile instead of skipping it; and the review-md walker test writes the dasllama image closure with CRLF line ends and asks the gate to keep the stamp, red with the fold reverted Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nswers on and posts /shutdown only to a child that reported ready - a fixed port with an unconditional shutdown could end an unrelated daslang-live when the test's own child failed to start; closing the handle ends a child that never became ready, and a span every port of which has a host skips the test Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hat the 4 KB pipe permits - its capacity four drains a second - instead of four pipes' worth between two drains; CLAUDE.md's idiom table drops the argument-order row, the fails-silently bullet being the one place the shape lives Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…skill, CLAUDE.md, lint.rst and the LINT030 fixture say the order is not defined and differs between tiers, and stop there - naming which tier goes which way invites reliance on an order the sentence calls undefined, and a host compiler's direction is not a claim a daslang probe can verify Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t citation - this folder's ARCHITECTURE.md or src/ast's, which seven comments here cite - to the section it names Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
It spans core runtime behavior changes (process I/O, panic/throw paths), lint engine additions, and multiple cross-platform CI/test gates that warrant final human verification.
Pull request overview
This PR addresses multiple “nightly red” CI failures by adjusting runtime behavior (module loading, error throwing, Windows process piping), adding/arming a new lint rule (LINT030), and updating tests/docs/gates to lock in the fixed behaviors across platforms and build modes.
Changes:
- Ensure
daslang-liveloads thelive_hostshared module before resolving its exports, with a newtests/live_hostregression test and updated.das_testgating. - Fix ASan-reported leaks on caught panics by moving pinvoke / dasbind throw messages to stack buffers before
Context::throw_error_atlongjmps. - Improve Windows child-process stdout/stderr throughput (64 KB pipe), add LINT030 (“argument order”) to
daslib/lint, and normalize CRLF-sensitive gates / fast-math-sensitive C++ tests.
File summaries
| File | Description |
|---|---|
| utils/lint/tests/lint030_argument_order.das | New fixture covering LINT030 positives/negatives. |
| utils/internal/review-md/test_walkers.das | Adds CRLF fixture for dasLLAMA stamp gate. |
| utils/daslang-live/main.cpp | Forces deferred loader to load live_host before dlsym/export reads. |
| tests/watchdog/test_watchdog.das | Adds Debug-scaled time guards for child lifecycle deadlines. |
| tests/README.md | Documents the new tests/live_host/test_host_ready.das. |
| tests/module_cache/test_require_module_now.das | Sequences child-run + output checks to avoid argument-order hazards (LINT030). |
| tests/module_cache/test_module_groups.das | Adds reported wrapper to keep child runs as statements (LINT030-safe). |
| tests/module_cache/test_macro_dep_invalidate.das | Arms LINT030 and avoids order-dependent child-run patterns. |
| tests/module_cache/test_generic_instance_origin.das | Arms LINT030 for module_cache child-run sequencing. |
| tests/module_cache/test_descriptor_manifest.das | Uses run_child_reported to avoid nested run_child(..., out) argument hazards. |
| tests/module_cache/test_deferred_modules.das | Uses run_child_reported throughout to avoid empty-output ordering on Windows AOT. |
| tests/module_cache/test_default_cache_path.das | Adds run_reported wrapper and sequences run/output checks safely. |
| tests/module_cache/REVIEW.md | Updates folder rules: require LINT030 + child runs must be standalone statements. |
| tests/module_cache/ARCHITECTURE.md | Documents why run_child_reported exists (argument evaluation order). |
| tests/module_cache/_mc_common.das | Adds run_child_reported helper. |
| tests/live_host/test_host_ready.das | New regression test verifying /status comes up and /shutdown exits cleanly. |
| tests/live_host/_fixture_host_ready.das | Minimal live-host fixture script for daslang-live. |
| tests/fio/test_process.das | Adds Debug-scaled time guards for child lifecycle deadlines. |
| tests/.das_test | Gates tests/live_host on both live_host and dashv. |
| tests-cpp/small/test_float2string.cpp | Hard-fails compilation under fast-math to keep fmt-based byte compares valid. |
| tests-cpp/CMakeLists.txt | Pins test_float2string.cpp to precise-math compile flags. |
| tests-cpp/big/vecmath_backend/test_vecmath_backend.cpp | Hard-fails compilation under fast-math for IEEE-asserting backend rows. |
| tests-cpp/big/vecmath_backend/CMakeLists.txt | Pins both vecmath backend executables to precise-math compile flags. |
| src/builtin/REVIEW.md | Adds rule: C++ comments citing ARCHITECTURE sections must update those sections in the same diff. |
| src/builtin/REVIEW.das | Removes stale STYLE030 nolint on review_nttp require. |
| src/builtin/module_builtin_fio.cpp | Windows spawn_process pipe sized to 64 KB (CreatePipe size param). |
| src/builtin/module_builtin_debugger.cpp | Avoids heap-owning locals across throw_error_at longjmp for pinvoke errors. |
| src/builtin/module_builtin_dasbind.cpp | Avoids heap-owning locals across throw_error_at for binder refusal message. |
| src/builtin/ARCHITECTURE.md | Documents sec.4 (panic-jump message discipline) and sec.5 (pipe sizing rationale). |
| skills/daslang/references/functions.md | Documents unspecified argument evaluation order. |
| modules/dasLLAMA/tests/test_arch_registry.das | Removes stale STYLE029 nolint marker. |
| modules/dasLLAMA/REVIEW.das | Normalizes CRLF->LF before hashing/stamping. |
| modules/dasLLAMA/dasllama/dasllama_asr.das | Removes stale STYLE029 nolint marker. |
| modules/dasLLAMA/ARCHITECTURE_IMAGE.md | Documents CRLF folding in the image-layout stamp closure. |
| examples/daslive/hello_stdio/main.das | Removes stale STYLE030 nolint marker. |
| doc/source/stdlib/handmade/module-builtin.rst | Corrects docs: builtin module doesn’t need require builtin. |
| doc/source/reference/language/lint.rst | Adds LINT030 documentation section. |
| doc/reflections/gen_module_examples.py | Adjusts generated module docs to omit “require” guidance when not applicable (builtin). |
| daslib/lint.das | Implements LINT030 (argument order dependency detection). |
| daslib/lint_config.das | Adds LINT030 to the default-disabled seed list. |
| daslib/ARCHITECTURE_LINT.md | Documents LINT030 implementation approach and why it ships default-off. |
| CLAUDE.md | Adds “argument order undefined” to the “fails silently” list + LINT030 mention. |
| .github/tsan_suppressions.txt | Adds suppression for libdbus lock-order report. |
| .gitattributes | Forces LF for tree-sitter generated artifacts to avoid CRLF hash diffs. |
Review details
- Files reviewed: 44/44 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…and what the page's own pair returns - 11 or 10 - instead of naming the call by its argument values; and it says which block reads count: one the outer call takes runs after every argument, one handed to a nested call in a sibling argument runs while that argument is evaluated Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The runtime behavior changes are consistent with the documented architecture rationale and the new/updated tests and gates directly cover the previously failing scenarios.
Review details
- Files reviewed: 44/44 changed files
- Comments generated: 0 new
- Review effort level: Lite
Behavior change: a Windows
spawn_processchild gets a 64 KB stdout pipe (was the 4 KB default), anddaslang-liveloads the LiveHost shared module before reading its exports - rebuilddaslang-liveand the modules.Why. Four nightly workflows were red. The dasImgui lane lost every playwright test since the lazy module scan (daslang-live read the LiveHost exports before anything loaded the module, so live mode never turned on); the ASan lane leaked 87 bytes per caught pinvoke panic; the Windows AOT host read an empty child output in every module_cache test; the Windows lanes throttled a chatty watchdog child to 16 KB/s; the tsan lane tripped on libdbus's own lock order; the extended checks read CRLF checkouts as changed bytes; the fastmath lane compared float printing against a fast-math fmt.
What changes.
live_hostbefore the dlsym;tests/live_host/test_host_ready.dasspawns it on a port nothing answers on and polls/status; the folder's gate intests/.das_testasks for dasHV too.pinvoke_named,pinvoke_impl2_core,pinvoke_impl3) and the[extern]binder's refusal move their message to the stack and free the string beforethrow_error_at(src/builtin/ARCHITECTURE.mdsec.4).spawn_processon Windows creates the child's pipe at the POSIX 64 KB (sec.5).daslib/lint.das, ships off) flags a sibling argument reading what a nested call writes by reference; the module_cache tests sequence every child run and arm the rule per file.eol=lf..github/tsan_suppressions.txtnames libdbus's module as the frame of its create/close lock-order report.test_float2string.cppand both vecmath backend arms pin precise math and#errorotherwise.nolintmarkers go; the builtin module's page stops telling readers torequire builtin.Observable behavior.
tests/module_cache: 11 red cells -> 40 passed, 7 host skips.LeakSanitizer: 87 byte(s)-> clean.test_tray_menu_over_private_bus: child exit 66 -> 0.Where to look.
daslib/lint.das(the LINT030 frame stack) andsrc/builtin/module_builtin_fio.cpp(the pipe size) are the two places that change runtime shape; the rest is tests, gates and docs.Validation, claims, ledger
Validation
D:\Work\das-nightly, Release Ninja;das-nightly-dbg, Debug) -test_aot.exeontests/module_cache40 passed / 7 skipped;tests/watchdog/test_watchdog.das46 Release and 46 Debug,tests/fio/test_process.das6 and 6; the chatty arm 96 s -> 9 s; the image-stamp gate reproduced the Windows hash by converting the dasllama folder to CRLF and read OK after the fold.-DDAS_USE_SANITIZER=tsan) reproduced the exit 66 with the libdbus lock-order report, then 12 passed with no report under the suppressions file.tests/live_host86,tests/module_cache61,tests/debug_agent54,tests/module_tests47,tests/lint84,tests/watchdog47,tests/fio/test_process6; ctestfloat2string|double2string|vecmath4/4; doc-verify green onmodule-builtin.rstandlint.rst;utils/lintanddasllamagates OK.daslang-liveand passes at 0.8 s on the new one.vecmath_scalar,vecmath_native,float2stringanddouble2stringrun for real on every non-fastmath lane throughctest -L small; on the fastmath lane their TUs are now precise-math while the library stays fast-math. Proof the pin takes under-ffast-math:clang++ -ffast-math -D_TARGET_SIMD_SCALAR=1 -DEXPECT_SCALAR=1 -Iinclude tests-cpp/big/vecmath_backend/test_vecmath_backend.cppstops at the#error, and with-fno-fast-mathappended (the CMake line's effect) both arms build and pass.modules/dasLLAMAchanges are two droppednolintmarkers and the stamp gate's CRLF fold; the module's--suite model-free/--suite stockedruns were not made for them - the gate itself ran (REVIEW.das dasllama: OKon the LF tree, and OK on the same folder converted to CRLF)./shutdowncould end an unrelated host - it now probes for a port nothing answers on and shuts down only a child that reported ready.take_ref(out, fill(out)); thenolintmarker case and the by-value-parameter case stay silent on the tip. The CRLF case inutils/internal/review-md/test_walkers.dasfails with the gate's line-end fold reverted (the stamp finding fires on the CRLF copy) and passes with it.lint.rst's LINT030 section namesoptions _lint = "LINT030"andLINT030 = truein.lint_config-utils/lint/main.dason the page's own example firesLINT030: argument 2 reads x while the call bump(...) in argument 1 writes it by referenceunder the first spelling and stays silent on the sequenced form, and the.lint_configre-enable is theCODE = truedirectivedaslib/lint_config.daserases the default-off seed on;module-builtin.rstsays nothing needs arequire, and doc-verify compiles the page's example with none -utils/internal/doc-verify/main.das --page reference/language/lintand--page stdlib/handmade/module-builtinboth green.Claims - stated, not tested
noLintflag.Not done
daslib/faker.dastwin draws, the dasLLAMA gemm emitter parts and kv accessors,array_data_ptrbesidelengthin dasLLVM, the spirv emitter) - a sweep of its own.tests/module_cache/REVIEW.mdasks every test there to carryoptions _lint = "LINT030"; noREVIEW.dasgate checks it yet - eight files comply today, the gate is a follow-up.utils/lint/tests(utils/lint/REVIEW.daschecks that each rule id has one; the linter skips the folder; nothing runs theirexpectcounts) - true of every fixture there, LINT030's included. A row of its own.