@nerviq/cli 1.9.0 → 1.10.0

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,168 +1,168 @@
1
- /**
2
- * Aider Freshness Operationalization
3
- *
4
- * Release gates, recurring probes, propagation checklists,
5
- * and staleness blocking for Aider surfaces.
6
- */
7
-
8
- const { version } = require('../../package.json');
9
-
10
- /**
11
- * P0 sources that must be fresh before any Aider release claim.
12
- */
13
- const P0_SOURCES = [
14
- {
15
- key: 'aider-docs',
16
- label: 'Aider Official Docs',
17
- url: 'https://aider.chat',
18
- stalenessThresholdDays: 30,
19
- verifiedAt: null,
20
- },
21
- {
22
- key: 'aider-config-reference',
23
- label: 'Aider Config Reference',
24
- url: 'https://aider.chat/docs/config/aider_conf.html',
25
- stalenessThresholdDays: 30,
26
- verifiedAt: null,
27
- },
28
- {
29
- key: 'aider-github-releases',
30
- label: 'Aider GitHub Releases',
31
- url: 'https://github.com/paul-gauthier/aider/releases',
32
- stalenessThresholdDays: 14,
33
- verifiedAt: null,
34
- },
35
- {
36
- key: 'aider-model-docs',
37
- label: 'Aider Model Documentation',
38
- url: 'https://aider.chat/docs/llms.html',
39
- stalenessThresholdDays: 30,
40
- verifiedAt: null,
41
- },
42
- {
43
- key: 'aider-pypi',
44
- label: 'Aider PyPI Package',
45
- url: 'https://pypi.org/project/aider-chat/',
46
- stalenessThresholdDays: 14,
47
- verifiedAt: null,
48
- },
49
- ];
50
-
51
- /**
52
- * Propagation checklist: when an Aider source changes, these must update.
53
- */
54
- const PROPAGATION_CHECKLIST = [
55
- {
56
- trigger: 'Aider release with new config keys',
57
- targets: [
58
- 'src/aider/techniques.js — update checks for new keys',
59
- 'src/aider/config-parser.js — update if YAML handling changes',
60
- 'src/aider/setup.js — update generated .aider.conf.yml template',
61
- ],
62
- },
63
- {
64
- trigger: 'New Aider model support or role changes',
65
- targets: [
66
- 'src/aider/techniques.js — update model config checks',
67
- 'src/aider/context.js — update modelRoles()',
68
- 'src/aider/governance.js — update policy packs if needed',
69
- ],
70
- },
71
- {
72
- trigger: 'New Aider edit format or architect changes',
73
- targets: [
74
- 'src/aider/techniques.js — update edit format checks',
75
- 'src/aider/setup.js — update template comments',
76
- ],
77
- },
78
- {
79
- trigger: 'Aider CLI flag changes (renamed/removed)',
80
- targets: [
81
- 'src/aider/techniques.js — update flag pattern matching',
82
- 'src/aider/setup.js — update generated config',
83
- 'src/aider/interactive.js — update wizard options',
84
- ],
85
- },
86
- {
87
- trigger: 'Aider domain pack definitions change',
88
- targets: [
89
- 'src/aider/domain-packs.js — update pack registry',
90
- 'src/aider/governance.js — governance export picks up changes',
91
- ],
92
- },
93
- ];
94
-
95
- /**
96
- * Check release gate — are all P0 sources fresh?
97
- */
98
- function checkReleaseGate(overrides = {}) {
99
- const now = new Date();
100
- const results = P0_SOURCES.map(source => {
101
- const verifiedAt = overrides[source.key] || source.verifiedAt;
102
- if (!verifiedAt) {
103
- return { ...source, status: 'unverified', daysStale: null };
104
- }
105
-
106
- const verifiedDate = new Date(verifiedAt);
107
- const daysSince = Math.floor((now - verifiedDate) / (1000 * 60 * 60 * 24));
108
-
109
- return {
110
- ...source,
111
- verifiedAt,
112
- status: daysSince <= source.stalenessThresholdDays ? 'fresh' : 'stale',
113
- daysStale: daysSince,
114
- };
115
- });
116
-
117
- const allFresh = results.every(r => r.status === 'fresh');
118
-
119
- return {
120
- ready: allFresh,
121
- results,
122
- nerviqVersion: version,
123
- checkedAt: now.toISOString(),
124
- };
125
- }
126
-
127
- /**
128
- * Format release gate for display.
129
- */
130
- function formatReleaseGate(overrides = {}) {
131
- const gateResult = checkReleaseGate(overrides);
132
- const lines = [
133
- `Aider Release Freshness Gate (nerviq v${version})`,
134
- `Status: ${gateResult.ready ? 'READY' : 'NOT READY'}`,
135
- '',
136
- ];
137
-
138
- for (const result of gateResult.results) {
139
- const icon = result.status === 'fresh' ? '✓' : result.status === 'stale' ? '✗' : '?';
140
- const age = result.daysStale !== null ? ` (${result.daysStale}d ago)` : ' (unverified)';
141
- lines.push(` ${icon} ${result.label}${age} — threshold: ${result.stalenessThresholdDays}d`);
142
- }
143
-
144
- if (!gateResult.ready) {
145
- lines.push('');
146
- lines.push('Action required: verify stale/unverified sources before claiming release freshness.');
147
- }
148
-
149
- return lines.join('\n');
150
- }
151
-
152
- /**
153
- * Get propagation targets for a given trigger.
154
- */
155
- function getPropagationTargets(triggerKeyword) {
156
- const keyword = triggerKeyword.toLowerCase();
157
- return PROPAGATION_CHECKLIST.filter(item =>
158
- item.trigger.toLowerCase().includes(keyword)
159
- );
160
- }
161
-
162
- module.exports = {
163
- P0_SOURCES,
164
- PROPAGATION_CHECKLIST,
165
- checkReleaseGate,
166
- formatReleaseGate,
167
- getPropagationTargets,
168
- };
1
+ /**
2
+ * Aider Freshness Operationalization
3
+ *
4
+ * Release gates, recurring probes, propagation checklists,
5
+ * and staleness blocking for Aider surfaces.
6
+ */
7
+
8
+ const { version } = require('../../package.json');
9
+
10
+ /**
11
+ * P0 sources that must be fresh before any Aider release claim.
12
+ */
13
+ const P0_SOURCES = [
14
+ {
15
+ key: 'aider-docs',
16
+ label: 'Aider Official Docs',
17
+ url: 'https://aider.chat',
18
+ stalenessThresholdDays: 30,
19
+ verifiedAt: '2026-04-08',
20
+ },
21
+ {
22
+ key: 'aider-config-reference',
23
+ label: 'Aider Config Reference',
24
+ url: 'https://aider.chat/docs/config/aider_conf.html',
25
+ stalenessThresholdDays: 30,
26
+ verifiedAt: '2026-04-08',
27
+ },
28
+ {
29
+ key: 'aider-github-releases',
30
+ label: 'Aider GitHub Releases',
31
+ url: 'https://github.com/Aider-AI/aider/releases',
32
+ stalenessThresholdDays: 14,
33
+ verifiedAt: '2026-04-08',
34
+ },
35
+ {
36
+ key: 'aider-model-docs',
37
+ label: 'Aider Model Documentation',
38
+ url: 'https://aider.chat/docs/llms.html',
39
+ stalenessThresholdDays: 30,
40
+ verifiedAt: '2026-04-08',
41
+ },
42
+ {
43
+ key: 'aider-pypi',
44
+ label: 'Aider PyPI Package',
45
+ url: 'https://pypi.org/project/aider-chat/',
46
+ stalenessThresholdDays: 14,
47
+ verifiedAt: '2026-04-08',
48
+ },
49
+ ];
50
+
51
+ /**
52
+ * Propagation checklist: when an Aider source changes, these must update.
53
+ */
54
+ const PROPAGATION_CHECKLIST = [
55
+ {
56
+ trigger: 'Aider release with new config keys',
57
+ targets: [
58
+ 'src/aider/techniques.js — update checks for new keys',
59
+ 'src/aider/config-parser.js — update if YAML handling changes',
60
+ 'src/aider/setup.js — update generated .aider.conf.yml template',
61
+ ],
62
+ },
63
+ {
64
+ trigger: 'New Aider model support or role changes',
65
+ targets: [
66
+ 'src/aider/techniques.js — update model config checks',
67
+ 'src/aider/context.js — update modelRoles()',
68
+ 'src/aider/governance.js — update policy packs if needed',
69
+ ],
70
+ },
71
+ {
72
+ trigger: 'New Aider edit format or architect changes',
73
+ targets: [
74
+ 'src/aider/techniques.js — update edit format checks',
75
+ 'src/aider/setup.js — update template comments',
76
+ ],
77
+ },
78
+ {
79
+ trigger: 'Aider CLI flag changes (renamed/removed)',
80
+ targets: [
81
+ 'src/aider/techniques.js — update flag pattern matching',
82
+ 'src/aider/setup.js — update generated config',
83
+ 'src/aider/interactive.js — update wizard options',
84
+ ],
85
+ },
86
+ {
87
+ trigger: 'Aider domain pack definitions change',
88
+ targets: [
89
+ 'src/aider/domain-packs.js — update pack registry',
90
+ 'src/aider/governance.js — governance export picks up changes',
91
+ ],
92
+ },
93
+ ];
94
+
95
+ /**
96
+ * Check release gate — are all P0 sources fresh?
97
+ */
98
+ function checkReleaseGate(overrides = {}) {
99
+ const now = new Date();
100
+ const results = P0_SOURCES.map(source => {
101
+ const verifiedAt = overrides[source.key] || source.verifiedAt;
102
+ if (!verifiedAt) {
103
+ return { ...source, status: 'unverified', daysStale: null };
104
+ }
105
+
106
+ const verifiedDate = new Date(verifiedAt);
107
+ const daysSince = Math.floor((now - verifiedDate) / (1000 * 60 * 60 * 24));
108
+
109
+ return {
110
+ ...source,
111
+ verifiedAt,
112
+ status: daysSince <= source.stalenessThresholdDays ? 'fresh' : 'stale',
113
+ daysStale: daysSince,
114
+ };
115
+ });
116
+
117
+ const allFresh = results.every(r => r.status === 'fresh');
118
+
119
+ return {
120
+ ready: allFresh,
121
+ results,
122
+ nerviqVersion: version,
123
+ checkedAt: now.toISOString(),
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Format release gate for display.
129
+ */
130
+ function formatReleaseGate(overrides = {}) {
131
+ const gateResult = checkReleaseGate(overrides);
132
+ const lines = [
133
+ `Aider Release Freshness Gate (nerviq v${version})`,
134
+ `Status: ${gateResult.ready ? 'READY' : 'NOT READY'}`,
135
+ '',
136
+ ];
137
+
138
+ for (const result of gateResult.results) {
139
+ const icon = result.status === 'fresh' ? '✓' : result.status === 'stale' ? '✗' : '?';
140
+ const age = result.daysStale !== null ? ` (${result.daysStale}d ago)` : ' (unverified)';
141
+ lines.push(` ${icon} ${result.label}${age} — threshold: ${result.stalenessThresholdDays}d`);
142
+ }
143
+
144
+ if (!gateResult.ready) {
145
+ lines.push('');
146
+ lines.push('Action required: verify stale/unverified sources before claiming release freshness.');
147
+ }
148
+
149
+ return lines.join('\n');
150
+ }
151
+
152
+ /**
153
+ * Get propagation targets for a given trigger.
154
+ */
155
+ function getPropagationTargets(triggerKeyword) {
156
+ const keyword = triggerKeyword.toLowerCase();
157
+ return PROPAGATION_CHECKLIST.filter(item =>
158
+ item.trigger.toLowerCase().includes(keyword)
159
+ );
160
+ }
161
+
162
+ module.exports = {
163
+ P0_SOURCES,
164
+ PROPAGATION_CHECKLIST,
165
+ checkReleaseGate,
166
+ formatReleaseGate,
167
+ getPropagationTargets,
168
+ };
@@ -3,7 +3,11 @@
3
3
  * Provides a static catalog and a runtime detector that checks a project context.
4
4
  */
5
5
 
6
- const path = require('path');
6
+ const {
7
+ getRepoInstructionBundle,
8
+ hasDocumentedVerificationGuidance,
9
+ hasDocumentedTestCommand,
10
+ } = require('./instruction-surfaces');
7
11
 
8
12
  const ANTI_PATTERNS = [
9
13
  {
@@ -93,15 +97,13 @@ const ANTI_PATTERNS = [
93
97
  id: 'AP007',
94
98
  name: 'No verification commands',
95
99
  severity: 'medium',
96
- description: 'Without test, lint, or build commands in CLAUDE.md, the agent cannot self-verify its changes.',
100
+ description: 'Without test, lint, or build commands across the repo instruction surfaces, agents cannot self-verify changes consistently.',
97
101
  platforms: ['claude', 'codex', 'cursor', 'windsurf', 'copilot', 'gemini', 'aider', 'opencode'],
98
- fix: 'Add ## Verification Commands section with test, lint, and build commands to your instruction file.',
102
+ fix: 'Add a canonical verification section or command doc in your repo instruction surfaces (for example CLAUDE.md, AGENTS.md, README, or platform rules).',
99
103
  detect: (ctx) => {
100
- const content = ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md') || '';
104
+ const content = getRepoInstructionBundle(ctx);
101
105
  if (!content) return false;
102
- const hasVerification = /\b(test|lint|build|check|verify)\b/i.test(content) &&
103
- /\b(npm |yarn |pnpm |pytest|cargo |go |make )/i.test(content);
104
- return !hasVerification;
106
+ return !hasDocumentedVerificationGuidance(content);
105
107
  },
106
108
  },
107
109
  {
@@ -203,13 +205,13 @@ const ANTI_PATTERNS = [
203
205
  id: 'AP014',
204
206
  name: 'No test command defined',
205
207
  severity: 'medium',
206
- description: 'Without a test command, the agent cannot verify its changes work before presenting them for review.',
208
+ description: 'Without a canonical test command in repo instructions or scripts, agents cannot verify changes reliably before handoff.',
207
209
  platforms: ['claude', 'codex', 'cursor', 'windsurf', 'copilot', 'gemini', 'aider', 'opencode'],
208
- fix: 'Add a test command in your instruction file, e.g., "Test: npm test" or "Test: pytest".',
210
+ fix: 'Add a canonical test command in repo instructions or package scripts, e.g. "Test: npm test" or "Test: pytest".',
209
211
  detect: (ctx) => {
210
- const content = ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md') || '';
212
+ const content = getRepoInstructionBundle(ctx);
211
213
  const pkg = ctx.jsonFile('package.json');
212
- const hasTestInMd = /(?:test|testing)\s*(?:command)?[:\s]+[`"']*(?:npm|yarn|pnpm|pytest|cargo|go|make)\s/i.test(content);
214
+ const hasTestInMd = hasDocumentedTestCommand(content);
213
215
  const hasTestScript = pkg && pkg.scripts && pkg.scripts.test;
214
216
  return !hasTestInMd && !hasTestScript;
215
217
  },
package/src/audit.js CHANGED
@@ -882,7 +882,7 @@ function printLiteAudit(result, dir) {
882
882
  console.log(colorize(` Found: ${result.detectedConfigFiles.join(', ')}`, 'dim'));
883
883
  }
884
884
  console.log('');
885
- console.log(` ${t('audit.score', { score: colorize(`${result.score}/100`, 'bold'), passed: result.passed, total: result.passed + result.failed })}`);
885
+ console.log(` ${t('audit.score', { score: colorize(`${result.score}/100`, 'bold'), passed: result.passed, total: result.passed + result.failed })}`);
886
886
 
887
887
  // Score explanation line (lite mode only)
888
888
  const _critCount = (result.results || []).filter(r => r.passed === false && r.impact === 'critical').length;
@@ -905,10 +905,11 @@ function printLiteAudit(result, dir) {
905
905
  scoreExplanation = t('audit.basic', { category: weakestCategory });
906
906
  } else {
907
907
  scoreExplanation = t('audit.early');
908
- }
909
- console.log(colorize(` ${scoreExplanation}`, 'dim'));
910
-
911
- if (result.platformScopeNote) {
908
+ }
909
+ console.log(colorize(` ${scoreExplanation}`, 'dim'));
910
+ console.log(colorize(' Score type: live repo audit (current files only, not snapshot history or benchmark projection).', 'dim'));
911
+
912
+ if (result.platformScopeNote) {
912
913
  console.log(colorize(` Scope: ${result.platformScopeNote.message}`, 'dim'));
913
914
  }
914
915
  if (result.workspaceHint && result.workspaceHint.workspaces.length > 0) {
@@ -52,23 +52,72 @@ function analyzeSuggestions(dir) {
52
52
  .sort((a, b) => b[1] - a[1])
53
53
  .map(([key, count]) => ({ key, failCount: count, auditCount: auditSnapshots.length }));
54
54
 
55
- return { totalEvents, auditCount: auditSnapshots.length, suggestedRules, suggestedSuppressions, suggestedPriorities };
55
+ const hasSuggestions = suggestedRules.length > 0 || suggestedSuppressions.length > 0 || suggestedPriorities.length > 0;
56
+ let bootstrap = { ready: true, state: 'ready', message: null, steps: [] };
57
+
58
+ if (totalEvents === 0 && auditSnapshots.length === 0) {
59
+ bootstrap = {
60
+ ready: false,
61
+ state: 'empty',
62
+ message: 'No local usage or snapshot history exists yet.',
63
+ steps: [
64
+ 'Run `nerviq audit --snapshot` to save the baseline.',
65
+ 'Use `nerviq fix`, `nerviq fix --all-critical`, or `nerviq feedback` to record recommendation outcomes.',
66
+ 'Run `nerviq audit --snapshot` again after a meaningful repo change.',
67
+ 'Re-run `nerviq suggest-rules`.',
68
+ ],
69
+ };
70
+ } else if (!hasSuggestions && totalEvents === 0 && auditSnapshots.length > 0) {
71
+ bootstrap = {
72
+ ready: false,
73
+ state: 'snapshots-only',
74
+ message: `${auditSnapshots.length} audit snapshot(s) exist, but no recommendation outcomes have been recorded yet.`,
75
+ steps: [
76
+ 'Run `nerviq fix` or `nerviq feedback` so Nerviq can learn which recommendations you accept or reject.',
77
+ 'Re-run `nerviq suggest-rules` after another fix cycle.',
78
+ ],
79
+ };
80
+ } else if (!hasSuggestions && totalEvents > 0 && auditSnapshots.length === 0) {
81
+ bootstrap = {
82
+ ready: false,
83
+ state: 'patterns-only',
84
+ message: `${totalEvents} usage event(s) exist, but no audit snapshots have been saved yet.`,
85
+ steps: [
86
+ 'Run `nerviq audit --snapshot` to save the baseline.',
87
+ 'Run it again after changes so repeated failures can be prioritized.',
88
+ 'Re-run `nerviq suggest-rules`.',
89
+ ],
90
+ };
91
+ } else if (!hasSuggestions) {
92
+ bootstrap = {
93
+ ready: false,
94
+ state: 'warming-up',
95
+ message: `Nerviq has some local history (${totalEvents} pattern events, ${auditSnapshots.length} audit snapshots), but not enough repeated signals yet.`,
96
+ steps: [
97
+ 'Keep saving snapshots with `nerviq audit --snapshot`.',
98
+ 'Keep recording outcomes with `nerviq fix` or `nerviq feedback`.',
99
+ 'Re-run `nerviq suggest-rules` after another change cycle.',
100
+ ],
101
+ };
102
+ }
103
+
104
+ return { totalEvents, auditCount: auditSnapshots.length, suggestedRules, suggestedSuppressions, suggestedPriorities, bootstrap };
56
105
  }
57
106
 
58
107
  /**
59
108
  * Format suggestions for CLI output.
60
109
  */
61
110
  function formatSuggestions(suggestions) {
62
- const { totalEvents, auditCount, suggestedRules, suggestedSuppressions, suggestedPriorities } = suggestions;
63
-
64
- if (totalEvents === 0 && auditCount === 0) {
65
- return ' No usage data yet. Run nerviq fix or nerviq audit to build pattern history.';
66
- }
111
+ const { totalEvents, auditCount, suggestedRules, suggestedSuppressions, suggestedPriorities, bootstrap } = suggestions;
67
112
 
68
113
  const sources = [];
69
114
  if (totalEvents > 0) sources.push(`${totalEvents} pattern events`);
70
115
  if (auditCount > 0) sources.push(`${auditCount} audit snapshots`);
71
- const lines = [` Auto-Suggested Rules (based on ${sources.join(', ')}):`];
116
+ const lines = [
117
+ sources.length > 0
118
+ ? ` Auto-Suggested Rules (based on ${sources.join(', ')}):`
119
+ : ' Auto-Suggested Rules:',
120
+ ];
72
121
 
73
122
  if (suggestedRules.length > 0) {
74
123
  lines.push('', ' Suggested as required (always accepted):');
@@ -91,8 +140,12 @@ function formatSuggestions(suggestions) {
91
140
  }
92
141
  }
93
142
 
94
- if (suggestedRules.length === 0 && suggestedSuppressions.length === 0 && suggestedPriorities.length === 0) {
95
- lines.push('', ' No strong patterns detected yet. Keep using nerviq fix and audit to build history.');
143
+ if (suggestedRules.length === 0 && suggestedSuppressions.length === 0 && suggestedPriorities.length === 0 && bootstrap && !bootstrap.ready) {
144
+ lines.push('', ` ${bootstrap.message}`);
145
+ lines.push(' Bootstrap it with:');
146
+ for (let i = 0; i < bootstrap.steps.length; i++) {
147
+ lines.push(` ${i + 1}. ${bootstrap.steps[i]}`);
148
+ }
96
149
  }
97
150
 
98
151
  return lines.join('\n');
package/src/benchmark.js CHANGED
@@ -201,31 +201,36 @@ function buildCaseStudy(before, after, applyResult) {
201
201
  };
202
202
  }
203
203
 
204
- function renderBenchmarkMarkdown(report) {
205
- return [
206
- '# NERVIQ CLI Benchmark Report',
207
- '',
208
- `- Generated by: ${report.generatedBy}`,
209
- `- Created at: ${report.createdAt}`,
210
- `- Source repo: ${report.directory}`,
211
- '',
212
- '## Methodology',
213
- ...report.methodology.map(item => `- ${item}`),
214
- '',
215
- '## Before',
216
- `- Score: ${report.before.score}/100`,
217
- `- Organic score: ${report.before.organicScore}/100`,
218
- `- Passing checks: ${report.before.passed}/${report.before.checkCount}`,
219
- '',
220
- '## After',
221
- `- Score: ${report.after.score}/100`,
222
- `- Organic score: ${report.after.organicScore}/100`,
223
- `- Passing checks: ${report.after.passed}/${report.after.checkCount}`,
224
- '',
225
- '## Delta',
226
- `- Score delta: ${report.delta.score}`,
227
- `- Organic score delta: ${report.delta.organicScore}`,
228
- `- Passed checks delta: ${report.delta.passed}`,
204
+ function renderBenchmarkMarkdown(report) {
205
+ return [
206
+ '# NERVIQ CLI Benchmark Report',
207
+ '',
208
+ `- Generated by: ${report.generatedBy}`,
209
+ `- Created at: ${report.createdAt}`,
210
+ `- Source repo: ${report.directory}`,
211
+ '',
212
+ '## Score Semantics',
213
+ `- Baseline live audit score: ${report.scoreSemantics.baseline}`,
214
+ `- Projected benchmark score: ${report.scoreSemantics.projected}`,
215
+ `- Organic score: ${report.scoreSemantics.organic}`,
216
+ '',
217
+ '## Methodology',
218
+ ...report.methodology.map(item => `- ${item}`),
219
+ '',
220
+ '## Baseline (Live Repo)',
221
+ `- Live audit score: ${report.before.score}/100`,
222
+ `- Organic live score: ${report.before.organicScore}/100`,
223
+ `- Passing checks: ${report.before.passed}/${report.before.checkCount}`,
224
+ '',
225
+ '## Projected (Isolated Benchmark Copy)',
226
+ `- Projected benchmark score: ${report.after.score}/100`,
227
+ `- Projected organic score: ${report.after.organicScore}/100`,
228
+ `- Passing checks: ${report.after.passed}/${report.after.checkCount}`,
229
+ '',
230
+ '## Delta',
231
+ `- Projected score delta: ${report.delta.score}`,
232
+ `- Projected organic score delta: ${report.delta.organicScore}`,
233
+ `- Passed checks delta: ${report.delta.passed}`,
229
234
  '',
230
235
  '## Executive Summary',
231
236
  `- ${report.executiveSummary.headline}`,
@@ -285,9 +290,14 @@ async function runBenchmark(options) {
285
290
  schemaVersion: 1,
286
291
  generatedBy: `nerviq@${version}`,
287
292
  createdAt: new Date().toISOString(),
288
- directory: sourceDir,
289
- platform,
290
- methodology: [
293
+ directory: sourceDir,
294
+ platform,
295
+ scoreSemantics: {
296
+ baseline: 'current repo state before benchmark runs',
297
+ projected: 'starter-safe post-setup score measured on an isolated temp copy',
298
+ organic: 'repo-owned config quality excluding starter-generated Nerviq assets',
299
+ },
300
+ methodology: [
291
301
  'Run a baseline audit on the source repo.',
292
302
  'Copy the repo into a temporary isolated workspace.',
293
303
  `Apply starter-safe ${platform === 'codex' ? 'Codex' : 'Claude'} artifacts only on the isolated copy.`,
@@ -316,19 +326,20 @@ function printBenchmark(report, options = {}) {
316
326
  return;
317
327
  }
318
328
 
319
- console.log('');
320
- console.log(' nerviq benchmark');
321
- console.log(' ═══════════════════════════════════════');
322
- console.log(' Runs in an isolated temp copy. Your current repo is not modified.');
323
- console.log('');
324
- const orgDeltaSign = report.delta.organicScore >= 0 ? '+' : '';
325
- const totalDeltaSign = report.delta.score >= 0 ? '+' : '';
326
- console.log(` Organic improvement: \x1b[1m${orgDeltaSign}${report.delta.organicScore} points\x1b[0m (your actual config quality)`);
327
- console.log(` Total with nerviq setup: ${totalDeltaSign}${report.delta.score} points`);
328
- console.log('');
329
- console.log(` Before: organic ${report.before.organicScore}/100, total ${report.before.score}/100`);
330
- console.log(` After: organic ${report.after.organicScore}/100, total ${report.after.score}/100`);
331
- console.log('');
329
+ console.log('');
330
+ console.log(' nerviq benchmark');
331
+ console.log(' ═══════════════════════════════════════');
332
+ console.log(' Runs in an isolated temp copy. Your current repo is not modified.');
333
+ console.log(' Score type: baseline = live repo audit, projected = isolated post-setup benchmark.');
334
+ console.log('');
335
+ const orgDeltaSign = report.delta.organicScore >= 0 ? '+' : '';
336
+ const totalDeltaSign = report.delta.score >= 0 ? '+' : '';
337
+ console.log(` Projected organic delta: \x1b[1m${orgDeltaSign}${report.delta.organicScore} points\x1b[0m (repo-owned config quality)`);
338
+ console.log(` Projected total delta with nerviq setup: ${totalDeltaSign}${report.delta.score} points`);
339
+ console.log('');
340
+ console.log(` Baseline live audit: organic ${report.before.organicScore}/100, total ${report.before.score}/100`);
341
+ console.log(` Projected after setup: organic ${report.after.organicScore}/100, total ${report.after.score}/100`);
342
+ console.log('');
332
343
  console.log(` ${report.executiveSummary.headline}`);
333
344
  console.log(` Recommendation: ${report.executiveSummary.decisionGuidance}`);
334
345
  console.log(` Workflow evidence: ${report.workflowEvidence.summary.passed}/${report.workflowEvidence.summary.total} tasks (${report.workflowEvidence.summary.coverageScore}%)`);