Skip to content

console: localize the organization-limit refusal (YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS) in the create-workspace dialog #28124

Closed

Description

@objectstack-fleet

Filing gate ②: a gap measured while landing objectstack-ai/cloud#3382, Sam's 「D 也做」 (2026-10-30 12:51Z), which lowers the hosted org cap to 2. Filed by repo:cloud seat 2. ⛔ Not a claim.

维护者速读

cloud 把每人可建组织数降到了 2。用户建第 3 个组织时,服务端会拒绝(403 YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS)。但控制台的「新建工作空间」对话框没有为这个错误码准备文案,只显示 better-auth 的英文原句,中文用户看到的是英文,也不知道上限是多少。这张卡给这个错误码加上各语言文案。

Facts (objectstack main)

  • ui/packages/app-shell/src/console/organizations/orgErrorMessage.ts: ORG_ERROR_MESSAGE_KEYS has no row for YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS, so the dialog falls back to better-auth's English "You have reached the maximum number of organizations".
  • Measured by cloud#3382's test org-limit-flow.test.ts (PR cloud#3384): a third owned org is refused with 403 and that code.

Work

  1. Map the code to a localized key in every i18n pack, e.g. 「你自己创建的组织已达上限。被邀请加入的组织不计入。」
  2. If the refusal body or the public config exposes the limit, name the number. Otherwise do not invent one.
  3. Tests: the code renders the localized string in zh and en. Include an ablation.

Done when

A zh session that hits the org cap sees a Chinese message that explains it.

Activity

  1. added
    enhancementNew feature or request
    domain:cloudTouches cloud: the whole card is the cloud PM's (repo:cloud seat); no objectstack lane claims it
    status:parkedParked — exempt from the PM sweep and half-state patrol until its owner migrates it (e.g. cloud PM)
    on Oct 30, 2026
  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: moved to the cloud PM · domain:cloud · status:parked · 2026-10-30T14:04Z

    ⛔ Not a claim.

    • This card is the localization gap that cloud#3382 measured (the hosted org cap of 2), and it was filed by the cloud seat. Work item 2 depends on what the cloud refusal body exposes. Under 「一个issue只要涉及 cloud ,就归 cloud pm 处理」 it belongs to the cloud PM.
    • domain:cloud and status:parked. The priority:p3 the filer set stays.

    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    repo:cloudCard routed whole to the cloud PM: needs cloud code, a producer or a fact (cloud owns it to closure)
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    status:parkedParked — exempt from the PM sweep and half-state patrol until its owner migrates it (e.g. cloud PM)
    pm:queueReady for the PM dispatch loop
    on Nov 7, 2026
  4. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    repo:cloud#3 · os-zhuang · session_01QUs3BvRcDHXqRU4TSVE4u6

    Claim: PM loop round 1
    Session: session_01QUs3BvRcDHXqRU4TSVE4u6
    Account: os-zhuang
    Branch: claude/project-thread-oobjtt
    Worktree: the card thread's own clone (mode:thread; the thread can push only its assigned branch, a measured platform exception to claude/issue-N-SLUG)
    Domain: domain:cloud (repo:cloud lane)
    Seat: repo:cloud#3
    File surface: ui/packages/app-shell/src/console/organizations/orgErrorMessage.ts, the 11 console locale packs, their tests, .changeset/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: opus (dispatch-gates --tier: no path-derived mandate, default tier; the maintainer's standing order pauses the ceiling tier), effort: high
    Clause-②: no (console copy only)
    Metadata-protocol: none
    Responsibility: implement + local gates; draft PR Closes #28124; seat reviews and lands
    Thread-read: 6524720181
    Premise: holds (pre-dispatch reading in the dispatch order; the dev re-measures first and stops on a falsified premise)
    Serial constraints cleared: none

  5. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    repo:cloud#3 · os-zhuang · session_01QUs3BveKCXohEcrrpsCh6c
    os-dev-report

    {
      "issue": 28124,
      "status": "done",
      "branch": "claude/project-thread-oobjtt",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/31465",
      "session": "session_01QUs3BveKCXohEcrrpsCh6c",
      "premise_still_valid": true,
      "summary": "Premise held on objectstack main 9728ab15: ORG_ERROR_MESSAGE_KEYS in ui/packages/app-shell/src/console/organizations/orgErrorMessage.ts had no row for YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS, so resolveOrgErrorMessage fell through to better-auth's English sentence. Work item 2: no number is exposed. better-auth 1.7.12 throws it at dist/plugins/organization/routes/crud-org.mjs:61 as APIError FORBIDDEN with the bare code and message; plugin-auth reads the cap inside the organizationLimit callback (auth-manager-organization-plugin.ts:204, resolveOrgLimit at packages/types/src/env.ts:727) and returns a boolean; the /auth/config features object (auth-manager.ts:5047 onward) does not publish it; cloud ac69aac sets OS_ORG_LIMIT: '2' only in the container env (apps/cloud/cloudflare/worker.ts:503). Done: the code maps to organization.errors.organizationLimitReached, defined in all 11 console packs (zh-Hant regenerated from zh-Hans by gen:zh-hant), saying the cap counts only organizations the user created, never invited ones, with no number; changeset @object-ui/i18n + @object-ui/app-shell patch. File surface: the claim's, plus CreateWorkspaceDialog.test.tsx (the dialog-level zh/en pin, a test of the mapping's one create-path consumer).",
      "tests": "Under ui/ on b1443871 (last code commit; head 0ad95797 adds only the changeset): npx vitest run packages/i18n/ packages/app-shell/src/console/organizations/ -> Test Files 116 passed (116), Tests 1967 passed | 13 skipped; VERDICT command-exit 0. New pins: orgErrorMessage-4474.test.ts top-level describe (zh renders the zh pack value, en the en pack value, every pack defines the key with its own sentence and no digit; exact-set pin gains the code) and CreateWorkspaceDialog.test.tsx top-level describe (real zh-Hans and en packs: workspace-create-error shows the pack sentence, not the server English; one create call, no provision). Ablation via scripts/ablation-replace.mjs renaming the mapping row key (anchor x1 -> x0, blob 335e7a7e -> 2050edb8; vitest resolves app-shell source directly, no dist leg): Tests 5 failed | 33 passed (zh+en in both files and the exact-set pin); restore blob == HEAD 335e7a7e, git diff HEAD empty.",
      "gates": "dispatch-gates --commands on head 0ad95797: 38 derived families, all run on that head, each exit 0; --ran: 38 derived, 38 run, 0 NOT-MEASURED, 0 UNRUN (derived zero, every row with its exit code). ui i18n gates: check:i18n-drift exit 0 (0 en values changed, 1 key added), check:i18n-keys exit 0, check:i18n-dead-keys exit 0 (report lists the new key needs-review like its nine organization.errors siblings, a key held as a mapping-table value). Declared narrowing: @object-ui/app-shell type-check not run locally (needs every @object-ui/* package built); Type Check UI on the PR covers it. PR check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "3 — mcp__github__issue_read (get x1, get_comments x2); no write tool",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST issues/31465/assignees, one dispatch, run 42467386136, read-back identical); post-stamped comment on #28124 (this report). git push is not a REST write.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }
  6. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    repo:cloud#3 · os-zhuang · session_01QUs3BvRcDHXqRU4TSVE4u6

    Landed · 2026-11-08T10:58Z

    objectstack#31465 merged at 2026-11-08T10:55Z as a1d243e06 and closed this card. The create-workspace dialog now explains the per-user organization limit in all 11 packs instead of showing the English server sentence. The eager i18n-locale-en ceiling moved 60,000 → 61,000 with its measured rationale. Moving the whole organization.* group into a lazy namespace is the class fix the dev named; it is left to the UI lane.

    Owed after a cloud pin round carries a1d243e06: none beyond the ordinary pin smoke (console-only change).

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

Metadata

Metadata

Assignees

Labels

domain:cloudTouches cloud: the whole card is the cloud PM's (repo:cloud seat); no objectstack lane claims itenhancementNew feature or requestpriority:p3repo:cloudCard routed whole to the cloud PM: needs cloud code, a producer or a fact (cloud owns it to closure)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions