From 9333eaed42206c596be83d5428681306a4cefa97 Mon Sep 17 00:00:00 2001 From: warren618 Date: Thu, 26 Mar 2026 12:06:11 +0800 Subject: [PATCH 1/2] fix(evolver): use word-boundary matching in _parse_confirmation to prevent false positives --- openspace/skill_engine/evolver.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openspace/skill_engine/evolver.py b/openspace/skill_engine/evolver.py index aab70a1..4dca928 100644 --- a/openspace/skill_engine/evolver.py +++ b/openspace/skill_engine/evolver.py @@ -652,10 +652,15 @@ class SkillEvolver: return bool(data.get("proceed", False)) except (json.JSONDecodeError, ValueError): pass - # Fallback: look for keywords - if any(w in response for w in ("\"proceed\": true", "proceed: true", "yes", "confirm")): + # Fallback: look for keywords (use word boundaries to avoid + # false positives from substrings like "know" matching "no") + _wb = re.search # shorthand + if any(w in response for w in ("\"proceed\": true", "proceed: true")) \ + or _wb(r"\byes\b", response) or _wb(r"\bconfirm\b", response): return True - if any(w in response for w in ("\"proceed\": false", "proceed: false", "no", "reject", "skip")): + if any(w in response for w in ("\"proceed\": false", "proceed: false")) \ + or _wb(r"\bno\b", response) or _wb(r"\breject\b", response) \ + or _wb(r"\bskip\b", response): return False # Default: skip — ambiguous response should not trigger costly evolution logger.debug("LLM confirmation response was ambiguous, defaulting to skip") From 1257f4cfeef791cf58fb743bfffe772aa35bbf75 Mon Sep 17 00:00:00 2001 From: warren618 Date: Fri, 27 Mar 2026 13:34:20 +0800 Subject: [PATCH 2/2] fix(evolver): use stem-style matching for confirm/reject/skip keywords Per reviewer feedback: keep strict \byes\b / \bno\b word boundaries to prevent false positives, but widen confirm/reject/skip to stem-style \bconfirm\w*\b etc. so common LLM variants like "confirmed", "rejected", "skipping" still parse correctly instead of falling through to the default False path. --- openspace/skill_engine/evolver.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/openspace/skill_engine/evolver.py b/openspace/skill_engine/evolver.py index 4dca928..ad9afdc 100644 --- a/openspace/skill_engine/evolver.py +++ b/openspace/skill_engine/evolver.py @@ -652,15 +652,21 @@ class SkillEvolver: return bool(data.get("proceed", False)) except (json.JSONDecodeError, ValueError): pass - # Fallback: look for keywords (use word boundaries to avoid - # false positives from substrings like "know" matching "no") + # Fallback: look for keywords. + # - yes/no use strict word boundaries to avoid false positives + # (e.g. "know" matching "no"). + # - confirm/reject/skip use stem-style matching so that common + # LLM variants like "confirmed", "rejected", "skipping" still + # parse correctly. _wb = re.search # shorthand if any(w in response for w in ("\"proceed\": true", "proceed: true")) \ - or _wb(r"\byes\b", response) or _wb(r"\bconfirm\b", response): + or _wb(r"\byes\b", response) \ + or _wb(r"\bconfirm\w*\b", response): return True if any(w in response for w in ("\"proceed\": false", "proceed: false")) \ - or _wb(r"\bno\b", response) or _wb(r"\breject\b", response) \ - or _wb(r"\bskip\b", response): + or _wb(r"\bno\b", response) \ + or _wb(r"\breject\w*\b", response) \ + or _wb(r"\bskip\w*\b", response): return False # Default: skip — ambiguous response should not trigger costly evolution logger.debug("LLM confirmation response was ambiguous, defaulting to skip")