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
Action confirm and parameter dialogs: a declared dismiss label (ActionSchema.cancelText), so "Cancel Invitation" no longer sits beside "Cancel" #28519
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 mainefb1620c). ⛔ 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 mainefb1620c, code read)
ActionRunner.confirmOptions() puts the action's label on the confirm button; ActionConfirmDialog draws the dismiss button with the fallback "Cancel".
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).
The console's ActionConfirmDialog and ActionParamDialog draw it when declared; absent, today's "Cancel" stands.
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).
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.
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.
{
"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"
]
}
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".
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: half-state healed ·
pm:queue· 2026-11-02T00:27Z⛔ Not a claim.
check-half-statesH13). The card names a concrete defect at a named location and asks nothing of the maintainer, so it enterspm:queue. Priority stays p3, and the lane takes it in priority order.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Claim: PM loop round 1 · 2026-11-02T00:31Z
Session:
session_01ADHkmPi25XXKx92Xmg4viS(seat); dev = card threadsession_01ADHkmNhdF5oapRdMKNBctQAccount:
os-steveBranch:
claude/project-thread-ejulkcWorktree: the card thread's own checkout of
objectstack-ai/objectstackDomain:
domain:specSeat:
domain:spec#1File 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, regeneratedcontent/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 ofpackages/spec/srcowes one CONTRACT_REVIEW_TIER review before the queue,effort: xhighClause-②: yes (widening)
Metadata-protocol: added
Responsibility:
n/a — not a defect cardThread-read: 6566175889
Premise: holds (
ActionSchemahassubmitTextatpackages/spec/src/ui/action.zod.ts≈L938 and no dismiss-label key;object-formcarriescancelTextatcomponent.zod.tsL7091)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_invitationdeclares 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 namecancelTextwaits for the maintainer's approval before landing (asked in the project); building under it proceeds meanwhile.Amended: the
Metadata-protocol:line now readsadded.widenedis outside the closed set (added | narrowed | semantic | none) thatcheck-changeset-no-majorreads; the dev measured it MALFORMED (report 6567093128, PR #28859). The judgement is unchanged: a new optional key.objectstack-fleet commentedon Nov 2, 2026
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
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Landed · 2026-11-02T02:31Z
76bf6c50d8, via the merge queue (Part of #28519)ActionSchema.cancelText)sys_invitationdeclares "Keep invitation")completedby the seat, split as #27944 → #28158 waspm:dispatchedremoved. 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".