diff --git a/.omo/evidence/20260723-awaited-network-timers/README.md b/.omo/evidence/20260723-awaited-network-timers/README.md new file mode 100644 index 00000000..8d64308c --- /dev/null +++ b/.omo/evidence/20260723-awaited-network-timers/README.md @@ -0,0 +1,22 @@ +# Awaited network timer QA evidence + +## What was tested + +- `npm test` built the current branch and ran the complete repository test suite. +- `node --test --test-timeout 60000 dist/tests/network/fetch.spec.js` ran the seven focused retry, timeout, abort, and error-normalization tests. +- `manual-runtime.json` records a direct call to the built `networkFetch` implementation. A synthetic first request returned HTTP 503, the awaited 20 ms retry delay elapsed, and the second request returned 200. A separate never-resolving fetch was aborted by the awaited 20 ms timeout. + +## What was observed + +- Full suite: 145 tests passed, 0 failed, 0 cancelled, exit code 0. Exact output: `full-suite.txt`. +- Focused suite: 7 tests passed, 0 failed, 0 cancelled, exit code 0. Exact output: `focused-tests.txt`. +- Manual runtime: retry completed after 44 ms with two calls and status 200; timeout completed after 22 ms with `network_timeout`. Exact structured output: `manual-runtime.json`. +- Before the fix, the same full suite consistently cancelled all seven network tests with `cancelledByParent` and `Promise resolution is still pending but the event loop has already resolved`. + +## Why it is enough + +The focused tests cover the network API contract, the full suite covers repository regressions, and the direct built-runtime exercise proves that both awaited timer paths keep the Node process alive until their promises settle. + +## What was omitted + +No credentials, request headers, environment dumps, or external network traffic were used. The manual runtime used local synthetic fetch implementations only. diff --git a/.omo/evidence/20260723-awaited-network-timers/focused-tests.txt b/.omo/evidence/20260723-awaited-network-timers/focused-tests.txt new file mode 100644 index 00000000..522f9e3c --- /dev/null +++ b/.omo/evidence/20260723-awaited-network-timers/focused-tests.txt @@ -0,0 +1,53 @@ +TAP version 13 +# Subtest: networkFetch retries retryable status responses and then succeeds +ok 1 - networkFetch retries retryable status responses and then succeeds + --- + duration_ms: 2.439708 + type: 'test' + ... +# Subtest: networkFetch uses retry-after when calculating retry delay +ok 2 - networkFetch uses retry-after when calculating retry delay + --- + duration_ms: 0.060416 + type: 'test' + ... +# Subtest: networkFetch caps retry-after delays with maxDelayMs +ok 3 - networkFetch caps retry-after delays with maxDelayMs + --- + duration_ms: 0.030167 + type: 'test' + ... +# Subtest: networkFetch normalizes DNS and reset errors +ok 4 - networkFetch normalizes DNS and reset errors + --- + duration_ms: 0.075833 + type: 'test' + ... +# Subtest: networkFetch times out requests +ok 5 - networkFetch times out requests + --- + duration_ms: 1.483667 + type: 'test' + ... +# Subtest: networkFetch honors init.signal abort reasons without options.signal +ok 6 - networkFetch honors init.signal abort reasons without options.signal + --- + duration_ms: 0.29525 + type: 'test' + ... +# Subtest: networkFetch preserves parent NetworkFetchError reasons passed through options.signal +ok 7 - networkFetch preserves parent NetworkFetchError reasons passed through options.signal + --- + duration_ms: 0.206041 + type: 'test' + ... +1..7 +# tests 7 +# suites 0 +# pass 7 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 96.512417 +focused_exit=0 diff --git a/.omo/evidence/20260723-awaited-network-timers/full-suite.txt b/.omo/evidence/20260723-awaited-network-timers/full-suite.txt new file mode 100644 index 00000000..ac885339 --- /dev/null +++ b/.omo/evidence/20260723-awaited-network-timers/full-suite.txt @@ -0,0 +1,902 @@ + +> pilotdeck@0.1.0 test +> npm run build && node --test --test-force-exit --test-timeout 60000 "dist/tests/**/*.test.js" "dist/tests/**/*.spec.js" + + +> pilotdeck@0.1.0 prebuild +> npm run check:runtime && node scripts/bootstrap-pilotdeck-config.mjs && cd src/context/memory/edgeclaw-memory-core && npm run build + + +> pilotdeck@0.1.0 check:runtime +> node scripts/check-node-runtime.mjs + + +> edgeclaw-memory-core@0.0.0 build +> node -e "require('fs').rmSync('lib',{recursive:true,force:true})" && tsc -p tsconfig.json + + +> pilotdeck@0.1.0 build +> node -e "require('fs').rmSync('dist',{recursive:true,force:true})" && tsc -p tsconfig.json && node -e "require('fs').cpSync('src/extension/plugins/builtin','dist/src/extension/plugins/builtin',{recursive:true})" + +TAP version 13 +# Subtest: Feishu handles permission replies before the active chat drain finishes +ok 1 - Feishu handles permission replies before the active chat drain finishes + --- + duration_ms: 1.330209 + type: 'test' + ... +# Subtest: ImPermissionHelper resolves all pending permission requests for a chat +ok 2 - ImPermissionHelper resolves all pending permission requests for a chat + --- + duration_ms: 1.8485 + type: 'test' + ... +# Subtest: ImPermissionHelper keeps pending requests when the reply is invalid +ok 3 - ImPermissionHelper keeps pending requests when the reply is invalid + --- + duration_ms: 0.081292 + type: 'test' + ... +# Subtest: ordinary edit failures after a successful write do not enter large-file repair +ok 4 - ordinary edit failures after a successful write do not enter large-file repair + --- + duration_ms: 0.764667 + type: 'test' + ... +# Subtest: an explicit post-draft large-file failure starts bounded recovery +ok 5 - an explicit post-draft large-file failure starts bounded recovery + --- + duration_ms: 0.167584 + type: 'test' + ... +# Subtest: successful focused write clears an active large-file repair episode +ok 6 - successful focused write clears an active large-file repair episode + --- + duration_ms: 0.145208 + type: 'test' + ... +# Subtest: permission failures are never reclassified as large-file recovery +ok 7 - permission failures are never reclassified as large-file recovery + --- + duration_ms: 0.043292 + type: 'test' + ... +# Subtest: explore subagent does not probe tool safety before execution +ok 8 - explore subagent does not probe tool safety before execution + --- + duration_ms: 9.431791 + type: 'test' + ... +# Subtest: explore registry ignores an unallowed dynamic execute_code tool without probing it +ok 9 - explore registry ignores an unallowed dynamic execute_code tool without probing it + --- + duration_ms: 0.655958 + type: 'test' + ... +# Subtest: read-only subagent evaluates bash safety from the real command +ok 10 - read-only subagent evaluates bash safety from the real command + --- + duration_ms: 4.357791 + type: 'test' + ... +# Subtest: read-only execute_code checks the real code instead of crashing on registry setup +ok 11 - read-only execute_code checks the real code instead of crashing on registry setup + --- + duration_ms: 0.298209 + type: 'test' + ... +# Subtest: filterIncompleteToolCalls tolerates malformed messages without content +ok 12 - filterIncompleteToolCalls tolerates malformed messages without content + --- + duration_ms: 1.814666 + type: 'test' + ... +# Subtest: turn environment provides an isolated PilotDeck-owned work directory +ok 13 - turn environment provides an isolated PilotDeck-owned work directory + --- + duration_ms: 1.415583 + type: 'test' + ... +# Subtest: turn environment inherits the process environment when no override is configured +ok 14 - turn environment inherits the process environment when no override is configured + --- + duration_ms: 0.293333 + type: 'test' + ... +# Subtest: config bootstrap does not copy bundled skills into user storage +ok 15 - config bootstrap does not copy bundled skills into user storage + --- + duration_ms: 74.174709 + type: 'test' + ... +# Subtest: Office attachments are reported unsupported before size checks +ok 16 - Office attachments are reported unsupported before size checks + --- + duration_ms: 5.784542 + type: 'test' + ... +# Subtest: default prompt does not require Markdown links for generated files +ok 17 - default prompt does not require Markdown links for generated files + --- + duration_ms: 1.372583 + type: 'test' + ... +# Subtest: default prompt does not advertise web search when the tool is unavailable +ok 18 - default prompt does not advertise web search when the tool is unavailable + --- + duration_ms: 0.101041 + type: 'test' + ... +# Subtest: available skills include the resolved SKILL.md path and bounded lookup guidance +ok 19 - available skills include the resolved SKILL.md path and bounded lookup guidance + --- + duration_ms: 2.661917 + type: 'test' + ... +# Subtest: budget snapshot uses conservative budget tokens for ratio while preserving real tokens +ok 20 - budget snapshot uses conservative budget tokens for ratio while preserving real tokens + --- + duration_ms: 1.009458 + type: 'test' + ... +# Subtest: tool text under token budget remains inline even when over legacy byte threshold +ok 21 - tool text under token budget remains inline even when over legacy byte threshold + --- + duration_ms: 4958.558167 + type: 'test' + ... +# Subtest: tool text over token budget is persisted with expanded grep-first preview +ok 22 - tool text over token budget is persisted with expanded grep-first preview + --- + duration_ms: 6.280042 + type: 'test' + ... +# Subtest: large tool error references preserve error semantics for model replay +ok 23 - large tool error references preserve error semantics for model replay + --- + duration_ms: 2.016458 + type: 'test' + ... +# Subtest: multibyte truncated tool result references advertise read_file access +ok 24 - multibyte truncated tool result references advertise read_file access + --- + duration_ms: 1.231958 + type: 'test' + ... +# Subtest: standalone skills expose only their slug without a parent-directory namespace +ok 25 - standalone skills expose only their slug without a parent-directory namespace + --- + duration_ms: 6.372416 + type: 'test' + ... +# Subtest: a plugin skill directory used as the configured base never derives a parent namespace +ok 26 - a plugin skill directory used as the configured base never derives a parent namespace + --- + duration_ms: 0.157458 + type: 'test' + ... +# Subtest: standalone skill precedence is project > user > builtin without legacy aliases +ok 27 - standalone skill precedence is project > user > builtin without legacy aliases + --- + duration_ms: 39.912917 + type: 'test' + ... +# Subtest: legacy bundled migration backs up only byte-identical bootstrap copies +ok 28 - legacy bundled migration backs up only byte-identical bootstrap copies + --- + duration_ms: 41.159917 + type: 'test' + ... +# Subtest: legacy bundled migration leaves user skills untouched when the release bundle is missing +ok 29 - legacy bundled migration leaves user skills untouched when the release bundle is missing + --- + duration_ms: 7.99 + type: 'test' + ... +# Subtest: SkillManager lists built-ins separately and describes override relationships +ok 30 - SkillManager lists built-ins separately and describes override relationships + --- + duration_ms: 30.598209 + type: 'test' + ... +# Subtest: SkillManager permits reading but rejects mutations of built-in skills +ok 31 - SkillManager permits reading but rejects mutations of built-in skills + --- + duration_ms: 4.945333 + type: 'test' + ... +# Subtest: registered plain-text attachments with non-whitelisted names are described as read_file inspectable +ok 32 - registered plain-text attachments with non-whitelisted names are described as read_file inspectable + --- + duration_ms: 13.637708 + type: 'test' + ... +# Subtest: registered Office attachments are still described as not directly inspectable +ok 33 - registered Office attachments are still described as not directly inspectable + --- + duration_ms: 2.423125 + type: 'test' + ... +# Subtest: startPilotDeckServer listens before a background channel finishes starting +ok 34 - startPilotDeckServer listens before a background channel finishes starting + --- + duration_ms: 19.203916 + type: 'test' + ... +# (node:89878) ExperimentalWarning: SQLite is an experimental feature and might change at any time +# (Use `node --trace-warnings ...` to show where the warning was created) +# Subtest: browser-use args do not inherit generic proxy env by default +ok 35 - browser-use args do not inherit generic proxy env by default + --- + duration_ms: 1.013209 + type: 'test' + ... +# Subtest: browser-use args use explicit browser proxy server +ok 36 - browser-use args use explicit browser proxy server + --- + duration_ms: 0.090333 + type: 'test' + ... +# Subtest: browser-use args only inherit generic proxy env when opted in +ok 37 - browser-use args only inherit generic proxy env when opted in + --- + duration_ms: 0.064959 + type: 'test' + ... +# Subtest: browser-use args use config proxy when browser env proxy is absent +ok 38 - browser-use args use config proxy when browser env proxy is absent + --- + duration_ms: 0.082583 + type: 'test' + ... +# Subtest: browser-use args allow explicit direct mode to disable config proxy +ok 39 - browser-use args allow explicit direct mode to disable config proxy + --- + duration_ms: 0.057542 + type: 'test' + ... +# Subtest: mapAgentEvent propagates runId to streaming lifecycle boundaries +ok 40 - mapAgentEvent propagates runId to streaming lifecycle boundaries + --- + duration_ms: 1.368042 + type: 'test' + ... +# Subtest: mapAgentEvent bounds live tool result previews at the gateway +ok 41 - mapAgentEvent bounds live tool result previews at the gateway + --- + duration_ms: 2.653291 + type: 'test' + ... +# Subtest: mapAgentEvent bounds large strings inside successful tool data +ok 42 - mapAgentEvent bounds large strings inside successful tool data + --- + duration_ms: 0.31875 + type: 'test' + ... +# Subtest: mapAgentEvent bounds subagent tool result content and preview +ok 43 - mapAgentEvent bounds subagent tool result content and preview + --- + duration_ms: 0.140583 + type: 'test' + ... +# Subtest: WeixinChannel.start returns while QR login is waiting +ok 44 - WeixinChannel.start returns while QR login is waiting + --- + duration_ms: 17.565917 + type: 'test' + ... +# Subtest: channel runtime status reporter persists the latest channel state +ok 45 - channel runtime status reporter persists the latest channel state + --- + duration_ms: 3.022167 + type: 'test' + ... +# Subtest: UI weixin QR route only reads runtime status +ok 46 - UI weixin QR route only reads runtime status + --- + duration_ms: 1.573875 + type: 'test' + ... +# Subtest: UI weixin QR begin route delegates to gateway prepare RPC +ok 47 - UI weixin QR begin route delegates to gateway prepare RPC + --- + duration_ms: 0.183209 + type: 'test' + ... +# Subtest: Gateway settings keeps existing status rendered during silent refresh +ok 48 - Gateway settings keeps existing status rendered during silent refresh + --- + duration_ms: 0.687834 + type: 'test' + ... +# Subtest: Gateway settings starts weixin QR by begin route and ignores stale runtime errors +ok 49 - Gateway settings starts weixin QR by begin route and ignores stale runtime errors + --- + duration_ms: 0.288959 + type: 'test' + ... +# Subtest: Gateway protocol exposes prepare_weixin_login RPC +ok 50 - Gateway protocol exposes prepare_weixin_login RPC + --- + duration_ms: 0.68475 + type: 'test' + ... +# Subtest: McpClient keeps stdio clients idle before connection +ok 51 - McpClient keeps stdio clients idle before connection + --- + duration_ms: 0.478917 + type: 'test' + ... +# Subtest: McpClient constructs streamable_http transport without requiring stdio fields +ok 52 - McpClient constructs streamable_http transport without requiring stdio fields + --- + duration_ms: 0.041292 + type: 'test' + ... +# Subtest: McpClient routes streamable_http fetches with bounded timeouts +ok 53 - McpClient routes streamable_http fetches with bounded timeouts + --- + duration_ms: 0.670583 + type: 'test' + ... +# Subtest: expandMcpString expands ${env:*} placeholders +ok 54 - expandMcpString expands ${env:*} placeholders + --- + duration_ms: 0.608333 + type: 'test' + ... +# Subtest: expandMcpString expands ${userHome} placeholder +ok 55 - expandMcpString expands ${userHome} placeholder + --- + duration_ms: 0.3365 + type: 'test' + ... +# Subtest: expandMcpString expands ~ prefix +ok 56 - expandMcpString expands ~ prefix + --- + duration_ms: 0.092208 + type: 'test' + ... +# Subtest: expandMcpString leaves unknown env vars as empty string +ok 57 - expandMcpString leaves unknown env vars as empty string + --- + duration_ms: 0.071875 + type: 'test' + ... +# Subtest: expandMcpString handles combined placeholders +ok 58 - expandMcpString handles combined placeholders + --- + duration_ms: 0.125 + type: 'test' + ... +# Subtest: expandMcpConfig recursively expands objects and arrays +ok 59 - expandMcpConfig recursively expands objects and arrays + --- + duration_ms: 1.156542 + type: 'test' + ... +# Subtest: parsePluginMcpServers expands ${env:*} in stdio env +ok 60 - parsePluginMcpServers expands ${env:*} in stdio env + --- + duration_ms: 0.18175 + type: 'test' + ... +# Subtest: parsePluginMcpServers expands ${env:*} in stdio command before transport detection +ok 61 - parsePluginMcpServers expands ${env:*} in stdio command before transport detection + --- + duration_ms: 0.0515 + type: 'test' + ... +# Subtest: parsePluginMcpServers drops empty expanded stdio command +ok 62 - parsePluginMcpServers drops empty expanded stdio command + --- + duration_ms: 0.1995 + type: 'test' + ... +# Subtest: parsePluginMcpServers expands ${userHome} in stdio cwd +ok 63 - parsePluginMcpServers expands ${userHome} in stdio cwd + --- + duration_ms: 0.232208 + type: 'test' + ... +# Subtest: parsePluginMcpServers expands ~ in stdio args (backward compat) +ok 64 - parsePluginMcpServers expands ~ in stdio args (backward compat) + --- + duration_ms: 0.107583 + type: 'test' + ... +# Subtest: parsePluginMcpServers expands ${env:*} in streamable_http url +ok 65 - parsePluginMcpServers expands ${env:*} in streamable_http url + --- + duration_ms: 0.045292 + type: 'test' + ... +# Subtest: parsePluginMcpServers expands ${env:*} in streamable_http headers +ok 66 - parsePluginMcpServers expands ${env:*} in streamable_http headers + --- + duration_ms: 0.036958 + type: 'test' + ... +# Subtest: user config and plugin config resolve same placeholders consistently +ok 67 - user config and plugin config resolve same placeholders consistently + --- + duration_ms: 0.038334 + type: 'test' + ... +# Subtest: catalog provider resolves api key from default env var when apiKey is omitted +ok 68 - catalog provider resolves api key from default env var when apiKey is omitted + --- + duration_ms: 0.754792 + type: 'test' + ... +# Subtest: catalog provider resolves api key from default env var when apiKey is blank +ok 69 - catalog provider resolves api key from default env var when apiKey is blank + --- + duration_ms: 0.082916 + type: 'test' + ... +# Subtest: normalizeModelError classifies common network failures +ok 70 - normalizeModelError classifies common network failures + --- + duration_ms: 3.17075 + type: 'test' + ... +# Subtest: model request failure preserves provider raw message before action guidance +ok 71 - model request failure preserves provider raw message before action guidance + --- + duration_ms: 2.730792 + type: 'test' + ... +# Subtest: model_not_found guidance points users to local model settings +ok 72 - model_not_found guidance points users to local model settings + --- + duration_ms: 1.192291 + type: 'test' + ... +# Subtest: stream idle timeout is classified as timeout with network and timeoutMs guidance +ok 73 - stream idle timeout is classified as timeout with network and timeoutMs guidance + --- + duration_ms: 0.295 + type: 'test' + ... +# Subtest: billing and rate limit guidance distinguish provider-side fixes +ok 74 - billing and rate limit guidance distinguish provider-side fixes + --- + duration_ms: 0.123625 + type: 'test' + ... +# Subtest: unknown provider errors still give actionable settings and provider checks +ok 75 - unknown provider errors still give actionable settings and provider checks + --- + duration_ms: 0.045167 + type: 'test' + ... +# Subtest: OpenAI Responses usage reads cached tokens from input token details +ok 76 - OpenAI Responses usage reads cached tokens from input token details + --- + duration_ms: 4.103333 + type: 'test' + ... +# Subtest: Gemini usage counts thoughts tokens as output consumption +ok 77 - Gemini usage counts thoughts tokens as output consumption + --- + duration_ms: 0.656291 + type: 'test' + ... +# Subtest: Ollama provider uses catalog defaults and does not require apiKey +ok 78 - Ollama provider uses catalog defaults and does not require apiKey + --- + duration_ms: 1.610209 + type: 'test' + ... +# Subtest: Ollama provider builds OpenAI-compatible chat completions body +ok 79 - Ollama provider builds OpenAI-compatible chat completions body + --- + duration_ms: 1.766166 + type: 'test' + ... +# Subtest: model request builders tolerate malformed messages with missing content +ok 80 - model request builders tolerate malformed messages with missing content + --- + duration_ms: 0.86825 + type: 'test' + ... +# Subtest: cloneMessages normalizes malformed messages with missing content +ok 81 - cloneMessages normalizes malformed messages with missing content + --- + duration_ms: 0.511416 + type: 'test' + ... +# Subtest: networkFetch retries retryable status responses and then succeeds +ok 82 - networkFetch retries retryable status responses and then succeeds + --- + duration_ms: 2.578 + type: 'test' + ... +# Subtest: networkFetch uses retry-after when calculating retry delay +ok 83 - networkFetch uses retry-after when calculating retry delay + --- + duration_ms: 0.066917 + type: 'test' + ... +# Subtest: networkFetch caps retry-after delays with maxDelayMs +ok 84 - networkFetch caps retry-after delays with maxDelayMs + --- + duration_ms: 0.032458 + type: 'test' + ... +# Subtest: networkFetch normalizes DNS and reset errors +ok 85 - networkFetch normalizes DNS and reset errors + --- + duration_ms: 0.084334 + type: 'test' + ... +# Subtest: networkFetch times out requests +ok 86 - networkFetch times out requests + --- + duration_ms: 5.909042 + type: 'test' + ... +# Subtest: networkFetch honors init.signal abort reasons without options.signal +ok 87 - networkFetch honors init.signal abort reasons without options.signal + --- + duration_ms: 0.531208 + type: 'test' + ... +# Subtest: networkFetch preserves parent NetworkFetchError reasons passed through options.signal +ok 88 - networkFetch preserves parent NetworkFetchError reasons passed through options.signal + --- + duration_ms: 0.478583 + type: 'test' + ... +# Subtest: web search can be explicitly disabled without discarding provider config +ok 89 - web search can be explicitly disabled without discarding provider config + --- + duration_ms: 1.932875 + type: 'test' + ... +# Subtest: web search enabled remains optional for backwards compatibility +ok 90 - web search enabled remains optional for backwards compatibility + --- + duration_ms: 0.078917 + type: 'test' + ... +# Subtest: web search enabled must be a boolean +ok 91 - web search enabled must be a boolean + --- + duration_ms: 0.057416 + type: 'test' + ... +# Subtest: file artifacts include every meaningful workspace change without an extension allowlist +ok 92 - file artifacts include every meaningful workspace change without an extension allowlist + --- + duration_ms: 62.128375 + type: 'test' + ... +# Subtest: file artifact fingerprints are reused for unchanged files across scans and turns +ok 93 - file artifact fingerprints are reused for unchanged files across scans and turns + --- + duration_ms: 20.121458 + type: 'test' + ... +# Subtest: TurnRunner emits and persists file artifacts before completing the turn +ok 94 - TurnRunner emits and persists file artifacts before completing the turn + --- + duration_ms: 33.167417 + type: 'test' + ... +# Subtest: TurnRunner does not collect generated files when artifacts are disabled +ok 95 - TurnRunner does not collect generated files when artifacts are disabled + --- + duration_ms: 5.732875 + type: 'test' + ... +# Subtest: bash success result is formatted with assertions, stdout, and stderr +ok 96 - bash success result is formatted with assertions, stdout, and stderr + --- + duration_ms: 4.396458 + type: 'test' + ... +# Subtest: bash failure tool result includes raw stdout and stderr tail for UI and model +ok 97 - bash failure tool result includes raw stdout and stderr tail for UI and model + --- + duration_ms: 36.568959 + type: 'test' + ... +# Subtest: bash failure diagnostic extracts Python traceback location and exception +ok 98 - bash failure diagnostic extracts Python traceback location and exception + --- + duration_ms: 0.372125 + type: 'test' + ... +# Subtest: bash success keeps full output for ToolResultBudget persistence +ok 99 - bash success keeps full output for ToolResultBudget persistence + --- + duration_ms: 14.255333 + type: 'test' + ... +# Subtest: agent tool accepts explorer as an alias for explore +ok 100 - agent tool accepts explorer as an alias for explore + --- + duration_ms: 1.370334 + type: 'test' + ... +# Subtest: agent tool defaults general-purpose to explore in ask mode +ok 101 - agent tool defaults general-purpose to explore in ask mode + --- + duration_ms: 0.121875 + type: 'test' + ... +# Subtest: agent tool preserves unknown custom fallback subagent names +ok 102 - agent tool preserves unknown custom fallback subagent names + --- + duration_ms: 0.656417 + type: 'test' + ... +# Subtest: execute_code read-only probe handles missing input +ok 103 - execute_code read-only probe handles missing input + --- + duration_ms: 0.720375 + type: 'test' + ... +# Subtest: disabling web search removes it from the registry but keeps web fetch +ok 104 - disabling web search removes it from the registry but keeps web fetch + --- + duration_ms: 1.093459 + type: 'test' + ... +# Subtest: execute_code rejects nested web search calls when web search is disabled +ok 105 - execute_code rejects nested web search calls when web search is disabled + --- + duration_ms: 0.124042 + type: 'test' + ... +# Subtest: read_skill returns the resolved SKILL.md path with the skill body +ok 106 - read_skill returns the resolved SKILL.md path with the skill body + --- + duration_ms: 0.589917 + type: 'test' + ... +# Subtest: read_skill preserves legacy content-only loading when metadata is unavailable +ok 107 - read_skill preserves legacy content-only loading when metadata is unavailable + --- + duration_ms: 0.062917 + type: 'test' + ... +# Subtest: web_search retries transient provider failures +ok 108 - web_search retries transient provider failures + --- + duration_ms: 589.888375 + type: 'test' + ... +# Subtest: web_search turns request timeout into tool_timeout +ok 109 - web_search turns request timeout into tool_timeout + --- + duration_ms: 2.267375 + type: 'test' + ... +# Subtest: web_search turns network timeout errors into tool_timeout +ok 110 - web_search turns network timeout errors into tool_timeout + --- + duration_ms: 1.769209 + type: 'test' + ... +# Subtest: write_file freshness error tells the model to read the file first +ok 111 - write_file freshness error tells the model to read the file first + --- + duration_ms: 1.142541 + type: 'test' + ... +# Subtest: write_file missing content points at the missing field and chunked recovery +ok 112 - write_file missing content points at the missing field and chunked recovery + --- + duration_ms: 0.253584 + type: 'test' + ... +# Subtest: invalid tool input keeps a bounded original error block +ok 113 - invalid tool input keeps a bounded original error block + --- + duration_ms: 0.207209 + type: 'test' + ... +# Subtest: edit_file old_string miss tells the model to reread and copy exact text +ok 114 - edit_file old_string miss tells the model to reread and copy exact text + --- + duration_ms: 0.060875 + type: 'test' + ... +# Subtest: read_file invalid range preserves the concrete issue +ok 115 - read_file invalid range preserves the concrete issue + --- + duration_ms: 0.108959 + type: 'test' + ... +# Subtest: bash missing command reports the required command parameter +ok 116 - bash missing command reports the required command parameter + --- + duration_ms: 0.099375 + type: 'test' + ... +# Subtest: bash timeout over max keeps foreground and task_wait guidance +ok 117 - bash timeout over max keeps foreground and task_wait guidance + --- + duration_ms: 0.132042 + type: 'test' + ... +# Subtest: bash background rejection keeps background-specific guidance +ok 118 - bash background rejection keeps background-specific guidance + --- + duration_ms: 0.078041 + type: 'test' + ... +# Subtest: write_file can create a new file without a prior read_file call +ok 119 - write_file can create a new file without a prior read_file call + --- + duration_ms: 15.993625 + type: 'test' + ... +# Subtest: edit_file can create a new file with empty old_string without a prior read_file call +ok 120 - edit_file can create a new file with empty old_string without a prior read_file call + --- + duration_ms: 3.750625 + type: 'test' + ... +# Subtest: read_file auto-pages large text files instead of failing +ok 121 - read_file auto-pages large text files instead of failing + --- + duration_ms: 1969.401791 + type: 'test' + ... +# Subtest: read_file rejects Office container files during validation +ok 122 - read_file rejects Office container files during validation + --- + duration_ms: 1.041167 + type: 'test' + ... +# Subtest: read_file explicit limit reads a large file range without auto paging +ok 123 - read_file explicit limit reads a large file range without auto paging + --- + duration_ms: 4.072209 + type: 'test' + ... +# Subtest: read_file auto-shrinks oversized persisted tool-result ref ranges +ok 124 - read_file auto-shrinks oversized persisted tool-result ref ranges + --- + duration_ms: 22909.11525 + type: 'test' + ... +# Subtest: read_file keeps explicit oversized ordinary file ranges strict +ok 125 - read_file keeps explicit oversized ordinary file ranges strict + --- + duration_ms: 3.2935 + type: 'test' + ... +# Subtest: read_file explicit limit records a ranged snapshot for follow-up edits +ok 126 - read_file explicit limit records a ranged snapshot for follow-up edits + --- + duration_ms: 4.728917 + type: 'test' + ... +# Subtest: read_file auto-paged large files record a ranged snapshot for follow-up edits +ok 127 - read_file auto-paged large files record a ranged snapshot for follow-up edits + --- + duration_ms: 1630.869334 + type: 'test' + ... +# Subtest: read_file returns a head-tail preview for a single oversized line +ok 128 - read_file returns a head-tail preview for a single oversized line + --- + duration_ms: 2.504542 + type: 'test' + ... +# Subtest: read_file classifies common Office formats as binary +ok 129 - read_file classifies common Office formats as binary + --- + duration_ms: 0.185625 + type: 'test' + ... +# Subtest: read_file rejects ranged binary input instead of hanging +ok 130 - read_file rejects ranged binary input instead of hanging + --- + duration_ms: 0.952666 + type: 'test' + ... +# Subtest: read_file range honors an aborted signal +ok 131 - read_file range honors an aborted signal + --- + duration_ms: 0.6925 + type: 'test' + ... +# Subtest: glob result text tells the model when more files are available +ok 132 - glob result text tells the model when more files are available + --- + duration_ms: 24.117625 + type: 'test' + ... +# Subtest: grep result text includes next offset when paginated +ok 133 - grep result text includes next offset when paginated + --- + duration_ms: 11.931708 + type: 'test' + ... +# Subtest: todo_write returns the actual todo list in model-visible content +ok 134 - todo_write returns the actual todo list in model-visible content + --- + duration_ms: 2.315542 + type: 'test' + ... +# Subtest: task_list returns model-visible status and next action hints +ok 135 - task_list returns model-visible status and next action hints + --- + duration_ms: 0.853 + type: 'test' + ... +# Subtest: applyResultSizeLimit keeps both head and tail when truncating text output +ok 136 - applyResultSizeLimit keeps both head and tail when truncating text output + --- + duration_ms: 0.822458 + type: 'test' + ... +# Subtest: large tool results are persisted under workspace .pilotdeck and readable by read_file +ok 137 - large tool results are persisted under workspace .pilotdeck and readable by read_file + --- + duration_ms: 14.128 + type: 'test' + ... +# Subtest: large tool result read_file aliases are short and sequential +ok 138 - large tool result read_file aliases are short and sequential + --- + duration_ms: 7.043834 + type: 'test' + ... +# Subtest: history replay restores structured agent file artifacts +ok 139 - history replay restores structured agent file artifacts + --- + duration_ms: 8.174041 + type: 'test' + ... +# Subtest: history replay hides Agent file artifacts in general conversations +ok 140 - history replay hides Agent file artifacts in general conversations + --- + duration_ms: 3.0185 + type: 'test' + ... +# Subtest: history replay preserves agent status i18n metadata and user hint +ok 141 - history replay preserves agent status i18n metadata and user hint + --- + duration_ms: 8.40825 + type: 'test' + ... +# Subtest: history token usage restores latest non-empty turn past latest empty turn result +ok 142 - history token usage restores latest non-empty turn past latest empty turn result + --- + duration_ms: 2.363583 + type: 'test' + ... +# Subtest: history token usage prefers persisted context budget snapshot +ok 143 - history token usage prefers persisted context budget snapshot + --- + duration_ms: 2.846333 + type: 'test' + ... +# Subtest: web reducer merges persisted tool result detail path into existing tool result +ok 144 - web reducer merges persisted tool result detail path into existing tool result + --- + duration_ms: 1.929625 + type: 'test' + ... +# Subtest: web reducer bounds huge live tool result previews +ok 145 - web reducer bounds huge live tool result previews + --- + duration_ms: 0.186708 + type: 'test' + ... +1..145 +# tests 145 +# suites 0 +# pass 145 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 27625.149209 diff --git a/.omo/evidence/20260723-awaited-network-timers/manual-runtime.json b/.omo/evidence/20260723-awaited-network-timers/manual-runtime.json new file mode 100644 index 00000000..72184cf3 --- /dev/null +++ b/.omo/evidence/20260723-awaited-network-timers/manual-runtime.json @@ -0,0 +1,11 @@ +{ + "retry": { + "calls": 2, + "status": 200, + "elapsedMs": 44 + }, + "timeout": { + "code": "network_timeout", + "elapsedMs": 22 + } +} diff --git a/src/network/fetch.ts b/src/network/fetch.ts index aa14b1bb..d78efee2 100644 --- a/src/network/fetch.ts +++ b/src/network/fetch.ts @@ -66,9 +66,6 @@ export async function networkFetch( const timeout = options.timeoutMs && options.timeoutMs > 0 ? setTimeout(() => controller.abort(new NetworkFetchError("network_timeout", `Network request timed out after ${options.timeoutMs}ms.`)), options.timeoutMs) : undefined; - if (timeout && typeof timeout === "object" && "unref" in timeout) { - (timeout as NodeJS.Timeout).unref(); - } try { const response = await performFetch(input, { @@ -233,21 +230,13 @@ function parseRetryAfterHeader(headerValue: string | null | undefined): number | } function delay(ms: number, signal?: AbortSignal): Promise { - if (!signal) return new Promise((resolve) => { - const timer = setTimeout(resolve, ms); - if (typeof timer === "object" && "unref" in timer) { - (timer as NodeJS.Timeout).unref(); - } - }); + if (!signal) return new Promise((resolve) => setTimeout(resolve, ms)); if (signal.aborted) return Promise.reject(new NetworkFetchError("network_abort", "Network retry aborted.", signal.reason)); return new Promise((resolve, reject) => { const timer = setTimeout(() => { signal.removeEventListener("abort", onAbort); resolve(); }, ms); - if (typeof timer === "object" && "unref" in timer) { - (timer as NodeJS.Timeout).unref(); - } const onAbort = () => { clearTimeout(timer); reject(new NetworkFetchError("network_abort", "Network retry aborted.", signal.reason));