Skip to content

Add cache schema versioning and validation to fetch system#174

Merged
jeremiah-k merged 19 commits intomainfrom
maint-22-1
Feb 12, 2026
Merged

Add cache schema versioning and validation to fetch system#174
jeremiah-k merged 19 commits intomainfrom
maint-22-1

Conversation

@jeremiah-k
Copy link
Owner

@jeremiah-k jeremiah-k commented Feb 2, 2026

Overview

This PR adds explicit cache schema versioning and validation for the GitHub releases cache, centralizes pruning/normalization logic in the cache manager, replaces a development assert with production-safe behavior in the Android downloader, and updates tests and documentation. The intent is to make cache reads robust against legacy, malformed, or stale entries by treating mismatches/invalid data as cache misses and ensuring writes record the active schema version.

Key changes

Features

  • Add GITHUB_RELEASES_CACHE_SCHEMA_VERSION = "1.0" and extended docstring guidance for schema bumps (src/fetchtastic/constants.py).
  • Persist schema_version in releases cache entries written by CacheManager.write_releases_cache_entry.
  • Add CacheManager.prune_cache_data to normalize legacy formats, remove expired entries, and optionally enforce schema_version.
  • Add CacheManager.clear_releases_cache() to remove the releases cache file.
  • Add _validate_release_entry to perform per-entry structure/type checks (tag_name, prerelease, published_at) with logging on failures.
  • Read/write cache flows now validate schema_version and per-entry data; write path prunes invalid/stale entries before persisting.
  • Add integration test (tests/test_cache_flow_integration.py) verifying schema mismatch triggers a fresh API fetch and rewrite with the new schema.

Fixes / Safety

  • Entries missing schema_version or with mismatched schema_version are treated as cache misses; invalid per-entry data causes the releases payload to be ignored to avoid returning partial/corrupt data.
  • Replace brittle assert/invariant in MeshtasticAndroidAppDownloader.update_release_history with logging, cache-clear, and graceful return (None) to avoid crashes.
  • Tests expanded to cover legacy formats, schema mismatches, missing fields, pruning behavior, and Android invariant paths.

Refactors / Misc

  • Consolidated expiry/pruning/schema handling and clarified docstrings in the cache module (src/fetchtastic/download/cache.py).
  • Adjusted related cache utilities (read_with_expiry and normalization paths) to use the new pruning/validation helpers.
  • Bumped project version 0.10.2 → 0.10.3 (pyproject.toml).
  • Large test updates across unit and integration tests to align with the new cache schema and validation behavior.

Migration / Breaking notes

  • On-disk releases cache entries that lack "schema_version" or whose schema_version differs from GITHUB_RELEASES_CACHE_SCHEMA_VERSION will be treated as cache misses; the next run will fetch fresh data and write the new schema. There is no automatic migration.
  • The Android downloader now clears the releases cache on certain invariant detections (deliberate conservative behavior); this may be more aggressive than necessary for some deployments—consider documenting or narrowing this behavior if desired.

Add cache schema versioning constants and validation system to ensure cache integrity. Includes schema version tracking in cache entries, a new _validate_release_entry method to verify release data structure, and validation checks during cache retrieval. Also adds a safety filter in the Android downloader to prevent prereleases from slipping through stable release filters, with automatic cache clearing on detection.
@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jeremiah-k, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the reliability and integrity of the release caching system. It introduces schema versioning to cached data, allowing for automatic invalidation of outdated cache formats. Furthermore, it adds comprehensive validation checks for individual release entries within the cache, ensuring data integrity and preventing the use of malformed or incorrect data, such as prereleases mistakenly identified as stable. These changes aim to improve the overall stability and correctness of release data fetching by proactively handling potential cache corruption or format changes.

Highlights

  • Cache Schema Versioning: Introduced schema version constants for various cache types (releases, prerelease history, prerelease commits) and implemented a check in the releases cache to invalidate entries with an outdated schema version, ensuring compatibility and data freshness.
  • Robust Release Entry Validation: Added a new _validate_release_entry method and integrated it into the releases cache reading process. This method performs detailed validation of individual cached release objects, checking for correct types and presence of critical fields like tag_name, prerelease, and published_at.
  • Prerelease Safeguard in Android Releases: Implemented a critical check in the Android release update logic to detect if any prereleases mistakenly 'slipped through' the stable release filter. If detected, it logs an error, clears the entire releases cache, and forces a refresh to prevent incorrect data from being used.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai bot changed the title @coderabbitai Add cache schema versioning and validation to fetch system Feb 2, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces cache schema versioning and validation to improve the robustness of caching mechanisms. A defensive check was also added to the Android downloader. My review identifies a potential issue in the new cache validation logic that could lead to incorrect cache handling and suggests a correction. Additionally, I've pointed out a violation of encapsulation in the Android downloader's new defensive check and proposed a refactoring to improve the design.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Added a releases cache schema version constant and made releases cache read/write/prune/clear schema-aware with per-entry validation; Android downloader filters to stable releases and returns/clears history on invariant violations; project version bumped and tests extended for schema, pruning, and legacy-format normalization.

Changes

Cohort / File(s) Summary
Constants
src/fetchtastic/constants.py
Add GITHUB_RELEASES_CACHE_SCHEMA_VERSION = "1.0" and accompanying documentation describing cache schema fields and versioning rules.
Releases cache logic
src/fetchtastic/download/cache.py
Introduce schema-aware cache handling: add schema_version to entries, enforce schema matching on read, per-entry validation (_validate_release_entry), prune_cache_data(...), clear_releases_cache(), and prune-on-write using RELEASES_CACHE_EXPIRY_HOURS; normalize legacy formats and treat mismatches/invalid entries as cache misses.
Android downloader
src/fetchtastic/download/android.py
update_release_history now filters out prereleases, returns None when no stable releases, logs concise status with label "Android", and returns the written history dict when an update occurs.
Project metadata
pyproject.toml
Bump project version 0.10.20.10.3.
Tests
tests/test_cache_management.py, tests/test_android_downloader_comprehensive.py, tests/test_cache_flow_integration.py
Expand/add tests for schema version handling, pruning behavior, legacy-format normalization, per-entry validation, cache clearing/refresh on schema mismatch, and Android downloader prerelease filtering; add integration test simulating old schema to trigger refresh.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Downloader as Android Downloader
    participant Cache as Releases Cache
    participant GitHub as GitHub API
    participant Logger

    Client->>Downloader: request get_releases / update_release_history
    Downloader->>Cache: read_releases_cache_entry(key)
    alt cache valid & schema matches
        Cache-->>Downloader: validated releases list
    else cache miss / invalid / schema mismatch
        Cache-->>Downloader: cache miss
        Downloader->>GitHub: fetch releases
        GitHub-->>Downloader: releases payload
        Downloader->>Cache: write_releases_cache_entry(schema_version, releases)
    end
    Downloader->>Downloader: filter out prerelease entries
    alt no stable releases
        Downloader-->>Client: return None
    else stable releases present
        Downloader->>Cache: write_pruned_history(schema_version, releases)
        Downloader-->>Client: return written history dict
    end
    alt invariant violation detected
        Downloader->>Logger: log invariant violation ("Android")
        Downloader->>Cache: clear_releases_cache()
        Downloader-->>Client: return None
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped into the cache with a grin,

I tagged the schema, tidy and thin.
I pruned the old burrows, checked every name,
I nudged the downloader to play the new game.
Now releases hop home, neat and sane.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title Check ✅ Passed Title check skipped as CodeRabbit has written the PR title.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch maint-22-1

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
tests/test_android_downloader_comprehensive.py (1)

304-316: Consider asserting the history content excludes prereleases.

The test verifies the return type but doesn't confirm that the prerelease (v2.7.15-rc1) was actually filtered out of the written history. A content check would strengthen confidence in the filtering logic.

src/fetchtastic/download/cache.py (1)

1057-1074: read_commit_timestamp_cache normalization: dict entries missing "timestamp" are silently dropped.

After prune_cache_data returns valid (non-expired) entries, the normalization loop at lines 1064–1069 only includes dict entries that have both "timestamp" and "cached_at". A dict with cached_at but no timestamp key passes pruning but is silently excluded from the result. This is likely the correct behavior (such an entry is malformed for commit timestamps), but there's no log message for this case, which could make debugging harder.

Optional: log a debug message for skipped malformed dict entries
             if isinstance(value, dict):
                 # Legacy format: {"timestamp": "...", "cached_at": "..."}
                 timestamp = value.get("timestamp")
                 cached_at = value.get("cached_at")
                 if timestamp and cached_at:
                     normalized[key] = [timestamp, cached_at]
+                else:
+                    logger.debug("Skipping malformed commit timestamp entry: %s", key)
             else:
                 # New format: [timestamp_iso, cached_at_iso]
                 normalized[key] = list(value)
tests/test_cache_management.py (1)

565-593: Nit: comment says "Missing: prerelease and published_at" but published_at is optional.

The validation failure is actually caused solely by the missing prerelease field. published_at can be absent and still pass validation. The comment is slightly misleading.

Clarify the comment
                     {
                         "tag_name": "v1.0.0",
-                        # Missing: prerelease and published_at
+                        # Missing: prerelease (required field)
                     }

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

… helper method

Introduce clear_releases_cache() method that handles path resolution and file removal internally. Simplify MeshtasticAndroidAppDownloader by replacing direct cache manager calls with the new abstraction. Revise write_json_with_timestamp() documentation to clarify atomic write behavior and timestamp key defaults.
…istic data

- Add null assertions to verify cache read operations return valid data
- Include prerelease and published_at fields in test releases data
- Add type ignore comments for proper type checking with list indexing
@jeremiah-k
Copy link
Owner Author

/gemini review

@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a cache schema versioning and validation system, which is a great step towards ensuring data integrity and forward compatibility. The changes are mostly well-implemented, with new constants for schema versions, validation logic for release entries, and a safety check in the Android downloader. My review includes a critical fix for the schema version validation to correctly handle old cache entries as described in the PR, and a suggestion to remove a redundant check in the Android downloader to improve code clarity. The test updates corresponding to these changes are appropriate.

@codecov
Copy link

codecov bot commented Feb 2, 2026

Codecov Report

❌ Patch coverage is 80.00000% with 15 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/fetchtastic/download/cache.py 79.72% 10 Missing and 5 partials ⚠️

📢 Thoughts on this report? Let us know!

- Fix schema version validation to reject old cache entries (no schema_version field)
- Replace redundant prerelease safety loop with invariant assertion
- Add comprehensive tests for schema version validation (old format, mismatch, missing fields)
- Add tests for update_release_history prerelease filtering
- Fix existing test to include schema_version field

This improves patch coverage for the cache schema versioning changes
and simplifies the prerelease safety net logic.
@jeremiah-k
Copy link
Owner Author

/gemini review

@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces valuable improvements by adding schema versioning and validation to the caching system, making it more robust against malformed data. The changes are well-structured, with new constants for schema versions, validation logic in the CacheManager, and updated tests to cover the new behavior.

My main feedback is regarding the defensive guard in the Android downloader. The implementation uses an assert, which is disabled in production environments, rather than the intended production-safe check described in the pull request. I've provided a suggestion to align the code with the described behavior.

- Changed assert to if statement with logger.critical
- Clear releases cache and return None if prerelease found in stable_releases
- Addresses code review feedback: assert is removed in production (-O flag)
- Ensures safety guard works in production environments
@jeremiah-k
Copy link
Owner Author

/gemini review

@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces cache schema versioning and validation, which is a significant improvement for cache robustness. The changes in cache.py and the associated tests are well-executed. I've identified a small issue in src/fetchtastic/download/android.py where a new safety check is logically unreachable. My review includes a suggestion to correct this, aligning the code with the stated intent of the pull request.

The check on lines 188-194 was logically unreachable:
- Line 184 filters releases with: if not self._is_android_prerelease(r)
- Line 188 checked if any: self._is_android_prerelease(r) for r in stable_releases
- Since stable_releases only contains elements where NOT prerelease,
  the condition any(prerelease) can never be True

The filtering logic is correct and complete. Cache corruption is already
handled by the schema validation in cache.py (read_releases_cache_entry),
which validates each entry and forces refresh on any invalid data.

Removing dead code eliminates confusion and gives proper credit to the
reviewer's correct observation.

