Makes the server the authority for form validity while the client validates for speed, sharing error codes, focusing the first invalid field, and never leaking whether a private record exists.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Validate on the client to catch empty required fields and format mistakes before the network. Treat those checks as provisional. The server re-validates the same rules plus authorization and uniqueness; its error codes are authoritative. Map them onto the same fields. Focus the first invalid control and announce the summary. When a lookup would reveal a private record, return a generic conflict that does not distinguish missing from forbidden.
Scope
- Data-entry forms with overlapping client and server validators.
- Error codes, focus order, and assistive announcements.
- Responses that must not disclose private or cross-tenant existence.
- Retry after correction without losing unrelated values.
Outside this block
- Async list feedback beyond field errors.
- CAPTCHA and rate limits.
- Stored-document schema migration.
Contract
- A submit that fails client rules sends no request; the first invalid control receives focus with its accessible name and error text.
- The server returns
field_errorsas{code, field}pairs using the same codes the client uses for overlapping rules. - A client-valid payload may still fail; the UI replaces client messages with the server list and does not invent a second vocabulary.
- After a failed submit, focus moves to the first server-invalid field in document order; a polite live region announces the error count once.
- Existence-sensitive lookups return one generic code such as
not_availablefor both missing and unauthorized. - Unrelated dirty fields stay populated; passwords and secrets are not echoed in HTML or JSON.
Implementation
Share a machine-readable rule list for format and required checks. Keep uniqueness and authorization on the server. Render errors next to the labeled control. Collapse existence-sensitive negatives inside an authorization scope. Test keyboard-only and a screen reader on first-error focus.
Failure handling
If the server is unreachable, keep values, show a request-level error distinct from field errors, and leave submit enabled. Unknown codes get a generic field message while retaining the field association. Two fields sharing a code both show it; focus still goes to the first in document order.
Verification
Contract-test overlapping codes. Confirm a private slug clash is indistinguishable from reservation. Check focus and a single announcement. Execute the packaged scenarios in the form harness.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.