Skip to content

Action confirm and parameter dialogs: a declared dismiss label (ActionSchema.cancelText), so "Cancel Invitation" no longer sits beside "Cancel" #28519

Closed

Description

@objectstack-fleet

domain:ui#1 · os-tesla · session_01L9qibw2uhdSeHYfnZdAf4V

Filing gate: ② the spec half of a measured suggestion row: #27521 row 9, admin half, the last open row of that card (ledger /mnt/project-files/ui-seat-1/r2026-10-31b/out/27521-ledger.md, measured on main efb1620c). ⛔ Not a claim. Triage sets the lane and grade.
Reach: every action whose verb is itself "Cancel …" or "Close …" and that asks for confirmation. On Setup → Invitations, the row menu's Cancel Invitation opens a confirm whose two buttons read Cancel and Cancel Invitation, so an admin cannot tell which button keeps the invitation.
Reader who acts: domain:spec (the key), then domain:ui (the dialog reads it) and the sys_invitation action declares it.
Duplicate search: "cancelText action confirm", "dismiss label action" → none open. #27944 added ActionSchema.submitText for the dialog's submit verb; no dismiss counterpart exists.

Observed (at main efb1620c, code read)

Wanted

  1. ActionSchema.cancelText (an I18nLabelSchema, optional): the label of the dismiss button on the action's confirm and parameter dialogs, beside submitText, with the same translation path (objects.OBJECT._actions.ACTION.cancelText).
  2. The console's ActionConfirmDialog and ActionParamDialog draw it when declared; absent, today's "Cancel" stands.
  3. sys_invitation's cancel action declares cancelText: 'Keep invitation' (with its translations), the row that started this.

Tests

  • Spec: the key parses, translates through the bundle path, and is listed wherever submitText is (the ui SPEC_ACTION_KEYS pin, /meta/types, FLS-style tables that enumerate action keys).
  • Console: a declared cancelText is the dismiss label on both dialogs; control: absent keeps "Cancel".

Acceptance

