Skip to content

fix(web): accept the weak kit ETag in If-Match - #116

Merged
mrgoonie merged 2 commits into
mainfrom
fix/kit-if-match-weak-etag
Oct 20, 2026
Merged

mrgoonie merged 2 commits into
mainfrom
fix/kit-if-match-weak-etag

Conversation

@mrgoonie

Copy link
Copy Markdown
Contributor

Summary

The production smoke for #88 (2026-10-20 09:43 +07, worker version d06de037) showed two problems:

  • GET /api/v1/kits/@h/n returns ETag: W/"g<n>" even though the worker sets the strong "g<n>". Cloudflare weakens strong ETags when it compresses a response. A client that sends that header back in If-Match, as the docs describe, gets 400 invalid_request, so the documented CAS flow is broken in production.
  • A read that carries only the admin secret answers 401 (it is treated as anonymous), while the docs say 404.

Changes

  • kit-http.ts: If-Match now also accepts W/"g<n>" and W/"<n>". The generation must still match exactly: a stale one is still 412 and a disagreement with the body is still 400. *, lists, W/g0 and a lowercase w/ are still 400.
  • Tests: a new case covers a weak ETag being accepted, including a stale weak ETag returning 412. The malformed-value list is updated.
  • docs/personal-kits-api.md: documents the weak form and the admin-secret read and write statuses.

Test plan

  • pnpm vitest run apps/web/tests/personal-kits: 10 files, 391/391 passed.
  • pnpm --filter web typecheck: exit 0.
  • After merge: deploy, then a production CAS smoke that echoes the received ETag in If-Match.

Rollback: revert, or set SKILLX_PERSONAL_KITS_API to "0".

Docs impact: docs/personal-kits-api.md updated (If-Match forms, admin secret statuses).
Refs #88

🤖 Generated with Claude Code

mrgoonie and others added 2 commits October 20, 2026 09:50
Production answers GET /api/v1/kits/@h/n with ETag W/"g<n>": Cloudflare
weakens the worker's strong ETag when it compresses the response. Clients
that echo the header they received got 400 invalid_request, so the
documented If-Match flow failed in production. Accept the W/ prefix; the
generation still has to match exactly, and a stale one is still 412.

Also document that the admin secret on a kit read is anonymous (401) and
only a write that presents it gets 404, as production answers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mrgoonie
mrgoonie merged commit 6e7ae6e into main Oct 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant