Skip to content

feat: expose window_days on historical hunts - #332

Merged
alanjds merged 7 commits into
developfrom
historical-hunt-window
Oct 21, 2026
Merged

alanjds merged 7 commits into
developfrom
historical-hunt-window

Conversation

@alanjds

@alanjds alanjds commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

  • historical_create(..., window_days=None) on both clients: how many days back a historical hunt reaches (30, 60, 90 or 180). Omit it and the request is unchanged.
  • HistoricalHunt.window_days is parsed on the single GET and the list: an int, or None for a hunt created without a window.
  • Bumps the version to 4.8.0 here so the CLI can raise its floor to polyswarm_api>=4.8.0 in its paired PR.

Semantics

  • window_days is a new optional trailing keyword. It rides the JSON body as an int; None leaves the key out, so a bare call sends exactly what it always did and the hunt reaches the platform maximum.
  • No client-side validation, as elsewhere in the SDK: the server owns the 30/60/90/180 enum and answers anything else with a 400, which surfaces as the usual typed exception.
  • HistoricalHunt.window_days is an additive .get(), like the provenance fields. None means no window was requested, or a server that predates the field.
  • The server already accepts and returns window_days, so the release order (server, then this SDK, then the CLI) is satisfied.
  • Changes: aio/api.py (canonical) with the regenerated api.py mirror, resources.py, and the endpoint, resource and testing specs.

Version

4.7.0 -> 4.8.0, in its own commit, under the standing exception in AGENTS.md: the CLI's CI installs this SDK from the same-named branch, and its polyswarm_api>= floor cannot name a version this repo has not declared. It is a minor bump per the versioning table (a new optional keyword whose default preserves the current request, plus a new resource field). It was produced with bump-my-version and checked: pyproject.toml (version and current_version) and __init__.py all read a clean 4.8.0, with no .devN or local suffix.

Testing

  • Full suite offline (VCR replay) with the CI command pytest -s -v: 431 passed, which is the 410 on develop plus 21 new. Also 431 passed on Python 3.11.
  • Sync mirror check (what test-unasync-mirror runs): scripts/regenerate_sync.py, then git diff --exit-code -- src/polyswarm_api/ is clean.
  • New test/historical_window_test.py:
    • pure-unit builder: an int in the body, the key absent for None, an out-of-enum value sent untouched;
    • pure-unit parse: an int, an explicit null and a missing key, on HistoricalHunt and HistoricalHuntList;
    • respx on both clients through the shared ClientTestCase: the body historical_create sends (a bare call and window_days=None are byte-identical). This stays respx because VCR does not match request bodies.
  • Each new guard was checked to fail when its line is removed: dropping the keyword from either client fails that client's tests only, and dropping the parse fails the parse tests.
  • Live against the staging API, on both clients: the sync client's historical_create(window_days=60) reads back 60 on the create response, historical_get and historical_list; the async client's window_days=90 reads back 90 on create and get. window_days=45 is refused by the server with 400 Failed schema validation: 45 is not one of [30, 60, 90, 180], raised as RequestException.
  • Live round trip, recorded: test_historical_window_days (client_scan_test.py) and test_async_historical_window_days (async_client_test.py) create one hunt with window_days=30 and one without, read both back on create, get and list (30 and None), then delete them. The cassettes were recorded against the e2e stack, and both tests also pass with TESTS_VCR=off.
  • Re-recorded the six historical cassettes (test_historical, test_list_historical, test_historical_results and their async twins), whose responses predated window_days and the provenance fields the SDK already parses. Each hunt in them now carries window_days, rule_id, rule_modified and source_rule_changed, all null for these unwindowed inline-rule hunts. They were re-recorded by deleting each cassette and running its test. All eight historical tests pass on replay and live.

claude and others added 4 commits October 20, 2026 17:46
A historical hunt can now be bounded to the last 30, 60, 90 or 180 days.
The new optional keyword goes into the POST body as an int; None drops
the key, so a bare call sends what it always did and the server applies
its own default (the platform maximum).

The SDK does not validate the value: the server owns the enum and
answers anything else with a 400, which surfaces as the usual typed
exception. The sync mirror is regenerated from the async source.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
The server now returns the hunt's time window on the single GET and on
the list. It is an additive .get() like the provenance fields: an int
for a hunt created with a window, None for one created without (it
reaches the platform maximum) or for a server that predates the field.
HistoricalHuntList inherits the parse, so both endpoints are covered.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
Pure-unit tests cover the request shape (an int in the body, the key
absent for None, no client-side validation) and the parse (int,
explicit null, missing key). One respx body per client pair checks what
historical_create sends and what the create, get and list responses
carry; VCR cannot, because it does not match bodies and the recorded
hunts predate the field.

