12 KiB
Changelog
All notable changes to snipe are documented here.
Format follows Keep a Changelog.
Versions follow Semantic Versioning.
[0.5.1] — 2026-04-16
Added
Reported sellers tracking — after bulk-reporting sellers to eBay Trust & Safety, cards show a muted "Reported to eBay" badge so users know not to re-report the same seller.
- Migration 012:
reported_sellerstable in user DB (UNIQUE on platform + seller ID, preserves first-report timestamp on re-report). Store.mark_reported/list_reportedmethods.POST /api/reported+GET /api/reportedendpoints.reportedPinia store: optimistic local update, best-effort server persistence.ListingCard: acceptssellerReportedprop; shows.card__reported-badgewhen true.App.vue: loads reported store at startup alongside blocklist.
Community blocklist share toggle — Settings > Community section (signed-in users only, default OFF).
- Toggle persisted as
community.blocklist_sharevia existing user preferences path system. - Backend
add_to_blocklistnow gates community signal publishing on opt-in preference; privacy-by-architecture: sharing is never implicit.
Fixed
- SSE live score push (snipe#1) verified working end-to-end: enrichment thread correctly streams re-scored trust scores via
SimpleQueue → StreamingResponsegenerator, terminates withevent: done. Closed.
[0.5.0] — 2026-04-16
Added
Listing detail page — full trust breakdown for any individual listing (closes placeholder)
ListingView.vuerewritten from "coming soon" stub into a full trust breakdown view.- SVG trust ring:
stroke-dasharrayfill proportional to composite score (0–100), colour-codedlv-ring--high/mid/low(≥80 / 50–79 / <50). - Five-signal breakdown table: account age, feedback count, feedback ratio, price vs. market, category history — each row shows score, max, and a plain-English label.
- Red flag badges: hard flags (
.lv-flag--hard) fornew_account,suspicious_price,duplicate_photo,zero_feedback,established_bad_actor; soft flags (.lv-flag--soft) forscratch_dent_mentioned,long_on_market,significant_price_drop,account_under_30_days. - Triple Red easter egg: new/under-30-days account + suspicious price + photo/actor/zero-feedback/scratch flag combination triggers pulsing red glow animation.
- Partial score warning:
score_is_partialflag shows.lv-verdict__partialnotice and "pending" in affected signal rows. - Seller panel: username, account age, feedback count/ratio, category history JSON, inline block-seller form.
- Photo carousel: thumbnail strip with keyboard-navigable main image.
- Not-found state for direct URL navigation when store is empty.
getListing(platformListingId)getter added to search store.ListingCard.vue: "Details" link wired to/listing/:idroute.
Theme override — user-controlled dark/light/system toggle in Settings
useThemecomposable: module-levelmoderef,setMode()writesdata-themeattribute + localStorage,restore()re-reads localStorage on hard reload.theme.css: explicit[data-theme="dark"]and[data-theme="light"]attribute selector blocks so user preference beats OS media query. Snipe mode override preserved.SettingsView.vue: new Appearance section with System/Dark/Light segmented button group.App.vue:restoreTheme()called inonMountedalongside snipe mode restore.
Frontend test suite — 32 Vitest tests, all green
useTheme.test.ts(7 tests): defaults, setMode, data-theme attribute, localStorage persistence, restore() behaviour.searchStore.test.ts(7 tests): getListing() edge cases, pipe characters in IDs, trustScores/sellers map lookups.ListingView.test.ts(18 tests): not-found state, title/price/score/signals/seller rendering, hard/soft flag badges, no-flags, triple-red class, partial/pending signals, ring colour classes.
Fixed
useTheme.restore()re-reads from localStorage instead of cached module-level ref — prevented correct theme restore after asetMode()call in the same JS session.- Landing hero subtitle rewritten with narrative opener ("Seen a listing that looks almost too good to pass up?") — universal framing, no category assumptions.
- eBay cancellation callout CTA updated to "Search above to score listings before you commit" — direct action vs. passive notice.
- Tile descriptions: concrete examples added ("40% below median", quoted "scratch and dent") for instant domain recognition.
[0.4.0] — 2026-04-14
Added
Search with AI — natural language to eBay search filters (closes #29, Paid+ tier)
QueryTranslator: sends a free-text prompt to a local LLM (via cf-orch, defaulting tollama3.1:8b) with a domain-aware system prompt and eBay Taxonomy category hints. Returns structuredSearchParamsResponse(keywords, price range, condition, category, sort order, pages).EbayCategoryCache: bootstraps from a seed list; refreshes from the eBay Browse API Taxonomy endpoint on a 7-day TTL.get_relevant(query)injects the 10 closest categories into the system prompt to reduce hallucinated filter values.POST /api/search/build— tier-gated endpoint (paid+) that accepts{"prompt": "..."}and returns populatedSearchParamsResponse. Wired toLLMRoutervia the Peregrine-style shim.LLMQueryPanel.vue: collapsible panel above the search form with a text area, a "Search with AI" button, and an auto-run toggle. A11y (accessibility):aria-expanded,aria-controls,aria-live="polite"on status, keyboard-navigable,prefers-reduced-motionguard on collapse animation.useLLMQueryBuildercomposable: managesbuildQuery()state machine (idle | loading | done | error), exposesautoRunflag, callspopulateFromLLM()on the search store.SettingsView: new "Search with AI" section with the auto-run toggle persisted to user preferences.search.ts:populateFromLLM()merges LLM-returned filters into the store; guardsv-model.numberempty-string edge case (cleared price inputs sentNaNto the API).
Preferences system
Store.get_user_preference/set_user_preference/get_all_preferences: dot-path read/write over a singletonuser_preferencesJSON row (immutable update pattern viacircuitforge_core.preferences.paths).Store.save_community_signal: persists trust feedback signals tocommunity_signalstable.preferencesStore(Pinia): loaded after session bootstrap;load()/set()/get()surface preferences to Vue components.
Community module (closes #31 #32 #33)
correctionsrouter wired:POST /api/community/signalnow lands in SQLitecommunity_signals.COMMUNITY_DB_URLenv var documented in.env.example.
Fixed
useTrustFeedback: prefixes fetch URL withVITE_API_BASEso feedback signals route correctly under menagerie reverse proxy.App.vue: skip-to-main link moved before<AppNav>so keyboard users reach it as the first focusable element (WCAG 2.4.1 bypass-blocks compliance).@/path alias removed from Vue components (Vite config had no alias configured; replaced with relative imports to fix production build).search.ts: LLM-populated filters now sync back intoSearchViewlocal state so the form reflects the AI-generated values immediately.- Python import ordering pass (isort) across adapters, trust modules, tasks, and test files.
Closed
#29LLM query builder — shipped.#31#32#33Community corrections router — shipped.
[0.3.0] — 2026-04-14
Added
Infrastructure and DevOps
.forgejo/workflows/ci.yml— Python lint (ruff) + pytest + Vue typecheck + vitest on every PR/push to main. Installs circuitforge-core from GitHub mirror so the CI runner doesn't need the sibling directory..forgejo/workflows/release.yml— Docker build and push (api + web images) to Forgejo container registry onv*tags. Builds both images multi-arch (amd64 + arm64). Creates a Forgejo release with git-cliff changelog notes..forgejo/workflows/mirror.yml— Mirror push to GitHub and Codeberg on main/tags.install.sh— Full rewrite following the CircuitForge installer pattern: colored output,--docker/--bare-metal/--helpflags, auto-detection of Docker/conda/Python/Node/Chromium/Xvfb, license key prompting, structured named functions.docs/nginx-self-hosted.conf— Sample nginx config for bare-metal self-hosted deployments (SPA fallback, SSE proxy settings, long-term asset caching).docs/getting-started/installation.md— No-Docker install section: bare-metal instructions, nginx setup, Chromium/Xvfb note.compose.override.yml—cf-orch-agentsidecar service for routing vision tasks to a cf-orch GPU coordinator (--profile orchopt-in).CF_ORCH_COORDINATOR_URLenv var documented..env.example—CF_ORCH_URLandCF_ORCH_COORDINATOR_URLcomments expanded with self-hosted coordinator guidance.
Screenshots (post CSS fix)
- Retook all docs screenshots (
01-hero,02-results,03-steal-badge,hero) after the color-mix token fix so tints match the theme in both dark and light mode.
Closed
#1SSE live score push — already fully implemented in 0.2.0; closed.#22Forgejo Actions CI/CD — shipped.#24nginx config for no-Docker self-hosting — shipped.#25Self-hosted installer script — shipped.#15cf-orch agent in compose stack — shipped.#27MCP server — already shipped in 0.2.0; closed.
[0.2.0] — 2026-04-12
Added
Trust signal UI — community feedback on seller trust scores (MIT component layer)
web/src/components/TrustFeedbackButtons.vue: "This score looks right / This score is wrong" button pair displayed below the trust badge on each listing card. Shows "Thanks, noted." on submission with no countdown or urgency.web/src/composables/useTrustFeedback.ts:FeedbackStatemachine (idle | sending | confirmed | disputed). Fail-soft: any network error still transitions to confirmed state — the UI never surfaces signal pipeline failures.- Slotted into
ListingCard.vueafter the trust badge, inside.card__score-col. - WCAG (Web Content Accessibility Guidelines) 2.1 compliance:
aria-live="polite"on confirmation message,aria-busyduring send, keyboard-focusable buttons withfocus-visiblestyles,prefers-reduced-motionguard on transitions. - Uses
--trust-high/--trust-lowtheme CSS custom properties for color consistency.
Note: The backend signal endpoint (POST /api/community/signal) and seller signal store are gated on cf-orch community postgres landing. The UI degrades gracefully when the endpoint is absent.
Forgejo feedback FAB (floating action button)
FeedbackButton.vue: floating "Feedback" button in the corner of every view. Opens a two-step modal (type + description → attribution + confirm) that files a Forgejo issue againstCircuit-Forge/snipe. Hidden whenFORGEJO_API_TOKENis unset or in demo mode.GET /api/feedback/status— returns{"enabled": bool}so the button never flashes before checking.POST /api/feedback— files the issue; returnsissue_numberandissue_url.
Live SSE score push (closes #1)
- Background enrichment results pushed to the browser via Server-Sent Events as trust scores complete.
[0.1.0] — 2026-03-25
Added
Initial beta release of Snipe — eBay listing intelligence and trust scoring.
- Listing search via eBay scraper (Kasada bypass with headed Chromium + Xvfb).
- Trust score composite: feedback rate, negative feedback ratio, member age, zero-feedback penalty.
TrustScoredataclass with red flags, partial score flag, composite score (0-100).- Vue 3 SPA frontend: search view, listing card grid, listing detail view, blocklist management.
- FastAPI backend:
/api/search,/api/enrich,/api/blocklist. - Keyword filtering for search queries.
- SQLite persistence via cf-core
dbmodule.