Skip to content

Stores built from a storage, and resolutions that apply themselves - #41

Merged
SashankBhamidi merged 3 commits into
mainfrom
feat/storage-strategy
Oct 28, 2026
Merged

SashankBhamidi merged 3 commits into
mainfrom
feat/storage-strategy

Conversation

@SashankBhamidi

Copy link
Copy Markdown
Member

Closes #39.
Closes #40.

From @niccokunzmann's reviews of #29 and #30, done before the release so nothing needs a deprecation later.

A store is a StateStore over a Storage now. A new storage implements Storage and StorageTransaction, both with public names, and gets every check from the store. A MemoryKeeper replaces subclassing MemoryStore to keep its data in a file.

Resolutions and push outcomes decide their own effect, so the replica has no match on them anymore. Nothing public changed, and no test either.

Also the three fixes I promised in the threads, and resolve_conflicts returns the conflicts it resolved, left open or found changed, instead of a count.

Fixed: a failed rollback replaced the block's own error, so Ctrl-C came out as UnexpectedStoreError.

The adapter hooks keep their underscores: the app calls sync() on the adapter, and a public read() or send() next to it would skip the session.

@codecov

codecov Bot commented Oct 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@SashankBhamidi
SashankBhamidi requested a balanced review from Copilot and removed request for stevepiercy October 28, 2026 19:30
@read-the-docs-community

read-the-docs-community Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The changes can destroy saved state when the destination already ends in .new and allow post-construction mapping mutations to bypass validation, accepting invalid incremental entries and advancing the scope token.

2 open issues
What changed in this PR

Refactors storage and conflict handling to support new backends without subclass hooks and move resolution behavior out of Replica, addressing #39 and #40.

Changes:

  • Introduces public storage interfaces and optional MemoryKeeper persistence.
  • Moves resolution and push-outcome behavior into their value classes and returns detailed conflict-resolution results.
  • Updates validation, transaction error handling, tests, examples, and documentation.
File Description
src/​calendaring_sync/​tests/​test_sync_unit.py Updates interface tests and adds failure-path coverage.
src/​calendaring_sync/​tests/​conftest.py Adds a custom-storage test fixture.
src/​calendaring_sync/​tests/​_storage.py Adds a minimal storage implementation for tests.
src/​calendaring_sync/​store/​sqlite.py Separates SQLite storage and transaction operations.
src/​calendaring_sync/​store/​memory.py Adds memory storage transactions and keeper persistence.
src/​calendaring_sync/​store/​base.py Defines storage interfaces and centralizes store safeguards.
src/​calendaring_sync/​store/​__init__.py Updates the package description.
src/​calendaring_sync/​session.py Delegates push-outcome validation.
src/​calendaring_sync/​replica.py Delegates effects and reports conflict-resolution results.
src/​calendaring_sync/​objects/​resolution.py Implements resolution behavior and result fields.
src/​calendaring_sync/​objects/​record.py Clarifies copy terminology in documentation.
src/​calendaring_sync/​objects/​push.py Implements push-outcome checks and effects.
src/​calendaring_sync/​objects/​feed.py Clarifies a feed-entry comment.
src/​calendaring_sync/​objects/​edit.py Updates synced-copy terminology.
src/​calendaring_sync/​objects/​conflict.py Clarifies conflict documentation.
src/​calendaring_sync/​objects/​change_set.py Validates incremental entries during construction.
src/​calendaring_sync/​objects/​_data.py Updates shared-field comments.
src/​calendaring_sync/​error.py Clarifies stale-conflict documentation.
src/​calendaring_sync/​adapters/​base.py Explains underscored adapter hooks.
src/​calendaring_sync/​_classify.py Updates classifier documentation terminology.
src/​calendaring_sync/​__init__.py Exports new storage and result types.
news/​9.feature.rst Documents detailed conflict-resolution results.
news/​40.feature.rst Announces storage composition.
news/​28.feature.rst Documents keeper-based persistence.
docs/​reference/​store.rst Documents the new public storage interfaces.
docs/​reference/​guarantees.rst Updates the concurrent-read capability reference.
docs/​reference/​glossary.rst Defines storage and copy terminology.
docs/​how-to/​store.rst Explains keepers and custom storage.
docs/​how-to/​mirror.rst Clarifies mirrored-copy terminology.
docs/​how-to/​conflicts.rst Explains conflict-resolution results.
docs/​explanation/​design.rst Updates storage architecture and conflict terminology.
docs/​examples/​keeper.py Adds a file-backed keeper example.
docs/​contribute.rst Updates the storage module description.
docs/​conf.py Hides private bases in generated documentation.

Review effort: Balanced

Comment thread docs/examples/keeper.py Outdated
for object_id, change in change_set.changes.items():
if not change_set.full_listing and isinstance(change, Unchanged):
raise ValueError(f"Unchanged object {object_id!r} outside a full listing")
self._apply(scope.id, object_id, change, now, claimed, freed)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in b41eae6 differently: ChangeSet now keeps its own read-only copy, so later changes to the mapping never reach it.

@SashankBhamidi
SashankBhamidi requested a balanced review from Copilot October 28, 2026 19:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@SashankBhamidi
SashankBhamidi merged commit 6ae13db into main Oct 28, 2026
15 checks passed
@SashankBhamidi
SashankBhamidi deleted the feat/storage-strategy branch October 28, 2026 19:48
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.

Build stores from a storage strategy instead of subclass hooks Let resolutions and push outcomes apply themselves

2 participants