Skip to content

sync: taiji 定制版同步最新基线 8d810b99e(LegionCard 样式统一 + 群聊 P0 修复) - #2262

Open
1688mengdie wants to merge 148 commits into
GCWing:mainfrom
1688mengdie:custom/taiji-unofficial
Open

sync: taiji 定制版同步最新基线 8d810b99e(LegionCard 样式统一 + 群聊 P0 修复)#2262
1688mengdie wants to merge 148 commits into
GCWing:mainfrom
1688mengdie:custom/taiji-unofficial

Conversation

@1688mengdie

Copy link
Copy Markdown

同步内容

taiji 定制版(custom/taiji-unofficial)同步最新基线 \8d810b99e\(相对上次合并基线 aa98261 前进,含上游合流 9b05dd0)。

本 PR 新增关键提交

  • \8d810b99e\ feat(UI): unify LegionCard style with CoreAgentCard surface
  • \2ba9a7ecd\ fix(P0): group chat auto-creates Claw session for missing member
  • \5b9999431\ fix(CI): gate local_download_name_key test import to platforms that use it
  • 上游合流 9b05dd0(centralize default feature ownership)+ dmg branding + harmonyos fixes

验证

  • 前端 type-check:web → 0 error
  • 前端 vitest → 3381 tests 全绿
  • cargo check bitfun-core/cli/desktop(--jobs 4)→ 0 error
  • cargo test bitfun-core → 144 passed 0 failed

Single commit containing the complete taiji fork on top of upstream/main:
- all customizations previously squashed in ea11f78 (108 fixes,
  configurable thresholds, token/context fixes, legion/task tooling, etc.)
- tool-cluster documentation fix (compact/role/legion action docs)
- upstream merged: bffe514 .. 5700984

Tree identical to the pre-squash state; commit history flattened to the
delivery form requested by the owner (one commit, parent = upstream/main).
…aller signing pubkey + nightly web bindings)
UX-P0-1 root-cause fix: SessionHistory had no authorization gate - any
session holding the tool could export any other session's full transcript
(including tool_inputs/thinking) by session id alone.

- Add resolve_session_read_authorization (session_control_tool.rs)
  aligned with the R4 shared mutation gate: same-workspace ownership
  check, owner (Commander/RBAC-off) bypass, created_by match, in-tree
  ancestor/descendant authorization (memory tree fast path + persisted
  metadata chain fallback), Warden/daemon caller exemption (R-A.04).
- Wire the gate into SessionHistoryTool::call_impl (fail-closed when the
  caller session or workspace cannot be resolved).
- Narrow the toolset: SessionHistory removed from shared_coding_mode_tools
  / subagent_default_tools; only the Warden template retains it
  (cross-session audit reads) plus the in-tool authorization gate.
- Add attacker-matrix tests: unrelated reject, owner bypass, created_by,
  ancestor->descendant, descendant->ancestor, sibling reject,
  cross-workspace reject, warden daemon bypass, fail-closed no-caller.
UX-P1-1: legion thresholds (legion_max_nodes=20 / legion_max_total_nodes=60 / legion_deploy_frequency_per_hour=10) are top-level ai.legion_* keys, not ai.thresholds.* subdomain. Add config-service contract test asserting top-level set/get round-trips and that ai.thresholds.legion.* is not a valid key (set/get fail). 12-legion doc updated out-of-repo.
前端-P1-1: ThresholdsShape.subagent gains max_dispatch_per_parent_window (20) / dispatch_window_secs (3600) / dispatch_cooldown_secs (300) matching backend SubagentThresholds (types.rs:958-989) consumed by coordinator.rs configured_subagent_dispatch_*. Renders in domainSections, adds en/zh-CN/zh-TW i18n keys, and asserts render+persist in ThresholdsConfig.test.tsx. BasicsConfig legion section comment clarifies ai.legion_* top-level-key semantics (UX-P1-1).
…d re-register RBAC roles on storage-path session restore

P1-S1: Executor/Reviewer templates no longer rely on empty-allowlist
allow-all semantics. Whitelists = subagent_default_tools() plus the
deferred-tool gateway pair, GetTime, and the review-shape tools
(GetFileDiff/submit_code_review/LaunchReviewAgent/LS), merged with the
subagent deny list as a second layer. Newly registered tools are denied
by default on subagent sessions, matching the MiniApp whitelist
philosophy. Regression test asserts unknown tools are rejected and all
nine deny entries still hold.

P1-S2: every storage-path and workspace-path restore variant now calls
restore_session_role_best_effort after restore, so a process restart no
longer silently drops subagent RBAC roles (falling back to the
context-level empty allowlist). Covers restore_session_from_storage_path,
restore_internal_session_from_storage_path, both with_turns storage-path
variants, all session-view storage-path timed/tail variants, the
workspace-path view/tail/internal view variants, and the legacy
restore_session entry. New assertion test verifies main-session commander
re-registration, subagent executor re-registration with landed template,
and the view storage-path variant.
P1-S3: a shame-wall registry whose JSON fails to parse is no longer
silently overwritten by the next atomic save. load_from_path_quarantining
renames the corrupt file to <name>.corrupt-<unix-ts> (preserving the
recovery path) and then starts with an empty registry, matching the
tombstone corrupt-file philosophy while keeping startup available.
WardenRuntime::with_shame_wall_path now uses the quarantining loader.
Tests: corrupt file is renamed away, backup preserves original contents,
live path is recreated by save and the backup survives; a missing file
creates no backup.
Hot append paths (add_message / replace_context_messages) no longer
synchronously rewrite the full turn-context snapshot per message, which
made long sessions O(N^2) in context length (10MB context -> 10MB clone
+ serialization + fsync per append).

- add_message marks the session dirty via schedule_current_turn_snapshot_flush
- a single background flush task drains the dirty set after a 200ms
  debounce window, coalescing N rapid appends into one atomic write per
  session per window (shared per-session flush lock)
- turn-start / turn-end (complete/fail/cancel) / compression
  (replace_context_messages) / listing-diff removal now flush
  synchronously (persist_current_turn_context_snapshot_forced), which
  also supersedes any pending debounced marker, so crash-recovery
  semantics are preserved (a crash mid-turn loses at most the last
  200ms window of in-memory appends)
- compact serialization already in place in JsonFileStore; sanitize was
  already Cow-based
- regression tests: debounced flush coalesces rapid appends; forced
  turn-end flush supersedes pending debounced flush
…OT at startup (UX-P1-3)

CLI startup previously only initialized the global config service; the
KnowledgeBaseSearch tool reads BITFUN_KNOWLEDGE_BASE_ROOT at call time, so a
configured ai.knowledge_base_root was silently ignored in CLI deployments
(L6-P0-1 was desktop-only). Mirror the desktop host injection
(desktop/lib.rs:518-548): resolve ai.knowledge_base_root once at startup and
inject it into the environment, keeping the explicit-env escape hatch.
Adds inject_knowledge_base_root_if_needed + 4 unit tests (configured inject /
explicit env wins / unset leaves env absent / blank treated as unset).
export_session_transcript used a bare fs::write over the transcript file; a
concurrent reader (SessionHistory export / compression transcript readers)
could observe a torn/partial file. create_compression_transcript used
create_new + write_all, which is equally non-atomic while holding the lock
open during the write.

Replace both with the JsonFileStore temp+rename / hard-link publish path:
- export_session_transcript -> write_text_atomic (BestEffortReplace)
- create_compression_transcript -> write_text_atomic_create_new for the
  transcript and metadata pair, preserving the unique-name retry semantics of
  the former create_new reservation (AlreadyExists -> retry with a fresh stem)
  and removing partial files when the pair reservation fails.

Adds two regression tests: transcript_atomic_write_leaves_no_torn_or_temp_artifacts
(complete read after re-export, no .tmp droppings) and
compression_transcript_pair_is_published_atomically (pair fully readable,
no .tmp droppings).
… aggregate cap (UX-P1-4 + UX-P1-5)

