Skip to content

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

@objectstack-fleet

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:

  • objectui triage first-grades and routes it.
  • Then a domain:ui execution seat dispatches the fix in packages/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: ImportWizard preview checkImportCell

Blocked-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:

  • Dates are looser than the server. 07/15/2026, July 15, 2026 and 1/2/26 are left unmarked and counted. The server's parseDateCell (published 17.7.0) refuses all three with invalid_date. The preview uses Date.parse.
  • Some numeric and boolean types are not checked. rating, slider, progress and toggle have no arm in the check. The server coerces them as numbers and booleans (the spec's NUMERIC_VALUE_TYPES / BOOLEAN_VALUE_TYPES). So abc in a progress column is unmarked and counted.
  • Email is stricter than the server. A non-ASCII domain such as 735431496@柴仟.com is marked invalid_email and 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

  • Public door: the Import Wizard preview, measured by the objectui#11814 dev in a probe that compared the client check with the published 17.7.0 server functions.
  • The button count these feed lands with PR objectui#11886. Before it, the same disagreements already marked or left unmarked the wrong cells.

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

  • Semantic issue search on objectstack-ai/objectui (open and closed).
    • Query: import wizard preview check disagrees with server import coercion date email progress rating toggle. 2 hits, neither the same defect: objectui#11814 (open, option values and the button count) and objectui#2163 (closed, the legacy path writing lookup text).
    • Second query: ImportWizard preview date Date.parse parseDateCell looser than server. 0 hits.
  • Positive control: the first query returned objectui#11814, the card this one comes from.

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:ui seat 2 (session_01MgfduSkFrfM3eorB3UGfAU) from the objectui#11814 dev report (out_of_scope_findings).


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 8, 2026
  2. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: 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 on 5e446ab), under packages/plugin-grid/src/:

    • ImportWizard.tsx: checkImportCell (about :654–:673) and only what its arms need. That means the date arm (today Date.parse), the email arm (today isPlausibleEmail), and new arms for rating, slider, progress and toggle. Where the spec exports the server's tables (NUMERIC_VALUE_TYPES and BOOLEAN_VALUE_TYPES from @objectstack/spec/data), the arms read them by reference, as the option-type sets already are read. The cellRefusalMessage arm changes only if a code's sentence must follow.
    • importParsers.ts: only if the date grammar belongs beside parseImportNumber.
    • The tests beside these (ImportWizard.cellCheck-11814.test.ts and a new *-11889.test.*), and .changeset/11889-*.md.

    ⛔ Not on it:

    • The server's import (@objectstack/core's import-coerce.ts, the engine validator) and any packages/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.tsx and packages/components/src/renderers/complex/data-table.tsx (seat 2's objectui#11816).
    • packages/i18n/**. The existing grid.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/objectui over ImportWizard.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: none blocking.

    • Blocked-by objectui#11814: closed 2026-10-08T05:22:23Z by PR objectui#11886, merged at the same minute. checkImportCell is on main 5e446ab.
    • area:records in flight: seat 2's objectui#11816 (grid inline edit). Its claim 6051569447 names ImportWizard.tsx and importParsers.ts as off its surface, so the two are disjoint.
    • Open objectui PRs: none of the 10 open PRs touches ImportWizard.tsx or importParsers.ts. Read 2026-10-08T05:27Z.
    • This seat: dispatch is parallel, batch 3 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/types member or accepted input changes, and the server's answer is unchanged.

  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-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"
    ]
    }

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — PR objectui#11911 (head 2867a40)

    domain:ui seat 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 report 6053626712, read 2026-10-08T06:15Z.

    • Shape: draft → main. The first line is Fixes #11889, and Clause-②: no starts the next line.
    • Scope: 6 files, +456/−49, inside claim 6053019192's surface. Everything is under packages/plugin-grid/src/.
      • ImportWizard.tsx (+26/−26 net): checkImportCell's arms. The boolean and numeric arms read the spec's BOOLEAN_VALUE_TYPES / NUMERIC_VALUE_TYPES, the date arm reads isImportableDateCell, and the email arm reads isRecordEmail. The unused isPlausibleEmail is removed.
      • importCoercionContract.ts (+165): the mirrored date grammar and supported years, and the email rule, each with a paired inventory in importCoercionContract.test.ts.
      • A new pin file, a rewritten importEmailValidation.test.ts, and an @object-ui/plugin-grid patch changeset.
    • Clause-② re-read: isPlausibleEmail, isImportableDateCell, isRecordEmail and IMPORT_TEMPORAL_YEARS are module exports, not package-entry exports: the package entry exports only ImportWizard and its two types. No prop, type member or accepted input changes. no holds.
    • 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, then readYearFirstCell, 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, 2026 and 1/2/26 are now marked.
        • Parity probe (one-off, uncommitted) against the published 17.7.0 coerceFieldValue and the write door's temporal rule: 43,212 (cell, kind) pairs, 0 disagreements under three time zones. The old Date.parse rule disagreed on 16,107 of them.
      • Types: the spec's sets, which exist at the pinned 17.7.0 and at the ^17.5.0 floor, by reference. toggle, rating, slider and progress are checked. summary is 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@柴仟.com passes, and a@b is still marked.
        • The identity path, measured: the wizard does import into sys_user, but identityImportFields types that email column as text, so the strict rule never reached it. Removing isPlausibleEmail changes nothing there. The gap it leaves (that path checks no email at all) is filed below.
    • 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 datetime is 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 in packages/i18n, which is fenced.
    • Tests:
      • Local union on 2867a40 (with main 9844bbf merged in): the whole plugin-grid suite, 193 files and 1,818 tests, green. The type-check, eslint on the changed files (0 errors) and the derived check:* set are green, including check:spec-symbols, check:phantom-deps and check:installed-pin-claims.

      • check:spec-floors exits 1 workspace-wide on 13 no-artifact findings outside the build closure. plugin-grid itself 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-tree against main 230e4b2 is 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 time column 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

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11911 → main 9fc6ad7

    domain:ui seat 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 2867a40 before queueing: 40 of 43 check runs passed, and the 3 skipped are the expected ones.
      • check-governed-merges.mjs: not governed, +456/−49.
    • Content check:
      • 9fc6ad7 is one squash commit on parent a49c4bd. 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 -U0 patch-id matches (798901d9…).
    • Card: closed completed by the PR's Fixes. pm:dispatched was 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 time column and the user import's email are objectui#11913.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions