From c8ee449daea92dd9f7b568288cf517d0deeaf44a Mon Sep 17 00:00:00 2001 From: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> Date: Fri, 11 Sep 2026 12:12:31 +0800 Subject: [PATCH] fix(runtime): align idle timeout grammar Signed-off-by: BigDataDZ <76271875+BigDataDZ@users.noreply.github.com> --- loopx/control_plane/effect_runtime.py | 7 ++++--- loopx/control_plane/effect_runtime_config.ts | 6 +++--- tests/fixtures/effect_runtime_idle_ms.json | 15 ++++++++++++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/loopx/control_plane/effect_runtime.py b/loopx/control_plane/effect_runtime.py index af116b983d..ad9e4ee8ec 100644 --- a/loopx/control_plane/effect_runtime.py +++ b/loopx/control_plane/effect_runtime.py @@ -32,6 +32,7 @@ STARTUP_READY_TIMEOUT_SECONDS = 15.0 STARTUP_POLL_SECONDS = 0.025 _NODE_VERSION_RE = re.compile(r"^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$") +_IDLE_MS_RE = re.compile(r"[ \t\r\n\f\v]*([0-9]+)[ \t\r\n\f\v]*") _RUNTIME_SOURCE_SUFFIXES = frozenset({".json", ".ts"}) _RuntimeSourceSnapshot = tuple[tuple[str, int, int, int], ...] @@ -40,13 +41,13 @@ def _validate_effect_runtime_idle_ms(environment: Mapping[str, str]) -> int: raw = environment.get("LOOPX_EFFECT_RUNTIME_IDLE_MS") if raw is None: return DEFAULT_EFFECT_RUNTIME_IDLE_MS - normalized = raw.strip() - if not re.fullmatch(r"[0-9]+", normalized): + match = _IDLE_MS_RE.fullmatch(raw) + if match is None: raise EffectRuntimeStartupError( "LOOPX_EFFECT_RUNTIME_IDLE_MS must be a positive base-10 integer", diagnostic_code="invalid_runtime_idle_ms", ) - parsed = int(normalized) + parsed = int(match.group(1)) if not 1 <= parsed <= MAX_EFFECT_RUNTIME_IDLE_MS: raise EffectRuntimeStartupError( "LOOPX_EFFECT_RUNTIME_IDLE_MS must be between " diff --git a/loopx/control_plane/effect_runtime_config.ts b/loopx/control_plane/effect_runtime_config.ts index d6e57efa38..2adac02176 100644 --- a/loopx/control_plane/effect_runtime_config.ts +++ b/loopx/control_plane/effect_runtime_config.ts @@ -3,13 +3,13 @@ export const MAX_EFFECT_RUNTIME_IDLE_MS = 2_147_483_647; export function effectRuntimeIdleMs(value: string | undefined): number { if (value === undefined) return DEFAULT_EFFECT_RUNTIME_IDLE_MS; - const normalized = value.trim(); - if (!/^\d+$/u.test(normalized)) { + const match = /^[\t\n\v\f\r ]*(\d+)[\t\n\v\f\r ]*$/u.exec(value); + if (match === null) { throw new Error( "LOOPX_EFFECT_RUNTIME_IDLE_MS must be a positive base-10 integer", ); } - const parsed = Number(normalized); + const parsed = Number(match[1]); if ( !Number.isSafeInteger(parsed) || parsed < 1 || parsed > MAX_EFFECT_RUNTIME_IDLE_MS diff --git a/tests/fixtures/effect_runtime_idle_ms.json b/tests/fixtures/effect_runtime_idle_ms.json index 1ed0dd30e5..c2a64f840b 100644 --- a/tests/fixtures/effect_runtime_idle_ms.json +++ b/tests/fixtures/effect_runtime_idle_ms.json @@ -4,7 +4,20 @@ "valid": [ { "raw": null, "value": 300000 }, { "raw": " 250 ", "value": 250 }, + { "raw": "\t250\n", "value": 250 }, + { "raw": "\u000b250\u000c", "value": 250 }, { "raw": "2147483647", "value": 2147483647 } ], - "invalid": ["", "not-a-number", "0", "-1", "1.5", "1e3", "2147483648"] + "invalid": [ + "", + "not-a-number", + "0", + "-1", + "1.5", + "1e3", + "2147483648", + "\u0085250\u0085", + "\u001c250\u001c", + "\ufeff250\ufeff" + ] }