release(0.13.1): drift-fixes — B1 check_v3 + B3 chain_end + M3 approximate_budget + B2 track_single docstring#55
Merged
Merged
Conversation
…imate_budget + B2 track_single docstring
Drift audit 2026-07-04 (docs/drift.md) found 4 BLOCKERs still active
in 0.13.0 SDK vs backend wire contract. All four closed:
* B1: Transport.check_v3 (drift B1) — was POSTing to /api/v1/check
(removed 2026-06-27, returns 410 Gone with replacement=/api/v1/gate).
Now delegates to Transport.check which targets /api/v1/gate and
forwards all v3 wire fields (chain_id, chain_op, idempotency_key,
stream). check() is the canonical entry; check_v3 is kept as a
v3-named alias for backward compat.
* B2: Transport.track_single docstring + test body — described
fictitious wire shape {execution_id, actual_cost_cents, api_key_id,
cost_source}. Real TrackRequestRaw is {workflow_id, tokens,
cost_cents, ...} (built by runtime._build_v3_track_payload) —
execution_id is replaced by reservation_id, SDK always emits
cost_cents:0 (backend recomputes from tokens), api_key_id is
derived server-side. Docstring + test now match real contract.
* B3: Transport.chain_end (drift B3) — was POSTing to /api/v1/chain/end
(never registered on backend). Now POSTs to /api/v1/gate with
chain_op: "end" (matches documented backend contract).
* M3: Transport.approximate_budget (drift M3) — was appending
?organization_id=<id>. Backend resolves org from X-API-Key /
Authorization header, does NOT accept query params. Method now
calls bare URL. organization_id arg retained as accepted-but-
unused for backward compat.
Tests touched (tests/test_v3_wire_contract.py):
* test_check_v3_includes_protocol_header — re-mocked /api/v1/gate
* test_check_v3_accepts_chain_context — re-mocked /api/v1/gate
* test_chain_end_includes_protocol_header — re-mocked /api/v1/gate
+ added chain_op=end check
* test_chain_end_sends_chain_id_in_body — re-mocked /api/v1/gate
+ added chain_op=end check
* test_track_single_includes_protocol_header — body matches real
wire shape
1037 lib tests pass (no regression). No SDK_MIN_VERSION bump —
wire format unchanged from caller's perspective; only URLs +
docstrings changed. Recommended upgrade path: 0.13.0 -> 0.13.1.
The Postman collection + environments were exported under docs/postman/ for ad-hoc local API exploration. They are working artifacts, not part of the SDK source surface — keeping them on disk but out of VCS.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
release(0.13.1): drift-fixes — closes 4 BLOCKERs from drift.md 2026-07-04
Drift audit
docs/drift.md(2026-07-04) found four BLOCKER items still active in 0.13.0 SDK vs backend wire contract. All four are closed in this release.What changed
src/nullrun/transport.pyTransport.check_v3was POSTing to/api/v1/check(removed 2026-06-27 — returns 410 Gone withreplacement: /api/v1/gate). Now delegates toTransport.checkwhich targets/api/v1/gateand forwards all v3 wire fields (chain_id,chain_op,idempotency_key,stream).check()is the canonical entry;check_v3kept as a v3-named alias for backward compat.src/nullrun/transport.py+tests/test_v3_wire_contract.pyTransport.track_singledocstring +test_track_single_includes_protocol_headerbody described a fictitious wire shape{execution_id, actual_cost_cents, api_key_id, cost_source}. RealTrackRequestRawis{workflow_id, tokens, cost_cents, ...}(built byruntime._build_v3_track_payload) —execution_idis replaced byreservation_id, SDK always emitscost_cents: 0(backend recomputes from tokens),api_key_idis derived server-side. Docstring + test now match the real contract.src/nullrun/transport.pyTransport.chain_endwas POSTing to/api/v1/chain/end(never registered on backend —backend/src/proxy/http/routes.rshas zero matches). Now POSTs to/api/v1/gatewithchain_op: "end"(matches the documented backend contract frombackend/src/proxy/http/cancel.rs:39's own comment).src/nullrun/transport.pyTransport.approximate_budgetwas appending?organization_id=<id>. Backend'sapproximate_budget_handler(backend/src/proxy/http/budget.rs:130-145) resolves the org from the X-API-Key / Authorization header — does NOT accept a query parameter. Method now calls the bare URL.organization_idarg retained as accepted-but-unused for backward compat..gitignoredocs/postman/— working artifacts (Postman collection + environments), not part of the SDK source surface.Diff scope
origin/masterafter the 0.13.0 squash-merge in PR release(0.13.0): drift-fixes — idempotency_key on /track + status_code on decisions #53, so it carries no of the previously-merged 0.13.0 commits)Backwards compatibility
SDK_MIN_VERSIONbump — wire format unchanged from the caller's perspective; only URLs + docstrings changedcheck_v3()retained as alias forcheck()— existing call sites keep workingorganization_idarg onapproximate_budgetretained (silently no-ops now)0.13.0 -> 0.13.1Tests
tests/test_v3_wire_contract.py— 53/53 pass (re-mocked against/api/v1/gate, body shape pinned to realTrackRequestRaw)