From 7962a2528a47cc685abb121e7f5de839b14dc1a4 Mon Sep 17 00:00:00 2001 From: J Date: Tue, 23 Jun 2026 17:16:52 +0800 Subject: [PATCH] docs(channel): document non-rolling cutover constraint for the lark->channel migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elon deploy review: keeping the lark_* tables (deferred drop) stops old v0.3.27 code from crashing, but is not full expand/contract. Migration 124 is a one-time backfill; afterwards new code runs on channel_* (lease + dedup on channel_*) while pre-cutover code runs on lark_* (lease + dedup on lark_*). If both run concurrently during a rolling deploy, each side claims the same Feishu bot's WS lease on its own table and double-processes inbound events. This release therefore requires a NON-ROLLING cutover (stop the old hub before applying migration 124 + starting new code; rollback is not lossless once new code writes channel_*). Documented where deployers/reviewers see it: migration 124 header gains a ROLLOUT note; the channel_store.go header is corrected (lark_* tables are retained one release for rollback safety, not "gone"; the store still never touches them). Comment-only — no schema/codegen/behavior change. MUL-3515 Co-authored-by: multica-agent --- server/internal/integrations/lark/channel_store.go | 8 +++++--- server/migrations/124_channel_generalization.up.sql | 12 ++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/server/internal/integrations/lark/channel_store.go b/server/internal/integrations/lark/channel_store.go index 08c45072af..e030179a3b 100644 --- a/server/internal/integrations/lark/channel_store.go +++ b/server/internal/integrations/lark/channel_store.go @@ -7,9 +7,11 @@ package lark // by a channel_* query and translating at the JSONB-config boundary (store.go). // // The methods take and return the package's flat domain types (Installation, -// UserBinding, ChatSessionBinding, InboundMessageDedup, BindingToken, -// OutboundCardMessage) and the *Params types in params.go. Only channel_* rows -// are ever read or written; the retired lark_* tables and queries are gone. +// UserBinding, ChatSessionBinding, InboundMessageDedup, BindingTokenRow, +// OutboundCardMessage) and the *Params types in params.go. This store reads +// and writes only channel_*, never lark_*; queries/lark.sql is deleted. The +// physical lark_* tables are retained one release for rollout/rollback safety +// (see migration 124's ROLLOUT note) and dropped by a later cleanup migration. import ( "context" diff --git a/server/migrations/124_channel_generalization.up.sql b/server/migrations/124_channel_generalization.up.sql index 54b3fdc812..3d6f655748 100644 --- a/server/migrations/124_channel_generalization.up.sql +++ b/server/migrations/124_channel_generalization.up.sql @@ -20,6 +20,18 @@ -- ship green on its own. This migration only ADDS channel_* and -- copies the data forward. -- +-- * ROLLOUT — NON-ROLLING CUTOVER REQUIRED. This backfill is a one-time +-- copy. After it runs, new code reads/writes channel_* while any +-- pre-cutover (v0.3.x) code still reads/writes lark_*: the two table +-- sets never cross-deduplicate, and each side would claim the same +-- Feishu bot's WS lease on its own table and open a duplicate +-- connection, double-processing inbound events (duplicate messages / +-- /issue / runs). So old and new backend hub processes MUST NOT run +-- concurrently against this schema — stop the old hub before applying +-- this migration and starting the new code (recreate, not rolling). +-- Rollback to a pre-cutover build is not lossless once the new code has +-- written Feishu state into channel_*. +-- -- app_secret_encrypted is BYTEA; it is carried into the JSONB config as a -- base64 string. PostgreSQL's encode(...,'base64') MIME-wraps the output -- with a newline every 76 chars, and a secretbox-sealed app secret (~72