Files
makelore/.project-docs/40-domain/business-rules.md
brother7 eedd20d061
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled
docs(integration): record remember password boundary
2026-08-20 23:45:13 +08:00

80 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Business Rules
## Durable Rules
- 面向用户的 AI 编程新建流程必须在 `mini_game`、`mini_program`、`custom` 中选择;`ProjectType` 是产品类型,创建后不能通过 UI 或 Host API 修改,未传类型的兼容 API 调用按 `custom` 处理。
- 新建小游戏和小程序会生成平台固定版本的受控 Vite 发布模板,并可使用项目配置中的单一“提交审核”入口;`custom` 和缺少类型字段的旧项目不提供一键发布。
- `ProjectType` 不等于 `BuildPreset`:第一期两个可发布产品类型都映射到内部受控 Vite preset;本地 `projectType` 不是授权边界,Main-owned 安全打包、Host API 和服务端包体校验仍必须执行。
- 非专业用户只执行一次“提交审核”;构建通过后由运营审核,审核通过即直接发布。
- 创建者发布唯一链路是项目配置“一键提交审核” → Main 本地 npm/Vite 构建 → 最终 built snapshot 的客户端 UX 预检 → source+built+artifact contract 上传 → 服务端校验/固化 → 运营审核;不恢复独立发布上传页、云部署工作台、Compose/deploy-check、自动 watcher/arm/upload 或手工 ZIP 入口。
- 本地构建必须由 Main 对安全源码快照使用安装版 Electron Node 和固定 npm 11.6.2 执行 `npm ci --ignore-scripts`,再显式调用项目 `package-lock.json` 安装的 Vite;不得依赖全局 PATH、既有 `node_modules` 或 Renderer 提供的任意路径/origin。
- 项目 Vite config/plugins 以桌面用户权限执行,因此发布链只适用于用户信任的本地项目;它不是 sandbox。安装依赖需要网络,运行时闭包缺失或版本不符必须 fail closed。
- 提交前预检必须由 Main 以一次性 loopback origin 提供最终上传 `built_archive` 的同一内存文件快照,以 fresh 非持久 Electron WebContents/CDP 检查桌面/移动视口、运行错误、白屏与外域访问;不得调用 Playwright 或污染用户浏览器状态。
- 客户端预检是可绕过的 UX fail-fast,不上传可信 receipt,也不声称具备生产 opaque-origin parity。服务端把源码、构建归档和 contract 当作不可信字节,独立重算、校验并固化不可变 Release;人工审核仍是不可绕过发布门禁。未来若要求 runtime 强门禁,必须由可信 verifier 绑定精确构建产物。
- 发布安全边界由 Electron Main 持有,Renderer 不接触账号 Token、ZIP、幂等键和本地绝对路径。
- 发布 Host API 必须在读取凭据、查询项目和打包前校验 Renderer capability;仅持有 Host token/base 的非 UI 调用方不得发起发布。
- 首次 Works Project 发布必须选择 PNG/JPEG/WebP 封面(不超过 10 MiB),并由 Electron Main 将项目资料与封面通过服务端单一 multipart create 合同原子绑定;Renderer 仅传有界封面 DTO,不接触 Works Token、项目路径、归档或幂等身份。服务端创建冲突或失败时客户端必须停止版本上传,不能回退到先传封面再 JSON create。已有 draft/published 仍只提交新版本并沿用平台资料与封面;在具备 metadata revision/ETag 与 draft-only 条件写前,不得用无条件 PATCH 模拟已有资料编辑。
- 客户端只持久化服务端已接受的 submission binding v2。旧 `submitted` 绑定必须保留;旧 `armed`、`waiting_for_package`、`waiting_for_login`、`uploading`、`failed` 必须迁移为可理解的 `legacy_retired`,不得恢复后台任务。
- 云端上传成功但本机 submission binding 保存失败时,提交仍视为成功;客户端显示固定、无本地路径的告警并继续轮询服务端校验与 Release 固化状态,避免诱导重复提交。
- 旧客户端缺少 source+built+contract 新协议,或服务端仍存在旧 sandbox/browser 任务时,必须提示升级客户端并重新构建提交;不得把它们伪装为新版瞬时故障。新版合同校验后的 `BUILD_STALE`、归档存储或 ReleaseStore 瞬时失败由运营在“构建异常”中重试。
- 已发布作品优先读取 `play_url`,只有字段缺失时才使用一个客户端版本的 `runtime_url` 回退。公共播放 URL 必须是 Works Square 同源 HTTPS、无 userinfo/loopback、精确 `/apps/{encodeURIComponent(app_id)}/`、无 query/fragment,且上游明确 `playable === true` 并提供非空版本名;否则按不可播放处理。
- `works-cloud-deploy.json` 仅是已安装客户端的数据兼容文件名,不表示客户端仍提供 cloud deployment coordinator。
- Works Square 会话按真实键盘、鼠标或触摸活动滑动续期,连续 7 天未使用才要求重新授权。
- “记住密码”是独立于七天会话的可选桌面凭据记录:只能由 Electron Main 在正式安装包中通过可用的系统安全存储加密落盘,账号密码不得进入 Renderer 持久状态、日志或 Works Square 持久化。退出登录和短信登录保留记录;只有成功的未勾选密码登录清除旧记录。系统安全存储不可用或未打包开发版必须禁用该选项。
- 运营端可按用户关闭 Code、Canvas、Learning 或 Robot 客户端入口,默认全开。Makelore 通过 Main-owned `/api/auth/me` 只消费四布尔安全投影;缺失 `module_access` 或字段按开启处理,服务端 `design` 对应现有客户端 `painting`。
- 关闭的模块卡片必须置灰且无法点击;其根路由、深层路由和别名路由必须在 `MainLayout` 或模块初始化前阻断。Code provider 只能在 auth policy hydration 完成且 Code 已开启时初始化;`/settings` 是全局设置,不得随 Code 关闭而失去访问。
- 模块置灰/路由阻断不是 API 授权边界。每个 Works/模块服务端 API 仍必须独立执行身份与权限检查;`/api/auth/me` 返回终止性 `401` 时必须清理 Main 和 Renderer 会话,不得以默认全开继续。
- AI 编程伙伴 `model` 只决定新 OpenCode Session 的默认模型;现有 Session 的 active model 由 OpenCode 持有。页面模型选择器与 `/models` / `/model` 必须调用同一个 native Session 切换动作,普通 prompt、项目命令和上下文压缩不得重发伙伴默认模型覆盖用户选择,也不得把该操作写成 provider 配置变更或 runtime restart。
- owned fresh runtime generation 中,新创建且本 generation 从未见过的唯一 Agent id 可在 live registry 暴露后立即使用,并且不得阻断已有未修改伙伴。同 id 内容编辑、删除后同 id 重建、live id 缺失以及 attached/unknown generation 必须保持 pending,直到权威 reload 或 generation rollover。
- 客户端更新检查由 Electron Main 持有。缺少当前平台正式稳定 manifest 必须保持错误并提示稍后重试或从官网下载,不得宣称“已是最新版”;设置页只显示一条中文用户提示,原始堆栈、URL、路径和错误码只保留在 Main 日志。
- 一个 AI 绘画 Workspace 可以包含多条独立 Conversation;新建 Conversation 不得创建新 Workspace。
- Conversation 持有消息、Brief、Quote 和 `turnRevision`;生成任务和资产属于 Workspace,切换 Conversation 后必须继续可见。
- 每条 Conversation 使用服务端持久 Agent Gateway Session。客户端注销或退出时只关闭本地流并清除本机 Session-id 缓存,不删除服务端 Session。
- Conversation 异步与流式更新必须同时核对 Workspace 和 Conversation 身份;任务事件按 Workspace 归并。
- 已连接的 Conversation Agent 命令、Run 和设计事件共用 WebSocket。只有命令发送失败、连接关闭或 ACK 超时可用同一 `client_command_id` 回退 REST;Gateway 结构化业务错误不得重复提交。Main 只向 Renderer 投影已知错误码的固定中文提示,未知上游错误文本必须脱敏为通用提示。
- AI 绘画 Workspace JSON 请求与 shared Works token refresh 必须覆盖取凭据、发请求和读取响应 body 的完整 30 秒 deadline;即使底层 transport 忽略 abort,调用方也必须确定性结束为 `504 DESIGN_WORKSPACE_REQUEST_TIMEOUT` 并释放共同等待者。Electron-to-Node 透明 fallback 仅允许 `GET`/`HEAD`/`OPTIONS`;mutation 不得因 transport failure 被隐式重放,任何重试必须由上层显式幂等合同授权。
- 确认生成后按 Quote 对账 Workspace 任务。任务已经落库但 Run 随后失败时应恢复右侧任务列表;切换 Conversation 后仍同步 Workspace 任务,但旧确认不得覆盖当前 Conversation、清除其 pending turn,或用任务对账失败覆盖新会话错误。
- 图片生成支持无参考图的文生图和单参考图图生图;参考图必须来自当前 Workspace 的已完成图片 Asset,或先通过现有 Workspace 上传接口把本地图片转成 Asset,再随当前 Conversation Turn 提交唯一 Asset ID。
- 视频首帧与图生图参考图复用单图选择器,但用途由当前 Brief medium 决定:只有明确 `image` 使用图生图语义,`video`、null 或缺失值保持视频首帧兼容语义。选择作品或上传成功后应关闭弹窗。
- 当前 quick reply 文案匹配只是兼容契约;新增更多素材输入用途前,应改为结构化 action/purpose,不得继续依赖本地化展示字符串推断行为。
- Canvas generation Quote 的最终 Prompt、清晰度、画幅或视频时长变化必须经服务端重新报价;报价进行中不得确认。客户端只展示服务端返回的设计点并提交参数原值,不计算供应商价格、尺寸映射或积分价格。
- 删除 Canvas 项目必须要求用户完整输入项目名并通过 Main-owned Workspace DELETE。成功后被删 Workspace 的会话、任务和资产不得继续留在 Renderer 可访问状态;服务端决定软删除、任务取消、预留积分释放和运行中任务结算。
- Prompt Museum 只展示服务端审核并带稳定作者、来源、许可证/署名和素材授权信息的内容;客户端不内置数据集、不推断缺失版权、不提供投稿/点赞/评论/收藏/关注/排行,也不自动发送或生成选中的 Prompt。
- Prompt Museum Renderer 只能通过 Main-owned 固定 GET 路由读取列表和详情。Works Token 不得进入 Renderer;列表查询只允许搜索、使用场景、风格、主体、语言、模型、游标和限制字段。需要受保护图片时必须新增 Main-owned 媒体代理,不能把 access token、内部路径或用户隐私放进图片 URL。
- 产品界面当前只支持中文;系统语言与历史持久设置中的其他值必须归一为 `zh`,不得保留不可达的伪语言选择。
- Learning 是登录必需且受 `module_access.learning` 控制的运营精选项目目录。客户端只提供项目列表、README 详情和用户触发的 ZIP 下载,不提供课程生成、进度、本地课程库、OpenMAIC 播放、Agent、ASR 或课堂 runtime,也不保留旧 API/数据兼容读取路径。
- Works Square 运营后台拥有项目名称、摘要、封面、标签、版本、排序、状态、Markdown、ZIP、声明字节数和 SHA-256。只有冻结了元数据、媒体和归档校验结果的 `published` 项目可被客户端列表或详情读取;客户端不提供上传、编辑或发布入口。
- README 使用安全 Markdown/GFM 并禁用原始 HTML。运营发布时必须解析 Markdown,只保留无凭据、默认端口、无 fragment 且当前 DNS 全部指向公网地址的 HTTPS 图片 URL;不得下载、识别格式、转码或镜像 README 图片。客户端仅允许 Markdown 图片节点直连这些 URL,支持范围和可用性由 Electron 与远程 origin 决定;封面和历史发布媒体继续走受控媒体路径。
- Main 打开原生保存对话框,将项目 ZIP 下载流写入临时文件,只允许无 userinfo、最多五跳且保持 Works origin 的重定向,重定向请求不携带 Bearer;客户端下载不校验 `Content-Length`、`archiveBytes`、实际流字节数或大小上限,只在 SHA-256 与 ZIP 签名匹配后原子重命名。Works Square 可保留独立的运营上传/存储限制。Renderer 不得获得 Works Token、对象存储地址、任意下载 URL、临时路径或最终本地路径。
- 新客户端不读取、迁移或展示历史下载课程,但也不自动删除用户现有课程数据。任何清理功能必须另行设计为用户明确控制的可恢复维护动作。
- `game-engine` 不再是内置 OpenCode Skill。`planning-with-files` 在复杂任务中把 `task_plan.md`、`findings.md`、`progress.md` 写到当前项目根目录;不得写入 Skill 安装目录或用户目录。
- Robot V1 在现有 Binding 体验内扫描符合条件的开放 `Xiaozhi-*` 配网热点,并只连接用户明确选择的短效候选;该便利信号不得宣称为可信设备发现、自动下发家庭 Wi-Fi、自动认领或自动确认在线。
- Guided Hotspot Binding capability 由 Electron Main 持有且默认开启。精确 `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` 关闭引导;关闭或 capability 读取失败时保留现有六位码 Binding,Renderer 可以读取但不能覆盖它。
- Robot hotspot scan/connect 必须由 Electron Main 持有并在读取 Works 凭据前本地完成。Renderer 只能提交最近扫描生成的短效不透明 candidate ID,不能提交任意 SSID、BSSID、接口、profile 或命令。
- 只有开放、可连接、可打印、UTF-8 不超过 32 bytes 且以 `Xiaozhi-` 开头的候选可进入页面。连接只有在当前 SSID 与候选完全一致时成功;权限、平台、扫描或连接失败必须保留系统 Wi-Fi 兜底。
- Robot portal 必须由 Main 以系统浏览器打开固定 `http://192.168.4.1/`。Renderer 不得提交任意 URL;该本地动作不得读取 Works 凭据或访问云端。
- Wi-Fi SSID/密码只在现有固件 portal 内输入。Makelore 不收集、不代理、不日志记录、不持久化 Wi-Fi 凭据。
- 产品已明确选择在保留当前固件行为时 default-on;开放 SoftAP 与明文 HTTP portal 仍是已知残余风险,不能据此推断安全风险已被单独验收。界面必须保留不在不可信公共环境操作的警告。未核对精确固件镜像、六位码发行/消费契约、原生 opener E2E 与真机 smoke 前,不得宣称完整兼容或端到端验收;现场异常必须可用精确环境值 `0` 回滚。
- Binding 成功仅表示设备与账号/Agent 的云端关系建立,不表示设备在线或业务协议 ready。
- 同一进程内无法确认结果的 Binding 重试必须复用原 operation ID。无效、过期或已消费 activation code 必须清除 code 与 operation ID;下一个新码使用新 operation ID。Main 必须把 `ai_hardware_activation_code_invalid` 投影为 non-retryable,不信任上游相反标记。
- 应用重启后,当前 overview DTO 不能证明旧码对应的 Binding 结果;客户端不得重放旧码或旧 operation ID,必须要求新码,无法取得时停止流程。
## Open Questions
- 生产整链需要真实账号、新上传/校验合同、OSS immutable Release、CDN/Edge、运营审核、App 播放与监控环境完成最终验收;当前客户端验证不能替代该验收。
- 是否需要在生产发布链引入绑定精确 Release/digest 的可信 runtime verifier;当前客户端 loopback preflight 不能承担该职责。
- 在一个客户端兼容版本且服务端与存量数据稳定提供 `play_url` 后,移除 `runtime_url` 回退。
- 多 Conversation 客户端发布前需确认服务端迁移 `0033`、Conversation API 与持久 Session 契约已经部署。
- 图生图随客户端发布前,需确认相匹配的服务端 `image_to_image` Brief/Quote/Task 冻结、私有源图复核与 Bailian edit 执行链已部署,并使用真实 Workspace Asset 完成生产 smoke。
- Updater 生产恢复仍需对齐权威版本、发布正式签名/公证的平台产物,并从旧安装版本执行发现、下载、重启和安装 smoke;源码提示修复本身不构成发布链恢复。
- AI Canvas 双向 Gateway 与 Quote 任务恢复仍需真实账号执行一次生产确认 smoke,核对 WebSocket 不产生 `/runs/{run_id}` 轮询、任务按 Quote 出现在 Workspace 列表,并区分真正的 `agent_runtime_unavailable` worker 故障。
- AI Canvas 请求冻结修复仍需在安装包内用真实账号重复 Quote PATCH、重试报价和继续调整:确认超时在 30 秒内释放 UI、并行请求可继续、服务端没有隐式重复 mutation。临时 `disable-http2` 不构成根因结论;修复确认后应恢复 HTTP/2 做对照 smoke,再决定正式协议策略。
- Robot Guided Hotspot Binding default-on 发布仍需确认指定硬件/固件确实提供被审计的开放 Hotspot/Portal、部署端签发严格六位 ASCII 数字码且与 Works validator 的时效/消费语义一致,并完成 Windows 真机、签名 macOS x64/arm64 native worker/association 与真实设备端到端 smoke。
- Prompt Museum 客户端契约和页面完成不等于 Works Square 内容后台、审核数据或 CDN 已部署;上线前需以真实登录账号验证列表、详情、署名链接、分页、图片和 Prompt 回填。
- Learning 客户端集成不等于 Works Square 运营后台、对象存储或项目 API 已部署;上线前需先部署服务端合同,再以真实账号验证发布/下架、分页、远程 HTTPS README 图片(含 SVG 与失败隔离)、保存取消、缺失或错误 `Content-Length` 的 ZIP、摘要/签名错误以及 Windows/签名 macOS 安装包。
- 四模块入口策略上线前需确认 Works `module_access` migration/API 已部署,安装包包含对应客户端,并用真实账号逐一关闭四个模块验证卡片、根/深层/别名路由和独立 API 授权。
## Last Reviewed
2026-08-20