summaryrefslogtreecommitdiff
path: root/.githooks/pre-commit
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-09-25 17:09:13 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-09-25 17:09:13 +0000
commit593ee7740de24aae22ddec1dc5a2e083fff06bd3 (patch)
treea7cb89b34e2ff5f8ad32073a1078f70468daf0c0 /.githooks/pre-commit
parentf04a01c672c01f4913d4b9bbaf2fc4febbaec08c (diff)
Slow drip: work through an archive a few episodes at a time
The second of Phase 2's three tracks. A show can be set to release its back catalogue on a cadence -- one a day, oldest first, by default -- and while drip is on the show lists only what has been released rather than the raw feed. A 600 episode archive then reads as a show you are keeping up with instead of a wall. A release always enqueues, and deliberately does not go through the rule engine. Drip decides when you see an episode and the rules decide what happens to one; running a released episode through the rules as well would let a rule silently cancel a release, which reads as the drip being broken. Three pieces of arithmetic worth keeping, all in DripSchedule and all tested: The clock advances by whole intervals rather than to now. Moving it to now discards the part-interval already elapsed, and a six-hourly worker against a daily drip loses hours every day until "one a day" means one every day and a bit. A long absence is capped at ten and the excess is forgiven rather than carried. A month away owes thirty episodes; handing those over empties the archive into the queue, which is the thing the feature exists to avoid. Carrying the debt instead would just pay it out as a capped burst on each of the next three runs. Switching drip on settles what it already owes: everything played or already queued is released up front, because hiding episodes you have heard makes a show followed for a year look like it has three, and hiding one mid-queue strands it where nothing can reach it. Re-enabling starts the cadence from now rather than paying off a debt accrued while it was off. Visibility is a query parameter, not stored state, so switching drip off restores the whole catalogue without touching a row. Android Auto browses the same set. Feed reconciliation deliberately still sees everything -- matching against the visible set alone would read a held-back episode as missing and re-insert it on every refresh. RFC 5005 archive paging is what gives a drip anything to drip: FeedArchiveWalker follows prev-archive pages, resolving relative hrefs against the page that carried them, and stops on a loop, a page cap, or a fetch failure -- keeping what it collected and reporting why, because half an archive is useful and a silent half surfaces months later as "why did this show run out?". Two gaps found while wiring it up, both fixed here: the subscription screen had no snackbar at all, so a refresh started from it reported nothing and an archive fetch would have been silent; and both toggles were bare Switches with no accessible name, which TalkBack cannot announce and the UI checker cannot tap. Schema v2 -> v3. The four non-null drip columns carry SQL defaults because SQLite cannot add a NOT NULL column without one, declared on the entity too so the migration and the exported schema describe the same table. Verified twice: the migration test now covers 1 -> 3 straight through, and a real v2 database seeded with a subscription, an episode at position 424242 and a rule was upgraded in place on a device with all three surviving and drip defaulting off. OPML moved to its own view model rather than growing ListenViewModel past its function limit again -- it shares nothing with the library, is used by one screen, and the settings screen now depends on it alone. The exported-schema trap from the last commit happened again, after I had written the warning down. Step 9 of the pre-commit hook now refuses a commit that modifies an already-committed schema JSON, since a note was demonstrably not enough. No permission changes. 333 unit tests green, detekt and lint clean, coverage 63.63 -> 65.30. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to '.githooks/pre-commit')
-rwxr-xr-x.githooks/pre-commit28
1 files changed, 20 insertions, 8 deletions
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
index 32b492a..4a3bcc5 100755
--- a/.githooks/pre-commit
+++ b/.githooks/pre-commit
@@ -9,23 +9,23 @@ fail() {
exit 1
}
-echo "== [1/8] Build =="
+echo "== [1/9] Build =="
./gradlew :app:compileDebugKotlin -q
-echo "== [2/8] Tests =="
+echo "== [2/9] Tests =="
./gradlew :app:testDebugUnitTest -q
-echo "== [3/8] Static analysis: lint =="
+echo "== [3/9] Static analysis: lint =="
if ! ./gradlew :app:lintDebug -q; then
fail "lint failed -- fix all lint ERRORS before committing (warnings are fine to accumulate, see CLAUDE.md)."
fi
-echo "== [4/8] Static analysis: detekt (code-quality auditor) =="
+echo "== [4/9] Static analysis: detekt (code-quality auditor) =="
if ! ./gradlew :app:detekt -q; then
fail "detekt found new issues beyond the tracked baseline. Fix them, or if they're genuinely pre-existing debt being touched incidentally, regenerate the baseline with './gradlew :app:detektBaseline' and explain why in the commit message."
fi
-echo "== [5/8] Coverage must not decrease =="
+echo "== [5/9] Coverage must not decrease =="
./gradlew :app:jacocoTestReport -q
REPORT="app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml"
BASELINE_FILE=".coverage-baseline"
@@ -59,7 +59,7 @@ else
echo "pre-commit: coverage ${BASELINE}% -> ${CURRENT}%"
fi
-echo "== [6/8] WebView JavaScript justification =="
+echo "== [6/9] WebView JavaScript justification =="
STAGED_KT=$(git diff --cached --name-only --diff-filter=ACM -- '*.kt' || true)
if [ -n "$STAGED_KT" ]; then
for f in $STAGED_KT; do
@@ -73,14 +73,14 @@ if [ -n "$STAGED_KT" ]; then
done
fi
-echo "== [7/8] Manifest permission diff =="
+echo "== [7/9] Manifest permission diff =="
if git diff --cached --name-only | grep -q '^app/src/main/AndroidManifest.xml$'; then
if git diff --cached -- app/src/main/AndroidManifest.xml | grep -qE '^\+.*<uses-permission'; then
echo "pre-commit: WARNING -- AndroidManifest.xml adds a new <uses-permission>. Make sure the commit message says why."
fi
fi
-echo "== [8/8] Secret scan =="
+echo "== [8/9] Secret scan =="
if [ -z "${SECRET_SCAN_OVERRIDE:-}" ]; then
SECRET_HIT=$(git diff --cached -U0 -- . ':!*.lock' | grep -E '^\+' | grep -viE '^\+\+\+' | grep -E '(api[_-]?key|secret|password|token)["'\'' ]*[:=]["'\'' ]*[A-Za-z0-9_\-]{16,}' || true)
if [ -n "$SECRET_HIT" ]; then
@@ -91,4 +91,16 @@ else
echo "pre-commit: secret scan skipped (SECRET_SCAN_OVERRIDE set)"
fi
+echo "== [9/9] Exported Room schemas are append-only =="
+# A schema JSON already committed describes a database version that exists on a phone. Room
+# rewrites the file for whatever version the @Database annotation declares, so editing an entity
+# before bumping that number silently overwrites the record of the old shape -- and the migration
+# test then validates happily against a schema that never shipped. It happened twice building
+# Phase 2, and a note in CLAUDE.md did not prevent the second time.
+SCHEMA_EDITS=$(git diff --cached --name-only --diff-filter=M -- 'app/schemas/**/*.json' || true)
+if [ -n "$SCHEMA_EDITS" ]; then
+ echo "$SCHEMA_EDITS" >&2
+ fail "an already-committed Room schema was modified (see above). Bump the database version first so a new file is written, then restore these with: git checkout -- app/schemas/"
+fi
+
echo "pre-commit: all checks passed."