Merge branch 'pr-1585' into integration/validation-batch

This commit is contained in:
Alex Newman
2026-04-06 14:18:28 -07:00
2 changed files with 41 additions and 15 deletions
+35 -14
View File
@@ -94,9 +94,12 @@ function getTrackedFolders(workingDir: string): Set<string> {
const absPath = path.join(workingDir, file); const absPath = path.join(workingDir, file);
let dir = path.dirname(absPath); let dir = path.dirname(absPath);
// Add all parent directories up to (but not including) the working dir // Add all parent directories up to and including the working dir itself.
while (dir.length > workingDir.length && dir.startsWith(workingDir)) { // The working dir is included so that root-level files (stored in the DB
// as bare filenames with no directory component) can be matched. Fixes #1514.
while (dir.length >= workingDir.length && dir.startsWith(workingDir)) {
folders.add(dir); folders.add(dir);
if (dir === workingDir) break;
dir = path.dirname(dir); dir = path.dirname(dir);
} }
} }
@@ -164,19 +167,37 @@ function findObservationsByFolder(db: Database, relativeFolderPath: string, proj
// Query more results than needed since we'll filter some out // Query more results than needed since we'll filter some out
const queryLimit = limit * 3; const queryLimit = limit * 3;
const sql = ` // For the root folder (empty relativeFolderPath), observations may have bare
SELECT o.*, o.discovery_tokens // filenames stored without any directory component (e.g. ["dashboard.html"]).
FROM observations o // In that case the LIKE pattern below would never match, so we fetch all
WHERE o.project = ? // observations for the project and let isDirectChild filter to root-level files.
AND (o.files_modified LIKE ? OR o.files_read LIKE ?) // Fixes #1514.
ORDER BY o.created_at_epoch DESC let allMatches: ObservationRow[];
LIMIT ?
`;
// Files in DB are stored as relative paths like "src/services/foo.ts" if (relativeFolderPath === '' || relativeFolderPath === '.') {
// Match any file that starts with this folder path (we'll filter to direct children below) const sql = `
const likePattern = `%"${relativeFolderPath}/%`; SELECT o.*, o.discovery_tokens
const allMatches = db.prepare(sql).all(project, likePattern, likePattern, queryLimit) as ObservationRow[]; FROM observations o
WHERE o.project = ?
AND (o.files_modified IS NOT NULL OR o.files_read IS NOT NULL)
ORDER BY o.created_at_epoch DESC
LIMIT ?
`;
allMatches = db.prepare(sql).all(project, queryLimit) as ObservationRow[];
} else {
const sql = `
SELECT o.*, o.discovery_tokens
FROM observations o
WHERE o.project = ?
AND (o.files_modified LIKE ? OR o.files_read LIKE ?)
ORDER BY o.created_at_epoch DESC
LIMIT ?
`;
// Files in DB are stored as relative paths like "src/services/foo.ts"
// Match any file that starts with this folder path (we'll filter to direct children below)
const likePattern = `%"${relativeFolderPath}/%`;
allMatches = db.prepare(sql).all(project, likePattern, likePattern, queryLimit) as ObservationRow[];
}
// Filter to only observations with direct child files (not in subfolders) // Filter to only observations with direct child files (not in subfolders)
return allMatches.filter(obs => hasDirectChildFile(obs, relativeFolderPath)).slice(0, limit); return allMatches.filter(obs => hasDirectChildFile(obs, relativeFolderPath)).slice(0, limit);
+6 -1
View File
@@ -58,7 +58,12 @@ export function isDirectChild(filePath: string, folderPath: string): boolean {
const folderSegments = normFolder.split('/'); const folderSegments = normFolder.split('/');
const fileSegments = normFile.split('/'); const fileSegments = normFile.split('/');
if (fileSegments.length < 2) return false; // Need at least folder/file // Handle bare filenames (no directory component, e.g. stored as "dashboard.html").
// These are root-level files and are a direct child only of the root folder.
// Fixes #1514: bare filenames stored in DB were never matched by any folder query.
if (fileSegments.length < 2) {
return normFolder === '' || normFolder === '.';
}
const fileDir = fileSegments.slice(0, -1).join('/'); // Directory part of file const fileDir = fileSegments.slice(0, -1).join('/'); // Directory part of file
const fileName = fileSegments[fileSegments.length - 1]; // Actual filename const fileName = fileSegments[fileSegments.length - 1]; // Actual filename