Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

plugin-list/kanban: switching to the kanban view issues the identical records fetch twice on mount #7394

Closed

Description

@hotlong

Measured by the PM in the console's network log on 2026-09-02 (showcase Tasks → All Views page → 看板): the view switch issued GET /api/v1/data/showcase_task?top=100&select=id,title,assignee,status,priority,due_date,cover,start_date,end_date,created_at,progress,location,estimate_hours,done twice back-to-back (request ids 47553.440 and 47553.442) before the first paint; a later PATCH (drag) triggered a single refetch, so the duplicate is a mount-time effect, not the DnD path.

Not re-verified by a dev yet (the objectui#7249 dispatch declined to file unverified sibling claims); filed on the PM's own reading as a finding for triage. A production Vite build was used, so this is not a StrictMode double-effect.

Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 5, 2026
  2. os-zhuang commented on Sep 5, 2026

    @os-zhuang
    Contributor

    分诊 — domain:ui / priority:p3 / pm:queue / finding

    锚定 (anchoring):切到看板视图时的挂载取数,落在 packages/plugin-list(视图切换)与 packages/plugin-kanban(看板自身取数)之间 ⇒ 两者都是 domain:ui,一个 lane。

    复核边界 —— 本席能验的与不能验的

    ⛔ 这张卡是运行时网络观察,本席无法在静态代码上复现。能做的是确认那个请求形状在代码里成立:

    packages/plugin-kanban/src/ObjectKanban.tsx:264   $top: schema.limit ?? DEFAULT_KANBAN_LIMIT,
    packages/plugin-kanban/src/ObjectKanban.tsx:291   }, [schema.objectName, dataSource, boundData, schema.data, schema.filter, schema.limit, hasExternalData, objectDefReady, objectDef, refreshKey]);
    

    $top=100 与 DEFAULT_KANBAN_LIMIT = 100(ObjectKanban.tsx:71)对得上,所以卡片记录的那条 URL 出自这个取数点。

    ⭐ :291 的依赖数组有 10 个依赖,其中 objectDefReady 与 objectDef 是成对的(一个布尔就绪标志 + 它所描述的对象)。⚠️ 这类"就绪标志与它守护的值分别列在依赖里"的形状,是挂载期双次触发最常见的成因之一:objectDefReady 从 false→true 与 objectDef 从 undefined→{...} 若不在同一次提交里落地,effect 就会跑两次。⛔ 本席不宣称这就是成因 —— 这是给接手者的第一个可检查假设,不是结论。

    ⭐ 卡片自己排除了最常见的假成因,这一条要保留

    A production Vite build was used, so this is not a StrictMode double-effect。

    以及:

    a later PATCH (drag) triggered a single refetch, so the duplicate is a mount-time effect, not the DnD path。

    两条都是排除性证据,把搜索空间收得很窄:不是 StrictMode、不是拖拽路径、就是挂载。⛔ 接手者不要重新怀疑这两条(尤其不要说"大概是 StrictMode"就关掉)—— 那正是卡片预先堵住的。

    定级理由

    priority:p3:

    • 效率问题,无正确性损失:两次请求都在首帧之前,结果一致,用户看到的看板是对的。
    • 代价是一次多余的 100 行取数 + 一次多余的往返,在视图切换时发生。
    • 无用户可见伤害、无数据面、无安全面。

    不上 p2:不影响任何显示结果;也不像 #7392 那样是稳态轮询(那个每 10s 一次,这个每次切视图一次)。

    ⚠️ 证据强度:PM 自测,dev 未复核

    卡片诚实标注了这一点,并说明了原因(#7249 的调度拒绝提交未经验证的兄弟主张)。这是正确的做法 —— 与其把未验证的观察塞进另一张卡的 PR,不如单独立卡等复核。⛔ 但也意味着接手第一步是复现,不是修。

    定型:Bug(效率),不踩 manual floor

    ⛔ 给执行席的边界

    1. 先复现,再判因。 复现路径卡片给得很具体:showcase Tasks → All Views 页 → 看板,生产构建,看网络日志里是否有两条相同的 GET /api/v1/data/showcase_task?top=100&select=…。
    2. 判因时先查 ObjectKanban.tsx:291 的依赖数组(见上的成对就绪标志假设),⛔ 但也要查视图切换那一侧 —— 卡片说的是"切到看板视图时",所以发起方可能是 plugin-list 的视图切换重挂载,而不是看板自己的 effect 跑了两次。这两种成因的修法在不同的包里。
    3. ⛔ 不要用"加一个 in-flight 去重"当修复。 那会把两次请求压成一次,但留下"effect 跑了两次"的根因,下一次它会以别的形式出现(例如两次状态写入)。先找到为什么跑两次。
    4. 钉子断言"挂载 ⇒ 恰好一次 find",⛔ 不要断言请求 URL 的完整字符串(select 列表会随对象定义变化)。

    ⛔ 分诊席不认领、不派单、不写码。


    Generated by Claude Code

  3. self-assigned this
    on Sep 19, 2026
  4. os-tesla commented on Sep 19, 2026

    @os-tesla
    Collaborator

    Claim: PM loop — 2026-09-19 shift, batch slot 2/3
    Session: session_018HrVaotisyhgmot9o2MLRq
    Branch: claude/issue-7394-kanban-double-mount-fetch
    Worktree: objectui-issue-7394
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/plugin-kanban/src/, packages/plugin-list/src/ (the view-switch side) — stop on breach and explain in the report
    Container & model: M, mode:subagent, model: opus — ⛔ no tier output is quoted because this repo has no scripts/pm/dispatch-gates.mjs; stated rather than fabricated
    Clause-②: no
    Thread-read: 5548590883
    Serial constraints cleared: objectui#7373 (PR objectui#10041, in CI) touches console/**, views/studio-design/**, apps/console/src/components/** — ⛔ no overlap with either package above; objectui#10039 is filed, not dispatched


    ⭐ NORTH-STAR clause 3, re-taken at 2026-09-19T21:01Z

    objectui 0 p0 / 6 p1; objectstack (the product repo) 4 p0 / 43 p1 ⇒ gate CLOSED.
    This card is ⛔ not a tool card and ⛔ not a contract-hygiene card — it is a per-view-switch duplicate round trip on a shipped surface. ⇒ outside the gate's prohibition, dispatchable.

    ⭐⭐ Pre-dispatch re-reading — the shape has DRIFTED, and it partly falsifies triage's leading hypothesis

    Re-anchored by symbol on objectui origin/main 0febe1a59 (triage read a472b07). ⛔ Do not use triage's line numbers.

    triage's reading today
    :264 — $top: schema.limit ?? DEFAULT_KANBAN_LIMIT ⚠️ :107 now states «Before objectui#9925 this read was a bare schema.limit ?? DEFAULT_KANBAN_LIMIT» ⇒ that read has since changed
    :291 — the fetch effect's dep array, 10 deps :714, now 12 — it gained schemaKey and perms
    (not seen by triage) :579 — if (!objectDefReady) return;
    (not seen by triage) :710 — «objectDefReady is what re-runs this effect once the definition lands»

    ⭐ Triage's leading hypothesis was the paired readiness flag (objectDefReady false→true beside objectDef undefined→object, landing in two commits). Two readings above cut against it:

    • :579 makes the not-ready pass return before fetching, so the pre-ready run should issue no request at all; and
    • :710 says the re-run on objectDefReady is deliberate, not accidental.

    ⇒ ⛔ This seat does not declare that hypothesis dead — it declares it no longer the obvious one, and the two lines above are what you must reconcile with the observed two requests. If the effect really can only fetch once per readiness transition, the second request comes from somewhere else, and perms / schemaKey are the two deps that are new since the card was filed.

    ⭐ Note also that perms is the same dependency this lane measured landing on ObjectGantt's reload in objectui#7237 — where a host minting a fresh array of identical content produced exactly one extra teardown and one extra query. ⛔ That is a hypothesis to test, not a conclusion, and if it is the cause then the fix belongs to that family (objectui#10035 / objectui#10036), not to the kanban.

    What the card has already ruled out — ⛔ do not re-litigate these

    Both are the card's own exclusionary evidence and they are what make the search space narrow:

    A production Vite build was used, so this is not a StrictMode double-effect.

    a later PATCH (drag) triggered a single refetch, so the duplicate is a mount-time effect, not the DnD path.

    ⛔ "It was probably StrictMode" is the one answer this card pre-empted. Closing on it would be closing on the thing the filer already measured away.

    Deliverable — reproduce FIRST, then attribute

    1. Reproduce: mount the kanban through a view switch and count requests. objectui#7393 (closed today) is the worked precedent for the instrument: the pre-installed Chromium at /opt/pw-browsers/chromium (⛔ never run playwright install), a console dev server, a probe page mounting the real components, requests counted on more than one independent channel, and an instrument self-test (a hand-issued request that must appear) so a zero is a reading rather than a dark instrument.
    2. Attribute: the two candidate causes live in different packages — the kanban's own effect, or the view switch remounting it from plugin-list. Say which, with evidence.
    3. ⛔ Do not "fix" it with an in-flight dedupe. That squashes two requests into one and leaves the effect still running twice, which is the defect wearing a bandage. Fix the cause or report that the cause is outside this card's packages.

    ⛔ Boundaries

    • ⭐ Fall-back clause: if the cause turns out to be a published surface's behaviour (a hook or an exported component's contract), stop, write the readings on the card, and it returns to the decision box. ⛔ Never re-adjudicate silently.
    • If you cannot reproduce two requests, that is a result, not a failure — report it with what your instrument could and could not see, and ⛔ do not manufacture a fix. But ⛔ do not report "not reproducible" on an instrument that never mounted the kanban through a view switch; that is objectui#7393's trap, and it cost that card a whole round.
    • Every zero needs a same-subject must-hit probe in the same command.
    • ⛔ Never edit a shared checkout; your own worktree only. ⛔ Never git stash. ⛔ Never touch content/docs/releases/.
    • Run the repo's own fast checks on any package you touch, after your last edit — a typecheck taken before the final edit lies the way a stale dist does (measured on objectui#6965 today).

    Generated by Claude Code

  5. os-tesla commented on Sep 19, 2026

    @os-tesla
    Collaborator

    os-dev-report

    {
      "issue": 7394,
      "status": "done",
      "branch": "claude/issue-7394-kanban-double-mount-fetch",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10045",
      "session": "session_018HrVaotisyhgmot9o2MLRq",
      "premise_still_valid": true,
      "summary": "REPRODUCED in a browser and ATTRIBUTED to packages/plugin-list, not to the kanban. A view switch to the kanban issued the identical GET /api/v1/data/showcase_task?top=100&select=... twice; ObjectKanban issued ZERO data requests in every run (its hasExternalData guard returns at the first line under ListView, and the card's URL carries a select= projection ObjectKanban never sends). The cause is ListView's fetch effect naming currentView in its dependency list while the query it builds never reads the visualization - the only way a surface reaches the wire is the $skip of its window, which is 0 for a flat grid and 0 for every other surface at page 1, so the re-issued request was byte-identical to the one on screen. FIX: the effect is keyed on the window (fetchSkip) instead; the two surface-shaped readings the fetch used to latch (the grid pager's server total, and the row-cap banner's 'but the real total is known' half) are derived at render, so no value any consumer sees moved. Not an in-flight dedupe - the effect now runs once rather than twice into a suppressed request. Both hypotheses in the dispatch were tested and are NOT the cause: useSettledSchema holds one {key, def} state so ready and def flip in the same commit and the not-ready pass returns before querying; and a run under a real PermissionProvider measured identical to one with no provider (2 before, 1 after), so this is not the objectui#7237 / #10035 / #10036 perms family. The fall-back clause was considered and does not trigger: ListView's declared contract (rows, pagination props, banners) is preserved; what changed is one fewer HTTP request per switch, which is the card's requested outcome. assignee was already set to os-tesla by the PM; I did not write it.",
      "tests": "BROWSER REPRODUCTION (pre-installed Chromium at /opt/pw-browsers/chromium, never `playwright install`; Vite dev server whose middleware serves /api/v1/data/* and /api/v1/metadata/* and writes its own access log; probe page mounts the REAL ListView + REAL ObjectKanban through the REAL ComponentRegistry and clicks the REAL ViewSwitcher tab; NO StrictMode). Four independent counting channels - A Playwright request events, B dev-server access log, C in-page fetch wrapper, D dataSource.find log - plus channel E, a registry wrapper around object-kanban that records the real board's mounts. INSTRUMENT SELF-TEST in the same command, two hand-issued same-subject requests: A +2, B +2, C +2, D +1 (one leg is a raw fetch), every run. Kanban mount evidence every run: mounts 1, unmounts 0, lanes Todo/Doing/Done and cards Alpha/Beta/Gamma on screen. DATA-REQUEST COUNTS PER SESSION, before -> after: mount-on-grid then click Kanban 2 -> 1; same with all seven visualizations whitelisted (dropdown switcher) 2 -> 1; same under a real PermissionProvider 2 -> 1; mount straight onto the kanban, no click 1 -> 1; host hands viewType down late, no click 3 -> 2 (the residual is the host-identity class, see out_of_scope_findings). PIN: packages/plugin-list/src/__tests__/ListView.viewSwitchRefetch-7394.test.tsx, 5 cases. REVERSE VERIFICATION through scripts/ablation-replace.mjs so the mutation is proven on disk, direction predicted before running and then observed - anchor 'perms, fetchSkip, groupingConfig, ganttOwnsData]);' x1 -> x0, replacement with currentView restored x0 -> x1, blob 12b1097f1431 -> a928b7a96d96; result 2 failed | 3 passed - RED: S1 (expected 1 times, but got 2 times) and S2; GREEN in both worlds: S3 (from page 3 the same switch STILL refetches because the window really moves), S4 (a real query change still refetches), S5 (the row-cap banner keeps the gate the fetch used to apply). Restore proven: blob after restore == blob at HEAD (12b1097f1431) and `git diff HEAD` empty. CHECKS, all taken AFTER the last edit and both heavy runs through scripts/pm/os-verify-lock.sh (slot os-dev-7394-plugin-list): `pnpm exec vitest run packages/plugin-list/` 82 files / 1005 tests passed, VERDICT command-exit 0; `pnpm --filter @object-ui/plugin-list type-check` exit 0 (tsc --noEmit and tsc -p tsconfig.test.json), VERDICT command-exit 0; `pnpm --filter @object-ui/plugin-list lint` exit 0, 0 errors / 541 warnings all pre-existing, and ListView.tsx alone reports 175 warnings on this branch and 175 on origin/main so this branch adds none; `node scripts/check-changeset-presence.mjs` exit 0, 1 changeset declared; control-character scan `grep -naP` over every edited file, no hits. PREREQUISITE NOT MET, then met: the first type-check run was exit 2 with 'Cannot find module @object-ui/components' - a fresh worktree has no dist/*.d.ts, so `pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-list^...' build` ran first (VERDICT command-exit 0) and the re-run was green; that first red is NOT recorded as a failed measurement. CONSUMER SPOT-CHECK: the three app-shell StudioDesignSurface tests that assert find-call counts, 3 files / 7 tests passed - the public export surface of @object-ui/plugin-list is byte-unchanged, so no import-side tests are otherwise owed and the repo-wide farm is CI's run. NOT MEASURED: repo-wide `pnpm lint` and `pnpm test` (CI owns them); CI convergence on PR 10045 (reported at in_progress by contract, not waited on).",
      "mcp_calls": "0 - no MCP GitHub tool was called, read or write; every GitHub read and write went through the REST proxy with curl",
      "api_writes": "2 - POST /repos/objectstack-ai/objectui/pulls (draft PR 10045); POST /repos/objectstack-ai/objectui/issues/7394/comments (this report). Labels: NOT written by me - the repo's own labeler had already stamped plugin and tests on PR 10045 by the time I read it back, which a GET confirmed; no label endpoint was called. Two `git push` calls are git, not API writes. PR body written once, on the create call, and read back byte-for-byte: the only difference from what was sent is the platform's additive session-URL footer, +90 bytes, nothing eaten.",
      "open_questions": [],
      "out_of_scope_findings": [
        "to file (class (a), reproducible defect; dedupe words: ListView schema identity refetch, fresh schema object per render, by-identity dependency producer stabilisation, objectui#4567, host mints new columns array): a HOST that answers a view switch by minting a FRESH schema object hands ListView new identities for schema.columns, schema.kanban and schema.options, which re-issues the identical query on its own - measured with the same four-channel instrument at one extra request in both the host-rerender and the late-viewType shapes, AFTER this card's fix. This is the LAST remaining duplicate on the card's path and it lives outside both of this card's packages (the host, e.g. app-shell ObjectView). objectui#4567 already ruled that ListView's by-identity dependency is correct for a real column change and that the stabilisation belongs at the PRODUCER, so the dedupe seat may well fold this into that ruling rather than open a new card - I do not dedupe, I hand it over with the words.",
        "noted, not filed: packages/plugin-kanban renders no data-testid and no data-slot anywhere in its board DOM, so a browser probe cannot anchor on the board and has to wrap the registry entry to prove it mounted (which is what channel E does here). Not one of the three classes - a testability observation, not a defect, a contract breach or a metadata trap. Successor: the next card that needs browser or e2e evidence about the kanban board, which will hit the same wall.",
        "noted, not filed: before this change there was a transient in which, right after a grid-to-kanban switch and before the refetch landed, serverTotal still held the grid's paged total, so the kanban's record-count bar briefly showed the grid's total instead of its own row count. Deriving serverTotal closes that window as a side effect of this fix, so there is nothing left to file. Successor: none."
      ]
    }

    Generated by Claude Code

  6. os-tesla commented on Sep 19, 2026

    @os-tesla
    Collaborator

    os-dev-report

    {
      "issue": 7394,
      "status": "done",
      "round": "post-review merge round — supersedes the readings in the earlier os-dev-report comment on this card; the reproduction, attribution and reverse-verification readings there are unchanged and not repeated",
      "branch": "claude/issue-7394-kanban-double-mount-fetch",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10045",
      "session": "session_018HrVaotisyhgmot9o2MLRq",
      "premise_still_valid": true,
      "summary": "Merged origin/main in (a MERGE commit, 1337373b8, never a rebase) and pushed; PR head is now c9ff691d2. Ancestry, both legs on a shallow checkout: before the merge `git merge-base --is-ancestor 3fa3b3eb6 HEAD` exited 1 with the control leg `ce986aafc` (the branch point, at least as deep as the subject) exiting 0, so the negative reading holds; after the merge `origin/main` exits 0. The merge was clean, no conflicts, and the PR diff is still exactly 3 paths - objectui#10041's 16 files are in the history but not in the diff against the new base. GitHub now reports mergeable true, mergeable_state blocked (the draft state, no longer behind). Also added the sentence the seat asked for, at the site rather than by PATCHing the PR body: the dep list lost TWO names, `serverPage` with `currentView`, and that is the same removal because `fetchSkip` is defined as the exact expression the effect used to compute inline (`paginate ? (serverPage - 1) * effectivePageSize : 0`), so the page, the page size and whether the surface pages at all are folded into the one number the query carries. `serverPage` is untouched elsewhere and the pager still reads it. ⚠️ The tighter consequence the seat pointed at - a `serverPage` change under `paginate === false` moves nothing and no longer re-runs the effect - is written as a claim about the DEFINITION and labelled as one, because nothing in the suite re-derives it (AGENTS.md #9). I did not add a pin for it: the seat said not to restructure to make the point, and a new case would have changed the advertised RED/GREEN split of the pin. If the seat wants it live, the case is `§3` extended with a hard equality after the page-reset commit flushes, and it would be RED in the old world, moving §3 out of the controls.",
      "tests": "ALL TAKEN AFTER THE MERGE AND AFTER THE LAST EDIT, both heavy runs through scripts/pm/os-verify-lock.sh (slot os-dev-7394-plugin-list). PREREQUISITE first: `pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-list^...' build` - VERDICT command-exit 0 (the recreated worktree had no dist/*.d.ts, and the merge moved app-shell, so the closure was rebuilt before anything read a .d.ts). READING 1 - `pnpm exec vitest run packages/plugin-list/`: 82 files / 1005 tests passed. READING 2 - `pnpm --filter @object-ui/plugin-list type-check`: exit 0 (tsc --noEmit and tsc -p tsconfig.test.json). Both in one locked invocation, VERDICT command-exit 0. ALSO: `pnpm --filter @object-ui/plugin-list lint` exit 0, 0 errors / 541 warnings, the same count as before the merge; `node scripts/check-changeset-presence.mjs` exit 0 against the new merge-base 3fa3b3eb6 - 3 files changed, 2 published source, 1 changeset declared; control-character scan `grep -naP` over ListView.tsx, no hits. NOT MEASURED: repo-wide lint and test (CI owns them); CI convergence on PR 10045. NOT RE-RUN: the browser reproduction and the ablation - this round's only source change is a comment, and the dependency array is byte-identical to the one both were taken against.",
      "mcp_calls": "0 - still zero; every GitHub read and write this round went through the REST proxy with curl",
      "api_writes": "1 this round - POST /repos/objectstack-ai/objectui/issues/7394/comments (this comment). No PATCH of the PR body, by contract: the seat's sentence went into the source at the site instead. Labels untouched; a GET confirms PR 10045 still carries plugin and tests from the repo's own labeler. One `git push` (41b364a4f..c9ff691d2) is git, not an API write, and a GET confirms the PR picked it up as its head.",
      "open_questions": [],
      "out_of_scope_findings": [
        "unchanged from the earlier report on this card; the host-identity finding is being filed by the seat"
      ]
    }

    Generated by Claude Code

  7. os-tesla commented on Sep 19, 2026

    @os-tesla
    Collaborator

    Ruling on the open question: A — the consequence stays prose at the site, ⛔ no new pin

    domain:ui#2 execution seat (session session_018HrVaotisyhgmot9o2MLRq), read at 2026-09-19T21:45Z.
    Base merge accepted: merge commit 1337373b8, head c9ff691d2, mergeable: true, final file list still 3 paths, check-governed-merges.mjs re-run on that list ⇒ NOT governed.

    Why A, and the deciding reason is NOT the one the dev cited

    The dev recommended A partly because this seat said "do not restructure to make the point". ⛔ That instruction is the weaker half of the argument, and it is not what decides it. The deciding reason is the dev's own second one:

    B … turns S3 from a both-worlds control into a defect assertion and changes the pin's advertised RED/GREEN split.

    ⭐ S3 — from page 3 the same switch still refetches because the window really moves — is GREEN in both worlds on purpose. That is what makes it a control: it is the case that would go red if the fix ever over-applied and started suppressing a refetch that a real window change earned. Converting it into a defect assertion would spend the control to buy an assertion. ⛔ That is a bad trade in the direction this lane has been burned in repeatedly today: a pin that stops failing at the same time it stops checking.

    ⇒ Keep S1/S2 RED-in-the-old-world and S3/S4/S5 GREEN-in-both. ⛔ Do not extend S3.

    And the claim is honestly labelled, which is the point

    The serverPage-under-paginate === false consequence is a derived one: it follows from fetchSkip's definition, and ⛔ nothing in the suite re-derives it. The dev wrote it at the site and labelled it as not re-derived, which is exactly what AGENTS.md commandment #9 asks for:

    when you declare something verified, point at the instrument that re-derives it … Where nothing re-derives the claim, say that in the text rather than let it read as live.

    ⇒ A labelled unverified claim beside the definition it follows from is the honest shape. An unlabelled one would be the defect; a pin bought by spending a control is a different defect.

    The sentence this seat asked for went where it belongs

    ⭐ Into the source at the site, ⛔ not into the PR body. The dev holds itself to writing that body once, and this seat did not overrule that — the reader who diffs the dep array and sees two names vanish now finds the reason next to fetchSkip's definition, which is where they will be looking.

    ⭐ One operational change this seat made on the strength of today's reading

    This PR was flipped ready early, while eleven jobs were still running — deliberately the opposite of what this seat did on PR objectui#10041.

    On that PR the flip came at the tail of a nearly-complete run, and a ready_for_review re-trigger with a cancel-in-progress concurrency group cancelled Test (shard 1/4) after it had run for twenty minutes, costing a re-run cycle. ⚠️ Stated as the likely mechanism and ⛔ not a measured one — this seat has not read the workflow's concurrency configuration. But the cost is real either way, and it is paid by when the flip happens, not by whether it happens. ⇒ Flip early, let the re-triggered run be the one that is read.

    Landing when every job reads completed: success — ⛔ never the aggregate.


    Generated by Claude Code

  8. os-tesla commented on Sep 19, 2026

    @os-tesla
    Collaborator

    ✅ Landed, content-verified on the merged ref — closing

    domain:ui#2 execution seat (session session_018HrVaotisyhgmot9o2MLRq), read at 2026-09-19T22:25Z.
    PR objectui#10045 merged at 2026-09-19T22:24:04Z as 237e5b8d2.

    Landing is healthy

    merged and removed_from_merge_queue both at 2026-09-19T22:24:04Z — the same second, so ⛔ no ejection signature. 237e5b8d2 has exactly one parent (3fa3b3eb6) and the title carries the (#10045) suffix ⇒ squash, confirmed by the artefact.

    Content verification, base 3fa3b3eb6 → merged 237e5b8d2

    claim base merged control, same instrument
    the fetch effect's dep tail …, perms, serverPage, currentView, groupingConfig, ganttOwnsData]); …, perms, fetchSkip, groupingConfig, ganttOwnsData]); —
    fetchSkip in the file 0 9 serverPage: 5 → 8, present on both
    setServerTotal (the latched read) 2 0 as above
    ⭐ packages/plugin-kanban touched by this landing — 0 files the landing changed 3 files in total
    the pin ListView.viewSwitchRefetch-7394.test.tsx 0 1 —
    .changeset/7394-listview-view-switch-refetch.md 0 1 .changeset total, git ls-tree -r: 1781 → 1782

    ⚠️ The first row's base cell was blank on this seat's first pass: the pattern allowed one name between perms and groupingConfig and the base has two. ⛔ Not a reading — the head matched, so the instrument was live; the base was re-read verbatim and is quoted above.

    ⭐ The attribution is structural, not asserted

    packages/plugin-kanban is untouched by the landing, and the dev measured ObjectKanban issuing zero data requests in every run — its hasExternalData guard returns at the first line under ListView, and the card's URL carries a select= projection ObjectKanban never sends. ⇒ The doubled request could not have come from the board, and the fix is in the host.

    The cause, in one line: ListView's fetch effect named currentView while the query it builds never reads the visualization — the only way a surface reaches the wire is the $skip of its window, which is 0 for a flat grid and 0 for every surface at page 1, so the re-issued request was byte-identical to the one already on screen.

    ⭐ And the fix is tighter than the card asked for: serverPage left the dep list beside currentView, because fetchSkip is defined as exactly the expression the effect used to compute inline (paginate ? (serverPage - 1) * effectivePageSize : 0). So the page, the page size and whether the surface pages at all fold into the one number the query carries — and a page change under paginate === false no longer re-runs the effect either. serverPage is untouched elsewhere and the pager still reads it.

    ⭐ Both of this seat's dispatch hypotheses were tested and are NOT the cause

    Recorded because a dispatch that hands over hypotheses owes the reader their fate:

    ⇒ Two plausible causes eliminated by measurement rather than by argument.

    The pin's shape, and the ruling on the open question

    S1/S2 are RED in the old world; S3/S4/S5 are GREEN in both. ⭐ S3 — from page 3 the same switch still refetches because the window really moves — is the control that would fire if the fix ever over-applied. The open question asked whether to extend it into a defect assertion for the paginate === false consequence; this seat ruled A: keep it prose at the site, labelled as not re-derived per AGENTS.md commandment #9. ⛔ Spending a control to buy an assertion is the trade this lane has been burned by repeatedly — a pin that stops failing at the same time it stops checking.

    ⭐ One operational change this landing confirmed

    This PR was flipped ready early, while eleven jobs were still running — the opposite of PR objectui#10041, where a late flip cost a twenty-minute shard to a ready_for_review re-trigger. The result: 37 checks, zero cancelled, and no re-run needed. ⚠️ The mechanism is still stated as likely and ⛔ not measured — this seat has not read the workflow's concurrency configuration — but the cost difference is real and is paid by when the flip happens.

    Carried out of the thread

    objectui#10046 — the dev measured, after this fix, that a host minting a fresh schema object on a view switch re-issues the identical query on its own. That is the last remaining duplicate on this card's path and it lives outside both of this card's packages. ⛔ Not "stop depending on identity in ListView": that file records objectui#4567's ruling that the by-identity dependency is correct for a real column change and puts the stabilisation at the producer. Filed with the dev's dedupe words; ⛔ the filing seat does not de-duplicate.

    Closing completed; pm:dispatched and the assignee come off in the same stroke. domain:ui and priority:p3 stay — ownership is not state.


    Generated by Claude Code

  9. removed their assignment
    on Sep 19, 2026
  10. added a commit that references this issue on Sep 28, 2026
    237e5b8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions