Skip to content

[Decision] Field changes are recorded but not shown unless an object opts in: who decides a record shows its change history? #30074

Closed

Description

@objectstack-fleet

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

The maintainer: 「等我决定的都要立卡,并且从业务的角度给我具体解释和我沟通」 (2026-11-04). Measured by the seat on main 63b86b385d, on the example CRM unless noted. No domain:* label is set: triage routes this card.

The question

A manager asks who changed a deal's amount and from what. The platform has already recorded it, yet the record's 动态 shows only "更新了 商机…:赢单概率 (%)", with no old or new value. The values appear only if the object declares enable.trackHistory: true, and most authors will not know to.

Governing text: packages/spec/src/data/object.zod.ts:236 (trackHistory is an opt-in flag) and ui/packages/app-shell/src/views/RecordDetailView.tsx:2375-2380.

Measured

  • sys_audit_log held the old and new values for a probability change from 70 to 75 (reviewer's reading; the seat read the gate in code).
  • examples/app-crm declares no enable on its objects. examples/app-showcase and app-todo set it on some.
  • The 动态 tab offers a 变更 filter even when no changes can appear.

Options

  • A. Example first: the CRM example opens it on its four main objects, the 变更 filter hides when history is off, and the flag stays opt-in.
  • B. Default on: every business object shows history unless it opts out.
  • C. Leave it.

Recommendation: A

四轴分析

实际业务需求。 「谁把金额从多少改成多少」是销售管理几乎每天的问题,也是出错后追责的依据。不开时只能找管理员查审计表,运营往往不知道有这张表。

项目长远合理性。 B 对用户最省事,但改变所有存量对象的行为,也要先确认存储量、隐私和字段权限(看不到的字段不能出现在历史里)。A 先让示例示范正确做法,B 留到确认这些之后。

防 AI 写错。 AI 照着示例写应用,示例开了它就会开。隐藏无效的 变更 筛选,也去掉一个看起来能用实际没内容的入口。

创业阶段不扩散。 A 只改示例和一个显示条件。B 影响面大,不适合现在做。

棱 A B C
业务 中 强 弱
长远 中 强 弱
防错 强 中 弱
不扩散 强 弱 强

Not measured

The cost of B on storage and read speed, and whether history honours field-level read rules.

Re-check

git grep -n "trackHistory !== true" origin/main -- ui/packages/app-shell/src/views/RecordDetailView.tsx

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Nov 4, 2026
  2. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

    The maintainer, 2026-11-04: 「30079这种不是应该在元数据应用中自己去开发自定义操作吗?你的意见是批量换负责人放到内核吗?其他全部同意」.

    Ruling: option A. The CRM example opens enable.trackHistory on its four main objects, and the 变更 filter hides when history is off. The flag stays opt-in. Defaulting it on is not decided here. needs-user-decision is removed; triage routes this card.

  3. removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Nov 4, 2026
  4. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 kept · domain:ui · 2026-11-04T13:04Z

    ⛔ Not a claim.

    • Read fresh. The ruling recorded on this card (A, 「其他全部同意」) is the scope. The CRM example turns on enable.trackHistory on its four main objects, and the 变更 filter hides when history is off. The flag stays opt-in. p2 kept.

    Generated by Claude Code

  5. added
    domain:uiDomain lane — seat card indexed by label:pm:seat
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 4, 2026
  6. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3

    Claim: PM loop round 1
    Session: session_01QSeKYnE9YNkSZen7sijLA3
    Account: os-justin
    Branch: claude/issue-30074-crm-track-history
    Worktree: objectstack-issue-30074
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: examples/app-crm/src/objects/{account,contact,lead,opportunity}.object.ts (the enable.trackHistory opt-in only), ui/packages/app-shell/src/views/RecordDetailView.tsx (the 动态 tab's 变更 filter visibility, near historyEnabled), their tests, one root .changeset/ file (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: TIER_DEFAULT — --tier: "no path-derived mandate: the surface hits none of the 4 declared glob(s)", effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6631387255
    Premise: holds
    Serial constraints cleared: none — no open domain:ui pm:dispatched claim names RecordDetailView.tsx or examples/app-crm (read 2026-11-04T15:49Z: #30059 and #30057 (seat 1) declare studio-design/** only; #30038 and #30050 are held by seat 3)
    Ruling-ref: 6631104393 (option A, the maintainer's 「其他全部同意」)

  7. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3
    os-dev-report

    {
      "issue": 30074,
      "status": "done",
      "branch": "claude/issue-30074-crm-track-history",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30158",
      "session": "session_01QSeKYnE9YNkSZen7sijLA3",
      "premise_still_valid": true,
      "summary": "CRM example: crm_lead, crm_account, crm_contact, crm_opportunity now declare enable: { trackHistory: true } (the four Sales-nav objects other than crm_activity, the activity log itself; crm_opportunity_line_item is a child without a nav entry). The Changes chip is rendered by @object-ui/plugin-detail (RecordActivityTimeline, state in the record:activity renderer), not by RecordDetailView.tsx, so the landing is there: new RecordFieldHistoryContext (default true) + timelineStreamFilters(); record:activity drops the changes chip while it is false and falls back to all if it was chosen; RecordDetailView provides its existing historyEnabled. Premise partly false, executed as ruled anyway: the card's 'the Changes filter shows even when no changes can appear' is not so -- sys_activity created/updated/deleted/assigned/shared rows map to the field_change feed type and sit under Changes (existing pin 'the four chips' holds one), so on a non-history object those rows are now reachable only under All; raised in open_questions. Surface breach (declared in PR): 4 plugin-detail src files + plugin-detail README beyond the claimed surface, as the dispatch allowed.",
      "tests": "head 8c5b89c91. New pins: plugin-detail recordTimelineStream-27055.test.tsx (top-level describe, 4 cases: shown=4 chips, not shown=3 chips + All draws all, no provider=4 control, chosen Changes removed to All) and app-shell RecordDetailView.recordPageTiers-26678.test.tsx (top-level describe, real RecordDetailView mount on ?related=timeline: trackHistory object to all/activity/discussion/changes; same object without it to all/activity/discussion and 0 audit reads). Targeted 3 files: Test Files 3 passed (3), Tests 27 passed (27), VERDICT command-exit 0. plugin-detail whole: Test Files 369 passed | 1 skipped (370), Tests 3264 passed | 18 skipped, VERDICT 0. app-shell NARROWED (declared): 218 files naming RecordDetailView/RecordActivityTimeline/recordTimelineStream/record-activity: 218 passed, Tests 1630 passed, VERDICT 0; rest of the package to CI Test UI. type-check: plugin-detail exit 0, app-shell exit 0 (script names echoed: tsc --noEmit && tsc -p tsconfig.test.json). example-crm typecheck exit 0, vitest 7/7 files, 48/48 tests. Ablation: scripts/ablation-replace.mjs on record-activity.tsx anchor 'timelineStreamFilters(React.useContext(RecordFieldHistoryContext))' to 'timelineStreamFilters(true || ...)' (subject resolves to src via ui/vitest.config.mts alias, no dist leg): anchor 1 to 0, blob 7b5fe9176ec0 to 69e1bc36c51c; 3 red (both plugin-detail not-shown pins, app-shell without-it pin), shown/control green; restored blob == HEAD 7b5fe9176ec0, git diff HEAD empty.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 8c5b89c91: 53 commands, all run, exit captured before pipes; --ran: '53 derived famil(ies) accounted for -- 53 run, 0 NOT-MEASURED (a DERIVED zero -- all 53 recorded an exit code and none of them is 3)'. 50 exit 0 first pass; check:dual-build-cjs-loads and check:i18n-coverage exit 3 (PREREQUISITE NOT MET) then exit 0 after prerequisite builds; check:type-check-debt 124 (local 400s timeout) then exit 0 under the lock; ui vitest scripts/ 170 passed | 2 skipped. check-sdui-manifest exit 0. check-platform-checklist not owed (no export renamed/removed). CI check-runs on 8c5b89c91 at report time: all required contexts queued (Lint & Repo Gates lanes, TypeScript Type Check lanes, Test Core, Build Core, Governed Surface Queue Guard, Lint UI, Type Check UI, Test UI 1-16, Build & E2E UI, Live E2E UI) -- in_progress, not waited on.",
      "dogfood_battery": "n/a -- no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 -- relay pr_create x1 (POST /repos/objectstack-ai/objectstack/dispatches, executed as pulls create: draft, no labels, no assignees; the dispatch tool's 300s client wait timed out, PR #30158 confirmed by REST read and not re-sent); os-dev-report comment x1 via post-stamped.mjs (issues/30074/comments). Plus git push x4 (empty-branch probe and 3 commits), not REST.",
      "open_questions": [
        {
          "question": "With history off, sys_activity created/updated/deleted/assigned/shared rows (feed type field_change) used to sit under 变更; with 变更 hidden they are reachable only under 全部 (活动 excludes field_change). Keep it so?",
          "options": [
            "A keep as landed: rows only under 全部 on non-history objects",
            "B while 变更 is hidden, 活动 also lists the activity-sourced field_change rows (small change in filterTimelineStream, one pin)",
            "C hide 变更 only when nothing can feed it (history off AND enable.activities false)"
          ],
          "recommendation": "B, because it keeps the ruling (no 变更 chip without history) and keeps every row filterable; C contradicts the ruling's wording; A is acceptable but loses a filter the stream had."
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none -- the premise note above is in PR Acceptance notes and open_questions, not filed"
      ],
      "deviations": "app-shell suite narrowed to 218 related files (declared; CI Test UI runs it whole). Branch not re-merged with main: 8 commits landed after base 55337f4ce, none touches a diff path. Comment/commit trailers use the model-free pair per AGENTS.md, not the harness reminder's.",
      "files_changed": [
        ".changeset/30074-crm-track-history.md",
        "examples/app-crm/src/objects/account.object.ts",
        "examples/app-crm/src/objects/contact.object.ts",
        "examples/app-crm/src/objects/lead.object.ts",
        "examples/app-crm/src/objects/opportunity.object.ts",
        "ui/packages/app-shell/src/views/RecordDetailView.recordPageTiers-26678.test.tsx",
        "ui/packages/app-shell/src/views/RecordDetailView.tsx",
        "ui/packages/plugin-detail/README.md",
        "ui/packages/plugin-detail/src/RecordActivityTimeline.tsx",
        "ui/packages/plugin-detail/src/__tests__/recordTimelineStream-27055.test.tsx",
        "ui/packages/plugin-detail/src/index.tsx",
        "ui/packages/plugin-detail/src/recordTimelineStream.ts",
        "ui/packages/plugin-detail/src/renderers/record-activity.tsx"
      ]
    }
  8. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3

    维护者速读 · #30074 回箱:裁决 A 的一个前提被证伪 · 2026-11-04T17:43Z

    一句话问题。 你裁的 A 是「记录未开字段历史时,动态里的『变更』筛选隐藏」。卡上给你的前提是(席位自己测的)「那时变更里不会有内容」。实测这个前提不成立:没开历史的对象,动态里「创建了 / 更新了 / 删除了 / 分配了 / 共享了」这几类记录(不带旧值新值)今天也都归在「变更」下。所以按 A 原样把「变更」隐藏后,这些记录只能在「全部」里看到,「活动」里也没有。PR #30158 已按 A 原样实现,停在 draft,等你定这一点。

    Governing text: the ruling 6631104393 (option A); ui/packages/plugin-detail/src/renderers/recordActivityFeed.ts:140-144 (created/updated/deleted/assigned/shared → 'field_change'); ui/packages/plugin-detail/src/recordTimelineStream.ts:162 (变更 = type === 'field_change'). Spec declares the field_change feed type (packages/spec/src/data/feed.zod.ts:32), but no spec text names which types a chip shows (git grep -n "chip" origin/main -- packages/spec/src/data/feed.zod.ts → 0; positive control field_change in the same file → 1 hit).

    Protocol: no spec change in any option; UI-only.

    Premise (re-check)

    • git grep -n "created: 'field_change'" origin/main -- ui/packages/plugin-detail/src/renderers/recordActivityFeed.ts → 1 hit (positive control: system: 'system' in the same table).
    • Audit-sourced items carry source: 'sys_audit_log' (recordTimelineStream.ts, auditEntriesToFeedItems), so the two kinds can be told apart.

    选项

    选项 做什么 客户看到的后果 工作量
    A 保持现状落地 PR #30158 原样 没开历史的对象,「创建了/更新了…」这类记录只在「全部」里,筛选少了一档 0(已写好)
    B 隐藏时挪到「活动」 只在「变更」隐藏时,把这几类记录归到「活动」 没开历史时这些记录在「活动」里;开了历史时仍在「变更」里,同一条记录的归类随开关变 ui · 本 PR 内 · 约 +20 行 + 1 个 pin,无先例
    C 按含义分类,不看开关 「变更」只放带旧值新值的字段变更(审计来源);「创建了/更新了/分配了…」这类事件一律归「活动」 无论开不开历史,「变更」都只有「谁把什么从多少改成多少」;没开历史时「变更」本就无内容,隐藏就名副其实 ui · 本 PR 内 · 约 +30 行 + 改 1 个既有 pin(「四个筛选」那条)+ 1 个新 pin,无先例。改法限定:在 filterTimelineStream 里按来源判(source === 'sys_audit_log'),⛔ 不改 ACTIVITY_TYPE_TO_FEED_TYPE 映射表(那会牵动 5 个以上既有 pin 与平台测试清单);同步改 RecordActivityTimeline.tsx:285 面板下拉的 changes_only,否则面板与流的「变更」不一致

    业务含义直译。 A 相当于把一类记录放进了只有「全部」能翻到的抽屉;B 相当于同一张单据随部门设置换柜子;C 相当于按单据种类固定柜子:「改了哪个字段、从多少改成多少」一个柜,「谁创建、谁分配」另一个柜。

    推荐:C

    只看① 选 C;②③④ 是否翻转:否。

    项目长远合理性(领起)。 两年后这个面板应当像主流 CRM 那样:「字段历史」(Salesforce Field History、HubSpot property history)只放字段级前后值,「活动」放事件。C 让分类由记录本身的含义决定,没有开关相关的特例;B 在分类规则里多出一条「看开关」的分支,以后谁都要记住;A 留下一类在筛选里无处可去的记录。

    实际业务需求。 这个标志是按需开启的(object.zod.ts:236)。本 PR 之前,示例 CRM 的 7 个对象和 app-multi-package 都没有开(app-showcase、app-todo 的部分对象开了)。任何没开的对象,用户按「活动」筛选时都找不到「谁创建、谁分配」这类最常看的记录。

    防 AI 写错。 都不涉及 AI 写的元数据。C 的规则一句话就能说清(「变更 = 有旧值新值」),AI 改这块代码时最不容易写错;B 的条件分支最容易在后续改动里漏掉。

    创业阶段不扩散。 三者都不加键、不动服务端。C 比 B 多改一个既有 pin,工作量相近(不足 3 倍差)。

    未取的变体 C′。 把创建/删除/共享映射到 spec 已有的 record_create/record_delete/sharing 类型(feed.zod.ts:40-43),语义更干净,但要改映射表,代价见 C 行,现在不荐。

    置信缺口。 没测开了历史的对象上,「更新了」事件与审计条目并存时用户是否觉得重复:现有代码在有审计条目时已去掉「更新了」事件(recordTimelineStream.ts:138),C 不改这一点。

    裁后执行。 选 C:同一 dev 在 PR #30158 上续改 recordTimelineStream.ts 的分类与 pin,席位复核后落地。选 B:同上,改法换成 B。选 A:席位直接按现 PR 复核落地。

    os-decision-facets

    • ① 长远:C 缩小特例(分类不看开关);B 增加一条开关相关分支;A 留下无处可筛的一类记录。
    • ② 拉动:任何未开历史的对象今天就会撞上(「活动」里找不到创建/分配记录);代码读取与既有 pin 证实(27055 the four chips),未在浏览器实测(PR 也未测)。
    • ③ 防错:C 是一句话的闭合规则;B 的条件分支易被后续改动漏掉。
    • ④ 不扩散:三者都不加键、不动服务端;C 与 B 工作量相近。

    Contract review: isolated CONTRACT_REVIEW_TIER review returned FAIL with 6 required corrections; all applied in this text (spec grep, example census, premise attribution, C's route and the second filter, facet ② evidence, stamp).

    Prior rulings read: trackHistory, 变更, field_change on #30074 and #26676 → 1 ruling (6631104393); ADR none; thread: 6631104393.

  9. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 4, 2026
  10. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3

    Release: claim 6635173915 (session_01QSeKYnE9YNkSZen7sijLA3, seat domain:ui#2) is released at clock-out, 2026-11-05T03:15Z, on the maintainer's 「当前任务处理完,合并后就下班」.
    Resume-from: claude/issue-30074-crm-track-history@8c5b89c9

    State: the card stays on needs-user-decision (analysis 6637710958, options A/B/C, seat recommends C). Draft PR #30158 carries option A as built, CI green on 8c5b89c9, not ACCEPTed. After the ruling, a sibling domain:ui seat re-claims, resumes from the line above, and has the same dev change recordTimelineStream.ts (and the panel's changes_only filter) to the chosen letter. Its PR is serial with #30122 (record timeline).

  11. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3

    Ruling recorded · #30074 · letter C · 2026-11-05T04:24Z

    The maintainer (os-justin) gave this ruling verbatim in seat domain:ui#2's session: 「C」. It answers the seat's analysis 6637710958 (options A/B/C, recommendation C), which the maintainer was shown in the same session just before ruling.

    Ruling: option C. The timeline's 变更 chip holds only field-level changes with old and new values (audit-sourced, source: 'sys_audit_log'). Activity-sourced events (created / updated / deleted / assigned / shared) always sit under 活动, whatever the history flag. With history off, 变更 has nothing to hold, so hiding it (ruling A of 6631104393, which this refines) is now accurate. Neither the CRM example's enable.trackHistory on its four main objects nor the opt-in posture changes.

    Execution (from the analysis's 裁后执行 and its corrections):

    State: needs-user-decision → pm:queue in this stroke. The card is unassigned; any domain:ui seat may claim it.

  12. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Nov 5, 2026
  13. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC

    Claim: PM loop round 4 (resume of released claim 6635173915)
    Session: session_01WGufzic59DvGAbu7U78pZt
    Account: os-support-ai (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/project-thread-7ocxgx
    Worktree: objectstack-issue-30074
    Domain: domain:ui
    Seat: domain:ui#1
    Resume-from: claude/issue-30074-crm-track-history@8c5b89c9 (draft PR #30158; Release 6648707864). The new PR supersedes #30158; the seat closes #30158 once it is up.
    File surface: #30158's 13 files (examples/app-crm four objects' enable.trackHistory, ui/packages/plugin-detail/src/recordTimelineStream.ts, RecordActivityTimeline.tsx, renderers/record-activity.tsx, index.tsx, README, ui/packages/app-shell/src/views/RecordDetailView.tsx and their tests, the changeset); ⛔ ACTIVITY_TYPE_TO_FEED_TYPE not edited; no server, REST or spec change (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (p2), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the record timeline (filterTimelineStream, the panel's changes_only) puts activity-sourced rows under 变更 | ruling C (6649643659): 变更 holds only audit-sourced field changes with old/new values | every record page reader, and the CRM example as the reference posture, today
    Thread-read: 6649643659
    Premise: holds (filterTimelineStream classifies by feed type, not source, on origin/main 9b8a5867; #30158 at 8c5b89c9 carries ruling A only)
    Serial constraints cleared: none — only #30158 (superseded by this claim) touches recordTimelineStream.ts / RecordActivityTimeline.tsx; #30122 goes after this card, not folded.

  14. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 5, 2026
  15. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzic59DvGAbu7U78pZt
    os-dev-report

    Stamp: 2026-11-05T05:15Z

    {
      "issue": 30074,
      "status": "done",
      "branch": "claude/project-thread-7ocxgx",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30294",
      "session": "session_01WGufzic59DvGAbu7U78pZt",
      "premise_still_valid": true,
      "summary": "Resumed claude/issue-30074-crm-track-history@8c5b89c9 (PR #30158, ruling A) onto the pinned branch, merged origin/main 9b8a5867 cleanly (os-regen-merge.sh), and added the ruling C delta: new isFieldHistoryEntry(item) in recordTimelineStream.ts (type field_change AND source sys_audit_log); filterTimelineStream's changes chip holds those only and activity holds everything that is neither a comment nor one of those, so sys_activity created/updated/deleted/assigned/shared rows sit under Activity whatever the history flag; RecordActivityTimeline's changes_only uses the same predicate. ACTIVITY_TYPE_TO_FEED_TYPE untouched. Ruling A half of #30158 kept unchanged. Changeset and README amended to C. Surface: 15 files = #30158's 13 plus 2 existing plugin-detail test files whose pins read the old classification (declared in the PR).",
      "tests": "head 93bbdd78. Flipped pin 'the four chips' (recordTimelineStream-27055): created row under activity, changes = audit only, every entry in exactly one of activity/discussion/changes. New pins same file: history on AND off, activity lists all five activity events and no audit change; CONTROL history on, changes holds the old/new field change and no event; panel changes_only same rule. Fixture triage: record-activity.test 'filterMode seeds which slice' reseeded to tasks_only + new pin 'changes_only holds no activity event'; 8968 fixture field-change row gains source sys_audit_log (the only fieldChanges producer is auditEntriesToFeedItems), assertions unchanged. Targeted 3 files: Test Files 3 passed (3), Tests 69 passed (69), VERDICT command-exit 0. plugin-detail whole + app-shell RecordDetailView.recordPageTiers-26678: Test Files 370 passed | 1 skipped (371), Tests 3292 passed | 18 skipped. type-check plugin-detail exit 0; app-shell exit 0 after full build (first run before the full build red on unbuilt @object-ui declarations TS2307, not this diff). Ablation scripts/ablation-replace.mjs on recordTimelineStream.ts, anchor isFieldHistoryEntry body to type-only (src via ui vitest alias, no dist leg): anchor 1 to 0, blob 16c475ce1d79 to aee54ae67d0a; 6 red = exactly the flipped + new pins, 8968 green; restored blob == HEAD 16c475ce1d79, git diff HEAD empty. Live CRM zh-CN (objectstack dev --seed-admin --fresh + Vite console): new crm_lead edited once: chips all/activity/discussion/changes, changes = company old to new plus the create entry's initial values, activity = created row only; new crm_activity (history off) edited once: chips all/activity/discussion, no changes chip, activity = updated + created. Shots in /mnt/project-files/ui-orders/30074-shots/ (5 png).",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 93bbdd78: 53 commands, run serially after a full build, exit captured before pipes: 53 of 53 exit 0. --ran: '53 derived famil(ies) accounted for -- 53 run, 0 NOT-MEASURED (a DERIVED zero -- all 53 recorded an exit code and none of them is 3)'. check-sdui-manifest exit 0; ui vitest scripts/ 170 passed | 2 skipped. ui check:new-line-citations 0 new, exit 0. check-platform-checklist not owed (nothing renamed/removed). CI check-runs on 93bbdd78: in_progress at report time, not waited on.",
      "dogfood_battery": "n/a -- no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "4 -- issue_read get x1, issue_read get_comments x2, pull_request_read get x1; all reads, no write tool",
      "api_writes": "2 -- relay pr_create x1 (repository_dispatch, run 41972781306, PR #30294 read back identical 9453 bytes, draft, no labels, no assignees); os-dev-report comment x1 via post-stamped.mjs (issues/30074/comments). Plus git push x1, not REST.",
      "open_questions": [
        {
          "question": "Off the default record page the record:activity panel reads no audit, so under ruling C its changes_only option is always empty there (before, it listed activity created/updated rows). Keep offering it?",
          "options": [
            "A keep as landed (ruling C as written; the option is empty where no audit is read)",
            "B hide changes_only in the panel dropdown where the host gives no field history (small follow-up, same RecordFieldHistoryContext)"
          ],
          "recommendation": "A for this PR (executes the ruling); B as a seat follow-up if the maintainer wants it, because an always-empty filter is the shape the card removed for the stream."
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: #30122 -- live: on a history-on crm_lead created via the data API, the creation is said twice in All (activity 'created' row plus an audit entry listing every initial value), because auditEntriesToFeedItems keeps any entry with changes, the create entry included, though its doc says the creation is the activity stream's own row; compact rows did name the actor in this run",
        "carrier: none -- panel changes_only empty off the default page: in PR Acceptance notes and open_questions, not filed"
      ],
      "deviations": "File surface +2 existing plugin-detail test files (pins read the old classification; ruling-driven). Branch not re-merged after main moved 14 commits (none touches the 15 paths; merge-tree clean). Not subscribed to PR activity and no assignee/reviewer set: the os-dev contract overrides the harness posture. Commit trailers use the model-free pair."
    }
    
  16. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC

    Landed · PR #30294 · 2026-11-05T05:48Z

    probe reading
    merge MERGED c1240a38ac at 2026-11-05T05:47:51Z, via the merge queue (seat ACCEPT on PR #30294)
    card closed completed by Fixes #30074
    content on origin/main isFieldHistoryEntry in ui/packages/plugin-detail/src/recordTimelineStream.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions