Repository navigation
feat(spec): ImportRowResultSchema declares errors, every cell error of a failed row - #26454
Conversation
… of a failed row Claude-Session: https://claude.ai/code/session_01WGufzfC9dmHR7kTAVNHv56 Co-authored-by: Claude <noreply@anthropic.com>
…ortRowResult.errors Claude-Session: https://claude.ai/code/session_01WGufzfC9dmHR7kTAVNHv56 Co-authored-by: Claude <noreply@anthropic.com>
…sult.errors Claude-Session: https://claude.ai/code/session_01WGufzfC9dmHR7kTAVNHv56 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 146 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 72b207b93a8f3ce0af5e434ef441903042a24314 && git checkout 72b207b93a8f3ce0af5e434ef441903042a24314
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 775a0006bddbf7a1afc88b3a83e52cc0eea96711 eff10df553173382ac5f2164b152375803ad4214 && git checkout -B drift-repro 775a0006bddbf7a1afc88b3a83e52cc0eea96711 && git merge --no-ff eff10df553173382ac5f2164b152375803ad4214
node scripts/docs-audit/affected-docs.mjs --json 775a0006bddbf7a1afc88b3a83e52cc0eea96711 |
Contract reviewServed-tier: ① Derived judgments
② Semver levelFAIL. The changeset grades Precedent agrees with the gate: the Byte-for-byte agreement: the PR body, the changeset and claim 6433227708 all read Respin needed: changeset ③ Boundary flags
Implemented-by: Rendered by an isolated CONTRACT_REVIEW_TIER subagent of seat session_01WGufzfhobWEgUUrjz4rrbh ( VERDICT: FAIL |
… name its cell-coercion scope Claude-Session: https://claude.ai/code/session_01WGufzfC9dmHR7kTAVNHv56 Co-authored-by: Claude <noreply@anthropic.com>
Contract review — addendum to record 6433766607 (FAIL at prior head 2c2ade7)Served-tier: This addendum judges the delta from the prior head 2c2ade7 to this head against the two findings of PR comment 6433766607; the ① judgments of that record stand unless an item below says otherwise. ① Derived judgments
② Semver levelPASS. ③ Boundary flags
Implemented-by: Rendered by an isolated CONTRACT_REVIEW_TIER subagent of seat session_01WGufzfhobWEgUUrjz4rrbh ( VERDICT: PASS |
席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Fixes #26425
Clause-②: yes (widening)
Metadata-protocol: added
维护者速读
errors,列出该行所有转换出错的单元格;原有的field/code/error保留,仍指第一个错误。spec 小版本(minor)。packages/spec/src/api/export.zod.ts(新errors成员与其说明)、packages/spec/src/api/export.test.ts(新 describe 块)。pnpm --filter @objectstack/spec exec vitest run src/api/export.test.ts,预期 57 个测试全绿,其中 7 个是新块。What changes
ImportRowResultSchema(packages/spec/src/api/export.zod.ts) declares one optional member,errors:z.array(ValidateDataIssueSchema), one element per failed cell of a failed row. Its describe says the list holds the import's cell-coercion errors and that a cell error never carries the advisory-onlyruleorseverity, that it is present only on a failed row with at least one cell error, that a row failing for another reason (a duplicate or ambiguous match key) omits it, and that the first-error keysfield,codeanderrorstay and name element 0. The three first-error describes now say they are element 0 whenerrorsis present. The schema docblock gains one paragraph on the key.ImportResponseSchema.resultsand the async job'sImportJobResultsSchema.resultscarry it through the shared row schema; no other schema changes.packages/core/src/utils/import-runner.tsis untouched. Filling the list is /import: common spreadsheet cell shapes fail whole rows (dotted / compact dates, option value case, one error per row) #25582's server half.packages/spec/authorable-surface/api.jsongainsapi/ImportRowResult:errors;content/docs/references/api/export.mdxregenerated bygen:docs. Aminorchangeset for@objectstack/spec(Metadata-protocol: added: the authorable surface gainsapi/ImportRowResult:errors).Why
Ruling
6377844879on #25582 (batch #9 item 3a, letter A), quoted as written: 「一行所有单元格错误一次报全(报告加errors: [{ field, code, message }],原有第一错字段保留)」. Without a declared key,ImportRowResultSchema.parsestrips one, so every reader typed by the schema would lose the list.Element shape:
ValidateDataIssueSchema, reusedMeasured against what the issue asked (reuse unless there is a reason not to):
{ field, code, message }, allz.string().coerceRowreturnsFieldCoerceError[](packages/core/src/utils/import-coerce.ts),{ field: string; code: FieldErrorCode; message: string }, andFieldErrorCodeis a string enum, so the server half can copy the list without mapping.warnings, and the validate verdict's rowerrors(ValidateDataResponseSchema,protocol.zod.ts) isValidateDataIssueSchema[]too, so a row speaks one issue shape and a dry-run reader needs no third type.ruleandseverity. A cell error never carries them (the docblock says so), and both are optional, so nothing is required that a cell error cannot give. Not a reason to mint a new shape.The test pins the element by identity (
toBe(ValidateDataIssueSchema), and equal to thewarningselement) and by type (expectTypeOfagainstValidateDataIssue).Tests
New
describe('ImportRowResultSchema — errors (every cell error of a failed row)')inpackages/spec/src/api/export.test.ts, 7 tests: parse keeps every element in order;field/code/erroragree with element 0 after parse; the key is optional (a first-error-only failed row parses unchanged, noerrorskey); the element isValidateDataIssueSchemaitself; an element withoutmessageis refused at['errors', 0, 'message'];ImportResponseSchemaandImportJobResultsSchemaboth keep it; the typed reader seesValidateDataIssue.Acceptance notes
errortocomposeValidationMessage(verdict.errors)(import-runner.ts, about:1293), every finding joined by;, not element 0'smessage. A row filled fromcoerceRow's list (:1221) keepserrorequal to element 0's message. The describe now scopes the list to the cell-coercion errors, so /import: common spreadsheet cell shapes fail whole rows (dotted / compact dates, option value case, one error per row) #25582 fills it fromcoerceRowonly (option A, confirmed by the spec seat); filling it from verdict rows later would be a visible spec change.check:dev-prereqs(local-only family) is red on this container because 37 workspace packages (mostlyui/) are not built; it judges local workspace state, not this diff.packages/spec/distitself is fresh (the declaration stamp matches, percheck:generated).Verification
Local readings below were taken at head
2c2ade72; the respin ateff10df5(changeset grade and describe sentence only) re-ran the build,gen:docs,check:generated, the changeset gates and the spec suite, recorded in the next block.spec test, typecheck, generated artifacts
pnpm --filter @objectstack/spec test(under the verify lock):Test Files 727 passed (727),Tests 22016 passed | 1 todo (22017), lockVERDICT command-exit 0.pnpm --filter @objectstack/spec typecheck:VERDICT command-exit 0;check:test-typecheck: OK, debt ledger held.pnpm --filter @objectstack/spec check:generated: first run namedcontent/docs/references/**stale; aftergen:docs,✓ All 14 generated artifacts are up to date.respin at eff10df (Metadata-protocol added, minor, describe sentence)
pnpm --filter @objectstack/spec build && gen:docs(lock):VERDICT command-exit 0;check:generated:✓ All 14 generated artifacts are up to date.pnpm --filter @objectstack/spec test(lock):Test Files 727 passed (727),Tests 22016 passed | 1 todo (22017),VERDICT command-exit 0.node scripts/check-changeset-no-major.mjs --base origin/mainwith this body as the event: exit 0,LEVEL AXIS: this PR declares clause-② yes (widening) and metadata-protocol added, and no package ... is graded patch.check-adr-0087-registration: exit 0, no declared-breaking changeset.ablation (one, on the tested behaviour)
node scripts/ablation-replace.mjsrenamed the declared key (errors:toablatedErrors:, anchor 1 to 0, blobee8a1e9b6078to69e10a948a46) and ranvitest run src/api/export.test.ts:Tests 5 failed | 52 passed (57); the five red were the parse, element-0 agreement, element identity, refusal and response/job tests. The optional-key test stayed green, as it should. Restored: blob equals HEAD andgit diff HEADempty. The test imports./export.zodfrom source, so no dist leg applies.derived gate families (dispatch-gates)
node scripts/pm/dispatch-gates.mjs --commandsderived 106 commands from 5 changed paths (142 changed lines). All 106 ran; reconciliation with exit codes recorded:106 derived famil(ies) accounted for — 99 run, 7 NOT-MEASURED (7 DERIVED from a recorded exit 3).NOT MEASURED (exit 3, a prerequisite the gate refused on, none about
packages/spec):pnpm --filter @objectstack/lint run check:doc-formula-expressions,check:doc-security-posture:@objectstack/formula/@objectstack/lintnot built.pnpm --filter @objectstack/spec run check:skill-examples:packages/client-react/distnot built.pnpm check:docs-transcript-drift:@objectstack/lintnot built.pnpm check:dual-build-cjs-loads,pnpm check:lean-entry-closure: other packages'dist/not built.node scripts/check-plugin-teardown-shape.mjs --self-test: shallow checkout (checker health only).CI builds the workspace fresh and runs these families; their verdicts are the PR's check-runs.
Human Minimum
packages/specholds no runtime logic.pnpm lintis CI's run (repo-wide scan, not run locally).main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code