Repository navigation
Releases: Skare69/clipshelf
Release list
v0.9.0
New features
- Add outbox entry delete and load-older paging
- Bound the outbox and reject shares visibly when full
Bug fixes
- Refuse restore from non-file-backed sqlite databases
- Reject setup passwords similar to the admin email
- Authenticate admin token sessions for reauthentication
- Fetch direct media once under the media size bound
- Bound whole-fetch deadline across slow reads and address retries
- Normalize null screening key, keep re-typed llm key on endpoint move
- Snapshot the default collection before scheduling
- Decline asset downloads whose content type mismatches the viewer
- Show the rejected share count on the hub
- Keep collection and entry load errors visible
- Drop stale library pages and advance the offset only on success
- Android: changing the server endpoint now needs a fresh password sign-in at the new server. The app no longer accepts a matching public instance id as proof and never sends the existing session token to the new server. After the change, the app revokes the old server's session (best effort).
- Separate receipt-mismatch pause from auth pause and harden outbox persistence
- Dedup cased github keys against legacy lowercase entries and tombstones
- Mark required confirm dialog fields
- Screen legacy imports outside the transaction
- Bound logout revocation attempts per call
- Chain outbox continuation instead of backoff after 50 rows
- Replay committed shares, accept charsequence extras, gate setup readiness
- Refill worker slots on completion and keep staging ownership-safe
- Make deploy probes unique and non-destructive
- Honor historical GitHub removal keys
- Correct server import, retry, and view behavior
- Guard backup and restore publication
- Guard exporter links and runtime image audit
- Preserve Android HTTP errors and asset bounds
- Wait up to 40 minutes for the release before attaching the apk
- Separate android durable completions from activity ui updates
- Make restore asset publication crash-safe
- Route expired import sessions through shared auth loss
- Make offline logout revocation explicit
- Expect tzdata on every platform in the license inventory
- Issue invitation links from the approved canonical origin
- Whitelist the third-party notices in the docker build context
- Create the gradle build dir before the license deps dump
- Check license inventory against the multistage image build
- Contain android session tokens to the verified origin
- Reject malformed docker release versions
- Give ci android builds tag history
- Stamp monotonic android release versions
- Enforce concurrent browser import request identity
- Tombstone every contributor on owner entry moderation
- Prevent private admin response caching
Changes
- API error schema change:
/api/error responses now carrydetail(a message) and, for field errors,errors(a list). The olderrorandcodekeys are gone, so clients that readerrororcodemust readdetailinstead. This includes the 409 response when an import file was already imported to a different collection. 405 and CSRF responses do not change. - Add
python clipshelf.py clean: it lists staging work that finished more than 30 days ago (paths and sizes) and deletes nothing.clean --executedeletes exactly the listed paths. Known issue: at release commite2233859,clean --executefails withRuntimeError(nested data lock) and deletes nothing. Commitfadab36(card 9c3e4a9f) fixes this on main. - Android: turn off OS cloud backup of app data (
android:allowBackup="false"). The endpoint, account identity, encrypted session token, and outbox no longer go into Android cloud backups. On Android 12 and later, this flag does not stop device-to-device transfer. - Android release builds for a
v*tag now attach the signed APK to the GitHub release. - The Docker image and CI now install Python dependencies from the hash-locked
requirements.lock(pip install --require-hashes). The image pinspython:3.13-slimby digest, and CI pins its GitHub Actions by commit. - Ship
THIRD_PARTY_NOTICES.mdin the Docker image and in the Android app assets. The image license label is nowMIT AND GPL-2.0-only. - Build/test: mutation testing runs the full CI suite per mutation run
- Build/test: resolve each Robolectric android-all version separately for the test artifact seed
- Build/test: seed Robolectric artifacts through Gradle and stop leaking test JVM threads
- Build/test: the dependency lock gate tolerates platform-conditional pins
- Remove an unused SecureRandom import
- Derive outbox pager visibility from the row count
- Expose the outbox drain loop as a jvm test seam
- Drop dead frontend selectors and exports
- Remove the unused persisted Android admin flag
- Exclude sqlite compiler tools from the runtime image
v0.8.4 - queued capture endpoint semantics
Docs
- Decided the queued Android capture endpoint semantics (review finding A10): a queued share is bound by identity (server instance + account), never by the capture-time hostname. Delivery posts through the active profile's endpoint, and only after that endpoint proves the same identity — a settings-verified host change under the same instance/account moves queued transport, every drain re-verifies identity before any POST, and a receipt must match the row's identity or delivery blocks. A different server or account never acquires queued rows. The outbox row's endpoint column is documented as capture-time provenance for the outbox screen, never a routing input. No behavior change.
Image: ghcr.io/skare69/clipshelf:0.8.4 (amd64 + arm64).
v0.8.3 - contain failed android asset temp files
Bug fixes
- Android asset viewing no longer leaves partial temporary files in the app cache when a download fails or exceeds the size limit; the staging file is now deleted on every error path.
Image: ghcr.io/skare69/clipshelf:0.8.3 (amd64 + arm64).
v0.8.2 - ruff and pip-audit CI gates
CI
- Added a ruff lint gate (conservative E/F plus built-in Django rules, scoped to the
clipshelfpackage viaruff.toml), running before the Django checks in thepythonCI job. - Added a blocking pip-audit dependency audit of
requirements.txt; the current pins audit clean, so no upgrades.
Code cleanup
- Removed an unused import in
clipshelf/acquisition.pyand an unused variable binding in the member-add API (clipshelf/views.py). No behavior change.
Image: ghcr.io/skare69/clipshelf:0.8.2 (amd64 + arm64).
No APK changes.
v0.8.1 - sidebar icons
Nav icons
The sidebar views (Library, Inbox, Collections, Settings, Admin) got inline SVG icons in the same Material style as the in-app action icons. Static markup - they render before JavaScript boots, in the mobile drawer too.
Image: ghcr.io/skare69/clipshelf:0.8.1 (amd64 + arm64). No APK changes.
v0.8.0 - UI overhaul
UI overhaul
One reskin, zero behavior change: the whole stylesheet was rewritten on a new design system while every class, template, and line of JS stayed put.
- Warm graphite surfaces with a brass accent replace the legacy M3 purple; light and dark both tuned for contrast.
- Serif display stack for the brand and view headers; wider measures and a calmer type scale.
- The library grid is now a gapless, hairline-ruled sheet instead of floating cards; status badges became quiet outline chips (filled only for errors); forms got uppercase labels, taller inputs, and consistent focus rings.
- Motion is native CSS: cards and captures reveal on scroll (scroll-driven animations, progressive enhancement), cards lift on hover, thumbnails ease-zoom.
prefers-reduced-motionstill disables all of it. - No new dependencies, no webfonts, no third-party requests — same single-image deployment.
Image: ghcr.io/skare69/clipshelf:0.8.0 (amd64 + arm64). No APK changes. Hard-reload once; afterwards upgrades propagate on normal reloads.
v0.7.3 - transport seams made public
Changes
- The two transport adapters are now public and documented as the test seam:
interpretation.post()(the one HTTP call to the LLM endpoint) andjudgment.ask()(the one screening request). Same code, honest names - test fakes are first-class users of the interface instead of reaching past an underscore.
Deployment
Image: ghcr.io/skare69/clipshelf:0.7.3 (amd64 + arm64). No APK changes this release.
v0.7.2 - native ES modules, no more hard reloads
Changes
- The web app is split into native ES modules (
core.js= transport/state/chrome,panels.js= library/inbox/collections/settings,admin.js= admin) withapp.jsas the entry — still no build step, no framework, no new requests. Script and CSS tags now carry?v=<version>, so upgrades no longer require a hard reload.
Deployment
Image: ghcr.io/skare69/clipshelf:0.7.2 (amd64 + arm64). No APK changes this release. One normal reload after upgrading; hard reloads are no longer needed for future upgrades.
v0.7.0 - Job owns its lifecycle
Changes
- Job owns its lifecycle: every state rewrite now goes through one of six methods on the model (
mark_running,defer,mark_blocked,mark_done,fail,requeue), replacing the scattered field-write sites across worker, views, and services.requeuecarries its own not-while-active rule;failowns the bounded-retry/backoff policy. No behavior change; no payload change.
Deployment
Image: ghcr.io/skare69/clipshelf:0.7.0 (amd64 + arm64). No APK changes this release.
v0.6.6 - verdicts projected by the server
Changes
- Job payloads carry the verdicts:
guardrail(state-scoped) andscreening_warnings. The web app dropped its error-string matching and renders the projections; the Android app shows "Guardrail blocked — findings withheld" and a screened warning count on the entry detail.CONTEXT.mdadded as the domain glossary.
Deployment
Image: ghcr.io/skare69/clipshelf:0.6.6 (amd64 + arm64). APK attached, same signing key — installs over the previous one. Hard-reload the web app after upgrading.