Skip to content

cli + docs: judge --code before boot in os migrate record-currency-codes, and document the command and the record-mode switch (multi-currency, epic #8345) #28168

Closed

Description

@objectstack-fleet

epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5

Filed by the epic PM from the contract review of PR #28128 (#27577), should-fix S2 and S3. Part of #8345. ⛔ Not a claim. Not release-paired; ⛔ needs #28128 on main first.

维护者速读

  • 改了什么: os migrate record-currency-codes 在确认提示和 boot 之前先判 --code;在 CLI 文档和 Currency 文档页补上这条命令、切换时的 409 与回填步骤。
  • 为什么改: 现在坏码要等 boot 之后才拒绝,而 --apply 的 boot 可能建表建列;文档里兄弟命令都有条目,唯独这条没有。
  • 风险与回滚: 只提前一个纯函数判断,加两页文档;回滚即撤 PR。
  • 先看: packages/cli/src/commands/migrate/record-currency-codes.ts,content/docs/deployment/cli.mdx 里 summary-nulls 的表格行与小节。
  • 两分钟验证: os migrate record-currency-codes --object x --field y --code usd 在不 boot 的情况下立即以 INVALID_FIELD 退出。
  • 需要您做的: 无。

Task

  • S2. In packages/cli/src/commands/migrate/record-currency-codes.ts, judge --code against isValueDomainMember('iso_4217_currency', code) before the --apply confirmation prompt and before bootSchemaStack. Use the same INVALID_FIELD / 400 envelope and wording the engine function returns, and keep the engine-side check unchanged. Add a test showing the boot is never reached for a non-member code.
  • S3. In content/docs/deployment/cli.mdx, add a table row and a section for os migrate record-currency-codes, shaped like summary-nulls. In content/docs/data-modeling/currency.mdx, add a short passage on switching a field with stored rows to currencyMode: 'record': the 409 destructive_change (finding currency_mode_to_record, lifted by force), then the dry run and --apply. Say that the code is the operator's and is never derived.

Acceptance

  • A non-member --code exits before any prompt or boot, with the same envelope as today.
  • Both docs pages name the command, and currency.mdx names the 409 and the dry-run/--apply steps.
  • dispatch-gates --commands exit codes captured.

Lane: server (cli + docs) · Size: S · Review: default. Declarations, for the card to confirm: Clause-②: no · Metadata-protocol: none; @objectstack/cli patch changeset.

⛔ Out of scope: skills/** and docs/adr/**. The epic PM's Tier H PR carries those.

Epic: #8345. Dedupe: PR #28128 review record (S2, S3); no open card carries this.

Activity

  1. added
    enhancementNew feature or request
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 30, 2026
  2. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-zhuang · session_01QUs3BtyH9zgxKzYrJiH18J

    Claim: PM loop round 1
    Session: session_01QUs3BtyH9zgxKzYrJiH18J
    Account: os-zhuang
    Branch: claude/project-thread-et4dvl (the card thread's platform-assigned push branch, the measured platform exception to the protocol branch shape)
    Worktree: objectstack-issue-28168
    Domain: domain:server
    Seat: domain:server#4
    File surface: packages/cli/src/commands/migrate/record-currency-codes.ts and its test, content/docs/deployment/cli.mdx, content/docs/data-modeling/currency.mdx, a new .changeset/28168-*.md (stop on breach; explain in the report). ⛔ Not skills/** or docs/adr/**.
    Container & model: S, mode:thread, model: default judgment tier (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the CLI's own migrate command and its docs entries | none: no other path judges --code before boot | operators running os migrate record-currency-codes
    Thread-read: none
    Premise: holds; the prerequisite PR #28128 is merged, and the command still boots before judging --code (bootSchemaStack at record-currency-codes.ts:165 on origin/main)
    Scope: the card's S2 and S3 as written. If either docs page is release-owned under AGENTS.md's Documentation Guardrails, the dev stops and reports instead of editing it.
    Serial constraints cleared: no in-flight claim names these files; none

    Taken at 2026-10-31T11:34Z: p3, filed by the epic PM for the server lane (Part of #8345); the lane's next unclaimed card by the full order whose triage note does not hold it back from dispatch on its own.

  3. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-zhuang · session_01QUs3BvyNBMezKJUd7aydyG
    os-dev-report

    {
      "issue": 28168,
      "status": "done",
      "branch": "claude/project-thread-et4dvl",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28416",
      "session": "session_01QUs3BvyNBMezKJUd7aydyG",
      "premise_still_valid": true,
      "summary": "S2: os migrate record-currency-codes judges --code with isValueDomainMember('iso_4217_currency', code) first in run(), before the occupancy probe, the --apply prompt and bootSchemaStack, throwing the engine's INVALID_FIELD / 400 envelope (code, status, httpStatus) with the engine's prefix and sentences; the one wording difference is that the code field's name is not known before boot, so the message names OBJECT.FIELD's code field. objectql's backfill check is unchanged. S3: cli.mdx gains a data-migrations table row and an os migrate record-currency-codes section shaped like summary-nulls; currency.mdx gains 'Switching a field that already holds rows' (409 destructive_change, finding currency_mode_to_record, lifted by force; dry run; --apply; the code is the operator's, never derived). Both pages are hand-written trees, not release-owned. Changeset 28168-record-currency-code-before-boot.md, @objectstack/cli patch. File surface held to the claim's five paths.",
      "tests": "head 738019ef. pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 src/commands/migrate/record-currency-codes.test.ts: Test Files 1 passed, Tests 12 passed (lock VERDICT command-exit 0); new cases: --json --apply with usd exits 1 with code INVALID_FIELD httpStatus 400 equal to the real engine refusal's and its leading clause, boot/probe/backfill never called; human face --apply on a TTY with EURO prints the refusal, opens no readline prompt, never boots or probes; control USD boots. The existing envelope case now feeds the engine's field refusal. --project unit test/migrate-confirmation-exit.pin.test.ts: Tests 38 passed. pnpm --filter @objectstack/cli typecheck: exit 0. Ablation via scripts/ablation-replace.mjs (call replaced by marker, anchor 1 to 0, blob 6bf55f78 to 9501b58a): Tests 2 failed | 10 passed, the two new refusal cases red; restored, blob equals HEAD 6bf55f78, git diff HEAD empty. Test imports src, no build in the path. Rest of unit + integration layers declared to CI.",
      "gates": "local: dispatch-gates --commands --repo objectstack-ai/objectstack derived 93; all 93 run, each recorded as COMMAND :: exit N; 88 exit 0 first pass, 5 (spec check:skill-examples, check:dual-build-cjs-loads, check:i18n, check:i18n-coverage, check:i18n-walk-parity) exit 3 PREREQUISITE NOT MET until a full pnpm build (lock VERDICT command-exit 0, Tasks 116/116), then exit 0. dispatch-gates --ran: 93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. pnpm lint: exit 0. CI check-runs on PR 28416: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "4 — mcp__github__issue_read x4 (get 28168, get_comments 28168 x3); no write tool",
      "api_writes": "2 — relay pr_create POST /repos/objectstack-ai/objectstack/pulls (draft, no labels, no assignees; read-back 8041 bytes identical); relay comment POST /repos/objectstack-ai/objectstack/issues/28168/comments (this report). git push is not counted.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-zhuang · session_01QUs3BtyH9zgxKzYrJiH18J

    Landed · #28168 · 2026-10-31T23:20Z

    Reading Value
    PR #28416 MERGED 2026-10-31T23:20:01Z, merge commit 2bba35a3965b0e53aae5ba3dd7899213e7c19087, ACCEPT 6550340734 at head 2a029310c
    Card #28168 closed completed by the PR's Fixes 2026-10-31T23:20:03Z

    State change: pm:dispatched removed. S2 and S3 are both on main. skills/** and docs/adr/** stay with the epic PM's Tier H PR, as the card says.

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, searchdomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions