跳至内容

iOS 库内智能找菜 ​

关联 #181、#174 与 0007。2026-10-28 冻结首版产品边界:先验收自然语言转可编辑条件,再接真实模型;仅 iOS,Web 后续单独推进。

2026-11-07 按维护者确认的模拟器范围收尾 ​

维护者在本次收尾中明确确认「用模拟器验收即可」。#181 的关闭按这一更新后的范围判定,不再等待原先要求的真机、真人 VoiceOver 听读或新版 TestFlight 使用;下方真机盘点及历史未完成记录保留其当时结论,不回填为真实使用通过。个人 Key 的真实远程调用仍未验证,本轮使用既有隔离测试与传输替身证据,不把它写成实际 DeepSeek 调用成功。#174 的维护者内容复核与原人工清单继续独立保留。

使用本地候选 e988475ffe3f9059049c3336088a26da55ee640b(2.0.0 / 13)与归档时相同的生成数据输入,复用现有共享设备执行 SearchIntentUITests 的全部四条流程:

模拟器系统结果工具记录耗时
iPhone 16 ProiOS 26.54 通过、0 失败、0 跳过166.7 秒
iPad Pro 11-inch (M5)iOS 27.04 通过、0 失败、0 跳过282.2 秒

iPad 直接复用 iPhone 的同一 .xctestproducts,没有重建另一套测试产品。两端显式关闭并行测试,未新增、克隆或清空模拟器,也未占用原本已启动的其他设备。测试使用已有 -ui-testing 隔离数据与内存钥匙串,不读取手机凭据,不执行真实计费请求。

原断言覆盖:条件预览与标签移除、44pt 点击区域及透明边缘、取消不应用、确认后才应用、待确认项默认阻止应用、最大辅助字号深色、AI 设置安全输入与返回、结束键盘编辑、原句改写使旧预览失效、重新识别及取消后食材不被写入。已核对两端标准字号浅色与最大辅助字号深色原始截图,原生控件标签与交互结果符合预期;这些结果不称为真人 VoiceOver 朗读。每端仍记录两条 Invalid frame dimension (negative or non-finite) 警告;对应截图和操作断言通过,原日志保留,不认定唯一根因。

否定词、别名、严格契约、条件交集、个人 Key 边界、传输取消/失败恢复及迟到响应隔离,继续复用 #197 中源码与测试匹配的 38 项 Node、14 项 Swift 核心和 46 项 App 测试证据。此次没有修改产品、数据、测试断言或 CI 框架,也没有再跑这些单元测试或增加 mock。本轮新增执行仅为上述八次 UI 流程,结果包摘要、原始截图、层级、日志与脱敏收尾记录保存在 ~/Library/Developer/ReleaseArtifacts/Cook/20261107-issue-181-simulator-closeout。

另行回查 ASC:构建 13 存在 Xcode 本地导出生成的 AWAITING_UPLOAD 分析会话 330c89c1-715d-4a28-9161-4af5fa76a2c5,文件仅为 ASSET_SPI 分析压缩包和 ASSET_DESCRIPTION 描述;精确查询构建 13 的实际 build 为空。该记录不是 App 二进制上传或分发。本轮未补传、删除或重建该会话,也未上传新包;后续发布前需重新核对占用情况,不能直接把下一构建号仍视为 13。

按维护者接受的模拟器验收范围,S0–S4 的工程与模拟器验收已完成,#181 可关闭。此结论不覆盖真实个人 Key 调用、真机 VoiceOver、TestFlight 分发、会员购买/恢复或 #174 的内容复核;这些项目没有被伪记为通过。

2026-11-07 真机与候选盘点 ​

#197 已于 2026-11-06 合并,合并提交为 c7a28d65bd486f2ec77af2105190100fd0cfb72b,无需重新实施契约修复。本次冻结的源码候选为 main 691cc38fe6abc38e3ef9d112139726788341d630。智能找菜的八个核心/原生源文件、五个相关测试文件、Git 跟踪的顶层 JSON/菜谱 CSV 以及 cook-ai-intent 与 #197 最终 head c511b5a8 无差异;同步测试夹具、未跟踪的生成文件及其他模块不在该等价结论内。当前生成的公共词典、版本与服务契约另由生成器只读检查核对。

生产函数已重新只读查询为 Active / Nodejs24.11,实际通道仍为 cloudbase / deepseek-v4.1-flash-1017。完整包五个源文件的 SHA-256 均与上一轮证据一致,当前 1878cc5772dc 与已分发 faf919fc0041 的三项版本选择保持有效。本次未部署、切换模型或重复真实计费调用;11 月 6 日的真实 HTTP 结果仍按其原始日期记录。

ASC 初次只读回查的最新构建仍为 2.0.0 (12),Build ID 315742ed-3c67-48d3-907b-ed88dad320d4,状态 VALID / INTERNAL_ONLY / IN_BETA_TESTING,外部 NOT_APPLICABLE,仅关联既有内部测试组。当时观察到的下一构建号为 13;后续 Xcode 本地导出已自动生成构建 13 的分析会话,详见本页最终收尾记录。没有调用 App 二进制上传或组分发操作。

