Skip to content

docs(error-catalog): INVALID_FORMAT names what really checks a value (field type or a format rule) - #19878

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-19848-error-catalog-invalid-format
Sep 24, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-19848-error-catalog-invalid-format

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #19848
Clause-②: no

What changed

content/docs/api/error-catalog.mdx only.

  1. The INVALID_FORMAT entry. Its Fix line told authors to match "the field's format constraint". No write-time check reads a field-level format key, so following that advice changes nothing. The entry now says what actually decides:
    • No route emits the top-level INVALID_FORMAT today. The entry now says so and tells clients to branch on VALIDATION_FAILED + fields[].code. That is the same shape the page's INVALID_REFERENCE entry already uses.
    • The field type. The built-in email / url / phone checks key on type and answer invalid_email / invalid_url / invalid_phone. Date and time parse failures answer invalid_date / invalid_time.
    • A format validation rule (a different key: its regex or its named format email | url | phone | json) answers field-level invalid_format. The link goes to /docs/data-modeling/validation#format-validation, the anchor PR docs(data-modeling): stop crediting field format with validation #19847 uses.
    • Field-level invalid_format is also emitted for a missed declared pattern outside record metadata: a settings value, or a request body a route parses with Zod.
    • The Fix line now names the field type or the format validation rule as the things to change, and says a field-level format key runs no write-time check on any field type.
  2. A bounded in-place fix in the same file (declared here). The VALIDATION_ERROR JSON example showed an email miss as "code": "invalid_format". The Zod mapper answers invalid_email for that miss. See the Acceptance notes.

The wording follows PR #19847 (still open at the time of writing; this PR depends on none of its files) and the spec's format describe: "keyed on type", "a field-level format key is not read", "a format validation rule".

Evidence (all at base 2bbb4623)

Claim Where
Record validator never reads field format: def.format 0 hits, same-file control def.type 7 packages/objectql/src/validation/record-validator.ts
email / url / phone checks key on type, emit invalid_email / invalid_url / invalid_phone record-validator.ts:746-754
date / time parse failures emit invalid_date / invalid_time record-validator.ts:839, :858
A format validation rule (regex or named format) emits field-level invalid_format packages/objectql/src/validation/rule-validator.ts:2776-2790 (check), :2822 (formatViolation)
Settings pattern miss emits field-level invalid_format packages/services/service-settings/src/settings-service.ts:2042
Zod-parsed routes: email to invalid_email, url to invalid_url, other format/regex to invalid_format packages/spec/src/api/zod-issues-to-fields.ts:82-85
Top-level INVALID_FORMAT has no producer: git grep INVALID_FORMAT outside tests and dist hits only the enum member packages/spec/src/api/errors.zod.ts:57, the ADR note and the unpinned baseline scripts/error-status-unpinned-baseline.json:15 ("documented with an HTTP status that NO producer ... declares"); ADR-0114 line 37 records the six field-shaped top-level members as a known wart
Spec contract on the field key packages/spec/src/data/field.zod.ts:1090-1094 (the format describe: "the write-time record validator's built-in email, url and phone checks key on type, never on this key")

Verification (final head 40758ef8)

  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 41 commands. I ran all 41 on 40758ef8: 41 exited 0.
    • Reconciliation: --ran printed 41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED (a DERIVED zero — all 41 recorded an exit code and none of them is 3).
    • On the first pass (d56a2a7f), four gates exited 3 (PREREQUISITE NOT MET): check:doc-formula-expressions, check:doc-security-posture, check:skill-examples and check:docs-transcript-drift. The lint, formula and client packages had not been built yet. After those builds all four re-ran with exit 0.
  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/api/error-catalog-docs.test.ts (the test that reads this page against the wire face): Test Files 1 passed (1) · Tests 5 passed (5) on 40758ef8.
  • Not measured, and owned by CI: the families dispatch-gates lists outside its derived total, and the path-scheduled Build Docs / Test Core jobs.

Changeset

Docs-only. content/docs/** is not in any package's files[], so this PR publishes nothing and falls under skip-changeset. Per the dispatch, this seat writes no labels.

Acceptance notes

  • Bounded in-place fix (the VALIDATION_ERROR example invalid_format → invalid_email). All four exemption conditions hold:

    • same defect class (a docs line that says format where the real check keys on the email type);
    • a mechanical, pinned form (zod-issues-to-fields.ts:83);
    • the file is this card's claimed file;
    • the same gate family.

    It lies outside the claim's declared "(the INVALID_FORMAT entry)" sub-surface. The claim's file surface needs this entry added.

  • content/docs/ui/forms.mdx:229 (400 VALIDATION_FAILED · "object schema validators fail (required, format, length, …)"): read, not edited. It lists kinds of constraint in the When column and gives no fix, so it does not tell anyone to edit a field format key. It does not carry the same false meaning. Not listed as a defect.

  • Sibling entries on the same page (a finding, not fixed here): VALUE_TOO_LONG and VALUE_TOO_SHORT also have no producer (git grep outside tests/dist: 0 hits each; control 'VALIDATION_FAILED': 70). Both appear in scripts/error-status-unpinned-baseline.json. The page still documents them as live causes. The record validator answers field-level max_length / min_length under VALIDATION_FAILED instead. This is reported to the seat for filing and is out of scope for this card.


Generated by Claude Code

…s format

The INVALID_FORMAT entry told authors to fix the failure by matching "the
field's `format` constraint", but the write-time record validator never reads
a field-level `format` key: its email / url / phone shape checks key on the
field `type`, and a `format` validation rule (a different key) answers
field-level `invalid_format`. No route emits the top-level INVALID_FORMAT at
all, so the entry now says so and points at VALIDATION_FAILED + fields[].code,
the same shape the INVALID_REFERENCE entry already uses.

The VALIDATION_ERROR example's email entry now carries `invalid_email`, the
code the Zod issue mapper actually produces for an email-format miss.

Claude-Session: https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv
Co-authored-by: Claude <noreply@anthropic.com>
Outside `autonumber` the key is a display hint and on `autonumber` it is the
record-number pattern, so 'a display hint the server never checks' was only
right for most types; what holds for every type is that no write-time check
reads it.

Claude-Session: https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 40758ef85a4dc1a7b894bba1530f0e90ea90a57b

① Derived judgments

All measured on origin/main 1f89ba0d70 (git show / git grep only). Diff: 1 file, content/docs/api/error-catalog.mdx, +16/-3.

  1. "No route emits the top-level INVALID_FORMAT today" — TRUE. Whole-tree git grep INVALID_FORMAT excluding tests, dist/** and content/docs hits exactly three non-producers: the enum member packages/spec/src/api/errors.zod.ts:57, the ADR note docs/adr/0114-field-level-error-code-catalog.md:37, and scripts/error-status-unpinned-baseline.json:15. No producer in packages/, apps/, examples/ or scripts/.
  2. Field type checks and codes — TRUE. packages/objectql/src/validation/record-validator.ts:746-753: email → invalid_email, url → invalid_url, phone → invalid_phone (fail's first arg is the wire code, :611-617); :835-839 date/datetime → invalid_date; :848-858 time → invalid_time. def.format: 0 reads (control def.type: 7).
  3. format validation rule → field-level invalid_format — TRUE. rule-validator.ts:2770-2790 (checkFormat: regex miss or named-format miss) → :2818-2822 { code: 'invalid_format' }. Closed set email | url | phone | json — TRUE (packages/spec/src/data/validation.zod.ts:214; matchesNamedFormat :2793-2815). Link target ### Format Validation exists (content/docs/data-modeling/validation.mdx:146).
  4. "a declared pattern outside record metadata … also answers field-level invalid_format" — TRUE on the field code: settings packages/services/service-settings/src/settings-service.ts:2038-2046; Zod-parsed bodies packages/spec/src/api/zod-issues-to-fields.ts:82-85. Advisory only: the settings service wraps its fields[] in a SETTINGS_VALIDATION top-level code (settings-service.types.ts:584), not VALIDATION_FAILED; no changed sentence is false, but the Fix line's "branch on VALIDATION_FAILED" should not be over-generalised to settings writes.
  5. "a field-level format key runs no write-time check on any field type" — TRUE and consistent with the spec describe (packages/spec/src/data/field.zod.ts:1090-1094). On autonumber the key is the record-number pattern used to mint the value (generation, not validation); the validator exempts autonumber (:620-623, :972) and reads no def.format.
  6. JSON example invalid_email — TRUE: an email miss is invalid_email from both the Zod mapper (zod-issues-to-fields.ts:83) and the record validator (:747).
  7. "same shape the page's INVALID_REFERENCE entry already uses" — TRUE (error-catalog.mdx:227-232 on main).
  8. Clause-②: no — right: one docs file, no code, no package surface.
  9. The declared bounded in-place fix (the JSON example) is inside the claimed file; the seat amended the claim surface to include it.

② Semver level

None (docs-only). One file under content/docs/**; no .changeset; no package files[] on origin/main includes content/docs. skip-changeset is the right disposition.

③ Boundary flags

  • No governed surface or release-owned tree touched; head Governed Surface Queue Guard = success.
  • content/docs/ui/forms.mdx untouched; its :229 row lists constraint kinds with no fix — no false prescription.
  • Nothing in the new text misleads an AI author; the one advisory is ①.4.
  • Check-runs on head at read time (30): Check Changeset failure (expected, pending the label); Test Core (1/6), (6/6), Build Docs, the four Type Check · lanes and Lint & Repo Gates in progress; every completed check otherwise success or path-skipped.

Implemented-by: claude/issue-19848-error-catalog-invalid-format
Reviewed-by: session_01VDtqoecgES7ScQYGbFVDRv

VERDICT: PASS

Landing still needs, separately from this verdict: every in-progress check green on this head, and the maintainer's skip-changeset label for Check Changeset. Isolated at-tier reviewer, adopted by the domain:devx#1 seat.


Generated by Claude Code

@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 24, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 24, 2026 15:13
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 67ebc84 Sep 24, 2026
37 of 38 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-19848-error-catalog-invalid-format branch September 24, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant