Commit Graph
8706 Commits
Author SHA1 Message Date
Kinyoo 347ca4effc fix(client): drop redundant mobile negative-margin/padding on input toolbar
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 790a14da64)
2026-07-14 17:07:15 +08:00
KinyooandClaude Opus 4.8 9a9e9331e7 feat(client): dual-axis Button design-system component + btn-* tokens
New color×variant×size Button API (solid/outlined/filled/text/link) with legacy shadcn variants auto-mapped; btn-* semantic tokens + touch hit-area in style.css/tailwind; app-wide hoverOnlyWhenSupported; gallery ButtonSection; migrate KnowledgeSpaceSidebar create button to the new API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:58:32 +08:00
KinyooandClaude Opus 4.8 324f299ffd feat(client): add semantic typography scale + gallery typography section
Two-layer type tokens (primitive --font-size-N + semantic --text-*) in style.css with a mobile remap, wired to Tailwind fontSize; system font stack; new gallery TypographySection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 15:05:28 +08:00
LineWalkerandClaude Opus 4.8 715ebaf991 fix(channel): sync information articles under per-tenant context
sync_information_article iterated channel_info_source (a tenant-aware table)
with no tenant context set, so on a multi-tenant deploy the first SELECT raised
NoTenantContextError and the daily article sync never ran — subscribed sources'
content never updated.

Mirror reconcile_all_tenants: enumerate active tenants (root + active children,
or the default tenant when multi-tenancy is off) and run the sync under each
tenant's context, isolating per-tenant failures. Add a sync counterpart
TenantDao.get_children_ids_active for the sync worker path, and fix a latent
missing `import asyncio` in the knowledge-space dispatch hook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 21:41:36 +08:00
LineWalkerandClaude Opus 4.8 c42a3edc08 fix(workbench): drop unused char-whitelist pattern on app-center text
Follow-up to 1208fa158: instead of only relaxing the pattern to allow the
empty string, remove it entirely to align with feat/2.6.0 (72fd1e8f0
"fix: unused pattern"). The whitelist could not stop XSS (it allowed <>/"'&)
yet rejected the empty default plus emoji / non-CJK text; real escaping is
done by the frontend (React text nodes, no dangerouslySetInnerHTML). Keeping
all three branches identical avoids a future merge conflict on these lines.

Update regression tests accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 18:31:51 +08:00
LineWalkerandClaude Opus 4.8 1208fa1580 fix(workbench): accept empty application-center text in WorkstationConfig
applicationCenterWelcomeMessage / applicationCenterDescription were declared
with default="" but a pattern requiring >=1 char (^[...]+$). Any tenant whose
stored workstation config left these fields empty or unset (the default) made
WorkstationConfig(**raw) raise a pydantic ValidationError, so GET
/api/v1/workstation/config returned 500 and the client rendered its full-screen
"system maintenance" overlay — /workspace/c/new appeared broken.

Relax both patterns from + to * so the empty string is accepted while keeping
the character whitelist for non-empty input. Add regression tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 18:02:36 +08:00
dolphin 32ee955eac fix(feedback): keep task-mode like highlight across conversation switch
The task result panel reads its liked verdict from the linsight store, which is
seeded once on hydration. An optimistic like updated only the button's local
state + backend, not the store — so switching away and back re-mounted the panel
with the stale store value and the highlight vanished (a full page reload fixed
it, since that re-hydrates the store from the server).

Sync the verdict back to the store on click via a new onLikedChange callback
(TaskTurnPanel + ExecutionFlow pass updateLinsight), so the store stays current
and the highlight survives switch-away/switch-back.
2026-07-11 11:13:02 +08:00
dolphin ae636b7a36 fix(feedback): task-mode like targets the real answer id, not the placeholder
In task mode the result panel's like/dislike showed as soon as the run hit
'completed', but the task turn still carried its streaming placeholder id
(userMessageId + '_') — the real persisted category="task" ChatMessage id only
arrived on a page reload. A like clicked the moment the panel appeared wrote to
a non-existent row and silently vanished (occasional, timing-dependent).

Source the feedback id from the linsight store instead of the conversation
message, and populate the store's real message_id at completion by reusing the
existing session-version-list enrichment (no new endpoint/field):
- Websocket final_result: fetch the version list, copy this version's real
  message_id + liked into the store
- TaskTurnPanel: ResultPanel reads linsight.message_id (history hydration
  already seeds it via the same endpoint); add allowFeedback prop for the
  share-view opt-out
- AiMessageBubble: pass allowFeedback instead of encoding it via messageId

The button now appears only once the real id is in the store, so show-time and
id-availability are aligned and the placeholder can never reach /liked.
2026-07-11 10:44:58 +08:00
LineWalkerandClaude Opus 4.8 ed0d4a0fca fix(llm): preserve workbench models when a partial POST omits them
update_workbench_llm persisted the incoming WorkbenchModelConfig wholesale, so a
body without `models` (Pydantic defaults it to None) nulled the entire configured
dialogue-model list — the way a stale admin page wiped the Root config in prod.
Treat a missing/None `models` as "no change" and keep the stored list; an explicit
`models: []` still clears. asr/tts/chat_title keep their None-clears semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:48:37 +08:00
LineWalkerandClaude Opus 4.8 13f1a28c27 fix(model): guard empty-id workbench models from crashing the picker
A blank dialogue-model row ({id:''}) saved from the workbench model config
flows into the workspace model pickers as <SelectItem value="">, which Radix
forbids — it throws and crashes the whole /workspace/c/new page.

- client: drop empty/invalid-id options in AiModelSelect and the Linsight
  ModelSelector so a stale/blank model never renders an empty-string
  SelectItem value (defense that doesn't rely on backend sanitizing).
- platform: reject saving a blank model row in WorkbenchModel — validation
  only checked models.length, letting {id:''} through and overwriting the
  configured dialogue models with an empty row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:26:49 +08:00
dolphin 3cbd4461d4 fix(channel): carry the real answer message_id on the stream end event
Channel article chat yielded the 'end' event BEFORE persisting the answer
ChatMessage, so the client never got the real id — the streamed answer kept its
temporary placeholder id and a like clicked before switching away wrote to a
non-existent row and vanished (same class of bug as the knowledge-space fix).

Persist the answer first, then emit the end event with its message_id so the
client can swap the placeholder out immediately (frontend useChannelChat already
consumes it).
2026-07-10 19:07:03 +08:00
dolphin 8964cbd134 fix(llm): TTS synthesis failure returns a business error, not HTTP 500
A TTS provider failure (e.g. empty audio) raised a bare exception that
propagated as HTTP 500, which the client's global interceptor treats as a
service outage and redirects to the maintenance overlay — a poor experience
for what is just 'this one utterance failed to synthesize'.

- backend: wrap the synthesis call, raise a dedicated TtsSynthesisFailedError
  (code 10026) instead of letting it bubble up as 500
- frontend: textToSpeech opts into the interceptor's translate-and-toast path
  (skip403Redirect) instead of the 500 escape hatch; TextToSpeechButton no
  longer masks the real error or double-toasts once the interceptor already
  showed the localized message
- add api_errors.10026 to zh-Hans/en/ja
2026-07-10 18:42:30 +08:00
dolphin e3d2ed803d fix(feedback): swap streamed-answer placeholder id for the real one on stream end
Knowledge-space chat (single-file / folder) rendered the streaming answer under
a temporary client-side placeholder id (userMessageId + '_') and never swapped
it for the real persisted ChatMessage id, so a like clicked before the first
page reload wrote to a row that never existed — it silently vanished. Reload
loaded the real id from history and worked fine, masking the bug as 'only
fails right after sending, fixed by refresh'.

- backend: the 'end' stream event now carries the persisted answer message_id
- frontend: useStreamChatSSE forwards it through onFinal; useFolderChat /
  useFileChat / useChannelChat swap their placeholder messageId for it so
  like/dislike (and any other per-message action) targets the right row
  immediately, not just after a reload
2026-07-10 18:42:30 +08:00
KinyooandClaude Opus 4.8 71d7a3cbe2 style(client): tighten top padding to pt-4 across chat nav + knowledge headers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:11:25 +08:00
KinyooandClaude Opus 4.8 67c92b1b5a refactor(client): unified CommentDialog for feedback + menu-apply reason (UI unification infra)
Add a shared CommentDialog (optional-comment / reason dialog) + gallery FeedbackSection; migrate the message 点赞/点踩 feedback (dropping the bespoke MessageFeedbackForm) and the menu-unavailable apply-reason dialog onto it; feedback comment is now optional (com_feedback_placeholder, en/zh/ja).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:11:25 +08:00
dolphin ec99d17d43 feat(feedback): unify task-mode 点赞/点踩 on the task-result ChatMessage
The linsight task result is already persisted as a category="task" ChatMessage
in the unified daily conversation, so rate it through the shared chatmessage
feedback (/liked + /chat/comment) instead of a linsight_session_version-specific
column/endpoint. All four AI Q&A surfaces now share one storage + rollup path.

Backend:
- chat_helpers: agent history formatter returns liked + remark (fixes daily +
  in-conversation task-turn highlight on reload)
- workstation_schema: WorkstationMessage carries liked + remark (channel surface)
- linsight utils: get_task_feedback_by_version maps session_version -> its task
  ChatMessage {message_id, liked}
- linsight endpoint: session-version-list enriches each version with message_id +
  liked for the standalone linsight page

Frontend:
- ResultPanel: rate by messageId via likeChatApi / disLikeCommentApi
- TaskTurnPanel forwards messageId + liked; AiMessageBubble passes the task row's
  message.messageId (hidden on the read-only share view); ExecutionFlow reads them
  from the enriched session-version store field
- drop the now-unused likeLinsightVersion / commentLinsightVersion
2026-07-10 01:31:08 +08:00
LineWalkerandClaude Opus 4.8 18adc59068 docs(feedback): remove message 点赞/点踩 feedback PRD
The PRD doc is no longer needed; the 点赞/点踩 feature itself (98b48c93a) is
unaffected — only its now-redundant design doc is removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:35:26 +08:00
GuoQing Zhang 871e830ca5 Merge branch 'feat/2.6.0-beta4' of github.com:dataelement/bisheng into feat/2.6.0-beta4 2026-07-09 20:57:36 +08:00
GuoQing Zhang 5c2802e9a4 fix: tool sse event twice 2026-07-09 20:57:27 +08:00
Sarah b35f390dd2 fix(llm): sanitize stale workbench model refs 2026-07-09 18:08:39 +08:00
KinyooandClaude Opus 4.8 05260ec837 style(knowledge): edit-tags modal spacing, focus ring, neutral placeholder colors
Tighten padding (px-6 -> px-5), add a focus ring (border + 2px shadow) on the tag input, disable autocomplete, and normalize placeholder / no-tags text to #999.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 17:47:26 +08:00
KinyooandClaude Opus 4.8 9e3f7518ae style(knowledge): edit-tags modal goes full-screen on mobile via max-md breakpoints
Swap the touch-mobile: variant for max-md: so the edit-tags dialog uses the standard breakpoint-based mobile full-screen sheet (rounded corners only from md up).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:30:38 +08:00
KinyooandClaude Opus 4.8 1166f52aa1 refactor(client): migrate SharedLinks + guest-convo delete to the unified ConfirmDialog (UI unification infra)
Replace OGDialog/OGDialogTemplate delete confirmations in SharedLinks and the standalone guest-convo item with useConfirm; touch up the ConfirmDialog + Modal gallery sections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:30:38 +08:00
dolphin 0836db4b6f fix(knowledge): sidebar tree — select never reloads, expand only via chevron
- Root-list loading no longer depends on currentFolderId, so selecting a
  folder (click or route change) never rebuilds this or any other space's
  tree; switching the active space leaves background trees untouched.
- Clicking a folder row (or a space row) only selects/navigates; expanding
  and collapsing is exclusively the chevron's job.
- Deep links (direct URL into a nested folder) still auto-expand the
  ancestor chain, fetching only levels not already cached, gated on the
  root list being genuinely loaded (fixes the reload race that left the
  tree half-expanded).
2026-07-09 11:14:09 +08:00
LineWalkerandClaude Opus 4.8 98b48c93a7 feat(client): add 点赞/点踩 feedback to the four AI Q&A surfaces
Share a MessageFeedbackButtons control (thumbs + dislike-comment modal) across
two insertion points:
- AiMessageBubble action row -> workstation daily, knowledge-space 知源,
  channel subscription (reuse existing /api/v1/liked + /chat/comment,
  message_session rollup already maintained backend-side).
- Linsight ResultPanel -> task mode (inline + full-page /linsight), via new
  likeLinsightVersion / commentLinsightVersion (backend endpoint + liked
  column pending per PRD; optimistic UI for now).

Seed the highlight from chatmessage.liked on history reload (ChatMessage.liked
+ both mappers). Hidden on the read-only share view (allowFeedback=!shareToken).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:59:08 +08:00
LineWalkerandClaude Opus 4.8 532597a226 docs(feedback): add message 点赞/点踩 feedback PRD
Product PRD (pyramid structure) for adding thumbs up/down feedback to the
four AI Q&A surfaces (workstation daily, linsight task mode, knowledge-space
知源, channel subscription). Feedback persists on the answer row and rolls up
into message_session for single-table, per-surface analytics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:59:08 +08:00
KinyooandClaude Opus 4.8 84fc35aa2d refactor(client): collapse input-toolbar labels by container width, not viewport
Add useContainerCompact (ResizeObserver on the flex-1 toolbar column) + TOOLBAR_COMPACT_THRESHOLD; the daily/task input toolbars now collapse button labels to icons based on the actual space available (correct when the sidebar opens) instead of a viewport media query, sized for the widest (English) locale so labels collapse as a group before any single one truncates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 17:21:26 +08:00
dolphin f8a36ac1cc test(client): remove jest.mock-based unit tests pending rework
Delete the 22 client test files using jest.mock() (flagged by a customer
scan). Not wired into CI; suite to be reorganized later. No production code
references them.
2026-07-08 14:20:42 +08:00
KinyooandClaude Opus 4.8 7a1871637b style(platform): widen model description column + shorten placeholder copy
Give the description input more room (ModelManagement grid 1fr -> 1.3fr, WorkbenchModel container 640 -> 720px) and shorten modelDescriptionPlaceholder (en/zh/ja).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 14:06:05 +08:00
LineWalkerandClaude Opus 4.8 5a14fba892 fix(sso): fall back to guest department for SSO users without an HR dept
Interactive SSO login-sync never received a department for OAuth/LDAP
logins: the gateway sends identity only, and department binding is a
WeCom-only batch org-sync that is off by default. First-login users were
therefore left with no department (blank in the member picker), unlike
self-registered users who join 临时访客.

Mirror self-registration by reconciling guest-department membership on
login (invariant: a user is in the guest department iff they have no
other department). Orphan users join BS@guest as primary; the placeholder
is vacated once a real department exists. Guest is a local department
under the root tenant, so the leaf tenant stays ROOT — existing
department-less users keep their current tenant. Runs after the
account-disabled short-circuit so disabled placeholder users are skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 12:43:13 +08:00
KinyooandClaude Opus 4.8 f4c114c8cf style(client): redesign the system-maintenance illustration + friendlier copy
Swap the maintenance illustration from database-with-wrench to magnifier-over-a-bug (6 greens mapped to illus-500/300/100 by lightness, grey-mode aware); soften the overlay copy to a friendlier tone (en/zh/ja); update the illustration table in BRAND-THEME-HANDOFF.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 11:45:59 +08:00
KinyooandClaude Opus 4.8 9f118b5bb9 style(knowledge): stretch empty created/joined sidebar sections + center empty text
When a created/joined section is empty (and not the compact dropdown), stretch it to fill the remaining list height and vertically center the no-data text (both empty → 50/50); no-data color #818181 -> #999999.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:41:08 +08:00
KinyooandClaude Opus 4.8 afaaef06d2 fix(knowledge): loading state + race guard for the space-preview file list
Show a spinner while the first file-list page loads (no empty-state flash), guard against out-of-order responses on space/folder switch with a request-seq ref, and use EmptyStateIllustration / LoadingIcon for the empty and loading states.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:41:08 +08:00
KinyooandClaude Opus 4.8 77ab279e7b fix(client): truncate long select-item content before the check mark; cap picker width 240
Wrap SelectPrimitive.ItemText in a min-w-0 flex-1 div (Radix ItemText drops className) so long model name+description truncates before the pr-8 indicator instead of overflowing; drop both model pickers' max-width 280 -> 240.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:11:24 +08:00
KinyooandClaude Opus 4.8 7344632be5 style(subscription): reduce article-list empty-state padding (py-60 -> py-8)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 18:27:03 +08:00
KinyooandClaude Opus 4.8 3e891667b3 style(model): inline the model description (name · divider · desc) in the pickers
Switch the picker item from a stacked name/description column to a single row: name + a 1px divider + truncated description, so options stay one line tall.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 18:27:03 +08:00
KinyooandClaude Opus 4.8 e78037a262 style(model): use #999999 for the model-description line in the pickers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 18:21:14 +08:00
KinyooandClaude Opus 4.8 58cdbd05b4 fix(client): pin explore & knowledge-square to 100dvh on mobile so inner scrollers work
After html/body scrolling was globally disabled (WebView bottom-strip fix), these mobile pages' h-full collapsed under the h-auto MainLayout shell and nothing scrolled; pin them to 100dvh (<=767px) so their own overflow-y-auto becomes the scroller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 18:00:11 +08:00
KinyooandClaude Opus 4.8 9bd5a4fb78 feat(model): optional per-model description shown in the workspace model picker
Admins can set a one-line description (WSModel.description, max 50) per workbench model; the client model pickers (AiModelSelect / linsight ModelSelector) render it under the name, hidden when empty. Platform ModelManagement/WorkbenchModel gain the input + modelDescription(Placeholder) copy (en/zh/ja).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 18:00:11 +08:00
LineWalkerandClaude Opus 4.8 4caff4f548 fix(permission): forbid modifying your own permission in the member dialog
B(被授予的所有者)在成员管理弹窗把自己从所有者降级为编辑者→降级成功但失去
can_manage(manage_space_relation)→重新加载权限列表被 _has_resource_permission_
management_access 拒→「Permission denied / 权限记录加载失败」。典型自我降级自锁。

禁止任何人在成员弹窗修改/移除自己的权限(管理别人不受影响):
- 前端 PermissionListTab 加 currentUserId prop,自己行锁定(复用 isCreatorEntry
  那套静态展示,隐藏修改/移除);KnowledgeSpaceShareDialog + ChannelPermissionDialog
  从 store.user 传入
- 后端 authorize 加自我修改守卫(通用所有资源类型,防御纵深):拒绝 subject==
  login_user 的 grant/revoke,返回「不能修改自己的权限」

既有两个 self-owner-revoke 测试重构(移除自己现被禁,改测 self 被拦 + 移除别人);
新增前后端自我修改测试。前端 10 单测绿,后端 67 passed。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:50:19 +08:00
KinyooandClaude Opus 4.8 8dcd1bdd19 style(subscription): center the empty-state text in the add-source list
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 16:05:31 +08:00
KinyooandClaude Opus 4.8 dfce51cb1a style(linsight): show Shift+Enter hint in the active custom-answer placeholder
Custom-answer placeholder grows the Shift+Enter newline hint once the row is active (new com_linsight_clarify_custom_active, en/zh/ja); always font-normal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:39:52 +08:00
GuoQing Zhang a37c3135fa Merge branch 'feat/2.6.0-beta4' of github.com:dataelement/bisheng into feat/2.6.0-beta4 2026-07-07 15:33:47 +08:00
GuoQing Zhang 9d69248745 feat: remove knowledge space file_num 2026-07-07 15:33:36 +08:00
KinyooandClaude Opus 4.8 99bf6c312b fix(platform): fall back to the model's own name when displayName is left empty
ModelManagement shows the resolved model name as the display-name placeholder; WorkbenchModel save maps empty displayName to the model's cascader label so the workspace model picker never renders a blank option.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:28:57 +08:00
KinyooandClaude Opus 4.8 1b94ae4248 fix(linsight): clarify custom answer supports multi-line auto-grow textarea
Swap the custom-answer input for an auto-growing textarea: Shift+Enter inserts a newline (plain Enter still confirms+advances, IME-guarded), height re-fits to the current question on page change (the DOM node is reused), and the number pins to the first line / 确定 to the bottom-right as it grows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:28:57 +08:00
KinyooandClaude Fable 5 6a59633208 fix: strip whitespace from LLM server credential/url config on save
Users pasting an api_key with a trailing space into the model provider
config caused every LLM call to fail with APIConnectionError, because
httpx/h11 rejects "Bearer sk-xxx " as an illegal Authorization header.
Sanitize key/secret/url/endpoint fields in LLMService on both create
and update so the stored config is always clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:35:29 +08:00
GuoQing Zhang ede6926391 feat(knowledge): replace folder file_num with has_failed_files; show folder update time
The space children/search endpoints no longer return the per-folder file_num
(an expensive recursive count). Folders now expose a lightweight has_failed_files
boolean (computed from the same status-grouped query, true when a child is
FAILED/VIOLATION) which drives the "retry" affordance precisely.

Client: folder rows drop the "x个项目" count and simply show the folder's most
recent update time; folder retry gating (single + batch) now uses has_failed_files
instead of successFileNum < fileNum. The actual retry stays fully backend-driven.
2026-07-07 11:33:03 +08:00
LineWalkerandClaude Opus 4.8 7364239893 fix(linsight): whole-conversation share returns all task turns to non-owner
session-version-list unconditionally narrowed the version list to
meta_data.versionId after the shared_to_session grant. A whole-conversation
(workbench_chat) share carries no versionId, so the filter collapsed the
list to empty and non-owner viewers saw "任务详情加载失败" while the owner
(user_id match, bypass branch) always worked.

In 2.6 task mode the 2.0 integer-"version" re-run concept is dead (version is
now a datetime sort key, one session_version per turn), so a whole-conversation
share must return every turn's version. Narrow only when the share explicitly
pins a versionId (single-version linsight_session share); also guard
meta_data=None against a 500.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 22:41:09 +08:00
GuoQing Zhang 0b8fd3a536 docs(alembic): tighten migration rule to DDL-only, no data migration
Sharpen the earlier 'schema vs script' guidance into a hard rule: alembic
revisions may contain only DDL; the sole permitted data effect is a
server_default fill on an added column. Any read-then-write on existing rows
(SELECT->UPDATE/INSERT, INSERT...SELECT, dedup/backfill/cleanup/reconcile) is a
separate operational procedure, never in a revision — including cleanup needed
before a constraint (run as an ops prerequisite; the DDL fails loudly if data
wasn't prepared).

Removes the prior 'not part of a schema change' loophole. Notes existing
revisions (f001, f011 dedup, f035, ...) as grandfathered. Motivated by the
100k-user case where inline SELECT-then-UPDATE / per-row Python loops stall the
(now fail-fast) startup migration.

Updates both src/backend/AGENTS.md and the alembic AGENTS.md (Sec 5 + checklist).
2026-07-06 22:09:09 +08:00