feat: auto-inject deterministic dedup key in api-request.sh for create endpoints - #49
feat: auto-inject deterministic dedup key in api-request.sh for create endpoints#49Jinyi-S wants to merge 1 commit into
Conversation
e89e8fc to
756baab
Compare
amurph491
left a comment
There was a problem hiding this comment.
Architecture Review
This PR has the right intent but the wrong architecture. Three significant issues:
1. The -H passthrough won't work with api-request.sh
The api wrapper only accepts positional args: <skill> <METHOD> <path> [json_body] (scripts/api-request.sh lines 108–117). It doesn't parse -H flags. So when a skill does:
api POST "ad_accounts/{ad_account_id}/ad_sets" \
-H "Idempotency-Key: <uuid>" \
'{...}'-H gets slotted into $4 (the BODY variable), and the actual JSON body becomes $5 and is silently ignored. Every create command in this PR would send -H as the request body instead of the JSON payload. This is a breaking change.
2. Header management belongs in the wrapper, not scattered across skills
The whole point of api-request.sh is to centralize header management — Authorization, X-Spotify-Ads-Sdk, X-Spotify-Ads-Skill, and Content-Type are all handled there. Skills just call api POST "path" '{body}' and don't think about headers. This PR breaks that pattern by requiring every skill to manually add a header, creating 6+ places to maintain the same logic.
The correct fix: add automatic key generation to api-request.sh for POST requests on the 6 supported create endpoints. Skills wouldn't change at all — the wrapper detects that the path matches a create endpoint, generates a UUID, and includes the header automatically. Zero skill changes needed.
3. The term "idempotency" must not be user-facing
The term appears in AGENTS.md, 5 skill files, the agent instructions, 9 test scenario titles, and the reference doc. Non-technical users will encounter this term and be confused by it. This protection should be completely invisible — on by default, with no user-facing terminology. Advanced users can opt out only if they specifically ask for it.
Recommended Approach
-
api-request.sh— detect POST to the 6 create endpoints and auto-inject the key header viauuidgen. Add a flag (e.g.--no-dedup-key) or read a setting so advanced users can disable it if they specifically ask. On by default, no user action needed. -
Skills — no changes. They keep calling
api POST "path" '{body}'exactly as they do today. -
AGENTS.md retry safety — keep the existing guidance about not auto-retrying POST/PATCH. The wrapper handles the header; retry semantics can stay documented in an internal reference doc renamed to something like
references/create-retry-safety.md(not "idempotency"). -
Test scenarios — rewrite to test that the wrapper adds the header automatically (not that each skill manually includes it), and remove technical terminology from scenario names.
756baab to
dd75ed6
Compare
973d752 to
92ef3ad
Compare
|
Thanks for the review @amurph491
Also added |
8e7a8a2 to
2b0411d
Compare
2b0411d to
c55bc7e
Compare
…e endpoints Generate a SHA-256 hash from the canonical request fingerprint (base URL, uppercase method, resolved path, canonical JSON body) as the Idempotency-Key. Uses canonicaljson library via uv for JSON normalization, with json.dumps and shasum fallbacks. Same request always produces the same key. No client-side cache or state. Add --no-dedup-key flag for opt-out. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
c55bc7e to
a18ad0a
Compare
Description
Auto-inject a deterministic dedup key in the API request wrapper for the 6 supported create endpoints. The key is a SHA-256 hash of the canonical request fingerprint — same request always produces the same key, so retries are automatically detected by the server. No client-side cache or state.
How it works
canonicaljsonlibrary (sorts keys, strips whitespace, handles unicode) withjson.dumpsfallbackIdempotency-KeyheaderFallback chain
python3 canonical-hash.py— fastest (~50ms), usescanonicaljsonif installed, otherwisejson.dumpsuv run canonical-hash.py— auto-installscanonicaljsonifpython3fails entirelyshasum— raw string hash, last resortChanges
scripts/canonical-hash.pyuvinline deps for canonical JSON hashingscripts/api-request.shcanonical-hash.pyvia fallback chain.--no-dedup-keyflag for opt-outskills/api-reference/references/create-retry-safety.mdtests/test-scenarios.mdDesign decisions
canonicaljsonlibrary for proper normalization,json.dumpsfallbackuv runfirstexec curlunchanged — no response capture, no buffering change--no-dedup-key— opt-out for cases like toggling a PATCH field multiple timesChecklist