已从本地候选提交 e988475ffe3f9059049c3336088a26da55ee640b 准备 2.0.0 (13) 的 Release 归档、dSYM 与仅内部测试 IPA;相对上述 main 仅修改工程版本来源的构建号,产品代码和数据不变。IPA SHA-256 为 6787dd0dc9733d641a91f36c357f7429de3295b9a6e097591b8ed08203749886。分发签名、描述文件、关闭调试权限、Production 权限及隐私清单已通过共享验包脚本;正式反馈/AI 地址、关闭的会员入口/购买开关和 dSYM UUID 已逐项核对。从实际 IPA 内置文件重建的完整公共契约与生产当前词典一致,数据版本 1878cc5772dc、877 道菜、饮食标注 ead74d1c15c9。同一散列的 IPA 已通过 Apple altool --validate-app,结果为无错误;此操作没有上传 TestFlight。

首次归档因 Swift Package 资源目标缺少开发团队失败;补齐全局 DEVELOPMENT_TEAM 参数后归档、导出成功,没有修改产品源码或新建签名资源。原始失败记录保留。本地版本分支尚未推送或合入 main,候选包未上传、安装或分发;后续须重新核对构建号占用、完成候选审阅及人工验收,并按实际授权执行分发,不能把验包成功称为 S4 通过。候选包、源码副本与签名证据位于 ~/Library/Developer/ReleaseArtifacts/Cook/20261107-issue-181-candidate-13。

设备盘点实际发现一台可连接的 iPhone 15 Pro/iOS 27.0.1,已配对、开发者模式开启、无线隧道连通。其已安装 App 为 fun.yunle.cook / 2.0.0 (12);仅核对安装清单,不据版本号推定该安装包与归档逐字相同。VoiceOver 查询为关闭。查看画面时设备正在其他使用中,本次没有接管手机、启用 VoiceOver、更改网络或覆盖现有 App;本轮未发现可用的实体 iPad。本机有效签名身份及 Cook 开发/分发描述文件已盘点,但签名资源存在不代表新包已构建或验收。

本次进程环境未提供个人 DeepSeek Key,手机内 Key 是否可用尚待持有人在 App 内确认;没有提取手机钥匙串或使用服务端 Key 冒充个人路径。源码仍使用不可同步、仅解锁可用且限本机的 Keychain 条目;普通设置仅保存通道选择。这是源码核对,不能替代个人 Key 真机真实调用与故障恢复。

新增人工验收步骤与待填记录,并校正 #174 共用人工清单中已过时的入口、目标与标注版本。真实 VoiceOver、个人 Key、断网/失败恢复及同一新版候选使用均未执行,S4 和 #181 继续开放;维护者内容复核、会员购买/恢复及其已知 UI 超时不由本轮结论覆盖。

验证复用 #197 的 38 项 Node、14 项 Swift 核心及 iPhone/iPad 各 46 项 App+4 条 UI 成功记录,只用于上述源码/数据等价范围。此次仅修改验收文档,不重复运行原生矩阵或新增 mock。脱敏生产回读、源码对比清单、设备/ASC 摘要与清理记录保存在本机 ~/Library/Developer/ReleaseArtifacts/Cook/20261107-issue-181-readiness;原始失败、取消及线上回退证据仍在 11 月 6 日目录,未改动。

2026-11-06 契约与发布验收收尾 ​

本轮按维护者要求先完成无需真机的部分,修复 PR #197。实际 VoiceOver 朗读和个人 Key 真机调用继续待验收,S4 与 issue 保持开放;本轮没有上传新的 TestFlight。

生产服务及已分发 TestFlight 构建 12 使用 faf919fc0041,当前 App 测试产物内置 1878cc5772dc。使用现有受管会员测试身份,已在线复现当前版本解析返回 409 VERSION_MISMATCH。服务新增已分发契约快照,按请求三项版本精确选择词典、模型提示词及输出校验;保留旧版边界,不把新版食材或控制体重目标发给旧客户端。

代码提交 0889d1497a7cf50f8ab67860e7ff1e962b30c485 已通过生产单函数代码更新发布,回读为 Active。下载后的五个源文件与提交逐字节一致,既有环境变量、运行时、超时、内存、权限及触发器等配置全部保持原值。当前实际通道为 CloudBase 托管 deepseek-v4.1-flash-1017,没有切换通道。当前和旧版各一次真实解析均为 HTTP 200,前者准确返回鸡蛋、不吃辣和控制体重,后者不包含新增目标;未知版本仍为 409,未登录/无效令牌为 401,GET 为 405。所有本轮测试登录会话已注销。

首次 MCP 更新返回请求已接收,但最终状态为 UpdateFailed / ResourceNotFound.Package,旧代码仍可用。当前所连工具强制启用云端依赖安装,与本函数预打包依赖的发布方式不符;核对本机工具实现及仓库既有处理记录后,改用现有 CLI 的单函数代码更新,显式保留 installDependency=false。没有将首次接收回执记为发布成功,也没有修改其他服务配置。

验证与剩余范围:

  • 服务与契约:38 项 Node 测试通过,覆盖两个版本分别选择词典、旧版拒绝新增目标/食材、历史快照不可变、损坏或歧义配置关闭服务、未知版本在预留额度前拒绝及两种模型通道。
  • 原生核心:14 项契约与意图解析测试通过,完整公共词典、版本和已审核目标与当前 App 数据一致。
  • iPhone 16 Pro/iOS 26.5:46 项 App 测试、4 条智能找菜 UI 流程全部通过,0 失败、0 跳过。覆盖编辑/取消/应用、最大字号深色、设置往返、文本改写及旧预览失效;已核对原始截图。
  • iPad Pro 13-inch (M5)/iOS 27.0:原运行 47 项通过,1 项因取消而失败,未形成完整通过结果。日志反复记录每次 60 秒的 App animations complete notification not received,与仓库已记录的输入法相关现象相同;当前键盘为简体拼音,尚未据此确定唯一系统或产品根因。工具等待到期后确认原进程状态并停止测试,保留结果包、日志及截图,设备恢复 Shutdown。
  • 共享 iPad Pro 11-inch (M5)/iOS 27.0 已有 English (US) 键盘状态,使用相同测试产品、中文输入和全部原有断言复验:46 项 App 测试、4 条智能找菜 UI 流程全部通过,0 失败、0 跳过,耗时 214.6 秒,未出现每步 60 秒的动画等待。已核对普通字号浅色与最大辅助字号深色原始截图;不以原运行的局部通过替代完整结果。
  • iPhone/iPad 各出现两条 Invalid frame dimension (negative or non-finite) 运行时警告,截图与对应操作断言通过;警告保留,未断言其唯一根因或将其删除。本轮未修改原生产品或测试源码。
  • 隐私数据流已对照原生两条请求适配器、服务端及政策复核:个人 Key 直连;会员使用既有登录令牌,模型请求不携带该令牌或个人 Key;原始输入/响应不进入应用持久化、配额记录或应用日志。第三方平台处理以其政策为准。

仍需单独完成:实际 VoiceOver 焦点顺序、完整朗读和移除动作;个人 Key 真机真实调用;对应新 App 候选的分发及真机使用。会员 HTTP 实际调用、注入传输测试和模拟器不能替代这些项目。

脱敏证据摘要记录源码、版本、部署文件散列、线上状态及各轮测试范围。必要日志、摘要、截图与服务回退源码保存在本机 ~/Library/Developer/ReleaseArtifacts/Cook/20261106-issue-181-contract;本轮使用的三台设备均恢复最初 Shutdown 状态,没有新增、克隆或清空设备。

实施与验收边界 ​

已实现本地意图契约、可编辑预览、原生搜索、AI 设置与本机 Keychain,并于 2026-10-29 接通会员服务。请求适配器按官方 Chat Completions 接口与 JSON Output 说明使用 deepseek-flash、关闭思考、JSON 输出、2048 token 上限。个人 Key 路径保留模拟验收记录;会员服务已使用既有受管会员测试身份完成真实线上联调,见会员接入。

内置服务通过云乐坊核验当前账号和会员,再执行原子限流、请求预算及模型调用。登录成功不能替代会员验证;原生端只有取得有效服务能力响应后才能启用,退出或切换账号会关闭对应路径,资格缓存到期会阻止新请求并要求重新核验。会员资格在每次模型请求时仍重新核验。

S0 意图契约 ​

SearchIntent 表达一次请求的解析草稿,不是推荐结果或可执行命令。模型和本地适配器使用同一契约,进入预览前先校验,确认应用前再次按当前数据与政策校验。

当前格式为 { schemaVersion: 1, dataVersion, policyVersion: 1, source, query, goal?, unresolved }。dataVersion 必须等于当前加载的菜谱数据版本,source 仅接受 local、mock、deepseek,且必须与本次适配器匹配。goal 为单个 DietaryGoal 的原始值或空值;unresolved 为字符串数组。

内容约束与现有实现的关系
食材、忌口、厨具、不吃辣、难度、做法复用 CookQuery 的 stuff、avoid、tool、noSpicy、difficulty、methodGroups 语义;名称来自公共词典,别名规范到标准名
可选饮食目标最多一个,只接受当前 DietaryCatalog.availableGoals 中的目标;枚举存在不等于当前开放
待确认诉求模糊表达、词典外食材、冲突、未支持目标与无法核实的条件需显示给用户,不默默转成其他条件
解析来源区分本地与模型;mock 仅用于测试,不能成为线上 AI 状态
版本携带意图格式、菜谱数据与政策版本;旧响应不能绕过当前词典和目标门槛

根对象和嵌套 query 的未知字段、非法类型、词典外的标准值、不支持的版本、无效或未开放目标应拒绝;不能把部分非法响应当作成功条件应用。query 中的数组与 noSpicy 必填,tool 可选,unknown 必须为空;数组不得重复,stuff 与 avoid 不得交叉。输入最多 1000 字,响应 JSON 最多 32 KiB,每类条件最多 100 项,unresolved 最多 20 条不重复的非空文本,每条最多 500 字。模型输出不得包含最终菜谱 ID、新菜谱、热量、糖量、烹饪时间、账号状态、服务权限或自动执行指令。

普通词表搜索已有的 CookQuery.unknown 行为继续保留;智能草稿中的未知食材进入待确认项,不能通过模型输出直接扩展公共词典。无论来源如何,忌口优先于「有这个食材」,不会因模型建议静默放宽已有忌口。

草稿、确认与候选 ​

  1. 普通输入继续本地解析。用户主动进入条件预览时,先从本地规则生成草稿;只有显式选择智能找菜才有资格发起模型请求。 原生搜索框输入后,点击建议中的「预览找菜条件」进入草稿;直接回车仍沿用原有个人词典和词典外食材逻辑。呈现预览期间保留搜索建议的状态,关闭弹层后再清空搜索框和结束搜索,避免同时移除建议按钮与呈现弹层造成生命周期竞争;普通提交有草稿存在时不会写入条件。
  2. 预览独立保存,不改 CookSession、SwiftData 或饮食目标本机记忆。标签可以移除或修改,待确认项单独列出;不把它们描述成已生效筛选。
  3. 用户确认后,将已验证条件交给现有会话逻辑。忌口和不吃辣沿用既有显式设置的持久化方式;目标记忆仍由用户控制,不在识别时自动开启。
  4. 首版只检索内置菜谱。目标候选必须通过当前 DietaryCatalog 的数据指纹、原文锚点及目标状态校验;再与食材、忌口、厨具、做法等条件求交集,结果保留核对理由与实际做法来源。
  5. 「控制体重」遵守既有开放门槛;痘痘、孕期、生酮、疾病饮食等不支持诉求进入说明或待确认项,不替换成已经开放的目标。无候选时显示无结果,不扩大目标池。

失败与请求状态 ​

状态行为
空输入或超长输入提示修正,不发模型请求,不改当前选择
本地识别不完整展示可确认部分和待确认项,允许编辑或返回普通搜索
无 Key、服务未配置、会员状态未知或过期内置服务或对应模型路径不可用,本地识别可继续
离线、超时或网络失败保留当前选择和本地草稿,允许重试或继续本地解析
用户取消取消当前请求,不把取消展示为模型识别成功
新输入或新请求取代旧请求取消旧请求,并用请求身份隔离响应;即使取消后返回也不能覆盖新草稿
未知、非法或版本过期的响应拒绝应用,显示可恢复错误,不执行模型给出的操作
用户确认前数据或政策更新重新校验;失效条件不能进入会话

失败与取消均不能清除原食材、忌口、目标或偏好。重试需要用户操作;模型不可用不阻塞本地做菜流程。

模型与设置 ​

自带 DeepSeek API Key ​

设置提供模型总开关及自带 Key 的保存、替换与删除。Key 使用独立的 Keychain 项,设置 kSecAttrSynchronizable = false、kSecAttrAccessibleWhenUnlockedThisDeviceOnly;不写 UserDefaults、SwiftData、CloudKit、导入导出或日志,也不附在 URL 中。页面不回显已保存的完整 Key,测试使用内存存储,不触碰用户凭据。

数据流为「用户显式选择智能找菜 → 客户端携带个人 Key 请求 DeepSeek → 严格校验响应 → 可编辑草稿 → 用户确认 → 本地检索」。仅发送本次文本,以及解析所需的公共词典、当前可用目标和数据/政策版本。不会上传偏好、冰箱、私人菜谱、收藏、历史、账号资料或云乐坊会话。调用使用用户个人 DeepSeek 账户额度,不要求云乐坊会员。

请求使用固定 HTTPS 服务地址,不允许模型指定 URL 或变更目标服务;网络会话不共享 Cookie、不缓存请求或响应、不跟随携带凭据的重定向。超时、取消及迟到响应遵守上面的状态约束。开启功能与保存 Key 本身不等于同意后台调用,只有用户的显式模型操作才发送本次文本。

内置 DeepSeek:S2 服务端契约 ​

内置服务仅供有效云乐坊会员。设置区分未登录、非会员、过期、服务不可用和资格待刷新;自带 Key 为独立路径,不通过内置服务转发个人 Key。

服务端约束与验证如下,实际线上与注入验收范围见会员接入:

  • 从已验证会话确定非匿名 UID,检查账号可用状态;不接受客户端指定受益 UID 或 isMember。
  • 在线读取平台会员有效状态及到期时间;缺失、过期、未知或读取失败均拒绝内置模型调用。现有平台账户服务 account-api.getAccount 返回 { coin, membership: { isActive, level, expireAt } };本次转发已验证用户的同一短期令牌,不给 App 或模型额外的内部服务凭据。
  • 在调用模型前执行按身份的限流、输入大小限制、并发控制与服务预算检查。未配置预算、无法确认剩余额度、达到限制或上游异常时关闭该请求,不绕过校验直接调用。
  • 平台模型 Key 只存在服务端。模型路由可替换;响应只给意图草稿及必要状态,不给客户端服务凭据或模型执行权限。
  • 默认不保存原始饮食文本、待确认健康诉求或模型原始响应。日志与统计仅记录有限状态、耗时等诊断值,不记录文本、Key、token、账号资料或可还原用户诉求的数据。
  • 同步更新实际对外数据流说明,并验收未登录、非会员、过期会员、会员失效、限流、预算耗尽及错误响应;前端限制不能代替服务端检查。

