Skip to content

fix(wire): close five wire-protocol gaps from design review (#56)#102

Merged
cuibonobo merged 1 commit into
mainfrom
claude/issue-56-design-review-vrn80g
Jul 17, 2026
Merged

fix(wire): close five wire-protocol gaps from design review (#56)#102
cuibonobo merged 1 commit into
mainfrom
claude/issue-56-design-review-vrn80g

Conversation

@cuibonobo

Copy link
Copy Markdown
Member

Summary

Closes #56 — a batch of wire-level gaps where the adapter or spec quietly delivers less than the query/API surface promises.

  • relatedTo.label was silently dropped. buildQueryParams now sends relatedToLabel alongside relatedTo on the GET /records fallback path (the POST /records/query path already carried it, since it forwards the full filter object). Added to the spec's query param list.
  • content/search filters were silently dropped on incapable servers. APIAdapter.queryRecords() now throws a new APIAdapterCapabilityError — naming the missing capability — when filter.content is used without contentFieldQuery, or filter.search without fullTextSearch, before any request is sent. Previously the filter evaporated and the server returned an unfiltered superset presented as the filtered result.
  • DELETE /records/:id/associations took its payload in the body. DELETE bodies have no defined wire semantics (RFC 9110 §9.3.5) and are a portability landmine behind arbitrary proxies/gateways. dissociate() now sends POST /records/:id/associations/delete. Updated in the spec, the shared conformance fixtures, and adapter-api tests.
  • Discovery omitted the attachment size limit. Added maxAttachmentBytes: number | null to AdapterCapabilities and the discovery response, so apps can pre-check upload limits instead of learning the ceiling only after a 413. Local/embedded adapters (JSON, sql.js, native SQLite) declare null (unbounded) since nothing at the storage layer imposes a limit; only a server behind the API adapter enforces one.
  • Every create()/update() cost an extra getType() round trip. Stack now caches Types by versioned id, populated by getType(), defineType(), and listTypes() (never invalidated — a Type's schema is immutable once defined; listTypes() refreshes the cache wholesale as the explicit way to pick up a name-only rename from another writer). create(), update(), and restoreVersion() validate against the cached entry instead of a fresh adapter round trip.

Test plan

  • pnpm -r build — all packages build
  • pnpm -r typecheck — clean
  • pnpm -r lint — clean
  • pnpm -r test — full suite green (458 tests in core, 97 in adapter-api, etc.)
  • New tests: relatedToLabel GET-param serialization, capability-guard throws for filter.content/filter.search without a request being sent, dissociate()'s new verb/path, discovery maxAttachmentBytes round trip, and a spy-based test proving create() × N hits adapter.getType() exactly once after the type is cached
  • docs/spec.md and @haverstack/conformance-fixtures updated to match the new wire shapes

Generated by Claude Code

- relatedTo.label now reaches the wire on the GET /records fallback
  path (relatedToLabel param) instead of being silently dropped.
- APIAdapter throws APIAdapterCapabilityError for filter.content or
  filter.search against a server lacking the matching capability,
  instead of degrading to an unfiltered superset with no signal.
- dissociate() moves off DELETE-with-body to POST
  /records/:id/associations/delete — DELETE bodies have no defined
  wire semantics and are a portability landmine.
- AdapterCapabilities gains maxAttachmentBytes (discovery-exposed),
  so apps can pre-check upload limits instead of learning them from
  a 413 after the fact.
- Stack now caches Types by versioned id, populated by getType(),
  defineType(), and listTypes(); create()/update()/restoreVersion()
  validate against the cache instead of paying a getType() round
  trip on every write.

Spec, conformance fixtures, and tests updated to match.
@cuibonobo
cuibonobo merged commit 2d113d7 into main Jul 17, 2026
5 checks passed
@cuibonobo
cuibonobo deleted the claude/issue-56-design-review-vrn80g branch July 17, 2026 18:32
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.

Wire protocol gaps: silently dropped query filters, DELETE-with-body, missing discovery fields, getType round trip per write

2 participants