UX-P1-5: the deployment-frequency limit was a best-effort read-modify-write —
two concurrent loads could both read an empty legionDeployTimes history, both
pass the cap check, and both deploy. Guard the check-and-reserve with a
KeyedAsyncLock keyed by (workspace, creator) so the in-flight deployment is
already counted by the next load; the reservation is written before the
creation loop and rolled back on every failure path (depth cap, create error,
attach rollback, aggregate-cap rejection). A reservation persistence failure
now fails the load closed instead of silently deploying without a counter.

The cross-deployment aggregate cap is now workspace-dimensional: it counts all
persisted legion node sessions in the deployment workspace (via the new
SessionManager::count_workspace_legion_node_sessions) instead of the creator
subtree, so recursive fission (children deployed as independent creators) can
no longer exceed ai.legion_max_total_nodes layer by layer.

UX-P1-4: document that max_nodes is resolved once per dispatch and passed into
resolve_legion_topology — validate_input stays an early-reject hint and the
dispatch-time value is authoritative, so a config hot-update between validate
and call cannot make validation and execution disagree.

Adds 3 tests: frequency_limit_helper_rejects_only_at_the_cap,
rollback_helper_removes_only_the_reserved_timestamp,
concurrent_loads_of_the_same_creator_are_serialized_by_the_deploy_lock,
sequential_check_reserve_under_lock_counts_inflight_deployments.
…notation (UX-P1-3 + UX-P1-6)

UX-P1-3: add a Knowledge Base section to BasicsConfig with an input + save
button for ai.knowledge_base_root (injected into BITFUN_KNOWLEDGE_BASE_ROOT by
the desktop/CLI hosts at startup). Adds en/zh-CN/zh-TW i18n keys and a vitest
spec covering load/render, persist, and clear.

UX-P1-6: annotate the legion node role label in CreateLegionPage with a
'display only' badge + tooltip explaining that legionRole is orchestration
metadata only — the deployed session's permissions are always resolved by the
standard subagent role (Executor), never by this label. Adds en/zh-CN/zh-TW
roleAnnotation keys.
UserSteering messages persisted into history could still be re-processed
across round/turn boundaries; content-based dedup keys risk prompt-cache
prefix drift when matching against the injected payload.

- MessageMetadata gains optional steering_id (serde default None,
  skip_serializing_if none) so the dedup marker persists with the message
  into snapshots and round-trips through serialization (backwards
  compatible with legacy snapshots)
- execution_engine attaches the injection id to injected UserSteering
  messages instead of relying on content scanning
- SessionRoundInjectionBuffer dedup upgraded to prefer the steering-id
  metadata key (id:<steering_id>), falling back to the content key for
  legacy entries without an id; drain/acknowledge/undelivered paths all
  record the id key; distinct steering events with identical content are
  no longer collapsed
- tests: consumed steering id suppresses reinjection without content
  scanning; distinct steering ids survive after one is consumed; legacy
  content-key fallback keeps suppressing; steering_id metadata
  round-trips and legacy snapshots still load
P2-S1: document PunishmentExecutor SessionControl scope (list/inspect only,
      cancel/delete stay behind resolve_session_mutation_authorization)
P2-S2: Warden template path_policy restricted to .bitfun/warden audit root
      (WARDEN_AUDIT_WRITE_ROOT) so prompt injection cannot write arbitrary files
P2-S4: tombstone parent=None now Err-propagates (d4-P1-1 family) in both
      list_deleted_session_ids and record_deleted_session_id
P2-S5: warden judgement tool_args embedded as digest summary (param name +
      length + sha256 fingerprint), never raw text (prompt-injection surface)
P2-S6: task ACP persist scan distinguishes idle slot (Ok(None) -> append) from
      read error (Err -> keep scanning, never overwrite corrupt index)
P2-S7: remote collect_workspace_reader returns (data, timed_out) so callers
      can distinguish no-output from truncated output
P2-S8: session tree serialization marks truncated nodes with "truncated": true
      (mirrors orphaned marker); + truncation regression test
UX-P2-2: SessionControl list rejects cross-workspace listing unless owner or
      warden/daemon audit session
UX-P2-3: transient sessions deny LegionControl (no persistent legion nodes
      from throwaway scopes); + deny assertion test
UX-P2-4: session JSON artifacts forced 0o600-equivalent on Unix (best-effort)
      before atomic publish

Verification: cargo check 0e0w (core/services-core/services-integrations/
desktop); core 2427 + agent-runtime 325 + desktop 274 + services-core 12 lib
tests green.
… content digest (TOKEN-03)

PERF-02: EventQueue stats switched from async Mutex<QueueStats> to
      AtomicU64 counters, removing two async Mutex acquisitions from the
      per-delta enqueue path (~thousands of locks per 2k-token reply).
TOKEN-03: User Context cache identity now appends |instr:<sha256> digest of
      workspace instruction files (workspace AGENTS.md/CLAUDE.md + external
      user sources when enabled), appended AFTER the stable prefix so
      unchanged content keeps hitting the cache while an edited instruction
      file invalidates it (TTL=None never expires otherwise). Digest failure
      falls back to "unreadable" (cache miss, never blocks prompt assembly).

Verification: cargo check 0e0w; core 2427 (incl. user_context_cache_identity
switch-state/remote-layer tests) + agent-runtime 325 (incl. event_queue)
lib tests green.
# Conflicts:
#	scripts/core-boundaries/rules/feature-rules.mjs
#	src/crates/assembly/core/Cargo.toml
#	src/crates/assembly/core/src/agentic/agents/registry/external.rs
#	src/crates/assembly/core/src/agentic/tools/implementations/mod.rs
#	src/crates/assembly/core/src/agentic/tools/product_runtime/materialization.rs
#	src/crates/assembly/core/src/product_runtime/runtime_services.rs
… after upstream sync

Upstream added tool_feature_group owner validation for product tool plans;
local customization tools (WorkspaceScan/KnowledgeBaseSearch/PlanList/PlanRead/
PlanUpdate/LegionControl/acp_*) were missing from the mapping, breaking the
default tool runtime feature closure. Keep them owned by Basic/AgentControl
groups (customization preserved).
…basics-config knowledgeBase part, legion font-weight token
…ot scan (平台-P1-2)

根因:resolve_session_workspace_binding 第三查依赖本进程 workspace 注册表,
跨工作区会话(另一 host/runtime scope 创建)不在注册表中,即使元数据已
持久化也扫不到 -> 'Workspace for session could not be resolved'。

修复:
1. 第三查注册表候选从 ? 短路改为安全退化;
2. 新增第四查:扫描 user-level projects_root 下所有含 sessions 目录的
   工作区,从会话自身元数据重建绑定(不依赖注册表);
3. session_config_from_persisted_metadata 优先读 stored state 文件恢复
   完整 SessionConfig(workspace_id/execution_target),metadata 兜底。

测试:新增 cross_workspace_session_resolves_binding_from_projects_root_scan,
bitfun-core lib 2439 全绿,session_manager 模块 131 全绿。
- 三项注入改造:会话级注入开关 + 配置体系(global/service/types)+ 前端 SessionConfig
- 泄露链 A+C 修复:prompt_builder/prompt_cache/prompt_markup/scheduler 链路
- 子代理 steering 修复 + steering 打断修复:coordinator/execution_engine/session_manager
- P2 修复:chat_state/instruction_sources/instruction_context
- platform-P1-2 修复:tool_pipeline/agent-runtime
…UI consistency + models.dev reasoning preset)
t added 30 commits August 13, 2026 09:21
…ion)+ content_render_kline/content_publish/knowledge_graph 六处注册面同步(gbrain_tool.rs 独立文件避免冲突)
…pending-parent 缓解

- 契约层:Session/SessionMetadata 新增 orphaned + orphanKind(后端 metadata 带出,page 构建时计算不落盘)
- 前端:SessionsSection 树构建拆分 orphanedSessions → 「孤立会话」独立折叠区(可见/可标识/可删)
- 透传:DanglingChild(relationship 父缺失)/ DetachedChild(creator marker 父缺失),与 GC 分类器同规则
- 排序:compareSessionsForNavStable 孤儿排后,不影响分页 cursor 与 top-level 计数
- 验证:vitest 38+34 / cargo 5+6+17 / tsc 改动文件 0 错误 / i18n contract 37 绿
- 报告:docs/pr-docs/02-侦察/报告-RAD08-孤儿会话UX-20260813.md(桌面端 release 验证待确认)
…ging(53 commit)

A 高危裁决落位:
- A1 双依赖保持:react-virtuoso ^4.18.11(群聊 GroupChatPane/GroupChatsSection 保持)+ 上游 TanStack 主链
- A2/A3 恢复:StickyTaskIndicator/UserSteeringBubble/UserMessage/TurnHistoryPanel/TurnRollbackButton + defaultAppearanceRegistry 5 处 appearance(恢复待 10-03 落位)

冲突解决(2 文件):
- desktop-package.yml:本侧 stable 直链 TAURI_UPDATER_ENDPOINT + 上游 beta channel 机制融合
- FlowChatHeader.tsx:本侧 empty-session header 常驻 + 上游 hasTurnInfo 条件渲染融合
…art + expanded/collapsed/orphan states)——修复 R-AD-08 漏注册导致 Frontend Build appearance:contract-audit 失败
Frontend Build Run web UI tests 产生约 1151 条
"Warning: The current testing environment is not configured to support act(...)"。
根因:vitest setup(src/test/setup.ts)未设置 IS_REACT_ACT_ENVIRONMENT,
约 80 个测试文件各自手动设置。

修复:在全局 setup.ts 一次性设置该标志,消除全部环境级 act 警告;
剩余真实未包裹 act 的组件测试警告(AgentCompanionDesktopPet/GroupChatPane/GroupChatsSection)单独处理。

验证:pnpm --dir src/web-ui run test:run 462 files / 3310 tests 全绿;
type-check 通过;eslint 通过。
…ompanionDesktopPet 测试)

前提交全局开启 IS_REACT_ACT_ENVIRONMENT 消除 1151 条环境级 act 警告后,
剩余 39 条为组件测试真实未包裹 act() 的异步 state 更新:

1. GroupChatPane.test.tsx:mount effect 的 loadMembers/loadMessages store 更新
   落在 act() 外。renderPane 改为 act 内冲刷 invoke 链(默认 IPC 返回与
   pre-seed 一致的数据),调用处 await。
2. GroupChatsSection.test.tsx:mount effect 的 loadRooms/loadMembers 对 IPC
   pending(不 resolve),state 更新不再落到 act() 外;delete 测试显式只
   resolve group_chat_delete。
3. AgentCompanionDesktopPet.test.tsx:Enter 提交经 async submitBubbleComposer
   await sendPetCommand 后 setState 在 act 外;dispatch 后 act 内冲刷。

验证:vitest run 462 files / 3310 tests 全绿,act 警告 0 条;
tsc --noEmit 通过;eslint 通过。
… concurrent flake

1c66b52 only serialized persist_session_lineage itself; sibling on-disk
tests still ran concurrently against the process-global SESSION_PERSISTENCE_LOCKS
registry and host temp_dir(), and CI kept observing NotFound in the lineage
test (2447 passed; 1 failed on ubuntu).

Now TestWorkspace::new() acquires a family-wide re-entrant per-thread guard
(PERSISTED_SESSION_TESTS_LOCK + thread-local depth counter), so every on-disk
persisted-session test is mutually exclusive with its siblings while pure
in-memory tests stay parallel. The lineage test drops its redundant manual lock
(TestWorkspace now owns it).

Verified: cargo test -p bitfun-core --features product-full --jobs 4 --lib
2445 passed; 0 failed (3 serial rounds of session_manager all green).
CLI Rust warnings(CLI Tests ubuntu/macos 各 3 个 + Windows 特有 6 个):
- model_selection.rs / agent_selector.rs / popups.rs: 仅测试引用的
  resolve_session_model_display_id / show_modes_only / show_agent_modes_only
  加 #[cfg(test)]
