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
spec(ui): an inline action accepts confirmText beside params, the pair ActionSchema refuses as two dialogs; once #29369 gives the inline pick description, decide whether the inline door refuses it too #29383
Ruled: 6595808462 · letter A · 2026-11-03T04:55Z
Ruling-ref: 6595808462
Filing gate: ① a design question named by the CONTRACT_REVIEW_TIER review of PR #29370's sibling PR #29369 (#29248), record 6578506913, kept out of that PR to hold it to its claimed surface (it would be a Clause-②: no (narrowing) rider on a widening). ⛔ Not a claim. No grade: triage sets it.
What the code does
packages/spec/src/ui/action.zod.ts, ActionSchema's refinement on confirmText beside a non-empty params (≈L2280–2305 on main): refused, because the console opens a confirm dialog and then a separate params dialog, and the remedy the message names is to move the sentence into description, which the params dialog draws under its title. The comment beside it says the refusal is scoped by schema boundary: BulkActionDefSchema renders the pair as ONE dialog (correct there), and InlineActionSchema.pick()s from the field factory, so the refusal does not reach it.
InlineActionSchema (≈L2581) picks both params and confirmText. On main it did not pick description, so an inline author had nowhere to move the sentence and refusing the pair would have left no remedy. PR #29369 adds description: true to the pick, so that reason no longer holds once it lands.
The question
Does an inline action with confirmText and non-empty params open two dialogs in the renderer (elements.tsx → ActionRunner → useConsoleActionRuntime), the same way a registered action does? Not measured here.
If it does: the inline door should refuse the pair with the same message family (move the sentence to description), a Clause-②: no (narrowing) change with an ADR-0087 entry and a census of inline actions that carry both keys across examples/, packages/** and cloud fixtures.
If it draws one dialog: the inline shape is like the bulk shape, and the action.zod.ts comment should say so instead of leaving the question open.
Wanted
Measure the renderer path for an inline action carrying both keys, count the in-repo inline actions that do, and land whichever of the two answers the measurement gives, with a test that pins it.
Blocked-by: #29248 (the inline description pick, PR #29369)
Reader who acts: the packages/spec ui-schema owner (domain:spec by the anchoring rule).
Dedupe: searched confirmText params InlineAction, confirmText params inline action refuse, confirm-params-guard: only the closed copy-slot cards #24798 / #24814 and unrelated dialog cards. New.
Claim: PM loop round 1 · 2026-11-02T15:10Z
Session: session_01ADHkmPi25XXKx92Xmg4viS (seat); dev = card thread session_01ADHkmRm5hBTGQxuqruuueG
Account: os-steve
Branch: claude/project-thread-k5x85e
Worktree: the card thread's own checkout of objectstack-ai/objectstack
Domain: domain:spec
Seat: domain:spec#1
File surface: packages/spec/src/ui/action.zod.ts (the confirmText / params refinement comment, or after a ruling InlineActionSchema's refinement) and its test; on the narrowing path only, an ADR-0087 entry and each in-repo inline carrier's sentence moved to description; root .changeset/; not ui runtime code (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default — the tier is the PM's per-card call (floor sonnet · default opus · ceiling fable); one CONTRACT_REVIEW_TIER review (published schema face) before landing, effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: packages/spec action.zod.ts InlineActionSchema | the confirmText-beside-params refusal stops at the schema boundary and its comment leaves the inline renderer path unmeasured | authors of inline actions carrying both keys
Thread-read: 6580249013
Premise: holds (PR #29369 merged, so the inline pick carries description and the "no remedy" reason no longer holds)
Serial constraints cleared: no open PR names ui/action.zod.ts
Measure first. On one dialog, the comment and a pinning test land under the lines above. On two dialogs, the dev stops and reports; the narrowing (Clause-②: no (narrowing) · Metadata-protocol: narrowed) goes to the maintainer as needs-user-decision on this card before anything is built, and the seat amends this claim.
{
"issue": 29383,
"status": "blocked",
"branch": "claude/project-thread-k5x85e",
"pr": null,
"session": "session_01ADHkmRm5hBTGQxuqruuueG",
"premise_still_valid": true,
"summary": "Step 1 measured TWO dialogs: an inline action (element:button properties.action) carrying confirmText beside a non-empty params array opens the confirm dialog first and the param dialog second, the same shape ActionSchema refuses. Per the delta this is the narrowing path, so I stopped before building anything; nothing is committed or pushed. In-repo census of inline carriers with both keys: 1, a spec test fixture that pins the current acceptance; 0 in examples, templates, skills, ui fixtures or shipped metadata.",
"renderer_path": [
"ui/packages/components/src/renderers/basic/elements.tsx:351 the element:button renderer takes execute from useAction() (the ActionProvider runner the console mounts)",
"elements.tsx:377-378 an ARRAY params is forwarded as actionParams; elements.tsx:417 confirmText is forwarded as is; elements.tsx:397 await execute({...})",
"ui/packages/react/src/context/ActionContext.tsx:126,130 ActionProvider wires onConfirm -> setConfirmHandler and onParamCollection -> setParamCollectionHandler on the shared ActionRunner",
"ui/packages/app-shell/src/hooks/useConsoleActionRuntime.tsx:255-259 confirmHandler opens ActionConfirmDialog (rendered at :976); :268 paramCollectionHandler opens the param dialog; both handed to the provider at :944/:947",
"ui/packages/core/src/actions/ActionRunner.ts:1655-1667 execute() computes confirmMessage (:2011, returns text whenever confirmText is declared, with no params check) and AWAITS confirmHandler; a cancel returns 'Action cancelled by user'",
"ActionRunner.ts:1674-1735 only after the confirm resolves true does it read actionParams and AWAIT paramCollectionHandler: dialog two",
"Contrast, bulk: ui/packages/plugin-grid/src/ObjectGrid.tsx:2087 strips confirmText before the runner and BulkActionDialog.tsx:441 renders it inside the one bulk dialog above the params, which is why BulkActionDefSchema's pair is one dialog",
"Reading is static (file:line); no runtime probe was run, since the container has no install and the two awaits are straight-line code with no branch on params in confirmMessage"
],
"census": {
"scope": "git grep at origin/main a6441636 over examples/, packages/**, ui/**, skills/, templates: every file containing both element:button and confirmText (23 files), each read by hand",
"inline_carriers_with_both_keys": [
"packages/spec/src/ui/action-confirm-params-guard.test.ts:230 InlineActionSchema.safeParse({type:'url', target:'/approvals?reject=1', label:'Reject', confirmText:'Reject this request?', params:[{name:'reason',...}]}) expects success: the pin a refusal flips (forced test edit on the narrowing path)"
],
"near_misses_not_counted": [
"packages/spec/src/ui/inline-action.test.ts:64-67 carries both keys but params: [] (empty) and parses through ActionSchema, not the inline door",
"packages/lint/src/validate-action-copy-templates.test.ts:131 confirmText + params array on an action:button row (registered-action reference), not an inline action",
"packages/spec/src/system/i18n-resolver.test.ts:510-512 a registered action fixture",
"ui element-button / localizer tests (element-button-i18nCopy-12757, useActionTextLocalizer.cancelText-28879, elementButtonActionMembers-8071): confirmText without an array params"
],
"shipped_metadata_carriers": 0
},
"proposed_refusal": "Add to InlineActionSchema's refine chain the same predicate ActionSchema uses (confirmText != null and params is a non-empty array), path ['confirmText'], in the same message family: the pair shows TWO dialogs for one decision; carry the confirm question in the inline action's description (it renders under the param dialog's title) and drop confirmText; confirmText stays correct on a param-less inline action. Claim lines would become Clause-②: no (narrowing) / Metadata-protocol: narrowed; an ADR-0087 disposition (in-repo census 0 shipped carriers, so likely a no-conversion refusal entry with the remedy in the message); flip the action-confirm-params-guard.test.ts:221-239 pin to a refusal pin and add the description-carrying accept control; move the action.zod.ts:2297-2301 comment from 'not decided here' to the ruling. Consumers to run on that path: lint validate-action-copy-templates (inline INLINE_KEYS), ui files that grep InlineActionSchema, node ui/scripts/check-action-forward-parity.mjs, plus full dogfood (narrowing arm).",
"tests": "none run: measure-only stop per the delta's two-dialog branch",
"gates": "none run: no diff (git status clean on claude/project-thread-k5x85e at a6441636)",
"dogfood_battery": "n/a: nothing built",
"mcp_calls": "1: mcp__github__issue_read (get_comments, read-only, to verify the Claim)",
"api_writes": "1: this os-dev-report comment on #29383 via post-stamped.mjs",
"files_changed": [],
"line_budget": "n/a: no diff",
"deviations": [],
"open_questions": [
{
"question": "Should InlineActionSchema refuse confirmText beside a non-empty params, as ActionSchema does? (narrowing, needs-user-decision)",
"options": [
"A refuse it on the inline door, same message family, remedy = move the sentence to description (census: 0 shipped carriers, 1 test pin flips)",
"B keep accepting it and rewrite the action.zod.ts comment to state the inline door renders TWO dialogs and accepts it deliberately",
"C fix the renderer so an inline pair renders as one dialog (ui runtime change, out of this card's surface)"
],
"recommendation": "A, because the inline renderer path is the registered action's path (same ActionRunner, same two awaits), so the defect ActionSchema refuses ships unrefused here; the remedy slot (description) now exists on the inline pick; and the census is 0, so nothing legal breaks."
}
],
"security_findings": "none",
"out_of_scope_findings": []
}
C 改渲染:让 ui 把确认文字放进参数框(像批量动作那样)。要在 ui 车道另开卡,spec 不动。
卡线程停在测量这一步,没有提交;裁决下来后,席位转给开发。
Seat recommendation: A. It matches the ActionSchema refusal, the census finds no real carrier to break, and description is now the remedy on the inline shape. On A, the dev builds on claude/project-thread-k5x85e and the seat amends the claim to the narrowing lines. On B, a comment-only change lands under the current claim. On C, the seat files a ui-lane card and closes this one with a cross-reference.
Spec seat 1 is closing for the day on the maintainer's word 「spec 车道当前任务处理完就下班」. This card is still waiting on the "Decision needed" above (6580700185), so it stays needs-user-decision, and the seat releases its hold on it.
For whichever spec seat picks it up once ruled:
The measurement is done (dev report 6580676225): an inline action with confirmText and non-empty params shows two dialogs. Nothing is committed on branch claude/project-thread-k5x85e.
On A: amend the claim to Clause-②: no (narrowing) / Metadata-protocol: narrowed, then build the refusal on InlineActionSchema. That means:
path confirmText, with the prescription "move it to description";
an ADR-0087 entry;
flip the one spec test pin, and add a description control.
On B: a describe-only note under the current claim.
On C: file a domain:ui card (render the confirm text inside the params dialog, as the bulk action does), and close this card with a cross-reference.
The seat-1 brief for this card is /mnt/project-files/spec-seat1/29383-delta.md.
Ruling: decision thread "Discuss pending spec rulings" item 3 · letter A · maintainer 「同意」 2026-11-03T04:55Z
The maintainer was presented the "Decision needed" above (6580700185) with the recommendation A in the project thread, and answered 「同意」 = the recommendation on every item presented, so this card's letter is A.
What the ruling binds (letter A):
InlineActionSchema refuses confirmText beside a non-empty params, with the same predicate and message family ActionSchema uses (the pair opens two dialogs for one decision; carry the question in description, which renders under the param dialog's title, and drop confirmText). confirmText stays correct on a param-less inline action. Issue path confirmText.
Declared as a narrowing: Clause-②: no (narrowing) · Metadata-protocol: narrowed, with an ADR-0087 disposition (in-repo census: 0 shipped carriers, one spec test pin flips and gains a description accept control). The action.zod.ts comment at the refinement moves from "not decided here" to this ruling.
Not taken: B (keep accepting and document two dialogs), C (a domain:ui renderer change; even with it the registered door would still refuse the pair, leaving the two doors inconsistent).
Workload of the letter:domain:spec · one S PR on claude/project-thread-k5x85e (dev report 6580676225 names the build: the refinement, the ADR-0087 entry, the flipped pin and control, the comment; consumers to run: lint validate-action-copy-templates, ui check-action-forward-parity.mjs, full dogfood on the narrowing arm) · one CONTRACT_REVIEW_TIER review before landing.
Execution: the domain:spec seat that picks the card up amends the claim to the narrowing lines and dispatches with Ruling-ref: naming this comment; the needs-user-decision → pm:dispatched stroke is that seat's. The Ruled: body line is written by this act.
Claim: PM loop round 6
Session: session_01WGufzfgvGexKn9vLHsy89K
Account: os-support-ai
Branch: the card thread's own claude/project-thread-* branch, named in the dev's hand-back and restated in a later claim (a measured platform exception to claude/issue-29383-…). Not claude/project-thread-k5x85e, which has nothing committed.
Worktree: objectstack-issue-29383
Domain: domain:spec
Seat: domain:spec#3
File surface: packages/spec/src/ui/action.zod.ts (InlineActionSchema refinement and the comment at ActionSchema's), packages/spec/src/ui/action-confirm-params-guard.test.ts, the ADR-0087 disposition where the narrowing precedent puts it, generated artifacts the refusal moves, .changeset/29383-*.md.
Container & model: S-M, mode:thread, model: TIER_DEFAULT, effort: high
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility: n/a — not a defect card (ruled narrowing)
Thread-read: 6595808462
Premise: holds. Ruling 6595808462 is letter A. On origin/main, InlineActionSchema picks description (#29369 merged) and action.zod.ts:2301 still says the inline pair is "not decided here". Measurement 6580676225 found two dialogs and 0 shipped carriers.
Serial constraints cleared: #29248 / PR #29369 (merged). Seat 1 released its hold on 2026-11-02T21:53Z (6589420791). The coordinator routed this card to seat 3, so seat 2 does not also claim it.
Claim: PM loop round 6
Session: session_01WGufzfgvGexKn9vLHsy89K
Account: os-support-ai
Branch: claude/project-thread-glsdvz (the card thread's own branch, off main2545021, reported by the dev; a measured platform exception to claude/issue-29383-…). This restates the seat's earlier claim (6595853086) with the branch named.
Worktree: objectstack-issue-29383
Domain: domain:spec
Seat: domain:spec#3
File surface: packages/spec/src/ui/action.zod.ts (InlineActionSchema refinement and the comment at ActionSchema's), packages/spec/src/ui/action-confirm-params-guard.test.ts, the ADR-0087 disposition where the narrowing precedent puts it, generated artifacts the refusal moves, .changeset/29383-*.md.
Container & model: S-M, mode:thread, model: TIER_DEFAULT, effort: high
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility: n/a — not a defect card (ruled narrowing)
Thread-read: 6595853086
Premise: holds. Ruling 6595808462 is letter A. On origin/main, InlineActionSchema picks description (#29369 merged) and action.zod.ts:2301 still says the inline pair is "not decided here". Measurement 6580676225 found two dialogs and 0 shipped carriers.
Serial constraints cleared: #29248 / PR #29369 (merged). Seat 1 released its hold on 2026-11-02T21:53Z (6589420791). The coordinator routed this card to seat 3, so seat 2 does not also claim it.
{
"issue": 29383,
"status": "done",
"branch": "claude/project-thread-glsdvz",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29829",
"head": "656657595b803b3c9ee684e5ece3b8a42addc4f9",
"session": "session_01WGufzfHVbsfKWji5VLrLbG",
"premise_still_valid": true,
"summary": "Letter A as ruled (6595808462): InlineActionSchema refuses confirmText beside a non-empty params at ['confirmText'] with ActionSchema's message. The predicate and the refusal are lifted to module level in action.zod.ts (declaresConfirmBesideParams, CONFIRM_BESIDE_PARAMS_REFUSAL) and both doors read them, no second copy. The refinement comment now states the ruling; the confirmText describe drops 'On a registered action,' and content/docs/references (4 files) are regenerated. Guard test: the inline acceptance pin is replaced by a refusal block (path, code, message equal to ActionSchema's, locale-map form) and three accept controls (description without confirmText, no params, params: []). Changeset @objectstack/spec minor with both declaration lines, the not-required (no-migration-prescription) ADR-0087 marker and the narrowing banner; no docs/adr path. Census re-run at b3d14150: unchanged, 0 shipped carriers, 1 spec test pin. Reach measured: lint validateComponentProps (os validate / runtime page save) reports component-props-invalid at properties.action.confirmText on the pair; defineStack does not parse properties bags, so it judges none of it, and the changeset says so.",
"tests": "head 65665759 under os-verify-lock. Targeted spec (5 files): 459 passed. pnpm --filter @objectstack/spec test && typecheck: Test Files 804 passed (804), Tests 23884 passed | 1 todo (23885), VERDICT command-exit 0. Ablation via ablation-replace.mjs (anchor 1 -> 0, blob c1a9cf11 -> 2b9084b3): inline predicate replaced by true ||, guard test 2 failed | 14 passed (16); restored, blob == HEAD, git diff HEAD empty. Lint consumers (validate-action-copy-templates, validate-component-props x3 files): Test Files 4 passed (4), Tests 207 passed (207). node ui/scripts/check-action-forward-parity.mjs: exit 0. spec test:repo not run locally (not named by the derivation, diff does not edit that project): declared to CI Test Core.",
"gates": "dispatch-gates --commands derived 102 on 65665759 (7 paths vs merge base b3d14150). Serial pass: 100 exit 0, 2 exit 3 (spec check:skill-examples, check:dual-build-cjs-loads: built-output prerequisites); teardown-shape --self-test fixture 621a4876 fetched first, exit 0. After pnpm turbo run build --concurrency=2 (118/118, VERDICT 0) both reran exit 0. --ran: 102 derived, 102 run, 0 NOT-MEASURED, exit 0. check:generated: only check:docs stale, fixed. check-changeset-no-major with the PR body as event: exit 0 (LEVEL AXIS narrowing/narrowed, no patch-graded moved package). CI check-runs: in_progress at report time.",
"dogfood_battery": "65665759 · os-verify-lock: VERDICT command-exit 0 (dogfood^... build + dogfood test, held 44m19s) · Test Files 404 passed | 3 skipped (407) · Tests 3326 passed | 28 skipped (3354) · no failures",
"mcp_calls": "0",
"api_writes": "2 — relay pr_create objectstack-ai/objectstack#29829 (13528 bytes sent = stored, no assignees, no reviewers); post-stamped comment on #29383 (this report). Plus git push.",
"deviations": [
"PR opened on head 65665759 without merging origin/main (19 commits behind at open, b0ef25f5); none touches action.zod.ts or the guard test, two regenerate other lines of content/docs/references/data/object.mdx, local merge-tree clean. Merging would unpin the dogfood reading."
],
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · content/docs/protocol/objectui/actions.mdx L444 (hand-written) says 'On a registered action, pairing it with a non-empty params is refused': still true, no longer names the inline door; outside the claim surface, noted in Acceptance notes",
"carrier: none · skills/objectstack-ui/rules/actions.md L22 'A registered action is refused it beside a non-empty params': still true; a widening is a skills/** (Tier H) edit, noted in Acceptance notes"
]
}
The third door found by contract review 6597260383 (action:button, ActionButtonPropsSchema, accepts confirmText beside an array params) is ruled A and filed as #29844 (ruling 6597621758). It ships as its own PR after #29829 lands; #29829 is not widened.
Landed · PR #29829 merged as 2c881fbd · 2026-11-03T07:31Z
Ruling A (6595808462) is in place. InlineActionSchema refuses confirmText beside a non-empty params, using the same predicate and message as ActionSchema. Contract review 6597260383 PASS (narrowing face), ACCEPT 6597480079. The third door, action:button, is ruled A and goes ahead as #29844, dispatched now. Removing pm:dispatched here.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p3 ·
domain:spec·pm:queue· 2026-11-02T14:53Z⛔ Not a claim.
confirmTextbesideparams, asActionSchemadoes? A refusal is a narrowing, so it needs the declaration and a contract review. p3. Decide after feat(spec): InlineActionSchema picksdescription, so an inline action's param dialog can say what it does #29369 lands.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Claim: PM loop round 1 · 2026-11-02T15:10Z
Session:
session_01ADHkmPi25XXKx92Xmg4viS(seat); dev = card threadsession_01ADHkmRm5hBTGQxuqruuueGAccount:
os-steveBranch:
claude/project-thread-k5x85eWorktree: the card thread's own checkout of
objectstack-ai/objectstackDomain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/ui/action.zod.ts(theconfirmText/paramsrefinement comment, or after a rulingInlineActionSchema's refinement) and its test; on the narrowing path only, an ADR-0087 entry and each in-repo inline carrier's sentence moved todescription; root.changeset/; not ui runtime code (stop on breach; explain in the report)Container & model:
S,mode:thread,model: default — the tier is the PM's per-card call (floor sonnet · default opus · ceiling fable); one CONTRACT_REVIEW_TIER review (published schema face) before landing,effort: highClause-②: no
Metadata-protocol: none
Responsibility:
packages/spec action.zod.ts InlineActionSchema | the confirmText-beside-params refusal stops at the schema boundary and its comment leaves the inline renderer path unmeasured | authors of inline actions carrying both keysThread-read: 6580249013
Premise: holds (PR #29369 merged, so the inline pick carries
descriptionand the "no remedy" reason no longer holds)Serial constraints cleared: no open PR names
ui/action.zod.tsMeasure first. On one dialog, the comment and a pinning test land under the lines above. On two dialogs, the dev stops and reports; the narrowing (
Clause-②: no (narrowing)·Metadata-protocol: narrowed) goes to the maintainer asneeds-user-decisionon this card before anything is built, and the seat amends this claim.objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmRm5hBTGQxuqruuueG
os-dev-report
{ "issue": 29383, "status": "blocked", "branch": "claude/project-thread-k5x85e", "pr": null, "session": "session_01ADHkmRm5hBTGQxuqruuueG", "premise_still_valid": true, "summary": "Step 1 measured TWO dialogs: an inline action (element:button properties.action) carrying confirmText beside a non-empty params array opens the confirm dialog first and the param dialog second, the same shape ActionSchema refuses. Per the delta this is the narrowing path, so I stopped before building anything; nothing is committed or pushed. In-repo census of inline carriers with both keys: 1, a spec test fixture that pins the current acceptance; 0 in examples, templates, skills, ui fixtures or shipped metadata.", "renderer_path": [ "ui/packages/components/src/renderers/basic/elements.tsx:351 the element:button renderer takes execute from useAction() (the ActionProvider runner the console mounts)", "elements.tsx:377-378 an ARRAY params is forwarded as actionParams; elements.tsx:417 confirmText is forwarded as is; elements.tsx:397 await execute({...})", "ui/packages/react/src/context/ActionContext.tsx:126,130 ActionProvider wires onConfirm -> setConfirmHandler and onParamCollection -> setParamCollectionHandler on the shared ActionRunner", "ui/packages/app-shell/src/hooks/useConsoleActionRuntime.tsx:255-259 confirmHandler opens ActionConfirmDialog (rendered at :976); :268 paramCollectionHandler opens the param dialog; both handed to the provider at :944/:947", "ui/packages/core/src/actions/ActionRunner.ts:1655-1667 execute() computes confirmMessage (:2011, returns text whenever confirmText is declared, with no params check) and AWAITS confirmHandler; a cancel returns 'Action cancelled by user'", "ActionRunner.ts:1674-1735 only after the confirm resolves true does it read actionParams and AWAIT paramCollectionHandler: dialog two", "Contrast, bulk: ui/packages/plugin-grid/src/ObjectGrid.tsx:2087 strips confirmText before the runner and BulkActionDialog.tsx:441 renders it inside the one bulk dialog above the params, which is why BulkActionDefSchema's pair is one dialog", "Reading is static (file:line); no runtime probe was run, since the container has no install and the two awaits are straight-line code with no branch on params in confirmMessage" ], "census": { "scope": "git grep at origin/main a6441636 over examples/, packages/**, ui/**, skills/, templates: every file containing both element:button and confirmText (23 files), each read by hand", "inline_carriers_with_both_keys": [ "packages/spec/src/ui/action-confirm-params-guard.test.ts:230 InlineActionSchema.safeParse({type:'url', target:'/approvals?reject=1', label:'Reject', confirmText:'Reject this request?', params:[{name:'reason',...}]}) expects success: the pin a refusal flips (forced test edit on the narrowing path)" ], "near_misses_not_counted": [ "packages/spec/src/ui/inline-action.test.ts:64-67 carries both keys but params: [] (empty) and parses through ActionSchema, not the inline door", "packages/lint/src/validate-action-copy-templates.test.ts:131 confirmText + params array on an action:button row (registered-action reference), not an inline action", "packages/spec/src/system/i18n-resolver.test.ts:510-512 a registered action fixture", "ui element-button / localizer tests (element-button-i18nCopy-12757, useActionTextLocalizer.cancelText-28879, elementButtonActionMembers-8071): confirmText without an array params" ], "shipped_metadata_carriers": 0 }, "proposed_refusal": "Add to InlineActionSchema's refine chain the same predicate ActionSchema uses (confirmText != null and params is a non-empty array), path ['confirmText'], in the same message family: the pair shows TWO dialogs for one decision; carry the confirm question in the inline action's description (it renders under the param dialog's title) and drop confirmText; confirmText stays correct on a param-less inline action. Claim lines would become Clause-②: no (narrowing) / Metadata-protocol: narrowed; an ADR-0087 disposition (in-repo census 0 shipped carriers, so likely a no-conversion refusal entry with the remedy in the message); flip the action-confirm-params-guard.test.ts:221-239 pin to a refusal pin and add the description-carrying accept control; move the action.zod.ts:2297-2301 comment from 'not decided here' to the ruling. Consumers to run on that path: lint validate-action-copy-templates (inline INLINE_KEYS), ui files that grep InlineActionSchema, node ui/scripts/check-action-forward-parity.mjs, plus full dogfood (narrowing arm).", "tests": "none run: measure-only stop per the delta's two-dialog branch", "gates": "none run: no diff (git status clean on claude/project-thread-k5x85e at a6441636)", "dogfood_battery": "n/a: nothing built", "mcp_calls": "1: mcp__github__issue_read (get_comments, read-only, to verify the Claim)", "api_writes": "1: this os-dev-report comment on #29383 via post-stamped.mjs", "files_changed": [], "line_budget": "n/a: no diff", "deviations": [], "open_questions": [ { "question": "Should InlineActionSchema refuse confirmText beside a non-empty params, as ActionSchema does? (narrowing, needs-user-decision)", "options": [ "A refuse it on the inline door, same message family, remedy = move the sentence to description (census: 0 shipped carriers, 1 test pin flips)", "B keep accepting it and rewrite the action.zod.ts comment to state the inline door renders TWO dialogs and accepts it deliberately", "C fix the renderer so an inline pair renders as one dialog (ui runtime change, out of this card's surface)" ], "recommendation": "A, because the inline renderer path is the registered action's path (same ActionRunner, same two awaits), so the defect ActionSchema refuses ships unrefused here; the remedy slot (description) now exists on the inline pick; and the census is 0, so nothing legal breaks." } ], "security_findings": "none", "out_of_scope_findings": [] }Stamped 2026-11-02T15:12Z.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Decision needed · refuse confirmText beside params on an inline action · 2026-11-02T15:13Z
维护者速读
confirmText和非空params时,要不要像注册动作(ActionSchema)一样拒收?description, so an inline action's param dialog can say what it does #29369 合入后,行内动作已经能写description,所以作者有地方挪这句话。InlineActionSchema上加同一条拒收规则,报错路径confirmText,提示把这句话挪到description。这是一处小的收窄(Clause-②: no (narrowing)·Metadata-protocol: narrowed),带 ADR-0087 条目,翻转那条测试 pin,并加一个description可通过的对照。行为和注册动作一致,作者不会碰到双弹框。Seat recommendation: A. It matches the
ActionSchemarefusal, the census finds no real carrier to break, anddescriptionis now the remedy on the inline shape. On A, the dev builds onclaude/project-thread-k5x85eand the seat amends the claim to the narrowing lines. On B, a comment-only change lands under the current claim. On C, the seat files a ui-lane card and closes this one with a cross-reference.objectstack-fleet commentedon Nov 2, 2026
domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS
Hand-off · spec seat 1 going offline · 2026-11-02T21:53Z
Spec seat 1 is closing for the day on the maintainer's word 「spec 车道当前任务处理完就下班」. This card is still waiting on the "Decision needed" above (6580700185), so it stays
needs-user-decision, and the seat releases its hold on it.For whichever spec seat picks it up once ruled:
confirmTextand non-emptyparamsshows two dialogs. Nothing is committed on branchclaude/project-thread-k5x85e.Clause-②: no (narrowing)/Metadata-protocol: narrowed, then build the refusal onInlineActionSchema. That means:confirmText, with the prescription "move it todescription";descriptioncontrol.domain:uicard (render the confirm text inside the params dialog, as the bulk action does), and close this card with a cross-reference./mnt/project-files/spec-seat1/29383-delta.md.os-support-ai commentedon Nov 3, 2026
decision thread · os-support-ai · session_01WGufzepGFmf3XtoZaZuheq
Ruling: decision thread "Discuss pending spec rulings" item 3 · letter A · maintainer 「同意」 2026-11-03T04:55Z
The maintainer was presented the "Decision needed" above (6580700185) with the recommendation A in the project thread, and answered 「同意」 = the recommendation on every item presented, so this card's letter is A.
What the ruling binds (letter A):
InlineActionSchemarefusesconfirmTextbeside a non-emptyparams, with the same predicate and message familyActionSchemauses (the pair opens two dialogs for one decision; carry the question indescription, which renders under the param dialog's title, and dropconfirmText).confirmTextstays correct on a param-less inline action. Issue pathconfirmText.Clause-②: no (narrowing)·Metadata-protocol: narrowed, with an ADR-0087 disposition (in-repo census: 0 shipped carriers, one spec test pin flips and gains adescriptionaccept control). Theaction.zod.tscomment at the refinement moves from "not decided here" to this ruling.domain:uirenderer change; even with it the registered door would still refuse the pair, leaving the two doors inconsistent).Workload of the letter:
domain:spec· one S PR onclaude/project-thread-k5x85e(dev report 6580676225 names the build: the refinement, the ADR-0087 entry, the flipped pin and control, the comment; consumers to run: lintvalidate-action-copy-templates, uicheck-action-forward-parity.mjs, full dogfood on the narrowing arm) · oneCONTRACT_REVIEW_TIERreview before landing.Execution: the
domain:specseat that picks the card up amends the claim to the narrowing lines and dispatches withRuling-ref:naming this comment; theneeds-user-decision→pm:dispatchedstroke is that seat's. TheRuled:body line is written by this act.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Claim: PM loop round 6
Session:
session_01WGufzfgvGexKn9vLHsy89KAccount:
os-support-aiBranch: the card thread's own
claude/project-thread-*branch, named in the dev's hand-back and restated in a later claim (a measured platform exception toclaude/issue-29383-…). Notclaude/project-thread-k5x85e, which has nothing committed.Worktree:
objectstack-issue-29383Domain:
domain:specSeat:
domain:spec#3File surface:
packages/spec/src/ui/action.zod.ts(InlineActionSchemarefinement and the comment atActionSchema's),packages/spec/src/ui/action-confirm-params-guard.test.ts, the ADR-0087 disposition where the narrowing precedent puts it, generated artifacts the refusal moves,.changeset/29383-*.md.Container & model:
S-M,mode:thread,model: TIER_DEFAULT,effort: highClause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility:
n/a — not a defect card(ruled narrowing)Thread-read: 6595808462
Premise: holds. Ruling 6595808462 is letter A. On
origin/main,InlineActionSchemapicksdescription(#29369 merged) andaction.zod.ts:2301still says the inline pair is "not decided here". Measurement 6580676225 found two dialogs and 0 shipped carriers.Serial constraints cleared: #29248 / PR #29369 (merged). Seat 1 released its hold on 2026-11-02T21:53Z (6589420791). The coordinator routed this card to seat 3, so seat 2 does not also claim it.
objectstack-fleet commentedon Nov 3, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Claim: PM loop round 6
Session:
session_01WGufzfgvGexKn9vLHsy89KAccount:
os-support-aiBranch:
claude/project-thread-glsdvz(the card thread's own branch, offmain2545021, reported by the dev; a measured platform exception toclaude/issue-29383-…). This restates the seat's earlier claim (6595853086) with the branch named.Worktree:
objectstack-issue-29383Domain:
domain:specSeat:
domain:spec#3File surface:
packages/spec/src/ui/action.zod.ts(InlineActionSchemarefinement and the comment atActionSchema's),packages/spec/src/ui/action-confirm-params-guard.test.ts, the ADR-0087 disposition where the narrowing precedent puts it, generated artifacts the refusal moves,.changeset/29383-*.md.Container & model:
S-M,mode:thread,model: TIER_DEFAULT,effort: highClause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility:
n/a — not a defect card(ruled narrowing)Thread-read: 6595853086
Premise: holds. Ruling 6595808462 is letter A. On
origin/main,InlineActionSchemapicksdescription(#29369 merged) andaction.zod.ts:2301still says the inline pair is "not decided here". Measurement 6580676225 found two dialogs and 0 shipped carriers.Serial constraints cleared: #29248 / PR #29369 (merged). Seat 1 released its hold on 2026-11-02T21:53Z (6589420791). The coordinator routed this card to seat 3, so seat 2 does not also claim it.
objectstack-fleet commentedon Nov 3, 2026
domain:spec#3 · os-support-ai · session_01WGufzfHVbsfKWji5VLrLbG
os-dev-report
{ "issue": 29383, "status": "done", "branch": "claude/project-thread-glsdvz", "pr": "https://github.com/objectstack-ai/objectstack/pull/29829", "head": "656657595b803b3c9ee684e5ece3b8a42addc4f9", "session": "session_01WGufzfHVbsfKWji5VLrLbG", "premise_still_valid": true, "summary": "Letter A as ruled (6595808462): InlineActionSchema refuses confirmText beside a non-empty params at ['confirmText'] with ActionSchema's message. The predicate and the refusal are lifted to module level in action.zod.ts (declaresConfirmBesideParams, CONFIRM_BESIDE_PARAMS_REFUSAL) and both doors read them, no second copy. The refinement comment now states the ruling; the confirmText describe drops 'On a registered action,' and content/docs/references (4 files) are regenerated. Guard test: the inline acceptance pin is replaced by a refusal block (path, code, message equal to ActionSchema's, locale-map form) and three accept controls (description without confirmText, no params, params: []). Changeset @objectstack/spec minor with both declaration lines, the not-required (no-migration-prescription) ADR-0087 marker and the narrowing banner; no docs/adr path. Census re-run at b3d14150: unchanged, 0 shipped carriers, 1 spec test pin. Reach measured: lint validateComponentProps (os validate / runtime page save) reports component-props-invalid at properties.action.confirmText on the pair; defineStack does not parse properties bags, so it judges none of it, and the changeset says so.", "tests": "head 65665759 under os-verify-lock. Targeted spec (5 files): 459 passed. pnpm --filter @objectstack/spec test && typecheck: Test Files 804 passed (804), Tests 23884 passed | 1 todo (23885), VERDICT command-exit 0. Ablation via ablation-replace.mjs (anchor 1 -> 0, blob c1a9cf11 -> 2b9084b3): inline predicate replaced by true ||, guard test 2 failed | 14 passed (16); restored, blob == HEAD, git diff HEAD empty. Lint consumers (validate-action-copy-templates, validate-component-props x3 files): Test Files 4 passed (4), Tests 207 passed (207). node ui/scripts/check-action-forward-parity.mjs: exit 0. spec test:repo not run locally (not named by the derivation, diff does not edit that project): declared to CI Test Core.", "gates": "dispatch-gates --commands derived 102 on 65665759 (7 paths vs merge base b3d14150). Serial pass: 100 exit 0, 2 exit 3 (spec check:skill-examples, check:dual-build-cjs-loads: built-output prerequisites); teardown-shape --self-test fixture 621a4876 fetched first, exit 0. After pnpm turbo run build --concurrency=2 (118/118, VERDICT 0) both reran exit 0. --ran: 102 derived, 102 run, 0 NOT-MEASURED, exit 0. check:generated: only check:docs stale, fixed. check-changeset-no-major with the PR body as event: exit 0 (LEVEL AXIS narrowing/narrowed, no patch-graded moved package). CI check-runs: in_progress at report time.", "dogfood_battery": "65665759 · os-verify-lock: VERDICT command-exit 0 (dogfood^... build + dogfood test, held 44m19s) · Test Files 404 passed | 3 skipped (407) · Tests 3326 passed | 28 skipped (3354) · no failures", "mcp_calls": "0", "api_writes": "2 — relay pr_create objectstack-ai/objectstack#29829 (13528 bytes sent = stored, no assignees, no reviewers); post-stamped comment on #29383 (this report). Plus git push.", "deviations": [ "PR opened on head 65665759 without merging origin/main (19 commits behind at open, b0ef25f5); none touches action.zod.ts or the guard test, two regenerate other lines of content/docs/references/data/object.mdx, local merge-tree clean. Merging would unpin the dogfood reading." ], "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · content/docs/protocol/objectui/actions.mdx L444 (hand-written) says 'On a registered action, pairing it with a non-empty params is refused': still true, no longer names the inline door; outside the claim surface, noted in Acceptance notes", "carrier: none · skills/objectstack-ui/rules/actions.md L22 'A registered action is refused it beside a non-empty params': still true; a widening is a skills/** (Tier H) edit, noted in Acceptance notes" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
ACCEPT → PR #29829 comment 6597480079 (head
65665759, contract review 6597260383 PASS, narrowing face). Ready + auto-merge next.objectstack-fleet commentedon Nov 3, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
The third door found by contract review 6597260383 (
action:button,ActionButtonPropsSchema, acceptsconfirmTextbeside an arrayparams) is ruled A and filed as #29844 (ruling 6597621758). It ships as its own PR after #29829 lands; #29829 is not widened.objectstack-fleet commentedon Nov 3, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Landed · PR #29829 merged as
2c881fbd· 2026-11-03T07:31ZRuling A (6595808462) is in place.
InlineActionSchemarefusesconfirmTextbeside a non-emptyparams, using the same predicate and message asActionSchema. Contract review 6597260383 PASS (narrowing face), ACCEPT 6597480079. The third door,action:button, is ruled A and goes ahead as #29844, dispatched now. Removingpm:dispatchedhere.