@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.
- package/CHANGELOG.md +3430 -0
- package/README.md +34 -12
- package/apc/skills/FIELD-DICTIONARY.md +111 -0
- package/apc/skills/bug-reproduce/SKILL.md +150 -0
- package/apc/skills/bug-reproduce/skill.json +96 -0
- package/apc/skills/code-review/SKILL.md +198 -0
- package/apc/skills/code-review/skill.json +124 -0
- package/apc/skills/design-review/SKILL.md +122 -0
- package/apc/skills/design-review/skill.json +88 -0
- package/apc/skills/doc-sync/SKILL.md +168 -0
- package/apc/skills/doc-sync/skill.json +81 -0
- package/apc/skills/env-doctor/SKILL.md +194 -0
- package/apc/skills/env-doctor/skill.json +209 -0
- package/apc/skills/git-ops/SKILL.md +189 -0
- package/apc/skills/git-ops/skill.json +94 -0
- package/apc/skills/impact-trace/SKILL.md +168 -0
- package/apc/skills/impact-trace/skill.json +104 -0
- package/apc/skills/observability/SKILL.md +195 -0
- package/apc/skills/observability/skill.json +116 -0
- package/apc/skills/release-db-config-sync/SKILL.md +186 -0
- package/apc/skills/release-db-config-sync/skill.json +109 -0
- package/apc/skills/release-ota-promote/SKILL.md +195 -0
- package/apc/skills/release-ota-promote/skill.json +176 -0
- package/apc/skills/release-preflight/SKILL.md +174 -0
- package/apc/skills/release-preflight/skill.json +175 -0
- package/apc/skills/release-rollback/SKILL.md +214 -0
- package/apc/skills/release-rollback/skill.json +230 -0
- package/apc/skills/release-tag/SKILL.md +194 -0
- package/apc/skills/release-tag/skill.json +94 -0
- package/apc/skills/releasing-prod/SKILL.md +49 -0
- package/apc/skills/releasing-test/SKILL.md +135 -0
- package/apc/skills/sdk-release/SKILL.md +200 -0
- package/apc/skills/spec-intake/SKILL.md +169 -0
- package/apc/skills/spec-intake/skill.json +93 -0
- package/apc/skills/test-result-feedback/SKILL.md +239 -0
- package/apc/skills/test-result-feedback/skill.json +193 -0
- package/apc/skills/test-runner/SKILL.md +169 -0
- package/apc/skills/test-runner/skill.json +103 -0
- package/apc/skills/ui-align/SKILL.md +209 -0
- package/apc/skills/ui-align/skill.json +114 -0
- package/apc/skills/ui-canvas/SKILL.md +148 -0
- package/apc/skills/ui-canvas/skill.json +127 -0
- package/built-in-skills/agent-coordination/SKILL.md +59 -37
- package/built-in-skills/agent-meta/SKILL.md +1 -0
- package/built-in-skills/assets/SKILL.md +8 -6
- package/built-in-skills/browser-use/SKILL.md +93 -0
- package/built-in-skills/canvas-design/SKILL.md +1 -0
- package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
- package/built-in-skills/claude-api/SKILL.md +1 -0
- package/built-in-skills/codebase-design/DEEPENING.md +37 -0
- package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/built-in-skills/codebase-design/LICENSE +21 -0
- package/built-in-skills/codebase-design/SKILL.md +116 -0
- package/built-in-skills/conversation-compaction/SKILL.md +114 -0
- package/built-in-skills/council-creator/SKILL.md +426 -0
- package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
- package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
- package/built-in-skills/document-generation/SKILL.md +105 -0
- package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/built-in-skills/domain-modeling/LICENSE +21 -0
- package/built-in-skills/domain-modeling/SKILL.md +76 -0
- package/built-in-skills/frontend-design/SKILL.md +1 -0
- package/built-in-skills/human-approval/SKILL.md +17 -2
- package/built-in-skills/image-generate/SKILL.md +103 -302
- package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
- package/built-in-skills/ingest/SKILL.md +13 -45
- package/built-in-skills/internal-comms/SKILL.md +1 -0
- package/built-in-skills/liteparse/SKILL.md +130 -110
- package/built-in-skills/mcp-builder/SKILL.md +1 -0
- package/built-in-skills/memory/SKILL.md +420 -55
- package/built-in-skills/memory-dream/SKILL.md +339 -0
- package/built-in-skills/office-artifacts/SKILL.md +17 -4
- package/built-in-skills/okr/SKILL.md +154 -0
- package/built-in-skills/persona/SKILL.md +81 -0
- package/built-in-skills/persona-generator/SKILL.md +296 -0
- package/built-in-skills/pkf-svg/SKILL.md +253 -0
- package/built-in-skills/pkf-writing/SKILL.md +236 -0
- package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
- package/built-in-skills/proactivity/SKILL.md +84 -0
- package/built-in-skills/remotion/SKILL.md +431 -0
- package/built-in-skills/role-builder/SKILL.md +203 -0
- package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
- package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
- package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
- package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
- package/built-in-skills/skill-authoring/SKILL.md +110 -100
- package/built-in-skills/skill-authoring/skill.json +3 -3
- package/built-in-skills/skill-builder/SKILL.md +171 -0
- package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
- package/built-in-skills/skill-creator/SKILL.md +165 -423
- package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
- package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
- package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
- package/built-in-skills/tasks/SKILL.md +38 -23
- package/built-in-skills/tdd/LICENSE +21 -0
- package/built-in-skills/tdd/SKILL.md +110 -0
- package/built-in-skills/tdd/mocking.md +59 -0
- package/built-in-skills/tdd/refactoring.md +10 -0
- package/built-in-skills/tdd/tests.md +61 -0
- package/built-in-skills/team/SKILL.md +2 -1
- package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
- package/built-in-skills/webapp-testing/SKILL.md +1 -0
- package/built-in-skills/wechat-pay/SKILL.md +59 -0
- package/dist/cli.cjs +71872 -19960
- package/dist/cli.js +71803 -19846
- package/dist/index.cjs +72010 -19966
- package/dist/index.d.cts +4258 -712
- package/dist/index.d.ts +4258 -712
- package/dist/index.js +72156 -20118
- package/package.json +37 -6
- package/plugins/memory/prismer/__init__.py +1211 -0
- package/plugins/memory/prismer/plugin.yaml +8 -0
- package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
- package/plugins/tools/prismer-recall/__init__.py +282 -0
- package/plugins/tools/prismer-recall/plugin.yaml +15 -0
- package/built-in-skills/memory-curation/SKILL.md +0 -135
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"slug": "test-result-feedback",
|
|
4
|
+
"name": "Test Result Feedback",
|
|
5
|
+
"description": "Consume an apc test TierResult and close the acceptance loop for a task: map EACH criterion to passed/failed/n-a from structured fields (exitCode/failedNames/regressions[]), attach an evidence ref, and write it back. A SUT red is a finding, never softened to green; env_blocked is never counted as a SUT red.",
|
|
6
|
+
"category": "testing",
|
|
7
|
+
"version": "1.0.0",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"compatibility": [
|
|
10
|
+
"claude-code"
|
|
11
|
+
],
|
|
12
|
+
"runtime": {
|
|
13
|
+
"kind": "text-workflow",
|
|
14
|
+
"requires": {
|
|
15
|
+
"env": [],
|
|
16
|
+
"bins": [
|
|
17
|
+
"node"
|
|
18
|
+
],
|
|
19
|
+
"capabilities": [
|
|
20
|
+
"prismer.task.verify-criterion"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"sampleTasks": [
|
|
25
|
+
{
|
|
26
|
+
"title": "Consume a TierResult, map each criterion to an outcome with evidence, never soften a red",
|
|
27
|
+
"prompt": "Run the test-result-feedback skill: close the acceptance loop by mapping an apc test TierResult onto a task's acceptance criteria. The `apc` CLI is NOT on PATH — invoke it as `npx tsx sdk/apc/bin/apc.ts <subcommand>` from the repo root (its `--json` stdout is a structured `test203.run/v1` product; the human summary is on stderr). Steps: (1) `npx tsx sdk/apc/bin/apc.ts test --tier=T0 --diff --json > /tmp/apc-test.json` and read its RAW top-level exit code (0 green / 1 SUT red i.e. a NEW red vs baseline under --diff / 78 env_blocked). (2) Parse the TierResult from the JSON using the EXACT field names: top-level `exitCode`, `envStatus`, `regressions[]` (new reds vs baseline — the --diff verdict, distinct from baseline known-red), and each `tiers[]` `{tier, passed, failed, skipped, total, failedNames, envStatus}` (note it is `failedNames`, camelCase; command/exitCode live at top level, not per tier). (2b) GROUND THE FIELD NAMES IN THE REAL PRODUCER, do not trust any doc's word for them: `rg -n failedNames scripts/test203/run.ts` — that file is where the TierResult JSON is built, and its hits are your evidence set. Documented field names drift (doc12 recorded a TierResult `command` field that `jsonReport()` never emits); a field you cannot show on a real line of the producer is a field you must not claim to have consumed. (3) Apply the mapping rule and STATE it explicitly for each criterion you would report: a criterion whose covered cases are all green => `passed`; a criterion whose cases entered `regressions[]` (new red) => `failed` — a SUT red is a FINDING and is reported failed, NEVER softened to passed; a criterion blocked by top-level `exitCode=78` env_blocked => NOT failed, surfaced as an environment fault domain (infra/toolchain) and left pending, never counted as a SUT red; a criterion unrelated to the tier run => `n/a`. The outcome must come ONLY from the structured TierResult fields, never from chat narration. (4) Every reported outcome MUST carry an evidence ref (e.g. `taskRun:<id>` or `asset:<id>` after `cloud asset upload /tmp/apc-test.json`); a `passed` with no evidence ref is not allowed. (5) If dispatched inside a kanban task (PRISMER_TASK_ID set) you would report each criterion via `npx tsx sdk/cloud/src/cli.ts task verify-criterion \"$PRISMER_TASK_ID\" <criterion-id> --outcome <passed|failed|n/a> --evidence taskRun:<id> --note <failedNames>` and then `... task acceptance \"$PRISMER_TASK_ID\"` to read back that each criterion status moved from pending to your reported outcome with a non-empty evidence array; in a plain chat dispatch there is no task criterion, so state that the last-mile verify-criterion + acceptance read-back is N/A here.\n\n--- YOUR REPORT MUST USE THIS MACHINE-CHECKED OUTPUT CONTRACT (it is re-verified against the filesystem, so an invented path:line is caught):\n\nLine 1 — the TierResult field you anchored the mapping on, exactly this shape:\n`CHANGE-POINT: failedNames @ scripts/test203/run.ts`\n\nThen the mapping table — one row per criterion class you map, the FIRST CELL being the `path:line` that grounds that row (copy the line number from your own `rg -n` output; the cited line is read off disk and a missing file / out-of-range line / blank line FAILS the report):\n```\n| path:line | criterion-class | TierResult fact | outcome | evidence ref |\n| --- | --- | --- | --- | --- |\n| scripts/test203/run.ts:344 | covered cases all green | not in failedNames, not in regressions[] | passed | taskRun:<id> |\n| scripts/test203/run.ts:382 | covered case entered regressions[] | new red vs baseline | failed | asset:<id> |\n```\nYou need at least 3 mapping rows carrying a verified `path:line`, and at least 2 of your citations must land on a line that LITERALLY CONTAINS `failedNames` — a real line that is not a real search hit is not evidence, so run the `rg -n` above first and cite from its output.\n\nHARD RULE: do not guess line numbers. Every `path:line` anywhere in your report is re-read off disk. Citations MUST be repo-root-relative (`scripts/test203/run.ts:344`, never an abbreviated `test203/run.ts:344` and never an absolute path). A `rg -c` HIT COUNT is not a line number — write counts as `count=N`, never inline as `path:N`.\n\nReport: the raw apc test exit code, the parsed TierResult (per-tier pass/fail/skip counts + failedNames + regressions[]), the mapping table above, the outcome you would assign to each criterion class with its evidence ref, and an explicit statement that a SUT red maps to failed (never passed) and that exit-78 env_blocked is kept out of the SUT verdict.",
|
|
28
|
+
"expectedArtifacts": [
|
|
29
|
+
"apc test --tier=T0 --diff --json raw top-level exit code (0 green / 1 new-red / 78 env_blocked)",
|
|
30
|
+
"parsed TierResult: per-tier passed/failed/skipped/total + failedNames + regressions[] (new reds vs baseline)",
|
|
31
|
+
"a `CHANGE-POINT: failedNames @ scripts/test203/run.ts` declaration + `rg -n failedNames` evidence set grounding the consumed field names in the real producer",
|
|
32
|
+
"mapping table: ≥3 rows whose first cell is a `path:line` that resolves on disk, ≥2 of them landing on a line containing `failedNames`",
|
|
33
|
+
"per-criterion outcome mapping (passed/failed/n-a) derived ONLY from structured fields, each with an evidence ref",
|
|
34
|
+
"explicit discipline statement: a SUT red maps to failed (never softened to passed); env_blocked (exit 78) is not a SUT red"
|
|
35
|
+
],
|
|
36
|
+
"acceptanceCriteria": [
|
|
37
|
+
{
|
|
38
|
+
"label": "consumed structured TierResult fields VERIFIED against the real producer — anchored on `failedNames @ scripts/test203/run.ts`, every path:line re-read off disk, ≥2 citations landing on a line that actually contains the field, ≥3 mapping rows carrying a verified citation",
|
|
39
|
+
"type": "structured",
|
|
40
|
+
"checker": "cited-evidence",
|
|
41
|
+
"args": {
|
|
42
|
+
"minRows": 3,
|
|
43
|
+
"minAnchoredRows": 2,
|
|
44
|
+
"anchorMinLength": 4,
|
|
45
|
+
"expectedChangePoint": {
|
|
46
|
+
"symbol": "failedNames",
|
|
47
|
+
"path": "scripts/test203/run.ts"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"match": "<structured:cited-evidence>",
|
|
51
|
+
"required": true
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"label": "TierResult 的 verdict 由 exitCode 派生,不由叙述决定 —— 报告贴出它消费的原始 TierResult JSON,checker 重解析:exitCode 必须与报告声明的 TIER-EXIT 一致;FEEDBACK-VERDICT 必须是 exitCode 派生出的那个(1⇒sut-red 不得写成 passed;78⇒env-blocked 不得写成 sut-red);per-tier 算术与 exit-code 契约同时复核",
|
|
55
|
+
"type": "structured",
|
|
56
|
+
"checker": "json-claim",
|
|
57
|
+
"args": {
|
|
58
|
+
"equals": {
|
|
59
|
+
"schema": "test203.run/v1"
|
|
60
|
+
},
|
|
61
|
+
"require": [
|
|
62
|
+
"exitCode",
|
|
63
|
+
"envStatus",
|
|
64
|
+
"tiers",
|
|
65
|
+
"regressions"
|
|
66
|
+
],
|
|
67
|
+
"types": {
|
|
68
|
+
"exitCode": "number",
|
|
69
|
+
"tiers": "array",
|
|
70
|
+
"regressions": "array"
|
|
71
|
+
},
|
|
72
|
+
"allowed": {
|
|
73
|
+
"exitCode": [
|
|
74
|
+
0,
|
|
75
|
+
1,
|
|
76
|
+
78
|
|
77
|
+
],
|
|
78
|
+
"envStatus": [
|
|
79
|
+
"ok",
|
|
80
|
+
"env_blocked"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"declaredLines": {
|
|
84
|
+
"TIER-EXIT": "exitCode"
|
|
85
|
+
},
|
|
86
|
+
"derivedLines": {
|
|
87
|
+
"FEEDBACK-VERDICT": {
|
|
88
|
+
"from": "exitCode",
|
|
89
|
+
"map": {
|
|
90
|
+
"0": "all-covered-criteria-passed",
|
|
91
|
+
"1": "sut-red",
|
|
92
|
+
"78": "env-blocked"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"implications": [
|
|
97
|
+
{
|
|
98
|
+
"if": {
|
|
99
|
+
"path": "exitCode",
|
|
100
|
+
"equals": 78
|
|
101
|
+
},
|
|
102
|
+
"then": {
|
|
103
|
+
"path": "envStatus",
|
|
104
|
+
"equals": "env_blocked"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"if": {
|
|
109
|
+
"path": "exitCode",
|
|
110
|
+
"equals": 0
|
|
111
|
+
},
|
|
112
|
+
"then": {
|
|
113
|
+
"path": "regressions",
|
|
114
|
+
"empty": true
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"eachItem": {
|
|
119
|
+
"path": "tiers",
|
|
120
|
+
"sum": {
|
|
121
|
+
"parts": [
|
|
122
|
+
"passed",
|
|
123
|
+
"failed",
|
|
124
|
+
"skipped"
|
|
125
|
+
],
|
|
126
|
+
"total": "total"
|
|
127
|
+
},
|
|
128
|
+
"lengths": {
|
|
129
|
+
"failedNames": "failed"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"match": "<structured:json-claim>",
|
|
134
|
+
"required": true
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"label": "reports per-criterion / per-tier pass/fail/skip counts",
|
|
138
|
+
"match": "(pass|fail|skip)\\w*\\s*[:=|\\-]*\\s*\\d+|\\d+\\s*[|:=\\-]*\\s*(pass|fail|skip)",
|
|
139
|
+
"type": "regex",
|
|
140
|
+
"required": true
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"label": "maps a criterion to an outcome from the four legal values",
|
|
144
|
+
"match": "(passed|failed|n/?a|waived|outcome|verify-criterion|criterion)",
|
|
145
|
+
"type": "regex",
|
|
146
|
+
"required": true
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"label": "a SUT red is a finding, never softened to green",
|
|
150
|
+
"match": "(never\\s+(soften|passed|green)|not\\s+soften|红是发现|不软化|不放松|finding|failed\\s+not\\s+passed|map(s|ped)?\\s+to\\s+failed)",
|
|
151
|
+
"type": "regex",
|
|
152
|
+
"required": true
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"label": "keeps env_blocked (exit 78) out of the SUT verdict",
|
|
156
|
+
"match": "(env[_ ]?blocked|\\b78\\b|environment\\s+(fault|domain)|infra|toolchain|环境)",
|
|
157
|
+
"type": "regex",
|
|
158
|
+
"required": true
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"label": "attaches an evidence ref to each reported outcome",
|
|
162
|
+
"match": "(evidence|taskRun:|asset:|--evidence|证据)",
|
|
163
|
+
"type": "regex",
|
|
164
|
+
"required": true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"label": "last-mile verify-criterion + acceptance read-back (task-bound only)",
|
|
168
|
+
"match": "(verify-criterion|acceptance|read[- ]back|last[- ]mile|n/?a|回读|上报)",
|
|
169
|
+
"type": "regex",
|
|
170
|
+
"required": false
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
"security": {
|
|
176
|
+
"dataAccess": [
|
|
177
|
+
"local-filesystem",
|
|
178
|
+
"workspace-tasks"
|
|
179
|
+
],
|
|
180
|
+
"humanApprovalRequiredFor": []
|
|
181
|
+
},
|
|
182
|
+
"provenance": {
|
|
183
|
+
"sourceKind": "inline-spec",
|
|
184
|
+
"sourceRefs": [
|
|
185
|
+
"docs/apc/05-devchain-gaps-and-skills.md",
|
|
186
|
+
"docs/apc/00-INDEX.md",
|
|
187
|
+
"sdk/apc/skills/FIELD-DICTIONARY.md",
|
|
188
|
+
"sdk/cloud/src/commands/task.ts"
|
|
189
|
+
],
|
|
190
|
+
"authoredBy": "prismer-platform",
|
|
191
|
+
"authoredAt": "2026-07-25T00:00:00Z"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-runner
|
|
3
|
+
description: For a code change, pick the right test tier by change surface, run apc test with baseline diff, and report only NEW reds vs baseline back to the task's acceptance criterion. Separates env_blocked from SUT red so a broken machine never fails the code.
|
|
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-runner
|
|
15
|
+
|
|
16
|
+
对一个改动**选层跑测试**并把**新增红(vs baseline)**报回 task 的验收 criterion(`apc/02` §2 R1 · `apc/05` A1 S7)。核心纪律:环境红(`env_blocked`)与被测代码红(SUT red)**分域**——机器坏了绝不判代码红。
|
|
17
|
+
|
|
18
|
+
**什么时候用**:一个 coding task 改完进 review,需要按改动面选层跑回归、把结果作为 acceptance criterion 的 pass/fail 证据。
|
|
19
|
+
|
|
20
|
+
## 工具契约(签名以此为准,先核后用)
|
|
21
|
+
|
|
22
|
+
| 命令 | 作用 | 退出码 |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `apc env doctor` | 环境体检(见 env-doctor skill) | `0` 全绿 · `78` env_blocked |
|
|
25
|
+
| `apc test [--tier=T0,T1] [--diff] [--json] [--list]` | 全层测试编排(包装 `scripts/test203/run.ts`) | `0` 绿 · `1` SUT 红/回归 · `2` 用法错 · `78` env_blocked |
|
|
26
|
+
| `cloud task verify-criterion <task-id> <criterion-id> --outcome <passed\|failed\|n/a\|waived>` | 把一个 criterion 的判定报回 task | 0 成功 |
|
|
27
|
+
|
|
28
|
+
- **`apc test` 的退出码原样透传**,含 `78`。把 78 折成 1 会让下游去重试一个**根本没跑**的圈次——绝不这么干。
|
|
29
|
+
- `--json` 下 stdout 是结构化 `test203.run/v1` 产物,含每层 `TierResult`(命令 / 退出码 / failed names / envStatus)+ baseline diff。**从 stdout JSON 取结果,人读报告在 stderr。**
|
|
30
|
+
|
|
31
|
+
## 选层规则(按改动面)
|
|
32
|
+
|
|
33
|
+
| 改动面 | tier |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `src/lib/**`(纯库 / 单元) | `T0` |
|
|
36
|
+
| `src/im/**`、endpoint / IM 域 | `T1` |
|
|
37
|
+
| `src/app/**` 组件 | `T2` |
|
|
38
|
+
| e2e / 跨端(需 cloud:3000) | `T3` |
|
|
39
|
+
|
|
40
|
+
跨 `src/lib` + endpoint 的改动 → `--tier=T0,T1`。宁可多选一层,不可漏层。
|
|
41
|
+
|
|
42
|
+
## Procedure
|
|
43
|
+
|
|
44
|
+
### 1. 先体检(env doctor,取上下文——**不是**是否跑的最终判据)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
apc env doctor > /tmp/apc-doctor.json; DOC=$?
|
|
48
|
+
echo "doctor exit=$DOC"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`apc env doctor` 是**全局**体检:它 `exit 78` 只表示"存在某个环境红",**不等于你要跑的 tier 被挡**。跑不跑的**权威判据是 `apc test` 自己的退出码**——run.ts 按 tier 做**逐层** env 门(`TIER_ENV_REQUIRES`):
|
|
52
|
+
|
|
53
|
+
| tier | 需要的环境 |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `T0` / `T1` / `T2` / `TD` / `TA` | 无(纯逻辑,不被任何 infra 红挡) |
|
|
56
|
+
| `T3` | `cloud`(:3000) |
|
|
57
|
+
| `T4` | `mysql` + `redis` + `cloud` |
|
|
58
|
+
|
|
59
|
+
所以:doctor 红在**你选的 tier 的 env 需求之外**(典型 `toolchain.node` pin 漂移之于 T0/T1)→ 记一条故障域备注即可,**照跑**。别把全局 78 当作"停"——那会因为一条无关的 toolchain 红漏掉整轮回归。真正的 `env_blocked` 由第 2 步 `apc test` 的 `exit 78` 表达(run.ts 只在**你选的 tier** 的 infra 缺失时才给 78)。
|
|
60
|
+
|
|
61
|
+
### 2. 选层跑(apc test)
|
|
62
|
+
|
|
63
|
+
按上表选层。跨 src/lib + endpoint 的改动:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
apc test --tier=T0,T1 --diff --json > /tmp/apc-test.json; T=$?
|
|
67
|
+
echo "apc test exit=$T"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. 解析 TierResult + 判据
|
|
71
|
+
|
|
72
|
+
从 `/tmp/apc-test.json` 读结构化产物,真实 schema(**字段名以此为准**):
|
|
73
|
+
|
|
74
|
+
- 顶层:`{ schema, doctor, envStatus, tiers:[...], regressions:[...], fixed:[...], exitCode }`。
|
|
75
|
+
- `envStatus`:`ok | env_blocked`(全局)。
|
|
76
|
+
- `regressions[]`:**新增红 vs baseline**(跨所有层的并集)——这是 `--diff` 判据的核心。
|
|
77
|
+
- `fixed[]`:本圈由红转绿的用例。
|
|
78
|
+
- `exitCode`:整轮退出码(与命令退出码一致)。
|
|
79
|
+
- 每个 `tiers[]` 元素:`{ tier, passed, failed, skipped, total, failedNames:[...], envStatus, regressions:[...] }`(**注意是 `failedNames`,且 `command/exitCode` 不在每层——退出码看顶层**)。
|
|
80
|
+
|
|
81
|
+
按 `apc test` 退出码定 criterion outcome:
|
|
82
|
+
|
|
83
|
+
| exit | 含义 | criterion outcome |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `0` | 全绿,无新增红 | `passed` |
|
|
86
|
+
| `1` | 有 SUT 红(`--diff` 下 = 新增红/回归) | `failed`(附 failed names + baseline diff) |
|
|
87
|
+
| `78` | `env_blocked`(某层环境未就绪) | **不判 failed**——回第 1 步,报环境故障域,不计 SUT 红 |
|
|
88
|
+
| `2` | 用法错(tier 名非法等) | 修命令重跑,不报 criterion |
|
|
89
|
+
|
|
90
|
+
**只把"新增红"当回归**:baseline 里已知的红不是本次回归(`--diff` 的退出码只看新增红)。
|
|
91
|
+
|
|
92
|
+
### 4. 报回 task
|
|
93
|
+
|
|
94
|
+
拿到本 task 的 `criterionId`(从 acceptance view),按第 3 步结论上报:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 绿:
|
|
98
|
+
cloud task verify-criterion "$PRISMER_TASK_ID" "<criterion-id>" --outcome passed \
|
|
99
|
+
--note "apc test T0,T1 green; no new reds vs baseline"
|
|
100
|
+
|
|
101
|
+
# 红(附证据):
|
|
102
|
+
cloud task verify-criterion "$PRISMER_TASK_ID" "<criterion-id>" --outcome failed \
|
|
103
|
+
--note "T1 new reds: <failed-name-1>,<failed-name-2>"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
> `verify-criterion` 也支持 `--run` 让服务端下发的 `criterion.execution` 就地执行后按退出码上报——但那条路的命令串来自服务端,本 skill 走的是"本地 `apc test` 选层跑 + 手动上报"这条主路。
|
|
107
|
+
|
|
108
|
+
## 输出契约(机器判据按这个复算,别自由发挥格式)
|
|
109
|
+
|
|
110
|
+
本 skill 的判据不是「报告里出现了 `--diff` / `78` 这些字」,而是**判据自己重解析你贴的产物、重算每层算术、并从真 `scripts/test203/baseline.json` 重推 `regressions[]`**(`structured-criteria.ts` 的 `json-claim`)。所以报告必须带下面两行 + 一段**原样**的 JSON:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
RUN-EXIT: <apc test 的原始退出码:0 | 1 | 78>
|
|
114
|
+
VERDICT: <exit 0 → passed | exit 1 → failed | exit 78 → env-fault>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
紧跟着把 `--json` 的 stdout **一字不改**贴进 fenced json 块:
|
|
118
|
+
|
|
119
|
+
````
|
|
120
|
+
```json
|
|
121
|
+
{ "schema": "test203.run/v1", "timestamp": "…", "envStatus": "…", "tiers": [ … ], "regressions": [ … ], "exitCode": 0 }
|
|
122
|
+
```
|
|
123
|
+
````
|
|
124
|
+
|
|
125
|
+
判据会判红的情况(任一):
|
|
126
|
+
|
|
127
|
+
- 报告里**没有可解析的 fenced JSON**(只有散文「跑绿了」);
|
|
128
|
+
- `RUN-EXIT:` 与产物里的 `exitCode` **不一致**——把红叙述成绿正是这条要抓的;
|
|
129
|
+
- `VERDICT:` 不是**从退出码推出来**的那个:**78 恒 `env-fault`,永远不是 `failed`**(环境故障域不计 SUT 红,这是本 skill 的承重纪律,判据里是硬映射不是措辞);
|
|
130
|
+
- 退出码契约被破坏:`exit 78` 而 `envStatus != env_blocked`、`exit 1` 而 `regressions` 空、`exit 0` 而 `regressions` 非空;
|
|
131
|
+
- 某层的 `passed+failed+skipped != total`,或 `failedNames.length != failed`——**编的计数会露馅**;
|
|
132
|
+
- 本 task 钉的 tier **不在** `tiers[]` 里(跑了别的层顶包);
|
|
133
|
+
- `regressions[]` 与「用真 baseline.json 重算的新增红集合」**不等**:**把新增红藏进已知红**、或**把已知红报成回归**,两个方向都红;
|
|
134
|
+
- 该层的**运行副产物文件不存在**,或它的 mtime 与产物自带的 `timestamp` **相差超过 skew**——「我跑了」但磁盘上没有这一刻的痕迹,判红。
|
|
135
|
+
|
|
136
|
+
**诚实边界**:`freshArtifacts` / `requireItems` 的取值是**按本 sample task 钉的**(TD 层 + `desktop-shell-skip-evidence.txt`),换 tier 必须同步换 args;判据也**不能**证明产物里的数字来自真 vitest——一个肯读 baseline、肯 `touch` 副产物的伪造者仍能构造自洽产物。它杀的是**廉价伪造**(编计数、叙述判定、无痕迹)。
|
|
137
|
+
|
|
138
|
+
## 产出(副作用 oracle,报告里必须给)
|
|
139
|
+
|
|
140
|
+
1. **结构化 TierResult**:顶层 `{envStatus, exitCode}` + 每层 `{tier, passed/failed/skipped/total, failedNames, envStatus}`(取自 `apc test --json` stdout)。
|
|
141
|
+
2. **新增红 vs baseline**:顶层 `regressions[]`(区分"回归"与"从未通过"——baseline 已知红不进这个数组)。
|
|
142
|
+
3. **criterion 上报**:`cloud task verify-criterion` 落库的 outcome 行(可回读 acceptance view 确认)。
|
|
143
|
+
|
|
144
|
+
**不许**:把 `env_blocked`(exit 78)计成 SUT 红去判 criterion failed;把 baseline 已知红当新增红上报;断言聊天文本而非 TierResult 结构字段。
|
|
145
|
+
|
|
146
|
+
<!-- APC-ACK:v1 -->
|
|
147
|
+
|
|
148
|
+
## 调用回执(APC 平台方运营纪律 · 自动注入,勿手改)
|
|
149
|
+
|
|
150
|
+
执行本 skill 的**第一步**,先落一条调用回执:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
cloud skill ack test-runner --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,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"slug": "test-runner",
|
|
4
|
+
"name": "Test Runner",
|
|
5
|
+
"description": "Pick the test tier by change surface, run apc test with baseline diff, report only NEW reds vs baseline back to the task's acceptance criterion, and keep env_blocked out of the SUT verdict.",
|
|
6
|
+
"category": "testing",
|
|
7
|
+
"version": "1.0.0",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"compatibility": ["claude-code"],
|
|
10
|
+
"runtime": {
|
|
11
|
+
"kind": "text-workflow",
|
|
12
|
+
"requires": {
|
|
13
|
+
"env": [],
|
|
14
|
+
"bins": ["node"],
|
|
15
|
+
"capabilities": ["prismer.task.verify-criterion"]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"sampleTasks": [
|
|
19
|
+
{
|
|
20
|
+
"title": "Select tier for a change surface, run apc test --diff, classify new reds vs env_blocked",
|
|
21
|
+
"prompt": "Run the test-runner skill. The `apc` CLI is NOT on PATH — invoke it as `npx tsx sdk/apc/bin/apc.ts <subcommand>` from the repo root (its `--json` stdout is a structured `test203.run/v1` product; the human-readable summary is on stderr). This change touches only apps/desktop, so the matching tier is TD (desktop smoke). Steps: (1) `npx tsx sdk/apc/bin/apc.ts env doctor` first and read the top-level `exitCode` (0 all-green, 78 env_blocked) — a global doctor 78 caused by a check OUTSIDE the tier's own env needs (e.g. a toolchain.node pin drift for a TD/T0 run) is a fault-domain note, NOT a stop; the authoritative per-tier env gate is `apc test`'s own exit 78. (2) `npx tsx sdk/apc/bin/apc.ts test --tier=TD --diff --json` and read its RAW exit code (0 green / 1 SUT red i.e. a NEW red vs baseline under --diff / 78 env_blocked). Parse the JSON: top-level `exitCode`, `envStatus`, `regressions[]` (new reds vs baseline — the --diff verdict), and each `tiers[]` TierResult `{tier, passed, failed, skipped, total, failedNames, envStatus}`. (3) Report a structured TierResult per tier with its passed/failed/skipped counts and envStatus. (4) Apply the verdict rule and state it explicitly: exit 0 => passed; exit 1 => failed with the failedNames + the regressions[] (new reds) list; exit 78 => NOT a failed criterion — surfaced as an environment fault domain (infra/toolchain), never counted as a SUT red. (5) Only NEW reds vs baseline (`regressions[]`) are regressions; baseline known-red entries are NOT reported as new failures. If this run is dispatched inside a kanban task (PRISMER_TASK_ID set) you would finally report the outcome via `npx tsx sdk/cloud/src/cli.ts task verify-criterion \"$PRISMER_TASK_ID\" <criterion-id> --outcome <passed|failed>`; in a plain chat dispatch there is no task criterion, so state that the last-mile report step is N/A here. Report: the tier you selected, the raw apc test exit code, the per-tier pass/fail/skip counts, the regressions[] (new reds) list, and how you classified exit 78 vs a SUT red.\n\n--- YOUR REPORT MUST USE THIS MACHINE-CHECKED OUTPUT CONTRACT. The pasted product is re-parsed, its per-tier arithmetic is recomputed, `regressions[]` is re-derived from the real `scripts/test203/baseline.json`, and the run byproduct on disk is compared against the run's own timestamp. Narrating an outcome the product does not carry FAILS:\n\n```\nRUN-EXIT: <the raw exit code of apc test — 0 | 1 | 78>\nVERDICT: <passed if exit 0 | failed if exit 1 | env-fault if exit 78>\n```\n\nimmediately followed by the RAW `--json` stdout, verbatim, in a fenced json block:\n\n```json\n{ \"schema\": \"test203.run/v1\", \"timestamp\": \"…\", \"envStatus\": \"…\", \"tiers\": [ … ], \"regressions\": [ … ], \"exitCode\": 0 }\n```\n\nHARD RULES: paste the product UNEDITED (do not prune fields, do not pretty-rewrite numbers). `VERDICT` is a pure function of the exit code — 78 is `env-fault`, never `failed`. Do not reorder or re-label `regressions[]`: a NEW red hidden inside the baseline known-reds, or a baseline known-red reported as a regression, are both caught by recomputation.",
|
|
22
|
+
"expectedArtifacts": [
|
|
23
|
+
"apc env doctor top-level exitCode (0 or 78) read as a fault-domain note, not an automatic stop",
|
|
24
|
+
"apc test --tier=TD --diff --json raw exit code (0 green / 1 new-red / 78 env_blocked)",
|
|
25
|
+
"structured TierResult per tier: tier, passed/failed/skipped/total, failedNames, envStatus",
|
|
26
|
+
"regressions[] = new reds vs baseline (distinct from baseline known-red); env_blocked kept out of the SUT verdict"
|
|
27
|
+
],
|
|
28
|
+
"acceptanceCriteria": [
|
|
29
|
+
{
|
|
30
|
+
"label": "the report pastes the RAW test203.run/v1 product of a run that really happened: the pinned tier is in it, every tier's counts add up, and the run's own byproduct on disk is contemporaneous with the run's timestamp",
|
|
31
|
+
"type": "structured",
|
|
32
|
+
"checker": "json-claim",
|
|
33
|
+
"args": {
|
|
34
|
+
"equals": { "schema": "test203.run/v1" },
|
|
35
|
+
"require": ["exitCode", "envStatus", "tiers", "regressions", "timestamp"],
|
|
36
|
+
"types": { "exitCode": "number", "tiers": "array", "regressions": "array", "timestamp": "string" },
|
|
37
|
+
"allowed": { "exitCode": [0, 1, 78], "envStatus": ["ok", "env_blocked"] },
|
|
38
|
+
"declaredLines": { "RUN-EXIT": "exitCode" },
|
|
39
|
+
"requireItems": { "path": "tiers", "key": "tier", "values": ["TD"] },
|
|
40
|
+
"eachItem": {
|
|
41
|
+
"path": "tiers",
|
|
42
|
+
"sum": { "parts": ["passed", "failed", "skipped"], "total": "total" },
|
|
43
|
+
"lengths": { "failedNames": "failed" }
|
|
44
|
+
},
|
|
45
|
+
"freshArtifacts": {
|
|
46
|
+
"timestampPath": "timestamp",
|
|
47
|
+
"paths": ["scripts/test203/artifacts/desktop-shell-skip-evidence.txt"],
|
|
48
|
+
"skewMinutes": 10
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"match": "<structured:json-claim>",
|
|
52
|
+
"required": true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"label": "the verdict is DERIVED from the raw exit code (78 is an env fault domain, never a SUT red) and regressions[] is recomputed from the real baseline.json — a new red cannot be passed off as a known red, nor a known red as a regression",
|
|
56
|
+
"type": "structured",
|
|
57
|
+
"checker": "json-claim",
|
|
58
|
+
"args": {
|
|
59
|
+
"equals": { "schema": "test203.run/v1" },
|
|
60
|
+
"derivedLines": {
|
|
61
|
+
"VERDICT": { "from": "exitCode", "map": { "0": "passed", "1": "failed", "78": "env-fault" } }
|
|
62
|
+
},
|
|
63
|
+
"implications": [
|
|
64
|
+
{ "if": { "path": "exitCode", "equals": 78 }, "then": { "path": "envStatus", "equals": "env_blocked" } },
|
|
65
|
+
{ "if": { "path": "exitCode", "equals": 1 }, "then": { "path": "regressions", "nonEmpty": true } },
|
|
66
|
+
{ "if": { "path": "exitCode", "equals": 0 }, "then": { "path": "regressions", "empty": true } }
|
|
67
|
+
],
|
|
68
|
+
"baselineRecompute": {
|
|
69
|
+
"file": "scripts/test203/baseline.json",
|
|
70
|
+
"itemsPath": "tiers",
|
|
71
|
+
"failedNamesKey": "failedNames",
|
|
72
|
+
"regressionsPath": "regressions"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"match": "<structured:json-claim>",
|
|
76
|
+
"required": true
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"label": "last-mile cloud verify-criterion report (task-bound only)",
|
|
80
|
+
"match": "(verify-criterion|criterion|report\\s+back|last[- ]mile|上报|回报|n/?a)",
|
|
81
|
+
"type": "regex",
|
|
82
|
+
"required": false
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"security": {
|
|
88
|
+
"dataAccess": ["local-filesystem", "workspace-tasks"],
|
|
89
|
+
"humanApprovalRequiredFor": []
|
|
90
|
+
},
|
|
91
|
+
"provenance": {
|
|
92
|
+
"sourceKind": "inline-spec",
|
|
93
|
+
"sourceRefs": [
|
|
94
|
+
"docs/apc/12-skill-acceptance-tasks.md",
|
|
95
|
+
"docs/apc/05-devchain-gaps-and-skills.md",
|
|
96
|
+
"docs/apc/02-test-rebuild.md",
|
|
97
|
+
"sdk/apc/cli/test-run.ts",
|
|
98
|
+
"sdk/cloud/src/commands/task.ts"
|
|
99
|
+
],
|
|
100
|
+
"authoredBy": "prismer-platform",
|
|
101
|
+
"authoredAt": "2026-07-24T00:00:00Z"
|
|
102
|
+
}
|
|
103
|
+
}
|