fix: derive refresh test freshness epochs from the clock - #53
Merged
Conversation
RefreshEngine.run compares the bound discovery policy epoch against its own wall clock, and the ledger's commit_initial_round then requires the inventory authority to agree with that bound policy. Four tests in test_refresh_discovery.py wrote the literal month they were authored in, so they agreed with the engine for exactly one calendar month. On 2026-09-01 the clock rolled over and every one of them began raising "inventory authority conflicts with bound discovery policy" on all five interpreters at once, leaving the Required CI aggregate red and every open pull request unmergeable through no fault of its own. Both engine-driving test modules now derive the epoch the same way the engine does, and the staleness test builds its rejected month as an explicit offset from today rather than naming one. Two guard tests were passing on the right status for the wrong reason. test_generation_start_binds_discovery_preflight_before_inventory_send was tripping the epoch mismatch instead of the missing s2 credential it exists to prove, so both it and the staleness test now pin the exact detail string their guard must return. A new contract test fails on any double-quoted YYYY-MM literal in a test_refresh_*.py module that drives RefreshEngine, so this cannot be reintroduced silently. Single-quoted months inside the SQL of test_refresh_corpus.py are deliberate drift-guard mismatches and stay. Verified against a simulated 2027-02 clock, and the full suite runs 2077 passed, 2 skipped, 7 deselected with ruff and mypy clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What broke
RefreshEngine.runcompares the bound discovery policy epoch against its own wall clock (citeforge/refresh/engine.py:116), and derives the inventory task epoch from that same clock (engine.py:142).Ledger.commit_initial_roundthen requires the inventory authority to agree with the bound discovery policy (citeforge/refresh/ledger.py:4463).Four tests in
tests/test_refresh_discovery.pywrote the literal month they were authored in ("2026-08"), so they agreed with the engine for exactly one calendar month. When the clock rolled to2026-09the engine started deriving2026-09while the bound policy still said2026-08, and all four began raising:That is a test-only defect. No production code path pins a month, and the monthly workflow derives its own with
date +%Y-%m.Blast radius
Every
Test (py3.10 … py3.14)leg failed identically, which failed theRequired CIaggregate and left PR #52 (a Dependabotuvbump touching onlyrequirements-build.inand.lock)BLOCKEDon a failure it did not cause. Any PR opened after 2026-09-01 would have been blocked the same way.Fix
Both engine-driving test modules derive the epoch exactly as the engine does. The staleness test builds its rejected month as an explicit offset from today rather than naming one.
Two guard tests were also passing on the right status for the wrong reason.
test_generation_start_binds_discovery_preflight_before_inventory_sendwas tripping the epoch mismatch instead of the missings2credential it exists to prove. Both it and the staleness test now pin the exactdetailstring their guard must return, so a guard that starts firing for a different cause fails instead of passing silently.test_no_refresh_test_pins_a_literal_freshness_epochfails on any double-quotedYYYY-MMliteral in atest_refresh_*.pymodule that drivesRefreshEngine, so this cannot be reintroduced. Single-quoted months inside the SQL oftest_refresh_corpus.pywrite a deliberately mismatching epoch to trip a drift guard and are correctly left alone.Verification
Run locally on Python 3.14.7 against
origin/main.ValueError, before any edit.pytest -m 'not live'(CI's exact invocation): 2077 passed, 2 skipped, 7 deselected.ruff check citeforge/ tests/ main.py: clean.mypy citeforge/ main.py: clean, 56 source files.2027-02clock: all pass, confirming the time coupling is gone rather than merely re-pinned to the current month.test_refresh_discovery.py, then restored.Merging this unblocks #52.