Skip to content

fix: snapshot() returns deep copies to prevent internal store mutation#153

Merged
CyberSecDef merged 2 commits into
mainfrom
copilot/fix-snapshot-method-shallow-copies
Apr 8, 2026
Merged

fix: snapshot() returns deep copies to prevent internal store mutation#153
CyberSecDef merged 2 commits into
mainfrom
copilot/fix-snapshot-method-shallow-copies

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 8, 2026

snapshot() returned shallow dict(v) copies, meaning callers could mutate nested structures (e.g. chapters_done, consistency) and corrupt the internal store — inconsistent with the deep-copy guarantee already provided by get().

Changes

  • novelforge/progress.py: Replace dict(v) with copy.deepcopy(v) in snapshot(); update docstring to reflect deep-copy semantics.
  • tests/test_progress_manager.py: Rename test_snapshot_returns_shallow_copiestest_snapshot_returns_deep_copies and add a nested-mutation assertion that directly exercises the fixed behaviour.
# Before
def snapshot(self) -> dict[str, ProgressState]:
    with self._lock:
        return {k: dict(v) for k, v in self._store.items()}

# After
def snapshot(self) -> dict[str, ProgressState]:
    with self._lock:
        return {k: copy.deepcopy(v) for k, v in self._store.items()}

Copilot AI requested review from Copilot and removed request for Copilot April 8, 2026 20:43
Copilot AI linked an issue Apr 8, 2026 that may be closed by this pull request
Copilot AI requested review from Copilot and removed request for Copilot April 8, 2026 20:45
Copilot AI changed the title [WIP] Fix snapshot() method to return deep copies fix: snapshot() returns deep copies to prevent internal store mutation Apr 8, 2026
Copilot AI requested a review from CyberSecDef April 8, 2026 20:46
@CyberSecDef CyberSecDef marked this pull request as ready for review April 8, 2026 20:49
Copilot AI review requested due to automatic review settings April 8, 2026 20:49
@CyberSecDef CyberSecDef merged commit 6a3bc98 into main Apr 8, 2026
9 checks passed
@CyberSecDef CyberSecDef deleted the copilot/fix-snapshot-method-shallow-copies branch April 8, 2026 20:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aligns ProgressManager.snapshot() with get() by returning deep copies, preventing callers from mutating nested structures and corrupting the internal in-memory progress store.

Changes:

  • Update ProgressManager.snapshot() to return copy.deepcopy(...) entries instead of shallow dict(...) copies.
  • Update the snapshot() docstring to reflect deep-copy semantics and safe caller mutation.
  • Strengthen the snapshot test to assert nested mutations don’t affect stored state.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
novelforge/progress.py Make snapshot() return deep copies and update documentation to match the intended immutability boundary.
tests/test_progress_manager.py Rename and extend the snapshot test to cover nested-mutation behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread novelforge/progress.py
Comment on lines 191 to +192
with self._lock:
return {k: dict(v) for k, v in self._store.items()} # type: ignore[misc]
return {k: copy.deepcopy(v) for k, v in self._store.items()} # type: ignore[misc]
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

snapshot() now uses copy.deepcopy, which should generally preserve the ProgressState type. Consider removing the broad # type: ignore[misc] (or replacing it with a narrower cast(...) / correct ignore code) so mypy can validate the return type instead of suppressing it.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

snapshot() Method Returns Shallow Copies

3 participants