Skip to content

spec(formula): a currency hole with no argument still formats in US dollars — refuse it at authoring in every template dialect (follow-up of #26660) #26939

Closed

Description

@objectstack-fleet

Filing gate: ① a silent default that triage ruled out, measured by in-flight work. Found while landing #26660 item (b) (PR #26937): the dev's os-dev-report on #26660 (6455019677, open question 1, with a census). Filed by domain:spec seat 3 · os-support-ai · session session_01WGufzgbJhFoXYsLSe5WSPP. ⛔ Not a claim. No grade: triage sets lane and grade (spec lane suggested).

Business reason. {{ amount | currency }} with no argument formats the amount in US dollars, whatever currency the record is in. An author who forgets the argument gets a wrong-currency email or page with no refusal anywhere. That is the silent default currency the first triage on #26660 ruled out (6441491903: "⛔ Never a silent default currency"). PR #26799 removed the USD fallback for a bad argument, and PR #26937 adds currency:@path for mail; only the no-argument form still defaults to USD.

Measured (census on 6090bb73, by the #26660 dev; generated, CHANGELOG and release files excluded)

  • Shipped templates that rely on it: examples 0, seeds 0, skills 0, apps 0.
  • Prose and describes that show it: docs 2 (content/docs/automation/flows.mdx:472, content/docs/data-modeling/formulas.mdx:79, both in-app); spec describes / comments 4 (flow-text-slot-template.ts:23, io-node-config.zod.ts:161, :632, :686); service-automation 2 (notify-node.ts:810, builtin/template.ts:104); example prose 2 (the formula invalid-hole message, migration 18.flow-text-slot-single-brace-refused.ts:24).
  • Tests that pin the USD output: 4 (formula template-formatters.test.ts:19, template-hole-grammar.test.ts:114, plugin-email template-engine.test.ts:79, template-hole-grammar.render.test.ts:110), plus 3 fixtures carrying the hole.

Wanted (the spec seat decides the shape)

  • Refuse a no-argument currency at authoring in every dialect that shares the formatter (mail, in-app templates, flow text slots, action / bulk-action copy), with the prescription currency:USD for a fixed code, or currency:@path in mail once feat(spec, formula, plugin-email, lint): a mail template formats an amount in the record's own currency with currency:@path #26937 lands. Same judge as email-template-hole-grammar / the shared hole grammar in @objectstack/formula.
  • Render never formats a no-argument currency in USD silently.
  • Migrate the 2 docs, the describes and comments, and re-pin the 4 tests to the refusal.
  • BREAKING: a stored template with a no-argument currency is refused at its next publish. ADR-0087 disposition: likely a D3 note (the conversion cannot know which currency was meant).

Clause-②: likely no (narrowing). Metadata-protocol: likely narrowed. Skills / docs / eval owed under #26369 B.

Land after PR #26937 (#26660), which touches the same grammar files.

Dedupe

search_issues on this repo: "currency formatter no argument USD default" (open): 2 hits, #26660 (this card's source) and #8345 (exchange rates, a different subject). New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: domain:spec, p2, area:formula · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T22:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Triage: pm:blocked on decision card #27119 (Q2) · 2026-10-28T06:43Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Re-scoped on ruling 6464202770 (#27119 Q2 = X, batch #421, maintainer 「其他同意」) · director seat · session_01QSeKYo7qYsX6HsAneHBMP2 · 2026-10-28T08:29Z · ⛔ not a claim

    Target, replacing the body's "refuse a no-argument currency at authoring" (that was Y):

    State: pm:blocked → pm:queue in this act (the block was this ruling). Ruling-ref: 6464202770.

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 · 2026-10-28T09:36Z
    Session: session_01WGufzfhobWEgUUrjz4rrbh
    Account: os-support-ai
    Branch: claude/project-thread-xl4rgk (card thread session_01WGufzizxYz7JyC5JLW3Gmv. The platform assigns the thread's branch and the thread can push only that one, so the branch is written as measured instead of claude/issue-26939-<slug>.)
    Worktree: objectstack-issue-26939
    Domain: domain:spec
    Seat: domain:spec#1
    File surface:

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 26939,
    "status": "done",
    "branch": "claude/project-thread-xl4rgk",
    "pr": "#27249",
    "session": "session_01WGufzizxYz7JyC5JLW3Gmv",
    "premise_still_valid": true,
    "summary": "A template currency hole with no argument formats in the organization's default currency (localization.currency) in every dialect: mail (plugin-email render, fed by the messaging email and inbox channels), flow text slots (AutomationContext.currency seeded once at run setup), and action / bulk-action copy (ActionRunner.setTenantCurrency from useLocalization). Every server-side read goes through core's resolveLocalizationContext. With no default the render refuses by name: mail TEMPLATE_INVALID (graded permanent, nothing sent), a flow node fails, an action sentence shows as written; the mail refusal also prescribes currency:@path after merging #26937. Changeset carries Clause-② no (narrowing), Metadata-protocol narrowed, Skills-docs, BREAKING with Before/Now, and ADR-0087 registered D3 entry template-currency-no-argument-tenant-default.",
    "tests": "Under os-verify-lock on merged tree f54fc76: test+typecheck exit 0 for @objectstack/formula (1502+), plugin-email, lint, service-messaging, service-automation, spec (22229 passed); spec check:generated exit 0. Pre-merge (ui untouched by the merge): @object-ui/core 4128 passed, react 1502, plugin-grid 2261, type-check exit 0 each. New files: formula template-currency-tenant-default.test.ts, plugin-email template-currency-tenant-default.render.test.ts, messaging template-tenant-currency.test.ts (5), automation builtin/notify-currency-tenant-default.test.ts (8), three ui TenantCurrency-26939 tests. No ablation: the changed behaviour is pinned red/green by the new refusal and render tests themselves.",
    "gates": "dispatch-gates --commands on f54fc76: 121 families, each run with :: exit N recorded; --ran: 121 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0. check:error-code-casing exit 0; check-platform-checklist --changed-from origin/main OK (28 anchors, 0 lost). After the last commit (changeset-only, 645d56f): check-empty-changeset, check-adr-0087-registration --base origin/main, check-changeset-no-major exit 0. Pre-merge: 113/113 exit 0 after building prerequisite dist and deepening the clone (5 first answered exit 3). CI check-runs on #27249: pending at report time.",
    "dogfood_battery": "f54fc7656 · os-verify-lock VERDICT command-exit 0 · dogfood typecheck exit 0 · Test Files 348 passed | 3 skipped (351) · Tests 2804 passed | 20 skipped (2824) · no failures",
    "mcp_calls": "reads only — mcp__github__issue_read, mcp__github__pull_request_read (about 8 calls in all); no MCP write tool used. GitHub writes went through the scripts/pm fleet-write relay: pr_create (#27249), pr_request_reviewers, and this comment.",
    "api_writes": "0",
    "open_questions": [
    {
    "question": "With no tenant default, should a flow screen text render the sentence without a symbol (display surface) instead of failing the node like every other flow text slot?",
    "options": [
    "A keep: every flow text slot refuses the node, one refusal path",
    "B follow-up card: screen texts render the sentence as written, like action copy"
    ],
    "recommendation": "A, because a flow has one renderer and a screen refusal names the hole and the remedy; B can follow if seat 1 reads ruling X's display clause as covering screens."
    }
    ],
    "out_of_scope_findings": [
    "carrier: PR #27249 · the unreleased .changeset/26660-
    .md notes say a no-argument hole still formats in US dollars; check-empty-changeset forbids editing them, so #27249's changeset carries a 'Supersedes, in the same release' paragraph · noted, not filed",
    "carrier: PR #27217 (#26948) · edits plugin-email render() adjacent to this PR's hunk; whichever lands second merges main · noted, not filed"
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-28T16:01Z

    PR #27249 merged through the queue at 79ed6f7d, which is an ancestor of origin/main. On 43 of the 48 paths the PR touched, the merge tree matches the accepted head 9727b511 byte for byte. Five paths are shared with PR #27270, which landed first: email-templates.mdx, formula index.ts and template-engine.ts, plugin-email template-engine.ts, and spec email-service.ts. On those five, the PR's net hunks from the merge-base 9ff8154c are identical to 79ed6f7d^1..79ed6f7d. The queue composed both changes in render() without a manual merge.

    A currency hole with no argument now renders in the tenant's default currency wherever one reaches the render. That covers flow screen text, decision segments resumed cold, and mail through withMailTenantCurrency, which serves both organization mail and identity mail. With no tenant default, screen text fails the node, and action copy is shown as written, with one log line per distinct sentence. This replaces the four pending 26660-*.md USD sentences in the same release. The residual is #27257: a settings read fault is graded permanent.

    The card closed through Fixes #26939, and this seat removes pm:dispatched.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions