pstack Feature Verification Map 实战指南:为 Agent 冷启动编写可执行的用户视角验证地图
2026/9/17 15:27:55 网站建设 项目流程

pstack Feature Verification Map 实战指南:为 Agent 冷启动编写可执行的用户视角验证地图

【免费下载链接】pluginsCursor plugin specification and official plugins项目地址: https://gitcode.com/GitHub_Trending/plugins125/plugins

导读

本文以 pstack 插件中create-verification-skill技能自带的 Feature Verification Map(特性验证地图)示例为骨架,完整讲解"如何为你的应用编写一份让 AI Agent 能够冷启动驱动的验证地图"。你将掌握验证地图的目录组织方式、基线前置条件(Baseline Preconditions)、驱动约定(Driving Conventions)、证据与跳过报告标准(Proof and Skip Reporting),以及每个特性文件的四段式结构约定(Feature Entry Contract),并看到 Notes 应用完整的create-note.mdsearch.md实战示例。读完即可为自己的项目生成同规格的验证地图。


1. 什么是 Feature Verification Map,它解决什么问题

在 pstack 的工程理念里,"可验证"是交付的前提,对应其核心原则之一prove-it-works(对真实产物验证,而不是对代理结果或"能编译"自欺欺人)。但"验证"存在一个现实矛盾:验证脚本往往写得像写给人类的测试文档,充满了 CSS 选择器、坐标和隐式假设,一旦换一个从未见过该应用的 Agent 来执行,就会在中途迷路。

Feature Verification Map 正是为此而生的产物。它由create-verification-skill技能在生成项目本地验证技能时同步创建,其定位是:

This directory is the maintained source for verifying the user-facing behavior of Notes. Read the index before driving the app, then use the matching feature file as the recipe.

也就是说,验证地图目录是"验证用户可见行为的权威维护源"。先读索引(README),再按匹配的特性文件当作菜谱执行。它刻意把实现细节排除在外部("Keep implementation details out of the map"),只保留用户路径、稳定句柄、所需状态、命令和可观察证据——因为它的读者不是人类 QA,而是任务中途、对应用一无所知、需要"冷读取"的 Agent。

参考示例位于 pstack/skills/create-verification-skill/references/feature-map-example/,共三个文件:

  • README.md—— 地图索引与全局约定(本文主题);
  • create-note.md—— 特性"创建笔记"的完整验证配方;
  • search.md—— 特性"搜索笔记"的完整验证配方。

create-verification-skill的 SKILL.md 中,生成流程第 3 步"Seed the feature map"明确要求:创建.cursor/skills/verify-<app>/features/README.md加每个用户可见特性一个文件(起步建议 3~5 个),并严格遵循本示例目录的形状。而maintain-verification-skill则把这份地图当作后续维护的唯一事实源——应用一变,地图就会"腐烂",需要定期以特性为单位做源审查 + 一次实机驱动的校正循环。


2. 地图索引 README:全局约定的四大部分

feature-map-example/README.md把全局规则收敛为四个部分,任何特性文件都必须在这份框架内书写。

2.1 Baseline preconditions(基线前置条件)

每次验证运行都必须从同一个可复现的起点出发,否则证据不可比、并发会互相污染。示例给出的基线是:

  • http://127.0.0.1:4173启动 Notes,并使用一次性数据目录;
  • 设置NOTES_DATA_DIR=/tmp/notes-verify-$RUN_ID,使并发运行之间不共享状态;
  • 预置标题为Quarterly planGrocery list的种子笔记;
  • control-notesnotesCLI 加入PATH
  • 运行control-notes doctor,要求返回预期的 URL、数据目录和构建版本号;
  • 绝不去驱动一个不是本次验证运行启动的实例

这里有几个值得注意的设计意图:

  1. 状态隔离是第一优先$RUN_ID式的临时目录保证多次并行验证互不踩踏,对应 pstack 原则里的 make-operations-idempotent(无论先前部分运行如何,都收敛到同一终态)。
  2. doctor 是入场安检。在create-verification-skill生成的技能结构中,Doctor 是唯一一个只读检查,回答"这个实例值不值得驱动"——进程在不在、版本/构建对不对、端口是否归我们、鉴权是否有效。基线前置条件要求先跑 doctor,正是把这条规则下沉为每次运行的强制第一步。
  3. "只驱动自己启动的实例"是硬性安全线。从源码结构看,这与control-ui的 guardrails(不要使用来自其他仓库的硬编码选择器/端口)以及maintain-verification-skill中"绝不在未健康检查的实例上驱动"的不变量一脉相承。

2.2 Driving conventions(驱动约定)

约定是让所有特性文件保持风格统一、让 Agent 少踩坑的通用规矩:

  • 除非某个配方的前置条件另有说明,否则每个配方都从基线状态开始;
  • 优先使用 ARIA role 与可访问名称,而不是 CSS 选择器或 DOM 位置
  • 把每条命令当作字面量对待,引号内的名字与 flag 保持不变;
  • 浏览器操作一律通过control-notes browser执行;
  • 终端操作一律通过control-notes cli -- <command>执行;
  • 变更数据后要恢复种子数据;清理时不得移除证明产物(proof artifacts)

"优先 ARIA role 与可访问名称"这一点,与control-ui的 Setup Pattern 第 6 条完全一致:"Prefer accessibility roles, labels, and stabledata-*selectors over coordinates."。坐标点击只在紧接截图之后才被允许(control-ui的 Guardrails 第 2 条),而本地图直接将其排除在默认约定之外,因为坐标与 DOM 位置在应用改版后最容易漂移,ARIA 名称则相对稳定。

2.3 Proof and skip reporting(证据与跳过报告)

证据标准决定了"验证过"到底意味着什么。README 给出的五条标准值得逐条展开:

  • 捕获用户动作与结果状态,而不只是最终画面。例如"点击保存后出现Note saved状态",动作与状态缺一不可;
  • UI 证据包括一份 ARIA 快照 + 一张能看到应用身份的截图;
  • CLI 证据包括命令、stdout、stderr 与退出码;
  • 变更(mutation)证据要求用第二个只读视图复核存储后的值——防止"看起来保存了"其实是假象;
  • 每个证明产物都要记录对应的特性 ID 与入口点。

关于跳过(skip)报告,README 立了两条非常严格的红线:

  • 无法到达某条路径时,要报告"尝试过的命令 + 未满足的前置条件",而不是含糊地说"这功能测不了";
  • 不得把某个入口点通过另一条路径验证过就当作它被验证了

这两条红线与maintain-verification-skill的 Live pass 不变量呼应:无法到达的特性只有在给出具体前置条件(鉴权、权限、OS、外部状态)与尝试过的路径时,才能标记为verified-unreachable。证据文化也直接对应 pstack 的 show-me-your-work 思路——可审查的决策痕迹。

2.4 Feature entry contract(特性文件契约)

这是整个地图格式的核心约束。每个特性文件必须:

  1. H1 标题 + 一段描述用户可见行为的段落开头;
  2. 之后恰好四个 H2 小节,顺序固定
H2 小节内容
Sub-features列出简短 ID,每个行为一行
How to get to it (user POV)列出该特性的每一个用户入口点
Driving it with <harness>Preconditions:开头,用带标签的 bullet 把每个用户动作与精确命令、可观察结果配对
Gotchas列出会浪费或使一次验证运行失效的陷阱

最后再次强调:"Keep implementation details out of the map. Name only user paths, stable handles, required state, commands, and observable proof."(把实现细节排除在地图之外,只点名用户路径、稳定句柄、所需状态、命令与可观察证据)。

这个四段式契约的价值在于:H1+H2 结构是机器可解析的。Agent 读取特性文件时能确定性地知道"行为是什么 → 用户怎么到达 → 我怎么驱动 → 什么会坑我",这正是"让一个从未见过应用的 Agent 冷启动执行"成为可能的结构基础。


3. 特性文件实战剖析一:Create a note

create-note.md演示了一个同时覆盖浏览器与 CLI、含取消与持久化确认的完整特性配方。

3.1 Sub-features 与用户入口点

四个子特性 ID 精确描述了行为切片:

  • create-open—— 从每个浏览器入口点打开空白编辑器;
  • create-save—— 持久化标题与正文;
  • create-cancel—— 丢弃未完成的浏览器草稿;
  • create-cli—— 从终端创建同样形状的笔记。

用户视角的入口点(POV)则列出三种到达方式:

  • 点击浏览器工具栏的New note按钮;
  • 焦点不在可编辑字段内时按n键;
  • 终端运行notes create --title <title> --body <body>

注意"焦点不在可编辑字段内"这个限定——它直接预告了 Gotchas 中的第一条陷阱。

3.2 Driving it with control-notes:动作 × 命令 × 可观察结果

配方以Preconditions:开头,声明三条:Notes 健康运行在http://127.0.0.1:4173;不存在标题为Release checklist的笔记;control-notes doctor报告预期的 URL 与一次性数据目录。

随后每个带标签的 bullet 都是"用户动作 → harness 命令 → 可观察结果"三元组:

  • Open editorcontrol-notes browser click --role button --name "New note"→ 出现名为Note editor的表单,焦点在Title文本框;
  • Enter contentcontrol-notes browser fill --role textbox --name "Title" --value "Release checklist"--role textbox --name "Body" --value "Tag and publish"Save note按钮变为可用;
  • Save notecontrol-notes browser click --role button --name "Save note"→ 出现Note saved状态,标题读作Release checklist
  • Confirm persistence:依次control-notes browser click --role link --name "All notes"--role link --name "Release checklist"重开笔记 → 编辑器显示两个已保存的值;
  • Cancel draft:开新笔记、填入Discard me、点Cancel→ 笔记列表返回且没有Discard me链接;
  • CLI entrycontrol-notes cli -- notes create --title "CLI note" --body "Created from terminal" --format json→ 退出码0,stdout 含新笔记 ID 与标题;
  • Proof:重开两篇已保存笔记后,control-notes browser snapshot --aria --path artifacts/create-note/list.aria.txtcontrol-notes browser screenshot --path artifacts/create-note/list.png,产物中同时出现Release checklistCLI note

这段配方是 README 全部约定的一次完整示范:ARIA role+name 定位、动作与状态成对捕获、CLI 用--format json保证可稳定断言、证据落到artifacts/下的命名位置。

3.3 Gotchas:让验证运行免于浪费

  • 文本框聚焦时按n会输入字符而不是打开新编辑器;
  • 保存时标题会被 trim,断言应针对渲染后的标题而非草稿输入值;
  • 仅凭保存状态不足以证明持久化,必须从列表重开笔记复核;
  • 夹具清理时要移除Release checklistCLI note,但保留它们的证明产物。

第 3 条直接呼应 README 的 mutation proof 规则——"变更证据要求第二个只读视图"。这也与maintain-verification-skill中"证据必须在清理后仍存在于指定位置"的不变量一致。


4. 特性文件实战剖析二:Search notes

search.md展示了一个更复杂的交互型特性:标题/正文匹配、空态与清除态、键盘入口、CLI 双路径验证。

4.1 六个子特性与入口点

  • search-open—— 从每个支持的浏览器入口点打开搜索;
  • search-match—— 返回标题与正文匹配且不改动笔记数据;
  • search-open-result—— 在笔记编辑器中打开搜索结果;
  • search-empty—— 对无匹配查询展示完整空态;
  • search-clear—— 移除查询并恢复最近笔记视图;
  • search-cli—— 终端返回同样的匹配结果。

入口点:工具栏Search按钮;焦点不在可编辑字段时按/;终端notes search <query>

4.2 驱动配方的可观察结果设计

  • 工具栏入口与键盘入口均断言"对话框Search notes出现且焦点在搜索框",键盘入口额外断言页面没有插入斜杠字符;
  • 标题匹配:填入quarterlySearch resultsQuarterly plan且不含Grocery list双向断言,匹配与排除同时验证);
  • 正文匹配:换成budgetQuarterly plan仍可见且带正文匹配摘录;
  • 打开结果:点击Quarterly plan→ 对话框关闭、编辑器标题读作Quarterly plan
  • 空态:填入volcano→ 搜索完成后出现No matching notes状态(注意"搜索完成后",即等待具体状态而非固定 sleep);
  • 清除:点Clear search→ 搜索框为空,Recent notes区域替换结果列表;
  • CLI 命中与未命中:notes search "quarterly" --format json返回含Quarterly plan的对象数组,notes search "volcano" --format json退出码0且 stdout 为[]——未命中也要证明,且用空数组表达
  • Proof:快照与截图落盘到artifacts/search/results.*,两个产物都要能识别出 Notes、查询词与Quarterly plan

4.3 Gotchas:交互特性的专属陷阱

  • 编辑器或搜索框聚焦时按/会插入文本而不是打开搜索;
  • 结果有防抖延迟,应等待结果列表或空态出现,而不是固定 sleep(与control-cli的"prefer deterministic waits over sleeps"完全同源);
  • 归档笔记默认被排除,除非用户启用Include archived
  • CLI 默认输出是给人看的格式,稳定断言必须用--format json
  • 打开结果会改变浏览器状态,证明下一个查询前要重新打开搜索——这是状态管理层面的关键提醒。

