create-harness-vibe-coding 0.8.13 → 0.8.17
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 +174 -0
- package/README-CN.md +110 -107
- package/README.md +93 -44
- package/package.json +2 -1
- package/src/generator.js +609 -489
- package/src/index.js +5 -5
- package/templates/common/.claude/agents/architect-manager.md +1 -0
- package/templates/common/.claude/agents/architect.md +2 -1
- package/templates/common/.claude/agents/codebase-explorer.md +1 -0
- package/templates/common/.claude/agents/context-master.md +2 -1
- package/templates/common/.claude/agents/debugger.md +1 -0
- package/templates/common/.claude/agents/docs-researcher.md +2 -1
- package/templates/common/.claude/agents/explore-manager.md +1 -0
- package/templates/common/.claude/agents/implement-manager.md +1 -0
- package/templates/common/.claude/agents/implementer.md +1 -0
- package/templates/common/.claude/agents/memory-master.md +2 -1
- package/templates/common/.claude/agents/planner.md +3 -2
- package/templates/common/.claude/agents/reflector.md +1 -0
- package/templates/common/.claude/agents/researcher.md +1 -0
- package/templates/common/.claude/agents/review-manager.md +1 -0
- package/templates/common/.claude/agents/reviewer.md +2 -1
- package/templates/common/.claude/agents/task-scribe.md +1 -0
- package/templates/common/.claude/agents/tdd-guide.md +5 -4
- package/templates/common/.claude/agents/test-writer.md +6 -5
- package/templates/common/.claude/agents/verifier.md +1 -0
- package/templates/common/.claude/commands/wf-auto-spark.md +16 -0
- package/templates/common/.claude/commands/wf-auto.md +16 -0
- package/templates/{optional/skills/browser-e2e/.opencode → common/.claude}/commands/wf-browser.md +3 -2
- package/templates/common/.claude/commands/wf-help.md +9 -5
- package/templates/common/.claude/commands/wf-learn.md +16 -0
- package/templates/common/.claude/commands/wf-max.md +20 -0
- package/templates/common/.claude/commands/wf-readme.md +16 -0
- package/templates/common/.claude/commands/wf-remove.md +16 -0
- package/templates/common/.claude/commands/wf-review.md +16 -0
- package/templates/common/.claude/commands/wf-update.md +68 -10
- package/templates/common/.claude/commands/wf.md +16 -0
- package/templates/common/.claude/rules/ecc/common.md +6 -5
- package/templates/common/.claude/skills/subagent-orchestrator/SKILL.md +12 -6
- package/templates/common/.claude/skills/tdd/SKILL.md +5 -5
- package/templates/common/.claude/skills/wf/SKILL.md +13 -5
- package/templates/common/.claude/skills/wf-agents-docs/SKILL.md +119 -0
- package/templates/common/.claude/skills/wf-auto/SKILL.md +27 -7
- package/templates/common/.claude/skills/wf-auto-spark/SKILL.md +12 -5
- package/templates/common/.claude/skills/wf-browser/SKILL.md +176 -0
- package/templates/common/.claude/skills/wf-help/SKILL.md +30 -0
- package/templates/common/.claude/skills/wf-learn/SKILL.md +6 -0
- package/templates/common/.claude/skills/wf-max/SKILL.md +43 -14
- package/templates/common/.claude/skills/wf-readme/SKILL.md +8 -2
- package/templates/common/.claude/skills/wf-remove/SKILL.md +6 -0
- package/templates/common/.claude/skills/wf-review/SKILL.md +10 -3
- package/templates/common/.claude/skills/wf-update/SKILL.md +41 -4
- package/templates/common/.codex/config.toml +3 -5
- package/templates/common/.harness-version +326 -131
- package/templates/common/.opencode/agents/architect-manager.md +8 -1
- package/templates/common/.opencode/agents/architect.md +2 -1
- package/templates/common/.opencode/agents/codebase-explorer.md +1 -0
- package/templates/common/.opencode/agents/context-master.md +2 -1
- package/templates/common/.opencode/agents/debugger.md +1 -0
- package/templates/common/.opencode/agents/docs-researcher.md +2 -1
- package/templates/common/.opencode/agents/explore-manager.md +11 -1
- package/templates/common/.opencode/agents/implement-manager.md +6 -3
- package/templates/common/.opencode/agents/implementer.md +1 -0
- package/templates/common/.opencode/agents/memory-master.md +2 -1
- package/templates/common/.opencode/agents/planner.md +3 -2
- package/templates/common/.opencode/agents/reflector.md +1 -0
- package/templates/common/.opencode/agents/researcher.md +1 -0
- package/templates/common/.opencode/agents/review-manager.md +6 -2
- package/templates/common/.opencode/agents/reviewer.md +2 -1
- package/templates/common/.opencode/agents/task-scribe.md +1 -0
- package/templates/common/.opencode/agents/tdd-guide.md +5 -4
- package/templates/common/.opencode/agents/test-writer.md +6 -5
- package/templates/common/.opencode/agents/verifier.md +1 -0
- package/templates/common/.opencode/commands/wf-auto-spark.md +3 -2
- package/templates/common/.opencode/commands/wf-auto.md +3 -2
- package/templates/common/.opencode/commands/wf-browser.md +16 -0
- package/templates/common/.opencode/commands/wf-help.md +9 -5
- package/templates/common/.opencode/commands/wf-learn.md +3 -2
- package/templates/common/.opencode/commands/wf-max.md +12 -6
- package/templates/common/.opencode/commands/wf-readme.md +3 -2
- package/templates/common/.opencode/commands/wf-remove.md +3 -2
- package/templates/common/.opencode/commands/wf-review.md +3 -2
- package/templates/common/.opencode/commands/wf-update.md +68 -10
- package/templates/common/.opencode/commands/wf.md +3 -2
- package/templates/common/CLAUDE.md +15 -13
- package/templates/common/Harness/MEMORY.md +24 -21
- package/templates/common/Harness/README.md +50 -47
- package/templates/common/Harness/ownership.manifest.json +878 -0
- package/templates/common/Harness/{architecture.md → project/architecture.md} +1 -1
- package/templates/common/Harness/research/README.md +3 -3
- package/templates/common/Harness/scripts/archive-tasks.mjs +12 -220
- package/templates/common/Harness/scripts/context-budget.mjs +95 -0
- package/templates/common/Harness/scripts/l2-cache-telemetry.mjs +703 -0
- package/templates/common/Harness/scripts/scan-clean.mjs +16 -12
- package/templates/common/Harness/scripts/task-state.mjs +889 -0
- package/templates/common/Harness/scripts/validate-harness.mjs +553 -191
- package/templates/common/Harness/scripts/wf-remove.mjs +61 -35
- package/templates/common/Harness/scripts/wf-update-check.mjs +358 -45
- package/templates/common/Harness/settings.json +43 -0
- package/templates/common/Harness/{ECC-GUIDE.md → specs/guides/ECC-GUIDE.md} +4 -4
- package/templates/common/Harness/{SETUP.md → specs/guides/SETUP.md} +34 -37
- package/templates/common/Harness/{extension.md → specs/guides/extension.md} +3 -3
- package/templates/common/Harness/{lifecycle.md → specs/guides/lifecycle.md} +2 -2
- package/templates/common/Harness/specs/protocols/TASK_ARCHIVE.md +76 -0
- package/templates/common/Harness/{agent-workflow.md → specs/runtime/agent-workflow.md} +6 -6
- package/templates/common/Harness/{context-loading.md → specs/runtime/context-loading.md} +85 -21
- package/templates/common/Harness/{dispatch.md → specs/runtime/dispatch.md} +4 -3
- package/templates/common/Harness/{subagents.md → specs/runtime/subagents.md} +19 -10
- package/templates/common/Harness/{WF-AUTO-SPARK.md → specs/workflows/WF-AUTO-SPARK.md} +2 -2
- package/templates/common/Harness/{WF-AUTO.md → specs/workflows/WF-AUTO.md} +12 -7
- package/templates/common/Harness/{WF-KERNEL.md → specs/workflows/WF-KERNEL.md} +11 -1
- package/templates/common/Harness/{WF-MAX.md → specs/workflows/WF-MAX.md} +40 -7
- package/templates/common/Harness/specs/workflows/WF-STATE.md +141 -0
- package/templates/common/Harness/{WF.md → specs/workflows/WF.md} +12 -1
- package/templates/common/README.md +8 -6
- package/templates/common/memory/startup-hints.md +19 -17
- package/templates/common/opencode.json +1 -0
- package/templates/optional/catalog.json +2 -9
- package/templates/optional/skills/github-pr-review/.claude/skills/github-pr-review/SKILL.md +1 -1
- package/templates/optional/skills/python-backend/.claude/skills/python-backend/SKILL.md +1 -1
- package/templates/optional/skills/ts-react-frontend/.claude/skills/ts-react-frontend/SKILL.md +1 -1
- package/templates/optional/skills/ui-ux-review/.claude/skills/ui-ux-review/SKILL.md +1 -1
- package/templates/common/Harness/TASK_ARCHIVE.md +0 -56
- package/templates/common/Harness/WF-STATE.md +0 -83
- package/templates/optional/skills/browser-e2e/.claude/skills/browser-e2e/SKILL.md +0 -42
- package/templates/optional/skills/browser-e2e/.claude/skills/wf-browser/SKILL.md +0 -194
- package/templates/optional/skills/browser-e2e/Harness/workflows/browser-e2e.md +0 -119
- /package/templates/common/Harness/{ACCEPTANCE_PROTOCOL.md → specs/protocols/ACCEPTANCE_PROTOCOL.md} +0 -0
- /package/templates/common/Harness/{AGENT_ISOLATION.md → specs/protocols/AGENT_ISOLATION.md} +0 -0
- /package/templates/common/Harness/{DEBUG_PROTOCOL.md → specs/protocols/DEBUG_PROTOCOL.md} +0 -0
- /package/templates/common/Harness/{HARNESS_BRIDGE.md → specs/protocols/HARNESS_BRIDGE.md} +0 -0
- /package/templates/common/Harness/{MEMORY_PROTOCOL.md → specs/protocols/MEMORY_PROTOCOL.md} +0 -0
- /package/templates/common/Harness/{TDD-GUIDE.md → specs/protocols/TDD-GUIDE.md} +0 -0
- /package/templates/common/Harness/{WF-AUTO-ANGLES.md → specs/workflows/WF-AUTO-ANGLES.md} +0 -0
|
@@ -38,29 +38,39 @@ const commonAgents = [
|
|
|
38
38
|
|
|
39
39
|
const commonSkills = [
|
|
40
40
|
'wf',
|
|
41
|
+
'wf-help',
|
|
41
42
|
'tdd',
|
|
42
43
|
'wf-update',
|
|
43
44
|
'wf-max',
|
|
44
45
|
'wf-review',
|
|
45
46
|
'wf-learn',
|
|
47
|
+
'wf-browser',
|
|
46
48
|
'subagent-orchestrator',
|
|
47
49
|
'wf-readme',
|
|
50
|
+
'wf-agents-docs',
|
|
48
51
|
'wf-remove',
|
|
49
52
|
'wf-auto',
|
|
50
53
|
'wf-auto-spark',
|
|
51
54
|
];
|
|
52
55
|
|
|
53
|
-
const
|
|
56
|
+
const workflowCommands = [
|
|
54
57
|
'wf',
|
|
55
58
|
'wf-max',
|
|
56
59
|
'wf-auto',
|
|
57
60
|
'wf-auto-spark',
|
|
58
61
|
'wf-learn',
|
|
59
62
|
'wf-review',
|
|
63
|
+
'wf-browser',
|
|
60
64
|
'wf-readme',
|
|
61
65
|
'wf-remove',
|
|
62
66
|
];
|
|
63
67
|
|
|
68
|
+
const opencodeWorkflowCommands = workflowCommands;
|
|
69
|
+
|
|
70
|
+
const cacheDisciplinedSkills = commonSkills.filter(skill => (
|
|
71
|
+
skill === 'subagent-orchestrator' || (skill.startsWith('wf') && skill !== 'wf-help')
|
|
72
|
+
));
|
|
73
|
+
|
|
64
74
|
const memoryFiles = [
|
|
65
75
|
'Harness/memory/startup-hints.md',
|
|
66
76
|
'Harness/memory/routes.md',
|
|
@@ -74,13 +84,13 @@ const required = [
|
|
|
74
84
|
'CLAUDE.md',
|
|
75
85
|
'README.md',
|
|
76
86
|
'Harness/MEMORY.md',
|
|
77
|
-
'Harness/WF.md',
|
|
78
|
-
'Harness/WF-MAX.md',
|
|
79
|
-
'Harness/ACCEPTANCE_PROTOCOL.md',
|
|
80
|
-
'Harness/AGENT_ISOLATION.md',
|
|
81
|
-
'Harness/HARNESS_BRIDGE.md',
|
|
82
|
-
'Harness/DEBUG_PROTOCOL.md',
|
|
83
|
-
'Harness/MEMORY_PROTOCOL.md',
|
|
87
|
+
'Harness/specs/workflows/WF.md',
|
|
88
|
+
'Harness/specs/workflows/WF-MAX.md',
|
|
89
|
+
'Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md',
|
|
90
|
+
'Harness/specs/protocols/AGENT_ISOLATION.md',
|
|
91
|
+
'Harness/specs/protocols/HARNESS_BRIDGE.md',
|
|
92
|
+
'Harness/specs/protocols/DEBUG_PROTOCOL.md',
|
|
93
|
+
'Harness/specs/protocols/MEMORY_PROTOCOL.md',
|
|
84
94
|
'Harness/templates/PRD.template.md',
|
|
85
95
|
'Harness/templates/ACCEPTANCE.template.md',
|
|
86
96
|
'Harness/templates/UI_CONTRACT.template.md',
|
|
@@ -90,10 +100,12 @@ const required = [
|
|
|
90
100
|
'Harness/templates/VALIDATION_REPORT.template.md',
|
|
91
101
|
...memoryFiles,
|
|
92
102
|
'.codex/config.toml',
|
|
103
|
+
'.codex/hooks.json',
|
|
93
104
|
'opencode.json',
|
|
94
105
|
'.claude/settings.json',
|
|
95
106
|
'.claude/commands/wf-help.md',
|
|
96
107
|
'.claude/commands/wf-update.md',
|
|
108
|
+
...workflowCommands.map(command => `.claude/commands/${command}.md`),
|
|
97
109
|
'.opencode/commands/wf-help.md',
|
|
98
110
|
'.opencode/commands/wf-update.md',
|
|
99
111
|
...opencodeWorkflowCommands.map(command => `.opencode/commands/${command}.md`),
|
|
@@ -104,24 +116,30 @@ const required = [
|
|
|
104
116
|
...commonSkills.map(skill => `.claude/skills/${skill}/SKILL.md`),
|
|
105
117
|
...commonSkills.map(skill => `.agents/skills/${skill}/SKILL.md`),
|
|
106
118
|
'Harness/README.md',
|
|
119
|
+
'Harness/settings.json',
|
|
120
|
+
'Harness/specs/guides/SETUP.md',
|
|
107
121
|
'Harness/PROGRESS.md',
|
|
108
|
-
'Harness/lifecycle.md',
|
|
109
|
-
'Harness/subagents.md',
|
|
110
|
-
'Harness/dispatch.md',
|
|
111
|
-
'Harness/extension.md',
|
|
112
|
-
'Harness/context-loading.md',
|
|
113
|
-
'Harness/
|
|
114
|
-
'Harness/
|
|
115
|
-
'Harness/
|
|
122
|
+
'Harness/specs/guides/lifecycle.md',
|
|
123
|
+
'Harness/specs/runtime/subagents.md',
|
|
124
|
+
'Harness/specs/runtime/dispatch.md',
|
|
125
|
+
'Harness/specs/guides/extension.md',
|
|
126
|
+
'Harness/specs/runtime/context-loading.md',
|
|
127
|
+
'Harness/ownership.manifest.json',
|
|
128
|
+
'Harness/specs/workflows/WF-KERNEL.md',
|
|
129
|
+
'Harness/specs/runtime/agent-workflow.md',
|
|
130
|
+
'Harness/project/architecture.md',
|
|
116
131
|
'Harness/research/README.md',
|
|
117
132
|
'Harness/research/research-results.md',
|
|
118
133
|
'Harness/research/PRD.md',
|
|
134
|
+
'Harness/scripts/context-budget.mjs',
|
|
135
|
+
'Harness/scripts/l2-cache-telemetry.mjs',
|
|
119
136
|
'Harness/scripts/wf-update-check.mjs',
|
|
120
137
|
'Harness/scripts/wf-remove.mjs',
|
|
121
138
|
'Harness/scripts/scan-clean.mjs',
|
|
139
|
+
'Harness/scripts/task-state.mjs',
|
|
122
140
|
'Harness/scripts/archive-tasks.mjs',
|
|
123
|
-
'Harness/WF-STATE.md',
|
|
124
|
-
'Harness/TASK_ARCHIVE.md',
|
|
141
|
+
'Harness/specs/workflows/WF-STATE.md',
|
|
142
|
+
'Harness/specs/protocols/TASK_ARCHIVE.md',
|
|
125
143
|
'Harness/.harness-version',
|
|
126
144
|
];
|
|
127
145
|
|
|
@@ -129,7 +147,7 @@ const projectFacts = [
|
|
|
129
147
|
'Harness/PROGRESS.md',
|
|
130
148
|
'Harness/research/PRD.md',
|
|
131
149
|
'Harness/research/research-results.md',
|
|
132
|
-
'Harness/architecture.md',
|
|
150
|
+
'Harness/project/architecture.md',
|
|
133
151
|
];
|
|
134
152
|
|
|
135
153
|
const contextPacks = [
|
|
@@ -149,9 +167,34 @@ const contextPacks = [
|
|
|
149
167
|
|
|
150
168
|
const durableCommunicationDocs = [
|
|
151
169
|
'Harness/README.md',
|
|
152
|
-
'Harness/subagents.md',
|
|
153
|
-
'Harness/dispatch.md',
|
|
170
|
+
'Harness/specs/runtime/subagents.md',
|
|
171
|
+
'Harness/specs/runtime/dispatch.md',
|
|
172
|
+
'Harness/specs/runtime/context-loading.md',
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
const legacyRootSpecDocs = [
|
|
176
|
+
'Harness/ACCEPTANCE_PROTOCOL.md',
|
|
177
|
+
'Harness/AGENT_ISOLATION.md',
|
|
178
|
+
'Harness/DEBUG_PROTOCOL.md',
|
|
179
|
+
'Harness/ECC-GUIDE.md',
|
|
180
|
+
'Harness/HARNESS_BRIDGE.md',
|
|
181
|
+
'Harness/MEMORY_PROTOCOL.md',
|
|
182
|
+
'Harness/SETUP.md',
|
|
183
|
+
'Harness/TASK_ARCHIVE.md',
|
|
184
|
+
'Harness/TDD-GUIDE.md',
|
|
185
|
+
'Harness/WF-AUTO-ANGLES.md',
|
|
186
|
+
'Harness/WF-AUTO-SPARK.md',
|
|
187
|
+
'Harness/WF-AUTO.md',
|
|
188
|
+
'Harness/WF-KERNEL.md',
|
|
189
|
+
'Harness/WF-MAX.md',
|
|
190
|
+
'Harness/WF-STATE.md',
|
|
191
|
+
'Harness/WF.md',
|
|
192
|
+
'Harness/agent-workflow.md',
|
|
154
193
|
'Harness/context-loading.md',
|
|
194
|
+
'Harness/dispatch.md',
|
|
195
|
+
'Harness/extension.md',
|
|
196
|
+
'Harness/lifecycle.md',
|
|
197
|
+
'Harness/subagents.md',
|
|
155
198
|
];
|
|
156
199
|
|
|
157
200
|
const errors = [];
|
|
@@ -171,6 +214,19 @@ function forbidText(rel, text, label = text) {
|
|
|
171
214
|
if (body && body.includes(text)) errors.push(`${rel} contains forbidden ${label}`);
|
|
172
215
|
}
|
|
173
216
|
|
|
217
|
+
function activeToml(rel) {
|
|
218
|
+
return read(rel)
|
|
219
|
+
.split(/\r?\n/)
|
|
220
|
+
.map(line => line.trim())
|
|
221
|
+
.filter(line => line && !line.startsWith('#'))
|
|
222
|
+
.join('\n');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function forbidActiveToml(rel, pattern, label) {
|
|
226
|
+
const body = activeToml(rel);
|
|
227
|
+
if (body && pattern.test(body)) errors.push(`${rel} contains active forbidden ${label}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
174
230
|
function frontmatterField(text, field) {
|
|
175
231
|
const match = text.match(new RegExp(`^${field}:\\s*(.+)$`, 'm'));
|
|
176
232
|
return match ? match[1].trim() : '';
|
|
@@ -199,6 +255,28 @@ function listMarkdownFiles(rel) {
|
|
|
199
255
|
const TASK_NAME_RE = /^task-[a-z]+(-[a-z0-9]+){1,4}$/;
|
|
200
256
|
const TASK_NAME_MAX = 46; // "task-" (5) + ≤40 chars body + 1 safety = 46
|
|
201
257
|
const TASK_RESERVED = new Set(['_template', 'auto', '_archive']);
|
|
258
|
+
const TASK_SAFE_ARCHIVE_STATUSES = new Set(['complete', 'verified', 'archived', 'abandoned', 'obsolete', 'done', 'closed', 'closeout']);
|
|
259
|
+
const TASK_NEVER_ARCHIVE_STATUSES = new Set(['active', 'blocked', 'in_progress', 'running', 'pending', 'needs-user-decision']);
|
|
260
|
+
const TASK_PHASE_ALIASES = new Map([
|
|
261
|
+
['implementation', 'implement'],
|
|
262
|
+
['build', 'implement'],
|
|
263
|
+
['validation', 'verify'],
|
|
264
|
+
['complete', 'verified'],
|
|
265
|
+
['done', 'verified'],
|
|
266
|
+
['closed', 'closeout'],
|
|
267
|
+
]);
|
|
268
|
+
const TASK_STATUS_ALIASES = new Map([
|
|
269
|
+
['in-progress', 'in_progress'],
|
|
270
|
+
['inprogress', 'in_progress'],
|
|
271
|
+
['needs_user_decision', 'needs-user-decision'],
|
|
272
|
+
['needs-user', 'needs-user-decision'],
|
|
273
|
+
]);
|
|
274
|
+
const TASK_VALID_PHASES = new Set([
|
|
275
|
+
'intake', 'clarify', 'requirements', 'prd', 'acceptance', 'plan', 'explore',
|
|
276
|
+
'implement', 'verify', 'review', 'fix', 'reflect', 'closeout', 'blocked',
|
|
277
|
+
'archived', 'verified',
|
|
278
|
+
]);
|
|
279
|
+
const TASK_VALID_STATUSES = new Set([...TASK_SAFE_ARCHIVE_STATUSES, ...TASK_NEVER_ARCHIVE_STATUSES, 'skipped', 'failed']);
|
|
202
280
|
|
|
203
281
|
function validateTaskName(name, strict) {
|
|
204
282
|
if (TASK_RESERVED.has(name)) return null;
|
|
@@ -215,6 +293,57 @@ function validateTaskName(name, strict) {
|
|
|
215
293
|
return null;
|
|
216
294
|
}
|
|
217
295
|
|
|
296
|
+
function normalizeTaskToken(value, validSet, aliasMap) {
|
|
297
|
+
if (value === null || value === undefined) return '';
|
|
298
|
+
const raw = String(value).trim().toLowerCase();
|
|
299
|
+
if (!raw) return '';
|
|
300
|
+
const compact = raw.replace(/\s+/g, '-');
|
|
301
|
+
const direct = aliasMap.get(compact) || compact;
|
|
302
|
+
if (validSet.has(direct)) return direct;
|
|
303
|
+
const tokens = raw
|
|
304
|
+
.replace(/[`*_()[\]{}:]/g, ' ')
|
|
305
|
+
.replace(/[^a-z0-9_-]+/g, ' ')
|
|
306
|
+
.split(/\s+/)
|
|
307
|
+
.map(token => token.trim())
|
|
308
|
+
.filter(Boolean);
|
|
309
|
+
for (const token of tokens) {
|
|
310
|
+
const canonical = aliasMap.get(token) || token;
|
|
311
|
+
if (validSet.has(canonical)) return canonical;
|
|
312
|
+
}
|
|
313
|
+
return '';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function normalizeTaskStatus(value) {
|
|
317
|
+
return normalizeTaskToken(value, TASK_VALID_STATUSES, TASK_STATUS_ALIASES);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function normalizeTaskPhase(value) {
|
|
321
|
+
return normalizeTaskToken(value, TASK_VALID_PHASES, TASK_PHASE_ALIASES);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function taskStateIssue(message) {
|
|
325
|
+
if (strict) errors.push(message);
|
|
326
|
+
else console.warn(`Warning: ${message}`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function parseRootTaskProgress(text) {
|
|
330
|
+
const activeMatch = text.match(/## Active Task\s*\r?\n+(?:\s*\r?\n)?\s*-\s*([^\r\n]+)/);
|
|
331
|
+
const rawActive = activeMatch ? activeMatch[1].trim() : '';
|
|
332
|
+
const activeTask = rawActive && !/^none$/i.test(rawActive) ? rawActive : null;
|
|
333
|
+
const rows = [];
|
|
334
|
+
const taskIndexMatch = text.match(/## Task Index\s*\r?\n([\s\S]*?)(?=\r?\n## |\s*$)/);
|
|
335
|
+
if (taskIndexMatch) {
|
|
336
|
+
for (const line of taskIndexMatch[1].split(/\r?\n/)) {
|
|
337
|
+
const trimmed = line.trim();
|
|
338
|
+
if (!trimmed.startsWith('|')) continue;
|
|
339
|
+
if (/^\|\s*-+/.test(trimmed) || /^\|\s*ID\s*\|/i.test(trimmed)) continue;
|
|
340
|
+
const cells = trimmed.split('|').slice(1, -1).map(cell => cell.trim());
|
|
341
|
+
if (cells.length >= 4 && cells[0]) rows.push({ id: cells[0], phase: cells[2] });
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return { activeTask, rows };
|
|
345
|
+
}
|
|
346
|
+
|
|
218
347
|
function unresolvedTemplatePlaceholders(text) {
|
|
219
348
|
const placeholders = [];
|
|
220
349
|
const pattern = /\{\{([^{}\r\n]+)\}\}/g;
|
|
@@ -262,7 +391,6 @@ function listedWorkflowCommands(...texts) {
|
|
|
262
391
|
for (const match of text.matchAll(pattern)) {
|
|
263
392
|
const command = `/${match[1]}`;
|
|
264
393
|
if (command === '/wf-help') continue;
|
|
265
|
-
if (command === '/wf-browser') continue; // optional workflow, not a required skill
|
|
266
394
|
commands.add(command);
|
|
267
395
|
}
|
|
268
396
|
}
|
|
@@ -276,6 +404,27 @@ for (const rel of required) {
|
|
|
276
404
|
}
|
|
277
405
|
}
|
|
278
406
|
|
|
407
|
+
for (const rel of legacyRootSpecDocs) {
|
|
408
|
+
if (fs.existsSync(path.join(root, rel))) {
|
|
409
|
+
errors.push(`legacy root Harness spec doc should be migrated to Harness/specs/**: ${rel}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const manifestText = read('Harness/ownership.manifest.json');
|
|
414
|
+
if (manifestText) {
|
|
415
|
+
try {
|
|
416
|
+
const manifest = JSON.parse(manifestText);
|
|
417
|
+
for (const entry of manifest.frameworkOwned || []) {
|
|
418
|
+
if (!entry || typeof entry.path !== 'string') continue;
|
|
419
|
+
if (!fs.existsSync(path.join(root, ...entry.path.split('/')))) {
|
|
420
|
+
errors.push(`ownership manifest frameworkOwned file missing: ${entry.path}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
} catch (err) {
|
|
424
|
+
errors.push(`Harness/ownership.manifest.json is not valid JSON: ${err.message}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
279
428
|
const removedHookArtifacts = [
|
|
280
429
|
'Harness/HOOK_PROTOCOL.md',
|
|
281
430
|
'Harness/scripts/wf-mode-hook.mjs',
|
|
@@ -328,7 +477,7 @@ for (const taskDir of taskDirs) {
|
|
|
328
477
|
// M2: MCP-as-Worker fake-compliance guard.
|
|
329
478
|
// Task capsules MUST NOT record mcp__codex.codex_implement / mcp__claude.claude_implement
|
|
330
479
|
// as Worker execution. Historical do-not-repeat references are allowed only when the
|
|
331
|
-
// file is marked ANTI-PATTERN. See Harness/WF-MAX.md "Worker Channel Degradation & Independence".
|
|
480
|
+
// file is marked ANTI-PATTERN. See Harness/specs/workflows/WF-MAX.md "Worker Channel Degradation & Independence".
|
|
332
481
|
const MCP_AS_WORKER_RE = /mcp__(?:codex)\.codex_implement|mcp__(?:claude)\.claude_implement/;
|
|
333
482
|
for (const taskDir of taskDirs) {
|
|
334
483
|
if (!taskDir.startsWith('task-')) continue;
|
|
@@ -372,13 +521,13 @@ for (const rel of durableCommunicationDocs) {
|
|
|
372
521
|
requireText(rel, 'chat/subagent transcript state is non-authoritative', 'non-authoritative transcript invariant');
|
|
373
522
|
}
|
|
374
523
|
|
|
375
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'L1/L2/L3 Memory Architecture', 'L2/L3 memory architecture section');
|
|
376
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'Memory Candidate Detection', 'memory candidate detection section');
|
|
377
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'explicit user preference', 'explicit user preference immediate write rule');
|
|
378
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'Memory Routing (L3)', 'memory routing section');
|
|
379
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'Scenario pack', 'route scoring scenario pack');
|
|
380
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'same tool or command pattern fails 3+ times', 'tool reflection trigger');
|
|
381
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'user corrects the same assumption or preference 2+ times', 'user correction reflection trigger');
|
|
524
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'L1/L2/L3 Memory Architecture', 'L2/L3 memory architecture section');
|
|
525
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'Memory Candidate Detection', 'memory candidate detection section');
|
|
526
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'explicit user preference', 'explicit user preference immediate write rule');
|
|
527
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'Memory Routing (L3)', 'memory routing section');
|
|
528
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'Scenario pack', 'route scoring scenario pack');
|
|
529
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'same tool or command pattern fails 3+ times', 'tool reflection trigger');
|
|
530
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'user corrects the same assumption or preference 2+ times', 'user correction reflection trigger');
|
|
382
531
|
requireText('CLAUDE.md', 'startup-hints.md', 'CLAUDE startup-hints routing');
|
|
383
532
|
requireText('.claude/rules/ecc/common.md', 'startup-hints.md', 'ECC startup-hints routing');
|
|
384
533
|
requireText('.claude/rules/ecc/common.md', 'memory candidates', 'ECC memory candidate detection');
|
|
@@ -398,20 +547,57 @@ requireText('Harness/memory/tool-usage-reflections.md', 'supersedes', 'tool refl
|
|
|
398
547
|
requireText('Harness/memory/agent-lessons-patterns.md', 'supersedes', 'agent lessons template date rule');
|
|
399
548
|
requireText('Harness/MEMORY.md', 'startup-hints.md', 'MEMORY.md startup-hints registration');
|
|
400
549
|
requireText('Harness/MEMORY.md', 'Memory routes', 'MEMORY.md routes.md registration');
|
|
550
|
+
requireText('Harness/MEMORY.md', '../.claude/commands/wf-update.md', 'MEMORY.md wf-update direct command registration');
|
|
401
551
|
requireText('CLAUDE.md', 'If `Harness/` exists, this repository is governed by the Harness contract', 'Harness binding contract');
|
|
402
552
|
requireText('CLAUDE.md', 'memory and resource router', 'memory/resource router');
|
|
403
553
|
requireText('CLAUDE.md', '## 5a. Low-Noise Progress', 'low-noise progress section');
|
|
554
|
+
requireText('CLAUDE.md', "Match the user's language for all user-facing prose", 'user-facing language match rule');
|
|
404
555
|
requireText('CLAUDE.md', 'Keep intermediate user updates to 1-2 short sentences', 'low-noise intermediate update rule');
|
|
405
556
|
requireText('.claude/rules/ecc/common.md', '## Low-Noise Progress', 'ECC low-noise progress section');
|
|
557
|
+
requireText('.claude/rules/ecc/common.md', "Match the user's language for user-facing prose", 'ECC user-facing language match rule');
|
|
406
558
|
requireText('.claude/rules/ecc/common.md', 'Do not recap plans, paste logs, or narrate obvious file reads', 'ECC low-noise no-recap rule');
|
|
559
|
+
requireText('.claude/rules/ecc/common.md', 'excluding `/wf-help`, `$wf-help`, `/skills wf-help`, `/wf-update`, `$wf-update`, and `/skills wf-update`', 'ECC direct command exemption');
|
|
407
560
|
requireText('Harness/README.md', 'Load By Task', 'Harness task router');
|
|
408
|
-
requireText('
|
|
561
|
+
requireText('Harness/README.md', 'Need context/cache/token efficiency', 'cache/token router row');
|
|
562
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Context Tiers', 'context tier load budget section');
|
|
563
|
+
requireText('Harness/specs/runtime/context-loading.md', 'automatic route profiles, not user-selected modes', 'context tiers are automatic route profiles');
|
|
564
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Budgets are regression guards, not exclusion rules', 'context budgets do not block required files');
|
|
565
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Do not skip required rules', 'context budget correctness priority');
|
|
566
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Escalation rule', 'context-loading targeted escalation rule');
|
|
567
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Thin startup', 'thin startup context tier');
|
|
568
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Routed skill/doc', 'routed skill/doc lazy tier');
|
|
569
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Cache-First Context Contract', 'cache-first context contract');
|
|
570
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Cache Validation Levels', 'cache validation levels');
|
|
571
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Do not claim real cache hits', 'real cache telemetry boundary');
|
|
572
|
+
requireText('Harness/specs/runtime/context-loading.md', 'cached_tokens', 'OpenAI cache telemetry field');
|
|
573
|
+
requireText('Harness/specs/runtime/context-loading.md', 'cache_read_input_tokens', 'Anthropic cache telemetry field');
|
|
574
|
+
requireText('Harness/specs/workflows/WF.md', 'Cache Discipline', 'WF cache discipline');
|
|
575
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'Cache-First Context Contract', 'WF-KERNEL cache-first contract');
|
|
576
|
+
requireText('Harness/specs/runtime/dispatch.md', 'Cache-first dispatch', 'dispatch cache-first discipline');
|
|
577
|
+
requireText('Harness/specs/runtime/subagents.md', 'Cache-first discipline', 'subagents cache-first discipline');
|
|
578
|
+
forbidText('CLAUDE.md', 'Harness/specs/guides/SETUP.md', 'CLAUDE.md SETUP reference');
|
|
409
579
|
forbidText('CLAUDE.md', 'follow it before normal project work', 'installed-project SETUP hot-path routing');
|
|
410
|
-
requireText('Harness/SETUP.md', 'Harness/MEMORY_PROTOCOL.md', 'setup memory protocol reference');
|
|
580
|
+
requireText('Harness/specs/guides/SETUP.md', 'Harness/specs/protocols/MEMORY_PROTOCOL.md', 'setup memory protocol reference');
|
|
581
|
+
requireText('Harness/specs/guides/SETUP.md', 'no startup dependency on this setup reference', 'SETUP startup boundary');
|
|
582
|
+
forbidText('Harness/specs/guides/SETUP.md', 'bootstrap contract line', 'stale SETUP-to-CLAUDE bootstrap contract');
|
|
583
|
+
forbidText('Harness/specs/runtime/context-loading.md', 'Always keep:', 'ambiguous always-load context rule');
|
|
584
|
+
requireText('Harness/scripts/context-budget.mjs', 'thin-startup', 'context-budget thin startup route');
|
|
585
|
+
requireText('Harness/scripts/context-budget.mjs', 'cache-diagnostics-route', 'context-budget cache diagnostics route');
|
|
586
|
+
requireText('Harness/scripts/context-budget.mjs', 'not runtime exclusion rules', 'context-budget non-exclusion guard');
|
|
587
|
+
requireText('Harness/scripts/context-budget.mjs', 'approxTokens', 'context-budget approximate token output');
|
|
588
|
+
requireText('Harness/specs/runtime/context-loading.md', 'Harness/scripts/l2-cache-telemetry.mjs', 'L2 telemetry script reference');
|
|
589
|
+
requireText('Harness/README.md', 'scripts/l2-cache-telemetry.mjs', 'Harness README L2 telemetry script route');
|
|
590
|
+
requireText('Harness/scripts/l2-cache-telemetry.mjs', 'cache_read_input_tokens', 'L2 telemetry cache-read field');
|
|
591
|
+
requireText('Harness/scripts/l2-cache-telemetry.mjs', 'cache_creation_input_tokens', 'L2 telemetry cache-creation field');
|
|
592
|
+
requireText('Harness/scripts/l2-cache-telemetry.mjs', 'claimGate', 'L2 telemetry claim gate');
|
|
593
|
+
requireText('Harness/scripts/l2-cache-telemetry.mjs', '--strict-mcp-config', 'L2 telemetry strict MCP isolation');
|
|
594
|
+
requireText('Harness/scripts/l2-cache-telemetry.mjs', '--max-budget-usd', 'L2 telemetry per-turn budget');
|
|
595
|
+
requireText('Harness/scripts/l2-cache-telemetry.mjs', '--resume', 'L2 telemetry session resume');
|
|
596
|
+
forbidText('Harness/scripts/l2-cache-telemetry.mjs', '--bare', 'L2 telemetry bare mode');
|
|
411
597
|
requireText('Harness/README.md', 'subagent', 'subagent orchestrator entry trigger');
|
|
412
598
|
requireText('Harness/README.md', 'PROGRESS.md', 'PROGRESS global task index');
|
|
413
599
|
requireText('CLAUDE.md', 'Harness/tasks/', 'task capsule directory reference');
|
|
414
|
-
requireText('Harness/subagents.md', 'Subagents are readers and reporters', 'subagent state committer rule');
|
|
600
|
+
requireText('Harness/specs/runtime/subagents.md', 'Subagents are readers and reporters', 'subagent state committer rule');
|
|
415
601
|
for (const heading of ['## 2. Think Before Coding', '## 3. Simplicity First', '## 4. Surgical Changes', '## 5. Goal-Driven Execution']) {
|
|
416
602
|
requireText('CLAUDE.md', heading, `Karpathy-style rule heading: ${heading}`);
|
|
417
603
|
}
|
|
@@ -426,21 +612,21 @@ if (progress) {
|
|
|
426
612
|
|
|
427
613
|
// Legacy PLAN.md deprecation check (removed — stub only)
|
|
428
614
|
|
|
429
|
-
const dispatch = read('Harness/dispatch.md');
|
|
615
|
+
const dispatch = read('Harness/specs/runtime/dispatch.md');
|
|
430
616
|
if (dispatch) {
|
|
431
617
|
for (const agent of commonAgents) {
|
|
432
|
-
if (!dispatch.includes(`\`${agent}\``)) errors.push(`Harness/dispatch.md missing common agent: ${agent}`);
|
|
618
|
+
if (!dispatch.includes(`\`${agent}\``)) errors.push(`Harness/specs/runtime/dispatch.md missing common agent: ${agent}`);
|
|
433
619
|
}
|
|
434
|
-
if (!dispatch.includes('## Handoff Format')) errors.push('Harness/dispatch.md missing heading: ## Handoff Format');
|
|
620
|
+
if (!dispatch.includes('## Handoff Format')) errors.push('Harness/specs/runtime/dispatch.md missing heading: ## Handoff Format');
|
|
435
621
|
}
|
|
436
622
|
|
|
437
|
-
const contextLoading = read('Harness/context-loading.md');
|
|
623
|
+
const contextLoading = read('Harness/specs/runtime/context-loading.md');
|
|
438
624
|
if (contextLoading) {
|
|
439
625
|
if (!contextLoading.includes('Harness/README.md` is the primary Harness documentation router')) {
|
|
440
|
-
errors.push('Harness/context-loading.md must declare Harness/README.md as the primary Harness documentation router');
|
|
626
|
+
errors.push('Harness/specs/runtime/context-loading.md must declare Harness/README.md as the primary Harness documentation router');
|
|
441
627
|
}
|
|
442
628
|
for (const pack of contextPacks) {
|
|
443
|
-
if (!contextLoading.includes(pack)) errors.push(`Harness/context-loading.md missing subagent pack: ${pack}`);
|
|
629
|
+
if (!contextLoading.includes(pack)) errors.push(`Harness/specs/runtime/context-loading.md missing subagent pack: ${pack}`);
|
|
444
630
|
}
|
|
445
631
|
}
|
|
446
632
|
|
|
@@ -489,7 +675,7 @@ for (const command of listedWorkflowCommands(docsReadme, read('.claude/commands/
|
|
|
489
675
|
|
|
490
676
|
for (const workflowFile of registeredWorkflowFiles(docsReadme, memory)) {
|
|
491
677
|
if (!fs.existsSync(path.join(root, workflowFile))) {
|
|
492
|
-
// Optional workflows (
|
|
678
|
+
// Optional workflows (ts-react-frontend, ui-ux-review, etc.) may not be installed
|
|
493
679
|
continue;
|
|
494
680
|
}
|
|
495
681
|
}
|
|
@@ -509,9 +695,14 @@ function requireUiSelectorContract(rel) {
|
|
|
509
695
|
}
|
|
510
696
|
}
|
|
511
697
|
|
|
512
|
-
requireUiSelectorContract('
|
|
698
|
+
requireUiSelectorContract('.claude/skills/wf-browser/SKILL.md');
|
|
699
|
+
requireUiSelectorContract('.agents/skills/wf-browser/SKILL.md');
|
|
513
700
|
requireUiSelectorContract('Harness/workflows/ts-react-frontend.md');
|
|
514
701
|
|
|
702
|
+
if (fs.existsSync(path.join(root, 'Harness/workflows/browser-e2e.md'))) {
|
|
703
|
+
errors.push('retired optional workflow must not exist: Harness/workflows/browser-e2e.md');
|
|
704
|
+
}
|
|
705
|
+
|
|
515
706
|
for (const skill of commonSkills) {
|
|
516
707
|
const rel = `.claude/skills/${skill}/SKILL.md`;
|
|
517
708
|
const text = read(rel);
|
|
@@ -632,183 +823,243 @@ for (const claudeRel of listMarkdownFiles('.claude/commands')) {
|
|
|
632
823
|
}
|
|
633
824
|
}
|
|
634
825
|
|
|
635
|
-
requireText('Harness/extension.md', 'Skills should extend the harness');
|
|
636
|
-
requireText('Harness/agent-workflow.md', 'Harness/tasks/<task-id>/PROGRESS.md');
|
|
826
|
+
requireText('Harness/specs/guides/extension.md', 'Skills should extend the harness');
|
|
827
|
+
requireText('Harness/specs/runtime/agent-workflow.md', 'Harness/tasks/<task-id>/PROGRESS.md');
|
|
637
828
|
requireText('Harness/README.md', 'Task records are compact by default', 'compact task record router rule');
|
|
638
|
-
requireText('Harness/agent-workflow.md', 'AC record size', 'compact AC record size rule');
|
|
639
|
-
requireText('Harness/ACCEPTANCE_PROTOCOL.md', 'Default to 1-3 concise ACs', 'compact AC default');
|
|
640
|
-
requireText('Harness/WF.md', 'task-scribe', 'compact heartbeat rule');
|
|
829
|
+
requireText('Harness/specs/runtime/agent-workflow.md', 'AC record size', 'compact AC record size rule');
|
|
830
|
+
requireText('Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'Default to 1-3 concise ACs', 'compact AC default');
|
|
831
|
+
requireText('Harness/specs/workflows/WF.md', 'task-scribe', 'compact heartbeat rule');
|
|
641
832
|
requireText('Harness/tasks/_template/PLAN.md', 'Compact task record', 'compact task PLAN template');
|
|
642
833
|
requireText('Harness/tasks/_template/PLAN.md', 'Default: keep 1-3 concise ACs', 'compact task PLAN AC guidance');
|
|
643
834
|
requireText('Harness/tasks/_template/PROGRESS.md', 'Compact heartbeat', 'compact task PROGRESS template');
|
|
644
|
-
requireText('Harness/agent-workflow.md', 'TDD-GUIDE.md', 'agent workflow loads TDD guide');
|
|
645
|
-
requireText('Harness/agent-workflow.md', 'real user-path test', 'agent workflow real user path requirement');
|
|
835
|
+
requireText('Harness/specs/runtime/agent-workflow.md', 'TDD-GUIDE.md', 'agent workflow loads TDD guide');
|
|
836
|
+
requireText('Harness/specs/runtime/agent-workflow.md', 'real user-path test', 'agent workflow real user path requirement');
|
|
646
837
|
requireText('Harness/research/README.md', 'research-results.md');
|
|
647
|
-
requireText('Harness/WF.md', 'Orchestration Loop', 'WF orchestration loop');
|
|
648
|
-
requireText('Harness/WF.md', 'WF-KERNEL.md', 'WF references WF-KERNEL');
|
|
649
|
-
requireText('Harness/WF.md', 'Cross-review and reflector NOT mandatory', 'WF-Light no mandatory cross-review');
|
|
650
|
-
requireText('Harness/WF.md', '`.claude/agents/`', 'WF agent roster path');
|
|
651
|
-
requireText('Harness/WF.md', 'Harness/tasks/', 'WF task directory reference');
|
|
838
|
+
requireText('Harness/specs/workflows/WF.md', 'Orchestration Loop', 'WF orchestration loop');
|
|
839
|
+
requireText('Harness/specs/workflows/WF.md', 'WF-KERNEL.md', 'WF references WF-KERNEL');
|
|
840
|
+
requireText('Harness/specs/workflows/WF.md', 'Cross-review and reflector NOT mandatory', 'WF-Light no mandatory cross-review');
|
|
841
|
+
requireText('Harness/specs/workflows/WF.md', '`.claude/agents/`', 'WF agent roster path');
|
|
842
|
+
requireText('Harness/specs/workflows/WF.md', 'Harness/tasks/', 'WF task directory reference');
|
|
843
|
+
const taskIdConvention = '`task-<verb>-<noun>[-detail]`';
|
|
844
|
+
requireText('Harness/specs/workflows/WF.md', taskIdConvention, 'WF task-id naming convention');
|
|
845
|
+
requireText('Harness/specs/workflows/WF-STATE.md', taskIdConvention, 'WF-STATE task-id naming convention');
|
|
846
|
+
requireText('Harness/specs/workflows/WF-MAX.md', taskIdConvention, 'WF-MAX task-id naming convention');
|
|
652
847
|
requireText('Harness/README.md', 'explicit WF token', 'WF explicit contract');
|
|
653
848
|
requireText('Harness/README.md', 'tier-gated acceptance', 'WF tiered acceptance router output');
|
|
654
|
-
requireText('.claude/skills/wf/SKILL.md', 'Harness/WF.md', 'wf skill loads core WF doc');
|
|
849
|
+
requireText('.claude/skills/wf/SKILL.md', 'Harness/specs/workflows/WF.md', 'wf skill loads core WF doc');
|
|
655
850
|
requireText('.claude/skills/wf/SKILL.md', 'Tier-aware acceptance', 'wf skill tier-aware acceptance');
|
|
656
|
-
requireText('.
|
|
657
|
-
requireText('.
|
|
851
|
+
requireText('.claude/skills/wf/SKILL.md', taskIdConvention, 'wf skill task-id naming convention');
|
|
852
|
+
requireText('.agents/skills/wf/SKILL.md', 'Harness/specs/workflows/WF.md', 'Codex wf skill loads core WF doc');
|
|
853
|
+
requireText('.agents/skills/wf/SKILL.md', taskIdConvention, 'Codex wf skill task-id naming convention');
|
|
854
|
+
requireText('.claude/skills/subagent-orchestrator/SKILL.md', 'Harness/specs/runtime/subagents.md', 'subagent-orchestrator loads subagents doc');
|
|
658
855
|
requireText('.claude/skills/subagent-orchestrator/SKILL.md', '.claude/agents/', 'subagent-orchestrator built-in agent roster path');
|
|
659
856
|
requireText('.claude/skills/subagent-orchestrator/SKILL.md', 'WF/WF-MAX requires tier-specific', 'subagent-orchestrator WF tier-specific contract');
|
|
660
857
|
requireText('.claude/skills/wf-readme/SKILL.md', 'README.md', 'wf-readme loads README');
|
|
661
|
-
requireText('.claude/skills/wf-readme/SKILL.md', 'Harness/architecture.md', 'wf-readme links architecture docs');
|
|
662
|
-
requireText('Harness/subagents.md', '## Source Attribution', 'subagent source attribution');
|
|
663
|
-
requireText('Harness/subagents.md', 'npx skills find', 'find-skills discovery attribution');
|
|
664
|
-
requireText('Harness/subagents.md', 'superpowers:dispatching-parallel-agents', 'parallel-agent source attribution');
|
|
665
|
-
requireText('Harness/subagents.md', 'superpowers:subagent-driven-development', 'subagent-driven source attribution');
|
|
666
|
-
requireText('Harness/subagents.md', '## Built-in Agent Roster', 'built-in agent roster');
|
|
667
|
-
requireText('Harness/subagents.md', '## WF Default Fan-Out', 'WF default fan-out');
|
|
668
|
-
requireText('Harness/subagents.md', 'concrete conditions', 'subagent decision tree');
|
|
669
|
-
requireText('Harness/subagents.md', 'parallel planner/researcher/docs-researcher/architect subagents', 'WF roster orchestration shape');
|
|
670
|
-
requireText('Harness/subagents.md', '`reflector`', 'reflector agent roster');
|
|
671
|
-
requireText('Harness/subagents.md', 'reflector PASS', 'reflector review gate');
|
|
672
|
-
requireText('Harness/subagents.md', '## Efficiency Ladder', 'subagent efficiency ladder');
|
|
673
|
-
requireText('Harness/subagents.md', '## Review Gates', 'subagent review gates');
|
|
674
|
-
requireText('Harness/architecture.md', '## 2. Interface Decoupling', 'architecture interface decoupling');
|
|
675
|
-
requireText('Harness/architecture.md', '## 3. State Design', 'architecture state design');
|
|
676
|
-
requireText('Harness/architecture.md', 'Avoid speculative abstraction', 'anti-overengineering architecture rule');
|
|
858
|
+
requireText('.claude/skills/wf-readme/SKILL.md', 'Harness/project/architecture.md', 'wf-readme links architecture docs');
|
|
859
|
+
requireText('Harness/specs/runtime/subagents.md', '## Source Attribution', 'subagent source attribution');
|
|
860
|
+
requireText('Harness/specs/runtime/subagents.md', 'npx skills find', 'find-skills discovery attribution');
|
|
861
|
+
requireText('Harness/specs/runtime/subagents.md', 'superpowers:dispatching-parallel-agents', 'parallel-agent source attribution');
|
|
862
|
+
requireText('Harness/specs/runtime/subagents.md', 'superpowers:subagent-driven-development', 'subagent-driven source attribution');
|
|
863
|
+
requireText('Harness/specs/runtime/subagents.md', '## Built-in Agent Roster', 'built-in agent roster');
|
|
864
|
+
requireText('Harness/specs/runtime/subagents.md', '## WF Default Fan-Out', 'WF default fan-out');
|
|
865
|
+
requireText('Harness/specs/runtime/subagents.md', 'concrete conditions', 'subagent decision tree');
|
|
866
|
+
requireText('Harness/specs/runtime/subagents.md', 'parallel planner/researcher/docs-researcher/architect subagents', 'WF roster orchestration shape');
|
|
867
|
+
requireText('Harness/specs/runtime/subagents.md', '`reflector`', 'reflector agent roster');
|
|
868
|
+
requireText('Harness/specs/runtime/subagents.md', 'reflector PASS', 'reflector review gate');
|
|
869
|
+
requireText('Harness/specs/runtime/subagents.md', '## Efficiency Ladder', 'subagent efficiency ladder');
|
|
870
|
+
requireText('Harness/specs/runtime/subagents.md', '## Review Gates', 'subagent review gates');
|
|
871
|
+
requireText('Harness/project/architecture.md', '## 2. Interface Decoupling', 'architecture interface decoupling');
|
|
872
|
+
requireText('Harness/project/architecture.md', '## 3. State Design', 'architecture state design');
|
|
873
|
+
requireText('Harness/project/architecture.md', 'Avoid speculative abstraction', 'anti-overengineering architecture rule');
|
|
677
874
|
requireText('CLAUDE.md', 'Use explicit interfaces or state models only when they protect a real boundary', 'CLAUDE interface/state simplicity rule');
|
|
678
875
|
requireText('Harness/README.md', '/wf-update', 'wf update startup instruction');
|
|
679
876
|
requireText('Harness/README.md', 'Need harness update', 'update routing row');
|
|
680
|
-
requireText('Harness/WF-MAX.md', 'three-layer architecture', 'WF-MAX three-layer architecture');
|
|
681
|
-
requireText('Harness/WF-MAX.md', 'dispatch permissions', 'WF-MAX role separation');
|
|
682
|
-
requireText('Harness/WF-MAX.md', 'file_claim', 'WF-MAX coloring algorithm');
|
|
683
|
-
requireText('Harness/WF-MAX.md', 'CEO → Manager → Worker', 'WF-MAX wave dispatch');
|
|
684
|
-
requireText('Harness/WF-MAX.md', 'inherits the full', 'WF-MAX strict superset');
|
|
685
|
-
requireText('Harness/WF-MAX.md', 'Cross-CLI', 'WF-MAX cross-CLI overflow');
|
|
686
|
-
requireText('Harness/WF-MAX.md', 'claude -p', 'WF-MAX Claude CLI overflow');
|
|
687
|
-
requireText('Harness/WF-MAX.md', 'codex exec', 'WF-MAX Codex CLI overflow');
|
|
688
|
-
requireText('Harness/WF-MAX.md', 'agents.max_threads', 'WF-MAX Codex max_threads
|
|
689
|
-
requireText('Harness/WF-MAX.md', '
|
|
690
|
-
requireText('Harness/WF-MAX.md', '
|
|
691
|
-
requireText('Harness/WF-MAX.md', '
|
|
692
|
-
requireText('Harness/WF-MAX.md', '
|
|
693
|
-
requireText('Harness/WF-MAX.md', '
|
|
694
|
-
requireText('Harness/WF-MAX.md', '
|
|
695
|
-
requireText('
|
|
696
|
-
requireText('
|
|
877
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'three-layer architecture', 'WF-MAX three-layer architecture');
|
|
878
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'dispatch permissions', 'WF-MAX role separation');
|
|
879
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'file_claim', 'WF-MAX coloring algorithm');
|
|
880
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'CEO → Manager → Worker', 'WF-MAX wave dispatch');
|
|
881
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'inherits the full', 'WF-MAX strict superset');
|
|
882
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Cross-CLI', 'WF-MAX cross-CLI overflow');
|
|
883
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'claude -p', 'WF-MAX Claude CLI overflow');
|
|
884
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'codex exec', 'WF-MAX Codex CLI overflow');
|
|
885
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'agents.max_threads', 'WF-MAX Codex legacy max_threads alias');
|
|
886
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'max_concurrent_threads_per_session', 'WF-MAX Codex concurrent thread config');
|
|
887
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Mandatory Fan-Out Contract', 'WF-MAX mandatory fan-out attempt contract');
|
|
888
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'fanoutAttempted: true', 'WF-MAX records fan-out attempt');
|
|
889
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Runtime Capacity Map', 'WF-MAX runtime capacity map');
|
|
890
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION', 'WF-MAX Claude Code subagent cap docs');
|
|
891
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS', 'WF-MAX Claude Code concurrent subagent cap docs');
|
|
892
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH', 'WF-MAX Claude Code spawn-depth cap docs');
|
|
893
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Do not scaffold Codex scalar agent caps', 'WF-MAX Codex config compatibility guard');
|
|
894
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'subagent_depth = 2', 'WF-MAX OpenCode subagent depth default');
|
|
895
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'asks the user before any project/global Codex config change', 'WF-MAX asks before changing Codex config');
|
|
896
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Close completed agents', 'WF-MAX close completed agents before overflow');
|
|
897
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Codex++', 'WF-MAX forbids relying on Codex++ as stable capacity');
|
|
898
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'does not authorize CEO source edits', 'WF-MAX useful-degrade CEO source-edit boundary');
|
|
899
|
+
requireText('Harness/specs/workflows/WF-MAX.md', '## Cross-Task Decisions', 'WF-MAX PROGRESS heading preservation');
|
|
900
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'agents.max_concurrent_threads_per_session', 'wf-max skill Codex thread config');
|
|
901
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'agents.max_threads', 'wf-max skill Codex legacy alias');
|
|
902
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'Do not scaffold scalar `[agents]` caps', 'wf-max skill Codex config compatibility guard');
|
|
903
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION', 'wf-max skill Claude Code subagent cap');
|
|
904
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS', 'wf-max skill Claude Code concurrent subagent cap');
|
|
905
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH', 'wf-max skill Claude Code spawn-depth cap');
|
|
906
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'subagent_depth = 2', 'wf-max skill OpenCode subagent depth default');
|
|
697
907
|
requireText('.claude/skills/wf-max/SKILL.md', 'ask the user before raising', 'wf-max skill asks before raising Codex thread cap');
|
|
698
908
|
requireText('.claude/skills/wf-max/SKILL.md', 'Codex++', 'wf-max skill forbids Codex++ capacity assumption');
|
|
699
|
-
requireText('.
|
|
700
|
-
requireText('.
|
|
701
|
-
requireText('.
|
|
909
|
+
requireText('.claude/skills/wf-max/SKILL.md', taskIdConvention, 'wf-max skill task-id naming convention');
|
|
910
|
+
requireText('.agents/skills/wf-max/SKILL.md', taskIdConvention, 'Codex wf-max skill task-id naming convention');
|
|
911
|
+
requireText('.claude/skills/wf-max/SKILL.md', 'does not authorize CEO source edits', 'wf-max skill useful-degrade CEO source-edit boundary');
|
|
912
|
+
requireText('.claude/skills/wf-max/SKILL.md', '## Cross-Task Decisions', 'wf-max skill PROGRESS heading preservation');
|
|
913
|
+
requireText('.codex/config.toml', 'intentionally avoids WF-MAX capacity defaults', 'Codex config compatibility note');
|
|
914
|
+
forbidActiveToml('.codex/config.toml', /^\[agents\]$/m, 'Codex project config agents table');
|
|
915
|
+
forbidActiveToml('.codex/config.toml', /^\s*max_concurrent_threads_per_session\s*=/m, 'Codex project config concurrent thread scalar');
|
|
916
|
+
forbidActiveToml('.codex/config.toml', /^\s*max_depth\s*=/m, 'Codex project config max_depth scalar');
|
|
917
|
+
forbidActiveToml('.codex/config.toml', /^\s*max_threads\s*=/m, 'Codex project config legacy max_threads scalar');
|
|
702
918
|
requireText('opencode.json', '"$schema": "https://opencode.ai/config.json"', 'OpenCode config schema');
|
|
703
919
|
requireText('opencode.json', '.claude/rules/ecc/common.md', 'OpenCode instructions reference to ECC rules');
|
|
920
|
+
requireText('opencode.json', '"subagent_depth": 2', 'OpenCode WF-MAX subagent nesting depth');
|
|
921
|
+
requireText('.opencode/commands/wf-max.md', 'MUST attempt native runtime subagent fan-out', 'OpenCode wf-max command fan-out attempt');
|
|
922
|
+
requireText('.opencode/commands/wf-max.md', 'subagent_depth >= 2', 'OpenCode wf-max command subagent depth requirement');
|
|
923
|
+
requireText('.opencode/commands/wf-max.md', 'fanoutAttempted: true', 'OpenCode wf-max command records fan-out attempt');
|
|
924
|
+
requireText('.opencode/agents/explore-manager.md', 'task:', 'OpenCode explore-manager task permission');
|
|
925
|
+
requireText('.opencode/agents/explore-manager.md', '"codebase-explorer": allow', 'OpenCode explore-manager child allowlist');
|
|
926
|
+
requireText('.opencode/agents/explore-manager.md', '"git status*": allow', 'OpenCode explore-manager read-only git status');
|
|
927
|
+
requireText('.opencode/agents/explore-manager.md', '"git diff*": allow', 'OpenCode explore-manager read-only git diff');
|
|
928
|
+
forbidText('.opencode/agents/explore-manager.md', '"git *": allow', 'OpenCode explore-manager broad git permission');
|
|
929
|
+
requireText('.opencode/agents/architect-manager.md', '"architect": allow', 'OpenCode architect-manager child allowlist');
|
|
930
|
+
requireText('.opencode/agents/implement-manager.md', '"implementer": allow', 'OpenCode implement-manager child allowlist');
|
|
931
|
+
forbidText('.opencode/agents/implement-manager.md', '"node *": allow', 'OpenCode implement-manager broad node permission');
|
|
932
|
+
forbidText('.opencode/agents/implement-manager.md', '"npm *": allow', 'OpenCode implement-manager broad npm permission');
|
|
933
|
+
requireText('.opencode/agents/review-manager.md', '"reviewer": allow', 'OpenCode review-manager child allowlist');
|
|
934
|
+
forbidText('.opencode/agents/review-manager.md', '"node *": allow', 'OpenCode review-manager broad node permission');
|
|
704
935
|
requireText('Harness/README.md', '/wf-max', 'wf max router alias');
|
|
705
936
|
requireText('Harness/README.md', 'WF-MAX.md', 'WF-MAX router reference');
|
|
706
937
|
requireText('Harness/README.md', 'ACCEPTANCE_PROTOCOL.md', 'acceptance protocol router reference');
|
|
707
938
|
requireText('Harness/README.md', 'TDD-GUIDE.md', 'TDD guide router reference');
|
|
708
|
-
requireText('Harness/ACCEPTANCE_PROTOCOL.md', 'PRD-GATE', 'acceptance PRD gate');
|
|
709
|
-
requireText('Harness/ACCEPTANCE_PROTOCOL.md', 'AC-GATE', 'acceptance AC gate');
|
|
710
|
-
requireText('Harness/ACCEPTANCE_PROTOCOL.md', 'Acceptance Result', 'acceptance result matrix');
|
|
711
|
-
requireText('Harness/ACCEPTANCE_PROTOCOL.md', 'Syntax-only checks', 'syntax-only checks are not browser acceptance evidence');
|
|
712
|
-
requireText('Harness/AGENT_ISOLATION.md', 'implementer', 'agent isolation implementer rule');
|
|
713
|
-
requireText('Harness/HARNESS_BRIDGE.md', 'Network Trace Collector', 'harness bridge network trace collector');
|
|
714
|
-
requireText('Harness/WF-AUTO.md', 'Intent Checkpoint', 'wf-auto intent checkpoint');
|
|
715
|
-
requireText('Harness/WF-AUTO.md', 'Adaptive Coverage Exhaustion Gate', 'wf-auto adaptive coverage exhaustion gate');
|
|
716
|
-
requireText('Harness/WF-AUTO.md', 'dynamic high-risk obligations', 'wf-auto dynamic high-risk obligations');
|
|
717
|
-
requireText('Harness/WF-AUTO.md', 'two different confirmation strategies', 'wf-auto two different confirmation strategies');
|
|
718
|
-
requireText('Harness/WF-AUTO-ANGLES.md', 'Selection algorithm', 'wf-auto adaptive angle selection');
|
|
719
|
-
requireText('Harness/WF-AUTO-ANGLES.md', 'Dynamic obligations', 'wf-auto dynamic obligations');
|
|
720
|
-
requireText('Harness/WF-AUTO-ANGLES.md', 'Common probe recipes', 'wf-auto common probe recipes');
|
|
721
|
-
forbidText('Harness/WF-AUTO.md', 'All 8 exhausted', 'stale eight-angle exhaustion rule');
|
|
722
|
-
forbidText('Harness/WF-AUTO.md', '3 consecutive all-exhausted rounds', 'stale three-consecutive-all-exhausted stop rule');
|
|
723
|
-
forbidText('Harness/WF-AUTO.md', '8-Angle Exhaustion Gate', 'stale eight-angle exhaustion gate name');
|
|
724
|
-
forbidText('Harness/WF-AUTO-SPARK.md', '8 parallel external searches', 'stale eight-spark fixed-count search');
|
|
725
|
-
requireText('Harness/WF-AUTO.md', 'Inherited WF/WF-MAX Constraints', 'wf-auto inherited WF/WF-MAX constraints');
|
|
726
|
-
requireText('Harness/WF-AUTO.md', 'Mini PRD -> AC IDs -> test/validation plan -> implementer -> verifier', 'wf-auto per-cycle WF chain');
|
|
727
|
-
requireText('Harness/WF-AUTO.md', 'reflector PASS', 'wf-auto reflector gate');
|
|
728
|
-
requireText('Harness/WF-AUTO
|
|
729
|
-
requireText('Harness/WF-AUTO
|
|
730
|
-
requireText('Harness/WF-AUTO
|
|
731
|
-
requireText('Harness/WF-AUTO-SPARK.md', '
|
|
732
|
-
requireText('Harness/WF-AUTO-SPARK.md', '
|
|
733
|
-
requireText('Harness/WF-AUTO-SPARK.md', '
|
|
734
|
-
requireText('Harness/WF-AUTO-SPARK.md', '
|
|
735
|
-
requireText('Harness/WF-AUTO-SPARK.md', '
|
|
736
|
-
requireText('Harness/WF-
|
|
737
|
-
requireText('Harness/
|
|
738
|
-
requireText('Harness/
|
|
739
|
-
requireText('Harness/
|
|
740
|
-
requireText('Harness/
|
|
741
|
-
requireText('Harness/
|
|
742
|
-
requireText('Harness/
|
|
743
|
-
requireText('Harness/TDD-GUIDE.md', '
|
|
939
|
+
requireText('Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'PRD-GATE', 'acceptance PRD gate');
|
|
940
|
+
requireText('Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'AC-GATE', 'acceptance AC gate');
|
|
941
|
+
requireText('Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'Acceptance Result', 'acceptance result matrix');
|
|
942
|
+
requireText('Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'Syntax-only checks', 'syntax-only checks are not browser acceptance evidence');
|
|
943
|
+
requireText('Harness/specs/protocols/AGENT_ISOLATION.md', 'implementer', 'agent isolation implementer rule');
|
|
944
|
+
requireText('Harness/specs/protocols/HARNESS_BRIDGE.md', 'Network Trace Collector', 'harness bridge network trace collector');
|
|
945
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Intent Checkpoint', 'wf-auto intent checkpoint');
|
|
946
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Adaptive Coverage Exhaustion Gate', 'wf-auto adaptive coverage exhaustion gate');
|
|
947
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'dynamic high-risk obligations', 'wf-auto dynamic high-risk obligations');
|
|
948
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'two different confirmation strategies', 'wf-auto two different confirmation strategies');
|
|
949
|
+
requireText('Harness/specs/workflows/WF-AUTO-ANGLES.md', 'Selection algorithm', 'wf-auto adaptive angle selection');
|
|
950
|
+
requireText('Harness/specs/workflows/WF-AUTO-ANGLES.md', 'Dynamic obligations', 'wf-auto dynamic obligations');
|
|
951
|
+
requireText('Harness/specs/workflows/WF-AUTO-ANGLES.md', 'Common probe recipes', 'wf-auto common probe recipes');
|
|
952
|
+
forbidText('Harness/specs/workflows/WF-AUTO.md', 'All 8 exhausted', 'stale eight-angle exhaustion rule');
|
|
953
|
+
forbidText('Harness/specs/workflows/WF-AUTO.md', '3 consecutive all-exhausted rounds', 'stale three-consecutive-all-exhausted stop rule');
|
|
954
|
+
forbidText('Harness/specs/workflows/WF-AUTO.md', '8-Angle Exhaustion Gate', 'stale eight-angle exhaustion gate name');
|
|
955
|
+
forbidText('Harness/specs/workflows/WF-AUTO-SPARK.md', '8 parallel external searches', 'stale eight-spark fixed-count search');
|
|
956
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Inherited WF/WF-MAX Constraints', 'wf-auto inherited WF/WF-MAX constraints');
|
|
957
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Mini PRD -> AC IDs -> test/validation plan -> implementer -> verifier', 'wf-auto per-cycle WF chain');
|
|
958
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'reflector PASS', 'wf-auto reflector gate');
|
|
959
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Manual or benchmark-driven single-cycle', 'wf-auto bounded single-cycle tick contract');
|
|
960
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Harness/tasks/auto/PLAN.md', 'wf-auto bounded tick PLAN record');
|
|
961
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Harness/tasks/auto/PROGRESS.md', 'wf-auto bounded tick PROGRESS record');
|
|
962
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'Inherited Execution Chain', 'wf-auto-spark inherited execution chain');
|
|
963
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'External spark search replaces discovery only', 'wf-auto-spark discovery-only inheritance');
|
|
964
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'reflector PASS', 'wf-auto-spark reflector gate');
|
|
965
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'task-scribe formats task-state writes', 'wf-auto-spark task-scribe recorder delegation');
|
|
966
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'searchFallback: ceo-direct', 'wf-auto-spark search fallback');
|
|
967
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'pre-implementation triage', 'wf-auto-spark reflector escalation');
|
|
968
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'Literal anti-pattern matching', 'wf-auto-spark anti-pattern invariant guard');
|
|
969
|
+
requireText('Harness/specs/workflows/WF-AUTO-SPARK.md', 'node scripts/build-version.mjs --check', 'wf-auto-spark checksum drift guard');
|
|
970
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'process-file delegation is the default', 'WF-MAX task-scribe process-file delegation default');
|
|
971
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'Scenario Memory Hints', 'memory protocol scenario hints');
|
|
972
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'WF closeout', 'memory protocol WF closeout injection row');
|
|
973
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'memory-master owns writes', 'memory protocol memory write ownership');
|
|
974
|
+
requireText('Harness/specs/protocols/TDD-GUIDE.md', 'Browser/UI Acceptance TDD Gate', 'browser UI acceptance TDD gate');
|
|
975
|
+
requireText('Harness/specs/protocols/TDD-GUIDE.md', 'syntax-only', 'syntax-only acceptance prohibition');
|
|
976
|
+
requireText('Harness/specs/protocols/TDD-GUIDE.md', 'Playwright/CDP', 'Playwright/CDP acceptance requirement');
|
|
977
|
+
requireText('Harness/specs/protocols/TDD-GUIDE.md', 'AC-by-AC result matrix', 'AC-by-AC TDD evidence matrix');
|
|
744
978
|
requireText('Harness/tasks/_template/PLAN.md', 'Expanded evidence required when triggered', 'task template expanded evidence trigger');
|
|
745
979
|
requireText('Harness/templates/TEST_PLAN.template.md', 'syntax-only checks', 'test plan template syntax-only prohibition');
|
|
746
|
-
requireText('.claude/skills/tdd/SKILL.md', 'Harness/ACCEPTANCE_PROTOCOL.md', 'tdd skill loads acceptance protocol');
|
|
747
|
-
requireText('.claude/skills/tdd/SKILL.md', 'Harness/HARNESS_BRIDGE.md', 'tdd skill loads harness bridge');
|
|
980
|
+
requireText('.claude/skills/tdd/SKILL.md', 'Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'tdd skill loads acceptance protocol');
|
|
981
|
+
requireText('.claude/skills/tdd/SKILL.md', 'Harness/specs/protocols/HARNESS_BRIDGE.md', 'tdd skill loads harness bridge');
|
|
748
982
|
requireText('.claude/skills/tdd/SKILL.md', 'No syntax-only acceptance', 'tdd skill forbids syntax-only acceptance');
|
|
749
983
|
requireText('.claude/skills/wf-remove/SKILL.md', 'User-facing removal is the slash/skill command', 'wf-remove slash command is user-facing');
|
|
750
984
|
requireText('.claude/skills/wf-remove/SKILL.md', 'agent-internal execution steps', 'wf-remove script commands are agent-internal');
|
|
751
985
|
requireText('.claude/skills/wf-remove/SKILL.md', 'verify residual discovery folders', 'wf-remove residual discovery verification');
|
|
986
|
+
forbidText('Harness/scripts/wf-remove.mjs', '\uFFFD', 'replacement character in wf-remove output');
|
|
987
|
+
for (const marker of ['codebase-explorer', 'task-scribe', 'wf-agents-docs', 'wf-auto-spark']) {
|
|
988
|
+
requireText('Harness/scripts/wf-remove.mjs', marker, `wf-remove built-in registry includes ${marker}`);
|
|
989
|
+
}
|
|
752
990
|
requireText('.claude/skills/wf-review/SKILL.md', 'opencode run --agent reviewer', 'wf-review OpenCode peer CLI path');
|
|
753
991
|
requireText('.claude/skills/wf-review/SKILL.md', 'Role: reviewer', 'wf-review installed reviewer role fallback');
|
|
754
992
|
requireText('.claude/skills/wf-review/SKILL.md', 'The main agent is the controller', 'wf-review controller final authority');
|
|
993
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'claude -p --output-format json', 'wf-agents-docs Claude JSON CLI path');
|
|
994
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'codex exec --json', 'wf-agents-docs Codex JSONL CLI path');
|
|
995
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'opencode run --format json', 'wf-agents-docs OpenCode JSON CLI path');
|
|
996
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'cache_read_input_tokens', 'wf-agents-docs Claude cache telemetry field');
|
|
997
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'Do not trust exit code alone', 'wf-agents-docs PowerShell wrapper guard');
|
|
998
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'Evidence-Packet Review Pattern', 'wf-agents-docs evidence-packet review method');
|
|
999
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'No Scratch-File Rule', 'wf-agents-docs scratch-file guard');
|
|
1000
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'Subagent Output Contract', 'wf-agents-docs subagent output contract');
|
|
1001
|
+
requireText('.claude/skills/wf-agents-docs/SKILL.md', 'Do not write CLI probe output under `%TEMP%`', 'wf-agents-docs temp pollution guard');
|
|
1002
|
+
requireText('Harness/README.md', 'Need peer CLI automation docs', 'Harness router peer CLI automation docs row');
|
|
755
1003
|
requireText('.opencode/commands/wf-review.md', 'peer-review contract', 'OpenCode wf-review wrapper peer-review contract');
|
|
756
|
-
requireText('Harness/subagents.md', 'For `/wf-review`, use the installed `reviewer` role', 'subagents wf-review role fallback');
|
|
1004
|
+
requireText('Harness/specs/runtime/subagents.md', 'For `/wf-review`, use the installed `reviewer` role', 'subagents wf-review role fallback');
|
|
757
1005
|
requireText('.claude/agents/tdd-guide.md', 'Browser Acceptance Rules', 'tdd-guide browser acceptance rules');
|
|
758
1006
|
requireText('.claude/agents/tdd-guide.md', 'real user actions', 'tdd-guide real user action requirement');
|
|
759
|
-
requireText('.claude/agents/test-writer.md', 'Harness/ACCEPTANCE_PROTOCOL.md', 'test-writer loads acceptance protocol');
|
|
1007
|
+
requireText('.claude/agents/test-writer.md', 'Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md', 'test-writer loads acceptance protocol');
|
|
760
1008
|
requireText('.claude/agents/test-writer.md', 'real user-path test', 'test-writer real user path requirement');
|
|
761
1009
|
requireText('.claude/agents/test-writer.md', 'network URL, method, payload', 'test-writer network assertion requirement');
|
|
762
1010
|
requireText('.claude/agents/reflector.md', 'PASS, RETURN_TO_DEBUG, or BLOCKED', 'reflector verdict contract');
|
|
763
|
-
requireText('Harness/DEBUG_PROTOCOL.md', 'Layer Classification', 'debug layer classification');
|
|
764
|
-
requireText('Harness/MEMORY_PROTOCOL.md', 'AC ID', 'memory AC traceability');
|
|
765
|
-
requireText('Harness/subagents.md', 'Max parallelism', 'subagents max parallelism row');
|
|
766
|
-
requireText('Harness/dispatch.md', 'Concurrency group', 'dispatch concurrency group field');
|
|
767
|
-
requireText('Harness/dispatch.md', 'File claim', 'dispatch file claim field');
|
|
1011
|
+
requireText('Harness/specs/protocols/DEBUG_PROTOCOL.md', 'Layer Classification', 'debug layer classification');
|
|
1012
|
+
requireText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'AC ID', 'memory AC traceability');
|
|
1013
|
+
requireText('Harness/specs/runtime/subagents.md', 'Max parallelism', 'subagents max parallelism row');
|
|
1014
|
+
requireText('Harness/specs/runtime/dispatch.md', 'Concurrency group', 'dispatch concurrency group field');
|
|
1015
|
+
requireText('Harness/specs/runtime/dispatch.md', 'File claim', 'dispatch file claim field');
|
|
768
1016
|
requireText('CLAUDE.md', '/wf-max', 'wf max startup instruction');
|
|
769
1017
|
requireText('.claude/commands/wf-help.md', 'Do not invoke a skill', 'wf-help direct command boundary');
|
|
770
1018
|
requireText('.claude/commands/wf-help.md', '| `/wf-help` |', 'wf-help command row');
|
|
771
1019
|
requireText('.claude/commands/wf-help.md', '| `/wf-max <task>` |', 'wf-help wf-max row');
|
|
772
1020
|
requireText('.claude/commands/wf-help.md', '| `/wf-auto` |', 'wf-help wf-auto row');
|
|
773
1021
|
requireText('.claude/commands/wf-help.md', '| `/wf-readme <task>` |', 'wf-help wf-readme row');
|
|
1022
|
+
forbidText('.claude/commands/wf-help.md', '.opencode/skills/', 'wf-help nonexistent OpenCode skills directory claim');
|
|
1023
|
+
forbidText('.opencode/commands/wf-help.md', '.opencode/skills/', 'OpenCode wf-help nonexistent skills directory claim');
|
|
774
1024
|
requireText('Harness/README.md', '## Direct Commands', 'direct commands section');
|
|
775
1025
|
requireText('Harness/README.md', '.claude/commands/wf-help.md', 'wf-help router reference');
|
|
776
|
-
requireText('Harness/WF-MAX.md', 'three-layer architecture', 'CLAUDE.md three-layer role architecture');
|
|
777
|
-
requireText('Harness/README.md', 'no runtime hook state', 'CLAUDE no-hook role enforcement statement');
|
|
778
|
-
requireText('Harness/
|
|
779
|
-
requireText('Harness/WF-AUTO.md', '
|
|
780
|
-
requireText('Harness/WF-AUTO.md', 'only `/wf-auto` may use a runtime hook', 'wf-auto-only hook boundary');
|
|
1026
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'three-layer architecture', 'CLAUDE.md three-layer role architecture');
|
|
1027
|
+
requireText('Harness/README.md', 'role enforcement has no runtime hook state', 'CLAUDE no-hook role enforcement statement');
|
|
1028
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'Runtime Hook Boundaries', 'runtime hook boundaries');
|
|
1029
|
+
requireText('Harness/specs/workflows/WF-AUTO.md', 'only `/wf-auto` may use a runtime hook to drive auto-optimization', 'wf-auto-only hook boundary');
|
|
781
1030
|
forbidText('CLAUDE.md', 'Enforced by hooks', 'WF-MAX hook enforcement claim');
|
|
782
|
-
forbidText('Harness/WF.md', 'MUST use at least 3 distinct role passes', 'old WF role-pass minimum');
|
|
783
|
-
forbidText('Harness/WF.md', 'at least three distinct role passes', 'old WF role-pass wording');
|
|
784
|
-
forbidText('Harness/dispatch.md', 'requires ≥3 distinct subagents', 'old dispatch WF role minimum');
|
|
1031
|
+
forbidText('Harness/specs/workflows/WF.md', 'MUST use at least 3 distinct role passes', 'old WF role-pass minimum');
|
|
1032
|
+
forbidText('Harness/specs/workflows/WF.md', 'at least three distinct role passes', 'old WF role-pass wording');
|
|
1033
|
+
forbidText('Harness/specs/runtime/dispatch.md', 'requires ≥3 distinct subagents', 'old dispatch WF role minimum');
|
|
785
1034
|
forbidText('CLAUDE.md', 'WF-MAX hooks', 'WF-MAX hook enforcement claim');
|
|
786
1035
|
forbidText('Harness/README.md', 'PreToolUse hook', 'WF-MAX PreToolUse hook claim');
|
|
787
1036
|
forbidText('Harness/README.md', 'SessionStart hook', 'WF-MAX SessionStart hook claim');
|
|
788
1037
|
forbidText('Harness/README.md', 'hook-managed', 'hook-managed runtime claim');
|
|
789
1038
|
forbidText('Harness/README.md', 'HOOK_PROTOCOL.md', 'removed hook protocol reference');
|
|
790
|
-
forbidText('Harness/WF-AUTO.md', 'Hook-Assisted Long Loop', 'wf-auto hook loop section');
|
|
791
|
-
forbidText('Harness/dispatch.md', 'removes the cap entirely', 'unbounded runtime-cap claim');
|
|
792
|
-
forbidText('Harness/WF-MAX.md', 'no hard agent cap; recursion governed', 'unbounded agent-cap claim');
|
|
793
|
-
forbidText('Harness/MEMORY_PROTOCOL.md', 'Hooks may', 'hook-triggered memory claim');
|
|
1039
|
+
forbidText('Harness/specs/workflows/WF-AUTO.md', 'Hook-Assisted Long Loop', 'wf-auto hook loop section');
|
|
1040
|
+
forbidText('Harness/specs/runtime/dispatch.md', 'removes the cap entirely', 'unbounded runtime-cap claim');
|
|
1041
|
+
forbidText('Harness/specs/workflows/WF-MAX.md', 'no hard agent cap; recursion governed', 'unbounded agent-cap claim');
|
|
1042
|
+
forbidText('Harness/specs/protocols/MEMORY_PROTOCOL.md', 'Hooks may', 'hook-triggered memory claim');
|
|
794
1043
|
forbidText('.claude/settings.json', 'wf-mode-hook.mjs', 'Claude WF hook command registration');
|
|
795
1044
|
forbidText('.codex/hooks.json', 'wf-mode-hook.mjs', 'Codex WF hook command registration');
|
|
796
1045
|
const codexHookConfig = read('.codex/hooks.json');
|
|
797
1046
|
const claudeSettings = read('.claude/settings.json');
|
|
798
1047
|
requireText('.codex/hooks.json', '"SessionStart"', 'Codex startup-only update hook');
|
|
799
1048
|
requireText('.claude/settings.json', '"SessionStart"', 'Claude startup-only update hook');
|
|
800
|
-
forbidText('.codex/hooks.json', 'UserPromptSubmit', 'Codex turn-by-turn
|
|
1049
|
+
forbidText('.codex/hooks.json', 'UserPromptSubmit', 'Codex turn-by-turn status hook');
|
|
1050
|
+
forbidText('.codex/hooks.json', '"Stop"', 'Codex stop status hook');
|
|
1051
|
+
forbidText('.codex/hooks.json', 'wf-status.mjs', 'removed Codex WF status script');
|
|
801
1052
|
forbidText('.claude/settings.json', 'UserPromptSubmit', 'Claude turn-by-turn update hook');
|
|
802
1053
|
requireText('.opencode/plugins/harness-wf-status.mjs', 'opencode.startup', 'OpenCode startup-only update check');
|
|
803
1054
|
forbidText('.opencode/plugins/harness-wf-status.mjs', "'chat.message'", 'OpenCode turn-by-turn update hook');
|
|
804
|
-
if (codexHookConfig && !codexHookConfig.includes('wf-auto')) {
|
|
805
|
-
errors.push('.codex/hooks.json
|
|
1055
|
+
if (codexHookConfig && !codexHookConfig.includes('wf-auto-update-prompt.mjs')) {
|
|
1056
|
+
errors.push('.codex/hooks.json missing startup wf-auto update check');
|
|
806
1057
|
}
|
|
807
1058
|
if (claudeSettings.includes('"hooks"') && !claudeSettings.includes('wf-auto')) {
|
|
808
1059
|
errors.push('.claude/settings.json hooks may only be used for wf-auto');
|
|
809
1060
|
}
|
|
810
|
-
if (read('.codex/config.toml').includes('hooks = true') && !codexHookConfig.includes('wf-auto')) {
|
|
811
|
-
errors.push('.codex/config.toml may enable hooks only with a
|
|
1061
|
+
if (read('.codex/config.toml').includes('hooks = true') && !codexHookConfig.includes('wf-auto-update-prompt.mjs')) {
|
|
1062
|
+
errors.push('.codex/config.toml may enable hooks only with a Harness hook configuration');
|
|
812
1063
|
}
|
|
813
1064
|
|
|
814
1065
|
// AGENTS.md must be a thin shim — no Harness/WF-MAX/command table content
|
|
@@ -821,24 +1072,65 @@ requireText('AGENTS.md', 'compatibility entry', 'AGENTS.md Codex shim purpose');
|
|
|
821
1072
|
requireText('AGENTS.md', 'single source', 'AGENTS.md CLAUDE.md as single source');
|
|
822
1073
|
|
|
823
1074
|
// Implicit WF trigger phrases forbidden in active runtime docs and SETUP
|
|
824
|
-
for (const rel of ['Harness/README.md', 'Harness/WF.md', 'Harness/context-loading.md', 'Harness/subagents.md', 'Harness/SETUP.md']) {
|
|
1075
|
+
for (const rel of ['Harness/README.md', 'Harness/specs/workflows/WF.md', 'Harness/specs/runtime/context-loading.md', 'Harness/specs/runtime/subagents.md', 'Harness/specs/guides/SETUP.md']) {
|
|
825
1076
|
forbidText(rel, 'workflow mode', 'implicit WF trigger: workflow mode');
|
|
826
1077
|
forbidText(rel, 'wk mode', 'implicit WF trigger: wk mode');
|
|
827
1078
|
}
|
|
828
1079
|
// SETUP must not require old WF complete-role-chain contract
|
|
829
|
-
requireText('Harness/SETUP.md', 'explicit WF entry only', 'SETUP explicit WF entry contract');
|
|
830
|
-
requireText('Harness/SETUP.md', 'WF-Light', 'SETUP WF-Light tier reference');
|
|
831
|
-
requireText('Harness/SETUP.md', 'WF-Max-Useful', 'SETUP WF-Max-Useful tier reference');
|
|
1080
|
+
requireText('Harness/specs/guides/SETUP.md', 'explicit WF entry only', 'SETUP explicit WF entry contract');
|
|
1081
|
+
requireText('Harness/specs/guides/SETUP.md', 'WF-Light', 'SETUP WF-Light tier reference');
|
|
1082
|
+
requireText('Harness/specs/guides/SETUP.md', 'WF-Max-Useful', 'SETUP WF-Max-Useful tier reference');
|
|
832
1083
|
|
|
833
1084
|
// Memory Preflight markers required in workflow skill adapters
|
|
834
|
-
for (const skill of ['wf', 'wf-max', 'subagent-orchestrator']) {
|
|
1085
|
+
for (const skill of ['wf', 'wf-max', 'wf-auto', 'subagent-orchestrator']) {
|
|
835
1086
|
requireText(`.claude/skills/${skill}/SKILL.md`, 'Memory Preflight', `${skill} skill Memory Preflight section`);
|
|
836
1087
|
}
|
|
1088
|
+
for (const skill of cacheDisciplinedSkills) {
|
|
1089
|
+
requireText(`.claude/skills/${skill}/SKILL.md`, 'Cache Discipline', `${skill} skill cache discipline`);
|
|
1090
|
+
}
|
|
1091
|
+
requireText('.claude/skills/wf-auto/SKILL.md', 'bounded test tick', 'wf-auto skill bounded tick auto capsule rule');
|
|
1092
|
+
requireText('.claude/skills/wf-auto/SKILL.md', 'missing auto capsule evidence', 'wf-auto skill missing auto capsule failure rule');
|
|
1093
|
+
requireText('.claude/skills/wf-auto/SKILL.md', 'Harness/tasks/auto/PLAN.md', 'wf-auto skill PLAN record');
|
|
1094
|
+
requireText('.claude/skills/wf-auto/SKILL.md', 'Harness/tasks/auto/PROGRESS.md', 'wf-auto skill PROGRESS record');
|
|
1095
|
+
requireText('.claude/skills/wf-auto/SKILL.md', 'evidence ledger path/summary', 'wf-auto skill return evidence ledger path');
|
|
1096
|
+
if (fs.existsSync(path.join(root, '.claude/skills/wf-browser/SKILL.md'))) {
|
|
1097
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'Cache Discipline', 'wf-browser skill cache discipline');
|
|
1098
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'Browser Evidence Contract', 'wf-browser browser evidence contract');
|
|
1099
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'Controllable UI Contract', 'wf-browser controllable UI contract');
|
|
1100
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'Browser Use CLI', 'wf-browser current Browser Use CLI guidance');
|
|
1101
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'browser-use --doctor', 'wf-browser Browser Use doctor command');
|
|
1102
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'browser-use skill', 'wf-browser Browser Use skill command');
|
|
1103
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'new_tab("https://example.com")', 'wf-browser Browser Use script-style example');
|
|
1104
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'capture_screenshot', 'wf-browser Browser Use screenshot helper');
|
|
1105
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'old `browser-use open/state/click/screenshot/input/wait` subcommands are removed', 'wf-browser removed old Browser Use subcommands');
|
|
1106
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'data-testid', 'wf-browser data-testid guidance');
|
|
1107
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'accessible labels/roles', 'wf-browser accessible selector guidance');
|
|
1108
|
+
requireText('.claude/skills/wf-browser/SKILL.md', 'inputs, buttons, filters, rows, empty/error/loading states', 'wf-browser controllable UI coverage targets');
|
|
1109
|
+
}
|
|
837
1110
|
|
|
838
1111
|
// Direct command checks
|
|
839
1112
|
requireText('Harness/README.md', '/wf-update', 'wf-update direct command reference');
|
|
840
1113
|
requireText('.claude/commands/wf-update.md', 'Do not invoke a skill', 'wf-update direct command boundary');
|
|
1114
|
+
for (const rel of ['.claude/commands/wf-update.md', '.opencode/commands/wf-update.md']) {
|
|
1115
|
+
requireText(rel, '## Cache Discipline', `${rel} cache discipline`);
|
|
1116
|
+
requireText(rel, 'agent.safeApplyCommand', `${rel} safe apply step`);
|
|
1117
|
+
requireText(rel, '--apply-safe', `${rel} apply-safe command`);
|
|
1118
|
+
requireText(rel, 'agent.aiMergeRequired', `${rel} AI merge step`);
|
|
1119
|
+
requireText(rel, '--accept-local', `${rel} accept-local decision`);
|
|
1120
|
+
requireText(rel, '--accept-merged', `${rel} accept-merged decision`);
|
|
1121
|
+
requireText(rel, '--accept-template', `${rel} accept-template decision`);
|
|
1122
|
+
requireText(rel, '--finalize', `${rel} finalize command`);
|
|
1123
|
+
requireText(rel, 'strict `--apply` only when', `${rel} strict apply boundary`);
|
|
1124
|
+
requireText(rel, '## Return', `${rel} return contract`);
|
|
1125
|
+
requireText(rel, 'agent.releaseHighlights', `${rel} release highlights summary`);
|
|
1126
|
+
requireText(rel, 'releaseNotes.highlights', `${rel} release notes fallback`);
|
|
1127
|
+
}
|
|
1128
|
+
requireText('Harness/scripts/wf-update-check.mjs', 'releaseHighlights', 'wf-update-check release highlights metadata');
|
|
1129
|
+
requireText('Harness/scripts/wf-update-check.mjs', 'updateReportRequired', 'wf-update-check user update report requirement');
|
|
841
1130
|
requireText('.claude/commands/wf-help.md', 'direct command', 'wf-help wf-update direct command classification');
|
|
1131
|
+
requireText('.claude/commands/wf-help.md', '$wf-help', 'wf-help Codex compatibility usage');
|
|
1132
|
+
requireText('.claude/commands/wf-help.md', '/wf-browser', 'wf-help built-in browser workflow row');
|
|
1133
|
+
requireText('.opencode/commands/wf-help.md', '/wf-browser', 'OpenCode wf-help built-in browser workflow row');
|
|
842
1134
|
|
|
843
1135
|
// wf-update skill must NOT claim Claude Code /wf-update as a skill invocation
|
|
844
1136
|
// (allow mentions in the description/body that say "direct command" — those are correct)
|
|
@@ -853,6 +1145,10 @@ for (const command of opencodeWorkflowCommands) {
|
|
|
853
1145
|
requireText(`.opencode/commands/${command}.md`, 'workflow command', `OpenCode ${command} workflow command classification`);
|
|
854
1146
|
requireText(`.opencode/commands/${command}.md`, `.claude/skills/${command}/SKILL.md`, `OpenCode ${command} wrapper skill routing`);
|
|
855
1147
|
requireText(`.opencode/commands/${command}.md`, 'Harness/MEMORY.md', `OpenCode ${command} wrapper router load`);
|
|
1148
|
+
requireText(`.opencode/commands/${command}.md`, 'Cache-First Context Contract', `OpenCode ${command} cache-first routing`);
|
|
1149
|
+
}
|
|
1150
|
+
if (fs.existsSync(path.join(root, '.opencode/commands/wf-browser.md'))) {
|
|
1151
|
+
requireText('.opencode/commands/wf-browser.md', 'Cache-First Context Contract', 'OpenCode wf-browser cache-first routing');
|
|
856
1152
|
}
|
|
857
1153
|
|
|
858
1154
|
// wf-max adapter must stay tier-aware, not the old unconditional contract
|
|
@@ -866,31 +1162,33 @@ requireText('.claude/agents/codebase-explorer.md', 'model: haiku', 'codebase-exp
|
|
|
866
1162
|
requireText('.claude/agents/codebase-explorer.md', 'read-only', 'codebase-explorer read-only contract');
|
|
867
1163
|
|
|
868
1164
|
// WF-KERNEL.md required invariants
|
|
869
|
-
requireText('Harness/WF-KERNEL.md', 'Ready-Queue', 'WF-KERNEL ready-queue section');
|
|
870
|
-
requireText('Harness/WF-KERNEL.md', 'Role / Model Matrix', 'WF-KERNEL role-model matrix');
|
|
871
|
-
requireText('Harness/WF-KERNEL.md', 'Dispatch Packet', 'WF-KERNEL dispatch packet format');
|
|
872
|
-
requireText('Harness/WF-KERNEL.md', 'Task Type', 'WF-KERNEL task type routing');
|
|
873
|
-
requireText('Harness/WF-KERNEL.md', 'small-fast', 'WF-KERNEL small-fast tier mapping');
|
|
1165
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'Ready-Queue', 'WF-KERNEL ready-queue section');
|
|
1166
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'Role / Model Matrix', 'WF-KERNEL role-model matrix');
|
|
1167
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'Dispatch Packet', 'WF-KERNEL dispatch packet format');
|
|
1168
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'Task Type', 'WF-KERNEL task type routing');
|
|
1169
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'small-fast', 'WF-KERNEL small-fast tier mapping');
|
|
874
1170
|
|
|
875
1171
|
// WF variants reference WF-KERNEL
|
|
876
|
-
requireText('Harness/WF.md', 'WF-KERNEL.md', 'WF.md references WF-KERNEL');
|
|
877
|
-
requireText('Harness/WF-MAX.md', 'WF-KERNEL.md', 'WF-MAX.md references WF-KERNEL');
|
|
878
|
-
requireText('Harness/WF-MAX.md', '
|
|
1172
|
+
requireText('Harness/specs/workflows/WF.md', 'WF-KERNEL.md', 'WF.md references WF-KERNEL');
|
|
1173
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'WF-KERNEL.md', 'WF-MAX.md references WF-KERNEL');
|
|
1174
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Use proven channels only', 'WF-MAX proven-channel degradation rule');
|
|
1175
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Evidence-Packet', 'WF-MAX evidence-packet channel record');
|
|
1176
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'Do not create ad hoc probe scripts', 'WF-MAX no ad hoc probe scripts');
|
|
879
1177
|
|
|
880
1178
|
// Tier-aware acceptance: WF-Light must NOT require global cross-review/reflector
|
|
881
|
-
requireText('Harness/WF.md', 'Cross-review and reflector NOT mandatory', 'WF.md WF-Light no mandatory cross-review');
|
|
882
|
-
requireText('Harness/WF-KERNEL.md', 'Cross-review and reflector are NOT mandatory', 'WF-KERNEL WF-Light no mandatory cross-review');
|
|
1179
|
+
requireText('Harness/specs/workflows/WF.md', 'Cross-review and reflector NOT mandatory', 'WF.md WF-Light no mandatory cross-review');
|
|
1180
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'Cross-review and reflector are NOT mandatory', 'WF-KERNEL WF-Light no mandatory cross-review');
|
|
883
1181
|
|
|
884
1182
|
// WF-MAX: maximum safe fan-out, not unconditional
|
|
885
|
-
requireText('Harness/WF-MAX.md', 'maximum safe fan-out', 'WF-MAX maximum safe fan-out');
|
|
886
|
-
requireText('Harness/WF-MAX.md', 'WF-Max-Useful', 'WF-MAX useful fan-out mode');
|
|
887
|
-
requireText('Harness/WF-MAX.md', 'WF-Max-Strict', 'WF-MAX strict override mode');
|
|
1183
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'maximum safe fan-out', 'WF-MAX maximum safe fan-out');
|
|
1184
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'WF-Max-Useful', 'WF-MAX useful fan-out mode');
|
|
1185
|
+
requireText('Harness/specs/workflows/WF-MAX.md', 'WF-Max-Strict', 'WF-MAX strict override mode');
|
|
888
1186
|
|
|
889
1187
|
// task-scribe is task-state write exception
|
|
890
|
-
requireText('Harness/subagents.md', 'task-scribe', 'subagents.md task-scribe registration');
|
|
891
|
-
requireText('Harness/dispatch.md', 'task-scribe', 'dispatch.md task-scribe roster');
|
|
892
|
-
requireText('Harness/WF-KERNEL.md', 'task-scribe', 'WF-KERNEL task-scribe ownership');
|
|
893
|
-
forbidText('Harness/WF-KERNEL.md', 'Only the main agent writes task', 'old single-writer rule');
|
|
1188
|
+
requireText('Harness/specs/runtime/subagents.md', 'task-scribe', 'subagents.md task-scribe registration');
|
|
1189
|
+
requireText('Harness/specs/runtime/dispatch.md', 'task-scribe', 'dispatch.md task-scribe roster');
|
|
1190
|
+
requireText('Harness/specs/workflows/WF-KERNEL.md', 'task-scribe', 'WF-KERNEL task-scribe ownership');
|
|
1191
|
+
forbidText('Harness/specs/workflows/WF-KERNEL.md', 'Only the main agent writes task', 'old single-writer rule');
|
|
894
1192
|
|
|
895
1193
|
// Old WF contract must not return to hot-path docs:
|
|
896
1194
|
// /wf is WF-KERNEL tiered orchestration, not a default complete role chain;
|
|
@@ -899,16 +1197,16 @@ const hotPathDocs = [
|
|
|
899
1197
|
'CLAUDE.md',
|
|
900
1198
|
'Harness/MEMORY.md',
|
|
901
1199
|
'Harness/README.md',
|
|
902
|
-
'Harness/WF.md',
|
|
903
|
-
'Harness/WF-MAX.md',
|
|
904
|
-
'Harness/WF-AUTO.md',
|
|
905
|
-
'Harness/WF-AUTO-SPARK.md',
|
|
906
|
-
'Harness/WF-KERNEL.md',
|
|
907
|
-
'Harness/agent-workflow.md',
|
|
908
|
-
'Harness/dispatch.md',
|
|
909
|
-
'Harness/subagents.md',
|
|
910
|
-
'Harness/context-loading.md',
|
|
911
|
-
'Harness/ACCEPTANCE_PROTOCOL.md',
|
|
1200
|
+
'Harness/specs/workflows/WF.md',
|
|
1201
|
+
'Harness/specs/workflows/WF-MAX.md',
|
|
1202
|
+
'Harness/specs/workflows/WF-AUTO.md',
|
|
1203
|
+
'Harness/specs/workflows/WF-AUTO-SPARK.md',
|
|
1204
|
+
'Harness/specs/workflows/WF-KERNEL.md',
|
|
1205
|
+
'Harness/specs/runtime/agent-workflow.md',
|
|
1206
|
+
'Harness/specs/runtime/dispatch.md',
|
|
1207
|
+
'Harness/specs/runtime/subagents.md',
|
|
1208
|
+
'Harness/specs/runtime/context-loading.md',
|
|
1209
|
+
'Harness/specs/protocols/ACCEPTANCE_PROTOCOL.md',
|
|
912
1210
|
];
|
|
913
1211
|
for (const rel of hotPathDocs) {
|
|
914
1212
|
forbidText(rel, 'complete role chain mandatory', 'old /wf default complete-role-chain contract');
|
|
@@ -919,16 +1217,80 @@ for (const rel of hotPathDocs) {
|
|
|
919
1217
|
}
|
|
920
1218
|
|
|
921
1219
|
// WF-STATE.md and TASK_ARCHIVE.md must be reachable from the entry router
|
|
922
|
-
requireText('CLAUDE.md', 'Harness/WF-STATE.md', 'CLAUDE.md WF-STATE routing');
|
|
923
|
-
requireText('CLAUDE.md', 'Harness/TASK_ARCHIVE.md', 'CLAUDE.md TASK_ARCHIVE routing');
|
|
1220
|
+
requireText('CLAUDE.md', 'Harness/specs/workflows/WF-STATE.md', 'CLAUDE.md WF-STATE routing');
|
|
1221
|
+
requireText('CLAUDE.md', 'Harness/specs/protocols/TASK_ARCHIVE.md', 'CLAUDE.md TASK_ARCHIVE routing');
|
|
924
1222
|
requireText('Harness/README.md', 'WF-STATE.md', 'README WF-STATE routing');
|
|
925
|
-
requireText('Harness/TASK_ARCHIVE.md', 'archive-tasks.mjs', 'TASK_ARCHIVE script reference');
|
|
1223
|
+
requireText('Harness/specs/protocols/TASK_ARCHIVE.md', 'archive-tasks.mjs', 'TASK_ARCHIVE script reference');
|
|
1224
|
+
requireText('Harness/specs/workflows/WF-STATE.md', 'task-state.mjs', 'WF-STATE task-state script contract');
|
|
1225
|
+
requireText('Harness/specs/protocols/TASK_ARCHIVE.md', 'task-state.mjs', 'TASK_ARCHIVE task-state script reference');
|
|
1226
|
+
|
|
1227
|
+
// Task-state consistency: prompt text is not authoritative for machine state.
|
|
1228
|
+
const rootTaskProgress = parseRootTaskProgress(read('Harness/PROGRESS.md'));
|
|
1229
|
+
const outerTaskSet = new Set(taskDirs.filter(name => !TASK_RESERVED.has(name) && !name.startsWith('_')));
|
|
1230
|
+
const rootTaskRows = new Set(rootTaskProgress.rows.map(row => row.id));
|
|
1231
|
+
|
|
1232
|
+
if (rootTaskProgress.activeTask && !outerTaskSet.has(rootTaskProgress.activeTask)) {
|
|
1233
|
+
taskStateIssue(`Harness/PROGRESS.md Active Task "${rootTaskProgress.activeTask}" does not exist under Harness/tasks/`);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
for (const row of rootTaskProgress.rows) {
|
|
1237
|
+
if (!outerTaskSet.has(row.id)) {
|
|
1238
|
+
taskStateIssue(`Harness/PROGRESS.md Task Index row has no outer task directory: ${row.id}`);
|
|
1239
|
+
}
|
|
1240
|
+
if (row.phase && !normalizeTaskPhase(row.phase)) {
|
|
1241
|
+
taskStateIssue(`Harness/PROGRESS.md Task Index row has unknown phase for ${row.id}: ${row.phase}`);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
const activeStateTasks = [];
|
|
1246
|
+
for (const taskDir of outerTaskSet) {
|
|
1247
|
+
if (!rootTaskRows.has(taskDir)) {
|
|
1248
|
+
taskStateIssue(`Harness/tasks/${taskDir}/ is missing from Harness/PROGRESS.md Task Index`);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const statePath = path.join(root, 'Harness', 'tasks', taskDir, 'STATE.json');
|
|
1252
|
+
if (!fs.existsSync(statePath)) {
|
|
1253
|
+
taskStateIssue(`Harness/tasks/${taskDir}/STATE.json is missing; run node Harness/scripts/task-state.mjs reconcile --apply`);
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
let state;
|
|
1258
|
+
try {
|
|
1259
|
+
state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
1260
|
+
} catch (err) {
|
|
1261
|
+
taskStateIssue(`Harness/tasks/${taskDir}/STATE.json is invalid JSON: ${err.message}`);
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
if (state.taskId && state.taskId !== taskDir) {
|
|
1266
|
+
taskStateIssue(`Harness/tasks/${taskDir}/STATE.json taskId "${state.taskId}" does not match directory`);
|
|
1267
|
+
}
|
|
1268
|
+
const status = normalizeTaskStatus(state.status);
|
|
1269
|
+
const phase = normalizeTaskPhase(state.phase);
|
|
1270
|
+
if (state.status && !status) {
|
|
1271
|
+
taskStateIssue(`Harness/tasks/${taskDir}/STATE.json has unknown status "${state.status}"`);
|
|
1272
|
+
}
|
|
1273
|
+
if (state.phase && !phase) {
|
|
1274
|
+
taskStateIssue(`Harness/tasks/${taskDir}/STATE.json has unknown phase "${state.phase}"`);
|
|
1275
|
+
}
|
|
1276
|
+
if (status === 'active') activeStateTasks.push(taskDir);
|
|
1277
|
+
if (status === 'active' && taskDir !== rootTaskProgress.activeTask) {
|
|
1278
|
+
taskStateIssue(`Harness/tasks/${taskDir}/STATE.json is active but Harness/PROGRESS.md Active Task is ${rootTaskProgress.activeTask || 'None'}; run node Harness/scripts/task-state.mjs reconcile --apply`);
|
|
1279
|
+
}
|
|
1280
|
+
if (taskDir === rootTaskProgress.activeTask && status && status !== 'active') {
|
|
1281
|
+
taskStateIssue(`Harness/PROGRESS.md Active Task points to ${taskDir}, but STATE.json status is "${status}"; run node Harness/scripts/task-state.mjs reconcile --apply`);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
if (activeStateTasks.length > 1) {
|
|
1286
|
+
taskStateIssue(`Multiple STATE.json files are active: ${activeStateTasks.join(', ')}; run node Harness/scripts/task-state.mjs reconcile --apply`);
|
|
1287
|
+
}
|
|
926
1288
|
|
|
927
|
-
// Outer task capsule cap: keep Harness/tasks/ lean (see Harness/TASK_ARCHIVE.md)
|
|
1289
|
+
// Outer task capsule cap: keep Harness/tasks/ lean (see Harness/specs/protocols/TASK_ARCHIVE.md)
|
|
928
1290
|
const OUTER_TASK_CAP = 5;
|
|
929
1291
|
const outerTasks = taskDirs.filter(name => !TASK_RESERVED.has(name) && !name.startsWith('_'));
|
|
930
1292
|
if (outerTasks.length > OUTER_TASK_CAP) {
|
|
931
|
-
const capMsg = `Harness/tasks/ has ${outerTasks.length} outer task capsules (cap ${OUTER_TASK_CAP}); archive completed tasks with node Harness/scripts/archive-tasks.mjs --apply
|
|
1293
|
+
const capMsg = `Harness/tasks/ has ${outerTasks.length} outer task capsules (cap ${OUTER_TASK_CAP}); archive completed tasks with node Harness/scripts/task-state.mjs archive --apply (compat: node Harness/scripts/archive-tasks.mjs --apply; see Harness/specs/protocols/TASK_ARCHIVE.md)`;
|
|
932
1294
|
if (strict) errors.push(capMsg);
|
|
933
1295
|
else console.warn(`Warning: ${capMsg}`);
|
|
934
1296
|
}
|