All three Wanted items are pinned, or answered "will not do" with the reason. Clause-②: yes (widening).

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: half-state healed · pm:queue · 2026-11-02T00:27Z

    ⛔ Not a claim.

    • When triage graded this card p3, it routed it but set no pm state. That left it invisible to every lane's candidate query (check-half-states H13). The card names a concrete defect at a named location and asks nothing of the maintainer, so it enters pm:queue. Priority stays p3, and the lane takes it in priority order.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Claim: PM loop round 1 · 2026-11-02T00:31Z
    Session: session_01ADHkmPi25XXKx92Xmg4viS (seat); dev = card thread session_01ADHkmNhdF5oapRdMKNBctQ
    Account: os-steve
    Branch: claude/project-thread-ejulkc
    Worktree: the card thread's own checkout of objectstack-ai/objectstack
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: the spec half only (Wanted 1 + its tests), mirroring PR #28188's surface for cancelText: packages/spec/src/ui/action.zod.ts + a new test, packages/spec/src/system/translation.zod.ts, packages/spec/src/system/i18n-resolver.ts, packages/lint/src/validate-translation-references.ts + test, packages/spec/liveness/action.json + state-counts/action.md, packages/spec/authorable-surface/ui.json, the metadata-protocol meta-types test pin, ui/packages/core/src/actions/actionKeys.ts, regenerated content/docs/references/**, content/docs/protocol/objectui/actions.mdx, root .changeset/ (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default — dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling fable)"; a widening of packages/spec/src owes one CONTRACT_REVIEW_TIER review before the queue, effort: xhigh
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: n/a — not a defect card
    Thread-read: 6566175889
    Premise: holds (ActionSchema has submitText at packages/spec/src/ui/action.zod.ts ≈L938 and no dismiss-label key; object-form carries cancelText at component.zod.ts L7091)
    Serial constraints cleared: none (no open PR names cancelText; the seat has no other card in flight)

    PR body first line: Part of #28519. Wanted 2 (console dialogs) and Wanted 3 (sys_invitation declares it) are the follow-up half, split as #27944 → #28158 was; the seat files that follow-up from the dev's report. The new public key name cancelText waits for the maintainer's approval before landing (asked in the project); building under it proceeds meanwhile.

    Amended: the Metadata-protocol: line now reads added. widened is outside the closed set (added | narrowed | semantic | none) that check-changeset-no-major reads; the dev measured it MALFORMED (report 6567093128, PR #28859). The judgement is unchanged: a new optional key.

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmNhdF5oapRdMKNBctQ
    os-dev-report

    {
      "issue": 28519,
      "status": "done",
      "branch": "claude/project-thread-ejulkc",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28859",
      "head": "6e2b3ddb",
      "session": "session_01ADHkmNhdF5oapRdMKNBctQ",
      "premise_still_valid": true,
      "summary": "Spec half of #28519 (Wanted 1 + its tests), mirroring #28188's surface: ActionSchema.cancelText, an optional I18nLabel for the dismiss button of the dialog an action opens before it runs (the confirm dialog of a param-less action with confirmText, or the param dialog of an action with non-empty params). Blank refused at parse; refused on an action that declares neither confirmText nor non-empty params (the submitText no-dialog rule carried to this button's two hosts, ADR-0078); cancelLabel renames to it; not picked onto InlineActionSchema. Translation slot objects.OBJECT._actions.ACTION.cancelText / globalActions.ACTION.cancelText, overlaid by translateAction only for an action that opens either dialog; lint checkActionCancelText reports a translation under a dialog-less action as translation-target-unknown (error). Liveness row planned + authorWarn, reconciliation omit row, authorable-surface, SPEC_ACTION_KEYS, meta-types count 51 -> 52, docs section, regenerated references, three changesets (spec minor, lint patch, @object-ui/core patch). PR body line 3 is `Part of #28519`. The PR is a non-governed draft; per the claim it owes one CONTRACT_REVIEW_TIER review before the queue.",
      "tests": "At head 6e2b3ddb (origin/main 3e62a22c merged in), each via os-verify-lock (VERDICT command-exit 0): spec test Files 789/789, Tests 23311 passed + 1 todo; lint Files 189/189, Tests 7829/7829; metadata-protocol (rerun after the main merge, main moved its src) Files 297 passed + 4 skipped, Tests 22093 passed + 26 skipped; @object-ui/core Files 228/228, Tests 4226 passed + 27 skipped. typecheck spec/lint/metadata-protocol Done, @object-ui/core type-check exit 0; eslint on the 8 changed packages/ .ts files exit 0, ui eslint on actionKeys.ts exit 0. Ablations through ablation-replace, each restored to the HEAD blob: no-dialog refinement -> action-cancel-text.test.ts 2 failed | 18 passed; lint confirmText guard -> 2 failed | 231 passed; translateAction guard -> 1 failed | 19 passed; SPEC_ACTION_KEYS minus cancelText -> actionKeys.pin.test.ts 1 failed | 18 passed with missing ['cancelText'] (the pin reads the rebuilt spec dist).",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 6e2b3ddb: 109 commands, 21 paths vs merge base 3e62a22c4, 525 changed lines (+513/-12). All 109 exit 0 (check-plugin-teardown-shape --self-test exited 3 first on a shallow clone; after git fetch --depth=1 origin 621a4876 it reports 48 cases pass, exit 0). --ran: '109 derived famil(ies) accounted for — 109 run, 0 NOT-MEASURED (a DERIVED zero)'. check-changeset-no-major --event with this PR body: exit 0, @objectstack/spec minor for yes (widening) + added. Local-only: check:skill-frame-freshness exit 0; check:dev-prereqs exit 1 as a box precondition (34 ui/ workspace dists not built here; packages/** build 78/78). CI check-runs on #28859: in_progress at report time (not waited on).",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "files_changed": [
        ".changeset/28519-action-cancel-text.md",
        ".changeset/28519-action-keys-cancel-text.md",
        ".changeset/28519-lint-cancel-text-translation.md",
        "content/docs/protocol/objectui/actions.mdx",
        "content/docs/references/data/object.mdx",
        "content/docs/references/kernel/metadata-plugin.mdx",
        "content/docs/references/system/translation.mdx",
        "content/docs/references/ui/action.mdx",
        "content/docs/ui/translations.mdx",
        "packages/lint/src/validate-translation-references.test.ts",
        "packages/lint/src/validate-translation-references.ts",
        "packages/metadata-protocol/src/protocol.meta-types-degenerate-derivation.test.ts",
        "packages/spec/authorable-surface/ui.json",
        "packages/spec/liveness/action.json",
        "packages/spec/liveness/state-counts/action.md",
        "packages/spec/src/system/i18n-resolver.ts",
        "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts",
        "packages/spec/src/system/translation.zod.ts",
        "packages/spec/src/ui/action-cancel-text.test.ts",
        "packages/spec/src/ui/action.zod.ts",
        "ui/packages/core/src/actions/actionKeys.ts"
      ],
      "line_budget": "21 files, +513 / -12 (525 changed lines, under the 3000 human-merge threshold); no governed path; the claimed file surface, nothing outside it",
      "deviations": [
        "Metadata-protocol line: the PR body and the spec changeset say `added`, not the claim's `widened`. `widened` is outside the closed set (added|narrowed|semantic|none): check-changeset-no-major --event with `widened` exits 1, 'metadata-protocol line: MALFORMED … LEVEL AXIS: NOT MEASURED'; with `added` it exits 0. The seat may amend the claim line.",
        "PR body layout: lines 1-2 are the session's required attribution block (marker + Requested-by line), so `Part of #28519` is line 3, right after it (os-dev's harness-attribution exception).",
        "The session's harness instruction to set os-steve as the PR's assignee and reviewer was not carried out: os-dev forbids PR assignees and the standard order forbids MCP writes. The seat hands the PR on.",
        "check:dev-prereqs exit 1 is a box precondition (ui/ dists absent in this container), not run to green."
      ],
      "mcp_calls": "0 — no mcp__github__ calls; reads went through gh api (REST GET)",
      "api_writes": "2 — (1) fleet-write relay dispatch pr_create -> #28859 (POST /repos/objectstack-ai/objectstack/dispatches, run 41373886121 success, 13108 bytes sent = stored); (2) this os-dev-report comment on #28519 through post-stamped.mjs (relay). git push is not counted.",
      "open_questions": [
        {
          "question": "New public key name: does the maintainer approve `cancelText` (standard order item 5)?",
          "options": ["A `cancelText` — the protocol's existing word (object-form's cancelText beside submitText)", "B another name — a rename on this branch"],
          "recommendation": "A, because it pairs with ActionSchema.submitText and object-form's submitText/cancelText; the seat already asked Steve."
        },
        {
          "question": "The no-dialog refusal (cancelText on an action with neither confirmText nor non-empty params is refused at parse) is not in Wanted 1's text. Keep it?",
          "options": ["A keep — the submitText precedent's second rule, so a label that can never show fails loudly (ADR-0078)", "B drop it and keep only the blank refusal"],
          "recommendation": "A, because without it the key parses clean on a click-to-run action and is never drawn, the declared-not-enforced shape the precedent refused."
        },
        {
          "question": "Aliases: only `cancelLabel` (measured on the console's form and alert-dialog renderers) renames to cancelText. Add unmeasured spellings such as dismissText / dismissLabel?",
          "options": ["A cancelLabel only", "B add dismissText / dismissLabel"],
          "recommendation": "A, because the precedent took only measured near-miss spellings."
        },
        {
          "question": "Cross-reference with object-form's cancelText?",
          "options": ["A as built: the ActionSchema docblocks name object-form's pair and each other (submitText's docblock now points at actionCancelText); component.zod.ts describes untouched", "B also add a back-reference in object-form's describes"],
          "recommendation": "A, because submitText's precedent added no back-reference there and B would widen this PR into component.zod.ts and its regenerated reference."
        },
        {
          "question": "Migrations: nothing owed? Checked: git grep -c 'cancelLabel|cancelText' over packages/spec/src/migrations + conversions = 0 files (control submitLabel: 4 files, 17 lines); element:form's six retired keys hold no cancel label; translation-component-submit-label-retired concerns the component copy key submitLabel alone.",
          "options": ["A no twin entry — cancelText moves no existing key", "B add an entry"],
          "recommendation": "A, because nothing is retired or renamed."
        },
        {
          "question": "Follow-up card for Wanted 2 + 3 (as #28158 was for #27944), suggested surface:",
          "options": [
            "ui: core/actions/ActionRunner.ts (ActionDef.cancelText derived from the spec; confirmOptions hands it to the confirm handler) + actionKeys.ts ACTION_DEF_KEYS; react/hooks/useActionTextLocalizer.ts resolves it for the confirm path; components/renderers/action/action-{button,icon,group,menu}.tsx forward it (+ action-forward-precedence test); app-shell hooks/useConsoleActionRuntime.tsx + views/RecordDetailView.tsx paramCollectionHandler pass it; views/ActionParamDialog.tsx draws it over actionDialog.cancel (ActionConfirmDialog.tsx already draws options.cancelText); i18n/useObjectLabel.ts actionCancelText",
            "framework: cli/src/utils/i18n-extract.ts emits it (beside confirmText or params) + test; platform-objects identity/sys-invitation.object.ts cancel_invitation declares cancelText 'Keep invitation' + regenerated translations with zh-CN/ja-JP/es-ES values; spec liveness row -> live (drop authorWarn), delete the reconciliation omit row, offer the key in action.form.ts, drop 'no renderer shows it yet' from the two describes, regenerate references; docs actions.mdx flip both 'does not draw it yet' sentences",
            "tests: a declared cancelText is the dismiss label on both dialogs; control: absent keeps Cancel; bundle key resolves on both paths. Skills (Tier H, separate PR): skills/objectstack-ui/rules/actions.md, skills/objectstack-i18n/SKILL.md"
          ],
          "recommendation": "File it as one ui-lane card with the platform-objects + cli rows, Blocked-by #28859, and a separate skills card for the two governed files."
        }
      ],
      "out_of_scope_findings": [
        "carrier: the Wanted 2+3 follow-up card · noted, not filed — content/docs/protocol/objectui/actions.mdx's submitText section still ends 'The console does not draw it yet', false since #28392 (liveness row live); not this card's defect class"
      ]
    }

    Stamped 2026-11-02T01:44Z.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Landed · 2026-11-02T02:31Z

    Probe Reading
    PR #28859 MERGED, merge commit 76bf6c50d8, via the merge queue (Part of #28519)
    Wanted 1 (ActionSchema.cancelText) landed by PR #28859; maintainer approved the key name 「新协议键 cancelText 这个名字 同意」 (triage record 6567306297)
    Wanted 2 + 3 (console dialogs draw it; sys_invitation declares "Keep invitation") carried to #28879, which also takes the cli extractor and the "declared ahead of its reader" flips from the contract review (6567255334)
    #28519 closed completed by the seat, split as #27944 → #28158 was

    pm:dispatched removed. The seat record is ACCEPT 6567121709 and the contract review is PASS 6567255334, both on PR #28859. Skills-docs follow-up (two Tier H files) is named in #28879 "Not here".

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