Skip to content

Releases: Alih-b/Josty

v0.7.1

Choose a tag to compare

@Alih-b Alih-b released this 25 Sep 23:47
e886eff

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

Choose a tag to compare

@Alih-b Alih-b released this 19 Sep 21:57

Patch release. Housekeeping on top of v0.6.0.

Fixed

  • tests/scenario_eval.py and tests/benchmark.py no longer build sys.path from the pre-refactor .agents/skills/josty/src. They load the source tree at src/, so the scenario eval and frozen-corpus replay can no longer silently score whichever josty happened to be installed.

Removed

  • Seven unused datetime.UTC compatibility shims and the unreferenced AUTHORITATIVE_DOMAINS alias. No public API, CLI, or schema change.

Changed

  • CI runs the declared Python 3.10 floor alongside 3.11–3.13.
  • The development ruff floor 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

Choose a tag to compare

@Alih-b Alih-b released this 19 Sep 15:13

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" exits 1, so
    a total outage is visible to exit-code checkers. complete, degraded, and
    empty stay 0 (read partial / coverage in-band), and usage or validation
    errors stay 2. JSON is printed to stdout first in every search case (#42).
  • fetch.status="noop" when --fetch was requested but the SERP produced no
    results to fetch. skipped now means only "fetch was not requested". Additive
    enum value; schema stays 1.0 (#56).

Changed

  • Successful searches with no final results now report status="empty" instead
    of "complete" (#58). Schema remains 1.0; failure precedence, fetch and
    diagnose statuses are unchanged.
  • This intentionally changes the previous documented status contract. Strict
    consumers that validate status values must accept empty before 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 as empty.
    An empty SearchRun with no provider entries also reports empty, with
    provider_count=0, coverage=null, and partial=false.
  • The Python package moved out of the agent skill directory to a repo-root
    src/josty/ layout, and the single 2,506-line engine.py was split into
    focused modules (status, models, errors, ranking, cache, breaker,
    backends, fetch) with engine.py keeping the Josty facade. The public
    josty API and the CLI are unchanged; this is a maintainer-facing change.

Fixed

  • The Josty(...) library default for max_content_chars is now 8000, matching
    the CLI, instead of 50000. 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,
    and request_count. status=complete with a single contributing engine is now
    visible instead of looking like a fused multi-engine confirmation.
  • Fetch-phase counters on the envelope fetch object (requested, attempted,
    ok, failed, status). A total extraction miss degrades the run.
  • --diagnose envelopes set phase: "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 --fetch reuses 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

  • --version CLI 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/Josty casing (pyproject metadata,
    README links, GitHub API User-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 is error_kind: "blocked"
    rather than rate_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.
  • --diagnose skips 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 with error_kind: "skipped" when the pool is saturated.
  • CLI JSON sanitizes non-finite floats to null so 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_kind is the most severe real failure across variants so partial
    throttling stays visible; empty/skipped never attach to a non-empty hit; error is
    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 to backend="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 affected providers[] entries, so agents can distinguish a deliberate breaker
    skip from an unclassified unknown failure.
  • --diagnose now skips unknown/disabled engines with error_kind="skipped" and a named
    error instead of probing their hosts and reporting a generic failure.

Fixed

  • SearchRun.partial now accounts for aggregated per-engine statuses whose query variants
    partially failed (ok=true with a failure error_kind): a run where one variant was
    throttled or errored reports degraded instead of a clean complete. "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 duplicate providers[] entries.
  • Aggregated error_kind no longer lets empty or skipped outrank a clean hit: a
    variant that returned URLs keeps error_kind=null even if a sibling variant was empty
    or skipped. empty is only emitted when ok=true and result_count=0; skipped only
    when no variant reached the engine.
  • Empty-ok branches no longer call record_success on 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 .pop instead
    of del.
  • --diagnose maps wikipedia and grokipedia to their upstream hosts. An available
    engine with no mapped host is skipped with a named error_kind="skipped" instead of
    unknown / "no known upstream host".
  • Fetch Content-Type matching uses the media type token only (so text/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 mode 0600.

[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 original run_at, so agents can judge
    the age of a cached: true result instead of trusting it blindly.
  • Freshness TTL floors for the search cache: timelimit=d entries expire after 30
    minutes, timelimit=w after 2 hours, and category=news after 1 hour (previously a
    flat 6 hours for everything). A caller-configured shorter cache_ttl is always
    respected.
  • Scenario-eval staleness check (require_run_at, max_age_s) plus a frozen
    stale_news_day_old_cache fixture 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_kind to "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 flag cached (true only on cache hit).
  • --cache-stats CLI flag (plus SearchCache.stats() / Josty.cache_stats()) reporting
    aggregate cache telemetry — rows, payload bytes, cumulative hits — so the bounded cache is
    inspectable wit...
Read more

v0.5.2

Choose a tag to compare

@Alih-b Alih-b released this 05 Sep 18:57
96f6fe2

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, and request_count. status=complete with a single contributing engine is now visible instead of looking like a fused multi-engine confirmation.
  • Fetch-phase counters on the envelope fetch object (requested, attempted, ok, failed, status). A total extraction miss degrades the run.
  • --diagnose envelopes set phase: "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 --fetch reuses the cached SERP and only downloads pages, instead of repeating the provider fanout.

v0.5.1

Choose a tag to compare

@Alih-b Alih-b released this 04 Sep 21:28

[0.5.1] - 2026-09-05

Added

  • --version CLI 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/Josty casing (pyproject metadata,
    README links, GitHub API User-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 is error_kind: "blocked"
    rather than rate_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.
  • --diagnose skips 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 with error_kind: "skipped" when the pool is saturated.
  • CLI JSON sanitizes non-finite floats to null so one NaN field cannot fail the query.

v0.5.0 — Per-engine search fanout and availability gate

Choose a tag to compare

@Alih-b Alih-b released this 03 Sep 08:15
59f27fc

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_kind is the most severe real failure across variants so partial
    throttling stays visible; empty/skipped never attach to a non-empty hit; error is
    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 to backend="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 affected providers[] entries, so agents can distinguish a deliberate breaker
    skip from an unclassified unknown failure.
  • --diagnose now skips unknown/disabled engines with error_kind="skipped" and a named
    error instead of probing their hosts and reporting a generic failure.

Fixed

  • SearchRun.partial now accounts for aggregated per-engine statuses whose query variants
    partially failed (ok=true with a failure error_kind): a run where one variant was
    throttled or errored reports degraded instead of a clean complete. "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 duplicate providers[] entries.
  • Aggregated error_kind no longer lets empty or skipped outrank a clean hit: a
    variant that returned URLs keeps error_kind=null even if a sibling variant was empty
    or skipped. empty is only emitted when ok=true and result_count=0; skipped only
    when no variant reached the engine.
  • Empty-ok branches no longer call record_success on 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 .pop instead
    of del.
  • --diagnose maps wikipedia and grokipedia to their upstream hosts. An available
    engine with no mapped host is skipped with a named error_kind="skipped" instead of
    unknown / "no known upstream host".
  • Fetch Content-Type matching uses the media type token only (so text/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 mode 0600.

josty 0.4.0

Choose a tag to compare

@Alih-b Alih-b released this 02 Sep 07:24

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_at freshness 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 every providers[] entry, and challenged: true on --diagnose probes returning HTTP 401/403/429.
  • Single-source version: josty.__version__, the GitHub User-Agent, and hatchling build metadata all derive from one literal in engine.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__.py that the registry rejected.

Validation

  • 310 tests passing; ruff check . clean; wheel + sdist pass twine check.