roadmapsmith 0.9.27 → 0.9.28

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roadmapsmith",
3
- "version": "0.9.27",
3
+ "version": "0.9.28",
4
4
  "description": "One-command evidence-backed ROADMAP.md generator and sync tool for AI coding agents, with shared RoadmapSmith plugin skills for Codex and Claude plus the roadmapsmith status readiness surface.",
5
5
  "author": {
6
6
  "name": "PapiScholz"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roadmapsmith",
3
- "version": "0.9.27",
3
+ "version": "0.9.28",
4
4
  "description": "One-command evidence-backed ROADMAP.md generator and sync tool for AI coding agents, with shared RoadmapSmith plugin skills for Codex and Claude plus the roadmapsmith status readiness surface.",
5
5
  "author": {
6
6
  "name": "PapiScholz"
package/README.md CHANGED
@@ -28,7 +28,7 @@ npx skills add PapiScholz/roadmapsmith --skill '*' -a claude-code
28
28
  ```
29
29
 
30
30
  This is the recommended Claude Code install path for native GUI slash commands such as `/roadmap`, `/roadmap-zero`, `/roadmap-maintain`, `/roadmap-status`, `/roadmap-init`, `/roadmap-generate`, `/roadmap-validate`, `/roadmap-update`, `/roadmap-audit`, and `/roadmap-setup`.
31
- If you install only `--skill roadmap-sync`, Claude GUI will expose only `/roadmap-sync`.
31
+ `roadmap-sync` is deprecated compatibility only; install the full bundle for new workflows and use `/roadmap-maintain` or `/roadmap-update`.
32
32
  The skill bundle does not install the CLI and it does not create visible VS Code actions by itself.
33
33
  The published `roadmapsmith` package/plugin surface now also ships the shared bundle files for both hosts (`skills.json`, `skills/*`, `.codex-plugin/plugin.json`, `.claude-plugin/plugin.json`) for downstream host installers, but consuming the CLI alone still does not auto-register native Codex or Claude GUI commands.
34
34
 
@@ -101,7 +101,11 @@ Use the lower-level commands only when you want manual control over generation,
101
101
  | CI | Use disposable checkouts if you run `sync --audit`, because it still mutates the roadmap today. |
102
102
  | Other hosts | Use the skill plus manual CLI commands. |
103
103
 
104
- If Node is installed outside PATH, set `ROADMAPSMITH_NODE` to a working `node` executable before using the generated VS Code tasks.
104
+ If Node is installed outside PATH, set `ROADMAPSMITH_NODE` to a working `node` executable before using the generated VS Code tasks. If the globally installed `roadmapsmith` shim itself cannot resolve Node, bypass it in PowerShell with:
105
+
106
+ ```powershell
107
+ & "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" <command>
108
+ ```
105
109
 
106
110
  ---
107
111
 
@@ -119,6 +123,7 @@ roadmapsmith maintain [--project-root <path>] [--config <path>] [--roadmap-file
119
123
  roadmapsmith init [--roadmap-file <path>] [--agents-file <path>] [--dry-run]
120
124
  roadmapsmith generate [--project-root <path>] [--config <path>] [--roadmap-file <path>] [--dry-run] [--audit] [--full-regen]
121
125
  roadmapsmith sync [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run] [--audit]
126
+ roadmapsmith update --task <stable-id> --evidence <text> [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run]
122
127
  roadmapsmith validate [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--task <id|text>] [--json]
123
128
  roadmapsmith status [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json]
124
129
  roadmapsmith doctor [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json] # compatibility alias
@@ -183,6 +188,8 @@ The repo does not remove user-global skills automatically. Use the `doctor` outp
183
188
  - `- ⚠️ attempted but validation failed: <reason>` when there is concrete attempt evidence
184
189
  - `- ⚠️ no implementation evidence found yet: <reason>` when there is not
185
190
  - Preserves unmanaged markdown content by updating only the managed roadmap block.
191
+ - `validate` emits structured diagnostics in human and JSON output (`FAIL:NOT_IMPLEMENTED`, `FAIL:NO_TEST`, `FAIL:MISSING_REFERENCE`, and `WARN:STALE_EVIDENCE`).
192
+ - `update --task <id> --evidence <text>` writes only when the evidence validates at high confidence; otherwise the roadmap is unchanged.
186
193
 
187
194
  ## Defaults
188
195
 
package/bin/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const readline = require('node:readline/promises');
7
- const { parseArgv } = require('../src/utils');
7
+ const { ensureTrailingNewline, parseArgv } = require('../src/utils');
8
8
  const { loadConfig, resolveRoadmapFile, resolveAgentsFile, loadPlugins, readUserConfig, resolveConfigPath } = require('../src/config');
9
9
  const { readTextIfExists, writeText, printDryRunDiff } = require('../src/io');
10
10
  const { buildSetupFiles, applySetupFiles, inspectHostSetup, parseHosts, assertSupportedEditor } = require('../src/host');
@@ -30,6 +30,7 @@ function printHelp() {
30
30
  ' roadmapsmith setup [--project-root <path>] [--config <path>] [--editor vscode] [--hosts <codex,claude>] [--dry-run]',
31
31
  ' roadmapsmith generate [--project-root <path>] [--config <path>] [--roadmap-file <path>] [--dry-run] [--audit] [--full-regen]',
32
32
  ' roadmapsmith sync [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run] [--audit]',
33
+ ' roadmapsmith update --task <stable-id> --evidence <text> [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run]',
33
34
  ' roadmapsmith validate [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--task <id|text>] [--json]',
34
35
  ' roadmapsmith status [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json]',
35
36
  ' roadmapsmith doctor [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json] # compatibility alias'
@@ -44,8 +45,13 @@ function isEnabled(value) {
44
45
  }
45
46
 
46
47
  function formatResultLine(task, result) {
47
- const status = result.passed ? 'PASS' : 'FAIL';
48
- const reason = result.reasons.length > 0 ? ` :: ${result.reasons.join('; ')}` : '';
48
+ const diagnostics = Array.isArray(result.diagnostics) ? result.diagnostics : [];
49
+ const primaryError = diagnostics.find((item) => item.severity === 'error');
50
+ const warnings = diagnostics.filter((item) => item.severity === 'warning');
51
+ const status = primaryError ? `FAIL:${primaryError.code}` : (result.passed ? 'PASS' : 'FAIL');
52
+ const parts = [...result.reasons];
53
+ warnings.forEach((item) => parts.push(`WARN:${item.code} ${item.message}`));
54
+ const reason = parts.length > 0 ? ` :: ${parts.join('; ')}` : '';
49
55
  return `${status} [${task.id}] ${task.text}${reason}`;
50
56
  }
51
57
 
@@ -215,6 +221,77 @@ function runSyncCommand(projectRoot, config, flags, options = {}) {
215
221
  }
216
222
  }
217
223
 
224
+ function addEvidenceToTask(content, task, evidenceText) {
225
+ const lines = String(content || '').split(/\r?\n/);
226
+ const evidenceLine = `${task.indent || ''} - Evidence: ${evidenceText}`;
227
+ if (Array.isArray(task.evidenceLines) && task.evidenceLines.length > 0) {
228
+ lines[task.evidenceLines[0].lineIndex] = evidenceLine;
229
+ return ensureTrailingNewline(lines.join('\n'));
230
+ }
231
+
232
+ const insertionIndex = task.warningLineIndex != null
233
+ ? task.warningLineIndex
234
+ : task.lastChildLineIndex + 1;
235
+ lines.splice(insertionIndex, 0, evidenceLine);
236
+ return ensureTrailingNewline(lines.join('\n'));
237
+ }
238
+
239
+ function runUpdateCommand(projectRoot, config, flags) {
240
+ const hasTask = flags.task != null;
241
+ const hasEvidence = flags.evidence != null;
242
+ if (!hasTask && !hasEvidence) {
243
+ runSyncCommand(projectRoot, config, flags);
244
+ return;
245
+ }
246
+ if (!hasTask || !hasEvidence || Array.isArray(flags.task) || Array.isArray(flags.evidence)) {
247
+ throw new Error('update requires exactly one --task <stable-id> and one --evidence <text> value');
248
+ }
249
+
250
+ const taskId = String(flags.task).trim();
251
+ const evidenceText = String(flags.evidence).trim();
252
+ if (!taskId || !evidenceText || /[\r\n]/.test(evidenceText)) {
253
+ throw new Error('update requires a non-empty single-line --task and --evidence value');
254
+ }
255
+
256
+ const roadmapFile = resolveRoadmapFile(projectRoot, config, flags['roadmap-file']);
257
+ const content = readTextIfExists(roadmapFile);
258
+ if (content == null) {
259
+ throw new Error(`Roadmap not found: ${roadmapFile}`);
260
+ }
261
+
262
+ const parsedRoadmap = parseRoadmap(content);
263
+ const matches = tasksInManagedBlock(parsedRoadmap).filter((task) => task.id === taskId);
264
+ if (matches.length !== 1) {
265
+ throw new Error(matches.length === 0
266
+ ? `Roadmap task not found: ${taskId}`
267
+ : `Roadmap task ID is ambiguous: ${taskId}`);
268
+ }
269
+
270
+ const draft = addEvidenceToTask(content, matches[0], evidenceText);
271
+ const draftTask = tasksInManagedBlock(parseRoadmap(draft)).find((task) => task.id === taskId);
272
+ const validationContext = buildValidationContext(projectRoot, config, loadPlugins(projectRoot, config.plugins));
273
+ const result = validateTasks([draftTask], validationContext, config, validationContext.plugins)[taskId];
274
+ const errors = (result.diagnostics || []).filter((item) => item.severity === 'error');
275
+ const suppliedEvidenceResolved = result.evidence.authoritative && result.evidence.authoritativeFiles.length > 0;
276
+ if (!suppliedEvidenceResolved || !result.passed || result.confidence !== 'high' || errors.length > 0) {
277
+ const reasons = result.reasons.length > 0 ? `: ${result.reasons.join('; ')}` : '';
278
+ throw new Error(`Task ${taskId} was not updated; supplied evidence must resolve in the repository and validate at high confidence${reasons}`);
279
+ }
280
+
281
+ const next = applySync(draft, [draftTask], { [taskId]: result });
282
+ const dryRun = isEnabled(flags['dry-run']);
283
+ const writeResult = writeText(roadmapFile, next, { dryRun });
284
+ if (dryRun) {
285
+ if (writeResult.changed) {
286
+ printDryRunDiff(roadmapFile, writeResult.before, writeResult.after);
287
+ } else {
288
+ console.log(`No changes for ${roadmapFile}`);
289
+ }
290
+ } else {
291
+ console.log(writeResult.changed ? `Updated ${roadmapFile}` : `No changes for ${roadmapFile}`);
292
+ }
293
+ }
294
+
218
295
  function printHumanStatus(payload) {
219
296
  console.log('RoadmapSmith status\n');
220
297
  console.log(`Project root: ${payload.projectRoot}`);
@@ -343,6 +420,8 @@ async function run() {
343
420
  if (slashAction.id === 'audit') {
344
421
  flags.audit = true;
345
422
  effectiveCommand = 'sync';
423
+ } else if (slashAction.id === 'sync' && String(command).trim().toLowerCase() === '/roadmap-update') {
424
+ effectiveCommand = 'update';
346
425
  } else {
347
426
  effectiveCommand = slashAction.id;
348
427
  }
@@ -411,6 +490,13 @@ async function run() {
411
490
  return;
412
491
  }
413
492
 
493
+ if (effectiveCommand === 'update') {
494
+ const projectRoot = path.resolve(String(flags['project-root'] || process.cwd()));
495
+ const config = loadConfig({ projectRoot, configPath: flags.config });
496
+ runUpdateCommand(projectRoot, config, flags);
497
+ return;
498
+ }
499
+
414
500
  if (effectiveCommand === 'validate') {
415
501
  const projectRoot = path.resolve(String(flags['project-root'] || process.cwd()));
416
502
  const config = loadConfig({ projectRoot, configPath: flags.config });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roadmapsmith",
3
- "version": "0.9.27",
3
+ "version": "0.9.28",
4
4
  "description": "One-command evidence-backed ROADMAP.md generator and sync tool for AI coding agents, with shared RoadmapSmith plugin skills for Codex and Claude plus the roadmapsmith status readiness surface.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -13,7 +13,7 @@ Use this command as the native discovery entrypoint for the shared RoadmapSmith
13
13
  2. When working inside the RoadmapSmith repository itself and `roadmap-skill/bin/cli.js` exists, prefer the local engine:
14
14
  - `node roadmap-skill/bin/cli.js /roadmap`
15
15
  - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js /roadmap` if `node` is not in PATH
16
- 3. Otherwise, if the `roadmapsmith` CLI is available, you may run `roadmapsmith /roadmap` from the project root and use that output directly.
16
+ 3. Otherwise, if the `roadmapsmith` CLI is available, you may run `roadmapsmith /roadmap` from the project root and use that output directly. If its global shim cannot resolve `node`, use `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" /roadmap`.
17
17
  4. If the CLI is missing, provide the palette manually and explain the install path:
18
18
  - `npm install -g roadmapsmith`
19
19
  - `npx skills add PapiScholz/roadmapsmith --skill '*' -a claude-code`
@@ -12,7 +12,8 @@ Use this command when the repository already has code, tests, docs, or an existi
12
12
  1. Prefer the local engine inside this repository:
13
13
  - `node roadmap-skill/bin/cli.js maintain --project-root .`
14
14
  - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js maintain --project-root .` if `node` is not in PATH
15
- 2. Otherwise prefer `roadmapsmith maintain --project-root .`.
15
+ 2. Otherwise prefer `roadmapsmith maintain --project-root .`. If that global shim fails because `node` is not in PATH, run `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" maintain --project-root .`.
16
16
  3. Treat this command as CLI-backed. Do not silently replace it with manual reasoning when the CLI is unavailable.
17
17
  4. Mention that maintain runs preserve-first generate, sync, and audit in one invocation.
18
- 5. Mention that `roadmapsmith maintain --full-regen` or `roadmapsmith generate --full-regen` is the explicit destructive rebuild path when the user truly wants a full managed-block replacement.
18
+ 5. After a successful maintain cycle, do not propose generate, sync, or audit separately unless the user needs manual control or inspection.
19
+ 6. Mention that `roadmapsmith maintain --full-regen` or `roadmapsmith generate --full-regen` is the explicit destructive rebuild path when the user truly wants a full managed-block replacement.
@@ -12,6 +12,6 @@ Use this command to inspect whether the shared bundle, native host surfaces, CLI
12
12
  1. Prefer the local engine inside this repository:
13
13
  - `node roadmap-skill/bin/cli.js doctor --json --project-root .`
14
14
  - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js doctor --json --project-root .` if `node` is not in PATH
15
- 2. Otherwise prefer `roadmapsmith doctor --json --project-root .`.
15
+ 2. Otherwise prefer `roadmapsmith doctor --json --project-root .`. If its global shim cannot resolve `node`, use `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" doctor --json --project-root .`.
16
16
  3. Parse and summarize the JSON output in plain language.
17
17
  4. Explicitly call out missing commands or duplicate `/roadmap-sync` registration when doctor reports them.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: roadmap-sync
3
- description: Legacy namespaced root and policy guidance for RoadmapSmith slash workflows.
3
+ description: DEPRECATED legacy root for RoadmapSmith slash workflows; use roadmap-maintain or roadmap-update.
4
4
  ---
5
5
 
6
- # RoadmapSmith Legacy Root
6
+ # RoadmapSmith Legacy Root (Deprecated)
7
7
 
8
- Use this skill when the host exposes or the user invokes `/roadmap-sync`, or when the agent needs the RoadmapSmith operating rules for roadmap maintenance.
8
+ Use this skill only when the host exposes or the user explicitly invokes `/roadmap-sync`. For new work, use `/roadmap-maintain` for the daily flow or `/roadmap-update` for evidence-backed completion.
9
9
 
10
10
  ## Required behavior
11
11
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "interface": {
3
- "display_name": "Roadmap Sync",
4
- "short_description": "Legacy root plus policy for evidence-backed ROADMAP.md slash workflows.",
3
+ "display_name": "Roadmap Sync (Deprecated)",
4
+ "short_description": "DEPRECATED legacy root; use /roadmap-maintain or /roadmap-update.",
5
5
  "default_prompt": "Prefer /roadmap, /roadmap-status, /roadmap-maintain, and /roadmap-update."
6
6
  }
7
7
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: roadmap-update
3
- description: Apply evidence-backed checklist sync through the RoadmapSmith CLI.
3
+ description: Apply evidence-backed checklist sync or complete one task with verified evidence through the RoadmapSmith CLI.
4
4
  ---
5
5
 
6
6
  # RoadmapSmith Update
@@ -10,8 +10,9 @@ Use this command when the user wants the direct sync surface without routing thr
10
10
  ## Required behavior
11
11
 
12
12
  1. Prefer the local engine inside this repository:
13
- - `node roadmap-skill/bin/cli.js sync --project-root .`
14
- - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js sync --project-root .` if `node` is not in PATH
15
- 2. Otherwise prefer `roadmapsmith sync --project-root .`.
13
+ - `node roadmap-skill/bin/cli.js update --project-root .`
14
+ - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js update --project-root .` if `node` is not in PATH
15
+ 2. Otherwise prefer `roadmapsmith update --project-root .`. If that global shim fails because `node` is not in PATH, run `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" update --project-root .`.
16
16
  3. Explain that `/roadmap-update` is the visible namespaced sync command, while `/roadmap-sync <action>` remains legacy compatibility.
17
- 4. Keep the evidence-backed sync semantics unchanged: sync updates checklist state from repository evidence; it is not a full regeneration path.
17
+ 4. Keep the evidence-backed sync semantics unchanged: no-argument update syncs the roadmap from repository evidence; it is not a full regeneration path.
18
+ 5. To complete one task, run `roadmapsmith update --task <stable-id> --evidence "<single-line evidence>"`. It writes only after the supplied evidence validates at high confidence; use `--dry-run` to preview it.
package/skills.json CHANGED
@@ -10,86 +10,85 @@
10
10
  ],
11
11
  "usageExamples": [
12
12
  "npx skills add PapiScholz/roadmapsmith --skill '*' -a claude-code",
13
- "npx skills add PapiScholz/roadmapsmith --skill roadmap-sync",
14
13
  "roadmapsmith setup",
15
14
  "roadmapsmith zero",
16
15
  "roadmapsmith maintain",
17
16
  "roadmapsmith /roadmap",
18
- "roadmapsmith /roadmap-update",
17
+ "roadmapsmith update --task p2-customer-history --evidence \"src/app/api/customers/route.ts, test/customers.test.js\"",
19
18
  "roadmapsmith validate --json"
20
19
  ],
21
20
  "install": {
22
21
  "command": "npx skills add PapiScholz/roadmapsmith --skill '*' -a claude-code",
23
22
  "source": "PapiScholz/roadmapsmith",
24
23
  "skill": "*",
25
- "notes": "Recommended Claude Code install path for native GUI slash commands like /roadmap, /roadmap-zero, /roadmap-maintain, /roadmap-status, /roadmap-init, /roadmap-generate, /roadmap-validate, /roadmap-update, /roadmap-audit, and /roadmap-setup. The legacy /roadmap-sync root remains available for compatibility, especially as /roadmap-sync <action>. Install the roadmapsmith CLI separately for actual command execution; roadmapsmith status is the visible readiness command and roadmapsmith doctor remains a compatibility alias. Then run /reload-skills and, if applicable, /reload-plugins. Codex native plugin installs use the repo/package .codex-plugin surface instead of this Claude-specific skills CLI path."
24
+ "notes": "Recommended Claude Code install path for native GUI slash commands like /roadmap, /roadmap-zero, /roadmap-maintain, /roadmap-status, /roadmap-init, /roadmap-generate, /roadmap-validate, /roadmap-update, /roadmap-audit, and /roadmap-setup. DEPRECATED: /roadmap-sync remains only as a compatibility root for existing automation; use /roadmap-maintain or /roadmap-update for new workflows. Install the roadmapsmith CLI separately for actual command execution; roadmapsmith status is the visible readiness command and roadmapsmith doctor remains a compatibility alias. Then run /reload-skills and, if applicable, /reload-plugins. Codex native plugin installs use the repo/package .codex-plugin surface instead of this Claude-specific skills CLI path."
26
25
  },
27
26
  "skills": [
28
27
  {
29
28
  "name": "roadmap",
30
29
  "path": "skills/roadmap",
31
30
  "description": "Native slash palette for RoadmapSmith commands and recommended entrypoints across supported hosts.",
32
- "version": "0.9.27"
31
+ "version": "0.9.28"
33
32
  },
34
33
  {
35
34
  "name": "roadmap-zero",
36
35
  "path": "skills/roadmap-zero",
37
36
  "description": "Native slash entrypoint for the one-command Zero Mode CLI workflow.",
38
- "version": "0.9.27"
37
+ "version": "0.9.28"
39
38
  },
40
39
  {
41
40
  "name": "roadmap-maintain",
42
41
  "path": "skills/roadmap-maintain",
43
42
  "description": "Native slash entrypoint for the preserve-first generate + sync + audit flow.",
44
- "version": "0.9.27"
43
+ "version": "0.9.28"
45
44
  },
46
45
  {
47
46
  "name": "roadmap-status",
48
47
  "path": "skills/roadmap-status",
49
48
  "description": "Native slash readiness check grounded in roadmapsmith status JSON.",
50
- "version": "0.9.27"
49
+ "version": "0.9.28"
51
50
  },
52
51
  {
53
52
  "name": "roadmap-init",
54
53
  "path": "skills/roadmap-init",
55
54
  "description": "Native slash entrypoint for creating ROADMAP.md and AGENTS.md.",
56
- "version": "0.9.27"
55
+ "version": "0.9.28"
57
56
  },
58
57
  {
59
58
  "name": "roadmap-generate",
60
59
  "path": "skills/roadmap-generate",
61
60
  "description": "Native slash entrypoint for managed roadmap updates that require --full-regen before destructive replacement.",
62
- "version": "0.9.27"
61
+ "version": "0.9.28"
63
62
  },
64
63
  {
65
64
  "name": "roadmap-validate",
66
65
  "path": "skills/roadmap-validate",
67
66
  "description": "Native slash entrypoint for evidence-backed roadmap validation.",
68
- "version": "0.9.27"
67
+ "version": "0.9.28"
69
68
  },
70
69
  {
71
70
  "name": "roadmap-update",
72
71
  "path": "skills/roadmap-update",
73
- "description": "Native slash entrypoint for applying evidence-backed checklist sync.",
74
- "version": "0.9.27"
72
+ "description": "Native slash entrypoint for evidence-backed sync and verified single-task completion.",
73
+ "version": "0.9.28"
75
74
  },
76
75
  {
77
76
  "name": "roadmap-sync",
78
77
  "path": "skills/roadmap-sync",
79
- "description": "Legacy namespaced root plus policy guidance for RoadmapSmith slash workflows.",
80
- "version": "0.9.27"
78
+ "description": "DEPRECATED legacy compatibility root; use roadmap-maintain or roadmap-update.",
79
+ "version": "0.9.28"
81
80
  },
82
81
  {
83
82
  "name": "roadmap-audit",
84
83
  "path": "skills/roadmap-audit",
85
84
  "description": "Native slash entrypoint for the current sync-plus-audit workflow.",
86
- "version": "0.9.27"
85
+ "version": "0.9.28"
87
86
  },
88
87
  {
89
88
  "name": "roadmap-setup",
90
89
  "path": "skills/roadmap-setup",
91
90
  "description": "Native slash entrypoint for generating RoadmapSmith host integration files.",
92
- "version": "0.9.27"
91
+ "version": "0.9.28"
93
92
  }
94
93
  ]
95
94
  }
package/src/sync/index.js CHANGED
@@ -142,6 +142,18 @@ function applySync(content, parsedTasks, results) {
142
142
  lines.splice(warningIndex, 1);
143
143
  offset -= 1;
144
144
  }
145
+ if (
146
+ result.staleEvidenceResolved &&
147
+ (!Array.isArray(task.evidenceLines) || task.evidenceLines.length === 0) &&
148
+ result.discoveredEvidence
149
+ ) {
150
+ const insertionIndex = Math.max(
151
+ lineIndex + 1,
152
+ (task.lastChildLineIndex + offset) + 1
153
+ );
154
+ lines.splice(insertionIndex, 0, `${task.indent || ''} - Evidence: ${result.discoveredEvidence}`);
155
+ offset += 1;
156
+ }
145
157
  continue;
146
158
  }
147
159
 
@@ -1290,6 +1290,52 @@ function buildValidationContext(projectRoot, config, plugins) {
1290
1290
  };
1291
1291
  }
1292
1292
 
1293
+ function diagnosticCodeForReason(reason) {
1294
+ const normalized = String(reason || '').toLowerCase();
1295
+ if (normalized.includes('missing referenced file') || normalized.includes('evidence file(s) not found')) {
1296
+ return 'MISSING_REFERENCE';
1297
+ }
1298
+ if (normalized.includes('missing test evidence')) {
1299
+ return 'NO_TEST';
1300
+ }
1301
+ if (
1302
+ normalized.includes('no code, test, or artifact evidence found') ||
1303
+ normalized.includes('implementation task requires evidence line') ||
1304
+ normalized.includes('weak path') ||
1305
+ normalized.includes('file reference shows implementation location')
1306
+ ) {
1307
+ return 'NOT_IMPLEMENTED';
1308
+ }
1309
+ return null;
1310
+ }
1311
+
1312
+ function buildDiagnostics(reasons, options = {}) {
1313
+ const diagnostics = [];
1314
+ const seen = new Set();
1315
+ for (const reason of Array.isArray(reasons) ? reasons : []) {
1316
+ const code = diagnosticCodeForReason(reason);
1317
+ if (!code || seen.has(code)) {
1318
+ continue;
1319
+ }
1320
+ seen.add(code);
1321
+ diagnostics.push({ code, severity: 'error', message: reason });
1322
+ }
1323
+ if (options.staleEvidence) {
1324
+ diagnostics.push({
1325
+ code: 'STALE_EVIDENCE',
1326
+ severity: 'warning',
1327
+ message: 'historical validation warning conflicts with fresh repository evidence'
1328
+ });
1329
+ }
1330
+ return diagnostics;
1331
+ }
1332
+
1333
+ function buildDiscoveredEvidenceLine(evidence) {
1334
+ const files = unionArrays(evidence.codeFiles, evidence.testFiles)
1335
+ .sort((left, right) => left.localeCompare(right));
1336
+ return files.length > 0 ? files.join(', ') : null;
1337
+ }
1338
+
1293
1339
  function validateTask(task, context, config, plugins) {
1294
1340
  const {
1295
1341
  paths: pathHints,
@@ -1467,8 +1513,15 @@ function validateTask(task, context, config, plugins) {
1467
1513
  // evidence, artifact evidence, or strong code+test threshold to pass.
1468
1514
  // Already-checked tasks with found path hints are preserved via shouldPreserveCheckedTask.
1469
1515
  const hasHighConfidenceImplementationEvidence = meetsStrongThreshold && evidence.code && evidence.test;
1516
+ const hasFreshRepositoryEvidence = hasStrongEvidence || hasWeakEvidence;
1517
+ let staleEvidenceDetected = false;
1518
+ let staleEvidenceResolved = false;
1470
1519
  let passed = authoritativeEvidence.passed || hasArtifactTaskPass || hasTrustedRuleEvidencePass || meetsStrongThreshold;
1471
1520
 
1521
+ if (task.warningText && !task.checked && hasFreshRepositoryEvidence && !authoritativeEvidence.passed) {
1522
+ staleEvidenceDetected = true;
1523
+ }
1524
+
1472
1525
  if (!passed && !task.checked && hasDirectReferencePass) {
1473
1526
  const locationReason = 'file reference shows implementation location, not confirmed completion';
1474
1527
  if (!uniqueReasons.includes(locationReason)) {
@@ -1476,13 +1529,15 @@ function validateTask(task, context, config, plugins) {
1476
1529
  }
1477
1530
  }
1478
1531
 
1479
- // Unchecked tasks with an existing ⚠️ warning are preserved as failing unless an Evidence line
1480
- // explicitly confirms implementation. meetsStrongThreshold (token match) cannot override a
1481
- // human/agent judgment that the feature is incomplete.
1532
+ // Historical warnings are only cleared by independent, high-confidence repository evidence.
1482
1533
  if (task.warningText && !task.checked && passed && !authoritativeEvidence.passed) {
1483
- passed = false;
1484
- if (uniqueReasons.length === 0) {
1485
- uniqueReasons.push('validation failed');
1534
+ if (hasHighConfidenceImplementationEvidence && negativeSignalMatches.length === 0 && uniqueReasons.length === 0) {
1535
+ staleEvidenceResolved = true;
1536
+ } else {
1537
+ passed = false;
1538
+ if (uniqueReasons.length === 0) {
1539
+ uniqueReasons.push('validation failed');
1540
+ }
1486
1541
  }
1487
1542
  }
1488
1543
  if (negativeSignalMatches.length > 0) {
@@ -1533,17 +1588,21 @@ function validateTask(task, context, config, plugins) {
1533
1588
  // Used by auditValidation to flag implementation tasks that pass solely via documentation.
1534
1589
  const evidenceIsDocOnly = !evidence.code && !evidence.test && evidence.artifact && !isDocTask(task.text);
1535
1590
 
1591
+ const finalPassed = overrideResult ? overrideResult.passed !== false : (passed && uniqueReasons.length === 0);
1536
1592
  return {
1537
1593
  taskId: task.id,
1538
- passed: overrideResult ? overrideResult.passed !== false : (passed && uniqueReasons.length === 0),
1594
+ passed: finalPassed,
1539
1595
  confidence,
1540
1596
  reasons: uniqueReasons,
1597
+ diagnostics: buildDiagnostics(uniqueReasons, { staleEvidence: staleEvidenceDetected }),
1541
1598
  evidence,
1542
1599
  evidenceIsDocOnly,
1543
1600
  requiresTest,
1544
1601
  hasEvidence: hasStrongEvidence || hasWeakEvidence,
1545
1602
  attempted,
1546
- preservedCheckedState
1603
+ preservedCheckedState,
1604
+ staleEvidenceResolved,
1605
+ discoveredEvidence: staleEvidenceResolved ? buildDiscoveredEvidenceLine(evidence) : null
1547
1606
  };
1548
1607
  }
1549
1608