@godv61/dsh-task-engine 0.25.0 → 0.26.1
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/.acceptance.mjs +150 -150
- package/.assessment-batch1.mjs +20 -20
- package/.enforce-test.mjs +138 -138
- package/.evidence-test.mjs +118 -119
- package/.filter-test.mjs +92 -92
- package/.hook-test.mjs +195 -195
- package/.p0-test.mjs +59 -59
- package/.preset-test.mjs +160 -160
- package/.revision-test.mjs +30 -16
- package/.roundtrip-test.mjs +178 -63
- package/.workflow-test.mjs +86 -0
- package/README.md +8 -8
- package/cordis.patch.yml +10 -10
- package/defaults/eng.json +70 -22
- package/docs/BRIEF-FOR-REVIEW.md +162 -162
- package/docs/CHANGELOG.md +18 -0
- package/docs/README.md +40 -40
- package/docs/configuration.md +14 -9
- package/docs/development.md +1 -1
- package/docs/faq.md +4 -4
- package/docs/listing/godv61__dsh-task-engine.yml +5 -5
- package/docs/listing/submission.md +83 -83
- package/docs/manual.html +32 -27
- package/docs/releases/0.23.2.md +21 -21
- package/docs/roadmap.md +34 -34
- package/docs/testing/0.23.2/R02/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +56 -56
- package/docs/testing/0.23.2/R03/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +38 -38
- package/docs/testing/0.23.2//346/265/213/350/257/225/346/212/245/345/221/212.md +65 -65
- package/hooks/commit-msg +70 -1
- package/lib/client.js +870 -571
- package/lib/client.js.map +3 -3
- package/lib/controller.d.ts +2 -1
- package/lib/controller.js +6 -3
- package/lib/controller.js.map +1 -1
- package/lib/dev-task.js +83 -15
- package/lib/dev-task.js.map +1 -1
- package/lib/engine.d.ts +15 -0
- package/lib/engine.js +29 -5
- package/lib/engine.js.map +1 -1
- package/lib/hook.js +3 -0
- package/lib/hook.js.map +1 -1
- package/lib/skill-audit.js +3 -3
- package/lib/skill-audit.js.map +1 -1
- package/lib/workflows.d.ts +4 -1
- package/lib/workflows.js +90 -2
- package/lib/workflows.js.map +1 -1
- package/package.json +1 -1
- package/preset/agent.cordis.yml +22 -22
- package/preset/enable.mjs +87 -87
- package/preset/persona.md +5 -5
- package/preset/preset.yml +1 -1
- package/rules/coding-conventions.md +6 -6
- package/rules/commit-conventions.md +6 -6
- package/rules/security-redlines.md +5 -5
- package/scripts/verify-dsh-compat.mjs +144 -144
- package/skills/code-implement/SKILL.md +1 -1
- package/skills/code-verify/SKILL.md +3 -3
- package/skills/eng-delivery/SKILL.md +10 -31
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DSH codec-contract compatibility check.
|
|
3
|
-
*
|
|
4
|
-
* The plugin's Typert Remote contribution must satisfy whichever strict-codec
|
|
5
|
-
* contract the installed DSH expects. DSH 0.1.6-alpha.2 replaced the
|
|
6
|
-
* materialized `schema` field with a lazy `create: () => TypertSchema` factory
|
|
7
|
-
* and rejects the old shape at plugin load, which took the whole contribution
|
|
8
|
-
* down at boot — a failure the unit tests could not see, because they never
|
|
9
|
-
* load the descriptors through a real registry.
|
|
10
|
-
*
|
|
11
|
-
* npm semver cannot wildcard prereleases, so the peer range enumerates them and
|
|
12
|
-
* a new DSH alpha silently falls outside it; pnpm only warns at install time.
|
|
13
|
-
* This check runs against a real DSH checkout, where the contract actually
|
|
14
|
-
* lives, and fails loudly when the two drift apart again.
|
|
15
|
-
*
|
|
16
|
-
* Run: `node scripts/verify-dsh-compat.mjs [path-to-dsh-checkout]`
|
|
17
|
-
* @module dsh-task-engine/scripts/verify-dsh-compat
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
21
|
-
import { join } from 'node:path'
|
|
22
|
-
import { fileURLToPath } from 'node:url'
|
|
23
|
-
|
|
24
|
-
const DEFAULT_DSH_ROOT = 'D:/dsharness/deepseek-harness'
|
|
25
|
-
|
|
26
|
-
const problems = []
|
|
27
|
-
function check(name, ok, detail = '') {
|
|
28
|
-
console.log(`${ok ? 'ok ' : 'FAIL'} ${name}${detail === '' ? '' : `: ${detail}`}`)
|
|
29
|
-
if (!ok) problems.push(name)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Locate the typert protocol package inside a DSH checkout. */
|
|
33
|
-
function protocolDir(root) {
|
|
34
|
-
const candidates = [
|
|
35
|
-
join(root, 'packages', 'typert', 'protocol'),
|
|
36
|
-
join(root, 'node_modules', '@deepseek-ai', 'dsh-typert-protocol'),
|
|
37
|
-
]
|
|
38
|
-
return candidates.find(dir => existsSync(join(dir, 'package.json')))
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const dshRoot = process.argv[2] ?? DEFAULT_DSH_ROOT
|
|
42
|
-
console.log(`DSH checkout: ${dshRoot}`)
|
|
43
|
-
|
|
44
|
-
if (!existsSync(dshRoot)) {
|
|
45
|
-
// Absent checkout is not a failure: this script is advisory outside CI.
|
|
46
|
-
console.log('ok (skipped) no DSH checkout at that path')
|
|
47
|
-
process.exit(0)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const dir = protocolDir(dshRoot)
|
|
51
|
-
if (dir === undefined) {
|
|
52
|
-
check('locate the typert protocol package', false, 'not found under the DSH checkout')
|
|
53
|
-
process.exit(1)
|
|
54
|
-
}
|
|
55
|
-
const protocol = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
|
|
56
|
-
console.log(` typert protocol version: ${protocol.version}`)
|
|
57
|
-
|
|
58
|
-
// 1. Which contract does this DSH expect? Read the type, not a guess.
|
|
59
|
-
const typesPath = [
|
|
60
|
-
join(dir, 'src', 'types.ts'),
|
|
61
|
-
join(dir, 'lib', 'types', 'types.d.ts'),
|
|
62
|
-
].find(path => existsSync(path))
|
|
63
|
-
const typesText = typesPath === undefined ? '' : readFileSync(typesPath, 'utf8')
|
|
64
|
-
const wantsCreate = /readonly create: \(\) => TypertSchema/u.test(typesText)
|
|
65
|
-
const wantsSchema = /readonly schema: TypertSchema/u.test(typesText)
|
|
66
|
-
console.log(` contract: ${wantsCreate ? 'create() factory' : wantsSchema ? 'schema field' : 'unknown'}`)
|
|
67
|
-
|
|
68
|
-
// 2. Our descriptors must satisfy it. Import the built contribution and inspect
|
|
69
|
-
// every strict codec exactly as the DSH registry would.
|
|
70
|
-
const pluginRoot = fileURLToPath(new URL('..', import.meta.url))
|
|
71
|
-
const clientBundle = join(pluginRoot, 'lib', 'client.js')
|
|
72
|
-
if (!existsSync(clientBundle)) {
|
|
73
|
-
check('built client bundle exists', false, 'run `npm run build` first')
|
|
74
|
-
process.exit(1)
|
|
75
|
-
}
|
|
76
|
-
const bundleText = readFileSync(clientBundle, 'utf8')
|
|
77
|
-
const strictCodecs = (bundleText.match(/mode:\s*"strict"/gu) ?? []).length
|
|
78
|
-
const withCreate = (bundleText.match(/create:\s*\(\)\s*=>/gu) ?? []).length
|
|
79
|
-
const withSchema = (bundleText.match(/schema:/gu) ?? []).length
|
|
80
|
-
|
|
81
|
-
check('the bundle carries strict codecs', strictCodecs > 0, `${strictCodecs} found`)
|
|
82
|
-
if (wantsCreate) {
|
|
83
|
-
check('every strict codec provides create()', withCreate >= strictCodecs,
|
|
84
|
-
`${withCreate} of ${strictCodecs}`)
|
|
85
|
-
}
|
|
86
|
-
if (wantsSchema) {
|
|
87
|
-
check('every strict codec provides schema', withSchema >= strictCodecs,
|
|
88
|
-
`${withSchema} of ${strictCodecs}`)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 3. The peer range must actually admit the installed DSH version, because npm
|
|
92
|
-
// semver will not match a prerelease the range does not name. Implemented
|
|
93
|
-
// here rather than via the `semver` package: that is a devDependency, so a
|
|
94
|
-
// consumer running this script from the installed tarball has no copy, and
|
|
95
|
-
// the whole point of this check is to run against whatever DSH is present.
|
|
96
|
-
const pkg = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'))
|
|
97
|
-
const range = pkg.peerDependencies['@deepseek-ai/dsh-typert-protocol'] ?? ''
|
|
98
|
-
check(`peer range admits DSH ${protocol.version}`, rangeAdmits(range, protocol.version), range)
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Whether one of a `||`-joined range's comparators admits `version`.
|
|
102
|
-
*
|
|
103
|
-
* npm semver matches a prerelease only when the comparator names a prerelease
|
|
104
|
-
* on the SAME major.minor.patch, which is why enumerating versions is the only
|
|
105
|
-
* way to cover a DSH alpha. This mirrors that rule for the caret and exact
|
|
106
|
-
* forms the manifest actually uses; it is deliberately conservative, and an
|
|
107
|
-
* unrecognized comparator reports `false` so the check fails loudly rather than
|
|
108
|
-
* passing by accident.
|
|
109
|
-
* @param range - the peer range expression.
|
|
110
|
-
* @param version - the installed DSH version to test.
|
|
111
|
-
* @returns true when the range admits the version.
|
|
112
|
-
*/
|
|
113
|
-
function rangeAdmits(range, version) {
|
|
114
|
-
const parse = text => {
|
|
115
|
-
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(text.trim())
|
|
116
|
-
return match === null
|
|
117
|
-
? undefined
|
|
118
|
-
: { major: +match[1], minor: +match[2], patch: +match[3], pre: match[4] }
|
|
119
|
-
}
|
|
120
|
-
const target = parse(version)
|
|
121
|
-
if (target === undefined) return false
|
|
122
|
-
for (const part of range.split('||').map(text => text.trim()).filter(Boolean)) {
|
|
123
|
-
const caret = /^\^(.+)$/u.exec(part)
|
|
124
|
-
const lower = parse(caret === null ? part : caret[1])
|
|
125
|
-
if (lower === undefined) continue
|
|
126
|
-
// Same prerelease tuple, or a plain release on the same caret line.
|
|
127
|
-
const sameTuple = target.major === lower.major
|
|
128
|
-
&& target.minor === lower.minor
|
|
129
|
-
&& target.patch === lower.patch
|
|
130
|
-
if (lower.pre !== undefined) {
|
|
131
|
-
if (sameTuple) return true
|
|
132
|
-
} else if (target.pre === undefined && target.major === lower.major) {
|
|
133
|
-
if (caret === null ? sameTuple : target.minor >= lower.minor) return true
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return false
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (problems.length > 0) {
|
|
140
|
-
console.error(`\n${problems.length} DSH compatibility problem(s)`)
|
|
141
|
-
console.error('A new DSH alpha likely changed the Typert contract. Update src/client/remote.ts')
|
|
142
|
-
console.error('and add the version to peerDependencies before releasing.')
|
|
143
|
-
process.exit(1)
|
|
144
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* DSH codec-contract compatibility check.
|
|
3
|
+
*
|
|
4
|
+
* The plugin's Typert Remote contribution must satisfy whichever strict-codec
|
|
5
|
+
* contract the installed DSH expects. DSH 0.1.6-alpha.2 replaced the
|
|
6
|
+
* materialized `schema` field with a lazy `create: () => TypertSchema` factory
|
|
7
|
+
* and rejects the old shape at plugin load, which took the whole contribution
|
|
8
|
+
* down at boot — a failure the unit tests could not see, because they never
|
|
9
|
+
* load the descriptors through a real registry.
|
|
10
|
+
*
|
|
11
|
+
* npm semver cannot wildcard prereleases, so the peer range enumerates them and
|
|
12
|
+
* a new DSH alpha silently falls outside it; pnpm only warns at install time.
|
|
13
|
+
* This check runs against a real DSH checkout, where the contract actually
|
|
14
|
+
* lives, and fails loudly when the two drift apart again.
|
|
15
|
+
*
|
|
16
|
+
* Run: `node scripts/verify-dsh-compat.mjs [path-to-dsh-checkout]`
|
|
17
|
+
* @module dsh-task-engine/scripts/verify-dsh-compat
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
21
|
+
import { join } from 'node:path'
|
|
22
|
+
import { fileURLToPath } from 'node:url'
|
|
23
|
+
|
|
24
|
+
const DEFAULT_DSH_ROOT = 'D:/dsharness/deepseek-harness'
|
|
25
|
+
|
|
26
|
+
const problems = []
|
|
27
|
+
function check(name, ok, detail = '') {
|
|
28
|
+
console.log(`${ok ? 'ok ' : 'FAIL'} ${name}${detail === '' ? '' : `: ${detail}`}`)
|
|
29
|
+
if (!ok) problems.push(name)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Locate the typert protocol package inside a DSH checkout. */
|
|
33
|
+
function protocolDir(root) {
|
|
34
|
+
const candidates = [
|
|
35
|
+
join(root, 'packages', 'typert', 'protocol'),
|
|
36
|
+
join(root, 'node_modules', '@deepseek-ai', 'dsh-typert-protocol'),
|
|
37
|
+
]
|
|
38
|
+
return candidates.find(dir => existsSync(join(dir, 'package.json')))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const dshRoot = process.argv[2] ?? DEFAULT_DSH_ROOT
|
|
42
|
+
console.log(`DSH checkout: ${dshRoot}`)
|
|
43
|
+
|
|
44
|
+
if (!existsSync(dshRoot)) {
|
|
45
|
+
// Absent checkout is not a failure: this script is advisory outside CI.
|
|
46
|
+
console.log('ok (skipped) no DSH checkout at that path')
|
|
47
|
+
process.exit(0)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const dir = protocolDir(dshRoot)
|
|
51
|
+
if (dir === undefined) {
|
|
52
|
+
check('locate the typert protocol package', false, 'not found under the DSH checkout')
|
|
53
|
+
process.exit(1)
|
|
54
|
+
}
|
|
55
|
+
const protocol = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
|
|
56
|
+
console.log(` typert protocol version: ${protocol.version}`)
|
|
57
|
+
|
|
58
|
+
// 1. Which contract does this DSH expect? Read the type, not a guess.
|
|
59
|
+
const typesPath = [
|
|
60
|
+
join(dir, 'src', 'types.ts'),
|
|
61
|
+
join(dir, 'lib', 'types', 'types.d.ts'),
|
|
62
|
+
].find(path => existsSync(path))
|
|
63
|
+
const typesText = typesPath === undefined ? '' : readFileSync(typesPath, 'utf8')
|
|
64
|
+
const wantsCreate = /readonly create: \(\) => TypertSchema/u.test(typesText)
|
|
65
|
+
const wantsSchema = /readonly schema: TypertSchema/u.test(typesText)
|
|
66
|
+
console.log(` contract: ${wantsCreate ? 'create() factory' : wantsSchema ? 'schema field' : 'unknown'}`)
|
|
67
|
+
|
|
68
|
+
// 2. Our descriptors must satisfy it. Import the built contribution and inspect
|
|
69
|
+
// every strict codec exactly as the DSH registry would.
|
|
70
|
+
const pluginRoot = fileURLToPath(new URL('..', import.meta.url))
|
|
71
|
+
const clientBundle = join(pluginRoot, 'lib', 'client.js')
|
|
72
|
+
if (!existsSync(clientBundle)) {
|
|
73
|
+
check('built client bundle exists', false, 'run `npm run build` first')
|
|
74
|
+
process.exit(1)
|
|
75
|
+
}
|
|
76
|
+
const bundleText = readFileSync(clientBundle, 'utf8')
|
|
77
|
+
const strictCodecs = (bundleText.match(/mode:\s*"strict"/gu) ?? []).length
|
|
78
|
+
const withCreate = (bundleText.match(/create:\s*\(\)\s*=>/gu) ?? []).length
|
|
79
|
+
const withSchema = (bundleText.match(/schema:/gu) ?? []).length
|
|
80
|
+
|
|
81
|
+
check('the bundle carries strict codecs', strictCodecs > 0, `${strictCodecs} found`)
|
|
82
|
+
if (wantsCreate) {
|
|
83
|
+
check('every strict codec provides create()', withCreate >= strictCodecs,
|
|
84
|
+
`${withCreate} of ${strictCodecs}`)
|
|
85
|
+
}
|
|
86
|
+
if (wantsSchema) {
|
|
87
|
+
check('every strict codec provides schema', withSchema >= strictCodecs,
|
|
88
|
+
`${withSchema} of ${strictCodecs}`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 3. The peer range must actually admit the installed DSH version, because npm
|
|
92
|
+
// semver will not match a prerelease the range does not name. Implemented
|
|
93
|
+
// here rather than via the `semver` package: that is a devDependency, so a
|
|
94
|
+
// consumer running this script from the installed tarball has no copy, and
|
|
95
|
+
// the whole point of this check is to run against whatever DSH is present.
|
|
96
|
+
const pkg = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'))
|
|
97
|
+
const range = pkg.peerDependencies['@deepseek-ai/dsh-typert-protocol'] ?? ''
|
|
98
|
+
check(`peer range admits DSH ${protocol.version}`, rangeAdmits(range, protocol.version), range)
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Whether one of a `||`-joined range's comparators admits `version`.
|
|
102
|
+
*
|
|
103
|
+
* npm semver matches a prerelease only when the comparator names a prerelease
|
|
104
|
+
* on the SAME major.minor.patch, which is why enumerating versions is the only
|
|
105
|
+
* way to cover a DSH alpha. This mirrors that rule for the caret and exact
|
|
106
|
+
* forms the manifest actually uses; it is deliberately conservative, and an
|
|
107
|
+
* unrecognized comparator reports `false` so the check fails loudly rather than
|
|
108
|
+
* passing by accident.
|
|
109
|
+
* @param range - the peer range expression.
|
|
110
|
+
* @param version - the installed DSH version to test.
|
|
111
|
+
* @returns true when the range admits the version.
|
|
112
|
+
*/
|
|
113
|
+
function rangeAdmits(range, version) {
|
|
114
|
+
const parse = text => {
|
|
115
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(text.trim())
|
|
116
|
+
return match === null
|
|
117
|
+
? undefined
|
|
118
|
+
: { major: +match[1], minor: +match[2], patch: +match[3], pre: match[4] }
|
|
119
|
+
}
|
|
120
|
+
const target = parse(version)
|
|
121
|
+
if (target === undefined) return false
|
|
122
|
+
for (const part of range.split('||').map(text => text.trim()).filter(Boolean)) {
|
|
123
|
+
const caret = /^\^(.+)$/u.exec(part)
|
|
124
|
+
const lower = parse(caret === null ? part : caret[1])
|
|
125
|
+
if (lower === undefined) continue
|
|
126
|
+
// Same prerelease tuple, or a plain release on the same caret line.
|
|
127
|
+
const sameTuple = target.major === lower.major
|
|
128
|
+
&& target.minor === lower.minor
|
|
129
|
+
&& target.patch === lower.patch
|
|
130
|
+
if (lower.pre !== undefined) {
|
|
131
|
+
if (sameTuple) return true
|
|
132
|
+
} else if (target.pre === undefined && target.major === lower.major) {
|
|
133
|
+
if (caret === null ? sameTuple : target.minor >= lower.minor) return true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (problems.length > 0) {
|
|
140
|
+
console.error(`\n${problems.length} DSH compatibility problem(s)`)
|
|
141
|
+
console.error('A new DSH alpha likely changed the Typert contract. Update src/client/remote.ts')
|
|
142
|
+
console.error('and add the version to peerDependencies before releasing.')
|
|
143
|
+
process.exit(1)
|
|
144
|
+
}
|
|
145
145
|
console.log('\nDSH compatibility verified')
|
|
@@ -16,7 +16,7 @@ description: 开发节点:按方案拆解实施项,独立交付可派子 age
|
|
|
16
16
|
- 不要等子代理返回才登记派发,否则任务台账会在实际开发时一直显示 todo。dispatch 只是计划记录,实际执行由子代理工具调用和结果证明;重派会使该项旧审核失效。
|
|
17
17
|
3. 本项实现完成后(主 agent 实施或子 agent 返回),主 agent 做两阶段审查(顺序不可反):
|
|
18
18
|
- 规格符合:对照需求/方案,查「做对了没、有没有超范围、漏没漏边界」。
|
|
19
|
-
-
|
|
19
|
+
- 代码质量:按当前任务为本技能配置的规则(若有)及实际代码契约查「做得好不好」——契约兼容、边界与错误处理、命名与结构;不自行补用未绑定的内置规则。
|
|
20
20
|
4. 审查完用 `dev_task`(operation=review_item, item_id=<本项 id>, spec_outcome=pass|fail, quality_outcome=pass|fail, notes=[结论或问题清单]) 落两阶段结论留痕。
|
|
21
21
|
5. 任一阶段不过:按第 2 步选择主 agent 小修正或 fresh 子 agent 重做,明确上次的问题;重做后再审查,并再次 `review_item` 覆盖前次结论。只改测试路径或文案时,运行受影响的定向检查,不重复无关的全量编译。
|
|
22
22
|
6. **两阶段都 pass 后**才用 `dev_task`(operation=items, items=[...]) 全量回写,把本项标 done(其余项原样保留);已有项可只传 id/status,省略 title 以保留原文与审核。追加修复项时不要重写已完成项标题;确需改标题应显式重开并重新审核。spec 或 quality 任一 fail 都不许标 done,回到第 5 步重做。
|
|
@@ -11,9 +11,9 @@ description: 交付验证节点:执行目标测试、编译与契约检查,
|
|
|
11
11
|
4. 文件或范围变更会使旧验证回执失效,审核修复后可在当前阶段重跑 verify。沙箱拒绝属于环境阻塞,不能改跑不相关的简单命令来冒充原验收通过。
|
|
12
12
|
5. 环境受阻时如实记"未编译/未联调";high_risk 核心行为无法验证时不得通过。
|
|
13
13
|
|
|
14
|
-
权限或沙箱拒绝后,不得切换等价命令、修改 ACL 或安全策略来规避限制。确认错误来自宿主权限后使用 Harness 正式审批;审批不可用时报告失败路径和所需授权,等待处理,不把工具访问限制推断为服务不可达。
|
|
15
|
-
|
|
16
|
-
`verify` / `skill_result` 的验证命令因沙箱受阻时,保持原命令,增加 `sandbox_permissions: "danger-full-access"` 和具体 `justification` 申请单次重试。批准发生在命令执行之前,只对本次调用生效;回执中的实际模式与退出码才是本次结果,不能引用之前 shell 调用通过的结果替代。保存完整测试输出后从已有日志提取用例,不为截取不同摘要重复跑已通过测试。
|
|
14
|
+
权限或沙箱拒绝后,不得切换等价命令、修改 ACL 或安全策略来规避限制。确认错误来自宿主权限后使用 Harness 正式审批;审批不可用时报告失败路径和所需授权,等待处理,不把工具访问限制推断为服务不可达。
|
|
15
|
+
|
|
16
|
+
`verify` / `skill_result` 的验证命令因沙箱受阻时,保持原命令,增加 `sandbox_permissions: "danger-full-access"` 和具体 `justification` 申请单次重试。批准发生在命令执行之前,只对本次调用生效;回执中的实际模式与退出码才是本次结果,不能引用之前 shell 调用通过的结果替代。保存完整测试输出后从已有日志提取用例,不为截取不同摘要重复跑已通过测试。
|
|
17
17
|
|
|
18
18
|
验证失败不得 advance。
|
|
19
19
|
|
|
@@ -1,38 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eng-delivery
|
|
3
|
-
description: 使用 dev_task
|
|
4
|
-
whenToUse:
|
|
3
|
+
description: 使用 dev_task 读取任务状态、执行流程门禁与完成条件;具体技能、规则、产物和提交文本以用户配置为准。
|
|
4
|
+
whenToUse: 在启用工程化交付会话预设后,开始或继续开发任务时先读取状态;阶段流转与完成必须通过 dev_task。
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# 工程流程编排
|
|
8
8
|
|
|
9
|
-
`dev_task`
|
|
9
|
+
`dev_task` 是任务状态、阶段流转与门禁的唯一事实来源。流程预设决定阶段图与守卫;项目配置决定阶段使用哪些技能、每个技能遵守哪些规则,以及产物字段和提交文本。内置业务技能与规则只是可选样本,不能因它们随包安装就推定任务必须使用。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
1. 先调用 `dev_task`(operation=status)查找当前工作区和分支的任务;有多个候选时让使用者明确目标。没有任务时按实际需求调用 `create`,已有任务则从返回的 `stage` 继续。
|
|
12
|
+
2. 读取 `status.bindings`、`skill_obligations`、`artifact_requirements`、`legal_next` 和 `commit`。只加载当前及即将进入的终态实际绑定的技能,遵守披露的冻结规则正文;没有绑定时不自行补上任何内置技能或规则。
|
|
13
|
+
3. 技能要求的证据以其配置和 `status.skill_obligations` 为准:仅对 `command_receipts_required` 列出的技能通过带真实命令的 `skill_result` 记录;`manual` 通过人工审批记录;`artifact`、`review` 与 `none` 按对应阶段操作或无需额外回执处理。不要把所有技能都当成命令型技能。技能加载成功不等于要求的证据已经完成。
|
|
14
|
+
4. 需要记录产物时,只使用 `artifact_requirements` 给出的 id 与字段。按当前流程要求完成确认、实施项、验证和审核,再调用 `advance`;被拒绝时按返回的阻塞原因修正,不改任务文件绕过门禁。
|
|
15
|
+
5. 只在 `status.commit` 允许的检查点申请提交,并按冻结配置校验文件范围与消息。提交后按工具要求回写真实 Git HEAD。到达终态后调用 `complete`,以其完成条件为准;需要返工时使用 `revise`。
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## 入口
|
|
16
|
-
|
|
17
|
-
1. 先 `dev_task`(operation=status, branch=当前分支)发现任务,再带 task_id 查询所选任务的详细状态;有多个候选时不要猜测:
|
|
18
|
-
- 没有任务 → `dev_task`(operation=create,task_id=短 ID 如 GREET-001,title=任务标题,branch=当前 git 分支,files=本任务涉及的文件列表)建立任务并停在**起始阶段**(由配置 `start_stage` 决定,默认「需求评审」),从起始阶段开始。
|
|
19
|
-
- 已有任务 → **从 `status` 返回的 `stage` 继续,绝不重走已过的阶段**。每个阶段对应一个节点技能:需求评审→`requirement-analysis`、设计→`solution-design`、开发→`code-implement`、交付→`code-verify`、代码审核→`code-review` + `code-commit`、完成→收尾。只做当前 stage 那一个节点的事:完成该阶段产物、满足 guard,才 `advance` 到下一阶段。
|
|
20
|
-
- 文件范围一时不清就先 `operation=create` 建任务,摸清后用 `operation=scope, files=...` 补齐。
|
|
21
|
-
2. 每阶段先通过 `skill` 工具加载所有绑定技能,再执行其指引;仅看到技能名称不算执行。完成本阶段产物后:
|
|
22
|
-
- 内置七项(eng-delivery、requirement-analysis、solution-design、code-implement、code-verify、code-review、code-commit)使用现有 record/verify/review/commit 门禁,**不需要 skill_result**,即使项目配置显式列出了这些名称。仅对 status.skill_obligations.command_receipts_required 列出的附加技能记录 skill_result;不要为内置节点重复写“检查字段非空”的验证命令。
|
|
23
|
-
- 新任务的附加技能还需 `operation=skill_result, skill_name=技能名, target_stage=所属阶段, evidence=[实际场景与结果], command=真实验收命令`。命令由引擎执行,失败不能流转;非测试技能可用检查其交付文件内容的命令,不能用 echo/恒成功命令代替验收。
|
|
24
|
-
- `status.skill_obligations` 包含紧邻的终态绑定:例如挂在“完成”的 software-testing,需要在代码审核阶段提前加载、执行、记录,再提交和进入完成。不要等宣告完成后才测试。
|
|
25
|
-
- 标准流程在代码审核阶段完成评审后提交;其他流程以 `status.commit` 返回的检查点为准。审核修复允许留在当前阶段处理,但改动后须重新验证,更新评审结论。
|
|
26
|
-
- 若本阶段配置了必交产物(`dev_task` operation=status 会列出 still missing 的字段),先用 `dev_task`(operation=record, artifact=..., fields=...)逐字段记录;字段不填全,流转会被 `artifacts_present` guard 拒绝。
|
|
27
|
-
- 再用 `dev_task`(operation=advance)流转到目标阶段;被拒绝说明 guard 未满足(需求/方案未获人批准 / 产物字段没填全 / 实施项没完 / 高风险没验证 / 评审没过),先补齐再重试,不得绕过。
|
|
28
|
-
3. 提交前用 `dev_task`(operation=commit, files=<要提交的文件列表>, message=...)校验阶段、文件范围与消息格式;拿到 approved 后再逐文件 git add 和 git commit,并把 commit hash 通过 `dev_task`(operation=commit, files=同一列表, message=同一消息, hash=真实HEAD)回写。引擎核对 Git HEAD、消息和实际文件。没有回写成功,不得离开提交检查点。落在任务 files 之外的文件先明确与当前需求的关系,必要时更新 scope;无关工作另开任务。
|
|
29
|
-
|
|
30
|
-
## 硬规则
|
|
31
|
-
|
|
32
|
-
- 需求、Bug、继续开发、验证、评审、提交请求一律经 `dev_task` 状态机推进,不自行绕过。
|
|
33
|
-
- 阶段是硬状态:`status` 的 `stage` 决定你现在做哪个节点;只做该节点绑定的技能与产物,不得在错误阶段做其他阶段的事,绝不倒带重走已过的阶段。
|
|
34
|
-
- 需求、方案的「确认」只能由人在审批中批准(`advance` 撞上确认门槛时系统会自动发起审批,人在页面点批准才放行);模型不能自己确认,也不能绕过这扇门。
|
|
35
|
-
- 阶段必交产物(如需求说明、设计文档、评审记录)必须用 `dev_task` operation=record 落库,字段不能留空、不能装样子。
|
|
36
|
-
- 先声明文件范围:任务 `files` 只放本任务真正要改的文件;提交的文件必须全在 `files` 内,范围外的文件(哪怕是"顺手改一下")也必须另开任务。
|
|
37
|
-
- 只做任务范围内的本地提交;绝不 push、合并、创建 PR、执行数据库、操作 Jenkins、部署或发布。
|
|
38
|
-
- `dev_task` 的拒绝是硬事实:修正前置条件,而不是换一种方式绕过。
|
|
17
|
+
不同流程的阶段数与守卫不同,不把某一预设的阶段顺序、技能映射、规则组合或提交格式当作所有项目的默认工作方法。用户修改配置只影响之后创建的任务;进行中的任务继续遵守创建时冻结的配置与资源。
|