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 bell and approvals badge keep polling every 60 s for the first 10 minutes of a hidden tab #28084
Filing gate: ③ ruling-directed. Ruling B on #26676 (6520722066) fixes a new card under #26676 as the remedy for a finding after a landing. Found by the post-merge proxy preview review of PR #27907 (#27626): comment 6522108365, on main18318361, examples/app-crm, 1440×900, evidence branch claude/issue-27626-proxy-evidence @ 4c9afa65. ⛔ Not a claim.
Business reason
Who: every console reader who leaves tabs open in the background. What happens: a hidden tab polls as often as a visible one for its first ten minutes, so the background load #27626 meant to cut stays.
Surface: any console page (for example /apps/com.example.crm/crm_contact), idle, no drawer, 1440 px. Evidence logs 12, 19, 20 and 29.
Wanted
A hidden tab stops the bell's and the approvals badge's polling, or polls clearly less often than a visible one. It reads once when the tab becomes visible again. Measure first why objectui#12439 kept a 10-minute hidden window. If that was a ruling, this card is needs_decision.
Acceptance
With the tab hidden, the feeds make no poll, or polls at the agreed hidden cadence, from the moment it hides. Pinned with fake timers and visibilitychange.
Claim: PM loop round 1
Session: session_01Utp6CbDAucNyQ4UtzCJKyh
Account: os-bill
Branch: claude/project-thread-rrumoz (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-28084
Domain: domain:ui
Seat: domain:ui#4
File surface: ui/packages/app-shell/src/hooks/hiddenTabPollStop.ts, ui/packages/app-shell/src/hooks/sharedUserFeeds.ts, ui/packages/app-shell/src/hooks/useInboxArrivalNotifier.ts, the hooks/components reading their constants, their tests, .changeset/*.md (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on fec60e00: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: a hidden tab stops (or clearly slows) the bell and approvals polling from the moment it hides and reads once per feed on becoming visible; first measure whether objectui#12439's 10-minute hidden window was ruled (then needs_decision)
Thread-read: none
Premise: holds
Serial constraints cleared: #27907 merged 11:04Z; no open PR touches the surface
Dispatched 2026-10-30T12:06Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
{
"issue": 28084,
"status": "needs_decision",
"branch": "claude/project-thread-rrumoz",
"pr": null,
"session": "session_01Utp6CXAofd4m4ymS3HqKt5 (card thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh, Claim 6522358408)",
"premise_still_valid": true,
"summary": "Stopped before any code, as the ruling section orders: the 10-minute hidden window was chosen by the maintainer and kept by triage, and its stated purpose is the desktop notification for a background tab. Reading of objectui#12439: the card was filed by hotlong (a GOVERNED_APPROVERS account) with a section headed 'The trade-off (needs an explicit yes)'. It proposes 'While hidden but under N minutes, keep today's 60 s cadence, so a tab switched away briefly still behaves exactly as now', names the cost ('a message that arrives after the tab has been hidden for more than N minutes gets no desktop notification until the user returns to the tab'), and says 'The maintainer asked for this card knowing the trade-off. Pick N, or make it configurable, with that cost in mind.' Triage 6186333502 set scope to 'the card's proposal. Stop arming the timer after N minutes (10 suggested)'; Claim 6186836402 and review 6187549213 fixed 10 minutes as a constant ('HIDDEN_POLL_STOP_MS (10 minutes, a constant, as the claim ruled)'); PR objectui#12445 merged as objectui main 27411ea. On objectstack origin/main 5448585d the hiddenTabPollStop.ts docblock still says the cost 'was accepted for this value when it was chosen'. What changed since: the window was designed when the foreground polled at 10 s / 30 s, so 60 s hidden was the slower cadence (the HIDDEN_POLL_MS docblock: 'a shared feed that polled a hidden tab at its foreground rate would have been a regression'). #27907 moved both foreground cadences to 60 s and left HIDDEN_POLL_MS at 60 s, so that invariant no longer holds for the first 10 minutes. The scale-to-zero goal of objectui#12439 is unaffected by any option below: every option still stops all polling after 10 minutes. Card premise holds as written (60 s hidden = 60 s visible for 10 minutes on main).",
"tests": "none: reading only, no diff. Code read on origin/main 5448585d: sharedUserFeeds.ts (APPROVALS_POLL_MS = INBOX_POLL_MS = HIDDEN_POLL_MS = 60_000; schedule() uses Math.max(HIDDEN_POLL_MS, backoffMs) when hidden; onVisibilityChange refetches once per feed on return), hiddenTabPollStop.ts (HIDDEN_POLL_STOP_MS = 10 * 60_000), useInboxArrivalNotifier.ts (hidden tab raises showDesktopNotification only when preferences.desktop and desktopPermission granted; the module header carries the objectui#12439 trade-off). The desktop toggle is user-facing in layout/NotificationPreferencesMenu.tsx. git grep over ui/ for hiddenTabPollStop / HIDDEN_POLL_STOP_MS / isPollingSuspended / HIDDEN_POLL_MS: the three hooks plus three tests (hiddenTabPollStop-12439, sharedUserFeeds.hiddenStop-12439, sharedInboxFeed.cadence-7249); no other poller reads the clock.",
"gates": "none run: no diff (needs_decision). check-sdui-manifest not applicable without a change.",
"dogfood_battery": "n/a - no PR",
"line_budget": "0 changed lines",
"files_changed": [],
"deviations": [
"The order says read objectui#12439 through REST; the objectui repository had to be attached to this session first (read via gh api after attach). No write to objectui."
],
"mcp_calls": "0 - no GitHub MCP tool used.",
"api_writes": "1 - this os-dev-report comment via post-stamped (POST issues/28084/comments). No push, no PR.",
"open_questions": [
{
"question": "In the first 10 minutes after a console tab goes to the background, how often should the bell (inbox) and the approvals badge still check for new items?",
"governing_text": "objectui#12439 body, section 'The trade-off (needs an explicit yes)', filed by hotlong; triage 6186333502 ('the card's proposal ... 10 suggested'); Claim 6186836402 (10 minutes, a constant); #26676 ruling 6520722066 and this card's ruling section (a hidden tab stops, or polls clearly less often than a visible one; one read per feed on return).",
"options": {
"A": "Stop at the moment the tab hides (no hidden cadence at all); one read per feed on return. Background load from a hidden tab drops to zero at once. Cost: a hidden tab never reads, so the desktop notification of objectui#7011 can never fire while no push channel exists, and the user-facing desktop toggle in the notification menu would switch on a feature that does nothing (Prime Directive #10, declared is not enforced). Honest version needs a second change outside this card's file surface: retire or hide that toggle and its permission prompt until a push channel lands. ui lane, 1 PR here plus 1 follow-up card.",
"B": "Keep the 10-minute window, slow the hidden cadence to clearly below the visible one: HIDDEN_POLL_MS 60 s to 180 s (three times the visible 60 s). A hidden tab reads at 3, 6 and 9 minutes, then stops at 10 as today; one read per feed on return. Desktop notification stays, up to about 3 minutes late instead of 1. ui lane, 1 small PR inside the claimed file surface (one constant, three docblocks, the hidden-stop pin plus an ablation), no new knob.",
"C": "Keep 60 s for 10 minutes as the maintainer accepted it; close this card as not planned and correct only the inaccurate 'still stop in a hidden tab' sentence in the unreleased #27907 changeset. No code change; the 10 hidden reads per feed in the first 10 minutes stay."
},
"four_axis": {
"long_term": "The lasting answer is the push channel #27626 already wired (setUserFeedPushChannelOpen): with it open, neither feed polls, hidden or not. Until then the poll is a fallback, and B restores the rule the hidden cadence has always had (slower than visible, #4225) with one constant. A goes further than the fallback needs and leaves a dead preference unless a second change retires it. C leaves the hidden and visible cadences equal, which no docblock in the tree intends.",
"business_need": "Measured need on the card: idle background tabs add request load (proxy preview evidence on app-crm). objectui#12439's own driver, staging kept awake, is already solved by the 10-minute stop under every option, because the staging idle window (15 / 30 minutes per that card) is longer than 10 minutes. So the gain on the table is load only: per hidden tab and feed, 10 reads in the first 10 minutes today, 3 under B, 0 under A. The desktop notification has a real user toggle (NotificationPreferencesMenu); no usage reading was taken.",
"ai_error_prevention": "No metadata is involved. A without the toggle retirement leaves a declared capability the runtime cannot deliver, which is the shape AGENTS.md forbids; B and C keep declaration and behaviour in step.",
"startup_scope": "B is the smallest change that meets this card's ruling (one constant, no new knob, no second lane). A costs two changes and removes a shipped feature. C costs nothing but leaves the card's finding standing."
},
"recommendation": "B. Long-term axis leads: it restores the slower-when-hidden rule with one constant and keeps the maintainer's accepted trade-off (desktop notification within the first 10 minutes) instead of deleting it; the other three axes do not flip it. If the maintainer prefers A, the toggle retirement should be carded in the same ruling. Confidence gap: 180 s is a proposed figure, not a measured one; any value clearly above 60 s fits the same PR."
}
],
"out_of_scope_findings": [
"carrier: seat 4 (PR text) · noted, not filed. #27907's PR body and changeset say the feeds 'still stop in a hidden tab'; on main they stop only after 10 continuous hidden minutes. That changeset (.changeset/27626-record-open-requests.md, 'still stop in a hidden tab') is still unreleased on origin/main 5448585d, so the PR that lands the ruled option can correct its sentence in place and state what is then true."
]
}
Ruling: #28084 hidden-tab cadence · letter B · maintainer 「B」 2026-10-30T12:30Z · decision thread 「决定后台标签页铃铛轮询频率」(presented 12:17Z, Bill ruled in person; not a proxy ruling)
Marker: maintainer-ruled, recorded by the decision thread.
Re-verified readings (on origin/mainec7e15a, by the decision thread, beside the card thread's report 6522509433):
schedule() L475–510 reads document.hidden only when it arms, so the foreground tick already armed at the moment of hiding fires once more; hidden ticks are then spaced at Math.max(HIDDEN_POLL_MS, backoffMs), and any tick due after HIDDEN_POLL_STOP_MS (10 min, hiddenTabPollStop.ts) sends nothing. onVisibilityChange L516–535 reads once per feed on return.
An inbox tick is two requests (messages + receipts, L1443–1450); an approvals tick is one. Today a hidden tab makes up to 10 ticks per feed in its first 10 minutes (≈30 requests); at 180 s it makes at most 4 (≤1 / ~4 / ~7 / ~10 min, ≈12 requests).
useInboxArrivalNotifier.ts L9–48, L202: the desktop notification (objectui#7011) fires only in a hidden tab, behind the user's preference and a granted permission; its header still says "up to about a minute late".
.changeset/27626-record-open-requests.md L15 (unreleased): "still stop in a hidden tab" — on main they stop only after 10 continuous hidden minutes.
Governing text: objectui#12439 (hotlong), section "The trade-off (needs an explicit yes)": keep polling while hidden for N minutes so a desktop notification can still reach a background tab; triage 6186333502 and Claim 6186836402 fixed N = 10 as a constant. #26676 ruling 6520722066 (findings after a landing become cards under #26676). This card's Wanted: "stops ... or polls clearly less often than a visible one", one read per feed on return.
Ruling (B, 一次裁清): the 10-minute hidden window and the full stop after it stay exactly as objectui#12439 chose them. The hidden cadence goes back to being clearly slower than the foreground: HIDDEN_POLL_MS 60_000 → 180_000. No new knob, no per-feed rule, the desktop notification and its toggle stay (now up to about three minutes late instead of one). Execution parameters:
useInboxArrivalNotifier.ts header: "up to about a minute late" → "up to about three minutes late".
.changeset/27626-record-open-requests.md L15: "still stop in a hidden tab" → polls every three minutes while the tab is hidden and stops after ten hidden minutes (the changeset is unreleased, so the sentence is corrected in place).
Pin (fake timers + visibilitychange, in sharedUserFeeds.hiddenStop-12439.test.tsx or a sibling): after hiding, each feed reads at most 4 times in 10 minutes, consecutive hidden reads 180 s apart after the first, nothing after the 10th minute, exactly one read per feed on return. Ablation: the constant set back to 60_000 must turn the pin red.
Four axes: Long term: the lasting answer is the push channel seam #27626 already wired (setUserFeedPushChannelOpen); until a host opens one the poll is a fallback, and the fallback's standing rule is hidden-slower-than-visible, which one constant restores. Business need: the card's evidence is request load from idle background tabs (6522108365); the scale-to-zero driver of objectui#12439 is already covered by the 10-minute stop under every option. Error prevention: no metadata; B keeps declaration and behaviour in step, whereas stopping at hide (A) would leave the desktop toggle declared but inert until a second card retired it. Scope: one constant, three docblocks, one pin; no new lane, no Clause-②.
Options not taken: A (stop at hide, plus a card retiring the desktop toggle), C (keep 60 s, correct only the changeset sentence), D (approvals stop at hide, inbox 180 s — two hidden rules for a small saving). Cadence values 120 s / 300 s were offered; the maintainer took the recommended 180 s by answering 「B」.
Execution after the ruling: the card thread (seat domain:ui#4, Claim 6522358408) lands the one PR above with Ruling-ref: <this comment>; no re-opening of the 10-minute window, the full stop, the immediate read on return, or the desktop toggle. Ledger row added to the project's rulings file; the seat 4 thread and the card thread are told with the maintainer's words.
{
"issue": 28084,
"status": "done",
"branch": "claude/project-thread-rrumoz",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28133",
"session": "session_01Utp6CXAofd4m4ymS3HqKt5 (card thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh, Claim 6522358408)",
"premise_still_valid": true,
"summary": "Executes ruling B (6522899149). sharedUserFeeds.ts HIDDEN_POLL_MS 60_000 to 180_000 with its docblock rewritten (hidden 3 min against foreground 1 min, slower-when-hidden since #4225, the already-armed foreground tick fires once after hiding, objectui#12439 full stop after HIDDEN_POLL_STOP_MS unchanged); module header names the cadence. useInboxArrivalNotifier.ts header now says a desktop notification can be up to about three minutes late. The unreleased .changeset/27626-record-open-requests.md sentence 'still stop in a hidden tab' is corrected in place (execution parameter 3). New changeset 28084-hidden-tab-bell-cadence.md (app-shell patch). The 10-minute window, the full stop, the read on return and the desktop toggle are untouched. Supersedes report 6522509433 (needs_decision).",
"tests": "Head e802b06a. Closure build --filter '@object-ui/app-shell^...' lock VERDICT command-exit 0. New case in sharedUserFeeds.hiddenStop-12439.test.tsx (fake timers + visibilitychange; visible mount, hidden 30 s in): 1 read at the already-armed foreground tick, then one per full 180 s, 4 reads per feed in the 10 hidden minutes, none after, 0 timers armed, exactly 1 read per feed on return. Three hidden-tab files: Test Files 3 passed (3), Tests 15 passed (15), VERDICT command-exit 0. Ablation via scripts/ablation-replace.mjs (implementation committed first): anchor 'const HIDDEN_POLL_MS = 180_000;' to 60_000, anchor 1 to 0, blob 3ebb502c to 74dfdfe3; Tests 3 failed / 7 passed of the two feed files, VERDICT command-exit 1 (new case 'expected { approvals: 3, inbox: 3 } to deeply equal { approvals: 1, inbox: 1 }', cut-off case '{ approvals: 10, inbox: 10 }' vs 4, 7249 hidden throttle 'expected 4 to be 2'); restored blob == HEAD 3ebb502c, git diff HEAD empty; tests import src, no dist rebuild. packages/app-shell/src/hooks/: Test Files 84 passed (84), Tests 715 passed (715). pnpm --filter @object-ui/app-shell run type-check (tsc --noEmit + tsconfig.test.json): exit 0.",
"gates": "dispatch-gates --commands at e802b06a: 34 derived; 34 run, 33 exit 0 (check-sdui-manifest, check-sdui-manifest --self-test, vitest run scripts/, check:type-check-coverage, check:type-check-debt, check:nul-bytes and the rest); --ran reconciliation 34 derived / 34 run / 0 NOT-MEASURED. One red by design: check-empty-changeset --base origin/main exit 1 on .changeset/27626-record-open-requests.md, the DELIBERATE CORRECTION class, ordered by ruling 6522899149 parameter 3 and stated in the PR body. check:new-line-citations: 0 new. CI check-runs: in_progress at report time.",
"dogfood_battery": "n/a - no '!' in the PR title and no (narrowing) arm",
"line_budget": "+93 / -25 across 6 files (one constant, docblocks, one test case, two changesets)",
"files_changed": [
".changeset/27626-record-open-requests.md",
".changeset/28084-hidden-tab-bell-cadence.md",
"ui/packages/app-shell/src/hooks/sharedUserFeeds.ts",
"ui/packages/app-shell/src/hooks/useInboxArrivalNotifier.ts",
"ui/packages/app-shell/src/hooks/__tests__/sharedUserFeeds.hiddenStop-12439.test.tsx",
"ui/packages/app-shell/src/hooks/__tests__/sharedInboxFeed.cadence-7249.test.tsx"
],
"deviations": [
"Harness after-PR assign/review step skipped, as the order requires (no assignees, no review request).",
"check-empty-changeset is red on purpose (pending note corrected in place per the ruling); the gate's own text says it stays red and a person confirms."
],
"mcp_calls": "0 - no GitHub MCP tool used.",
"api_writes": "3 - report 6522509433 (POST issues/28084/comments), pr_create via fleet-write (POST pulls, #28133, draft, no assignees), this report (POST issues/28084/comments). Plus one git push of the branch.",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Claim: PM loop round 1
Session:
session_01Utp6CbDAucNyQ4UtzCJKyhAccount:
os-billBranch:
claude/project-thread-rrumoz(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-28084Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/app-shell/src/hooks/hiddenTabPollStop.ts,ui/packages/app-shell/src/hooks/sharedUserFeeds.ts,ui/packages/app-shell/src/hooks/useInboxArrivalNotifier.ts, the hooks/components reading their constants, their tests,.changeset/*.md(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieronfec60e00: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: a hidden tab stops (or clearly slows) the bell and approvals polling from the moment it hides and reads once per feed on becoming visible; first measure whether objectui#12439's 10-minute hidden window was ruled (then needs_decision)
Thread-read: none
Premise: holds
Serial constraints cleared: #27907 merged 11:04Z; no open PR touches the surface
Dispatched 2026-10-30T12:06Z 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#4 · os-bill · session_01Utp6CXAofd4m4ymS3HqKt5
os-dev-report
{ "issue": 28084, "status": "needs_decision", "branch": "claude/project-thread-rrumoz", "pr": null, "session": "session_01Utp6CXAofd4m4ymS3HqKt5 (card thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh, Claim 6522358408)", "premise_still_valid": true, "summary": "Stopped before any code, as the ruling section orders: the 10-minute hidden window was chosen by the maintainer and kept by triage, and its stated purpose is the desktop notification for a background tab. Reading of objectui#12439: the card was filed by hotlong (a GOVERNED_APPROVERS account) with a section headed 'The trade-off (needs an explicit yes)'. It proposes 'While hidden but under N minutes, keep today's 60 s cadence, so a tab switched away briefly still behaves exactly as now', names the cost ('a message that arrives after the tab has been hidden for more than N minutes gets no desktop notification until the user returns to the tab'), and says 'The maintainer asked for this card knowing the trade-off. Pick N, or make it configurable, with that cost in mind.' Triage 6186333502 set scope to 'the card's proposal. Stop arming the timer after N minutes (10 suggested)'; Claim 6186836402 and review 6187549213 fixed 10 minutes as a constant ('HIDDEN_POLL_STOP_MS (10 minutes, a constant, as the claim ruled)'); PR objectui#12445 merged as objectui main 27411ea. On objectstack origin/main 5448585d the hiddenTabPollStop.ts docblock still says the cost 'was accepted for this value when it was chosen'. What changed since: the window was designed when the foreground polled at 10 s / 30 s, so 60 s hidden was the slower cadence (the HIDDEN_POLL_MS docblock: 'a shared feed that polled a hidden tab at its foreground rate would have been a regression'). #27907 moved both foreground cadences to 60 s and left HIDDEN_POLL_MS at 60 s, so that invariant no longer holds for the first 10 minutes. The scale-to-zero goal of objectui#12439 is unaffected by any option below: every option still stops all polling after 10 minutes. Card premise holds as written (60 s hidden = 60 s visible for 10 minutes on main).", "tests": "none: reading only, no diff. Code read on origin/main 5448585d: sharedUserFeeds.ts (APPROVALS_POLL_MS = INBOX_POLL_MS = HIDDEN_POLL_MS = 60_000; schedule() uses Math.max(HIDDEN_POLL_MS, backoffMs) when hidden; onVisibilityChange refetches once per feed on return), hiddenTabPollStop.ts (HIDDEN_POLL_STOP_MS = 10 * 60_000), useInboxArrivalNotifier.ts (hidden tab raises showDesktopNotification only when preferences.desktop and desktopPermission granted; the module header carries the objectui#12439 trade-off). The desktop toggle is user-facing in layout/NotificationPreferencesMenu.tsx. git grep over ui/ for hiddenTabPollStop / HIDDEN_POLL_STOP_MS / isPollingSuspended / HIDDEN_POLL_MS: the three hooks plus three tests (hiddenTabPollStop-12439, sharedUserFeeds.hiddenStop-12439, sharedInboxFeed.cadence-7249); no other poller reads the clock.", "gates": "none run: no diff (needs_decision). check-sdui-manifest not applicable without a change.", "dogfood_battery": "n/a - no PR", "line_budget": "0 changed lines", "files_changed": [], "deviations": [ "The order says read objectui#12439 through REST; the objectui repository had to be attached to this session first (read via gh api after attach). No write to objectui." ], "mcp_calls": "0 - no GitHub MCP tool used.", "api_writes": "1 - this os-dev-report comment via post-stamped (POST issues/28084/comments). No push, no PR.", "open_questions": [ { "question": "In the first 10 minutes after a console tab goes to the background, how often should the bell (inbox) and the approvals badge still check for new items?", "governing_text": "objectui#12439 body, section 'The trade-off (needs an explicit yes)', filed by hotlong; triage 6186333502 ('the card's proposal ... 10 suggested'); Claim 6186836402 (10 minutes, a constant); #26676 ruling 6520722066 and this card's ruling section (a hidden tab stops, or polls clearly less often than a visible one; one read per feed on return).", "options": { "A": "Stop at the moment the tab hides (no hidden cadence at all); one read per feed on return. Background load from a hidden tab drops to zero at once. Cost: a hidden tab never reads, so the desktop notification of objectui#7011 can never fire while no push channel exists, and the user-facing desktop toggle in the notification menu would switch on a feature that does nothing (Prime Directive #10, declared is not enforced). Honest version needs a second change outside this card's file surface: retire or hide that toggle and its permission prompt until a push channel lands. ui lane, 1 PR here plus 1 follow-up card.", "B": "Keep the 10-minute window, slow the hidden cadence to clearly below the visible one: HIDDEN_POLL_MS 60 s to 180 s (three times the visible 60 s). A hidden tab reads at 3, 6 and 9 minutes, then stops at 10 as today; one read per feed on return. Desktop notification stays, up to about 3 minutes late instead of 1. ui lane, 1 small PR inside the claimed file surface (one constant, three docblocks, the hidden-stop pin plus an ablation), no new knob.", "C": "Keep 60 s for 10 minutes as the maintainer accepted it; close this card as not planned and correct only the inaccurate 'still stop in a hidden tab' sentence in the unreleased #27907 changeset. No code change; the 10 hidden reads per feed in the first 10 minutes stay." }, "four_axis": { "long_term": "The lasting answer is the push channel #27626 already wired (setUserFeedPushChannelOpen): with it open, neither feed polls, hidden or not. Until then the poll is a fallback, and B restores the rule the hidden cadence has always had (slower than visible, #4225) with one constant. A goes further than the fallback needs and leaves a dead preference unless a second change retires it. C leaves the hidden and visible cadences equal, which no docblock in the tree intends.", "business_need": "Measured need on the card: idle background tabs add request load (proxy preview evidence on app-crm). objectui#12439's own driver, staging kept awake, is already solved by the 10-minute stop under every option, because the staging idle window (15 / 30 minutes per that card) is longer than 10 minutes. So the gain on the table is load only: per hidden tab and feed, 10 reads in the first 10 minutes today, 3 under B, 0 under A. The desktop notification has a real user toggle (NotificationPreferencesMenu); no usage reading was taken.", "ai_error_prevention": "No metadata is involved. A without the toggle retirement leaves a declared capability the runtime cannot deliver, which is the shape AGENTS.md forbids; B and C keep declaration and behaviour in step.", "startup_scope": "B is the smallest change that meets this card's ruling (one constant, no new knob, no second lane). A costs two changes and removes a shipped feature. C costs nothing but leaves the card's finding standing." }, "recommendation": "B. Long-term axis leads: it restores the slower-when-hidden rule with one constant and keeps the maintainer's accepted trade-off (desktop notification within the first 10 minutes) instead of deleting it; the other three axes do not flip it. If the maintainer prefers A, the toggle retirement should be carded in the same ruling. Confidence gap: 180 s is a proposed figure, not a measured one; any value clearly above 60 s fits the same PR." } ], "out_of_scope_findings": [ "carrier: seat 4 (PR text) · noted, not filed. #27907's PR body and changeset say the feeds 'still stop in a hidden tab'; on main they stop only after 10 continuous hidden minutes. That changeset (.changeset/27626-record-open-requests.md, 'still stop in a hidden tab') is still unreleased on origin/main 5448585d, so the PR that lands the ruled option can correct its sentence in place and state what is then true." ] }os-bill commentedon Oct 30, 2026
Ruling: #28084 hidden-tab cadence · letter B · maintainer 「B」 2026-10-30T12:30Z · decision thread 「决定后台标签页铃铛轮询频率」(presented 12:17Z, Bill ruled in person; not a proxy ruling)
Marker: maintainer-ruled, recorded by the decision thread.
Re-verified readings (on
origin/mainec7e15a, by the decision thread, beside the card thread's report 6522509433):ui/packages/app-shell/src/hooks/sharedUserFeeds.tsL112–136:APPROVALS_POLL_MS=INBOX_POLL_MS=HIDDEN_POLL_MS= 60 s since perf(console): opening a record re-reads no list, asks its field access once, and the bell polls once a minute #27907 (main 40be9b5); theHIDDEN_POLL_MSdocblock still states the rule it no longer meets ("a shared feed that polled a hidden tab at its foreground rate would have been a regression", Three datasource-admin routes answer 503 naming the wrong service (carried out of #3973 so it is not buried) #4225).schedule()L475–510 readsdocument.hiddenonly when it arms, so the foreground tick already armed at the moment of hiding fires once more; hidden ticks are then spaced atMath.max(HIDDEN_POLL_MS, backoffMs), and any tick due afterHIDDEN_POLL_STOP_MS(10 min,hiddenTabPollStop.ts) sends nothing.onVisibilityChangeL516–535 reads once per feed on return.useInboxArrivalNotifier.tsL9–48, L202: the desktop notification (objectui#7011) fires only in a hidden tab, behind the user's preference and a granted permission; its header still says "up to about a minute late"..changeset/27626-record-open-requests.mdL15 (unreleased): "still stop in a hidden tab" — on main they stop only after 10 continuous hidden minutes.Governing text: objectui#12439 (hotlong), section "The trade-off (needs an explicit yes)": keep polling while hidden for N minutes so a desktop notification can still reach a background tab; triage 6186333502 and Claim 6186836402 fixed N = 10 as a constant. #26676 ruling 6520722066 (findings after a landing become cards under #26676). This card's Wanted: "stops ... or polls clearly less often than a visible one", one read per feed on return.
Ruling (B, 一次裁清): the 10-minute hidden window and the full stop after it stay exactly as objectui#12439 chose them. The hidden cadence goes back to being clearly slower than the foreground:
HIDDEN_POLL_MS60_000 → 180_000. No new knob, no per-feed rule, the desktop notification and its toggle stay (now up to about three minutes late instead of one). Execution parameters:sharedUserFeeds.ts:HIDDEN_POLL_MS = 180_000; rewrite its docblock (hidden 3 min against foreground 1 min, slower-when-hidden is the rule since Three datasource-admin routes answer 503 naming the wrong service (carried out of #3973 so it is not buried) #4225, full stop afterHIDDEN_POLL_STOP_MSper objectui#12439).useInboxArrivalNotifier.tsheader: "up to about a minute late" → "up to about three minutes late"..changeset/27626-record-open-requests.mdL15: "still stop in a hidden tab" → polls every three minutes while the tab is hidden and stops after ten hidden minutes (the changeset is unreleased, so the sentence is corrected in place).visibilitychange, insharedUserFeeds.hiddenStop-12439.test.tsxor a sibling): after hiding, each feed reads at most 4 times in 10 minutes, consecutive hidden reads 180 s apart after the first, nothing after the 10th minute, exactly one read per feed on return. Ablation: the constant set back to 60_000 must turn the pin red.claude/project-thread-rrumoz, Fixes Console bell and approvals badge keep polling every 60 s for the first 10 minutes of a hidden tab #28084, inside the claimed file surface (Claim 6522358408).Four axes: Long term: the lasting answer is the push channel seam #27626 already wired (
setUserFeedPushChannelOpen); until a host opens one the poll is a fallback, and the fallback's standing rule is hidden-slower-than-visible, which one constant restores. Business need: the card's evidence is request load from idle background tabs (6522108365); the scale-to-zero driver of objectui#12439 is already covered by the 10-minute stop under every option. Error prevention: no metadata; B keeps declaration and behaviour in step, whereas stopping at hide (A) would leave the desktop toggle declared but inert until a second card retired it. Scope: one constant, three docblocks, one pin; no new lane, no Clause-②.Options not taken: A (stop at hide, plus a card retiring the desktop toggle), C (keep 60 s, correct only the changeset sentence), D (approvals stop at hide, inbox 180 s — two hidden rules for a small saving). Cadence values 120 s / 300 s were offered; the maintainer took the recommended 180 s by answering 「B」.
HIDDEN_POLL_MS60 s → 180 s;桌面通知与开关不动(最晚约 3 分钟);顺手把 perf(console): opening a record re-reads no list, asks its field access once, and the bell polls once a minute #27907 未发布 changeset 里「still stop in a hidden tab」改成实话。Execution after the ruling: the card thread (seat
domain:ui#4, Claim 6522358408) lands the one PR above withRuling-ref: <this comment>; no re-opening of the 10-minute window, the full stop, the immediate read on return, or the desktop toggle. Ledger row added to the project's rulings file; the seat 4 thread and the card thread are told with the maintainer's words.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CXAofd4m4ymS3HqKt5
os-dev-report
{ "issue": 28084, "status": "done", "branch": "claude/project-thread-rrumoz", "pr": "https://github.com/objectstack-ai/objectstack/pull/28133", "session": "session_01Utp6CXAofd4m4ymS3HqKt5 (card thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh, Claim 6522358408)", "premise_still_valid": true, "summary": "Executes ruling B (6522899149). sharedUserFeeds.ts HIDDEN_POLL_MS 60_000 to 180_000 with its docblock rewritten (hidden 3 min against foreground 1 min, slower-when-hidden since #4225, the already-armed foreground tick fires once after hiding, objectui#12439 full stop after HIDDEN_POLL_STOP_MS unchanged); module header names the cadence. useInboxArrivalNotifier.ts header now says a desktop notification can be up to about three minutes late. The unreleased .changeset/27626-record-open-requests.md sentence 'still stop in a hidden tab' is corrected in place (execution parameter 3). New changeset 28084-hidden-tab-bell-cadence.md (app-shell patch). The 10-minute window, the full stop, the read on return and the desktop toggle are untouched. Supersedes report 6522509433 (needs_decision).", "tests": "Head e802b06a. Closure build --filter '@object-ui/app-shell^...' lock VERDICT command-exit 0. New case in sharedUserFeeds.hiddenStop-12439.test.tsx (fake timers + visibilitychange; visible mount, hidden 30 s in): 1 read at the already-armed foreground tick, then one per full 180 s, 4 reads per feed in the 10 hidden minutes, none after, 0 timers armed, exactly 1 read per feed on return. Three hidden-tab files: Test Files 3 passed (3), Tests 15 passed (15), VERDICT command-exit 0. Ablation via scripts/ablation-replace.mjs (implementation committed first): anchor 'const HIDDEN_POLL_MS = 180_000;' to 60_000, anchor 1 to 0, blob 3ebb502c to 74dfdfe3; Tests 3 failed / 7 passed of the two feed files, VERDICT command-exit 1 (new case 'expected { approvals: 3, inbox: 3 } to deeply equal { approvals: 1, inbox: 1 }', cut-off case '{ approvals: 10, inbox: 10 }' vs 4, 7249 hidden throttle 'expected 4 to be 2'); restored blob == HEAD 3ebb502c, git diff HEAD empty; tests import src, no dist rebuild. packages/app-shell/src/hooks/: Test Files 84 passed (84), Tests 715 passed (715). pnpm --filter @object-ui/app-shell run type-check (tsc --noEmit + tsconfig.test.json): exit 0.", "gates": "dispatch-gates --commands at e802b06a: 34 derived; 34 run, 33 exit 0 (check-sdui-manifest, check-sdui-manifest --self-test, vitest run scripts/, check:type-check-coverage, check:type-check-debt, check:nul-bytes and the rest); --ran reconciliation 34 derived / 34 run / 0 NOT-MEASURED. One red by design: check-empty-changeset --base origin/main exit 1 on .changeset/27626-record-open-requests.md, the DELIBERATE CORRECTION class, ordered by ruling 6522899149 parameter 3 and stated in the PR body. check:new-line-citations: 0 new. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a - no '!' in the PR title and no (narrowing) arm", "line_budget": "+93 / -25 across 6 files (one constant, docblocks, one test case, two changesets)", "files_changed": [ ".changeset/27626-record-open-requests.md", ".changeset/28084-hidden-tab-bell-cadence.md", "ui/packages/app-shell/src/hooks/sharedUserFeeds.ts", "ui/packages/app-shell/src/hooks/useInboxArrivalNotifier.ts", "ui/packages/app-shell/src/hooks/__tests__/sharedUserFeeds.hiddenStop-12439.test.tsx", "ui/packages/app-shell/src/hooks/__tests__/sharedInboxFeed.cadence-7249.test.tsx" ], "deviations": [ "Harness after-PR assign/review step skipped, as the order requires (no assignees, no review request).", "check-empty-changeset is red on purpose (pending note corrected in place per the ruling); the gate's own text says it stays red and a person confirms." ], "mcp_calls": "0 - no GitHub MCP tool used.", "api_writes": "3 - report 6522509433 (POST issues/28084/comments), pr_create via fleet-write (POST pulls, #28133, draft, no assignees), this report (POST issues/28084/comments). Plus one git push of the branch.", "open_questions": [], "out_of_scope_findings": [] }objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
ACCEPT → PR #28133 comment 6524977384 · 2026-10-30T14:16Z
Generated by Claude Code