Skip to content

fix(errors): prevent billing false positive in sanitizeUserFacingText#13467

Closed
lailoo wants to merge 3 commits intoopenclaw:mainfrom
lailoo:fix/billing-false-positive-13434
Closed

fix(errors): prevent billing false positive in sanitizeUserFacingText#13467
lailoo wants to merge 3 commits intoopenclaw:mainfrom
lailoo:fix/billing-false-positive-13434

Conversation

@lailoo
Copy link

@lailoo lailoo commented Feb 10, 2026

Summary

Fixes #13434

Problem

sanitizeUserFacingText() unconditionally applies isBillingErrorMessage() to all user-facing text. The isBillingErrorMessage function uses a broad heuristic that matches any text containing both "billing" and one of "payment", "upgrade", "credits", or "plan". This causes assistant-generated content discussing billing/payment topics (e.g., gym membership billing details) to be replaced with the generic billing error warning.

Fix

Add a shouldRewriteBillingText() guard function (matching the existing shouldRewriteContextOverflowText() pattern) that distinguishes real billing errors from assistant prose:

  1. Precise billing patterns (402, insufficient credits, credit balance, payment required, plans & billing) are rewritten unconditionally — these are unambiguous error strings.
  2. Broad heuristic matches (billing + payment/upgrade/credits/plan) are only rewritten when the text looks like a raw error message (API payload, HTTP error, error prefix, or single-sentence without markdown/paragraphs).

Reproduction & Verification

Unit-level (direct function call):

Before fix (main branch) — Bug reproduced:

--- Assistant content (should NOT be rewritten) ---
  "**Billing:** Processed through ABC Financial Services..."  ❌ FALSE POSITIVE
  "The gym membership billing cycle runs monthly..."           ❌ FALSE POSITIVE
  "Here is a summary of the billing and payment options..."    ❌ FALSE POSITIVE

After fix — All verified:

--- Assistant content (should NOT be rewritten) ---
  ✅ PASS (all assistant content samples preserved)

--- Real billing errors (SHOULD be rewritten) ---
  ✅ PASS: "insufficient credits"
  ✅ PASS: "billing: please upgrade your plan"
  ✅ PASS: "Your credit balance is too low"

Integration-level (real gateway reply pipeline):

Added normalizeReplyPayload integration tests in src/auto-reply/reply/normalize-reply.test.ts that exercise the full reply normalization pipeline (normalizeReplyPayloadsanitizeUserFacingText):

Before fix (main branch) — Bug reproduced through real pipeline:

normalizeReplyPayload({ text: "**Billing:** ... payments ..." })
  → text: "⚠️ API provider returned a billing error..."  ❌ FALSE POSITIVE

After fix — Pipeline preserves assistant content:

normalizeReplyPayload({ text: "**Billing:** ... payments ..." })
  → text: "**Billing:** Processed through ABC Financial Services..."  ✅ PRESERVED

normalizeReplyPayload({ text: "insufficient credits" })
  → text: "⚠️ API provider returned a billing error..."  ✅ REWRITTEN

Effect on User Experience

Before fix:
Sub-agent researches gym membership details → output contains "Billing: ... payments" → parent receives "⚠️ API provider returned a billing error" instead of actual findings.

After fix:
Assistant content discussing billing/payment topics is delivered as-is. Real billing errors (402, insufficient credits, etc.) are still correctly caught and rewritten.

Testing

  • ✅ 14 unit tests pass (12 existing + 2 new regression tests in sanitizeuserfacingtext.test.ts)
  • ✅ 2 new integration tests pass (normalizeReplyPayload pipeline in normalize-reply.test.ts)
  • isBillingErrorMessage() unchanged — error classification for failover/logging still works

@openclaw-barnacle openclaw-barnacle bot added the agents Agent runtime and tooling label Feb 10, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +169 to +172
const hasMultipleSentences = /[.!?]\s+[A-Z]/.test(raw);
const hasMarkdown = /[*_#[\]|]/.test(raw);
const hasParagraphs = raw.includes("\n\n");
return !hasMultipleSentences && !hasMarkdown && !hasParagraphs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lowercase sentence false positive
hasMultipleSentences uses /[.!?]\s+[A-Z]/ (errors.ts:169), so multi-sentence prose where the next sentence starts lowercase (e.g., "... . payment is ...") is treated as single-sentence and will still be rewritten if it matches the broad billing heuristic. This undermines the goal of not rewriting assistant prose; consider using a sentence boundary check that doesn’t rely on capitalization (or a different prose-vs-error heuristic).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 169:172

Comment:
**Lowercase sentence false positive**
`hasMultipleSentences` uses `/[.!?]\s+[A-Z]/` (errors.ts:169), so multi-sentence prose where the next sentence starts lowercase (e.g., "... . payment is ...") is treated as single-sentence and will still be rewritten if it matches the broad billing heuristic. This undermines the goal of not rewriting assistant prose; consider using a sentence boundary check that doesn’t rely on capitalization (or a different prose-vs-error heuristic).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +168 to +172
// Single-sentence short texts without markdown are likely error messages.
const hasMultipleSentences = /[.!?]\s+[A-Z]/.test(raw);
const hasMarkdown = /[*_#[\]|]/.test(raw);
const hasParagraphs = raw.includes("\n\n");
return !hasMultipleSentences && !hasMarkdown && !hasParagraphs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One-sentence prose still rewritten
The fallback return !hasMultipleSentences && !hasMarkdown && !hasParagraphs; (errors.ts:168-172) will rewrite any single-sentence assistant content that happens to contain billing plus payment/upgrade/credits/plan (the broad heuristic). If the intent is to only rewrite raw error strings on the broad path, this condition is too permissive; a one-sentence paragraph of prose will be replaced by BILLING_ERROR_USER_MESSAGE.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 168:172

Comment:
**One-sentence prose still rewritten**
The fallback `return !hasMultipleSentences && !hasMarkdown && !hasParagraphs;` (errors.ts:168-172) will rewrite any single-sentence assistant content that happens to contain `billing` plus `payment/upgrade/credits/plan` (the broad heuristic). If the intent is to only rewrite raw error strings on the broad path, this condition is too permissive; a one-sentence paragraph of prose will be replaced by `BILLING_ERROR_USER_MESSAGE`.

How can I resolve this? If you propose a fix, please make it concise.

@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added stale Marked as stale due to inactivity and removed stale Marked as stale due to inactivity labels Feb 21, 2026
@steipete
Copy link
Contributor

Closing as AI-assisted stale-fix triage.

Linked issue #13434 ("False positive: Sub-agent output about billing/payments incorrectly flagged as API error") is currently closed and was closed on 2026-02-10T15:05:22Z with state reason completed.
Given that issue is closed, this fix PR is no longer needed in the active queue and is being closed as stale.

If this specific implementation is still needed on current main, please reopen #13467 (or open a new focused fix PR) and reference #13434 for fast re-triage.

@steipete steipete closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False positive: Sub-agent output about billing/payments incorrectly flagged as API error

2 participants