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
Record pane: Esc that a field already handled still steps the pane back a level (or restores it from maximized) #28156
Filing gate: ② a wrong state shown to the user. This is an out-of-scope finding from PR #28116 (#27524 ②), raised by its card thread and confirmed by that PR's at-tier delta review (③). It is not fixed there, because navigation-overlay.tsx is #27545's surface.
Business reason
Who: a reader working inside a record opened in the drawer or pane.
What happens: at any level below the pane's root (a related record opened in place), they press Esc inside a field to close a mention list, cancel a cell edit, or leave the 动态 composer. The field handles the key, but the pane also steps back a level. Once #27545 B wires ⤢, the same happens while the pane is maximized: the pane restores. The reader loses their place for a key they meant only for the field.
Reach: every console reader who opens a related record in place today. The maximized case arrives once #28129 is on main.
Mechanism
ui/packages/components/src/custom/navigation-overlay.tsx (main @ 27e0bd58, line 551) passes onEscapeKeyDown={onBack ? (e) => { e.preventDefault(); onBack(); } : undefined}. #27953 and #28129 add the maximized || arm. Radix's dismissable layer calls onEscapeKeyDown for every Esc it sees, before the defaultPrevented check that gates only its own default dismiss. So a key a field has already marked handled (event.defaultPrevented) still runs onBack / handleEscape. PR #28116's EnlargedFace marks a field's Esc handled for exactly this reason. Its pins cover the root drawer and the root split pane only.
Wanted
The pane's Escape handler returns early when event.defaultPrevented is set: if (e.defaultPrevented) return; before preventDefault() and the step back / restore.
Acceptance
At a level below the root, Esc in a field inside the record (the composer, a cell editor, a mention list) keeps the level open. A bare Esc still steps back one level (CONTROL).
Maximized, Esc in such a field keeps the pane maximized. A bare Esc still restores (CONTROL).
Pinned against the real NavigationOverlay, with an ablation of the guard turning the field case red.
Claim: PM loop round 1 · 2026-10-31T02:53Z
Session: session_01L9qibxgfM8p8t3fo6y9eFK (seat; card thread session_01L9qibwcrcmDwuHqtrvwstB)
Account: os-tesla
Branch: claude/project-thread-zmuy4v (card thread; the platform assigns the thread's branch)
Worktree: objectstack-28156
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/components/src/custom/navigation-overlay.tsx, its tests, root changeset (stop on breach; explain in the report)
Container & model: S (not mechanical), mode:thread, model: TIER_DEFAULT (default judgment tier), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: navigation-overlay.tsx (the pane's Escape handler, #27545's surface) | none — Radix gates only its own dismiss on defaultPrevented | every console reader who opens a related record in place
Thread-read: none
Premise: holds
Serial constraints cleared: PR #28116 (#27524 ②) does not touch navigation-overlay.tsx (its file list read); no other live claim names it
{
"issue": 28156,
"status": "done",
"branch": "claude/project-thread-zmuy4v",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28294",
"session": "session_01L9qibwcrcmDwuHqtrvwstB",
"premise_still_valid": true,
"summary": "The record drawer's onEscapeKeyDown (below the root, or maximized) now returns on defaultPrevented, holds the sheet open, and leaves the key to its target when escapeOwnedByTarget says a text field, editable region, or open menu/listbox/dialog owns it; escapeOwnedByTarget gains a pane argument so the sheet's own role=dialog never counts. Declared deviation from the card's one-line Wanted (seat ruling B, see below): Radix dismissable-layer 1.1.19 listens on document capture, so the guard alone fixed only window-capture markers (#28116's face), not React onKeyDown fields. Root drawer unchanged.",
"tests": "head e2e6e5e9. New navigation-overlay-field-escape-28156.test.tsx: Tests 19 passed (19). pnpm --dir ui exec vitest run packages/components/ (lock): Test Files 1 failed | 461 passed | 1 skipped (463); the red share-filter-sort-spec-parity.test.ts needs spec .d.ts, green after env -u OS_SKIP_DTS turbo build of @object-ui/components^... (Test Files 2 passed (2)). Ablations via scripts/ablation-replace.mjs, restore blob == HEAD each, source-resolved (no dist leg): A0 main's handler -> 8 failed | 11 passed; A1 defaultPrevented return removed -> 2 failed; A2 ownership test removed -> 4 failed; A3 owner !== pane removed -> 1 failed.",
"gates": "dispatch-gates --commands on e2e6e5e9: 34 derived, all :: exit 0 (node scripts/check-sdui-manifest.mjs among them); --ran reconcile 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Extra: pnpm --filter @object-ui/components run type-check :: exit 0; eslint on 2 changed files :: exit 0; pnpm --dir ui run check:new-line-citations :: exit 0. CI check-runs: in_progress at report time.",
"line_budget": "3 files, +245 / -6 = 251 changed lines (under 3000)",
"files_changed": [
"ui/packages/components/src/custom/navigation-overlay.tsx",
"ui/packages/components/src/__tests__/navigation-overlay-field-escape-28156.test.tsx",
".changeset/28156-record-pane-field-escape.md"
],
"deviations": [
"Wanted was the one-line defaultPrevented guard; shipped guard + escapeOwnedByTarget(target, sheet) on the drawer handler, per seat ruling B after the capture-order measure. Cost: Esc with focus in a text field never steps back (same as the split pane).",
"Components suite first run red in one file from local OS_SKIP_DTS build state; re-measured after a full .d.ts build."
],
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "4 — reads only: issue_read get, issue_read get_comments x2, pull_request_read get; 0 writes",
"api_writes": "1 relay write: pr_create objectstack-ai/objectstack#28294 (fleet-write run 41165491986); plus this report comment via post-stamped",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed: the root drawer (no onBack, not maximized) still dismisses on an Esc in a field unless the key was marked ahead of the layer; the card scopes only below-root and maximized"
]
}
Reported 2026-10-31T03:43Z on head e2e6e5e9, PR #28294. Seat ruling B (the guard plus the split pane's ownership test) was given in the dispatch thread at 2026-10-31T02:56Z.
Activity
objectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibxgfM8p8t3fo6y9eFK
Claim: PM loop round 1 · 2026-10-31T02:53Z
Session:
session_01L9qibxgfM8p8t3fo6y9eFK(seat; card threadsession_01L9qibwcrcmDwuHqtrvwstB)Account:
os-teslaBranch:
claude/project-thread-zmuy4v(card thread; the platform assigns the thread's branch)Worktree:
objectstack-28156Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/components/src/custom/navigation-overlay.tsx, its tests, root changeset (stop on breach; explain in the report)Container & model:
S(not mechanical),mode:thread,model: TIER_DEFAULT (default judgment tier),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
navigation-overlay.tsx(the pane's Escape handler, #27545's surface) | none — Radix gates only its own dismiss ondefaultPrevented| every console reader who opens a related record in placeThread-read: none
Premise: holds
Serial constraints cleared: PR #28116 (#27524 ②) does not touch
navigation-overlay.tsx(its file list read); no other live claim names itobjectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibwcrcmDwuHqtrvwstB
os-dev-report
{ "issue": 28156, "status": "done", "branch": "claude/project-thread-zmuy4v", "pr": "https://github.com/objectstack-ai/objectstack/pull/28294", "session": "session_01L9qibwcrcmDwuHqtrvwstB", "premise_still_valid": true, "summary": "The record drawer's onEscapeKeyDown (below the root, or maximized) now returns on defaultPrevented, holds the sheet open, and leaves the key to its target when escapeOwnedByTarget says a text field, editable region, or open menu/listbox/dialog owns it; escapeOwnedByTarget gains a pane argument so the sheet's own role=dialog never counts. Declared deviation from the card's one-line Wanted (seat ruling B, see below): Radix dismissable-layer 1.1.19 listens on document capture, so the guard alone fixed only window-capture markers (#28116's face), not React onKeyDown fields. Root drawer unchanged.", "tests": "head e2e6e5e9. New navigation-overlay-field-escape-28156.test.tsx: Tests 19 passed (19). pnpm --dir ui exec vitest run packages/components/ (lock): Test Files 1 failed | 461 passed | 1 skipped (463); the red share-filter-sort-spec-parity.test.ts needs spec .d.ts, green after env -u OS_SKIP_DTS turbo build of @object-ui/components^... (Test Files 2 passed (2)). Ablations via scripts/ablation-replace.mjs, restore blob == HEAD each, source-resolved (no dist leg): A0 main's handler -> 8 failed | 11 passed; A1 defaultPrevented return removed -> 2 failed; A2 ownership test removed -> 4 failed; A3 owner !== pane removed -> 1 failed.", "gates": "dispatch-gates --commands on e2e6e5e9: 34 derived, all :: exit 0 (node scripts/check-sdui-manifest.mjs among them); --ran reconcile 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Extra: pnpm --filter @object-ui/components run type-check :: exit 0; eslint on 2 changed files :: exit 0; pnpm --dir ui run check:new-line-citations :: exit 0. CI check-runs: in_progress at report time.", "line_budget": "3 files, +245 / -6 = 251 changed lines (under 3000)", "files_changed": [ "ui/packages/components/src/custom/navigation-overlay.tsx", "ui/packages/components/src/__tests__/navigation-overlay-field-escape-28156.test.tsx", ".changeset/28156-record-pane-field-escape.md" ], "deviations": [ "Wanted was the one-line defaultPrevented guard; shipped guard + escapeOwnedByTarget(target, sheet) on the drawer handler, per seat ruling B after the capture-order measure. Cost: Esc with focus in a text field never steps back (same as the split pane).", "Components suite first run red in one file from local OS_SKIP_DTS build state; re-measured after a full .d.ts build." ], "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "4 — reads only: issue_read get, issue_read get_comments x2, pull_request_read get; 0 writes", "api_writes": "1 relay write: pr_create objectstack-ai/objectstack#28294 (fleet-write run 41165491986); plus this report comment via post-stamped", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: the root drawer (no onBack, not maximized) still dismisses on an Esc in a field unless the key was marked ahead of the layer; the card scopes only below-root and maximized" ] }Reported 2026-10-31T03:43Z on head
e2e6e5e9, PR #28294. Seat ruling B (the guard plus the split pane's ownership test) was given in the dispatch thread at 2026-10-31T02:56Z.