d5s-async-expression-stringifies-promise
The solution is written to /workspace/solution.md. Here is the summary of what was done:
The .d5s compiler in src/trigger/d5s_lang.go wraps run expressions as JSON.stringify(EXPR) with no await (lines ~217 and ~235). When the expression is an async IIFE, JSON.stringify runs immediately on the returned Promise object, which has no enumerable properties — so it silently stringifies to '{}' with no error or warning. Downstream nodes then compute on {}. The sibling TS-DSL path (tsrun.go:127) was already fixed as (async () => JSON.stringify(await ((fn))(prev)))(), but the .d5s compiler never received the same treatment.
Change every JSON.stringify(...) emission in d5s_lang.go to a promise-aware IIFE wrap:
(async () => JSON.stringify(await (EXPR)))()
await on a sync literal/selector/template is a no-op, so existing semantics are untouched. The IIFE is required (not a bare top-level await) because global-script eval would raise a SyntaxError, and the WASM eval shim awaits a script's promise completion value via js_std_await + job loop.
The repo isn't checked out in this sandbox, so I couldn't run the actual Go test suite. But I verified the core JS semantics the fix depends on with the local node v22 runtime:
JSON.stringify(async-IIFE)): printed {} → bug reproduced(async () => JSON.stringify(await (src)))()): printed {"v":2,"awaited":true} → fix worksawait (42) correctly yields 42The markdown also includes a fixture regression spec (async IIFE node + consumer must yield 2) and existing-suite regression checks. Once the repo is available, apply the two-line-class change in d5s_lang.go and run the .d5s async fixture to confirm end-to-end.
# Evidence - Problem class: d5s-async-expression-stringifies-promise - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-21T22:37:35.032Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Hermes DAGger .d5s pipeline compiler: async run expressions silently complete with Output {} because the compiled wrap is JSON.stringify((async () => {...})()) with NO await \u2014 the Promise gets stringified to '{}'. Verified 2026-08-21 on a fresh HEAD build (<project> repo, src/trigger/d5s_lang.go:217 ExprLiteral wrap 'JSON.stringify(%s)' and :235 compileSelector same pattern; the TS-DSL path was already fixed in src/runner/tsrun.go:127 as '(async () => JSON.stringify(await ((fn))(prev)))()' per GAP-044). Repro: .d5s node 'async1' with run '(async () => { const sleep = (ms: number) => new Promise<void>(r => setTimeout(r, ms)); await sleep(100); return { v: 2, awaited: true }; })()' completes with Output {} (no error, no warning), downstream nodes compute on {}. Fix pattern: make the wrap promise-aware, e.g. (async () => JSON.stringify(await (EXPR)))() \u2014 await on sync expressions is a no-op so literal/selector/template semantics are unchanged; the executor's completion-value convention is a JSON string (canonicalJSON parses it) and the QJS binding awaits a script's promise completion value (js_std_await + job loop in the WASM eval shim), hence the IIFE (a bare top-level await would be a SyntaxError in global-script eval). Regression: async .d5s fixture (async IIFE node + consumer) must yield the awaited object, not {}.", "environment": "", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "d5s-async-expression-stringifies-promise", "provider": "openrouter", "solved_at": "2026-08-21T22:37:35.032Z", "version": ""}