Releases: Shaan-alpha/Skill-Issue
Releases · Shaan-alpha/Skill-Issue
v1.0.0
First stable release. Caps the v0.9.x beta-hardening line with launch polish.
Added
- Rich link previews for the homepage. Sharing the site now renders a branded Open Graph / Twitter card (image, title, description).
- The search box is focused on arrival (desktop), so you can type a username immediately.
- Analyze another profile without leaving a report — a search box now lives on the report page.
Changed
- Removed unused starter assets.
Fixed
- Mentor-mode advice no longer shows raw field names (e.g.
engineering_maturity) — it reads in plain English. - Tighter spacing at the top of the mobile landing page.
- The creator scorecard no longer overflows horizontally on mobile.
v0.9.8
Added
- Launch landing sections. Beneath the hero: a "see it in action" row of example profiles linking to live reports, a "how it works" methodology section, and a "Star on GitHub" call-to-action.
v0.9.7
Added
- Privacy Policy and Terms of Service. Plain-language legal pages at
/privacyand/terms, linked from a new site-wide footer.
v0.9.6
Added
- Load-test harness (
backend/loadtest/) — a reusable open-loop load tester for the backend warm/analyzepath, reporting latency percentiles, error rate, and achieved throughput against pass/fail thresholds. Includes a runbook for a local 100 RPS warm-cache run and for pointing at a deployed target.
v0.9.5
Security
- Full pre-launch security review — no high or critical findings. Authorization (ownership checks on every mutation), session encryption, OAuth CSRF protection, SQL-injection safety, output escaping, and SSRF protection on user-supplied input were all verified sound.
Changed
- Tightened the GitHub sign-in permission to read-only. Sign-in previously requested a scope that technically allowed writing to your public repositories; it now requests read-only access only, since Skill Issue exclusively reads public data. (Existing sessions are unaffected; the narrower permission applies on next sign-in.)
- Added HTTP security headers (
X-Frame-Options,X-Content-Type-Options,Referrer-Policy,Permissions-Policy) plus a report-only Content-Security-Policy as a baseline for hardening before public launch.
v0.9.4
Changed
- Database connection pool size is now configurable via the
DB_POOL_SIZEandDB_MAX_OVERFLOWenvironment variables (defaults unchanged at 5 each), so it can be tuned in production without a redeploy. Telemetry showed no connection-pool pressure at current scale, so this ships the capability without changing the running defaults.
Fixed
- Search button no longer sticks on a spinner after pressing browser Back. Returning to the landing page from a report could leave the analyze button spinning and its input disabled. The v0.9.3 attempt fixed the wrong mechanism; this is the real fix.
v0.9.3
Added
- Delete saved analyses. Each card on your history page (
/me) now has a ✕ to remove an analysis, with a brief Undo in case you change your mind. - Creator flair. The project's creator account gets a distinguished golden scorecard (gold ring, chips, and badges) and a "CREATOR · SKILL ISSUE" tag — on the report page and the shareable card, so the person who built Skill Issue is recognizable on their own report.
Fixed
- Stuck search spinner. After analyzing a profile and pressing the browser Back button, the landing-page search button could stay stuck spinning (and the input disabled). It now resets correctly when the page is restored.
v0.9.2
Added
- Rate limiting on analysis and narrative requests. Anonymous visitors are limited per IP; signed-in users get a higher per-account limit (they analyze with their own GitHub token). Exceeding a limit returns a clear, on-voice "slow down" page with a retry hint instead of a generic error. Defaults: 20 analyses / 30 narratives per hour for anonymous visitors, 60 / 90 for signed-in users — all tunable via env vars without a redeploy.
Changed
- The internal rate-limit counter is now keyed by a generic subject (
user:<id>orip:<addr>), shared across the force-refresh, analyze, and narrative limits.
Notes
- New env var
INTERNAL_PROXY_SECRET(set the same value on the frontend and backend) lets the site attribute analysis requests to the real visitor IP rather than the server's. Until it's set, anonymous analysis is not IP-limited — so real visitors are never throttled by mistake — while narrative and signed-in limits stay active. - All cache layers remain fail-open: if Redis is unavailable, requests are allowed rather than blocked.
v0.9.1
Fixed
/me/analysesN+1 query. The list endpoint was issuing oneSELECT AnalysisRunper row inside the serializer loop (21 round-trips per 20-row page).list_user_analysesalready JOINedAnalysisRunvialatest_run_idbut was discarding the join result; it now returnstuple[list[tuple[Analysis, AnalysisRun | None]], int]so the route consumes the joined row directly. Net: 1 query per page instead of 1+N. No JSON contract change.
Added
REPORT_SCHEMA_VERSIONconstant inapp/cache/keys.py. Layer A Report cache keys now carry a per-namespace version prefix: composed key shape issi:v1:report:v1:<lowercased-username>. BumpingREPORT_SCHEMA_VERSIONon futureReport-shape changes invalidates only the report namespace — no more silent ~6h of cross-namespace Pydantic validation warnings on every schema bump, and no need to bump globalKEY_PREFIX(which would nuke GH/narrative/lock/budget caches too).
Notes
- Existing
si:v1:report:<username>keys orphan in Upstash until their 6h TTL expires. No manual cache purge needed; the new keys win on first request, and old keys GC at TTL with bounded memory cost. - The
Analysismodel is unchanged. The N+1 fix is purely at the persistence/router layer; no new relationship, no new query path.
v0.9.0
Added
- Bounded GitHub fan-out in
ingest_profile. A new per-callasyncio.Semaphore(settings.gh_ingest_concurrency)(default 8) wraps bothasyncio.gatherblocks — the up-to-20 root-contents enrichment and the up-to-10 commit-history fetch. A single analysis can no longer burst past GitHub's secondary rate-limit threshold, and anonymous-token sharing scales to more analyses/hr before the 5000/hr ceiling bites. Sequentiallist_languagesloop is intentionally untouched (already bounded by construction; parallelizing it would increase peak concurrent for the same cost). Opens the v0.9.x Beta hardening family. GH_INGEST_CONCURRENCYenv var (optional, default8). Tune in prod without redeploy: raise if Layer A cache hit-rate is high and you want lower analysis latency; lower if you're hitting 403s. Backend env only.
Tests
- 2 new in
tests/test_ingestion.pyagainst aFakeGitHubClientthat records max in-flight calls across a 50-repo synthetic profile. Default-cap test assertsmax_in_flight ≤ 8; override-cap test (Settings(gh_ingest_concurrency=2)via monkeypatch) assertsmax_in_flight ≤ 2. Suite: 261 → 263 non-DB-fixture pass.
Notes
- This is the first slice of the v0.9.x Beta hardening family. Decomposed 2026-05-26 into: bounded fan-out (this) →
/me/analysesN+1 + Layer A cache schema version → DB pool tune → rate limiting + abuse heuristics → security review + load test → legal docs. Each slice is shippable in isolation. - Tail latency on heavy profiles increases by ~500ms on a cold cache (3 batches of 8 instead of 1 batch of 20). Layer A's 6h Report cache absorbs this cost — first hit per user pays it once, subsequent hits are sub-200ms. RUM via PostHog (v0.8.0) will surface real-user impact post-deploy.
_gateduses Python 3.12 PEP 695 generic syntax (async def _gated[T](sem, coro)) instead of legacyTypeVar— eliminates one import + satisfies ruffUP047.