确认时做法和难度与当前选择取交集。新旧厨具、目标或做法/难度存在无法表达的冲突时,先提示用户修改,不写入任何条件,不能用空数组表示冲突后扩大成“不限”。模型遗漏本地已识别的食材、忌口、不辣、厨具、目标、做法和难度时保留本地约束;不同的目标或厨具拒绝响应。

分期与验证清单 ​

下列为验收要求,未勾选表示仍需验证或后续实施;源码存在不等于全部验收完成。

  • S0:冻结意图字段、失败状态与人工确定预期的样本,说明与 CookQuery、当前可用目标及版本的关系。
  • S1:本地适配器、严格校验、可编辑草稿;用注入的 mock 独立验收,不依赖真实账号或 Key。
  • S2:会员鉴权、限流、请求预算及服务端适配器已部署,通过既有受管会员的真实会话完成正向调用;个人 Key 路径的真实设备验证仍单独记录。
  • S3:iOS 原生搜索接入预览、确认、加载、取消、重试与本地回退;新请求取代旧请求,过期响应不能写当前条件。请求状态通过注入的服务验收,真实账号调用仍见 S2 限制。
  • S4:否定词、别名、模糊表达、未开放目标、非法响应、版本变化、超时、取消和迟到响应回归;完成 iPhone/iPad、深浅色、大字号、VoiceOver 与隐私数据流验收。

人工确定的首批样本如下;目标预期随当前目标门槛检查,不能因样本存在而开启未开放目标。实际可执行用例与结果由测试记录补充,不能从待测解析器自动生成预期。

输入或响应人工预期
有鸡蛋和西葫芦,不要辣,想减少添加糖鸡蛋、西葫芦、不吃辣;目标可用时为减少添加糖,否则目标诉求待确认
西红柿和蛋,洋葱不要番茄、鸡蛋,忌口洋葱;不把洋葱同时作为已有食材
没有鸡蛋,用电饭煲不选鸡蛋,只设置电饭煲;不推断其他食材
想控制体重仅在目标门槛通过时设置目标,否则显示待确认,不替换成其他目标
孕期生酮、痘痘饮食未支持诉求待确认,不映射为处方或其他饮食目标
有鸡蛋,鸡蛋过敏本地保留鸡蛋忌口,移除同名已有食材;模型若同时返回食材和忌口则拒绝响应
十分钟做好、低热量、糖尿病能吃无法核实的诉求待确认,不编造时间、热量或适用性
我也不知道想吃什么不自动选择食材或饮食目标,显示未识别诉求
模型包含 recipeIds、未知字段或过期版本拒绝响应,不应用任何条件

验收还需确认用户未应用草稿时会话和偏好未变化,以及应用后没有目标池外或忌口冲突菜谱。

2026-10-28 验证记录 ​

  • CookCore 全量:88 项,87 通过、0 失败、1 项既有预期跳过。包含 13 项意图契约/本地解析测试与全部 877 道菜谱的共享用例。跳过的私人菜谱实时编码往返需独立脚本,与本改动无关。
  • 原生单元测试:29 项通过,包括 6 项 AI 设置、10 项 DeepSeek 适配器、6 项草稿与确认、7 项饮食目标会话回归。覆盖不提前写偏好、确认后来源池限制、现有条件交集、迟到响应拒绝、错误/取消/超时/断网、响应截断、错误目标及密钥不进入请求正文或本机普通设置。
  • iOS 27.0 的现有 iPhone 18 Pro 与 iPad Pro 13-inch (M5) 模拟器分别通过标准字号浅色的编辑/取消/确认,以及最大辅助字号深色的待确认条件/设置入口测试。深色通过仅 Debug UI 测试生效的外观配置固定,已检查实际截图,未改变设备的系统外观。
  • 首次 UI 回归发现搜索建议关闭时再次提交的行为,已修复。大字号场景改用弹层内的小幅拖动定位,避免整屏滑动越过标签;未删除断言或禁用应用动画。iPhone 一次运行出现系统动画空闲通知等待,随后按原断言完成;iPad 测试正常完成。没有新增、克隆或清空模拟器。
  • 内置会员服务尚未接通;没有真实 DeepSeek Key/真实调用验收记录。VoiceOver 实际朗读及发布后的数据流验收仍未完成。

2026-10-29 主分支集成与原生交互收尾 ​

基于 PR #183 的实现整合已合并 #175/#180 的主分支 d2bde74,保留原生 SwiftUI 搜索、表单、导航和确认交互。条件预览现在可直接进入 AI 设置;返回时继续编辑原草稿。目标标签复用共享图标和目标配色,名称完整换行,不截断窄屏文字。模型请求中保留表单内的原生取消按钮,取消或改写输入会使在途响应失效;重新本地识别会取消模型请求并重新生成草稿。等待期间仅禁用条件编辑和应用,仍允许取消、改写文本或切换到本地识别,不再用覆盖表单的悬浮按钮。

确认草稿继续与当前条件取交集,并保留结果页已有的菜名关键词。新增回归先在旧实现上复现:仅匹配“清炒花菜”的条件被清空关键词后扩大为 12 道;修复后保留原关键词及同一候选范围。另补充新请求替换旧请求后,迟到成功与迟到失败都不得覆盖新草稿的验证。传输层返回取消时保留本地条件,不把取消显示为失败。

本轮验证:

  • 原生 CookTests 最终 185 项通过,0 失败、0 跳过,包含关键词保留、替换请求的迟到成功/失败隔离和传输层取消三项新增回归。
  • CookCore 全量 89 项中 88 项通过、1 项既有预期跳过;未改变推荐规则或来源校验。
  • 27 项 Node 契约、服务注入和 CI 基础设施回放测试通过;生成的会员服务词典与当前公共数据一致。
  • iPhone 15 Pro/iPad Pro 11-inch (M5),均为共享 iOS 27.0 设备:标准浅色编辑/取消/应用、最大辅助字号深色待确认/设置、预览内设置往返和改写输入两端各 3 条流程通过(共 6 条),0 失败、0 跳过。复用已编译的同一份 xctestrun,显式关闭并行测试,不新增、克隆或清空设备;大号 iPad 正用于其他任务,保持原状。

本轮未执行真实模型计费调用或重新部署会员服务。此前线上会员联调与 TestFlight 记录保留;实际 VoiceOver 朗读、个人 Key 真机调用及最终集成完整 CI 仍需分别核对,不将自动化通过写成全部发布验收完成。

首轮新增 UI 用例误将 SwiftUI 输入控件限定为 TextView,两端定位失败;改用稳定的可访问性标识后,全部原有断言及新流程在两端通过。截图复核发现新目标标签在窄屏截断,改为图标与完整名称垂直排列后重新验收。中途被新版取代的 iPad 运行主动取消并保留记录,不计为通过;最终原始截图已人工核对。

2026-10-29 标签交互与合并验收 ​

已识别条件统一为原生横向胶囊按钮,使用随字号缩放的自适应列宽;标准字号下“减少添加糖”与相邻标签同高且完整单行显示。食材复用公共词典的 emoji,忌口、厨具、做法与难度使用类别图标,目标继续复用统一目标图标与配色。末尾的移除标记表示编辑本次草稿,原生按钮的可访问性名称保留完整条件含义。辅助大字号允许完整换行,不缩小用户字号。

历史完整 CI #634 仍按失败保留:iPad 最大字号的五项审计通过后,记忆开关在一次默认短点击后仍为 0;业务断言被正常阻断,没有进入基础设施复验。已核对原始触摸事件、截图及结果包;落点位于可见开关内,同一完整用例在本地未改动时通过,未确认唯一产品或系统根因。后续整合 c7e4b5b 的原生记忆按钮修正:整行可点击,直接绑定原有会话状态,以选中态和“已记住”值验证真实结果;保留显式开启、本机记忆及全部业务流程和审计。结果滚动只作用于可见菜谱列表,防止拖动弹层。此前单次按压的定向诊断不作为当前实现或完整 CI 通过证明。

标签调整沿用现有原生表单和网格,不修改意图契约、推荐规则或平台服务。局部 UI 试验暴露的可访问性容器包装已移除,保留真正按钮及其动作名称;原始截图与层级用于核对。合并前要求最终候选完整 CI 全部通过,本地定向记录不能替代这道门禁;当前完整验收状态由 PR #183 的最新检查与说明跟踪。

完整 CI #638 的 22 项饮食审计及记忆按钮均通过,但 iPhone 的来源浏览/最大字号流程和 iPad 最大字号的结果滚动仍失败,按业务失败保留,分类器没有允许重试。本机以同一条来源浏览用例复现:5 次自定义拖动后目标菜谱仍未进入视口。录像与手势记录表明,每次仅拖动列表可见高度的 20%,原有次数不足以越过长列表;iPad 另在自定义拖动反复解析列表坐标时出现查询超时,未将其归为已确认的同一系统根因。

收尾改用限定在 dietary.results 原生列表内的 swipeUp(velocity: .slow),由 XCTest 选择完整上滑范围,不再在手势中反复计算列表锚点。保留原有 5/25 次上限、列表存在性/可见性检查,以及实际点击目标菜谱、核对来源、记忆状态和随机推荐的全部断言。iPhone 15 Pro 的同一失败用例与最大字号完整流程,以及 iPad Pro 13-inch (M5) 的最大字号完整流程均通过;两个最大字号流程各保留五项审计。使用现有 iOS 27.0 共享设备和串行测试,没有新增、清空或克隆设备。下一候选完整 CI 结果继续由 PR 最新检查跟踪,不能用本地定向通过替代。

完整 CI #641 已解决此前的滚动距离失败:两端常规流程、标准审计与 iPad 最大字号流程均通过,22 项审计通过。唯一失败为 iPhone 最大字号首次上滑后,对整个应用 descendants(matching: .any) 查询 dietary.results 超时。应用日志记录 10:53:59 接收查询、10:54:37 返回匹配,已超过客户端查询期限;未发现同段日志中的布局循环或约束错误,不将其直接写成已确认的产品卡死。同一 iPhone 18 Pro/iOS 27.0 的本地完整流程通过,说明现象尚未稳定复现。

结果列表在本轮全部原始层级中均为原生 CollectionView,查询改为 app.collectionViews.matching(identifier: "dietary.results").firstMatch,只收窄控件类型,不移除列表存在性/可见性检查、手势、目标点击或后续来源与随机推荐断言,也不放宽 CI 重试分类。该改动仍需以新的完整 CI 结果验证;本地重复验证是额外证据,不能代替最终门禁。

本地定向复核:共享 iPhone 18 Pro/iOS 27.0 的最大字号完整流程在三个独立测试宿主中均通过,共 15 次审计通过;共享 iPad Pro 11-inch (M5)/iOS 27.0 的同一完整流程及五项审计通过。大号 iPad 正由其他任务使用,未抢占设备。没有新增、克隆或清空模拟器。

2026-10-29 紧凑标签与点击区域 ​

已识别条件改用自然内容宽度的原生 SwiftUI Layout 换行排列,标签之间保留 8pt 间距。标准字号的胶囊背景最小高度为 36pt,图标以 .subheadline 为基准从 16pt 随系统字号缩放;文字继续使用 .subheadline,不缩小用户字体。长名称先整体换行,最大辅助字号下允许标签内部增高和文字换行。目标图标、语义配色和完整的移除动作名称保持一致。

背景之外的整块原生按钮区域至少为 44 × 44pt,点击区域互不重叠,末尾叉号不成为独立的小按钮;按下及禁用状态均有反馈。UI 回归直接检查四类预览标签的可访问性矩形,并点击 36pt 背景之外、44pt 区域以内的透明边缘,验证西葫芦条件实际移除。尺寸比较仅容许坐标转换中的 0.001pt 浮点误差,控件本身仍声明至少 44pt。

共享 iPhone 15 Pro/iOS 27.0 的三条流程全部通过:编辑/取消/应用、最大辅助字号深色待确认与设置、预览内设置往返与改写输入。四个标准字号标签的实测区域高度均为 44pt,透明边缘点击有效;标准字号和最大字号深色原始截图已核对。首轮仅因 43.99999999999994 与 44 的数值比较失败,原始结果按失败保留,后续通过不覆盖该记录。iPad 复核期间电脑重启,进程及临时结果中断,该次不计为通过或产品断言失败;复用同一共享设备补跑,不新建、克隆或清空模拟器。

iPad 的标准字号(含四个 44pt 矩形及透明边缘移除)和最大辅助字号深色流程均通过,实际截图已核对。设置返回后改写输入的首轮失败按原结果保留:层级与录像显示,原计划追加的“,番茄”实际插入到了开头,文本成为“,番茄鸡蛋,不要辣”;同段键盘切换也改变了浮动表单的位置,触摸与原始层级已保存。没有将该失败归为已确认的唯一系统根因。

测试输入准备改为按原生 TextField 类型定位,先检查原文本,点击已有文字右侧后输入,并断言完整文本确为“鸡蛋,不要辣,番茄”。在提供原生“隐藏键盘”按钮的设备上,先收起键盘并验证其消失,再确认重新识别按钮完整可见后点击。保留新增番茄标签、改写使旧预览失效、取消后原选择不变等全部断言;不是对原失败的无条件复验。补齐这些前提后,共享 iPad 和 iPhone 的同一流程分别通过。最终仍要求新候选的完整 CI 通过。

完整 CI #649 的原生结果为 437 项通过、2 项原始失败:iPad 标准审计在测试开始前遇到既有的 runner-bootstrap-stall,按现有分类有界复验成功,原失败仍保留;最终四条饮食审计通过。阻断合并的是 iPad 设置返回、改写输入并重新识别后未出现番茄标签。该次完整文本与键盘消失检查均通过,iPhone 同一流程及两端标准/最大字号标签流程也通过。

已核对失败用例的原始合成触摸、最终层级与相邻录屏:默认合成触摸为 (516, 520.5);键盘收起前后浮动表单的位置发生变化,失败结束时按钮矩形为 x=242, y=535, width=548, height=52。录屏与原生事件没有精确同步,不能据最终矩形确定接触瞬间是否偏离按钮。自动附带快照仍含改写前的旧文本,不能只凭附件时间戳将其认定为点击瞬间的最新几何。重新识别交互改为在完整可见性检查之后,按按钮当前矩形中心生成实际坐标点击,保留原有全部识别结果及取消后状态断言。同款共享 iPad Pro 13-inch (M5)/iOS 27.0 的修正用例通过;未修改的本地对照也通过,说明原始 CI 偏差尚未在本地稳定复现,不推定唯一底层系统原因。最终仍由新候选的完整 CI 决定是否合并。

