fix(@deepnote/cli): timestamped snapshots#320
Conversation
📝 WalkthroughWalkthroughThe changes introduce timestamped snapshot file generation to the snapshot persistence mechanism. A new Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (58.82%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #320 +/- ##
==========================================
- Coverage 83.47% 83.43% -0.04%
==========================================
Files 114 114
Lines 6971 6980 +9
Branches 1864 1864
==========================================
+ Hits 5819 5824 +5
- Misses 1152 1156 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/cli/src/commands/run.test.ts (1)
67-69: 🧹 Nitpick | 🔵 TrivialInitial mock missing
timestampedSnapshotPath.Overwritten in
beforeEach, but inconsistent withSaveSnapshotResulttype.const mockSaveExecutionSnapshot: MockedFunction<typeof saveExecutionSnapshot> = vi .fn() - .mockResolvedValue({ snapshotPath: '/mock/snapshot.snapshot.deepnote' }) + .mockResolvedValue({ + snapshotPath: '/mock/snapshot.snapshot.deepnote', + timestampedSnapshotPath: '/mock/snapshot-timestamped.snapshot.deepnote', + })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/commands/run.test.ts` around lines 67 - 69, The mock for saveExecutionSnapshot (mockSaveExecutionSnapshot) returns an object missing timestampedSnapshotPath which violates the SaveSnapshotResult shape; update the mockResolvedValue to include timestampedSnapshotPath (alongside snapshotPath) so the initial mock matches the SaveSnapshotResult type used elsewhere (and remains consistent with the value overwritten in beforeEach).packages/mcp/src/tools/execution.ts (1)
248-298:⚠️ Potential issue | 🟠 MajorReturn type omits
timestampedSnapshotPath.Writes both snapshots but returns only
snapshotPath. CLI version returns both. Inconsistent API.-): Promise<{ snapshotPath: string }> { +): Promise<{ snapshotPath: string; timestampedSnapshotPath: string }> {And at line 298:
- return { snapshotPath } + return { snapshotPath, timestampedSnapshotPath }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mcp/src/tools/execution.ts` around lines 248 - 298, The function currently returns Promise<{ snapshotPath: string }> but writes both timestampedSnapshotPath and snapshotPath; update the return type to include timestampedSnapshotPath (e.g. Promise<{ snapshotPath: string; timestampedSnapshotPath: string }>) and change the final return to return both { snapshotPath, timestampedSnapshotPath } (symbols: snapshotPath, timestampedSnapshotPath, serializeDeepnoteSnapshot, generateSnapshotFilename); also search for and update any callers expecting the old single-field return to handle the new two-field object.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/cli/src/commands/run.test.ts`:
- Around line 67-69: The mock for saveExecutionSnapshot
(mockSaveExecutionSnapshot) returns an object missing timestampedSnapshotPath
which violates the SaveSnapshotResult shape; update the mockResolvedValue to
include timestampedSnapshotPath (alongside snapshotPath) so the initial mock
matches the SaveSnapshotResult type used elsewhere (and remains consistent with
the value overwritten in beforeEach).
In `@packages/mcp/src/tools/execution.ts`:
- Around line 248-298: The function currently returns Promise<{ snapshotPath:
string }> but writes both timestampedSnapshotPath and snapshotPath; update the
return type to include timestampedSnapshotPath (e.g. Promise<{ snapshotPath:
string; timestampedSnapshotPath: string }>) and change the final return to
return both { snapshotPath, timestampedSnapshotPath } (symbols: snapshotPath,
timestampedSnapshotPath, serializeDeepnoteSnapshot, generateSnapshotFilename);
also search for and update any callers expecting the old single-field return to
handle the new two-field object.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
packages/cli/src/commands/run.test.tspackages/cli/src/utils/output-persistence.test.tspackages/cli/src/utils/output-persistence.tspackages/mcp/src/tools/execution.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/convert/src/snapshot/save.ts`:
- Around line 102-113: Validate timing.finishedAt before calling toISOString in
save.ts: check that new Date(timing.finishedAt) is a valid Date (not Invalid
Date) and if it is invalid, either throw a clear error or fall back to a safe
timestamp (e.g., Date.now() or timing.startedAt) before constructing timestamp
(the variable assigned from toISOString) and calling
generateSnapshotFilename(slug, file.project.id, timestamp); ensure the chosen
fallback flows into timestampedFilename/timestampedSnapshotPath and the writes
that follow so snapshot saving does not throw unexpectedly.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
packages/cli/src/utils/output-persistence.tspackages/convert/src/index.tspackages/convert/src/snapshot/index.tspackages/convert/src/snapshot/save.tspackages/mcp/src/tools/execution.ts
d0fb902 to
7cf4901
Compare
| // Serialize and write both snapshot files | ||
| const snapshotYaml = serializeDeepnoteSnapshot(snapshot) | ||
| await fs.writeFile(timestampedSnapshotPath, snapshotYaml, 'utf-8') | ||
| await fs.writeFile(snapshotPath, snapshotYaml, 'utf-8') |
There was a problem hiding this comment.
Instead of writing directly to the latest snapshot, we should finish writing the timestamped file, and copy it to the latest path. That way we reduce the chance of corrupting the file.
There was a problem hiding this comment.
Good point, addressed 👌
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/mcp/src/tools/execution.ts (2)
243-298: 🧹 Nitpick | 🔵 TrivialDuplicated snapshot logic.
This function mirrors
saveExecutionSnapshotinpackages/cli/src/utils/output-persistence.ts. Consider importing or consolidating to avoid drift.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mcp/src/tools/execution.ts` around lines 243 - 298, The saveExecutionSnapshot implementation is duplicated; refactor to reuse the existing implementation in packages/cli/src/utils/output-persistence.ts by extracting the shared snapshot logic into a single shared utility (or directly importing the existing saveExecutionSnapshot/exported helpers) and update this file to call that shared function; specifically consolidate behaviors around building outputsByBlockId, merging outputs into DeepnoteFile, using splitDeepnoteFile, getSnapshotDir, slugifyProjectName, generateSnapshotFilename and serializeDeepnoteSnapshot so this module only calls the shared routine instead of duplicating the logic.
243-298:⚠️ Potential issue | 🟡 MinorReturn type inconsistent with output-persistence.ts.
timestampedSnapshotPathis computed but not returned. The sibling implementation inpackages/cli/src/utils/output-persistence.tsreturns both paths inSaveSnapshotResult.Proposed fix
async function saveExecutionSnapshot( sourcePath: string, file: DeepnoteFile, blockOutputs: Array<{ id: string; outputs: unknown[]; executionCount?: number | null }>, timing: { startedAt: string; finishedAt: string } -): Promise<{ snapshotPath: string }> { +): Promise<{ snapshotPath: string; timestampedSnapshotPath: string }> { // ... existing code ... - return { snapshotPath } + return { snapshotPath, timestampedSnapshotPath } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mcp/src/tools/execution.ts` around lines 243 - 298, The function saveExecutionSnapshot currently computes timestampedSnapshotPath but only returns snapshotPath, causing an inconsistent return type versus the sibling SaveSnapshotResult; change the function's return type (Promise<{ snapshotPath: string }>) to include timestampedSnapshotPath (e.g. Promise<{ snapshotPath: string; timestampedSnapshotPath: string }>), and update the final return to return both { snapshotPath, timestampedSnapshotPath }. Update any callers or exported type aliases (e.g., SaveSnapshotResult) to accept the new shape so usages of saveExecutionSnapshot receive both paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/mcp/src/tools/execution.ts`:
- Around line 243-298: The saveExecutionSnapshot implementation is duplicated;
refactor to reuse the existing implementation in
packages/cli/src/utils/output-persistence.ts by extracting the shared snapshot
logic into a single shared utility (or directly importing the existing
saveExecutionSnapshot/exported helpers) and update this file to call that shared
function; specifically consolidate behaviors around building outputsByBlockId,
merging outputs into DeepnoteFile, using splitDeepnoteFile, getSnapshotDir,
slugifyProjectName, generateSnapshotFilename and serializeDeepnoteSnapshot so
this module only calls the shared routine instead of duplicating the logic.
- Around line 243-298: The function saveExecutionSnapshot currently computes
timestampedSnapshotPath but only returns snapshotPath, causing an inconsistent
return type versus the sibling SaveSnapshotResult; change the function's return
type (Promise<{ snapshotPath: string }>) to include timestampedSnapshotPath
(e.g. Promise<{ snapshotPath: string; timestampedSnapshotPath: string }>), and
update the final return to return both { snapshotPath, timestampedSnapshotPath
}. Update any callers or exported type aliases (e.g., SaveSnapshotResult) to
accept the new shape so usages of saveExecutionSnapshot receive both paths.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/cli/src/utils/output-persistence.tspackages/mcp/src/tools/execution.ts

Summary by CodeRabbit
Release Notes
New Features
Tests