Skip to content

fix(feishu): add searchable streaming fallback#74808

Closed
yetval wants to merge 1 commit into
openclaw:mainfrom
yetval:fix/feishu-streaming-search-fallback
Closed

fix(feishu): add searchable streaming fallback#74808
yetval wants to merge 1 commit into
openclaw:mainfrom
yetval:fix/feishu-streaming-search-fallback

Conversation

@yetval

@yetval yetval commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an opt-in channels.feishu.streamingSearchFallback setting
  • send the final streamed Feishu card text as a plain text fallback when enabled so Feishu conversation search can index it
  • document the Feishu search limitation and visible duplicate-message tradeoff

Fixes #74767

Tests

  • pnpm test extensions/feishu/src/reply-dispatcher.test.ts extensions/feishu/src/streaming-card.test.ts
  • pnpm test extensions/feishu/src/tools-config.test.ts extensions/feishu/src/policy.test.ts extensions/feishu/src/accounts.test.ts
  • pnpm exec oxfmt --check --threads=1 extensions/feishu/src/reply-dispatcher.ts extensions/feishu/src/streaming-card.ts extensions/feishu/src/reply-dispatcher.test.ts docs/channels/feishu.md extensions/feishu/src/config-schema.ts extensions/feishu/openclaw.plugin.json

Real behavior proof

Behavior addressed: Feishu users searching their conversation history for content from streamed assistant replies could not find any matches (#74767), because OpenClaw's Feishu streaming path closes the final text into a CardKit interactive message (msg_type: "interactive"), and Feishu's conversation-search index does not cover interactive card content; only text and post messages are indexed, per https://open.feishu.cn/document/server-docs/im-v1/message/create.

Real environment tested: Linux, real OpenClaw checkout at this PR head, Node 22.19. The repro drives the actual production createFeishuReplyDispatcher (the function this PR changes) through a complete streamed final turn with channels.feishu.streamingSearchFallback first false, then true. The streaming card session, send.ts, the Lark client request construction, and the dispatcher gating are all unmodified production code; the only thing replaced is the literal network socket: the Lark SDK HTTP transport and the SSRF-guarded fetch the streaming card uses are swapped for an in-memory capturer that records every outbound Feishu API request and returns canned success bodies. No live Feishu credentials are exercised.

Exact steps or command run after this patch:

node scripts/run-vitest.mjs extensions/feishu/src/repro-74808-proof.test.ts

The repro registers the in-memory capturer, builds a config for each setting value, drives one full streamed final reply through createFeishuReplyDispatcher (deliver final, then idle/close), and records every outbound Feishu API request with its msg_type.

Evidence after fix: copied live output (full before/after capture, no redaction needed) from this PR head:

final reply text:
Here is what I found in the deployment runbook:

- ssh into the bastion via `ssh [email protected]`
- run `./scripts/rollout.sh canary --region=us-east-1`
- watch `./scripts/health-check.sh --watch` until p99 latency returns to baseline

Cite this in #incident-2026-05-15.

=== BEFORE  streamingSearchFallback: false (current main behavior) ===
  [cardkit fetch] POST /open-apis/cardkit/v1/cards
  [lark-sdk im.message] POST /open-apis/im/v1/messages/om_parent/reply msg_type="interactive"
  [cardkit fetch] PUT /open-apis/cardkit/v1/cards/ckcrd_fake_1/elements/content/content
  [cardkit fetch] PUT /open-apis/cardkit/v1/cards/ckcrd_fake_1/elements/note/content
  [cardkit fetch] PATCH /open-apis/cardkit/v1/cards/ckcrd_fake_1/settings
  -> message sends: interactive
  -> search-indexable send present (msg_type text/post): NO

=== AFTER   streamingSearchFallback: true (this PR) ===
  [cardkit fetch] POST /open-apis/cardkit/v1/cards
  [lark-sdk im.message] POST /open-apis/im/v1/messages/om_parent/reply msg_type="interactive"
  [cardkit fetch] PUT /open-apis/cardkit/v1/cards/ckcrd_fake_2/elements/content/content
  [cardkit fetch] PUT /open-apis/cardkit/v1/cards/ckcrd_fake_2/elements/note/content
  [cardkit fetch] PATCH /open-apis/cardkit/v1/cards/ckcrd_fake_2/settings
  [lark-sdk im.message] POST /open-apis/im/v1/messages/om_parent/reply msg_type="post"
  -> message sends: interactive, post
  -> search-indexable send present (msg_type text/post): YES
  -> searchable post payload content: {"zh_cn":{"content":[[{"tag":"md","text":"Here is what I found in the deployment runbook:\n\n- ssh into the bastion via `ssh [email protected]`\n- run `./scripts/rollout.sh canary --region=us-east-1`\n- watch `./scripts/health-check.sh --watch` until p99 latency returns to baseline\n\nCite this in #incident-2026-05-15."}]]}}

Observed result after fix: with the flag off (current main), the streamed final turn produces only the interactive streaming card (msg_type: "interactive"), so no search-indexable message is emitted; this is the symptom in #74767. With channels.feishu.streamingSearchFallback: true, the dispatcher additionally invokes sendSearchableStreamingFallback after the card closes, and the captured outbound request is an im.message.reply with msg_type: "post" whose content carries the full final reply text verbatim, which Feishu's conversation-search index covers. The duplicate visible message is the documented tradeoff and the setting stays default-off, so existing Feishu deployments are unaffected.

What was not tested: a live Feishu Open Platform round-trip against a real tenant, which requires Feishu app credentials and a configured chat. The capture above is the actual outbound JSON the production dispatcher produces; whether Feishu's search index ultimately surfaces the post is governed by Feishu's documented msg_type indexing rules cited above. A maintainer with a Feishu test tenant can confirm the end-to-end search hit if desired.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: feishu Channel integration: feishu size: S labels Apr 30, 2026
@clawsweeper

clawsweeper Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 12, 2026, 11:10 AM ET / 15:10 UTC.

Summary
Adds an opt-in channels.feishu.streamingSearchFallback setting that sends a second Feishu post copy of final streamed card text and documents the visible duplicate-message tradeoff.

PR surface: Source +32, Tests +35, Docs +4. Total +71 across 5 files.

Reproducibility: no. not at high confidence end to end. Current source and the linked report establish that streamed replies use interactive cards, while the harness proves the proposed outbound post, but no real tenant search result verifies the complete failure-and-fix path.

Review metrics: 2 noteworthy metrics.

  • Config surface added: 1 optional Feishu setting. The new operator setting controls user-visible duplicate delivery and therefore requires an explicit product decision.
  • Enabled delivery fanout: 1 additional post send per eligible streamed final. The extra transport send is the searchability mechanism and adds visible duplication, quota use, and an independent failure point.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Add a redacted live Feishu conversation-search hit for the exact fallback post, or obtain an explicit maintainer proof override.
  • Obtain Feishu owner acceptance for the duplicate-message, quota, and partial-failure tradeoffs.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The supplied harness exercises production dispatcher and sender code but replaces both Feishu transports with in-memory capturers, so it proves request shape rather than the claimed live conversation-search result; add redacted tenant proof or obtain an explicit maintainer override, then update the PR body to trigger re-review or ask a maintainer to comment @clawsweeper re-review.

Risk before merge

  • [P1] The defining outcome—a streamed reply becoming discoverable through Feishu conversation search—has not been shown against a real tenant, and the cited API page does not document that indexing behavior.
  • [P1] Enabling the option intentionally produces a second visible final message, which may be confusing in direct conversations and threads even though the default remains off.
  • [P1] Each enabled streamed final consumes another message send and introduces an independent partial-failure point after the interactive card has already completed.

Maintainer options:

  1. Require tenant proof and owner acceptance (recommended)
    Capture a redacted Feishu search hit for the exact fallback post and obtain explicit owner acceptance of duplicate delivery, quota use, and partial-failure behavior before merge.
  2. Accept payload-level proof
    A Feishu owner may explicitly override the live-proof gate and intentionally own the opt-in delivery tradeoffs despite the search-indexing contract remaining undocumented.
  3. Pause the workaround
    Leave the PR waiting or close it if maintainers do not want another config surface and duplicate delivery for an externally unverified search behavior.

Next step before merge

  • [P1] A Feishu owner should review the new configuration and duplicate-delivery policy, then either supply live tenant proof or explicitly override the proof gate; no narrow automated code repair is currently indicated.

Security
Cleared: The diff adds schema, manifest, docs, a focused test, and reuse of an existing Feishu sender without new dependencies, permissions, secret handling, downloads, or supply-chain execution.

Review details

Best possible solution:

Land the default-off fallback only after a real Feishu tenant proves that the exact emitted post reply appears in conversation search and Feishu owners explicitly accept the duplicate-delivery, quota, and partial-failure tradeoffs.

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

No, not at high confidence end to end. Current source and the linked report establish that streamed replies use interactive cards, while the harness proves the proposed outbound post, but no real tenant search result verifies the complete failure-and-fix path.

Is this the best way to solve the issue?

Unclear. Reusing the existing post sender behind a default-off setting is a narrow implementation, but it is only the best solution if Feishu owners accept the extra visible message and live tenant proof confirms that the post is actually searchable.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against e728957989f6.

Label changes

Label changes:

  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🦪 silver shellfish, so this older rating label is no longer current.

Label justifications:

  • P2: This is a bounded Feishu usability improvement with a documented workaround and no impact unless users opt in.
  • merge-risk: 🚨 message-delivery: Merging introduces an opt-in path that deliberately duplicates final reply delivery and can independently fail after the streaming card completes.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The supplied harness exercises production dispatcher and sender code but replaces both Feishu transports with in-memory capturers, so it proves request shape rather than the claimed live conversation-search result; add redacted tenant proof or obtain an explicit maintainer override, then update the PR body to trigger re-review or ask a maintainer to comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +32, Tests +35, Docs +4. Total +71 across 5 files.

View PR surface stats
Area Files Added Removed Net
Source 3 32 0 +32
Tests 1 35 0 +35
Docs 1 4 0 +4
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 5 71 0 +71

What I checked:

  • Current-main behavior: Current main closes streamed final replies through the interactive CardKit path and has no searchable fallback setting or second post-message send, so the requested behavior remains absent. (extensions/feishu/src/reply-dispatcher.ts:235, e728957989f6)
  • Clean current-main integration: GitHub's generated merge commit applies the five focused file changes on current main without removing newer Feishu dispatcher behavior. (extensions/feishu/src/reply-dispatcher.ts:237, 6dc87e617869)
  • Fallback implementation: The proposed merge gates the additional delivery behind the new default-off account setting, waits until the streaming close path, chunks the final text, and reuses the existing Feishu message sender. (extensions/feishu/src/reply-dispatcher.ts:423, 6dc87e617869)
  • Focused regression coverage: The PR adds coverage that enables the setting, completes a streamed final reply, and verifies one additional message send with the original reply and thread routing fields. (extensions/feishu/src/reply-dispatcher.test.ts:674, 6dc87e617869)
  • External API contract gap: Feishu's official message-create documentation distinguishes post and interactive message types and documents payload limits, but the cited page does not state that conversation search indexes post while excluding interactive-card content.
  • Proof discussion: The contributor explicitly states that no live Feishu tenant search result was tested and requests either maintainer tenant validation or a proof override; no such override or approving review is present. (9cc80a044526)

Likely related people:

  • xzq-xu: The original Feishu CardKit streaming commit explicitly credits @xzq-xu for the streaming implementation that this fallback extends. (role: introduced behavior; confidence: high; commits: 65be9ccf63f3; files: extensions/feishu/src/reply-dispatcher.ts, extensions/feishu/src/streaming-card.ts)
  • LeftX: Authored the commit that landed Feishu CardKit streaming support and its initial dispatcher, schema, tests, and streaming-session implementation. (role: feature merger; confidence: high; commits: 65be9ccf63f3; files: extensions/feishu/src/reply-dispatcher.ts, extensions/feishu/src/streaming-card.ts, extensions/feishu/src/config-schema.ts)
  • qiangu: Authored the recent merged refactor that expanded ordinary final-reply streaming-card behavior in the same dispatcher and streaming-session files. (role: recent adjacent contributor; confidence: high; commits: 3b8ab4e11232; files: extensions/feishu/src/reply-dispatcher.ts, extensions/feishu/src/reply-dispatcher.test.ts, extensions/feishu/src/streaming-card.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from 17d2087 to 3572c0f Compare May 3, 2026 02:47
@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime scripts Repository scripts size: M and removed size: S labels May 3, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from f42b457 to 3c24702 Compare May 3, 2026 03:19
@openclaw-barnacle openclaw-barnacle Bot added size: S and removed gateway Gateway runtime scripts Repository scripts size: M labels May 3, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from 3c24702 to 27816ac Compare May 14, 2026 19:31
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 14, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from d5dc8ef to 963b9bb Compare May 16, 2026 22:29
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 16, 2026
@clawsweeper

clawsweeper Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added the P2 Normal backlog priority with limited blast radius. label May 16, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch 2 times, most recently from 0a49d2b to 6d78d0e Compare May 18, 2026 14:58
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 18, 2026
@clawsweeper

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. label May 18, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from 6d78d0e to 3ee9dc1 Compare May 24, 2026 02:14
@clawsweeper

clawsweeper Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@yetval

yetval commented May 24, 2026

Copy link
Copy Markdown
Contributor Author

No Feishu/Lark tenant access on my side to capture the live search-result proof ClawSweeper is asking for. Requesting a maintainer with Feishu tenant credentials to either pick up live proof capture or apply a proof override.

Code review status from ClawSweeper (latest 2026-05-24 02:19 UTC): patch quality 🐚 platinum hermit, default-off opt-in setting (channels.feishu.streamingSearchFallback), only blockers are live tenant proof and owner acceptance of the duplicate-visible-message tradeoff.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels May 26, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from deba93b to 29c2ce5 Compare May 27, 2026 05:29
@yetval

yetval commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Rebased onto current openclaw/main (44c1cc8285c). Rank-up move addressed: stripped the CHANGELOG.md entry from fix(feishu): add searchable streaming fallback. Branch now no longer modifies CHANGELOG.md. No functional change. New head: 29c2ce5e50f.

@clawsweeper

clawsweeper Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@yetval

yetval commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

The code is unchanged and was rated clean in the last verdict (platinum hermit, no findings). The only remaining blocker is live Feishu/Lark tenant proof showing a streamed reply surfacing in tenant search after enabling streamingSearchFallback.

I do not have access to a Feishu/Lark tenant to capture that, and I will not submit fabricated screenshots/logs. Requesting one of:

  1. A maintainer with Feishu/Lark credentials enables streamingSearchFallback, sends a streamed reply, and records a redacted search hit; or
  2. An explicit maintainer proof override accepting the existing payload-level proof, given the option is default-off and reuses the existing post-message sender (no new dependency or delivery path when disabled).

Real behavior proof:
Behavior addressed: when streamingSearchFallback is enabled, final streamed card text is re-sent through the existing post-message sender after the streaming card closes, making the reply searchable in the Feishu conversation.
Real environment tested: dispatcher unit tests only (no live Feishu tenant).
Exact steps or command run after this patch: node scripts/run-vitest.mjs extensions/feishu/src/reply-dispatcher.test.ts
Evidence after fix: 56/56 reply-dispatcher tests pass, covering the fallback-enabled and default-off paths.
Observed result after fix: with the flag off, behavior is unchanged; with it on, one additional post-message send follows the closed streaming card.
What was not tested: a redacted live Feishu tenant search result; this needs tenant credentials I do not have. Requesting maintainer capture or an explicit proof override.

@RomneyDa

Copy link
Copy Markdown
Member

Heads up: this PR needs to be updated against current main before the new required Dependency Guard check can pass.

@yetval

yetval commented May 31, 2026

Copy link
Copy Markdown
Contributor Author

Status update to tee this up for maintainer review.

Code / surface is ready:

  • Config surface is aligned and default-off across all four places: extensions/feishu/src/config-schema.ts (StreamingSearchFallbackSchema, added to FeishuSharedConfigShape), the manifest extensions/feishu/openclaw.plugin.json (account-level + shared shape), and docs/channels/feishu.md (config example + the config reference table). streamingSearchFallback defaults to false, so existing tenants are unaffected on upgrade.
  • pnpm test extensions/feishu/src/reply-dispatcher.test.ts → 56 passed locally. CI is green.

Remaining blocker is the proof gap, which needs maintainer/tenant access:
The supplied proof is payload-level (outbound interactive card vs post plain-text) plus unit tests. The one thing it cannot show from the contributor side is a redacted live Feishu/Lark tenant conversation-search hit for the final streamed reply text, because that requires a Feishu test tenant I don't have access to.

Per the two maintainer options ClawSweeper laid out, this needs one of:

  1. A maintainer (or Mantis on a Feishu test tenant) capturing a redacted conversation-search hit after enabling streamingSearchFallback, or
  2. An explicit maintainer proof override accepting the payload-level proof, together with product acceptance of the documented tradeoff: when enabled, users see one additional final plain-text message after the streaming card closes (this is by design — it is what makes the content searchable).

Happy to adjust the implementation if maintainers prefer a different delivery shape for the fallback.

@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from c85ab81 to 0e7733b Compare June 2, 2026 21:50
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 2, 2026
@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from 0e7733b to 855c22b Compare June 5, 2026 08:04
@yetval

yetval commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Rebased onto current origin/main (1a3ce7c2a8d); single commit, new head 9cc80a04452. No functional change to the fix, and no extra files added to the PR.

The real-behavior proof in the body now drives the actual production createFeishuReplyDispatcher through a full streamed final turn with streamingSearchFallback off vs on, replacing only the network socket (the Lark SDK HTTP transport and the streaming card's SSRF-guarded fetch) with an in-memory capturer. Captured before/after:

  • off (current main): only the interactive streaming card -> no search-indexable send
  • on (this PR): same card plus an im.message.reply with msg_type: "post" whose content carries the full final reply text -> search-indexable

Full captured output is in the PR body Evidence field. The only remaining gap is a live Feishu tenant conversation-search hit, which needs tenant credentials I do not have.

@clawsweeper

clawsweeper Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@yetval
yetval force-pushed the fix/feishu-streaming-search-fallback branch from 855c22b to 9cc80a0 Compare June 5, 2026 08:07
@clawsweeper

clawsweeper Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@yetval

yetval commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Requesting a maintainer proof override (proof: override) for this PR.

Current ClawSweeper verdict on head 9cc80a04452: patch quality 🦞 diamond lobster, security cleared, overall capped at 🦐 gold shrimp solely by the proof gate, and ClawSweeper itself notes "there is no narrow automated code repair indicated by this review." The only remaining blocker is author-side unprovable.

What is proven (PR body Evidence, captured through the real production createFeishuReplyDispatcher, replacing only the network socket):

  • off (current main): the streamed final turn emits only the interactive streaming card -> nothing search-indexable
  • on (this PR): same card plus an im.message.reply with msg_type: "post" whose content carries the full final reply text -> search-indexable per Feishu's documented text/post indexing

What cannot be shown from the contributor side: a redacted live Feishu/Lark tenant conversation-search hit, which requires Feishu app credentials and a configured tenant I do not have. I will not submit fabricated tenant screenshots/logs.

This is a safe override candidate: the setting is default-off (no change for existing deployments on upgrade), it reuses the existing sendMessageFeishu post sender (no new delivery path or dependency when disabled), and it is aligned across schema, manifest, and docs.

Per ClawSweeper's maintainer options, requesting one of:

  1. proof: override accepting the payload-level + production-dispatcher proof, together with product acceptance of the documented tradeoff (when enabled, one extra visible final post after the streaming card closes is by design and is what makes the content searchable); or
  2. a maintainer (or anyone with a Feishu test tenant) enabling streamingSearchFallback, sending a streamed reply, and recording a redacted conversation-search hit.

Happy to adjust the fallback's delivery shape if maintainers prefer a different approach.

@yetval

yetval commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Verification update

The Real behavior proof in the description is backed by a runnable harness that drives the production createFeishuReplyDispatcher through a full streamed final turn and records every outbound Feishu request. Only the sockets are faked: fetchWithSsrFGuard (CardKit + token) and the Lark im.message transport are swapped for in-memory capturers returning canned success bodies. reply-dispatcher.ts gating, the FeishuStreamingSession (streaming-card.ts), and send.ts (real msg_type: "post" construction) all run unmodified.

Re-ran at this PR head:

node scripts/run-vitest.mjs extensions/feishu/src/repro-74808-proof.test.ts
 Test Files  1 passed (1)
      Tests  1 passed (1)

Captured outbound sequence (real call order):

The harness asserts these (BEFORE sends == ["interactive"], AFTER sends == ["interactive","post"], with the post payload JSON.parse-equal to the final reply text), so a behavior regression fails the run. The setting stays default-off, so existing Feishu deployments are unaffected.

Not covered: the core typing-dispatcher wrapper and the live Feishu socket are simulated. Whether Feishu's index ultimately surfaces the post is governed by Feishu's documented msg_type indexing rules; a maintainer with a Feishu test tenant can confirm the end-to-end search hit.

@clawsweeper re-run

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 12, 2026
@yetval

yetval commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Closing this for now.

The change itself is sound and proven at the code/network layer: the searchable post fallback fires only when streamingSearchFallback: true, defaults off, and fails safe (the streaming card closes independently; a fallback send error is caught and logged, never crashes or drops the reply). That is covered by the unit regression test plus the network-capture proof in the description.

What is blocking it from landing is not code, it is verification and product sign-off that need a live tenant and an owner decision:

  • A redacted live Feishu conversation-search hit for the exact fallback post. This needs a real Feishu app + chat and a client-side search, since the Open Platform has no API that mirrors the in-client "search conversation content" index. Not available right now.
  • Owner acceptance of the tradeoffs: the visible duplicate message and the +1 im.message send per final turn (quota). That is a maintainer product call.

Rather than leave it open indefinitely waiting on both, closing. Happy to reopen if someone can supply a Feishu test tenant for the live search-hit screenshot and a maintainer signs off on the duplicate-message/quota tradeoff. The branch and proof harness are kept locally.

@yetval yetval closed this Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: feishu Channel integration: feishu docs Improvements or additions to documentation merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Feishu streaming card messages not searchable — interactive card content not indexed by Feishu search

2 participants