5. 地图如何融入验证技能的生成与维护闭环

Feature Verification Map 不是孤立文档,而是create-verification-skill产出的项目本地验证技能(.cursor/skills/verify-<app>/)的第三个组成部分。生成流程共五步:

  1. Interview the repo, not the user——从代码库回答 Surface / Run / Drive / Observe / Isolate 五个问题,优先复用仓库已有的 Playwright/Cypress/expect 脚本等 harness;
  2. Generate the skill——写出带 YAML frontmatter 的SKILL.md,包含 Launch、Doctor、Drive、Evidence、Cleanup、Helpers 六个章节;
  3. Seed the feature map——即本文主角,创建features/README.md加每个特性一个文件,遵循示例目录的形状;
  4. Prove the generated skill before handing it over——端到端跑一遍自己的指令:launch → doctor → 驱动一个已映射特性 → 捕获证据 → 清理,并确认清理后证据仍在命名位置;
  5. Offer the maintenance loop——把维护职责交给/maintain-verification-skill

maintain-verification-skill则定义了这个地图的保质期管理:索引卫生(修正缺失/多余/重复/失效条目)、按特性并行的只读源审查、配方合并与漂移抽查、一次必须执行的实机 Live pass(每特性至少驱动一次,全程守住"不驱动未健康检查的实例 / 证据在清理后仍存在 / 驱动启动的东西不超出其用途寿命"三条不变量),最后以 clean / changed / blocked 三种结果之一收尾。核心取舍是:地图描述的某个行为应用不再有了,要么是文档漂移(修地图),要么是产品回归(上报,不在文档里掩盖)——这正是验证地图作为"维护的事实源"应有的地位。


6. 编写你自己的 Feature Verification Map:可复用的检查清单

综合上述内容,为任何项目(Web UI、CLI、Electron、纯服务)编写验证地图时,可按以下清单自检:

目录层(README)

  • 是否声明了可复现的基线:端口/URL、一次性数据目录、种子数据、PATH 依赖、doctor 校验项?
  • 是否用$RUN_ID式隔离保证并发运行不共享状态?
  • 是否明确"只驱动本次运行启动的实例"?
  • 是否写明驱动约定:ARIA role/name 优先、命令字面量、浏览器与 CLI 的入口封装?
  • 是否写明证据标准:UI(ARIA 快照 + 带身份截图)、CLI(命令/stdout/stderr/退出码)、mutation(第二个只读视图)、每个产物带特性 ID 与入口点?
  • 是否写明跳过报告规则:不可达路径要报命令与未满足前置条件,禁止用另一条路径冒充验证?
  • 特性清单是否链接到同目录的各个特性文件?

特性文件层(每个 feature)

  • H1 + 一段用户可见行为描述?
  • 恰好四个 H2:Sub-features/How to get to it (user POV)/Driving it with <harness>/Gotchas,顺序固定?
  • Sub-features是否每行一个短 ID、一个行为?
  • 入口点是否覆盖用户能触达的所有方式(工具栏、快捷键、CLI)?
  • 驱动段是否以Preconditions:开头,每个动作都是"用户动作 → 精确命令 → 可观察结果"?
  • 是否同时验证"出现什么"和"不出现什么"(双向断言)?
  • 是否包含持久化/副作用复核(重开、第二个视图)?
  • Gotchas是否覆盖焦点状态、格式差异(如 trim)、防抖等待、默认输出格式、状态污染?
  • 是否把实现细节排除在地图之外?

7. 结语

Feature Verification Map 把"验证"从一次性的临时脚本升级为可持续维护的工程资产。它的核心洞察是:验证配方的读者是冷的——一个任务中途、从未见过应用的 Agent。因此地图必须以机器可解析的结构(固定四段式契约)、用户视角的命名(ARIA role 与可访问名称)、字面量级精确的命令、以及"动作+状态成对"的证据标准来书写。结合 create-verification-skill 的生成流程与 maintain-verification-skill 的维护闭环,这套方法适用于任何语言、框架和平台——从 Web UI 到 CLI/TUI 再到纯服务。本文给出的 Notes 双特性示例(create-note.md、search.md)可作为直接对照的模板;对应的驱动 harness 约定可进一步参考 control-ui 与 control-cli。

【免费下载链接】pluginsCursor plugin specification and official plugins项目地址: https://gitcode.com/GitHub_Trending/plugins125/plugins

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询