Releases: Alih-b/Josty
Releases · Alih-b/Josty
Release list
v0.7.1
What's Changed
- feat(v0.7.0): SQLite breaker persistence, stdin fetch pipeline & boundary refactor by @Alih-b in #84
- feat(fanout): per-run bounded admission with honest sheds by @Alih-b in #85
- chore: drop deadweight docs, generated reports and the scenario harness by @Alih-b in #88
- ci: publish to PyPI by trusted publishing on release by @Alih-b in #87
- chore(release): 0.7.1 by @Alih-b in #89
Full Changelog: v0.6.1...v0.7.1
v0.6.1
Patch release. Housekeeping on top of v0.6.0.
Fixed
tests/scenario_eval.pyandtests/benchmark.pyno longer buildsys.pathfrom the pre-refactor.agents/skills/josty/src. They load the source tree atsrc/, so the scenario eval and frozen-corpus replay can no longer silently score whicheverjostyhappened to be installed.
Removed
- Seven unused
datetime.UTCcompatibility shims and the unreferencedAUTHORITATIVE_DOMAINSalias. No public API, CLI, or schema change.
Changed
- CI runs the declared Python 3.10 floor alongside 3.11–3.13.
- The development
rufffloor is now 0.16.8, matching the version CI resolves.
Full changelog: https://github.com/Alih-b/Josty/blob/main/CHANGELOG.md
v0.6.0
Changelog
All notable changes follow Keep a Changelog and
Semantic Versioning.
[0.6.0] - 2026-09-19
Added
- CLI exit codes now follow the search envelope:
status="failed"exits1, so
a total outage is visible to exit-code checkers.complete,degraded, and
emptystay0(readpartial/coveragein-band), and usage or validation
errors stay2. JSON is printed tostdoutfirst in every search case (#42). fetch.status="noop"when--fetchwas requested but the SERP produced no
results to fetch.skippednow means only "fetch was not requested". Additive
enum value; schema stays1.0(#56).
Changed
- Successful searches with no final results now report
status="empty"instead
of"complete"(#58). Schema remains1.0; failure precedence, fetch and
diagnose statuses are unchanged. - This intentionally changes the previous documented status contract. Strict
consumers that validate status values must acceptemptybefore upgrading;
an unchanged schema version does not guarantee compatibility for those consumers. - Status is recomputed when cached envelopes are read: a legacy
complete
envelope with no results and no branch failures now reads asempty.
An emptySearchRunwith no provider entries also reportsempty, with
provider_count=0,coverage=null, andpartial=false. - The Python package moved out of the agent skill directory to a repo-root
src/josty/layout, and the single 2,506-lineengine.pywas split into
focused modules (status,models,errors,ranking,cache,breaker,
backends,fetch) withengine.pykeeping theJostyfacade. The public
jostyAPI and the CLI are unchanged; this is a maintainer-facing change.
Fixed
- The
Josty(...)library default formax_content_charsis now8000, matching
the CLI, instead of50000. Python API callers no longer silently receive up to
six times more page text per result than the command line (#59).
[0.5.2] - 2026-09-05
Added
- Search envelope coverage and fanout telemetry (schema 1.0 additive):
provider_count,nonempty_provider_count,coverage,query_variant_count,
andrequest_count.status=completewith a single contributing engine is now
visible instead of looking like a fused multi-engine confirmation. - Fetch-phase counters on the envelope
fetchobject (requested,attempted,
ok,failed,status). A total extraction miss degrades the run. --diagnoseenvelopes setphase: "transport",probe: "https_host", and a
note that homepage HTTPS reachability is not search-backend health.
Fixed
- SERP cache identity no longer includes
fetch. Search then--fetchreuses the
cached SERP and only downloads pages, instead of repeating the provider fanout.
Expect a one-time cold SERP cache after upgrading (key shape changed).
[0.5.1] - 2026-09-05
Added
--versionCLI flag, single-sourced from the same__version__literal that drives the
build metadata (closes the SECURITY.md reporting instruction referencing it).
Fixed
- Repository URLs normalized to the canonical
Alih-b/Jostycasing (pyproject metadata,
README links, GitHub APIUser-Agent); GitHub redirects masked the drift. - README development flow creates and activates a virtualenv before the editable install
(PEP 668 externally-managed-environment on Debian/Ubuntu system Python). - CONTRIBUTING Python floor reconciled to the packaging floor: 3.10 or newer.
- RRF fusion and query-variant merge clone caller-owned results before backfilling
engine_ranks, so fusion no longer mutates input lists. - Search-error classification uses word-boundary tokens and status codes first:
"blocked"no longer matches"unblocked", and HTTP 401/403 iserror_kind: "blocked"
rather thanrate_limited. CircuitBreaker.get_state()is a read-only snapshot (expired OPEN is reported as
HALF_OPEN without clearing failures or flipping stored state).- HALF_OPEN admits a single in-flight trial probe; concurrent fanout callers skip until
that probe completes. - Consecutive trip counts decay after idle time past the last backoff plus the failure
window, so a backend idle for hours does not resume at max exponential backoff. --diagnoseskips OPEN circuits instead of probing them over the network.- Timed-out DDGS calls occupy a bounded executor slot until the ghost thread returns;
further work is skipped witherror_kind: "skipped"when the pool is saturated. - CLI JSON sanitizes non-finite floats to
nullso one NaN field cannot fail the query.
[0.5.0] - 2026-09-03
Added
- Per-engine search fanout: backend groups (
"brave,duckduckgo") now issue one ddgs call
per engine instead of one blended group call. Group-level RRF fusion is preserved, with
group-internal ranking now owned by Josty: a URL's position is its best rank across
engines, without ddgs's hidden frequency voting or wikipedia pin.providers[]reports
exactly one status per engine, aggregated across query variants (result_count= distinct
canonical URLs;error_kindis the most severe real failure across variants so partial
throttling stays visible;empty/skippednever attach to a non-empty hit;erroris
the first failure message) — an engine that silently returns empty or fails
inside a healthy group is visible instead of absorbed. The circuit breaker is per-engine
as a result. Unlike raw ddgs, which early-stops and can leave engines unqueried at small
limits, Josty always queries every configured engine: complete per-engine breaker health
is worth the extra page-1 requests (bounded by engine count ×max_query_variants). - Engine-availability gate: engines that are unknown or disabled in the installed ddgs
(e.g. ddgs 9.16.0 has bing/yandex text engines disabled upstream) are skipped with
ok=false,error_kind="skipped"and a named error, instead of triggering ddgs's
silent fallback tobackend="auto"(all engines) or being dropped without a trace. - Default text backends updated to engines ddgs 9.16.0 actually serves:
("brave,duckduckgo", "google,mojeek,startpage", "yahoo")— the previous defaults
included bing and yandex, which ddgs has disabled, silently running 6 engines instead
of the configured 8. - Circuit-breaker cool-down skips now report
error_kind: "skipped"(schema 1.0 additive)
on the affectedproviders[]entries, so agents can distinguish a deliberate breaker
skip from an unclassifiedunknownfailure. --diagnosenow skips unknown/disabled engines witherror_kind="skipped"and a named
error instead of probing their hosts and reporting a generic failure.
Fixed
SearchRun.partialnow accounts for aggregated per-engine statuses whose query variants
partially failed (ok=truewith a failureerror_kind): a run where one variant was
throttled or errored reportsdegradedinstead of a cleancomplete."empty"remains a
successful empty branch and does not degrade the run.- Engines configured in multiple groups are queried once, in their first group; duplicate
names across groups no longer double-call upstream or duplicateproviders[]entries. - Aggregated
error_kindno longer letsemptyorskippedoutrank a clean hit: a
variant that returned URLs keepserror_kind=nulleven if a sibling variant was empty
or skipped.emptyis only emitted whenok=trueandresult_count=0;skippedonly
when no variant reached the engine. - Empty-ok branches no longer call
record_successon the circuit breaker, so an empty
query variant cannot wipe sibling rate-limit failures. Only a non-empty success clears
the breaker. Breaker state is guarded with a lock; expired cool-down uses.popinstead
ofdel. --diagnosemapswikipediaandgrokipediato their upstream hosts. An available
engine with no mapped host is skipped with a namederror_kind="skipped"instead of
unknown/ "no known upstream host".- Fetch
Content-Typematching uses the media type token only (sotext/html; charset=utf-8
still works) and rejects a missing header or substring spoofs such as
application/pdf; x=text/html. - Fetch URL validation blocks multicast destinations (
224/4,ff00::/8) in addition to
non-global addresses. - Search cache creation no longer falls back to world-shared
/tmp/josty_cache.db; if the
cache directory cannot be created, caching is disabled. New cache files are mode0600.
[0.4.0] - 2026-09-02
Added
- Envelope field
run_at(ISO8601 UTC, optional, schema 1.0 compatible): the moment the
search was executed. Cached hits preserve the originalrun_at, so agents can judge
the age of acached: trueresult instead of trusting it blindly. - Freshness TTL floors for the search cache:
timelimit=dentries expire after 30
minutes,timelimit=wafter 2 hours, andcategory=newsafter 1 hour (previously a
flat 6 hours for everything). A caller-configured shortercache_ttlis always
respected. - Scenario-eval staleness check (
require_run_at,max_age_s) plus a frozen
stale_news_day_old_cachefixture that pins the pre-fix behavior as
intended_misleading— cached day-news staleness is now measured, not silent. - Empty-ok search branches now set
providers[].error_kindto"empty"(schema 1.0 compatible)
so callers can tell a real empty result from an unclassified success. - Diagnose envelope field
challenged: true when a reachable probe returns HTTP 401, 403, or 429. - Search cache access telemetry (
hit_count,last_accessed), a 5,000-row prune ceiling, and
envelope flagcached(true only on cache hit). --cache-statsCLI flag (plusSearchCache.stats()/Josty.cache_stats()) reporting
aggregate cache telemetry — rows, payload bytes, cumulative hits — so the bounded cache is
inspectable wit...
v0.5.2
Coverage, fanout, fetch-phase, and transport diagnose.
Added
- Search envelope coverage and fanout telemetry (schema 1.0 additive):
provider_count,nonempty_provider_count,coverage,query_variant_count, andrequest_count.status=completewith a single contributing engine is now visible instead of looking like a fused multi-engine confirmation. - Fetch-phase counters on the envelope
fetchobject (requested,attempted,ok,failed,status). A total extraction miss degrades the run. --diagnoseenvelopes setphase: "transport",probe: "https_host", and a note that homepage HTTPS reachability is not search-backend health.
Fixed
- SERP cache identity no longer includes
fetch. Search then--fetchreuses the cached SERP and only downloads pages, instead of repeating the provider fanout.
v0.5.1
[0.5.1] - 2026-09-05
Added
--versionCLI flag, single-sourced from the same__version__literal that drives the
build metadata (closes the SECURITY.md reporting instruction referencing it).
Fixed
- Repository URLs normalized to the canonical
Alih-b/Jostycasing (pyproject metadata,
README links, GitHub APIUser-Agent); GitHub redirects masked the drift. - README development flow creates and activates a virtualenv before the editable install
(PEP 668 externally-managed-environment on Debian/Ubuntu system Python). - CONTRIBUTING Python floor reconciled to the packaging floor: 3.10 or newer.
- RRF fusion and query-variant merge clone caller-owned results before backfilling
engine_ranks, so fusion no longer mutates input lists. - Search-error classification uses word-boundary tokens and status codes first:
"blocked"no longer matches"unblocked", and HTTP 401/403 iserror_kind: "blocked"
rather thanrate_limited. CircuitBreaker.get_state()is a read-only snapshot (expired OPEN is reported as
HALF_OPEN without clearing failures or flipping stored state).- HALF_OPEN admits a single in-flight trial probe; concurrent fanout callers skip until
that probe completes. - Consecutive trip counts decay after idle time past the last backoff plus the failure
window, so a backend idle for hours does not resume at max exponential backoff. --diagnoseskips OPEN circuits instead of probing them over the network.- Timed-out DDGS calls occupy a bounded executor slot until the ghost thread returns;
further work is skipped witherror_kind: "skipped"when the pool is saturated. - CLI JSON sanitizes non-finite floats to
nullso one NaN field cannot fail the query.
v0.5.0 — Per-engine search fanout and availability gate
Added
- Per-engine search fanout: backend groups (
"brave,duckduckgo") now issue one ddgs call
per engine instead of one blended group call. Group-level RRF fusion is preserved, with
group-internal ranking now owned by Josty: a URL's position is its best rank across
engines, without ddgs's hidden frequency voting or wikipedia pin.providers[]reports
exactly one status per engine, aggregated across query variants (result_count= distinct
canonical URLs;error_kindis the most severe real failure across variants so partial
throttling stays visible;empty/skippednever attach to a non-empty hit;erroris
the first failure message) — an engine that silently returns empty or fails
inside a healthy group is visible instead of absorbed. The circuit breaker is per-engine
as a result. Unlike raw ddgs, which early-stops and can leave engines unqueried at small
limits, Josty always queries every configured engine: complete per-engine breaker health
is worth the extra page-1 requests (bounded by engine count ×max_query_variants). - Engine-availability gate: engines that are unknown or disabled in the installed ddgs
(e.g. ddgs 9.16.0 has bing/yandex text engines disabled upstream) are skipped with
ok=false,error_kind="skipped"and a named error, instead of triggering ddgs's
silent fallback tobackend="auto"(all engines) or being dropped without a trace. - Default text backends updated to engines ddgs 9.16.0 actually serves:
("brave,duckduckgo", "google,mojeek,startpage", "yahoo")— the previous defaults
included bing and yandex, which ddgs has disabled, silently running 6 engines instead
of the configured 8. - Circuit-breaker cool-down skips now report
error_kind: "skipped"(schema 1.0 additive)
on the affectedproviders[]entries, so agents can distinguish a deliberate breaker
skip from an unclassifiedunknownfailure. --diagnosenow skips unknown/disabled engines witherror_kind="skipped"and a named
error instead of probing their hosts and reporting a generic failure.
Fixed
SearchRun.partialnow accounts for aggregated per-engine statuses whose query variants
partially failed (ok=truewith a failureerror_kind): a run where one variant was
throttled or errored reportsdegradedinstead of a cleancomplete."empty"remains a
successful empty branch and does not degrade the run.- Engines configured in multiple groups are queried once, in their first group; duplicate
names across groups no longer double-call upstream or duplicateproviders[]entries. - Aggregated
error_kindno longer letsemptyorskippedoutrank a clean hit: a
variant that returned URLs keepserror_kind=nulleven if a sibling variant was empty
or skipped.emptyis only emitted whenok=trueandresult_count=0;skippedonly
when no variant reached the engine. - Empty-ok branches no longer call
record_successon the circuit breaker, so an empty
query variant cannot wipe sibling rate-limit failures. Only a non-empty success clears
the breaker. Breaker state is guarded with a lock; expired cool-down uses.popinstead
ofdel. --diagnosemapswikipediaandgrokipediato their upstream hosts. An available
engine with no mapped host is skipped with a namederror_kind="skipped"instead of
unknown/ "no known upstream host".- Fetch
Content-Typematching uses the media type token only (sotext/html; charset=utf-8
still works) and rejects a missing header or substring spoofs such as
application/pdf; x=text/html. - Fetch URL validation blocks multicast destinations (
224/4,ff00::/8) in addition to
non-global addresses. - Search cache creation no longer falls back to world-shared
/tmp/josty_cache.db; if the
cache directory cannot be created, caching is disabled. New cache files are mode0600.
josty 0.4.0
What's new in 0.4.0
- Bounded cache in bytes, not just rows: cache stores SERPs only (fetch fields blanked on write), 50 MB byte-budget prune ceiling, and
run_atfreshness with tiered TTL floors (d=30m, news=1h, w=2h). Cached hits are now inspectable and honest. --cache-stats: aggregate cache telemetry (rows, payload bytes, cumulative hits) without opening the database.- Honest failure signals:
error_kind(network/rate_limited/empty/parse/unknown) on everyproviders[]entry, andchallenged: trueon--diagnoseprobes returning HTTP 401/403/429. - Single-source version:
josty.__version__, the GitHubUser-Agent, and hatchling build metadata all derive from one literal inengine.py— the 0.5.0 bump is a one-line edit. - No hidden query rewrite: empty fused results stay empty; callers rewrite.
Packaging
- sdist hardened against stray local dirs (
.venv*,build/,*.egg-info, caches) leaking into the tarball. - README links/logo point at absolute GitHub URLs so the PyPI page renders.
- belt.sh skill upload fixed: removed a 0-byte
__init__.pythat the registry rejected.
Validation
- 310 tests passing;
ruff check .clean; wheel + sdist passtwine check.