Files
pad/docs
xarmian 47ca9e521a fix(server): refuse a collection schema that repeats or empties a field key or option (TASK-3539, PR B) (#2009)
* fix(server): refuse a collection schema that repeats or empties a field key or option (TASK-3539, PR B)

Lead ruling: a repeated or empty field key or select option is a broken
schema, and the web renders fields and options as lists keyed by them, so
one repeat blanked the view (BUG-3538). PR A made the web render such a
schema; this stops new ones being written.

- Collection create and update refuse, with 400 validation_error naming
  it, a schema in which a field has no key, two fields share a key, or a
  select field lists an empty option or the same option twice
  (models.ValidateSchemaKeysAndOptions, beside ValidateAbandonedOptions).
  WRITE check only: a stored schema with a repeat still reads, and an update
  that sends no schema still applies. Live census on :7777: 0 of 213
  collections affected.
- Dynamic Client Registration registers a repeated redirect URI once (it is
  unauthenticated, and the connected-apps page lists URIs keyed by value).
- ListWorkspaceTags groups tags as TEXT: on SQLite json_each kept [1] and
  ["1"] apart while both scanned to "1".
- Pins that convention commands and surfaces are deduped on read: they are
  already (normalizeItemConventionMetadata); the census verdict that said
  otherwise was wrong.

Not done, deliberately: refusing repeated app-manifest event names or
companion field keys. appmanifest.Parse also re-reads a STORED manifest on
upgrade, so a new refusal there would fail a read of an installed app; PR A
made both web lists render repeats.

ToolSurfaceVersion 0.82 -> 0.83: pad_collection create/update refuse calls
they used to accept (the v0.43 / v0.48 grounds). docs/api.md states the 400.

* fix(server): hold companion and template schemas to the key/option rule (TASK-3539)

Codex round 1: writers that bypass the collection handlers could still store
a schema that repeats or empties a key or option.
- An app's companion collection schemas are checked in the install/upgrade
  preview, on the NEW manifest beside the reserved-key check, and refused
  422 invalid_manifest. Not in appmanifest.Parse, which also re-reads an
  installed app's stored manifest.
- Every template and default collection schema the repo ships is checked by
  a test (they seed through the store, not the handlers).
- The legacy-schema test also reads and creates items in a collection stored
  with a repeat.
Workspace and artifact import, and the library option widening (which
already dedupes), are unchanged: refuse on write only.

* docs(mcp): the v0.83 entry in docs/mcp.md's version history (TASK-3539)

Codex round 2: the current-version labels said v0.83, the history began at
v0.82.

* docs(mcp): docs/mcp.md's intro names the current catalog, v0.83 (TASK-3539)

Codex round 3: the intro still said v0.81, stale since before this change.

* fix(server): the option check covers select and multi_select only (TASK-3539)

Codex round 4: it refused empty or repeated options on every field type, but
only a select or multi_select's options are a rendered list. Another type can
carry a legacy options list (the old field DSL put a third part there), and
refusing it would block an unrelated schema save. Tested both ways.

* test(collections): the template schema check is independent of the validator (TASK-3539)

Codex round 5: calling ValidateSchemaKeysAndOptions from the template test was
circular. It now uses its own check. Also records, at the write, why the
library option widening is not held to the validator: it only appends missing
words (never a repeat), and refusing would fail an item create over a legacy
schema.
2026-10-10 03:04:20 -04:00
..