diff --git a/frontend-web/src/components/workspace/user-identity-badge.tsx b/frontend-web/src/components/workspace/user-identity-badge.tsx
new file mode 100644
index 00000000..5929040e
--- /dev/null
+++ b/frontend-web/src/components/workspace/user-identity-badge.tsx
@@ -0,0 +1,54 @@
+"use client";
+
+import { User } from "lucide-react";
+import { useMemo } from "react";
+
+import { getStoredAuth } from "@/core/auth";
+import { useMyPosition } from "@/core/positions";
+import { cn } from "@/lib/utils";
+import { readUserInfo } from "@/strategy-components/lib/light-app";
+
+/**
+ * 名称 + 岗位 用户标识。全量模式由 strategy-components/Header.tsx 顶栏右侧展示;
+ * 紧凑模式(不带全局顶栏)无处承载,故抽成共享组件,复用同一套数据来源
+ * (`readUserInfo().userName` 优先、回退 auth 邮箱前缀;岗位取 `useMyPosition`),
+ * 供页面级顶栏(如 ChatPage)右侧复用,保证两套布局一致。
+ *
+ * 配色按当前内容区前景色(foreground / muted-foreground),适配聊天页浅底顶栏,
+ * 而非 Header 的白字贴 banner 方案。
+ */
+export function UserIdentityBadge({ className }: { className?: string }) {
+ const auth = getStoredAuth();
+ const { data: myPosition } = useMyPosition();
+ const positionName = myPosition?.name?.trim() || "";
+
+ // 与 Header.tsx 一致:外部登录写入的真实用户名优先,缺省回退邮箱前缀。
+ const displayName = useMemo(() => {
+ const info = readUserInfo();
+ const name = typeof info.userName === "string" ? info.userName.trim() : "";
+ if (name) return name;
+ const email = auth?.email?.trim();
+ return email ? email.split("@")[0] : "用户";
+ }, [auth?.email]);
+
+ return (
+
+
+
+
+
+
+ {displayName}
+
+ {positionName && (
+
+ {positionName}
+
+ )}
+
+
+ );
+}
diff --git a/frontend-web/src/pages/ChatPage.tsx b/frontend-web/src/pages/ChatPage.tsx
index 81f21b66..b1c24df3 100644
--- a/frontend-web/src/pages/ChatPage.tsx
+++ b/frontend-web/src/pages/ChatPage.tsx
@@ -27,6 +27,7 @@ import { QuestionNavigator } from "@/components/workspace/question-navigator";
import { ThreadTitle } from "@/components/workspace/thread-title";
import { TodoList } from "@/components/workspace/todo-list";
import { TokenUsageIndicator } from "@/components/workspace/token-usage-indicator";
+import { UserIdentityBadge } from "@/components/workspace/user-identity-badge";
import { Welcome } from "@/components/workspace/welcome";
import { CompactWelcome } from "@/components/workspace/compact-welcome";
import { readSidebarEnabled } from "@/core/page-layout/sidebar-enabled";
@@ -481,6 +482,17 @@ export default function ChatPage() {
+ {/* 不带全局顶栏(紧凑模式)时,名称+岗位回落到聊天页顶栏右侧,
+ 与全量模式 Header 右上角保持一致。全量模式已有顶栏则不重复展示。 */}
+ {!compactChrome && (
+ <>
+
+
+ >
+ )}
diff --git a/offline-backend-20260512/backend/CLAUDE.md b/offline-backend-20260512/backend/CLAUDE.md
index d75ca744..712c7339 100644
--- a/offline-backend-20260512/backend/CLAUDE.md
+++ b/offline-backend-20260512/backend/CLAUDE.md
@@ -368,7 +368,7 @@ shown to users ARE the **recommended questions** (`recommended_questions` table)
types into the existing "我的" tables, idempotently:
- agents → `agent_favorites` rows with `origin='position'`
- **skills → `skill_favorites` rows with `origin='position'`** (table
- `SkillFavoriteRow`, migration `20260616_02`, auto-created by `create_all`)
+ `SkillFavoriteRow`, migration `20260616_04`, auto-created by `create_all`)
- scheduled tasks → `scheduled_task_subscriptions` rows with `origin='position'`
Skills behave **exactly like agents**: a position only *adds* its tagged skills
diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260611_01_roundtable_draft_task_id.py b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260611_02_roundtable_draft_task_id.py
similarity index 77%
rename from offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260611_01_roundtable_draft_task_id.py
rename to offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260611_02_roundtable_draft_task_id.py
index 076a329b..c80317d5 100644
--- a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260611_01_roundtable_draft_task_id.py
+++ b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260611_02_roundtable_draft_task_id.py
@@ -7,8 +7,14 @@ draft is keyed/shared by ``task_id`` and is no longer partitioned by ``user_id``
``create_all`` adds the column for brand-new DBs; this revision patches DBs that
already have the table.
-Revision ID: 20260611_01
-Revises: 20260609_02
+Note: this migration originally shared the revision id ``20260611_01`` with
+``20260611_01_agents_skills_square_id`` (both branched off ``20260609_02``),
+which corrupted the alembic DAG ("present more than once" + phantom heads). It
+was renumbered to ``20260611_02`` and re-chained after that revision so the
+history is linear and single-headed.
+
+Revision ID: 20260611_02
+Revises: 20260611_01
Create Date: 2026-06-11
"""
@@ -19,8 +25,8 @@ from alembic import op
from sqlalchemy import inspect
-revision = "20260611_01"
-down_revision = "20260609_02"
+revision = "20260611_02"
+down_revision = "20260611_01"
branch_labels = None
depends_on = None
diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260612_01_roundtable_jobs_orchestration_plan.py b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260612_01_roundtable_jobs_orchestration_plan.py
index f7a2cf90..a9b700fd 100644
--- a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260612_01_roundtable_jobs_orchestration_plan.py
+++ b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260612_01_roundtable_jobs_orchestration_plan.py
@@ -6,7 +6,7 @@
LONGTEXT(计划 JSON 可超 64 KB)。
Revision ID: 20260612_01
-Revises: 20260611_01
+Revises: 20260611_02
Create Date: 2026-06-12
"""
@@ -19,7 +19,7 @@ from sqlalchemy.dialects.mysql import LONGTEXT
revision = "20260612_01"
-down_revision = "20260611_01"
+down_revision = "20260611_02"
branch_labels = None
depends_on = None
diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_03_skill_always_on.py b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_03_skill_always_on.py
index 68d458bd..57c0b0df 100644
--- a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_03_skill_always_on.py
+++ b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_03_skill_always_on.py
@@ -1,7 +1,7 @@
"""Add always_on (常驻/免压缩) column to skills table.
Revision ID: 20260616_03
-Revises: 20260616_02
+Revises: 20260616_04
Create Date: 2026-06-16
"""
@@ -13,7 +13,7 @@ from sqlalchemy import inspect
revision = "20260616_03"
-down_revision = "20260616_02"
+down_revision = "20260616_04"
branch_labels = None
depends_on = None
diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_02_skill_favorites.py b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_04_skill_favorites.py
similarity index 81%
rename from offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_02_skill_favorites.py
rename to offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_04_skill_favorites.py
index 0a223a3b..e531a31e 100644
--- a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_02_skill_favorites.py
+++ b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260616_04_skill_favorites.py
@@ -10,8 +10,14 @@ startup (new tables are always created, even on existing DBs); this migration
keeps the alembic history consistent per the repo convention (see
backend/CLAUDE.md → Schema Migrations).
-Revision ID: 20260616_02
-Revises: 20260616_01
+Note: this migration originally shared the revision id ``20260616_02`` with
+``20260616_02_knowledge_folders_templates`` (both branched off ``20260616_01``),
+which corrupted the alembic DAG ("present more than once" + phantom heads). It
+was renumbered to ``20260616_04`` and re-chained after that revision so the
+history is linear and single-headed.
+
+Revision ID: 20260616_04
+Revises: 20260616_02
Create Date: 2026-06-16
"""
@@ -22,8 +28,8 @@ from alembic import op
from sqlalchemy import inspect
-revision = "20260616_02"
-down_revision = "20260616_01"
+revision = "20260616_04"
+down_revision = "20260616_02"
branch_labels = None
depends_on = None
diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260617_01_merge_chain_seat_and_skill_always_on_heads.py b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260617_01_merge_chain_seat_and_skill_always_on_heads.py
new file mode 100644
index 00000000..5eb84731
--- /dev/null
+++ b/offline-backend-20260512/backend/packages/harness/deerflow/persistence/migrations/versions/20260617_01_merge_chain_seat_and_skill_always_on_heads.py
@@ -0,0 +1,30 @@
+"""Merge the chain-seat-mode and skill-always-on migration heads.
+
+Two lineages both descend from ``20260612_01`` (roundtable_jobs orchestration
+plan): ``20260615_01`` (chain seat mode) branched directly off it, while the
+``20260616_*`` line (positions → knowledge folders/templates → skill_favorites →
+skill always_on) is the other branch. That left the graph with two heads
+(``20260615_01`` and ``20260616_03``) so ``alembic upgrade head`` failed with
+"Multiple head revisions are present". This no-op merge revision joins both
+lineages so ``upgrade head`` resolves to a single head again.
+
+Revision ID: 20260617_01
+Revises: 20260615_01, 20260616_03
+Create Date: 2026-06-17
+"""
+
+from __future__ import annotations
+
+
+revision = "20260617_01"
+down_revision = ("20260615_01", "20260616_03")
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ pass
+
+
+def downgrade() -> None:
+ pass