Files
Agent-System/.doc/ops/short-term/2026-09-27-frontend-demo-fallback.md
T

11 KiB
Raw Blame History

title, task_id, status, created, updated, owner, task_type, task_tier, policy_revision, branch, worktree, base_dev_sha, write_scope, allowed_environments, head_sha, mutex, review_state, integration_state, deployment, cleanup, cleanup_owner, cleanup_trigger, remote_sync
title task_id status created updated owner task_type task_tier policy_revision branch worktree base_dev_sha write_scope allowed_environments head_sha mutex review_state integration_state deployment cleanup cleanup_owner cleanup_trigger remote_sync
前端 demo fallback 在真实 dev 环境产生 404/403 frontend-demo-fallback-2026-09-27-r2 done 2026-09-27 2026-09-27 pi implementation small agent-governance-2026-09-21-r1 @ dev 56928ac206 fix/frontend-demo-fallback-2026-09-27 .worktrees/frontend-demo-fallback-2026-09-27 56928ac206
web/src
.doc/ops/short-term
dev-readonly
dev-browser-verify
db038aa7a7 web-chat-fallback not_required merged passed done 独立集成/维护执行者 owner 退出且 dev 合入+验收证据齐备 not_requested

前端 demo fallback 在真实 dev 环境产生 404/403

用户目标与授权

  • 用户目标/授权来源:用户报告 dev 页面(frp-mix.com:58880)登录后控制台 7 个 API 404/403;会话中明确授权"按照规范进行修复,测试完成后合入 dev,清理 worktree"。
  • 交付终点:修复合入 dev、dev 实际运行验证通过、worktree 清理。
  • 禁止项:不 push 远端;不动 test/main;不改后端(本 bug 根因在前端 fallback)。
  • 例外:无。

问题事实与根因(2026-09-27 排查)

  • 现象:登录后首屏 GET /api/v1/projects/1、/projects/1/settings、/chat/messages/window|categories|dates|unread?session_id=sess-001 404;/intent-plans/active?project_id=1 403。
  • 链路核实:frp-mix.com:58880 → vite dev :3100(proxy /api → 127.0.0.1:8080)→ bin/agent-server(ENV=dev,2026-09-26 构建/启动,裸进程非 compose)。后端路由全部存在。
  • 数据核实(dev PG :5433 只读):projects 20 行无 id=1;project_members 无 project 1 成员;chat_sessions 80 行无 sess-001;user_id=4=系统管理员(真实登录用户)。
  • 根因:demo seeds 关闭模式(vite 未设 VITE_ENABLE_DEMO_SEEDS,后端 SEED_DEMO_USERS=false)下,前端残留 demo 假设硬编码:
    • web/src/App.tsx:138 loadActiveSessionId('sess-001')——无本地会话时激活不存在的 demo 会话;
    • web/src/App.tsx:206 currentProjectId fallback 1——找不到会话项目时默认不存在的项目 1。
  • 为何防护未拦:storage.ts legacy 清理只过滤 messages 的 legacy sessionId(:121),不清 activeSessionId;purgeDemoSeedsFromLocalStorage 清 localStorage 但 fallback 常量会再生成假请求。
  • 状态码差异属既有设计:projects/:id 对"不存在或无权限"统一 404;intent-plans/active 走 authorizer 映射 403。
  • 功能影响:新登录用户首屏噪音 + chat 回退本地缓存;无数据损坏证据。

同类排查

  • grep 全前端:sess-001 残留仅 App.tsx:138 一处(storage.ts:121 为正确防御);projectId fallback 1 仅 App.tsx:206 一处。
  • 观察不扩大范围:App.tsx activeDocId fallback 的 doc-001/5201/3 为 demo 残留,但仅影响本地文档选择、不发 API 请求,不属于本 bug(控制台 404 均为 API 请求);记录待后续清理。
  • ISSUES.md 无同类记录(检索 404/demo 残留/purge 无命中)。

相关问题与经验

  • issue_ids:本次新增 ISSUE-20260927-demo-fallback(登记于 ISSUES.md)。
  • 开工检索:404 fallback、sess-001、demo 残留,lessons 无命中;采纳验证契约"问题修复回归范围"节。
  • 收口经验:见闭环更新(ISSUES.md + 本文档验证节)。

修复方案(A:改共用 fallback 机制)

  1. App.tsx:138 loadActiveSessionId('sess-001') → loadActiveSessionId():demo 开启时仍取 NEUROPULSE_ACTIVE_SESSION_ID,关闭时为 ''(disabled 模式导出空串)。
  2. App.tsx:203-208 currentProjectId fallback 1 → 0,注释同步。
  3. 不需新增空态分支:chatBlockedNoProject(App.tsx:249)已含 currentProjectId <= 0,ChatColumn 渲染"请先创建或加入项目后再开始对话";会话纠正 effect(App.tsx:268-277)在可见会话出现时自动恢复 activeSessionId。
  4. 下游 guard 已核(空 sessionId/projectId=0 不发请求):getProject/settings/lineage effect(:397,:421)、useChatWindow(:120)、useUnreadMarks(fetchUnread 顶部)、categories/dates effect(:1037)、intent-plans effect(:1060)。

步骤与验收

  1. 根因与同类排查 — 本文档上文。
  2. 实施修复 — App.tsx 两处改动(:138 fallback 去常量、:206 projectId fallback 0)。
  3. web/ npm test、npm run build — 全绿(含 demo on/off 双模式构建)。
  4. 真实浏览器验证 — 修复前 9 假请求复现 / 修复后 0(author+member 双账号);老用户回归无新增 404/403。
  5. 合入 dev — integrate prepare/validate/integrate 规范流程;dev 56928ac2→0de657f0(--no-ff,first parent=D)。
  6. dev 实际运行验证 — 主目录 vite :3100(frp 用户入口同一 server)热载新代码,空 storage 登录 phantom=0、404/403=0、工作台正常。
  7. 清理 worktree、收口 — 详见收口节。

验证与证据

验证日期 2026-09-27;被测代码:worktree fix/frontend-demo-fallback-2026-09-27(基准 dev 56928ac2 + 本修复);环境:本机 dev 后端 127.0.0.1:8080(ENV=dev,agent-server 裸进程)+ 独立 vite :3101(worktree 代码,proxy 同源配置)。浏览器:Playwright chromium headless(brew 用户态补齐运行库);账号:dev 本地审计 e2e 账号(凭证不入库,来源 .doc/test-reports/assets/2026-09-26-full-system-browser-e2e/audit-login-credentials.md)。

范围 命令与环境 预期 实际 / 判定 证据
前端单测 npm test(worktree,node_modules 链接主目录) 全绿 PASS:tsx 512 pass/0 fail;vitest 34 pass/0 fail 控制台输出(本节记录)
前端构建(demo off) npm run build 成功 PASS:built 无错误,66 组产物预压缩 控制台输出
前端构建(demo on) VITE_ENABLE_DEMO_SEEDS=true npm run build 成功(alias 切换不破坏类型) PASS:✓ built in 9.40s 控制台输出
原例复现(修复前对照) 空 localStorage 登录主目录 :3100(旧代码) 复现假请求 复现:9 个 phantom(projects/1×4→403、sess-001×4→404、intent-plans 403);与用户报告一致 Network 抓取清单(下附)
原例修复(修复后) 空 localStorage 登录 worktree :3101(新代码) 零假请求 PASS:phantom=0,404/403=0,工作台正常渲染,84 个真实 API 全 2xx 同上
同类变体(第二角色) member 账号同样流程 :3101 零假请求 PASS:phantom=0,404/403=0,83 API 全 2xx 同上
正常行为回归(老用户) 同一 author 账号在 :3101 登录后真实会话/项目加载 不受损 PASS:会话纠冀 effect 选真实会话,项目/文档/血缘 API 全 2xx 同上
边界:demo enabled fallback 代码审查 loadActiveSessionId() 无参路径 demo 开启时仍回退 NEUROPULSE_ACTIVE_SESSION_ID PASS:`fallback

修复前对照抓取(:3100,旧代码,author 账号):

phantom: /api/v1/projects/1, /projects/1/settings, /projects/1/lineage,
/projects/1/documents?category=workflow, /chat/messages/window?session_id=sess-001&days=7,
/chat/unread?session_id=sess-001&user_id=60, /chat/categories?session_id=sess-001,
/chat/dates?session_id=sess-001, /intent-plans/active?project_id=1&session_id=sess-001
→ 403×5(project 1 无权限), 404×4(sess-001 不存在)

修复后(:3101,新代码,同账号 + member 变体):phantom=0;404/403=0;workbench 正常渲染。

注:临时验证脚本未入库(/tmp 与 web/ 下临时文件已删);worktree 独立 vite :3101 已停。用户报障中 projects/1→404 与本地复现 →403 的差异仅因报障账号(user 4 系统管理员)对该项目访问落在本项目不存在分支,两状态码均属既有「不存在或无权限」映射,非另改行为。

经验小结

  • 触发条件:前端存在 demo/生产双模式(构建期 alias 切换)且模式专属常量进入运行时 fallback 路径。
  • 机制:fallback 优先级高于模式开关清理逻辑;purge/legacy 清理只处理 storage 残留,无法阻止常量重新生成假 ID,首屏即对真实后端发请求。
  • 应做检查:关闭模式的默认值必须是空值/由服务端数据驱动,不得硬编码业务对象 ID;模式常量 grep 其在非模式代码(App/入口/hooks)的引用;新用户首屏用空 storage 真实浏览器验证 Network。
  • 错误做法与原因:只加 storage 清理不清理 fallback 常量(本例现状);只验证 demo 开启路径。
  • 验证方法:修复前后同流程对照(本任务 before 9/after 0)+ 双模式构建 + 第二角色变体。
  • 适用边界:前端双模式常量;同类见 App.tsx activeDocId 的 doc-001/5201/3 残留(仅本地选择无 API 请求,待后续清理)。
  • 独立 lesson 文件待后续覆盖 .doc/ops/lessons/ scope 的任务补登;本节为可检索替代。

收口与交接

  • 剩余工作:无(授权范围验收全部满足)。后续可选项:activeDocId 的 doc-001/5201/3 本地选择残留(无 API 请求,非本 bug);独立 lesson 文件补登(需覆盖 lessons/ scope 的任务)。
  • 状态分别记录:
    • 本地提交:db038aa7(任务分支 fix/frontend-demo-fallback-2026-09-27)+ 本收口提交。
    • dev 集成:merged,dev 0de657f0(validate 收据 run 85420f37-2e99-4c9b-b72c-277d7203efe9,SHA 0de657f0)。
    • 部署制品:dev 前端为主目录 vite dev server(热载,无镜像制品);后端二进制未变更(纯前端修复)。
    • 远端:not_requested(用户未要求 push;本地 dev 前进,origin/dev 未动)。
    • cleanup:任务与 integrate 两个 worktree 均按规范 remove + 分支删除。
  • 本次影响:App.tsx 两处 fallback;新登录用户首屏不再发 9 个假请求;demo 开启构建不受影响。

相关链接

  • ISSUES.md 新增条目:ISSUE-20260927-demo-fallback。