@peterxiaoyang/superspec 0.1.42 → 0.1.44
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/dist/format.d.ts +0 -1
- package/dist/format.js +3 -13
- package/dist/git_state.js +1 -1
- package/dist/phase_confirmation.js +32 -4
- package/dist/phase_plan.d.ts +1 -1
- package/dist/phase_plan.js +50 -26
- package/dist/record.js +102 -18
- package/dist/review.d.ts +48 -1
- package/dist/review.js +90 -2
- package/dist/review_job_gates.d.ts +5 -0
- package/dist/review_job_gates.js +52 -1
- package/dist/sync.js +0 -1
- package/dist/transition.js +10 -9
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/templates/workflow/agents/executor.toml +1 -1
- package/templates/workflow/agents/test-runner.toml +1 -1
- package/templates/workflow/prompts/architect.md +18 -8
- package/templates/workflow/prompts/critic.md +21 -11
- package/templates/workflow/prompts/test-engineer.md +17 -8
- package/templates/workflow/prompts/test-runner.md +1 -1
- package/templates/workflow/skills/superspec-apply/SKILL.md +1 -1
- package/templates/workflow/skills/superspec-explore/SKILL.md +2 -0
- package/templates/workflow/skills/superspec-propose/SKILL.md +21 -36
package/dist/review.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { docRef, sha256File, sha256Text } from "./store.js";
|
|
5
|
-
import { EXPLORE_DISCOVERY_REVIEW_GATE_ID, PROPOSE_FINAL_REVIEW_GATE_ID, REVIEW_FINAL_VERIFIER_GATE, } from "./review_job_gates.js";
|
|
5
|
+
import { EXPLORE_DISCOVERY_REVIEW_GATE_ID, PROPOSE_FINAL_REVIEW_GATE, PROPOSE_FINAL_REVIEW_GATE_ID, REVIEW_FINAL_VERIFIER_GATE, } from "./review_job_gates.js";
|
|
6
6
|
import { computeCodeStateCheck, effectiveCoverageExemptionRefsFromEvents } from "./code_review.js";
|
|
7
7
|
export const REVIEW_DOC_PATHS = [
|
|
8
8
|
"proposal.md",
|
|
@@ -10,7 +10,6 @@ export const REVIEW_DOC_PATHS = [
|
|
|
10
10
|
"design.md",
|
|
11
11
|
"specs/",
|
|
12
12
|
".superspec/artifacts/discovery.md",
|
|
13
|
-
".superspec/artifacts/business-invariants.md",
|
|
14
13
|
".superspec/artifacts/test-contract.md",
|
|
15
14
|
];
|
|
16
15
|
const CORE_COMMIT_FIELDS = new Set([
|
|
@@ -59,6 +58,17 @@ function reviewResultKind(value) {
|
|
|
59
58
|
? value
|
|
60
59
|
: null;
|
|
61
60
|
}
|
|
61
|
+
export const REVIEW_REJECTION_OVERRIDE_SCOPE_PREFIX = "review_rejection_override:";
|
|
62
|
+
export const REVIEW_REJECTION_OVERRIDE_ANSWER = "do_not_block";
|
|
63
|
+
export function reviewRejectionOverrideScope(jobId) {
|
|
64
|
+
return `${REVIEW_REJECTION_OVERRIDE_SCOPE_PREFIX}${jobId}`;
|
|
65
|
+
}
|
|
66
|
+
export function parseReviewRejectionOverrideScope(scope) {
|
|
67
|
+
if (!scope.startsWith(REVIEW_REJECTION_OVERRIDE_SCOPE_PREFIX))
|
|
68
|
+
return null;
|
|
69
|
+
const jobId = scope.slice(REVIEW_REJECTION_OVERRIDE_SCOPE_PREFIX.length).trim();
|
|
70
|
+
return jobId === "" ? null : jobId;
|
|
71
|
+
}
|
|
62
72
|
function reviewCycleState(gate) {
|
|
63
73
|
if (gate.gate_id === EXPLORE_DISCOVERY_REVIEW_GATE_ID)
|
|
64
74
|
return "explore";
|
|
@@ -109,6 +119,7 @@ function reviewTerminalResultsForGateRole(events, gate, role) {
|
|
|
109
119
|
const findings = Array.isArray(payload.findings) ? payload.findings : undefined;
|
|
110
120
|
results.push({
|
|
111
121
|
job,
|
|
122
|
+
event,
|
|
112
123
|
state: event.event_type === "job_accepted" ? "accepted" : "rejected",
|
|
113
124
|
...(event.event_type === "job_rejected"
|
|
114
125
|
? { result_kind: reviewResultKind(payload.result_kind) ?? (findings ? "review_failed" : "invalid_report") }
|
|
@@ -119,6 +130,69 @@ function reviewTerminalResultsForGateRole(events, gate, role) {
|
|
|
119
130
|
}
|
|
120
131
|
return results;
|
|
121
132
|
}
|
|
133
|
+
export function latestReviewTerminalForGateRole(events, gate, role) {
|
|
134
|
+
return reviewTerminalResultsForGateRole(events, gate, role).at(-1) ?? null;
|
|
135
|
+
}
|
|
136
|
+
function validReviewRejectionOverridePayload(event, terminal, gate) {
|
|
137
|
+
if (event.event_type !== "user_decision_recorded")
|
|
138
|
+
return null;
|
|
139
|
+
const payload = event.payload;
|
|
140
|
+
if (payload.accepted !== true ||
|
|
141
|
+
payload.scope !== reviewRejectionOverrideScope(terminal.job.job_id) ||
|
|
142
|
+
payload.answer !== REVIEW_REJECTION_OVERRIDE_ANSWER ||
|
|
143
|
+
(payload.decision_source !== "main_process" && payload.decision_source !== "user") ||
|
|
144
|
+
typeof payload.reason !== "string" || payload.reason.trim() === "" ||
|
|
145
|
+
!payload.review_rejection_override ||
|
|
146
|
+
typeof payload.review_rejection_override !== "object" ||
|
|
147
|
+
Array.isArray(payload.review_rejection_override))
|
|
148
|
+
return null;
|
|
149
|
+
const audit = payload.review_rejection_override;
|
|
150
|
+
if (audit.job_id !== terminal.job.job_id ||
|
|
151
|
+
audit.role !== terminal.job.role ||
|
|
152
|
+
audit.gate_id !== gate.gate_id ||
|
|
153
|
+
audit.packet_digest !== terminal.job.packet_digest)
|
|
154
|
+
return null;
|
|
155
|
+
return {
|
|
156
|
+
job_id: terminal.job.job_id,
|
|
157
|
+
role: terminal.job.role,
|
|
158
|
+
gate_id: gate.gate_id,
|
|
159
|
+
packet_digest: terminal.job.packet_digest,
|
|
160
|
+
decision_source: payload.decision_source,
|
|
161
|
+
reason: payload.reason.trim(),
|
|
162
|
+
decision_event_id: event.event_id,
|
|
163
|
+
decision_event_digest: event.event_digest,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
export function effectiveReviewRejectionOverride(events, gate, terminal) {
|
|
167
|
+
const cycleStartIndex = currentReviewGateCycleStart(events, gate);
|
|
168
|
+
if (cycleStartIndex == null)
|
|
169
|
+
return null;
|
|
170
|
+
const terminalIndex = events.findIndex(event => event.event_id === terminal.event.event_id);
|
|
171
|
+
if (terminalIndex < cycleStartIndex)
|
|
172
|
+
return null;
|
|
173
|
+
for (let i = events.length - 1; i > terminalIndex; i--) {
|
|
174
|
+
const audit = validReviewRejectionOverridePayload(events[i], terminal, gate);
|
|
175
|
+
if (audit)
|
|
176
|
+
return audit;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
export function reviewGateRoleResolution(events, changeRoot, gate, role) {
|
|
181
|
+
const terminal = latestReviewTerminalForGateRole(events, gate, role);
|
|
182
|
+
if (!terminal)
|
|
183
|
+
return { kind: "none" };
|
|
184
|
+
const staleReason = boundFilesStaleReason(terminal.job, changeRoot);
|
|
185
|
+
if (staleReason)
|
|
186
|
+
return { kind: "stale", terminal, stale_reason: staleReason };
|
|
187
|
+
if (terminal.state === "accepted")
|
|
188
|
+
return { kind: "accepted", terminal };
|
|
189
|
+
if (terminal.result_kind !== "review_failed")
|
|
190
|
+
return { kind: "rejected_invalid", terminal };
|
|
191
|
+
const override = effectiveReviewRejectionOverride(events, gate, terminal);
|
|
192
|
+
return override
|
|
193
|
+
? { kind: "overridden", terminal, override }
|
|
194
|
+
: { kind: "rejected_pending", terminal };
|
|
195
|
+
}
|
|
122
196
|
export function latestReviewHistoryForGateRole(events, gate, role) {
|
|
123
197
|
const terminalResults = reviewTerminalResultsForGateRole(events, gate, role);
|
|
124
198
|
const latest = terminalResults.at(-1);
|
|
@@ -156,6 +230,20 @@ export function latestReviewHistoryForGateRole(events, gate, role) {
|
|
|
156
230
|
job_id: latest.job.job_id,
|
|
157
231
|
};
|
|
158
232
|
}
|
|
233
|
+
export function historicalProposeReadyRoles(events) {
|
|
234
|
+
const roles = new Set();
|
|
235
|
+
for (const event of events) {
|
|
236
|
+
if (event.event_type !== "transition_commit")
|
|
237
|
+
continue;
|
|
238
|
+
const jobs = event.payload.new_jobs ?? [];
|
|
239
|
+
for (const job of jobs) {
|
|
240
|
+
if (PROPOSE_FINAL_REVIEW_GATE.isJobForGate(job) &&
|
|
241
|
+
(job.role === "critic" || job.role === "architect" || job.role === "test-engineer"))
|
|
242
|
+
roles.add(job.role);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return [...roles];
|
|
246
|
+
}
|
|
159
247
|
export function isReviewReadyVerifier(job) {
|
|
160
248
|
return job.role === "verifier" && REVIEW_FINAL_VERIFIER_GATE.isJobForGate(job);
|
|
161
249
|
}
|
|
@@ -15,6 +15,11 @@ export declare const EXPLORE_DISCOVERY_REVIEW_GATE_ID: "explore.discovery_review
|
|
|
15
15
|
export declare const PROPOSE_FINAL_REVIEW_GATE_ID: "propose.final_review";
|
|
16
16
|
export declare const REVIEW_CODE_REVIEW_GATE_ID: "review.code_review";
|
|
17
17
|
export declare const REVIEW_FINAL_VERIFIER_GATE_ID: "review.final_verifier";
|
|
18
|
+
export declare function reviewScopeForGateRole(gate: ReviewGateRule, role: JobRole): {
|
|
19
|
+
reviewTargets: string[];
|
|
20
|
+
readOnlyRefs: string[];
|
|
21
|
+
boundPaths: string[];
|
|
22
|
+
};
|
|
18
23
|
export declare const EXPLORE_DISCOVERY_REVIEW_GATE: ReviewGateRule;
|
|
19
24
|
export declare const PROPOSE_FINAL_REVIEW_GATE: ReviewGateRule;
|
|
20
25
|
export declare const REVIEW_CODE_REVIEW_GATE: ReviewGateRule;
|
package/dist/review_job_gates.js
CHANGED
|
@@ -19,6 +19,58 @@ export const EXPLORE_DISCOVERY_REVIEW_GATE_ID = "explore.discovery_review";
|
|
|
19
19
|
export const PROPOSE_FINAL_REVIEW_GATE_ID = "propose.final_review";
|
|
20
20
|
export const REVIEW_CODE_REVIEW_GATE_ID = "review.code_review";
|
|
21
21
|
export const REVIEW_FINAL_VERIFIER_GATE_ID = "review.final_verifier";
|
|
22
|
+
function defaultReviewScope(gate) {
|
|
23
|
+
return {
|
|
24
|
+
reviewTargets: [...gate.reviewTargets],
|
|
25
|
+
readOnlyRefs: [...gate.readOnlyRefs],
|
|
26
|
+
boundPaths: [...new Set([...gate.reviewTargets, ...gate.readOnlyRefs])],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function reviewScopeForGateRole(gate, role) {
|
|
30
|
+
if (gate.gate_id !== PROPOSE_FINAL_REVIEW_GATE_ID)
|
|
31
|
+
return defaultReviewScope(gate);
|
|
32
|
+
if (role === "critic") {
|
|
33
|
+
const reviewTargets = ["proposal.md", "specs/", "tasks.md"];
|
|
34
|
+
const readOnlyRefs = [
|
|
35
|
+
"design.md",
|
|
36
|
+
".superspec/artifacts/test-contract.md",
|
|
37
|
+
".superspec/artifacts/discovery.md",
|
|
38
|
+
];
|
|
39
|
+
return {
|
|
40
|
+
reviewTargets,
|
|
41
|
+
readOnlyRefs,
|
|
42
|
+
boundPaths: [...reviewTargets, ".superspec/artifacts/discovery.md"],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (role === "architect") {
|
|
46
|
+
const reviewTargets = ["design.md"];
|
|
47
|
+
return {
|
|
48
|
+
reviewTargets,
|
|
49
|
+
readOnlyRefs: [
|
|
50
|
+
"proposal.md",
|
|
51
|
+
"specs/",
|
|
52
|
+
"tasks.md",
|
|
53
|
+
".superspec/artifacts/discovery.md",
|
|
54
|
+
".superspec/artifacts/test-contract.md",
|
|
55
|
+
],
|
|
56
|
+
boundPaths: [...reviewTargets],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (role === "test-engineer") {
|
|
60
|
+
const reviewTargets = [".superspec/artifacts/test-contract.md", "tasks.md"];
|
|
61
|
+
return {
|
|
62
|
+
reviewTargets,
|
|
63
|
+
readOnlyRefs: [
|
|
64
|
+
"proposal.md",
|
|
65
|
+
"specs/",
|
|
66
|
+
"design.md",
|
|
67
|
+
".superspec/artifacts/discovery.md",
|
|
68
|
+
],
|
|
69
|
+
boundPaths: [...reviewTargets],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return defaultReviewScope(gate);
|
|
73
|
+
}
|
|
22
74
|
const EXPLORE_DISCOVERY_REVIEW_ROLES = ["critic"];
|
|
23
75
|
const PROPOSAL_REVIEW_ROLES = ["critic", "architect", "test-engineer"];
|
|
24
76
|
const PROPOSAL_REVIEW_ROLE_SET = new Set(PROPOSAL_REVIEW_ROLES);
|
|
@@ -46,7 +98,6 @@ export const PROPOSE_FINAL_REVIEW_GATE = makeReviewGateRule({
|
|
|
46
98
|
"tasks.md",
|
|
47
99
|
"design.md",
|
|
48
100
|
"specs/",
|
|
49
|
-
".superspec/artifacts/business-invariants.md",
|
|
50
101
|
".superspec/artifacts/test-contract.md",
|
|
51
102
|
],
|
|
52
103
|
readOnlyRefs: [".superspec/artifacts/discovery.md"],
|
package/dist/sync.js
CHANGED
|
@@ -7,7 +7,6 @@ import { invalidReasonForSnapshot } from "./job_validity.js";
|
|
|
7
7
|
const TRACKED_DOCS = [
|
|
8
8
|
"proposal.md", "design.md", "tasks.md", "specs/",
|
|
9
9
|
".superspec/artifacts/discovery.md",
|
|
10
|
-
".superspec/artifacts/business-invariants.md",
|
|
11
10
|
".superspec/artifacts/test-contract.md",
|
|
12
11
|
];
|
|
13
12
|
/** 从 events.jsonl 推导:当前状态、jobs、attempts、pending decisions */
|
package/dist/transition.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ensureChangeLayout, readEvents, appendEvent, makeEvent, writeSnapshot,
|
|
|
5
5
|
import { rebuildSnapshot } from "./sync.js";
|
|
6
6
|
import { requiredJobActions } from "./job_action.js";
|
|
7
7
|
import { assertCommitPayloadExtension, isFreshReviewVerifier, isReviewReadyVerifier, latestReviewHistoryForGateRole, readReviewPolicyFromEvents, reviewBoundFiles, reviewEvidenceDigest, reviewPolicyForRisk, REVIEW_DOC_PATHS, } from "./review.js";
|
|
8
|
-
import { REVIEW_CODE_REVIEW_GATE_ID, REVIEW_FINAL_VERIFIER_GATE_ID, } from "./review_job_gates.js";
|
|
8
|
+
import { REVIEW_CODE_REVIEW_GATE_ID, REVIEW_FINAL_VERIFIER_GATE_ID, reviewScopeForGateRole, } from "./review_job_gates.js";
|
|
9
9
|
import { codeReviewBoundFiles, codeReviewDecisionScope, codeReviewJobStaleReason, codeReviewPacketContext, codeReviewPacketDigest, collectCodeReviewGateFacts, computeCodeStateCheck, currentCodeReviewWorkingPaths, dismissedCodeReviewSummary, latestCodeReviewDecision, latestCodeReviewFailedStatus, missingCoverageExemptionTestIds, requiresFinalVerifierForCurrentReview, scanCodeChangesForReview, } from "./code_review.js";
|
|
10
10
|
import { taskEvidenceReadiness } from "./task_evidence.js";
|
|
11
11
|
import { adoptedContractForTask, findTaskInLines, isReviewFixTaskId, parseTasksMd, parseTestContractEntries, } from "./format.js";
|
|
@@ -18,8 +18,9 @@ let jobSeq = 0;
|
|
|
18
18
|
function newJobId(change, role) { return `JOB-${change.slice(0, 8)}-${role.slice(0, 4)}-${Date.now()}-${++jobSeq}`; }
|
|
19
19
|
function createReviewJobsForGate(state, gate, roles, changeRoot, change, reason, events) {
|
|
20
20
|
const newJobs = roles.map(role => {
|
|
21
|
-
const
|
|
22
|
-
//
|
|
21
|
+
const scope = reviewScopeForGateRole(gate, role);
|
|
22
|
+
// 角色职责目标和显式 freshness 路径绑定时点指纹:单文件缺失使用 sha256:missing,目录缺失使用稳定空指纹。
|
|
23
|
+
const boundPaths = [...new Set(scope.boundPaths)];
|
|
23
24
|
const boundFiles = boundPaths
|
|
24
25
|
.map(p => docRef(changeRoot, p));
|
|
25
26
|
const previousRejection = latestReviewHistoryForGateRole(events, gate, role);
|
|
@@ -29,14 +30,14 @@ function createReviewJobsForGate(state, gate, roles, changeRoot, change, reason,
|
|
|
29
30
|
state: "requested",
|
|
30
31
|
gate_id: gate.gate_id,
|
|
31
32
|
boundFiles,
|
|
32
|
-
...(
|
|
33
|
-
...(
|
|
33
|
+
...(scope.reviewTargets.length > 0 ? { review_targets: [...scope.reviewTargets] } : {}),
|
|
34
|
+
...(scope.readOnlyRefs.length > 0 ? { read_only_refs: [...scope.readOnlyRefs] } : {}),
|
|
34
35
|
packet_digest: sha256Text(JSON.stringify({
|
|
35
36
|
role,
|
|
36
37
|
gate_id: gate.gate_id,
|
|
37
38
|
boundFiles,
|
|
38
|
-
review_targets:
|
|
39
|
-
read_only_refs:
|
|
39
|
+
review_targets: scope.reviewTargets,
|
|
40
|
+
read_only_refs: scope.readOnlyRefs,
|
|
40
41
|
created_from_transition: gate.created_from_transition,
|
|
41
42
|
...(previousRejection ? { previous_rejection: previousRejection } : {}),
|
|
42
43
|
})),
|
|
@@ -440,7 +441,7 @@ function transitionPlanToDecision(snapshot, changeRoot, change, plan, events) {
|
|
|
440
441
|
case "skip":
|
|
441
442
|
return { skip: true, message: plan.message };
|
|
442
443
|
case "blocked":
|
|
443
|
-
return { blocked: true, reason: plan.reason, jobs: plan.jobs };
|
|
444
|
+
return { blocked: true, reason: plan.reason, jobs: plan.jobs, ...(plan.details ? { details: plan.details } : {}) };
|
|
444
445
|
case "create_gate_jobs":
|
|
445
446
|
return createReviewJobsForGate(snapshot.state, plan.gate, plan.roles, changeRoot, change, plan.reason, events);
|
|
446
447
|
case "advance":
|
|
@@ -483,7 +484,7 @@ export function commitTransition(projectRoot, change, changeRoot, opts) {
|
|
|
483
484
|
from_state: snapshot.state,
|
|
484
485
|
to_state: snapshot.state,
|
|
485
486
|
created_jobs: [],
|
|
486
|
-
required_jobs: requiredJobActions(change, decision.jobs),
|
|
487
|
+
...(decision.jobs.length > 0 ? { required_jobs: requiredJobActions(change, decision.jobs) } : {}),
|
|
487
488
|
message: decision.reason,
|
|
488
489
|
events_written: 0,
|
|
489
490
|
...(decision.details ? { details: decision.details } : {}),
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -9,5 +9,5 @@ Task binding: load `.codex/prompts/executor.md` first, then read the current tas
|
|
|
9
9
|
|
|
10
10
|
Boundary: mutating but bounded. Edit only paths listed in `declared_task_write_scope`; do not edit OpenSpec artifacts, `.superspec/**`, task checkboxes, evidence, review reports, or archives. Stop and report blockers when scope or context is insufficient.
|
|
11
11
|
|
|
12
|
-
Output: concise Simplified Chinese implementation report with changed files, task/test
|
|
12
|
+
Output: concise Simplified Chinese implementation report with changed files, task/test mapping, suggested GREEN checks, artifact refs, and residual risk.
|
|
13
13
|
"""
|
|
@@ -9,5 +9,5 @@ Task binding: load `.codex/prompts/test-runner.md` first, then read the current
|
|
|
9
9
|
|
|
10
10
|
Boundary: read-only by default. Do not edit production code, OpenSpec artifacts, `.superspec/**`, task checkboxes, evidence, review reports, or archives. Run only the allowed command from current task instructions and report blockers for missing command, unsafe side effects, or incomplete raw transcript refs.
|
|
11
11
|
|
|
12
|
-
Output: concise Simplified Chinese test report with command, cwd, phase, task/test id, exit status, semantic status candidate, result summary, raw transcript ref, repo head, dirty-state summary,
|
|
12
|
+
Output: concise Simplified Chinese test report with command, cwd, phase, task/test id, exit status, semantic status candidate, result summary, raw transcript ref, repo head, dirty-state summary, guard fingerprint, and unverified items.
|
|
13
13
|
"""
|
|
@@ -9,31 +9,41 @@ argument-hint: "本次架构审查说明"
|
|
|
9
9
|
|
|
10
10
|
你是 Architect。你审查系统边界、接口契约、数据流、长期维护风险、回滚难度和设计取舍。只读审查,不修改文件,不替主流程做最终判断。
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 执行协议
|
|
13
13
|
|
|
14
14
|
- 先读 job packet 和任务说明;材料、范围、报告格式、提交方式和停止条件以 job packet 为准。
|
|
15
15
|
- 不评价没有打开或未被 job packet、主流程 refs 指向的材料;需要扩大审查范围时向主流程说明缺口,不自行改派或改代码。
|
|
16
|
-
- 若 job packet
|
|
17
|
-
- JSON 报告按 job packet
|
|
16
|
+
- 若 job packet 带有上次拒绝原因,本次是修复复核:优先判断原问题是否仍成立,不借复核重新展开与修复无直接因果关系的故障模型或历史设计议题。
|
|
17
|
+
- JSON 报告按 job packet 规定的字段、格式和提交方式输出;报告结论必须与 findings 的阻塞性一致。
|
|
18
|
+
|
|
19
|
+
## 审查边界与停止条件
|
|
20
|
+
|
|
21
|
+
- 只有问题同时满足“由本次 change 新增、修改或明确依赖”“有当前材料或代码的直接证据”“会影响已声明验收或使实现无法落地”时,才作为阻塞架构问题并使用 `verdict:"fail"`;不满足时省略或列为非阻塞观察。
|
|
22
|
+
- 目标是验证已声明方案能否以最小、可落地的设计满足本次验收,不是把系统升级为理想架构,也不是穷举理论上可能发生的故障。
|
|
23
|
+
- 基础设施不可用、外部调用失败、并发或乱序、进程中断等通用故障,只有在本次 change 明确新增或改变对应保证,或直接证据证明当前接入无法满足用户已确认的强制需求、规格约束或明确验收结果时才适用。不得仅因理论上可能发生就要求单独设计、task 或测试,也不得自行新增或升级强制要求。
|
|
24
|
+
- 声明复用现有机制时,只核对复用对象、接入位置、本次差异和保持不变的语义;不重新证明该机制的一般可靠性。若接入确实绕过或破坏既有契约,只报告无法满足的具体契约,不得把未经确认的新基础设施、可靠性模式或版本协调机制本身写成 required fix。
|
|
25
|
+
- 用户决定和 design 的明确非目标约束方案取舍;若新证据证明其事实前提不成立,只报告事实冲突及验收影响,不直接恢复已被排除的路线。
|
|
26
|
+
- recommendation 只能描述需要补足的结果、契约或证据;除非 proposal、design 或用户决定已经选定某项机制,否则不得指定新的基础设施或可靠性模式。推荐方案不是 finding 成立的证据。
|
|
27
|
+
- 已确认复用路线、接入位置明确、没有新的用户可观察语义且已满足本次验收时停止向更底层展开;不从一个故障场景递归推导下一层基础设施设计。
|
|
18
28
|
|
|
19
29
|
## 计划 / 设计审查口径
|
|
20
30
|
|
|
21
31
|
重点审查技术方案是否可落地、系统责任边界是否合理、关键设计契约是否充分。文档结构、跨文档登记和 task 格式由 Critic 主责;测试可验证性由 Test Engineer 主责。不要重复报告纯标题、空章节、复述、task ID / 顺序或 TEST 映射格式问题,但发现真实技术影响未登记时仍须直接报告。
|
|
22
32
|
|
|
23
33
|
- `design.md` 的代码影响型能力应有技术上可行的实现路线,说明方案落在哪个系统责任边界,以及本次实际涉及的数据、接口、状态或控制流如何变化;缺少到实现者无法落地时必须 `verdict:"fail"`
|
|
24
|
-
-
|
|
34
|
+
- 当本次 change 确实新增或改变行为、字段组、数据语义、接口兼容、状态转换、优先级、一致性、事务 / 幂等 / 并发、恢复结果或关键算法语义,且不同选择会影响已声明验收时,design 才需要明确对应绑定性契约;仍需实现者自行选择会改变验收结果的关键语义时应失败。未被本次 change 改变的既有语义不要求重新设计。逐行代码、完整 SQL,以及以文件修改、task 执行或测试操作为对象的机械清单不属于 design;算法阶段、数据 / 控制流、状态转换和事务顺序可以有序表达
|
|
25
35
|
- discovery / proposal / specs 中影响实现的事实和约束必须转成具体设计安排;只罗列材料、关键约束未进入方案,或方案建立在与已确认事实不符的假设上时,必须 `verdict:"fail"`
|
|
26
36
|
- 声明复用现有链路时,应能确认复用对象、接入位置、本次差异和保持不变的语义;重复上游已有变形、增加双重兜底或改变持久化语义却没有明确理由时,应失败。改变已确认的规则变形或持久化语义时,不仅要说明理由和边界,还必须明确声明为本次目标,并与 proposal、specs 和 Impact 按适用范围完成对账
|
|
27
37
|
- 多个功能点共享字段组、接口语义、状态机、优先级或一致性规则时,应形成统一契约;不同方案对同一契约给出冲突解释时,应失败
|
|
28
38
|
- 关键路线未定且未进入 `## 待用户确认`,或 `tasks.md` 无法从实现方案和边界约束中技术性推出时,必须失败
|
|
29
|
-
-
|
|
39
|
+
- 不按固定章节判定设计质量,也不要要求虚假替代方案或风险。只有存在具体触发条件、当前证据和用户 / 系统可观察影响的明显误走路线,或本次 change 已确认涉及的共享契约、兼容、回滚、发布顺序仍无法落地时,才可失败;长期可能性、通用故障模型和未改变的既有风险不作为 blocker。只有不影响方案落地和边界判定、但仍值得关注的问题才列为非阻塞风险
|
|
30
40
|
- discovery 含 `## 输入数据来源核查` 时,数据来源必须追到目标字段或集合最后一次改变形态的位置;输入完整性方案与 consumer 获得完整输入后的算法方案必须分开说明
|
|
31
41
|
- `IDC-xxx` 为 `未知阻塞` 时 design 不得 ready;为 `未知非阻塞` 时,理由必须在技术上成立,并绑定验收口径或反例
|
|
32
42
|
- discovery 含 `## 链路五要素` 时,方案不得违背已确认的来源、规则变形、持久化语义、消费者或视图差异;确需重复防御或二次变形时必须说明原因和边界
|
|
33
|
-
-
|
|
43
|
+
- 有直接证据证明某个系统边界、消费者、视图差异或用户 / 系统可观察行为会被本次 change 改变,但 Impact 未登记且无排除理由,并且该遗漏会影响明确验收或使实现无法落地时,才判为 Impact / design 对账缺口;仅被检查但行为不变的范围、纯测试脆弱性和实现复杂度不要求进入 Impact
|
|
34
44
|
- 输入来源修复不得无说明地扩大相邻规则、查询、缓存或数据形态的语义
|
|
35
|
-
- task 的 `设计` 引用应指向技术上可行的实现方案、共享契约或边界约束;`边界` 应保护具体系统行为、数据语义、外部接口或共享规则。引用存在但方案不可行、边界与 design / Impact
|
|
36
|
-
- task
|
|
45
|
+
- task 的 `设计` 引用应指向技术上可行的实现方案、共享契约或边界约束;`边界` 应保护具体系统行为、数据语义、外部接口或共享规则。引用存在但方案不可行、边界与 design / Impact 冲突,或有直接证据证明本次 change 改变的关键边界未被保护且会影响明确验收时,应失败
|
|
46
|
+
- task 分组应符合本次 change 实际涉及的系统责任边界;只有多个独立行为、跨入口改动或大改动确实无法在一个 RED/GREEN 闭环中独立验证时才要求拆分,不因模块通常被视为高风险就机械增加 task
|
|
37
47
|
|
|
38
48
|
## 输出风格
|
|
39
49
|
|
|
@@ -9,33 +9,44 @@ argument-hint: "本次反方审查说明"
|
|
|
9
9
|
|
|
10
10
|
你是 Critic。你做前置反方审查:用证据挑战 discovery、proposal、design、tasks 是否足以进入下一阶段,重点找隐藏假设、范围漂移、验收漏洞、业务语义风险和证据跳读。只读审查,不替主流程决策。
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 执行协议
|
|
13
13
|
|
|
14
14
|
- 先读 job packet 和任务说明;材料、范围、报告格式、提交方式和停止条件以 job packet 为准。
|
|
15
15
|
- 必须打开被引用文件或 refs 后再判断。
|
|
16
|
-
- 不自行扩展审查范围;本 prompt 明确列入核对范围的材料(如 Proposal 审查中的 `specs/`)属于既定范围,不算扩展。若 job packet
|
|
16
|
+
- 不自行扩展审查范围;本 prompt 明确列入核对范围的材料(如 Proposal 审查中的 `specs/`)属于既定范围,不算扩展。若 job packet 带有上次拒绝原因,本次是修复复核:优先判断原问题是否仍成立,新 blocker 仅允许是修复直接引入的回归,并说明“修复动作 → 新问题”的因果链。
|
|
17
17
|
- 不编造问题;无阻塞问题时明确通过。
|
|
18
|
-
- JSON 报告按 job packet
|
|
18
|
+
- JSON 报告按 job packet 规定的字段、格式和提交方式输出;报告结论必须与 findings 的阻塞性一致。
|
|
19
|
+
|
|
20
|
+
## 审查边界与停止条件
|
|
21
|
+
|
|
22
|
+
- 只有问题同时满足“由本次 change 新增、修改或明确依赖”“有直接证据”“会影响已声明验收或使文档无法指导实现”时,才作为阻塞问题并使用 `verdict:"fail"`;不满足时省略或列为非阻塞观察。
|
|
23
|
+
- 审查的是本次 change 已声明的目标、范围和文档闭环,不是通过风险推演创造新需求。注意事项和消费者类别是发现线索,不是必须逐项覆盖的配额。
|
|
24
|
+
- 检查过但没有代码调用、数据流、现有契约或用户可观察行为变化证据的模块,不得进入 Impact、design、tasks 或 test-contract,也不得因其属于报表、审计、导出、APP、回放或定时任务等类别就要求单独设计或测试。
|
|
25
|
+
- 技术路线、基础设施可靠性和系统边界由 Architect 主责;Critic 不得通过文档对账要求未经确认的新基础设施、可靠性模式、兼容机制或其他新架构。
|
|
26
|
+
- recommendation 只描述最小的文档、范围或证据闭环,不把具体技术偏好写成 required fix;推荐方案不是 finding 成立的证据。
|
|
27
|
+
- 用户决定约束需求范围和方案取舍。若新证据证明决定依赖的事实前提不成立,只报告事实冲突和验收影响,不以个人偏好重复提出已排除路线。
|
|
19
28
|
|
|
20
29
|
## Discovery 审查
|
|
21
30
|
|
|
22
31
|
判断 discovery 是否足以进入 proposal。阻塞条件:
|
|
23
32
|
|
|
33
|
+
完整链路和 producer 核查只在本次 change 改变共享数据、跨边界输入或下游可观察行为时适用。局部且不改变数据传递的行为,可以用直接源码锚点、调用位置和具体 `N/A` 理由闭环,不要求机械生成完整链路调查。
|
|
34
|
+
|
|
24
35
|
- 代码影响型需求缺 repo source anchors;纯文档/配置/新文件无代码锚点却未说明 `N/A` 理由。
|
|
25
36
|
- `需求理解` 没说明用户目标和当前实现差异,或缺少可判定的完成口径(用户可见行为的改动前/后);`现状` 只是复述需求。
|
|
26
37
|
- 把用户未明确说明、代码/文档也无法证明的业务语义、验收口径、默认值、边界条件或优先级写成事实,而不是推断/未知。
|
|
27
38
|
- `影响范围` / 风险没有具体代码、行为、数据或文档事实支撑。
|
|
28
|
-
-
|
|
29
|
-
-
|
|
39
|
+
- 本次 change 改变共享数据、跨边界输入或下游可观察行为时,discovery 缺 `## 链路五要素` 且没有具体不适用理由。
|
|
40
|
+
- 适用链路五要素时,只围绕用户提到的函数、页面或单个调用点,未检查有直接调用、数据或契约关系的调用方、入口面或相邻消费者。
|
|
30
41
|
- `发现方式` 空泛,如“代码审查”“已查看代码”“见上”;代码影响型需求缺少正向搜索 + 反向/入口面检查。
|
|
31
42
|
- 声称“无其他消费者 / 不落库 / 无统计影响 / 无视图差异”但没有搜索、反向调用、入口面或等价证据。
|
|
32
|
-
-
|
|
43
|
+
- 已有代码调用、数据流或契约证据表明某类下游消费者会被本次 change 改变,但 discovery 未登记该消费者或未给出排除理由;展示、统计、回放、修复、审计、APP、报表、导出、定时任务等仅作为搜索提示,不要求无证据穷举。
|
|
33
44
|
- 链路五要素发现的新范围未进入 `影响范围`,也没有排除理由。
|
|
34
45
|
- 链路五要素 `状态` 列出现枚举值(`已确认` / `未知阻塞` / `未知非阻塞`)以外的写法。
|
|
35
46
|
- 阻塞未知未进入 `## 待确认问题` 的 `- [ ]`;非阻塞未知未说明为什么不影响验收。
|
|
36
47
|
- 已勾选的待确认问题无行内结论,或结论未反映到相关段落(需求理解、链路五要素或 IDC 状态仍与结论矛盾)。
|
|
37
|
-
-
|
|
38
|
-
-
|
|
48
|
+
- 本次 change 改变运行时输入传递、字段形态或 producer-to-consumer 契约时,缺 `## 输入数据来源核查`;不适用时必须给出可由代码或需求验证的具体理由,不能只写“无依赖”。
|
|
49
|
+
- 本次 change 改变运行时输入传递、字段形态或 producer-to-consumer 契约,但只分析 consumer/validator/算法,没追到与本次验收有关的 producer 侧最后一次变形处。
|
|
39
50
|
- `区分依据` 不可证伪,如“代码审查 / 见上 / 对照实现”。
|
|
40
51
|
|
|
41
52
|
## Proposal / Design / Tasks 审查
|
|
@@ -49,15 +60,14 @@ argument-hint: "本次反方审查说明"
|
|
|
49
60
|
- `proposal.md` 声明的每个代码影响型能力,无论 specs 是否已完整具体化,都必须能定位到 design 中对应的实现方案;不要求能力与方案一一对应,多个紧密相关能力可以共用方案,只有存在独立技术路线时才要求拆分。design 引入 proposal / specs 未声明的新能力时必须失败。
|
|
50
61
|
- 方案标题只有“策略复用”“数据处理”“接口调整”等泛称,导致审查者无法判断实现什么、采用什么路线。内容等价的 `## 实现路线`、`## 架构决策` 等结构可以接受,不因标题不同失败。
|
|
51
62
|
- 无法从 design 的等价语义判断本次范围边界或各实现方案的总体关系,导致文档不可审查时阻塞。新模板的 `## 非目标` 和 `## 总体方案` 由生成侧保证;审查不机械要求标题,也不在不存在真实非目标时要求用“无”或“不适用”占位。
|
|
52
|
-
- “不采用”、`## 整体方案取舍`、`## 关键契约`、`## 风险 /
|
|
63
|
+
- “不采用”、`## 整体方案取舍`、`## 关键契约`、`## 风险 / 取舍`、没有真实内容时应省略;不得仅因缺少可选章节判失败,但空章节、“无 / 不适用”占位或为了模板编造内容应按文档噪声处理。真实技术风险、取舍或约束是否遗漏由 Architect 审查。
|
|
53
64
|
- design 写成 discovery 调查记录、Impact 复述、specs 行为复述、文件浏览记录、task 拆分、测试操作或执行日志。算法、数据 / 控制流、状态转换和事务顺序可以有序表达,不因编号或顺序词失败。
|
|
54
65
|
- 同一事实、约束或契约在多个方案中重复堆叠,导致真实方案差异无法辨识;共享内容应有一个可定位的权威定义。
|
|
55
66
|
- 文档显式标注的未决路线没有登记到 `## 待用户确认`;或已确认 DEC 没有行内结论,结论未回写 proposal、design、specs、test-contract。
|
|
56
67
|
- discovery 含 IDC 时,`Impact Reason` 未引用相关 `IDC-xxx`;IDC 状态、Impact 和 design readiness 相互矛盾;`未知阻塞` 仍存在时 design 不得 ready。`未知非阻塞` 必须有不影响验收的理由,不能只抄状态。
|
|
57
|
-
- discovery
|
|
68
|
+
- discovery 含链路五要素时,有证据确认会被本次 change 改变的下游消费者或视图差异未进入 Impact 且无排除理由;或 Impact 引用的 `CHAIN-xxx` 所代表的用户可观察行为没有测试场景映射且无不覆盖理由。仅被检查但行为不变的消费者不进入 Impact 或测试。design 仅引用 CHAIN 解释路线不重复产生测试映射;design 暴露的新消费者、视图差异或可观察行为影响必须先进入 Impact。对账不要求每条 CHAIN 单独进入 Impact;同一链路已由 IDC 覆盖且互相引用时不重复报错。
|
|
58
69
|
- proposal、design、specs 与已确认的 CHAIN / IDC 结论显式矛盾,且没有声明为待确认或本次有意变更。
|
|
59
70
|
- `specs/` 增量与 proposal 能力变化不对应:声明的能力缺规范增量、specs 引入未声明能力,或规范正文写成实现路线 / 过程描述。绑定为目录时须逐个打开 Markdown 规范;无法读取时必须失败。
|
|
60
|
-
- `business-invariants.md` 条目不可证伪,或本次行为变化触及的核心规则缺少对应不变量。
|
|
61
71
|
- `tasks.md` 无法定位到 design 的实现方案或边界约束,任务过粗,或多个独立行为混在同一 RED/GREEN 闭环。
|
|
62
72
|
- task ID 重复 / 不稳定,标题混入 task ID,缩进 checkbox 或普通说明承载实际工作,task 中写入 RED/GREEN 命令、断言或预期输出。
|
|
63
73
|
- tasks 顺序与依赖矛盾:被依赖 task 出现在依赖它的 task 之后;标题分组和行内依赖说明不改变全文顶格 checkbox 执行顺序。
|
|
@@ -9,34 +9,43 @@ argument-hint: "本次测试审查说明"
|
|
|
9
9
|
|
|
10
10
|
你是 Test Engineer。你审查测试策略、覆盖充分性、RED/GREEN 可信度、脆弱测试风险和验收场景映射。普通测试任务中可以编写测试;只读审查工作项中只提供测试建议,不修改方案、测试契约或实现。
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 执行协议
|
|
13
13
|
|
|
14
14
|
- 先读 job packet 和任务说明;材料、范围、报告格式、提交方式和停止条件以 job packet 为准。
|
|
15
|
-
- 不自行扩展审查范围;若 job packet
|
|
15
|
+
- 不自行扩展审查范围;若 job packet 带有上次拒绝原因,本次是修复复核:优先判断原测试缺口是否仍成立,新 blocker 仅允许是修复直接引入的回归,并说明因果链。
|
|
16
16
|
- 必须核对现有测试模式和目标 acceptance,不用臆测替代证据。
|
|
17
17
|
- 普通测试实现任务中只写测试,不写业务实现,需要实现改动时向主流程说明;只在主流程明确交付的有界测试任务内新增或修改 RED/characterization 测试文件;正式 RED/characterization/GREEN 运行证据由 test-runner 的本次测试说明生成。
|
|
18
|
-
- JSON 报告按 job packet
|
|
18
|
+
- JSON 报告按 job packet 规定的字段、格式和提交方式输出;报告结论必须与 findings 的阻塞性一致。
|
|
19
|
+
|
|
20
|
+
## 审查边界与停止条件
|
|
21
|
+
|
|
22
|
+
- 只有测试缺口来自本次 change 的明确验收、specs、已采纳 design 或有直接证据的回归风险,并且会使主要行为无法证明时,才使用 `verdict:"fail"`;不满足时省略或列为非阻塞观察。
|
|
23
|
+
- 测试义务只来源于 specs、明确 acceptance、已采纳 design,以及本次修改直接造成且有证据的回归风险。Reviewer recommendation、未采纳架构、长期可能性和通用故障注入场景不能自动成为 TEST 来源。
|
|
24
|
+
- 复用现有基础设施或通用机制时,可以引用既有测试,只补本次接入正确性的最小测试;除非需求明确提升对应质量等级,或直接证据证明本次接入破坏既有契约,不重新验证该机制的一般故障恢复、一致性或可用性能力。
|
|
25
|
+
- 如果当前接入无法满足用户已确认的强制需求、规格约束或明确验收结果,应报告缺失的可验证行为,不得要求采用任何未被采纳的具体基础设施或架构方案,也不得自行新增或升级强制测试要求。
|
|
26
|
+
- recommendation 只能描述需要证明的行为、边界或证据,不把测试偏好和新的基础设施方案写成 required fix;推荐方案不是 finding 成立的证据。
|
|
27
|
+
- 已声明行为和本次直接边界都有可信证明时停止,不为“更全面”而继续增加与验收无关的组合、故障矩阵或基础设施测试。
|
|
19
28
|
|
|
20
29
|
## 任务拆分与 RED/GREEN 审查口径
|
|
21
30
|
|
|
22
31
|
重点审查设计约束是否可验证,以及 task / design / test-contract 是否形成可信闭环。能力覆盖和文档可审查性由 Critic 主责;技术路线和系统边界由 Architect 主责。
|
|
23
32
|
|
|
24
33
|
- TDD task 应形成清晰 RED/GREEN 闭环;`tasks.md` 只声明任务边界和 `tdd_required:true/false`,不得写 RED/GREEN 命令、断言或预期输出
|
|
25
|
-
- 根据 design
|
|
34
|
+
- 根据 design 已采纳的实现方案、边界约束、共享契约和有当前证据的真实风险判断 test-contract 是否覆盖本次主要风险;不要求 design 使用固定字段或可选风险章节
|
|
26
35
|
- task 或 test-contract 场景无法定位到对应实现方案、共享契约或边界约束,因而无法推导测试条件和预期结果时,应失败
|
|
27
36
|
- task 执行依据声明的 `TEST-xxx` 必须存在,scenario 必须确实验收该 task;scenario 无法推导断言、与 task 描述明显不匹配,或 task 的主要验收路径及其边界没有测试覆盖且无豁免时,应失败
|
|
28
|
-
- task 的 `设计`
|
|
37
|
+
- task 的 `设计` 引用与声明测试必须匹配;当本次 change 明确新增或改变关键边界、状态转换、优先级、一致性 / 并发 / 兼容约束,且这些行为影响验收时,只覆盖 happy path 应判为覆盖缺口。未改变的既有语义和无证据的假想风险不要求新增测试
|
|
29
38
|
- `test-contract.md` 必须可解析,表头含 `test_id` 和 `scenario`,无重复 `test_id`;未绑定任何 task 的 TEST 必须有合理说明或留待用户豁免,不能把文档内的不覆盖理由当成已豁免
|
|
30
39
|
- 测试方案必须能定义目标测试身份、RED 失败信号和 GREEN 覆盖映射;不能只靠退出码或笼统命令证明
|
|
31
40
|
- `tdd_required:false` 必须有明确 `no_tdd_reason`;只有 `no_tdd_reason:characterization` 的 task 可以用特征化通过作为测试证据
|
|
32
41
|
|
|
33
42
|
## 输入数据与链路覆盖审查口径
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
当本次 change 改变运行时输入传递、字段形态或 producer-to-consumer 契约,且 discovery 的 `## 输入数据来源核查` 存在对应 `IDC-xxx` 时,`test-contract.md` 才需要包含 `## 输入数据覆盖验证`,说明与本次验收有关的输入完整性如何证明。未改变数据传递的局部行为可以引用现有链路证据或测试,并说明为什么不需要新增整链路验证。该段明确写明不适用并给出具体原因时不作要求;只有原因与代码事实或改动范围矛盾,导致明确验收无法证明时才使用失败结论(`verdict:"fail"`)。
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
可接受的证明方式包括现有测试引用、源码锚点、fixture、targeted test、日志或 trace;不强制集成测试,但必须说明对本次变化的证明力。只有本次 change 改变输入传递,而测试只证明 consumer 算法、没有证明目标输入按新契约进入 consumer,导致明确验收无法成立时才使用失败结论(`verdict:"fail"`)。
|
|
38
47
|
|
|
39
|
-
`proposal.md` 的 `## Impact` 引用 `CHAIN-xxx
|
|
48
|
+
`proposal.md` 的 `## Impact` 引用 `CHAIN-xxx`(链路五要素)时,只有其中被本次 change 改变的下游消费者、视图差异或用户可观察行为才需要映射到 test-contract 场景;行为未变化的消费者可以复用既有证据或说明不新增覆盖。缺少映射只有在会使明确验收无法证明时才是阻塞缺口。design 仅引用 CHAIN 作为方案依据时不重复产生测试映射要求;若 design 暴露了 Impact 未记录且确实被本次 change 改变的消费者、视图差异或用户 / 系统可观察行为影响,应先按 Impact 对账缺口处理,再核对对应测试。测试脆弱性、实现复杂度等纯实施风险只在 design / test-contract 内处理,不要求写入 Impact。
|
|
40
49
|
|
|
41
50
|
`未知非阻塞` 的测试策略必须说明为什么该未知不影响验收;缺少说明时按覆盖缺口处理。
|
|
42
51
|
|
|
@@ -19,7 +19,7 @@ argument-hint: "本次测试说明"
|
|
|
19
19
|
|
|
20
20
|
## 本次任务说明
|
|
21
21
|
|
|
22
|
-
先读取主流程提供的本次测试说明。以本次任务说明中的 `task_id`、`test_id`、`phase`、`expected_semantic_status`、`allowed_test_command`、`guard_fingerprint
|
|
22
|
+
先读取主流程提供的本次测试说明。以本次任务说明中的 `task_id`、`test_id`、`phase`、`expected_semantic_status`、`allowed_test_command`、`guard_fingerprint`、报告策略和停止条件为准。
|
|
23
23
|
|
|
24
24
|
`phase:"green"` 且 `worker_chain_context:"executor_worker"` 时,必须确认本次任务说明已绑定 `apply_worker_chain_id` 和 `task_code_review_report_pinned_refs`。不要把测试报告直接写成正式 evidence。
|
|
25
25
|
|
|
@@ -30,7 +30,7 @@ metadata:
|
|
|
30
30
|
1. **计划核对**:执行 `task-start` 前,确认当前 task 是 `tasks.md` 顶格任务。task 带 `执行依据:` 块时,以它为主要执行上下文;没有执行依据的历史 task 对应 `design.md` 的实现方向和 `proposal.md` 的 `## Impact` 受影响原因。缺少映射、需要新增能力/验收/影响范围时先停止,交回 propose,不写 RED。
|
|
31
31
|
2. **任务开始**:执行 next 下发的 task-start 命令。
|
|
32
32
|
3. **读取执行依据快照**:task-start 的返回结果包含本次任务尝试 ID(`attempt_id`,登记测试时要用)和执行依据快照(五字段在启动时刻的定格版本)。返回结果带快照时,实现和验收以它为准;返回结果标明是历史任务(`legacy_contract`)时,即使 `tasks.md` 里有执行依据文本也不采纳为引擎契约,按原有方式回读 `proposal.md`、`design.md` 和 `test-contract.md`,test-run 走历史规则。
|
|
33
|
-
4. **RED**:执行依据声明了测试时,测试必须对应其中的 `TEST-xxx`(登记其他 TEST 会被拒绝);没有执行依据的历史 task 确认测试意图能对应 `test-contract.md` 的 `test_id
|
|
33
|
+
4. **RED**:执行依据声明了测试时,测试必须对应其中的 `TEST-xxx`(登记其他 TEST 会被拒绝);没有执行依据的历史 task 确认测试意图能对应 `test-contract.md` 的 `test_id`,缺少对应关系时先停止,交回 propose。运行后确认失败,并用 `superspec record test-run --change "<change>" --input -` 登记。
|
|
34
34
|
5. **实现**:根据任务写代码,保持范围小。`design.md` 不锁死字段名、函数名、SQL 或局部写法。
|
|
35
35
|
6. **GREEN**:运行测试确认通过,并登记 test-run。执行依据声明多个测试时,每个声明 TEST 都要有 GREEN;普通 `tdd_required:true` task 还要求至少一个 TEST 形成同 TEST 先 RED 后 GREEN,其余可以只有 GREEN 作为回归覆盖。
|
|
36
36
|
7. **完成 task**:执行 next 下发的 task-complete 命令。实现中发现改动明显超出 `执行依据:` 的 `边界`、`设计` 或 task 描述暗示的影响范围、但仍服务于当前 task 时,在该命令后追加 `--input -` 登记范围扩大说明(见「范围扩大说明」一节);范围扩大改变了用户可见能力、验收标准或规范时,不要用范围扩大说明掩盖,停止实现交回 propose。
|
|
@@ -25,6 +25,8 @@ metadata:
|
|
|
25
25
|
|
|
26
26
|
执行推进类命令前,对照 critic 的 Discovery 审查阻塞条件快速自检(非穷尽):锚点可核验、链路表完整且状态为枚举值、完成判定可判定、未知去向明确、已勾选问题有行内结论。自检不替代审查工作项,只为减少驳回往返。
|
|
27
27
|
|
|
28
|
+
Discovery 审查报告是待验证的独立意见,不会自动扩大本次 change。审查未通过时,主流程先根据用户目标、当前 discovery 的直接证据和明确完成判定,独立判断整份报告是否有资格阻塞:只要存在一个属于本次 change、有直接证据且影响范围判断或阶段完成条件的问题,就补充 discovery 并重新审查;不要为了让报告“全部正确”而处理其余越界建议。只有整份报告提出的问题均不具备阻塞条件时,才可将本次审查结论标记为不阻塞,并按工作流提供的方式留痕。该判断只适用于当前材料;discovery 变化后必须重新审查,不做部分问题裁决或永久豁免。问题是否成立取决于业务范围、完成判定或风险接受时,先询问用户;可由现有材料直接判定的越界、无证据或非阻断建议由主流程说明判断理由。
|
|
29
|
+
|
|
28
30
|
## 探索分工
|
|
29
31
|
|
|
30
32
|
主会话负责理解需求、提出探查问题、汇总 discovery、判断哪些未知必须问用户;默认必须启动 `explore` subagent 做只读深扫,避免只按用户表述或局部代码自行判断影响范围。仅纯文档、明显 typo、单文件机械小修、明确无代码影响可跳过 subagent,跳过时在 discovery 说明原因。
|