fix(recent-projects): keep codex partial warning only for empty results
Large Codex histories routinely hit the scan budget while still returning useful project candidates, so the detailed "partial" warning was firing on healthy degraded runs. Only warn when a degraded scan yields zero candidates; otherwise the run is logged at info level with the degraded flag.
This commit is contained in:
parent
95e0f34d31
commit
816ff210b7
2 changed files with 65 additions and 6 deletions
|
|
@ -643,7 +643,9 @@ export class CodexSessionFileRecentProjectsSourceAdapter implements RecentProjec
|
|||
.sort((left, right) => right.lastActivityAt - left.lastActivityAt)
|
||||
.slice(0, CODEX_PROJECT_CANDIDATE_LIMIT);
|
||||
const durationMs = Date.now() - startedAt;
|
||||
if (degraded) {
|
||||
// Large Codex histories often hit scan budgets while still producing useful candidates.
|
||||
// Keep the detailed partial warning for user-visible empty results only.
|
||||
if (degraded && snapshots.length === 0) {
|
||||
this.deps.logger.warn('codex session-file recent-projects source partial', {
|
||||
files: candidateFiles.length,
|
||||
visitedFiles,
|
||||
|
|
|
|||
|
|
@ -550,10 +550,65 @@ describe('CodexSessionFileRecentProjectsSourceAdapter', () => {
|
|||
expect(result.candidates.map((candidate) => candidate.primaryPath)).toEqual([
|
||||
'/Users/test/projects/fast',
|
||||
]);
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
'codex session-file recent-projects source loaded',
|
||||
expect.objectContaining({
|
||||
degraded: true,
|
||||
files: 2,
|
||||
timedOutReads: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps a partial warning when no recent project candidates are available', async () => {
|
||||
const codexHome = path.join(tempDir, '.codex');
|
||||
const appDataPath = path.join(tempDir, 'app-data');
|
||||
const logger = createLogger();
|
||||
const identityResolver = {
|
||||
resolve: vi.fn().mockResolvedValue(null),
|
||||
} as unknown as RecentProjectIdentityResolver;
|
||||
const slowSessionPath = path.join(
|
||||
codexHome,
|
||||
'sessions',
|
||||
'2026',
|
||||
'04',
|
||||
'14',
|
||||
'rollout-slow.jsonl'
|
||||
);
|
||||
await writeRollout(
|
||||
slowSessionPath,
|
||||
{
|
||||
cwd: '/Users/test/projects/slow',
|
||||
},
|
||||
new Date('2026-04-14T12:00:00.000Z')
|
||||
);
|
||||
const originalOpen = fs.open.bind(fs);
|
||||
vi.spyOn(fs, 'open').mockImplementation(async (...args) => {
|
||||
if (String(args[0]) === slowSessionPath) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 2500));
|
||||
}
|
||||
return originalOpen(...args);
|
||||
});
|
||||
|
||||
const adapter = new CodexSessionFileRecentProjectsSourceAdapter({
|
||||
getActiveContext: () => ({ type: 'local', id: 'local-1' }) as never,
|
||||
getLocalContext: () => ({ type: 'local', id: 'local-1' }) as never,
|
||||
identityResolver,
|
||||
logger,
|
||||
codexHome,
|
||||
appDataPath,
|
||||
});
|
||||
const result = await adapter.list();
|
||||
|
||||
expect(result).toEqual({
|
||||
candidates: [],
|
||||
degraded: true,
|
||||
});
|
||||
expect(logger.warn).toHaveBeenCalledWith(
|
||||
'codex session-file recent-projects source partial',
|
||||
expect.objectContaining({
|
||||
files: 2,
|
||||
candidates: 0,
|
||||
files: 1,
|
||||
timedOutReads: 1,
|
||||
})
|
||||
);
|
||||
|
|
@ -695,9 +750,10 @@ describe('CodexSessionFileRecentProjectsSourceAdapter', () => {
|
|||
expect(firstResult.candidates.map((candidate) => candidate.primaryPath)).toEqual([
|
||||
'/Users/test/projects/alpha',
|
||||
]);
|
||||
expect(logger.warn).toHaveBeenCalledWith(
|
||||
'codex session-file recent-projects source partial',
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
'codex session-file recent-projects source loaded',
|
||||
expect.objectContaining({
|
||||
degraded: true,
|
||||
files: 171,
|
||||
uncachedReads: 160,
|
||||
skippedUncached: 11,
|
||||
|
|
@ -758,9 +814,10 @@ describe('CodexSessionFileRecentProjectsSourceAdapter', () => {
|
|||
expect(result.candidates.map((candidate) => candidate.primaryPath)).toEqual([
|
||||
'/Users/test/projects/alpha',
|
||||
]);
|
||||
expect(logger.warn).toHaveBeenCalledWith(
|
||||
'codex session-file recent-projects source partial',
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
'codex session-file recent-projects source loaded',
|
||||
expect.objectContaining({
|
||||
degraded: true,
|
||||
files: 500,
|
||||
visitedFiles: 505,
|
||||
droppedOlderFiles: 5,
|
||||
|
|
|
|||
Loading…
Reference in a new issue