roadmapsmith 0.9.34 → 0.9.36
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/bin/cli.js +35 -7
- package/package.json +1 -1
- package/skills.json +11 -11
- package/src/config.js +8 -0
- package/src/io.js +14 -1
- package/src/parser/index.js +6 -0
- package/src/sync/index.js +15 -1
- package/src/validator/index.js +54 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roadmapsmith",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.36",
|
|
4
4
|
"description": "Evidence-backed ROADMAP.md workflows for AI coding agents, with canonical RoadmapSmith status and maintain surfaces plus advanced sync/generate tools and legacy compatibility aliases.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "PapiScholz"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roadmapsmith",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.36",
|
|
4
4
|
"description": "Evidence-backed ROADMAP.md workflows for AI coding agents, with canonical RoadmapSmith status and maintain surfaces plus advanced sync/generate tools and legacy compatibility aliases.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "PapiScholz"
|
package/bin/cli.js
CHANGED
|
@@ -92,6 +92,15 @@ function printAudit(audit) {
|
|
|
92
92
|
console.log(`- [${item.task.id}] ${item.task.text}`);
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
+
if (Array.isArray(audit.newlyUnchecked) && audit.newlyUnchecked.length > 0) {
|
|
96
|
+
console.log(`Unchecked by this run (${audit.newlyUnchecked.length}): ${audit.newlyUnchecked.join(', ')}`);
|
|
97
|
+
}
|
|
98
|
+
if (Array.isArray(audit.humanVerifiedTasks) && audit.humanVerifiedTasks.length > 0) {
|
|
99
|
+
console.log(`Human-verified tasks (${audit.humanVerifiedTasks.length}):`);
|
|
100
|
+
audit.humanVerifiedTasks.forEach((item) => {
|
|
101
|
+
console.log(`- [${item.task.id}] ${item.task.text}`);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
function printReadinessSummary(summary) {
|
|
@@ -276,8 +285,18 @@ function runSyncCommand(projectRoot, config, flags, options = {}) {
|
|
|
276
285
|
const validationContext = buildValidationContext(projectRoot, config, loadPlugins(projectRoot, config.plugins));
|
|
277
286
|
const results = validateTasks(syncTasks, validationContext, config, validationContext.plugins);
|
|
278
287
|
applyMinimumConfidence(results, config.validation?.minimumConfidence);
|
|
288
|
+
if (isEnabled(flags.audit)) {
|
|
289
|
+
const audit = auditValidation(syncTasks, results);
|
|
290
|
+
printAudit(audit);
|
|
291
|
+
const hasMismatch = audit.checkedWithoutEvidence.length > 0 || audit.readyButUnchecked.length > 0;
|
|
292
|
+
if (hasMismatch) {
|
|
293
|
+
process.exitCode = 2;
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
279
298
|
const forceRefresh = isEnabled(flags['refresh-annotations']);
|
|
280
|
-
const next = applySync(content, syncTasks, results, { forceRefresh });
|
|
299
|
+
const { content: next, changes } = applySync(content, syncTasks, results, { forceRefresh });
|
|
281
300
|
const dryRun = isEnabled(flags['dry-run']);
|
|
282
301
|
emitPreWriteWarning(roadmapFile, {
|
|
283
302
|
commandName: options.commandName || 'roadmapsmith sync',
|
|
@@ -294,11 +313,17 @@ function runSyncCommand(projectRoot, config, flags, options = {}) {
|
|
|
294
313
|
console.log(`No changes for ${roadmapFile}`);
|
|
295
314
|
}
|
|
296
315
|
} else {
|
|
316
|
+
if (changes.newlyUnchecked.length > 0) {
|
|
317
|
+
console.log(`Unchecked ${changes.newlyUnchecked.length} task(s): ${changes.newlyUnchecked.join(', ')}`);
|
|
318
|
+
}
|
|
319
|
+
if (changes.newlyChecked.length > 0) {
|
|
320
|
+
console.log(`Checked ${changes.newlyChecked.length} task(s): ${changes.newlyChecked.join(', ')}`);
|
|
321
|
+
}
|
|
297
322
|
console.log(writeResult.changed ? `Updated ${roadmapFile}` : `No changes for ${roadmapFile}`);
|
|
298
323
|
}
|
|
299
324
|
|
|
300
|
-
if (options.audit
|
|
301
|
-
const audit = auditValidation(syncTasks, results);
|
|
325
|
+
if (options.audit) {
|
|
326
|
+
const audit = auditValidation(syncTasks, results, changes);
|
|
302
327
|
printAudit(audit);
|
|
303
328
|
}
|
|
304
329
|
}
|
|
@@ -354,13 +379,16 @@ function runUpdateCommand(projectRoot, config, flags) {
|
|
|
354
379
|
const validationContext = buildValidationContext(projectRoot, config, loadPlugins(projectRoot, config.plugins));
|
|
355
380
|
const result = validateTasks([draftTask], validationContext, config, validationContext.plugins)[taskId];
|
|
356
381
|
const errors = (result.diagnostics || []).filter((item) => item.severity === 'error');
|
|
382
|
+
const isEscapeHatch = draftTask.verifiedBy === 'human' || draftTask.kind === 'docs';
|
|
357
383
|
const suppliedEvidenceResolved = result.evidence.authoritative && result.evidence.authoritativeFiles.length > 0;
|
|
358
|
-
|
|
384
|
+
const evidenceAccepted = isEscapeHatch ? result.passed : (suppliedEvidenceResolved && result.passed && result.confidence === 'high');
|
|
385
|
+
if (!evidenceAccepted || errors.length > 0) {
|
|
359
386
|
const reasons = result.reasons.length > 0 ? `: ${result.reasons.join('; ')}` : '';
|
|
360
|
-
|
|
387
|
+
const hint = isEscapeHatch ? '; escape-hatch task requires an Evidence: child line' : '; supplied evidence must resolve in the repository and validate at high confidence';
|
|
388
|
+
throw new Error(`Task ${taskId} was not updated${hint}${reasons}`);
|
|
361
389
|
}
|
|
362
390
|
|
|
363
|
-
const next = applySync(draft, [draftTask], { [taskId]: result });
|
|
391
|
+
const { content: next } = applySync(draft, [draftTask], { [taskId]: result });
|
|
364
392
|
const dryRun = isEnabled(flags['dry-run']);
|
|
365
393
|
emitPreWriteWarning(roadmapFile, {
|
|
366
394
|
commandName: 'roadmapsmith update',
|
|
@@ -489,7 +517,7 @@ function runMaintainCommand(projectRoot, flags) {
|
|
|
489
517
|
forceFullRegenerate: fullRegen,
|
|
490
518
|
warningState
|
|
491
519
|
});
|
|
492
|
-
runSyncCommand(projectRoot, config, { ...flags, audit:
|
|
520
|
+
runSyncCommand(projectRoot, config, { ...flags, audit: undefined }, {
|
|
493
521
|
audit: true,
|
|
494
522
|
commandName: 'roadmapsmith maintain',
|
|
495
523
|
warningState
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roadmapsmith",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.36",
|
|
4
4
|
"description": "Evidence-backed ROADMAP.md workflows for AI coding agents, with canonical RoadmapSmith status and maintain surfaces plus advanced sync/generate tools and legacy compatibility aliases.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/skills.json
CHANGED
|
@@ -28,67 +28,67 @@
|
|
|
28
28
|
"name": "roadmap",
|
|
29
29
|
"path": "skills/roadmap",
|
|
30
30
|
"description": "Native slash palette for RoadmapSmith commands and recommended entrypoints across supported hosts.",
|
|
31
|
-
"version": "0.9.
|
|
31
|
+
"version": "0.9.36"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"name": "roadmap-zero",
|
|
35
35
|
"path": "skills/roadmap-zero",
|
|
36
36
|
"description": "Native slash entrypoint for Zero Mode, including non-interactive config-plus-flag discovery.",
|
|
37
|
-
"version": "0.9.
|
|
37
|
+
"version": "0.9.36"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"name": "roadmap-maintain",
|
|
41
41
|
"path": "skills/roadmap-maintain",
|
|
42
42
|
"description": "Native slash entrypoint for conservative managed-block maintenance plus sync and audit output.",
|
|
43
|
-
"version": "0.9.
|
|
43
|
+
"version": "0.9.36"
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
"name": "roadmap-status",
|
|
47
47
|
"path": "skills/roadmap-status",
|
|
48
48
|
"description": "Native slash readiness check grounded in roadmapsmith status JSON.",
|
|
49
|
-
"version": "0.9.
|
|
49
|
+
"version": "0.9.36"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"name": "roadmap-init",
|
|
53
53
|
"path": "skills/roadmap-init",
|
|
54
54
|
"description": "Native slash entrypoint for creating ROADMAP.md and AGENTS.md.",
|
|
55
|
-
"version": "0.9.
|
|
55
|
+
"version": "0.9.36"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"name": "roadmap-generate",
|
|
59
59
|
"path": "skills/roadmap-generate",
|
|
60
60
|
"description": "Native slash entrypoint for managed roadmap updates that require --full-regen before destructive replacement.",
|
|
61
|
-
"version": "0.9.
|
|
61
|
+
"version": "0.9.36"
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
"name": "roadmap-validate",
|
|
65
65
|
"path": "skills/roadmap-validate",
|
|
66
66
|
"description": "Native slash entrypoint for evidence-backed roadmap validation.",
|
|
67
|
-
"version": "0.9.
|
|
67
|
+
"version": "0.9.36"
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
"name": "roadmap-update",
|
|
71
71
|
"path": "skills/roadmap-update",
|
|
72
72
|
"description": "Native slash entrypoint for evidence-backed inline annotation refresh and verified single-task completion.",
|
|
73
|
-
"version": "0.9.
|
|
73
|
+
"version": "0.9.36"
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
"name": "roadmap-sync",
|
|
77
77
|
"path": "skills/roadmap-sync",
|
|
78
78
|
"description": "DEPRECATED legacy compatibility root; use roadmap-maintain or roadmap-update.",
|
|
79
|
-
"version": "0.9.
|
|
79
|
+
"version": "0.9.36"
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"name": "roadmap-audit",
|
|
83
83
|
"path": "skills/roadmap-audit",
|
|
84
84
|
"description": "Native slash entrypoint for the advanced sync-plus-audit mutating summary workflow.",
|
|
85
|
-
"version": "0.9.
|
|
85
|
+
"version": "0.9.36"
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
"name": "roadmap-setup",
|
|
89
89
|
"path": "skills/roadmap-setup",
|
|
90
90
|
"description": "Native slash entrypoint for generating RoadmapSmith host integration files.",
|
|
91
|
-
"version": "0.9.
|
|
91
|
+
"version": "0.9.36"
|
|
92
92
|
}
|
|
93
93
|
]
|
|
94
94
|
}
|
package/src/config.js
CHANGED
|
@@ -30,6 +30,9 @@ const DEFAULT_CONFIG = {
|
|
|
30
30
|
constraints: [],
|
|
31
31
|
doneCriteria: []
|
|
32
32
|
},
|
|
33
|
+
scan: {
|
|
34
|
+
excludeDirs: []
|
|
35
|
+
},
|
|
33
36
|
validation: {
|
|
34
37
|
minimumConfidence: 'low',
|
|
35
38
|
testReports: [],
|
|
@@ -95,6 +98,11 @@ function mergeConfig(userConfig) {
|
|
|
95
98
|
? userConfig.zeroMode.doneCriteria
|
|
96
99
|
: DEFAULT_CONFIG.zeroMode.doneCriteria
|
|
97
100
|
},
|
|
101
|
+
scan: {
|
|
102
|
+
excludeDirs: Array.isArray(userConfig && userConfig.scan && userConfig.scan.excludeDirs)
|
|
103
|
+
? userConfig.scan.excludeDirs
|
|
104
|
+
: DEFAULT_CONFIG.scan.excludeDirs
|
|
105
|
+
},
|
|
98
106
|
validation: {
|
|
99
107
|
...DEFAULT_CONFIG.validation,
|
|
100
108
|
...((userConfig && userConfig.validation) || {}),
|
package/src/io.js
CHANGED
|
@@ -12,6 +12,16 @@ const DEFAULT_IGNORED_DIRS = new Set([
|
|
|
12
12
|
'.nuxt',
|
|
13
13
|
'.turbo',
|
|
14
14
|
'.cache',
|
|
15
|
+
'.open-next',
|
|
16
|
+
'.vercel',
|
|
17
|
+
'.svelte-kit',
|
|
18
|
+
'.parcel-cache',
|
|
19
|
+
'.angular',
|
|
20
|
+
'.expo',
|
|
21
|
+
'.serverless',
|
|
22
|
+
'.wrangler',
|
|
23
|
+
'.tmp',
|
|
24
|
+
'tmp',
|
|
15
25
|
'dist',
|
|
16
26
|
'dist-electron',
|
|
17
27
|
'build',
|
|
@@ -68,7 +78,10 @@ function writeText(filePath, content, options = {}) {
|
|
|
68
78
|
}
|
|
69
79
|
|
|
70
80
|
function walkFiles(rootPath, options = {}) {
|
|
71
|
-
|
|
81
|
+
let ignoredDirs = options.ignoredDirs || DEFAULT_IGNORED_DIRS;
|
|
82
|
+
if (Array.isArray(options.extraIgnoredDirs) && options.extraIgnoredDirs.length > 0) {
|
|
83
|
+
ignoredDirs = new Set([...ignoredDirs, ...options.extraIgnoredDirs]);
|
|
84
|
+
}
|
|
72
85
|
const result = [];
|
|
73
86
|
|
|
74
87
|
function walk(current) {
|
package/src/parser/index.js
CHANGED
|
@@ -147,6 +147,10 @@ function parseRoadmap(content) {
|
|
|
147
147
|
|
|
148
148
|
const { indent, checked, text, markerId, markerFlags } = taskLine;
|
|
149
149
|
const noTest = /\brs:no-test\b/i.test(markerFlags);
|
|
150
|
+
const kindMatch = markerFlags.match(/\brs:kind=(\S+)/i);
|
|
151
|
+
const taskKind = kindMatch ? kindMatch[1].toLowerCase() : null;
|
|
152
|
+
const verifiedByMatch = markerFlags.match(/\brs:verified-by=(\S+)/i);
|
|
153
|
+
const taskVerifiedBy = verifiedByMatch ? verifiedByMatch[1].toLowerCase() : null;
|
|
150
154
|
const taskIndentWidth = getIndentWidth(indent);
|
|
151
155
|
|
|
152
156
|
let warningLineIndex = null;
|
|
@@ -243,6 +247,8 @@ function parseRoadmap(content) {
|
|
|
243
247
|
blockedByIds,
|
|
244
248
|
markerId,
|
|
245
249
|
noTest,
|
|
250
|
+
kind: taskKind,
|
|
251
|
+
verifiedBy: taskVerifiedBy,
|
|
246
252
|
indent,
|
|
247
253
|
section
|
|
248
254
|
});
|
package/src/sync/index.js
CHANGED
|
@@ -139,6 +139,13 @@ function applySync(content, parsedTasks, results, options) {
|
|
|
139
139
|
const lines = [...parsed.lines];
|
|
140
140
|
const tasks = parsedTasks || parsed.tasks;
|
|
141
141
|
|
|
142
|
+
const changes = {
|
|
143
|
+
newlyUnchecked: [],
|
|
144
|
+
newlyChecked: [],
|
|
145
|
+
warningsAdded: [],
|
|
146
|
+
warningsRemoved: []
|
|
147
|
+
};
|
|
148
|
+
|
|
142
149
|
let offset = 0;
|
|
143
150
|
for (const task of tasks) {
|
|
144
151
|
const result = results[task.id];
|
|
@@ -151,7 +158,13 @@ function applySync(content, parsedTasks, results, options) {
|
|
|
151
158
|
continue;
|
|
152
159
|
}
|
|
153
160
|
|
|
161
|
+
const wasChecked = task.checked;
|
|
154
162
|
lines[lineIndex] = setChecklistState(lines[lineIndex], result.passed);
|
|
163
|
+
if (wasChecked && !result.passed) {
|
|
164
|
+
changes.newlyUnchecked.push(task.id);
|
|
165
|
+
} else if (!wasChecked && result.passed) {
|
|
166
|
+
changes.newlyChecked.push(task.id);
|
|
167
|
+
}
|
|
155
168
|
|
|
156
169
|
const reason = normalizeWarningReasons(result.reasons).join('; ');
|
|
157
170
|
const warningText = formatWarning(task.indent || '', reason || 'validation failed', result.attempted);
|
|
@@ -198,6 +211,7 @@ function applySync(content, parsedTasks, results, options) {
|
|
|
198
211
|
} else {
|
|
199
212
|
lines.splice(lastChildLineIndex + 1, 0, warningText);
|
|
200
213
|
offset += 1;
|
|
214
|
+
changes.warningsAdded.push(task.id);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
217
|
const recipeIndex = findVerificationRecipeIndex(lines, lineIndex);
|
|
@@ -218,7 +232,7 @@ function applySync(content, parsedTasks, results, options) {
|
|
|
218
232
|
}
|
|
219
233
|
}
|
|
220
234
|
|
|
221
|
-
return ensureTrailingNewline(lines.join('\n'));
|
|
235
|
+
return { content: ensureTrailingNewline(lines.join('\n')), changes };
|
|
222
236
|
}
|
|
223
237
|
|
|
224
238
|
module.exports = {
|
package/src/validator/index.js
CHANGED
|
@@ -13,7 +13,11 @@ const CODE_EXTENSIONS = new Set([
|
|
|
13
13
|
]);
|
|
14
14
|
const TRANSLATION_DIR_SEGMENTS = ['locale', 'locales', 'i18n', 'translations'];
|
|
15
15
|
const DEFAULT_EXCLUDED_PATH_PREFIXES = ['.claude/', '.agent/', 'roadmap-skill/'];
|
|
16
|
-
const GENERATED_OUTPUT_PREFIXES = [
|
|
16
|
+
const GENERATED_OUTPUT_PREFIXES = [
|
|
17
|
+
'dist-electron/', 'dist/', 'build/', 'out/', '.next/', 'coverage/',
|
|
18
|
+
'.open-next/', '.vercel/', '.svelte-kit/', '.parcel-cache/', '.angular/',
|
|
19
|
+
'.expo/', '.serverless/', '.wrangler/', '.tmp/', 'tmp/'
|
|
20
|
+
];
|
|
17
21
|
const AUXILIARY_HEURISTIC_PATH_SEGMENTS = new Set(['scripts', 'tools', 'tooling', 'demo', 'demos']);
|
|
18
22
|
|
|
19
23
|
// "docs" omitted from DOC_HINTS — it is a path prefix in scan tasks, not a doc-authoring keyword.
|
|
@@ -246,6 +250,7 @@ function readFileIndex(projectRoot, files, config) {
|
|
|
246
250
|
if (SELF_REFERENTIAL_FILES.has(relativePath)) continue;
|
|
247
251
|
if (isFixturePath(relativePath)) continue;
|
|
248
252
|
if (shouldExcludeByDefaultPath(relativePath, config)) continue;
|
|
253
|
+
if (isGeneratedOutputPath(relativePath)) continue;
|
|
249
254
|
|
|
250
255
|
const absolutePath = path.resolve(projectRoot, relativePath);
|
|
251
256
|
const ext = path.extname(relativePath).toLowerCase();
|
|
@@ -1774,7 +1779,10 @@ function evaluateDeterministicVerification(task, context) {
|
|
|
1774
1779
|
}
|
|
1775
1780
|
|
|
1776
1781
|
function buildValidationContext(projectRoot, config, plugins, options = {}) {
|
|
1777
|
-
const
|
|
1782
|
+
const userExcludeDirs = Array.isArray(config && config.scan && config.scan.excludeDirs)
|
|
1783
|
+
? config.scan.excludeDirs
|
|
1784
|
+
: [];
|
|
1785
|
+
const files = walkFiles(projectRoot, { extraIgnoredDirs: userExcludeDirs });
|
|
1778
1786
|
const fileIndex = readFileIndex(projectRoot, files, config);
|
|
1779
1787
|
const testFrameworks = detectTestFrameworks(projectRoot, files);
|
|
1780
1788
|
const pathHintResolver = buildPathHintResolver(fileIndex);
|
|
@@ -1852,6 +1860,39 @@ function buildDiscoveredEvidenceLine(evidence) {
|
|
|
1852
1860
|
}
|
|
1853
1861
|
|
|
1854
1862
|
function validateTask(task, context, config, plugins) {
|
|
1863
|
+
if (task.verifiedBy === 'human') {
|
|
1864
|
+
const hasEvidenceLine = Array.isArray(task.evidenceLines) &&
|
|
1865
|
+
task.evidenceLines.some((e) => e.text && e.text.trim().length > 0);
|
|
1866
|
+
if (!hasEvidenceLine) {
|
|
1867
|
+
return {
|
|
1868
|
+
passed: false,
|
|
1869
|
+
confidence: 'low',
|
|
1870
|
+
attempted: false,
|
|
1871
|
+
reasons: ['human-verified tasks require an Evidence: child line'],
|
|
1872
|
+
evidence: { code: false, test: false, artifact: false, files: [], codeFiles: [], testFiles: [], weakPathFiles: [], weakPathContentTokens: [], artifactFiles: [], heuristicArtifacts: [], symbols: [], structuralEvidence: null, authoritative: false, authoritativeFiles: [], authoritativeSummaries: [] },
|
|
1873
|
+
diagnostics: [],
|
|
1874
|
+
verificationRecipe: null,
|
|
1875
|
+
staleEvidenceDetected: false,
|
|
1876
|
+
staleEvidenceResolved: false,
|
|
1877
|
+
generatedTestEvidence: null
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
const evidenceText = task.evidenceLines[0].text;
|
|
1881
|
+
return {
|
|
1882
|
+
passed: true,
|
|
1883
|
+
confidence: 'medium',
|
|
1884
|
+
attempted: true,
|
|
1885
|
+
reasons: [],
|
|
1886
|
+
evidence: { code: false, test: false, artifact: false, files: [], codeFiles: [], testFiles: [], weakPathFiles: [], weakPathContentTokens: [], artifactFiles: [], heuristicArtifacts: [], symbols: [], structuralEvidence: null, authoritative: true, authoritativeFiles: [], authoritativeSummaries: [evidenceText] },
|
|
1887
|
+
diagnostics: [],
|
|
1888
|
+
verificationRecipe: null,
|
|
1889
|
+
staleEvidenceDetected: false,
|
|
1890
|
+
staleEvidenceResolved: false,
|
|
1891
|
+
generatedTestEvidence: null,
|
|
1892
|
+
humanVerified: true
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1855
1896
|
const {
|
|
1856
1897
|
paths: pathHints,
|
|
1857
1898
|
externalPaths,
|
|
@@ -1943,6 +1984,7 @@ function validateTask(task, context, config, plugins) {
|
|
|
1943
1984
|
|
|
1944
1985
|
const requiresTest =
|
|
1945
1986
|
!task.noTest &&
|
|
1987
|
+
task.kind !== 'docs' &&
|
|
1946
1988
|
context.testFrameworks.length > 0 &&
|
|
1947
1989
|
isCodeTask(task.text) &&
|
|
1948
1990
|
!isDocTask(task.text) &&
|
|
@@ -2010,6 +2052,7 @@ function validateTask(task, context, config, plugins) {
|
|
|
2010
2052
|
// Only pure path hints (not line-reference hints like file.ts:169) count as direct evidence.
|
|
2011
2053
|
const hasDirectReferencePass = filesFromPurePathHints.length > 0 || filesFromSymbols.length > 0;
|
|
2012
2054
|
const hasArtifactTaskPass = evidence.artifact && (
|
|
2055
|
+
task.kind === 'docs' ||
|
|
2013
2056
|
isDocTask(task.text) ||
|
|
2014
2057
|
evidence.heuristicArtifacts.length > 0 ||
|
|
2015
2058
|
filesFromPaths.some((relativePath) => !CODE_EXTENSIONS.has(path.extname(relativePath).toLowerCase()))
|
|
@@ -2226,17 +2269,23 @@ function validateTasks(tasks, context, config, plugins) {
|
|
|
2226
2269
|
return result;
|
|
2227
2270
|
}
|
|
2228
2271
|
|
|
2229
|
-
function auditValidation(tasks, results) {
|
|
2272
|
+
function auditValidation(tasks, results, changes) {
|
|
2230
2273
|
const checkedWithoutEvidence = [];
|
|
2231
2274
|
const readyButUnchecked = [];
|
|
2232
2275
|
const checkedWithWeakEvidence = [];
|
|
2233
2276
|
const documentationOnlyEvidenceForImplementation = [];
|
|
2234
2277
|
const checkedWithNoStructuralEvidence = [];
|
|
2278
|
+
const humanVerifiedTasks = [];
|
|
2279
|
+
const newlyUnchecked = Array.isArray(changes && changes.newlyUnchecked) ? changes.newlyUnchecked : [];
|
|
2235
2280
|
|
|
2236
2281
|
for (const task of tasks) {
|
|
2237
2282
|
const result = results[task.id];
|
|
2238
2283
|
if (!result) continue;
|
|
2239
2284
|
|
|
2285
|
+
if (result.humanVerified) {
|
|
2286
|
+
humanVerifiedTasks.push({ task, result });
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2240
2289
|
if (task.checked && !result.passed) {
|
|
2241
2290
|
checkedWithoutEvidence.push({ task, result });
|
|
2242
2291
|
}
|
|
@@ -2265,6 +2314,8 @@ function auditValidation(tasks, results) {
|
|
|
2265
2314
|
checkedWithWeakEvidence,
|
|
2266
2315
|
documentationOnlyEvidenceForImplementation,
|
|
2267
2316
|
checkedWithNoStructuralEvidence,
|
|
2317
|
+
humanVerifiedTasks,
|
|
2318
|
+
newlyUnchecked
|
|
2268
2319
|
};
|
|
2269
2320
|
}
|
|
2270
2321
|
|