Skip to content

fix BTW usage placeholder visibility#78824

Merged
vincentkoc merged 2 commits intoopenclaw:mainfrom
RajvardhanPatil07:fix/btw-usage-placeholder
May 7, 2026
Merged

fix BTW usage placeholder visibility#78824
vincentkoc merged 2 commits intoopenclaw:mainfrom
RajvardhanPatil07:fix/btw-usage-placeholder

Conversation

@RajvardhanPatil07
Copy link
Copy Markdown
Contributor

@RajvardhanPatil07 RajvardhanPatil07 commented May 7, 2026

Summary

  • Problem: /btw without a side question returns Usage: /btw <side question>, and plain-text channel sanitization treats <side question> as an HTML-like tag.
  • Why it matters: users on sanitized outbound channels can see only Usage: /btw , losing the helpful placeholder.
  • What changed: changed the producer string to Usage: /btw [side question], updated the /btw command test, added a sanitizer regression, and added a changelog entry.
  • What did NOT change (scope boundary): no sanitizer rules, command parsing, /side alias behavior, or live channel delivery plumbing changed.

AI-assisted: yes.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: the /btw missing-question usage placeholder must remain visible after outbound plain-text sanitization.
  • Real environment tested: local OpenClaw source checkout on macOS with Node v25.9.0 and pnpm 10.33.2 via npx; actual sanitizeForPlainText implementation imported with tsx.
  • Exact steps or command run after this patch:
    • npx pnpm@10.33.2 exec tsx -e 'import { sanitizeForPlainText } from "./src/infra/outbound/sanitize-text.ts"; console.log("old:", JSON.stringify(sanitizeForPlainText("Usage: /btw <side question>"))); console.log("new:", JSON.stringify(sanitizeForPlainText("Usage: /btw [side question]")));'
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):
old: "Usage: /btw "
new: "Usage: /btw [side question]"
  • Observed result after fix: the old tag-shaped placeholder is still stripped by the sanitizer, while the new bracketed placeholder remains visible exactly as delivered to plain-text channels.
  • What was not tested: a live WhatsApp/Telegram/Signal send; this patch is isolated to the command producer text plus the shared sanitizer behavior.
  • Before evidence (optional but encouraged): the same terminal capture above includes the pre-fix string shape as old: "Usage: /btw ".

Root Cause (if applicable)

  • Root cause: the usage placeholder was written with angle brackets, so the outbound sanitizer's remaining-HTML stripping pattern interpreted <side question> as a tag.
  • Missing detection / guardrail: no regression asserted that command usage examples with placeholders survive the plain-text sanitizer.
  • Contributing context (if known): inline code/backticks would not be enough if the inner placeholder remains tag-shaped before the final stripping pass.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/auto-reply/reply/commands-btw.test.ts and src/infra/outbound/sanitize-text.test.ts.
  • Scenario the test should lock in: /btw with no question returns the bracketed usage string, and that usage string survives sanitizeForPlainText unchanged.
  • Why this is the smallest reliable guardrail: the regression is caused by the specific producer text plus the shared plain-text sanitizer, so focused coverage locks both sides without requiring a live channel.
  • Existing test that already covers this (if any): the existing /btw missing-question test covered the producer output, but expected the unsafe placeholder.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

/btw with no side question now replies with Usage: /btw [side question] instead of Usage: /btw <side question>.

Diagram (if applicable)

Before:
/btw -> Usage: /btw <side question> -> sanitizer strips placeholder -> Usage: /btw 

After:
/btw -> Usage: /btw [side question] -> sanitizer preserves placeholder -> Usage: /btw [side question]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node v25.9.0, pnpm 10.33.2 via npx
  • Model/provider: N/A
  • Integration/channel (if any): shared plain-text outbound sanitizer path; no live channel credentials used
  • Relevant config (redacted): N/A

Steps

  1. Run the live sanitizer command from the real behavior proof section.
  2. Run npx pnpm@10.33.2 test src/auto-reply/reply/commands-btw.test.ts src/infra/outbound/sanitize-text.test.ts.
  3. Run npx pnpm@10.33.2 exec oxfmt --check --threads=1 src/auto-reply/reply/commands-btw.ts src/auto-reply/reply/commands-btw.test.ts src/infra/outbound/sanitize-text.test.ts CHANGELOG.md.
  4. Run npx pnpm@10.33.2 check:changed.

Expected

  • The bracketed usage placeholder stays visible after sanitization.
  • Focused tests, formatting, and changed-file checks pass.

Actual

  • old: "Usage: /btw "
  • new: "Usage: /btw [side question]"
  • Focused tests passed 2 Vitest shards: 39 tests total.
  • oxfmt --check reported all matched files use the correct format.
  • check:changed completed successfully.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: old placeholder shape strips in the actual sanitizer, new placeholder shape survives; /btw missing-question command now returns the bracketed usage string; focused sanitizer and command tests pass.
  • Edge cases checked: formatting, whitespace, and repo changed-file checks.
  • What you did not verify: live external-channel delivery with real credentials.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

None.

@openclaw-barnacle openclaw-barnacle Bot added size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels May 7, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 7, 2026

Codex review: needs maintainer review before merge.

Summary
The PR changes the /btw missing-question usage text to a bracketed placeholder, updates command and sanitizer tests, and adds a changelog fix entry.

Reproducibility: yes. Current main returns the tag-shaped /btw usage placeholder, and source inspection shows the shared plain-text sanitizer removes that tag-shaped text; the PR body also supplies old/new output from the real sanitizer implementation.

Real behavior proof
Sufficient (terminal): The PR body contains terminal output from a real local OpenClaw checkout using the actual sanitizer implementation, showing the after-fix placeholder remains visible.

Next step before merge
No repair PR is needed for the diff itself; the remaining blocker is human/contributor handling to update the branch and rerun exact-head checks.

Security
Cleared: The diff changes static command copy, tests, and changelog text only; it does not introduce a concrete security or supply-chain concern.

Review details

Best possible solution:

Land the narrow producer-text fix with focused regression coverage and changelog after updating the branch and getting exact-head checks green; track any broader slash-command placeholder audit separately.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main returns the tag-shaped /btw usage placeholder, and source inspection shows the shared plain-text sanitizer removes that tag-shaped text; the PR body also supplies old/new output from the real sanitizer implementation.

Is this the best way to solve the issue?

Yes. Changing the producer placeholder to brackets is the narrowest maintainable fix because it preserves the sanitizer's existing HTML-stripping and autolink contracts while keeping this usage hint visible.

Acceptance criteria:

  • pnpm test src/auto-reply/reply/commands-btw.test.ts src/infra/outbound/sanitize-text.test.ts
  • pnpm exec oxfmt --check --threads=1 src/auto-reply/reply/commands-btw.ts src/auto-reply/reply/commands-btw.test.ts src/infra/outbound/sanitize-text.test.ts CHANGELOG.md
  • pnpm check:changed

What I checked:

  • Current main emits tag-shaped usage text: On current main, the /btw missing-question branch returns BTW_USAGE, which is still Usage: /btw <side question>. (src/auto-reply/reply/commands-btw.ts:7, 62ccd8b644eb)
  • Shared sanitizer strips the placeholder shape: HTML_TAG_RE matches lowercase tag-shaped text and sanitizeForPlainText removes remaining HTML-like tags after autolink preservation. (src/infra/outbound/sanitize-text.ts:36, 62ccd8b644eb)
  • Outbound plain-text delivery uses the shared sanitizer: The direct text/media outbound adapter applies sanitizeForPlainText through its sanitizeText hook, so the producer string affects sanitized channel delivery. (src/channels/plugins/outbound/direct-text-media.ts:116, 62ccd8b644eb)
  • PR diff targets only the implicated surface: The PR changes BTW_USAGE to Usage: /btw [side question], updates the command expectation, adds a sanitizer regression, and adds one changelog entry. (src/auto-reply/reply/commands-btw.ts:7, e9abc34dc9f3)
  • Real behavior proof is sufficient: The PR body includes copied terminal output from the actual sanitizeForPlainText implementation showing the old string becomes Usage: /btw while the new bracketed string remains visible; the Real behavior proof check passed on the PR head. (e9abc34dc9f3)
  • Exact-head CI is not yet green: The PR head is based on 2e78fc57af0983aef12225021d076aae4836b64e; failed annotations are in extension auth/typecheck files, while current main contains 62ccd8b644ebeade4c12091980b60686cc92e660 addressing model/tool normalization regressions. (extensions/codex/src/app-server/auth-bridge.ts:275, e9abc34dc9f3)

Likely related people:

  • ngutman: Introduced the /btw side-question command, including the command handler, tests, and slash-command documentation where the usage shape originated. (role: introduced behavior; confidence: high; commits: 9aac55d30614; files: src/auto-reply/reply/commands-btw.ts, src/auto-reply/reply/commands-btw.test.ts, docs/tools/slash-commands.md)
  • Takhoffman: Recently maintained the same /btw command handler and tests around target session and agent-directory behavior. (role: recent maintainer; confidence: medium; commits: f5d0b5456311, dcf49fa5d81e, a46606924fb9; files: src/auto-reply/reply/commands-btw.ts, src/auto-reply/reply/commands-btw.test.ts)
  • AytuncYildizli: Introduced the plain-text sanitizer behavior that strips HTML-like tags; the narrow fix still belongs in the /btw producer string. (role: adjacent sanitizer owner; confidence: medium; commits: 62d0cfeee7af; files: src/infra/outbound/sanitize-text.ts)
  • steipete: Recently maintained the outbound sanitizer and direct outbound delivery surfaces involved in the reproduction path. (role: recent adjacent maintainer; confidence: medium; commits: 92284bc46043, c2d31a5e59c1, 856592cf001b; files: src/infra/outbound/sanitize-text.ts, src/channels/plugins/outbound/direct-text-media.ts)

Remaining risk / open question:

  • Exact-head GitHub checks currently fail in unrelated extension auth/typecheck jobs; the branch should be rebased or updated onto current main and rerun before merge.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 62ccd8b644eb.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@RajvardhanPatil07 RajvardhanPatil07 force-pushed the fix/btw-usage-placeholder branch from f6ea63d to e9abc34 Compare May 7, 2026 07:13
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@RajvardhanPatil07 RajvardhanPatil07 marked this pull request as ready for review May 7, 2026 07:30
@vincentkoc vincentkoc self-assigned this May 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@vincentkoc vincentkoc merged commit c25f319 into openclaw:main May 7, 2026
95 of 112 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proof: supplied External PR includes structured after-fix real behavior proof. size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BTW usage string <side question> placeholder eaten by markdown channels

2 participants