You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Amounts in notices render as bare ungrouped numbers (71100) while the Console shows 13,300.00 #183
Filing gate: ① user-visible defect, found by #179's dev (PR #182), measured on 18.2.0.
Symptom. The overdue-instalment notice (clm.payment_overdue) reads 「计划金额 71100,目前已收付 0」 and 17437.5, with no grouping and no fixed decimals. The same amounts read 13,300.00 in the Console list. Other bundles that carry an amount may do the same, so check every src/email-templates/* hole that holds money.
Expected. Amounts in notices read as they do in the Console (grouped, 2 decimals). The 18.2 template engine has a number formatter (for example number:2). Check that it groups per the recipient's locale.
Not this card. Showing the contract's own currency symbol needs the platform card filed alongside (mail currency formatter takes only a literal code).
Claim: PM loop round 17
Ruling-ref: none (seat-filed defect from #179, PR #182)
Session: session_017nzWFRUo2U7evMkPdVniAn
Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-183-notice-amounts
Worktree: hotclm-issue-183
Domain: repo:hotclm (single-lane sister repo — no domain:*)
Seat: repo:hotclm#1
File surface: src/email-templates/** (amount holes only) — stop on breach; explain in the report
Container & model: S, mode:subagent, model: opus (TIER_DEFAULT; hand-derived for a sister repo), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: this app's notice amounts (grouped and with decimals, as in the Console) | objectstack-ai/objectstack#26660 carries the currency symbol | finance controllers and contract owners
Thread-read: none
Premise: re-measured by the dev on origin/main6abe6a0 (@objectstack 18.2.0)
Serial constraints cleared: #179 landed (PR #182). In flight: #19 (src/data/**) and #181 (renewal-notice.flow.ts); both on disjoint files.
{
"issue": 183,
"status": "needs_decision",
"branch": "claude/issue-183-notice-amounts",
"pr": null,
"session": "session_017nzWFRUo2U7evMkPdVniAn",
"premise_still_valid": true,
"summary": "Premise holds on 6abe6a0 (18.2.0): in a live zh-CN bell, finance reads '计划金额 71100,目前已收付 0' and '计划金额 34875,目前已收付 17437.5'. Only one bundle carries money: clm.payment_overdue has planned_amount and actual_amount, in both members, so 4 holes. The other 7 bundles carry no amount. The 18.2.0 mail renderer takes exactly ONE formatter per hole. number:2 groups per the recipient's locale with fixed 2 decimals (zh-CN 71,100.00; en 71,100.00; fr-FR 71 100,00 with U+202F), but it renders null as empty. Formatters do not chain. '{{ actual_amount | default:0 | number:2 }}' parses as default with the argument '0 | number:2'. It renders the literal text '0 | number:2' for null and the bare ungrouped value otherwise. The reverse order renders empty for null and drops the fixed decimals. So inside the claimed surface (src/email-templates/** only) an amount cannot both read grouped with 2 decimals and keep #179's null-reads-0. Per the surface rule I stopped: no commit, no push, no PR. Route A below was measured live with an uncommitted edit that I then reverted. When I first read the card, the seat's claim was still queued in the relay. It has landed since: labels are pm:dispatched, the assignee is zhuangjianguo, and the Claim comment names src/email-templates/** (amount holes only). I posted no claim.",
"tests": "Renderer: @objectstack/plugin-email@18.2.0 EmailServicePlugin.init with a fake ctx, persist:false, registry = allEmailTemplates. Then services.email.renderTemplate({template, data, locale}), the same method the inbox channel calls. BEFORE (6abe6a0), clm.payment_overdue text, for null/0/71100/17437.5. zh-CN: '计划金额 ,目前已收付 0' / '计划金额 0,目前已收付 0' / '计划金额 71100,目前已收付 71100' / '计划金额 17437.5,目前已收付 17437.5'. en and fr-FR (en-US floor): 'Planned ; received so far 0' / '0; 0' / '71100; 71100' / '17437.5; 17437.5'. Probe, one hole per formatter spelling, x = null/0/71100/17437.5. A number:2 gives ''/0.00/71,100.00/17,437.50 in zh-CN and en, and ''/0,00/71 100,00/17 437,50 in fr-FR. B default:0 | number:2 gives '0 | number:2'/0/71100/17437.5 in all three locales. C number:2 | default:0 gives ''/0/71,100/17,437.5. D number gives ''/0/71,100/17,437.5. E default:0 gives 0/0/71100/17437.5. F number:'2' is the same as A. ROUTE A (template number:2 on both holes plus flow templateData actual_amount = coalesce(guarded read, 0); uncommitted). renderTemplate gives zh-CN 71,100.00 / 17,437.50 / 0.00, en the same, and fr-FR 71 100,00 / 17 437,50 / 0,00 in the text and html faces. Null at the template gives 'Planned ; received so far .', which is why the coalesce has to sit in the caller. LIVE, pnpm demo:zh, port 3159, throwaway DB per run, with the uncommitted cron '* * * * *' on the payment_overdue sweepFlow. finance@example.com set its language to 中文 in the Console account menu (PATCH sys_user locale zh-CN). As finance I created two instalments on MSA-2026-0008: seq 8 (planned 71100, actual null) and seq 9 (planned 34875, actual 17437.5), dated 2026-10-25 and 2026-10-24. The next sweep took both to overdue. Each bell was read in Chromium, signed in as finance, zh-CN. BEFORE bell: '合同 MSA-2026-0008 的第 8 期应于 2026-10-25 收付,目前尚未结清。计划金额 71100,目前已收付 0。' and '…第 9 期…计划金额 34875,目前已收付 17437.5。'. ROUTE-A bell: '…计划金额 71,100.00,目前已收付 0.00。' and '…计划金额 34,875.00,目前已收付 17,437.50。'. 18 seeded rows read the same way, for example '计划金额 217,000.00,目前已收付 108,500.00'. Route-A run: 3 payment_overdue runs completed with error null; sys_notification_delivery 80 success, 0 failed. Browser console in both runs: one 404 and one 401 on resource loads, as in earlier rounds. Both servers were stopped by PID. All measurement edits were reverted with git checkout HEAD: git diff HEAD is empty and grep -c 'MEASUREMENT|cron:' on the flow is 0. Ablation: n/a, nothing committed.",
"gates": "Nothing committed, so there is no head to gate. pnpm install exit 0. Measurement-only runs: pnpm validate exit 0 with the route-A edits applied, which accepts the CEL coalesce in templateData. pnpm validate exit 0 and pnpm lint exit 0 with the chained spelling 'default:0 | number:2' applied, with no diagnostic on it (see finding). The worktree is back at 6abe6a0, clean.",
"dogfood_battery": "n/a — no PR",
"mcp_calls": "0",
"api_writes": "1 — this os-dev-report comment via post-stamped.mjs on objectstack-ai/hotclm#183. No git push (nothing committed). No pr_create.",
"open_questions": [
{
"question": "Where should a null actual_amount become 0 once both amount holes in clm.payment_overdue use number:2?",
"options": [
"A. Widen the claim by one line in src/flows/payment-overdue.flow.ts. templateData.actual_amount becomes a coalesce to 0 in CEL (coalesce(guarded read, 0); 'os validate' accepts it). Both members use '{{ planned_amount | number:2 }}' and '{{ actual_amount | number:2 }}', and default:0 leaves the template. Measured live: '计划金额 71,100.00,目前已收付 0.00' / '17,437.50', 80/80 deliveries. Cost: about 20 minutes plus gates and one more live read. The flow file has no other claim this round (#181 is renewal-notice.flow.ts).",
"B. Template-only, Part of #183. Use number:2 on planned_amount (required, never null) and keep actual_amount as bare default:0. The sentence then mixes formats: '计划金额 34,875.00,目前已收付 17437.5'. The card's own example stays broken.",
"C. Block #183 on a platform card for formatter chaining in mail holes (or a number formatter with a null fallback), and wait."
],
"recommendation": "A. The 18.2.0 template engine says it outright: email templates are data-only renderings and 'any branching belongs in the caller'. So the coalesce is the platform's intended route, not a workaround. It gives the Console's 13,300.00 shape in every locale, and #179's 'nothing received reads 0' keeps holding (now 0.00). The currency symbol stays with objectstack#26660 either way."
}
],
"out_of_scope_findings": [
"class: c · reach: os validate and os lint both exit 0 on a chained mail hole '{{ actual_amount | default:0 | number:2 }}' with no diagnostic, and EmailService.renderTemplate (18.2.0) renders it as the literal text '0 | number:2' for null and as the bare value (71100) otherwise, in subject, text and html. Neither the formula parseHole nor the plugin-email FILTER_RE refuses a second pipe: each reads everything after the first colon as the argument · evidence: probe B above plus the validate and lint runs with the edit applied (since reverted) · Seam: spec:email_template.bodyText/subject hole grammar → runtime:plugin-email template-engine render, formula formatValue · dedupe words: mail template formatter chain, second pipe hole argument, default number chained formatter, template hole multiple formatters"
]
}```---_Generated by [Claude Code](https://claude.ai/code)_
Seat call — open question A · claim amended · 2026-10-27
The dev measured that on 18.2.0 a mail hole takes one formatter only, so number:2 and #179's default:0 cannot share a hole. Seat call: A. The claim's file surface gains one line, templateData.actual_amount in src/flows/payment-overdue.flow.ts, which becomes a CEL coalesce to 0. Both members then use number:2 on both amount holes. Reason: the 18.2.0 template engine states that templates are data-only and 'any branching belongs in the caller', so the coalesce is the platform's intended route, not a workaround. B leaves the card's own example broken, and C waits on a card for a feature the platform documents as out of scope for templates.
File surface (amended): src/email-templates/** (amount holes) · src/flows/payment-overdue.flow.ts (templateData.actual_amount only). The silent acceptance of a chained hole goes to a platform card.
{
"issue": 183,
"status": "done",
"branch": "claude/issue-183-notice-amounts",
"pr": "https://github.com/objectstack-ai/hotclm/pull/188",
"session": "session_017nzWFRUo2U7evMkPdVniAn",
"premise_still_valid": true,
"summary": "Addendum after the seat chose route A (surface widened to templateData.actual_amount in payment-overdue.flow.ts). Commit 1c9f2a5 has three parts. (1) Both members of clm.payment_overdue use number:2 on planned_amount and actual_amount; default:0 is dropped. (2) The header comment and the actual_amount variable description say why the null is settled in the caller: one formatter per hole, number renders null empty, and a second pipe is read as the first formatter's argument. (3) The flow line is now actual_amount: { dialect: 'cel', source: coalesce(ref('instalment.actual_amount').source, 0) }. That is one line, with no new import. Amounts now read grouped with 2 decimals in the recipient's locale, like the Console. Nothing received reads 0.00. No currency symbol, no hard-coded currency (objectstack#26660). The relay opened PR #188 as a draft although the pr_create op carried no draft key, as it did with #182; I left that state alone. The chained-hole finding is not filed here, at the seat's instruction.",
"tests": "renderTemplate: @objectstack/plugin-email@18.2.0 EmailServicePlugin, services.email.renderTemplate over allEmailTemplates at 1c9f2a5, text face shown (html face identical in all 12 cases). zh-CN: 0 gives '计划金额 0.00,目前已收付 0.00', 71100 gives 71,100.00, 17437.5 gives 17,437.50. en (en-US floor): 0.00 / 71,100.00 / 17,437.50. fr-FR (en-US floor): 0,00 / 71 100,00 / 17 437,50, with U+202F. Null at template level renders empty in all three locales; the flow never passes null now. celEngine (@objectstack/formula@18.2.0) on the committed flow expression gives: null to 0, absent to 0, 0 to 0, 71100 to 71100, 17437.5 to 17437.5. Before (6abe6a0), every value rendered bare (71100, 17437.5). LIVE: pnpm demo:zh, port 3159, throwaway DB, with an uncommitted cron '* * * * *' on the payment_overdue sweepFlow. finance@example.com set 中文 in the Console account menu (sys_user.locale zh-CN). As finance I added instalments 8 (71100, nothing received) and 9 (34875, received 17437.5) to MSA-2026-0008, past-dated; the sweep took both to overdue. I then opened bell, then 查看全部通知, then row 8, in Chromium signed in as finance, zh-CN. It read '合同 MSA-2026-0008 的第 8 期应于 2026-10-25 收付,目前尚未结清。计划金额 71,100.00,目前已收付 0.00。'. The bell's first page showed, for example, '计划金额 34,875.00,目前已收付 17,437.50' and '597,200.00 / 298,600.00'. All 20 finance inbox rows match the grouped 2-decimal shape. 3 payment_overdue runs completed with error null; sys_notification_delivery 80 success, 0 failed. Browser console: one 404 and one 401 on resource loads, the same as before. The server was stopped by PID. The cron override was reverted with git checkout HEAD: git diff HEAD is empty, git show HEAD | grep -c cron = 0. This is stated in the PR body. Ablation: n/a. The repo has no test suite pinning this; the proof is the render and live readings above.",
"gates": "head 1c9f2a5, tree equal to HEAD: pnpm install exit 0; pnpm validate exit 0, 'Validation passed', 7 diagnostics, the same set as main, none on these files; pnpm lint exit 0, 0 warnings, 6 suggestions, the same as main; pnpm typecheck exit 0; pnpm lint:i18n-gate exit 0, 'COVERAGE : 0 missing keys across 2 locale(s)'; CLM_DEMO_SEED=1 pnpm validate exit 0. CI check-runs on 1c9f2a5 when read: Validate completed success, plus a second Validate in_progress.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "3 in this session: (1) the first os-dev-report comment (needs_decision) on hotclm#183; (2) pr_create via the fleet-write relay giving hotclm#188 (relay run 40504990324, read-back identical, assignee zhuangjianguo); (3) this addendum comment on hotclm#183. Plus one git push of the branch (not a REST write).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: the PM seat (it is filing it) · the chained mail-hole trap from the first report ('{{ x | default:0 | number:2 }}' passes os validate and os lint, and renders '0 | number:2' for null) · noted, not filed by me"
]
}
Release: amounts in the overdue-instalment notice now read grouped with two decimals in the recipient's locale (「计划金额 71,100.00,目前已收付 0.00」), as in the Console. The currency symbol waits on objectstack#26660. State: pm:dispatched removed, assignee cleared.
Activity
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 17
Ruling-ref: none (seat-filed defect from #179, PR #182)
Session:
session_017nzWFRUo2U7evMkPdVniAnAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-183-notice-amountsWorktree:
hotclm-issue-183Domain:
repo:hotclm(single-lane sister repo — nodomain:*)Seat:
repo:hotclm#1File surface:
src/email-templates/**(amount holes only) — stop on breach; explain in the reportContainer & model:
S,mode:subagent,model: opus(TIER_DEFAULT; hand-derived for a sister repo),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
this app's notice amounts (grouped and with decimals, as in the Console) | objectstack-ai/objectstack#26660 carries the currency symbol | finance controllers and contract ownersThread-read: none
Premise: re-measured by the dev on
origin/main6abe6a0(@objectstack 18.2.0)Serial constraints cleared: #179 landed (PR #182). In flight: #19 (
src/data/**) and #181 (renewal-notice.flow.ts); both on disjoint files.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 183, "status": "needs_decision", "branch": "claude/issue-183-notice-amounts", "pr": null, "session": "session_017nzWFRUo2U7evMkPdVniAn", "premise_still_valid": true, "summary": "Premise holds on 6abe6a0 (18.2.0): in a live zh-CN bell, finance reads '计划金额 71100,目前已收付 0' and '计划金额 34875,目前已收付 17437.5'. Only one bundle carries money: clm.payment_overdue has planned_amount and actual_amount, in both members, so 4 holes. The other 7 bundles carry no amount. The 18.2.0 mail renderer takes exactly ONE formatter per hole. number:2 groups per the recipient's locale with fixed 2 decimals (zh-CN 71,100.00; en 71,100.00; fr-FR 71 100,00 with U+202F), but it renders null as empty. Formatters do not chain. '{{ actual_amount | default:0 | number:2 }}' parses as default with the argument '0 | number:2'. It renders the literal text '0 | number:2' for null and the bare ungrouped value otherwise. The reverse order renders empty for null and drops the fixed decimals. So inside the claimed surface (src/email-templates/** only) an amount cannot both read grouped with 2 decimals and keep #179's null-reads-0. Per the surface rule I stopped: no commit, no push, no PR. Route A below was measured live with an uncommitted edit that I then reverted. When I first read the card, the seat's claim was still queued in the relay. It has landed since: labels are pm:dispatched, the assignee is zhuangjianguo, and the Claim comment names src/email-templates/** (amount holes only). I posted no claim.", "tests": "Renderer: @objectstack/plugin-email@18.2.0 EmailServicePlugin.init with a fake ctx, persist:false, registry = allEmailTemplates. Then services.email.renderTemplate({template, data, locale}), the same method the inbox channel calls. BEFORE (6abe6a0), clm.payment_overdue text, for null/0/71100/17437.5. zh-CN: '计划金额 ,目前已收付 0' / '计划金额 0,目前已收付 0' / '计划金额 71100,目前已收付 71100' / '计划金额 17437.5,目前已收付 17437.5'. en and fr-FR (en-US floor): 'Planned ; received so far 0' / '0; 0' / '71100; 71100' / '17437.5; 17437.5'. Probe, one hole per formatter spelling, x = null/0/71100/17437.5. A number:2 gives ''/0.00/71,100.00/17,437.50 in zh-CN and en, and ''/0,00/71 100,00/17 437,50 in fr-FR. B default:0 | number:2 gives '0 | number:2'/0/71100/17437.5 in all three locales. C number:2 | default:0 gives ''/0/71,100/17,437.5. D number gives ''/0/71,100/17,437.5. E default:0 gives 0/0/71100/17437.5. F number:'2' is the same as A. ROUTE A (template number:2 on both holes plus flow templateData actual_amount = coalesce(guarded read, 0); uncommitted). renderTemplate gives zh-CN 71,100.00 / 17,437.50 / 0.00, en the same, and fr-FR 71 100,00 / 17 437,50 / 0,00 in the text and html faces. Null at the template gives 'Planned ; received so far .', which is why the coalesce has to sit in the caller. LIVE, pnpm demo:zh, port 3159, throwaway DB per run, with the uncommitted cron '* * * * *' on the payment_overdue sweepFlow. finance@example.com set its language to 中文 in the Console account menu (PATCH sys_user locale zh-CN). As finance I created two instalments on MSA-2026-0008: seq 8 (planned 71100, actual null) and seq 9 (planned 34875, actual 17437.5), dated 2026-10-25 and 2026-10-24. The next sweep took both to overdue. Each bell was read in Chromium, signed in as finance, zh-CN. BEFORE bell: '合同 MSA-2026-0008 的第 8 期应于 2026-10-25 收付,目前尚未结清。计划金额 71100,目前已收付 0。' and '…第 9 期…计划金额 34875,目前已收付 17437.5。'. ROUTE-A bell: '…计划金额 71,100.00,目前已收付 0.00。' and '…计划金额 34,875.00,目前已收付 17,437.50。'. 18 seeded rows read the same way, for example '计划金额 217,000.00,目前已收付 108,500.00'. Route-A run: 3 payment_overdue runs completed with error null; sys_notification_delivery 80 success, 0 failed. Browser console in both runs: one 404 and one 401 on resource loads, as in earlier rounds. Both servers were stopped by PID. All measurement edits were reverted with git checkout HEAD: git diff HEAD is empty and grep -c 'MEASUREMENT|cron:' on the flow is 0. Ablation: n/a, nothing committed.", "gates": "Nothing committed, so there is no head to gate. pnpm install exit 0. Measurement-only runs: pnpm validate exit 0 with the route-A edits applied, which accepts the CEL coalesce in templateData. pnpm validate exit 0 and pnpm lint exit 0 with the chained spelling 'default:0 | number:2' applied, with no diagnostic on it (see finding). The worktree is back at 6abe6a0, clean.", "dogfood_battery": "n/a — no PR", "mcp_calls": "0", "api_writes": "1 — this os-dev-report comment via post-stamped.mjs on objectstack-ai/hotclm#183. No git push (nothing committed). No pr_create.", "open_questions": [ { "question": "Where should a null actual_amount become 0 once both amount holes in clm.payment_overdue use number:2?", "options": [ "A. Widen the claim by one line in src/flows/payment-overdue.flow.ts. templateData.actual_amount becomes a coalesce to 0 in CEL (coalesce(guarded read, 0); 'os validate' accepts it). Both members use '{{ planned_amount | number:2 }}' and '{{ actual_amount | number:2 }}', and default:0 leaves the template. Measured live: '计划金额 71,100.00,目前已收付 0.00' / '17,437.50', 80/80 deliveries. Cost: about 20 minutes plus gates and one more live read. The flow file has no other claim this round (#181 is renewal-notice.flow.ts).", "B. Template-only, Part of #183. Use number:2 on planned_amount (required, never null) and keep actual_amount as bare default:0. The sentence then mixes formats: '计划金额 34,875.00,目前已收付 17437.5'. The card's own example stays broken.", "C. Block #183 on a platform card for formatter chaining in mail holes (or a number formatter with a null fallback), and wait." ], "recommendation": "A. The 18.2.0 template engine says it outright: email templates are data-only renderings and 'any branching belongs in the caller'. So the coalesce is the platform's intended route, not a workaround. It gives the Console's 13,300.00 shape in every locale, and #179's 'nothing received reads 0' keeps holding (now 0.00). The currency symbol stays with objectstack#26660 either way." } ], "out_of_scope_findings": [ "class: c · reach: os validate and os lint both exit 0 on a chained mail hole '{{ actual_amount | default:0 | number:2 }}' with no diagnostic, and EmailService.renderTemplate (18.2.0) renders it as the literal text '0 | number:2' for null and as the bare value (71100) otherwise, in subject, text and html. Neither the formula parseHole nor the plugin-email FILTER_RE refuses a second pipe: each reads everything after the first colon as the argument · evidence: probe B above plus the validate and lint runs with the edit applied (since reverted) · Seam: spec:email_template.bodyText/subject hole grammar → runtime:plugin-email template-engine render, formula formatValue · dedupe words: mail template formatter chain, second pipe hole argument, default number chained formatter, template hole multiple formatters" ] }``` --- _Generated by [Claude Code](https://claude.ai/code)_objectstack-fleet commentedon Oct 27, 2026
Seat call — open question A · claim amended · 2026-10-27
The dev measured that on 18.2.0 a mail hole takes one formatter only, so
number:2and #179'sdefault:0cannot share a hole. Seat call: A. The claim's file surface gains one line,templateData.actual_amountinsrc/flows/payment-overdue.flow.ts, which becomes a CEL coalesce to 0. Both members then usenumber:2on both amount holes. Reason: the 18.2.0 template engine states that templates are data-only and 'any branching belongs in the caller', so the coalesce is the platform's intended route, not a workaround. B leaves the card's own example broken, and C waits on a card for a feature the platform documents as out of scope for templates.File surface (amended):
src/email-templates/**(amount holes) ·src/flows/payment-overdue.flow.ts(templateData.actual_amountonly). The silent acceptance of a chained hole goes to a platform card.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
Addendum: route A shipped as PR #188.
{ "issue": 183, "status": "done", "branch": "claude/issue-183-notice-amounts", "pr": "https://github.com/objectstack-ai/hotclm/pull/188", "session": "session_017nzWFRUo2U7evMkPdVniAn", "premise_still_valid": true, "summary": "Addendum after the seat chose route A (surface widened to templateData.actual_amount in payment-overdue.flow.ts). Commit 1c9f2a5 has three parts. (1) Both members of clm.payment_overdue use number:2 on planned_amount and actual_amount; default:0 is dropped. (2) The header comment and the actual_amount variable description say why the null is settled in the caller: one formatter per hole, number renders null empty, and a second pipe is read as the first formatter's argument. (3) The flow line is now actual_amount: { dialect: 'cel', source: coalesce(ref('instalment.actual_amount').source, 0) }. That is one line, with no new import. Amounts now read grouped with 2 decimals in the recipient's locale, like the Console. Nothing received reads 0.00. No currency symbol, no hard-coded currency (objectstack#26660). The relay opened PR #188 as a draft although the pr_create op carried no draft key, as it did with #182; I left that state alone. The chained-hole finding is not filed here, at the seat's instruction.", "tests": "renderTemplate: @objectstack/plugin-email@18.2.0 EmailServicePlugin, services.email.renderTemplate over allEmailTemplates at 1c9f2a5, text face shown (html face identical in all 12 cases). zh-CN: 0 gives '计划金额 0.00,目前已收付 0.00', 71100 gives 71,100.00, 17437.5 gives 17,437.50. en (en-US floor): 0.00 / 71,100.00 / 17,437.50. fr-FR (en-US floor): 0,00 / 71 100,00 / 17 437,50, with U+202F. Null at template level renders empty in all three locales; the flow never passes null now. celEngine (@objectstack/formula@18.2.0) on the committed flow expression gives: null to 0, absent to 0, 0 to 0, 71100 to 71100, 17437.5 to 17437.5. Before (6abe6a0), every value rendered bare (71100, 17437.5). LIVE: pnpm demo:zh, port 3159, throwaway DB, with an uncommitted cron '* * * * *' on the payment_overdue sweepFlow. finance@example.com set 中文 in the Console account menu (sys_user.locale zh-CN). As finance I added instalments 8 (71100, nothing received) and 9 (34875, received 17437.5) to MSA-2026-0008, past-dated; the sweep took both to overdue. I then opened bell, then 查看全部通知, then row 8, in Chromium signed in as finance, zh-CN. It read '合同 MSA-2026-0008 的第 8 期应于 2026-10-25 收付,目前尚未结清。计划金额 71,100.00,目前已收付 0.00。'. The bell's first page showed, for example, '计划金额 34,875.00,目前已收付 17,437.50' and '597,200.00 / 298,600.00'. All 20 finance inbox rows match the grouped 2-decimal shape. 3 payment_overdue runs completed with error null; sys_notification_delivery 80 success, 0 failed. Browser console: one 404 and one 401 on resource loads, the same as before. The server was stopped by PID. The cron override was reverted with git checkout HEAD: git diff HEAD is empty, git show HEAD | grep -c cron = 0. This is stated in the PR body. Ablation: n/a. The repo has no test suite pinning this; the proof is the render and live readings above.", "gates": "head 1c9f2a5, tree equal to HEAD: pnpm install exit 0; pnpm validate exit 0, 'Validation passed', 7 diagnostics, the same set as main, none on these files; pnpm lint exit 0, 0 warnings, 6 suggestions, the same as main; pnpm typecheck exit 0; pnpm lint:i18n-gate exit 0, 'COVERAGE : 0 missing keys across 2 locale(s)'; CLM_DEMO_SEED=1 pnpm validate exit 0. CI check-runs on 1c9f2a5 when read: Validate completed success, plus a second Validate in_progress.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "3 in this session: (1) the first os-dev-report comment (needs_decision) on hotclm#183; (2) pr_create via the fleet-write relay giving hotclm#188 (relay run 40504990324, read-back identical, assignee zhuangjianguo); (3) this addendum comment on hotclm#183. Plus one git push of the branch (not a REST write).", "open_questions": [], "out_of_scope_findings": [ "carrier: the PM seat (it is filing it) · the chained mail-hole trap from the first report ('{{ x | default:0 | number:2 }}' passes os validate and os lint, and renders '0 | number:2' for null) · noted, not filed by me" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Ruling-ref: none (seat-filed defect from #179; seat call A on this card)
Landed — PR #188 · 2026-10-27
MERGED(squash onmain), merged at its ACCEPT head1c9f2a5;Fixes #183closes this cardRelease: amounts in the overdue-instalment notice now read grouped with two decimals in the recipient's locale (「计划金额 71,100.00,目前已收付 0.00」), as in the Console. The currency symbol waits on objectstack#26660. State:
pm:dispatchedremoved, assignee cleared.Generated by Claude Code