Skip to content

[finding] the zh-CN Operation Message Catalog punctuates with an ASCII comma, while the platform's other shipped zh-CN copy uses the full-width one #12717

Closed

Description

@os-litant

Observational, cosmetic, no behaviour attached. Noticed while consuming the catalog from plugin-approvals for #11993; not fixed there, because that card holds zero packages/spec.

The measurement

Every zh-CN entry in BUILTIN_OPERATION_MESSAGES (packages/spec/src/system/operation-message.ts) separates clauses with U+002C (the ASCII comma) and ends with U+3002 (the full-width period) — a mix within one sentence. Codepoints read off the approval_recall_not_submitter entry:

只有提交人可以撤回这条审批请求,如需撤回请联系提交人或管理员。
                    ^ U+002C                              ^ U+3002

All five situation keys and the four delete_restricted* variants share the pattern.

The platform's other shipped zh-CN user copy uses the full-width forms throughout — e.g. packages/plugins/plugin-approvals/src/translations/zh-CN.objects.generated.ts:

撤回该请求?撤回后审批人将无法继续处理,记录随即解锁。

— U+FF0C and U+FF1F.

Why it is worth a card rather than nothing

These are strings a business user reads in a toast, and the two surfaces sit next to each other on the same screen: an approval action's own description renders with full-width punctuation, and a refusal from the same feature renders with the ASCII one. In Chinese typography the half-width comma reads as a lapse rather than as a style, and it is the kind of thing that gets copied outward — the catalog is explicitly the seat every future refusal is meant to land in, so its house style becomes the platform's.

Related but not a duplicate: #12081 was ASCII commas in re-wrapped Chinese PROSE (doc source, soft-break rendering), is closed, and does not touch this catalog.

Scope note

The English, ja-JP and es-ES rows are unaffected. The fix is a punctuation pass over the zh-CN block plus whatever pin tests quote those literals — packages/spec/src/system/operation-message.test.ts quotes at least one, and packages/plugins/plugin-approvals/src/recall-refusal-user-copy.test.ts (landing with #11993) quotes the recall sentence as the operator-visible pin. Both would move with it.

Measured on origin/main at 15bf9e859. Filed unassigned by the domain:services dev seat.

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 27, 2026
  2. added
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 27, 2026
  3. added theissue type on Aug 27, 2026
  4. huangyiirene commented on Aug 27, 2026

    @huangyiirene
    Collaborator

    Finding round: graded, promoted to pm:queue, finding shed. Routed domain:spec (packages/spec/src/system/operation-message.ts — that package is one lane including its shipped text). Filed correctly rather than ridden along on #11993, which holds zero packages/spec.

    Type Bug, not Task, and the filer's own "cosmetic" framing undersells it: the entries mix U+002C and U+3002 inside a single sentence. That is not a house-style preference anyone chose — it is incorrect Chinese typography, and it ships to a business user in a toast. This seat typed the two objectui copy findings this round (#6610 ar, #6611 de) the same way, so the treatment is consistent across all three.

    ⭐ The propagation argument is what makes it worth doing now rather than eventually. The catalog is explicitly the seat every future refusal is meant to land in — so whatever punctuation it uses becomes the platform's de-facto house style, copied outward by every subsequent entry. Nine keys is a cheap pass; ninety is not. And the two surfaces genuinely sit together on one screen: an approval action's description renders full-width (packages/plugins/plugin-approvals/src/translations/zh-CN.objects.generated.ts, U+FF0C / U+FF1F) while a refusal from the same feature renders ASCII.

    ⚠️ Clause-② path leg fires — the diff touches packages/spec/src/**, and the path leg is independent of content, so it does not care that this is text-only. Dispatched below the contract-review tier, it is ⛔ not enqueueable without needs:contract-review. Same note as #12722 this round; the spec seat should pick the tier deliberately. ⛔ This seat does not attach the gate label — that is the dispatching seat's action at enqueue time.

    ⚠️ Cross-lane read-coupling, and this is the part that will bite if unstated. The fix moves string literals that two pin tests quote:

    ⇒ The file surfaces do not intersect, so a batch-independence check would clear these two — but a pin in the services lane asserts the exact literal this card changes. Whichever lands second turns the other red for no real reason. ⛔ Do not fix that by editing a pin's expectation to match new output. The order that works: #11993's pin lands first, then this card moves the literal and that pin together in one PR, declaring the cross-lane file in its claim. If this card somehow goes first, #11993's dev must be told to write the pin against the new punctuation — ⛔ not against the sentence as quoted in either card body.

    Also in the same cluster this round: #12716 (approvals recall visible-predicate, domain:services, queued this round) touches the same feature though not these literals. Three cards now converge on approval_recall; the services and spec seats should compare notes before dispatching any of them.

    Scope as filed: zh-CN block only — English, ja-JP and es-ES rows are unaffected. All five situation keys plus the four delete_restricted* variants share the pattern. Measured on origin/main at 15bf9e859; re-verify at dispatch, since #11993's pin may have landed meanwhile.

    Dedup confirmed: #12081 (closed) was ASCII commas in re-wrapped Chinese prose in doc source with soft-break rendering — same character, different surface and different cause. ⛔ Not a duplicate.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specDomain lane — seat card indexed by label:pm:seat

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions