Repository navigation
Commit e161ad3
fix(rest): a NOT NULL refusal's hint leads with the remedy for a declared column and names schema drift only as a condition (#21001)
Fixes #20963
Clause-②: no
The `hint` on a driver's NOT NULL refusal no longer asserts that the
schema has drifted. It first says the column requires a value (provide
it, or declare the field `required`), then names drift in one sentence
that is conditional on the object declaring neither `required` nor
`storage: { notNull: true }`. Prose only, in the one branch of the
driver-string classifier in `packages/rest/src/error-response.ts`; the
branch's comment gets the same correction (ADR-0113 D1 / D2). The
status, `code`, `error`, `fields` and `object` are unchanged, no key is
added, no registry is read, and the import row is untouched (PR #20956
pins its key set).
## Repro (`hint`, same answer on both doors)
Object `proj_notnull_hint_20963` declares `must: { type: 'text',
storage: { notNull: true } }` with no `required`. `POST
/api/v1/data/:object` with `must` omitted, and `PATCH
/api/v1/data/:object/:id` writing `must: null`, over a real ObjectQL +
SQLite `:memory:` (the pin's harness). Both answer `400
VALIDATION_FAILED`, `error: "must is required"`, `fields: [{ field:
'must', code: 'required', message: 'must is required' }]`, `object`.
- **Before** (`origin/main` 05be352, the pin run red on it): "If
'must' is optional in your object metadata, the database column is still
NOT NULL — the physical schema has drifted from metadata. Run 'os
migrate' to reconcile (or reset the dev database)."
- **After**: "The database column for 'must' requires a value: provide
it, or declare the field `required` in the object metadata. If the
object declares neither `required` nor `storage: { notNull: true }` for
'must', the physical schema has drifted from metadata instead: run 'os
migrate' to reconcile (or reset the dev database)."
## What is pinned
`packages/rest/src/data-not-null-hint-20963.test.ts`, three tests, by
kind and not by wording:
- the fixture is the ADR-0113 posture: the engine's own insert is
refused by the database for the missing value, and the field declares no
`required`;
- the control, on both doors: status 400, `code`, `error`, the
`required` finding and `object` as before, and the body's key set is
exactly `code, error, fields, hint, object`;
- the `hint`: its first sentence says the column requires a value, tells
the caller to provide it or declare `required`, and names no drift;
drift appears in exactly one later sentence, which begins with a
condition naming `storage` and `notNull`; the update door answers the
create door's hint byte for byte.
Not pinned: telling the two cases apart. That needs a registry read, a
wider change than this card asks.
## Verification (head 5920691)
- **Red on the old text, green on the new.** The pin on `origin/main`
before the edit: 2 failed, 1 passed (the fixture test). With the fix: 3
passed.
- **Ablation.** With the fix committed (cf4bd61, before the rebase
onto 7fa67da), `scripts/ablation-replace.mjs` put the old hint text
back (anchor hit 1 time, blob 0b1a393 to 3197ecfe1; the mutated file
resolves by relative source import from the test, so no rebuild applies)
and the pin went red: 2 failed, 1 passed (the control and fixture held;
the hint tests failed). The restore proved `blob == HEAD` and an empty
`git diff HEAD`. Direction: turned red, the usual one.
- **Package.** `pnpm --filter @objectstack/rest typecheck` exit 0 (`tsc
--noEmit`, and `check:test-typecheck` over `tsconfig.test.json`: 0
files, 0 errors; the new test is in that program). `vitest run --project
local` on `@objectstack/rest`: 250 files passed, 4964 tests passed, 114
skipped. The ten files that read this mapper, this file included, were
also run alone: 10 passed, 567 tests.
- **Gates.** `dispatch-gates --commands` derived 61 commands at this
head; all 61 were run with exit codes recorded and `--ran` reconciled:
61 derived, 59 run, 2 NOT MEASURED, 0 unrun. The two NOT MEASURED exited
3, PREREQUISITE NOT MET: `check:dual-build-cjs-loads` and
`check:type-check-debt` read every package's built output and need the
full-repo build, which was not run on the shared box; `Build Core` and
`Lint & Repo Gates` cover them in CI. The diff adds no package, no
export and no ledger entry, and the package's own test-layer typecheck
holds 0 debt.
- **Lint.** `pnpm lint` (eslint over the whole repo,
`--no-inline-config`) exit 0 at this head, no narrowing.
## Acceptance notes
Noted, not filed (no defect, polish only):
- `packages/rest/src/rest.test.ts` (the test "maps SQLite NOT NULL
constraint → 400 VALIDATION_FAILED with required field", about `:2514`)
keeps a comment that says reaching this branch means the metadata did
not require the field, so it is physical-schema drift. Its assertions
still hold (the hint keeps `os migrate` and "drifted from metadata" in
the conditional sentence), so only the comment restates the corrected
reading. It sits outside this claim's file surface, so it is untouched.
- `packages/rest/src/error-response.ts` `:176` lists "not-null drift" as
a label for the branch in a docblock about a different branch. A name,
not a claim about the hint.
- Branch note: rebased once onto `origin/main` 7fa67da (only
`scripts/pm/fleet-write/` moved) with `--force-with-lease`, before any
PR existed, so the dispatch-gates families were derived from a current
tree.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 8055ff2 commit e161ad3
3 files changed
Lines changed: 201 additions & 7 deletions
File tree
- .changeset
- packages/rest/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1813 | 1813 | | |
1814 | 1814 | | |
1815 | 1815 | | |
1816 | | - | |
1817 | | - | |
1818 | | - | |
| 1816 | + | |
| 1817 | + | |
| 1818 | + | |
| 1819 | + | |
| 1820 | + | |
| 1821 | + | |
| 1822 | + | |
| 1823 | + | |
| 1824 | + | |
| 1825 | + | |
| 1826 | + | |
| 1827 | + | |
| 1828 | + | |
1819 | 1829 | | |
1820 | | - | |
1821 | | - | |
| 1830 | + | |
| 1831 | + | |
1822 | 1832 | | |
1823 | 1833 | | |
1824 | 1834 | | |
1825 | 1835 | | |
1826 | 1836 | | |
1827 | 1837 | | |
1828 | 1838 | | |
1829 | | - | |
1830 | | - | |
| 1839 | + | |
| 1840 | + | |
| 1841 | + | |
1831 | 1842 | | |
1832 | 1843 | | |
1833 | 1844 | | |
| |||
0 commit comments