Skip to content

spec(field): fixed-mode currencyConfig with no defaultCurrency materialises 'CNY' — require the code, drop the default (narrowing; #27119 Q2 X, G3) #27157

Closed

Description

@objectstack-fleet

Filing gate ③ (maintainer-directed). Ruling 6464202770 on #27119 (batch #421 item 2, Q2 = X, maintainer 「其他同意」 2026-10-28): G3. Filed by the director seat (session_01QSeKYo7qYsX6HsAneHBMP2, ledger objectstack#12708). ⛔ Not a claim; triage sets the lane (domain:spec expected) and grade.

Ruling-ref: 6464202770

维护者速读

  • 改了什么: currencyConfig.currencyMode: 'fixed' 必须写 defaultCurrency;去掉 schema 里的 'CNY' 默认值。没写的在发布时拒收,拒收信息写明「fixed 需要币种代码,或改用 dynamic(组织默认币种)」。
  • 为什么改: 今天不写代码的 fixed 字段静默变成人民币字段;美元 / 欧元应用看到 ¥。而且这个默认值在每次 parse 都被物化,连 dynamic 配置也带着它、前端只能刻意忽略——违反已裁原则 FieldSchema accepts deleteBehavior: 'set_null' on a master_detail, and the engine silently resolves it to cascade #9689「永不物化一个 schema 本不会接受的默认」。
  • 风险与回滚: BREAKING(narrowing,minor + 迁移 + ADR-0087 处置)。存量调查:fixed 且无代码的配置预期 0 条,调查是证明。动态行上物化出的 defaultCurrency: 'CNY' 由 ADR-0087 转换剥掉(无读者),固定行保留(曾是生效值)。
  • 先看: packages/spec/src/data/field.zod.ts:555–559。
  • 两分钟验证: { currencyMode: 'fixed' } 不带代码 ⇒ 发布拒收;{ currencyMode: 'dynamic' } parse 结果不再带 defaultCurrency。
  • 需要您做的: 无。

Measured (on origin/main e6e41998, 2026-10-28)

Task

Clause-②: no (narrowing) · Metadata-protocol: narrowed · Skills-docs: line owed in the PR body. Dedupe: #27119 (the ruling), #8345 Q7 (on hold), #9689, #19992 (precision removal); no open card on the CNY default.

Activity

  1. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · 2026-10-28T09:15Z
    Session: session_01WGufzgbJhFoXYsLSe5WSPP
    Account: os-support-ai
    Branch: claude/project-thread-rd9t22 (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-27157-<slug>)
    Worktree: objectstack-issue-27157
    Domain: domain:spec
    Seat: domain:spec#3
    Ruling-ref: 6464202770 (on #27119, Q2 = X: fixed requires defaultCurrency; the 'CNY' default goes; dynamic output carries no defaultCurrency)
    File surface: packages/spec/src/data/field.zod.ts (currencyConfig) and the formula returnType: 'currency' shape, their tests, the ADR-0087 disposition, the liveness ledger line, regenerated baselines / forms / docs, any stored metadata the survey finds, one changeset per touched published package(stop on breach; explain in the report) Container & model:S, mode:thread, model: TIER_DEFAULT — --tier: no path-derived mandate (narrowing; one CONTRACT_REVIEW_TIER review owed, run by the seat; full dogfood owed), effort: highClause-②: no (narrowing) Metadata-protocol: narrowed Responsibility: the spec lane ownsFieldSchema's currency shape; readers outside spec are measured, and changed only if the narrowing breaks them Thread-read: 6464202770 Premise: holds on origin/main 6866e2e: field.zod.ts:559declaresdefaultCurrency: z.string().length(3).default('CNY'), materialised on every parse including dynamicSerial constraints cleared:no open PR on field.zod.ts's currency shape (open PRs searched 09:13Z; #26937 touches formula/plugin-email currency holes, not this schema)`

  2. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 27157,
      "status": "done",
      "branch": "claude/project-thread-rd9t22",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27218",
      "session": "session_01WGufzgHpEdH4Nc37mK73zh",
      "premise_still_valid": true,
      "summary": "Measured on main 6866e2e7: {currencyMode:'fixed'} parsed to defaultCurrency 'CNY' and {currencyMode:'dynamic'} / {} carried 'CNY'. CurrencyConfigSchema.defaultCurrency is now optional with no default; a superRefine refuses fixed without a code at defaultCurrency with the prescription (ISO 4217 code, or dynamic = tenant default), shared by currency fields and formula returnType currency. ADR-0087: D2 currency-config-dynamic-default-currency-removed (toMajor 18, retiredFromLoadPath, retiredAfter 18.2.0) strips the code from dynamic/mode-less stored configs and keeps fixed ones; D3 currency-config-fixed-default-currency-required; DEFAULT_CHANGES_BY_MAJOR[18] row; dropped-refinements +13 sites; liveness note; forms + 4 locale bundles; two docs tables. Survey: 11 fixed configs in examples/platform-objects/qa/seeds/fixtures, 0 without a code. Readers: only @objectstack/formula currencyOf changes (fixed without code now reads unproven, pinned); ui resolveFieldCurrency, analytics relay, share-link projection display unchanged.",
      "tests": "head 5f876858f: spec vitest --project local 742/742 files, 22243 passed | 1 todo; spec typecheck exit 0; formula 56/56 files, 1484 tests, typecheck exit 0; platform-objects 96/96 files, 1361 tests; ui packages/i18n 89/89 files, 1373 passed | 13 skipped; check:generated --fix 14/14 current. Final head c172c878e changes the changeset text only. No ablation run.",
      "gates": "dispatch-gates --commands: 113 derived (same list on c172c878e). 110 exit 0 on the code head; ui scripts vitest (one 15s timeout under dogfood load, exit 0 on rerun), spec check:skill-examples and check:dual-build-cjs-loads (exit 3 prerequisite, exit 0 after building their dist) re-run on c172c878e; changeset families re-run on c172c878e all exit 0; --ran: 113 run, 0 NOT-MEASURED. check-adr-0087-registration: registered currency-config-fixed-default-currency-required, currency-config-dynamic-default-currency-removed. CI check-runs: in_progress at report time.",
      "dogfood_battery": "5f876858f · VERDICT command-exit 0 · Test Files 348 passed | 3 skipped (351) · Tests 2804 passed | 20 skipped (2824) · no failures",
      "mcp_calls": "1 — get_session (read, own session id); no GitHub MCP calls",
      "api_writes": "3 via fleet-write relay — pr_create objectstack-ai/objectstack#27218; pr_request_reviewers #27218; comment #27157 (this report)",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #27218 comment 6469020240

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 3 · os-support-ai · 2026-10-28T13:23Z

    reading value
    PR #27218 merged through the queue at 2026-10-28T13:22Z, merge commit 0cd578f726
    origin/main contains the merge commit (git merge-base --is-ancestor)

    Delivered (ruling X, 6464202770 on #27119 Q2):

    • currencyConfig.defaultCurrency has no 'CNY' default. A fixed config with no code is refused at parse, for currency fields and for formula fields returning currency, with the prescription "give an ISO 4217 code, or use dynamic (the tenant default currency)".
    • A dynamic config's parse output carries no defaultCurrency. The ADR-0087 conversion currency-config-dynamic-default-currency-removed strips the materialised code from stored dynamic rows on read.
    • A stored code-less fixed row still loads and registers, is counted invalid at boot with [metadata_spec_invalid], and its next save returns 422 until a code is written. Its display is unchanged.

    Owed elsewhere: #27184 (currencyMode: 'record'), which also reshapes currencyMode and is where a discriminated union would make the JSON Schema project this rule exactly. pm:dispatched is removed here.

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:specpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions