Skip to content

feat(lark): show last text/card send observation to workspace admins - #9820

Open
jiahao6635 wants to merge 4 commits into
multica-ai:mainfrom
jiahao6635:feat/lark-send-observation
Open

jiahao6635 wants to merge 4 commits into
multica-ai:mainfrom
jiahao6635:feat/lark-send-observation

Conversation

@jiahao6635

Copy link
Copy Markdown
Contributor

What does this PR do?

When an ordinary Feishu/Lark chat reply fails, the current Patcher only logs the error. Message-reception verification from #9709 cannot explain whether a subsequent reply request was confirmed, refused, or left uncertain.

Expose the last text/card send observation to human workspace owners/admins in Settings → Channels → Feishu. This is one historical API-call observation, not end-to-end delivery, reading, attachment delivery, or current connection health. No saved observation means no recorded evidence, not that the bot has never sent a reply.

The narrow boundary is intentional: observe actual ChatDone text/Markdown-card calls, including each existing fallback call. Empty/skipped replies, failed-task notices, binding messages, typing cleanup and attachment completion do not manufacture or replace evidence.

Related Issue

Follow-up to #9709. Existing related issue/PR searches found no equivalent send-observation UI. No new issue or duplicate PR was created for this change. #9813 and #9804 are unchanged.

Type of Change

  • New feature
  • Documentation update
  • Tests

Changes Made

  • Capture completion time and the installation snapshot before persisting. Store only UTC time, a result enum and a safe classification. Never persist message text, recipient IDs, message IDs, raw responses, tokens, or Error() strings.
  • Require both nil error and a nonempty message ID for API confirmation. Whitelist documented refusals for missing group membership, disabled bot capability, app availability, required reply permission and group send restrictions. Code 0/missing ID, 230049, 5xx, timeouts and unclassified errors remain uncertain. Unknown codes do not recommend adding permissions.
  • Preserve original send/fallback return values and behavior. Capture results during calls, then attempt persistence after the reply/fallback/attachment handoff returns. Each write has an independent 250 ms budget; failure only emits a generic warning and never retries the reply.
  • Atomically merge one last_send_observation config field with installation/workspace/channel/status/app/generation fences and completion-order comparison. Preserve concurrent receipt/identity fields and updated_at. Rebind replaces config and clears the observation; stale generations cannot repopulate it.
  • Exclude observation metadata from connection fingerprints while retaining credential/generation sensitivity.
  • Add a separate owner/admin read endpoint with workspace-scoped lookup and a human-actor gate. The member-visible installation response is unchanged.
  • Add a read-on-expand UI, schema validation, safe malformed/unknown handling, all six UI translations, and English/Simplified Chinese docs. Separate query-cache entries by installation revision so a rebind does not show the previous binding's cached evidence while fetching. Preserve subsecond installed_at precision with RFC3339Nano so same-second rebinds have distinct cache revisions without exposing the private binding generation.

Official error references: send, reply.

How to Test

Verified locally on Linux/amd64, Go 1.26.9, using this checkout's managed, disposable migrated PostgreSQL database and the repository Agent CLI guard.

  • make sqlc completed and generated only the new query wrapper.
  • Full go test -race -count=1 ./internal/integrations/lark passed. The affected observation tests were rerun after the final context-key rename.
  • The focused handler race suite passed for TestLarkSendObservationAccessAndWire, TestLarkInstallationSameSecondRebindRevision and TestLarkInstallationReceiptWireShape, including owner/admin access, ordinary-member rejection, cross-workspace rejection, machine-credential rejection, list non-disclosure, absent evidence and same-second timestamp serialization.
  • go vet ./internal/integrations/lark ./internal/handler ./cmd/server passed.
  • Core: 17 tests passed via pnpm --filter @multica/core exec vitest run api/lark-send-observation.test.ts api/lark-verification.test.ts lark/queries.test.ts.
  • Views: 300 tests passed via pnpm --filter @multica/views exec vitest run settings/components/lark-tab.test.tsx settings/components/lark-send-observation.test.tsx locales/parity.test.ts.
  • Core and Views typechecks, ESLint on modified implementation/test files, and base-to-head git diff --check passed.

The database regression covers concurrent inbound-receipt/identity/send-observation writes, nanosecond ordering, wrong workspace/app/generation/channel, revoked installations and rebind clearing. Wiring tests cover actual calls, fallback order, skip paths, independent persistence context, unchanged errors and storage failures. UI tests cover deferred reads, errors versus absent evidence, access affordances and same-second rebind cache isolation. The new serializer regression was run before the precision fix and failed with same-second rebinds share the send-observation cache revision on the previous branch head (5ab4eea4a3ce2c6433c60e3963f22579a24ed0a9). After changing only the existing installed_at timestamp format to RFC3339Nano, the two bindings retain their distinct microsecond timestamps. Existing response fields and types remain unchanged.

Reverse verification used temporary Go overlays, leaving the candidate tree unchanged:

  1. Disable the SQL generation predicate: the generation subtest fails with out-of-scope observation accepted, and the rebind assertion fails with old send wrote into a new binding.
  2. Remove the fingerprint exclusion: TestSendObservationFingerprint fails with observation restarted connection.

These are expected mutation failures, not failures of the candidate.

Risks and Verification Limits

  • Recording is best effort. A crash before persistence or a database timeout can leave older/no evidence; the timestamp remains historical, and the UI must not be interpreted as a live health signal.
  • Completion ordering uses the server's captured UTC timestamp. This is not a full delivery ledger or an audit history.
  • Up to two bounded diagnostic writes can add up to 500 ms after a reply/fallback path, before its event callback finishes; they do not consume the original send/fallback budget.
  • The UI refreshes saved evidence when expanded/reopened or through normal Query refresh behavior; there is no live health polling or external probe.
  • No new tables, migrations, permissions, default test messages, uploads, paid agent runs, deployment or automatic retries were added.
  • No live Feishu tenant, real model/agent execution, browser screenshots, full repository suite, full E2E or remote CI was verified. Redis-specific behavior is outside this validation.

Checklist

  • Included the project context and thinking path
  • Ran relevant local tests and reported the results
  • Added regression coverage
  • Included before/after browser screenshots
  • Updated relevant documentation
  • Checked Chinese product copy against repository conventions
  • Documented risks and verification limits
  • Address reviewer comments before requesting merge

AI Disclosure

AI tool used: OpenAI Codex

Prompt / approach: Implement the authorized narrow follow-up to Feishu message-reception verification: expose only the latest actual ordinary text/card reply API-call observation, with safe uncertainty semantics and owner/admin access. Inspected current main and existing contributions; preserved send/retry behavior, used atomic generation-fenced config writes, added database/handler/component regressions, ran the checks above and two reverse-verification mutations. Implementation and self-review were automated; no independent human review is claimed.

Publication Status

The feature branch is prepared for manual Draft PR publication. PR creation/edit/comment operations were previously denied with HTTP 403 in this session history; they were not retried or bypassed.

@vercel

vercel Bot commented Nov 2, 2026

Copy link
Copy Markdown

@jiahao6635 is attempting to deploy a commit to the IndexLabs Team on Vercel.

A member of the Team first needs to authorize it.

jiahao6635 and others added 2 commits November 6, 2026 08:50
Keep the Lark send observation and workspace pinning schemas. Add the observation copy for the Spanish locale introduced upstream.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant