Skip to content

Commit 8910712

Browse files
committed
feat(hooks): delivery honesty gaps for stage report and overclaim
Add stage-report-missing and progress-overclaim classifiers, Stop wiring, PreTool block when plan exists without 05, delivery-honesty tests on stop-gate/control-plane chains, and DeliveryHonestyMatrix progress template.
1 parent 8adaa5b commit 8910712

8 files changed

Lines changed: 314 additions & 5 deletions

File tree

‎changelogs/unreleased.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
## 当前未发布实现候选
77

8+
- **Agent 交付诚实门(delivery-honesty)**:`classifyDeliveryHonesty` → gap `stage-report-missing` / `progress-overclaim`;Stop 接线;PreTool 有 04 无 05 时禁控制面写;`npm run test:delivery-honesty` 挂 stop-gate 与 control-plane;进度模板 DeliveryHonestyMatrix。需求:`Agent交付诚实与过程产物强制修复`。
89
- **维护者站点×完整功能清单对账门(docs-surface-inventory)**:新增 `scripts/lib/docs-surface-inventory.js` + `npm run test:docs-surface-inventory`;校验 Skills84/plugin 双向、workflows×8(含 other)、MCP15、Hooks5/runtime、prompts30、instructions15、website≥156、process-enforcement 文件与 script;挂入 `test:control-plane` 与 validation-manifest 节点 `docs-surface-inventory` / `process-enforcement-e2e`(fast/full)。public-text-surfaces 扩展 guide/index 与 host-parity-grok。intro 增加能力证据三列表。
910
- **全宿主流程强制 + 产物路径准确(process-enforcement)**:新增 `scripts/lib/process-enforcement.js`(MutationCpGate 受保护路径 hard-deny、ArtifactPathGate、复审清单/过程包齐套判定)与 `host-enforcement-matrix.js`(五宿主策略真相源);`lifecycle.cjs` PreTool 接线;`lifecycle-stop-gate.cjs` 追加 `review-checklist-missing` / `process-artifact-incomplete` / `progress-artifact-missing`;`npm run test:process-enforcement-e2e` 并入 `test:stop-gate` 与 `test:control-plane`。文档:`02-output-paths` ArtifactPathGate 行、README 流程强制条;配套 PI-REQ-ASSESS 需求模板评估字段。
1011
- **需求模板强制项目实况评估(PI-REQ-ASSESS-20260726)**:`requirement-overview.prompt.md` 新增 §10(AI 填写:CodeTruth 锚点 + 合理性/可实施性/收益/验证状态/影响范围 + 推荐);`requirement.prompt.md` 新增 §2.6 同构字段;与 compliance 五项验证对齐;禁止空表过关。台账 PI-REQ-ASSESS / PI-REQ-NO-SPLIT。需求:`全宿主流程强制与产物路径准确` 概况 v0.4。

