@prismer/runtime 2.0.8 → 2.2.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +3430 -0
  2. package/README.md +34 -12
  3. package/apc/skills/FIELD-DICTIONARY.md +111 -0
  4. package/apc/skills/bug-reproduce/SKILL.md +150 -0
  5. package/apc/skills/bug-reproduce/skill.json +96 -0
  6. package/apc/skills/code-review/SKILL.md +198 -0
  7. package/apc/skills/code-review/skill.json +124 -0
  8. package/apc/skills/design-review/SKILL.md +122 -0
  9. package/apc/skills/design-review/skill.json +88 -0
  10. package/apc/skills/doc-sync/SKILL.md +168 -0
  11. package/apc/skills/doc-sync/skill.json +81 -0
  12. package/apc/skills/env-doctor/SKILL.md +194 -0
  13. package/apc/skills/env-doctor/skill.json +209 -0
  14. package/apc/skills/git-ops/SKILL.md +189 -0
  15. package/apc/skills/git-ops/skill.json +94 -0
  16. package/apc/skills/impact-trace/SKILL.md +168 -0
  17. package/apc/skills/impact-trace/skill.json +104 -0
  18. package/apc/skills/observability/SKILL.md +195 -0
  19. package/apc/skills/observability/skill.json +116 -0
  20. package/apc/skills/release-db-config-sync/SKILL.md +186 -0
  21. package/apc/skills/release-db-config-sync/skill.json +109 -0
  22. package/apc/skills/release-ota-promote/SKILL.md +195 -0
  23. package/apc/skills/release-ota-promote/skill.json +176 -0
  24. package/apc/skills/release-preflight/SKILL.md +174 -0
  25. package/apc/skills/release-preflight/skill.json +175 -0
  26. package/apc/skills/release-rollback/SKILL.md +214 -0
  27. package/apc/skills/release-rollback/skill.json +230 -0
  28. package/apc/skills/release-tag/SKILL.md +194 -0
  29. package/apc/skills/release-tag/skill.json +94 -0
  30. package/apc/skills/releasing-prod/SKILL.md +49 -0
  31. package/apc/skills/releasing-test/SKILL.md +135 -0
  32. package/apc/skills/sdk-release/SKILL.md +200 -0
  33. package/apc/skills/spec-intake/SKILL.md +169 -0
  34. package/apc/skills/spec-intake/skill.json +93 -0
  35. package/apc/skills/test-result-feedback/SKILL.md +239 -0
  36. package/apc/skills/test-result-feedback/skill.json +193 -0
  37. package/apc/skills/test-runner/SKILL.md +169 -0
  38. package/apc/skills/test-runner/skill.json +103 -0
  39. package/apc/skills/ui-align/SKILL.md +209 -0
  40. package/apc/skills/ui-align/skill.json +114 -0
  41. package/apc/skills/ui-canvas/SKILL.md +148 -0
  42. package/apc/skills/ui-canvas/skill.json +127 -0
  43. package/built-in-skills/agent-coordination/SKILL.md +59 -37
  44. package/built-in-skills/agent-meta/SKILL.md +1 -0
  45. package/built-in-skills/assets/SKILL.md +8 -6
  46. package/built-in-skills/browser-use/SKILL.md +93 -0
  47. package/built-in-skills/canvas-design/SKILL.md +1 -0
  48. package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
  49. package/built-in-skills/claude-api/SKILL.md +1 -0
  50. package/built-in-skills/codebase-design/DEEPENING.md +37 -0
  51. package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  52. package/built-in-skills/codebase-design/LICENSE +21 -0
  53. package/built-in-skills/codebase-design/SKILL.md +116 -0
  54. package/built-in-skills/conversation-compaction/SKILL.md +114 -0
  55. package/built-in-skills/council-creator/SKILL.md +426 -0
  56. package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
  57. package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
  58. package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  59. package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
  60. package/built-in-skills/document-generation/SKILL.md +105 -0
  61. package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
  62. package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  63. package/built-in-skills/domain-modeling/LICENSE +21 -0
  64. package/built-in-skills/domain-modeling/SKILL.md +76 -0
  65. package/built-in-skills/frontend-design/SKILL.md +1 -0
  66. package/built-in-skills/human-approval/SKILL.md +17 -2
  67. package/built-in-skills/image-generate/SKILL.md +103 -302
  68. package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
  69. package/built-in-skills/ingest/SKILL.md +13 -45
  70. package/built-in-skills/internal-comms/SKILL.md +1 -0
  71. package/built-in-skills/liteparse/SKILL.md +130 -110
  72. package/built-in-skills/mcp-builder/SKILL.md +1 -0
  73. package/built-in-skills/memory/SKILL.md +420 -55
  74. package/built-in-skills/memory-dream/SKILL.md +339 -0
  75. package/built-in-skills/office-artifacts/SKILL.md +17 -4
  76. package/built-in-skills/okr/SKILL.md +154 -0
  77. package/built-in-skills/persona/SKILL.md +81 -0
  78. package/built-in-skills/persona-generator/SKILL.md +296 -0
  79. package/built-in-skills/pkf-svg/SKILL.md +253 -0
  80. package/built-in-skills/pkf-writing/SKILL.md +236 -0
  81. package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
  82. package/built-in-skills/proactivity/SKILL.md +84 -0
  83. package/built-in-skills/remotion/SKILL.md +431 -0
  84. package/built-in-skills/role-builder/SKILL.md +203 -0
  85. package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
  86. package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
  87. package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
  88. package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
  89. package/built-in-skills/skill-authoring/SKILL.md +110 -100
  90. package/built-in-skills/skill-authoring/skill.json +3 -3
  91. package/built-in-skills/skill-builder/SKILL.md +171 -0
  92. package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
  93. package/built-in-skills/skill-creator/SKILL.md +165 -423
  94. package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
  95. package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
  96. package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
  97. package/built-in-skills/tasks/SKILL.md +38 -23
  98. package/built-in-skills/tdd/LICENSE +21 -0
  99. package/built-in-skills/tdd/SKILL.md +110 -0
  100. package/built-in-skills/tdd/mocking.md +59 -0
  101. package/built-in-skills/tdd/refactoring.md +10 -0
  102. package/built-in-skills/tdd/tests.md +61 -0
  103. package/built-in-skills/team/SKILL.md +2 -1
  104. package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
  105. package/built-in-skills/webapp-testing/SKILL.md +1 -0
  106. package/built-in-skills/wechat-pay/SKILL.md +59 -0
  107. package/dist/cli.cjs +71872 -19960
  108. package/dist/cli.js +71803 -19846
  109. package/dist/index.cjs +72010 -19966
  110. package/dist/index.d.cts +4258 -712
  111. package/dist/index.d.ts +4258 -712
  112. package/dist/index.js +72156 -20118
  113. package/package.json +37 -6
  114. package/plugins/memory/prismer/__init__.py +1211 -0
  115. package/plugins/memory/prismer/plugin.yaml +8 -0
  116. package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
  117. package/plugins/tools/prismer-recall/__init__.py +282 -0
  118. package/plugins/tools/prismer-recall/plugin.yaml +15 -0
  119. package/built-in-skills/memory-curation/SKILL.md +0 -135
@@ -0,0 +1,169 @@
1
+ ---
2
+ name: spec-intake
3
+ description: Turn one atomic feature/gap request into a dispatchable task in a single pass — create the task, write SPEC.md (auto-folded into linkedAssetIds server-side), add acceptance criteria, record provenance. Two-part epics are refused, not silently split.
4
+ license: MIT
5
+ scope: common
6
+ compatibility:
7
+ - claude-code
8
+ - prismer-sdk
9
+ allowed-tools:
10
+ - Bash
11
+ metadata:
12
+ category: planning
13
+ ---
14
+
15
+ # spec-intake
16
+
17
+ 把**一个原子** feature/gap 请求一次性做成**可派发**的 task:`create` + `spec-set`(SPEC 自动折进 dispatch 可见的 `linkedAssetIds`)+ acceptanceCriteria + provenance(`apc/05` §1 C1 · S3)。核心纪律:**SPEC 折进 dispatch 由服务端自动做,你不手动折**;期望写进 description/SPEC,coding agent 才看得到。
18
+
19
+ **什么时候用**:一个原子级 feature/gap 要进研发链——需要建 task、写清 SPEC 与验收标准,让下游 coding agent 一 dispatch 就拿到完整上下文。
20
+
21
+ ## 承重约束(先记死)
22
+
23
+ - **原子级 only**:S3 是"一个 gap → 一个 task"。请求里裹了**两个及以上**独立 feature(epic)→ **拒绝,不许 silently 拆**。epic 拆分/依赖排序不在本 skill,交人先拆。
24
+ - **SPEC 折进 dispatch 是服务端自动的**:`cloud task spec-set` 落 SPEC asset 后,服务端已把它折进 `metadata.assets.linkedAssetIds`(`task-spec.service.ts` C1/S3)。**你不要再 `cloud task meta set` 手动折 SPEC**——那会重复且可能覆盖兄弟键。
25
+ - **期望进 description + SPEC**:dispatch 只把 title/description + `linkedAssetIds` 喂给 coding agent。验收期望要么写进 description,要么写进 SPEC(会被折进 linkedAssetIds),否则 agent 看不到。
26
+ - **provenance 用 `--set-string`**:sha / id 用 `--set` 会被推断成 number(全数字 sha 精度毁)。写 sha 一律 `--set-string`。
27
+ - **metadata 写权限**:`cloud task meta set` 走 gate = **creator / orchestrator / admin / owner**。spec-intake 是 intake 步、由主 agent 跑,主 agent 建的 task 天然是 creator——所以能写。**assignee 不在内**。
28
+
29
+ ## 工具契约(签名以此为准,先核后用)
30
+
31
+ | 命令 | 作用 | 关键 flag |
32
+ | --- | --- | --- |
33
+ | `cloud task create --title <t>` | 建 task;期望写进 `--description` | `--title`(必填)· `--description` · `--kind work_item\|goal`(默认 work_item)· `--assignee-id` · `--json` |
34
+ | `cloud task spec-set <task-id> -m <md>` | 写 SPEC.md(服务端自动折进 linkedAssetIds) | `-m/--markdown` 或 `-f/--file`(内容源) · `--json` |
35
+ | `cloud task add-criterion <task-id> --mode <m> --expectation <md>` | 加一条验收标准 | `--mode qualitative\|quantitative\|agent-self-check\|manual`(必填)· `--expectation`(必填)· `--optional` · `--json` |
36
+ | `cloud task acceptance <task-id>` | 读回验收标准 + 汇总状态 | `--json` |
37
+ | `cloud task get <task-id>` | 读回 task(含 metadata) | `--json` |
38
+ | `cloud task meta set <task-id> --set-string k=v` | 写 provenance(非 SPEC 的 id / sha) | `--set-string`(值恒字符串) |
39
+
40
+ - **`--kind`** 合法值恰好两个:`work_item`(默认,可派发工作项)| `goal`(长期目标投影)。intake 用 `work_item`。
41
+ - **`--mode`** 合法值恰好四个:`qualitative` | `quantitative` | `agent-self-check` | `manual`。
42
+ - 各命令 `--json` 下 stdout 是结构化响应;成功退出码 `0`,失败非零。
43
+
44
+ ## Procedure
45
+
46
+ ### 0. 先判:是不是原子请求?
47
+
48
+ 请求里如果有"**并且**做 X **又**做 Y"这种两个独立 feature 的形状 → **停手,拒绝**,回一句"这是 epic,请先拆成原子请求再逐个 intake"。不要建一个塞两件事的 task,也不要偷偷建两个 task。
49
+
50
+ ### 1. 建 task(期望写进 description)
51
+
52
+ ```bash
53
+ cloud task create \
54
+ --title "feat: 一句话需求" \
55
+ --description "期望/验收要点写这里,coding agent dispatch 时看得到。" \
56
+ --kind work_item --json > /tmp/task.json
57
+ ```
58
+
59
+ 从 stdout 取 `data.id`(下称 `$TID`)。
60
+
61
+ ### 2. 写 SPEC(服务端自动折进 linkedAssetIds)
62
+
63
+ ```bash
64
+ cloud task spec-set "$TID" -m "# SPEC
65
+
66
+ ## 目标
67
+ ...
68
+
69
+ ## 验收标准
70
+ - ...
71
+ " --json
72
+ ```
73
+
74
+ **不要**再手动 `meta set` 折 SPEC——`spec-set` 已经把 SPEC asset id 折进 `metadata.assets.linkedAssetIds` 了。
75
+
76
+ ### 3. 加验收标准(每条一个 criterion)
77
+
78
+ ```bash
79
+ cloud task add-criterion "$TID" \
80
+ --mode qualitative \
81
+ --expectation "done 长这样:<可判定的验收点>" --json
82
+ ```
83
+
84
+ 按需要加多条。verifier 具体方法(怎么验)留给下游,这里只钉 qualitative/quantitative 的**期望**。
85
+
86
+ ### 4. 写 provenance(非 SPEC 的 id / sha,用 `--set-string`)
87
+
88
+ ```bash
89
+ cloud task meta set "$TID" \
90
+ --set-string intake.sourceSha="$SOURCE_SHA" \
91
+ --set-string intake.gapRef="apc/05 C1"
92
+ ```
93
+
94
+ `--set-string` 保证 sha 落库是字符串(全数字 sha 不被数字化)。
95
+
96
+ ### 5. 读回确认(副作用 oracle)
97
+
98
+ ```bash
99
+ cloud task get "$TID" --json # 看 metadata.assets.linkedAssetIds 含 SPEC asset id
100
+ cloud task acceptance "$TID" --json # 看 criteria 落库
101
+ ```
102
+
103
+ ## 输出契约(机器判据按这个回读,别自由发挥格式)
104
+
105
+ 本 skill 的判据不是「报告里出现了 `spec-set` 这几个字」,而是**判据拿你声明的 id 去真库/真 API 回读**(`structured-criteria.ts` 的 `declared-id-readback`)。apc/12 §0.6 记了实证:一份**一条 `cloud` 命令都没跑**的编造报告,在旧文本判据下 **5/5 全绿**。所以报告必须带下面这几类**可机器解析的行**:
106
+
107
+ ```
108
+ TASK: <cloud task create 返回的 task id>
109
+ ASSET: <已在 metadata.assets.linkedAssetIds 里的 SPEC asset id> | role: spec
110
+ CRITERION: <cloud task acceptance 里的一个 criterion id>
111
+ META: intake.sourceSha = <你写进去的值> | type: string
112
+ ```
113
+
114
+ 判据会判红的情况(任一):
115
+
116
+ - `TASK:` 声明的 id **在服务端不存在**(回读 404)——这正是「声称跑了但没跑」的指纹;
117
+ - 该 task **不是本次跑出来的**(`createdAt` 超过 `maxAgeMinutes`)——拿一个老 task 的 id 冒充不成立;
118
+ - task 不是 `metadata.kind=work_item`,或 **description 太短**(dispatch 只喂 title/description + linkedAssetIds,描述空 = 下游 agent 看不到期望);
119
+ - `ASSET:` 声明的 id **不在** `metadata.assets.linkedAssetIds` 里——SPEC 没折进 dispatch;
120
+ - `CRITERION:` 声明的 id **不在** 该 task 的 acceptance view 上,或该 task 一条 criterion 都没有;
121
+ - `META:` 的键在 metadata 里**不存在**、**值与服务端存的不一致**,或**存储类型不是 `string`**——`--set` 的数字化在这里被逮住,不靠你自述「我用了 `--set-string`」。
122
+
123
+ **回读凭据缺失(无 `APC_READBACK_TOKEN` / `DEV_JWT` / `PRISMER_API_KEY`)或 API 不可达 ⇒ 判红**。「验不了」永远不算过。
124
+
125
+ > ⚠️ **回读凭据必须与真正跑命令的那个身份一致**。`GET /api/im/tasks/:id` 的 ACL 是 creator / assignee / workspace 成员——**换一个账号回读会 403**(判据 fail-closed 判红,是**假红**)。实测踩过:`cloud` CLI 优先读 `~/.prismer/config.toml` 的 `api_key`(**先于** `PRISMER_API_KEY` env),于是 task 建在 A 账号名下、回读用 B 账号的 JWT ⇒ 403。跑验收时把 `APC_READBACK_TOKEN` 设成执行 agent 自己的凭据;`APC_READBACK_BASE` 默认 `http://127.0.0.1:3000`。
126
+
127
+ **这些 id 必须从命令输出里原样复制**,不要重打、不要凭记忆写——回读比对的是字节。
128
+
129
+ ## 产出(副作用 oracle,报告里必须给)
130
+
131
+ 1. **task 真建**:`cloud task create` 的 `data.id` + `cloud task get` 读回。
132
+ 2. **SPEC 折进 dispatch**:`cloud task get --json` 的 `metadata.assets.linkedAssetIds` **含 SPEC asset id**(服务端自动折的,不是本 skill 手动折)。
133
+ 3. **criteria 落库**:`cloud task acceptance --json` 读回的 criteria 列表(每条 expectation + status)。
134
+ 4. **provenance 落库**:`metadata.intake.sourceSha` 是**字符串**(读回确认,全数字 sha 也不被数字化)。
135
+ 5. **epic 拒绝**:两部分请求下,未建 task(或明确拒绝)——不 silently 拆。
136
+
137
+ **不许**:手动折 SPEC 进 linkedAssetIds(服务端已做);把两部分 epic silently 拆成多 task;用 `--set` 写 sha;断言聊天文本而非 metadata/criteria 副作用。
138
+
139
+ ## 诚实边界
140
+
141
+ - **判据的能力上界**:回读证明的是「这些 id 真在库里、关系真成立、类型真对」。它**不**证明 SPEC 内容质量,也**不**能证明「两部分 epic 被拒」——「什么都没建」是**缺失**,回读不了,那一条至今仍是文本判据(apc/12 §0.6 记录的残余空洞,不得声称已闭合)。
142
+ - spec-intake 只承接**原子级**需求(`apc/05` §1 C1 诚实边界)。epic 分解需先经人拆分。
143
+ - **`spec-set` 会服务端**给 task 落 `metadata.devEntryApprovalRequired=true`(apc/03 §1「需求进入开发」门,服务端 `task-spec.service.ts` 自动,非你手动写)。该 flag **潜伏**——仅当该 task 又绑了 feature/bugfix 卡(`cardBound`)时,首次 coding dispatch 前才 park 到 `awaiting_approval` 等人审「进开发」;非卡任务 flag 无效果、照常派发。所以本 skill 后续若走 09 §0 spec 段证据(「审批 进开发 decision」),请 `cloud approval request-human` 起该审批供人裁决。
144
+ - 本 skill 若作为独立 dispatch 运行(无父 task 上下文),下方 `cloud skill ack` 会 **exit 3**(无 task 上下文)——这是契约限制,报告里不得声称已 ack。它建的 task 是**产物**,不是它自己的 dispatch task。
145
+
146
+ <!-- APC-ACK:v1 -->
147
+
148
+ ## 调用回执(APC 平台方运营纪律 · 自动注入,勿手改)
149
+
150
+ 执行本 skill 的**第一步**,先落一条调用回执:
151
+
152
+ ```bash
153
+ cloud skill ack spec-intake --task "$PRISMER_TASK_ID"
154
+ ```
155
+
156
+ **按退出码分流**(这条命令的退出码是承重信息,禁止用 `||` 兜底、`; true`、
157
+ `set +e` 或重定向把它抹掉):
158
+
159
+ | exit | 含义 | 你要做的 |
160
+ | --- | --- | --- |
161
+ | `0` | 回执已落库(`im_task_logs.action='skill_ack'`) | 继续执行本 skill |
162
+ | `3` | **无 task 上下文**——本次运行没有 task,产不出回执 | 继续执行本 skill;但本次运行**没有回执**,任何报告里都不得声称已 ack |
163
+ | `4` | 你不是该 task 的 assignee,服务端拒绝 | 停下并上报:回执只能由执行该 task 的 agent 产生 |
164
+ | `1` | 其它失败(网络 / 服务端) | 重试一次;仍失败则继续执行,并在结果里显式标注「回执缺失」 |
165
+
166
+ 回执只证明本 skill **被调度**,不证明**执行正确**——效果证明由本 skill 自己的
167
+ acceptanceCriteria 副作用断言承担(apc/04 §2 层 1 诚实标注)。
168
+
169
+ <!-- /APC-ACK:v1 -->
@@ -0,0 +1,93 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "slug": "spec-intake",
4
+ "name": "Spec Intake",
5
+ "description": "Turn one atomic feature/gap request into a dispatchable task in a single pass: create the task, write SPEC.md (auto-folded into linkedAssetIds server-side), add acceptance criteria, and record provenance. Two-part epics are refused, not silently split.",
6
+ "category": "planning",
7
+ "version": "1.0.0",
8
+ "license": "MIT",
9
+ "compatibility": ["claude-code", "prismer-sdk"],
10
+ "runtime": {
11
+ "kind": "text-workflow",
12
+ "requires": {
13
+ "env": [],
14
+ "bins": ["cloud"],
15
+ "capabilities": ["prismer.task.create", "prismer.task.spec", "prismer.task.acceptance", "prismer.task.meta"]
16
+ }
17
+ },
18
+ "sampleTasks": [
19
+ {
20
+ "title": "Intake an atomic feature request into a task + SPEC + criteria",
21
+ "prompt": "Given one atomic feature request, run the spec-intake skill for real: `cloud task create` (kind=work_item, expectations written into --description), `cloud task spec-set` to write SPEC.md (the server folds the SPEC asset into metadata.assets.linkedAssetIds — you never fold it yourself), `cloud task add-criterion` for each acceptance criterion, and `cloud task meta set --set-string` for the provenance sha. Then read back with `cloud task get --json` / `cloud task acceptance --json`. If the request bundles two independent features, REFUSE — do not silently split.\n\n--- YOUR REPORT MUST USE THIS MACHINE-CHECKED OUTPUT CONTRACT. Every id below is RE-READ from the live API (the task row, its metadata and its acceptance view). An id that does not resolve server-side, an asset that is not really in linkedAssetIds, a criterion that is not really on the task, or a sha that is stored as a NUMBER instead of a string all make the report FAIL. There is no wording that can substitute for these lines:\n\n```\nTASK: <the task id cloud task create returned>\nASSET: <the SPEC asset id now inside metadata.assets.linkedAssetIds> | role: spec\nCRITERION: <a criterion id from cloud task acceptance>\nMETA: intake.sourceSha = <the exact value you wrote> | type: string\n```\n\nThen, in prose: the epic-refusal rule you applied (and, if the request had been a two-part epic, that you would have created NO task rather than splitting it), plus the readback output you actually saw.\n\nHARD RULES: copy the ids verbatim from the command output — do not retype or invent them. Declare exactly ONE `TASK:` line. `META:` must carry the value the server stored (read it back), and `type: string` is a claim about the STORED type, so `--set` instead of `--set-string` is caught.",
22
+ "expectedArtifacts": [
23
+ "a `TASK: <id>` line carrying the id `cloud task create` returned (re-read from the API)",
24
+ "an `ASSET: <id> | role: spec` line whose id is really inside metadata.assets.linkedAssetIds (server-side fold)",
25
+ "a `CRITERION: <id>` line whose id is really on the task's acceptance view",
26
+ "a `META: intake.sourceSha = <value> | type: string` line matching the stored value AND stored type",
27
+ "the epic-refusal rule (a two-part request creates no task and is not silently split)"
28
+ ],
29
+ "acceptanceCriteria": [
30
+ {
31
+ "label": "the declared task really exists server-side, was created by THIS run, is a dispatchable work_item with expectations in its description, and the SPEC asset really folded into metadata.assets.linkedAssetIds",
32
+ "type": "structured",
33
+ "checker": "declared-id-readback",
34
+ "args": {
35
+ "require": ["task", "asset"],
36
+ "expect": { "metadata.kind": "work_item", "descriptionMinChars": 40 },
37
+ "assetsPath": "metadata.assets.linkedAssetIds",
38
+ "minCriteria": 0,
39
+ "maxAgeMinutes": 240
40
+ },
41
+ "match": "<structured:declared-id-readback>",
42
+ "required": true
43
+ },
44
+ {
45
+ "label": "the declared criterion ids are really on the task's acceptance view (criteria landed in the DB, not in the prose)",
46
+ "type": "structured",
47
+ "checker": "declared-id-readback",
48
+ "args": {
49
+ "require": ["task", "criterion"],
50
+ "minCriteria": 1,
51
+ "maxAgeMinutes": 240
52
+ },
53
+ "match": "<structured:declared-id-readback>",
54
+ "required": true
55
+ },
56
+ {
57
+ "label": "provenance is stored on the task with the declared value AND as a string — `--set` number-coercion is caught by reading the stored type back",
58
+ "type": "structured",
59
+ "checker": "declared-id-readback",
60
+ "args": {
61
+ "require": ["task", "meta"],
62
+ "minCriteria": 0,
63
+ "maxAgeMinutes": 240
64
+ },
65
+ "match": "<structured:declared-id-readback>",
66
+ "required": true
67
+ },
68
+ {
69
+ "label": "a two-part epic request is refused, not silently split (atomic-only)",
70
+ "match": "(epic[\\s\\S]{0,120}(refus|reject|拒|split|拆|atomic)|(refus|reject|拒绝|not\\s+split)[\\s\\S]{0,120}epic|atomic[- ]?only|单个原子|两个.{0,10}feature|first\\s+split)",
71
+ "type": "regex",
72
+ "flags": "is",
73
+ "required": true
74
+ }
75
+ ]
76
+ }
77
+ ],
78
+ "security": {
79
+ "dataAccess": ["workspace-tasks"],
80
+ "humanApprovalRequiredFor": []
81
+ },
82
+ "provenance": {
83
+ "sourceKind": "inline-spec",
84
+ "sourceRefs": [
85
+ "docs/apc/05-devchain-gaps-and-skills.md",
86
+ "docs/apc/12-skill-acceptance-tasks.md",
87
+ "sdk/cloud/src/commands/task.ts",
88
+ "src/im/services/task-spec.service.ts"
89
+ ],
90
+ "authoredBy": "prismer-platform",
91
+ "authoredAt": "2026-07-24T00:00:00Z"
92
+ }
93
+ }
@@ -0,0 +1,239 @@
1
+ ---
2
+ name: test-result-feedback
3
+ description: Close the acceptance loop for a tested change — consume the apc test TierResult, map EACH acceptance criterion to a pass/fail outcome from structured fields (never chat text), attach an evidence ref, and write it back to the task. A SUT red is a finding, never softened to green.
4
+ license: MIT
5
+ scope: coding
6
+ compatibility:
7
+ - claude-code
8
+ allowed-tools:
9
+ - Bash
10
+ metadata:
11
+ category: testing
12
+ ---
13
+
14
+ # test-result-feedback
15
+
16
+ 把 `apc test` 的 **TierResult** 回流成 task 每条验收 criterion 的 **结构化判定 + 证据**(`apc/05` C2 · S5b)。这是「测试→回流」的后半段:test-runner 负责**选层跑**并把新增红报回**一条** criterion;本 skill 负责把一轮 TierResult 摊到 task 的**每一条** criterion 上,逐条 `passed/failed/n/a` 落库并**挂证据 ref**,喂给循环级视图(cockpit 用 task metadata `loopId` 聚合,不建 loop 实体)。
17
+
18
+ **承重纪律(本 skill 存在的唯一理由)**:**红是一个发现,不是要修绿的对象。** TierResult 里一条 SUT 红 → 对应 criterion 必须报 `failed` 并附失败证据;**绝不**因为"就差一点"或"看起来还行"把红判成 `passed`。把断言放松到红能过 = 作废(`CLAUDE.md` 验收纪律 §3)。判定只取自 TierResult 的**结构字段**(`exitCode/failedNames/regressions[]/pass 计数`),**绝不**取自 agent 自己的聊天叙述——文本会冒充证据。
19
+
20
+ **什么时候用**:一个 coding task 跑完测试(test-runner 产出或 `apc test --json`),需要把这轮结果**逐 criterion** 落回 task 的验收账、并留下可回读的证据 ref。
21
+
22
+ ## 工具契约(签名以此为准,先核后用)
23
+
24
+ | 命令 | 作用 | 退出码 |
25
+ | --- | --- | --- |
26
+ | `apc test [--tier=T0,T1] [--diff] [--json]` | 全层测试编排(包装 `scripts/test203/run.ts`),产出 TierResult | `0` 绿 · `1` SUT 红/回归 · `2` 用法错 · `78` env_blocked |
27
+ | `cloud task verify-criterion <task-id> <criterion-id> --outcome <passed\|failed\|n/a\|waived> [--evidence <ref>...] [--note <md>]` | 把**一条** criterion 的判定 + 证据报回 task | 0 成功 |
28
+ | `cloud task acceptance <task-id>` | 读回 acceptance-view(回读确认 criterion 落库) | 0 成功 |
29
+
30
+ - `--outcome` 合法值**恰好四个**:`passed` / `failed` / `n/a` / `waived`(其它值 CLI 直接报错)。
31
+ - `--evidence <ref>` **可重复**,取值形如 `taskRun:<runId>` / `asset:<id>` / `url:...`——把这轮 TierResult 的可追溯锚挂上去(典型:把 `apc test --json` 产物 `cloud asset upload` 成 asset 后引 `asset:<id>`,或引 dispatch 的 `taskRun:<id>`)。**报 `failed` 必须带证据**,否则就是空口判红。
32
+ - `--note` 是自由 markdown:写清判定方法 + 失败用例名(`failedNames`)+ 复现指令。
33
+
34
+ ## TierResult 字段(以 `FIELD-DICTIONARY.md` 为准,别照抽象词猜)
35
+
36
+ `apc test --json` stdout 顶层:`{ schema, doctor, envStatus, tiers:[...], regressions:[...], fixed:[...], exitCode }`。
37
+
38
+ - `exitCode`:整轮退出码(`0` 绿 / `1` SUT 红(`--diff` 下=新增红)/ `78` env_blocked)。
39
+ - `regressions[]`:**新增红 vs baseline**(跨所有层并集)——判"回归"只看它,**baseline 已知红不算本轮的红**。
40
+ - 每个 `tiers[]`(TierResult):`{ tier, passed, failed, skipped, total, failedNames:[...], skippedNames, regressions, envStatus, durationMs }`(是 `failedNames` 驼峰;`command/exitCode` 在**顶层**不在每层)。
41
+
42
+ ## Decision table(TierResult → 每条 criterion 的 outcome)
43
+
44
+ 对 task 的每一条 criterion,按它断言的对象在 TierResult 里查证:
45
+
46
+ | TierResult 事实 | criterion 该报的 outcome |
47
+ | --- | --- |
48
+ | 该 criterion 覆盖的用例全绿(不在任何 `failedNames`,不在 `regressions[]`) | `passed`(附 `--evidence taskRun:...`) |
49
+ | 该 criterion 覆盖的用例进了 `regressions[]`(新增红) | `failed`(附 `failedNames` + evidence,**不得软化**) |
50
+ | 该 criterion 覆盖的用例在 `failedNames` 但命中 baseline 已知红(非新增) | `failed` 如实报 + note 标"baseline 已知红非本轮回归"(**仍是红,不粉饰**);是否 baseline 漂移另查,不放松本条 |
51
+ | 顶层 `exitCode=78`(env_blocked) | **不判 failed**——环境没跑起来,报环境故障域,criterion 维持 `pending`,绝不把 env_blocked 计成 SUT 红 |
52
+ | criterion 与本轮 tier 无关(未覆盖) | `n/a`(说明为何不适用,不硬凑绿) |
53
+
54
+ > flaky 辨伪(字段字典 §并行 flaky):`regressions[]` 出现**新面孔**红 → **单独重跑该文件**确认;单跑绿=flaky(note 记录,不判 `failed`);单跑仍红=真回归(如实 `failed`)。flaky 签名=重跑红集合漂移;真回归签名=稳定复现同一批。
55
+
56
+ ## Workflow
57
+
58
+ ### 1. 先落调用回执(见文末 ACK 块),再取本 task 的 criterion 清单
59
+
60
+ ```bash
61
+ cloud task acceptance "$PRISMER_TASK_ID" # 拿每条 criterion 的 id + label + 当前 status(多为 pending)
62
+ ```
63
+
64
+ ### 2. 跑/取本轮 TierResult
65
+
66
+ 若尚无产物,按改动面选层跑(选层规则见 test-runner skill):
67
+
68
+ ```bash
69
+ npx tsx sdk/apc/bin/apc.ts test --tier=T0,T1 --diff --json > /tmp/apc-test.json; T=$?
70
+ echo "apc test exit=$T"
71
+ ```
72
+
73
+ 若上游已有产物,直接读它——但产物必须是**本轮真跑**的,不许拿旧 probe 当证据。
74
+
75
+ ### 3. 逐 criterion 判定 + 挂证据回写
76
+
77
+ 从 `/tmp/apc-test.json` 读结构字段,对第 1 步每条 criterion 按 Decision table 定 outcome,逐条上报(**一条一命令**):
78
+
79
+ ```bash
80
+ # 绿:附可追溯锚
81
+ cloud task verify-criterion "$PRISMER_TASK_ID" "<criterion-id>" --outcome passed \
82
+ --evidence "taskRun:$PRISMER_TASK_RUN_ID" \
83
+ --note "apc test T0,T1 green; covered cases not in failedNames/regressions"
84
+
85
+ # 红:附失败用例名 + 证据,绝不软化
86
+ cloud task verify-criterion "$PRISMER_TASK_ID" "<criterion-id>" --outcome failed \
87
+ --evidence "taskRun:$PRISMER_TASK_RUN_ID" \
88
+ --note "T1 new reds vs baseline: <failed-name-1>,<failed-name-2>"
89
+ ```
90
+
91
+ (可选:`cloud asset upload /tmp/apc-test.json` 拿 `asset:<id>`,再 `--evidence asset:<id>` 把整份 TierResult 挂成 criterion 的持久证据。)
92
+
93
+ ### 4. 回读确认落库
94
+
95
+ ```bash
96
+ cloud task acceptance "$PRISMER_TASK_ID" # 每条 criterion status 应从 pending → 你报的 outcome,evidence 非空
97
+ ```
98
+
99
+ ### 5. 整轮结果回流 cockpit(`apc/05` §1 C2 的另一半)
100
+
101
+ 第 3 步是**逐 criterion**回流;这一步是**整轮**回流——把同一份 `/tmp/apc-test.json` 摊平成一条
102
+ `test_result_feedback` task-event,喂给 `insights-cockpit.service.ts::getAcceptanceFeedback`
103
+ 的 acceptanceFeedback 面板(此前这个 reader 一直有读无写,面板恒空):
104
+
105
+ ```bash
106
+ cloud task test-feedback "$PRISMER_TASK_ID" /tmp/apc-test.json
107
+ ```
108
+
109
+ 不带文件参数时从 stdin 读,可以直接接编排命令的输出:
110
+
111
+ ```bash
112
+ npx tsx sdk/apc/bin/apc.ts test --tier=T0,T1 --diff --json | cloud task test-feedback "$PRISMER_TASK_ID"
113
+ ```
114
+
115
+ **映射规则**(与第 3 步的 Decision table 保持同一条纪律——env_blocked 绝不算 SUT 红):
116
+
117
+ | TierResult 事实 | `test-feedback` 上报的 `status` |
118
+ | --- | --- |
119
+ | 顶层 `envStatus==='env_blocked'` 或 `exitCode===78` | `env_blocked`(**绝不映射成 `failed`**——环境没跑起来,不是产品红) |
120
+ | 上面都不成立且 `exitCode===0` | `passed` |
121
+ | 其余(`exitCode` 非 0 且非 env_blocked) | `failed` |
122
+
123
+ `payload.tiers` 取自顶层 `tiers[]`,每项落 `{tier, passed, failed, skipped, total}`;`payload.failureCount`
124
+ 是每层 `failed` 的和;`exitCode` / `regressions[]` 原样透传,供 cockpit 之后细分。同样只有该 task 的
125
+ **assignee** 能报(非 assignee 报会 403 / CLI 退出 4),与第 1 步的 `cloud skill ack` 是同一条鉴权。
126
+
127
+ ## Failure / escalate
128
+
129
+ - 顶层 `exitCode=78` → 环境没起来。报环境故障域(infra/toolchain),**不碰 criterion**,交给 env-doctor。
130
+ - criterion 与任何已跑 tier 都对不上 → 报 `n/a` + 说明,别硬判绿;缺 tier 覆盖是一个发现。
131
+ - 判据模糊到无法从结构字段确定 → 停手 escalate(留 `/tmp/apc-test.json`),**绝不**猜一个绿。
132
+
133
+ ## 输出契约(机器判据按这个复验,别自由发挥格式)
134
+
135
+ 旧判据是「正文里出现过 `failedNames`/`regressions`/`--json` 这几个词」——**一篇没跑过 `apc test`、字段名全靠背的报告照样满分**,而且**字段名记错也照绿**(doc12 实测到的漂移:TierResult 根本没有 `command` 字段,但 doc 写了、判据也不在乎)。现在判据(`cited-evidence`)把报告里每条 `path:line` **读回磁盘复核**,并要求你把消费的字段名**钉到真实产出方的真实行**上。
136
+
137
+ > **⚠️ 但 `cited-evidence` 管不到本 skill 最承重的那件事**(2026-07-26 实测坐实):把一份逐字真实、引用全对的报告里**两条真红改判 `passed`**,其余一个字不动 —— 旧的 7 条判据给 **7/7 全绿**。引用真实性与 outcome 真实性是两回事,而本 skill 存在的唯一理由恰恰是后者。故新增下面的 **③**(`json-claim`,与 test-runner 同一 checker),把「红不软化」「env_blocked 不计产品红」两条纪律**从措辞检查升级为机器判据**。
138
+
139
+ **① 字段锚点声明**(一行;符号会被复核确实出现在该文件里):
140
+
141
+ ```
142
+ CHANGE-POINT: failedNames @ scripts/test203/run.ts
143
+ ```
144
+
145
+ `scripts/test203/run.ts` 是 TierResult JSON 的**真实产出方**(`apc test` 只是包装它)。开工先取证据集:
146
+
147
+ ```bash
148
+ rg -n failedNames scripts/test203/run.ts # 你的证据集;表里的引用从这份输出里抄
149
+ ```
150
+
151
+ **② 映射表**(markdown 表,**首列是 `path:line`**):每行把一条 criterion 类别映射到 outcome,并用一条**真实命中行**把该行的依据钉住。判据要求:**≥3 行**带可复核引用,且**≥2 条引用所在的那一行真的含 `failedNames`**("真实存在的行" ≠ "真实的搜索命中")。
152
+
153
+ ```
154
+ | path:line | criterion-class | TierResult fact | outcome | evidence ref |
155
+ | --- | --- | --- | --- | --- |
156
+ | scripts/test203/run.ts:344 | 覆盖用例全绿 | 不在 failedNames / regressions[] | passed | taskRun:<id> |
157
+ | scripts/test203/run.ts:382 | 覆盖用例进 regressions[] | 新增红 vs baseline | failed | asset:<id> |
158
+ ```
159
+
160
+ **引用写法三条(判据按这个复核,写错会把如实的报告判红)**:
161
+
162
+ 1. **必须 repo-root-relative**:写 `scripts/test203/run.ts:344`,不要写简写 `test203/run.ts:344`,也不要写绝对路径。
163
+ 2. **计数不是行号**:`rg -c` 输出的 `path:12` 是"12 个命中",要引用就写 `count=12`。
164
+ 3. **散文里出现的 `path:line` 一样会被复核**——报告里任何一处 `path:line` 都是一次声明;贴失败堆栈时注意里面的相对 `file.ts:line` 也算数。
165
+
166
+ > 这条判据管的是「**你消费的字段名是真的、你的映射依据可回溯**」,**不**替代下面的落库 oracle——outcome 是否真落库仍以 `cloud task acceptance` 回读为准。
167
+
168
+ **③ 原始产物 + 两行判定声明**(`json-claim` 复核;**这条是本 skill 的承重判据**)
169
+
170
+ 把你消费的那份 TierResult **原样贴进一个 fenced JSON 块**(就是 `apc test --json` 的 stdout,别摘录、别改写),checker 会重新解析它,然后核对下面两行:
171
+
172
+ ```
173
+ TIER-EXIT: 1
174
+ FEEDBACK-VERDICT: sut-red
175
+ ```
176
+
177
+ - **`TIER-EXIT`** 必须逐字等于产物里的 `exitCode`。叙述与产物对不上即红。
178
+ - **`FEEDBACK-VERDICT`** 不是你的判断,是**从 `exitCode` 派生**的,只有三个合法值:
179
+
180
+ | `exitCode` | 唯一合法的 `FEEDBACK-VERDICT` | 它挡住的事 |
181
+ | --- | --- | --- |
182
+ | `0` | `all-covered-criteria-passed` | — |
183
+ | `1` | `sut-red` | 把真红叙述成绿(**本 skill 的头号禁令**) |
184
+ | `78` | `env-blocked` | 把环境故障冤枉成 SUT 红 |
185
+
186
+ 写 `1` 却声明 `all-covered-criteria-passed` ⇒ **红**。写 `78` 却声明 `sut-red` ⇒ **红**。这两条以前只是正文里有没有出现「不软化」「env_blocked」这些词,现在是算术。
187
+
188
+ 同时被复核的还有:`schema` 必须是 `test203.run/v1`;`exitCode ∈ {0,1,78}`、`envStatus ∈ {ok,env_blocked}`;每层 `passed+failed+skipped == total` 且 `failedNames.length == failed`(per-tier 算术);`exitCode=78 ⇒ envStatus='env_blocked'`、`exitCode=0 ⇒ regressions 为空`(exit-code 契约)。
189
+
190
+ > **诚实边界**(沿用 `json-claim` 自己的声明):一个肯读 baseline 与 tier 清单的伪造者,仍能手工拼出一份自洽产物——没有任何本地工件是不可伪造的。这条判据杀掉的是**廉价伪造**(编数字、叙述压过产物、拿旧产物冒充本轮),与其余 checker 同一档次。**逐 criterion 是否真落库,仍以 `cloud task acceptance` 回读为准,判据不替代它。**
191
+
192
+ ## 产出(副作用 oracle,报告里必须给)
193
+
194
+ 1. **每条 criterion 的落库 outcome 行**:`cloud task acceptance` 回读,status 从 `pending` → 上报值(`passed/failed/n/a`),**这是真值**——不是 agent 说"我报了"。
195
+ 2. **证据 ref 已挂**:每条报出的 criterion 带非空 evidence(`taskRun:` / `asset:`),可回溯到本轮 TierResult。
196
+ 3. **红如实落红**:TierResult 里的 SUT 红对应的 criterion 是 `failed`(不是被软化成 `passed`)。
197
+
198
+ **不许**:把 SUT 红判成 `passed`(红是发现)· 把 `env_blocked`(exit 78)计成 SUT 红 · 断言聊天文本而非 TierResult 结构字段 · 空口判绿(`passed` 无证据 ref)· 拿旧 probe/上一轮产物冒充本轮证据。
199
+
200
+ ## PKF 直写(研发回环 · doc07 §B2 写入点①)
201
+
202
+ **产出时机**:逐 criterion 回流落库后,把这轮 TierResult 的结论**直写成一张 PKF 记忆页**(pageType=`decision`)——同一页既是回用户侧的富报告,也是可召回的记忆页。这与经验抽取(durable 教训走 memory skill 的 CONSTRUCT→PLACE→WRITE)是并存的两条边,不互相取代(doc07 §B1)。这条直写不改上面逐 criterion 回流的任何一步,是回流**之后**的一次投影。
203
+
204
+ **语法照 `pkf-writing` skill**——本 skill 不再内嵌语法骨架(frontmatter / typed link / 数据块写法都在那边)。写入面**不新造**:code agent 走 `prismer memory write`(SS-14 §4.3 appendix;hermes 侧是 native `memory_write`)。
205
+
206
+ **声明**(doc10 §2.5 格式,报告末尾一行):
207
+
208
+ ```
209
+ PKF: prismer://workspace/<ws>/memory/<path>
210
+ ```
211
+
212
+ 写入面不可达时如实声明 `PKF: none — 写入面不可达(<哪一条>)`,**绝不允许**为了满足规则而假装写了。
213
+
214
+ **回读**:声明后必须回读该页(`pkf_read` / memory read),确认**真实存在、正文非空**且与结论一致(`contradicts` 只在本轮结论**推翻**了某条既有决策时才加,指向那条决策页);typed link 的 `prismer://` 目标必须**真实存在**(validator 规则 2c/4 挡 `invalid-prismer-host`),无对应页就删该 link 行、宁缺勿造伪目标;写入自动挂 INDEX 反孤儿锚(SS-14 §4.2),优先 edit 既有页而非 dump 新叶(PLACE 治理照走)。
215
+
216
+ <!-- APC-ACK:v1 -->
217
+
218
+ ## 调用回执(APC 平台方运营纪律 · 自动注入,勿手改)
219
+
220
+ 执行本 skill 的**第一步**,先落一条调用回执:
221
+
222
+ ```bash
223
+ cloud skill ack test-result-feedback --task "$PRISMER_TASK_ID"
224
+ ```
225
+
226
+ **按退出码分流**(这条命令的退出码是承重信息,禁止用 `||` 兜底、`; true`、
227
+ `set +e` 或重定向把它抹掉):
228
+
229
+ | exit | 含义 | 你要做的 |
230
+ | --- | --- | --- |
231
+ | `0` | 回执已落库(`im_task_logs.action='skill_ack'`) | 继续执行本 skill |
232
+ | `3` | **无 task 上下文**——本次运行没有 task,产不出回执 | 继续执行本 skill;但本次运行**没有回执**,任何报告里都不得声称已 ack |
233
+ | `4` | 你不是该 task 的 assignee,服务端拒绝 | 停下并上报:回执只能由执行该 task 的 agent 产生 |
234
+ | `1` | 其它失败(网络 / 服务端) | 重试一次;仍失败则继续执行,并在结果里显式标注「回执缺失」 |
235
+
236
+ 回执只证明本 skill **被调度**,不证明**执行正确**——效果证明由本 skill 自己的
237
+ acceptanceCriteria 副作用断言承担(apc/04 §2 层 1 诚实标注)。
238
+
239
+ <!-- /APC-ACK:v1 -->