The live round trip needs a fresh e2e stack, so it is recorded as an
open question rather than faked into the existing cassettes.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
The CLI client adopts `historical_create(window_days=)` in the paired
change set and expresses that as `polyswarm_api>=4.8.0`. develop already
declares 4.7.0 for a surface that does not include this keyword, so the
floor needs the next version up; a floor cannot name a version this repo
has not declared, so the bump lands here, in the feature PR (AGENTS.md's
standing exception).

Minor: one new optional keyword whose default preserves today's request,
plus an additive resource field, so no existing call changes behaviour.
Bumped with bump-my-version; the emitted string is a clean `4.8.0`. The
server already accepts and returns `window_days`, so this repo can
release ahead of the CLI.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
@claude

claude Bot commented Oct 20, 2026

Copy link
Copy Markdown

Code, codegen mirror, specs, and the 4.8.0 bump (clean X.Y.0, CLI resolves from source) all match AGENTS.md. One thing to fix:

Test tier: the live VCR lifecycle test is missing, and the reason given doesn't hold up. specs/04-testing.md invariant 1 says "VCR-backed live-e2e tests are the default for new endpoint tests", and respx is allowed only "when the live e2e stack can't reasonably produce the scenario". The PR body says "The server already accepts and returns window_days". So the stack can produce this, and HistoricalWindowResponseTestCase is checking fabricated envelopes in place of the real contract. The ioc_search precedent this copies was explicitly "a stand-in until the e2e stack serves the parameter". That condition is already met here. Needing a fresh stack is the normal recording workflow, not a blocker.

Action: add the live pair before merge. Create a hunt with window_days=30, then historical_get + historical_list and assert the value comes back unchanged. Also assert that a hunt created without a window reads back None. Put the sync version in client_scan_test.py and the async one in async_client_test.py, recorded against a fresh stack. Then delete HistoricalWindowResponseTestCase and the new 99-open-questions.md entry, and fix the 04-testing.md line to match. The builder, parse, and request-body pass-through tests can stay: VCR doesn't match request bodies, so those still earn their place.

claude and others added 2 commits October 21, 2026 10:15
A live pair, sync and async, creates one hunt with a 30-day window and one
without, then reads both back on create, get and list: 30 and None. The
cassettes were recorded against the e2e stack, and the pair also passes
with VCR off. It replaces the respx stand-in that asserted fabricated
envelopes, and closes the open question that tracked the gap. The builder,
pass-through and parse tests stay: a cassette cannot see request bodies.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
Their recorded create, get and list responses predated window_days.
Re-recorded by deleting each cassette and running its test against the
e2e stack, so replay serves the shape the server returns today, the key
included.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
@claude

This comment has been minimized.

Co-Authored-By: Alan Justino <alan.justino@yahoo.com.br>
@claude

claude Bot commented Oct 21, 2026

Copy link
Copy Markdown

Reviewed against AGENTS.md and specs/02, 03, 04 and 05. No issues found. It targets develop, the minor bump to a clean 4.8.0 falls under the documented downstream-floor exception, the sync mirror matches the canonical async source, the new kwarg is trailing and defaults to sending the same request as before, the specs are updated in this PR, and tests cover the builder, the parse, respx on both transports and VCR e2e on both transports.

@alanjds
alanjds marked this pull request as ready for review October 21, 2026 14:40
@alanjds
alanjds requested a review from a team October 21, 2026 14:41
@mjbradford89

Copy link
Copy Markdown
Contributor

Findings (round 1)

Adds an optional window_days to historical hunt creation and reads it back on get and list. Nothing blocking found.

Part of a change across 3 PRs — merge #332 → polyswarm/polyswarm-cli#279 → polyswarm/portal#2577.

Reviewed at d5502a7. Fixes are suggestions; nothing was run.

@mjbradford89 mjbradford89 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing open from this review.

@alanjds
alanjds merged commit a11168f into develop Oct 21, 2026
2 checks passed
@alanjds
alanjds deleted the historical-hunt-window branch October 21, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants