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
console: an action dialog opened from a record gets no row and always says Confirm, a lookup pick cannot fill another field, highlights colour booleans by value, and the import matcher never tries an object's unique fields #27434
Measured by HotCRM on platform 18.2.0 while implementing hotcrm#2369, its forms and record pages card. The implementer's report is hotcrm#2369 comment 6489824787, and the HotCRM side is hotcrm#2380. HotCRM shipped what it could inside 18.2.0; each row is the half it could not.
#
Observed on 18.2.0
Evidence
Suggestion
1
An action's param dialog opened from the record header or a list row's ⋮ menu gets no row. A {{ record.x }} hole in the action description or a param helpText prints raw, and a defaultFromRow param stays empty.
HotCRM send_email (contact) and log_call / log_meeting (contact, case, opportunity).
Pass the row to the dialog, so description, helpText and defaultFromRow can read it.
2
The dialog's submit button always reads "Confirm" (actionDialog.confirm). No metadata key gives the action's own verb ("Send", "Log Call").
Same actions.
An action key for the dialog's submit label, falling back to "Confirm".
3
In a form, picking a lookup cannot fill another field: a quote line's Sales Price arrives only after save, from the server hook.
HotCRM quote line item, product → unit_price.
A declared lookup-pick autofill (field ← lookup.field) on the form.
4
record:highlights draws a boolean false as a red "× No" and true as a green "✓ Yes", whatever the field means, so "SLA Violated: No" wears red. record:details draws a neutral circle for the same value.
HotCRM case is_sla_violated. hotcrm#2380 moved it out of the strip into an alert.
Neutral by default in highlights, as in details, or a field-level key saying which value is the bad one.
5
A record_header action button cannot show per-reader state, such as "you voted Helpful" on a knowledge article.
A per-reader active (or pressed) predicate on a header action.
6
The import lookup matcher (resolveRef in @objectstack/core) tries the id, the lookup's displayField, the target's nameField, then name/title/label/full_name/email/username. It never tries the target's unique fields, so "ACC-000012" names nothing, and any change to a record title breaks every old export file.
Also try the target's unique fields (an autonumber included) before reporting reference_not_found.
7
outcomeMessages interpolate ${result.x}, while successMessage takes {{ result.x }}. A {{ }} hole in outcomeMessages prints raw, and no lint rule says so.
HotCRM knowledge article feedback actions.
One hole syntax for both, or a lint rule on the other one.
Acceptance
Each row is either taken, as a card of its own where it needs one, or answered "will not do" with the reason.
Filed by the repo:hotcrm lane seat (session session_01J8VVAnPkgK6CWrJa6t7Fk5) from hotcrm#2369's report. Dedupe: searched objectstack issues for action dialog record context / defaultFromRow, dialog confirm label, lookup pick autofill, highlights boolean colour, import resolve by unique field. Related: #24981, #26951, #5150 (all closed, different gaps). No open card.
Claim: PM loop round 1
Session: session_01Utp6CaJoinvGQSbHeDaWBe
Account: os-bill
Branch: claude/project-thread-0uo37t (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27434
Domain: domain:ui
Seat: domain:ui#3
File surface: action param dialog row plumbing and the record:highlights boolean cell (ui/packages/**, outside seat 4's PR regions), tests beside, root changeset, i18n only if a sentence changes (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on 178b5238: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: ui code produces the defect | no platform path covers it | every Studio / console author reaches it today
Thread-read: none
Premise: holds
Serial constraints cleared: seat 4 PR #27793 owns RecordDetailView.tsx apiHandler + useConsoleActionRuntime.tsx: stop and ask before touching
Scope of this claim: triage of rows 1–7 by the seat's order. Rows 1 and 4 (ui-only) are expected to be taken in one PR (Part of #27434); rows that need a new metadata key, spec, core or lint change are filed as their own cards by the seat. Coordinated with domain:ui seat 4 2026-10-30T04:03Z: its PR regions (#27793, #27907, #27893, #27912) are off limits.
Dispatched 2026-10-30T04:03Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Row reaches the dialog from the header and a list row (params._rowRecord); defaultFromRow seeded; dollar-brace record holes filled in description/helpText since objectui#12967; double-brace holes print raw
2
CARD (spec + ui)
no submit-verb key; footer reads actionDialog.confirm
3
CARD (spec + form)
no form lookup autofill; only the line-item grid column autofill
{
"issue": 27434,
"status": "done",
"branch": "claude/project-thread-0uo37t",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27935",
"head": "189ad8a20869465b93de59df67ca5d9cc84e8667",
"session": "session_01Utp6CXKnRMVhmD51khWToM (card thread; seat session_01Utp6CaJoinvGQSbHeDaWBe)",
"premise_still_valid": true,
"summary": "Triage of rows 1-7 on main e41642dd. Row 4 TAKEN: HeaderHighlight draws a boolean as one neutral chip (bg-muted / text-foreground / ring-border, the locale word from useBooleanValueLabel, no glyph) for both values, as the details body draws a plain word; Check and X imports dropped. Row 1 ALREADY DONE (premise of the row disproved): the row reaches the param dialog from the record header (page:header dispatchHeaderAction stashes params._rowRecord) and a list row menu (objectGridActionsColumn), both handlers seed defaultFromRow from it (field ?? name), and the runner interpolate fills dollar-brace record holes in description and helpText on both doors since objectui#12967 (18.0.0); what prints raw is a double-brace record hole, the hole-syntax split of row 7, so that residual joins the row 7 card. Rows 2, 3, 5, 6, 7 are CARD rows listed under out_of_scope_findings for the seat to file. PR is Part of #27434: the card closes when the seat has filed them.",
"tests": "New ui/packages/plugin-detail/src/__tests__/HeaderHighlight.booleanNeutral-27434.test.tsx 3/3 (no state colour class and no svg in either chip; true and false chips share one className and differ only by word Yes/No; CONTROL non-boolean value drawn). Ablation on committed 189ad8a2, restored from HEAD each time, git hash-object equal to HEAD blob after both: (1) file restored to origin/main -> 2 of 3 red; (2) scripts/ablation-replace.mjs anchor rounded-full bg-muted px-2 -> rounded-full bg-amber-500/10 px-2 (anchor 1 -> 0, blob d507687e -> 41dcb49d) -> case 1 red. Imports resolve from src (relative ../HeaderHighlight), no dist leg. Targeted plugin-detail run of 22 files (HeaderHighlight*, RecordHighlights*, recordPage*, summaryChip*, recordHighlightsInputs*) under the lock: 21 passed, 1 skipped, 177 tests passed, VERDICT command-exit 0. @object-ui/plugin-detail type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0. Row 1 measurement: a scratch ActionRunner test (deleted, never committed) dispatching description Email DOUBLE-BRACE record.display_name / DOLLAR-BRACE record.display_name read back Email DOUBLE-BRACE record.display_name / Acme from the header door and from the row door, and the row door handler received action.params._rowRecord.",
"gates": "At 189ad8a2: dispatch-gates --commands --repo objectstack-ai/objectstack derived 34; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm check:type-check-debt :: exit 0; Outside the derivation: @object-ui/plugin-detail type-check :: exit 0; pnpm --dir ui check:new-line-citations :: exit 0 (0 new). CI check-runs on 189ad8a2 at report time: TypeScript Type Check, Type Check workspace/source gates/debt ledger/consumer gates, Test Core, Live E2E UI, every Lint job, PR-body guards success; Type Check UI and Test UI shards 3,4,8,14,15,16 in_progress; the rest success.",
"dogfood_battery": "n/a - no ! in the PR title and no narrowing arm (Clause-2: no)",
"line_budget": "116 changed lines (+104 / -12) vs origin/main: HeaderHighlight.tsx +11/-12, new test +83, changeset +10",
"files_changed": [
".changeset/27434-highlights-boolean-neutral.md",
"ui/packages/plugin-detail/src/HeaderHighlight.tsx",
"ui/packages/plugin-detail/src/__tests__/HeaderHighlight.booleanNeutral-27434.test.tsx"
],
"deviations": [
"PR is Part of #27434 rather than Fixes: rows 2, 3, 5, 6, 7 still need their cards filed by the seat (dispatch Ruling allows Part of).",
"Row 1 not taken: its premise (dialog built without the row) is disproved on main; nothing in RecordDetailView.tsx or useConsoleActionRuntime.tsx was touched.",
"Commit trailers use the model-free pair, not the harness-suggested model-named co-author.",
"The harness post-PR assignee/reviewer step was skipped per the dispatch and the maintainer routing rule.",
"No docs page edited (ui/AGENTS.md #2): no authorable key changed; the chip is renderer styling."
],
"mcp_calls": "0 GitHub MCP calls.",
"api_writes": "2 - relay pr_create (draft, no assignee, no reviewer, run 41003332594, body read back identical 5603 bytes) and this report via post-stamped (POST issues/27434/comments). Plus git push of the branch (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"Row 2 CARD · carrier: #27434 row 2 (seat files) · title: Action param dialog: an action key for the submit button verb, falling back to Confirm · body: The param dialog footer always reads actionDialog.confirm. An action that collects params cannot say its own verb (Send, Log Call), so every param dialog ends in the same generic button. Add an optional I18nLabel key on ActionSchema for the dialog submit label (translation path _actions.NAME.KEY, resolved like description), read by both param-collection handlers and drawn by ActionParamDialog, with Confirm as the fallback. Measured on main e41642dd: no such key in packages/spec/src/ui/action.zod.ts; ActionParamDialog footer reads t(actionDialog.confirm). · landing: packages/spec/src/ui/action.zod.ts + lint validate-translation-references + ui/packages/app-shell ActionParamDialog and its two handlers · lane: domain:spec first, then domain:ui · dedupe: param dialog submit label; actionDialog.confirm; action verb button; confirm button label",
"Row 3 CARD · carrier: #27434 row 3 (seat files) · title: A form cannot fill a field from a picked lookup record (declared lookup-pick autofill) · body: Picking a lookup in a record form fills nothing else: a quote line Sales Price arrives only after save, from a server hook. The only autofill today is the line-item grid column key autofill (packages/spec/src/data/field.zod.ts, on by default, copies same-named fields, grid only). Declare a lookup-pick autofill on the form or field (target field from lookup.field), honoured by the form lookup widget. · landing: packages/spec (field or form schema) + ui fields LookupField / form renderer · lane: domain:spec, then domain:ui · dedupe: lookup autofill form; copy fields from lookup; lookup pick fill; unit_price from product",
"Row 5 CARD · carrier: #27434 row 5 (seat files) · title: A record_header action cannot show per-reader state (active / pressed predicate) · body: A header action button cannot tell the reader they already acted (voted Helpful on a knowledge article). Add an optional per-reader predicate on ActionSchema (active or pressed, CEL over record and user) that the header button draws as aria-pressed and a pressed face. Measured: no such key in action.zod.ts. · landing: packages/spec/src/ui/action.zod.ts + ui components page:header buttons and DeclaredActionsBar · lane: domain:spec, then domain:ui · dedupe: action pressed state; toggle action active; per-user action state; aria-pressed header action",
"Row 6 CARD · carrier: #27434 row 6 (seat files) · title: Import lookup matcher never tries the target unique fields (autonumber) · body: resolveRef in packages/core/src/utils/import-runner.ts tries id, the lookup displayField, the target title field, then name/title/label/full_name/email/username, and stops. A cell holding the target autonumber or another unique field (ACC-000012) names nothing and reports reference_not_found, and any title change breaks every old export file. Also try the target fields declared unique (autonumber included) before reporting reference_not_found, keeping the ambiguity rule. Measured on main e41642dd: candidate list unchanged. Related: #24981 (closed, added the title field). · landing: packages/core/src/utils/import-runner.ts resolveRef + its tests · lane: domain:server · dedupe: import resolve by unique field; resolveRef autonumber; reference_not_found unique; import lookup matcher",
"Row 7 CARD (with row 1 residual) · carrier: #27434 rows 7 and 1 (seat files) · title: Action copy takes two hole syntaxes: description, param helpText and outcomeMessages read dollar-brace, confirmText and successMessage read double-brace · body: confirmText and successMessage are ADR-0032 template slots (double-brace holes, publish gate refuses dollar-brace). outcomeMessages is filled by substituteScopeTokens (dollar-brace result holes, composeSuccessMessage), and the param dialog description and each param helpText are filled through the runner evaluator (dollar-brace, templateEvaluatorFor). The spec tells an author whose action has params to move the confirm question from confirmText onto description, where the same double-brace record hole now prints raw (measured through the runner from both doors). Make all five one template slot (spec describe + publish refusal + ui runner fill + a migration for existing dollar-brace copy), or at minimum a lint rule naming the wrong hole on each key. · landing: packages/spec/src/ui/action-copy-template.ts + action.zod.ts, ui/packages/core ActionRunner (composeSuccessMessage, templateEvaluatorFor) · lane: domain:spec, then domain:ui · dedupe: outcomeMessages hole syntax; description helpText template holes; double brace vs dollar brace action copy; successMessage outcomeMessages interpolation",
"Row 4 spec half · carrier: #27434 row 4 (seat decides whether to file) · a field-level key naming which boolean value is the bad one, if wanted beyond the neutral default; not built (dispatch: do not invent a per-field colour rule) · dedupe: boolean polarity field; highlights boolean colour key"
]
}
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Claim: PM loop round 1
Session:
session_01Utp6CaJoinvGQSbHeDaWBeAccount:
os-billBranch:
claude/project-thread-0uo37t(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27434Domain:
domain:uiSeat:
domain:ui#3File surface: action param dialog row plumbing and the record:highlights boolean cell (ui/packages/**, outside seat 4's PR regions), tests beside, root changeset, i18n only if a sentence changes (stop on breach; explain in the report)
Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieron178b5238: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: ui code produces the defect | no platform path covers it | every Studio / console author reaches it today
Thread-read: none
Premise: holds
Serial constraints cleared: seat 4 PR #27793 owns RecordDetailView.tsx apiHandler + useConsoleActionRuntime.tsx: stop and ask before touching
Scope of this claim: triage of rows 1–7 by the seat's order. Rows 1 and 4 (ui-only) are expected to be taken in one PR (
Part of #27434); rows that need a new metadata key, spec, core or lint change are filed as their own cards by the seat. Coordinated withdomain:uiseat 4 2026-10-30T04:03Z: its PR regions (#27793, #27907, #27893, #27912) are off limits.Dispatched 2026-10-30T04:03Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
os-dev-report
Reported 2026-10-30T04:43Z by card thread session_01Utp6CXKnRMVhmD51khWToM.
{ "issue": 27434, "status": "done", "branch": "claude/project-thread-0uo37t", "pr": "https://github.com/objectstack-ai/objectstack/pull/27935", "head": "189ad8a20869465b93de59df67ca5d9cc84e8667", "session": "session_01Utp6CXKnRMVhmD51khWToM (card thread; seat session_01Utp6CaJoinvGQSbHeDaWBe)", "premise_still_valid": true, "summary": "Triage of rows 1-7 on main e41642dd. Row 4 TAKEN: HeaderHighlight draws a boolean as one neutral chip (bg-muted / text-foreground / ring-border, the locale word from useBooleanValueLabel, no glyph) for both values, as the details body draws a plain word; Check and X imports dropped. Row 1 ALREADY DONE (premise of the row disproved): the row reaches the param dialog from the record header (page:header dispatchHeaderAction stashes params._rowRecord) and a list row menu (objectGridActionsColumn), both handlers seed defaultFromRow from it (field ?? name), and the runner interpolate fills dollar-brace record holes in description and helpText on both doors since objectui#12967 (18.0.0); what prints raw is a double-brace record hole, the hole-syntax split of row 7, so that residual joins the row 7 card. Rows 2, 3, 5, 6, 7 are CARD rows listed under out_of_scope_findings for the seat to file. PR is Part of #27434: the card closes when the seat has filed them.", "tests": "New ui/packages/plugin-detail/src/__tests__/HeaderHighlight.booleanNeutral-27434.test.tsx 3/3 (no state colour class and no svg in either chip; true and false chips share one className and differ only by word Yes/No; CONTROL non-boolean value drawn). Ablation on committed 189ad8a2, restored from HEAD each time, git hash-object equal to HEAD blob after both: (1) file restored to origin/main -> 2 of 3 red; (2) scripts/ablation-replace.mjs anchor rounded-full bg-muted px-2 -> rounded-full bg-amber-500/10 px-2 (anchor 1 -> 0, blob d507687e -> 41dcb49d) -> case 1 red. Imports resolve from src (relative ../HeaderHighlight), no dist leg. Targeted plugin-detail run of 22 files (HeaderHighlight*, RecordHighlights*, recordPage*, summaryChip*, recordHighlightsInputs*) under the lock: 21 passed, 1 skipped, 177 tests passed, VERDICT command-exit 0. @object-ui/plugin-detail type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0. Row 1 measurement: a scratch ActionRunner test (deleted, never committed) dispatching description Email DOUBLE-BRACE record.display_name / DOLLAR-BRACE record.display_name read back Email DOUBLE-BRACE record.display_name / Acme from the header door and from the row door, and the row door handler received action.params._rowRecord.", "gates": "At 189ad8a2: dispatch-gates --commands --repo objectstack-ai/objectstack derived 34; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm check:type-check-debt :: exit 0; Outside the derivation: @object-ui/plugin-detail type-check :: exit 0; pnpm --dir ui check:new-line-citations :: exit 0 (0 new). CI check-runs on 189ad8a2 at report time: TypeScript Type Check, Type Check workspace/source gates/debt ledger/consumer gates, Test Core, Live E2E UI, every Lint job, PR-body guards success; Type Check UI and Test UI shards 3,4,8,14,15,16 in_progress; the rest success.", "dogfood_battery": "n/a - no ! in the PR title and no narrowing arm (Clause-2: no)", "line_budget": "116 changed lines (+104 / -12) vs origin/main: HeaderHighlight.tsx +11/-12, new test +83, changeset +10", "files_changed": [ ".changeset/27434-highlights-boolean-neutral.md", "ui/packages/plugin-detail/src/HeaderHighlight.tsx", "ui/packages/plugin-detail/src/__tests__/HeaderHighlight.booleanNeutral-27434.test.tsx" ], "deviations": [ "PR is Part of #27434 rather than Fixes: rows 2, 3, 5, 6, 7 still need their cards filed by the seat (dispatch Ruling allows Part of).", "Row 1 not taken: its premise (dialog built without the row) is disproved on main; nothing in RecordDetailView.tsx or useConsoleActionRuntime.tsx was touched.", "Commit trailers use the model-free pair, not the harness-suggested model-named co-author.", "The harness post-PR assignee/reviewer step was skipped per the dispatch and the maintainer routing rule.", "No docs page edited (ui/AGENTS.md #2): no authorable key changed; the chip is renderer styling." ], "mcp_calls": "0 GitHub MCP calls.", "api_writes": "2 - relay pr_create (draft, no assignee, no reviewer, run 41003332594, body read back identical 5603 bytes) and this report via post-stamped (POST issues/27434/comments). Plus git push of the branch (not REST).", "open_questions": [], "out_of_scope_findings": [ "Row 2 CARD · carrier: #27434 row 2 (seat files) · title: Action param dialog: an action key for the submit button verb, falling back to Confirm · body: The param dialog footer always reads actionDialog.confirm. An action that collects params cannot say its own verb (Send, Log Call), so every param dialog ends in the same generic button. Add an optional I18nLabel key on ActionSchema for the dialog submit label (translation path _actions.NAME.KEY, resolved like description), read by both param-collection handlers and drawn by ActionParamDialog, with Confirm as the fallback. Measured on main e41642dd: no such key in packages/spec/src/ui/action.zod.ts; ActionParamDialog footer reads t(actionDialog.confirm). · landing: packages/spec/src/ui/action.zod.ts + lint validate-translation-references + ui/packages/app-shell ActionParamDialog and its two handlers · lane: domain:spec first, then domain:ui · dedupe: param dialog submit label; actionDialog.confirm; action verb button; confirm button label", "Row 3 CARD · carrier: #27434 row 3 (seat files) · title: A form cannot fill a field from a picked lookup record (declared lookup-pick autofill) · body: Picking a lookup in a record form fills nothing else: a quote line Sales Price arrives only after save, from a server hook. The only autofill today is the line-item grid column key autofill (packages/spec/src/data/field.zod.ts, on by default, copies same-named fields, grid only). Declare a lookup-pick autofill on the form or field (target field from lookup.field), honoured by the form lookup widget. · landing: packages/spec (field or form schema) + ui fields LookupField / form renderer · lane: domain:spec, then domain:ui · dedupe: lookup autofill form; copy fields from lookup; lookup pick fill; unit_price from product", "Row 5 CARD · carrier: #27434 row 5 (seat files) · title: A record_header action cannot show per-reader state (active / pressed predicate) · body: A header action button cannot tell the reader they already acted (voted Helpful on a knowledge article). Add an optional per-reader predicate on ActionSchema (active or pressed, CEL over record and user) that the header button draws as aria-pressed and a pressed face. Measured: no such key in action.zod.ts. · landing: packages/spec/src/ui/action.zod.ts + ui components page:header buttons and DeclaredActionsBar · lane: domain:spec, then domain:ui · dedupe: action pressed state; toggle action active; per-user action state; aria-pressed header action", "Row 6 CARD · carrier: #27434 row 6 (seat files) · title: Import lookup matcher never tries the target unique fields (autonumber) · body: resolveRef in packages/core/src/utils/import-runner.ts tries id, the lookup displayField, the target title field, then name/title/label/full_name/email/username, and stops. A cell holding the target autonumber or another unique field (ACC-000012) names nothing and reports reference_not_found, and any title change breaks every old export file. Also try the target fields declared unique (autonumber included) before reporting reference_not_found, keeping the ambiguity rule. Measured on main e41642dd: candidate list unchanged. Related: #24981 (closed, added the title field). · landing: packages/core/src/utils/import-runner.ts resolveRef + its tests · lane: domain:server · dedupe: import resolve by unique field; resolveRef autonumber; reference_not_found unique; import lookup matcher", "Row 7 CARD (with row 1 residual) · carrier: #27434 rows 7 and 1 (seat files) · title: Action copy takes two hole syntaxes: description, param helpText and outcomeMessages read dollar-brace, confirmText and successMessage read double-brace · body: confirmText and successMessage are ADR-0032 template slots (double-brace holes, publish gate refuses dollar-brace). outcomeMessages is filled by substituteScopeTokens (dollar-brace result holes, composeSuccessMessage), and the param dialog description and each param helpText are filled through the runner evaluator (dollar-brace, templateEvaluatorFor). The spec tells an author whose action has params to move the confirm question from confirmText onto description, where the same double-brace record hole now prints raw (measured through the runner from both doors). Make all five one template slot (spec describe + publish refusal + ui runner fill + a migration for existing dollar-brace copy), or at minimum a lint rule naming the wrong hole on each key. · landing: packages/spec/src/ui/action-copy-template.ts + action.zod.ts, ui/packages/core ActionRunner (composeSuccessMessage, templateEvaluatorFor) · lane: domain:spec, then domain:ui · dedupe: outcomeMessages hole syntax; description helpText template holes; double brace vs dollar brace action copy; successMessage outcomeMessages interpolation", "Row 4 spec half · carrier: #27434 row 4 (seat decides whether to file) · a field-level key naming which boolean value is the bad one, if wanted beyond the neutral default; not built (dispatch: do not invent a per-field colour rule) · dedupe: boolean polarity field; highlights boolean colour key" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Triage done: row 4 → PR #27935 (ACCEPT comment 6515246049); row 1 premise disproved, residual in #27948; cards #27944 (row 2), #27945 (row 3), #27946 (row 5), #27947 (row 6), #27948 (rows 7 + 1). The PR closes this card on merge. · 2026-10-30T04:50Z
Generated by Claude Code