- self_update.rs: GzDecoder/Cursor/Archive imports + DEPRECATION_WARNING +
  find_package_dir + validate_entrypoint_pair 标记 #[cfg(unix)]
  (Windows 空实现不引用,消除 Windows 特有 unused warnings)

Cargo Deny: display-info 0.4.8 通过 screenshots 进入依赖树,manifest 用
license-file 而非 SPDX license 字段触发 no-license-field warning;
ci.yml 'cargo deny check licenses' 加 -A no-license-field 消除(LICENSE
文本仍按 allow 列表门禁)
…消除 /tmp canonicalize 抖动)+ InstructionSwitches 竞态补 lock_environment
…erver 8, bitfun-desktop 8, lib tests 5)

- bitfun-server: DispatchHostState fields and AppState.dispatch_host carry
  explicit dead-code intent (external_sources dispatch is dormant until the
  follow-up re-wires it onto the app-server schema); dispatch.rs module keeps
  its platform-neutral routes for tests with a module-level allow.
- bitfun-desktop: webview_recovery decision engine is intentionally platform
  neutral (Windows install + unit tests); module-level allow documents it.
- group_chat_router test: assert_ingest_result is async but callers forgot
  .await — now awaited (f2 convergence test actually asserts).
- ssh_api test: drop unused local_download_name_key import.
- embedded_relay_host test: last_err only feeds the panic branch; annotate
  the discardable assignment.

Verified locally: cargo check -p bitfun-server --locked = 0 warnings;
cargo test -p bitfun-core --features product-full group_chat_router = 11 passed.
Desktop build script needs frontend artifacts (mobile-web/dist) that CI
produces; local check blocked by that env gap, not by these lint fixes.
browser-direct ACP-over-WS 重构移除了旧 handle_command 接线后,
routes/dispatch.rs 的 supports/dispatch/store/parse_request/encode/
operation_error 全仓无调用点,DispatchHostState 及 AppState.dispatch_host
仅被该死模块消费(每次启动还白加载 SSH 凭据)——与 external_sources.rs
同批的重构漏删,按军令状删干净不留半成品。

删除:
- routes/dispatch.rs(227 行)
- AppState.dispatch_host 字段 + DispatchHostState
- main() 中 PathManager/SSHConnectionManager 初始化(白加载凭据)
- 相关测试断言与模块声明

验证:cargo check -p bitfun-server 0 warning(EXITCODE=0);
cargo test -p bitfun-server 10 passed 0 failed。
warn-zero-ci: bitfun-desktop 8 dead-code warnings (RENDERER_FAILURE_WINDOW /
RESTART_FAILURE_WINDOW, FailureKind / RecoveryAction enums, RecoveryHistory,
decide_recovery / restart_or_block / restart_after_failed_reload).

Verdict: NOT dead code, NOT unwired feature - the recovery feature is fully
wired (appearance::create_main_window -> webview_recovery::install registers
the WebView2 ProcessFailed handler on Windows). The engine is platform-neutral
by design: Windows install path + unit tests are its only consumers.

Root cause: cross-platform cfg not annotated. On non-Windows builds nothing
outside #[cfg(test)] references the engine, so dead_code fires. Module-level
#![allow(dead_code)] would have silenced it too broadly; per-symbol
#[cfg(any(target_os = "windows", test))] mirrors exactly where each symbol
is used, so dead-code detection stays active everywhere else.

Also annotate the discardable last_err assignment in embedded_relay_host
test (same lint class the engine fix surfaced, aligned with upstream fix).

Verified: cargo check -p bitfun-desktop --lib = 0 warnings;
cargo check -p bitfun-desktop --tests = 0 warnings;
cargo test -p bitfun-desktop --lib webview_recovery = 9 passed.
42b55ec warning-cleanup round deleted this import as unused, but the
case-insensitive download-collision test still calls it. macos/windows
Rust Build Check failed with E0425 at ssh_api.rs:1180-1181. Restoring
the import; cargo check + ssh_api tests pass locally.
…h.rs

