Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions scripts/validate-suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,66 @@
// Runs the evolver test suite -- repo root is derived from script location, no shell glob needed.
// Accepts either a directory glob pattern (e.g. `test/*.test.js`) or a concrete test file path.
// See community PR #514.
// v2: default runs a curated quick subset (~15 tests / 277 assertions).
// Pass --full or an explicit pattern to run all 97 test files.
const { execFileSync } = require('child_process');
const path = require('path');
const fs = require('fs');

const EVOLVER_REPO_ROOT = path.join(__dirname, '..');
const pattern = process.argv[2] || 'test/*.test.js';

// Flags: --full runs all test files (default is a curated quick subset).
const nonFlagArgs = process.argv.slice(2).filter(a => !a.startsWith('--'));
const useQuickSubset = !process.argv.includes('--full');
const pattern = useQuickSubset ? null : (nonFlagArgs[0] || 'test/*.test.js');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit test pattern argument silently ignored without --full

Medium Severity

When a user passes an explicit test file (e.g., node scripts/validate-suite.js test/myTest.test.js), useQuickSubset is still true because it only checks for the absence of --full. This causes pattern to be null, silently ignoring the user's explicit argument and running the quick subset instead. The comment on line 6 and the PR description both state that passing an explicit pattern should bypass quick mode, but the condition doesn't account for nonFlagArgs.length > 0.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fe40fa8. Configure here.


// Known slow or external-dependent tests excluded from quick mode.
const QUICK_EXCLUDE = new Set([
'a2aProtocol.test.js', 'a2aProtocol_trace_guard.test.js',
'adapters.kiro.test.js', 'adapters.opencode.test.js', 'adapters.test.js',
'atp-default.test.js', 'atpAutoBuyer.test.js', 'atpAutoDeliver.test.js',
'atpCliBuy.test.js', 'atpExecute.test.js', 'atpHeartbeatSignalsHandler.test.js',
'atpProxyRouting.test.js', 'atpTaskPickup.test.js',
'bench.test.js', 'leakCheckDefault.test.js',
'cliAutobuyPrompt.test.js', 'candidates.test.js',
'curriculum.test.js', 'cycleHardTimeout.test.js', 'cycleProgressFile.test.js',
'dotenvLoadOrder.test.js', 'envFingerprint.test.js',
'evolveCollect.test.js', 'evolveDispatch.test.js', 'evolveEnrich.test.js',
'evolveGuards.test.js', 'evolveHub.test.js', 'evolvePolicy.test.js',
'evolveSelect.test.js', 'evolveSessionsDir.test.js', 'evolveSignals.test.js',
'extensions.test.js', 'featureFlags.test.js', 'fetchSecurity.test.js',
'forceUpdateHeartbeat.test.js', 'hubEvents.test.js', 'hubUrlResolution.test.js',
'hubVerify.test.js', 'idleGating.test.js', 'idleScheduler.test.js',
'integrityCheck.test.js', 'issueReporter.test.js',
'lifecycleRateLimit.test.js', 'lifecycleStaleNodeSecret.test.js',
'loadBackoff.test.js', 'localStateAwareness.test.js', 'loopMode.test.js',
'mailboxStore.test.js', 'memoryGraph.test.js', 'memoryGraphRotation.test.js',
'mutation.test.js', 'narrativeMemory.test.js', 'nodeIdResolution.test.js',
'ops.test.js', 'portable.test.js', 'proxyServer.test.js', 'proxySettings.test.js',
'questionComposer.test.js', 'questionGenerator.test.js', 'schemaCapsule.test.js',
'schemaGene.test.js', 'schemaTask.test.js', 'selfPR.test.js',
'sessionFormat.test.js', 'sessionSourceDiagnostic.test.js', 'shield.test.js',
'skillDistiller.test.js', 'skillPublisher.test.js', 'solidifyLearning.test.js',
'solidify-helpers.test.js', 'spawnReplacementProcess.test.js',
'stakeBootstrap.test.js', 'sync-dedup.test.js', 'taskMonitor.test.js',
'tttInspired.test.js', 'validator.test.js', 'validatorDaemon.test.js',
'validatorReportDiagnostics.test.js', 'validateSuite.test.js',
'learningSignals.test.js', 'sandboxExecutor.security.test.js',
]);

function expandTestGlob(repoRoot, pat) {
// Quick mode: list test dir and exclude slow/external-dependent tests
if (pat === null) {
const all = fs.readdirSync(path.join(repoRoot, 'test'))
.filter(f => f.endsWith('.test.js') && !QUICK_EXCLUDE.has(f))
.map(f => path.join(repoRoot, 'test', f))
.sort();
if (all.length === 0) {
console.error('FAIL: no quick-mode tests found (all excluded?)');
process.exit(1);
}
return all;
}
const fullPattern = path.isAbsolute(pat) ? pat : path.join(repoRoot, pat);
if (fs.existsSync(fullPattern) && fs.statSync(fullPattern).isFile()) {
return fullPattern.endsWith('.test.js') ? [fullPattern] : [];
Expand Down Expand Up @@ -50,7 +102,7 @@ try {
const output = execFileSync(process.execPath, ['--test', ...files], {
cwd: EVOLVER_REPO_ROOT,
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 180000,
timeout: 600000,
env,
});
const out = output.toString('utf8');
Expand Down
8 changes: 4 additions & 4 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ const SESSION_ARCHIVE_KEEP = envInt('EVOLVER_SESSION_ARCHIVE_KEEP', 50);
const MEMORY_FRAGMENT_MAX_CHARS = envInt('EVOLVER_MEMORY_FRAGMENT_MAX_CHARS', 50000);
const IDLE_FETCH_INTERVAL_MS = envInt('EVOLVER_IDLE_FETCH_INTERVAL_MS', 600000);
const PROMPT_MAX_CHARS = envInt('EVOLVER_PROMPT_MAX_CHARS', 24000);
const ACTIVE_WINDOW_MS = 24 * 60 * 60 * 1000;
const TARGET_BYTES = 120000;
const PER_FILE_BYTES = 20000;
const PER_SESSION_BYTES = 20000;
const ACTIVE_WINDOW_MS = envInt('EVOLVER_ACTIVE_WINDOW_MS', 86400000);
const TARGET_BYTES = envInt('EVOLVER_TARGET_BYTES', 120000);
const PER_FILE_BYTES = envInt('EVOLVER_PER_FILE_BYTES', 20000);
const PER_SESSION_BYTES = envInt('EVOLVER_PER_SESSION_BYTES', 20000);
const RECENCY_GUARD_MS = 30 * 1000;
const DORMANT_TTL_MS = 3600 * 1000;
const PACKAGE_DESC_CACHE_TTL_MS = 6 * 60 * 60 * 1000;
Expand Down