Skip to content

feat: store and API checks for typed fields (RFC-0041 step 2) - #95

Merged
Madraka merged 1 commit into
mainfrom
feat/fields-store
Oct 23, 2026
Merged

Madraka merged 1 commit into
mainfrom
feat/fields-store

Conversation

@Madraka

@Madraka Madraka commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Step 2 of RFC-0041's rollout (ADR-0043), built on #94.

Site writes (updateSite, createSite, PUT /collections/:key)

  • checkFieldDefinitions and the caps run only when collections changed.
  • Removing a key or a select option still used by entries is refused with field_change_needs_operation (409), naming the operation to use. A count query runs before the write, and the same condition guards the site CAS (rule 4).

Entry writes (EntryEngine.write)

  • Only changed values are checked. Unknown keys are refused once the collection has definitions.
  • field_not_localized on translations.
  • requiredToPublish on review and publish writes, like required_term.
  • The 256 KB cap applies when fields changes, in every collection (§2 states it unconditionally).
  • Image and rich-text asset references must be in the same site (an image field needs an image). They are written to asset_refs in the same batch, so a used asset cannot be deleted.
  • Sites without definitions add no statements.

Search: searchable text and rich-text values join the entry's search text, and a translation falls back to the original's. Rows without searchable fields are byte-identical.

API: new codes with details.issues ([{path, code, message}]), documented in the README:

  • 422: invalid_fields, unknown_field, field_not_localized, required_field, too_many_fields;
  • 400: the field_key_*, field_option_duplicate and field_bounds codes;
  • 409: field_change_needs_operation and too_large.

Tests

  • New fields suites: 36/36 across sqlite, D1 and DO SQLite.
  • api: 403/403.
  • mcp-server, astro-renderer, cloudflare and docs are green.
  • Locally, some DO SQLite tests fail with EADDRNOTAVAIL (socket exhaustion); the same happens on clean main.

Follow-ups

  • Changing a non-localized value on an original still marks its translations stale: the node hash covers every field. Fix in step 3 or separately.
  • A translation's search row that falls back to the original is rewritten only when the translation or the searchable definitions change.

Changeset: minor (core-ts, api).

🤖 Generated with Claude Code

…ep 2)

- Site writes run the definition checks and caps. Removing a key or a
  select option that entries still use is refused
  (field_change_needs_operation), checked before the write and guarded
  on the site CAS.
- Entry writes check changed values, refuse unknown keys once a
  collection has definitions, refuse non-localized values on
  translations, check requiredToPublish on review and publish, cap
  fields at 256 KB, and check image and rich-text asset references in
  the same site, recorded in asset_refs so a used asset is not deleted.
- Search indexes searchable text and rich-text fields; rows of sites
  without them are byte-identical.
- API: new codes with details.issues (422/400/409), README.

Shared suites on sqlite, D1 and Durable Object SQLite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
@Madraka
Madraka merged commit 6574ec7 into main Oct 23, 2026
4 checks passed
@Madraka
Madraka deleted the feat/fields-store branch October 23, 2026 00:33
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