为核对修正后的真实落点,仅在独立的本地 xctestrun 副本中将系统附件保留设为 keepAlways,测试行为和断言保持一致。该次流程通过;原始合成触摸为 (516, 359.75),坐标锚点偏移为 (274, 26.25),结合相邻录屏确认落在当时的重新识别行内,随后实际出现番茄标签。普通运行配置未改动,原始失败与快照复用的限制均保留。

CI #652 在新增验证记录的双花括号坐标处触发 VitePress/Vue 插值编译错误,Web 验收因构建依赖未通过而失败。坐标改用普通字段表述;整合后的生产文档构建与该页面生成已通过,原始构建错误和录屏时序限制继续保留。该文档修正不改变原生交互、断言或重试策略,合并仍以新候选完整 CI 为准。

2026-10-30 明确结束预览输入焦点 ​

完整 CI #653 保留为失败:iPad 设置往返后的重新识别未出现番茄、iPhone 云厨房旋转后的锅位置断言超时,以及 iPad 标准审计在结果列表滚动后的层级查询超时。未重跑该失败任务,也未修改业务断言、审计范围或基础设施重试分类。

这轮 iPad 的原始触摸仍为 (516, 520.5)。录屏与最终层级显示,系统“隐藏键盘”后文本框仍有焦点,后续交互期间浮动表单发生竖直位移;仅按元素中心生成坐标仍不足以保证落在移动后的按钮内。失败结束时重新识别行中心为 (516, 561)。这些证据不能证明解析器丢失了结果,也没有据此改动草稿状态模型。

预览文本框现在绑定原生 FocusState,仅在本框获得焦点时显示键盘工具栏“完成”按钮。用户可明确结束输入,再重新识别;该工具栏不由后续设置页面的输入框继承。UI 流程通过这一真实按钮结束输入,检查工具栏与键盘消失、完整输入仍使旧预览失效,再点击可见的重新识别行。保留番茄必须出现、取消不写入当前筛选等全部断言,并保存点击前的原始截图。首轮 iPad 本地验证中,点击前截图的输入正确且无光标,合成触摸 (516, 561.25) 落在可见行中,随后番茄出现。

云厨房和列表超时的原始结果独立保留,不以本地通过改写 CI 失败。列表采样期间应用主线程处于运行循环等待,尚未确认唯一的产品或系统根因;没有增加超时或放宽重试条件。最终候选必须重新通过完整 CI,具体检查与本地验收边界继续由 PR #183 跟踪。

最终本地验证:共享 iPhone 16 Pro/iOS 26.5 的三条智能找菜流程通过;共享 iPad Pro 13-inch (M5)/iOS 27.0 的同三条流程和未修改的旋转用例通过。iPad 标准目标完整流程另在独立宿主通过,包含六类无障碍审计、结果滚动、实际打开来源、记忆状态与随机推荐。四张标准/最大字号深色预览已核对,44pt 区域与透明边缘移除断言保持有效。全部使用既有设备并关闭并行,结束后恢复本轮初始 Shutdown。较早的未限定焦点工具栏原型在大字号关闭时等待动画,被最终版本取代后主动停止,不计为完整通过;最终限定焦点版本三条流程均通过。

PR #185 整合限定焦点的最终实现后,补充两项直接覆盖:原输入仍聚焦时进入 AI 设置,在个人 Key 框输入单个测试字符但不保存,确认原预览的“完成”工具栏未被设置框继承,再返回改写和重新识别;另在最大辅助字号深色下实际输入、点击“完成”、重新识别并取消。设置 Form 增加唯一可访问性标识,仅用于限定原生查询;没有保存个人 Key、切换服务或发送模型请求。

定向验收复用共享 iPad Pro 11-inch (M5)/iOS 27.0 和 iPhone 16 Pro/iOS 26.5。iPad 设置往返流程通过;首轮新增最大字号流程已正确取消弹层,但主页面的单列懒加载食材网格尚未显示鸡蛋,原全应用等待失败,原始结果、录像、层级及冻结源码均保留。只为该新大字号场景补齐 cook.chooser 内的有界原生滚动,分别检查番茄与鸡蛋可点击且未选中,不点击或清空选择;普通字号取消后的三条原断言保持不变。修正后 iPad 大字号流程通过,iPhone 两项流程在同一最终测试源码下均通过。合计四项目标场景得到通过证据,另保留一项首轮失败,不将不同源码的结果拼称同一完整绿色测试包。

所有本地测试关闭并行,两台设备均恢复本轮初始 Shutdown。首轮 iPad 的测试已结束后,额外系统诊断收集器等待较久,核对进程归属后仅停止该收集器;测试包正常封口,原失败没有删除,额外系统诊断可能不完整。改动后的完整 CI 仍须独立通过;本地定向结果不替代最新候选的合并门禁,也不构成实际 VoiceOver 或个人 Key 真机调用验收。