‎hooks/_runtime/lifecycle-stop-gate.cjs‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ try {
2121

2222
let classifyReviewChecklistCompletion
2323
let classifyProcessArtifactCompleteness
24+
let classifyDeliveryHonesty
2425
try {
2526
;({
2627
classifyReviewChecklistCompletion,
27-
classifyProcessArtifactCompleteness
28+
classifyProcessArtifactCompleteness,
29+
classifyDeliveryHonesty
2830
} = require('../../scripts/lib/process-enforcement.js'))
2931
} catch {
3032
classifyReviewChecklistCompletion = () => ({ ok: true, code: null, gap: null })
3133
classifyProcessArtifactCompleteness = () => ({ ok: true, code: null, gap: null, missing: [] })
34+
classifyDeliveryHonesty = () => ({ ok: true, gaps: [], code: null, gap: null })
3235
}
3336

3437
function extractLastAssistantMessage (payload) {
@@ -267,6 +270,22 @@ function evaluateStopCompletionGate (input = {}) {
267270
gaps.push(processPkg.gap)
268271
}
269272

273+
// Delivery honesty (A/B): strong closure claim + report path / over-claim
274+
// Note: do not pass completionClaimed=true from mere 完成检查 block — classifier uses strong phrases.
275+
if (typeof classifyDeliveryHonesty === 'function') {
276+
const honestyGaps = classifyDeliveryHonesty({
277+
text,
278+
mode: modeL || mode,
279+
workflow: wf || workflow,
280+
mutated
281+
})
282+
if (!honestyGaps.ok && Array.isArray(honestyGaps.gaps)) {
283+
for (const g of honestyGaps.gaps) {
284+
if (g && !gaps.includes(g)) gaps.push(g)
285+
}
286+
}
287+
}
288+
270289
const uniqueGaps = [...new Set(gaps)]
271290
honesty.processGaps = uniqueGaps
272291

‎hooks/_runtime/lifecycle.cjs‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,36 @@ async function main() {
15021502
}
15031503
}
15041504

1505+
// 2.7 E: plan without progress forbids control-plane source mutation (delivery honesty H1)
1506+
if (
1507+
isSourceCodeMutation(payload, platform, state) &&
1508+
!(state.simpleTaskFastPath === true || state.taskPathMode === 'simple')
1509+
) {
1510+
const toolPaths = extractToolPaths(payload)
1511+
const hitsProtected = toolPaths.some(p => isStrictProtectedPath(p))
1512+
if (hitsProtected) {
1513+
const task = (typeof findIncompleteTaskForPaths === 'function')
1514+
? findIncompleteTaskForPaths(payload, state)
1515+
: null
1516+
const bound = task || (typeof findIncompleteTask === 'function' ? findIncompleteTask(state) : null)
1517+
if (bound && bound.fullPath && hasTaskArtifact(bound, 'CP3')) {
1518+
const progressPath = path.join(bound.fullPath, '05-实施进度.md')
1519+
if (!fs.existsSync(progressPath)) {
1520+
state.lastReason = PROCESS_ENFORCEMENT_CODES.PROGRESS_ARTIFACT_MISSING || 'progress-artifact-missing'
1521+
saveState(state)
1522+
writeStdout(buildInterceptionOutput(
1523+
state, platform, eventName, INTERCEPTION_ACTION.REQUIRE_COMPLETION,
1524+
'progress-artifact-missing',
1525+
'Progress artifact required',
1526+
`控制面 mutation 需要任务目录 05-实施进度.md(已有 04 实施计划):${bound.name || bound.fullPath}`,
1527+
'Create 05-实施进度.md under the active requirement before mutating control-plane sources.'
1528+
))
1529+
return
1530+
}
1531+
}
1532+
}
1533+
}
1534+
15051535
// 3. CP gate — block source code mutations until checkpoints confirmed
15061536
// PF-process-enforcement: hard-deny for strict-protected paths even under safety-only (D1)
15071537
// Non-protected paths: legacy safety-only warning + Honesty cp2-unconfirmed-write

‎package.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
"test:package-release": "node scripts/run-validation.js --route package-release",
8989
"test:control-plane-module-contracts": "node scripts/test-control-plane-module-contracts.js",
9090
"test:closure-evidence": "node scripts/test-closure-evidence-controls.js",
91-
"test:control-plane": "npm run test:probe-registry && npm run test:cli-command-registry && npm run test:cli-json-contract && npm run test:governance-status-summary && npm run test:always-on-governance && npm run test:intent-consistency && npm run test:local-probe && npm run test:context-read && npm run test:context-binding && npm run test:context-read-controls && npm run test:tenant-selection && npm run test:workflow-capabilities && npm run test:api-verification-contracts && npm run test:git-index-isolation && npm run test:control-plane-contracts && npm run test:markdown-structure && npm run test:control-plane-module-contracts && npm run test:consumer-evolution-controls && npm run test:residual-absorption-controls && npm run test:brand-visual-quality && npm run test:turn-liveness && npm run test:closure-evidence && npm run test:workflow-completion && npm run test:public-text-integrity && npm run test:external-review-claim && npm run test:candidate-review-bundle && npm run test:capability-surface-decision && npm run test:host-capability-routing && npm run test:requirement-parallel-orchestration && npm run test:evidence-freshness && npm run test:optimization-backlog-evidence && npm run test:discipline-execution && npm run test:skill-resolve && npm run test:process-enforcement-e2e && npm run test:docs-surface-inventory",
91+
"test:control-plane": "npm run test:probe-registry && npm run test:cli-command-registry && npm run test:cli-json-contract && npm run test:governance-status-summary && npm run test:always-on-governance && npm run test:intent-consistency && npm run test:local-probe && npm run test:context-read && npm run test:context-binding && npm run test:context-read-controls && npm run test:tenant-selection && npm run test:workflow-capabilities && npm run test:api-verification-contracts && npm run test:git-index-isolation && npm run test:control-plane-contracts && npm run test:markdown-structure && npm run test:control-plane-module-contracts && npm run test:consumer-evolution-controls && npm run test:residual-absorption-controls && npm run test:brand-visual-quality && npm run test:turn-liveness && npm run test:closure-evidence && npm run test:workflow-completion && npm run test:public-text-integrity && npm run test:external-review-claim && npm run test:candidate-review-bundle && npm run test:capability-surface-decision && npm run test:host-capability-routing && npm run test:requirement-parallel-orchestration && npm run test:evidence-freshness && npm run test:optimization-backlog-evidence && npm run test:discipline-execution && npm run test:skill-resolve && npm run test:process-enforcement-e2e && npm run test:docs-surface-inventory && npm run test:delivery-honesty",
9292
"test:tenant-selection": "node scripts/test-tenant-selection.js",
9393
"test:workflow-capabilities": "node scripts/test-workflow-capabilities.js",
9494
"test:api-verification-contracts": "node scripts/test-api-verification-contracts.js",
@@ -113,9 +113,10 @@
113113
"prepublishOnly": "npm run test:all:with-audit",
114114
"test:executable-absorption-gates": "node scripts/test-executable-absorption-gates.js",
115115
"test:skill-resolve": "node scripts/test-skill-resolve.js && node scripts/test-skill-resolution-hook-paths.js && node scripts/test-workspace-skill-auto-match.js",
116-
"test:stop-gate": "node scripts/test-lifecycle-stop-gate.js && node scripts/test-r10-control-plane-honesty.js && node scripts/replay-stop-gate-hook-matrix.js && node scripts/test-process-enforcement-e2e.js",
116+
"test:stop-gate": "node scripts/test-lifecycle-stop-gate.js && node scripts/test-r10-control-plane-honesty.js && node scripts/replay-stop-gate-hook-matrix.js && node scripts/test-process-enforcement-e2e.js && node scripts/test-delivery-honesty.js",
117117
"test:process-enforcement-e2e": "node scripts/test-process-enforcement-e2e.js",
118118
"test:docs-surface-inventory": "node scripts/test-docs-surface-inventory.js",
119+
"test:delivery-honesty": "node scripts/test-delivery-honesty.js",
119120
"test:skill-automatch-accept": "node scripts/replay-skill-automatch-accept.cjs"
120121
},
121122
"keywords": [
@@ -231,6 +232,7 @@
231232
"scripts/test-r10-control-plane-honesty.js",
232233
"scripts/test-process-enforcement-e2e.js",
233234
"scripts/test-docs-surface-inventory.js",
235+
"scripts/test-delivery-honesty.js",
234236
"scripts/lib/docs-surface-inventory.js",
235237
"scripts/lib/process-enforcement.js",
236238
"scripts/lib/host-enforcement-matrix.js",

‎prompts/implementation-progress.prompt.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ applyTo: .devcodex/**/{requirements,bugs}/**; .devcodex/**/fix/**
3838
- [变更记录](#变更记录)
3939
```
4040

41+
## DeliveryHonestyMatrix(强制 · 防过报)
42+
43+
> 进度只能写 **有证据 / 未做 / partial**;禁止「全 ✅ / 5/6 / 只差验收」而无验证表。
44+
> 强完成宣称须带阶段报告路径(`reports/...`)。机器 gap:`progress-overclaim` · `stage-report-missing`。
45+
46+
| 字段 | 值 |
47+
|------|-----|
48+
| stageReportPath | 有路径 / 无 / N/A+skipReason |
49+
| progressHonest | 是(每行有证据)/ 否 |
50+
| checklistVisible | 03-复审清单 或 review-checklists 路径 |
51+
| validationEvidence | 命令 + exitCode |
52+
4153
## 进度总览
4254

4355
> 只记录执行推进情况,不重复需求背景、技术方案正文或实施计划的完整任务定义。

‎scripts/lib/process-enforcement.js‎

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ const ERROR_CODES = Object.freeze({
1717
/** Control-plane / multi-batch completion without 05 progress file path evidence */
1818
PROGRESS_ARTIFACT_MISSING: 'progress-artifact-missing',
1919
/** Formal R3 process package incomplete (04/05/checklist triad) */
20-
PROCESS_ARTIFACT_INCOMPLETE: 'process-artifact-incomplete'
20+
PROCESS_ARTIFACT_INCOMPLETE: 'process-artifact-incomplete',
21+
/** Completion claim without discoverable stage report path */
22+
STAGE_REPORT_MISSING: 'stage-report-missing',
23+
/** Over-claim progress without validation evidence rows */
24+
PROGRESS_OVERCLAIM: 'progress-overclaim'
2125
})
2226

2327
/** Paths that use hard-deny for unconfirmed CP even under default safety-only (D1). */
@@ -228,6 +232,99 @@ function simpleTaskForbidsPath(filePath) {
228232
return false
229233
}
230234

235+
function isDeliveryHonestyExempt (text) {
236+
return /SimpleTaskFastPath|报告\s*[::]\s*N\/A|report\s*[::=]\s*N\/A|skipReason\s*[::=]\s*(?:simple-task|simple_task|probe|chat)|mode\s*[=:]\s*chat/i.test(
237+
String(text || '')
238+
)
239+
}
240+
241+
function hasStageReportPath (text) {
242+
return /reports[/\\]|requirements[/\\][^\n]+[/\\]reports[/\\]|阶段.*报告|\d{8}--.+\.md/i.test(
243+
String(text || '')
244+
)
245+
}
246+
247+
function hasValidationEvidence (text) {
248+
const t = String(text || '')
249+
return (
250+
/exitCode\s*[:=]?\s*0|验证摘要|FinalValidationSummary|npm run test:/i.test(t) &&
251+
/exitCode|exit\s*0|PASS|passed/i.test(t)
252+
)
253+
}
254+
255+
function looksLikeOverclaim (text) {
256+
return /5\s*\/\s*6|全部完成|全部✅|全绿|Fix-[0-9A-F].*全\s*✅|只差验收|可关闭需求|需求已完成|100%\s*完成/i.test(
257+
String(text || '')
258+
)
259+
}
260+
261+
/**
262+
* Delivery honesty: stage report path + progress over-claim (A/B/H).
263+
* @param {{ completionClaimed?: boolean, text?: string, mode?: string, workflow?: string, mutated?: boolean }} input
264+
*/
265+
function classifyDeliveryHonesty (input = {}) {
266+
const text = String(input.text || '')
267+
const mode = String(input.mode || '').toLowerCase()
268+
const wf = String(input.workflow || mode || '').toLowerCase()
269+
// Strong closure claims only — do not treat mere 「完成检查」block as stage-report duty
270+
const strongClaim =
271+
input.completionClaimed === true ||
272+
/已完成|任务完成|all work is complete|宣告完成|可关闭需求|本需求.*闭环|DoD.*闭环|只差验收/i.test(text)
273+
274+
if (!strongClaim) return { ok: true, gaps: [], code: null, gap: null }
275+
if (mode === 'chat' || wf === 'chat') return { ok: true, gaps: [], code: null, gap: null }
276+
if (isDeliveryHonestyExempt(text)) return { ok: true, gaps: [], code: null, gap: null }
277+
278+
const gaps = []
279+
const nonChatWork =
280+
input.mutated === true ||
281+
['dev', 'fix', 'self-fix'].includes(mode) ||
282+
['dev', 'fix', 'self-fix'].includes(wf) ||
283+
/控制面|ECR|实施|Fix-|Phase-|多文件|website\/docs/i.test(text)
284+
285+
if (nonChatWork && !hasStageReportPath(text)) {
286+
gaps.push(ERROR_CODES.STAGE_REPORT_MISSING)
287+
}
288+
if (looksLikeOverclaim(text) && !hasValidationEvidence(text)) {
289+
gaps.push(ERROR_CODES.PROGRESS_OVERCLAIM)
290+
}
291+
292+
if (gaps.length) {
293+
return {
294+
ok: false,
295+
gaps,
296+
code: gaps[0],
297+
gap: gaps[0]
298+
}
299+
}
300+
return { ok: true, gaps: [], code: null, gap: null }
301+
}
302+
303+
/**
304+
* Requirement-dir review checklist discoverability (C).
305+
* @param {{ taskRoot?: string|null, fs?: { readdirSync?: Function }, text?: string }} input
306+
*/
307+
function classifyReviewChecklistDiscoverability (input = {}) {
308+
const text = String(input.text || '')
309+
if (/03-复审清单|review-checklists[/\\]/i.test(text)) {
310+
return { ok: true, gap: null }
311+
}
312+
const root = input.taskRoot
313+
const fsys = input.fs
314+
if (root && fsys && typeof fsys.readdirSync === 'function') {
315+
try {
316+
const names = fsys.readdirSync(root)
317+
if (names.some((n) => /复审清单|review-checklist/i.test(String(n)))) {
318+
return { ok: true, gap: null }
319+
}
320+
} catch {
321+
/* ignore */
322+
}
323+
}
324+
// Only fail when completion claimed + R3 (caller combines with classifyReviewChecklistCompletion)
325+
return { ok: true, gap: null, note: 'use-with-checklist-classifier' }
326+
}
327+
231328
module.exports = {
232329
ERROR_CODES,
233330
STRICT_PROTECTED_PATH_RE,
@@ -238,6 +335,11 @@ module.exports = {
238335
classifyPathsForArtifacts,
239336
classifyReviewChecklistCompletion,
240337
classifyProcessArtifactCompleteness,
338+
classifyDeliveryHonesty,
339+
classifyReviewChecklistDiscoverability,
241340
simpleTaskForbidsPath,
242-
normalizePath
341+
normalizePath,
342+
hasStageReportPath,
343+
looksLikeOverclaim,
344+
hasValidationEvidence
243345
}

‎scripts/replay-stop-gate-hook-matrix.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const COMPLETE_BODY = [
6262
'Release actions: push/tag/release/publish 未执行',
6363
'`DevCodexVisibleEnvelopeV1 · completion-check · PASS · ' + 'c'.repeat(64) + '`',
6464
'',
65+
'阶段报告: reports/requirements/grok/20260723/01--stop-gate-replay.md',
6566
'工作已完成并收口。'
6667
].join('\n')
6768

0 commit comments

Comments
 (0)