Skip to content

console: the build fails on macOS (case-insensitive filesystem): WorkspaceTimezonePrompt.tsx and workspaceTimezonePrompt.ts differ only in case, so the component import resolves to the logic file #12184

Description

@hotlong

Filing gate ①: a reproduced product defect (local macOS build of the pinned console). Filed under the maintainer's direct instruction in this session (2026-10-12: 「你测试遇到的问题创建issue」, then 「使用 pm-dispatch 技能创建 issue」).
Reader: objectui triage (routing), then the domain:ui lane's execution seat. The fix is a file rename in apps/console.
Dedupe: repo:objectstack-ai/objectui is:issue workspaceTimezonePrompt → 5 hits, all states (this card plus #11908, #11758, #11801 and #11693, which are feature or i18n cards with no build defect). … "case-insensitive" build → 48, none about filename casing in the first page.

What was measured

On macOS (APFS, case-insensitive by default), pnpm build of @object-ui/console fails at tsc on objectui d758f2f20dd1, which is cloud's current .objectui-sha. origin/main still carries both files.

src/AppContent.tsx(18,10): error TS2305: Module '"./pages/settings/WorkspaceTimezonePrompt"' has no exported member 'WorkspaceTimezonePrompt'.
src/AppContent.tsx(18,41): error TS1261: Already included file name '.../pages/settings/WorkspaceTimezonePrompt.ts' differs from file name '.../pages/settings/workspaceTimezonePrompt.ts' only in casing.
src/pages/auth/SetupPage.tsx(28,33): error TS1149: ...
src/pages/settings/__tests__/WorkspaceTimezonePrompt.test.tsx(41,10): error TS2305: ...

Cause

apps/console/src/pages/settings/ holds two modules whose paths differ only in case. Both came in with #11761 (objectui#11758, 2026-10-07):

  • WorkspaceTimezonePrompt.tsx, the component
  • workspaceTimezonePrompt.ts, the logic

TypeScript tries .ts before .tsx. On a case-insensitive filesystem, the import ./pages/settings/WorkspaceTimezonePrompt therefore resolves to the logic file workspaceTimezonePrompt.ts, which has no WorkspaceTimezonePrompt export. Linux CI is case-sensitive, so CI stays green.

Reach

Every local macOS build of the console since 2026-10-07 fails this way. That includes cloud's scripts/dev-local/run-stack.sh --with-ui, which builds the console from the objectui checkout: it fails three attempts and aborts with console build failed and no prior dist. Measured 2026-10-12 while setting up a rig to reproduce objectstack-ai/hotcrm#2065.

Workaround, verified

Renaming the logic module to workspaceTimezonePromptLogic.ts and updating its three importers makes tsc pass, and the console build then succeeds. The importers are WorkspaceTimezonePrompt.tsx, __tests__/WorkspaceTimezonePrompt.test.tsx and pages/auth/SetupPage.tsx. No behaviour changes.

Suggested fix

  • Rename one of the two files so that no two paths in the repo differ only in case.
  • Optionally add a CI check that fails on case-colliding paths (git ls-files | sort -f | uniq -di), since Linux CI cannot see this class of break.

🤖 Generated with Claude Code

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Triage: first grade, bug · priority:p2 · domain:ui · area:devpath, into pm:queue. Rename the logic module; the optional case-collision gate is not taken

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T05:53Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Re-read on objectui main today: apps/console/src/pages/settings/ still holds both WorkspaceTimezonePrompt.tsx and workspaceTimezonePrompt.ts.
    • Lane: apps/console is domain:ui.
    • Why p2: every local macOS build of the console fails, and that includes cloud's run-stack.sh --with-ui rig, the one used to reproduce Convert Lead on the hosted 4.0.1 environment jack fails with "Record <id> not found in crm_lead"; it does not reproduce on 17.7.0 locally hotcrm#2065. CI stays green because Linux is case-sensitive, so nothing else will catch it.
    • Direction: rename the logic module (for example workspaceTimezonePromptLogic.ts) and update its three importers, as the card's verified workaround does. No behaviour changes.
    • ⛔ The optional CI case-collision check is not taken here. It is a new gate, and a new gate defaults to no. Re-entry: a second case-colliding pair lands on main, or the maintainer directs it.
    • Pin: tsc for @object-ui/console passes, and git ls-files apps/console | sort -f | uniq -di prints nothing for this directory (recorded in the PR, not as a gate).
    • Clause-②: no.
  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 12, 2026
  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 5 (as triage 6118599573 directs: rename the logic module and update its readers, with no behaviour change; the optional case-collision CI check is not taken)
    Session: session_016djJF12Qt14ejKR5Vjt4sK
    Account: os-steve
    Branch: claude/issue-12184-timezone-prompt-module-rename
    Worktree: objectui-issue-12184
    Domain: domain:ui
    Seat: domain:ui#1
    File surface, on objectui main 26b0bd2:

    • The rename: apps/console/src/pages/settings/workspaceTimezonePrompt.ts → workspaceTimezonePromptLogic.ts (the card's verified name), as a git mv, so the history follows the file.
    • Its readers, measured with git grep at 26b0bd2:
      • apps/console/src/pages/settings/WorkspaceTimezonePrompt.tsx:57 (the import) and :11 (the doc comment naming the file).
      • apps/console/src/pages/settings/__tests__/WorkspaceTimezonePrompt.test.tsx:47.
      • apps/console/src/pages/auth/SetupPage.tsx:28.
      • packages/i18n/src/__tests__/machineLocaleCensus-9909.test.ts:252. This is a fourth reader the card does not list: a census row that names the file by path.
    • .changeset/12184-timezone-prompt-module-rename.md: @object-ui/console patch.
    • ⛔ No new CI check, per the ruling. ⛔ No change to behaviour, exports or i18n keys.
    • (Stop on breach; explain in the report.)
      Container & model: M, mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
      Clause-②: no
      Responsibility: objectui's console app: two modules in apps/console/src/pages/settings/ share the extensionless stem WorkspaceTimezonePrompt and differ only in case, so the component import resolves to the logic file | TypeScript tries .ts before .tsx, and on a case-insensitive filesystem (macOS APFS by default) both resolve, while Linux CI is case-sensitive and stays green | every local macOS build of @object-ui/console since objectui#11758 (2026-10-07), including cloud's run-stack.sh --with-ui rig
      Thread-read: 6118599573
      Serial constraints cleared: read at 2026-10-12T06:46Z on objectui main 26b0bd2:
    • Duplicates: no remote branch or open PR touches this card's subject. The only open PRs are two dependabot bumps and the release PR.
    • This seat's round-5 neighbours, objectui#12187 (the boot screen, packages/app-shell/src/chrome/ and the @object-ui/i18n locale packs) and objectui#12188 (the gallery card title, plugin-list and plugin-detail), touch none of these files. The census file above is the only packages/i18n file here, and objectui#12187 does not touch it.

    A correction to triage's pin, before the dev starts (§0b④). The pin reads "git ls-files apps/console | sort -f | uniq -di prints nothing for this directory". That already prints nothing on main today: the two paths are WorkspaceTimezonePrompt.tsx and workspaceTimezonePrompt.ts, which differ in extension as well as case, so the pin cannot fail. The collision is in the extensionless module stem that TypeScript resolves. The pin the PR records instead:

    git ls-files | sed -E 's/\.(d\.ts|tsx|ts|jsx|js|mjs|cjs|mts|cts)$//' | sort -f | uniq -di
    

    At 26b0bd2 this prints exactly one line, apps/console/src/pages/settings/WorkspaceTimezonePrompt, the only such pair in the repo. After the rename it must print nothing. As triage ruled, this is recorded in the PR and is not a gate.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 12184,
    "status": "done",
    "branch": "claude/issue-12184-timezone-prompt-module-rename",
    "pr": "#12196",
    "session": "session_016djJF12Qt14ejKR5Vjt4sK (subagent: the parent seat's harness-stamped id, as the Claude-Session trailer carries it)",
    "premise_still_valid": true,
    "summary": "Renamed apps/console/src/pages/settings/workspaceTimezonePrompt.ts to workspaceTimezonePromptLogic.ts with git mv (R100, byte-identical) and updated its four readers: the dialog WorkspaceTimezonePrompt.tsx (import plus the doc comment naming the file), its test, pages/auth/SetupPage.tsx, and the machine-locale census row in packages/i18n (its file field only). Added .changeset/12184-timezone-prompt-module-rename.md (@object-ui/console patch). No behaviour, export or i18n-key change; no CI check added. The stem pin prints exactly apps/console/src/pages/settings/WorkspaceTimezonePrompt on origin/main 26b0bd2 and nothing on head 5a2a86c. No macOS run is claimed (H4): the evidence is the pin plus console type-check green. Draft PR #12196 is open with assignee os-steve; the labeler workflow added the path labels apps, tests and package: i18n (this run made no label write).",
    "tests": "All at head 5a2a86c unless stated. | H1 measured: git grep -n workspaceTimezonePrompt at 26b0bd2 found exactly the four path readers the dispatch names: the dialog (its import and the doc comment "is decided in workspaceTimezonePrompt.ts"), the dialog test (the import of browserTimeZone, isAdmissibleZone, mayWrite and promptRecordKey), SetupPage (the import of browserTimeZone) and the census row. Every other hit is an i18n key (console.workspaceTimezonePrompt.* in ten locale packs, t() calls, pending changeset 11758), so H3 holds. No vi.mock string and no docs path names the module. Re-read of origin/main just before pr_create: still 26b0bd2, so no new reader. | H2 measured red, before the commit, with the rename in place and the census row stale: vitest machineLocaleCensus-9909.test.ts gave Tests 2 failed | 5 passed (7), in "no call site passes nothing, ..." and "every declared exemption matches exactly the sites it declares", VERDICT command-exit 1. After the row edit, green (below). | Stem pin before (26b0bd2): one line, apps/console/src/pages/settings/WorkspaceTimezonePrompt. After (5a2a86c): 0 lines, PIPESTATUS 0 0 0 0. Control leg in the same run: the same pipeline over git ls-tree -r --name-only 26b0bd2 still printed that line. Triage pin git ls-files apps/console | sort -f | uniq -di printed nothing at 26b0bd2, confirming the claim's correction. | (1) os-verify-lock: timeout 530 pnpm exec turbo run build --filter='@object-ui/console^...' --concurrency=2: Tasks: 34 successful, 34 total (8 cached), VERDICT command-exit 0, held 230s. | (2) os-verify-lock: pnpm --filter @object-ui/console type-check echoed "tsc --noEmit && tsc -b tsconfig.node.json --force", VERDICT command-exit 0. tsc --listFilesOnly includes workspaceTimezonePromptLogic.ts, WorkspaceTimezonePrompt.tsx, SetupPage.tsx and tests/WorkspaceTimezonePrompt.test.tsx, so type-check covers the test too. | (2) os-verify-lock: pnpm exec vitest run --maxWorkers=2 on WorkspaceTimezonePrompt.test.tsx, setupCreateTimezone-11908.test.tsx, authExitBasename.test.tsx (the two tests that import SetupPage; SetupRoute.test.tsx stubs it) and machineLocaleCensus-9909.test.ts: Test Files 4 passed (4), Tests 44 passed (44), VERDICT command-exit 0. | ESLint narrowed to the five touched source files: --format json reports 5 files, 0 errors, 0 warnings, exit 0; eslint --print-config succeeds for each, so none is ignored. Invariance: eslint.config.js extends tseslint.configs.recommended with no parserOptions.project or projectService (0 hits), so type-aware linting is off, and no eslint-rules/ rule reads the filesystem (0 hits). The diff therefore cannot move a verdict on an untouched file. pnpm lint is CI's. | Ablation: none needed. This is a pure rename, and the H2 red/green pair is the one-time proof for the only reader that is not an import.",
    "gates": {
    "head": "5a2a86c",
    "derivation": "hand-derived for objectui (objectstack dispatch-gates refuses this repo); the dispatch clue list was re-checked against the real diff (six paths: one R100 rename, four reader edits, one changeset), and nothing beyond it is implicated",
    "results": [
    "turbo run build --filter=@object-ui/console^... --concurrency=2 (lock): exit 0",
    "pnpm --filter @object-ui/console type-check (lock): exit 0",
    "vitest, the four targeted files (lock): exit 0, 44/44",
    "pnpm check:unreferenced-sources: exit 0 ("OK Every shipped source file in every covered package is reachable.")",
    "pnpm check:test-path-roots: exit 0 ("check-test-path-roots: OK")",
    "pnpm check:vi-mock-specifiers: exit 0 ("check-vi-mock-specifiers: OK")",
    "node scripts/check-changeset-presence.mjs: exit 0 ("5 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)")",
    "pnpm check:changeset-claims: exit 0 ("No pending changeset names a file this change touches.")",
    "pnpm check:pending-changeset-literals: exit 0 ("No test source names a pending changeset.")",
    "pnpm check:control-bytes: exit 0 ("check-control-bytes: OK")",
    "pnpm check:new-line-citations: exit 0 ("VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only")",
    "node scripts/check-governed-queue-guard.mjs --test (diff paths): exit 0, NOT GOVERNED",
    "eslint on the 5 touched files: exit 0, 0/0"
    ],
    "ci": "in_progress (not awaited, per contract)"
    },
    "line_budget": "n/a: no skills/** and no governed ledger touched. The diff is 6 files, +10/-5, one of them an R100 rename.",
    "files_changed": [
    "apps/console/src/pages/settings/workspaceTimezonePrompt.ts renamed to apps/console/src/pages/settings/workspaceTimezonePromptLogic.ts (R100)",
    "apps/console/src/pages/settings/WorkspaceTimezonePrompt.tsx",
    "apps/console/src/pages/settings/tests/WorkspaceTimezonePrompt.test.tsx",
    "apps/console/src/pages/auth/SetupPage.tsx",
    "packages/i18n/src/tests/machineLocaleCensus-9909.test.ts",
    ".changeset/12184-timezone-prompt-module-rename.md"
    ],
    "deviations": [
    "The fleet relay's transport is one repository_dispatch POST to objectstack-ai/objectstack/dispatches per stroke (two strokes: pr_create, then this comment). That is the relay mechanism, not a content write to objectstack-ai/objectstack, but the dispatch said no write to that repo, so it is named here.",
    "The commit trailer is the model-free pair (Claude-Session plus Co-authored-by: Claude), and the PR footer is the session-URL form. The harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer; objectui AGENTS.md and the os-dev contract take precedence.",
    "The build step was wrapped in timeout 530 inside the lock, to stay under the foreground cap. It finished in 3m48s, so the wrapper never fired.",
    "check-changeset-presence counts two released packages (console, plus i18n through the census test under packages/i18n/src). The changeset declares only @object-ui/console, as the claim set; the fixed group bumps together."
    ],
    "mcp_calls": "0",
    "api_writes": "2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: (1) pr_create, i.e. POST /repos/objectstack-ai/objectui/pulls (draft) plus POST /repos//issues/12196/assignees [os-steve], read back as 5567 bytes sent and 5567 stored, identical; (2) this os-dev-report, POST /repos//issues/12184/comments. Label writes: 0. git push x2 (not REST).",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    ACCEPT: PR objectui#12196 (head 5a2a86c306) · domain:ui seat 1 · session_016djJF12Qt14ejKR5Vjt4sK · 2026-10-12T07:07Z

    Reviewed against GitHub and the diff, not the report. Claim 6119202194.

    Verdict

    • Shape:
      • Draft on main (base 26b0bd2). The first line is Fixes #12184, and Clause-②: no sits at a line start, copied from the claim.
      • Assignee os-steve. The commit trailer and the PR footer carry no model identifier.
    • Scope: 6 files, +10/−5, exactly the claim's surface. check-governed-merges --pr objectstack-ai/objectui#12196: NOT governed, 15 changed lines.
      • The logic module moves as workspaceTimezonePrompt.ts → workspaceTimezonePromptLogic.ts. Its blob is eca94a1964 at base and at head, so the content is byte-identical.
      • The four readers change one line each: the dialog's import and its doc comment, the dialog's test, SetupPage.tsx, and the census row's file field. The census row's expression, count, verdict and reason are unchanged.
      • No behaviour, export or i18n key changes, and no new CI check, as the ruling says.
    • The card's fourth reader is evidenced, not asserted:
      • With the rename in place and the census row stale, machineLocaleCensus-9909 went red (2 of 7), then green after the row edit. The census reads files from disk, so the row has to follow the file.
    • The pin, as the claim corrected it:
      • The extensionless-stem pipeline prints exactly apps/console/src/pages/settings/WorkspaceTimezonePrompt on 26b0bd2 and nothing on the head.
      • A control run of the same pipeline over the base tree still prints the line.
      • Triage's original pipeline printing nothing on main is recorded too. That confirms the correction.
    • What is not claimed: no macOS run. The PR says so, and the evidence is the pin plus type-check for @object-ui/console.
    • Changeset: @object-ui/console patch. The only packages/i18n change is one test row, and check-changeset-presence passes.
    • Gates on this head, read at this record: 23 success, 3 skipped by design, 16 in progress, 0 failure. The seat enqueues only once all of them read success.

    Out-of-scope findings

    None. The stem pin also shows there is no other case-only stem pair in the tree.

    Landing: ready and auto-merge through the merge queue once every check on 5a2a86c is success or skipped by design.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Handover note: PR objectui#12196, at the domain:ui seat 1 clock-out · session_016djJF12Qt14ejKR5Vjt4sK · 2026-10-12T12:24Z

    This seat clocks out on the maintainer's word 「当前任务处理完,合并后就下班」. This card is its one in-flight item, and it is not placed by standing guard, because the session stops. Caretaker: the next domain:ui seat 1 sitter (/pm-dispatch 接手). The claim (6119202194) and assignee os-steve stay as they are. The caretaker carries the landing only. The review judgment is done and is not re-opened.

    Current state:

    • PR objectui#12196 is a draft at head 5a2a86c306. ACCEPT 6119454839 covers that head (Clause-②: no, NOT governed).
    • Its only red is Test. Test (shard 1/8) hit the 20-minute cap and was cancelled with every finished test green; the test it interrupted was an unrelated plugin-form one. That is run 38215707699, attempt 1. PR comment 6119717818 says so.
    • The class is ruled on objectui#12208 (B staged; the 8 → 12 shard move rides objectui#12232, open at this note).

    Landing steps, in order:

    1. Get one green run on this PR. There are two legitimate ways:
    2. When every check on the current head is success or skipped by design, and check-governed-merges --pr reads NOT governed, run relay pr_ready plus automerge_enable and confirm added_to_merge_queue.
    3. After the merge:
      • blob-verify each of the PR's files against 5a2a86c (or line-prove any file a base merge touched);
      • post a landing note here and remove pm:dispatched;
      • check the card closed through Fixes #12184.
    • A head that changes beyond a base merge needs a fresh ACCEPT before step 2.

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Landed: PR objectui#12196 → main 08b5d97 · domain:ui seat 1 (tail item after clock-out) · session_016djJF12Qt14ejKR5Vjt4sK · 2026-10-12T13:26Z

    • The merge: through the merge queue, on top of 923504f. The card closed as completed through Fixes #12184. Read in this act: nothing else closed with it.
    • Content check: all 6 files the PR changes are blob-identical at 08b5d97 to the accepted head 5a2a86c306, which ACCEPT 6119454839 covers. The old path apps/console/src/pages/settings/workspaceTimezonePrompt.ts is gone (an R100 rename).
    • How it got green: the maintainer re-ran the failed job on run 38215707699, and attempt 2 passed. Handover step 1(a) in note 6124206253. The seat then enqueued it on the maintainer's question.
    • On main now: the timezone prompt's logic module is workspaceTimezonePromptLogic.ts, so it no longer shares a name, up to case, with WorkspaceTimezonePrompt.tsx. Its four readers point at the new name, and the console builds on a case-insensitive filesystem (macOS).
    • State: pm:dispatched is removed in this act. The card's other labels stay. This was the last in-flight item of the clocked-out seat.

    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:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions