Repository navigation
import preview: the cell check still disagrees with the server's import on dates (looser), rating/slider/progress/toggle (unchecked) and non-ASCII email domains (stricter), so the import button miscounts #11889
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchand removed
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsClaim: PM loop round 8
Session:session_01DrKzdPdyLLBW3qpZ4vtk7z
Account:huangyiirene
Branch:claude/issue-11889-import-cell-check
Worktree:objectui-issue-11889
Domain:domain:ui
Seat:domain:ui#1
File surface (line numbers on5e446ab), underpackages/plugin-grid/src/:ImportWizard.tsx:checkImportCell(about:654–:673) and only what its arms need. That means the date arm (todayDate.parse), the email arm (todayisPlausibleEmail), and new arms forrating,slider,progressandtoggle. Where the spec exports the server's tables (NUMERIC_VALUE_TYPESandBOOLEAN_VALUE_TYPESfrom@objectstack/spec/data), the arms read them by reference, as the option-type sets already are read. ThecellRefusalMessagearm changes only if a code's sentence must follow.importParsers.ts: only if the date grammar belongs besideparseImportNumber.- The tests beside these (
ImportWizard.cellCheck-11814.test.tsand a new*-11889.test.*), and.changeset/11889-*.md.
⛔ Not on it:
- The server's import (
@objectstack/core'simport-coerce.ts, the engine validator) and anypackages/spec/**. If the spec at objectui's pinned version does not export a table the fix needs, the dev reports it rather than widening the pin. packages/plugin-grid/src/ObjectGrid.tsxandpackages/components/src/renderers/complex/data-table.tsx(seat 2's objectui#11816).packages/i18n/**. The existinggrid.import.*sentences are used as they are.
Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuioverImportWizard.tsx: no path-derived mandate; default tier)
Clause-②: no
Responsibility:objectui import wizard preview: the cell check marks a cell the server takes, or passes one it refuses, on dates, rating/slider/progress/toggle and non-ASCII email domains, so the import button miscounts | the platform path is right: the server's import coercion and validator (published 17.7.0) are the contract, and the preview mirrors them, as objectui#11814 set out for options and numbers | everyone importing a CSV into a records list with such a column
Thread-read: none
Serial constraints cleared:noneblocking.- Blocked-by objectui#11814: closed 2026-10-08T05:22:23Z by PR objectui#11886, merged at the same minute.
checkImportCellis onmain5e446ab. area:recordsin flight: seat 2's objectui#11816 (grid inline edit). Its claim6051569447namesImportWizard.tsxandimportParsers.tsas off its surface, so the two are disjoint.- Open objectui PRs: none of the 10 open PRs touches
ImportWizard.tsxorimportParsers.ts. Read 2026-10-08T05:27Z. - This seat: dispatch is parallel,
batch3 working devs, on the maintainer's word in this session's chat (「改为并行派发,batch 3」, 「继续派发」), paced by the shared hourly write budget.- objectui#11871's dev has finished (PR objectui#11897), which freed this slot.
- Working with this card: objectui#11878's dev and objectui#11862's.
Why
Clause-②: no: a client-side preview check inside the Import Wizard. No export, prop,@object-ui/typesmember or accepted input changes, and the server's answer is unchanged.objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11889,
"status": "done",
"branch": "claude/issue-11889-import-cell-check",
"pr": "#11911",
"session": "session_01DrKzdPdyLLBW3qpZ4vtk7z — the session the claim comment 6053019192 names (mode:subagent; this run is its subagent)",
"premise_still_valid": true,
"summary": "checkImportCell now marks a cell exactly where the published 17.7.0 server import refuses it on all three legs. Dates: a mirror of core parseDateCell (readIsoTemporalCell then readYearFirstCell, real-day and clock rules, V8 zone rules computed with UTC setters) plus the supported years the write door applies, in importCoercionContract.ts (isImportableDateCell, IMPORT_TEMPORAL_YEARS) with a paired inventory; 07/15/2026, July 15, 2026 and 1/2/26 are now marked. Types: the boolean and numeric arms key on the spec BOOLEAN_VALUE_TYPES / NUMERIC_VALUE_TYPES (present at the pinned 17.7.0 and at the ^17.5.0 floor), so toggle, rating, slider and progress are checked. Email: isRecordEmail, a one-pass restatement of the record validator EMAIL_RE, takes 735431496@柴仟.com and still refuses a@b; isPlausibleEmail is removed because the identity import, the only path its strict rule served, types its email column text and so never reached the arm (its endpoint applies isLikelyEmail in its own dry run).",
"tests": {
"head": "2867a40 (branch merged with origin/main 9844bbf; local head equals the pushed head)",
"gates": [
"pnpm --workspace-concurrency=2 --filter "@object-ui/plugin-grid..." build → exit 0 → os-verify-lock VERDICT command-exit 0 (Scope: 15 of 47 workspace projects)",
"pnpm --filter @object-ui/plugin-grid type-check → exit 0 → VERDICT command-exit 0; tsc -p tsconfig.test.json --listFilesOnly lists all three edited test files",
"pnpm exec vitest run --maxWorkers=2 packages/plugin-grid/ → exit 0 → Test Files 193 passed (193), Tests 1818 passed (1818); covers every ImportWizard*, importCoercionContract*, importParsers*, importEmailValidation* suite and the new pins; no .guard.test. exists in packages/plugin-grid/src",
"pnpm check:control-bytes → 0 → check-control-bytes: OK (scanned 7937 tracked text file(s); skipped 85 binary)",
"pnpm check:new-line-citations → 0 → VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only",
"pnpm check:changeset-claims → 0 → No pending changeset names a file this change touches",
"pnpm check:pending-changeset-literals → 0 → No test source names a pending changeset",
"pnpm check:spec-symbols (derived: new spec imports) → 0 → nothing cites a key its spec symbol does not declare",
"pnpm check:spec-floors (derived) → 1 → NOT MEASURED for the workspace: all 13 findings are no-artifact on packages outside the build closure; plugin-grid was built and judged with no finding (its dist imports BOOLEAN_VALUE_TYPES / NUMERIC_VALUE_TYPES from @objectstack/spec/data; floor ^17.5.0 exports both)",
"pnpm check:installed-pin-claims (derived: version prose in tests) → 0 → OK",
"pnpm check:phantom-deps (derived) → 0 → Every in-scope import is declared by the package that publishes it",
"pnpm check:test-path-roots (derived: new test files) → 0 → OK",
"node scripts/check-changeset-presence.mjs (derived) → 0 → 5 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)",
"node scripts/check-changeset-no-major.mjs (derived) → 0 → No changeset declares a major bump",
"eslint --no-inline-config on the 5 edited source/test files → 0 → 0 errors, 9 warnings, all outside the diff hunks"
],
"reverse_checks": "Each on committed 0412260 (ImportWizard.tsx blob dfb5fea5), via objectstack scripts/ablation-replace.mjs: anchor 1→0 on disk, blob changed, in-lock grep of the injected text = 1; restore proven blob == HEAD and git diff HEAD empty. Dates (arm back to Date.parse): 2 failed / 7 passed — "date 07/15/2026: expected undefined to deeply equal { code: invalid_date … }" and the preview row-2 date unmarked: overcount, as predicted. Types (literal boolean and number/currency/percent lists): 3 failed / 6 passed — rating/slider/progress, toggle, preview count: overcount, as predicted. Email (old identity rule inline): 2 failed / 7 passed — "expected { code: invalid_email … } to be undefined" and the preview non-ASCII row marked: undercount, as predicted. The first email run hit lock queue-timeout 99 (NOT MEASURED, tree restored) and was rerun.",
"parity_probe": "One-off, not committed: isImportableDateCell vs the published @objectstack/core 17.7.0 coerceFieldValue followed by the write door temporal rule (isUninterpretableTemporalComparand), 43,212 (cell, kind) pairs, server takes 3,395 — 0 disagreements under TZ UTC, Asia/Shanghai and America/New_York; control: the old Date.parse rule disagrees on 16,107. isRecordEmail vs the objectql 17.7.0 EMAIL_RE literal extracted from the tag: 33 values, 0 disagreements.",
"hypotheses": {
"H1": "Confirmed with one correction. At @objectstack/core@17.7.0 (commit 4e4e8814) parseDateCell takes readIsoTemporalCell(s) ?? readYearFirstCell(s) for date/datetime and nothing else. The supported years (date 0001–9999, datetime 1000–9999) are refused at coercion only for a cell the reader already refuses (outsideYears picks the sentence, not the verdict), and at the engine write validation for a cell the reader takes; both answer invalid_date and the mirror carries both. A time cell is read by readTimeOfDayCell then year-first only; time IS a type the preview reaches (importTargetFields passes it) and the preview checks nothing on it — reported as a finding, not fixed (no invalid_time refusal or sentence inside the fence).",
"H2": "Harmless. NUMERIC_VALUE_TYPES at 17.7.0 includes summary, but neither host offers it: importTargetFields drops formula/summary (COMPUTED_TYPES) and ExcelImportBar drops formula/summary/autonumber; and the server coercion reads the same set, so a host that passed summary would still get the server answer.",
"H3": "Confirmed: objectql 17.7.0 record-validator.ts declares EMAIL_RE = /^[^\\s@]+@[^\\s@.]+(?:\.[^\\s@.]+)+$/ and an email cell passes coercion untouched. Mirrored as a one-pass check (no pattern), compared against the literal in importEmailValidation.test.ts, with the adversarial-input timing pin kept.",
"email_identity_measurement": "The wizard can import into an identity object: ObjectView wires sys_user (IDENTITY_IMPORT_OBJECT) to /api/v1/auth/admin/import-users for an admin with features.admin. But identityImportFields types its email column text, so checkImportCell never ran the email arm there, before or after; the identity endpoint applies isLikelyEmail in its dry run (its identity pre-validation runs for dryRun at 17.7.0). So the record validator rule applies alone in the arm, and isPlausibleEmail had no caller left."
},
"deviations": [
"Order premise corrected: the boolean token table is published — @objectstack/spec exports IMPORT_BOOLEAN_TRUE_TOKENS / IMPORT_BOOLEAN_FALSE_TOKENS (and IMPORT_REFERENCE_TYPES) at 17.5.0 and 17.7.0. The local mirror was kept (identical contents, outside the three legs) and noted in the PR Acceptance notes.",
"isPlausibleEmail removed and importEmailValidation.test.ts rewritten for isRecordEmail (the order allowed removal if the identity path no longer needs it; measured: it never reached it).",
"The email mirror lives in importCoercionContract.ts beside the date mirror (fence: mirrored grammar or table), not in ImportWizard.tsx.",
"Gates beyond the order list, derived from the diff: check:spec-symbols, check:spec-floors, check:installed-pin-claims, check:phantom-deps, check:test-path-roots, check-changeset-presence, check-changeset-no-major; and the whole plugin-grid suite instead of only the named paths.",
"Declared bounds of the mirror: a zone-naive datetime is read as UTC (the server reads it in the business timezone), which can differ only within a day of year 1000 or 9999; a supported-years refusal reads "is not a valid date" where the server names the range (needs an i18n key, fenced).",
"Commit trailers use the model-free pair of objectui AGENTS.md instead of the harness model-named Co-Authored-By; the PR footer uses the os-dev session-URL form. The merge commit 2867a40 carries git default message.",
"One-off probes used the @objectstack/core 17.7.0 dist already in objectui node_modules and an npm pack of @objectstack/spec 17.5.0 (scratchpad only). Two temporary probe test files were created and deleted, never committed."
],
"files_changed": [
".changeset/11889-import-cell-check.md (new, @object-ui/plugin-grid patch)",
"packages/plugin-grid/src/ImportWizard.tsx",
"packages/plugin-grid/src/importCoercionContract.ts",
"packages/plugin-grid/src/importCoercionContract.test.ts",
"packages/plugin-grid/src/importEmailValidation.test.ts",
"packages/plugin-grid/src/ImportWizard.cellCheck-11889.test.tsx (new)"
]
},
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "2 — through the fleet-write relay as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectui/pulls (pr_create, draft, PR 11911; read-back 8936 bytes sent = stored); POST /repos//issues/11889/comments (this os-dev-report, via post-stamped.mjs). Plus git push of the branch (not REST). Zero label, assignee or PATCH writes.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: probe of the preview check against the published @objectstack/core 17.7.0 coerceFieldValue (the form of this card own reach); the time target is reachable — importTargetFields passes time fields · evidence: checkImportCell has no time arm; measured, the preview takes 25:00, abc, 10:00Z and 9am in a time column (5 of 5 cells taken), and the server refuses those four with invalid_time and takes 10:00; the button overcounts · Seam: core import-coerce.ts readTimeOfDayCell → renderer: ImportWizard checkImportCell (needs an invalid_time refusal and a grid.import sentence) · dedupe words: import preview time column not validated · import preview invalid_time · time cell 25:00 counted by import button",
"class: a · reach: the same probe form on the user import (ObjectView sys_user → /api/v1/auth/admin/import-users) · evidence: identityImportFields types every column text, so the preview checks no email there; the identity endpoint refuses a non-ASCII or placeholder address with INVALID_EMAIL (isLikelyEmail / isPlaceholderEmail, in its dry run too), so until Validate the button counts that row · Seam: plugin-auth admin-import-users resolveRowIdentity → renderer: ImportWizard checkImportCell via identityImportFields · dedupe words: user import preview email not checked · identity import button counts invalid email · sys_user import preview INVALID_EMAIL",
"carrier: none (承接者:无) · noted, not filed — @objectstack/spec publishes IMPORT_BOOLEAN_TRUE_TOKENS / IMPORT_BOOLEAN_FALSE_TOKENS / IMPORT_REFERENCE_TYPES (17.5.0 and 17.7.0) while importCoercionContract.ts still mirrors the tokens under a stale "not published yet" note; identical today (unexercised drift); in the PR Acceptance notes",
"carrier: none (承接者:无) · noted, not filed — a supported-years refusal reads "is not a valid date" in the preview where the server names the range; a range sentence needs a new grid.import key in packages/i18n; in the PR Acceptance notes"
]
}objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsReview: ACCEPT — PR objectui#11911 (head
2867a40)domain:uiseat 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· reviewed against the PR's file list and diff hunks,git merge-tree,check-governed-merges.mjs, its check runs and the dev's report6053626712, read 2026-10-08T06:15Z.- Shape: draft →
main. The first line isFixes #11889, andClause-②: nostarts the next line. - Scope: 6 files, +456/−49, inside claim
6053019192's surface. Everything is underpackages/plugin-grid/src/.ImportWizard.tsx(+26/−26 net):checkImportCell's arms. The boolean and numeric arms read the spec'sBOOLEAN_VALUE_TYPES/NUMERIC_VALUE_TYPES, the date arm readsisImportableDateCell, and the email arm readsisRecordEmail. The unusedisPlausibleEmailis removed.importCoercionContract.ts(+165): the mirrored date grammar and supported years, and the email rule, each with a paired inventory inimportCoercionContract.test.ts.- A new pin file, a rewritten
importEmailValidation.test.ts, and an@object-ui/plugin-gridpatch changeset.
- Clause-② re-read:
isPlausibleEmail,isImportableDateCell,isRecordEmailandIMPORT_TEMPORAL_YEARSare module exports, not package-entry exports: the package entry exports onlyImportWizardand its two types. No prop, type member or accepted input changes.noholds. - Governed surface: 0 paths governed, 505 changed lines. That is an ordinary queue landing.
- The three legs, against the card:
- Dates: the server's grammar (
readIsoTemporalCell, thenreadYearFirstCell, with the real-day and clock rules) and its supported years (date 1–9999, datetime 1000–9999), restated with UTC setters so the browser's parser does not decide.07/15/2026,July 15, 2026and1/2/26are now marked.- Parity probe (one-off, uncommitted) against the published 17.7.0
coerceFieldValueand the write door's temporal rule: 43,212 (cell, kind) pairs, 0 disagreements under three time zones. The oldDate.parserule disagreed on 16,107 of them.
- Parity probe (one-off, uncommitted) against the published 17.7.0
- Types: the spec's sets, which exist at the pinned 17.7.0 and at the
^17.5.0floor, by reference.toggle,rating,sliderandprogressare checked.summaryis in the numeric set and harmless, because neither host offers it as a target (H2, measured). - Email: the record validator's rule, restated as a one-pass check with no pattern and compared against the 17.7.0 literal: 33 values, 0 disagreements.
735431496@柴仟.compasses, anda@bis still marked.- The identity path, measured: the wizard does import into
sys_user, butidentityImportFieldstypes that email column as text, so the strict rule never reached it. RemovingisPlausibleEmailchanges nothing there. The gap it leaves (that path checks no email at all) is filed below.
- The identity path, measured: the wizard does import into
- Dates: the server's grammar (
- Deviations, accepted:
- The boolean tokens are published by the spec (
IMPORT_BOOLEAN_TRUE_TOKENS/…_FALSE_TOKENS), against the order's premise. The local mirror is identical and outside the three legs, so it stays, noted in the PR. - The declared bounds of the mirror: a zone-naive
datetimeis read as UTC where the server uses the business timezone, so they can differ only within a day of year 1000 or 9999. An unsupported year reads "is not a valid date" where the server names the range, because a range sentence needs a new key inpackages/i18n, which is fenced.
- The boolean tokens are published by the spec (
- Tests:
-
Local union on
2867a40(withmain9844bbfmerged in): the wholeplugin-gridsuite, 193 files and 1,818 tests, green. The type-check,eslinton the changed files (0 errors) and the derivedcheck:*set are green, includingcheck:spec-symbols,check:phantom-depsandcheck:installed-pin-claims. -
check:spec-floorsexits 1 workspace-wide on 13 no-artifact findings outside the build closure.plugin-griditself was built and judged with no finding. -
Reverse checks, per leg:
- dates: 2 failed and 7 passed (an overcount);
- types: 3 failed and 6 passed (an overcount);
- email: 2 failed and 7 passed (an undercount).
Each went red in the predicted direction, and each restore was proven by blob hash.
-
- Overlap: an in-memory
git merge-treeagainstmain230e4b2is clean. - CI at
2867a40: converging at this read: 25 green, 3 expected skips, the rest running. The PR is queued when every check completes. - Filed from this card: objectui#11913 (a
timecolumn is not checked, and the user import checks no email; both leave the button overcounting). - Noted, not filed: the stale "not published yet" note on the mirrored boolean tokens, and the year-range sentence. Both are in the PR's Acceptance notes.
- PR assignee: set by this seat to
huangyiirene.
Generated by Claude Code
- Shape: draft →
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsLanded: PR objectui#11911 →
main9fc6ad7domain:uiseat 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· verified 2026-10-08T06:51Z.- Merged through the merge queue at 2026-10-08T06:51:08Z, after it was queued at 2026-10-08T06:34:15Z.
- CI on head
2867a40before queueing: 40 of 43 check runs passed, and the 3 skipped are the expected ones. check-governed-merges.mjs: not governed, +456/−49.
- CI on head
- Content check:
9fc6ad7is one squash commit on parenta49c4bd. It changes 6 files, +456/−49, the same as the PR.- All 6 files are blob-identical to the reviewed head
2867a40, and the whole diff's-U0patch-id matches (798901d9…).
- Card: closed
completedby the PR'sFixes.pm:dispatchedwas removed in the same pass and read back. - On record:
- The preview now marks a cell exactly where the published 17.7.0 import refuses it, for dates, the spec's numeric and boolean types, and record email (ACCEPT
6053665637). - The
timecolumn and the user import's email are objectui#11913.
- The preview now marks a cell exactly where the published 17.7.0 import refuses it, for dates, the spec's numeric and boolean types, and record email (ACCEPT
Generated by Claude Code
- Merged through the merge queue at 2026-10-08T06:51:08Z, after it was queued at 2026-10-08T06:34:15Z.
- added a commit that references this issue
on Oct 8, 2026 - added a commit that references this issue
on Oct 9, 2026
Filing gate ① — product defect with a named location and a reproduction. It is an out-of-scope finding, class a (user-visible wrong result), from the dev report on objectui#11814 (comment 6052219406).
Who acts on it:
domain:uiexecution seat dispatches the fix inpackages/plugin-grid/src/ImportWizard.tsx:checkImportCell's date and email arms and its type coverage.⛔ Not a claim.
Seam: objectstack
packages/core/src/utils/import-coerce.ts(coerceFieldValue,parseDateCell) and the engine's record validator → renderer:ImportWizardpreviewcheckImportCellBlocked-by: #11814
What happens
From PR objectui#11886, the import button counts the rows the preview finds nothing on. So wherever the preview's cell check disagrees with the server's import, the count is wrong, in either direction. Three disagreements remain after that PR:
07/15/2026,July 15, 2026and1/2/26are left unmarked and counted. The server'sparseDateCell(published 17.7.0) refuses all three withinvalid_date. The preview usesDate.parse.rating,slider,progressandtogglehave no arm in the check. The server coerces them as numbers and booleans (the spec'sNUMERIC_VALUE_TYPES/BOOLEAN_VALUE_TYPES). Soabcin a progress column is unmarked and counted.735431496@柴仟.comis markedinvalid_emailand left out of the count. The engine's validator (published 17.7.0) accepts it for a plain email field. The client check was written for the identity import path (framework#3566), which is stricter.Reach
Expected
The preview marks a cell exactly when the server's import refuses it, as objectui#11814 set out for option values and numbers.
Where the spec exports the server's tables, the client should read them by reference, as it already does for the boolean tokens and the option-type sets. The date grammar and the number grammar live in
@objectstack/core, and the client copies the number grammar today. Whether the spec should export them is a question for the fix's dispatch, not a precondition for it.Why it is blocked
All three fixes sit in
checkImportCell, which PR objectui#11886 adds. Until that PR merges and closes objectui#11814, a fix would conflict with it.Duplicate check
Dedupe words: import preview date check looser than server · US date format not flagged in import preview · import preview progress rating toggle not validated · import preview email non-ASCII marked server accepts
Filed by
domain:uiseat 2 (session_01MgfduSkFrfM3eorB3UGfAU) from the objectui#11814 dev report (out_of_scope_findings).Generated by Claude Code