Addresses code review feedback about unreachable code.
@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@jeremiah-k
Copy link
Owner Author

/gemini review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly improves the robustness of the caching system by introducing schema versioning and data validation. The changes are well-implemented and the new validation logic is a great step towards preventing issues with corrupted or outdated cache entries. The addition of comprehensive tests for the new caching behavior is also a valuable contribution. The PR description is clear, although there's a minor discrepancy regarding the replacement of an assert in MeshtasticAndroidAppDownloader, which I couldn't locate in the provided changes. Overall, this is a solid enhancement to the project's stability.

coderabbitai bot added a commit that referenced this pull request Feb 7, 2026
Docstrings generation was requested by @jeremiah-k.

* #174 (comment)

The following files were modified:

* `src/fetchtastic/download/android.py`
* `src/fetchtastic/download/cache.py`
Docstrings generation was requested by @jeremiah-k.

* #174 (comment)

The following files were modified:

* `src/fetchtastic/download/android.py`
* `src/fetchtastic/download/cache.py`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@jeremiah-k
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a robust cache schema versioning and validation system, which is a great improvement for handling cache consistency and preventing issues with outdated or malformed cached data. The centralization of pruning and normalization logic into the CacheManager is a significant refactoring that improves code clarity and maintainability. The replacement of an assert with production-safe error handling in the Android downloader is also a welcome change for stability. The new tests are comprehensive and cover the new functionality well. I have a couple of minor suggestions to improve type hints and docstrings for better maintainability.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/fetchtastic/download/android.py`:
- Around line 189-207: The invariant check that calls any(r.prerelease for r in
stable_releases) is unreachable because stable_releases is built by filtering
with self._is_android_prerelease(r) which already returns True when
release.prerelease is True; remove the dead branch or replace it with a
meaningful defense-in-depth check: either re-validate against the raw release
data (e.g., track the original release objects and check their prerelease field)
or change the comment to explicitly state this is a sanity assertion and keep it
as an assert (not runtime logic); update references to
self.cache_manager.clear_releases_cache() and the logger usage in the same block
accordingly so you don’t attempt to clear the cache for an unreachable
condition.

In `@src/fetchtastic/download/cache.py`:
- Around line 849-851: The docstring for the function that begins "Validate a
JSON cache file against an expiry period and return its parsed contents when
valid." contains a Unicode non‑breaking hyphen (U+2011) in "ISO‑8601"; replace
that character with a regular hyphen-minus (U+002D) so the text reads "ISO-8601"
to eliminate the RUF002 warning (search for the docstring text to locate the
correct function in src/fetchtastic/download/cache.py).
🧹 Nitpick comments (1)
src/fetchtastic/download/cache.py (1)

969-1036: prune_cache_data is well-designed; one minor observation on silent drops.

Entries without a cached_at field (lines 1008–1009) are silently pruned with no log message. This is fine for the current callers but differs from the explicit debug logging for schema mismatches (lines 1023, 1026–1031). Consider adding a debug log for entries dropped due to missing/unparseable cached_at for consistency, especially since this method is public and may be used by future callers who'd want visibility into why entries disappeared.

🔍 Optional: add debug logging for entries without cached_at
             if not cached_at_str:
+                logger.debug("Pruning entry without cached_at: %s", key)
                 continue
 
             cached_at = parse_iso_datetime_utc(cached_at_str)
             if not cached_at:
+                logger.debug("Pruning entry with unparseable cached_at: %s", key)
                 continue

…story update

Removed the defensive invariant violation check that detected prereleases in the stable_releases list and cleared the cache. This simplifies the release history update flow by trusting the upstream filtering mechanism that already separates stable and prerelease candidates. The related test case has also been removed as the invariant is now considered unnecessary overhead.
@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@jeremiah-k
Copy link
Owner Author

/gemini review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a robust cache schema versioning and validation system, which is a significant improvement for data integrity and handling of cache format changes. The centralization of cache pruning logic into the prune_cache_data method is a great refactoring that enhances maintainability and consistency across different cache types. The new validation steps in read_releases_cache_entry provide strong guarantees against returning stale or malformed data. The accompanying tests are comprehensive, including a valuable integration test that verifies the schema mismatch and refresh flow. Overall, this is a high-quality contribution that significantly strengthens the caching layer.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/fetchtastic/download/android.py (1)

168-200: ⚠️ Potential issue | 🟡 Minor

Docstring describes removed invariant-check behavior.

The docstring (lines 174–179, 187) still references a "production invariant" check that clears the releases cache and returns None on violation, but the code no longer contains this logic (it was removed per the commit history). The Returns section also lists "invariant violation" as a reason for returning None.

📝 Proposed docstring fix
     def update_release_history(
         self, releases: List[Release], *, log_summary: bool = True
     ) -> Optional[Dict[str, Any]]:
         """
-        Update the on-disk Android release history and optionally emit a summary log.
-
-        Records only stable (non-prerelease) releases from the provided list into the persistent
-        release history. If no releases are provided or no stable releases are present, the
-        function returns None and does not modify history. As a defensive measure, if a
-        production invariant is violated (a prerelease is detected among the stable releases),
-        the function attempts to clear the releases cache and returns None without updating
-        the on-disk history.
+        Update the on-disk Android release history and optionally emit a summary log.
+
+        Records only stable (non-prerelease) releases from the provided list into the persistent
+        release history. If no releases are provided or no stable releases are present, the
+        function returns None and does not modify history.

         Parameters:
             releases (List[Release]): Releases to record in history.
             log_summary (bool): When True, emit a concise release status summary to the log.

         Returns:
-            Optional[Dict[str, Any]]: The updated history data written to disk, or `None` when
-            no update was performed (no releases, no stable releases, or invariant violation).
+            Optional[Dict[str, Any]]: The updated history data written to disk, or `None` when
+            no update was performed (no releases or no stable releases).
         """
🧹 Nitpick comments (1)
src/fetchtastic/download/cache.py (1)

1004-1013: Entries without cached_at are silently discarded — consider a debug log.

Lines 1008–1009 drop entries that have no cached_at (or a falsy value) without any logging. While acceptable for a cache, adding a logger.debug here would aid diagnosing unexpected pruning, consistent with the debug logs on lines 1023 and 1026–1031 for schema mismatches.

💡 Optional: add debug logging for entries dropped due to missing cached_at
             if not cached_at_str:
+                logger.debug("Pruning entry without cached_at timestamp: %s", key)
                 continue
 
             cached_at = parse_iso_datetime_utc(cached_at_str)
             if not cached_at:
+                logger.debug("Pruning entry with unparseable cached_at: %s", key)
                 continue

@jeremiah-k
Copy link
Owner Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@jeremiah-k
Copy link
Owner Author

/gemini review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant improvements to the caching system by adding schema versioning and validation, which greatly enhances robustness and maintainability. The centralization of cache pruning logic into a new prune_cache_data utility is a commendable refactoring that simplifies the codebase. The added tests, including a new integration test for schema mismatch, are thorough and provide good coverage for the new functionality. My review includes a couple of points for consideration, one regarding a potential discrepancy between documentation and implementation in the Android downloader, and another about a minor type consistency improvement in the cache module. Overall, this is a high-quality contribution.

…he debugging

Remove the defensive prerelease invariant check from release history update in
MeshtasticAndroidAppDownloader, simplifying the logic to just return None when
no releases or no stable releases are present. Add debug logging to cache pruning
to improve observability of entry invalidation, and ensure cache values are
converted to lists for consistent data handling.
@jeremiah-k
Copy link
Owner Author

@coderabbitai review

@jeremiah-k
Copy link
Owner Author

/gemini review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces explicit cache schema versioning and validation, which is a great improvement for the robustness of the caching system. The centralization of cache pruning logic into CacheManager.prune_cache_data is a nice refactoring that simplifies the code and improves maintainability. The addition of comprehensive unit and integration tests, especially for schema mismatch scenarios, ensures the new functionality is working as expected. Overall, this is a high-quality contribution that significantly enhances the fetch system.

@jeremiah-k
Copy link
Owner Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

✅ Actions performed

Full review triggered.

@jeremiah-k jeremiah-k changed the base branch from maint-22-1-review to main February 12, 2026 00:07
@jeremiah-k jeremiah-k merged commit 541824f into main Feb 12, 2026
9 checks passed
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.

1 participant