af6c0e7 removed src/apps/server/src/routes/dispatch.rs (dead dispatch
host shell). dispatch.contract.test.ts still read it in the 'exposes no
way to build the CLI on a target' source scan, failing with ENOENT on
Frontend Build. The remaining scan sources (routing tables, dispatchApi,
types) fully cover the contract.
存量 warning 清零(main=13bcd6dd9 基础上新增):
- core path_manager: 删除 3 个死测试 helper + guard(默认 feature 下 scheduler tests 不编译)
- cli provision: 删 unused use super::*
- events agentic: 补 #[test] 注册漏跑的 dead 测试函数
- linker_messages: workspace lints allow(MSVC 平台噪音,lint 本身忽略 -D warnings)
- relay-server/relay-service 独立 lints 块同步 allow

门禁:
- rust-build-check / cli-test: RUSTFLAGS=-D warnings
- frontend lint: eslint --max-warnings=0
… + relay device_kind + flowchat scroll stability)
- provision.rs: use super::* 改 #[cfg(unix)] 精确导入 ensure_private_request_file
  (Windows 下全量导入 unused, 且测试本身 unix-only)
- installer commands.rs: unsafe fn 内调用 GetDiskFreeSpaceExW 补 unsafe block
  (workspace lint unsafe_op_in_unsafe_fn 在 -D warnings 下变 E0133)
serde::{Deserialize, Serialize} + std::time::Duration only used by the
platform-neutral decision engine consumed on Windows install path and in
unit tests. On non-Windows lib builds they were unused imports under
RUSTFLAGS=-D warnings (ubuntu/macos Rust Build Check red).
…lans dir

write_bound_plan_file wrote the plan file under the test tempdir, but the
binding layer resolves bare file names through the global PathManager's
~/.bitfun/projects/<workspace-slug>/plans/ and the PLAN-01 containment
fence rejects anything outside it. The tests only passed on machines where
a stale slug directory already existed in the real home; clean CI runners
failed deterministically (windows lib test job red). Write the plan file
at the path resolve_plan_path_for_backend actually resolves, and return the
bare file name so the binding metadata targets that exact file.
…mport warning

Evidence:
- cdb49e8 introduced get_path_manager_arc at module top-level but it is
  only used inside the test-only write_bound_plan_file helper, so plain lib
  builds (cargo check without --tests) hit -D warnings: unused_imports.
- Local repro: cargo check -p bitfun-core failed with 'error: unused import'
  before the fix, Finished with 0 warnings after.
- Cargo.lock: cargo check refreshed the lock to drop getopts, matching the
  upstream feature-centralization (9b05dd0) dependency graph.

Fix: narrow the import to the tests module where the symbol is used.
Root cause: MainNav enumerated assistant workspaces (assistantId like
'bd56fce3') as group chat member candidates, but the backend validated
members against registered sessions only — a workspace id without a
session failed with 'group chat member session does not exist'.

Fix (主人定标 2026-08-13: 创建群聊按 Claw 预设类型新建对话):
- New shared helper ensure_claw_member_sessions: member session missing
  (memory + disk) -> create a Claw session bound to the assistant
  workspace (agent_type='Claw', deterministic session_id = assistantId);
  non-Claw existing sessions still rejected (P1-7).
- create_room_impl and join_room_impl both use the helper (create/join
  same semantics). Idempotent: checks memory then persisted storage
  before creating; clear error when the assistant workspace dir is missing.
- Added 3 tests: auto-create Claw session / clear error without assistant
  workspace / non-Claw rejection.
Align legion preset cards with core agent card styling:
- Use agent-surface-card mixin: 200px height, 15px radius, hover lift
  + gradient overlay, footer gradient bar (previously 10px radius, no
  gradient, no fixed height)
- Inject per-pattern gradient via getCardGradient(id || name) like
  AgentCard; icon area uses accent-colored glass style matching
  CoreAgentCard
- Preserve legion-specific content: complexity badge (L1-L7) + node/
  edge/gate meta counts; BEM + data-bf-part structure unchanged
- prefers-reduced-motion guard added
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